Skip to content

Commit

Permalink
Replace nose (unmaintained) with nose2, remove Python 3.5 from CI (EO…
Browse files Browse the repository at this point in the history
…L), add warning to slow test, call it v0.14 for real this time

Potential FIXMEs for nose2?  It has some frustrating differences from nose
(https://docs.nose2.io/en/latest/differences.html), including:

- lack of 'assert_[a-z]' or 'assert[A-Z]*' functions, except as
  *methods* of unittest.TestCase subclasses
- inability to set '--verbose' when running as 'python setup.py test' (I
  tried adding '[unittest]\nverbosity = 2' to setup.cfg...  does nothing,
  unlike putting it in unittest.cfg, which works but only when running
  explicitly via 'nose2' CLI)
  • Loading branch information
dlenski committed Dec 17, 2021
1 parent 61cd221 commit 85f457c
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 28 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/test_and_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.5', '3.6', '3.7', '3.8', '3.x']
python-version: ['3.6', '3.7', '3.8', '3.x']

steps:
- uses: actions/checkout@v2
Expand All @@ -33,7 +33,7 @@ jobs:
- name: Tests and coverage
run: |
if [ -f requirements-test.txt ]; then pip install -r requirements-test.txt; fi
coverage run --source=vipaccess setup.py test && coverage report -m
coverage run --source=vipaccess -m nose2 --pretty-assert -v && coverage report -m
- name: Coveralls
uses: AndreMiras/coveralls-python-action@develop
with:
Expand Down
2 changes: 1 addition & 1 deletion requirements-test.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
nose>=1.0
nose2
coverage
4 changes: 4 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
[coverage:run]
relative_files = True

# Ensures that --pretty-assert is on even when run as 'python setup.py test'
[pretty-assert]
always-on = True
5 changes: 1 addition & 4 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,5 @@
'vipaccess=vipaccess.__main__:main',
],
},
test_requires=[
'nose>=1.0',
],
test_suite='nose.collector',
test_suite='nose2.collector.collector',
)
44 changes: 23 additions & 21 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@

from vipaccess.provision import *

from nose.tools import assert_equal, assert_true, assert_false, assert_is_none, assert_is_not_none
from time import sleep
from warnings import warn


def test_generate_request():
Expand All @@ -45,7 +45,7 @@ def test_generate_request():
'os': 'MacBookPro10,1',
}
request = generate_request(**params)
assert_equal(expected, request)
assert expected == request

def test_get_token_from_response():
test_response = b'<?xml version="1.0" encoding="UTF-8"?>\n<GetSharedSecretResponse RequestId="1412030064" Version="2.0" xmlns="http://www.verisign.com/2006/08/vipservice">\n <Status>\n <ReasonCode>0000</ReasonCode>\n <StatusMessage>Success</StatusMessage>\n </Status>\n <SharedSecretDeliveryMethod>HTTPS</SharedSecretDeliveryMethod>\n <SecretContainer Version="1.0">\n <EncryptionMethod>\n <PBESalt>u5lgf1Ek8WA0iiIwVkjy26j6pfk=</PBESalt>\n <PBEIterationCount>50</PBEIterationCount>\n <IV>Fsg1KafmAX80gUEDADijHw==</IV>\n </EncryptionMethod>\n <Device>\n <Secret type="HOTP" Id="SYMC26070843">\n <Issuer>OU = ID Protection Center, O = VeriSign, Inc.</Issuer>\n <Usage otp="true">\n <AI type="HMAC-SHA1-TRUNC-6DIGITS"/>\n <TimeStep>30</TimeStep>\n <Time>0</Time>\n <ClockDrift>4</ClockDrift>\n </Usage>\n <FriendlyName>OU = ID Protection Center, O = VeriSign, Inc.</FriendlyName>\n <Data>\n <Cipher>ILBweOCEOoMBLJARzoeUIlu0+5m6b3khZljd5dozARk=</Cipher>\n <Digest algorithm="HMAC-SHA1">MoaidW7XDzeTZJqhfRQCZEieARM=</Digest>\n </Data>\n <Expiry>2017-09-25T23:36:22.056Z</Expiry>\n </Secret>\n </Device>\n </SecretContainer>\n <UTCTimestamp>1412030065</UTCTimestamp>\n</GetSharedSecretResponse>'
Expand All @@ -63,15 +63,15 @@ def test_get_token_from_response():
'counter': None,
}
token = get_token_from_response(test_response)
assert_is_not_none(token.pop('timeskew', None))
assert_equal(expected_token, token)
assert token.pop('timeskew', None) is not None
assert expected_token == token

def test_decrypt_key():
test_iv = b'\x16\xc85)\xa7\xe6\x01\x7f4\x81A\x03\x008\xa3\x1f'
test_cipher = b' \xb0px\xe0\x84:\x83\x01,\x90\x11\xce\x87\x94"[\xb4\xfb\x99\xbaoy!fX\xdd\xe5\xda3\x01\x19'
expected_key = b'ZqeD\xd9wg]"\x12\x1f7\xc7v6"\xf0\x13\\i'
decrypted_key = decrypt_key(test_iv, test_cipher)
assert_equal(expected_key, decrypted_key)
assert expected_key == decrypted_key

def test_generate_totp_uri():
test_token = {
Expand All @@ -91,11 +91,11 @@ def test_generate_totp_uri():
test_secret = b'ZqeD\xd9wg]"\x12\x1f7\xc7v6"\xf0\x13\\i'
expected_uri = urlparse.urlparse('otpauth://totp/VIP%20Access:SYMC26070843?secret=LJYWKRGZO5TV2IQSD434O5RWELYBGXDJ&digits=6&algorithm=SHA1&period=30&image=https://raw.githubusercontent.com/dlenski/python-vipaccess/master/vipaccess.png')
generated_uri = urlparse.urlparse(generate_otp_uri(test_token, test_secret))
assert_equal(expected_uri.scheme, generated_uri.scheme)
assert_equal(expected_uri.netloc, generated_uri.netloc)
assert_equal(expected_uri.path, generated_uri.path)
assert_equal(urlparse.parse_qs(expected_uri.params), urlparse.parse_qs(generated_uri.params))
assert_equal(urlparse.parse_qs(expected_uri.query), urlparse.parse_qs(generated_uri.query))
assert expected_uri.scheme == generated_uri.scheme
assert expected_uri.netloc == generated_uri.netloc
assert expected_uri.path == generated_uri.path
assert urlparse.parse_qs(expected_uri.params) == urlparse.parse_qs(generated_uri.params)
assert urlparse.parse_qs(expected_uri.query) == urlparse.parse_qs(generated_uri.query)

def test_generate_hotp_uri():
test_token = {
Expand All @@ -115,25 +115,27 @@ def test_generate_hotp_uri():
test_secret = b'\x9a\x13\xcd2!\xad\xbd\x97R\xfcEE\xb6\x92e\xb4\x14\xb0\xfem'
expected_uri = urlparse.urlparse('otpauth://hotp/VIP%20Access:UBHE57586348?digits=6&algorithm=SHA1&counter=1&secret=TIJ42MRBVW6ZOUX4IVC3NETFWQKLB7TN&image=https://raw.githubusercontent.com/dlenski/python-vipaccess/master/vipaccess.png')
generated_uri = urlparse.urlparse(generate_otp_uri(test_token, test_secret))
assert_equal(expected_uri.scheme, generated_uri.scheme)
assert_equal(expected_uri.netloc, generated_uri.netloc)
assert_equal(expected_uri.path, generated_uri.path)
assert_equal(urlparse.parse_qs(expected_uri.params), urlparse.parse_qs(generated_uri.params))
assert_equal(urlparse.parse_qs(expected_uri.query), urlparse.parse_qs(generated_uri.query))
assert expected_uri.scheme == generated_uri.scheme
assert expected_uri.netloc == generated_uri.netloc
assert expected_uri.path == generated_uri.path
assert urlparse.parse_qs(expected_uri.params) == urlparse.parse_qs(generated_uri.params)
assert urlparse.parse_qs(expected_uri.query) == urlparse.parse_qs(generated_uri.query)

def provision_valid_token(token_model, attr, not_attr, check_sync=False):
test_request = generate_request(token_model=token_model)
test_response = requests.post(PROVISIONING_URL, data=test_request)
test_otp_token = get_token_from_response(test_response.content)
assert_is_not_none(test_otp_token[attr])
assert_is_none(test_otp_token[not_attr])
assert test_otp_token[attr] is not None
assert test_otp_token[not_attr] is None
assert test_otp_token['id'].startswith(token_model)
test_token_secret = decrypt_key(test_otp_token['iv'], test_otp_token['cipher'])
assert_true(check_token(test_otp_token, test_token_secret))
assert check_token(test_otp_token, test_token_secret)
if check_sync:
if test_otp_token['period'] is not None:
time.sleep(2 * test_otp_token['period'])
assert_true(sync_token(test_otp_token, test_token_secret))
warn('Test is still running. Need to sleep for {}s to check token sync...'.format(
2 * test_otp_token['period']))
sleep(2 * test_otp_token['period'])
assert sync_token(test_otp_token, test_token_secret)

def test_check_token_models():
# Only try syncing one TOTP token, because it requires a delay.
Expand All @@ -149,4 +151,4 @@ def test_check_token_models():
def test_check_token_detects_invalid_token():
test_token = {'id': 'SYMC26070843', 'period': 30}
test_token_secret = b'ZqeD\xd9wg]"\x12\x1f7\xc7v6"\xf0\x13\\i'
assert_false(check_token(test_token, test_token_secret))
assert not check_token(test_token, test_token_secret)

0 comments on commit 85f457c

Please sign in to comment.