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,
"rate": 19.3106,
"type": "BenchmarkRamSysbench"
},
{
"appearanceRange": "A",
"biosRange": "A",
"functionalityRange": "A",
"type": "WorkbenchRate"
}
],
"manufacturer": "ASUSTeK Computer INC."

View File

@ -12,6 +12,12 @@
"error": false,
"type": "StressTest",
"elapsed": 60
},
{
"appearanceRange": "A",
"biosRange": "A",
"functionalityRange": "A",
"type": "WorkbenchRate"
}
],
"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,
"elapsed": 1,
"type": "BenchmarkRamSysbench"
},
{
"appearanceRange": "B",
"biosRange": "A",
"functionalityRange": "C",
"type": "WorkbenchRate"
}
],
"type": "Desktop",

View File

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

View File

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

View File

@ -161,6 +161,121 @@ class DisplayDef(ComponentDef):
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):
VIEW = ManufacturerView
SCHEMA = schemas.Manufacturer

View File

@ -17,12 +17,13 @@ from sqlalchemy_utils import ColorType
from stdnum import imei, meid
from teal.db import CASCADE, POLYMORPHIC_ID, POLYMORPHIC_ON, ResourceNotFound, URL, check_lower, \
check_range
from teal.enums import Layouts
from teal.marshmallow import ValidationError
from teal.resource import url_for_resource
from ereuse_devicehub.db import db
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
@ -62,6 +63,19 @@ class Device(Thing):
"""
color = Column(ColorType)
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
def events(self) -> list:
@ -94,7 +108,7 @@ class Device(Thing):
for c in inspect(self.__class__).attrs
if isinstance(c, ColumnProperty)
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
def url(self) -> urlutils.URL:
@ -194,6 +208,11 @@ class Device(Thing):
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.comment = """
The size of the monitor in inches.
@ -212,6 +231,10 @@ class DisplayMixin:
The maximum vertical resolution the monitor can natively support
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:
v = ''
@ -226,6 +249,10 @@ class Computer(Device):
id = Column(BigInteger, ForeignKey(Device.id), primary_key=True)
chassis = Column(DBEnum(ComputerChassis), nullable=False)
def __init__(self, chassis, **kwargs) -> None:
chassis = ComputerChassis(chassis)
super().__init__(chassis=chassis, **kwargs)
@property
def events(self) -> list:
return sorted(chain(super().events, self.events_parent), key=attrgetter('created'))
@ -285,7 +312,9 @@ class Desktop(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):
@ -304,6 +333,10 @@ class TelevisionSet(Monitor):
pass
class Projector(Monitor):
pass
class Mobile(Device):
id = Column(BigInteger, ForeignKey(Device.id), primary_key=True)
imei = Column(BigInteger)
@ -479,6 +512,83 @@ class Display(JoinedComponentTableMixin, DisplayMixin, Component):
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):
__table_args__ = {'schema': 'common'}
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 boltons import urlutils
@ -6,11 +7,12 @@ from colour import Color
from sqlalchemy import Column, Integer
from sqlalchemy.orm import relationship
from teal.db import Model
from teal.enums import Layouts
from ereuse_devicehub.resources.agent.models import Agent
from ereuse_devicehub.resources.device import states
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.image.models import ImageList
from ereuse_devicehub.resources.lot.models import Lot
@ -31,6 +33,7 @@ class Device(Thing):
depth = ... # type: Column
color = ... # type: Column
lots = ... # type: relationship
production_date = ... # type: Column
def __init__(self, **kwargs) -> None:
super().__init__(**kwargs)
@ -52,6 +55,7 @@ class Device(Thing):
self.images = ... # type: ImageList
self.tags = ... # type: Set[Tag]
self.lots = ... # type: Set[Lot]
self.production_date = ... # type: datetime
@property
def url(self) -> urlutils.URL:
@ -86,6 +90,9 @@ class DisplayMixin:
size = ... # type: Column
resolution_width = ... # type: Column
resolution_height = ... # type: Column
refresh_rate = ... # type: Column
contrast_ratio = ... # type: Column
touchable = ... # type: Column
def __init__(self) -> None:
super().__init__()
@ -93,6 +100,9 @@ class DisplayMixin:
self.size = ... # type: Integer
self.resolution_width = ... # 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):
@ -135,7 +145,11 @@ class Desktop(Computer):
class Laptop(Computer):
pass
layout = ... # type: Column
def __init__(self, **kwargs) -> None:
super().__init__(**kwargs)
self.layout = ... # type: Layouts
class Server(Computer):
@ -233,12 +247,18 @@ class Motherboard(Component):
self.pcmcia = ... # type: int
class NetworkAdapter(Component):
class NetworkMixin:
speed = ... # type: Column
wireless = ... # type: Column
def __init__(self, **kwargs) -> None:
super().__init__(**kwargs)
self.speed = ... # type: int
self.wireless = ... # type: bool
class NetworkAdapter(NetworkMixin, Component):
pass
class Processor(Component):
@ -271,6 +291,88 @@ class Display(DisplayMixin, Component):
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):
CUSTOM_MANUFACTURERS = ... # type: set
name = ... # type: Column

View File

@ -1,15 +1,16 @@
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 sqlalchemy.util import OrderedSet
from stdnum import imei, meid
from teal.enums import Layouts
from teal.marshmallow import EnumField, SanitizedStr, URL, ValidationError
from teal.resource import Schema
from ereuse_devicehub.marshmallow import NestedOn
from ereuse_devicehub.resources.device import models as m, states
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.schemas import Thing, UnitCodes
@ -40,6 +41,9 @@ class Device(Thing):
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_possessor = NestedOn('Agent', dump_only=True, data_key='physicalPossessor')
production_date = DateTime('iso',
description=m.Device.updated.comment,
data_key='productionDate')
@pre_load
def from_events_to_events_one(self, data: dict):
@ -98,6 +102,9 @@ class DisplayMixin:
resolution_height = Integer(data_key='resolutionHeight',
validate=Range(10, 20000),
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:
@ -212,3 +219,74 @@ class Manufacturer(Schema):
name = String(dump_only=True)
url = 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
from sqlalchemy.dialects import postgresql
from sqlalchemy.dialects.postgresql import TSVECTOR
@ -37,21 +39,24 @@ class DeviceSearch(db.Model):
@classmethod
def update_modified_devices(cls, session: db.Session):
"""Updates the documents of the devices that are part of a modified
event in the passed-in session.
"""Updates the documents of the devices that are part of a
modified event, or tag in the passed-in session.
This method is registered as a SQLAlchemy
listener in the Devicehub class.
This method is registered as a SQLAlchemy listener in the
Devicehub class.
"""
devices_to_update = set()
for event in (e for e in session.new if isinstance(e, Event)):
if isinstance(event, EventWithMultipleDevices):
devices_to_update |= event.devices
elif isinstance(event, EventWithOneDevice):
devices_to_update.add(event.device)
if event.parent:
devices_to_update.add(event.parent)
devices_to_update |= event.components
for model in chain(session.new, session.dirty):
if isinstance(model, Event):
if isinstance(model, EventWithMultipleDevices):
devices_to_update |= model.devices
elif isinstance(model, EventWithOneDevice):
devices_to_update.add(model.device)
if model.parent:
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:
# see https://groups.google.com/forum/#!topic/sqlalchemy/hBzfypgPfYo

View File

@ -229,7 +229,7 @@ class Sync:
if adding:
# For the components we are adding, let's remove them from their old parents
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):
if parent.id != 0: # Is not Computer Identity

View File

@ -234,15 +234,15 @@ class DeviceRow(OrderedDict):
class ManufacturerView(View):
class FindArgs(marshmallow.Schema):
name = marshmallow.fields.Str(required=True,
# Disallow like operators
validate=lambda x: '%' not in x and '_' not in x)
search = marshmallow.fields.Str(required=True,
# Disallow like operators
validate=lambda x: '%' not in x and '_' not in x)
@cache(datetime.timedelta(days=1))
def find(self, args: dict):
name = args['name']
search = args['search']
manufacturers = Manufacturer.query \
.filter(Manufacturer.name.ilike(name + '%')) \
.filter(Manufacturer.name.ilike(search + '%')) \
.paginate(page=1, per_page=6) # type: Pagination
return jsonify(
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
else:
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
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 teal.marshmallow import EnumField
from teal.resource import View
@ -36,6 +36,14 @@ class LotView(View):
ret.status_code = 201
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):
"""Gets one event."""
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
STR_SIZE = 64
@ -13,3 +14,8 @@ class Thing(Model):
type = ... # type: str
updated = ... # 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):
type = String(description='Only required when it is nested.')
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())
created = DateTime('iso', dump_only=True, description=m.Thing.created.comment.strip())
updated = DateTime('iso', dump_only=True, description=m.Thing.updated.comment)
created = DateTime('iso', dump_only=True, description=m.Thing.created.comment)
@post_load
def remove_type(self, data: dict):

View File

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

View File

@ -34,7 +34,7 @@ setup(
long_description=long_description,
long_description_content_type='text/markdown',
install_requires=[
'teal>=0.2.0a25', # teal always first
'teal>=0.2.0a26', # teal always first
'click',
'click-spinner',
'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',
'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 sqlalchemy.util import OrderedSet
from teal.db import ResourceNotFound
from teal.enums import Layouts
from ereuse_devicehub.client import Client, UserClient
from ereuse_devicehub.db import db
from ereuse_devicehub.devicehub import Devicehub
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.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.search import DeviceSearch
from ereuse_devicehub.resources.device.sync import MismatchBetweenTags, MismatchBetweenTagsAndHid, \
Sync
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.
"""
pc = Desktop(model='p1mo',
manufacturer='p1ma',
serial_number='p1s',
chassis=ComputerChassis.Tower)
net = NetworkAdapter(model='c1mo', manufacturer='c1ma', serial_number='c1s')
graphic = GraphicCard(model='c2mo', manufacturer='c2ma', memory=1500)
pc = d.Desktop(model='p1mo',
manufacturer='p1ma',
serial_number='p1s',
chassis=ComputerChassis.Tower)
net = d.NetworkAdapter(model='c1mo', manufacturer='c1ma', serial_number='c1s')
graphic = d.GraphicCard(model='c2mo', manufacturer='c2ma', memory=1500)
pc.components.add(net)
pc.components.add(graphic)
db.session.add(pc)
db.session.commit()
pc = Desktop.query.one()
pc = d.Desktop.query.one()
assert pc.serial_number == 'p1s'
assert pc.components == OrderedSet([net, graphic])
network_adapter = NetworkAdapter.query.one()
network_adapter = d.NetworkAdapter.query.one()
assert network_adapter.parent == pc
# Removing a component from pc doesn't delete the component
pc.components.remove(net)
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}
network_adapter = NetworkAdapter.query.one()
network_adapter = d.NetworkAdapter.query.one()
assert network_adapter not in pc.components
assert network_adapter.parent is None
# Deleting the pc deletes everything
gcard = GraphicCard.query.one()
gcard = d.GraphicCard.query.one()
db.session.delete(pc)
db.session.flush()
assert pc.id == 1
assert Desktop.query.first() is None
assert d.Desktop.query.first() is None
db.session.commit()
assert Desktop.query.first() is None
assert d.Desktop.query.first() is None
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 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__)
@ -79,26 +78,26 @@ def test_device_schema():
"""Ensures the user does not upload non-writable or extra fields."""
device_s = DeviceS()
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__)
def test_physical_properties():
c = Motherboard(slots=2,
usb=3,
serial_number='sn',
model='ml',
manufacturer='mr',
width=2.0,
color=Color())
pc = Desktop(chassis=ComputerChassis.Tower,
model='foo',
manufacturer='bar',
serial_number='foo-bar',
weight=2.8,
width=1.4,
height=2.1,
color=Color('LightSeaGreen'))
c = d.Motherboard(slots=2,
usb=3,
serial_number='sn',
model='ml',
manufacturer='mr',
width=2.0,
color=Color())
pc = d.Desktop(chassis=ComputerChassis.Tower,
model='foo',
manufacturer='bar',
serial_number='foo-bar',
weight=2.8,
width=1.4,
height=2.1,
color=Color('LightSeaGreen'))
pc.components.add(c)
db.session.add(pc)
db.session.commit()
@ -114,7 +113,6 @@ def test_physical_properties():
'weight': None,
'height': None,
'width': 2.0,
'color': Color(),
'depth': None
}
assert pc.physical_properties == {
@ -125,7 +123,6 @@ def test_physical_properties():
'width': 1.4,
'height': 2.1,
'depth': None,
'color': Color('LightSeaGreen'),
'chassis': ComputerChassis.Tower
}
@ -133,18 +130,18 @@ def test_physical_properties():
@pytest.mark.usefixtures(conftest.app_context.__name__)
def test_component_similar_one():
snapshot = conftest.file('pc-components.db')
d = snapshot['device']
pc = snapshot['device']
snapshot['components'][0]['serial_number'] = snapshot['components'][1]['serial_number'] = None
pc = Desktop(**d, components=OrderedSet(Component(**c) for c in snapshot['components']))
component1, component2 = pc.components # type: Component
pc = d.Desktop(**pc, components=OrderedSet(d.Component(**c) for c in snapshot['components']))
component1, component2 = pc.components # type: d.Component
db.session.add(pc)
db.session.flush()
# Let's create a new component named 'A' similar to 1
componentA = Component(model=component1.model, manufacturer=component1.manufacturer)
componentA = d.Component(model=component1.model, manufacturer=component1.manufacturer)
similar_to_a = componentA.similar_one(pc, set())
assert similar_to_a == component1
# Component B does not have the same model
componentB = Component(model='nope', manufacturer=component1.manufacturer)
# d.Component B does not have the same model
componentB = d.Component(model='nope', manufacturer=component1.manufacturer)
with pytest.raises(ResourceNotFound):
assert componentB.similar_one(pc, set())
# If we blacklist component A we won't get anything
@ -160,14 +157,14 @@ def test_add_remove():
# c4 is not with any pc
values = conftest.file('pc-components.db')
pc = values['device']
c1, c2 = (Component(**c) for c in values['components'])
pc = Desktop(**pc, components=OrderedSet([c1, c2]))
c1, c2 = (d.Component(**c) for c in values['components'])
pc = d.Desktop(**pc, components=OrderedSet([c1, c2]))
db.session.add(pc)
c3 = Component(serial_number='nc1')
pc2 = Desktop(serial_number='s2',
components=OrderedSet([c3]),
chassis=ComputerChassis.Microtower)
c4 = Component(serial_number='c4s')
c3 = d.Component(serial_number='nc1')
pc2 = d.Desktop(serial_number='s2',
components=OrderedSet([c3]),
chassis=ComputerChassis.Microtower)
c4 = d.Component(serial_number='c4s')
db.session.add(pc2)
db.session.add(c4)
db.session.commit()
@ -190,12 +187,12 @@ def test_sync_run_components_empty():
remove all the components from the device.
"""
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.commit()
# Create a new transient non-db synced object
pc = Desktop(**s['device'])
pc = d.Desktop(**s['device'])
db_pc, _ = Sync().run(pc, components=OrderedSet())
assert not db_pc.components
assert not pc.components
@ -208,25 +205,25 @@ def test_sync_run_components_none():
keep all the components from the device.
"""
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.commit()
# 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)
assert db_pc.components
assert db_pc.components == pc.components
@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:
"""
# 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)
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__)
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.commit()
pc = Desktop(
pc = d.Desktop(
**conftest.file('pc-components.db')['device']) # Create a new transient non-db object
# 1: device exists on DB
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__)
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.
"""
pc = Desktop(**conftest.file('pc-components.db')['device'])
pc = d.Desktop(**conftest.file('pc-components.db')['device'])
# 1: device has no HID
pc.hid = pc.model = None
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__)
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.
"""
@ -273,24 +270,24 @@ def test_sync_execute_register_desktop_tag_not_linked():
db.session.commit()
# 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)
assert returned_pc == pc
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__)
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
the Desktop was not existing before (otherwise the tag would
be linked), and thus it creates a new Desktop.
the d.Desktop was not existing before (otherwise the tag would
be linked), and thus it creates a new d.Desktop.
"""
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)
db.session.commit()
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
assert tag != db_tag, 'They are not the same tags though'
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__)
@ -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.
"""
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):
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
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.commit()
pc = Desktop(
pc = d.Desktop(
**conftest.file('pc-components.db')['device']) # Create a new transient non-db object
pc.tags.add(Tag(id='foo'))
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
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))
pc2 = Desktop(**conftest.file('pc-components.db')['device'])
pc2 = d.Desktop(**conftest.file('pc-components.db')['device'])
pc2.serial_number = 'pc2-serial'
pc2.hid = Naming.hid(pc2.manufacturer, pc2.serial_number, pc2.model)
db.session.add(Tag(id='foo-2', device=pc2))
db.session.commit()
pc1 = Desktop(
pc1 = d.Desktop(
**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-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
"""
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))
pc2 = Desktop(**conftest.file('pc-components.db')['device'])
pc2 = d.Desktop(**conftest.file('pc-components.db')['device'])
pc2.serial_number = 'pc2-serial'
pc2.hid = Naming.hid(pc2.manufacturer, pc2.serial_number, pc2.model)
db.session.add(Tag(id='foo-2', device=pc2))
db.session.commit()
pc1 = Desktop(
pc1 = d.Desktop(
**conftest.file('pc-components.db')['device']) # Create a new transient non-db object
pc1.tags.add(Tag(id='foo-2'))
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):
"""Checks GETting a Desktop with its components."""
"""Checks GETting a d.Desktop with its components."""
with app.app_context():
pc = Desktop(model='p1mo',
manufacturer='p1ma',
serial_number='p1s',
chassis=ComputerChassis.Tower)
pc = d.Desktop(model='p1mo',
manufacturer='p1ma',
serial_number='p1s',
chassis=ComputerChassis.Tower)
pc.components = OrderedSet([
NetworkAdapter(model='c1mo', manufacturer='c1ma', serial_number='c1s'),
GraphicCard(model='c2mo', manufacturer='c2ma', memory=1500)
d.NetworkAdapter(model='c1mo', manufacturer='c1ma', serial_number='c1s'),
d.GraphicCard(model='c2mo', manufacturer='c2ma', memory=1500)
])
db.session.add(pc)
db.session.add(Test(device=pc,
@ -400,7 +397,7 @@ def test_get_device(app: Devicehub, user: UserClient):
agent=Person(name='Timmy'),
author=User(email='bar@bar.com')))
db.session.commit()
pc, _ = user.get(res=Device, item=1)
pc, _ = user.get(res=d.Device, item=1)
assert len(pc['events']) == 1
assert pc['events'][0]['type'] == 'Test'
assert pc['events'][0]['device'] == 1
@ -415,46 +412,46 @@ def test_get_device(app: Devicehub, user: UserClient):
assert pc['model'] == 'p1mo'
assert pc['manufacturer'] == 'p1ma'
assert pc['serialNumber'] == 'p1s'
assert pc['type'] == 'Desktop'
assert pc['type'] == d.Desktop.t
def test_get_devices(app: Devicehub, user: UserClient):
"""Checks GETting multiple devices."""
with app.app_context():
pc = Desktop(model='p1mo',
manufacturer='p1ma',
serial_number='p1s',
chassis=ComputerChassis.Tower)
pc = d.Desktop(model='p1mo',
manufacturer='p1ma',
serial_number='p1s',
chassis=ComputerChassis.Tower)
pc.components = OrderedSet([
NetworkAdapter(model='c1mo', manufacturer='c1ma', serial_number='c1s'),
GraphicCard(model='c2mo', manufacturer='c2ma', memory=1500)
d.NetworkAdapter(model='c1mo', manufacturer='c1ma', serial_number='c1s'),
d.GraphicCard(model='c2mo', manufacturer='c2ma', memory=1500)
])
pc1 = Desktop(model='p2mo',
manufacturer='p2ma',
serial_number='p2s',
chassis=ComputerChassis.Tower)
pc2 = Laptop(model='p3mo',
manufacturer='p3ma',
serial_number='p3s',
chassis=ComputerChassis.Netbook)
pc1 = d.Desktop(model='p2mo',
manufacturer='p2ma',
serial_number='p2s',
chassis=ComputerChassis.Tower)
pc2 = d.Laptop(model='p3mo',
manufacturer='p3ma',
serial_number='p3s',
chassis=ComputerChassis.Netbook)
db.session.add_all((pc, pc1, pc2))
db.session.commit()
devices, _ = user.get(res=Device)
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'
devices, _ = user.get(res=d.Device)
assert tuple(dev['id'] for dev in devices['items']) == (1, 2, 3, 4, 5)
assert tuple(dev['type'] for dev in devices['items']) == (
d.Desktop.t, d.Desktop.t, d.Laptop.t, d.NetworkAdapter.t, d.GraphicCard.t
)
@pytest.mark.usefixtures(conftest.app_context.__name__)
def test_computer_monitor():
m = ComputerMonitor(technology=DisplayTech.LCD,
manufacturer='foo',
model='bar',
serial_number='foo-bar',
resolution_width=1920,
resolution_height=1080,
size=14.5)
m = d.ComputerMonitor(technology=DisplayTech.LCD,
manufacturer='foo',
model='bar',
serial_number='foo-bar',
resolution_width=1920,
resolution_height=1080,
size=14.5)
db.session.add(m)
db.session.commit()
@ -474,22 +471,8 @@ def test_computer_with_display():
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):
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 r.cache_control.public
assert r.expires > datetime.datetime.now()
@ -504,7 +487,7 @@ def test_manufacturer_enforced():
def test_device_properties_format(app: Devicehub, user: UserClient):
user.post(file('asus-eee-1000h.snapshot.11'), res=m.Snapshot)
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, 't') == 'Netbook 1000h'
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.graphic_card_model == 'mobile 945gse express integrated graphics controller'
assert pc.processor_model == 'intel atom cpu n270 @ 1.60ghz'
net = next(c for c in pc.components if isinstance(c, NetworkAdapter))
net = next(c for c in pc.components if isinstance(c, d.NetworkAdapter))
assert format(net) == 'NetworkAdapter 2: model ar8121/ar8113/ar8114 ' \
'gigabit or fast ethernet, S/N 00:24:8c:7f:cf:2d'
assert format(net, 't') == 'NetworkAdapter ar8121/ar8113/ar8114 gigabit or fast ethernet'
assert format(net, 's') == '(qualcomm atheros) 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, 't') == 'HardDrive st9160310as'
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):
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 'S/N 00:24:8C:7F:CF:2D 100 Mbps' in html
@pytest.mark.xfail(reason='Functionality not yet developed.')
def test_device_search_multiple_tags(user: UserClient):
"""Ensures that users can search multiple tags at once
and get their multiple devices."""
pass
@pytest.mark.usefixtures(conftest.app_context.__name__)
def test_computer_accessory_model():
sai = d.SAI()
db.session.add(sai)
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.resources.device.models import Desktop, Device, Laptop, Processor, \
SolidStateDrive
from ereuse_devicehub.resources.device.search import DeviceSearch
from ereuse_devicehub.resources.device.views import Filters, Sorting
from ereuse_devicehub.resources.enums import ComputerChassis
from ereuse_devicehub.resources.event.models import Snapshot
@ -174,6 +175,21 @@ def test_device_lots_query(user: UserClient):
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):
# todo improve
user.post(file('basic.snapshot'), res=Snapshot)

View File

@ -112,7 +112,10 @@ def test_install():
@pytest.mark.usefixtures(conftest.auth_app_context.__name__)
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')
computer.components.add(hdd)
@ -137,7 +140,10 @@ def test_update_components_event_one():
@pytest.mark.usefixtures(conftest.auth_app_context.__name__)
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')
computer.components.add(hdd)
@ -163,7 +169,10 @@ def test_update_components_event_multiple():
@pytest.mark.usefixtures(conftest.auth_app_context.__name__)
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')
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.usefixtures(conftest.auth_app_context.__name__)
def test_lot_device_relationship():

View File

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

View File

@ -15,7 +15,7 @@ Excluded cases in tests
import pytest
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, \
WorkbenchRate
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
pc_test = Desktop()
pc_test = Desktop(chassis=ComputerChassis.Tower)
data_storage = HardDrive(size=476940)
data_storage.events_one.add(BenchmarkDataStorage(read_speed=126, write_speed=29.8))
cpu = Processor(cores=2, speed=3.4)
@ -333,7 +333,7 @@ def test_rate_computer_rate():
assert round(rate_pc.rating, 2) == 4.61
# 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.events_one.add(BenchmarkDataStorage(read_speed=158, write_speed=34.7))
cpu = Processor(cores=2, speed=3.3)
@ -358,7 +358,7 @@ def test_rate_computer_rate():
assert round(rate_pc.rating, 2) == 3.48
# 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.events_one.add(BenchmarkDataStorage(read_speed=72.2, write_speed=24.3))
cpu = Processor(cores=1, speed=1.6)
@ -386,7 +386,7 @@ def test_rate_computer_rate():
assert round(rate_pc.rating, 2) == 1.58
# 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.events_one.add(BenchmarkDataStorage(read_speed=78.1, write_speed=24.4))
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)
else:
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')
def test_tag_manual_link(app: Devicehub, user: UserClient):
"""Tests linking manually a tag through PUT /tags/<id>/device/<id>"""
def test_tag_manual_link_search(app: Devicehub, user: UserClient):
"""Tests linking manually a tag through PUT /tags/<id>/device/<id>
Checks search has the term.
"""
with app.app_context():
db.session.add(Tag('foo-bar', secondary='foo-sec'))
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
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__)
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['chassis'] == 'Tower'
assert set(e['type'] for e in snapshot['events']) == {
'EreusePrice',
'AggregateRate',
'WorkbenchRate',
'BenchmarkDataStorage',
'BenchmarkProcessor',
'BenchmarkProcessorSysbench',
@ -149,11 +152,12 @@ def test_real_hp_11(user: UserClient):
'BenchmarkRamSysbench',
'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['processorModel'] == 'intel core i3 cpu 530 @ 2.93ghz'
assert pc['ramSize'] == 8192
assert pc['dataStorageSize'] == 305245
# todo check rating
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['tags'] == []
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']
wifi = components[0]
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.StressTest.t in event_types
assert em.Snapshot.t in event_types
assert len(events) == 5
assert len(events) == 7
gpu = components[3]
assert gpu['model'] == 'atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller'
assert gpu['manufacturer'] == 'intel corporation'