diff --git a/ereuse_devicehub/config.py b/ereuse_devicehub/config.py
index 251f72ce..edc54da7 100644
--- a/ereuse_devicehub/config.py
+++ b/ereuse_devicehub/config.py
@@ -39,12 +39,6 @@ class DevicehubConfig(Config):
}
API_DOC_CLASS_DISCRIMINATOR = 'type'
- # TODO is necessary??
- WORKBENCH_RATE_VERSION = StrictVersion('1.0')
- PHOTOBOX_RATE_VERSION = StrictVersion('1.0')
- """
- Official versions for WorkbenchRate and PhotoboxRate
- """
PRICE_SOFTWARE = PriceSoftware.Ereuse
PRICE_VERSION = StrictVersion('1.0')
PRICE_CURRENCY = Currency.EUR
diff --git a/ereuse_devicehub/dummy/files/asus-1001pxd.snapshot.11.yaml b/ereuse_devicehub/dummy/files/asus-1001pxd.snapshot.11.yaml
index e061af0f..a5af2694 100644
--- a/ereuse_devicehub/dummy/files/asus-1001pxd.snapshot.11.yaml
+++ b/ereuse_devicehub/dummy/files/asus-1001pxd.snapshot.11.yaml
@@ -164,7 +164,7 @@
{
"appearanceRange": "A",
"functionalityRange": "A",
- "type": "TestVisual"
+ "type": "VisualTest"
}
],
"manufacturer": "ASUSTeK Computer INC.",
diff --git a/ereuse_devicehub/dummy/files/asus-eee-1000h.snapshot.11.yaml b/ereuse_devicehub/dummy/files/asus-eee-1000h.snapshot.11.yaml
index 08b55c2e..de93be61 100644
--- a/ereuse_devicehub/dummy/files/asus-eee-1000h.snapshot.11.yaml
+++ b/ereuse_devicehub/dummy/files/asus-eee-1000h.snapshot.11.yaml
@@ -16,7 +16,7 @@
{
"appearanceRange": "A",
"functionalityRange": "A",
- "type": "TestVisual"
+ "type": "VisualTest"
}
],
"manufacturer": "ASUSTeK Computer INC."
diff --git a/ereuse_devicehub/dummy/files/computer-monitor.snapshot.yaml b/ereuse_devicehub/dummy/files/computer-monitor.snapshot.yaml
index 7236615b..3b02e128 100644
--- a/ereuse_devicehub/dummy/files/computer-monitor.snapshot.yaml
+++ b/ereuse_devicehub/dummy/files/computer-monitor.snapshot.yaml
@@ -11,7 +11,7 @@ device:
resolutionHeight: 1080
size: 21.5
events:
- - type: TestVisual
+ - type: VisualTest
appearanceRange: A
functionalityRange: C
labelling: False
diff --git a/ereuse_devicehub/dummy/files/dell-optiplexgx520.snapshot.11.yaml b/ereuse_devicehub/dummy/files/dell-optiplexgx520.snapshot.11.yaml
index a708ef55..98ae89a5 100644
--- a/ereuse_devicehub/dummy/files/dell-optiplexgx520.snapshot.11.yaml
+++ b/ereuse_devicehub/dummy/files/dell-optiplexgx520.snapshot.11.yaml
@@ -16,7 +16,7 @@
{
"appearanceRange": "A",
"functionalityRange": "A",
- "type": "TestVisual"
+ "type": "VisualTest"
}
],
"type": "Desktop",
diff --git a/ereuse_devicehub/dummy/files/keyboard.snapshot.yaml b/ereuse_devicehub/dummy/files/keyboard.snapshot.yaml
index 00ee55c0..e5e44ea6 100644
--- a/ereuse_devicehub/dummy/files/keyboard.snapshot.yaml
+++ b/ereuse_devicehub/dummy/files/keyboard.snapshot.yaml
@@ -8,7 +8,7 @@ device:
manufacturer: BAZ
layout: ES
events:
- - type: TestVisual
+ - type: VisualTest
appearanceRange: A
functionalityRange: A
labelling: False
diff --git a/ereuse_devicehub/dummy/files/nec.snapshot.11.yaml b/ereuse_devicehub/dummy/files/nec.snapshot.11.yaml
index 3723aed2..68ba4065 100644
--- a/ereuse_devicehub/dummy/files/nec.snapshot.11.yaml
+++ b/ereuse_devicehub/dummy/files/nec.snapshot.11.yaml
@@ -18,7 +18,7 @@
{
"appearanceRange": "B",
"functionalityRange": "C",
- "type": "TestVisual"
+ "type": "VisualTest"
}
],
"type": "Desktop",
diff --git a/ereuse_devicehub/dummy/files/pc-laudem.snapshot.11.yaml b/ereuse_devicehub/dummy/files/pc-laudem.snapshot.11.yaml
index 1bc00363..e6ce4df9 100644
--- a/ereuse_devicehub/dummy/files/pc-laudem.snapshot.11.yaml
+++ b/ereuse_devicehub/dummy/files/pc-laudem.snapshot.11.yaml
@@ -122,7 +122,7 @@
{
"appearanceRange": "A",
"functionalityRange": "A",
- "type": "TestVisual"
+ "type": "VisualTest"
}
],
"manufacturer": "Hewlett-Packard",
diff --git a/ereuse_devicehub/dummy/files/real-eee-1001pxd.snapshot.11.yaml b/ereuse_devicehub/dummy/files/real-eee-1001pxd.snapshot.11.yaml
index 987035d1..bb30132a 100644
--- a/ereuse_devicehub/dummy/files/real-eee-1001pxd.snapshot.11.yaml
+++ b/ereuse_devicehub/dummy/files/real-eee-1001pxd.snapshot.11.yaml
@@ -154,7 +154,7 @@
{
"appearanceRange": "B",
"functionalityRange": "A",
- "type": "TestVisual"
+ "type": "VisualTest"
}
]
},
diff --git a/ereuse_devicehub/dummy/files/real-hp.snapshot.11.yaml b/ereuse_devicehub/dummy/files/real-hp.snapshot.11.yaml
index 5cde0a35..cd8d15a3 100644
--- a/ereuse_devicehub/dummy/files/real-hp.snapshot.11.yaml
+++ b/ereuse_devicehub/dummy/files/real-hp.snapshot.11.yaml
@@ -157,7 +157,7 @@
{
"appearanceRange": "B",
"functionalityRange": "D",
- "type": "TestVisual"
+ "type": "VisualTest"
}
],
"serialNumber": "CZC0408YJG",
diff --git a/ereuse_devicehub/dummy/files/smartphone.snapshot.yaml b/ereuse_devicehub/dummy/files/smartphone.snapshot.yaml
index 04c4874f..63be0f3d 100644
--- a/ereuse_devicehub/dummy/files/smartphone.snapshot.yaml
+++ b/ereuse_devicehub/dummy/files/smartphone.snapshot.yaml
@@ -8,7 +8,7 @@ device:
serialNumber: ABCDEF
imei: 35686800-004141-20
events:
- - type: TestVisual
+ - type: VisualTest
appearanceRange: A
functionalityRange: B
labelling: False
diff --git a/ereuse_devicehub/dummy/files/workbench-server-1.snapshot.yaml b/ereuse_devicehub/dummy/files/workbench-server-1.snapshot.yaml
index 9a31c355..c5a99cb3 100644
--- a/ereuse_devicehub/dummy/files/workbench-server-1.snapshot.yaml
+++ b/ereuse_devicehub/dummy/files/workbench-server-1.snapshot.yaml
@@ -18,90 +18,90 @@ device:
model: d1ml
manufacturer: d1mr
tags:
- - type: Tag
- id: tag1
+ - type: Tag
+ id: tag1
events:
- - type: TestVisual
+ - type: VisualTest
appearanceRange: A
functionalityRange: B
- type: BenchmarkRamSysbench
rate: 2444
elapsed: 1
components:
-- type: GraphicCard
- serialNumber: gc1-1s
- model: gc1-1ml
- manufacturer: gc1-1mr
-- type: RamModule
- serialNumber: rm1-1s
- model: rm1-1ml
- manufacturer: rm1-1mr
- size: 1024
-- type: RamModule
- serialNumber: rm2-1s
- model: rm2-1ml
- manufacturer: rm2-1mr
- size: 1024
-- type: Processor
- model: p1-1ml
- manufacturer: p1-1mr
- events:
- - type: BenchmarkProcessor
- rate: 2410
- elapsed: 44
- - type: BenchmarkProcessorSysbench
- rate: 4400
- elapsed: 44
-- type: SolidStateDrive
- serialNumber: ssd1-1s
- model: ssd1-1ml
- manufacturer: ssd1-1mr
- size: 1100
- events:
- - type: BenchmarkDataStorage
- readSpeed: 20
- writeSpeed: 15
- elapsed: 21
- - type: TestDataStorage
- elapsed: 233
- severity: Info
- status: Completed without error
- length: Short
- lifetime: 99
- assessment: True
- powerCycleCount: 11
- reallocatedSectorCount: 2
- reportedUncorrectableErrors: 1
- commandTimeout: 11
- currentPendingSectorCount: 1
- offlineUncorrectable: 33
- remainingLifetimePercentage: 1
-- type: HardDrive
- serialNumber: hdd1-1s
- model: hdd1-1ml
- manufacturer: hdd1-1mr
- events:
- - type: BenchmarkDataStorage
- readSpeed: 10
- writeSpeed: 5
- elapsed: 20
-- type: Motherboard
- serialNumber: mb1-1s
- model: mb1-1ml
- manufacturer: mb1-1mr
-- type: NetworkAdapter
- serialNumber: na1-s
- model: na1-1ml
- manufacturer: na1-1mr
- speed: 1000
- wireless: False
-- type: NetworkAdapter
- serialNumber: na2-s
- model: na2-1ml
- manufacturer: na2-1mr
- wireless: True
- speed: 58
-- type: RamModule
- serialNumber: rm3-1s
- model: rm3-1ml
- manufacturer: rm3-1mr
+ - type: GraphicCard
+ serialNumber: gc1-1s
+ model: gc1-1ml
+ manufacturer: gc1-1mr
+ - type: RamModule
+ serialNumber: rm1-1s
+ model: rm1-1ml
+ manufacturer: rm1-1mr
+ size: 1024
+ - type: RamModule
+ serialNumber: rm2-1s
+ model: rm2-1ml
+ manufacturer: rm2-1mr
+ size: 1024
+ - type: Processor
+ model: p1-1ml
+ manufacturer: p1-1mr
+ events:
+ - type: BenchmarkProcessor
+ rate: 2410
+ elapsed: 44
+ - type: BenchmarkProcessorSysbench
+ rate: 4400
+ elapsed: 44
+ - type: SolidStateDrive
+ serialNumber: ssd1-1s
+ model: ssd1-1ml
+ manufacturer: ssd1-1mr
+ size: 1100
+ events:
+ - type: BenchmarkDataStorage
+ readSpeed: 20
+ writeSpeed: 15
+ elapsed: 21
+ - type: TestDataStorage
+ elapsed: 233
+ severity: Info
+ status: Completed without error
+ length: Short
+ lifetime: 99
+ assessment: True
+ powerCycleCount: 11
+ reallocatedSectorCount: 2
+ reportedUncorrectableErrors: 1
+ commandTimeout: 11
+ currentPendingSectorCount: 1
+ offlineUncorrectable: 33
+ remainingLifetimePercentage: 1
+ - type: HardDrive
+ serialNumber: hdd1-1s
+ model: hdd1-1ml
+ manufacturer: hdd1-1mr
+ events:
+ - type: BenchmarkDataStorage
+ readSpeed: 10
+ writeSpeed: 5
+ elapsed: 20
+ - type: Motherboard
+ serialNumber: mb1-1s
+ model: mb1-1ml
+ manufacturer: mb1-1mr
+ - type: NetworkAdapter
+ serialNumber: na1-s
+ model: na1-1ml
+ manufacturer: na1-1mr
+ speed: 1000
+ wireless: False
+ - type: NetworkAdapter
+ serialNumber: na2-s
+ model: na2-1ml
+ manufacturer: na2-1mr
+ wireless: True
+ speed: 58
+ - type: RamModule
+ serialNumber: rm3-1s
+ model: rm3-1ml
+ manufacturer: rm3-1mr
diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py
index b84e2dcc..29c0a39c 100644
--- a/ereuse_devicehub/resources/device/models.py
+++ b/ereuse_devicehub/resources/device/models.py
@@ -422,8 +422,7 @@ class Computer(Device):
1. The max Ethernet speed of the computer, 0 if ethernet
adaptor exists but its speed is unknown, None if no eth
- adaptor exists.# TODO add all grade tables (chassis defects, camera defects, buttons test, connectivity, ..)
-
+ adaptor exists.
2. The max WiFi speed of the computer, 0 if computer has
WiFi but its speed is unknown, None if no WiFi adaptor
exists.
diff --git a/ereuse_devicehub/resources/device/models.pyi b/ereuse_devicehub/resources/device/models.pyi
index fcc7509b..d1956a3a 100644
--- a/ereuse_devicehub/resources/device/models.pyi
+++ b/ereuse_devicehub/resources/device/models.pyi
@@ -42,7 +42,7 @@ class Device(Thing):
production_date = ... # type: Column
brand = ... # type: Column
generation = ... # type: Column
- variant = ... # type: Column
+ variant = ... # type: Column
def __init__(self, **kwargs) -> None:
super().__init__(**kwargs)
@@ -65,7 +65,7 @@ class Device(Thing):
self.production_date = ... # type: Optional[datetime]
self.brand = ... # type: Optional[str]
self.generation = ... # type: Optional[int]
- self.variant = ... # type: Optional[str]
+ self.variant = ... # type: Optional[str]
@property
def events(self) -> List[e.Event]:
@@ -202,15 +202,15 @@ class TelevisionSet(Monitor):
class Mobile(Device):
imei = ... # type: Column
meid = ... # type: Column
- ram_size = ... # type: Column
- data_storage_size = ... # type: Column
+ ram_size = ... # type: Column
+ data_storage_size = ... # type: Column
def __init__(self, **kwargs) -> None:
super().__init__(**kwargs)
self.imei = ... # type: Optional[int]
self.meid = ... # type: Optional[str]
- self.ram_size = ... # type: Optional[int]
- self.data_storage_size = ... # type: Optional[int]
+ self.ram_size = ... # type: Optional[int]
+ self.data_storage_size = ... # type: Optional[int]
class Smartphone(Mobile):
diff --git a/ereuse_devicehub/resources/device/schemas.py b/ereuse_devicehub/resources/device/schemas.py
index a5776adb..17b010f3 100644
--- a/ereuse_devicehub/resources/device/schemas.py
+++ b/ereuse_devicehub/resources/device/schemas.py
@@ -183,7 +183,6 @@ class Mobile(Device):
data_key='dataStorageSize',
description=m.Mobile.data_storage_size)
-
@pre_load
def convert_check_imei(self, data):
if data.get('imei', None):
diff --git a/ereuse_devicehub/resources/device/templates/devices/macros.html b/ereuse_devicehub/resources/device/templates/devices/macros.html
index 9d13c11b..fdd9d5e7 100644
--- a/ereuse_devicehub/resources/device/templates/devices/macros.html
+++ b/ereuse_devicehub/resources/device/templates/devices/macros.html
@@ -1,18 +1,18 @@
{% macro component_type(components, type) %}
-
+
{% endmacro %}
{% macro rate(range) %}
-
+
{{ range }}
{% endmacro %}
diff --git a/ereuse_devicehub/resources/device/views.py b/ereuse_devicehub/resources/device/views.py
index bbe229d6..337628b9 100644
--- a/ereuse_devicehub/resources/device/views.py
+++ b/ereuse_devicehub/resources/device/views.py
@@ -31,9 +31,9 @@ class OfType(f.Str):
class RateQ(query.Query):
- rating = query.Between(events.Rate.rating, f.Float())
- appearance = query.Between(events.Rate.appearance, f.Float())
- functionality = query.Between(events.Rate.functionality, f.Float())
+ rating = query.Between(events.Rate._rating, f.Float())
+ appearance = query.Between(events.Rate._appearance, f.Float())
+ functionality = query.Between(events.Rate._functionality, f.Float())
class TagQ(query.Query):
diff --git a/ereuse_devicehub/resources/documents/device_row.py b/ereuse_devicehub/resources/documents/device_row.py
index 78e9575f..8a1e3a4c 100644
--- a/ereuse_devicehub/resources/documents/device_row.py
+++ b/ereuse_devicehub/resources/documents/device_row.py
@@ -3,7 +3,8 @@ from collections import OrderedDict
from flask import current_app
from ereuse_devicehub.resources.device import models as d
-from ereuse_devicehub.resources.event.models import TestDataStorage, BenchmarkDataStorage
+from ereuse_devicehub.resources.event.models import BenchmarkDataStorage, RateComputer, \
+ TestDataStorage
class DeviceRow(OrderedDict):
@@ -43,6 +44,7 @@ class DeviceRow(OrderedDict):
if rate:
self['Rate'] = rate.rating
self['Range'] = rate.rating_range
+ assert isinstance(rate, RateComputer)
self['Processor Rate'] = rate.processor
self['Processor Range'] = rate.processor_range
self['RAM Rate'] = rate.ram
@@ -92,15 +94,18 @@ class DeviceRow(OrderedDict):
self['{} {} Size (MB)'.format(type, i)] = component.size
self['{} {} Privacy'.format(type, i)] = component.privacy
try:
- self['{} {} Lifetime'.format(type, i)] = component.last_event_of(TestDataStorage).lifetime
+ self['{} {} Lifetime'.format(type, i)] = component.last_event_of(
+ TestDataStorage).lifetime
except:
self['{} {} Lifetime'.format(type, i)] = ''
try:
- self['{} {} Reading speed'.format(type, i)] = component.last_event_of(BenchmarkDataStorage).read_speed
+ self['{} {} Reading speed'.format(type, i)] = component.last_event_of(
+ BenchmarkDataStorage).read_speed
except:
self['{} {} Reading speed'.format(type, i)] = ''
try:
- self['{} {} Writing speed'.format(type, i)] = component.last_event_of(BenchmarkDataStorage).write_speed
+ self['{} {} Writing speed'.format(type, i)] = component.last_event_of(
+ BenchmarkDataStorage).write_speed
except:
self['{} {} Writing speed'.format(type, i)] = ''
diff --git a/ereuse_devicehub/resources/documents/documents.py b/ereuse_devicehub/resources/documents/documents.py
index f8402078..c30506f4 100644
--- a/ereuse_devicehub/resources/documents/documents.py
+++ b/ereuse_devicehub/resources/documents/documents.py
@@ -109,7 +109,6 @@ class DevicesDocumentView(DeviceView):
query = self.query(args)
return self.generate_post_csv(query)
- # TODO fix only put one row for device.t == computer (rewrite multiples_devices.csv)
def generate_post_csv(self, query):
"""
Get device query and put information in csv format
@@ -122,9 +121,9 @@ class DevicesDocumentView(DeviceView):
for device in query:
d = DeviceRow(device)
if first:
- cw.writerow(name for name in d.keys())
+ cw.writerow(d.keys())
first = False
- cw.writerow(v for v in d.values())
+ cw.writerow(d.values())
output = make_response(data.getvalue())
output.headers['Content-Disposition'] = 'attachment; filename=export.csv'
output.headers['Content-type'] = 'text/csv'
diff --git a/ereuse_devicehub/resources/enums.py b/ereuse_devicehub/resources/enums.py
index 47b38668..47278c27 100644
--- a/ereuse_devicehub/resources/enums.py
+++ b/ereuse_devicehub/resources/enums.py
@@ -1,5 +1,4 @@
from contextlib import suppress
-from distutils.version import StrictVersion
from enum import Enum, IntEnum, unique
from typing import Set, Union
@@ -18,8 +17,8 @@ class SnapshotSoftware(Enum):
return self.name
-RATE_POSITIVE = 0, 10
-RATE_NEGATIVE = -3, 5
+R_POSITIVE = 0, 10
+R_NEGATIVE = -3, 5
@unique
@@ -65,45 +64,30 @@ class PriceSoftware(Enum):
Ereuse = 'Ereuse'
-@unique
-class AggregateRatingVersions(Enum):
- v1 = StrictVersion('1.0')
- """
- This version is set to aggregate :class:`ereuse_devicehub.resources.
- event.models.RateComputer` version X and :class:`ereuse_devicehub.
- resources.event.models.PhotoboxRate` version Y.
- """
-
-
@unique
class AppearanceRange(Enum):
- """
- This grade will be defined based on the aesthetics/cosmetic aspects, like visual damage or blemishes principally
- focused on chassis, physical buttons and screens.
- """
+ """Grades the imperfections that aesthetically affect the device, but not its usage."""
Z = 'Z. The device is new'
A = 'A. Is like new; without visual damage'
B = 'B. Is in really good condition; small visual damage in difficult places to spot'
- C = 'C. Is in good condition; small visual damage in parts that are easy to spot, minor cosmetic blemishes on chassis)'
+ C = 'C. Is in good condition; small visual damage in parts that are easy to spot, minor cosmetic blemishes on chassis'
D = 'D. Is acceptable; visual damage in visible parts, major cosmetic blemishes on chassis, missing cosmetic parts'
- E = 'E. Is unacceptable; severity visual damage, missing essential parts'
- NONE = 'NA. Grade doesn’t exists'
+ E = 'E. Is unacceptable; considerable visual damage, missing essential parts'
-
-APPEARANCE_RANGE = 0.5, -0.3
+ def __str__(self):
+ return self.name
@unique
class FunctionalityRange(Enum):
- """Based on usage condition of a device and its functionality aspects, like screen defect or camera defects"""
+ """Grades the defects of a device that affect its usage."""
A = 'A. All the buttons works perfectly, no screen/camera defects and chassis without usage issues'
B = 'B. There is a button difficult to press or unstable it, a screen/camera defect or chassis problem'
C = 'C. Chassis defects or multiple buttons don\'t work; broken or unusable it, some screen/camera defect'
D = 'D. Chassis severity usage problems. All buttons, screen or camera don\'t work; broken or unusable it'
- NONE = 'NA. Grade doesn’t exists'
-
-FUNCTIONALITY_RANGE = 0.4, -0.3
+ def __str__(self):
+ return self.name
@unique
@@ -113,9 +97,11 @@ class BatteryHealthRange(Enum):
B = 'B. Battery health is good'
C = 'C. Battery health is overheat / over voltage status but can stand the minimum duration'
D = 'D. Battery health is bad; can’t stand the minimum duration time'
- E = 'E. Battery health is very bad; and status is dead; unusable or miss it '
+ E = 'E. Battery health is very bad; and status is dead; unusable or miss it'
NONE = 'NA. Grade doesn’t exists'
+ def __str__(self):
+ return self.name
@unique
@@ -127,6 +113,9 @@ class BiosAccessRange(Enum):
D = 'D. Like B or C, but you had to unlock the BIOS (i.e. by removing the battery)'
E = 'E. The device could not be booted through the network.'
+ def __str__(self):
+ return self.name
+
@unique
class Orientation(Enum):
diff --git a/ereuse_devicehub/resources/event/__init__.py b/ereuse_devicehub/resources/event/__init__.py
index 96843230..4155464a 100644
--- a/ereuse_devicehub/resources/event/__init__.py
+++ b/ereuse_devicehub/resources/event/__init__.py
@@ -109,11 +109,6 @@ class TestConnectivityDef(TestDef):
SCHEMA = schemas.TestConnectivity
-class TestBatteryDef(TestDef):
- VIEW = None
- SCHEMA = schemas.TestBattery
-
-
class TestCameraDef(TestDef):
VIEW = None
SCHEMA = schemas.TestCamera
@@ -134,9 +129,9 @@ class TestBiosDef(TestDef):
SCHEMA = schemas.TestBios
-class TestVisualDef(TestDef):
+class VisualTestDef(TestDef):
VIEW = None
- SCHEMA = schemas.TestVisual
+ SCHEMA = schemas.VisualTest
class RateDef(EventDef):
diff --git a/ereuse_devicehub/resources/event/models.py b/ereuse_devicehub/resources/event/models.py
index dc3164a3..71be088b 100644
--- a/ereuse_devicehub/resources/event/models.py
+++ b/ereuse_devicehub/resources/event/models.py
@@ -14,7 +14,7 @@ from collections import Iterable
from contextlib import suppress
from datetime import datetime, timedelta
from decimal import Decimal, ROUND_HALF_EVEN, ROUND_UP
-from typing import Optional, Set, Union, Tuple
+from typing import Optional, Set, Union
from uuid import uuid4
import inflection
@@ -40,10 +40,10 @@ from ereuse_devicehub.db import db
from ereuse_devicehub.resources.agent.models import Agent
from ereuse_devicehub.resources.device.models import Component, Computer, DataStorage, Desktop, \
Device, Laptop, Server
-from ereuse_devicehub.resources.enums import BiosAccessRange, ErasureStandards, \
- PhysicalErasureMethod, PriceSoftware, RATE_NEGATIVE, RATE_POSITIVE, \
- RatingRange, ReceiverRole, Severity, SnapshotExpectedEvents, SnapshotSoftware, \
- TestDataStorageLength, FunctionalityRange, AppearanceRange, BatteryHealthRange
+from ereuse_devicehub.resources.enums import AppearanceRange, BatteryHealth, BiosAccessRange, \
+ ErasureStandards, FunctionalityRange, PhysicalErasureMethod, PriceSoftware, \
+ R_NEGATIVE, R_POSITIVE, RatingRange, ReceiverRole, Severity, SnapshotExpectedEvents, \
+ SnapshotSoftware, TestDataStorageLength
from ereuse_devicehub.resources.models import STR_SM_SIZE, Thing
from ereuse_devicehub.resources.user.models import User
@@ -669,7 +669,6 @@ class TestMixin:
return Column(UUID(as_uuid=True), ForeignKey(Test.id), primary_key=True)
-
class MeasureBattery(TestMixin, Test):
"""A sample of the status of the battery.
@@ -708,7 +707,7 @@ class TestDataStorage(TestMixin, Test):
assessment = Column(Boolean)
reallocated_sector_count = Column(SmallInteger)
power_cycle_count = Column(SmallInteger)
- reported_uncorrectable_errors = Column(SmallInteger)
+ _reported_uncorrectable_errors = Column('reported_uncorrectable_errors', Integer)
command_timeout = Column(Integer)
current_pending_sector_count = Column(SmallInteger)
offline_uncorrectable = Column(SmallInteger)
@@ -737,6 +736,16 @@ class TestDataStorage(TestMixin, Test):
t += self.description
return t
+ @property
+ def reported_uncorrectable_errors(self):
+ return self._reported_uncorrectable_errors
+
+ @reported_uncorrectable_errors.setter
+ def reported_uncorrectable_errors(self, value):
+ # We assume that a huge number is not meaningful
+ # So we keep it like this
+ self._reported_uncorrectable_errors = min(value, db.PSQL_INT_MAX)
+
class StressTest(TestMixin, Test):
"""The act of stressing (putting to the maximum capacity)
@@ -760,95 +769,84 @@ class TestAudio(TestMixin, Test):
"""
Test to check all this aspects related with audio functions, Manual Tests??
"""
- loudspeaker = Column(Boolean)
- loudspeaker.comment = 'Test to determine if the speaker is working properly and what sound quality it has.'
- microphone = Column(Boolean)
- microphone.comment = 'This evaluate if microphone works correctly'
+ _speaker = Column('speaker', Boolean)
+ _speaker.comment = """Whether the speaker works as expected."""
+ _microphone = Column('microphone', Boolean)
+ _microphone.comment = """Whether the microphone works as expected."""
+
+ @property
+ def speaker(self):
+ return self._speaker
+
+ @speaker.setter
+ def speaker(self, x):
+ self._speaker = x
+ self._check()
+
+ @property
+ def microphone(self):
+ return self._microphone
+
+ @microphone.setter
+ def microphone(self, x):
+ self._microphone = x
+ self._check()
+
+ def _check(self):
+ """Sets ``severity`` to ``error`` if any of the variables fail."""
+ if not self._speaker or not self._microphone:
+ self.severity = Severity.Error
class TestConnectivity(TestMixin, Test):
- """
- Test to check all this aspects related with functionality connections in devices
- """
- # TODO Add Severity and return unique score
- cellular_network = Column(Boolean)
- cellular_network.comment = 'Evaluate if cellular network works properly'
- wifi = Column(Boolean)
- wifi.comment = 'Evaluate if wifi connection works correctly'
- bluetooth = Column(Boolean)
- bluetooth.comment = 'Evaluate if bluetooth works'
- usb_port = Column(Boolean)
- usb_port.comment = 'Evaluate if usb port was detected and charger plug works'
- locked = Column(Boolean)
- locked.comment = 'Test to check if devices is locked'
+ """Tests that the device can connect both physically and
+ wirelessly.
-
-class TestBattery(TestMixin, Test):
+ A failing test means that at least one connection of the device
+ is not working well. A comment should get into more detail.
"""
- Test battery health, status and length of charge. Minimum X minutes discharging the device
- """
- # TODO how to determinate if test PASS depend on battery stat and/or health
- battery_stat = Column(Boolean)
- battery_stat.comment = """
- Some batteries can report a self-check life status.
- """
- battery_health = Column(DBEnum(BatteryHealthRange))
- battery_health.comment = BatteryHealthRange.__doc__
class TestCamera(TestMixin, Test):
+ """Tests the working conditions of the camera of the device,
+ specially when taking pictures or recording video.
"""
- Test to determinate functionality and defects on camera when take pictures or record video
- # TODO define when test FAIL
- """
- camera = Column(Boolean)
- camera.comment = ""
class TestKeyboard(TestMixin, Test):
- """
- Test to determinate if keyboard layout are and works correctly
- # TODO define when test FAIL
- """
- keyboard = Column(Boolean)
- keyboard.comment = ""
+ """Whether the keyboard works correctly."""
class TestTrackpad(TestMixin, Test):
- """
- Test trackpad works correctly
- # TODO define when test FAIL
- """
- trackpad = Column(Boolean)
- trackpad.comment = ""
+ """Whether the trackpad works correctly."""
class TestBios(TestMixin, Test):
- """
- Test that determinate motherboard no beeps, codes or errors when power on.
- And a grade to reflect some possibles difficult to access or modify setting in the BIOS, like password protection..
- """
+ """Tests the working condition and grades the usability of the BIOS."""
bios_power_on = Column(Boolean)
- bios_power_on.comment = """
- Motherboards do a self check when powering up (R2 p.23), test PASS if no beeps, codes, or errors appears.
+ bios_power_on.comment = """Whether there are no beeps or error
+ codes when booting up.
+
+ Reference: R2 standard page 23.
"""
access_range = Column(DBEnum(BiosAccessRange))
- access_range.comment = 'Range of difficult to access BIOS'
+ access_range.comment = """Difficulty to modify the boot menu.
+
+ This is used as an usability measure for accessing and modifying
+ a bios, specially as something as important as modifying the boot
+ menu."""
-class TestVisual(TestMixin, Test):
- """
- Manual rate test its are represented with grade and focuses mainly on
- the aesthetic or cosmetic defects of important parts of a device.
- Like defects on chassis, display, ..
+class VisualTest(TestMixin, Test):
+ """The act of visually inspecting the appearance and functionality
+ of the device.
"""
appearance_range = Column(DBEnum(AppearanceRange))
appearance_range.comment = AppearanceRange.__doc__
functionality_range = Column(DBEnum(FunctionalityRange))
functionality_range.comment = FunctionalityRange.__doc__
labelling = Column(Boolean)
- labelling.comment = """Whether there are tags to be removed.
- """
+ labelling.comment = """Whether there are tags to be removed."""
def __str__(self) -> str:
return super().__str__() + '. Appearance {} and functionality {}'.format(
@@ -858,29 +856,54 @@ class TestVisual(TestMixin, Test):
class Rate(JoinedWithOneDeviceMixin, EventWithOneDevice):
- """The act of computing a rate based on different categories:
- 1. Quality: the appearance, performance, and functionality
- of a device.
-
-
- There are two ways of rating a device:
-
- 1. When processing the device with Workbench and the Android App.
- 2. Anytime after with the Android App or website.X
+ """The act of computing a rate based on different categories"""
+ # todo jn: explain in each comment what the rate considers.
+ N = 2
+ """The number of significant digits for rates.
+ Values are rounded and stored to it.
"""
- rating = Column(Float(decimal_return_scale=2), check_range('rating', *RATE_POSITIVE))
- rating.comment = """The rating for the content."""
+ _rating = Column('rating', Float(decimal_return_scale=N), check_range('rating', *R_POSITIVE))
+ _rating.comment = """The rating for the content."""
version = Column(StrictVersionType)
version.comment = """The version of the software."""
- appearance = Column(Float(decimal_return_scale=2), check_range('appearance', *RATE_NEGATIVE))
- functionality = Column(Float(decimal_return_scale=2),
- check_range('functionality', *RATE_NEGATIVE))
+ _appearance = Column('appearance',
+ Float(decimal_return_scale=N),
+ check_range('appearance', *R_NEGATIVE))
+ _appearance.comment = """"""
+ _functionality = Column('functionality',
+ Float(decimal_return_scale=N),
+ check_range('functionality', *R_NEGATIVE))
+ _functionality.comment = """"""
+
+ @property
+ def rating(self):
+ return self._rating
+
+ @rating.setter
+ def rating(self, x):
+ self._rating = round(max(x, 0), self.N)
+
+ @property
+ def appearance(self):
+ return self._appearance
+
+ @appearance.setter
+ def appearance(self, x):
+ self._appearance = round(x, self.N)
+
+ @property
+ def functionality(self):
+ return self._functionality
+
+ @functionality.setter
+ def functionality(self, x):
+ self._functionality = round(x, self.N)
@property
def rating_range(self) -> RatingRange:
- if self.rating:
- return RatingRange.from_score(self.rating)
+ """"""
+ return RatingRange.from_score(self.rating) if self.rating else None
@declared_attr
def __mapper_args__(cls):
@@ -901,54 +924,82 @@ class Rate(JoinedWithOneDeviceMixin, EventWithOneDevice):
@classmethod
def compute(cls, device) -> 'RateComputer':
- """
- The act of compute general computer rate
- """
raise NotImplementedError()
-class RateComputer(Rate):
- """
- Main class to group by device type: Computer
- Computer is broadly extended by ``Desktop``, ``Laptop``, and
- ``Server``.
- """
- id = Column(UUID(as_uuid=True), ForeignKey(Rate.id), primary_key=True)
+class RateMixin:
+ @declared_attr
+ def id(cls):
+ return Column(UUID(as_uuid=True), ForeignKey(Rate.id), primary_key=True)
- processor = Column(Float(decimal_return_scale=2), check_range('processor', *RATE_POSITIVE),
- comment='Is a test explain cpu component.')
- ram = Column(Float(decimal_return_scale=2), check_range('ram', *RATE_POSITIVE),
- comment='RAM memory rate.')
- data_storage = Column(Float(decimal_return_scale=2), check_range('data_storage', *RATE_POSITIVE),
- comment='Data storage rate, like HHD, SSD.')
- graphic_card = Column(Float(decimal_return_scale=2), check_range('graphic_card', *RATE_POSITIVE),
- comment='Graphic card rate.')
- def __init__(self, **kwargs) -> None:
- super().__init__(**kwargs)
+class RateComputer(RateMixin, Rate):
+ """The act of rating a computer."""
+ _processor = Column('processor',
+ Float(decimal_return_scale=Rate.N),
+ check_range('processor', *R_POSITIVE))
+ _processor.comment = """The rate of the Processor."""
+ _ram = Column('ram', Float(decimal_return_scale=Rate.N), check_range('ram', *R_POSITIVE))
+ _ram.comment = """The rate of the RAM."""
+ _data_storage = Column('data_storage',
+ Float(decimal_return_scale=Rate.N),
+ check_range('data_storage', *R_POSITIVE))
+ _data_storage.comment = """'Data storage rate, like HHD, SSD.'"""
+ _graphic_card = Column('graphic_card',
+ Float(decimal_return_scale=Rate.N),
+ check_range('graphic_card', *R_POSITIVE))
+ _graphic_card.comment = 'Graphic card rate.'
+
+ @property
+ def processor(self):
+ return self._processor
+
+ @processor.setter
+ def processor(self, x):
+ self._processor = round(x, self.N)
+
+ @property
+ def ram(self):
+ return self._ram
+
+ @ram.setter
+ def ram(self, x):
+ self._ram = round(x, self.N)
+
+ @property
+ def data_storage(self):
+ return self._data_storage
+
+ @data_storage.setter
+ def data_storage(self, x):
+ self._data_storage = round(x, self.N)
+
+ @property
+ def graphic_card(self):
+ return self._graphic_card
+
+ @graphic_card.setter
+ def graphic_card(self, x):
+ self._graphic_card = round(x, self.N)
@property
def data_storage_range(self):
- if self.data_storage:
- return RatingRange.from_score(self.data_storage)
+ return RatingRange.from_score(self.data_storage) if self.data_storage else None
@property
def ram_range(self):
- if self.ram:
- return RatingRange.from_score(self.ram)
+ return RatingRange.from_score(self.ram) if self.ram else None
@property
def processor_range(self):
- if self.processor:
- return RatingRange.from_score(self.processor)
+ return RatingRange.from_score(self.processor) if self.processor else None
@property
def graphic_card_range(self):
- if self.graphic_card:
- return RatingRange.from_score(self.graphic_card)
+ return RatingRange.from_score(self.graphic_card) if self.graphic_card else None
@classmethod
- def compute(cls, device) -> Tuple['RateComputer', 'Price']:
+ def compute(cls, device):
"""
The act of compute general computer rate
"""
@@ -1004,7 +1055,7 @@ class Price(JoinedWithOneDeviceMixin, EventWithOneDevice):
@classmethod
def to_price(cls, value: Union[Decimal, float], rounding=ROUND) -> Decimal:
"""Returns a Decimal value with the correct scale for Price.price."""
- if isinstance(value, float):
+ if isinstance(value, (float, int)):
value = Decimal(value)
# equation from marshmallow.fields.Decimal
return value.quantize(Decimal((0, (1,), -cls.SCALE)), rounding=rounding)
@@ -1088,7 +1139,7 @@ class EreusePrice(Price):
self.warranty2 = EreusePrice.Type(rate[self.WARRANTY2][role], price)
def __init__(self, rating: RateComputer, **kwargs) -> None:
- if rating.rating_range == RatingRange.VERY_LOW:
+ if not rating.rating_range or rating.rating_range == RatingRange.VERY_LOW:
raise InvalidRangeForPrice()
# We pass ROUND_UP strategy so price is always greater than what refurbisher... amounts
price = self.to_price(rating.rating * self.MULTIPLIER[rating.device.__class__], ROUND_UP)
diff --git a/ereuse_devicehub/resources/event/models.pyi b/ereuse_devicehub/resources/event/models.pyi
index fd274c80..e6ef5165 100644
--- a/ereuse_devicehub/resources/event/models.pyi
+++ b/ereuse_devicehub/resources/event/models.pyi
@@ -2,7 +2,7 @@ import ipaddress
from datetime import datetime, timedelta
from decimal import Decimal
from distutils.version import StrictVersion
-from typing import Dict, List, Optional, Set, Union
+from typing import Dict, List, Optional, Set, Tuple, Union
from uuid import UUID
from boltons import urlutils
@@ -16,9 +16,9 @@ from teal.enums import Country
from ereuse_devicehub.resources.agent.models import Agent
from ereuse_devicehub.resources.device.models import Component, Computer, Device
-from ereuse_devicehub.resources.enums import AppearanceRange, Bios, ErasureStandards, \
- FunctionalityRange, PhysicalErasureMethod, PriceSoftware, RatingSoftware, ReceiverRole, \
- Severity, SnapshotExpectedEvents, SnapshotSoftware, TestDataStorageLength, BiosAccessRange
+from ereuse_devicehub.resources.enums import AppearanceRange, ErasureStandards, \
+ FunctionalityRange, PhysicalErasureMethod, PriceSoftware, RatingRange, \
+ ReceiverRole, Severity, SnapshotExpectedEvents, SnapshotSoftware, TestDataStorageLength
from ereuse_devicehub.resources.models import Thing
from ereuse_devicehub.resources.user.models import User
@@ -42,7 +42,7 @@ class Event(Thing):
severity = ... # type: Column
def __init__(self, **kwargs) -> None:
- super().__init__(created, updated)
+ super().__init__(**kwargs)
self.id = ... # type: UUID
self.name = ... # type: str
self.type = ... # type: str
@@ -75,7 +75,6 @@ class Event(Thing):
class EventWithOneDevice(Event):
-
def __init__(self, **kwargs) -> None:
super().__init__(**kwargs)
self.device = ... # type: Device
@@ -178,8 +177,7 @@ class Install(EventWithOneDevice):
self.address = ... # type: Optional[int]
-class SnapshotRequest(Mod assert rate_computer.rating == 4.61
-el):
+class SnapshotRequest(Model):
def __init__(self, **kwargs) -> None:
self.id = ... # type: UUID
self.request = ... # type: dict
@@ -226,6 +224,7 @@ class BenchmarkGraphicCard(BenchmarkWithRate):
class Test(EventWithOneDevice):
elapsed = ... # type: Column
+
def __init__(self, **kwargs) -> None:
super().__init__(**kwargs)
self.elapsed = ... # type: Optional[timedelta]
@@ -233,6 +232,20 @@ class Test(EventWithOneDevice):
class TestDataStorage(Test):
+ length = ... # type: Column
+ status = ... # type: Column
+ lifetime = ... # type: Column
+ first_error = ... # type: Column
+ passed_lifetime = ... # type: Column
+ assessment = ... # type: Column
+ reallocated_sector_count = ... # type: Column
+ power_cycle_count = ... # type: Column
+ reported_uncorrectable_errors = ... # type: Column
+ command_timeout = ... # type: Column
+ current_pending_sector_count = ... # type: Column
+ offline_uncorrectable = ... # type: Column
+ remaining_lifetime_percentage = ... # type: Column
+
def __init__(self, **kwargs) -> None:
super().__init__(**kwargs)
self.id = ... # type: UUID
@@ -259,70 +272,92 @@ class TestAudio(Test):
"""
Test to check all this aspects related with audio functions, Manual Tests??
"""
- loudspeaker = ... # type: Column
- microphone = ... # type: Column
+ _speaker = ... # type: Column
+ _microphone = ... # type: Column
+
+ def __init__(self, **kwargs) -> None:
+ super().__init__(**kwargs)
+ self.speaker = ... # type: bool
+ self.microphone = ... # type: bool
class TestConnectivity(Test):
- cellular_network = ... # type: Column
- wifi = ... # type: Column
- bluetooth = ... # type: Column
- usb_port = ... # type: Column
- locked = ... # type: Column
-
-
-class TestBattery(Test):
- battery_stat = ... # type: Column
- battery_health = ... # type: Column
+ pass
class TestCamera(Test):
- camera = ... # type: Column
+ pass
class TestKeyboard(Test):
- keyboard = ... # type: Column
+ pass
class TestTrackpad(Test):
- trackpad = ... # type: Column
+ pass
class TestBios(Test):
bios_power_on = ... # type: Column
- access_range = ... # type: BiosAccessRange
+ access_range = ... # type: Column
-class TestVisual(ManualRate):
+class VisualTest(Test):
appearance_range = ... # type: AppearanceRange
functionality_range = ... # type: FunctionalityRange
labelling = ... # type: Column
class Rate(EventWithOneDevice):
- rating = ... # type: Column
- appearance = ... # type: Column
- functionality = ... # type: Column
+ N = 2
+ _rating = ... # type: Column
+ _appearance = ... # type: Column
+ _functionality = ... # type: Column
version = ... # type: Column
def __init__(self, **kwargs) -> None:
super().__init__(**kwargs)
self.rating = ... # type: float
- self.software = ... # type: RatingSoftware
self.version = ... # type: StrictVersion
self.appearance = ... # type: float
self.functionality = ... # type: float
- self.rating_range = ... # type: str
+
+ @property
+ def rating_range(self) -> RatingRange:
+ pass
class RateComputer(Rate):
- id = ...
- processor = ...
- ram = ...
- data_storage = ...
+ _processor = ... # type: Column
+ _ram = ... # type: Column
+ _data_storage = ... # type: Column
+ _graphic_card = ... # type: Column
+
+ def __init__(self, **kwargs) -> None:
+ super().__init__(**kwargs)
+ self.processor = ... # type: float
+ self.ram = ... # type: float
+ self.data_storage = ... # type: float
+ self.graphic_card = ... # type: float
@classmethod
- def compute(cls, device):
+ def compute(cls, device: Device) -> Tuple[RateComputer, EreusePrice]:
+ pass
+
+ @property
+ def data_storage_range(self) -> Optional[RatingRange]:
+ pass
+
+ @property
+ def ram_range(self) -> Optional[RatingRange]:
+ pass
+
+ @property
+ def processor_range(self) -> Optional[RatingRange]:
+ pass
+
+ @property
+ def graphic_card_range(self) -> Optional[RatingRange]:
pass
diff --git a/ereuse_devicehub/resources/event/rate/rate.py b/ereuse_devicehub/resources/event/rate/rate.py
index eca005c4..3e11cb9f 100644
--- a/ereuse_devicehub/resources/event/rate/rate.py
+++ b/ereuse_devicehub/resources/event/rate/rate.py
@@ -1,6 +1,5 @@
-from typing import Iterable
-
import math
+from typing import Iterable
from ereuse_devicehub.resources.device.models import Device
diff --git a/ereuse_devicehub/resources/event/rate/workbench/v1_0.py b/ereuse_devicehub/resources/event/rate/workbench/v1_0.py
index 9f7a78d3..ebd53e80 100644
--- a/ereuse_devicehub/resources/event/rate/workbench/v1_0.py
+++ b/ereuse_devicehub/resources/event/rate/workbench/v1_0.py
@@ -1,18 +1,20 @@
from enum import Enum
from itertools import groupby
-from typing import Iterable
+from typing import Dict, Iterable, Tuple
-from ereuse_devicehub.resources.device.models import Computer, DataStorage, Processor, RamModule
+from ereuse_devicehub.resources.device.models import Computer, DataStorage, Processor, \
+ RamModule
from ereuse_devicehub.resources.event.models import BenchmarkDataStorage, BenchmarkProcessor, \
- RateComputer, TestVisual, BenchmarkProcessorSysbench
-# todo if no return assign then rate_c = 1 is assigned
-# todo fix corner cases, like components characteristics == None
+ BenchmarkProcessorSysbench, RateComputer, VisualTest
from ereuse_devicehub.resources.event.rate.rate import BaseRate
class RateAlgorithm(BaseRate):
- """
- Rate all components in Computer
+ """The algorithm that generates the Rate v1.0.
+
+ Do not call directly this class, but use
+ :meth:`ereuse_devicehub.resources.event.models.RateComputer.compute`,
+ which then calls this.
"""
class Range(Enum):
@@ -43,48 +45,43 @@ class RateAlgorithm(BaseRate):
Processor.t: ('processor', ProcessorRate()),
RamModule.t: ('ram', RamRate()),
DataStorage.t: ('data_storage', DataStorageRate())
- }
+ } # type: Dict[str, Tuple[str, BaseRate]]
- def compute(self, device: Computer):
+ def compute(self, device: Computer) -> RateComputer:
+ """Generates a new
+ :class:`ereuse_devicehub.resources.event.models.RateComputer`
+ for the passed-in device.
"""
- Compute RateComputer is a rate (score) ranging from 0 to 4.7
- that represents estimating value of use of desktop and laptop computer components.
- """
- if not isinstance(device, Computer): # todo can be an assert?
- raise CannotRate('Can only rate computers.')
+ assert isinstance(device, Computer), 'Can only rate computers'
+
+ try:
+ test_visual = device.last_event_of(VisualTest)
+ except LookupError:
+ raise CannotRate('You need a visual test.')
rate = RateComputer()
-
rate.processor = rate.data_storage = rate.ram = 1 # Init
- # Group cpus, rams, storages and compute their rate
+ # Group cpus, rams, storage and compute their rate
# Treat the same way with HardDrive and SolidStateDrive like (DataStorage)
clause = lambda x: DataStorage.t if isinstance(x, DataStorage) else x.t
c = (c for c in device.components if clause(c) in set(self.RATES.keys()))
for type, components in groupby(sorted(c, key=clause), key=clause):
if type == Processor.t: # ProcessorRate.compute expects only 1 processor
components = next(components)
- field, rate_cls = self.RATES[type] # type: str, BaseRate
- result = rate_cls.compute(components, rate)
+ field, rate_cls = self.RATES[type]
+ result = rate_cls.compute(components)
if result:
setattr(rate, field, result)
- # TODO is necessary check if TestVisual exists?? cause StopIteration Error
- try:
- test_visual = next(e for e in device.events if isinstance(e, TestVisual))
- except StopIteration:
- raise CannotRate('You need a visual test.')
rate_components = self.harmonic_mean_rates(rate.processor, rate.data_storage, rate.ram)
rate.appearance = self.Appearance.from_devicehub(test_visual.appearance_range).value
- rate.functionality = self.Functionality.from_devicehub(test_visual.functionality_range).value
+ rate.functionality = self.Functionality.from_devicehub(
+ test_visual.functionality_range).value
- rate.rating = round(max(rate_components + rate.functionality + rate.appearance, 0), 2)
- rate.appearance = round(rate.appearance, 2)
- rate.functionality = round(rate.functionality, 2)
- rate.processor = round(rate.processor, 2)
- rate.ram = round(rate.ram, 2)
- rate.data_storage = round(rate.data_storage, 2)
+ rate.rating = rate_components + rate.functionality + rate.appearance
device.events_one.add(rate)
+ assert 0 <= rate.rating <= 4.7, 'Rate ranges from 0 to 4.7'
return rate
@@ -101,18 +98,20 @@ class ProcessorRate(BaseRate):
# Intel(R) Core(TM) i3 CPU 530 @ 2.93GHz, score = 23406.92 but results inan score of 17503.
DEFAULT_SCORE = 4000
- def compute(self, processor: Processor, rate: RateComputer):
+ def compute(self, processor: Processor):
""" Compute processor rate
Obs: cores and speed are possible NULL value
:return: result is a rate (score) of Processor characteristics
"""
- # todo for processor_device in processors; more than one processor
+ # todo jn? for processor_device in processors; more than one processor
cores = processor.cores or self.DEFAULT_CORES
speed = processor.speed or self.DEFAULT_SPEED
- # todo fix StopIteration if don't exists BenchmarkProcessor
- benchmark_cpu = next(e for e in processor.events if
- isinstance(e, BenchmarkProcessor) and not isinstance(e, BenchmarkProcessorSysbench))
- # todo fix if benchmark_cpu.rate == 0
+ # todo jn? fix StopIteration if don't exists BenchmarkProcessor
+ benchmark_cpu = next(
+ e for e in reversed(processor.events)
+ if isinstance(e, BenchmarkProcessor) and not isinstance(e, BenchmarkProcessorSysbench)
+ )
+ # todo jn? fix if benchmark_cpu.rate == 0
benchmark_cpu = benchmark_cpu.rate or self.DEFAULT_SCORE
# STEP: Fusion components
@@ -129,8 +128,6 @@ class ProcessorRate(BaseRate):
processor_rate = self.rate_lin(processor_norm)
if processor_norm >= self.CLOG:
processor_rate = self.rate_log(processor_norm)
-
- assert processor_rate, 'Could not rate processor.'
return processor_rate
@@ -146,7 +143,7 @@ class RamRate(BaseRate):
# ram.size.weight; ram.speed.weight;
RAM_WEIGHTS = 0.7, 0.3
- def compute(self, ram_devices: Iterable[RamModule], rate: RateComputer):
+ def compute(self, ram_devices: Iterable[RamModule]):
"""
Obs: RamModule.speed is possible NULL value & size != NULL or NOT??
:return: result is a rate (score) of all RamModule components
@@ -203,7 +200,7 @@ class DataStorageRate(BaseRate):
# drive.size.weight; drive.readingSpeed.weight; drive.writingSpeed.weight;
DATA_STORAGE_WEIGHTS = 0.5, 0.25, 0.25
- def compute(self, data_storage_devices: Iterable[DataStorage], rate: RateComputer):
+ def compute(self, data_storage_devices: Iterable[DataStorage]):
"""
Obs: size != NULL and 0 value & read_speed and write_speed != NULL
:return: result is a rate (score) of all DataStorage devices
@@ -215,7 +212,7 @@ class DataStorageRate(BaseRate):
# STEP: Filtering, data cleaning and merging of component parts
for storage in data_storage_devices:
# We assume all hdd snapshots have BenchmarkDataStorage
- benchmark = next(e for e in storage.events if isinstance(e, BenchmarkDataStorage))
+ benchmark = storage.last_event_of(BenchmarkDataStorage)
# prevent NULL values
_size = storage.size or 0
size += _size
diff --git a/ereuse_devicehub/resources/event/schemas.py b/ereuse_devicehub/resources/event/schemas.py
index dc9677c4..0f12e7f3 100644
--- a/ereuse_devicehub/resources/event/schemas.py
+++ b/ereuse_devicehub/resources/event/schemas.py
@@ -13,8 +13,8 @@ from ereuse_devicehub.resources import enums
from ereuse_devicehub.resources.agent import schemas as s_agent
from ereuse_devicehub.resources.device import schemas as s_device
from ereuse_devicehub.resources.enums import AppearanceRange, BiosAccessRange, FunctionalityRange, \
- PhysicalErasureMethod, PriceSoftware, RATE_POSITIVE, RatingRange, ReceiverRole, \
- Severity, SnapshotExpectedEvents, SnapshotSoftware, TestDataStorageLength, BatteryHealthRange
+ PhysicalErasureMethod, R_POSITIVE, RatingRange, ReceiverRole, \
+ Severity, SnapshotExpectedEvents, SnapshotSoftware, TestDataStorageLength
from ereuse_devicehub.resources.event import models as m
from ereuse_devicehub.resources.models import STR_BIG_SIZE, STR_SIZE
from ereuse_devicehub.resources.schemas import Thing
@@ -176,38 +176,24 @@ class StressTest(Test):
class TestAudio(Test):
__doc__ = m.TestAudio.__doc__
- loudspeaker = Boolean()
- microphone = Boolean()
+ speaker = Boolean(description=m.TestAudio._speaker.comment)
+ microphone = Boolean(description=m.TestAudio._microphone.comment)
class TestConnectivity(Test):
__doc__ = m.TestConnectivity.__doc__
- cellular_network = Boolean()
- wifi = Boolean()
- bluetooth = Boolean()
- usb_port = Boolean()
- locked = Boolean()
-
-
-class TestBattery(Test):
- __doc__ = m.TestBattery.__doc__
- battery_stat = Boolean()
- battery_health = EnumField(BatteryHealthRange, data_key='batteryHealthRange')
class TestCamera(Test):
__doc__ = m.TestCamera.__doc__
- camera = Boolean()
class TestKeyboard(Test):
__doc__ = m.TestKeyboard.__doc__
- keyboard = Boolean()
class TestTrackpad(Test):
__doc__ = m.TestTrackpad.__doc__
- trackpad = Boolean()
class TestBios(Test):
@@ -216,8 +202,8 @@ class TestBios(Test):
access_range = EnumField(BiosAccessRange, data_key='accessRange')
-class TestVisual(Test):
- __doc__ = m.TestVisual.__doc__
+class VisualTest(Test):
+ __doc__ = m.VisualTest.__doc__
appearance_range = EnumField(AppearanceRange, data_key='appearanceRange')
functionality_range = EnumField(FunctionalityRange, data_key='functionalityRange')
labelling = Boolean()
@@ -225,14 +211,21 @@ class TestVisual(Test):
class Rate(EventWithOneDevice):
__doc__ = m.Rate.__doc__
- rating = Integer(validate=Range(*RATE_POSITIVE),
+ rating = Integer(validate=Range(*R_POSITIVE),
dump_only=True,
- description=m.Rate.rating.comment)
+ description=m.Rate._rating.comment)
version = Version(dump_only=True,
description=m.Rate.version.comment)
- appearance = Integer(validate=Range(-3, 5), dump_only=True)
- functionality = Integer(validate=Range(-3, 5), dump_only=True)
- rating_range = EnumField(RatingRange, dump_only=True, data_key='ratingRange')
+ appearance = Integer(validate=Range(enums.R_NEGATIVE),
+ dump_only=True,
+ description=m.Rate._appearance.comment)
+ functionality = Integer(validate=Range(enums.R_NEGATIVE),
+ dump_only=True,
+ description=m.Rate._functionality.comment)
+ rating_range = EnumField(RatingRange,
+ dump_only=True,
+ data_key='ratingRange',
+ description=m.Rate.rating_range.__doc__)
class RateComputer(Rate):
diff --git a/ereuse_devicehub/resources/event/views.py b/ereuse_devicehub/resources/event/views.py
index b8794eaa..72819176 100644
--- a/ereuse_devicehub/resources/event/views.py
+++ b/ereuse_devicehub/resources/event/views.py
@@ -1,4 +1,3 @@
-from contextlib import suppress
from distutils.version import StrictVersion
from typing import List
from uuid import UUID
@@ -11,8 +10,7 @@ from teal.resource import View
from ereuse_devicehub.db import db
from ereuse_devicehub.resources.device.models import Component, Computer
from ereuse_devicehub.resources.enums import SnapshotSoftware
-from ereuse_devicehub.resources.event.models import Event, Snapshot, Rate, RateComputer, InvalidRangeForPrice, \
- EreusePrice
+from ereuse_devicehub.resources.event.models import Event, RateComputer, Snapshot
from ereuse_devicehub.resources.event.rate.workbench.v1_0 import CannotRate
SUPPORTED_WORKBENCH = StrictVersion('11.0')
@@ -94,7 +92,6 @@ class EventView(View):
if price:
snapshot.events.add(price)
-
db.session.add(snapshot)
db.session().final_flush()
ret = self.schema.jsonify(snapshot) # transform it back
diff --git a/ereuse_devicehub/resources/lot/dag.sql b/ereuse_devicehub/resources/lot/dag.sql
index 3f4b4840..dd4a94c8 100644
--- a/ereuse_devicehub/resources/lot/dag.sql
+++ b/ereuse_devicehub/resources/lot/dag.sql
@@ -1,109 +1,115 @@
CREATE OR REPLACE FUNCTION add_edge(parent_id uuid, child_id uuid)
- /* Adds an edge between ``parent`` and ``child``.
+ /* Adds an edge between ``parent`` and ``child``.
- Designed to work with Directed Acyclic Graphs (DAG)
- (or said in another way, trees with multiple parents without cycles).
+ Designed to work with Directed Acyclic Graphs (DAG)
+ (or said in another way, trees with multiple parents without cycles).
- This method will raise an exception if:
- - Parent is the same as child.
- - Child contains the parent.
- - Edge parent - child already exists.
+ This method will raise an exception if:
+ - Parent is the same as child.
+ - Child contains the parent.
+ - Edge parent - child already exists.
- Influenced by:
- - https://www.codeproject.com/Articles/22824/A-Model-to-Represent-Directed-Acyclic-Graphs-DAG
- - http://patshaughnessy.net/2017/12/12/installing-the-postgres-ltree-extension
- - https://en.wikipedia.org/wiki/Directed_acyclic_graph
- */
- RETURNS void AS $$
+ Influenced by:
+ - https://www.codeproject.com/Articles/22824/A-Model-to-Represent-Directed-Acyclic-Graphs-DAG
+ - http://patshaughnessy.net/2017/12/12/installing-the-postgres-ltree-extension
+ - https://en.wikipedia.org/wiki/Directed_acyclic_graph
+ */
+ RETURNS void AS
+$$
DECLARE
- parent text := replace(CAST(parent_id as text), '-', '_');
- child text := replace(CAST(child_id as text), '-', '_');
+ parent text := replace(CAST(parent_id as text), '-', '_');
+ child text := replace(CAST(child_id as text), '-', '_');
BEGIN
- if parent = child
- then
- raise exception 'Cannot create edge: the parent is the same as the child.';
- end if;
+ if parent = child
+ then
+ raise exception 'Cannot create edge: the parent is the same as the child.';
+ end if;
- if EXISTS (
- SELECT 1 FROM path where path.path ~ CAST('*.' || child || '.*.' || parent || '.*' as lquery)
- )
- then
- raise exception 'Cannot create edge: child already contains parent.';
- end if;
+ if EXISTS(
+ SELECT 1
+ FROM path
+ where path.path ~ CAST('*.' || child || '.*.' || parent || '.*' as lquery)
+ )
+ then
+ raise exception 'Cannot create edge: child already contains parent.';
+ end if;
- -- We have two subgraphs: the parent subgraph that goes from the parent to the root,
- -- and the child subgraph, going from the child (which is the root of this subgraph)
- -- to all the leafs.
- -- We do the cartesian product from all the paths of the parent subgraph that end in the parent
- -- WITH all the paths that start from the child that end to its leafs.
- insert into path (lot_id, path) (
- select distinct lot_id, fp.path || subpath(path.path, index(path.path, text2ltree(child)))
- from path, (select path.path from path where path.path ~ CAST('*.' || parent AS lquery)) as fp
- where path.path ~ CAST('*.' || child || '.*' AS lquery)
- );
- -- Cleanup: old paths that start with the child (that where used above in the cartesian product)
- -- have became a subset of the result of the cartesian product, thus being redundant.
- delete from path where path.path ~ CAST(child || '.*' AS lquery);
+ -- We have two subgraphs: the parent subgraph that goes from the parent to the root,
+ -- and the child subgraph, going from the child (which is the root of this subgraph)
+ -- to all the leafs.
+ -- We do the cartesian product from all the paths of the parent subgraph that end in the parent
+ -- WITH all the paths that start from the child that end to its leafs.
+ insert into path (lot_id, path) (
+ select distinct lot_id, fp.path || subpath(path.path, index(path.path, text2ltree(child)))
+ from path,
+ (select path.path from path where path.path ~ CAST('*.' || parent AS lquery)) as fp
+ where path.path ~ CAST('*.' || child || '.*' AS lquery)
+ );
+ -- Cleanup: old paths that start with the child (that where used above in the cartesian product)
+ -- have became a subset of the result of the cartesian product, thus being redundant.
+ delete from path where path.path ~ CAST(child || '.*' AS lquery);
END
$$
-LANGUAGE plpgsql;
+ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION delete_edge(parent_id uuid, child_id uuid)
- /* Deletes an edge between ``parent`` and ``child``.
+ /* Deletes an edge between ``parent`` and ``child``.
- Designed to work with DAG (See ``add_edge`` function).
+ Designed to work with DAG (See ``add_edge`` function).
- This method will raise an exception if the relationship does not
- exist.
- */
- RETURNS void AS $$
+ This method will raise an exception if the relationship does not
+ exist.
+ */
+ RETURNS void AS
+$$
DECLARE
- parent text := replace(CAST(parent_id as text), '-', '_');
- child text := replace(CAST(child_id as text), '-', '_');
- number int;
+ parent text := replace(CAST(parent_id as text), '-', '_');
+ child text := replace(CAST(child_id as text), '-', '_');
+ number int;
BEGIN
- -- to delete we remove from the path of the descendants of the child
- -- (and the child) any ancestor coming from this edge.
- -- When we added the edge we did a cartesian product. When removing
- -- this part of the path we will have duplicate paths.
+ -- to delete we remove from the path of the descendants of the child
+ -- (and the child) any ancestor coming from this edge.
+ -- When we added the edge we did a cartesian product. When removing
+ -- this part of the path we will have duplicate paths.
- -- don't check uniqueness for path key until we delete duplicates
- SET CONSTRAINTS path_unique DEFERRED;
+ -- don't check uniqueness for path key until we delete duplicates
+ SET CONSTRAINTS path_unique DEFERRED;
- -- remove everything above the child lot_id in the path
- -- this creates duplicates on path and lot_id
- update path
- set path = subpath(path, index(path, text2ltree(child)))
- where path ~ CAST('*.' || parent || '.' || child || '.*' AS lquery);
+ -- remove everything above the child lot_id in the path
+ -- this creates duplicates on path and lot_id
+ update path
+ set path = subpath(path, index(path, text2ltree(child)))
+ where path ~ CAST('*.' || parent || '.' || child || '.*' AS lquery);
- -- remove duplicates
- -- we need an id field exclusively for this operation
- -- from https://wiki.postgresql.org/wiki/Deleting_duplicates
- DELETE
- FROM path
- WHERE id IN (SELECT id
- FROM (SELECT id, ROW_NUMBER() OVER (partition BY lot_id, path) AS rnum FROM path) t
- WHERE t.rnum > 1);
+ -- remove duplicates
+ -- we need an id field exclusively for this operation
+ -- from https://wiki.postgresql.org/wiki/Deleting_duplicates
+ DELETE
+ FROM path
+ WHERE id IN (SELECT id
+ FROM (SELECT id, ROW_NUMBER() OVER (partition BY lot_id, path) AS rnum
+ FROM path) t
+ WHERE t.rnum > 1);
- -- re-activate uniqueness check and perform check
- -- todo we should put this in a kind-of finally clause
- SET CONSTRAINTS path_unique IMMEDIATE;
+ -- re-activate uniqueness check and perform check
+ -- todo we should put this in a kind-of finally clause
+ SET CONSTRAINTS path_unique IMMEDIATE;
- -- After the update the one of the paths of the child will be
- -- containing only the child.
- -- This can only be when the child has no parent at all.
- -- In case the child has more than one parent, remove this path
- -- (note that we want it to remove it too from descendants of this
- -- child, ex. 'child_id'.'desc1')
- select COUNT(1) into number from path where lot_id = child_id;
- IF number > 1
- THEN
- delete from path where path <@ text2ltree(child);
- end if;
+ -- After the update the one of the paths of the child will be
+ -- containing only the child.
+ -- This can only be when the child has no parent at all.
+ -- In case the child has more than one parent, remove this path
+ -- (note that we want it to remove it too from descendants of this
+ -- child, ex. 'child_id'.'desc1')
+ select COUNT(1) into number from path where lot_id = child_id;
+ IF number > 1
+ THEN
+ delete from path where path <@ text2ltree(child);
+ end if;
END
$$
-LANGUAGE plpgsql;
+ LANGUAGE plpgsql;
diff --git a/ereuse_devicehub/resources/tag/schema.py b/ereuse_devicehub/resources/tag/schema.py
index 22a492d5..8c2c355b 100644
--- a/ereuse_devicehub/resources/tag/schema.py
+++ b/ereuse_devicehub/resources/tag/schema.py
@@ -1,5 +1,5 @@
-from sqlalchemy.util import OrderedSet
from marshmallow.fields import Boolean
+from sqlalchemy.util import OrderedSet
from teal.marshmallow import SanitizedStr, URL
from ereuse_devicehub.marshmallow import NestedOn
diff --git a/tests/files/asus-1001pxd.snapshot.yaml b/tests/files/asus-1001pxd.snapshot.yaml
index a8e64814..723db9e2 100644
--- a/tests/files/asus-1001pxd.snapshot.yaml
+++ b/tests/files/asus-1001pxd.snapshot.yaml
@@ -118,7 +118,7 @@
{
"appearanceRange": "A",
"functionalityRange": "A",
- "type": "TestVisual"
+ "type": "VisualTest"
}
],
"manufacturer": "ASUSTeK Computer INC.",
diff --git a/tests/files/basic.snapshot.yaml b/tests/files/basic.snapshot.yaml
index ecbd8779..fd976e83 100644
--- a/tests/files/basic.snapshot.yaml
+++ b/tests/files/basic.snapshot.yaml
@@ -10,7 +10,7 @@ device:
model: d1ml
manufacturer: d1mr
events:
- - type: TestVisual
+ - type: VisualTest
appearanceRange: A
functionalityRange: B
components:
diff --git a/tests/files/desktop-9644w8n-lenovo-0169622.snapshot.yaml b/tests/files/desktop-9644w8n-lenovo-0169622.snapshot.yaml
index 0b98a32b..815757b5 100644
--- a/tests/files/desktop-9644w8n-lenovo-0169622.snapshot.yaml
+++ b/tests/files/desktop-9644w8n-lenovo-0169622.snapshot.yaml
@@ -92,7 +92,7 @@
{
"appearanceRange": "D",
"functionalityRange": "D",
- "type": "TestVisual"
+ "type": "VisualTest"
},
{
"elapsed": 300,
diff --git a/tests/files/laptop-hp_255_g3_notebook-hewlett-packard-cnd52270fw.snapshot.yaml b/tests/files/laptop-hp_255_g3_notebook-hewlett-packard-cnd52270fw.snapshot.yaml
index bbf31071..bacf45dd 100644
--- a/tests/files/laptop-hp_255_g3_notebook-hewlett-packard-cnd52270fw.snapshot.yaml
+++ b/tests/files/laptop-hp_255_g3_notebook-hewlett-packard-cnd52270fw.snapshot.yaml
@@ -137,7 +137,7 @@
{
"appearanceRange": "A",
"functionalityRange": "A",
- "type": "TestVisual"
+ "type": "VisualTest"
},
{
"elapsed": 300,
diff --git a/tests/test_basic.py b/tests/test_basic.py
index d40f0ad1..f882f51e 100644
--- a/tests/test_basic.py
+++ b/tests/test_basic.py
@@ -42,4 +42,4 @@ def test_api_docs(client: Client):
'scheme': 'basic',
'name': 'Authorization'
}
- assert len(docs['definitions']) == 102
+ assert len(docs['definitions']) == 101
diff --git a/tests/test_device.py b/tests/test_device.py
index c2c69189..db2a7665 100644
--- a/tests/test_device.py
+++ b/tests/test_device.py
@@ -1,5 +1,4 @@
import datetime
-from datetime import timedelta
from uuid import UUID
import pytest
@@ -23,7 +22,7 @@ from ereuse_devicehub.resources.device.sync import MismatchBetweenTags, Mismatch
from ereuse_devicehub.resources.enums import ComputerChassis, DisplayTech, Severity, \
SnapshotSoftware
from ereuse_devicehub.resources.event import models as m
-from ereuse_devicehub.resources.event.models import Remove, Test
+from ereuse_devicehub.resources.event.models import Remove, TestConnectivity
from ereuse_devicehub.resources.tag.model import Tag
from ereuse_devicehub.resources.user import User
from tests import conftest
@@ -391,14 +390,14 @@ def test_get_device(app: Devicehub, user: UserClient):
])
db.session.add(pc)
# todo test is an abstract class. replace with another one
- db.session.add(Test(device=pc,
- severity=Severity.Info,
- agent=Person(name='Timmy'),
- author=User(email='bar@bar.com')))
+ db.session.add(TestConnectivity(device=pc,
+ severity=Severity.Info,
+ agent=Person(name='Timmy'),
+ author=User(email='bar@bar.com')))
db.session.commit()
pc, _ = user.get(res=d.Device, item=1)
assert len(pc['events']) == 1
- assert pc['events'][0]['type'] == 'Test'
+ assert pc['events'][0]['type'] == 'TestConnectivity'
assert pc['events'][0]['device'] == 1
assert pc['events'][0]['severity'] == 'Info'
assert UUID(pc['events'][0]['author'])
diff --git a/tests/test_event.py b/tests/test_event.py
index b58ddd00..fa2aa7bb 100644
--- a/tests/test_event.py
+++ b/tests/test_event.py
@@ -362,7 +362,6 @@ def test_manual_rate_after_workbench_rate(user: UserClient):
s = file('real-hp.snapshot.11')
snapshot, _ = user.post(s, res=models.Snapshot)
device, _ = user.get(res=Device, item=snapshot['device']['id'])
- # TODO
assert 'B' == device['rate']['appearanceRange']
assert device['rate'] == 1
user.post({
@@ -378,3 +377,27 @@ def test_manual_rate_after_workbench_rate(user: UserClient):
@pytest.mark.xfail(reson='Develop an algorithm that can make rates only from manual rates')
def test_manual_rate_without_workbench_rate(user: UserClient):
pass
+
+
+@pytest.mark.xfail(reson='develop')
+def test_measure_battery():
+ """Tests the MeasureBattery."""
+ # todo jn
+
+
+@pytest.mark.xfail(reson='develop')
+def test_test_camera():
+ """Tests the TestCamera."""
+ # todo jn
+
+
+@pytest.mark.xfail(reson='develop')
+def test_test_keyboard():
+ """Tests the TestKeyboard."""
+ # todo jn
+
+
+@pytest.mark.xfail(reson='develop')
+def test_test_trackpad():
+ """Tests the TestTrackpad."""
+ # todo jn
diff --git a/tests/test_rate.py b/tests/test_rate.py
index 3407cf45..204ebe2c 100644
--- a/tests/test_rate.py
+++ b/tests/test_rate.py
@@ -9,8 +9,8 @@ from ereuse_devicehub.resources.device.models import Computer, Desktop, HardDriv
RamModule
from ereuse_devicehub.resources.enums import AppearanceRange, ComputerChassis, \
FunctionalityRange
-from ereuse_devicehub.resources.event.models import BenchmarkDataStorage, \
- BenchmarkProcessor, RateComputer, TestVisual, Snapshot
+from ereuse_devicehub.resources.event.models import BenchmarkDataStorage, BenchmarkProcessor, \
+ RateComputer, Snapshot, VisualTest
from ereuse_devicehub.resources.event.rate.workbench.v1_0 import CannotRate
from tests import conftest
from tests.conftest import file
@@ -28,16 +28,11 @@ def test_workbench_rate_db():
db.session.commit()
-@pytest.mark.xfail(reason='AggreagteRate only takes data from WorkbenchRate as for now')
+@pytest.mark.xfail(reason='ComputerRate V1 can only be triggered from Workbench snapshot software')
def test_rate_workbench_then_manual():
- """Checks that a new Rate is generated with a new rate
- value when a TestVisual is performed after performing a
- RateComputer.
-
- The new Rate needs to be computed by the values of
- the appearance and funcitonality grade of TestVisual.
+ """Checks that a new Rate is generated for a snapshot
+ that is not from Workbench.
"""
- pass
@pytest.mark.usefixtures(conftest.app_context.__name__)
@@ -60,11 +55,9 @@ def test_rate():
}
# Add test visual with functionality and appearance range
- visual_test = TestVisual()
- visual_test.appearance_range = AppearanceRange.A
- visual_test.functionality_range = FunctionalityRange.A
-
- pc.events_one.add(visual_test)
+ VisualTest(appearance_range=AppearanceRange.A,
+ functionality_range=FunctionalityRange.A,
+ device=pc)
rate, price = RateComputer.compute(pc)
# events = pc.events
@@ -120,3 +113,14 @@ def test_no_rate_if_device_is_not_computer(user: UserClient):
device = file('keyboard.snapshot')
user.post(device, res=Snapshot)
assert CannotRate
+
+
+@pytest.mark.xfail(reason='Test not developed')
+def test_multiple_rates(user: UserClient):
+ """Tests submitting two rates from Workbench,
+ ensuring that the tests / benchmarks...
+ from the first rate do not contaminate the second rate.
+
+ This ensures that rates only takes the last version of events
+ and components (in case device has new components, for example).
+ """
diff --git a/tests/test_rate_workbench_v1.py b/tests/test_rate_workbench_v1.py
index 19191384..4040d8bd 100644
--- a/tests/test_rate_workbench_v1.py
+++ b/tests/test_rate_workbench_v1.py
@@ -18,7 +18,7 @@ import pytest
from ereuse_devicehub.resources.device.models import Desktop, HardDrive, Processor, RamModule
from ereuse_devicehub.resources.enums import AppearanceRange, ComputerChassis, FunctionalityRange
from ereuse_devicehub.resources.event.models import BenchmarkDataStorage, BenchmarkProcessor, \
- RateComputer, TestVisual
+ VisualTest
from ereuse_devicehub.resources.event.rate.workbench.v1_0 import DataStorageRate, ProcessorRate, \
RamRate, RateAlgorithm
@@ -32,31 +32,31 @@ def test_rate_data_storage_rate():
hdd_1969 = HardDrive(size=476940)
hdd_1969.events_one.add(BenchmarkDataStorage(read_speed=126, write_speed=29.8))
- data_storage_rate = DataStorageRate().compute([hdd_1969], RateComputer())
+ data_storage_rate = DataStorageRate().compute([hdd_1969])
- assert math.isclose(data_storage_rate, 4.02, rel_tol=0.001), 'DataStorageRate returns incorrect value(rate)'
+ assert math.isclose(data_storage_rate, 4.02, rel_tol=0.001)
hdd_3054 = HardDrive(size=476940)
hdd_3054.events_one.add(BenchmarkDataStorage(read_speed=158, write_speed=34.7))
# calculate DataStorage Rate
- data_storage_rate = DataStorageRate().compute([hdd_3054], RateComputer())
+ data_storage_rate = DataStorageRate().compute([hdd_3054])
- assert math.isclose(data_storage_rate, 4.07, rel_tol=0.001), 'DataStorageRate returns incorrect value(rate)'
+ assert math.isclose(data_storage_rate, 4.07, rel_tol=0.001)
hdd_81 = HardDrive(size=76319)
hdd_81.events_one.add(BenchmarkDataStorage(read_speed=72.2, write_speed=24.3))
- data_storage_rate = DataStorageRate().compute([hdd_81], RateComputer())
+ data_storage_rate = DataStorageRate().compute([hdd_81])
- assert math.isclose(data_storage_rate, 2.61, rel_tol=0.001), 'DataStorageRate returns incorrect value(rate)'
+ assert math.isclose(data_storage_rate, 2.61, rel_tol=0.001)
hdd_1556 = HardDrive(size=152587)
hdd_1556.events_one.add(BenchmarkDataStorage(read_speed=78.1, write_speed=24.4))
- data_storage_rate = DataStorageRate().compute([hdd_1556], RateComputer())
+ data_storage_rate = DataStorageRate().compute([hdd_1556])
- assert math.isclose(data_storage_rate, 3.70, rel_tol=0.001), 'DataStorageRate returns incorrect value(rate)'
+ assert math.isclose(data_storage_rate, 3.70, rel_tol=0.001)
def test_rate_data_storage_size_is_null():
@@ -69,7 +69,7 @@ def test_rate_data_storage_size_is_null():
hdd_null = HardDrive(size=None)
hdd_null.events_one.add(BenchmarkDataStorage(read_speed=0, write_speed=0))
- data_storage_rate = DataStorageRate().compute([hdd_null], RateComputer())
+ data_storage_rate = DataStorageRate().compute([hdd_null])
assert data_storage_rate is None
@@ -79,7 +79,7 @@ def test_rate_no_data_storage():
"""
hdd_null = HardDrive()
hdd_null.events_one.add(BenchmarkDataStorage(read_speed=0, write_speed=0))
- data_storage_rate = DataStorageRate().compute([hdd_null], RateComputer())
+ data_storage_rate = DataStorageRate().compute([hdd_null])
assert data_storage_rate is None
@@ -94,7 +94,7 @@ def test_rate_ram_rate():
ram1 = RamModule(size=2048, speed=1333)
- ram_rate = RamRate().compute([ram1], RateComputer())
+ ram_rate = RamRate().compute([ram1])
# todo rel_tol >= 0.002
assert math.isclose(ram_rate, 2.02, rel_tol=0.002), 'RamRate returns incorrect value(rate)'
@@ -109,7 +109,7 @@ def test_rate_ram_rate_2modules():
ram1 = RamModule(size=4096, speed=1600)
ram2 = RamModule(size=2048, speed=1067)
- ram_rate = RamRate().compute([ram1, ram2], RateComputer())
+ ram_rate = RamRate().compute([ram1, ram2])
assert math.isclose(ram_rate, 3.79, rel_tol=0.001), 'RamRate returns incorrect value(rate)'
@@ -125,7 +125,7 @@ def test_rate_ram_rate_4modules():
ram3 = RamModule(size=512, speed=667)
ram4 = RamModule(size=512, speed=533)
- ram_rate = RamRate().compute([ram1, ram2, ram3, ram4], RateComputer())
+ ram_rate = RamRate().compute([ram1, ram2, ram3, ram4])
# todo rel_tol >= 0.002
assert math.isclose(ram_rate, 1.993, rel_tol=0.001), 'RamRate returns incorrect value(rate)'
@@ -138,7 +138,7 @@ def test_rate_ram_module_size_is_0():
ram0 = RamModule(size=0, speed=888)
- ram_rate = RamRate().compute([ram0], RateComputer())
+ ram_rate = RamRate().compute([ram0])
assert ram_rate is None
@@ -150,13 +150,13 @@ def test_rate_ram_speed_is_null():
ram0 = RamModule(size=2048, speed=None)
- ram_rate = RamRate().compute([ram0], RateComputer())
+ ram_rate = RamRate().compute([ram0])
assert math.isclose(ram_rate, 1.85, rel_tol=0.002), 'RamRate returns incorrect value(rate)'
ram0 = RamModule(size=1024, speed=None)
- ram_rate = RamRate().compute([ram0], RateComputer())
+ ram_rate = RamRate().compute([ram0])
# todo rel_tol >= 0.004
assert math.isclose(ram_rate, 1.25, rel_tol=0.004), 'RamRate returns incorrect value(rate)'
@@ -168,7 +168,7 @@ def test_rate_no_ram_module():
"""
ram0 = RamModule()
- ram_rate = RamRate().compute([ram0], RateComputer())
+ ram_rate = RamRate().compute([ram0])
assert ram_rate is None
@@ -184,9 +184,9 @@ def test_rate_processor_rate():
# add score processor benchmark
cpu.events_one.add(BenchmarkProcessor(rate=3192.34))
- processor_rate = ProcessorRate().compute(cpu, RateComputer())
+ processor_rate = ProcessorRate().compute(cpu)
- assert math.isclose(processor_rate, 1, rel_tol=0.001), 'ProcessorRate returns incorrect value(rate)'
+ assert math.isclose(processor_rate, 1, rel_tol=0.001)
def test_rate_processor_rate_2cores():
@@ -199,17 +199,17 @@ def test_rate_processor_rate_2cores():
# add score processor benchmark
cpu.events_one.add(BenchmarkProcessor(rate=27136.44))
- processor_rate = ProcessorRate().compute(cpu, RateComputer())
+ processor_rate = ProcessorRate().compute(cpu)
- assert math.isclose(processor_rate, 3.95, rel_tol=0.001), 'ProcessorRate returns incorrect value(rate)'
+ assert math.isclose(processor_rate, 3.95, rel_tol=0.001)
cpu = Processor(cores=2, speed=3.3)
cpu.events_one.add(BenchmarkProcessor(rate=26339.48))
- processor_rate = ProcessorRate().compute(cpu, RateComputer())
+ processor_rate = ProcessorRate().compute(cpu)
# todo rel_tol >= 0.002
- assert math.isclose(processor_rate, 3.93, rel_tol=0.002), 'ProcessorRate returns incorrect value(rate)'
+ assert math.isclose(processor_rate, 3.93, rel_tol=0.002)
def test_rate_processor_with_null_cores():
@@ -220,10 +220,10 @@ def test_rate_processor_with_null_cores():
# todo try without BenchmarkProcessor, StopIteration problem
cpu.events_one.add(BenchmarkProcessor())
- processor_rate = ProcessorRate().compute(cpu, RateComputer())
+ processor_rate = ProcessorRate().compute(cpu)
# todo rel_tol >= 0.003
- assert math.isclose(processor_rate, 1.38, rel_tol=0.003), 'ProcessorRate returns incorrect value(rate)'
+ assert math.isclose(processor_rate, 1.38, rel_tol=0.003)
def test_rate_processor_with_null_speed():
@@ -233,9 +233,9 @@ def test_rate_processor_with_null_speed():
cpu = Processor(cores=1, speed=None)
cpu.events_one.add(BenchmarkProcessor(rate=0))
- processor_rate = ProcessorRate().compute(cpu, RateComputer())
+ processor_rate = ProcessorRate().compute(cpu)
- assert math.isclose(processor_rate, 1.06, rel_tol=0.001), 'ProcessorRate returns incorrect value(rate)'
+ assert math.isclose(processor_rate, 1.06, rel_tol=0.001)
def test_rate_computer_rate():
@@ -324,11 +324,9 @@ def test_rate_computer_rate():
cpu
}
# Add test visual with functionality and appearance range
- visual_test = TestVisual()
- visual_test.appearance_range = AppearanceRange.A
- visual_test.functionality_range = FunctionalityRange.A
-
- pc_test.events_one.add(visual_test)
+ VisualTest(appearance_range=AppearanceRange.A,
+ functionality_range=FunctionalityRange.A,
+ device=pc_test)
# Compute all components rates and general rating
rate_pc = RateAlgorithm().compute(pc_test)
@@ -353,10 +351,9 @@ def test_rate_computer_rate():
cpu
}
# Add test visual with functionality and appearance range
- visual_test = TestVisual()
- visual_test.appearance_range = AppearanceRange.B
- visual_test.functionality_range = FunctionalityRange.A
- pc_test.events_one.add(visual_test)
+ VisualTest(appearance_range=AppearanceRange.B,
+ functionality_range=FunctionalityRange.A,
+ device=pc_test)
# Compute all components rates and general rating
rate_pc = RateAlgorithm().compute(pc_test)
@@ -384,12 +381,9 @@ def test_rate_computer_rate():
cpu
}
# Add test visual with functionality and appearance range
- visual_test = TestVisual()
- visual_test.appearance_range = AppearanceRange.C
- visual_test.functionality_range = FunctionalityRange.A
-
- pc_test.events_one.add(visual_test)
-
+ VisualTest(appearance_range=AppearanceRange.C,
+ functionality_range=FunctionalityRange.A,
+ device=pc_test)
# Compute all components rates and general rating
rate_pc = RateAlgorithm().compute(pc_test)
@@ -399,7 +393,7 @@ def test_rate_computer_rate():
assert math.isclose(rate_pc.processor, 1, rel_tol=0.001)
- assert math.isclose(rate_pc.rating, 1.58, rel_tol=0.001)
+ assert rate_pc.rating == 1.57
# Create a new Computer with components characteristics of pc with id = 798
pc_test = Desktop(chassis=ComputerChassis.Tower)
@@ -413,11 +407,9 @@ def test_rate_computer_rate():
cpu
}
# Add test visual with functionality and appearance range
- visual_test = TestVisual()
- visual_test.appearance_range = AppearanceRange.B
- visual_test.functionality_range = FunctionalityRange.A
-
- pc_test.events_one.add(visual_test)
+ VisualTest(appearance_range=AppearanceRange.B,
+ functionality_range=FunctionalityRange.A,
+ device=pc_test)
# Compute all components rates and general rating
rate_pc = RateAlgorithm().compute(pc_test)
diff --git a/tests/test_snapshot.py b/tests/test_snapshot.py
index 6d86574b..e984af63 100644
--- a/tests/test_snapshot.py
+++ b/tests/test_snapshot.py
@@ -17,8 +17,8 @@ from ereuse_devicehub.resources.device.models import SolidStateDrive
from ereuse_devicehub.resources.device.sync import MismatchBetweenProperties, \
MismatchBetweenTagsAndHid
from ereuse_devicehub.resources.enums import ComputerChassis, SnapshotSoftware
-from ereuse_devicehub.resources.event.models import BenchmarkProcessor, \
- EraseSectors, Event, Snapshot, SnapshotRequest, RateComputer, TestVisual, BenchmarkDataStorage
+from ereuse_devicehub.resources.event.models import BenchmarkDataStorage, BenchmarkProcessor, \
+ EraseSectors, Event, RateComputer, Snapshot, SnapshotRequest, VisualTest
from ereuse_devicehub.resources.tag import Tag
from ereuse_devicehub.resources.user.models import User
from tests.conftest import file
@@ -70,7 +70,7 @@ def test_snapshot_post(user: UserClient):
snapshot = snapshot_and_check(user, file('basic.snapshot'),
event_types=(
BenchmarkProcessor.t,
- TestVisual.t,
+ VisualTest.t,
RateComputer.t
),
perform_second_snapshot=False)
@@ -116,15 +116,17 @@ def test_snapshot_component_add_remove(user: UserClient):
# (represented with their S/N) should be:
# PC 1: p1c1s, p1c2s, p1c3s. PC 2: ø
s1 = file('1-device-with-components.snapshot')
- # TODO if dont put len([event_types]) = 1 != len(event_types) = 18 is BenchmarkProcessor (str 18 chars); why??
- snapshot1 = snapshot_and_check(user, s1, event_types=('BenchmarkProcessor',), perform_second_snapshot=False)
+ snapshot1 = snapshot_and_check(user,
+ s1,
+ event_types=(BenchmarkProcessor.t,),
+ perform_second_snapshot=False)
pc1_id = snapshot1['device']['id']
pc1, _ = user.get(res=m.Device, item=pc1_id)
# Parent contains components
assert tuple(c['serialNumber'] for c in pc1['components']) == ('p1c1s', 'p1c2s', 'p1c3s')
# Components contain parent
assert all(c['parent'] == pc1_id for c in pc1['components'])
- # pc has Snapshot as event
+ # pc has two events: Snapshot and the BenchmarkProcessor
# TODO change assert to len(pc1['events']) == 2 cause we add BenchmarkProcessor event
assert len(pc1['events']) == 2
# TODO pc1['events'][0]['type'] == BenchmarkProcessor.t
@@ -154,7 +156,8 @@ def test_snapshot_component_add_remove(user: UserClient):
assert tuple(e['type'] for e in pc2['events']) == ('Snapshot',)
# p1c2s has two Snapshots, a Remove and an Add
p1c2s, _ = user.get(res=m.Device, item=pc2['components'][0]['id'])
- assert tuple(e['type'] for e in p1c2s['events']) == ('BenchmarkProcessor', 'Snapshot', 'Snapshot', 'Remove')
+ assert tuple(e['type'] for e in p1c2s['events']) == (
+ 'BenchmarkProcessor', 'Snapshot', 'Snapshot', 'Remove')
# We register the first device again, but removing motherboard
# and moving processor from the second device to the first.
@@ -243,11 +246,7 @@ def test_snapshot_tag_inner_tag(tag_id: str, user: UserClient, app: Devicehub):
b['device']['tags'] = [{'type': 'Tag', 'id': tag_id}]
snapshot_and_check(user, b,
- event_types=(
- RateComputer.t,
- BenchmarkProcessor.t,
- TestVisual.t
- ), perform_second_snapshot=False)
+ event_types=(RateComputer.t, BenchmarkProcessor.t, VisualTest.t))
with app.app_context():
tag = Tag.query.one() # type: Tag
assert tag.device_id == 1, 'Tag should be linked to the first device'
@@ -315,15 +314,17 @@ def test_erase_privacy_standards(user: UserClient):
EraseSectors.t,
BenchmarkDataStorage.t,
BenchmarkProcessor.t
- ), perform_second_snapshot=True)
+ ))
erase = next(e for e in snapshot['events'] if e['type'] == EraseSectors.t)
assert '2018-06-01T07:12:06+00:00' == erase['endTime']
storage = next(e for e in snapshot['components'] if e['type'] == SolidStateDrive.t)
storage, _ = user.get(res=m.Device, item=storage['id']) # Let's get storage events too
# order: creation time ascending
- erasure1, benchmark_data_storage1, _snapshot1, erasure2, benchmark_data_storage2, _snapshot2 = storage['events']
+ erasure1, benchmark_data_storage1, _snapshot1, erasure2, benchmark_data_storage2, _snapshot2 = \
+ storage['events']
assert erasure1['type'] == erasure2['type'] == 'EraseSectors'
- assert benchmark_data_storage1['type'] == benchmark_data_storage2['type'] == 'BenchmarkDataStorage'
+ assert benchmark_data_storage1['type'] == benchmark_data_storage2[
+ 'type'] == 'BenchmarkDataStorage'
assert _snapshot1['type'] == _snapshot2['type'] == 'Snapshot'
get_snapshot, _ = user.get(res=Event, item=_snapshot2['id'])
assert get_snapshot['events'][0]['endTime'] == '2018-06-01T07:12:06+00:00'
@@ -381,7 +382,7 @@ def test_snapshot_computer_monitor(user: UserClient):
@pytest.mark.xfail(reason='Not implemented yet, new rate is need it')
def test_snapshot_mobile_smartphone_imei_manual_rate(user: UserClient):
s = file('smartphone.snapshot')
- snapshot = snapshot_and_check(user, s, event_types=('TestVisual',))
+ snapshot = snapshot_and_check(user, s, event_types=('VisualTest',))
mobile, _ = user.get(res=m.Device, item=snapshot['device']['id'])
assert mobile['imei'] == 3568680000414120
# todo check that manual rate has been created
@@ -429,7 +430,7 @@ def assert_similar_components(components1: List[dict], components2: List[dict]):
def snapshot_and_check(user: UserClient,
input_snapshot: dict,
- event_types: Tuple[str] = tuple(),
+ event_types: Tuple[str, ...] = tuple(),
perform_second_snapshot=True) -> dict:
"""
Performs a Snapshot and then checks if the result is ok:
diff --git a/tests/test_workbench.py b/tests/test_workbench.py
index 838121a2..90a1ddba 100644
--- a/tests/test_workbench.py
+++ b/tests/test_workbench.py
@@ -36,7 +36,7 @@ def test_workbench_server_condensed(user: UserClient):
snapshot, _ = user.post(res=em.Snapshot, data=s)
events = snapshot['events']
assert {(event['type'], event['device']) for event in events} == {
- ('RateComputer', 1), # Only (RateComputer, 1), delete (Rate, 1)
+ ('RateComputer', 1),
('BenchmarkProcessorSysbench', 5),
('StressTest', 1),
('EraseSectors', 6),
@@ -47,7 +47,7 @@ def test_workbench_server_condensed(user: UserClient):
('BenchmarkDataStorage', 6),
('BenchmarkDataStorage', 7),
('TestDataStorage', 6),
- ('TestVisual', 1)
+ ('VisualTest', 1)
}
assert snapshot['closed']
assert snapshot['severity'] == 'Info'
@@ -62,11 +62,9 @@ def test_workbench_server_condensed(user: UserClient):
assert device['rate']['closed']
assert device['rate']['severity'] == 'Info'
assert device['rate']['rating'] == 0
- assert device['rate']['type'] == 'RateComputer' # New in rate v2
- # new asserts get in TestVisual event info; why change in every execution device['events'][X]
- # assert device['events'][0]['appearanceRange'] == 'A'
- # assert device['events'][0]['functionalityRange'] == 'B'
- # TODO add appearance and functionality Range in device[rate]
+ assert device['rate']['type'] == 'RateComputer'
+ assert device['events'][0]['appearanceRange'] == 'A'
+ assert device['events'][0]['functionalityRange'] == 'B'
assert device['tags'][0]['id'] == 'tag1'
@@ -154,8 +152,8 @@ def test_real_hp_11(user: UserClient):
'TestDataStorage',
'BenchmarkRamSysbench',
'StressTest',
- 'TestBios', # New in rate v2
- 'TestVisual' # New in rate v2
+ 'TestBios',
+ 'VisualTest'
}
assert len(list(e['type'] for e in snapshot['events'])) == 10
assert pc['networkSpeeds'] == [1000, None], 'Device has no WiFi'
@@ -188,7 +186,6 @@ def test_snapshot_real_eee_1001pxd(user: UserClient):
assert pc['networkSpeeds'] == [100, 0], 'Although it has WiFi we do not know the speed'
assert pc['rate']
rate = pc['rate']
- # new asserts get in TestVisual event info; why change pc['events'][X]
# assert pc['events'][0]['appearanceRange'] == 'A'
# assert pc['events'][0]['functionalityRange'] == 'B'
# TODO add appearance and functionality Range in device[rate]