From a85e7c90e115f9619d9db7499c4b07be1049aeec Mon Sep 17 00:00:00 2001 From: Santiago Lamora Date: Mon, 26 Sep 2022 12:24:14 +0200 Subject: [PATCH 01/18] Manage dependencies using pip-tools Add instructions to CONTRIBUTING.md & create requirements.in --- CONTRIBUTING.md | 26 +++++ requirements.in | 37 +++++++ requirements.txt | 265 +++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 287 insertions(+), 41 deletions(-) create mode 100644 requirements.in diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 142fd954..90d9b598 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -30,3 +30,29 @@ pre-commit install Do this: `device_detail.html` Don't do this: `DeviceDetail.html`, `Device-detail.html` + + +## Adding a new dependency to the project +This project tracks its packages using pip-tools, it could be installed by running: +``` +pip install pip-tools +``` + +Whenever you need to install a new package using pip install : +1. Put the package name into `requirements.in` instead. +``` +# requirements.in +... +new_package +``` + +2. Compile the requirements +``` +pip-compile requirements.in --output-file=requirements.txt + +``` + +3. Then install upgraded dependencies: +``` +pip install -U -r requirements.txt +``` diff --git a/requirements.in b/requirements.in new file mode 100644 index 00000000..8a9569ca --- /dev/null +++ b/requirements.in @@ -0,0 +1,37 @@ +alembic==1.4.2 +atomicwrites==1.4.0 +click-spinner==0.1.8 +colorama==0.3.9 +colour==0.1.5 +ereuse-utils[naming,test,session,cli]==0.4.0b50 +Flask-Cors==3.0.10 +Flask-Login==0.5.0 +Flask-WTF==1.0.0 +flask-weasyprint==0.4 +hashids==1.2.0 +more-itertools==8.12.0 +passlib==1.7.1 +phonenumbers==8.9.11 +psycopg2-binary==2.8.3 +pyjwt==2.4.0 +python-decouple==3.3 +python-dotenv==0.14.0 +python-stdnum==1.9 +pyyaml==5.4 +requests==2.27.1 +requests-mock==1.5.2 +requests-toolbelt==0.9.1 +sortedcontainers==2.1.0 +sqlalchemy-citext==1.3.post0 +sqlalchemy-utils==0.33.11 +teal==0.2.0a40 +tqdm==4.32.2 + +pint==0.9 +py-dmidecode==0.1.0 +pandas==1.3.5 +numpy==1.22.0 # pandas dependency +odfpy==1.4.1 # pandas dependency +xlrd==2.0.1 # pandas dependency +openpyxl==3.0.10 # pandas dependency +et_xmlfile==1.1.0 # pandas dependency diff --git a/requirements.txt b/requirements.txt index 8ec1e0a4..d482f549 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,53 +1,236 @@ +# +# This file is autogenerated by pip-compile with python 3.8 +# To update, run: +# +# pip-compile --output-file=requirements.txt requirements.in +# alembic==1.4.2 + # via -r requirements.in anytree==2.4.3 -apispec==0.39.0 + # via teal +apispec[yaml]==5.2.2 + # via + # apispec-webframeworks + # teal +apispec-webframeworks==0.5.2 + # via teal +atomicwrites==1.4.0 + # via -r requirements.in boltons==18.0.1 + # via + # ereuse-utils + # teal +cairocffi==1.4.0 + # via + # cairosvg + # weasyprint +cairosvg==2.5.2 + # via weasyprint +certifi==2022.9.24 + # via requests +cffi==1.15.1 + # via + # cairocffi + # weasyprint +charset-normalizer==2.0.12 + # via requests click==6.7 + # via + # ereuse-utils + # flask click-spinner==0.1.8 + # via + # -r requirements.in + # teal colorama==0.3.9 + # via + # -r requirements.in + # ereuse-utils colour==0.1.5 -ereuse-utils[naming,test,session,cli]==0.4.0b50 -Flask==1.0.2 -Flask-Cors==3.0.10 -Flask-Login==0.5.0 -Flask-SQLAlchemy==2.3.2 -Flask-WTF==1.0.0 + # via + # -r requirements.in + # sqlalchemy-utils +cssselect2==0.7.0 + # via + # cairosvg + # weasyprint +defusedxml==0.7.1 + # via + # cairosvg + # odfpy +ereuse-utils[cli,naming,session,test]==0.4.0b50 + # via + # -r requirements.in + # teal +et-xmlfile==1.1.0 + # via + # -r requirements.in + # openpyxl +flask==1.0.2 + # via + # ereuse-utils + # flask-cors + # flask-login + # flask-sqlalchemy + # flask-weasyprint + # flask-wtf + # teal +flask-cors==3.0.10 + # via + # -r requirements.in + # teal +flask-login==0.5.0 + # via -r requirements.in +flask-sqlalchemy==2.5.1 + # via teal +flask-weasyprint==0.4 + # via -r requirements.in +flask-wtf==1.0.0 + # via -r requirements.in hashids==1.2.0 + # via -r requirements.in +html5lib==1.1 + # via weasyprint +idna==3.4 + # via requests inflection==0.3.1 + # via ereuse-utils 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 + # via + # flask + # flask-wtf +jinja2==3.0.3 + # via flask +mako==1.2.3 + # via alembic +markupsafe==2.1.1 + # via + # jinja2 + # mako + # wtforms +marshmallow==3.18.0 + # via + # marshmallow-enum + # teal + # webargs marshmallow-enum==1.4.1 -passlib==1.7.1 -phonenumbers==8.9.11 -pytest==3.7.2 -pytest-runner==4.2 -python-dateutil==2.7.3 -python-stdnum==1.9 -PyYAML==5.4 -requests[security]==2.27.1 -requests-mock==1.5.2 -SQLAlchemy==1.3.24 -SQLAlchemy-Utils==0.33.11 -teal==0.2.0a38 -webargs==5.5.3 -Werkzeug==0.15.5 -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.4.0 -pint==0.9 -py-dmidecode==0.1.0 + # via teal +more-itertools==8.12.0 + # via -r requirements.in +numpy==1.22.0 + # via + # -r requirements.in + # pandas +odfpy==1.4.1 + # via -r requirements.in +openpyxl==3.0.10 + # via -r requirements.in +packaging==21.3 + # via marshmallow pandas==1.3.5 -numpy==1.22.0 # pandas dependency -odfpy==1.4.1 # pandas dependency -xlrd==2.0.1 # pandas dependency -openpyxl==3.0.10 # pandas dependency -et_xmlfile==1.1.0 # pandas dependency + # via -r requirements.in +passlib==1.7.1 + # via + # -r requirements.in + # sqlalchemy-utils +phonenumbers==8.9.11 + # via + # -r requirements.in + # sqlalchemy-utils +pillow==9.2.0 + # via cairosvg +pint==0.9 + # via -r requirements.in +psycopg2-binary==2.8.3 + # via -r requirements.in +py-dmidecode==0.1.0 + # via -r requirements.in +pycparser==2.21 + # via cffi +pyjwt==2.4.0 + # via -r requirements.in +pyparsing==3.0.9 + # via packaging +pyphen==0.13.0 + # via weasyprint +python-dateutil==2.7.3 + # via + # alembic + # pandas +python-decouple==3.3 + # via -r requirements.in +python-dotenv==0.14.0 + # via -r requirements.in +python-editor==1.0.4 + # via alembic +python-stdnum==1.9 + # via -r requirements.in +pytz==2022.2.1 + # via pandas +pyyaml==5.4 + # via + # -r requirements.in + # apispec +requests==2.27.1 + # via + # -r requirements.in + # requests-mock + # requests-toolbelt +requests-mock==1.5.2 + # via -r requirements.in +requests-toolbelt==0.9.1 + # via + # -r requirements.in + # ereuse-utils +six==1.16.0 + # via + # anytree + # flask-cors + # html5lib + # python-dateutil + # requests-mock + # sqlalchemy-utils +sortedcontainers==2.1.0 + # via -r requirements.in +sqlalchemy==1.3.24 + # via + # alembic + # flask-sqlalchemy + # sqlalchemy-citext + # sqlalchemy-utils +sqlalchemy-citext==1.3.post0 + # via -r requirements.in +sqlalchemy-utils[color,password,phone]==0.33.11 + # via + # -r requirements.in + # teal +teal==0.2.0a40 + # via -r requirements.in +tinycss2==1.1.1 + # via + # cairosvg + # cssselect2 + # weasyprint +tqdm==4.32.2 + # via + # -r requirements.in + # ereuse-utils +urllib3==1.26.12 + # via requests +weasyprint==44 + # via flask-weasyprint +webargs==5.5.3 + # via teal +webencodings==0.5.1 + # via + # cssselect2 + # html5lib + # tinycss2 +werkzeug==2.0.3 + # via + # flask + # teal +wtforms==3.0.1 + # via flask-wtf +xlrd==2.0.1 + # via -r requirements.in From 51c42ad94f7b0cb5fc42fc99b987474136e698e8 Mon Sep 17 00:00:00 2001 From: Santiago Lamora Date: Mon, 26 Sep 2022 12:44:40 +0200 Subject: [PATCH 02/18] Lock marshmallow version --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index d482f549..3fe7963d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -108,7 +108,7 @@ markupsafe==2.1.1 # jinja2 # mako # wtforms -marshmallow==3.18.0 +marshmallow==3.0.0 # via # marshmallow-enum # teal From abb675d9d32fd9cf21537ea886c3aedda90e0628 Mon Sep 17 00:00:00 2001 From: Santiago Lamora Date: Mon, 26 Sep 2022 12:55:11 +0200 Subject: [PATCH 03/18] Lock --- requirements.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 3fe7963d..e4ea1e1e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -108,7 +108,9 @@ markupsafe==2.1.1 # jinja2 # mako # wtforms -marshmallow==3.0.0 +# TODO fix https://github.com/marshmallow-code/marshmallow/issues/1040 +# A ValueError is raised when the missing parameter is passed for required fields (#1040). +marshmallow==3.0.0rc1 # via # marshmallow-enum # teal From cffa950fec154d0d35c629a35947c125fe8146d3 Mon Sep 17 00:00:00 2001 From: Santiago Lamora Date: Mon, 26 Sep 2022 13:24:40 +0200 Subject: [PATCH 04/18] Bump to teal 0.2.0a41 which fixes marshmallow version --- requirements.in | 2 +- requirements.txt | 10 ++-------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/requirements.in b/requirements.in index 8a9569ca..b76366ef 100644 --- a/requirements.in +++ b/requirements.in @@ -24,7 +24,7 @@ requests-toolbelt==0.9.1 sortedcontainers==2.1.0 sqlalchemy-citext==1.3.post0 sqlalchemy-utils==0.33.11 -teal==0.2.0a40 +teal==0.2.0a41 tqdm==4.32.2 pint==0.9 diff --git a/requirements.txt b/requirements.txt index e4ea1e1e..d0c85640 100644 --- a/requirements.txt +++ b/requirements.txt @@ -108,9 +108,7 @@ markupsafe==2.1.1 # jinja2 # mako # wtforms -# TODO fix https://github.com/marshmallow-code/marshmallow/issues/1040 -# A ValueError is raised when the missing parameter is passed for required fields (#1040). -marshmallow==3.0.0rc1 +marshmallow==3.0.0b11 # via # marshmallow-enum # teal @@ -127,8 +125,6 @@ odfpy==1.4.1 # via -r requirements.in openpyxl==3.0.10 # via -r requirements.in -packaging==21.3 - # via marshmallow pandas==1.3.5 # via -r requirements.in passlib==1.7.1 @@ -151,8 +147,6 @@ pycparser==2.21 # via cffi pyjwt==2.4.0 # via -r requirements.in -pyparsing==3.0.9 - # via packaging pyphen==0.13.0 # via weasyprint python-dateutil==2.7.3 @@ -206,7 +200,7 @@ sqlalchemy-utils[color,password,phone]==0.33.11 # via # -r requirements.in # teal -teal==0.2.0a40 +teal==0.2.0a41 # via -r requirements.in tinycss2==1.1.1 # via From d0c91d5d24864970cad04e5169c321ef7c1a8861 Mon Sep 17 00:00:00 2001 From: Santiago Lamora Date: Mon, 26 Sep 2022 13:45:27 +0200 Subject: [PATCH 05/18] Drop apispec-webframeworks requirement --- requirements.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/requirements.txt b/requirements.txt index d0c85640..407b789a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,12 +8,10 @@ alembic==1.4.2 # via -r requirements.in anytree==2.4.3 # via teal -apispec[yaml]==5.2.2 +apispec[yaml]==0.39.0 # via # apispec-webframeworks # teal -apispec-webframeworks==0.5.2 - # via teal atomicwrites==1.4.0 # via -r requirements.in boltons==18.0.1 From fe5d5408fe6709ce44f6b09ee4533b4fc5849eb5 Mon Sep 17 00:00:00 2001 From: Santiago Lamora Date: Mon, 26 Sep 2022 13:49:50 +0200 Subject: [PATCH 06/18] . --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 407b789a..61dc98fa 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,7 +8,7 @@ alembic==1.4.2 # via -r requirements.in anytree==2.4.3 # via teal -apispec[yaml]==0.39.0 +apispec==0.39.0 # via # apispec-webframeworks # teal From 8a49e63592a1349ccfdb4a7068ffdc32dc75e2c6 Mon Sep 17 00:00:00 2001 From: Santiago Lamora Date: Mon, 26 Sep 2022 14:00:11 +0200 Subject: [PATCH 07/18] Run selenium only on reviews --- .github/workflows/selenium.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/selenium.yml b/.github/workflows/selenium.yml index fab0faab..1408a3d3 100644 --- a/.github/workflows/selenium.yml +++ b/.github/workflows/selenium.yml @@ -1,10 +1,8 @@ name: Selenium on: - push: - branches: [master, testing] pull_request: - branches: [master, testing] + types: [ready_for_review, review_requested] jobs: build: From bcec57e752c3ba3973b9e81e61af9549b14d352d Mon Sep 17 00:00:00 2001 From: Santiago Lamora Date: Mon, 26 Sep 2022 14:00:48 +0200 Subject: [PATCH 08/18] Fix apispec dependencies --- requirements.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 61dc98fa..bba8c5a8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,10 +8,12 @@ alembic==1.4.2 # via -r requirements.in anytree==2.4.3 # via teal -apispec==0.39.0 +apispec==4.5.0 # via # apispec-webframeworks # teal +apispec-webframeworks==0.5.2 + # via teal atomicwrites==1.4.0 # via -r requirements.in boltons==18.0.1 From d9ba3889c006a1ed95b4c3f9ff4b30fb994c95cd Mon Sep 17 00:00:00 2001 From: Santiago Lamora Date: Mon, 26 Sep 2022 16:47:27 +0200 Subject: [PATCH 09/18] Revert teal version to 0.2.0a38 There are code not compatible with newer libraries --- requirements.in | 5 ++++- requirements.txt | 14 ++++---------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/requirements.in b/requirements.in index b76366ef..11ce696b 100644 --- a/requirements.in +++ b/requirements.in @@ -24,7 +24,7 @@ requests-toolbelt==0.9.1 sortedcontainers==2.1.0 sqlalchemy-citext==1.3.post0 sqlalchemy-utils==0.33.11 -teal==0.2.0a41 +teal==0.2.0a38 tqdm==4.32.2 pint==0.9 @@ -35,3 +35,6 @@ odfpy==1.4.1 # pandas dependency xlrd==2.0.1 # pandas dependency openpyxl==3.0.10 # pandas dependency et_xmlfile==1.1.0 # pandas dependency + +# manual dependency +marshmallow-enum==1.4.1 diff --git a/requirements.txt b/requirements.txt index bba8c5a8..d698c4c8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,11 +8,7 @@ alembic==1.4.2 # via -r requirements.in anytree==2.4.3 # via teal -apispec==4.5.0 - # via - # apispec-webframeworks - # teal -apispec-webframeworks==0.5.2 +apispec==0.39.0 # via teal atomicwrites==1.4.0 # via -r requirements.in @@ -114,7 +110,7 @@ marshmallow==3.0.0b11 # teal # webargs marshmallow-enum==1.4.1 - # via teal + # via -r requirements.in more-itertools==8.12.0 # via -r requirements.in numpy==1.22.0 @@ -200,7 +196,7 @@ sqlalchemy-utils[color,password,phone]==0.33.11 # via # -r requirements.in # teal -teal==0.2.0a41 +teal==0.2.0a38 # via -r requirements.in tinycss2==1.1.1 # via @@ -223,9 +219,7 @@ webencodings==0.5.1 # html5lib # tinycss2 werkzeug==2.0.3 - # via - # flask - # teal + # via flask wtforms==3.0.1 # via flask-wtf xlrd==2.0.1 From 814f36d4eeafdbcec325d1a68582b361c3c377ea Mon Sep 17 00:00:00 2001 From: Santiago Lamora Date: Mon, 26 Sep 2022 17:08:40 +0200 Subject: [PATCH 10/18] Drop "message" parameter of pytest.raises Deprecated since version 4.1 https://docs.pytest.org/en/4.6.x/deprecations.html#raises-message-deprecated --- tests/test_action.py | 23 ++++++++-------- tests/test_auth.py | 18 ++++++++++--- tests/test_inventory.py | 59 ++++++++++++++++++++++++++++------------- 3 files changed, 65 insertions(+), 35 deletions(-) diff --git a/tests/test_action.py b/tests/test_action.py index 14b9d697..bc27065b 100644 --- a/tests/test_action.py +++ b/tests/test_action.py @@ -1,5 +1,4 @@ import copy -import ipaddress import json import os import shutil @@ -7,7 +6,7 @@ from datetime import datetime, timedelta from decimal import Decimal from io import BytesIO from json.decoder import JSONDecodeError -from typing import Tuple, Type +from typing import Tuple import pytest from dateutil.tz import tzutc @@ -15,7 +14,7 @@ from flask import current_app as app from flask import g from pytest import raises from sqlalchemy.util import OrderedSet -from teal.enums import Currency, Subdivision +from teal.enums import Currency from ereuse_devicehub.client import Client, UserClient from ereuse_devicehub.db import db @@ -82,11 +81,7 @@ 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' @@ -94,6 +89,10 @@ def test_validate_device_data_storage(): clean_with_zeros=True, **conftest.T, ) + pytest.fail( + 'EraseBasic.device must be a DataStorage ' + 'but you passed ' + ) @pytest.mark.mvp @@ -292,9 +291,7 @@ def test_generic_action( for ams in [models.Recycling, models.Use, models.Refurbish, models.Management] ), ) -def test_simple_status_actions( - action_model: models.Action, user2: UserClient -): +def test_simple_status_actions(action_model: models.Action, user2: UserClient): """Simple test of status action.""" user = user2 snap, _ = user.post(file('basic.snapshot'), res=models.Snapshot) @@ -554,7 +551,9 @@ def test_status_without_lot(action_model: models.Action, user: UserClient): for ams in [models.Recycling, models.Use, models.Refurbish, models.Management] ), ) -def test_status_in_temporary_lot(action_model: models.Action, user: UserClient, app: Devicehub): +def test_status_in_temporary_lot( + action_model: models.Action, user: UserClient, app: Devicehub +): """Test of status actions for devices in a temporary lot.""" snap, _ = user.post(file('basic.snapshot'), res=models.Snapshot) abstract = Device.query.filter_by(id=snap['device']['id']).first() diff --git a/tests/test_auth.py b/tests/test_auth.py index 81cefb0e..54c70a3e 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -21,14 +21,22 @@ def test_authenticate_success(app: Devicehub): def test_authenticate_error(app: Devicehub): """Tests the authenticate method with wrong token values.""" with app.app_context(): - 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('Provide a suitable token.') + + +@pytest.mark.mvp +def test_authenticate_error_malformed_token(app: Devicehub): + """Tests the authenticate method with malformed token.""" + with app.app_context(): + create_user() # Wrong token format - with pytest.raises(Unauthorized, message=MESSAGE): + with pytest.raises(Unauthorized): app.auth.authenticate(token='this is a wrong uuid') + pytest.fail('Provide a suitable token.') @pytest.mark.mvp @@ -36,4 +44,6 @@ def test_auth_view(user: UserClient, client: Client): """Tests authentication at endpoint / view.""" user.get(res='User', item=user.user['id'], status=200) client.get(res='User', item=user.user['id'], status=Unauthorized) - client.get(res='User', item=user.user['id'], token='wrong token', status=Unauthorized) + client.get( + res='User', item=user.user['id'], token='wrong token', status=Unauthorized + ) diff --git a/tests/test_inventory.py b/tests/test_inventory.py index 70e4dfb7..8d939733 100644 --- a/tests/test_inventory.py +++ b/tests/test_inventory.py @@ -21,10 +21,12 @@ from tests.conftest import TestConfig class NoExcCliRunner(click.testing.CliRunner): """Runner that interfaces with the Devicehub CLI.""" - def invoke(self, *args, input=None, env=None, catch_exceptions=False, color=False, - **extra): - r = super().invoke(ereuse_devicehub.cli.cli, - args, input, env, catch_exceptions, color, **extra) + def invoke( + self, *args, input=None, env=None, catch_exceptions=False, color=False, **extra + ): + r = super().invoke( + ereuse_devicehub.cli.cli, args, input, env, catch_exceptions, color, **extra + ) assert r.exit_code == 0, 'CLI code {}: {}'.format(r.exit_code, r.output) return r @@ -69,16 +71,26 @@ def test_inventory_create_delete_user(cli, tdb1, tdb2): """ # Create first DB cli.inv('tdb1') - cli.invoke('inv', 'add', - '-n', 'Test DB1', - '-on', 'ACME DB1', - '-oi', 'acme-id', - '-tu', 'https://example.com', - '-tt', '3c66a6ad-22de-4db6-ac46-d8982522ec40', - '--common') + cli.invoke( + 'inv', + 'add', + '-n', + 'Test DB1', + '-on', + 'ACME DB1', + '-oi', + 'acme-id', + '-tu', + 'https://example.com', + '-tt', + '3c66a6ad-22de-4db6-ac46-d8982522ec40', + '--common', + ) # Create an user for first DB - cli.invoke('user', 'add', 'foo@foo.com', '-a', 'Foo', '-c', 'ES', '-p', 'Such password') + cli.invoke( + 'user', 'add', 'foo@foo.com', '-a', 'Foo', '-c', 'ES', '-p', 'Such password' + ) with tdb1.app_context(): # There is a row for the inventory @@ -98,12 +110,20 @@ def test_inventory_create_delete_user(cli, tdb1, tdb2): cli.inv('tdb2') # Create a second DB # Note how we don't create common anymore - cli.invoke('inv', 'add', - '-n', 'Test DB2', - '-on', 'ACME DB2', - '-oi', 'acme-id-2', - '-tu', 'https://example.com', - '-tt', 'fbad1c08-ffdc-4a61-be49-464962c186a8') + cli.invoke( + 'inv', + 'add', + '-n', + 'Test DB2', + '-on', + 'ACME DB2', + '-oi', + 'acme-id-2', + '-tu', + 'https://example.com', + '-tt', + 'fbad1c08-ffdc-4a61-be49-464962c186a8', + ) # Create an user for with access for both DB cli.invoke('user', 'add', 'bar@bar.com', '-a', 'Bar', '-p', 'Wow password') @@ -144,5 +164,6 @@ 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.') From bf423ab51546a9ce1c32d08159d74990c1ef0ea7 Mon Sep 17 00:00:00 2001 From: Santiago Lamora Date: Mon, 26 Sep 2022 17:12:18 +0200 Subject: [PATCH 11/18] Fix flake F841 variable assigned never used --- tests/test_action.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/tests/test_action.py b/tests/test_action.py index bc27065b..fe5b67e9 100644 --- a/tests/test_action.py +++ b/tests/test_action.py @@ -726,7 +726,7 @@ def test_live_without_TestDataStorage(user: UserClient, client: Client, app: Dev acer = file('acer.happy.battery.snapshot') snapshot, _ = user.post(acer, res=models.Snapshot) device_id = snapshot['device']['id'] - db_device = Device.query.filter_by(id=device_id).one() + post_request = { "transaction": "ccc", "name": "John", @@ -766,7 +766,7 @@ def test_live_without_hdd_1(user: UserClient, client: Client, app: Devicehub): acer = file('acer.happy.battery.snapshot') snapshot, _ = user.post(acer, res=models.Snapshot) device_id = snapshot['device']['id'] - db_device = Device.query.filter_by(id=device_id).one() + post_request = { "transaction": "ccc", "name": "John", @@ -802,7 +802,7 @@ def test_live_without_hdd_2(user: UserClient, client: Client, app: Devicehub): acer['components'] = components snapshot, _ = user.post(json_encode(acer), res=models.Snapshot) device_id = snapshot['device']['id'] - db_device = Device.query.filter_by(id=device_id).one() + post_request = { "transaction": "ccc", "name": "John", @@ -837,7 +837,7 @@ def test_live_without_hdd_3(user: UserClient, client: Client, app: Devicehub): acer['components'] = components snapshot, _ = user.post(json_encode(acer), res=models.Snapshot) device_id = snapshot['device']['id'] - db_device = Device.query.filter_by(id=device_id).one() + post_request = { "transaction": "ccc", "name": "John", @@ -874,7 +874,7 @@ def test_live_with_hdd_with_old_time(user: UserClient, client: Client, app: Devi acer = file('acer.happy.battery.snapshot') snapshot, _ = user.post(acer, res=models.Snapshot) device_id = snapshot['device']['id'] - db_device = Device.query.filter_by(id=device_id).one() + post_request = { "transaction": "ccc", "name": "John", @@ -2952,7 +2952,6 @@ def test_delete_devices_permitions(user: UserClient, user2: UserClient): file_snap = file('1-device-with-components.snapshot') snap, _ = user.post(file_snap, res=models.Snapshot) - device = Device.query.filter_by(id=snap['device']['id']).one() request = { 'type': 'Delete', @@ -3013,8 +3012,7 @@ def test_moveOnDocument_bug168(user: UserClient, user2: UserClient): 'container_to': id_hash, 'description': description, } - doc, _ = user.post(res=models.Action, data=request_moveOn) - trade = models.Trade.query.one() + user.post(res=models.Action, data=request_moveOn) trade_document1 = TradeDocument.query.filter_by(id=tradedocument_from['id']).one() trade_document2 = TradeDocument.query.filter_by(id=tradedocument_to['id']).one() assert trade_document1.total_weight == 150.0 From 5b9928699448f865b4466719479c584685db223c Mon Sep 17 00:00:00 2001 From: Santiago Lamora Date: Mon, 26 Sep 2022 17:15:40 +0200 Subject: [PATCH 12/18] E712 comparison to True should be 'if cond is True:' or 'if cond:' --- tests/test_action.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/test_action.py b/tests/test_action.py index fe5b67e9..8427bde1 100644 --- a/tests/test_action.py +++ b/tests/test_action.py @@ -1021,7 +1021,7 @@ def test_allocate(user: UserClient): allocate, _ = user.post(res=models.Allocate, data=post_request) # Normal allocate device, _ = user.get(res=Device, item=devicehub_id) - assert device['allocated'] == True + assert device['allocated'] is True action = [a for a in device['actions'] if a['type'] == 'Allocate'][0] assert action['transaction'] == allocate['transaction'] assert action['finalUserCode'] == allocate['finalUserCode'] @@ -1096,11 +1096,11 @@ def test_deallocate(user: UserClient): user.post(res=models.Allocate, data=post_allocate) device, _ = user.get(res=Device, item=devicehub_id) - assert device['allocated'] == True + assert device['allocated'] is True deallocate, _ = user.post(res=models.Deallocate, data=post_deallocate) assert deallocate['startTime'] == post_deallocate['startTime'] assert deallocate['devices'][0]['id'] == device_id - assert deallocate['devices'][0]['allocated'] == False + assert deallocate['devices'][0]['allocated'] is False res, _ = user.post(res=models.Deallocate, data=post_deallocate, status=422) assert res['code'] == 422 assert res['type'] == 'ValidationError' @@ -1203,8 +1203,8 @@ def test_offer_without_to(user: UserClient): users = [ac.user for ac in trade.acceptances] assert trade.user_to == device.owner assert request_post['code'].lower() in device.owner.email - assert device.owner.active == False - assert device.owner.phantom == True + assert device.owner.active is False + assert device.owner.phantom is True assert trade.user_to in users assert trade.user_from in users assert device.owner.email != user.email @@ -1282,8 +1282,8 @@ def test_offer_without_from(user: UserClient, user2: UserClient): phantom_user = trade.user_from assert request_post['code'].lower() in phantom_user.email - assert phantom_user.active == False - assert phantom_user.phantom == True + assert phantom_user.active is False + assert phantom_user.phantom is True # assert trade.confirm_transfer users = [ac.user for ac in trade.acceptances] @@ -2886,7 +2886,7 @@ def test_delete_devices(user: UserClient): assert action_delete.t == 'Delete' assert str(action_delete.id) == action['id'] - assert db_device.active == False + assert db_device.active is False # Check use of filter from frontend url = '/devices/?filter={"type":["Computer"]}' From c232320d6284be4d75fc26c388af16aecd4c99ae Mon Sep 17 00:00:00 2001 From: Santiago Lamora Date: Mon, 26 Sep 2022 17:18:10 +0200 Subject: [PATCH 13/18] Fix flake8: E713, E501 --- tests/test_action.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/test_action.py b/tests/test_action.py index 8427bde1..1a925db1 100644 --- a/tests/test_action.py +++ b/tests/test_action.py @@ -1777,12 +1777,12 @@ def test_confirmRevoke(user: UserClient, user2: UserClient): assert device_10 in trade.devices assert len(trade.devices) == 10 - # the SCRAP confirms the revoke action - request_confirm_revoke = { - 'type': 'ConfirmRevoke', - 'action': device_10.actions[-2].id, - 'devices': [snap10['device']['id']], - } + # TODO??? the SCRAP confirms the revoke action + # request_confirm_revoke = { + # 'type': 'ConfirmRevoke', + # 'action': device_10.actions[-2].id, + # 'devices': [snap10['device']['id']], + # } # check validation error # user2.post(res=models.Action, data=request_confirm_revoke, status=422) @@ -2804,7 +2804,7 @@ def test_moveOnDocument(user: UserClient, user2: UserClient): lotIn, _ = user.post({'name': 'MyLotIn'}, res=Lot) lotOut, _ = user.post({'name': 'MyLotOut'}, res=Lot) url = ( - 'http://www.ereuse.org/apapaapaapaapaapaapaapaapaapaapapaapaapaapaapaapaapaapaapaapapaapaapaapaapaapaapaapaapaapaaaa', + 'http://www.ereuse.org/apapaapaapaapaapaapaapaapaapaapapaapaapaapaapaapaapaapaapaapapaapaapaapaapaapaapaapaap', ) request_post1 = { 'filename': 'test.pdf', @@ -2971,7 +2971,7 @@ def test_moveOnDocument_bug168(user: UserClient, user2: UserClient): lotIn, _ = user.post({'name': 'MyLotIn'}, res=Lot) lotOut, _ = user.post({'name': 'MyLotOut'}, res=Lot) url = ( - 'http://www.ereuse.org/apapaapaapaapaapaapaapaapaapaapapaapaapaapaapaapaapaapaapaapapaapaapaapaapaapaapaapaapaapaaaa', + 'http://www.ereuse.org/apapaapaapaapaapaapaapaapaapaapapaapaapaapaapaapaapaapaapaapapaapaapaapaapaapaapaapaap', ) request_post1 = { 'filename': 'test.pdf', From 7bae66e04196056ae13f3f9178403a545a83f307 Mon Sep 17 00:00:00 2001 From: Santiago Lamora Date: Mon, 26 Sep 2022 17:19:14 +0200 Subject: [PATCH 14/18] Fix E711, E713 --- tests/test_action.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_action.py b/tests/test_action.py index 1a925db1..40e9cd15 100644 --- a/tests/test_action.py +++ b/tests/test_action.py @@ -2795,7 +2795,7 @@ def test_action_web_erase(user: UserClient, client: Client): ) assert "alert alert-info" in response assert "100% coincidence." in response - assert not "alert alert-danger" in response + assert "alert alert-danger" not in response @pytest.mark.mvp @@ -3018,6 +3018,6 @@ def test_moveOnDocument_bug168(user: UserClient, user2: UserClient): assert trade_document1.total_weight == 150.0 assert trade_document2.total_weight == 4.0 assert trade_document1.trading == 'Confirm' - assert trade_document2.trading == None + assert trade_document2.trading is None tradedocument, _ = user.delete(res=TradeDocument, item=tradedocument_to['id']) From 332c1088c0d3587d3cf14e38a54281b189b7872b Mon Sep 17 00:00:00 2001 From: Santiago Lamora Date: Thu, 29 Sep 2022 11:42:50 +0200 Subject: [PATCH 15/18] Fix can't compare offset-naive and offset-aware datetimes --- tests/test_device.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_device.py b/tests/test_device.py index f422c653..e2b1f078 100644 --- a/tests/test_device.py +++ b/tests/test_device.py @@ -1,6 +1,7 @@ import copy import datetime import pytest +import pytz from uuid import UUID from flask import g @@ -570,7 +571,7 @@ def test_manufacturer(user: UserClient): m, r = user.get(res='Manufacturer', query=[('search', 'asus')]) assert m == {'items': [{'name': 'Asus', 'url': 'https://en.wikipedia.org/wiki/Asus'}]} assert r.cache_control.public - assert r.expires > datetime.datetime.now() + assert r.expires.timestamp() > datetime.datetime.now().timestamp() @pytest.mark.mvp From 72457088078a0468bd01106e499bcb75be946d03 Mon Sep 17 00:00:00 2001 From: Santiago Lamora Date: Thu, 29 Sep 2022 11:44:43 +0200 Subject: [PATCH 16/18] Fix flake8 & reformat using black --- tests/test_device.py | 351 ++++++++++++++++++++++++++++--------------- 1 file changed, 230 insertions(+), 121 deletions(-) diff --git a/tests/test_device.py b/tests/test_device.py index e2b1f078..ac8c1d07 100644 --- a/tests/test_device.py +++ b/tests/test_device.py @@ -1,14 +1,12 @@ import copy import datetime -import pytest -import pytz - from uuid import UUID -from flask import g +import pytest from colour import Color from ereuse_utils.naming import Naming from ereuse_utils.test import ANY +from flask import g from pytest import raises from sqlalchemy.util import OrderedSet from teal.db import ResourceNotFound @@ -21,26 +19,35 @@ from ereuse_devicehub.resources.action import models as m from ereuse_devicehub.resources.action.models import Remove, TestConnectivity from ereuse_devicehub.resources.agent.models import Person from ereuse_devicehub.resources.device import models as d -from ereuse_devicehub.resources.device.exceptions import NeedsId from ereuse_devicehub.resources.device.schemas import Device as DeviceS -from ereuse_devicehub.resources.device.sync import MismatchBetweenTags, MismatchBetweenTagsAndHid, \ - Sync -from ereuse_devicehub.resources.enums import ComputerChassis, DisplayTech, Severity, \ - SnapshotSoftware, TransferState +from ereuse_devicehub.resources.device.sync import ( + MismatchBetweenTags, + MismatchBetweenTagsAndHid, + Sync, +) +from ereuse_devicehub.resources.enums import ( + ComputerChassis, + DisplayTech, + Severity, + SnapshotSoftware, + TransferState, +) from ereuse_devicehub.resources.tag.model import Tag from ereuse_devicehub.resources.user import User from tests import conftest -from tests.conftest import file, yaml2json, json_encode +from tests.conftest import file, json_encode, yaml2json @pytest.mark.mvp @pytest.mark.usefixtures(conftest.auth_app_context.__name__) def test_device_model(): """Tests that the correctness of the device model and its relationships.""" - pc = d.Desktop(model='p1mo', - manufacturer='p1ma', - serial_number='p1s', - chassis=ComputerChassis.Tower) + pc = d.Desktop( + model='p1mo', + manufacturer='p1ma', + serial_number='p1s', + chassis=ComputerChassis.Tower, + ) net = d.NetworkAdapter(model='c1mo', manufacturer='c1ma', serial_number='c1s') graphic = d.GraphicCard(model='c2mo', manufacturer='c2ma', memory=1500) pc.components.add(net) @@ -56,7 +63,9 @@ def test_device_model(): # Removing a component from pc doesn't delete the component pc.components.remove(net) db.session.commit() - pc = d.Device.query.filter_by(id=pc.id).first() # this is the same as querying for d.Desktop directly + pc = d.Device.query.filter_by( + id=pc.id + ).first() # this is the same as querying for d.Desktop directly assert pc.components == {graphic} network_adapter = d.NetworkAdapter.query.one() assert network_adapter not in pc.components @@ -73,7 +82,9 @@ def test_device_model(): assert network_adapter.id == 4 assert d.NetworkAdapter.query.first() is not None, 'We removed the network adaptor' assert gcard.id == 5, 'We should still hold a reference to a zombie graphic card' - assert d.GraphicCard.query.first() is None, 'We should have deleted it –it was inside the pc' + assert ( + d.GraphicCard.query.first() is None + ), 'We should have deleted it –it was inside the pc' @pytest.mark.xfail(reason='Test not developed') @@ -93,21 +104,25 @@ def test_device_schema(): @pytest.mark.mvp @pytest.mark.usefixtures(conftest.auth_app_context.__name__) def test_physical_properties(): - c = d.Motherboard(slots=2, - usb=3, - serial_number='sn', - model='ml', - manufacturer='mr', - width=2.0, - color=Color()) - pc = d.Desktop(chassis=ComputerChassis.Tower, - model='foo', - manufacturer='bar', - serial_number='foo-bar', - weight=2.8, - width=1.4, - height=2.1, - color=Color('LightSeaGreen')) + c = d.Motherboard( + slots=2, + usb=3, + serial_number='sn', + model='ml', + manufacturer='mr', + width=2.0, + color=Color(), + ) + pc = d.Desktop( + chassis=ComputerChassis.Tower, + model='foo', + manufacturer='bar', + serial_number='foo-bar', + weight=2.8, + width=1.4, + height=2.1, + color=Color('LightSeaGreen'), + ) pc.components.add(c) db.session.add(pc) db.session.commit() @@ -123,7 +138,7 @@ def test_physical_properties(): 'manufacturer': 'mr', 'bios_date': None, 'ram_max_size': None, - 'ram_slots': None + 'ram_slots': None, } assert pc.physical_properties == { 'chassis': ComputerChassis.Tower, @@ -133,7 +148,7 @@ def test_physical_properties(): 'receiver_id': None, 'serial_number': 'foo-bar', 'part_number': None, - 'transfer_state': TransferState.Initial + 'transfer_state': TransferState.Initial, } @@ -143,14 +158,19 @@ def test_component_similar_one(): user = User.query.filter().first() snapshot = yaml2json('pc-components.db') pc = snapshot['device'] - snapshot['components'][0]['serial_number'] = snapshot['components'][1]['serial_number'] = None - pc = d.Desktop(**pc, components=OrderedSet(d.Component(**c) for c in snapshot['components'])) + snapshot['components'][0]['serial_number'] = snapshot['components'][1][ + 'serial_number' + ] = None + pc = d.Desktop( + **pc, components=OrderedSet(d.Component(**c) for c in snapshot['components']) + ) component1, component2 = pc.components # type: d.Component db.session.add(pc) db.session.flush() # Let's create a new component named 'A' similar to 1 - componentA = d.Component(model=component1.model, manufacturer=component1.manufacturer, - owner_id=user.id) + componentA = d.Component( + model=component1.model, manufacturer=component1.manufacturer, owner_id=user.id + ) similar_to_a = componentA.similar_one(pc, set()) assert similar_to_a == component1 # d.Component B does not have the same model @@ -176,9 +196,11 @@ def test_add_remove(): pc = d.Desktop(**pc, components=OrderedSet([c1, c2])) db.session.add(pc) c3 = d.Component(serial_number='nc1', owner_id=user.id) - pc2 = d.Desktop(serial_number='s2', - components=OrderedSet([c3]), - chassis=ComputerChassis.Microtower) + pc2 = d.Desktop( + serial_number='s2', + components=OrderedSet([c3]), + chassis=ComputerChassis.Microtower, + ) c4 = d.Component(serial_number='c4s', owner_id=user.id) db.session.add(pc2) db.session.add(c4) @@ -202,7 +224,9 @@ def test_sync_run_components_empty(): remove all the components from the device. """ s = yaml2json('pc-components.db') - pc = d.Desktop(**s['device'], components=OrderedSet(d.Component(**c) for c in s['components'])) + pc = d.Desktop( + **s['device'], components=OrderedSet(d.Component(**c) for c in s['components']) + ) db.session.add(pc) db.session.commit() @@ -220,7 +244,9 @@ def test_sync_run_components_none(): keep all the components from the device. """ s = yaml2json('pc-components.db') - pc = d.Desktop(**s['device'], components=OrderedSet(d.Component(**c) for c in s['components'])) + pc = d.Desktop( + **s['device'], components=OrderedSet(d.Component(**c) for c in s['components']) + ) db.session.add(pc) db.session.commit() @@ -250,7 +276,8 @@ def test_sync_execute_register_desktop_existing_no_tag(): db.session.commit() pc = d.Desktop( - **yaml2json('pc-components.db')['device']) # Create a new transient non-db object + **yaml2json('pc-components.db')['device'] + ) # Create a new transient non-db object # 1: device exists on DB db_pc = Sync().execute_register(pc) pc.amount = 0 @@ -286,7 +313,9 @@ def test_sync_execute_register_desktop_tag_not_linked(): db.session.commit() # Create a new transient non-db object - pc = d.Desktop(**yaml2json('pc-components.db')['device'], tags=OrderedSet([Tag(id='foo')])) + pc = d.Desktop( + **yaml2json('pc-components.db')['device'], tags=OrderedSet([Tag(id='foo')]) + ) returned_pc = Sync().execute_register(pc) assert returned_pc == pc assert tag.device == pc, 'Tag has to be linked' @@ -327,7 +356,9 @@ def test_sync_execute_register_tag_does_not_exist(): Tags have to be created before trying to link them through a Snapshot. """ user = User.query.filter().first() - pc = d.Desktop(**yaml2json('pc-components.db')['device'], tags=OrderedSet([Tag('foo')])) + pc = d.Desktop( + **yaml2json('pc-components.db')['device'], tags=OrderedSet([Tag('foo')]) + ) pc.owner_id = user.id with raises(ResourceNotFound): Sync().execute_register(pc) @@ -346,7 +377,8 @@ def test_sync_execute_register_tag_linked_same_device(): db.session.commit() pc = d.Desktop( - **yaml2json('pc-components.db')['device']) # Create a new transient non-db object + **yaml2json('pc-components.db')['device'] + ) # Create a new transient non-db object pc.tags.add(Tag(id='foo')) db_pc = Sync().execute_register(pc) assert db_pc.id == orig_pc.id @@ -370,7 +402,8 @@ def test_sync_execute_register_tag_linked_other_device_mismatch_between_tags(): db.session.commit() pc1 = d.Desktop( - **yaml2json('pc-components.db')['device']) # Create a new transient non-db object + **yaml2json('pc-components.db')['device'] + ) # Create a new transient non-db object pc1.tags.add(Tag(id='foo-1')) pc1.tags.add(Tag(id='foo-2')) with raises(MismatchBetweenTags): @@ -394,7 +427,8 @@ def test_sync_execute_register_mismatch_between_tags_and_hid(): db.session.commit() pc1 = d.Desktop( - **yaml2json('pc-components.db')['device']) # Create a new transient non-db object + **yaml2json('pc-components.db')['device'] + ) # Create a new transient non-db object pc1.tags.add(Tag(id='foo-2')) with raises(MismatchBetweenTagsAndHid): Sync().execute_register(pc1) @@ -405,22 +439,36 @@ def test_sync_execute_register_mismatch_between_tags_and_hid(): def test_get_device(user: UserClient): """Checks GETting a d.Desktop with its components.""" g.user = User.query.one() - pc = d.Desktop(model='p1mo', - manufacturer='p1ma', - serial_number='p1s', - chassis=ComputerChassis.Tower, - owner_id=user.user['id']) - pc.components = OrderedSet([ - d.NetworkAdapter(model='c1mo', manufacturer='c1ma', serial_number='c1s', - owner_id=user.user['id']), - d.GraphicCard(model='c2mo', manufacturer='c2ma', memory=1500, owner_id=user.user['id']) - ]) + pc = d.Desktop( + model='p1mo', + manufacturer='p1ma', + serial_number='p1s', + chassis=ComputerChassis.Tower, + owner_id=user.user['id'], + ) + pc.components = OrderedSet( + [ + d.NetworkAdapter( + model='c1mo', + manufacturer='c1ma', + serial_number='c1s', + owner_id=user.user['id'], + ), + d.GraphicCard( + model='c2mo', manufacturer='c2ma', memory=1500, owner_id=user.user['id'] + ), + ] + ) db.session.add(pc) # todo test is an abstract class. replace with another one - db.session.add(TestConnectivity(device=pc, - severity=Severity.Info, - agent=Person(name='Timmy'), - author=User(email='bar@bar.com'))) + db.session.add( + TestConnectivity( + device=pc, + severity=Severity.Info, + agent=Person(name='Timmy'), + author=User(email='bar@bar.com'), + ) + ) db.session.commit() pc_api, _ = user.get(res=d.Device, item=pc.devicehub_id) assert len(pc_api['actions']) == 1 @@ -428,10 +476,14 @@ def test_get_device(user: UserClient): assert pc_api['actions'][0]['device'] == pc.id assert pc_api['actions'][0]['severity'] == 'Info' assert UUID(pc_api['actions'][0]['author']) - assert 'actions_components' not in pc_api, 'actions_components are internal use only' + assert ( + 'actions_components' not in pc_api + ), 'actions_components are internal use only' assert 'actions_one' not in pc_api, 'they are internal use only' assert 'author' not in pc_api - assert tuple(c['id'] for c in pc_api['components']) == tuple(c.id for c in pc.components) + assert tuple(c['id'] for c in pc_api['components']) == tuple( + c.id for c in pc.components + ) assert pc_api['hid'] == 'desktop-p1ma-p1mo-p1s' assert pc_api['model'] == 'p1mo' assert pc_api['manufacturer'] == 'p1ma' @@ -444,41 +496,59 @@ def test_get_device(user: UserClient): def test_get_devices(app: Devicehub, user: UserClient): """Checks GETting multiple devices.""" g.user = User.query.one() - pc = d.Desktop(model='p1mo', - manufacturer='p1ma', - serial_number='p1s', - chassis=ComputerChassis.Tower, - owner_id=user.user['id']) - pc.components = OrderedSet([ - d.NetworkAdapter(model='c1mo', manufacturer='c1ma', serial_number='c1s', - owner_id=user.user['id']), - d.GraphicCard(model='c2mo', manufacturer='c2ma', memory=1500, - owner_id=user.user['id']) - ]) - pc1 = d.Desktop(model='p2mo', - manufacturer='p2ma', - serial_number='p2s', - chassis=ComputerChassis.Tower, - owner_id=user.user['id']) - pc2 = d.Laptop(model='p3mo', - manufacturer='p3ma', - serial_number='p3s', - chassis=ComputerChassis.Netbook, - owner_id=user.user['id']) + pc = d.Desktop( + model='p1mo', + manufacturer='p1ma', + serial_number='p1s', + chassis=ComputerChassis.Tower, + owner_id=user.user['id'], + ) + pc.components = OrderedSet( + [ + d.NetworkAdapter( + model='c1mo', + manufacturer='c1ma', + serial_number='c1s', + owner_id=user.user['id'], + ), + d.GraphicCard( + model='c2mo', manufacturer='c2ma', memory=1500, owner_id=user.user['id'] + ), + ] + ) + pc1 = d.Desktop( + model='p2mo', + manufacturer='p2ma', + serial_number='p2s', + chassis=ComputerChassis.Tower, + owner_id=user.user['id'], + ) + pc2 = d.Laptop( + model='p3mo', + manufacturer='p3ma', + serial_number='p3s', + chassis=ComputerChassis.Netbook, + owner_id=user.user['id'], + ) db.session.add_all((pc, pc1, pc2)) db.session.commit() devices, _ = user.get(res=d.Device) ids = (pc.id, pc1.id, pc2.id, pc.components[0].id, pc.components[1].id) assert tuple(dev['id'] for dev in devices['items']) == ids assert tuple(dev['type'] for dev in devices['items']) == ( - d.Desktop.t, d.Desktop.t, d.Laptop.t, d.NetworkAdapter.t, d.GraphicCard.t + d.Desktop.t, + d.Desktop.t, + d.Laptop.t, + d.NetworkAdapter.t, + d.GraphicCard.t, ) @pytest.mark.mvp @pytest.mark.usefixtures(conftest.app_context.__name__) -def test_get_device_permissions(app: Devicehub, user: UserClient, user2: UserClient, - client: Client): +def test_get_device_permissions( + app: Devicehub, user: UserClient, user2: UserClient, client: Client +): """Checks GETting a d.Desktop with its components.""" s, _ = user.post(file('asus-eee-1000h.snapshot.11'), res=m.Snapshot) @@ -530,12 +600,12 @@ def test_get_devices_unassigned(user: UserClient): assert len(devices['items']) == 2 from ereuse_devicehub.resources.lot.models import Lot + device_id = devices['items'][0]['id'] my_lot, _ = user.post(({'name': 'My_lot'}), res=Lot) - lot, _ = user.post({}, - res=Lot, - item='{}/devices'.format(my_lot['id']), - query=[('id', device_id)]) + lot, _ = user.post( + {}, res=Lot, item='{}/devices'.format(my_lot['id']), query=[('id', device_id)] + ) lot = Lot.query.filter_by(id=lot['id']).one() assert next(iter(lot.devices)).id == device_id @@ -555,13 +625,15 @@ def test_get_devices_unassigned(user: UserClient): @pytest.mark.mvp @pytest.mark.usefixtures(conftest.auth_app_context.__name__) def test_computer_monitor(): - m = d.ComputerMonitor(technology=DisplayTech.LCD, - manufacturer='foo', - model='bar', - serial_number='foo-bar', - resolution_width=1920, - resolution_height=1080, - size=14.5) + m = d.ComputerMonitor( + technology=DisplayTech.LCD, + manufacturer='foo', + model='bar', + serial_number='foo-bar', + resolution_width=1920, + resolution_height=1080, + size=14.5, + ) db.session.add(m) db.session.commit() @@ -569,7 +641,9 @@ def test_computer_monitor(): @pytest.mark.mvp def test_manufacturer(user: UserClient): m, r = user.get(res='Manufacturer', query=[('search', 'asus')]) - assert m == {'items': [{'name': 'Asus', 'url': 'https://en.wikipedia.org/wiki/Asus'}]} + assert m == { + 'items': [{'name': 'Asus', 'url': 'https://en.wikipedia.org/wiki/Asus'}] + } assert r.cache_control.public assert r.expires.timestamp() > datetime.datetime.now().timestamp() @@ -592,12 +666,20 @@ def test_device_properties_format(app: Devicehub, user: UserClient): assert format(pc, 's') == '(asustek computer inc.) S/N 94OAAQ021116' assert pc.ram_size == 1024 assert pc.data_storage_size == 152627 - assert pc.graphic_card_model == 'mobile 945gse express integrated graphics controller' + assert ( + pc.graphic_card_model + == 'mobile 945gse express integrated graphics controller' + ) assert pc.processor_model == 'intel atom cpu n270 @ 1.60ghz' net = next(c for c in pc.components if isinstance(c, d.NetworkAdapter)) - assert format(net) == 'NetworkAdapter 5: model ar8121/ar8113/ar8114 ' \ - 'gigabit or fast ethernet, S/N 00:24:8c:7f:cf:2d' - assert format(net, 't') == 'NetworkAdapter ar8121/ar8113/ar8114 gigabit or fast ethernet' + assert ( + format(net) == 'NetworkAdapter 5: model ar8121/ar8113/ar8114 ' + 'gigabit or fast ethernet, S/N 00:24:8c:7f:cf:2d' + ) + assert ( + format(net, 't') + == 'NetworkAdapter ar8121/ar8113/ar8114 gigabit or fast ethernet' + ) assert format(net, 's') == 'qualcomm atheros 00:24:8C:7F:CF:2D – 100 Mbps' hdd = next(c for c in pc.components if isinstance(c, d.DataStorage)) assert format(hdd) == 'HardDrive 10: model st9160310as, S/N 5sv4tqa6' @@ -639,8 +721,12 @@ def test_networking_model(user: UserClient): @pytest.mark.usefixtures(conftest.app_context.__name__) def test_cooking_mixer(user: UserClient): - mixer = d.Mixer(serial_number='foo', model='bar', manufacturer='foobar', - owner_id=user.user['id']) + mixer = d.Mixer( + serial_number='foo', + model='bar', + manufacturer='foobar', + owner_id=user.user['id'], + ) db.session.add(mixer) db.session.commit() @@ -653,12 +739,12 @@ def test_cooking_mixer_api(user: UserClient): 'serialNumber': 'foo', 'model': 'bar', 'manufacturer': 'foobar', - 'type': 'Mixer' + 'type': 'Mixer', }, 'version': '11.0', - 'software': SnapshotSoftware.Web.name + 'software': SnapshotSoftware.Web.name, }, - res=m.Snapshot + res=m.Snapshot, ) mixer, _ = user.get(res=d.Device, item=snapshot['device']['id']) assert mixer['type'] == 'Mixer' @@ -674,14 +760,19 @@ def test_hid_with_mac(app: Devicehub, user: UserClient): pc, _ = user.get(res=d.Device, item=snap['device']['devicehubID']) assert pc['hid'] == 'laptop-asustek_computer_inc-1000h-94oaaq021116' pc = d.Device.query.filter_by(devicehub_id=snap['device']['devicehubID']).one() - assert pc.placeholder.binding.hid == 'laptop-asustek_computer_inc-1000h-94oaaq021116-00:24:8c:7f:cf:2d' + assert ( + pc.placeholder.binding.hid + == 'laptop-asustek_computer_inc-1000h-94oaaq021116-00:24:8c:7f:cf:2d' + ) @pytest.mark.mvp def test_hid_without_mac(app: Devicehub, user: UserClient): """Checks hid without mac.""" snapshot = yaml2json('asus-eee-1000h.snapshot.11') - snapshot['components'] = [c for c in snapshot['components'] if c['type'] != 'NetworkAdapter'] + snapshot['components'] = [ + c for c in snapshot['components'] if c['type'] != 'NetworkAdapter' + ] snap, _ = user.post(json_encode(snapshot), res=m.Snapshot) pc, _ = user.get(res=d.Device, item=snap['device']['devicehubID']) assert pc['hid'] == 'laptop-asustek_computer_inc-1000h-94oaaq021116' @@ -710,7 +801,10 @@ def test_hid_with_2networkadapters(app: Devicehub, user: UserClient): devices, _ = user.get(res=d.Device) laptop = devices['items'][0] - assert laptop['hid'] == 'laptop-asustek_computer_inc-1000h-94oaaq021116-00:24:8c:7f:cf:2d' + assert ( + laptop['hid'] + == 'laptop-asustek_computer_inc-1000h-94oaaq021116-00:24:8c:7f:cf:2d' + ) assert len([c for c in devices['items'] if c['type'] == 'Laptop']) == 2 @@ -727,14 +821,20 @@ def test_hid_with_2network_and_drop_no_mac_in_hid(app: Devicehub, user: UserClie pc, _ = user.get(res=d.Device, item=snap['device']['devicehubID']) assert pc['hid'] == 'laptop-asustek_computer_inc-1000h-94oaaq021116' pc = d.Device.query.filter_by(devicehub_id=snap['device']['devicehubID']).one() - assert pc.placeholder.binding.hid == 'laptop-asustek_computer_inc-1000h-94oaaq021116-00:24:8c:7f:cf:2d' + assert ( + pc.placeholder.binding.hid + == 'laptop-asustek_computer_inc-1000h-94oaaq021116-00:24:8c:7f:cf:2d' + ) snapshot['uuid'] = 'd1b70cb8-8929-4f36-99b7-fe052cec0abb' snapshot['components'] = [c for c in snapshot['components'] if c != network] user.post(json_encode(snapshot), res=m.Snapshot) devices, _ = user.get(res=d.Device) laptop = devices['items'][0] - assert pc.placeholder.binding.hid == 'laptop-asustek_computer_inc-1000h-94oaaq021116-00:24:8c:7f:cf:2d' + assert ( + pc.placeholder.binding.hid + == 'laptop-asustek_computer_inc-1000h-94oaaq021116-00:24:8c:7f:cf:2d' + ) assert len([c for c in devices['items'] if c['type'] == 'Laptop']) == 2 assert len([c for c in laptop['components'] if c['type'] == 'NetworkAdapter']) == 1 @@ -753,7 +853,10 @@ def test_hid_with_2network_and_drop_mac_in_hid(app: Devicehub, user: UserClient) pc, _ = user.get(res=d.Device, item=snap['device']['devicehubID']) assert pc['hid'] == 'laptop-asustek_computer_inc-1000h-94oaaq021116' pc = d.Device.query.filter_by(devicehub_id=snap['device']['devicehubID']).one() - assert pc.placeholder.binding.hid == 'laptop-asustek_computer_inc-1000h-94oaaq021116-00:24:8c:7f:cf:2d' + assert ( + pc.placeholder.binding.hid + == 'laptop-asustek_computer_inc-1000h-94oaaq021116-00:24:8c:7f:cf:2d' + ) # we drop the network card then is used for to build the hid snapshot['uuid'] = 'd1b70cb8-8929-4f36-99b7-fe052cec0abb' @@ -763,19 +866,25 @@ def test_hid_with_2network_and_drop_mac_in_hid(app: Devicehub, user: UserClient) laptops = [c for c in devices['items'] if c['type'] == 'Laptop'] assert len(laptops) == 4 hids = [laptops[0]['hid'], laptops[2]['hid']] - proof_hid = ['laptop-asustek_computer_inc-1000h-94oaaq021116-a0:24:8c:7f:cf:2d', - 'laptop-asustek_computer_inc-1000h-94oaaq021116-00:24:8c:7f:cf:2d'] + proof_hid = [ + 'laptop-asustek_computer_inc-1000h-94oaaq021116-a0:24:8c:7f:cf:2d', + 'laptop-asustek_computer_inc-1000h-94oaaq021116-00:24:8c:7f:cf:2d', + ] assert all([h in proof_hid for h in hids]) # we drop all network cards snapshot['uuid'] = 'd1b70cb8-8929-4f36-99b7-fe052cec0abc' - snapshot['components'] = [c for c in snapshot['components'] if c not in [network, network2]] + snapshot['components'] = [ + c for c in snapshot['components'] if c not in [network, network2] + ] user.post(json_encode(snapshot), res=m.Snapshot) devices, _ = user.get(res=d.Device) laptops = [c for c in devices['items'] if c['type'] == 'Laptop'] assert len(laptops) == 4 hids = [laptops[0]['hid'], laptops[2]['hid']] - proof_hid = ['laptop-asustek_computer_inc-1000h-94oaaq021116-a0:24:8c:7f:cf:2d', - 'laptop-asustek_computer_inc-1000h-94oaaq021116-00:24:8c:7f:cf:2d', - 'laptop-asustek_computer_inc-1000h-94oaaq021116'] + proof_hid = [ + 'laptop-asustek_computer_inc-1000h-94oaaq021116-a0:24:8c:7f:cf:2d', + 'laptop-asustek_computer_inc-1000h-94oaaq021116-00:24:8c:7f:cf:2d', + 'laptop-asustek_computer_inc-1000h-94oaaq021116', + ] assert all([h in proof_hid for h in hids]) From 8fecf9e37b6d86dc08ca06e4a57bcb976bd0dd1d Mon Sep 17 00:00:00 2001 From: Santiago Lamora Date: Thu, 29 Sep 2022 12:10:15 +0200 Subject: [PATCH 17/18] Group workbench dependencies --- requirements.in | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.in b/requirements.in index 11ce696b..13862036 100644 --- a/requirements.in +++ b/requirements.in @@ -27,6 +27,7 @@ sqlalchemy-utils==0.33.11 teal==0.2.0a38 tqdm==4.32.2 +# workbench json parsing dependencies pint==0.9 py-dmidecode==0.1.0 pandas==1.3.5 From 81fa78f6bb5bef1eae4698f7aaae2fac55656ddb Mon Sep 17 00:00:00 2001 From: Santiago Lamora Date: Thu, 29 Sep 2022 12:22:22 +0200 Subject: [PATCH 18/18] Add pip-compile pre-commit hook --- .pre-commit-config.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8d1307be..4d3d3d8d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -25,3 +25,7 @@ repos: entry: npm run babel language: node files: ^ereuse_devicehub/static/js/main_inventory.js + - repo: https://github.com/jazzband/pip-tools + rev: 6.8.0 + hooks: + - id: pip-compile