diff --git a/ereuse_devicehub/resources/device/views.py b/ereuse_devicehub/resources/device/views.py index 0b88dd8a..bb3d8fb0 100644 --- a/ereuse_devicehub/resources/device/views.py +++ b/ereuse_devicehub/resources/device/views.py @@ -54,7 +54,8 @@ class Filters(query.Query): _device_inside_lot = (Device.id == LotDevice.device_id) & (Lot.id == LotDevice.lot_id) _component_inside_lot_through_parent = (Device.id == Component.id) \ & (Component.parent_id == _parent.id) \ - & (_parent.id == LotDevice.device_id) + & (_parent.id == LotDevice.device_id) \ + & (Lot.id == LotDevice.lot_id) type = query.Or(OfType(Device.type)) model = query.ILike(Device.model) diff --git a/ereuse_devicehub/resources/lot/views.py b/ereuse_devicehub/resources/lot/views.py index 454dcdd5..9b2707dc 100644 --- a/ereuse_devicehub/resources/lot/views.py +++ b/ereuse_devicehub/resources/lot/views.py @@ -59,12 +59,8 @@ class LotView(View): you can filter. """ if args['format'] == LotFormat.UiTree: - nodes = [] - for model in Path.query: # type: Path - path = deque(model.path.path.split('.')) - self._p(nodes, path) return jsonify({ - 'items': nodes, + 'items': self.ui_tree(), 'url': request.path }) else: @@ -85,7 +81,16 @@ class LotView(View): } return jsonify(ret) - def _p(self, nodes: List[dict], path: deque): + @classmethod + def ui_tree(cls) -> List[dict]: + nodes = [] + for model in Path.query: # type: Path + path = deque(model.path.path.split('.')) + cls._p(nodes, path) + return nodes + + @classmethod + def _p(cls, nodes: List[dict], path: deque): """Recursively creates the nested lot structure. Every recursive step consumes path (a deque of lot_id), @@ -109,7 +114,7 @@ class LotView(View): } nodes.append(node) if path: - self._p(node['nodes'], path) + cls._p(node['nodes'], path) class LotBaseChildrenView(View): diff --git a/tests/conftest.py b/tests/conftest.py index 17ba7756..5fdfe479 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -104,7 +104,7 @@ def auth_app_context(app: Devicehub): password = '' app.auth.perform_auth(Auth()) - yield + yield app def file(name: str) -> dict: diff --git a/tests/test_device.py b/tests/test_device.py index e7608fa5..475a7f05 100644 --- a/tests/test_device.py +++ b/tests/test_device.py @@ -510,3 +510,10 @@ def test_device_public(user: UserClient, client: Client): html, _ = client.get(res=Device, item=s['device']['id'], accept=ANY) assert 'intel atom cpu n270 @ 1.60ghz' in html assert 'S/N 00:24:8c:7f:cf:2d – 100 Mbps' in html + + +@pytest.mark.xfail(reason='Functionality not yet developed.') +def test_device_search_multiple_tags(user: UserClient): + """Ensures that users can search multiple tags at once + and get their multiple devices.""" + pass diff --git a/tests/test_device_find.py b/tests/test_device_find.py index 71a49c2b..484957ae 100644 --- a/tests/test_device_find.py +++ b/tests/test_device_find.py @@ -4,7 +4,8 @@ from teal.utils import compiled from ereuse_devicehub.client import UserClient from ereuse_devicehub.db import db from ereuse_devicehub.devicehub import Devicehub -from ereuse_devicehub.resources.device.models import Desktop, Device, Laptop, SolidStateDrive +from ereuse_devicehub.resources.device.models import Desktop, Device, Laptop, Processor, \ + SolidStateDrive from ereuse_devicehub.resources.device.views import Filters, Sorting from ereuse_devicehub.resources.enums import ComputerChassis from ereuse_devicehub.resources.event.models import Snapshot @@ -73,6 +74,8 @@ def device_query_dummy(app: Devicehub): devices[-1].parent = devices[0] # s4 in s1 db.session.add_all(devices) + devices[0].components.add(Processor(model='ml5', manufacturer='mr5')) + db.session.commit() @@ -80,7 +83,7 @@ def device_query_dummy(app: Devicehub): def test_device_query_no_filters(user: UserClient): i, _ = user.get(res=Device) assert tuple(d['type'] for d in i['items']) == ( - 'Desktop', 'Laptop', 'Desktop', 'SolidStateDrive' + 'Desktop', 'Laptop', 'Desktop', 'SolidStateDrive', 'Processor' ) @@ -103,6 +106,12 @@ def test_device_query_filter_sort(user: UserClient): def test_device_query_filter_lots(user: UserClient): parent, _ = user.post({'name': 'Parent'}, res=Lot) child, _ = user.post({'name': 'Child'}, res=Lot) + + i, _ = user.get(res=Device, query=[ + ('filter', {'lot': {'id': [parent['id']]}}) + ]) + assert len(i['items']) == 0, 'No devices in lot' + parent, _ = user.post({}, res=Lot, item='{}/children'.format(parent['id']), @@ -122,13 +131,19 @@ def test_device_query_filter_lots(user: UserClient): ('filter', {'lot': {'id': [parent['id']]}}), ('sort', {'id': Sorting.ASCENDING}) ]) - assert len(i['items']) == 4 - assert tuple(x['id'] for x in i['items']) == (1, 2, 3, 4), \ + assert tuple(x['id'] for x in i['items']) == (1, 2, 3, 4, 5), \ 'The parent lot contains 2 items plus indirectly the third one, and 1st device the HDD.' + i, _ = user.get(res=Device, query=[ + ('filter', {'type': ['Computer'], 'lot': {'id': [parent['id']]}}), + ('sort', {'id': Sorting.ASCENDING}) + ]) + assert tuple(x['id'] for x in i['items']) == (1, 2, 3) + s, _ = user.get(res=Device, query=[ ('filter', {'lot': {'id': [child['id']]}}) ]) + assert len(s['items']) == 1 assert s['items'][0]['chassis'] == 'Microtower', 'The child lot only contains the last device.' s, _ = user.get(res=Device, query=[ ('filter', {'lot': {'id': [child['id'], parent['id']]}}) @@ -139,7 +154,6 @@ def test_device_query_filter_lots(user: UserClient): ('filter', {'lot': {'id': [parent['id']]}, 'type': ['Computer']}), ('sort', {'id': Sorting.ASCENDING}) ]) - assert len(i['items']) == 3 assert tuple(x['id'] for x in i['items']) == (1, 2, 3), 'Only computers now' diff --git a/tests/test_lot.py b/tests/test_lot.py index ccd76f4a..372330dc 100644 --- a/tests/test_lot.py +++ b/tests/test_lot.py @@ -81,8 +81,7 @@ def test_add_edge(): assert child in grandparent -@pytest.mark.usefixtures(conftest.auth_app_context.__name__) -def test_lot_multiple_parents(): +def test_lot_multiple_parents(auth_app_context): """Tests creating a lot with two parent lots: grandparent1 grandparent2 @@ -108,6 +107,18 @@ def test_lot_multiple_parents(): assert child in grandparent1 assert child in grandparent2 + nodes = auth_app_context.resources[Lot.t].VIEW.ui_tree() + assert nodes[0]['name'] == 'grandparent1' + assert nodes[0]['nodes'][0]['name'] == 'parent' + assert nodes[0]['nodes'][0]['nodes'][0]['name'] == 'child' + assert nodes[0]['nodes'][0]['nodes'][0]['nodes'] == [] + assert nodes[1]['name'] == 'grandparent2' + assert nodes[1]['nodes'][0]['name'] == 'parent' + assert nodes[1]['nodes'][0]['nodes'][0]['name'] == 'child' + assert nodes[1]['nodes'][0]['nodes'][0]['nodes'] == [] + + # Now remove all childs + grandparent1.remove_child(parent) assert parent not in grandparent1 assert child in parent @@ -115,6 +126,14 @@ def test_lot_multiple_parents(): assert child not in grandparent1 assert child in grandparent2 + nodes = auth_app_context.resources[Lot.t].VIEW.ui_tree() + assert nodes[0]['name'] == 'grandparent1' + assert nodes[0]['nodes'] == [] + assert nodes[1]['name'] == 'grandparent2' + assert nodes[1]['nodes'][0]['name'] == 'parent' + assert nodes[1]['nodes'][0]['nodes'][0]['name'] == 'child' + assert nodes[1]['nodes'][0]['nodes'][0]['nodes'] == [] + grandparent2.remove_child(parent) assert parent not in grandparent2 assert parent not in grandparent1 @@ -122,11 +141,30 @@ def test_lot_multiple_parents(): assert child not in grandparent1 assert child in parent + nodes = auth_app_context.resources[Lot.t].VIEW.ui_tree() + assert nodes[0]['name'] == 'grandparent1' + assert nodes[0]['nodes'] == [] + assert nodes[1]['name'] == 'grandparent2' + assert nodes[1]['nodes'] == [] + assert nodes[2]['name'] == 'parent' + assert nodes[2]['nodes'][0]['name'] == 'child' + assert nodes[2]['nodes'][0]['nodes'] == [] + parent.remove_child(child) assert child not in parent assert len(child.paths) == 1 assert len(parent.paths) == 1 + nodes = auth_app_context.resources[Lot.t].VIEW.ui_tree() + assert nodes[0]['name'] == 'grandparent1' + assert nodes[0]['nodes'] == [] + assert nodes[1]['name'] == 'grandparent2' + assert nodes[1]['nodes'] == [] + assert nodes[2]['name'] == 'parent' + assert nodes[2]['nodes'] == [] + assert nodes[3]['name'] == 'child' + assert nodes[3]['nodes'] == [] + @pytest.mark.usefixtures(conftest.auth_app_context.__name__) def test_lot_unite_graphs_and_find():