Review rate changes
This commit is contained in:
parent
e6d496872c
commit
16d00256df
|
@ -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
|
||||
|
|
|
@ -164,7 +164,7 @@
|
|||
{
|
||||
"appearanceRange": "A",
|
||||
"functionalityRange": "A",
|
||||
"type": "TestVisual"
|
||||
"type": "VisualTest"
|
||||
}
|
||||
],
|
||||
"manufacturer": "ASUSTeK Computer INC.",
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
{
|
||||
"appearanceRange": "A",
|
||||
"functionalityRange": "A",
|
||||
"type": "TestVisual"
|
||||
"type": "VisualTest"
|
||||
}
|
||||
],
|
||||
"manufacturer": "ASUSTeK Computer INC."
|
||||
|
|
|
@ -11,7 +11,7 @@ device:
|
|||
resolutionHeight: 1080
|
||||
size: 21.5
|
||||
events:
|
||||
- type: TestVisual
|
||||
- type: VisualTest
|
||||
appearanceRange: A
|
||||
functionalityRange: C
|
||||
labelling: False
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
{
|
||||
"appearanceRange": "A",
|
||||
"functionalityRange": "A",
|
||||
"type": "TestVisual"
|
||||
"type": "VisualTest"
|
||||
}
|
||||
],
|
||||
"type": "Desktop",
|
||||
|
|
|
@ -8,7 +8,7 @@ device:
|
|||
manufacturer: BAZ
|
||||
layout: ES
|
||||
events:
|
||||
- type: TestVisual
|
||||
- type: VisualTest
|
||||
appearanceRange: A
|
||||
functionalityRange: A
|
||||
labelling: False
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
{
|
||||
"appearanceRange": "B",
|
||||
"functionalityRange": "C",
|
||||
"type": "TestVisual"
|
||||
"type": "VisualTest"
|
||||
}
|
||||
],
|
||||
"type": "Desktop",
|
||||
|
|
|
@ -122,7 +122,7 @@
|
|||
{
|
||||
"appearanceRange": "A",
|
||||
"functionalityRange": "A",
|
||||
"type": "TestVisual"
|
||||
"type": "VisualTest"
|
||||
}
|
||||
],
|
||||
"manufacturer": "Hewlett-Packard",
|
||||
|
|
|
@ -154,7 +154,7 @@
|
|||
{
|
||||
"appearanceRange": "B",
|
||||
"functionalityRange": "A",
|
||||
"type": "TestVisual"
|
||||
"type": "VisualTest"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -157,7 +157,7 @@
|
|||
{
|
||||
"appearanceRange": "B",
|
||||
"functionalityRange": "D",
|
||||
"type": "TestVisual"
|
||||
"type": "VisualTest"
|
||||
}
|
||||
],
|
||||
"serialNumber": "CZC0408YJG",
|
||||
|
|
|
@ -8,7 +8,7 @@ device:
|
|||
serialNumber: ABCDEF
|
||||
imei: 35686800-004141-20
|
||||
events:
|
||||
- type: TestVisual
|
||||
- type: VisualTest
|
||||
appearanceRange: A
|
||||
functionalityRange: B
|
||||
labelling: False
|
||||
|
|
|
@ -21,28 +21,28 @@ device:
|
|||
- type: Tag
|
||||
id: tag1
|
||||
events:
|
||||
- type: TestVisual
|
||||
- type: VisualTest
|
||||
appearanceRange: A
|
||||
functionalityRange: B
|
||||
- type: BenchmarkRamSysbench
|
||||
rate: 2444
|
||||
elapsed: 1
|
||||
components:
|
||||
- type: GraphicCard
|
||||
- type: GraphicCard
|
||||
serialNumber: gc1-1s
|
||||
model: gc1-1ml
|
||||
manufacturer: gc1-1mr
|
||||
- type: RamModule
|
||||
- type: RamModule
|
||||
serialNumber: rm1-1s
|
||||
model: rm1-1ml
|
||||
manufacturer: rm1-1mr
|
||||
size: 1024
|
||||
- type: RamModule
|
||||
- type: RamModule
|
||||
serialNumber: rm2-1s
|
||||
model: rm2-1ml
|
||||
manufacturer: rm2-1mr
|
||||
size: 1024
|
||||
- type: Processor
|
||||
- type: Processor
|
||||
model: p1-1ml
|
||||
manufacturer: p1-1mr
|
||||
events:
|
||||
|
@ -52,7 +52,7 @@ components:
|
|||
- type: BenchmarkProcessorSysbench
|
||||
rate: 4400
|
||||
elapsed: 44
|
||||
- type: SolidStateDrive
|
||||
- type: SolidStateDrive
|
||||
serialNumber: ssd1-1s
|
||||
model: ssd1-1ml
|
||||
manufacturer: ssd1-1mr
|
||||
|
@ -76,7 +76,7 @@ components:
|
|||
currentPendingSectorCount: 1
|
||||
offlineUncorrectable: 33
|
||||
remainingLifetimePercentage: 1
|
||||
- type: HardDrive
|
||||
- type: HardDrive
|
||||
serialNumber: hdd1-1s
|
||||
model: hdd1-1ml
|
||||
manufacturer: hdd1-1mr
|
||||
|
@ -85,23 +85,23 @@ components:
|
|||
readSpeed: 10
|
||||
writeSpeed: 5
|
||||
elapsed: 20
|
||||
- type: Motherboard
|
||||
- type: Motherboard
|
||||
serialNumber: mb1-1s
|
||||
model: mb1-1ml
|
||||
manufacturer: mb1-1mr
|
||||
- type: NetworkAdapter
|
||||
- type: NetworkAdapter
|
||||
serialNumber: na1-s
|
||||
model: na1-1ml
|
||||
manufacturer: na1-1mr
|
||||
speed: 1000
|
||||
wireless: False
|
||||
- type: NetworkAdapter
|
||||
- type: NetworkAdapter
|
||||
serialNumber: na2-s
|
||||
model: na2-1ml
|
||||
manufacturer: na2-1mr
|
||||
wireless: True
|
||||
speed: 58
|
||||
- type: RamModule
|
||||
- type: RamModule
|
||||
serialNumber: rm3-1s
|
||||
model: rm3-1ml
|
||||
manufacturer: rm3-1mr
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)] = ''
|
||||
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
from typing import Iterable
|
||||
|
||||
import math
|
||||
from typing import Iterable
|
||||
|
||||
from ereuse_devicehub.resources.device.models import Device
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -14,7 +14,8 @@ CREATE OR REPLACE FUNCTION add_edge(parent_id uuid, child_id uuid)
|
|||
- http://patshaughnessy.net/2017/12/12/installing-the-postgres-ltree-extension
|
||||
- https://en.wikipedia.org/wiki/Directed_acyclic_graph
|
||||
*/
|
||||
RETURNS void AS $$
|
||||
RETURNS void AS
|
||||
$$
|
||||
DECLARE
|
||||
parent text := replace(CAST(parent_id as text), '-', '_');
|
||||
child text := replace(CAST(child_id as text), '-', '_');
|
||||
|
@ -24,8 +25,10 @@ BEGIN
|
|||
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)
|
||||
if EXISTS(
|
||||
SELECT 1
|
||||
FROM path
|
||||
where path.path ~ CAST('*.' || child || '.*.' || parent || '.*' as lquery)
|
||||
)
|
||||
then
|
||||
raise exception 'Cannot create edge: child already contains parent.';
|
||||
|
@ -38,7 +41,8 @@ BEGIN
|
|||
-- 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
|
||||
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)
|
||||
|
@ -46,7 +50,7 @@ BEGIN
|
|||
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``.
|
||||
|
@ -56,7 +60,8 @@ CREATE OR REPLACE FUNCTION delete_edge(parent_id uuid, child_id uuid)
|
|||
This method will raise an exception if the relationship does not
|
||||
exist.
|
||||
*/
|
||||
RETURNS void AS $$
|
||||
RETURNS void AS
|
||||
$$
|
||||
DECLARE
|
||||
parent text := replace(CAST(parent_id as text), '-', '_');
|
||||
child text := replace(CAST(child_id as text), '-', '_');
|
||||
|
@ -82,7 +87,8 @@ BEGIN
|
|||
DELETE
|
||||
FROM path
|
||||
WHERE id IN (SELECT id
|
||||
FROM (SELECT id, ROW_NUMBER() OVER (partition BY lot_id, path) AS rnum FROM path) t
|
||||
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
|
||||
|
@ -103,7 +109,7 @@ BEGIN
|
|||
|
||||
END
|
||||
$$
|
||||
LANGUAGE plpgsql;
|
||||
LANGUAGE plpgsql;
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -118,7 +118,7 @@
|
|||
{
|
||||
"appearanceRange": "A",
|
||||
"functionalityRange": "A",
|
||||
"type": "TestVisual"
|
||||
"type": "VisualTest"
|
||||
}
|
||||
],
|
||||
"manufacturer": "ASUSTeK Computer INC.",
|
||||
|
|
|
@ -10,7 +10,7 @@ device:
|
|||
model: d1ml
|
||||
manufacturer: d1mr
|
||||
events:
|
||||
- type: TestVisual
|
||||
- type: VisualTest
|
||||
appearanceRange: A
|
||||
functionalityRange: B
|
||||
components:
|
||||
|
|
|
@ -92,7 +92,7 @@
|
|||
{
|
||||
"appearanceRange": "D",
|
||||
"functionalityRange": "D",
|
||||
"type": "TestVisual"
|
||||
"type": "VisualTest"
|
||||
},
|
||||
{
|
||||
"elapsed": 300,
|
||||
|
|
|
@ -137,7 +137,7 @@
|
|||
{
|
||||
"appearanceRange": "A",
|
||||
"functionalityRange": "A",
|
||||
"type": "TestVisual"
|
||||
"type": "VisualTest"
|
||||
},
|
||||
{
|
||||
"elapsed": 300,
|
||||
|
|
|
@ -42,4 +42,4 @@ def test_api_docs(client: Client):
|
|||
'scheme': 'basic',
|
||||
'name': 'Authorization'
|
||||
}
|
||||
assert len(docs['definitions']) == 102
|
||||
assert len(docs['definitions']) == 101
|
||||
|
|
|
@ -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,
|
||||
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'])
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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).
|
||||
"""
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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]
|
||||
|
|
Reference in New Issue