Merge remote-tracking branch 'origin/master' into reports

This commit is contained in:
JNadeu 2018-10-23 17:37:43 +02:00
commit cad0b64125
30 changed files with 725 additions and 182 deletions

View File

@ -17,6 +17,12 @@
"elapsed": 19, "elapsed": 19,
"rate": 19.3106, "rate": 19.3106,
"type": "BenchmarkRamSysbench" "type": "BenchmarkRamSysbench"
},
{
"appearanceRange": "A",
"biosRange": "A",
"functionalityRange": "A",
"type": "WorkbenchRate"
} }
], ],
"manufacturer": "ASUSTeK Computer INC." "manufacturer": "ASUSTeK Computer INC."

View File

@ -12,6 +12,12 @@
"error": false, "error": false,
"type": "StressTest", "type": "StressTest",
"elapsed": 60 "elapsed": 60
},
{
"appearanceRange": "A",
"biosRange": "A",
"functionalityRange": "A",
"type": "WorkbenchRate"
} }
], ],
"type": "Desktop", "type": "Desktop",

View File

@ -0,0 +1,14 @@
type: Snapshot
version: '1.0'
software: Web
device:
type: Keyboard
model: FOO
serialNumber: BAR
manufacturer: BAZ
layout: ES
events:
- type: ManualRate
appearanceRange: A
functionalityRange: A
labelling: False

View File

@ -14,6 +14,12 @@
"rate": 0.9323, "rate": 0.9323,
"elapsed": 1, "elapsed": 1,
"type": "BenchmarkRamSysbench" "type": "BenchmarkRamSysbench"
},
{
"appearanceRange": "B",
"biosRange": "A",
"functionalityRange": "C",
"type": "WorkbenchRate"
} }
], ],
"type": "Desktop", "type": "Desktop",

View File

@ -145,6 +145,12 @@
"type": "StressTest", "type": "StressTest",
"error": false, "error": false,
"elapsed": 60 "elapsed": 60
},
{
"appearanceRange": "B",
"biosRange": "C",
"functionalityRange": "A",
"type": "WorkbenchRate"
} }
] ]
}, },

View File

@ -148,6 +148,12 @@
"rate": 0.9759, "rate": 0.9759,
"type": "BenchmarkRamSysbench", "type": "BenchmarkRamSysbench",
"elapsed": 1 "elapsed": 1
},
{
"appearanceRange": "B",
"biosRange": "A",
"functionalityRange": "D",
"type": "WorkbenchRate"
} }
], ],
"serialNumber": "CZC0408YJG", "serialNumber": "CZC0408YJG",

View File

@ -161,6 +161,121 @@ class DisplayDef(ComponentDef):
SCHEMA = schemas.Display SCHEMA = schemas.Display
class ComputerAccessoryDef(DeviceDef):
VIEW = None
SCHEMA = schemas.ComputerAccessory
def __init__(self, app, import_name=__name__, static_folder=None, static_url_path=None,
template_folder=None, 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 MouseDef(ComputerAccessoryDef):
VIEW = None
SCHEMA = schemas.Mouse
class KeyboardDef(ComputerAccessoryDef):
VIEW = None
SCHEMA = schemas.Keyboard
class SAIDef(ComputerAccessoryDef):
VIEW = None
SCHEMA = schemas.SAI
class MemoryCardReaderDef(ComputerAccessoryDef):
VIEW = None
SCHEMA = schemas.MemoryCardReader
class NetworkingDef(DeviceDef):
VIEW = None
SCHEMA = schemas.Networking
def __init__(self, app, import_name=__name__, static_folder=None, static_url_path=None,
template_folder=None, 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 RouterDef(NetworkingDef):
VIEW = None
SCHEMA = schemas.Router
class SwitchDef(NetworkingDef):
VIEW = None
SCHEMA = schemas.Switch
class HubDef(NetworkingDef):
VIEW = None
SCHEMA = schemas.Hub
class WirelessAccessPointDef(NetworkingDef):
VIEW = None
SCHEMA = schemas.WirelessAccessPoint
class PrinterDef(DeviceDef):
VIEW = None
SCHEMA = schemas.Printer
def __init__(self, app, import_name=__name__, static_folder=None, static_url_path=None,
template_folder=None, 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 LabelPrinterDef(PrinterDef):
VIEW = None
SCHEMA = schemas.LabelPrinter
class SoundDef(DeviceDef):
VIEW = None
SCHEMA = schemas.Sound
def __init__(self, app, import_name=__name__, static_folder=None, static_url_path=None,
template_folder=None, 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 MicrophoneDef(SoundDef):
VIEW = None
SCHEMA = schemas.Microphone
class VideoDef(DeviceDef):
VIEW = None
SCHEMA = schemas.Video
def __init__(self, app, import_name=__name__, static_folder=None, static_url_path=None,
template_folder=None, 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 VideoScalerDef(VideoDef):
VIEW = None
SCHEMA = schemas.VideoScaler
class VideoconferenceDef(VideoDef):
VIEW = None
SCHEMA = schemas.Videoconference
class ManufacturerDef(Resource): class ManufacturerDef(Resource):
VIEW = ManufacturerView VIEW = ManufacturerView
SCHEMA = schemas.Manufacturer SCHEMA = schemas.Manufacturer

View File

@ -17,12 +17,13 @@ from sqlalchemy_utils import ColorType
from stdnum import imei, meid from stdnum import imei, meid
from teal.db import CASCADE, POLYMORPHIC_ID, POLYMORPHIC_ON, ResourceNotFound, URL, check_lower, \ from teal.db import CASCADE, POLYMORPHIC_ID, POLYMORPHIC_ON, ResourceNotFound, URL, check_lower, \
check_range check_range
from teal.enums import Layouts
from teal.marshmallow import ValidationError from teal.marshmallow import ValidationError
from teal.resource import url_for_resource from teal.resource import url_for_resource
from ereuse_devicehub.db import db from ereuse_devicehub.db import db
from ereuse_devicehub.resources.enums import ComputerChassis, DataStorageInterface, \ from ereuse_devicehub.resources.enums import ComputerChassis, DataStorageInterface, \
DataStoragePrivacyCompliance, DisplayTech, RamFormat, RamInterface DataStoragePrivacyCompliance, DisplayTech, PrinterTechnology, RamFormat, RamInterface
from ereuse_devicehub.resources.models import STR_SM_SIZE, Thing from ereuse_devicehub.resources.models import STR_SM_SIZE, Thing
@ -62,6 +63,19 @@ class Device(Thing):
""" """
color = Column(ColorType) color = Column(ColorType)
color.comment = """The predominant color of the device.""" color.comment = """The predominant color of the device."""
production_date = Column(db.TIMESTAMP(timezone=True))
production_date.comment = """The date of production of the item."""
_NON_PHYSICAL_PROPS = {
'id',
'type',
'created',
'updated',
'parent_id',
'hid',
'production_date',
'color'
}
@property @property
def events(self) -> list: def events(self) -> list:
@ -94,7 +108,7 @@ class Device(Thing):
for c in inspect(self.__class__).attrs for c in inspect(self.__class__).attrs
if isinstance(c, ColumnProperty) if isinstance(c, ColumnProperty)
and not getattr(c, 'foreign_keys', None) and not getattr(c, 'foreign_keys', None)
and c.key not in {'id', 'type', 'created', 'updated', 'parent_id', 'hid'}} and c.key not in self._NON_PHYSICAL_PROPS}
@property @property
def url(self) -> urlutils.URL: def url(self) -> urlutils.URL:
@ -194,6 +208,11 @@ class Device(Thing):
class DisplayMixin: class DisplayMixin:
"""
Aspect ratio can be computed as in
https://github.com/mirukan/whratio/blob/master/whratio/ratio.py and
could be a future property.
"""
size = Column(Float(decimal_return_scale=2), check_range('size', 2, 150)) size = Column(Float(decimal_return_scale=2), check_range('size', 2, 150))
size.comment = """ size.comment = """
The size of the monitor in inches. The size of the monitor in inches.
@ -212,6 +231,10 @@ class DisplayMixin:
The maximum vertical resolution the monitor can natively support The maximum vertical resolution the monitor can natively support
in pixels. in pixels.
""" """
refresh_rate = Column(SmallInteger, check_range('refresh_rate', 10, 1000))
contrast_ratio = Column(SmallInteger, check_range('contrast_ratio', 100, 100000))
touchable = Column(Boolean, nullable=False, default=False)
touchable.comment = """Whether it is a touchscreen."""
def __format__(self, format_spec: str) -> str: def __format__(self, format_spec: str) -> str:
v = '' v = ''
@ -226,6 +249,10 @@ class Computer(Device):
id = Column(BigInteger, ForeignKey(Device.id), primary_key=True) id = Column(BigInteger, ForeignKey(Device.id), primary_key=True)
chassis = Column(DBEnum(ComputerChassis), nullable=False) chassis = Column(DBEnum(ComputerChassis), nullable=False)
def __init__(self, chassis, **kwargs) -> None:
chassis = ComputerChassis(chassis)
super().__init__(chassis=chassis, **kwargs)
@property @property
def events(self) -> list: def events(self) -> list:
return sorted(chain(super().events, self.events_parent), key=attrgetter('created')) return sorted(chain(super().events, self.events_parent), key=attrgetter('created'))
@ -285,7 +312,9 @@ class Desktop(Computer):
class Laptop(Computer): class Laptop(Computer):
pass layout = Column(DBEnum(Layouts))
layout.comment = """Layout of a built-in keyboard of the computer,
if any."""
class Server(Computer): class Server(Computer):
@ -304,6 +333,10 @@ class TelevisionSet(Monitor):
pass pass
class Projector(Monitor):
pass
class Mobile(Device): class Mobile(Device):
id = Column(BigInteger, ForeignKey(Device.id), primary_key=True) id = Column(BigInteger, ForeignKey(Device.id), primary_key=True)
imei = Column(BigInteger) imei = Column(BigInteger)
@ -479,6 +512,83 @@ class Display(JoinedComponentTableMixin, DisplayMixin, Component):
pass pass
class ComputerAccessory(Device):
id = Column(BigInteger, ForeignKey(Device.id), primary_key=True)
pass
class SAI(ComputerAccessory):
pass
class Keyboard(ComputerAccessory):
layout = Column(DBEnum(Layouts)) # If we want to do it not null
class Mouse(ComputerAccessory):
pass
class MemoryCardReader(ComputerAccessory):
pass
class Networking(NetworkMixin, Device):
id = Column(BigInteger, ForeignKey(Device.id), primary_key=True)
class Router(Networking):
pass
class Switch(Networking):
pass
class Hub(Networking):
pass
class WirelessAccessPoint(Networking):
pass
class Printer(Device):
id = Column(BigInteger, ForeignKey(Device.id), primary_key=True)
wireless = Column(Boolean, nullable=False, default=False)
wireless.comment = """Whether it is a wireless printer."""
scanning = Column(Boolean, nullable=False, default=False)
scanning.comment = """Whether the printer has scanning capabilities."""
technology = Column(DBEnum(PrinterTechnology))
technology.comment = """Technology used to print."""
monochrome = Column(Boolean, nullable=False, default=True)
monochrome.comment = """Whether the printer is only monochrome."""
class LabelPrinter(Printer):
pass
class Sound(Device):
pass
class Microphone(Sound):
pass
class Video(Device):
pass
class VideoScaler(Video):
pass
class Videoconference(Video):
pass
class Manufacturer(db.Model): class Manufacturer(db.Model):
__table_args__ = {'schema': 'common'} __table_args__ = {'schema': 'common'}
CSV_DELIMITER = csv.get_dialect('excel').delimiter CSV_DELIMITER = csv.get_dialect('excel').delimiter

View File

@ -1,3 +1,4 @@
from datetime import datetime
from typing import Dict, List, Set, Type, Union from typing import Dict, List, Set, Type, Union
from boltons import urlutils from boltons import urlutils
@ -6,11 +7,12 @@ from colour import Color
from sqlalchemy import Column, Integer from sqlalchemy import Column, Integer
from sqlalchemy.orm import relationship from sqlalchemy.orm import relationship
from teal.db import Model from teal.db import Model
from teal.enums import Layouts
from ereuse_devicehub.resources.agent.models import Agent from ereuse_devicehub.resources.agent.models import Agent
from ereuse_devicehub.resources.device import states from ereuse_devicehub.resources.device import states
from ereuse_devicehub.resources.enums import ComputerChassis, DataStorageInterface, \ from ereuse_devicehub.resources.enums import ComputerChassis, DataStorageInterface, \
DataStoragePrivacyCompliance, DisplayTech, RamFormat, RamInterface DataStoragePrivacyCompliance, DisplayTech, PrinterTechnology, RamFormat, RamInterface
from ereuse_devicehub.resources.event import models as e from ereuse_devicehub.resources.event import models as e
from ereuse_devicehub.resources.image.models import ImageList from ereuse_devicehub.resources.image.models import ImageList
from ereuse_devicehub.resources.lot.models import Lot from ereuse_devicehub.resources.lot.models import Lot
@ -31,6 +33,7 @@ class Device(Thing):
depth = ... # type: Column depth = ... # type: Column
color = ... # type: Column color = ... # type: Column
lots = ... # type: relationship lots = ... # type: relationship
production_date = ... # type: Column
def __init__(self, **kwargs) -> None: def __init__(self, **kwargs) -> None:
super().__init__(**kwargs) super().__init__(**kwargs)
@ -52,6 +55,7 @@ class Device(Thing):
self.images = ... # type: ImageList self.images = ... # type: ImageList
self.tags = ... # type: Set[Tag] self.tags = ... # type: Set[Tag]
self.lots = ... # type: Set[Lot] self.lots = ... # type: Set[Lot]
self.production_date = ... # type: datetime
@property @property
def url(self) -> urlutils.URL: def url(self) -> urlutils.URL:
@ -86,6 +90,9 @@ class DisplayMixin:
size = ... # type: Column size = ... # type: Column
resolution_width = ... # type: Column resolution_width = ... # type: Column
resolution_height = ... # type: Column resolution_height = ... # type: Column
refresh_rate = ... # type: Column
contrast_ratio = ... # type: Column
touchable = ... # type: Column
def __init__(self) -> None: def __init__(self) -> None:
super().__init__() super().__init__()
@ -93,6 +100,9 @@ class DisplayMixin:
self.size = ... # type: Integer self.size = ... # type: Integer
self.resolution_width = ... # type: int self.resolution_width = ... # type: int
self.resolution_height = ... # type: int self.resolution_height = ... # type: int
self.refresh_rate = ... # type: int
self.contrast_ratio = ... # type: int
self.touchable = ... # type: bool
class Computer(DisplayMixin, Device): class Computer(DisplayMixin, Device):
@ -135,7 +145,11 @@ class Desktop(Computer):
class Laptop(Computer): class Laptop(Computer):
pass layout = ... # type: Column
def __init__(self, **kwargs) -> None:
super().__init__(**kwargs)
self.layout = ... # type: Layouts
class Server(Computer): class Server(Computer):
@ -233,12 +247,18 @@ class Motherboard(Component):
self.pcmcia = ... # type: int self.pcmcia = ... # type: int
class NetworkAdapter(Component): class NetworkMixin:
speed = ... # type: Column speed = ... # type: Column
wireless = ... # type: Column
def __init__(self, **kwargs) -> None: def __init__(self, **kwargs) -> None:
super().__init__(**kwargs) super().__init__(**kwargs)
self.speed = ... # type: int self.speed = ... # type: int
self.wireless = ... # type: bool
class NetworkAdapter(NetworkMixin, Component):
pass
class Processor(Component): class Processor(Component):
@ -271,6 +291,88 @@ class Display(DisplayMixin, Component):
pass pass
class ComputerAccessory(Device):
pass
class SAI(ComputerAccessory):
pass
class Keyboard(ComputerAccessory):
layout = ... # type: Column
def __init__(self, layout: Layouts, **kwargs):
super().__init__(**kwargs)
self.layout = ... # type: Layouts
class Mouse(ComputerAccessory):
pass
class MemoryCardReader(ComputerAccessory):
pass
class Networking(NetworkMixin, Device):
pass
class Router(Networking):
pass
class Switch(Networking):
pass
class Hub(Networking):
pass
class WirelessAccessPoint(Networking):
pass
class Printer(Device):
wireless = ... # type: Column
scanning = ... # type: Column
technology = ... # type: Column
monochrome = ... # type: Column
def __init__(self, **kwargs) -> None:
super().__init__(**kwargs)
self.wireless = ... # type: bool
self.scanning = ... # type: bool
self.technology = ... # type: PrinterTechnology
self.monochrome = ... # type: bool
class LabelPrinter(Printer):
pass
class Sound(Device):
pass
class Microphone(Sound):
pass
class Video(Device):
pass
class VideoScaler(Video):
pass
class Videoconference(Video):
pass
class Manufacturer(Model): class Manufacturer(Model):
CUSTOM_MANUFACTURERS = ... # type: set CUSTOM_MANUFACTURERS = ... # type: set
name = ... # type: Column name = ... # type: Column

View File

@ -1,15 +1,16 @@
from marshmallow import post_load, pre_load from marshmallow import post_load, pre_load
from marshmallow.fields import Boolean, Float, Integer, List, Str, String from marshmallow.fields import Boolean, DateTime, Float, Integer, List, Str, String
from marshmallow.validate import Length, OneOf, Range from marshmallow.validate import Length, OneOf, Range
from sqlalchemy.util import OrderedSet from sqlalchemy.util import OrderedSet
from stdnum import imei, meid from stdnum import imei, meid
from teal.enums import Layouts
from teal.marshmallow import EnumField, SanitizedStr, URL, ValidationError from teal.marshmallow import EnumField, SanitizedStr, URL, ValidationError
from teal.resource import Schema from teal.resource import Schema
from ereuse_devicehub.marshmallow import NestedOn from ereuse_devicehub.marshmallow import NestedOn
from ereuse_devicehub.resources.device import models as m, states from ereuse_devicehub.resources.device import models as m, states
from ereuse_devicehub.resources.enums import ComputerChassis, DataStorageInterface, \ from ereuse_devicehub.resources.enums import ComputerChassis, DataStorageInterface, \
DataStoragePrivacyCompliance, DisplayTech, RamFormat, RamInterface DataStoragePrivacyCompliance, DisplayTech, PrinterTechnology, RamFormat, RamInterface
from ereuse_devicehub.resources.models import STR_BIG_SIZE, STR_SIZE from ereuse_devicehub.resources.models import STR_BIG_SIZE, STR_SIZE
from ereuse_devicehub.resources.schemas import Thing, UnitCodes from ereuse_devicehub.resources.schemas import Thing, UnitCodes
@ -40,6 +41,9 @@ class Device(Thing):
trading = EnumField(states.Trading, dump_only=True, description=m.Device.trading.__doc__) trading = EnumField(states.Trading, dump_only=True, description=m.Device.trading.__doc__)
physical = EnumField(states.Physical, dump_only=True, description=m.Device.physical.__doc__) physical = EnumField(states.Physical, dump_only=True, description=m.Device.physical.__doc__)
physical_possessor = NestedOn('Agent', dump_only=True, data_key='physicalPossessor') physical_possessor = NestedOn('Agent', dump_only=True, data_key='physicalPossessor')
production_date = DateTime('iso',
description=m.Device.updated.comment,
data_key='productionDate')
@pre_load @pre_load
def from_events_to_events_one(self, data: dict): def from_events_to_events_one(self, data: dict):
@ -98,6 +102,9 @@ class DisplayMixin:
resolution_height = Integer(data_key='resolutionHeight', resolution_height = Integer(data_key='resolutionHeight',
validate=Range(10, 20000), validate=Range(10, 20000),
description=m.DisplayMixin.resolution_height.comment) description=m.DisplayMixin.resolution_height.comment)
refresh_rate = Integer(data_key='refreshRate', validate=Range(10, 1000))
contrast_ratio = Integer(data_key='contrastRatio', validate=Range(100, 100000))
touchable = Boolean(missing=False, description=m.DisplayMixin.touchable.comment)
class NetworkMixin: class NetworkMixin:
@ -212,3 +219,74 @@ class Manufacturer(Schema):
name = String(dump_only=True) name = String(dump_only=True)
url = URL(dump_only=True) url = URL(dump_only=True)
logo = URL(dump_only=True) logo = URL(dump_only=True)
class ComputerAccessory(Device):
pass
class Mouse(ComputerAccessory):
pass
class MemoryCardReader(ComputerAccessory):
pass
class SAI(ComputerAccessory):
pass
class Keyboard(ComputerAccessory):
layout = EnumField(Layouts)
class Networking(NetworkMixin, Device):
pass
class Router(Networking):
pass
class Switch(Networking):
pass
class Hub(Networking):
pass
class WirelessAccessPoint(Networking):
pass
class Printer(Device):
wireless = Boolean(required=True, missing=False)
scanning = Boolean(required=True, missing=False)
technology = EnumField(PrinterTechnology, required=True)
monochrome = Boolean(required=True, missing=True)
class LabelPrinter(Printer):
pass
class Sound(Device):
pass
class Microphone(Sound):
pass
class Video(Device):
pass
class VideoScaler(Video):
pass
class Videoconference(Video):
pass

View File

@ -1,3 +1,5 @@
from itertools import chain
import inflection import inflection
from sqlalchemy.dialects import postgresql from sqlalchemy.dialects import postgresql
from sqlalchemy.dialects.postgresql import TSVECTOR from sqlalchemy.dialects.postgresql import TSVECTOR
@ -37,21 +39,24 @@ class DeviceSearch(db.Model):
@classmethod @classmethod
def update_modified_devices(cls, session: db.Session): def update_modified_devices(cls, session: db.Session):
"""Updates the documents of the devices that are part of a modified """Updates the documents of the devices that are part of a
event in the passed-in session. modified event, or tag in the passed-in session.
This method is registered as a SQLAlchemy This method is registered as a SQLAlchemy listener in the
listener in the Devicehub class. Devicehub class.
""" """
devices_to_update = set() devices_to_update = set()
for event in (e for e in session.new if isinstance(e, Event)): for model in chain(session.new, session.dirty):
if isinstance(event, EventWithMultipleDevices): if isinstance(model, Event):
devices_to_update |= event.devices if isinstance(model, EventWithMultipleDevices):
elif isinstance(event, EventWithOneDevice): devices_to_update |= model.devices
devices_to_update.add(event.device) elif isinstance(model, EventWithOneDevice):
if event.parent: devices_to_update.add(model.device)
devices_to_update.add(event.parent) if model.parent:
devices_to_update |= event.components devices_to_update.add(model.parent)
devices_to_update |= model.components
elif isinstance(model, Tag) and model.device:
devices_to_update.add(model.device)
# this flush is controversial: # this flush is controversial:
# see https://groups.google.com/forum/#!topic/sqlalchemy/hBzfypgPfYo # see https://groups.google.com/forum/#!topic/sqlalchemy/hBzfypgPfYo

View File

@ -229,7 +229,7 @@ class Sync:
if adding: if adding:
# For the components we are adding, let's remove them from their old parents # For the components we are adding, let's remove them from their old parents
def g_parent(component: Component) -> Device: def g_parent(component: Component) -> Device:
return component.parent or Computer(id=0) # Computer with id 0 is our Identity return component.parent or Device(id=0) # Computer with id 0 is our Identity
for parent, _components in groupby(sorted(adding, key=g_parent), key=g_parent): for parent, _components in groupby(sorted(adding, key=g_parent), key=g_parent):
if parent.id != 0: # Is not Computer Identity if parent.id != 0: # Is not Computer Identity

View File

@ -234,15 +234,15 @@ class DeviceRow(OrderedDict):
class ManufacturerView(View): class ManufacturerView(View):
class FindArgs(marshmallow.Schema): class FindArgs(marshmallow.Schema):
name = marshmallow.fields.Str(required=True, search = marshmallow.fields.Str(required=True,
# Disallow like operators # Disallow like operators
validate=lambda x: '%' not in x and '_' not in x) validate=lambda x: '%' not in x and '_' not in x)
@cache(datetime.timedelta(days=1)) @cache(datetime.timedelta(days=1))
def find(self, args: dict): def find(self, args: dict):
name = args['name'] search = args['search']
manufacturers = Manufacturer.query \ manufacturers = Manufacturer.query \
.filter(Manufacturer.name.ilike(name + '%')) \ .filter(Manufacturer.name.ilike(search + '%')) \
.paginate(page=1, per_page=6) # type: Pagination .paginate(page=1, per_page=6) # type: Pagination
return jsonify( return jsonify(
items=app.resources[Manufacturer.t].schema.dump( items=app.resources[Manufacturer.t].schema.dump(

View File

@ -276,3 +276,12 @@ class DataStoragePrivacyCompliance(Enum):
return cls.EraseSectors if not erasure.error else cls.EraseSectorsError return cls.EraseSectors if not erasure.error else cls.EraseSectorsError
else: else:
return cls.EraseBasic if not erasure.error else cls.EraseBasicError return cls.EraseBasic if not erasure.error else cls.EraseBasicError
class PrinterTechnology(Enum):
"""Technology of the printer."""
Toner = 'Toner / Laser'
Inkjet = 'Liquid inkjet'
SolidInk = 'Solid ink'
Dye = 'Dye-sublimation'
Thermal = 'Thermal'

View File

@ -4,7 +4,7 @@ from enum import Enum
from typing import List, Set from typing import List, Set
import marshmallow as ma import marshmallow as ma
from flask import jsonify, request from flask import Response, jsonify, request
from marshmallow import Schema as MarshmallowSchema, fields as f from marshmallow import Schema as MarshmallowSchema, fields as f
from teal.marshmallow import EnumField from teal.marshmallow import EnumField
from teal.resource import View from teal.resource import View
@ -36,6 +36,14 @@ class LotView(View):
ret.status_code = 201 ret.status_code = 201
return ret return ret
def patch(self, id):
l = request.get_json()
lot = Lot.query.filter_by(id=id).one()
for key, value in l.items():
setattr(lot, key, value)
db.session.commit()
return Response(status=204)
def one(self, id: uuid.UUID): def one(self, id: uuid.UUID):
"""Gets one event.""" """Gets one event."""
lot = Lot.query.filter_by(id=id).one() # type: Lot lot = Lot.query.filter_by(id=id).one() # type: Lot

View File

@ -1,5 +1,6 @@
from sqlalchemy import Column from datetime import datetime
from sqlalchemy import Column
from teal.db import Model from teal.db import Model
STR_SIZE = 64 STR_SIZE = 64
@ -13,3 +14,8 @@ class Thing(Model):
type = ... # type: str type = ... # type: str
updated = ... # type: Column updated = ... # type: Column
created = ... # type: Column created = ... # type: Column
def __init__(self, **kwargs) -> None:
super().__init__(**kwargs)
self.updated = ... # type: datetime
self.created = ... # type: datetime

View File

@ -22,8 +22,8 @@ class UnitCodes(Enum):
class Thing(Schema): class Thing(Schema):
type = String(description='Only required when it is nested.') type = String(description='Only required when it is nested.')
same_as = List(URL(dump_only=True), dump_only=True, data_key='sameAs') same_as = List(URL(dump_only=True), dump_only=True, data_key='sameAs')
updated = DateTime('iso', dump_only=True, description=m.Thing.updated.comment.strip()) updated = DateTime('iso', dump_only=True, description=m.Thing.updated.comment)
created = DateTime('iso', dump_only=True, description=m.Thing.created.comment.strip()) created = DateTime('iso', dump_only=True, description=m.Thing.created.comment)
@post_load @post_load
def remove_type(self, data: dict): def remove_type(self, data: dict):

View File

@ -25,7 +25,7 @@ requests==2.19.1
requests-mock==1.5.2 requests-mock==1.5.2
SQLAlchemy==1.2.11 SQLAlchemy==1.2.11
SQLAlchemy-Utils==0.33.3 SQLAlchemy-Utils==0.33.3
teal==0.2.0a25 teal==0.2.0a26
webargs==4.0.0 webargs==4.0.0
Werkzeug==0.14.1 Werkzeug==0.14.1
sqlalchemy-citext==1.3.post0 sqlalchemy-citext==1.3.post0

View File

@ -34,7 +34,7 @@ setup(
long_description=long_description, long_description=long_description,
long_description_content_type='text/markdown', long_description_content_type='text/markdown',
install_requires=[ install_requires=[
'teal>=0.2.0a25', # teal always first 'teal>=0.2.0a26', # teal always first
'click', 'click',
'click-spinner', 'click-spinner',
'ereuse-utils[Naming]>=0.4b9', 'ereuse-utils[Naming]>=0.4b9',

View File

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

View File

@ -40,4 +40,4 @@ def test_api_docs(client: Client):
'scheme': 'basic', 'scheme': 'basic',
'name': 'Authorization' 'name': 'Authorization'
} }
assert 75 == len(docs['definitions']) assert 92 == len(docs['definitions'])

View File

@ -9,16 +9,15 @@ from ereuse_utils.test import ANY
from pytest import raises from pytest import raises
from sqlalchemy.util import OrderedSet from sqlalchemy.util import OrderedSet
from teal.db import ResourceNotFound from teal.db import ResourceNotFound
from teal.enums import Layouts
from ereuse_devicehub.client import Client, UserClient from ereuse_devicehub.client import Client, UserClient
from ereuse_devicehub.db import db from ereuse_devicehub.db import db
from ereuse_devicehub.devicehub import Devicehub from ereuse_devicehub.devicehub import Devicehub
from ereuse_devicehub.resources.agent.models import Person 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.exceptions import NeedsId
from ereuse_devicehub.resources.device.models import Component, ComputerMonitor, DataStorage, \
Desktop, Device, GraphicCard, Laptop, Motherboard, NetworkAdapter
from ereuse_devicehub.resources.device.schemas import Device as DeviceS from ereuse_devicehub.resources.device.schemas import Device as DeviceS
from ereuse_devicehub.resources.device.search import DeviceSearch
from ereuse_devicehub.resources.device.sync import MismatchBetweenTags, MismatchBetweenTagsAndHid, \ from ereuse_devicehub.resources.device.sync import MismatchBetweenTags, MismatchBetweenTagsAndHid, \
Sync Sync
from ereuse_devicehub.resources.enums import ComputerChassis, DisplayTech from ereuse_devicehub.resources.enums import ComputerChassis, DisplayTech
@ -35,43 +34,43 @@ def test_device_model():
""" """
Tests that the correctness of the device model and its relationships. Tests that the correctness of the device model and its relationships.
""" """
pc = Desktop(model='p1mo', pc = d.Desktop(model='p1mo',
manufacturer='p1ma', manufacturer='p1ma',
serial_number='p1s', serial_number='p1s',
chassis=ComputerChassis.Tower) chassis=ComputerChassis.Tower)
net = NetworkAdapter(model='c1mo', manufacturer='c1ma', serial_number='c1s') net = d.NetworkAdapter(model='c1mo', manufacturer='c1ma', serial_number='c1s')
graphic = GraphicCard(model='c2mo', manufacturer='c2ma', memory=1500) graphic = d.GraphicCard(model='c2mo', manufacturer='c2ma', memory=1500)
pc.components.add(net) pc.components.add(net)
pc.components.add(graphic) pc.components.add(graphic)
db.session.add(pc) db.session.add(pc)
db.session.commit() db.session.commit()
pc = Desktop.query.one() pc = d.Desktop.query.one()
assert pc.serial_number == 'p1s' assert pc.serial_number == 'p1s'
assert pc.components == OrderedSet([net, graphic]) assert pc.components == OrderedSet([net, graphic])
network_adapter = NetworkAdapter.query.one() network_adapter = d.NetworkAdapter.query.one()
assert network_adapter.parent == pc assert network_adapter.parent == pc
# Removing a component from pc doesn't delete the component # Removing a component from pc doesn't delete the component
pc.components.remove(net) pc.components.remove(net)
db.session.commit() db.session.commit()
pc = Device.query.first() # this is the same as querying for Desktop directly pc = d.Device.query.first() # this is the same as querying for d.Desktop directly
assert pc.components == {graphic} assert pc.components == {graphic}
network_adapter = NetworkAdapter.query.one() network_adapter = d.NetworkAdapter.query.one()
assert network_adapter not in pc.components assert network_adapter not in pc.components
assert network_adapter.parent is None assert network_adapter.parent is None
# Deleting the pc deletes everything # Deleting the pc deletes everything
gcard = GraphicCard.query.one() gcard = d.GraphicCard.query.one()
db.session.delete(pc) db.session.delete(pc)
db.session.flush() db.session.flush()
assert pc.id == 1 assert pc.id == 1
assert Desktop.query.first() is None assert d.Desktop.query.first() is None
db.session.commit() db.session.commit()
assert Desktop.query.first() is None assert d.Desktop.query.first() is None
assert network_adapter.id == 2 assert network_adapter.id == 2
assert NetworkAdapter.query.first() is not None, 'We removed the network adaptor' assert d.NetworkAdapter.query.first() is not None, 'We removed the network adaptor'
assert gcard.id == 3, 'We should still hold a reference to a zombie graphic card' assert gcard.id == 3, 'We should still hold a reference to a zombie graphic card'
assert 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.usefixtures(conftest.app_context.__name__) @pytest.mark.usefixtures(conftest.app_context.__name__)
@ -79,19 +78,19 @@ def test_device_schema():
"""Ensures the user does not upload non-writable or extra fields.""" """Ensures the user does not upload non-writable or extra fields."""
device_s = DeviceS() device_s = DeviceS()
device_s.load({'serialNumber': 'foo1', 'model': 'foo', 'manufacturer': 'bar2'}) device_s.load({'serialNumber': 'foo1', 'model': 'foo', 'manufacturer': 'bar2'})
device_s.dump(Device(id=1)) device_s.dump(d.Device(id=1))
@pytest.mark.usefixtures(conftest.app_context.__name__) @pytest.mark.usefixtures(conftest.app_context.__name__)
def test_physical_properties(): def test_physical_properties():
c = Motherboard(slots=2, c = d.Motherboard(slots=2,
usb=3, usb=3,
serial_number='sn', serial_number='sn',
model='ml', model='ml',
manufacturer='mr', manufacturer='mr',
width=2.0, width=2.0,
color=Color()) color=Color())
pc = Desktop(chassis=ComputerChassis.Tower, pc = d.Desktop(chassis=ComputerChassis.Tower,
model='foo', model='foo',
manufacturer='bar', manufacturer='bar',
serial_number='foo-bar', serial_number='foo-bar',
@ -114,7 +113,6 @@ def test_physical_properties():
'weight': None, 'weight': None,
'height': None, 'height': None,
'width': 2.0, 'width': 2.0,
'color': Color(),
'depth': None 'depth': None
} }
assert pc.physical_properties == { assert pc.physical_properties == {
@ -125,7 +123,6 @@ def test_physical_properties():
'width': 1.4, 'width': 1.4,
'height': 2.1, 'height': 2.1,
'depth': None, 'depth': None,
'color': Color('LightSeaGreen'),
'chassis': ComputerChassis.Tower 'chassis': ComputerChassis.Tower
} }
@ -133,18 +130,18 @@ def test_physical_properties():
@pytest.mark.usefixtures(conftest.app_context.__name__) @pytest.mark.usefixtures(conftest.app_context.__name__)
def test_component_similar_one(): def test_component_similar_one():
snapshot = conftest.file('pc-components.db') snapshot = conftest.file('pc-components.db')
d = snapshot['device'] pc = snapshot['device']
snapshot['components'][0]['serial_number'] = snapshot['components'][1]['serial_number'] = None snapshot['components'][0]['serial_number'] = snapshot['components'][1]['serial_number'] = None
pc = Desktop(**d, components=OrderedSet(Component(**c) for c in snapshot['components'])) pc = d.Desktop(**pc, components=OrderedSet(d.Component(**c) for c in snapshot['components']))
component1, component2 = pc.components # type: Component component1, component2 = pc.components # type: d.Component
db.session.add(pc) db.session.add(pc)
db.session.flush() db.session.flush()
# Let's create a new component named 'A' similar to 1 # Let's create a new component named 'A' similar to 1
componentA = Component(model=component1.model, manufacturer=component1.manufacturer) componentA = d.Component(model=component1.model, manufacturer=component1.manufacturer)
similar_to_a = componentA.similar_one(pc, set()) similar_to_a = componentA.similar_one(pc, set())
assert similar_to_a == component1 assert similar_to_a == component1
# Component B does not have the same model # d.Component B does not have the same model
componentB = Component(model='nope', manufacturer=component1.manufacturer) componentB = d.Component(model='nope', manufacturer=component1.manufacturer)
with pytest.raises(ResourceNotFound): with pytest.raises(ResourceNotFound):
assert componentB.similar_one(pc, set()) assert componentB.similar_one(pc, set())
# If we blacklist component A we won't get anything # If we blacklist component A we won't get anything
@ -160,14 +157,14 @@ def test_add_remove():
# c4 is not with any pc # c4 is not with any pc
values = conftest.file('pc-components.db') values = conftest.file('pc-components.db')
pc = values['device'] pc = values['device']
c1, c2 = (Component(**c) for c in values['components']) c1, c2 = (d.Component(**c) for c in values['components'])
pc = Desktop(**pc, components=OrderedSet([c1, c2])) pc = d.Desktop(**pc, components=OrderedSet([c1, c2]))
db.session.add(pc) db.session.add(pc)
c3 = Component(serial_number='nc1') c3 = d.Component(serial_number='nc1')
pc2 = Desktop(serial_number='s2', pc2 = d.Desktop(serial_number='s2',
components=OrderedSet([c3]), components=OrderedSet([c3]),
chassis=ComputerChassis.Microtower) chassis=ComputerChassis.Microtower)
c4 = Component(serial_number='c4s') c4 = d.Component(serial_number='c4s')
db.session.add(pc2) db.session.add(pc2)
db.session.add(c4) db.session.add(c4)
db.session.commit() db.session.commit()
@ -190,12 +187,12 @@ def test_sync_run_components_empty():
remove all the components from the device. remove all the components from the device.
""" """
s = conftest.file('pc-components.db') s = conftest.file('pc-components.db')
pc = Desktop(**s['device'], components=OrderedSet(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.add(pc)
db.session.commit() db.session.commit()
# Create a new transient non-db synced object # Create a new transient non-db synced object
pc = Desktop(**s['device']) pc = d.Desktop(**s['device'])
db_pc, _ = Sync().run(pc, components=OrderedSet()) db_pc, _ = Sync().run(pc, components=OrderedSet())
assert not db_pc.components assert not db_pc.components
assert not pc.components assert not pc.components
@ -208,25 +205,25 @@ def test_sync_run_components_none():
keep all the components from the device. keep all the components from the device.
""" """
s = conftest.file('pc-components.db') s = conftest.file('pc-components.db')
pc = Desktop(**s['device'], components=OrderedSet(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.add(pc)
db.session.commit() db.session.commit()
# Create a new transient non-db synced object # Create a new transient non-db synced object
transient_pc = Desktop(**s['device']) transient_pc = d.Desktop(**s['device'])
db_pc, _ = Sync().run(transient_pc, components=None) db_pc, _ = Sync().run(transient_pc, components=None)
assert db_pc.components assert db_pc.components
assert db_pc.components == pc.components assert db_pc.components == pc.components
@pytest.mark.usefixtures(conftest.app_context.__name__) @pytest.mark.usefixtures(conftest.app_context.__name__)
def test_sync_execute_register_desktop_new_Desktop_no_tag(): def test_sync_execute_register_desktop_new_desktop_no_tag():
""" """
Syncs a new Desktop with HID and without a tag, creating it. Syncs a new d.Desktop with HID and without a tag, creating it.
:return: :return:
""" """
# Case 1: device does not exist on DB # Case 1: device does not exist on DB
pc = Desktop(**conftest.file('pc-components.db')['device']) pc = d.Desktop(**conftest.file('pc-components.db')['device'])
db_pc = Sync().execute_register(pc) db_pc = Sync().execute_register(pc)
assert pc.physical_properties == db_pc.physical_properties assert pc.physical_properties == db_pc.physical_properties
@ -234,13 +231,13 @@ def test_sync_execute_register_desktop_new_Desktop_no_tag():
@pytest.mark.usefixtures(conftest.app_context.__name__) @pytest.mark.usefixtures(conftest.app_context.__name__)
def test_sync_execute_register_desktop_existing_no_tag(): def test_sync_execute_register_desktop_existing_no_tag():
""" """
Syncs an existing Desktop with HID and without a tag. Syncs an existing d.Desktop with HID and without a tag.
""" """
pc = Desktop(**conftest.file('pc-components.db')['device']) pc = d.Desktop(**conftest.file('pc-components.db')['device'])
db.session.add(pc) db.session.add(pc)
db.session.commit() db.session.commit()
pc = Desktop( pc = d.Desktop(
**conftest.file('pc-components.db')['device']) # Create a new transient non-db object **conftest.file('pc-components.db')['device']) # Create a new transient non-db object
# 1: device exists on DB # 1: device exists on DB
db_pc = Sync().execute_register(pc) db_pc = Sync().execute_register(pc)
@ -250,11 +247,11 @@ def test_sync_execute_register_desktop_existing_no_tag():
@pytest.mark.usefixtures(conftest.app_context.__name__) @pytest.mark.usefixtures(conftest.app_context.__name__)
def test_sync_execute_register_desktop_no_hid_no_tag(): def test_sync_execute_register_desktop_no_hid_no_tag():
""" """
Syncs a Desktop without HID and no tag. Syncs a d.Desktop without HID and no tag.
This should fail as we don't have a way to identify it. This should fail as we don't have a way to identify it.
""" """
pc = Desktop(**conftest.file('pc-components.db')['device']) pc = d.Desktop(**conftest.file('pc-components.db')['device'])
# 1: device has no HID # 1: device has no HID
pc.hid = pc.model = None pc.hid = pc.model = None
with pytest.raises(NeedsId): with pytest.raises(NeedsId):
@ -264,7 +261,7 @@ def test_sync_execute_register_desktop_no_hid_no_tag():
@pytest.mark.usefixtures(conftest.app_context.__name__) @pytest.mark.usefixtures(conftest.app_context.__name__)
def test_sync_execute_register_desktop_tag_not_linked(): def test_sync_execute_register_desktop_tag_not_linked():
""" """
Syncs a new Desktop with HID and a non-linked tag. Syncs a new d.Desktop with HID and a non-linked tag.
It is OK if the tag was not linked, it will be linked in this process. It is OK if the tag was not linked, it will be linked in this process.
""" """
@ -273,24 +270,24 @@ def test_sync_execute_register_desktop_tag_not_linked():
db.session.commit() db.session.commit()
# Create a new transient non-db object # Create a new transient non-db object
pc = Desktop(**conftest.file('pc-components.db')['device'], tags=OrderedSet([Tag(id='foo')])) pc = d.Desktop(**conftest.file('pc-components.db')['device'], tags=OrderedSet([Tag(id='foo')]))
returned_pc = Sync().execute_register(pc) returned_pc = Sync().execute_register(pc)
assert returned_pc == pc assert returned_pc == pc
assert tag.device == pc, 'Tag has to be linked' assert tag.device == pc, 'Tag has to be linked'
assert Desktop.query.one() == pc, 'Desktop had to be set to db' assert d.Desktop.query.one() == pc, 'd.Desktop had to be set to db'
@pytest.mark.usefixtures(conftest.app_context.__name__) @pytest.mark.usefixtures(conftest.app_context.__name__)
def test_sync_execute_register_no_hid_tag_not_linked(tag_id: str): def test_sync_execute_register_no_hid_tag_not_linked(tag_id: str):
""" """
Validates registering a Desktop without HID and a non-linked tag. Validates registering a d.Desktop without HID and a non-linked tag.
In this case it is ok still, as the non-linked tag proves that In this case it is ok still, as the non-linked tag proves that
the Desktop was not existing before (otherwise the tag would the d.Desktop was not existing before (otherwise the tag would
be linked), and thus it creates a new Desktop. be linked), and thus it creates a new d.Desktop.
""" """
tag = Tag(id=tag_id) tag = Tag(id=tag_id)
pc = Desktop(**conftest.file('pc-components.db')['device'], tags=OrderedSet([tag])) pc = d.Desktop(**conftest.file('pc-components.db')['device'], tags=OrderedSet([tag]))
returned_pc = Sync().execute_register(pc) returned_pc = Sync().execute_register(pc)
db.session.commit() db.session.commit()
assert returned_pc == pc assert returned_pc == pc
@ -300,7 +297,7 @@ def test_sync_execute_register_no_hid_tag_not_linked(tag_id: str):
# they have the same pk though # they have the same pk though
assert tag != db_tag, 'They are not the same tags though' assert tag != db_tag, 'They are not the same tags though'
assert db_tag.id == tag.id assert db_tag.id == tag.id
assert Desktop.query.one() == pc, 'Desktop had to be set to db' assert d.Desktop.query.one() == pc, 'd.Desktop had to be set to db'
@pytest.mark.usefixtures(conftest.app_context.__name__) @pytest.mark.usefixtures(conftest.app_context.__name__)
@ -311,7 +308,7 @@ def test_sync_execute_register_tag_does_not_exist():
Tags have to be created before trying to link them through a Snapshot. Tags have to be created before trying to link them through a Snapshot.
""" """
pc = Desktop(**conftest.file('pc-components.db')['device'], tags=OrderedSet([Tag('foo')])) pc = d.Desktop(**conftest.file('pc-components.db')['device'], tags=OrderedSet([Tag('foo')]))
with raises(ResourceNotFound): with raises(ResourceNotFound):
Sync().execute_register(pc) Sync().execute_register(pc)
@ -324,11 +321,11 @@ def test_sync_execute_register_tag_linked_same_device():
(If it has HID it validates both HID and tag point at the same (If it has HID it validates both HID and tag point at the same
device, this his checked in ). device, this his checked in ).
""" """
orig_pc = Desktop(**conftest.file('pc-components.db')['device']) orig_pc = d.Desktop(**conftest.file('pc-components.db')['device'])
db.session.add(Tag(id='foo', device=orig_pc)) db.session.add(Tag(id='foo', device=orig_pc))
db.session.commit() db.session.commit()
pc = Desktop( pc = d.Desktop(
**conftest.file('pc-components.db')['device']) # Create a new transient non-db object **conftest.file('pc-components.db')['device']) # Create a new transient non-db object
pc.tags.add(Tag(id='foo')) pc.tags.add(Tag(id='foo'))
db_pc = Sync().execute_register(pc) db_pc = Sync().execute_register(pc)
@ -343,15 +340,15 @@ 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 Checks that sync raises an error if finds that at least two passed-in
tags are not linked to the same device. tags are not linked to the same device.
""" """
pc1 = Desktop(**conftest.file('pc-components.db')['device']) pc1 = d.Desktop(**conftest.file('pc-components.db')['device'])
db.session.add(Tag(id='foo-1', device=pc1)) db.session.add(Tag(id='foo-1', device=pc1))
pc2 = Desktop(**conftest.file('pc-components.db')['device']) pc2 = d.Desktop(**conftest.file('pc-components.db')['device'])
pc2.serial_number = 'pc2-serial' pc2.serial_number = 'pc2-serial'
pc2.hid = Naming.hid(pc2.manufacturer, pc2.serial_number, pc2.model) pc2.hid = Naming.hid(pc2.manufacturer, pc2.serial_number, pc2.model)
db.session.add(Tag(id='foo-2', device=pc2)) db.session.add(Tag(id='foo-2', device=pc2))
db.session.commit() db.session.commit()
pc1 = Desktop( pc1 = d.Desktop(
**conftest.file('pc-components.db')['device']) # Create a new transient non-db object **conftest.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-1'))
pc1.tags.add(Tag(id='foo-2')) pc1.tags.add(Tag(id='foo-2'))
@ -367,15 +364,15 @@ def test_sync_execute_register_mismatch_between_tags_and_hid():
In this case we set HID -> pc1 but tag -> pc2 In this case we set HID -> pc1 but tag -> pc2
""" """
pc1 = Desktop(**conftest.file('pc-components.db')['device']) pc1 = d.Desktop(**conftest.file('pc-components.db')['device'])
db.session.add(Tag(id='foo-1', device=pc1)) db.session.add(Tag(id='foo-1', device=pc1))
pc2 = Desktop(**conftest.file('pc-components.db')['device']) pc2 = d.Desktop(**conftest.file('pc-components.db')['device'])
pc2.serial_number = 'pc2-serial' pc2.serial_number = 'pc2-serial'
pc2.hid = Naming.hid(pc2.manufacturer, pc2.serial_number, pc2.model) pc2.hid = Naming.hid(pc2.manufacturer, pc2.serial_number, pc2.model)
db.session.add(Tag(id='foo-2', device=pc2)) db.session.add(Tag(id='foo-2', device=pc2))
db.session.commit() db.session.commit()
pc1 = Desktop( pc1 = d.Desktop(
**conftest.file('pc-components.db')['device']) # Create a new transient non-db object **conftest.file('pc-components.db')['device']) # Create a new transient non-db object
pc1.tags.add(Tag(id='foo-2')) pc1.tags.add(Tag(id='foo-2'))
with raises(MismatchBetweenTagsAndHid): with raises(MismatchBetweenTagsAndHid):
@ -383,15 +380,15 @@ def test_sync_execute_register_mismatch_between_tags_and_hid():
def test_get_device(app: Devicehub, user: UserClient): def test_get_device(app: Devicehub, user: UserClient):
"""Checks GETting a Desktop with its components.""" """Checks GETting a d.Desktop with its components."""
with app.app_context(): with app.app_context():
pc = Desktop(model='p1mo', pc = d.Desktop(model='p1mo',
manufacturer='p1ma', manufacturer='p1ma',
serial_number='p1s', serial_number='p1s',
chassis=ComputerChassis.Tower) chassis=ComputerChassis.Tower)
pc.components = OrderedSet([ pc.components = OrderedSet([
NetworkAdapter(model='c1mo', manufacturer='c1ma', serial_number='c1s'), d.NetworkAdapter(model='c1mo', manufacturer='c1ma', serial_number='c1s'),
GraphicCard(model='c2mo', manufacturer='c2ma', memory=1500) d.GraphicCard(model='c2mo', manufacturer='c2ma', memory=1500)
]) ])
db.session.add(pc) db.session.add(pc)
db.session.add(Test(device=pc, db.session.add(Test(device=pc,
@ -400,7 +397,7 @@ def test_get_device(app: Devicehub, user: UserClient):
agent=Person(name='Timmy'), agent=Person(name='Timmy'),
author=User(email='bar@bar.com'))) author=User(email='bar@bar.com')))
db.session.commit() db.session.commit()
pc, _ = user.get(res=Device, item=1) pc, _ = user.get(res=d.Device, item=1)
assert len(pc['events']) == 1 assert len(pc['events']) == 1
assert pc['events'][0]['type'] == 'Test' assert pc['events'][0]['type'] == 'Test'
assert pc['events'][0]['device'] == 1 assert pc['events'][0]['device'] == 1
@ -415,40 +412,40 @@ def test_get_device(app: Devicehub, user: UserClient):
assert pc['model'] == 'p1mo' assert pc['model'] == 'p1mo'
assert pc['manufacturer'] == 'p1ma' assert pc['manufacturer'] == 'p1ma'
assert pc['serialNumber'] == 'p1s' assert pc['serialNumber'] == 'p1s'
assert pc['type'] == 'Desktop' assert pc['type'] == d.Desktop.t
def test_get_devices(app: Devicehub, user: UserClient): def test_get_devices(app: Devicehub, user: UserClient):
"""Checks GETting multiple devices.""" """Checks GETting multiple devices."""
with app.app_context(): with app.app_context():
pc = Desktop(model='p1mo', pc = d.Desktop(model='p1mo',
manufacturer='p1ma', manufacturer='p1ma',
serial_number='p1s', serial_number='p1s',
chassis=ComputerChassis.Tower) chassis=ComputerChassis.Tower)
pc.components = OrderedSet([ pc.components = OrderedSet([
NetworkAdapter(model='c1mo', manufacturer='c1ma', serial_number='c1s'), d.NetworkAdapter(model='c1mo', manufacturer='c1ma', serial_number='c1s'),
GraphicCard(model='c2mo', manufacturer='c2ma', memory=1500) d.GraphicCard(model='c2mo', manufacturer='c2ma', memory=1500)
]) ])
pc1 = Desktop(model='p2mo', pc1 = d.Desktop(model='p2mo',
manufacturer='p2ma', manufacturer='p2ma',
serial_number='p2s', serial_number='p2s',
chassis=ComputerChassis.Tower) chassis=ComputerChassis.Tower)
pc2 = Laptop(model='p3mo', pc2 = d.Laptop(model='p3mo',
manufacturer='p3ma', manufacturer='p3ma',
serial_number='p3s', serial_number='p3s',
chassis=ComputerChassis.Netbook) chassis=ComputerChassis.Netbook)
db.session.add_all((pc, pc1, pc2)) db.session.add_all((pc, pc1, pc2))
db.session.commit() db.session.commit()
devices, _ = user.get(res=Device) devices, _ = user.get(res=d.Device)
assert tuple(d['id'] for d in devices['items']) == (1, 2, 3, 4, 5) assert tuple(dev['id'] for dev in devices['items']) == (1, 2, 3, 4, 5)
assert tuple(d['type'] for d in devices['items']) == ( assert tuple(dev['type'] for dev in devices['items']) == (
'Desktop', 'Desktop', 'Laptop', 'NetworkAdapter', 'GraphicCard' d.Desktop.t, d.Desktop.t, d.Laptop.t, d.NetworkAdapter.t, d.GraphicCard.t
) )
@pytest.mark.usefixtures(conftest.app_context.__name__) @pytest.mark.usefixtures(conftest.app_context.__name__)
def test_computer_monitor(): def test_computer_monitor():
m = ComputerMonitor(technology=DisplayTech.LCD, m = d.ComputerMonitor(technology=DisplayTech.LCD,
manufacturer='foo', manufacturer='foo',
model='bar', model='bar',
serial_number='foo-bar', serial_number='foo-bar',
@ -474,22 +471,8 @@ def test_computer_with_display():
pass pass
def test_device_search_all_devices_token_if_empty(app: Devicehub, user: UserClient):
"""Ensures DeviceSearch can regenerate itself when the table is empty."""
user.post(file('basic.snapshot'), res=m.Snapshot)
with app.app_context():
app.db.session.execute('TRUNCATE TABLE {}'.format(DeviceSearch.__table__.name))
app.db.session.commit()
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=Device, query=[('search', 'Desktop')])
assert not len(i['items'])
def test_manufacturer(user: UserClient): def test_manufacturer(user: UserClient):
m, r = user.get(res='Manufacturer', query=[('name', 'asus')]) 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.cache_control.public
assert r.expires > datetime.datetime.now() assert r.expires > datetime.datetime.now()
@ -504,7 +487,7 @@ def test_manufacturer_enforced():
def test_device_properties_format(app: Devicehub, user: UserClient): def test_device_properties_format(app: Devicehub, user: UserClient):
user.post(file('asus-eee-1000h.snapshot.11'), res=m.Snapshot) user.post(file('asus-eee-1000h.snapshot.11'), res=m.Snapshot)
with app.app_context(): with app.app_context():
pc = Laptop.query.one() # type: Laptop pc = d.Laptop.query.one() # type: d.Laptop
assert format(pc) == 'Laptop 1: model 1000h, S/N 94oaaq021116' assert format(pc) == 'Laptop 1: model 1000h, S/N 94oaaq021116'
assert format(pc, 't') == 'Netbook 1000h' assert format(pc, 't') == 'Netbook 1000h'
assert format(pc, 's') == '(asustek computer inc.) S/N 94OAAQ021116' assert format(pc, 's') == '(asustek computer inc.) S/N 94OAAQ021116'
@ -512,12 +495,12 @@ def test_device_properties_format(app: Devicehub, user: UserClient):
assert pc.data_storage_size == 152627 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' assert pc.processor_model == 'intel atom cpu n270 @ 1.60ghz'
net = next(c for c in pc.components if isinstance(c, NetworkAdapter)) net = next(c for c in pc.components if isinstance(c, d.NetworkAdapter))
assert format(net) == 'NetworkAdapter 2: model ar8121/ar8113/ar8114 ' \ assert format(net) == 'NetworkAdapter 2: model ar8121/ar8113/ar8114 ' \
'gigabit or fast ethernet, S/N 00:24:8c:7f:cf:2d' '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, 't') == 'NetworkAdapter ar8121/ar8113/ar8114 gigabit or fast ethernet'
assert format(net, 's') == '(qualcomm atheros) S/N 00:24:8C:7F:CF:2D 100 Mbps' assert format(net, 's') == '(qualcomm atheros) S/N 00:24:8C:7F:CF:2D 100 Mbps'
hdd = next(c for c in pc.components if isinstance(c, DataStorage)) hdd = next(c for c in pc.components if isinstance(c, d.DataStorage))
assert format(hdd) == 'HardDrive 7: model st9160310as, S/N 5sv4tqa6' assert format(hdd) == 'HardDrive 7: model st9160310as, S/N 5sv4tqa6'
assert format(hdd, 't') == 'HardDrive st9160310as' assert format(hdd, 't') == 'HardDrive st9160310as'
assert format(hdd, 's') == '(seagate) S/N 5SV4TQA6 152 GB' assert format(hdd, 's') == '(seagate) S/N 5SV4TQA6 152 GB'
@ -525,13 +508,26 @@ def test_device_properties_format(app: Devicehub, user: UserClient):
def test_device_public(user: UserClient, client: Client): def test_device_public(user: UserClient, client: Client):
s, _ = user.post(file('asus-eee-1000h.snapshot.11'), res=m.Snapshot) s, _ = user.post(file('asus-eee-1000h.snapshot.11'), res=m.Snapshot)
html, _ = client.get(res=Device, item=s['device']['id'], accept=ANY) html, _ = client.get(res=d.Device, item=s['device']['id'], accept=ANY)
assert 'intel atom cpu n270 @ 1.60ghz' in html assert 'intel atom cpu n270 @ 1.60ghz' in html
assert 'S/N 00:24:8C:7F:CF:2D 100 Mbps' in html assert 'S/N 00:24:8C:7F:CF:2D 100 Mbps' in html
@pytest.mark.xfail(reason='Functionality not yet developed.') @pytest.mark.usefixtures(conftest.app_context.__name__)
def test_device_search_multiple_tags(user: UserClient): def test_computer_accessory_model():
"""Ensures that users can search multiple tags at once sai = d.SAI()
and get their multiple devices.""" db.session.add(sai)
pass keyboard = d.Keyboard(layout=Layouts.ES)
db.session.add(keyboard)
mouse = d.Mouse()
db.session.add(mouse)
db.session.commit()
@pytest.mark.usefixtures(conftest.app_context.__name__)
def test_networking_model():
router = d.Router(speed=1000, wireless=True)
db.session.add(router)
switch = d.Switch(speed=1000, wireless=False)
db.session.add(switch)
db.session.commit()

View File

@ -6,6 +6,7 @@ from ereuse_devicehub.db import db
from ereuse_devicehub.devicehub import Devicehub from ereuse_devicehub.devicehub import Devicehub
from ereuse_devicehub.resources.device.models import Desktop, Device, Laptop, Processor, \ from ereuse_devicehub.resources.device.models import Desktop, Device, Laptop, Processor, \
SolidStateDrive SolidStateDrive
from ereuse_devicehub.resources.device.search import DeviceSearch
from ereuse_devicehub.resources.device.views import Filters, Sorting from ereuse_devicehub.resources.device.views import Filters, Sorting
from ereuse_devicehub.resources.enums import ComputerChassis from ereuse_devicehub.resources.enums import ComputerChassis
from ereuse_devicehub.resources.event.models import Snapshot from ereuse_devicehub.resources.event.models import Snapshot
@ -174,6 +175,21 @@ def test_device_lots_query(user: UserClient):
pass pass
def test_device_search_all_devices_token_if_empty(app: Devicehub, user: UserClient):
"""Ensures DeviceSearch can regenerate itself when the table is empty."""
user.post(file('basic.snapshot'), res=Snapshot)
with app.app_context():
app.db.session.execute('TRUNCATE TABLE {}'.format(DeviceSearch.__table__.name))
app.db.session.commit()
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)
app.db.session.commit()
i, _ = user.get(res=Device, query=[('search', 'Desktop')])
assert i['items']
def test_device_query_search(user: UserClient): def test_device_query_search(user: UserClient):
# todo improve # todo improve
user.post(file('basic.snapshot'), res=Snapshot) user.post(file('basic.snapshot'), res=Snapshot)

View File

@ -112,7 +112,10 @@ def test_install():
@pytest.mark.usefixtures(conftest.auth_app_context.__name__) @pytest.mark.usefixtures(conftest.auth_app_context.__name__)
def test_update_components_event_one(): def test_update_components_event_one():
computer = Desktop(serial_number='sn1', model='ml1', manufacturer='mr1') computer = Desktop(serial_number='sn1',
model='ml1',
manufacturer='mr1',
chassis=ComputerChassis.Tower)
hdd = HardDrive(serial_number='foo', manufacturer='bar', model='foo-bar') hdd = HardDrive(serial_number='foo', manufacturer='bar', model='foo-bar')
computer.components.add(hdd) computer.components.add(hdd)
@ -137,7 +140,10 @@ def test_update_components_event_one():
@pytest.mark.usefixtures(conftest.auth_app_context.__name__) @pytest.mark.usefixtures(conftest.auth_app_context.__name__)
def test_update_components_event_multiple(): def test_update_components_event_multiple():
computer = Desktop(serial_number='sn1', model='ml1', manufacturer='mr1') computer = Desktop(serial_number='sn1',
model='ml1',
manufacturer='mr1',
chassis=ComputerChassis.Tower)
hdd = HardDrive(serial_number='foo', manufacturer='bar', model='foo-bar') hdd = HardDrive(serial_number='foo', manufacturer='bar', model='foo-bar')
computer.components.add(hdd) computer.components.add(hdd)
@ -163,7 +169,10 @@ def test_update_components_event_multiple():
@pytest.mark.usefixtures(conftest.auth_app_context.__name__) @pytest.mark.usefixtures(conftest.auth_app_context.__name__)
def test_update_parent(): def test_update_parent():
computer = Desktop(serial_number='sn1', model='ml1', manufacturer='mr1') computer = Desktop(serial_number='sn1',
model='ml1',
manufacturer='mr1',
chassis=ComputerChassis.Tower)
hdd = HardDrive(serial_number='foo', manufacturer='bar', model='foo-bar') hdd = HardDrive(serial_number='foo', manufacturer='bar', model='foo-bar')
computer.components.add(hdd) computer.components.add(hdd)

View File

@ -23,6 +23,15 @@ In case of error, debug with:
""" """
def test_lot_modify_patch_endpoint(user: UserClient):
"""Creates and modifies lot properties through the endpoint"""
l, _ = user.post({'name': 'foo'}, res=Lot)
assert l['name'] == 'foo'
user.patch({'name': 'bar'}, res=Lot, item=l['id'], status=204)
l_after, _ = user.get(res=Lot, item=l['id'])
assert l_after['name'] == 'bar'
@pytest.mark.xfail(reason='Components are not added to lots!') @pytest.mark.xfail(reason='Components are not added to lots!')
@pytest.mark.usefixtures(conftest.auth_app_context.__name__) @pytest.mark.usefixtures(conftest.auth_app_context.__name__)
def test_lot_device_relationship(): def test_lot_device_relationship():

View File

@ -51,7 +51,7 @@ def test_rate():
appearance_range=AppearanceRange.A, appearance_range=AppearanceRange.A,
functionality_range=FunctionalityRange.A functionality_range=FunctionalityRange.A
) )
pc = Desktop() pc = Desktop(chassis=ComputerChassis.Tower)
hdd = HardDrive(size=476940) hdd = HardDrive(size=476940)
hdd.events_one.add(BenchmarkDataStorage(read_speed=126, write_speed=29.8)) hdd.events_one.add(BenchmarkDataStorage(read_speed=126, write_speed=29.8))
cpu = Processor(cores=2, speed=3.4) cpu = Processor(cores=2, speed=3.4)

View File

@ -15,7 +15,7 @@ Excluded cases in tests
import pytest import pytest
from ereuse_devicehub.resources.device.models import Desktop, HardDrive, Processor, RamModule from ereuse_devicehub.resources.device.models import Desktop, HardDrive, Processor, RamModule
from ereuse_devicehub.resources.enums import AppearanceRange, FunctionalityRange from ereuse_devicehub.resources.enums import AppearanceRange, ComputerChassis, FunctionalityRange
from ereuse_devicehub.resources.event.models import BenchmarkDataStorage, BenchmarkProcessor, \ from ereuse_devicehub.resources.event.models import BenchmarkDataStorage, BenchmarkProcessor, \
WorkbenchRate WorkbenchRate
from ereuse_devicehub.resources.event.rate.workbench.v1_0 import DataStorageRate, ProcessorRate, \ from ereuse_devicehub.resources.event.rate.workbench.v1_0 import DataStorageRate, ProcessorRate, \
@ -307,7 +307,7 @@ def test_rate_computer_rate():
""" """
# Create a new Computer with components characteristics of pc with id = 1193 # Create a new Computer with components characteristics of pc with id = 1193
pc_test = Desktop() pc_test = Desktop(chassis=ComputerChassis.Tower)
data_storage = HardDrive(size=476940) data_storage = HardDrive(size=476940)
data_storage.events_one.add(BenchmarkDataStorage(read_speed=126, write_speed=29.8)) data_storage.events_one.add(BenchmarkDataStorage(read_speed=126, write_speed=29.8))
cpu = Processor(cores=2, speed=3.4) cpu = Processor(cores=2, speed=3.4)
@ -333,7 +333,7 @@ def test_rate_computer_rate():
assert round(rate_pc.rating, 2) == 4.61 assert round(rate_pc.rating, 2) == 4.61
# Create a new Computer with components characteristics of pc with id = 1201 # Create a new Computer with components characteristics of pc with id = 1201
pc_test = Desktop() pc_test = Desktop(chassis=ComputerChassis.Tower)
data_storage = HardDrive(size=476940) data_storage = HardDrive(size=476940)
data_storage.events_one.add(BenchmarkDataStorage(read_speed=158, write_speed=34.7)) data_storage.events_one.add(BenchmarkDataStorage(read_speed=158, write_speed=34.7))
cpu = Processor(cores=2, speed=3.3) cpu = Processor(cores=2, speed=3.3)
@ -358,7 +358,7 @@ def test_rate_computer_rate():
assert round(rate_pc.rating, 2) == 3.48 assert round(rate_pc.rating, 2) == 3.48
# Create a new Computer with components characteristics of pc with id = 79 # Create a new Computer with components characteristics of pc with id = 79
pc_test = Desktop() pc_test = Desktop(chassis=ComputerChassis.Tower)
data_storage = HardDrive(size=76319) data_storage = HardDrive(size=76319)
data_storage.events_one.add(BenchmarkDataStorage(read_speed=72.2, write_speed=24.3)) data_storage.events_one.add(BenchmarkDataStorage(read_speed=72.2, write_speed=24.3))
cpu = Processor(cores=1, speed=1.6) cpu = Processor(cores=1, speed=1.6)
@ -386,7 +386,7 @@ def test_rate_computer_rate():
assert round(rate_pc.rating, 2) == 1.58 assert round(rate_pc.rating, 2) == 1.58
# Create a new Computer with components characteristics of pc with id = 798 # Create a new Computer with components characteristics of pc with id = 798
pc_test = Desktop() pc_test = Desktop(chassis=ComputerChassis.Tower)
data_storage = HardDrive(size=152587) data_storage = HardDrive(size=152587)
data_storage.events_one.add(BenchmarkDataStorage(read_speed=78.1, write_speed=24.4)) data_storage.events_one.add(BenchmarkDataStorage(read_speed=78.1, write_speed=24.4))
cpu = Processor(cores=2, speed=2.5) cpu = Processor(cores=2, speed=2.5)

View File

@ -411,3 +411,10 @@ def snapshot_and_check(user: UserClient,
return snapshot_and_check(user, input_snapshot, event_types, perform_second_snapshot=False) return snapshot_and_check(user, input_snapshot, event_types, perform_second_snapshot=False)
else: else:
return snapshot return snapshot
def test_snapshot_keyboard(user: UserClient):
s = file('keyboard.snapshot')
snapshot = snapshot_and_check(user, s, event_types=('ManualRate',))
keyboard = snapshot['device']
assert keyboard['layout'] == 'ES'

View File

@ -155,8 +155,11 @@ def test_tag_create_etags_cli(app: Devicehub, user: UserClient):
assert tag.provider == URL('https://t.ereuse.org') assert tag.provider == URL('https://t.ereuse.org')
def test_tag_manual_link(app: Devicehub, user: UserClient): def test_tag_manual_link_search(app: Devicehub, user: UserClient):
"""Tests linking manually a tag through PUT /tags/<id>/device/<id>""" """Tests linking manually a tag through PUT /tags/<id>/device/<id>
Checks search has the term.
"""
with app.app_context(): with app.app_context():
db.session.add(Tag('foo-bar', secondary='foo-sec')) db.session.add(Tag('foo-bar', secondary='foo-sec'))
desktop = Desktop(serial_number='foo', chassis=ComputerChassis.AllInOne) desktop = Desktop(serial_number='foo', chassis=ComputerChassis.AllInOne)
@ -179,6 +182,13 @@ def test_tag_manual_link(app: Devicehub, user: UserClient):
# cannot link to another device when already linked # cannot link to another device when already linked
user.put({}, res=Tag, item='foo-bar/device/99', status=LinkedToAnotherDevice) user.put({}, res=Tag, item='foo-bar/device/99', status=LinkedToAnotherDevice)
i, _ = user.get(res=Device, query=[('search', 'foo-bar')])
assert i['items']
i, _ = user.get(res=Device, query=[('search', 'foo-sec')])
assert i['items']
i, _ = user.get(res=Device, query=[('search', 'foo')])
assert i['items']
@pytest.mark.usefixtures(conftest.app_context.__name__) @pytest.mark.usefixtures(conftest.app_context.__name__)
def test_tag_secondary_workbench_link_find(user: UserClient): def test_tag_secondary_workbench_link_find(user: UserClient):

View File

@ -142,6 +142,9 @@ def test_real_hp_11(user: UserClient):
assert pc['hid'] == 'hewlett-packard-czc0408yjg-hp_compaq_8100_elite_sff' assert pc['hid'] == 'hewlett-packard-czc0408yjg-hp_compaq_8100_elite_sff'
assert pc['chassis'] == 'Tower' assert pc['chassis'] == 'Tower'
assert set(e['type'] for e in snapshot['events']) == { assert set(e['type'] for e in snapshot['events']) == {
'EreusePrice',
'AggregateRate',
'WorkbenchRate',
'BenchmarkDataStorage', 'BenchmarkDataStorage',
'BenchmarkProcessor', 'BenchmarkProcessor',
'BenchmarkProcessorSysbench', 'BenchmarkProcessorSysbench',
@ -149,11 +152,12 @@ def test_real_hp_11(user: UserClient):
'BenchmarkRamSysbench', 'BenchmarkRamSysbench',
'StressTest' 'StressTest'
} }
assert len(list(e['type'] for e in snapshot['events'])) == 6 assert len(list(e['type'] for e in snapshot['events'])) == 9
assert pc['networkSpeeds'] == [1000, None], 'Device has no WiFi' assert pc['networkSpeeds'] == [1000, None], 'Device has no WiFi'
assert pc['processorModel'] == 'intel core i3 cpu 530 @ 2.93ghz' assert pc['processorModel'] == 'intel core i3 cpu 530 @ 2.93ghz'
assert pc['ramSize'] == 8192 assert pc['ramSize'] == 8192
assert pc['dataStorageSize'] == 305245 assert pc['dataStorageSize'] == 305245
# todo check rating
def test_real_toshiba_11(user: UserClient): def test_real_toshiba_11(user: UserClient):
@ -177,6 +181,20 @@ def test_snapshot_real_eee_1001pxd(user: UserClient):
assert pc['hid'] == 'asustek_computer_inc-b8oaas048286-1001pxd' assert pc['hid'] == 'asustek_computer_inc-b8oaas048286-1001pxd'
assert pc['tags'] == [] assert pc['tags'] == []
assert pc['networkSpeeds'] == [100, 0], 'Although it has WiFi we do not know the speed' assert pc['networkSpeeds'] == [100, 0], 'Although it has WiFi we do not know the speed'
assert pc['rate']
rate = pc['rate']
assert rate['appearanceRange'] == 'B'
assert rate['functionalityRange'] == 'A'
assert rate['processorRange'] == 'VERY_LOW'
assert rate['ramRange'] == 'VERY_LOW'
assert rate['ratingRange'] == 'VERY_LOW'
assert rate['ram'] == 1.53
assert rate['data_storage'] == 3.76
assert rate['type'] == 'AggregateRate'
assert rate['biosRange'] == 'C'
assert rate['appearance'] > 0
assert rate['functionality'] > 0
assert rate['rating'] > 0 and rate['rating'] != 1
components = snapshot['components'] components = snapshot['components']
wifi = components[0] wifi = components[0]
assert wifi['hid'] == 'qualcomm_atheros-74_2f_68_8b_fd_c8-ar9285_wireless_network_adapter' assert wifi['hid'] == 'qualcomm_atheros-74_2f_68_8b_fd_c8-ar9285_wireless_network_adapter'
@ -208,7 +226,7 @@ def test_snapshot_real_eee_1001pxd(user: UserClient):
assert em.BenchmarkRamSysbench.t in event_types assert em.BenchmarkRamSysbench.t in event_types
assert em.StressTest.t in event_types assert em.StressTest.t in event_types
assert em.Snapshot.t in event_types assert em.Snapshot.t in event_types
assert len(events) == 5 assert len(events) == 7
gpu = components[3] gpu = components[3]
assert gpu['model'] == 'atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller' assert gpu['model'] == 'atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller'
assert gpu['manufacturer'] == 'intel corporation' assert gpu['manufacturer'] == 'intel corporation'