diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index 83098af8..cba0d1d1 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -1,5 +1,6 @@ """ -This file contains all actions can apply to a device and is sorted according to a structure based on: +This file contains all actions can apply to a device and is sorted according +to a structure based on: * Generic Actions * Benchmarks @@ -647,6 +648,12 @@ class Test(JoinedWithOneDeviceMixin, ActionWithOneDevice): """The act of testing the physical condition of a device and its components. + Ref in R2 Provision 6 pag.19: + Records of test results are imperative to documenting + the functionality of each device. + Pass or fail results for each test in the process must be recorded + either manually or through software automation. + Testing errors and warnings are easily taken in :attr:`ereuse_devicehub.resources.device.models.Device.working`. """ @@ -674,10 +681,23 @@ class TestMixin: class MeasureBattery(TestMixin, Test): - """A sample of the status of the battery. + """ + A sample of the status of the battery. + Ref in R2 Provision 6 pag.22 Example: + Length of charge; Expected results: Minimum 40 minutes. Operative Systems keep a record of several aspects of a battery. This is a sample of those. + + :class: 'Severtity' + Info/Pass(0): + + Notice(1): + + Warning(2): + + Error/Fail(3): + """ size = db.Column(db.Integer, nullable=False) size.comment = """Maximum battery capacity, in mAh.""" @@ -704,6 +724,16 @@ class TestDataStorage(TestMixin, Test): The test takes to other SMART values indicators of the overall health of the data storage. + + :class: 'Severtity' + Info/Pass(0): + + Notice(1): + + Warning(2): + + Error/Fail(3): + """ length = Column(DBEnum(TestDataStorageLength), nullable=False) # todo from type status = Column(Unicode(), check_lower('status'), nullable=False) @@ -771,7 +801,18 @@ class StressTest(TestMixin, Test): class TestAudio(TestMixin, Test): """ - Test to check all this aspects related with audio functions, Manual Tests?? + Test to check audio device aspects, focus on speaker sounds correctly + and microphone record sounds good + + :class: 'Severtity' + Info/Pass(0): + + Notice(1): + + Warning(2): + + Error/Fail(3): + """ _speaker = Column('speaker', Boolean) _speaker.comment = """Whether the speaker works as expected.""" @@ -803,35 +844,87 @@ class TestAudio(TestMixin, Test): class TestConnectivity(TestMixin, Test): - """Tests that the device can connect both physically and - wirelessly. + """ + Tests that the device can connect both physically and wirelessly. A failing test means that at least one connection of the device is not working well. A comment should get into more detail. + + :class: 'Severtity' + Info/Pass(0): + + Notice(1): + + Warning(2): + + Error/Fail(3): + """ class TestCamera(TestMixin, Test): - """Tests the working conditions of the camera of the device, + """ + Tests the working conditions of the camera of the device, specially when taking pictures or recording video. + Fail when camera can't take pictures. """ class TestKeyboard(TestMixin, Test): - """Whether the keyboard works correctly.""" + """ + Whether the keyboard works correctly. + + Ref in R2 Provision 6 pag.22 example: + PASS when each key produces character on the screen + """ class TestTrackpad(TestMixin, Test): - """Whether the trackpad works correctly.""" + """ + Whether the trackpad works correctly. + + Ref in R2 Provision 6 pag.22 example: + PASS when cursor moves on screen + """ + + +class TestScreenHinge(TestMixin, Test): + """ + Whether screen hinge works correctly. + + Laptop Test Ref in R2 Provision 6 pag.22 example: + PASS when laptop screen stays open/closed at desired angles + """ + + +class TestPowerAdapter(TestMixin, Test): + """ + Whether power adapter charge battery device without problems. + + Laptop Test Ref in R2 Provision 6 pag.22 example: + PASS when plug power adapter into laptop and charges the battery. + """ class TestBios(TestMixin, Test): - """Tests the working condition and grades the usability of the BIOS.""" - bios_power_on = Column(Boolean) - bios_power_on.comment = """Whether there are no beeps or error + """ + Tests the working condition and grades the usability of the BIOS. + + :class: 'Severtity' + Info/Pass(0): + + Notice(1): + + Warning(2): + + Error/Fail(3): + + """ + beeps_power_on = Column(Boolean) + beeps_power_on.comment = """Whether there are no beeps or error codes when booting up. - Reference: R2 standard page 23. + Reference: R2 provision 6 page 23. """ access_range = Column(DBEnum(BiosAccessRange)) access_range.comment = """Difficulty to modify the boot menu. @@ -842,8 +935,25 @@ class TestBios(TestMixin, Test): class VisualTest(TestMixin, Test): - """The act of visually inspecting the appearance and functionality + """ + The act of visually inspecting the appearance and functionality of the device. + + Reference R2 provision 6 Templates Ready for Resale Checklist (Desktop) + https://sustainableelectronics.org/sites/default/files/6.c.2%20Desktop%20R2-Ready%20for%20Resale%20Checklist.docx + Physical condition grade + + + :class: 'Severtity' + Info/Pass(0): + + Notice(1): + + Warning(2): + + Error/Fail(3): + + """ appearance_range = Column(DBEnum(AppearanceRange), nullable=False) appearance_range.comment = AppearanceRange.__doc__ @@ -860,7 +970,14 @@ class VisualTest(TestMixin, Test): class Rate(JoinedWithOneDeviceMixin, ActionWithOneDevice): - """The act of computing a rate based on different categories""" + """ + The act of computing a rate based on different categories: + + • Functionality (F). Tests, the act of testing usage condition of a device + • Appearance (A). Visual evaluation, surface deterioration. + • Performance (Q). Components characteristics and components benchmarks. + + """ # todo jn: explain in each comment what the rate considers. N = 2 """The number of significant digits for rates. @@ -938,7 +1055,11 @@ class RateMixin: class RateComputer(RateMixin, Rate): - """The act of rating a computer.""" + """ + The act of rating a computer type devices. + It's the starting point for calculating the rate. + Algorithm explained in v1.0 file + """ _processor = Column('processor', Float(decimal_return_scale=Rate.N), check_range('processor', *R_POSITIVE)) diff --git a/ereuse_devicehub/resources/action/rate/workbench/v1_0.py b/ereuse_devicehub/resources/action/rate/workbench/v1_0.py index c3f8b2a2..c2395766 100644 --- a/ereuse_devicehub/resources/action/rate/workbench/v1_0.py +++ b/ereuse_devicehub/resources/action/rate/workbench/v1_0.py @@ -12,6 +12,51 @@ from ereuse_devicehub.resources.device.models import Computer, DataStorage, Proc class RateAlgorithm(BaseRate): """The algorithm that generates the Rate v1.0. + Rate v1.0 is mainly based on 3 components (Processor, RAM and Data Storage) + and 2 visual grades (one for appearance aspects and other for functionality aspects). + + From components we take into account their main characteristics and + also some tests and benchmarks. In particular: + + * Processor: + - Cores + - Speed + - Benchmark processor + + * RAM: + - Size + - Speed + + * Data Storage: + - Size + - Benchmark data storage (Read and write speed) + + Step by step to compute Rate v1.0: + + 1. Normalization the components characteristics. + Normalized the characteristics of the components between 0 and 1. + with xMin and xMax and standardize the values applying + the following formula: + + **Normalization characteristic value = (x −xMin)/(xMax −xMin)** + + 2. Merge the characteristics of every component in one score for component. + + + 3. Merge the components individual rates into a single components rate. + We calculate this rate using the weighted harmonic mean. + We establish all the components weights, 50% for processor, + 20% for data storage, 30% for RAM. + The result is a unique performance score (components rate). + + 4. Grouping all categories aspects sum all in unique final rate. + To get Functionality and Appearance Rates values, only directly + related a value for each grade. + + **Final Rate = Components Rate + Functionality Rate + Appearance Rate** + + Final Rate are ranged from 0 to 4.7. + Do not call directly this class, but use :meth:`ereuse_devicehub.resources.action.models.RateComputer.compute`, which then calls this. @@ -74,7 +119,7 @@ class RateAlgorithm(BaseRate): rate.functionality = self.Functionality[visual_test.functionality_range.name].value rate.rating = rate_components + rate.functionality + rate.appearance device.actions_one.add(rate) - assert 0 <= rate.rating <= 4.7, 'Rate ranges from 0 to 4.7' + assert 0 <= rate.rating <= 4.7 return rate @@ -88,12 +133,11 @@ class ProcessorRate(BaseRate): DEFAULT_CORES = 1 DEFAULT_SPEED = 1.6 - # In case of i2, i3,.. result penalized. - # 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): """ Compute processor rate + We assume always exists a Benchmark Processor Obs: cores and speed are possible NULL value :return: result is a rate (score) of Processor characteristics """ @@ -106,7 +150,7 @@ class ProcessorRate(BaseRate): benchmark_cpu = benchmark_cpu.rate or self.DEFAULT_SCORE # STEP: Fusion components - processor_rate = (benchmark_cpu + speed * 2000 * cores) / 2 # todo magic number! + processor_rate = (benchmark_cpu + speed * 2000 * cores) / 2 # STEP: Normalize values processor_norm = max(self.norm(processor_rate, *self.PROCESSOR_NORM), 0) @@ -136,7 +180,7 @@ class RamRate(BaseRate): def compute(self, ram_devices: Iterable[RamModule]): """ - Obs: RamModule.speed is possible NULL value & size != NULL or NOT?? + If ram speed or ram size, we assume default values before declared :return: result is a rate (score) of all RamModule components """ size = 0.0 diff --git a/ereuse_devicehub/resources/action/views.py b/ereuse_devicehub/resources/action/views.py index 3d2a6876..42c50dc2 100644 --- a/ereuse_devicehub/resources/action/views.py +++ b/ereuse_devicehub/resources/action/views.py @@ -8,7 +8,7 @@ from teal.marshmallow import ValidationError from teal.resource import View from ereuse_devicehub.db import db -from ereuse_devicehub.resources.action.models import Action, RateComputer, Snapshot +from ereuse_devicehub.resources.action.models import Action, RateComputer, Snapshot, VisualTest from ereuse_devicehub.resources.action.rate.workbench.v1_0 import CannotRate from ereuse_devicehub.resources.device.models import Component, Computer from ereuse_devicehub.resources.enums import SnapshotSoftware @@ -28,6 +28,9 @@ class ActionView(View): a = resource_def.schema.load(json) if json['type'] == Snapshot.t: return self.snapshot(a, resource_def) + if json['type'] == VisualTest.t: + pass + # TODO JN add compute rate with new visual test and old components device Model = db.Model._decl_class_registry.data[json['type']]() action = Model(**a) db.session.add(action) diff --git a/ereuse_devicehub/resources/enums.py b/ereuse_devicehub/resources/enums.py index 17d2d139..3e95565e 100644 --- a/ereuse_devicehub/resources/enums.py +++ b/ereuse_devicehub/resources/enums.py @@ -273,13 +273,13 @@ class Severity(IntEnum): """A flag evaluating the action execution. Ex. failed actions have the value `Severity.Error`. Devicehub uses 4 severity levels: - * Info: default neutral severity. The action succeeded. + * Info (Pass): default neutral severity. The action succeeded. * Notice: The action succeeded but it is raising awareness. Notices are not usually that important but something (good or bad) worth checking. * Warning: The action succeeded but there is something important to check negatively affecting the action. - * Error: the action failed. + * Error (Fail): the action failed. Devicehub specially raises user awareness when an action has a Severity of ``Warning`` or greater.