Add Smartphone; remove Inventory and use DeviceView

This commit is contained in:
Xavier Bustamante Talavera 2018-10-04 10:59:31 +02:00
parent 3bd4168174
commit 94c44e3480
15 changed files with 303 additions and 338 deletions

View file

@ -7,16 +7,16 @@ from teal.config import Config
from teal.enums import Currency
from teal.utils import import_resource
from ereuse_devicehub.resources import agent, device, event, inventory, lot, tag, user
from ereuse_devicehub.resources import agent, event, lot, tag, user
from ereuse_devicehub.resources.device import definitions
from ereuse_devicehub.resources.enums import PriceSoftware, RatingSoftware
class DevicehubConfig(Config):
RESOURCE_DEFINITIONS = set(chain(import_resource(device),
RESOURCE_DEFINITIONS = set(chain(import_resource(definitions),
import_resource(event),
import_resource(user),
import_resource(tag),
import_resource(inventory),
import_resource(agent),
import_resource(lot)))
PASSWORD_SCHEMES = {'pbkdf2_sha256'} # type: Set[str]

View file

@ -10,8 +10,8 @@ import yaml
from ereuse_devicehub.client import UserClient
from ereuse_devicehub.db import db
from ereuse_devicehub.resources.agent.models import Person
from ereuse_devicehub.resources.device.models import Device
from ereuse_devicehub.resources.event import models as m
from ereuse_devicehub.resources.inventory import Inventory
from ereuse_devicehub.resources.lot.models import Lot
from ereuse_devicehub.resources.tag.model import Tag
from ereuse_devicehub.resources.user import User
@ -102,14 +102,13 @@ class Dummy:
assert len(lot['devices'])
# Keep this at the bottom
inventory, _ = user.get(res=Inventory)
assert len(inventory['devices'])
assert len(inventory['lots'])
inventory, _ = user.get(res=Device)
assert len(inventory['items'])
i, _ = user.get(res=Inventory, query=[('search', 'intel')])
assert len(i['devices']) == 10
i, _ = user.get(res=Inventory, query=[('search', 'pc')])
assert len(i['devices']) == 11
i, _ = user.get(res=Device, query=[('search', 'intel')])
assert len(i['items']) == 10
i, _ = user.get(res=Device, query=[('search', 'pc')])
assert len(i['items']) == 11
print('⭐ Done.')
def user_client(self, email: str, password: str):

View file

@ -0,0 +1,14 @@
type: Snapshot
software: Web
version: '1.0'
device:
type: Smartphone
manufacturer: Apple
model: A1586
serialNumber: ABCDEF
imei: 35686800-004141-20
events:
- type: AppRate
appearanceRange: A
functionalityRange: B
labelling: False

View file

@ -1,146 +0,0 @@
from typing import Callable, Iterable, Tuple
from teal.resource import Converters, Resource
from ereuse_devicehub.resources.device import schemas
from ereuse_devicehub.resources.device.models import Manufacturer
from ereuse_devicehub.resources.device.views import DeviceView, ManufacturerView
class DeviceDef(Resource):
SCHEMA = schemas.Device
VIEW = DeviceView
ID_CONVERTER = Converters.int
AUTH = False # We manage this at each view
def __init__(self, app,
import_name=__name__, static_folder=None,
static_url_path=None,
template_folder='templates',
url_prefix=None,
subdomain=None,
url_defaults=None,
root_path=None,
cli_commands: Iterable[Tuple[Callable, str or None]] = tuple()):
super().__init__(app, import_name, static_folder, static_url_path, template_folder,
url_prefix, subdomain, url_defaults, root_path, cli_commands)
class ComputerDef(DeviceDef):
VIEW = None
SCHEMA = schemas.Computer
class DesktopDef(ComputerDef):
VIEW = None
SCHEMA = schemas.Desktop
class LaptopDef(ComputerDef):
VIEW = None
SCHEMA = schemas.Laptop
class ServerDef(ComputerDef):
VIEW = None
SCHEMA = schemas.Server
class MonitorDef(DeviceDef):
VIEW = None
SCHEMA = schemas.Monitor
class ComputerMonitorDef(MonitorDef):
VIEW = None
SCHEMA = schemas.ComputerMonitor
class TelevisionSetDef(MonitorDef):
VIEW = None
SCHEMA = schemas.TelevisionSet
class MobileDef(DeviceDef):
VIEW = None
SCHEMA = schemas.Mobile
class SmartphoneDef(MobileDef):
VIEW = None
SCHEMA = schemas.Smartphone
class TabletDef(MobileDef):
VIEW = None
SCHEMA = schemas.Tablet
class CellphoneDef(MobileDef):
VIEW = None
SCHEMA = schemas.Cellphone
class ComponentDef(DeviceDef):
VIEW = None
SCHEMA = schemas.Component
class GraphicCardDef(ComponentDef):
VIEW = None
SCHEMA = schemas.GraphicCard
class DataStorageDef(ComponentDef):
VIEW = None
SCHEMA = schemas.DataStorage
class HardDriveDef(DataStorageDef):
VIEW = None
SCHEMA = schemas.HardDrive
class SolidStateDriveDef(DataStorageDef):
VIEW = None
SCHEMA = schemas.SolidStateDrive
class MotherboardDef(ComponentDef):
VIEW = None
SCHEMA = schemas.Motherboard
class NetworkAdapterDef(ComponentDef):
VIEW = None
SCHEMA = schemas.NetworkAdapter
class RamModuleDef(ComponentDef):
VIEW = None
SCHEMA = schemas.RamModule
class ProcessorDef(ComponentDef):
VIEW = None
SCHEMA = schemas.Processor
class SoundCardDef(ComponentDef):
VIEW = None
SCHEMA = schemas.SoundCard
class DisplayDef(ComponentDef):
VIEW = None
SCHEMA = schemas.Display
class ManufacturerDef(Resource):
VIEW = ManufacturerView
SCHEMA = schemas.Manufacturer
AUTH = True
def init_db(self, db: 'db.SQLAlchemy'):
"""Loads the manufacturers to the database."""
Manufacturer.add_all_to_session(db.session)

View file

@ -0,0 +1,146 @@
from typing import Callable, Iterable, Tuple
from teal.resource import Converters, Resource
from ereuse_devicehub.resources.device import schemas
from ereuse_devicehub.resources.device.models import Manufacturer
from ereuse_devicehub.resources.device.views import DeviceView, ManufacturerView
class DeviceDef(Resource):
SCHEMA = schemas.Device
VIEW = DeviceView
ID_CONVERTER = Converters.int
AUTH = False # We manage this at each view
def __init__(self, app,
import_name=__name__, static_folder=None,
static_url_path=None,
template_folder='templates',
url_prefix=None,
subdomain=None,
url_defaults=None,
root_path=None,
cli_commands: Iterable[Tuple[Callable, str or None]] = tuple()):
super().__init__(app, import_name, static_folder, static_url_path, template_folder,
url_prefix, subdomain, url_defaults, root_path, cli_commands)
class ComputerDef(DeviceDef):
VIEW = None
SCHEMA = schemas.Computer
class DesktopDef(ComputerDef):
VIEW = None
SCHEMA = schemas.Desktop
class LaptopDef(ComputerDef):
VIEW = None
SCHEMA = schemas.Laptop
class ServerDef(ComputerDef):
VIEW = None
SCHEMA = schemas.Server
class MonitorDef(DeviceDef):
VIEW = None
SCHEMA = schemas.Monitor
class ComputerMonitorDef(MonitorDef):
VIEW = None
SCHEMA = schemas.ComputerMonitor
class TelevisionSetDef(MonitorDef):
VIEW = None
SCHEMA = schemas.TelevisionSet
class MobileDef(DeviceDef):
VIEW = None
SCHEMA = schemas.Mobile
class SmartphoneDef(MobileDef):
VIEW = None
SCHEMA = schemas.Smartphone
class TabletDef(MobileDef):
VIEW = None
SCHEMA = schemas.Tablet
class CellphoneDef(MobileDef):
VIEW = None
SCHEMA = schemas.Cellphone
class ComponentDef(DeviceDef):
VIEW = None
SCHEMA = schemas.Component
class GraphicCardDef(ComponentDef):
VIEW = None
SCHEMA = schemas.GraphicCard
class DataStorageDef(ComponentDef):
VIEW = None
SCHEMA = schemas.DataStorage
class HardDriveDef(DataStorageDef):
VIEW = None
SCHEMA = schemas.HardDrive
class SolidStateDriveDef(DataStorageDef):
VIEW = None
SCHEMA = schemas.SolidStateDrive
class MotherboardDef(ComponentDef):
VIEW = None
SCHEMA = schemas.Motherboard
class NetworkAdapterDef(ComponentDef):
VIEW = None
SCHEMA = schemas.NetworkAdapter
class RamModuleDef(ComponentDef):
VIEW = None
SCHEMA = schemas.RamModule
class ProcessorDef(ComponentDef):
VIEW = None
SCHEMA = schemas.Processor
class SoundCardDef(ComponentDef):
VIEW = None
SCHEMA = schemas.SoundCard
class DisplayDef(ComponentDef):
VIEW = None
SCHEMA = schemas.Display
class ManufacturerDef(Resource):
VIEW = ManufacturerView
SCHEMA = schemas.Manufacturer
AUTH = True
def init_db(self, db: 'db.SQLAlchemy'):
"""Loads the manufacturers to the database."""
Manufacturer.add_all_to_session(db.session)

View file

@ -241,7 +241,7 @@ class Mobile(Device):
@validates('imei')
def validate_imei(self, _, value: int):
if not imei.is_valid(value):
if not imei.is_valid(str(value)):
raise ValidationError('{} is not a valid imei.'.format(value))
@validates('meid')

View file

@ -104,13 +104,18 @@ class TelevisionSet(Monitor):
class Mobile(Device):
imei = Integer(validate=lambda x: imei.validate(str(x)),
description=m.Mobile.imei.comment)
meid = Str(validate=meid.validate, description=m.Mobile.meid.comment)
imei = Integer(description=m.Mobile.imei.comment)
meid = Str(description=m.Mobile.meid.comment)
@post_load
def convert_meid(self, data: dict):
if 'meid' in data:
@pre_load
def convert_check_imei(self, data):
if data.get('imei', None):
data['imei'] = int(imei.validate(data['imei']))
return data
@pre_load
def convert_check_meid(self, data: dict):
if data.get('meid', None):
data['meid'] = meid.compact(data['meid'])

View file

@ -4,14 +4,60 @@ import marshmallow
from flask import current_app as app, render_template, request
from flask.json import jsonify
from flask_sqlalchemy import Pagination
from marshmallow import fields as f, validate as v
from teal import query
from teal.cache import cache
from teal.resource import View
from ereuse_devicehub import auth
from ereuse_devicehub.db import db
from ereuse_devicehub.resources import search
from ereuse_devicehub.resources.device.models import Device, Manufacturer
from ereuse_devicehub.resources.device.search import DeviceSearch
from ereuse_devicehub.resources.event.models import Rate
from ereuse_devicehub.resources.tag.model import Tag
class OfType(f.Str):
def __init__(self, column: db.Column, *args, **kwargs):
super().__init__(*args, **kwargs)
self.column = column
def _deserialize(self, value, attr, data):
v = super()._deserialize(value, attr, data)
return self.column.in_(app.resources[v].subresources_types)
class RateQ(query.Query):
rating = query.Between(Rate.rating, f.Float())
appearance = query.Between(Rate.appearance, f.Float())
functionality = query.Between(Rate.functionality, f.Float())
class TagQ(query.Query):
id = query.Or(query.ILike(Tag.id), required=True)
org = query.ILike(Tag.org)
class Filters(query.Query):
type = query.Or(OfType(Device.type))
model = query.ILike(Device.model)
manufacturer = query.ILike(Device.manufacturer)
serialNumber = query.ILike(Device.serial_number)
rating = query.Join(Device.id == Rate.device_id, RateQ)
tag = query.Join(Device.id == Tag.id, TagQ)
class Sorting(query.Sort):
created = query.SortField(Device.created)
class DeviceView(View):
class FindArgs(marshmallow.Schema):
search = f.Str()
filter = f.Nested(Filters, missing=[])
sort = f.Nested(Sorting, missing=[])
page = f.Integer(validate=v.Range(min=1), missing=1)
def get(self, id):
"""
@ -48,7 +94,29 @@ class DeviceView(View):
@auth.Auth.requires_auth
def find(self, args: dict):
"""Gets many devices."""
return self.schema.jsonify(Device.query, many=True)
search_p = args.get('search', None)
query = Device.query
if search_p:
properties = DeviceSearch.properties
tags = DeviceSearch.tags
query = query.join(DeviceSearch).filter(
search.Search.match(properties, search_p) | search.Search.match(tags, search_p)
).order_by(
search.Search.rank(properties, search_p) + search.Search.rank(tags, search_p)
)
query = query.filter(*args['filter']).order_by(*args['sort'])
devices = query.paginate(page=args['page'], per_page=30) # type: Pagination
ret = {
'items': self.schema.dump(devices.items, many=True, nested=1),
# todo pagination should be in Header like github
# https://developer.github.com/v3/guides/traversing-with-pagination/
'pagination': {
'page': devices.page,
'perPage': devices.per_page,
'total': devices.total
}
}
return jsonify(ret)
class ManufacturerView(View):

View file

@ -1,125 +0,0 @@
from flask import current_app as app, jsonify
from flask_sqlalchemy import Pagination
from marshmallow import Schema as MarshmallowSchema
from marshmallow.fields import Float, Integer, Nested, Str
from marshmallow.validate import Range
from sqlalchemy import Column
from teal.query import Between, ILike, Join, Or, Query, Sort, SortField
from teal.resource import Resource, View
from ereuse_devicehub.resources import search
from ereuse_devicehub.resources.device.models import Device
from ereuse_devicehub.resources.device.search import DeviceSearch
from ereuse_devicehub.resources.event.models import Rate
from ereuse_devicehub.resources.lot.models import Lot
from ereuse_devicehub.resources.schemas import Thing
from ereuse_devicehub.resources.tag import Tag
class Inventory(Thing):
pass
class RateQ(Query):
rating = Between(Rate.rating, Float())
appearance = Between(Rate.appearance, Float())
functionality = Between(Rate.functionality, Float())
class TagQ(Query):
id = Or(ILike(Tag.id), required=True)
org = ILike(Tag.org)
class OfType(Str):
def __init__(self, column: Column, *args, **kwargs):
super().__init__(*args, **kwargs)
self.column = column
def _deserialize(self, value, attr, data):
v = super()._deserialize(value, attr, data)
return self.column.in_(app.resources[v].subresources_types)
class Filters(Query):
type = Or(OfType(Device.type))
model = ILike(Device.model)
manufacturer = ILike(Device.manufacturer)
serialNumber = ILike(Device.serial_number)
rating = Join(Device.id == Rate.device_id, RateQ)
tag = Join(Device.id == Tag.id, TagQ)
class Sorting(Sort):
created = SortField(Device.created)
class InventoryView(View):
class FindArgs(MarshmallowSchema):
search = Str()
filter = Nested(Filters, missing=[])
sort = Nested(Sorting, missing=[Device.created.desc()])
page = Integer(validate=Range(min=1), missing=1)
def get(self, id):
"""Inventory view
---
description: Supports the inventory view of ``devicehub-client``; returns
all the devices, groups and widgets of this Devicehub instance.
responses:
200:
description: The inventory.
schema:
type: object
properties:
devices:
type: array
items:
$ref: '#/definitions/Device'
pagination:
type: object
properties:
page:
type: integer
minimum: 0
perPage:
type: integer
minimum: 0
total:
type: integer
minimum: 0
"""
# todo .format(yaml.load(schema2parameters(self.FindArgs, default_in='path', name='path')))
return super().get(id)
def find(self, args: dict):
"""See :meth:`.get` above."""
search_p = args.get('search', None)
query = Device.query
if search_p:
properties = DeviceSearch.properties
tags = DeviceSearch.tags
query = query.join(DeviceSearch).filter(
search.Search.match(properties, search_p) | search.Search.match(tags, search_p)
).order_by(
search.Search.rank(properties, search_p) + search.Search.rank(tags, search_p)
)
query = query.filter(*args['filter']).order_by(*args['sort'])
devices = query.paginate(page=args['page'], per_page=30) # type: Pagination
inventory = {
'devices': app.resources[Device.t].schema.dump(devices.items, many=True, nested=1),
'lots': app.resources[Lot.t].schema.dump(Lot.roots(), many=True, nested=1),
'widgets': {},
'pagination': {
'page': devices.page,
'perPage': devices.per_page,
'total': devices.total,
}
}
return jsonify(inventory)
class InventoryDef(Resource):
SCHEMA = Inventory
VIEW = InventoryView
AUTH = True

View file

@ -7,7 +7,7 @@ from teal.resource import Converters, Resource
from teal.teal import Teal
from ereuse_devicehub.db import db
from ereuse_devicehub.resources.device import DeviceDef
from ereuse_devicehub.resources.device.definitions import DeviceDef
from ereuse_devicehub.resources.tag import schema
from ereuse_devicehub.resources.tag.model import Tag
from ereuse_devicehub.resources.tag.view import TagDeviceView, TagView, get_device_from_tag

View file

@ -0,0 +1 @@
../../ereuse_devicehub/dummy/files/smartphone.snapshot.yaml

View file

@ -17,7 +17,6 @@ def test_api_docs(client: Client):
docs, _ = client.get('/apidocs')
assert set(docs['paths'].keys()) == {
# todo this does not appear: '/tags/{id}/device',
'/inventories/',
'/apidocs',
'/users/',
'/devices/',
@ -40,4 +39,4 @@ def test_api_docs(client: Client):
'scheme': 'basic',
'name': 'Authorization'
}
assert 78 == len(docs['definitions'])
assert 77 == len(docs['definitions'])

View file

@ -24,7 +24,6 @@ from ereuse_devicehub.resources.device.sync import MismatchBetweenTags, Mismatch
from ereuse_devicehub.resources.enums import ComputerChassis, DisplayTech
from ereuse_devicehub.resources.event import models as m
from ereuse_devicehub.resources.event.models import Remove, Test
from ereuse_devicehub.resources.inventory import Inventory
from ereuse_devicehub.resources.tag.model import Tag
from ereuse_devicehub.resources.user import User
from tests import conftest
@ -423,8 +422,8 @@ def test_get_devices(app: Devicehub, user: UserClient):
db.session.add_all((pc, pc1, pc2))
db.session.commit()
devices, _ = user.get(res=Device)
assert tuple(d['id'] for d in devices) == (1, 2, 3, 4, 5)
assert tuple(d['type'] for d in devices) == (
assert tuple(d['id'] for d in devices['items']) == (1, 2, 3, 4, 5)
assert tuple(d['type'] for d in devices['items']) == (
'Desktop', 'Desktop', 'Laptop', 'NetworkAdapter', 'GraphicCard'
)
@ -463,12 +462,12 @@ def test_device_search_all_devices_token_if_empty(app: Devicehub, user: UserClie
with app.app_context():
app.db.session.execute('TRUNCATE TABLE {}'.format(DeviceSearch.__table__.name))
app.db.session.commit()
i, _ = user.get(res=Inventory, query=[('search', 'Desktop')])
assert not len(i['devices'])
i, _ = user.get(res=Device, query=[('search', 'Desktop')])
assert not len(i['items'])
with app.app_context():
DeviceSearch.set_all_devices_tokens_if_empty(app.db.session)
i, _ = user.get(res=Inventory, query=[('search', 'Desktop')])
assert not len(i['devices'])
i, _ = user.get(res=Device, query=[('search', 'Desktop')])
assert not len(i['items'])
def test_manufacturer(user: UserClient):

View file

@ -5,15 +5,15 @@ 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.views import Filters, Sorting
from ereuse_devicehub.resources.enums import ComputerChassis
from ereuse_devicehub.resources.event.models import Snapshot
from ereuse_devicehub.resources.inventory import Filters, Inventory, Sorting
from tests import conftest
from tests.conftest import file
@pytest.mark.usefixtures(conftest.app_context.__name__)
def test_inventory_filters():
def test_device_filters():
schema = Filters()
q = schema.load({
'type': ['Computer', 'Laptop'],
@ -45,14 +45,14 @@ def test_inventory_filters():
@pytest.mark.usefixtures(conftest.app_context.__name__)
def test_inventory_sort():
def test_device_sort():
schema = Sorting()
r = next(schema.load({'created': True}))
assert str(r) == 'device.created ASC'
@pytest.fixture()
def inventory_query_dummy(app: Devicehub):
def device_query_dummy(app: Devicehub):
with app.app_context():
devices = ( # The order matters ;-)
Desktop(serial_number='s1',
@ -75,72 +75,72 @@ def inventory_query_dummy(app: Devicehub):
db.session.commit()
@pytest.mark.usefixtures(inventory_query_dummy.__name__)
def test_inventory_query_no_filters(user: UserClient):
i, _ = user.get(res=Inventory)
assert tuple(d['type'] for d in i['devices']) == (
'SolidStateDrive', 'Desktop', 'Laptop', 'Desktop'
@pytest.mark.usefixtures(device_query_dummy.__name__)
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'
)
@pytest.mark.usefixtures(inventory_query_dummy.__name__)
def test_inventory_query_filter_type(user: UserClient):
i, _ = user.get(res=Inventory, query=[('filter', {'type': ['Desktop', 'Laptop']})])
assert tuple(d['type'] for d in i['devices']) == ('Desktop', 'Laptop', 'Desktop')
@pytest.mark.usefixtures(device_query_dummy.__name__)
def test_device_query_filter_type(user: UserClient):
i, _ = user.get(res=Device, query=[('filter', {'type': ['Desktop', 'Laptop']})])
assert tuple(d['type'] for d in i['items']) == ('Desktop', 'Laptop', 'Desktop')
@pytest.mark.usefixtures(inventory_query_dummy.__name__)
def test_inventory_query_filter_sort(user: UserClient):
i, _ = user.get(res=Inventory, query=[
@pytest.mark.usefixtures(device_query_dummy.__name__)
def test_device_query_filter_sort(user: UserClient):
i, _ = user.get(res=Device, query=[
('sort', {'created': Sorting.ASCENDING}),
('filter', {'type': ['Computer']})
])
assert tuple(d['type'] for d in i['devices']) == ('Desktop', 'Laptop', 'Desktop')
assert tuple(d['type'] for d in i['items']) == ('Desktop', 'Laptop', 'Desktop')
def test_inventory_query(user: UserClient):
def test_device_query(user: UserClient):
"""Checks result of inventory."""
user.post(conftest.file('basic.snapshot'), res=Snapshot)
i, _ = user.get(res=Inventory)
pc = next(d for d in i['devices'] if d['type'] == 'Desktop')
i, _ = user.get(res=Device)
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']
@pytest.mark.xfail(reason='Functionality not yet developed.')
def test_inventory_lots_query(user: UserClient):
def test_device_lots_query(user: UserClient):
pass
def test_inventory_query_search(user: UserClient):
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=Inventory, query=[('search', 'desktop')])
assert i['devices'][0]['id'] == 1
i, _ = user.get(res=Inventory, query=[('search', 'intel')])
assert len(i['devices']) == 1
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
@pytest.mark.xfail(reason='No dictionary yet that knows asustek = asus')
def test_inventory_query_search_synonyms_asus(user: UserClient):
def test_device_query_search_synonyms_asus(user: UserClient):
user.post(file('real-eee-1001pxd.snapshot.11'), res=Snapshot)
i, _ = user.get(res=Inventory, query=[('search', 'asustek')])
assert len(i['devices']) == 1
i, _ = user.get(res=Inventory, query=[('search', 'asus')])
assert len(i['devices']) == 1
i, _ = user.get(res=Device, query=[('search', 'asustek')])
assert len(i['items']) == 1
i, _ = user.get(res=Device, query=[('search', 'asus')])
assert len(i['items']) == 1
@pytest.mark.xfail(reason='No dictionary yet that knows hp = hewlett packard')
def test_inventory_query_search_synonyms_intel(user: UserClient):
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=Inventory, query=[('search', 'hewlett packard')])
assert len(i['devices']) == 1
i, _ = user.get(res=Inventory, query=[('search', 'hewlett')])
assert len(i['devices']) == 1
i, _ = user.get(res=Inventory, query=[('search', 'hp')])
assert len(i['devices']) == 1
i, _ = user.get(res=Device, query=[('search', 'hewlett packard')])
assert len(i['items']) == 1
i, _ = user.get(res=Device, query=[('search', 'hewlett')])
assert len(i['items']) == 1
i, _ = user.get(res=Device, query=[('search', 'hp')])
assert len(i['items']) == 1

View file

@ -328,6 +328,11 @@ def test_snapshot_computer_monitor(user: UserClient):
snapshot_and_check(user, s, event_types=('AppRate',))
def test_snapshot_mobile_smartphone(user: UserClient):
s = file('smartphone.snapshot')
snapshot_and_check(user, s, event_types=('AppRate',))
def test_snapshot_components_none():
"""
Tests that a snapshot without components does not