diff --git a/ereuse_devicehub/auth.py b/ereuse_devicehub/auth.py index 5820c326..19f6e5fa 100644 --- a/ereuse_devicehub/auth.py +++ b/ereuse_devicehub/auth.py @@ -3,12 +3,17 @@ from teal.auth import TokenAuth from teal.db import ResourceNotFound from werkzeug.exceptions import Unauthorized -from ereuse_devicehub.resources.user.models import User +from ereuse_devicehub.resources.user.models import User, Session class Auth(TokenAuth): def authenticate(self, token: str, *args, **kw) -> User: try: - return User.query.filter_by(token=token).one() + user = User.query.filter_by(token=token).first() + if user: + return user + + ses = Session.query.filter_by(token=token).one() + return ses.user except (ResourceNotFound, DataError): raise Unauthorized('Provide a suitable token.') diff --git a/ereuse_devicehub/config.py b/ereuse_devicehub/config.py index beef8b25..5a37ace0 100644 --- a/ereuse_devicehub/config.py +++ b/ereuse_devicehub/config.py @@ -37,6 +37,7 @@ class DevicehubConfig(Config): DB_PASSWORD = config('DB_PASSWORD', 'ereuse') DB_HOST = config('DB_HOST', 'localhost') DB_DATABASE = config('DB_DATABASE', 'devicehub') + DB_SCHEMA = config('DB_SCHEMA', 'dbtest') SQLALCHEMY_DATABASE_URI = 'postgresql://{user}:{pw}@{host}/{db}'.format( user=DB_USER, pw=DB_PASSWORD, diff --git a/ereuse_devicehub/dummy/dummy.py b/ereuse_devicehub/dummy/dummy.py index da0fe385..183dbb9f 100644 --- a/ereuse_devicehub/dummy/dummy.py +++ b/ereuse_devicehub/dummy/dummy.py @@ -17,6 +17,8 @@ from ereuse_devicehub.resources.device.models import Device from ereuse_devicehub.resources.lot.models import Lot from ereuse_devicehub.resources.tag.model import Tag from ereuse_devicehub.resources.user import User +from ereuse_devicehub.resources.user.models import Session +from ereuse_devicehub.resources.enums import SessionType class Dummy: @@ -194,6 +196,10 @@ class Dummy: user.individuals.add(Person(name=name)) db.session.add(user) + session_external = Session(user=user, type=SessionType.External) + session_internal = Session(user=user, type=SessionType.Internal) + db.session.add(session_internal) + db.session.add(session_external) db.session.commit() client = UserClient(self.app, user.email, password, diff --git a/ereuse_devicehub/migrations/versions/21afd375a654_session_table.py b/ereuse_devicehub/migrations/versions/21afd375a654_session_table.py new file mode 100644 index 00000000..97a50435 --- /dev/null +++ b/ereuse_devicehub/migrations/versions/21afd375a654_session_table.py @@ -0,0 +1,62 @@ +"""session_table + +Revision ID: 21afd375a654 +Revises: 6a2a939d5668 +Create Date: 2021-04-13 11:18:27.720567 + +""" +from alembic import context +from alembic import op +from sqlalchemy.dialects import postgresql +import sqlalchemy as sa +import sqlalchemy_utils +import citext +import teal + +from ereuse_devicehub.resources.enums import SessionType + + +# revision identifiers, used by Alembic. +revision = '21afd375a654' +down_revision = '398826453b39' +branch_labels = None +depends_on = None +comment_update = 'The last time Devicehub recorded a change for this thing.\n' + + +def get_inv(): + INV = context.get_x_argument(as_dictionary=True).get('inventory') + if not INV: + raise ValueError("Inventory value is not specified") + return INV + + +def upgrade(): + op.create_table('session', + sa.Column('updated', sa.TIMESTAMP(timezone=True), + server_default=sa.text('CURRENT_TIMESTAMP'), + nullable=False, + comment=comment_update), + sa.Column('created', sa.TIMESTAMP(timezone=True), + server_default=sa.text('CURRENT_TIMESTAMP'), + nullable=False, comment='When Devicehub created this.'), + sa.Column('id', sa.BigInteger(), nullable=False), + sa.Column('expired', sa.BigInteger(), nullable=True), + sa.Column('token', postgresql.UUID(as_uuid=True), nullable=False), + sa.Column('type', teal.db.IntEnum(SessionType), nullable=False), + sa.Column('user_id', postgresql.UUID(as_uuid=True), nullable=True), + sa.ForeignKeyConstraint(['user_id'], ['common.user.id'], ), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('token'), + schema='common' + ) + op.create_index(op.f('ix_session_created'), 'session', ['created'], unique=False, schema='common') + op.create_index(op.f('ix_session_updated'), 'session', ['updated'], unique=False, schema='common') + op.create_index(op.f('ix_session_token'), 'session', ['token'], unique=True, schema='common') + + +def downgrade(): + op.drop_table('trade', schema=f'{get_inv()}') + op.drop_index(op.f('ix_session_created'), table_name='session', schema='common') + op.drop_index(op.f('ix_session_updated'), table_name='session', schema='common') + op.drop_index(op.f('ix_session_token'), table_name='session', schema='common') diff --git a/ereuse_devicehub/resources/documents/documents.py b/ereuse_devicehub/resources/documents/documents.py index 82008c69..3b72d85d 100644 --- a/ereuse_devicehub/resources/documents/documents.py +++ b/ereuse_devicehub/resources/documents/documents.py @@ -1,7 +1,8 @@ import csv -import datetime import enum import uuid +import datetime +import pathlib from collections import OrderedDict from io import StringIO from typing import Callable, Iterable, Tuple @@ -18,7 +19,9 @@ from flask.json import jsonify from teal.cache import cache from teal.resource import Resource, View +from ereuse_devicehub import auth from ereuse_devicehub.db import db +from ereuse_devicehub.resources.enums import SessionType from ereuse_devicehub.resources.action import models as evs from ereuse_devicehub.resources.device import models as devs from ereuse_devicehub.resources.deliverynote.models import Deliverynote @@ -253,7 +256,7 @@ class StampsView(View): url = urlutils.URL(request.url) url.normalize() url.path_parts = url.path_parts[:-2] + ['check', ''] - return url.to_text() + return url.to_text() def get(self): result = ('', '') @@ -314,6 +317,30 @@ class InternalStatsView(DeviceView): return output +class WbConfDocumentView(DeviceView): + def get(self, wbtype: str): + if not wbtype.lower() in ['usodyrate', 'usodywipe']: + return jsonify('') + + data = {'token': self.get_token(), + 'host': app.config['DB_HOST'], + 'inventory': app.config['DB_SCHEMA'] + } + data['erase'] = False + # data['erase'] = True if wbtype == 'usodywipe' else False + + env = flask.render_template('documents/wbSettings.ini', **data) + output = make_response(env) + output.headers['Content-Disposition'] = 'attachment; filename=settings.ini' + output.headers['Content-type'] = 'text/plain' + return output + + def get_token(self): + tk = [s.token for s in g.user.sessions if s.type == SessionType.Internal][0] + token = auth.Auth.encode(tk) + return token + + class DocumentDef(Resource): __type__ = 'Document' SCHEMA = None @@ -380,3 +407,9 @@ class DocumentDef(Resource): auth=app.auth) actions_view = app.auth.requires_auth(actions_view) self.add_url_rule('/actions/', defaults=d, view_func=actions_view, methods=get) + + wbconf_view = WbConfDocumentView.as_view('WbConfDocumentView', + definition=self, + auth=app.auth) + wbconf_view = app.auth.requires_auth(wbconf_view) + self.add_url_rule('/wbconf/', view_func=wbconf_view, methods=get) diff --git a/ereuse_devicehub/resources/documents/templates/documents/wbSettings.ini b/ereuse_devicehub/resources/documents/templates/documents/wbSettings.ini new file mode 100644 index 00000000..c7156a65 --- /dev/null +++ b/ereuse_devicehub/resources/documents/templates/documents/wbSettings.ini @@ -0,0 +1,17 @@ +[settings] + +DH_TOKEN="{{token}}" + +DH_HOST="{{host}}" +DH_DATABASE="{{inventory}}" +DEVICEHUB_URL=https://${DB_HOST}/${DB_DATABASE}/ + +WB_BENCHMARK = False +WB_STRESS_TEST = 0 +WB_SMART_TEST = "" + +WB_ERASE = {{erase}} +WB_ERASE_STEPS = 1 +WB_ERASE_LEADING_ZEROS = False + +WB_DEBUG = True diff --git a/ereuse_devicehub/resources/enums.py b/ereuse_devicehub/resources/enums.py index a07385d7..cff77056 100644 --- a/ereuse_devicehub/resources/enums.py +++ b/ereuse_devicehub/resources/enums.py @@ -393,3 +393,24 @@ class TransferState(IntEnum): def __str__(self): return self.name + + +@unique +class SessionType(IntEnum): + """ + Enumaration of types of sessions: + + * Internal: permanent Session for internal user. This is used in usb of WorkBench. + * External: permanent Session for external users. This is used in usb of WorkBench. + * Session: This is used for keep more than one session in the app frontend. + + Devicehub specially raises user awareness when an action + has a Severity of ``Warning`` or greater. + """ + + Internal = 0 + External = 1 + Session = 2 + + def __str__(self): + return self.name diff --git a/ereuse_devicehub/resources/user/__init__.py b/ereuse_devicehub/resources/user/__init__.py index ec9eed78..1bbe508b 100644 --- a/ereuse_devicehub/resources/user/__init__.py +++ b/ereuse_devicehub/resources/user/__init__.py @@ -7,7 +7,7 @@ from teal.resource import Converters, Resource from ereuse_devicehub.db import db from ereuse_devicehub.resources.user import schemas from ereuse_devicehub.resources.user.models import User -from ereuse_devicehub.resources.user.views import UserView, login +from ereuse_devicehub.resources.user.views import UserView, login, logout class UserDef(Resource): @@ -23,6 +23,8 @@ class UserDef(Resource): super().__init__(app, import_name, static_folder, static_url_path, template_folder, url_prefix, subdomain, url_defaults, root_path, cli_commands) self.add_url_rule('/login/', view_func=login, methods={'POST'}) + logout_view = app.auth.requires_auth(logout) + self.add_url_rule('/logout/', view_func=logout_view, methods={'GET'}) @argument('email') @option('-i', '--inventory', diff --git a/ereuse_devicehub/resources/user/models.py b/ereuse_devicehub/resources/user/models.py index 18e4efc8..f1690156 100644 --- a/ereuse_devicehub/resources/user/models.py +++ b/ereuse_devicehub/resources/user/models.py @@ -2,13 +2,15 @@ from uuid import uuid4 from citext import CIText from flask import current_app as app -from sqlalchemy import Column, Boolean +from sqlalchemy import Column, Boolean, BigInteger, Sequence from sqlalchemy.dialects.postgresql import UUID from sqlalchemy_utils import EmailType, PasswordType +from teal.db import IntEnum from ereuse_devicehub.db import db from ereuse_devicehub.resources.inventory.model import Inventory from ereuse_devicehub.resources.models import STR_SIZE, Thing +from ereuse_devicehub.resources.enums import SessionType class User(Thing): @@ -63,3 +65,18 @@ class UserInventory(db.Model): __table_args__ = {'schema': 'common'} user_id = db.Column(db.UUID(as_uuid=True), db.ForeignKey(User.id), primary_key=True) inventory_id = db.Column(db.Unicode(), db.ForeignKey(Inventory.id), primary_key=True) + + +class Session(Thing): + __table_args__ = {'schema': 'common'} + id = Column(BigInteger, Sequence('device_seq'), primary_key=True) + expired = Column(BigInteger, default=0) + token = Column(UUID(as_uuid=True), default=uuid4, unique=True, nullable=False) + type = Column(IntEnum(SessionType), default=SessionType.Internal, nullable=False) + user_id = db.Column(db.UUID(as_uuid=True), db.ForeignKey(User.id)) + user = db.relationship(User, + backref=db.backref('sessions', lazy=True, collection_class=set), + collection_class=set) + + def __str__(self) -> str: + return '{0.token}'.format(self) diff --git a/ereuse_devicehub/resources/user/schemas.py b/ereuse_devicehub/resources/user/schemas.py index e8d0d768..220e193b 100644 --- a/ereuse_devicehub/resources/user/schemas.py +++ b/ereuse_devicehub/resources/user/schemas.py @@ -9,6 +9,10 @@ from ereuse_devicehub.resources.inventory.schema import Inventory from ereuse_devicehub.resources.schemas import Thing +class Session(Thing): + token = String(dump_only=True) + + class User(Thing): id = UUID(dump_only=True) email = Email(required=True) diff --git a/ereuse_devicehub/resources/user/views.py b/ereuse_devicehub/resources/user/views.py index 8eadc863..2fc8fc31 100644 --- a/ereuse_devicehub/resources/user/views.py +++ b/ereuse_devicehub/resources/user/views.py @@ -1,11 +1,12 @@ -from uuid import UUID +from uuid import UUID, uuid4 from flask import g, request +from flask.json import jsonify from teal.resource import View +from ereuse_devicehub.db import db from ereuse_devicehub.resources.user.exceptions import WrongCredentials from ereuse_devicehub.resources.user.models import User -from ereuse_devicehub.resources.user.schemas import User as UserS class UserView(View): @@ -24,3 +25,11 @@ def login(): return schema_with_token.jsonify(user) else: raise WrongCredentials() + + +def logout(): + # We use custom schema as we only want to parse a subset of user + g.user.token = uuid4() + db.session.add(g.user) + db.session.commit() + return jsonify('Ok') diff --git a/tests/conftest.py b/tests/conftest.py index d0a0bdd2..4c45dc06 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -17,6 +17,8 @@ from ereuse_devicehub.devicehub import Devicehub from ereuse_devicehub.resources.agent.models import Person from ereuse_devicehub.resources.tag import Tag from ereuse_devicehub.resources.user.models import User +from ereuse_devicehub.resources.user.models import Session +from ereuse_devicehub.resources.enums import SessionType STARTT = datetime(year=2000, month=1, day=1, hour=1) """A dummy starting time to use in tests.""" @@ -111,7 +113,11 @@ def user2(app: Devicehub) -> UserClient: def create_user(email='foo@foo.com', password='foo') -> User: user = User(email=email, password=password) user.individuals.add(Person(name='Timmy')) + session_external = Session(user=user, type=SessionType.External) + session_internal = Session(user=user, type=SessionType.Internal) db.session.add(user) + db.session.add(session_internal) + db.session.add(session_external) db.session.commit() return user diff --git a/tests/files/basic.csv b/tests/files/basic.csv index a5370449..5b66408b 100644 --- a/tests/files/basic.csv +++ b/tests/files/basic.csv @@ -1,2 +1,2 @@ DevicehubID;DocumentID;Public Link;Tag 1 Type;Tag 1 ID;Tag 1 Organization;Tag 2 Type;Tag 2 ID;Tag 2 Organization;Tag 3 Type;Tag 3 ID;Tag 3 Organization;Device Hardware ID;Device Type;Device Chassis;Device Serial Number;Device Model;Device Manufacturer;Registered in;Registered (process);Updated in (software);Updated in (web);Physical state;Trading state;Processor;RAM (MB);Data Storage Size (MB);Processor 1;Processor 1 Manufacturer;Processor 1 Model;Processor 1 Serial Number;Processor 1 Number of cores;Processor 1 Speed (GHz);Benchmark Processor 1 (points);Benchmark ProcessorSysbench Processor 1 (points);Processor 2;Processor 2 Manufacturer;Processor 2 Model;Processor 2 Serial Number;Processor 2 Number of cores;Processor 2 Speed (GHz);Benchmark Processor 2 (points);Benchmark ProcessorSysbench Processor 2 (points);RamModule 1;RamModule 1 Manufacturer;RamModule 1 Model;RamModule 1 Serial Number;RamModule 1 Size (MB);RamModule 1 Speed (MHz);RamModule 2;RamModule 2 Manufacturer;RamModule 2 Model;RamModule 2 Serial Number;RamModule 2 Size (MB);RamModule 2 Speed (MHz);RamModule 3;RamModule 3 Manufacturer;RamModule 3 Model;RamModule 3 Serial Number;RamModule 3 Size (MB);RamModule 3 Speed (MHz);RamModule 4;RamModule 4 Manufacturer;RamModule 4 Model;RamModule 4 Serial Number;RamModule 4 Size (MB);RamModule 4 Speed (MHz);DataStorage 1;DataStorage 1 Manufacturer;DataStorage 1 Model;DataStorage 1 Serial Number;DataStorage 1 Size (MB);Erasure DataStorage 1;Erasure DataStorage 1 Serial Number;Erasure DataStorage 1 Size (MB);Erasure DataStorage 1 Software;Erasure DataStorage 1 Result;Erasure DataStorage 1 Type;Erasure DataStorage 1 Method;Erasure DataStorage 1 Elapsed (hours);Erasure DataStorage 1 Date;Erasure DataStorage 1 Steps;Erasure DataStorage 1 Steps Start Time;Erasure DataStorage 1 Steps End Time;Benchmark DataStorage 1 Read Speed (MB/s);Benchmark DataStorage 1 Writing speed (MB/s);Test DataStorage 1 Software;Test DataStorage 1 Type;Test DataStorage 1 Result;Test DataStorage 1 Power on (hours used);Test DataStorage 1 Lifetime remaining (percentage);DataStorage 2;DataStorage 2 Manufacturer;DataStorage 2 Model;DataStorage 2 Serial Number;DataStorage 2 Size (MB);Erasure DataStorage 2;Erasure DataStorage 2 Serial Number;Erasure DataStorage 2 Size (MB);Erasure DataStorage 2 Software;Erasure DataStorage 2 Result;Erasure DataStorage 2 Type;Erasure DataStorage 2 Method;Erasure DataStorage 2 Elapsed (hours);Erasure DataStorage 2 Date;Erasure DataStorage 2 Steps;Erasure DataStorage 2 Steps Start Time;Erasure DataStorage 2 Steps End Time;Benchmark DataStorage 2 Read Speed (MB/s);Benchmark DataStorage 2 Writing speed (MB/s);Test DataStorage 2 Software;Test DataStorage 2 Type;Test DataStorage 2 Result;Test DataStorage 2 Power on (hours used);Test DataStorage 2 Lifetime remaining (percentage);DataStorage 3;DataStorage 3 Manufacturer;DataStorage 3 Model;DataStorage 3 Serial Number;DataStorage 3 Size (MB);Erasure DataStorage 3;Erasure DataStorage 3 Serial Number;Erasure DataStorage 3 Size (MB);Erasure DataStorage 3 Software;Erasure DataStorage 3 Result;Erasure DataStorage 3 Type;Erasure DataStorage 3 Method;Erasure DataStorage 3 Elapsed (hours);Erasure DataStorage 3 Date;Erasure DataStorage 3 Steps;Erasure DataStorage 3 Steps Start Time;Erasure DataStorage 3 Steps End Time;Benchmark DataStorage 3 Read Speed (MB/s);Benchmark DataStorage 3 Writing speed (MB/s);Test DataStorage 3 Software;Test DataStorage 3 Type;Test DataStorage 3 Result;Test DataStorage 3 Power on (hours used);Test DataStorage 3 Lifetime remaining (percentage);DataStorage 4;DataStorage 4 Manufacturer;DataStorage 4 Model;DataStorage 4 Serial Number;DataStorage 4 Size (MB);Erasure DataStorage 4;Erasure DataStorage 4 Serial Number;Erasure DataStorage 4 Size (MB);Erasure DataStorage 4 Software;Erasure DataStorage 4 Result;Erasure DataStorage 4 Type;Erasure DataStorage 4 Method;Erasure DataStorage 4 Elapsed (hours);Erasure DataStorage 4 Date;Erasure DataStorage 4 Steps;Erasure DataStorage 4 Steps Start Time;Erasure DataStorage 4 Steps End Time;Benchmark DataStorage 4 Read Speed (MB/s);Benchmark DataStorage 4 Writing speed (MB/s);Test DataStorage 4 Software;Test DataStorage 4 Type;Test DataStorage 4 Result;Test DataStorage 4 Power on (hours used);Test DataStorage 4 Lifetime remaining (percentage);Motherboard 1;Motherboard 1 Manufacturer;Motherboard 1 Model;Motherboard 1 Serial Number;Display 1;Display 1 Manufacturer;Display 1 Model;Display 1 Serial Number;GraphicCard 1;GraphicCard 1 Manufacturer;GraphicCard 1 Model;GraphicCard 1 Serial Number;GraphicCard 1 Memory (MB);GraphicCard 2;GraphicCard 2 Manufacturer;GraphicCard 2 Model;GraphicCard 2 Serial Number;GraphicCard 2 Memory (MB);NetworkAdapter 1;NetworkAdapter 1 Manufacturer;NetworkAdapter 1 Model;NetworkAdapter 1 Serial Number;NetworkAdapter 2;NetworkAdapter 2 Manufacturer;NetworkAdapter 2 Model;NetworkAdapter 2 Serial Number;SoundCard 1;SoundCard 1 Manufacturer;SoundCard 1 Model;SoundCard 1 Serial Number;SoundCard 2;SoundCard 2 Manufacturer;SoundCard 2 Model;SoundCard 2 Serial Number;Device Rate;Device Range;Processor Rate;Processor Range;RAM Rate;RAM Range;Data Storage Rate;Data Storage Range;Price;Benchmark RamSysbench (points) -93652;;http://localhost/devices/93652;;;;;;;;;;desktop-d1mr-d1ml-d1s;Desktop;Microtower;d1s;d1ml;d1mr;Thu Oct 22 15:36:47 2020;Workbench 11.0;2020-10-22 15:36:47.814316+02:00;;;;p1ml;0;0;Processor 4: model p1ml, S/N p1s;p1mr;p1ml;p1s;;1.6;2410.0;;;;;;;;;;RamModule 3: model rm1ml, S/N rm1s;rm1mr;rm1ml;rm1s;;1333;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GraphicCard 2: model gc1ml, S/N gc1s;gc1mr;gc1ml;gc1s;;;;;;;;;;;;;;;;;;;;;;;1.0;VERY_LOW;1.0;VERY_LOW;1.0;VERY_LOW;1.0;VERY_LOW;; +93652;;http://localhost/devices/93652;;;;;;;;;;desktop-d1mr-d1ml-d1s;Desktop;Microtower;d1s;d1ml;d1mr;Fri Apr 16 18:13:33 2021;Workbench 11.0;2021-04-16 18:13:33.731090+02:00;;;;p1ml;0;0;Processor 6: model p1ml, S/N p1s;p1mr;p1ml;p1s;;1.6;2410.0;;;;;;;;;;RamModule 5: model rm1ml, S/N rm1s;rm1mr;rm1ml;rm1s;;1333;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GraphicCard 4: model gc1ml, S/N gc1s;gc1mr;gc1ml;gc1s;;;;;;;;;;;;;;;;;;;;;;;1.0;VERY_LOW;1.0;VERY_LOW;1.0;VERY_LOW;1.0;VERY_LOW;; diff --git a/tests/files/proposal_extended_csv_report.csv b/tests/files/proposal_extended_csv_report.csv index 2984ace0..473fc81e 100644 --- a/tests/files/proposal_extended_csv_report.csv +++ b/tests/files/proposal_extended_csv_report.csv @@ -1,3 +1,3 @@ -DevicehubID;DocumentID;Public Link;Tag 1 Type;Tag 1 ID;Tag 1 Organization;Tag 2 Type;Tag 2 ID;Tag 2 Organization;Tag 3 Type;Tag 3 ID;Tag 3 Organization;Device Hardware ID;Device Type;Device Chassis;Device Serial Number;Device Model;Device Manufacturer;Registered in;Registered (process);Updated in (software);Updated in (web);Physical state;Trading state;Processor;RAM (MB);Data Storage Size (MB);Processor 1;Processor 1 Manufacturer;Processor 1 Model;Processor 1 Serial Number;Processor 1 Number of cores;Processor 1 Speed (GHz);Benchmark Processor 1 (points);Benchmark ProcessorSysbench Processor 1 (points);Processor 2;Processor 2 Manufacturer;Processor 2 Model;Processor 2 Serial Number;Processor 2 Number of cores;Processor 2 Speed (GHz);Benchmark Processor 2 (points);Benchmark ProcessorSysbench Processor 2 (points);RamModule 1;RamModule 1 Manufacturer;RamModule 1 Model;RamModule 1 Serial Number;RamModule 1 Size (MB);RamModule 1 Speed (MHz);RamModule 2;RamModule 2 Manufacturer;RamModule 2 Model;RamModule 2 Serial Number;RamModule 2 Size (MB);RamModule 2 Speed (MHz);RamModule 3;RamModule 3 Manufacturer;RamModule 3 Model;RamModule 3 Serial Number;RamModule 3 Size (MB);RamModule 3 Speed (MHz);RamModule 4;RamModule 4 Manufacturer;RamModule 4 Model;RamModule 4 Serial Number;RamModule 4 Size (MB);RamModule 4 Speed (MHz);DataStorage 1;DataStorage 1 Manufacturer;DataStorage 1 Model;DataStorage 1 Serial Number;DataStorage 1 Size (MB);Erasure DataStorage 1;Erasure DataStorage 1 Serial Number;Erasure DataStorage 1 Size (MB);Erasure DataStorage 1 Software;Erasure DataStorage 1 Result;Erasure DataStorage 1 Type;Erasure DataStorage 1 Method;Erasure DataStorage 1 Elapsed (hours);Erasure DataStorage 1 Date;Erasure DataStorage 1 Steps;Erasure DataStorage 1 Steps Start Time;Erasure DataStorage 1 Steps End Time;Benchmark DataStorage 1 Read Speed (MB/s);Benchmark DataStorage 1 Writing speed (MB/s);Test DataStorage 1 Software;Test DataStorage 1 Type;Test DataStorage 1 Result;Test DataStorage 1 Power on (hours used);Test DataStorage 1 Lifetime remaining (percentage);DataStorage 2;DataStorage 2 Manufacturer;DataStorage 2 Model;DataStorage 2 Serial Number;DataStorage 2 Size (MB);Erasure DataStorage 2;Erasure DataStorage 2 Serial Number;Erasure DataStorage 2 Size (MB);Erasure DataStorage 2 Software;Erasure DataStorage 2 Result;Erasure DataStorage 2 Type;Erasure DataStorage 2 Method;Erasure DataStorage 2 Elapsed (hours);Erasure DataStorage 2 Date;Erasure DataStorage 2 Steps;Erasure DataStorage 2 Steps Start Time;Erasure DataStorage 2 Steps End Time;Benchmark DataStorage 2 Read Speed (MB/s);Benchmark DataStorage 2 Writing speed (MB/s);Test DataStorage 2 Software;Test DataStorage 2 Type;Test DataStorage 2 Result;Test DataStorage 2 Power on (hours used);Test DataStorage 2 Lifetime remaining (percentage);DataStorage 3;DataStorage 3 Manufacturer;DataStorage 3 Model;DataStorage 3 Serial Number;DataStorage 3 Size (MB);Erasure DataStorage 3;Erasure DataStorage 3 Serial Number;Erasure DataStorage 3 Size (MB);Erasure DataStorage 3 Software;Erasure DataStorage 3 Result;Erasure DataStorage 3 Type;Erasure DataStorage 3 Method;Erasure DataStorage 3 Elapsed (hours);Erasure DataStorage 3 Date;Erasure DataStorage 3 Steps;Erasure DataStorage 3 Steps Start Time;Erasure DataStorage 3 Steps End Time;Benchmark DataStorage 3 Read Speed (MB/s);Benchmark DataStorage 3 Writing speed (MB/s);Test DataStorage 3 Software;Test DataStorage 3 Type;Test DataStorage 3 Result;Test DataStorage 3 Power on (hours used);Test DataStorage 3 Lifetime remaining (percentage);DataStorage 4;DataStorage 4 Manufacturer;DataStorage 4 Model;DataStorage 4 Serial Number;DataStorage 4 Size (MB);Erasure DataStorage 4;Erasure DataStorage 4 Serial Number;Erasure DataStorage 4 Size (MB);Erasure DataStorage 4 Software;Erasure DataStorage 4 Result;Erasure DataStorage 4 Type;Erasure DataStorage 4 Method;Erasure DataStorage 4 Elapsed (hours);Erasure DataStorage 4 Date;Erasure DataStorage 4 Steps;Erasure DataStorage 4 Steps Start Time;Erasure DataStorage 4 Steps End Time;Benchmark DataStorage 4 Read Speed (MB/s);Benchmark DataStorage 4 Writing speed (MB/s);Test DataStorage 4 Software;Test DataStorage 4 Type;Test DataStorage 4 Result;Test DataStorage 4 Power on (hours used);Test DataStorage 4 Lifetime remaining (percentage);Motherboard 1;Motherboard 1 Manufacturer;Motherboard 1 Model;Motherboard 1 Serial Number;Display 1;Display 1 Manufacturer;Display 1 Model;Display 1 Serial Number;GraphicCard 1;GraphicCard 1 Manufacturer;GraphicCard 1 Model;GraphicCard 1 Serial Number;GraphicCard 1 Memory (MB);GraphicCard 2;GraphicCard 2 Manufacturer;GraphicCard 2 Model;GraphicCard 2 Serial Number;GraphicCard 2 Memory (MB);NetworkAdapter 1;NetworkAdapter 1 Manufacturer;NetworkAdapter 1 Model;NetworkAdapter 1 Serial Number;NetworkAdapter 2;NetworkAdapter 2 Manufacturer;NetworkAdapter 2 Model;NetworkAdapter 2 Serial Number;SoundCard 1;SoundCard 1 Manufacturer;SoundCard 1 Model;SoundCard 1 Serial Number;SoundCard 2;SoundCard 2 Manufacturer;SoundCard 2 Model;SoundCard 2 Serial Number;Device Rate;Device Range;Processor Rate;Processor Range;RAM Rate;RAM Range;Data Storage Rate;Data Storage Range;Price;Benchmark RamSysbench (points) -93652;;http://localhost/devices/93652;named;foo;FooOrg;;;;;;;laptop-asustek_computer_inc-1001pxd-b8oaas048285-14:da:e9:42:f6:7b;Laptop;Netbook;b8oaas048285;1001pxd;asustek computer inc.;Thu Nov 12 19:53:01 2020;Workbench 11.0a2;2020-11-12 19:54:03.959185+01:00;;;;intel atom cpu n455 @ 2.66ghz;1024;238475;Processor 4: model intel atom cpu n455 @ 2.66ghz, S/N None;intel corp.;intel atom cpu n455 @ 2.66ghz;;1;2.667;6666.24;164.0803;;;;;;;;;RamModule 8: model None, S/N None;;;;1024;667;;;;;;;;;;;;;;;;;;;HardDrive 9: model hts54322, S/N e2024242cv86mm;hitachi;hts54322;e2024242cv86mm;238475;harddrive-hitachi-hts54322-e2024242cv86mm;e2024242cv86mm;238475;Workbench 11.0a2;Success;EraseBasic;Shred;1:16:49;2020-11-12 19:53:01.899092+01:00;✓ – StepRandom 1:16:49;2018-07-03 11:15:22.257059+02:00;2018-07-03 12:32:11.843190+02:00;66.2;21.8;Workbench 11.0a2;Short;Failure;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;Motherboard 10: model 1001pxd, S/N eee0123456720;asustek computer inc.;1001pxd;eee0123456720;;;;;GraphicCard 5: model atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller, S/N None;intel corporation;atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller;;256;;;;;;NetworkAdapter 2: model ar9285 wireless network adapter, S/N 74:2f:68:8b:fd:c9;qualcomm atheros;ar9285 wireless network adapter;74:2f:68:8b:fd:c9;NetworkAdapter 3: model ar8152 v2.0 fast ethernet, S/N 14:da:e9:42:f6:7b;qualcomm atheros;ar8152 v2.0 fast ethernet;14:da:e9:42:f6:7b;SoundCard 6: model nm10/ich7 family high definition audio controller, S/N None;intel corporation;nm10/ich7 family high definition audio controller;;;;;;1.75;LOW;1.55;LOW;1.53;LOW;3.76;HIGH;52.50 €;15.7188 -64K64;;http://localhost/devices/64K64;;;;;;;;;;laptop-asustek_computer_inc-1001pxd-b8oaas048287-14:da:e9:42:f6:7c;Laptop;Netbook;b8oaas048287;1001pxd;asustek computer inc.;Thu Nov 12 19:53:02 2020;Workbench 11.0b11;2020-11-12 19:53:02.225373+01:00;;;;intel atom cpu n455 @ 1.66ghz;2048;558558;Processor 15: model intel atom cpu n455 @ 1.66ghz, S/N None;intel corp.;intel atom cpu n455 @ 1.66ghz;;1;1.667;6666.24;164.0803;;;;;;;;;RamModule 18: model None, S/N None;;;;1024;667;RamModule 19: model 48594d503131325336344350362d53362020, S/N 4f43487b;hynix semiconductor;48594d503131325336344350362d53362020;4f43487b;1024;667;;;;;;;;;;;;;HardDrive 20: model hts54322, S/N e2024242cv86hj;hitachi;hts54322;e2024242cv86hj;238475;harddrive-hitachi-hts54322-e2024242cv86hj;e2024242cv86hj;238475;Workbench 11.0b11;Success;EraseBasic;Shred;1:16:49;2020-11-12 19:53:02.175189+01:00;✓ – StepRandom 1:16:49;2018-07-03 11:15:22.257059+02:00;2018-07-03 12:32:11.843190+02:00;66.2;21.8;Workbench 11.0b11;Extended;Failure;;;DataStorage 21: model wdc wd1600bevt-2, S/N wd-wx11a80w7430;western digital;wdc wd1600bevt-2;wd-wx11a80w7430;160041;datastorage-western_digital-wdc_wd1600bevt-2-wd-wx11a80w7430;wd-wx11a80w7430;160041;Workbench 11.0b11;Failure;EraseBasic;Shred;0:45:36;2020-11-12 19:53:02.176882+01:00;✓ – StepRandom 0:45:36;2019-10-23 09:49:54.410830+02:00;2019-10-23 10:35:31.400587+02:00;41.6;17.3;Workbench 11.0b11;Short;Success;5293;195 days, 12:00:00;SolidStateDrive 22: model wdc wd1600bevt-2, S/N wd-wx11a80w7430;western digital;wdc wd1600bevt-2;wd-wx11a80w7430;160042;solidstatedrive-western_digital-wdc_wd1600bevt-2-wd-wx11a80w7430;wd-wx11a80w7430;160042;Workbench 11.0b11;Success;EraseSectors;Badblocks;1:46:03;2020-11-12 19:53:02.180043+01:00;✓ – StepRandom 0:46:03,✓ – StepZero 1:00:00;2019-08-19 18:48:19.690458+02:00,2019-08-19 19:34:22.690458+02:00;2019-08-19 19:34:22.930562+02:00,2019-08-19 20:34:22.930562+02:00;41.1;17.1;Workbench 11.0b11;Short;Success;5231;194 days, 17:00:00;;;;;;;;;;;;;;;;;;;;;;;;;Motherboard 23: model 1001pxd, S/N eee0123456789;asustek computer inc.;1001pxd;eee0123456789;;"auo ""auo""";auo lcd monitor;;GraphicCard 16: model atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller, S/N None;intel corporation;atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller;;256;;;;;;NetworkAdapter 13: model ar9285 wireless network adapter, S/N 74:2f:68:8b:fd:c8;qualcomm atheros;ar9285 wireless network adapter;74:2f:68:8b:fd:c8;NetworkAdapter 14: model ar8152 v2.0 fast ethernet, S/N 14:da:e9:42:f6:7c;qualcomm atheros;ar8152 v2.0 fast ethernet;14:da:e9:42:f6:7c;SoundCard 7: model usb 2.0 uvc vga webcam, S/N 0x0001;azurewave;usb 2.0 uvc vga webcam;0x0001;SoundCard 17: model nm10/ich7 family high definition audio controller, S/N None;intel corporation;nm10/ich7 family high definition audio controller;;1.72;LOW;1.31;LOW;1.99;LOW;3.97;HIGH;51.60 €;15.7188 +DevicehubID;DocumentID;Public Link;Tag 1 Type;Tag 1 ID;Tag 1 Organization;Tag 2 Type;Tag 2 ID;Tag 2 Organization;Tag 3 Type;Tag 3 ID;Tag 3 Organization;Device Hardware ID;Device Type;Device Chassis;Device Serial Number;Device Model;Device Manufacturer;Registered in;Registered (process);Updated in (software);Updated in (web);Physical state;Trading state;Processor;RAM (MB);Data Storage Size (MB);Processor 1;Processor 1 Manufacturer;Processor 1 Model;Processor 1 Serial Number;Processor 1 Number of cores;Processor 1 Speed (GHz);Benchmark Processor 1 (points);Benchmark ProcessorSysbench Processor 1 (points);Processor 2;Processor 2 Manufacturer;Processor 2 Model;Processor 2 Serial Number;Processor 2 Number of cores;Processor 2 Speed (GHz);Benchmark Processor 2 (points);Benchmark ProcessorSysbench Processor 2 (points);RamModule 1;RamModule 1 Manufacturer;RamModule 1 Model;RamModule 1 Serial Number;RamModule 1 Size (MB);RamModule 1 Speed (MHz);RamModule 2;RamModule 2 Manufacturer;RamModule 2 Model;RamModule 2 Serial Number;RamModule 2 Size (MB);RamModule 2 Speed (MHz);RamModule 3;RamModule 3 Manufacturer;RamModule 3 Model;RamModule 3 Serial Number;RamModule 3 Size (MB);RamModule 3 Speed (MHz);RamModule 4;RamModule 4 Manufacturer;RamModule 4 Model;RamModule 4 Serial Number;RamModule 4 Size (MB);RamModule 4 Speed (MHz);DataStorage 1;DataStorage 1 Manufacturer;DataStorage 1 Model;DataStorage 1 Serial Number;DataStorage 1 Size (MB);Erasure DataStorage 1;Erasure DataStorage 1 Serial Number;Erasure DataStorage 1 Size (MB);Erasure DataStorage 1 Software;Erasure DataStorage 1 Result;Erasure DataStorage 1 Type;Erasure DataStorage 1 Method;Erasure DataStorage 1 Elapsed (hours);Erasure DataStorage 1 Date;Erasure DataStorage 1 Steps;Erasure DataStorage 1 Steps Start Time;Erasure DataStorage 1 Steps End Time;Benchmark DataStorage 1 Read Speed (MB/s);Benchmark DataStorage 1 Writing speed (MB/s);Test DataStorage 1 Software;Test DataStorage 1 Type;Test DataStorage 1 Result;Test DataStorage 1 Power on (hours used);Test DataStorage 1 Lifetime remaining (percentage);DataStorage 2;DataStorage 2 Manufacturer;DataStorage 2 Model;DataStorage 2 Serial Number;DataStorage 2 Size (MB);Erasure DataStorage 2;Erasure DataStorage 2 Serial Number;Erasure DataStorage 2 Size (MB);Erasure DataStorage 2 Software;Erasure DataStorage 2 Result;Erasure DataStorage 2 Type;Erasure DataStorage 2 Method;Erasure DataStorage 2 Elapsed (hours);Erasure DataStorage 2 Date;Erasure DataStorage 2 Steps;Erasure DataStorage 2 Steps Start Time;Erasure DataStorage 2 Steps End Time;Benchmark DataStorage 2 Read Speed (MB/s);Benchmark DataStorage 2 Writing speed (MB/s);Test DataStorage 2 Software;Test DataStorage 2 Type;Test DataStorage 2 Result;Test DataStorage 2 Power on (hours used);Test DataStorage 2 Lifetime remaining (percentage);DataStorage 3;DataStorage 3 Manufacturer;DataStorage 3 Model;DataStorage 3 Serial Number;DataStorage 3 Size (MB);Erasure DataStorage 3;Erasure DataStorage 3 Serial Number;Erasure DataStorage 3 Size (MB);Erasure DataStorage 3 Software;Erasure DataStorage 3 Result;Erasure DataStorage 3 Type;Erasure DataStorage 3 Method;Erasure DataStorage 3 Elapsed (hours);Erasure DataStorage 3 Date;Erasure DataStorage 3 Steps;Erasure DataStorage 3 Steps Start Time;Erasure DataStorage 3 Steps End Time;Benchmark DataStorage 3 Read Speed (MB/s);Benchmark DataStorage 3 Writing speed (MB/s);Test DataStorage 3 Software;Test DataStorage 3 Type;Test DataStorage 3 Result;Test DataStorage 3 Power on (hours used);Test DataStorage 3 Lifetime remaining (percentage);DataStorage 4;DataStorage 4 Manufacturer;DataStorage 4 Model;DataStorage 4 Serial Number;DataStorage 4 Size (MB);Erasure DataStorage 4;Erasure DataStorage 4 Serial Number;Erasure DataStorage 4 Size (MB);Erasure DataStorage 4 Software;Erasure DataStorage 4 Result;Erasure DataStorage 4 Type;Erasure DataStorage 4 Method;Erasure DataStorage 4 Elapsed (hours);Erasure DataStorage 4 Date;Erasure DataStorage 4 Steps;Erasure DataStorage 4 Steps Start Time;Erasure DataStorage 4 Steps End Time;Benchmark DataStorage 4 Read Speed (MB/s);Benchmark DataStorage 4 Writing speed (MB/s);Test DataStorage 4 Software;Test DataStorage 4 Type;Test DataStorage 4 Result;Test DataStorage 4 Power on (hours used);Test DataStorage 4 Lifetime remaining (percentage);Motherboard 1;Motherboard 1 Manufacturer;Motherboard 1 Model;Motherboard 1 Serial Number;Display 1;Display 1 Manufacturer;Display 1 Model;Display 1 Serial Number;GraphicCard 1;GraphicCard 1 Manufacturer;GraphicCard 1 Model;GraphicCard 1 Serial Number;GraphicCard 1 Memory (MB);GraphicCard 2;GraphicCard 2 Manufacturer;GraphicCard 2 Model;GraphicCard 2 Serial Number;GraphicCard 2 Memory (MB);NetworkAdapter 1;NetworkAdapter 1 Manufacturer;NetworkAdapter 1 Model;NetworkAdapter 1 Serial Number;NetworkAdapter 2;NetworkAdapter 2 Manufacturer;NetworkAdapter 2 Model;NetworkAdapter 2 Serial Number;SoundCard 1;SoundCard 1 Manufacturer;SoundCard 1 Model;SoundCard 1 Serial Number;SoundCard 2;SoundCard 2 Manufacturer;SoundCard 2 Model;SoundCard 2 Serial Number;Device Rate;Device Range;Processor Rate;Processor Range;RAM Rate;RAM Range;Data Storage Rate;Data Storage Range;Price;Benchmark RamSysbench (points) +93652;;http://localhost/devices/93652;named;foo;FooOrg;;;;;;;laptop-asustek_computer_inc-1001pxd-b8oaas048285-14:da:e9:42:f6:7b;Laptop;Netbook;b8oaas048285;1001pxd;asustek computer inc.;Fri Apr 16 18:14:56 2021;Workbench 11.0a2;2021-04-16 18:14:57.353702+02:00;;;;intel atom cpu n455 @ 2.66ghz;1024;238475;Processor 6: model intel atom cpu n455 @ 2.66ghz, S/N None;intel corp.;intel atom cpu n455 @ 2.66ghz;;1;2.667;6666.24;164.0803;;;;;;;;;RamModule 10: model None, S/N None;;;;1024;667;;;;;;;;;;;;;;;;;;;HardDrive 11: model hts54322, S/N e2024242cv86mm;hitachi;hts54322;e2024242cv86mm;238475;harddrive-hitachi-hts54322-e2024242cv86mm;e2024242cv86mm;238475;Workbench 11.0a2;Success;EraseBasic;Shred;1:16:49;2021-04-16 18:14:56.819171+02:00;✓ – StepRandom 1:16:49;2018-07-03 11:15:22.257059+02:00;2018-07-03 12:32:11.843190+02:00;66.2;21.8;Workbench 11.0a2;Short;Failure;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;Motherboard 12: model 1001pxd, S/N eee0123456720;asustek computer inc.;1001pxd;eee0123456720;;;;;GraphicCard 7: model atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller, S/N None;intel corporation;atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller;;256;;;;;;NetworkAdapter 4: model ar9285 wireless network adapter, S/N 74:2f:68:8b:fd:c9;qualcomm atheros;ar9285 wireless network adapter;74:2f:68:8b:fd:c9;NetworkAdapter 5: model ar8152 v2.0 fast ethernet, S/N 14:da:e9:42:f6:7b;qualcomm atheros;ar8152 v2.0 fast ethernet;14:da:e9:42:f6:7b;SoundCard 8: model nm10/ich7 family high definition audio controller, S/N None;intel corporation;nm10/ich7 family high definition audio controller;;;;;;1.75;LOW;1.55;LOW;1.53;LOW;3.76;HIGH;52.50 €;15.7188 +J2MA2;;http://localhost/devices/J2MA2;;;;;;;;;;laptop-asustek_computer_inc-1001pxd-b8oaas048287-14:da:e9:42:f6:7c;Laptop;Netbook;b8oaas048287;1001pxd;asustek computer inc.;Fri Apr 16 18:14:57 2021;Workbench 11.0b11;2021-04-16 18:14:57.160888+02:00;;;;intel atom cpu n455 @ 1.66ghz;2048;558558;Processor 17: model intel atom cpu n455 @ 1.66ghz, S/N None;intel corp.;intel atom cpu n455 @ 1.66ghz;;1;1.667;6666.24;164.0803;;;;;;;;;RamModule 20: model None, S/N None;;;;1024;667;RamModule 21: model 48594d503131325336344350362d53362020, S/N 4f43487b;hynix semiconductor;48594d503131325336344350362d53362020;4f43487b;1024;667;;;;;;;;;;;;;HardDrive 22: model hts54322, S/N e2024242cv86hj;hitachi;hts54322;e2024242cv86hj;238475;harddrive-hitachi-hts54322-e2024242cv86hj;e2024242cv86hj;238475;Workbench 11.0b11;Success;EraseBasic;Shred;1:16:49;2021-04-16 18:14:57.093108+02:00;✓ – StepRandom 1:16:49;2018-07-03 11:15:22.257059+02:00;2018-07-03 12:32:11.843190+02:00;66.2;21.8;Workbench 11.0b11;Extended;Failure;;;DataStorage 23: model wdc wd1600bevt-2, S/N wd-wx11a80w7430;western digital;wdc wd1600bevt-2;wd-wx11a80w7430;160041;datastorage-western_digital-wdc_wd1600bevt-2-wd-wx11a80w7430;wd-wx11a80w7430;160041;Workbench 11.0b11;Failure;EraseBasic;Shred;0:45:36;2021-04-16 18:14:57.095327+02:00;✓ – StepRandom 0:45:36;2019-10-23 09:49:54.410830+02:00;2019-10-23 10:35:31.400587+02:00;41.6;17.3;Workbench 11.0b11;Short;Success;5293;195 days, 12:00:00;SolidStateDrive 24: model wdc wd1600bevt-2, S/N wd-wx11a80w7430;western digital;wdc wd1600bevt-2;wd-wx11a80w7430;160042;solidstatedrive-western_digital-wdc_wd1600bevt-2-wd-wx11a80w7430;wd-wx11a80w7430;160042;Workbench 11.0b11;Success;EraseSectors;Badblocks;1:46:03;2021-04-16 18:14:57.099341+02:00;✓ – StepRandom 0:46:03,✓ – StepZero 1:00:00;2019-08-19 18:48:19.690458+02:00,2019-08-19 19:34:22.690458+02:00;2019-08-19 19:34:22.930562+02:00,2019-08-19 20:34:22.930562+02:00;41.1;17.1;Workbench 11.0b11;Short;Success;5231;194 days, 17:00:00;;;;;;;;;;;;;;;;;;;;;;;;;Motherboard 25: model 1001pxd, S/N eee0123456789;asustek computer inc.;1001pxd;eee0123456789;;"auo ""auo""";auo lcd monitor;;GraphicCard 18: model atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller, S/N None;intel corporation;atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller;;256;;;;;;NetworkAdapter 15: model ar9285 wireless network adapter, S/N 74:2f:68:8b:fd:c8;qualcomm atheros;ar9285 wireless network adapter;74:2f:68:8b:fd:c8;NetworkAdapter 16: model ar8152 v2.0 fast ethernet, S/N 14:da:e9:42:f6:7c;qualcomm atheros;ar8152 v2.0 fast ethernet;14:da:e9:42:f6:7c;SoundCard 9: model usb 2.0 uvc vga webcam, S/N 0x0001;azurewave;usb 2.0 uvc vga webcam;0x0001;SoundCard 19: model nm10/ich7 family high definition audio controller, S/N None;intel corporation;nm10/ich7 family high definition audio controller;;1.72;LOW;1.31;LOW;1.99;LOW;3.97;HIGH;51.60 €;15.7188 diff --git a/tests/test_action.py b/tests/test_action.py index 346022d0..99b27e6a 100644 --- a/tests/test_action.py +++ b/tests/test_action.py @@ -387,7 +387,7 @@ def test_live_without_TestDataStorage(user: UserClient, client: Client, app: Dev acer = file('acer.happy.battery.snapshot') snapshot, _ = user.post(acer, res=models.Snapshot) device_id = snapshot['device']['id'] - db_device = Device.query.filter_by(id=1).one() + db_device = Device.query.filter_by(id=device_id).one() post_request = {"transaction": "ccc", "name": "John", "endUsers": 1, "devices": [device_id], "description": "aaa", "finalUserCode": "abcdefjhi", @@ -420,7 +420,7 @@ def test_live_without_hdd_1(user: UserClient, client: Client, app: Devicehub): acer = file('acer.happy.battery.snapshot') snapshot, _ = user.post(acer, res=models.Snapshot) device_id = snapshot['device']['id'] - db_device = Device.query.filter_by(id=1).one() + db_device = Device.query.filter_by(id=device_id).one() post_request = {"transaction": "ccc", "name": "John", "endUsers": 1, "devices": [device_id], "description": "aaa", "finalUserCode": "abcdefjhi", @@ -451,7 +451,7 @@ def test_live_without_hdd_2(user: UserClient, client: Client, app: Devicehub): acer['components'] = components snapshot, _ = user.post(acer, res=models.Snapshot) device_id = snapshot['device']['id'] - db_device = Device.query.filter_by(id=1).one() + db_device = Device.query.filter_by(id=device_id).one() post_request = {"transaction": "ccc", "name": "John", "endUsers": 1, "devices": [device_id], "description": "aaa", "finalUserCode": "abcdefjhi", @@ -482,7 +482,7 @@ def test_live_without_hdd_3(user: UserClient, client: Client, app: Devicehub): acer['components'] = components snapshot, _ = user.post(acer, res=models.Snapshot) device_id = snapshot['device']['id'] - db_device = Device.query.filter_by(id=1).one() + db_device = Device.query.filter_by(id=device_id).one() post_request = {"transaction": "ccc", "name": "John", "endUsers": 1, "devices": [device_id], "description": "aaa", "finalUserCode": "abcdefjhi", @@ -515,7 +515,7 @@ def test_live_with_hdd_with_old_time(user: UserClient, client: Client, app: Devi acer = file('acer.happy.battery.snapshot') snapshot, _ = user.post(acer, res=models.Snapshot) device_id = snapshot['device']['id'] - db_device = Device.query.filter_by(id=1).one() + db_device = Device.query.filter_by(id=device_id).one() post_request = {"transaction": "ccc", "name": "John", "endUsers": 1, "devices": [device_id], "description": "aaa", "finalUserCode": "abcdefjhi", diff --git a/tests/test_basic.py b/tests/test_basic.py index 244e84ea..bb53fda0 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -40,6 +40,7 @@ def test_api_docs(client: Client): '/documents/erasures/', '/documents/devices/', '/documents/stamps/', + '/documents/wbconf/{wbtype}', '/documents/internalstats/', '/documents/stock/', '/documents/check/', @@ -55,7 +56,8 @@ def test_api_docs(client: Client): '/tags/', '/tags/{tag_id}/device/{device_id}', '/users/', - '/users/login/' + '/users/login/', + '/users/logout/', # '/devices/{dev1_id}/merge/{dev2_id}', # '/batteries/{dev1_id}/merge/{dev2_id}', # '/bikes/{dev1_id}/merge/{dev2_id}', diff --git a/tests/test_device.py b/tests/test_device.py index 7d8cc374..4a058284 100644 --- a/tests/test_device.py +++ b/tests/test_device.py @@ -65,13 +65,13 @@ def test_device_model(): gcard = d.GraphicCard.query.one() db.session.delete(pc) db.session.flush() - assert pc.id == 1 + assert pc.id == 3 assert d.Desktop.query.first() is None db.session.commit() assert d.Desktop.query.first() is None - assert network_adapter.id == 2 + assert network_adapter.id == 4 assert d.NetworkAdapter.query.first() is not None, 'We removed the network adaptor' - assert gcard.id == 3, 'We should still hold a reference to a zombie graphic card' + assert gcard.id == 5, 'We should still hold a reference to a zombie graphic card' assert d.GraphicCard.query.first() is None, 'We should have deleted it –it was inside the pc' @@ -396,74 +396,73 @@ def test_sync_execute_register_mismatch_between_tags_and_hid(): @pytest.mark.mvp -def test_get_device(app: Devicehub, user: UserClient): +@pytest.mark.usefixtures(conftest.app_context.__name__) +def test_get_device(user: UserClient): """Checks GETting a d.Desktop with its components.""" - with app.app_context(): - pc = d.Desktop(model='p1mo', - manufacturer='p1ma', - serial_number='p1s', - chassis=ComputerChassis.Tower, - owner_id=user.user['id']) - pc.components = OrderedSet([ - d.NetworkAdapter(model='c1mo', manufacturer='c1ma', serial_number='c1s', - owner_id=user.user['id']), - d.GraphicCard(model='c2mo', manufacturer='c2ma', memory=1500, owner_id=user.user['id']) - ]) - db.session.add(pc) - # todo test is an abstract class. replace with another one - db.session.add(TestConnectivity(device=pc, - severity=Severity.Info, - agent=Person(name='Timmy'), - author=User(email='bar@bar.com'))) - db.session.commit() - devicehub_id = pc.devicehub_id - - pc, _ = user.get(res=d.Device, item=devicehub_id) - assert len(pc['actions']) == 1 - assert pc['actions'][0]['type'] == 'TestConnectivity' - assert pc['actions'][0]['device'] == 1 - assert pc['actions'][0]['severity'] == 'Info' - assert UUID(pc['actions'][0]['author']) - assert 'actions_components' not in pc, 'actions_components are internal use only' - assert 'actions_one' not in pc, 'they are internal use only' - assert 'author' not in pc - assert tuple(c['id'] for c in pc['components']) == (2, 3) - assert pc['hid'] == 'desktop-p1ma-p1mo-p1s' - assert pc['model'] == 'p1mo' - assert pc['manufacturer'] == 'p1ma' - assert pc['serialNumber'] == 'p1s' - assert pc['type'] == d.Desktop.t + pc = d.Desktop(model='p1mo', + manufacturer='p1ma', + serial_number='p1s', + chassis=ComputerChassis.Tower, + owner_id=user.user['id']) + pc.components = OrderedSet([ + d.NetworkAdapter(model='c1mo', manufacturer='c1ma', serial_number='c1s', + owner_id=user.user['id']), + d.GraphicCard(model='c2mo', manufacturer='c2ma', memory=1500, owner_id=user.user['id']) + ]) + db.session.add(pc) + # todo test is an abstract class. replace with another one + db.session.add(TestConnectivity(device=pc, + severity=Severity.Info, + agent=Person(name='Timmy'), + author=User(email='bar@bar.com'))) + db.session.commit() + pc_api, _ = user.get(res=d.Device, item=pc.devicehub_id) + assert len(pc_api['actions']) == 1 + assert pc_api['actions'][0]['type'] == 'TestConnectivity' + assert pc_api['actions'][0]['device'] == pc.id + assert pc_api['actions'][0]['severity'] == 'Info' + assert UUID(pc_api['actions'][0]['author']) + assert 'actions_components' not in pc_api, 'actions_components are internal use only' + assert 'actions_one' not in pc_api, 'they are internal use only' + assert 'author' not in pc_api + assert tuple(c['id'] for c in pc_api['components']) == tuple(c.id for c in pc.components) + assert pc_api['hid'] == 'desktop-p1ma-p1mo-p1s' + assert pc_api['model'] == 'p1mo' + assert pc_api['manufacturer'] == 'p1ma' + assert pc_api['serialNumber'] == 'p1s' + assert pc_api['type'] == d.Desktop.t @pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) def test_get_devices(app: Devicehub, user: UserClient): """Checks GETting multiple devices.""" - with app.app_context(): - pc = d.Desktop(model='p1mo', - manufacturer='p1ma', - serial_number='p1s', - chassis=ComputerChassis.Tower, - owner_id=user.user['id']) - pc.components = OrderedSet([ - d.NetworkAdapter(model='c1mo', manufacturer='c1ma', serial_number='c1s', - owner_id=user.user['id']), - d.GraphicCard(model='c2mo', manufacturer='c2ma', memory=1500, - owner_id=user.user['id']) - ]) - pc1 = d.Desktop(model='p2mo', - manufacturer='p2ma', - serial_number='p2s', - chassis=ComputerChassis.Tower, - owner_id=user.user['id']) - pc2 = d.Laptop(model='p3mo', - manufacturer='p3ma', - serial_number='p3s', - chassis=ComputerChassis.Netbook, - owner_id=user.user['id']) - db.session.add_all((pc, pc1, pc2)) - db.session.commit() + pc = d.Desktop(model='p1mo', + manufacturer='p1ma', + serial_number='p1s', + chassis=ComputerChassis.Tower, + owner_id=user.user['id']) + pc.components = OrderedSet([ + d.NetworkAdapter(model='c1mo', manufacturer='c1ma', serial_number='c1s', + owner_id=user.user['id']), + d.GraphicCard(model='c2mo', manufacturer='c2ma', memory=1500, + owner_id=user.user['id']) + ]) + pc1 = d.Desktop(model='p2mo', + manufacturer='p2ma', + serial_number='p2s', + chassis=ComputerChassis.Tower, + owner_id=user.user['id']) + pc2 = d.Laptop(model='p3mo', + manufacturer='p3ma', + serial_number='p3s', + chassis=ComputerChassis.Netbook, + owner_id=user.user['id']) + db.session.add_all((pc, pc1, pc2)) + db.session.commit() devices, _ = user.get(res=d.Device) - assert tuple(dev['id'] for dev in devices['items']) == (1, 2, 3, 4, 5) + ids = (pc.id, pc1.id, pc2.id, pc.components[0].id, pc.components[1].id) + assert tuple(dev['id'] for dev in devices['items']) == ids assert tuple(dev['type'] for dev in devices['items']) == ( d.Desktop.t, d.Desktop.t, d.Laptop.t, d.NetworkAdapter.t, d.GraphicCard.t ) @@ -536,7 +535,7 @@ def test_device_properties_format(app: Devicehub, user: UserClient): user.post(file('asus-eee-1000h.snapshot.11'), res=m.Snapshot) with app.app_context(): pc = d.Laptop.query.one() # type: d.Laptop - assert format(pc) == 'Laptop 1: model 1000h, S/N 94oaaq021116' + assert format(pc) == 'Laptop 3: model 1000h, S/N 94oaaq021116' assert format(pc, 't') == 'Netbook 1000h' assert format(pc, 's') == '(asustek computer inc.) S/N 94OAAQ021116' assert pc.ram_size == 1024 @@ -544,12 +543,12 @@ def test_device_properties_format(app: Devicehub, user: UserClient): assert pc.graphic_card_model == 'mobile 945gse express integrated graphics controller' assert pc.processor_model == 'intel atom cpu n270 @ 1.60ghz' net = next(c for c in pc.components if isinstance(c, d.NetworkAdapter)) - assert format(net) == 'NetworkAdapter 2: model ar8121/ar8113/ar8114 ' \ + assert format(net) == 'NetworkAdapter 4: model ar8121/ar8113/ar8114 ' \ 'gigabit or fast ethernet, S/N 00:24:8c:7f:cf:2d' assert format(net, 't') == 'NetworkAdapter ar8121/ar8113/ar8114 gigabit or fast ethernet' assert format(net, 's') == 'qualcomm atheros 00:24:8C:7F:CF:2D – 100 Mbps' hdd = next(c for c in pc.components if isinstance(c, d.DataStorage)) - assert format(hdd) == 'HardDrive 7: model st9160310as, S/N 5sv4tqa6' + assert format(hdd) == 'HardDrive 9: model st9160310as, S/N 5sv4tqa6' assert format(hdd, 't') == 'HardDrive st9160310as' assert format(hdd, 's') == 'seagate 5SV4TQA6 – 152 GB' diff --git a/tests/test_device_find.py b/tests/test_device_find.py index 476ec36d..fa6cd83d 100644 --- a/tests/test_device_find.py +++ b/tests/test_device_find.py @@ -176,10 +176,10 @@ def test_device_query_filter_lots(user: UserClient): @pytest.mark.mvp def test_device_query(user: UserClient): """Checks result of inventory.""" - snap, _ = user.post(conftest.file('basic.snapshot'), res=Snapshot) + snapshot, _ = user.post(conftest.file('basic.snapshot'), res=Snapshot) i, _ = user.get(res=Device) assert i['url'] == '/devices/' - assert i['items'][0]['url'] == '/devices/%s' % snap['device']['devicehubID'] + assert i['items'][0]['url'] == '/devices/%s' % snapshot['device']['devicehubID'] pc = next(d for d in i['items'] if d['type'] == 'Desktop') assert len(pc['actions']) == 4 assert len(pc['components']) == 3 @@ -241,16 +241,16 @@ def test_device_search_regenerate_table(app: DeviceSearch, user: UserClient): @pytest.mark.mvp def test_device_query_search(user: UserClient): # todo improve - user.post(file('basic.snapshot'), res=Snapshot) + snapshot, _ = user.post(file('basic.snapshot'), res=Snapshot) user.post(file('computer-monitor.snapshot'), res=Snapshot) user.post(file('real-eee-1001pxd.snapshot.11'), res=Snapshot) i, _ = user.get(res=Device, query=[('search', 'desktop')]) - assert i['items'][0]['id'] == 1 + assert i['items'][0]['id'] == snapshot['device']['id'] i, _ = user.get(res=Device, query=[('search', 'intel')]) assert len(i['items']) == 1 i, _ = user.get(res=Device, query=[('search', i['items'][0]['devicehubID'])]) assert len(i['items']) == 1 - i, _ = user.get(res=Device, query=[('search', '1')]) + i, _ = user.get(res=Device, query=[('search', snapshot['device']['id'])]) assert len(i['items']) == 1 diff --git a/tests/test_documents.py b/tests/test_documents.py index c0c92cf2..45e6cb95 100644 --- a/tests/test_documents.py +++ b/tests/test_documents.py @@ -10,14 +10,17 @@ from werkzeug.exceptions import Unauthorized import teal.marshmallow from ereuse_utils.test import ANY +from ereuse_devicehub import auth from ereuse_devicehub.client import Client, UserClient from ereuse_devicehub.devicehub import Devicehub +from ereuse_devicehub.resources.user.models import Session from ereuse_devicehub.resources.action.models import Snapshot, Allocate, Live from ereuse_devicehub.resources.documents import documents from ereuse_devicehub.resources.device import models as d from ereuse_devicehub.resources.lot.models import Lot from ereuse_devicehub.resources.tag.model import Tag from ereuse_devicehub.resources.hash_reports import ReportHash +from ereuse_devicehub.resources.enums import SessionType from ereuse_devicehub.db import db from tests import conftest from tests.conftest import file @@ -262,6 +265,7 @@ def test_export_extended(app: Devicehub, user: UserClient): pc.tags.add(tag) db.session.add(pc) db.session.commit() + csv_str, _ = user.get(res=documents.DocumentDef.t, item='devices/', accept='text/csv', @@ -464,7 +468,7 @@ def test_get_document_lots(user: UserClient, user2: UserClient): assert export2_csv[1][3] == 'comments,lot3,testcomment-lot3,' -@pytest.mark.mvp +@pytest.mark.mvp def test_verify_stamp(user: UserClient, client: Client): """Test verify stamp of one export device information in a csv file.""" snapshot, _ = user.post(file('basic.snapshot'), res=Snapshot) @@ -472,12 +476,12 @@ def test_verify_stamp(user: UserClient, client: Client): item='devices/', accept='text/csv', query=[('filter', {'type': ['Computer']})]) - + response, _ = client.post(res=documents.DocumentDef.t, item='stamps/', content_type='multipart/form-data', accept='text/html', - data={'docUpload': [(BytesIO(bytes(csv_str, 'utf-8')), 'example.csv')]}, + data={'docUpload': [(BytesIO(bytes(csv_str, 'utf-8')), 'example.csv')]}, status=200) assert "alert alert-info" in response assert not "alert alert-danger" in response @@ -501,10 +505,10 @@ def test_verify_stamp(user: UserClient, client: Client): assert not "alert alert-danger" in response -@pytest.mark.mvp +@pytest.mark.mvp def test_verify_stamp_log_info(user: UserClient, client: Client): """Test verify stamp of one export lots-info in a csv file.""" - + l, _ = user.post({'name': 'Lot1', 'description': 'comments,lot1,testcomment-lot1,'}, res=Lot) l, _ = user.post({'name': 'Lot2', 'description': 'comments,lot2,testcomment-lot2,'}, res=Lot) @@ -516,8 +520,8 @@ def test_verify_stamp_log_info(user: UserClient, client: Client): item='stamps/', content_type='multipart/form-data', accept='text/html', - data={'docUpload': [(BytesIO(bytes(csv_str, 'utf-8')), - 'example.csv')]}, + data={'docUpload': [(BytesIO(bytes(csv_str, 'utf-8')), + 'example.csv')]}, status=200) assert "alert alert-info" in response @@ -538,7 +542,7 @@ def test_verify_stamp_devices_stock(user: UserClient, client: Client): content_type='multipart/form-data', accept='text/html', data={'docUpload': [(BytesIO(bytes(csv_str, 'utf-8')), - 'example.csv')]}, + 'example.csv')]}, status=200) assert "alert alert-info" in response @@ -573,8 +577,8 @@ def test_verify_stamp_csv_actions(user: UserClient, client: Client): item='stamps/', content_type='multipart/form-data', accept='text/html', - data={'docUpload': [(BytesIO(bytes(csv_str, 'utf-8')), - 'example.csv')]}, + data={'docUpload': [(BytesIO(bytes(csv_str, 'utf-8')), + 'example.csv')]}, status=200) assert "alert alert-info" in response @@ -594,8 +598,8 @@ def test_verify_stamp_erasure_certificate(user: UserClient, client: Client): item='stamps/', content_type='multipart/form-data', accept='text/html', - data={'docUpload': [(BytesIO(bytes(doc, 'utf-8')), - 'example.csv')]}, + data={'docUpload': [(BytesIO(bytes(doc, 'utf-8')), + 'example.csv')]}, status=200) assert "alert alert-danger" in response @@ -611,15 +615,15 @@ def test_verify_stamp_erasure_certificate(user: UserClient, client: Client): item='stamps/', content_type='multipart/form-data', accept='text/html', - data={'docUpload': [(BytesIO(doc), - 'example.csv')]}, + data={'docUpload': [(BytesIO(doc), + 'example.csv')]}, status=200) assert "alert alert-info" in response @pytest.mark.mvp def test_get_document_internal_stats(user: UserClient, user2: UserClient): - """Tests for get teh internal stats.""" + """Tests for get the internal stats.""" # csv_str, _ = user.get(res=documents.DocumentDef.t, # item='internalstats/') @@ -644,3 +648,24 @@ def test_get_document_internal_stats(user: UserClient, user2: UserClient): export_csv = list(obj_csv) assert csv_str.strip() == '""' + + +@pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) +def test_get_wbconf(user: UserClient): + """Tests for get env file for usb wb.""" + + env, _ = user.get(res=documents.DocumentDef.t, item='wbconf/usodyrate', accept=ANY) + assert 'WB_ERASE = False' in env + + env, _ = user.get(res=documents.DocumentDef.t, item='wbconf/usodywipe', accept=ANY) + assert 'WB_ERASE = False' in env + # assert 'WB_ERASE = True' in env + + session = Session.query.filter_by(user_id=user.user['id'], + type=SessionType.Internal).first() + token = session.token + token = auth.Auth.encode(session.token) + assert token in env + user.user['token'] = token + snapshot, _ = user.post(file('basic.snapshot'), res=Snapshot) diff --git a/tests/test_snapshot.py b/tests/test_snapshot.py index 8d10f8d4..82989f17 100644 --- a/tests/test_snapshot.py +++ b/tests/test_snapshot.py @@ -37,6 +37,7 @@ from tests import conftest @pytest.mark.mvp @pytest.mark.usefixtures('auth_app_context') +# cayop def test_snapshot_model(): """Tests creating a Snapshot with its relationships ensuring correct DB mapping. @@ -318,7 +319,7 @@ def test_snapshot_tag_inner_tag(user: UserClient, tag_id: str, app: Devicehub): action_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' + assert tag.device_id == 3, 'Tag should be linked to the first device' @pytest.mark.mvp diff --git a/tests/test_workbench.py b/tests/test_workbench.py index 3a38b1ae..b2952f13 100644 --- a/tests/test_workbench.py +++ b/tests/test_workbench.py @@ -32,20 +32,24 @@ def test_workbench_server_condensed(user: UserClient): user.post({'id': t['id']}, res=Tag) snapshot, _ = user.post(res=em.Snapshot, data=s) + pc_id = snapshot['device']['id'] + cpu_id = snapshot['components'][3]['id'] + ssd_id= snapshot['components'][4]['id'] + hdd_id = snapshot['components'][5]['id'] actions = snapshot['actions'] assert {(action['type'], action['device']) for action in actions} == { - ('BenchmarkProcessorSysbench', 5), - ('StressTest', 1), - ('EraseSectors', 6), - ('EreusePrice', 1), - ('BenchmarkRamSysbench', 1), - ('BenchmarkProcessor', 5), - ('Install', 6), - ('EraseSectors', 7), - ('BenchmarkDataStorage', 6), - ('BenchmarkDataStorage', 7), - ('TestDataStorage', 6), - ('RateComputer', 1) + ('BenchmarkProcessorSysbench', cpu_id), + ('StressTest', pc_id), + ('EraseSectors', ssd_id), + ('EreusePrice', pc_id), + ('BenchmarkRamSysbench', pc_id), + ('BenchmarkProcessor', cpu_id), + ('Install', ssd_id), + ('EraseSectors', hdd_id), + ('BenchmarkDataStorage', ssd_id), + ('BenchmarkDataStorage', hdd_id), + ('TestDataStorage', ssd_id), + ('RateComputer', pc_id) } assert snapshot['closed'] assert snapshot['severity'] == 'Info'