Pass test_workbench_server_condensed
This commit is contained in:
parent
f00c6f2f49
commit
ef132098cb
|
@ -29,7 +29,7 @@ class Client(TealClient):
|
||||||
item=None,
|
item=None,
|
||||||
headers: dict = None,
|
headers: dict = None,
|
||||||
token: str = None,
|
token: str = None,
|
||||||
**kw) -> Tuple[Union[Dict[str, Any], str], Response]:
|
**kw) -> Tuple[Union[Dict[str, object], str], Response]:
|
||||||
if isclass(res) and issubclass(res, (models.Thing, schemas.Thing)):
|
if isclass(res) and issubclass(res, (models.Thing, schemas.Thing)):
|
||||||
res = res.t
|
res = res.t
|
||||||
return super().open(uri, res, status, query, accept, content_type, item, headers, token,
|
return super().open(uri, res, status, query, accept, content_type, item, headers, token,
|
||||||
|
@ -44,7 +44,7 @@ class Client(TealClient):
|
||||||
accept: str = JSON,
|
accept: str = JSON,
|
||||||
headers: dict = None,
|
headers: dict = None,
|
||||||
token: str = None,
|
token: str = None,
|
||||||
**kw) -> Tuple[Union[Dict[str, Any], str], Response]:
|
**kw) -> Tuple[Union[Dict[str, object], str], Response]:
|
||||||
return super().get(uri, res, query, status, item, accept, headers, token, **kw)
|
return super().get(uri, res, query, status, item, accept, headers, token, **kw)
|
||||||
|
|
||||||
def post(self,
|
def post(self,
|
||||||
|
@ -57,7 +57,7 @@ class Client(TealClient):
|
||||||
accept: str = JSON,
|
accept: str = JSON,
|
||||||
headers: dict = None,
|
headers: dict = None,
|
||||||
token: str = None,
|
token: str = None,
|
||||||
**kw) -> Tuple[Union[Dict[str, Any], str], Response]:
|
**kw) -> Tuple[Union[Dict[str, object], str], Response]:
|
||||||
return super().post(data, uri, res, query, status, content_type, accept, headers, token,
|
return super().post(data, uri, res, query, status, content_type, accept, headers, token,
|
||||||
**kw)
|
**kw)
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ class Client(TealClient):
|
||||||
res: Union[Type[Union[models.Thing, schemas.Thing]], str],
|
res: Union[Type[Union[models.Thing, schemas.Thing]], str],
|
||||||
resources: Iterable[Union[dict, int]],
|
resources: Iterable[Union[dict, int]],
|
||||||
key: str = None,
|
key: str = None,
|
||||||
**kw) -> Iterable[Union[Dict[str, Any], str]]:
|
**kw) -> Iterable[Union[Dict[str, object], str]]:
|
||||||
"""Like :meth:`.get` but with many resources."""
|
"""Like :meth:`.get` but with many resources."""
|
||||||
return (
|
return (
|
||||||
self.get(res=res, item=r[key] if key else r, **kw)[0]
|
self.get(res=res, item=r[key] if key else r, **kw)[0]
|
||||||
|
@ -106,6 +106,6 @@ class UserClient(Client):
|
||||||
item=None,
|
item=None,
|
||||||
headers: dict = None,
|
headers: dict = None,
|
||||||
token: str = None,
|
token: str = None,
|
||||||
**kw) -> Tuple[Union[Dict[str, Any], str], Response]:
|
**kw) -> Tuple[Union[Dict[str, object], str], Response]:
|
||||||
return super().open(uri, res, status, query, accept, content_type, item, headers,
|
return super().open(uri, res, status, query, accept, content_type, item, headers,
|
||||||
self.user['token'] if self.user else token, **kw)
|
self.user['token'] if self.user else token, **kw)
|
||||||
|
|
|
@ -5,10 +5,11 @@ from ereuse_devicehub.resources.device import ComponentDef, ComputerDef, DataSto
|
||||||
DesktopDef, DeviceDef, GraphicCardDef, HardDriveDef, LaptopDef, MicrotowerDef, \
|
DesktopDef, DeviceDef, GraphicCardDef, HardDriveDef, LaptopDef, MicrotowerDef, \
|
||||||
MotherboardDef, NetbookDef, NetworkAdapterDef, ProcessorDef, RamModuleDef, ServerDef, \
|
MotherboardDef, NetbookDef, NetworkAdapterDef, ProcessorDef, RamModuleDef, ServerDef, \
|
||||||
SolidStateDriveDef
|
SolidStateDriveDef
|
||||||
from ereuse_devicehub.resources.event import AddDef, AggregateRateDef, EventDef, InstallDef, \
|
from ereuse_devicehub.resources.event import AddDef, AggregateRateDef, BenchmarkDataStorageDef, \
|
||||||
|
BenchmarkDef, BenchmarkProcessorDef, BenchmarkProcessorSysbenchDef, BenchmarkRamSysbenchDef, \
|
||||||
|
BenchmarkWithRateDef, EraseBasicDef, EraseSectorsDef, EventDef, InstallDef, \
|
||||||
PhotoboxSystemRateDef, PhotoboxUserDef, RateDef, RemoveDef, SnapshotDef, StepDef, \
|
PhotoboxSystemRateDef, PhotoboxUserDef, RateDef, RemoveDef, SnapshotDef, StepDef, \
|
||||||
StepRandomDef, StepZeroDef, TestDataStorageDef, TestDef, WorkbenchRateDef, EraseBasicDef, \
|
StepRandomDef, StepZeroDef, StressTestDef, TestDataStorageDef, TestDef, WorkbenchRateDef
|
||||||
EraseSectorsDef
|
|
||||||
from ereuse_devicehub.resources.inventory import InventoryDef
|
from ereuse_devicehub.resources.inventory import InventoryDef
|
||||||
from ereuse_devicehub.resources.tag import TagDef
|
from ereuse_devicehub.resources.tag import TagDef
|
||||||
from ereuse_devicehub.resources.user import OrganizationDef, UserDef
|
from ereuse_devicehub.resources.user import OrganizationDef, UserDef
|
||||||
|
@ -23,7 +24,9 @@ class DevicehubConfig(Config):
|
||||||
OrganizationDef, TagDef, EventDef, AddDef, RemoveDef, EraseBasicDef, EraseSectorsDef,
|
OrganizationDef, TagDef, EventDef, AddDef, RemoveDef, EraseBasicDef, EraseSectorsDef,
|
||||||
StepDef, StepZeroDef, StepRandomDef, RateDef, AggregateRateDef, WorkbenchRateDef,
|
StepDef, StepZeroDef, StepRandomDef, RateDef, AggregateRateDef, WorkbenchRateDef,
|
||||||
PhotoboxUserDef, PhotoboxSystemRateDef, InstallDef, SnapshotDef, TestDef,
|
PhotoboxUserDef, PhotoboxSystemRateDef, InstallDef, SnapshotDef, TestDef,
|
||||||
TestDataStorageDef, WorkbenchRateDef, InventoryDef
|
TestDataStorageDef, StressTestDef, WorkbenchRateDef, InventoryDef, BenchmarkDef,
|
||||||
|
BenchmarkDataStorageDef, BenchmarkWithRateDef, BenchmarkProcessorDef,
|
||||||
|
BenchmarkProcessorSysbenchDef, BenchmarkRamSysbenchDef
|
||||||
}
|
}
|
||||||
PASSWORD_SCHEMES = {'pbkdf2_sha256'} # type: Set[str]
|
PASSWORD_SCHEMES = {'pbkdf2_sha256'} # type: Set[str]
|
||||||
SQLALCHEMY_DATABASE_URI = 'postgresql://localhost/dh-db1' # type: str
|
SQLALCHEMY_DATABASE_URI = 'postgresql://localhost/dh-db1' # type: str
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
|
from ereuse_devicehub.marshmallow import NestedOn
|
||||||
|
from ereuse_devicehub.resources.enums import RamFormat, RamInterface
|
||||||
|
from ereuse_devicehub.resources.models import STR_BIG_SIZE, STR_SIZE
|
||||||
|
from ereuse_devicehub.resources.schemas import Thing, UnitCodes
|
||||||
from marshmallow import post_load, pre_load
|
from marshmallow import post_load, pre_load
|
||||||
from marshmallow.fields import Float, Integer, Str
|
from marshmallow.fields import Float, Integer, Str
|
||||||
from marshmallow.validate import Length, OneOf, Range
|
from marshmallow.validate import Length, OneOf, Range
|
||||||
from marshmallow_enum import EnumField
|
from marshmallow_enum import EnumField
|
||||||
from sqlalchemy.util import OrderedSet
|
from sqlalchemy.util import OrderedSet
|
||||||
|
|
||||||
from ereuse_devicehub.marshmallow import NestedOn
|
|
||||||
from ereuse_devicehub.resources.enums import RamFormat, RamInterface
|
|
||||||
from ereuse_devicehub.resources.models import STR_BIG_SIZE, STR_SIZE
|
|
||||||
from ereuse_devicehub.resources.schemas import Thing, UnitCodes
|
|
||||||
from teal.marshmallow import ValidationError
|
from teal.marshmallow import ValidationError
|
||||||
|
|
||||||
|
|
||||||
|
@ -52,11 +52,11 @@ class Device(Thing):
|
||||||
@post_load
|
@post_load
|
||||||
def validate_snapshot_events(self, data):
|
def validate_snapshot_events(self, data):
|
||||||
"""Validates that only snapshot-related events can be uploaded."""
|
"""Validates that only snapshot-related events can be uploaded."""
|
||||||
from ereuse_devicehub.resources.event.models import EraseBasic, Test, Rate, Install
|
from ereuse_devicehub.resources.event.models import EraseBasic, Test, Rate, Install, \
|
||||||
|
Benchmark
|
||||||
for event in data['events_one']:
|
for event in data['events_one']:
|
||||||
if not isinstance(event, (Install, EraseBasic, Rate, Test)):
|
if not isinstance(event, (Install, EraseBasic, Rate, Test, Benchmark)):
|
||||||
raise ValidationError('You cannot upload {}'.format(event['type']),
|
raise ValidationError('You cannot upload {}'.format(event), field_names=['events'])
|
||||||
field_names='events')
|
|
||||||
|
|
||||||
|
|
||||||
class Computer(Device):
|
class Computer(Device):
|
||||||
|
|
|
@ -2,14 +2,15 @@ from contextlib import suppress
|
||||||
from itertools import groupby
|
from itertools import groupby
|
||||||
from typing import Iterable, Set
|
from typing import Iterable, Set
|
||||||
|
|
||||||
from sqlalchemy import inspect
|
|
||||||
from sqlalchemy.util import OrderedSet
|
|
||||||
|
|
||||||
from ereuse_devicehub.db import db
|
from ereuse_devicehub.db import db
|
||||||
from ereuse_devicehub.resources.device.exceptions import NeedsId
|
from ereuse_devicehub.resources.device.exceptions import NeedsId
|
||||||
from ereuse_devicehub.resources.device.models import Component, Computer, Device
|
from ereuse_devicehub.resources.device.models import Component, Computer, Device
|
||||||
from ereuse_devicehub.resources.event.models import Remove
|
from ereuse_devicehub.resources.event.models import Remove
|
||||||
from ereuse_devicehub.resources.tag.model import Tag
|
from ereuse_devicehub.resources.tag.model import Tag
|
||||||
|
from sqlalchemy import inspect
|
||||||
|
from sqlalchemy.exc import IntegrityError
|
||||||
|
from sqlalchemy.util import OrderedSet
|
||||||
|
|
||||||
from teal.db import ResourceNotFound
|
from teal.db import ResourceNotFound
|
||||||
from teal.marshmallow import ValidationError
|
from teal.marshmallow import ValidationError
|
||||||
|
|
||||||
|
@ -153,7 +154,10 @@ class Sync:
|
||||||
if device.hid:
|
if device.hid:
|
||||||
with suppress(ResourceNotFound):
|
with suppress(ResourceNotFound):
|
||||||
db_device = Device.query.filter_by(hid=device.hid).one()
|
db_device = Device.query.filter_by(hid=device.hid).one()
|
||||||
|
try:
|
||||||
tags = {Tag.query.filter_by(id=tag.id).one() for tag in device.tags} # type: Set[Tag]
|
tags = {Tag.query.filter_by(id=tag.id).one() for tag in device.tags} # type: Set[Tag]
|
||||||
|
except ResourceNotFound:
|
||||||
|
raise ResourceNotFound('tag you are linking to device {}'.format(device))
|
||||||
linked_tags = {tag for tag in tags if tag.device_id} # type: Set[Tag]
|
linked_tags = {tag for tag in tags if tag.device_id} # type: Set[Tag]
|
||||||
if linked_tags:
|
if linked_tags:
|
||||||
sample_tag = next(iter(linked_tags))
|
sample_tag = next(iter(linked_tags))
|
||||||
|
@ -172,7 +176,18 @@ class Sync:
|
||||||
db.session.add(device)
|
db.session.add(device)
|
||||||
db_device = device
|
db_device = device
|
||||||
db_device.tags |= tags # Union of tags the device had plus the (potentially) new ones
|
db_device.tags |= tags # Union of tags the device had plus the (potentially) new ones
|
||||||
|
try:
|
||||||
db.session.flush()
|
db.session.flush()
|
||||||
|
except IntegrityError as e:
|
||||||
|
# Manage 'one tag per organization' unique constraint
|
||||||
|
if 'One tag per organization' in e.args[0]:
|
||||||
|
# todo test for this
|
||||||
|
id = int(e.args[0][135:e.args[0].index(',', 135)])
|
||||||
|
raise ValidationError('The device is already linked to tag {} '
|
||||||
|
'from the same organization.'.format(id),
|
||||||
|
field_names=['device.tags'])
|
||||||
|
else:
|
||||||
|
raise
|
||||||
assert db_device is not None
|
assert db_device is not None
|
||||||
return db_device
|
return db_device
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
from typing import Callable, Iterable, Tuple
|
from typing import Callable, Iterable, Tuple
|
||||||
|
|
||||||
from ereuse_devicehub.resources.device.sync import Sync
|
from ereuse_devicehub.resources.device.sync import Sync
|
||||||
from ereuse_devicehub.resources.event.schemas import Add, AggregateRate, EraseBasic, Event, \
|
from ereuse_devicehub.resources.event.schemas import Add, AggregateRate, Benchmark, \
|
||||||
Install, PhotoboxSystemRate, PhotoboxUserRate, Rate, Remove, Snapshot, Step, StepRandom, \
|
BenchmarkDataStorage, BenchmarkProcessor, BenchmarkProcessorSysbench, BenchmarkRamSysbench, \
|
||||||
StepZero, Test, TestDataStorage, WorkbenchRate, EraseSectors
|
BenchmarkWithRate, EraseBasic, EraseSectors, Event, Install, PhotoboxSystemRate, \
|
||||||
|
PhotoboxUserRate, Rate, Remove, Snapshot, Step, StepRandom, StepZero, StressTest, Test, \
|
||||||
|
TestDataStorage, WorkbenchRate
|
||||||
from ereuse_devicehub.resources.event.views import EventView, SnapshotView
|
from ereuse_devicehub.resources.event.views import EventView, SnapshotView
|
||||||
from teal.resource import Converters, Resource
|
from teal.resource import Converters, Resource
|
||||||
|
|
||||||
|
@ -85,3 +87,31 @@ class TestDef(EventDef):
|
||||||
|
|
||||||
class TestDataStorageDef(TestDef):
|
class TestDataStorageDef(TestDef):
|
||||||
SCHEMA = TestDataStorage
|
SCHEMA = TestDataStorage
|
||||||
|
|
||||||
|
|
||||||
|
class StressTestDef(TestDef):
|
||||||
|
SCHEMA = StressTest
|
||||||
|
|
||||||
|
|
||||||
|
class BenchmarkDef(EventDef):
|
||||||
|
SCHEMA = Benchmark
|
||||||
|
|
||||||
|
|
||||||
|
class BenchmarkDataStorageDef(BenchmarkDef):
|
||||||
|
SCHEMA = BenchmarkDataStorage
|
||||||
|
|
||||||
|
|
||||||
|
class BenchmarkWithRateDef(BenchmarkDef):
|
||||||
|
SCHEMA = BenchmarkWithRate
|
||||||
|
|
||||||
|
|
||||||
|
class BenchmarkProcessorDef(BenchmarkWithRateDef):
|
||||||
|
SCHEMA = BenchmarkProcessor
|
||||||
|
|
||||||
|
|
||||||
|
class BenchmarkProcessorSysbenchDef(BenchmarkProcessorDef):
|
||||||
|
SCHEMA = BenchmarkProcessorSysbench
|
||||||
|
|
||||||
|
|
||||||
|
class BenchmarkRamSysbenchDef(BenchmarkWithRateDef):
|
||||||
|
SCHEMA = BenchmarkRamSysbench
|
||||||
|
|
|
@ -2,6 +2,14 @@ from collections import Iterable
|
||||||
from typing import Set, Union
|
from typing import Set, Union
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
||||||
|
from ereuse_devicehub.db import db
|
||||||
|
from ereuse_devicehub.resources.device.models import Component, Computer, DataStorage, Device
|
||||||
|
from ereuse_devicehub.resources.enums import AppearanceRange, BOX_RATE_3, BOX_RATE_5, Bios, \
|
||||||
|
FunctionalityRange, RATE_NEGATIVE, RATE_POSITIVE, RatingRange, RatingSoftware, \
|
||||||
|
SnapshotExpectedEvents, SnapshotSoftware, TestHardDriveLength
|
||||||
|
from ereuse_devicehub.resources.image.models import Image
|
||||||
|
from ereuse_devicehub.resources.models import STR_BIG_SIZE, STR_SIZE, STR_SM_SIZE, Thing
|
||||||
|
from ereuse_devicehub.resources.user.models import User
|
||||||
from flask import g
|
from flask import g
|
||||||
from sqlalchemy import BigInteger, Boolean, CheckConstraint, Column, DateTime, Enum as DBEnum, \
|
from sqlalchemy import BigInteger, Boolean, CheckConstraint, Column, DateTime, Enum as DBEnum, \
|
||||||
Float, ForeignKey, Interval, JSON, SmallInteger, Unicode, event
|
Float, ForeignKey, Interval, JSON, SmallInteger, Unicode, event
|
||||||
|
@ -12,14 +20,6 @@ from sqlalchemy.orm import backref, relationship
|
||||||
from sqlalchemy.orm.events import AttributeEvents as Events
|
from sqlalchemy.orm.events import AttributeEvents as Events
|
||||||
from sqlalchemy.util import OrderedSet
|
from sqlalchemy.util import OrderedSet
|
||||||
|
|
||||||
from ereuse_devicehub.db import db
|
|
||||||
from ereuse_devicehub.resources.device.models import Component, Computer, DataStorage, Device
|
|
||||||
from ereuse_devicehub.resources.enums import AppearanceRange, BOX_RATE_3, BOX_RATE_5, Bios, \
|
|
||||||
FunctionalityRange, RATE_NEGATIVE, RATE_POSITIVE, RatingRange, RatingSoftware, \
|
|
||||||
SnapshotExpectedEvents, SnapshotSoftware, TestHardDriveLength
|
|
||||||
from ereuse_devicehub.resources.image.models import Image
|
|
||||||
from ereuse_devicehub.resources.models import STR_BIG_SIZE, STR_SIZE, STR_SM_SIZE, Thing
|
|
||||||
from ereuse_devicehub.resources.user.models import User
|
|
||||||
from teal.db import ArrayOfEnum, CASCADE, CASCADE_OWN, INHERIT_COND, POLYMORPHIC_ID, \
|
from teal.db import ArrayOfEnum, CASCADE, CASCADE_OWN, INHERIT_COND, POLYMORPHIC_ID, \
|
||||||
POLYMORPHIC_ON, StrictVersionType, check_range
|
POLYMORPHIC_ON, StrictVersionType, check_range
|
||||||
|
|
||||||
|
@ -46,6 +46,8 @@ class Event(Thing):
|
||||||
closed.comment = """
|
closed.comment = """
|
||||||
Whether the author has finished the event.
|
Whether the author has finished the event.
|
||||||
After this is set to True, no modifications are allowed.
|
After this is set to True, no modifications are allowed.
|
||||||
|
|
||||||
|
By default are events are closed when performed.
|
||||||
"""
|
"""
|
||||||
error = Column(Boolean, default=False, nullable=False)
|
error = Column(Boolean, default=False, nullable=False)
|
||||||
error.comment = """
|
error.comment = """
|
||||||
|
@ -392,7 +394,7 @@ class StressTest(Test):
|
||||||
|
|
||||||
|
|
||||||
class Benchmark(JoinedTableMixin, EventWithOneDevice):
|
class Benchmark(JoinedTableMixin, EventWithOneDevice):
|
||||||
pass
|
elapsed = Column(Interval)
|
||||||
|
|
||||||
|
|
||||||
class BenchmarkDataStorage(Benchmark):
|
class BenchmarkDataStorage(Benchmark):
|
||||||
|
|
|
@ -1,9 +1,3 @@
|
||||||
from flask import current_app as app
|
|
||||||
from marshmallow import ValidationError, validates_schema
|
|
||||||
from marshmallow.fields import Boolean, DateTime, Float, Integer, Nested, String, TimeDelta, UUID
|
|
||||||
from marshmallow.validate import Length, Range
|
|
||||||
from marshmallow_enum import EnumField
|
|
||||||
|
|
||||||
from ereuse_devicehub.marshmallow import NestedOn
|
from ereuse_devicehub.marshmallow import NestedOn
|
||||||
from ereuse_devicehub.resources.device.schemas import Component, Device
|
from ereuse_devicehub.resources.device.schemas import Component, Device
|
||||||
from ereuse_devicehub.resources.enums import AppearanceRange, Bios, FunctionalityRange, \
|
from ereuse_devicehub.resources.enums import AppearanceRange, Bios, FunctionalityRange, \
|
||||||
|
@ -12,6 +6,13 @@ from ereuse_devicehub.resources.event import models as m
|
||||||
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
|
from ereuse_devicehub.resources.schemas import Thing
|
||||||
from ereuse_devicehub.resources.user.schemas import User
|
from ereuse_devicehub.resources.user.schemas import User
|
||||||
|
from flask import current_app as app
|
||||||
|
from marshmallow import ValidationError, validates_schema
|
||||||
|
from marshmallow.fields import Boolean, DateTime, Float, Integer, List, Nested, String, TimeDelta, \
|
||||||
|
UUID
|
||||||
|
from marshmallow.validate import Length, Range
|
||||||
|
from marshmallow_enum import EnumField
|
||||||
|
|
||||||
from teal.marshmallow import Version
|
from teal.marshmallow import Version
|
||||||
from teal.resource import Schema
|
from teal.resource import Schema
|
||||||
|
|
||||||
|
@ -26,6 +27,7 @@ class Event(Thing):
|
||||||
components = NestedOn(Component, dump_only=True, many=True)
|
components = NestedOn(Component, dump_only=True, many=True)
|
||||||
description = String(default='', description=m.Event.description.comment)
|
description = String(default='', description=m.Event.description.comment)
|
||||||
author = NestedOn(User, dump_only=True, exclude=('token',))
|
author = NestedOn(User, dump_only=True, exclude=('token',))
|
||||||
|
closed = Boolean(missing=True, description=m.Event.closed.comment)
|
||||||
|
|
||||||
|
|
||||||
class EventWithOneDevice(Event):
|
class EventWithOneDevice(Event):
|
||||||
|
@ -157,7 +159,7 @@ class WorkbenchRate(IndividualRate):
|
||||||
|
|
||||||
|
|
||||||
class Install(EventWithOneDevice):
|
class Install(EventWithOneDevice):
|
||||||
name = String(validate=Length(STR_BIG_SIZE),
|
name = String(validate=Length(min=4, max=STR_BIG_SIZE),
|
||||||
required=True,
|
required=True,
|
||||||
description='The name of the OS installed.')
|
description='The name of the OS installed.')
|
||||||
elapsed = TimeDelta(precision=TimeDelta.SECONDS, required=True)
|
elapsed = TimeDelta(precision=TimeDelta.SECONDS, required=True)
|
||||||
|
@ -176,12 +178,12 @@ class Snapshot(EventWithOneDevice):
|
||||||
description='The software that generated this Snapshot.')
|
description='The software that generated this Snapshot.')
|
||||||
version = Version(required=True, description='The version of the software.')
|
version = Version(required=True, description='The version of the software.')
|
||||||
events = NestedOn(Event, many=True, dump_only=True)
|
events = NestedOn(Event, many=True, dump_only=True)
|
||||||
expected_events = EnumField(SnapshotExpectedEvents,
|
expected_events = List(EnumField(SnapshotExpectedEvents),
|
||||||
many=True,
|
|
||||||
data_key='expectedEvents',
|
data_key='expectedEvents',
|
||||||
description='Keep open this Snapshot until the following events'
|
description='Keep open this Snapshot until the following events'
|
||||||
'are performed. Setting this value will activate'
|
'are performed. Setting this value will activate'
|
||||||
'the async Snapshot.')
|
'the async Snapshot.')
|
||||||
|
|
||||||
device = NestedOn(Device)
|
device = NestedOn(Device)
|
||||||
elapsed = TimeDelta(precision=TimeDelta.SECONDS, required=True)
|
elapsed = TimeDelta(precision=TimeDelta.SECONDS, required=True)
|
||||||
components = NestedOn(Component,
|
components = NestedOn(Component,
|
||||||
|
@ -217,8 +219,42 @@ class TestDataStorage(Test):
|
||||||
length = EnumField(TestHardDriveLength, required=True)
|
length = EnumField(TestHardDriveLength, required=True)
|
||||||
status = String(validate=Length(max=STR_SIZE), required=True)
|
status = String(validate=Length(max=STR_SIZE), required=True)
|
||||||
lifetime = TimeDelta(precision=TimeDelta.DAYS, required=True)
|
lifetime = TimeDelta(precision=TimeDelta.DAYS, required=True)
|
||||||
first_error = Integer()
|
first_error = Integer(missing=0, data_key='firstError')
|
||||||
|
passed_lifetime = TimeDelta(precision=TimeDelta.DAYS, data_key='passedLifetime')
|
||||||
|
assessment = Boolean()
|
||||||
|
reallocated_sector_count = Integer(data_key='reallocatedSectorCount')
|
||||||
|
power_cycle_count = Integer(data_key='powerCycleCount')
|
||||||
|
reported_uncorrectable_errors = Integer(data_key='reportedUncorrectableErrors')
|
||||||
|
command_timeout = Integer(data_key='commandTimeout')
|
||||||
|
current_pending_sector_count = Integer(data_key='currentPendingSectorCount')
|
||||||
|
offline_uncorrectable = Integer(data_key='offlineUncorrectable')
|
||||||
|
remaining_lifetime_percentage = Integer(data_key='remainingLifetimePercentage')
|
||||||
|
|
||||||
|
|
||||||
class StressTest(Test):
|
class StressTest(Test):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Benchmark(EventWithOneDevice):
|
||||||
|
elapsed = TimeDelta(precision=TimeDelta.SECONDS)
|
||||||
|
|
||||||
|
|
||||||
|
class BenchmarkDataStorage(Benchmark):
|
||||||
|
read_speed = Float(required=True, data_key='readSpeed')
|
||||||
|
write_speed = Float(required=True, data_key='writeSpeed')
|
||||||
|
|
||||||
|
|
||||||
|
class BenchmarkWithRate(Benchmark):
|
||||||
|
rate = Integer(required=True)
|
||||||
|
|
||||||
|
|
||||||
|
class BenchmarkProcessor(BenchmarkWithRate):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class BenchmarkProcessorSysbench(BenchmarkProcessor):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class BenchmarkRamSysbench(BenchmarkWithRate):
|
||||||
|
pass
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
from uuid import UUID
|
||||||
|
|
||||||
|
from boltons.urlutils import URL
|
||||||
|
from sqlalchemy import Column
|
||||||
|
from sqlalchemy.orm import relationship
|
||||||
|
|
||||||
|
from ereuse_devicehub.resources.device.models import Device
|
||||||
|
from ereuse_devicehub.resources.models import Thing
|
||||||
|
|
||||||
|
|
||||||
|
class Tag(Thing):
|
||||||
|
id = ... # type: Column
|
||||||
|
org_id = ... # type: Column
|
||||||
|
org = ... # type: relationship
|
||||||
|
provider = ... # type: Column
|
||||||
|
device_id = ... # type: Column
|
||||||
|
device = ... # type: relationship
|
||||||
|
|
||||||
|
def __init__(self, **kwargs) -> None:
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self.id = ... # type: str
|
||||||
|
self.org_id = ... # type: UUID
|
||||||
|
self.provider = ... # type: URL
|
||||||
|
self.device_id = ... # type: int
|
||||||
|
self.device = ... # type: Device
|
|
@ -1,12 +1,11 @@
|
||||||
from flask import Response, current_app as app, request
|
from flask import Response, current_app as app, request
|
||||||
from marshmallow import Schema
|
|
||||||
from marshmallow.fields import List, String, URL
|
from marshmallow.fields import List, String, URL
|
||||||
from webargs.flaskparser import parser
|
from webargs.flaskparser import parser
|
||||||
|
|
||||||
from ereuse_devicehub.resources.device.models import Device
|
from ereuse_devicehub.resources.device.models import Device
|
||||||
from ereuse_devicehub.resources.tag import Tag
|
from ereuse_devicehub.resources.tag import Tag
|
||||||
from teal.marshmallow import ValidationError
|
from teal.marshmallow import ValidationError
|
||||||
from teal.resource import View
|
from teal.resource import View, Schema
|
||||||
|
|
||||||
|
|
||||||
class TagView(View):
|
class TagView(View):
|
||||||
|
|
|
@ -9,8 +9,8 @@ type: 'Snapshot'
|
||||||
uuid: 'cb8ce6b5-6a1b-4084-b5b9-d8fadad2a015'
|
uuid: 'cb8ce6b5-6a1b-4084-b5b9-d8fadad2a015'
|
||||||
version: '11.0'
|
version: '11.0'
|
||||||
software: 'Workbench'
|
software: 'Workbench'
|
||||||
startTime: '2018-06-08T17:52:00'
|
|
||||||
expectedEvents: ['TestDataStorage', 'StressTest', 'EraseSectors', 'Install']
|
expectedEvents: ['TestDataStorage', 'StressTest', 'EraseSectors', 'Install']
|
||||||
|
elapsed: 500
|
||||||
device:
|
device:
|
||||||
type: 'Microtower'
|
type: 'Microtower'
|
||||||
serialNumber: 'd1s'
|
serialNumber: 'd1s'
|
||||||
|
@ -19,8 +19,6 @@ device:
|
||||||
tags:
|
tags:
|
||||||
- type: 'Tag'
|
- type: 'Tag'
|
||||||
id: 'tag1'
|
id: 'tag1'
|
||||||
- type: 'Tag'
|
|
||||||
id: 'tag2'
|
|
||||||
events:
|
events:
|
||||||
- type: 'WorkbenchRate'
|
- type: 'WorkbenchRate'
|
||||||
appearanceRange: 'A'
|
appearanceRange: 'A'
|
||||||
|
@ -43,7 +41,7 @@ components:
|
||||||
- type: 'Processor'
|
- type: 'Processor'
|
||||||
model: 'p1-1s'
|
model: 'p1-1s'
|
||||||
manufacturer: 'p1-1mr'
|
manufacturer: 'p1-1mr'
|
||||||
benchmarks:
|
events:
|
||||||
- type: 'BenchmarkProcessor'
|
- type: 'BenchmarkProcessor'
|
||||||
rate: 2410
|
rate: 2410
|
||||||
- type: 'BenchmarkProcessorSysbench'
|
- type: 'BenchmarkProcessorSysbench'
|
||||||
|
@ -52,18 +50,19 @@ components:
|
||||||
serialNumber: 'ssd1-1s'
|
serialNumber: 'ssd1-1s'
|
||||||
model: 'ssd1-1ml'
|
model: 'ssd1-1ml'
|
||||||
manufacturer: 'ssd1-1mr'
|
manufacturer: 'ssd1-1mr'
|
||||||
benchmark:
|
events:
|
||||||
type: 'BenchmarkDataStorage'
|
- type: 'BenchmarkDataStorage'
|
||||||
readingSpeed: 20
|
readSpeed: 20
|
||||||
writingSpeed: 15
|
writeSpeed: 15
|
||||||
test:
|
elapsed: 21
|
||||||
type: 'TestDataStorage'
|
- type: 'TestDataStorage'
|
||||||
|
elapsed: 233
|
||||||
firstError: 0
|
firstError: 0
|
||||||
error: False
|
error: False
|
||||||
status: 'Completed without error'
|
status: 'Completed without error'
|
||||||
length: 'Short'
|
length: 'Short'
|
||||||
lifetime: 99
|
lifetime: 99
|
||||||
passedLifeTime: 99
|
passedLifetime: 99
|
||||||
assessment: True
|
assessment: True
|
||||||
powerCycleCount: 11
|
powerCycleCount: 11
|
||||||
reallocatedSectorCount: 2
|
reallocatedSectorCount: 2
|
||||||
|
@ -77,10 +76,10 @@ components:
|
||||||
serialNumber: 'hdd1-1s'
|
serialNumber: 'hdd1-1s'
|
||||||
model: 'hdd1-1ml'
|
model: 'hdd1-1ml'
|
||||||
manufacturer: 'hdd1-1mr'
|
manufacturer: 'hdd1-1mr'
|
||||||
benchmark:
|
events:
|
||||||
type: 'BenchmarkDataStorage'
|
- type: 'BenchmarkDataStorage'
|
||||||
readingSpeed: 10
|
readSpeed: 10
|
||||||
writingSpeed: 5
|
writeSpeed: 5
|
||||||
- type: 'Motherboard'
|
- type: 'Motherboard'
|
||||||
serialNumber: 'mb1-1s'
|
serialNumber: 'mb1-1s'
|
||||||
model: 'mb1-1ml'
|
model: 'mb1-1ml'
|
||||||
|
|
|
@ -9,4 +9,4 @@
|
||||||
type: 'StressTest'
|
type: 'StressTest'
|
||||||
elapsed: 300
|
elapsed: 300
|
||||||
error: False
|
error: False
|
||||||
snapshot: None # fulfill!
|
# snapshot: None fulfill!
|
|
@ -8,8 +8,8 @@
|
||||||
|
|
||||||
type: 'EraseSectors'
|
type: 'EraseSectors'
|
||||||
error: False
|
error: False
|
||||||
snapshot: None # fulfill!
|
# snapshot: None fulfill!
|
||||||
device: None # fulfill!
|
# device: None fulfill!
|
||||||
cleanWithZeros: False
|
cleanWithZeros: False
|
||||||
startTime: 2018-01-01T10:10:10
|
startTime: 2018-01-01T10:10:10
|
||||||
endTime: 2018-01-01T12:10:10
|
endTime: 2018-01-01T12:10:10
|
||||||
|
@ -19,3 +19,5 @@ steps:
|
||||||
startTime: '2018-01-01T10:10:10'
|
startTime: '2018-01-01T10:10:10'
|
||||||
endTime: '2018-01-01T12:10:10'
|
endTime: '2018-01-01T12:10:10'
|
||||||
error: False
|
error: False
|
||||||
|
cleanWithZeros: False
|
||||||
|
secureRandomSteps: 0
|
||||||
|
|
|
@ -9,6 +9,6 @@
|
||||||
type: 'Install'
|
type: 'Install'
|
||||||
elapsed: 420
|
elapsed: 420
|
||||||
error: False
|
error: False
|
||||||
snapshot: None # fulfill!
|
# snapshot: None fulfill!
|
||||||
device: None # fulfill!
|
# device: None fulfill!
|
||||||
name: 'LinuxMint 18.01 32b'
|
name: 'LinuxMint 18.01 32b'
|
|
@ -1,13 +1,52 @@
|
||||||
"""
|
"""
|
||||||
Tests that emulates the behaviour of a WorkbenchServer.
|
Tests that emulates the behaviour of a WorkbenchServer.
|
||||||
"""
|
"""
|
||||||
|
import pytest
|
||||||
from ereuse_devicehub.client import UserClient
|
from ereuse_devicehub.client import UserClient
|
||||||
from ereuse_devicehub.resources.device.models import Device
|
from ereuse_devicehub.resources.device.models import Device
|
||||||
from ereuse_devicehub.resources.event.models import EraseSectors, Install, Snapshot, \
|
from ereuse_devicehub.resources.event.models import EraseSectors, Install, Snapshot, \
|
||||||
StressTest
|
StressTest
|
||||||
|
from ereuse_devicehub.resources.tag.model import Tag
|
||||||
|
|
||||||
from tests.conftest import file
|
from tests.conftest import file
|
||||||
|
|
||||||
|
|
||||||
|
def test_workbench_server_condensed(user: UserClient):
|
||||||
|
"""
|
||||||
|
As :def:`.test_workbench_server_phases` but all the events
|
||||||
|
condensed in only one big ``Snapshot`` file, as described
|
||||||
|
in the docs.
|
||||||
|
"""
|
||||||
|
s = file('workbench-server-1.snapshot')
|
||||||
|
del s['expectedEvents']
|
||||||
|
s['device']['events'].append(file('workbench-server-2.stress-test'))
|
||||||
|
s['components'][4]['events'].extend((
|
||||||
|
file('workbench-server-3.erase'),
|
||||||
|
file('workbench-server-4.install')
|
||||||
|
))
|
||||||
|
s['components'][5]['events'] = [file('workbench-server-3.erase')]
|
||||||
|
# Create tags
|
||||||
|
user.post(res=Tag, query=[('ids', t['id']) for t in s['device']['tags']], data={})
|
||||||
|
snapshot, _ = user.post(res=Snapshot, data=s)
|
||||||
|
events = snapshot['events']
|
||||||
|
assert {(event['type'], event['device']) for event in events} == {
|
||||||
|
# todo missing Rate event aggregating the rates
|
||||||
|
('WorkbenchRate', 1),
|
||||||
|
('BenchmarkProcessorSysbench', 5),
|
||||||
|
('StressTest', 1),
|
||||||
|
('EraseSectors', 6),
|
||||||
|
('BenchmarkRamSysbench', 1),
|
||||||
|
('BenchmarkProcessor', 5),
|
||||||
|
('Install', 6),
|
||||||
|
('EraseSectors', 7),
|
||||||
|
('BenchmarkDataStorage', 6),
|
||||||
|
('TestDataStorage', 6)
|
||||||
|
}
|
||||||
|
assert snapshot['closed']
|
||||||
|
assert not snapshot['error']
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xfail(reason='Functionality not yet developed.')
|
||||||
def test_workbench_server_phases(user: UserClient):
|
def test_workbench_server_phases(user: UserClient):
|
||||||
"""
|
"""
|
||||||
Tests the phases described in the docs section `Snapshots from
|
Tests the phases described in the docs section `Snapshots from
|
||||||
|
@ -73,43 +112,3 @@ def test_workbench_server_phases(user: UserClient):
|
||||||
|
|
||||||
pc, _ = user.get(res=Device, item=snapshot['id'])
|
pc, _ = user.get(res=Device, item=snapshot['id'])
|
||||||
assert len(pc['events']) == 10 # todo shall I add child events?
|
assert len(pc['events']) == 10 # todo shall I add child events?
|
||||||
|
|
||||||
|
|
||||||
def test_workbench_server_condensed(user: UserClient):
|
|
||||||
"""
|
|
||||||
As :def:`.test_workbench_server_phases` but all the events
|
|
||||||
condensed in only one big ``Snapshot`` file, as described
|
|
||||||
in the docs.
|
|
||||||
"""
|
|
||||||
s = file('workbench-server-1.snapshot')
|
|
||||||
s['events'].append(file('workbench-server-2.stress-test'))
|
|
||||||
s['components'][5]['erasure'] = file('workbench-server-3.erase')
|
|
||||||
s['components'][5]['installation'] = file('workbench-server-4.install')
|
|
||||||
s['components'][6]['erasure'] = file('workbench-server-3.erase')
|
|
||||||
snapshot, _ = user.post(res=Snapshot, data=s)
|
|
||||||
events = snapshot['events']
|
|
||||||
assert events[0]['type'] == 'Rate'
|
|
||||||
assert events[0]['device'] == 1
|
|
||||||
assert events[0]['closed']
|
|
||||||
assert events[0]['type'] == 'WorkbenchRate'
|
|
||||||
assert events[0]['device'] == 1
|
|
||||||
assert events[1]['type'] == 'BenchmarkProcessor'
|
|
||||||
assert events[1]['device'] == 5
|
|
||||||
assert events[2]['type'] == 'BenchmarkProcessorSysbench'
|
|
||||||
assert events[2]['device'] == 5
|
|
||||||
assert events[3]['type'] == 'BenchmarkDataStorage'
|
|
||||||
assert events[3]['device'] == 6
|
|
||||||
assert events[4]['type'] == 'TestDataStorage'
|
|
||||||
assert events[4]['device'] == 6
|
|
||||||
assert events[4]['type'] == 'BenchmarkDataStorage'
|
|
||||||
assert events[4]['device'] == 7
|
|
||||||
assert events[5]['type'] == 'StressTest'
|
|
||||||
assert events[5]['device'] == 1
|
|
||||||
assert events[6]['type'] == 'EraseSectors'
|
|
||||||
assert events[6]['device'] == 6
|
|
||||||
assert events[7]['type'] == 'EraseSectors'
|
|
||||||
assert events[7]['device'] == 7
|
|
||||||
assert events[8]['type'] == 'Install'
|
|
||||||
assert events[8]['device'] == 6
|
|
||||||
assert snapshot['closed']
|
|
||||||
assert not snapshot['error']
|
|
||||||
|
|
Reference in New Issue