示例#1
0
def test_export_multiple_devices(user: UserClient):
    """
    Test a export multiple devices (Computers and other types) with different information
    """
    # Post all devices snapshots
    snapshot_pc, _ = user.post(file('real-eee-1001pxd.snapshot.11'), res=Snapshot)
    snapshot_empty, _ = user.post(file('basic.snapshot'), res=Snapshot)
    snapshot_keyboard, _ = user.post(file('keyboard.snapshot'), res=Snapshot)
    snapshot_monitor, _ = user.post(file('computer-monitor.snapshot'), res=Snapshot)

    # need query param??
    csv_str, _ = user.get(res=documents.DocumentDef.t,
                          item='devices/',
                          accept='text/csv')
    f = StringIO(csv_str)
    obj_csv = csv.reader(f, f)
    export_csv = list(obj_csv)

    # Open fixture csv and transform to list
    with Path(__file__).parent.joinpath('files').joinpath('multiples_devices.csv').open() \
            as csv_file:
        obj_csv = csv.reader(csv_file)
        fixture_csv = list(obj_csv)

    assert fixture_csv[0] == export_csv[0], 'Headers are not equal'

    max_range = max(len(export_csv), len(fixture_csv)) - 1
    # check if all devices information is correct
    for i in range(1, max_range):
        if isinstance(datetime.strptime(export_csv[i][8], '%c'), datetime):
            export_csv[i] = export_csv[i][:8] + export_csv[i][9:]
            fixture_csv[i] = fixture_csv[i][:8] + fixture_csv[i][9:]

        assert fixture_csv[i] == export_csv[i], 'Some fields are not equal'
示例#2
0
def test_workbench_server_condensed(user: UserClient):
    """
    As :def:`.test_workbench_server_phases` but all the events
    condensed in only one big ``Snapshot`` file, as described
    in the docs.
    """
    s = file('workbench-server-1.snapshot')
    del s['expectedEvents']
    s['device']['events'].append(file('workbench-server-2.stress-test'))
    s['components'][4]['events'].extend(
        (file('workbench-server-3.erase'), file('workbench-server-4.install')))
    s['components'][5]['events'] = [file('workbench-server-3.erase')]
    # Create tags
    user.post(res=Tag,
              query=[('ids', t['id']) for t in s['device']['tags']],
              data={})
    snapshot, _ = user.post(res=Snapshot, data=s)
    events = snapshot['events']
    assert {(event['type'], event['device'])
            for event in events} == {
                # todo missing Rate event aggregating the rates
                ('WorkbenchRate', 1),
                ('BenchmarkProcessorSysbench', 5),
                ('StressTest', 1),
                ('EraseSectors', 6),
                ('BenchmarkRamSysbench', 1),
                ('BenchmarkProcessor', 5),
                ('Install', 6),
                ('EraseSectors', 7),
                ('BenchmarkDataStorage', 6),
                ('TestDataStorage', 6)
            }
    assert snapshot['closed']
    assert not snapshot['error']
示例#3
0
def test_snapshot_tag_inner_tag_mismatch_between_tags_and_hid(user: UserClient, tag_id: str):
    """Ensures one device cannot 'steal' the tag from another one."""
    pc1 = file('basic.snapshot')
    pc1['device']['tags'] = [{'type': 'Tag', 'id': tag_id}]
    user.post(pc1, res=Snapshot)
    pc2 = file('1-device-with-components.snapshot')
    user.post(pc2, res=Snapshot)  # PC2 uploads well
    pc2['device']['tags'] = [{'type': 'Tag', 'id': tag_id}]  # Set tag from pc1 to pc2
    user.post(pc2, res=Snapshot, status=MismatchBetweenTagsAndHid)
def test_device_query_search(user: UserClient):
    # todo improve
    user.post(file('basic.snapshot'), res=Snapshot)
    user.post(file('computer-monitor.snapshot'), res=Snapshot)
    user.post(file('real-eee-1001pxd.snapshot.11'), res=Snapshot)
    i, _ = user.get(res=Device, query=[('search', 'desktop')])
    assert i['items'][0]['id'] == 1
    i, _ = user.get(res=Device, query=[('search', 'intel')])
    assert len(i['items']) == 1
    i, _ = user.get(res=Device, query=[('search', '1')])
    assert len(i['items']) == 1
示例#5
0
def test_sync_execute_register_computer_existing_no_tag():
    """
    Syncs an existing computer with HID and without a tag.
    """
    pc = Computer(**file('pc-components.db')['device'])
    db.session.add(pc)
    db.session.commit()

    pc = Computer(**file('pc-components.db')['device'])  # Create a new transient non-db object
    # 1: device exists on DB
    db_pc = Sync().execute_register(pc)
    assert pc.physical_properties == db_pc.physical_properties
示例#6
0
def test_workbench_server_condensed(user: UserClient):
    """
    As :def:`.test_workbench_server_phases` but all the events
    condensed in only one big ``Snapshot`` file, as described
    in the docs.
    """
    s = file('workbench-server-1.snapshot')
    del s['expectedEvents']
    s['device']['events'].append(file('workbench-server-2.stress-test'))
    s['components'][4]['events'].extend(
        (file('workbench-server-3.erase'), file('workbench-server-4.install')))
    s['components'][5]['events'].append(file('workbench-server-3.erase'))
    # Create tags
    for t in s['device']['tags']:
        user.post({'id': t['id']}, res=Tag)

    snapshot, _ = user.post(res=em.Snapshot, data=s)
    events = snapshot['events']
    assert {(event['type'], event['device'])
            for event in events} == {('AggregateRate', 1),
                                     ('WorkbenchRate', 1),
                                     ('BenchmarkProcessorSysbench', 5),
                                     ('StressTest', 1), ('EraseSectors', 6),
                                     ('BenchmarkRamSysbench', 1),
                                     ('BenchmarkProcessor', 5), ('Install', 6),
                                     ('EraseSectors', 7),
                                     ('BenchmarkDataStorage', 6),
                                     ('BenchmarkDataStorage', 7),
                                     ('TestDataStorage', 6)}
    assert snapshot['closed']
    assert snapshot['severity'] == 'Info'
    device, _ = user.get(res=Device, item=snapshot['device']['id'])
    assert device['dataStorageSize'] == 1100
    assert device['chassis'] == 'Tower'
    assert device['hid'] == 'desktop-d1mr-d1ml-d1s'
    assert device['graphicCardModel'] == device['components'][0][
        'model'] == 'gc1-1ml'
    assert device['networkSpeeds'] == [1000, 58]
    assert device['processorModel'] == device['components'][3][
        'model'] == 'p1-1ml'
    assert device[
        'ramSize'] == 2048, 'There are 3 RAM: 2 x 1024 and 1 None sizes'
    assert device['rate']['closed']
    assert device['rate']['severity'] == 'Info'
    assert device['rate']['rating'] == 0
    assert device['rate']['workbench']
    assert device['rate']['appearanceRange'] == 'A'
    assert device['rate']['functionalityRange'] == 'B'
    assert device['tags'][0]['id'] == 'tag1'
示例#7
0
def test_snapshot_post(user: UserClient):
    """
    Tests the post snapshot endpoint (validation, etc), data correctness,
    and relationship correctness.
    """
    snapshot = snapshot_and_check(user,
                                  file('basic.snapshot'),
                                  event_types=('WorkbenchRate', ),
                                  perform_second_snapshot=False)
    assert snapshot['software'] == 'Workbench'
    assert snapshot['version'] == '11.0'
    assert snapshot['uuid'] == 'f5efd26e-8754-46bc-87bf-fbccc39d60d9'
    assert snapshot['elapsed'] == 4
    assert snapshot['author']['id'] == user.user['id']
    assert 'events' not in snapshot['device']
    assert 'author' not in snapshot['device']
    device, _ = user.get(res=Device, item=snapshot['device']['id'])
    assert snapshot['components'] == device['components']

    assert tuple(c['type'] for c in snapshot['components']) == ('GraphicCard',
                                                                'RamModule')
    rate, _ = user.get(res=Event, item=snapshot['events'][0]['id'])
    assert rate['device']['id'] == snapshot['device']['id']
    assert rate['components'] == snapshot['components']
    assert rate['snapshot']['id'] == snapshot['id']
示例#8
0
def test_add_remove():
    # Original state:
    # pc has c1 and c2
    # pc2 has c3
    # c4 is not with any pc
    values = file('pc-components.db')
    pc = values['device']
    c1, c2 = (Component(**c) for c in values['components'])
    pc = Computer(**pc, components=OrderedSet([c1, c2]))
    db.session.add(pc)
    c3 = Component(serial_number='nc1')
    pc2 = Computer(serial_number='s2', components=OrderedSet([c3]))
    c4 = Component(serial_number='c4s')
    db.session.add(pc2)
    db.session.add(c4)
    db.session.commit()

    # Test:
    # pc has only c3
    events = Sync.add_remove(device=pc, components={c3, c4})
    db.session.add_all(events)
    db.session.commit()  # We enforce the appliance of order_by
    assert len(events) == 1
    assert isinstance(events[0], Remove)
    assert events[0].device == pc2
    assert events[0].components == OrderedSet([c3])
示例#9
0
def test_erase(user: UserClient):
    """Tests a Snapshot with EraseSectors."""
    s = file('erase-sectors.snapshot')
    snapshot = snapshot_and_check(user,
                                  s, ('EraseSectors', ),
                                  perform_second_snapshot=True)
    storage, *_ = snapshot['components']
    assert storage[
        'type'] == 'SolidStateDrive', 'Components must be ordered by input order'
    storage, _ = user.get(res=SolidStateDrive,
                          item=storage['id'])  # Let's get storage events too
    # order: creation time descending
    _snapshot1, erasure1, _snapshot2, erasure2 = storage['events']
    assert erasure1['type'] == erasure2['type'] == 'EraseSectors'
    assert _snapshot1['type'] == _snapshot2['type'] == 'Snapshot'
    assert snapshot == user.get(res=Event, item=_snapshot2['id'])[0]
    erasure, _ = user.get(res=EraseBasic, item=erasure1['id'])
    assert len(erasure['steps']) == 2
    assert erasure['steps'][0]['startTime'] == '2018-06-01T08:15:00+00:00'
    assert erasure['steps'][0]['endTime'] == '2018-06-01T09:16:00+00:00'
    assert erasure['steps'][1]['startTime'] == '2018-06-01T08:16:00+00:00'
    assert erasure['steps'][1]['endTime'] == '2018-06-01T09:17:00+00:00'
    assert erasure['device']['id'] == storage['id']
    for step in erasure['steps']:
        assert step['type'] == 'StepZero'
        assert step['error'] is False
        assert step['secureRandomSteps'] == 1
        assert step['cleanWithZeros'] is True
        assert 'num' not in step
示例#10
0
def test_export_full_snapshot(user: UserClient):
    """
    Test a export device with all information and a lot of components
    """
    snapshot, _ = user.post(file('real-eee-1001pxd.snapshot.11'), res=Snapshot)
    csv_str, _ = user.get(res=documents.DocumentDef.t,
                          item='devices/',
                          accept='text/csv',
                          query=[('filter', {'type': ['Computer']})])
    f = StringIO(csv_str)
    obj_csv = csv.reader(f, f)
    export_csv = list(obj_csv)

    # Open fixture csv and transform to list
    with Path(__file__).parent.joinpath('files').joinpath('real-eee-1001pxd.csv').open() \
            as csv_file:
        obj_csv = csv.reader(csv_file)
        fixture_csv = list(obj_csv)

    assert isinstance(datetime.strptime(export_csv[1][8], '%c'), datetime), \
        'Register in field is not a datetime'

    # Pop dates fields from csv lists to compare them
    fixture_csv[1] = fixture_csv[1][:8] + fixture_csv[1][9:]
    export_csv[1] = export_csv[1][:8] + export_csv[1][9:]

    assert fixture_csv[0] == export_csv[0], 'Headers are not equal'
    assert fixture_csv[1] == export_csv[1], 'Computer information are not equal'
示例#11
0
def test_snapshot_post(user: UserClient):
    """
    Tests the post snapshot endpoint (validation, etc), data correctness,
    and relationship correctness.
    """
    snapshot = snapshot_and_check(user, file('basic.snapshot'),
                                  event_types=(
                                      WorkbenchRate.t,
                                      AggregateRate.t,
                                      BenchmarkProcessor.t
                                  ),
                                  perform_second_snapshot=False)
    assert snapshot['software'] == 'Workbench'
    assert snapshot['version'] == '11.0'
    assert snapshot['uuid'] == 'f5efd26e-8754-46bc-87bf-fbccc39d60d9'
    assert snapshot['elapsed'] == 4
    assert snapshot['author']['id'] == user.user['id']
    assert 'events' not in snapshot['device']
    assert 'author' not in snapshot['device']
    device, _ = user.get(res=m.Device, item=snapshot['device']['id'])
    key = itemgetter('serialNumber')
    snapshot['components'].sort(key=key)
    device['components'].sort(key=key)
    assert snapshot['components'] == device['components']

    assert {c['type'] for c in snapshot['components']} == {m.GraphicCard.t, m.RamModule.t,
                                                           m.Processor.t}
    rate = next(e for e in snapshot['events'] if e['type'] == WorkbenchRate.t)
    rate, _ = user.get(res=Event, item=rate['id'])
    assert rate['device']['id'] == snapshot['device']['id']
    rate['components'].sort(key=key)
    assert rate['components'] == snapshot['components']
    assert rate['snapshot']['id'] == snapshot['id']
示例#12
0
def test_bug_141(user: UserClient):
    """This test check one bug that create a problem when try to up one snapshot
       with a big number in the parameter command_timeout of the DataStorage

    """
    dev = file('2021-5-4-13-41_time_out_test_datastorage')
    user.post(dev, res=Snapshot)
示例#13
0
def test_erasure_certificate_public_one(user: UserClient, client: Client):
    """Public user can get certificate from one device as HTML or PDF."""
    s = file('erase-sectors.snapshot')
    snapshot, _ = user.post(s, res=e.Snapshot)

    doc, response = client.get(res=docs.DocumentDef.t,
                               item='erasures/{}'.format(snapshot['device']['id']),
                               accept=ANY)
    assert 'html' in response.content_type
    assert '<html' in doc
    assert '2018' in doc

    doc, response = client.get(res=docs.DocumentDef.t,
                               item='erasures/{}'.format(snapshot['device']['id']),
                               query=[('format', 'PDF')],
                               accept='application/pdf')
    assert 'application/pdf' == response.content_type

    erasure = next(e for e in snapshot['events'] if e['type'] == 'EraseSectors')

    doc, response = client.get(res=docs.DocumentDef.t,
                               item='erasures/{}'.format(erasure['id']),
                               accept=ANY)
    assert 'html' in response.content_type
    assert '<html' in doc
    assert '2018' in doc
示例#14
0
def test_device_public(user: UserClient, client: Client):
    s, _ = user.post(file('asus-eee-1000h.snapshot.11'), res=m.Snapshot)
    html, _ = client.get(res=d.Device,
                         item=s['device']['devicehubID'],
                         accept=ANY)
    assert 'intel atom cpu n270 @ 1.60ghz' in html
    assert '00:24:8C:7F:CF:2D – 100 Mbps' in html
示例#15
0
def test_rate_with_multiple_visual_tests(user: UserClient):
    """Perform a ComputerRate and then update the device with a new VisualTest.

    Devicehub must make the final rate with the first computer rate
    plus the new visual test, without considering the appearance /
    functionality values of the computer rate.
    """
    s = file('real-hp.snapshot.11')
    snapshot, _ = user.post(s, res=Snapshot)
    device, _ = user.get(res=Device, item=snapshot['device']['devicehubID'])
    visual_test = next(e for e in reversed(device['actions'])
                       if e['type'] == VisualTest.t)

    assert visual_test['appearanceRange'] == 'B'
    assert visual_test['functionalityRange'] == 'D'
    assert device['rate']['rating'] == 2

    # Adding new visual test
    user.post(
        {
            'type': 'VisualTest',
            'device': device['id'],
            'appearanceRange': 'A',
            'functionalityRange': 'A'
        },
        res=Action)
    device, _ = user.get(res=Device, item=snapshot['device']['devicehubID'])
    visual_test = next(e for e in reversed(device['actions'])
                       if e['type'] == VisualTest.t)

    assert visual_test['appearanceRange'] == 'A'
    assert visual_test['functionalityRange'] == 'A'
    assert device['rate']['rating'] == 3.7
示例#16
0
def test_hid_with_mac(app: Devicehub, user: UserClient):
    """Checks hid with mac."""
    snapshot = file('asus-eee-1000h.snapshot.11')
    snap, _ = user.post(snapshot, res=m.Snapshot)
    pc, _ = user.get(res=d.Device, item=snap['device']['devicehubID'])
    assert pc[
        'hid'] == 'laptop-asustek_computer_inc-1000h-94oaaq021116-00:24:8c:7f:cf:2d'
示例#17
0
def test_sync_execute_register_tag_linked_same_device():
    """
    If the tag is linked to the device, regardless if it has HID,
    the system should match the device through the tag.
    (If it has HID it validates both HID and tag point at the same
    device, this his checked in ).
    """
    orig_pc = Computer(**file('pc-components.db')['device'])
    db.session.add(Tag(id='foo', device=orig_pc))
    db.session.commit()

    pc = Computer(**file('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
    assert len(db_pc.tags) == 1
    assert next(iter(db_pc.tags)).id == 'foo'
示例#18
0
def test_snapshot_different_properties_same_tags(user: UserClient, tag_id: str):
    """Tests a snapshot performed to device 1 with tag A and then to
    device 2 with tag B. Both don't have HID but are different type.
    Devicehub must fail the Snapshot.
    """
    # 1. Upload PC1 without hid but with tag
    pc1 = file('basic.snapshot')
    pc1['device']['tags'] = [{'type': 'Tag', 'id': tag_id}]
    del pc1['device']['serialNumber']
    user.post(pc1, res=Snapshot)
    # 2. Upload PC2 without hid, a different characteristic than PC1, but with same tag
    pc2 = file('basic.snapshot')
    pc2['uuid'] = uuid4()
    pc2['device']['tags'] = pc1['device']['tags']
    # pc2 model is unknown but pc1 model is set = different property
    del pc2['device']['model']
    user.post(pc2, res=Snapshot, status=MismatchBetweenProperties)
示例#19
0
def test_snapshot_tag_inner_tag(tag_id: str, user: UserClient, app: Devicehub):
    """Tests a posting Snapshot with a local tag."""
    b = file('basic.snapshot')
    b['device']['tags'] = [{'type': 'Tag', 'id': tag_id}]
    snapshot_and_check(user, b, event_types=('WorkbenchRate', ))
    with app.app_context():
        tag, *_ = Tag.query.all()  # type: Tag
        assert tag.device_id == 1, 'Tag should be linked to the first device'
示例#20
0
def test_sync_execute_register_computer_new_computer_no_tag():
    """
    Syncs a new computer with HID and without a tag, creating it.
    :return:
    """
    # Case 1: device does not exist on DB
    pc = Computer(**file('pc-components.db')['device'])
    db_pc = Sync().execute_register(pc)
    assert pc.physical_properties == db_pc.physical_properties
示例#21
0
def test_test_data_storage(user: UserClient):
    """Tests a Snapshot with EraseSectors."""
    s = file('erase-sectors-2-hdd.snapshot')
    snapshot, _ = user.post(res=Snapshot, data=s)
    incidence_test = next(
        ev for ev in snapshot['events']
        if ev.get('reallocatedSectorCount', None) == 15
    )
    assert incidence_test['severity'] == 'Error'
示例#22
0
def test_sync_execute_register_tag_linked_other_device_mismatch_between_tags():
    """
    Checks that sync raises an error if finds that at least two passed-in
    tags are not linked to the same device.
    """
    pc1 = Computer(**file('pc-components.db')['device'])
    db.session.add(Tag(id='foo-1', device=pc1))
    pc2 = Computer(**file('pc-components.db')['device'])
    pc2.serial_number = 'pc2-serial'
    pc2.hid = Naming.hid(pc2.manufacturer, pc2.serial_number, pc2.model)
    db.session.add(Tag(id='foo-2', device=pc2))
    db.session.commit()

    pc1 = Computer(**file('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):
        Sync().execute_register(pc1)
示例#23
0
def test_device_query(user: UserClient):
    """Checks result of inventory."""
    user.post(conftest.file('basic.snapshot'), res=Snapshot)
    i, _ = user.get(res=Device)
    assert i['url'] == '/devices/'
    assert i['items'][0]['url'] == '/devices/1'
    pc = next(d for d in i['items'] if d['type'] == 'Desktop')
    assert len(pc['events']) == 4
    assert len(pc['components']) == 3
    assert not pc['tags']
示例#24
0
def test_snapshot_mobil(app: Devicehub, user: UserClient):
    """ This test check if the end_time != 0001-01-01 00:00:00+00:00
    and then we get a /devices, this create a crash
    """
    snapshot_file = file('mobil')
    snapshot, _ = user.post(res=Snapshot, data=snapshot_file)
    device, _ = user.get(res=m.Device, item=snapshot['device']['devicehubID'])

    tmp_snapshots = app.config['TMP_SNAPSHOTS']
    shutil.rmtree(tmp_snapshots)
示例#25
0
def test_sync_execute_register_mismatch_between_tags_and_hid():
    """
    Checks that sync raises an error if it finds that the HID does
    not point at the same device as the tag does.

    In this case we set HID -> pc1 but tag -> pc2
    """
    pc1 = Computer(**file('pc-components.db')['device'])
    db.session.add(Tag(id='foo-1', device=pc1))
    pc2 = Computer(**file('pc-components.db')['device'])
    pc2.serial_number = 'pc2-serial'
    pc2.hid = Naming.hid(pc2.manufacturer, pc2.serial_number, pc2.model)
    db.session.add(Tag(id='foo-2', device=pc2))
    db.session.commit()

    pc1 = Computer(**file('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)
示例#26
0
def test_sync_execute_register_tag_does_not_exist():
    """
    Ensures not being able to register if the tag does not exist,
    even if the device has HID or it existed before.

    Tags have to be created before trying to link them through a Snapshot.
    """
    pc = Computer(**file('pc-components.db')['device'], tags=OrderedSet([Tag()]))
    with raises(ResourceNotFound):
        Sync().execute_register(pc)
示例#27
0
def test_generic_event(event_model_state: Tuple[models.Event, states.Trading],
                       user: UserClient):
    """Tests POSTing all generic events."""
    event_model, state = event_model_state
    snapshot, _ = user.post(file('basic.snapshot'), res=models.Snapshot)
    event = {'type': event_model.t, 'devices': [snapshot['device']['id']]}
    event, _ = user.post(event, res=models.Event)
    assert event['devices'][0]['id'] == snapshot['device']['id']
    device, _ = user.get(res=Device, item=snapshot['device']['id'])
    assert device['events'][-1]['id'] == event['id']
    assert device['physical'] == state.name
示例#28
0
def test_sync_execute_register_computer_no_hid_no_tag():
    """
    Syncs a computer without HID and no tag.

    This should fail as we don't have a way to identify it.
    """
    pc = Computer(**file('pc-components.db')['device'])
    # 1: device has no HID
    pc.hid = pc.model = None
    with pytest.raises(NeedsId):
        Sync().execute_register(pc)
示例#29
0
def test_device_query_search_synonyms_intel(user: UserClient):
    s = file('real-hp.snapshot.11')
    s['device']['model'] = 'foo'  # The model had the word 'HP' in it
    user.post(s, res=Snapshot)
    i, _ = user.get(res=Device, query=[('search', 'hewlett packard')])
    assert 1 == len(i['items'])
    i, _ = user.get(res=Device, query=[('search', 'hewlett')])
    assert 1 == len(i['items'])
    i, _ = user.get(res=Device, query=[('search', 'hp')])
    assert 1 == len(i['items'])
    i, _ = user.get(res=Device, query=[('search', 'h.p')])
    assert 1 == len(i['items'])
示例#30
0
def test_get_devices_permissions(app: Devicehub, user: UserClient,
                                 user2: UserClient):
    """Checks GETting multiple devices."""

    user.post(file('asus-eee-1000h.snapshot.11'), res=m.Snapshot)
    url = '/devices/?filter={"type":["Computer"]}'

    devices, res = user.get(url, None)
    devices2, res2 = user2.get(url, None)
    assert res.status_code == 200
    assert res2.status_code == 200
    assert len(devices['items']) == 1
    assert len(devices2['items']) == 0