From 87e8d5077c42d09cafc69d8c0c54fc6729a3e0c5 Mon Sep 17 00:00:00 2001 From: tayler6000 Date: Tue, 27 Sep 2022 01:46:13 -0500 Subject: [PATCH] [ADD] Added pytest and tests for SIP authentication header parsing. [ADD] Added black checks for tests. [CHANGE] Changed auth_match compile to use r-string to fix deprecation. [CHANGE] Removed version pinning from requirements-test. [CHANGE] Ran black over setup.py --- .github/workflows/black.yml | 4 +++- .github/workflows/pytest.yml | 34 +++++++++++++++++++++++++++++ pyVoIP/SIP.py | 2 +- requirements-test.txt | 3 ++- setup.py | 24 ++++++++++----------- tests/__init__.py | 0 tests/test_sip.py | 42 ++++++++++++++++++++++++++++++++++++ 7 files changed, 94 insertions(+), 15 deletions(-) create mode 100644 .github/workflows/pytest.yml create mode 100644 tests/__init__.py create mode 100644 tests/test_sip.py diff --git a/.github/workflows/black.yml b/.github/workflows/black.yml index e011ee9..6f3963e 100644 --- a/.github/workflows/black.yml +++ b/.github/workflows/black.yml @@ -30,5 +30,7 @@ jobs: run: | python -m pip install --upgrade pip pip install -e . -r requirements-test.txt - - name: Black + - name: Black pyVoIP run: black --check pyVoIP + - name: Black tests + run: black --check tests diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml new file mode 100644 index 0000000..05488f8 --- /dev/null +++ b/.github/workflows/pytest.yml @@ -0,0 +1,34 @@ +# This workflow will install Python dependencies, run tests and lint +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions + +name: Check pytest + +on: + push: + branches: + - "master" + - "development" + pull_request: + +jobs: + check-pytest: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: + - "3.7" + + steps: + - uses: actions/checkout@v3.0.2 + with: + fetch-depth: 2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4.0.0 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -e . -r requirements-test.txt + - name: pytest + run: pytest diff --git a/pyVoIP/SIP.py b/pyVoIP/SIP.py index 92a8345..93372a7 100644 --- a/pyVoIP/SIP.py +++ b/pyVoIP/SIP.py @@ -341,7 +341,7 @@ def __init__(self, data: bytes): self.body: Dict[str, Any] = {} self.authentication: Dict[str, str] = {} self.raw = data - self.auth_match = re.compile('(\w+)=("[^",]+"|[^ \t,]+)') + self.auth_match = re.compile(r'(\w+)=("[^",]+"|[^ \t,]+)') self.parse(data) def summary(self) -> str: diff --git a/requirements-test.txt b/requirements-test.txt index 0a098f1..6e9e9dd 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -1 +1,2 @@ -black==22.8.0 +black +pytest diff --git a/setup.py b/setup.py index a8a46be..22c17e8 100644 --- a/setup.py +++ b/setup.py @@ -2,21 +2,21 @@ from setuptools import setup -with open("README.md", "r", encoding='utf-8') as f: +with open("README.md", "r", encoding="utf-8") as f: long_description = f.read() setup( - name='pyVoIP', - version='1.6.2', - description='PyVoIP is a pure python VoIP/SIP/RTP library.', + name="pyVoIP", + version="1.6.2", + description="PyVoIP is a pure python VoIP/SIP/RTP library.", long_description=long_description, long_description_content_type="text/markdown", - author='Tayler Porter', - author_email='taylerporter@gmail.com', - url='https://github.com/tayler6000/pyVoIP', + author="Tayler Porter", + author_email="taylerporter@gmail.com", + url="https://github.com/tayler6000/pyVoIP", project_urls={ "Bug Tracker": "https://github.com/tayler6000/pyVoIP/issues", - "Documentaiton": "https://pyvoip.readthedocs.io/" + "Documentaiton": "https://pyvoip.readthedocs.io/", }, classifiers=[ "Programming Language :: Python :: 3", @@ -28,9 +28,9 @@ "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", "Natural Language :: English", "Topic :: Communications :: Internet Phone", - "Topic :: Communications :: Telephony" + "Topic :: Communications :: Telephony", ], - packages=find_packages(), - package_data={'pyVoIP': ['py.typed']}, - python_requires=">=3.6" + packages=find_packages(exclude=("tests",)), + package_data={"pyVoIP": ["py.typed"]}, + python_requires=">=3.6", ) diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_sip.py b/tests/test_sip.py new file mode 100644 index 0000000..d81c7d0 --- /dev/null +++ b/tests/test_sip.py @@ -0,0 +1,42 @@ +from pyVoIP.SIP import SIPMessage +import pytest + + +@pytest.mark.parametrize( + "packet,expected", + [ + ( + b"""SIP/2.0 401 Unauthorized\r\nVia: SIP/2.0/UDP 0.0.0.0:5060;branch=z9hG4bK03150189fc65493a9d4e3a582;rport=5060;received=192.168.178.110\r\nFrom: "tarantulla" ;tag=9338abd3\r\nTo: "tarantulla" ;tag=950C00889AC0DB3B\r\nCall-ID: 6b86b273ff34fce19d6b804eff5a3f57@0.0.0.0:5060\r\nCSeq: 1 REGISTER\r\nWWW-Authenticate: Digest realm="fritz.box", nonce="78B29326485EAE52"\r\nUser-Agent: FRITZ!OS\r\nContent-Length: 0\r\n\r\n""", + {"realm": "fritz.box", "nonce": "78B29326485EAE52"}, + ), + ( + b"""SIP/2.0 401 Unauthorized\r\nVia: SIP/2.0/UDP 0.0.0.0:5060;branch=z9hG4bK03150189fc65493a9d4e3a582;rport=5060;received=192.168.178.110\r\nFrom: "tarantulla" ;tag=9338abd3\r\nTo: "tarantulla" ;tag=950C00889AC0DB3B\r\nCall-ID: 6b86b273ff34fce19d6b804eff5a3f57@0.0.0.0:5060\r\nCSeq: 1 REGISTER\r\nWWW-Authenticate: Digest algorithm=MD5,realm="local",nonce="111111:222222aaaaaa333333bbbbbb444444"\r\nUser-Agent: FRITZ!OS\r\nContent-Length: 0\r\n\r\n""", + { + "algorithm": "MD5", + "realm": "local", + "nonce": "111111:222222aaaaaa333333bbbbbb444444", + }, + ), + ( + b"""SIP/2.0 401 Unauthorized\r\nVia: SIP/2.0/UDP 0.0.0.0:5060;branch=z9hG4bK03150189fc65493a9d4e3a582;rport=5060;received=192.168.178.110\r\nFrom: "tarantulla" ;tag=9338abd3\r\nTo: "tarantulla" ;tag=950C00889AC0DB3B\r\nCall-ID: 6b86b273ff34fce19d6b804eff5a3f57@0.0.0.0:5060\r\nCSeq: 1 REGISTER\r\nWWW-Authenticate: Digest algorithm=MD5, realm="asterisk",nonce="45f77cee"\r\nUser-Agent: FRITZ!OS\r\nContent-Length: 0\r\n\r\n""", + { + "algorithm": "MD5", + "realm": "asterisk", + "nonce": "45f77cee", + }, + ), + ( + b"""SIP/2.0 401 Unauthorized\r\nVia: SIP/2.0/UDP 192.168.0.76:5060;rport=5060;received=192.168.0.76;branch=z9hG4bK92b19bf363d84d2ea95d18cd3\r\nCall-ID: 6b86b273ff34fce19d6b804eff5a3f57@192.168.0.76:5060\r\nFrom: "5555" ;tag=fb11549a\r\nTo: "5555" ;tag=z9hG4bK92b19bf363d84d2ea95d18cd3\r\nCSeq: 1 REGISTER\r\nWWW-Authenticate: Digest realm="asterisk",nonce="1664256201/30ff48bd45c78b935077262030d584bd",opaque="5f0937be1ccec4cf",algorithm=md5,qop="auth"\r\nServer: Asterisk PBX 18.2.0\r\nContent-Length: 0\r\n\r\n""", + { + "algorithm": "md5", + "realm": "asterisk", + "nonce": "1664256201/30ff48bd45c78b935077262030d584bd", + "opaque": "5f0937be1ccec4cf", + "qop": "auth", + }, + ), + ], +) +def test_sip_authentication(packet, expected): + message = SIPMessage(packet) + assert message.authentication == expected