diff --git a/.github/workflows/flask.yml b/.github/workflows/flask.yml index 16086b5b..91fd2b77 100644 --- a/.github/workflows/flask.yml +++ b/.github/workflows/flask.yml @@ -47,7 +47,7 @@ jobs: sudo apt-get update -qy sudo apt-get -y install postgresql-client --no-install-recommends python -m pip install --upgrade pip - pip install flake8 pytest coverage + pip install -r requirements-testing.txt pip install -r requirements.txt - name: Prepare database diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 00000000..3be22c69 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,3 @@ +[pytest] +markers = + mvp: mark tests as required by MVP diff --git a/requirements-testing.txt b/requirements-testing.txt new file mode 100644 index 00000000..a802865d --- /dev/null +++ b/requirements-testing.txt @@ -0,0 +1,4 @@ +coverage +flake8 +pytest==7.0.0 +requests-mock==1.5.2 diff --git a/requirements.txt b/requirements.txt index b91a1673..0ddebbc1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,35 +12,32 @@ Flask-Cors==3.0.10 Flask-Login==0.5.0 Flask-SQLAlchemy==2.3.2 Flask-WTF==1.0.0 +flask-WeasyPrint==0.5 hashids==1.2.0 inflection==0.3.1 +# lock itsdangerous version until upgrade to Flask 2.x itsdangerous==2.0.1 # lock Jinja2 version because it's the latest compatible with Flask 1.0.X # see related info on https://github.com/pallets/jinja/issues/1628 Jinja2==3.0.3 marshmallow==3.0.0b11 marshmallow-enum==1.4.1 +more-itertools==8.12.0 passlib==1.7.1 phonenumbers==8.9.11 -pytest==3.7.2 -pytest-runner==4.2 +psycopg2-binary==2.8.3 +PyJWT==2.0.0a1 python-dateutil==2.7.3 +python-decouple==3.3 python-stdnum==1.9 PyYAML==5.4 requests[security]==2.27.1 -requests-mock==1.5.2 +sortedcontainers==2.1.0 SQLAlchemy==1.3.24 +sqlalchemy-citext==1.3.post0 SQLAlchemy-Utils==0.33.11 # teal under development version -e git+https://github.com/eReuse/teal/@upgrade-dependencies#egg=teal +WeasyPrint==44 webargs==5.5.3 Werkzeug>=2.0 -sqlalchemy-citext==1.3.post0 -flask-weasyprint==0.5 -weasyprint==44 -psycopg2-binary==2.8.3 -sortedcontainers==2.1.0 -tqdm==4.32.2 -python-decouple==3.3 -python-dotenv==0.14.0 -pyjwt==2.0.0a1 diff --git a/setup.py b/setup.py index 6a0db9b9..287cf651 100644 --- a/setup.py +++ b/setup.py @@ -3,11 +3,6 @@ from setuptools import find_packages, setup from ereuse_devicehub import __version__ -test_requires = [ - 'pytest', - 'requests_mock' -] - setup( name='ereuse-devicehub', version=__version__, @@ -52,17 +47,12 @@ setup( 'docs-auto': [ 'sphinx-autobuild' ], - 'test': test_requires }, - tests_require=test_requires, entry_points={ 'console_scripts': [ 'dh = ereuse_devicehub.cli:cli' ] }, - setup_requires=[ - 'pytest-runner' - ], classifiers=[ 'Development Status :: 2 - Pre-Alpha', 'Environment :: Web Environment', @@ -71,8 +61,7 @@ setup( 'License :: OSI Approved :: GNU Affero General Public License v3', 'Operating System :: OS Independent', 'Programming Language :: Python :: 3 :: Only', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', 'Topic :: Internet :: WWW/HTTP :: WSGI :: Application', 'Topic :: Software Development :: Libraries :: Python Modules', diff --git a/tests/test_action.py b/tests/test_action.py index 8de74e81..8ca9c44b 100644 --- a/tests/test_action.py +++ b/tests/test_action.py @@ -75,14 +75,14 @@ def test_erase_basic(): def test_validate_device_data_storage(): """Checks the validation for data-storage-only actions works.""" # We can't set a GraphicCard - with pytest.raises(TypeError, - message='EraseBasic.device must be a DataStorage ' - 'but you passed '): + with pytest.raises(TypeError): models.EraseBasic( device=GraphicCard(serial_number='foo', manufacturer='bar', model='foo-bar'), clean_with_zeros=True, **conftest.T ) + pytest.fail('EraseBasic.device must be a DataStorage ' + 'but you passed ') @pytest.mark.mvp @@ -335,10 +335,10 @@ def test_outgoinlot_status_actions(action_model: models.Action, user: UserClient @pytest.mark.parametrize('action_model', (pytest.param(ams, id=ams.__class__.__name__) for ams in [ - models.Recycling, - models.Use, - models.Refurbish, - models.Management + models.Recycling, + models.Use, + models.Refurbish, + models.Management ])) def test_incominglot_status_actions(action_model: models.Action, user: UserClient, user2: UserClient): """Test of status actions in outgoinlot.""" @@ -494,10 +494,10 @@ def test_recycling_container(user: UserClient): @pytest.mark.parametrize('action_model', (pytest.param(ams, id=ams.__class__.__name__) for ams in [ - models.Recycling, - models.Use, - models.Refurbish, - models.Management + models.Recycling, + models.Use, + models.Refurbish, + models.Management ])) def test_status_without_lot(action_model: models.Action, user: UserClient): """Test of status actions for devices without lot.""" @@ -512,10 +512,10 @@ def test_status_without_lot(action_model: models.Action, user: UserClient): @pytest.mark.parametrize('action_model', (pytest.param(ams, id=ams.__class__.__name__) for ams in [ - models.Recycling, - models.Use, - models.Refurbish, - models.Management + models.Recycling, + models.Use, + models.Refurbish, + models.Management ])) def test_status_in_temporary_lot(action_model: models.Action, user: UserClient): """Test of status actions for devices in a temporary lot.""" @@ -913,7 +913,7 @@ def test_allocate(user: UserClient): snapshot, _ = user.post(file('basic.snapshot'), res=models.Snapshot) device_id = snapshot['device']['id'] devicehub_id = snapshot['device']['devicehubID'] - post_request = {"transaction": "ccc", + post_request = {"transaction": "ccc", "finalUserCode": "aabbcc", "name": "John", "severity": "Info", @@ -1638,7 +1638,7 @@ def test_confirmRevoke(user: UserClient, user2: UserClient): item='{}/devices'.format(lot['id']), query=devices) - # the manager shares the temporary lot with the SCRAP as an incoming lot + # the manager shares the temporary lot with the SCRAP as an incoming lot # for the CRAP to confirm it request_post = { 'type': 'Trade', @@ -1659,8 +1659,8 @@ def test_confirmRevoke(user: UserClient, user2: UserClient): 'type': 'Confirm', 'action': trade.id, 'devices': [ - snap1['device']['id'], - snap2['device']['id'], + snap1['device']['id'], + snap2['device']['id'], snap3['device']['id'], snap4['device']['id'], snap5['device']['id'], @@ -1677,7 +1677,7 @@ def test_confirmRevoke(user: UserClient, user2: UserClient): assert trade.devices[-1].actions[-1].t == 'Confirm' assert trade.devices[-1].actions[-1].user == trade.user_from - # The manager remove one device of the lot and automaticaly + # The manager remove one device of the lot and automaticaly # is create one revoke action device_10 = trade.devices[-1] lot, _ = user.delete({}, @@ -1804,7 +1804,7 @@ def test_trade_case2(user: UserClient, user2: UserClient): item='{}/devices'.format(lot['id']), query=devices[:-1]) - # the manager shares the temporary lot with the SCRAP as an incoming lot + # the manager shares the temporary lot with the SCRAP as an incoming lot # for the CRAP to confirm it request_post = { 'type': 'Trade', @@ -1926,7 +1926,7 @@ def test_trade_case4(user: UserClient, user2: UserClient): item='{}/devices'.format(lot['id']), query=devices[:-1]) - # the manager shares the temporary lot with the SCRAP as an incoming lot + # the manager shares the temporary lot with the SCRAP as an incoming lot # for the CRAP to confirm it request_post = { 'type': 'Trade', @@ -1991,7 +1991,7 @@ def test_trade_case5(user: UserClient, user2: UserClient): item='{}/devices'.format(lot['id']), query=devices) - # the manager shares the temporary lot with the SCRAP as an incoming lot + # the manager shares the temporary lot with the SCRAP as an incoming lot # for the CRAP to confirm it request_post = { 'type': 'Trade', @@ -2057,7 +2057,7 @@ def test_trade_case6(user: UserClient, user2: UserClient): item='{}/devices'.format(lot['id']), query=devices[:-1]) - # the manager shares the temporary lot with the SCRAP as an incoming lot + # the manager shares the temporary lot with the SCRAP as an incoming lot # for the CRAP to confirm it request_post = { 'type': 'Trade', @@ -2125,7 +2125,7 @@ def test_trade_case7(user: UserClient, user2: UserClient): item='{}/devices'.format(lot['id']), query=devices) - # the manager shares the temporary lot with the SCRAP as an incoming lot + # the manager shares the temporary lot with the SCRAP as an incoming lot # for the CRAP to confirm it request_post = { 'type': 'Trade', @@ -2192,7 +2192,7 @@ def test_trade_case8(user: UserClient, user2: UserClient): item='{}/devices'.format(lot['id']), query=devices) - # the manager shares the temporary lot with the SCRAP as an incoming lot + # the manager shares the temporary lot with the SCRAP as an incoming lot # for the CRAP to confirm it request_post = { 'type': 'Trade', @@ -2266,7 +2266,7 @@ def test_trade_case9(user: UserClient, user2: UserClient): item='{}/devices'.format(lot['id']), query=devices[:-1]) - # the manager shares the temporary lot with the SCRAP as an incoming lot + # the manager shares the temporary lot with the SCRAP as an incoming lot # for the CRAP to confirm it request_post = { 'type': 'Trade', @@ -2348,7 +2348,7 @@ def test_trade_case10(user: UserClient, user2: UserClient): item='{}/devices'.format(lot['id']), query=devices[:-1]) - # the manager shares the temporary lot with the SCRAP as an incoming lot + # the manager shares the temporary lot with the SCRAP as an incoming lot # for the CRAP to confirm it request_post = { 'type': 'Trade', @@ -2435,7 +2435,7 @@ def test_trade_case11(user: UserClient, user2: UserClient): item='{}/devices'.format(lot['id']), query=devices) - # the manager shares the temporary lot with the SCRAP as an incoming lot + # the manager shares the temporary lot with the SCRAP as an incoming lot # for the CRAP to confirm it request_post = { 'type': 'Trade', @@ -2507,7 +2507,7 @@ def test_trade_case12(user: UserClient, user2: UserClient): item='{}/devices'.format(lot['id']), query=devices) - # the manager shares the temporary lot with the SCRAP as an incoming lot + # the manager shares the temporary lot with the SCRAP as an incoming lot # for the CRAP to confirm it request_post = { 'type': 'Trade', @@ -2584,7 +2584,7 @@ def test_trade_case13(user: UserClient, user2: UserClient): item='{}/devices'.format(lot['id']), query=devices[:-1]) - # the manager shares the temporary lot with the SCRAP as an incoming lot + # the manager shares the temporary lot with the SCRAP as an incoming lot # for the CRAP to confirm it request_post = { 'type': 'Trade', @@ -2664,7 +2664,7 @@ def test_trade_case14(user: UserClient, user2: UserClient): item='{}/devices'.format(lot['id']), query=devices[:-1]) - # the manager shares the temporary lot with the SCRAP as an incoming lot + # the manager shares the temporary lot with the SCRAP as an incoming lot # for the CRAP to confirm it request_post = { 'type': 'Trade', diff --git a/tests/test_auth.py b/tests/test_auth.py index 81cefb0e..f59964fc 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -24,11 +24,14 @@ def test_authenticate_error(app: Devicehub): MESSAGE = 'Provide a suitable token.' create_user() # Token doesn't exist - with pytest.raises(Unauthorized, message=MESSAGE): + with pytest.raises(Unauthorized): app.auth.authenticate(token=str(uuid4())) + pytest.fail(MESSAGE) + # Wrong token format - with pytest.raises(Unauthorized, message=MESSAGE): + with pytest.raises(Unauthorized): app.auth.authenticate(token='this is a wrong uuid') + pytest.fail(MESSAGE) @pytest.mark.mvp diff --git a/tests/test_inventory.py b/tests/test_inventory.py index 70e4dfb7..056253dc 100644 --- a/tests/test_inventory.py +++ b/tests/test_inventory.py @@ -144,5 +144,7 @@ def test_create_existing_inventory(cli, tdb1): cli.invoke('inv', 'add', '--common') with tdb1.app_context(): assert db.has_schema('tdb1') - with pytest.raises(AssertionError, message='Schema tdb1 already exists.'): + + with pytest.raises(AssertionError): cli.invoke('inv', 'add', '--common') + pytest.fail('Schema tdb1 already exists.')