Use teal.test_import_resource; reformat imports; add generic events

This commit is contained in:
Xavier Bustamante Talavera 2018-07-22 22:42:49 +02:00
parent 6d85f314ef
commit 8efca0d589
12 changed files with 219 additions and 124 deletions

View file

@ -1,41 +1,21 @@
from distutils.version import StrictVersion
from itertools import chain
from typing import Set
from ereuse_devicehub.resources.device import CellphoneDef, ComponentDef, ComputerDef, \
ComputerMonitorDef, DataStorageDef, DesktopDef, DeviceDef, DisplayDef, GraphicCardDef, \
HardDriveDef, LaptopDef, MobileDef, MonitorDef, MotherboardDef, NetworkAdapterDef, \
ProcessorDef, RamModuleDef, ServerDef, SmartphoneDef, SolidStateDriveDef, SoundCardDef, \
TabletDef, TelevisionSetDef
from ereuse_devicehub.resources import device, event, inventory, tag, user
from ereuse_devicehub.resources.enums import PriceSoftware, RatingSoftware
from ereuse_devicehub.resources.event import AddDef, AggregateRateDef, AppRateDef, \
BenchmarkDataStorageDef, BenchmarkDef, BenchmarkProcessorDef, BenchmarkProcessorSysbenchDef, \
BenchmarkRamSysbenchDef, BenchmarkWithRateDef, EraseBasicDef, EraseSectorsDef, EreusePriceDef, \
EventDef, InstallDef, PhotoboxSystemRateDef, PhotoboxUserDef, PriceDef, RateDef, RemoveDef, \
SnapshotDef, StepDef, StepRandomDef, StepZeroDef, StressTestDef, TestDataStorageDef, TestDef, \
WorkbenchRateDef
from ereuse_devicehub.resources.inventory import InventoryDef
from ereuse_devicehub.resources.tag import TagDef
from ereuse_devicehub.resources.user import OrganizationDef, UserDef
from teal.auth import TokenAuth
from teal.config import Config
from teal.currency import Currency
from teal.utils import import_resource
class DevicehubConfig(Config):
RESOURCE_DEFINITIONS = {
DeviceDef, ComputerDef, DesktopDef, LaptopDef, ServerDef, MonitorDef, TelevisionSetDef,
ComputerMonitorDef, ComponentDef, GraphicCardDef, DataStorageDef,
SolidStateDriveDef, MobileDef, DisplayDef, SmartphoneDef, TabletDef, CellphoneDef,
HardDriveDef, MotherboardDef, NetworkAdapterDef, RamModuleDef, ProcessorDef, SoundCardDef,
UserDef,
OrganizationDef, TagDef, EventDef, AddDef, RemoveDef, EraseBasicDef, EraseSectorsDef,
StepDef, StepZeroDef, StepRandomDef, RateDef, AggregateRateDef, WorkbenchRateDef,
PhotoboxUserDef, PhotoboxSystemRateDef, PriceDef, EreusePriceDef,
InstallDef, SnapshotDef, TestDef,
TestDataStorageDef, StressTestDef, WorkbenchRateDef, InventoryDef, BenchmarkDef,
BenchmarkDataStorageDef, BenchmarkWithRateDef, AppRateDef, BenchmarkProcessorDef,
BenchmarkProcessorSysbenchDef, BenchmarkRamSysbenchDef
}
RESOURCE_DEFINITIONS = set(chain(import_resource(device),
import_resource(event),
import_resource(user),
import_resource(tag),
import_resource(inventory)))
PASSWORD_SCHEMES = {'pbkdf2_sha256'} # type: Set[str]
SQLALCHEMY_DATABASE_URI = 'postgresql://dhub:ereuse@localhost/devicehub' # type: str
SCHEMA = 'dhub'

View file

@ -1,13 +1,10 @@
from ereuse_devicehub.resources.device.schemas import Cellphone, Component, Computer, \
ComputerMonitor, DataStorage, Desktop, Device, Display, GraphicCard, HardDrive, Laptop, Mobile, \
Monitor, Motherboard, NetworkAdapter, Processor, RamModule, Server, Smartphone, \
SolidStateDrive, SoundCard, Tablet, TelevisionSet
from ereuse_devicehub.resources.device import schemas
from ereuse_devicehub.resources.device.views import DeviceView
from teal.resource import Converters, Resource
class DeviceDef(Resource):
SCHEMA = Device
SCHEMA = schemas.Device
VIEW = DeviceView
ID_CONVERTER = Converters.int
AUTH = True
@ -15,109 +12,109 @@ class DeviceDef(Resource):
class ComputerDef(DeviceDef):
VIEW = None
SCHEMA = Computer
SCHEMA = schemas.Computer
class DesktopDef(ComputerDef):
VIEW = None
SCHEMA = Desktop
SCHEMA = schemas.Desktop
class LaptopDef(ComputerDef):
VIEW = None
SCHEMA = Laptop
SCHEMA = schemas.Laptop
class ServerDef(ComputerDef):
VIEW = None
SCHEMA = Server
SCHEMA = schemas.Server
class MonitorDef(DeviceDef):
VIEW = None
SCHEMA = Monitor
SCHEMA = schemas.Monitor
class ComputerMonitorDef(MonitorDef):
VIEW = None
SCHEMA = ComputerMonitor
SCHEMA = schemas.ComputerMonitor
class TelevisionSetDef(MonitorDef):
VIEW = None
SCHEMA = TelevisionSet
SCHEMA = schemas.TelevisionSet
class MobileDef(DeviceDef):
VIEW = None
SCHEMA = Mobile
SCHEMA = schemas.Mobile
class SmartphoneDef(MobileDef):
VIEW = None
SCHEMA = Smartphone
SCHEMA = schemas.Smartphone
class TabletDef(MobileDef):
VIEW = None
SCHEMA = Tablet
SCHEMA = schemas.Tablet
class CellphoneDef(MobileDef):
VIEW = None
SCHEMA = Cellphone
SCHEMA = schemas.Cellphone
class ComponentDef(DeviceDef):
VIEW = None
SCHEMA = Component
SCHEMA = schemas.Component
class GraphicCardDef(ComponentDef):
VIEW = None
SCHEMA = GraphicCard
SCHEMA = schemas.GraphicCard
class DataStorageDef(ComponentDef):
VIEW = None
SCHEMA = DataStorage
SCHEMA = schemas.DataStorage
class HardDriveDef(DataStorageDef):
VIEW = None
SCHEMA = HardDrive
SCHEMA = schemas.HardDrive
class SolidStateDriveDef(DataStorageDef):
VIEW = None
SCHEMA = SolidStateDrive
SCHEMA = schemas.SolidStateDrive
class MotherboardDef(ComponentDef):
VIEW = None
SCHEMA = Motherboard
SCHEMA = schemas.Motherboard
class NetworkAdapterDef(ComponentDef):
VIEW = None
SCHEMA = NetworkAdapter
SCHEMA = schemas.NetworkAdapter
class RamModuleDef(ComponentDef):
VIEW = None
SCHEMA = RamModule
SCHEMA = schemas.RamModule
class ProcessorDef(ComponentDef):
VIEW = None
SCHEMA = Processor
SCHEMA = schemas.Processor
class SoundCardDef(ComponentDef):
VIEW = None
SCHEMA = SoundCard
SCHEMA = schemas.SoundCard
class DisplayDef(ComponentDef):
VIEW = None
SCHEMA = Display
SCHEMA = schemas.Display

View file

@ -1,17 +1,13 @@
from typing import Callable, Iterable, Tuple
from ereuse_devicehub.resources.device.sync import Sync
from ereuse_devicehub.resources.event.schemas import Add, AggregateRate, AppRate, Benchmark, \
BenchmarkDataStorage, BenchmarkProcessor, BenchmarkProcessorSysbench, BenchmarkRamSysbench, \
BenchmarkWithRate, EraseBasic, EraseSectors, EreusePrice, Event, Install, PhotoboxSystemRate, \
PhotoboxUserRate, Price, Rate, Remove, Snapshot, Step, StepRandom, StepZero, StressTest, Test, \
TestDataStorage, WorkbenchRate
from ereuse_devicehub.resources.event import schemas
from ereuse_devicehub.resources.event.views import EventView, SnapshotView
from teal.resource import Converters, Resource
class EventDef(Resource):
SCHEMA = Event
SCHEMA = schemas.Event
VIEW = EventView
AUTH = True
ID_CONVERTER = Converters.uuid
@ -19,87 +15,87 @@ class EventDef(Resource):
class AddDef(EventDef):
VIEW = None
SCHEMA = Add
SCHEMA = schemas.Add
class RemoveDef(EventDef):
VIEW = None
SCHEMA = Remove
SCHEMA = schemas.Remove
class EraseBasicDef(EventDef):
VIEW = None
SCHEMA = EraseBasic
SCHEMA = schemas.EraseBasic
class EraseSectorsDef(EraseBasicDef):
VIEW = None
SCHEMA = EraseSectors
SCHEMA = schemas.EraseSectors
class StepDef(Resource):
VIEW = None
SCHEMA = Step
SCHEMA = schemas.Step
class StepZeroDef(StepDef):
VIEW = None
SCHEMA = StepZero
SCHEMA = schemas.StepZero
class StepRandomDef(StepDef):
VIEW = None
SCHEMA = StepRandom
SCHEMA = schemas.StepRandom
class RateDef(EventDef):
VIEW = None
SCHEMA = Rate
SCHEMA = schemas.Rate
class AggregateRateDef(RateDef):
VIEW = None
SCHEMA = AggregateRate
SCHEMA = schemas.AggregateRate
class WorkbenchRateDef(RateDef):
VIEW = None
SCHEMA = WorkbenchRate
SCHEMA = schemas.WorkbenchRate
class PhotoboxUserDef(RateDef):
VIEW = None
SCHEMA = PhotoboxUserRate
SCHEMA = schemas.PhotoboxUserRate
class PhotoboxSystemRateDef(RateDef):
VIEW = None
SCHEMA = PhotoboxSystemRate
SCHEMA = schemas.PhotoboxSystemRate
class AppRateDef(RateDef):
VIEW = None
SCHEMA = AppRate
SCHEMA = schemas.AppRate
class PriceDef(EventDef):
VIEW = None
SCHEMA = Price
SCHEMA = schemas.Price
class EreusePriceDef(EventDef):
VIEW = None
SCHEMA = EreusePrice
SCHEMA = schemas.EreusePrice
class InstallDef(EventDef):
VIEW = None
SCHEMA = Install
SCHEMA = schemas.Install
class SnapshotDef(EventDef):
VIEW = None
SCHEMA = Snapshot
SCHEMA = schemas.Snapshot
VIEW = SnapshotView
def __init__(self, app, import_name=__package__, static_folder=None, static_url_path=None,
@ -112,44 +108,74 @@ class SnapshotDef(EventDef):
class TestDef(EventDef):
VIEW = None
SCHEMA = Test
SCHEMA = schemas.Test
class TestDataStorageDef(TestDef):
VIEW = None
SCHEMA = TestDataStorage
SCHEMA = schemas.TestDataStorage
class StressTestDef(TestDef):
VIEW = None
SCHEMA = StressTest
SCHEMA = schemas.StressTest
class BenchmarkDef(EventDef):
VIEW = None
SCHEMA = Benchmark
SCHEMA = schemas.Benchmark
class BenchmarkDataStorageDef(BenchmarkDef):
VIEW = None
SCHEMA = BenchmarkDataStorage
SCHEMA = schemas.BenchmarkDataStorage
class BenchmarkWithRateDef(BenchmarkDef):
VIEW = None
SCHEMA = BenchmarkWithRate
SCHEMA = schemas.BenchmarkWithRate
class BenchmarkProcessorDef(BenchmarkWithRateDef):
VIEW = None
SCHEMA = BenchmarkProcessor
SCHEMA = schemas.BenchmarkProcessor
class BenchmarkProcessorSysbenchDef(BenchmarkProcessorDef):
VIEW = None
SCHEMA = BenchmarkProcessorSysbench
SCHEMA = schemas.BenchmarkProcessorSysbench
class BenchmarkRamSysbenchDef(BenchmarkWithRateDef):
VIEW = None
SCHEMA = BenchmarkRamSysbench
SCHEMA = schemas.BenchmarkRamSysbench
class ToRepairDef(EventDef):
VIEW = None
SCHEMA = schemas.ToRepair
class RepairDef(EventDef):
VIEW = None
SCHEMA = schemas.Repair
class ToPrepareDef(EventDef):
VIEW = None
SCHEMA = schemas.ToPrepare
class PrepareDef(EventDef):
VIEW = None
SCHEMA = schemas.Prepare
class ToDisposeDef(EventDef):
VIEW = None
SCHEMA = schemas.ToDispose
class DisposeDef(EventDef):
VIEW = None
SCHEMA = schemas.Dispose

View file

@ -581,6 +581,30 @@ class BenchmarkRamSysbench(BenchmarkWithRate):
pass
class ToRepair(EventWithMultipleDevices):
pass
class Repair(EventWithMultipleDevices):
pass
class ToPrepare(EventWithMultipleDevices):
pass
class Prepare(EventWithMultipleDevices):
pass
class ToDispose(EventWithMultipleDevices):
pass
class Dispose(EventWithMultipleDevices):
pass
# Listeners
# Listeners validate values and keep relationships synced

View file

@ -301,3 +301,27 @@ class BenchmarkProcessorSysbench(BenchmarkProcessor):
class BenchmarkRamSysbench(BenchmarkWithRate):
pass
class ToRepair(EventWithMultipleDevices):
pass
class Repair(EventWithMultipleDevices):
pass
class ToPrepare(EventWithMultipleDevices):
pass
class Prepare(EventWithMultipleDevices):
pass
class ToDispose(EventWithMultipleDevices):
pass
class Dispose(EventWithMultipleDevices):
pass

View file

@ -5,7 +5,7 @@ from marshmallow.fields import Boolean, DateTime, Float, Integer, List, Nested,
from marshmallow.validate import Length, Range
from ereuse_devicehub.marshmallow import NestedOn
from ereuse_devicehub.resources.device.schemas import Component, Device, Computer
from ereuse_devicehub.resources.device.schemas import Component, Computer, Device
from ereuse_devicehub.resources.enums import AppearanceRange, Bios, FunctionalityRange, \
PriceSoftware, RATE_POSITIVE, RatingSoftware, SnapshotExpectedEvents, SnapshotSoftware, \
TestHardDriveLength
@ -299,3 +299,27 @@ class BenchmarkProcessorSysbench(BenchmarkProcessor):
class BenchmarkRamSysbench(BenchmarkWithRate):
pass
class ToRepair(EventWithMultipleDevices):
pass
class Repair(EventWithMultipleDevices):
pass
class ToPrepare(EventWithMultipleDevices):
pass
class Prepare(EventWithMultipleDevices):
pass
class ToDispose(EventWithMultipleDevices):
pass
class Dispose(EventWithMultipleDevices):
pass

View file

@ -1,4 +1,4 @@
from flask import current_app, current_app as app, jsonify
from flask import current_app as app, jsonify
from flask_sqlalchemy import Pagination
from marshmallow import Schema as MarshmallowSchema
from marshmallow.fields import Float, Integer, Nested, Str
@ -35,7 +35,7 @@ class OfType(Str):
def _deserialize(self, value, attr, data):
v = super()._deserialize(value, attr, data)
return self.column.in_(current_app.resources[v].subresources_types)
return self.column.in_(app.resources[v].subresources_types)
class Filters(Query):

View file

@ -3,15 +3,15 @@ from typing import Tuple
from click import argument, option
from ereuse_devicehub.db import db
from ereuse_devicehub.resources.tag import schema
from ereuse_devicehub.resources.tag.model import Tag
from ereuse_devicehub.resources.tag.schema import Tag as TagS
from ereuse_devicehub.resources.tag.view import TagView, get_device_from_tag
from teal.resource import Resource
from teal.teal import Teal
class TagDef(Resource):
SCHEMA = TagS
SCHEMA = schema.Tag
VIEW = TagView
def __init__(self, app: Teal, import_name=__package__, static_folder=None,
@ -37,7 +37,7 @@ class TagDef(Resource):
@argument('ids', nargs=-1, required=True)
def create_tags(self, ids: Tuple[str], org: str = None, provider: str = None):
"""Create TAGS and associates them to a specific PROVIDER."""
tag_schema = TagS(only=('id', 'provider', 'org'))
tag_schema = schema.Tag(only=('id', 'provider', 'org'))
db.session.add_all(
Tag(**tag_schema.load({'id': tag_id, 'provider': provider, 'org': org}))

View file

@ -1,16 +1,15 @@
from click import argument, option
from flask import current_app as app
from ereuse_devicehub.db import db
from ereuse_devicehub.resources.user import schemas
from ereuse_devicehub.resources.user.models import Organization, User
from ereuse_devicehub.resources.user.schemas import User as UserS
from ereuse_devicehub.resources.user.views import UserView, login
from teal.db import SQLAlchemy
from teal.resource import Converters, Resource
class UserDef(Resource):
SCHEMA = UserS
SCHEMA = schemas.User
VIEW = UserView
ID_CONVERTER = Converters.uuid
AUTH = True
@ -64,5 +63,6 @@ class OrganizationDef(Resource):
def init_db(self, db: SQLAlchemy):
"""Creates the default organization."""
from flask import current_app as app
org = Organization(**app.config.get_namespace('ORGANIZATION_'))
db.session.add(org)

View file

@ -35,7 +35,7 @@ setup(
long_description=long_description,
long_description_content_type='text/markdown',
install_requires=[
'teal>=0.2.0a8',
'teal>=0.2.0a9',
'marshmallow_enum',
'ereuse-utils[Naming]>=0.4b1',
'psycopg2-binary',

View file

@ -35,4 +35,4 @@ def test_api_docs(client: Client):
'scheme': 'basic',
'name': 'Authorization'
}
assert 54 == len(docs['definitions'])
assert 60 == len(docs['definitions'])

View file

@ -4,13 +4,13 @@ import pytest
from flask import g
from sqlalchemy.util import OrderedSet
from ereuse_devicehub.client import UserClient
from ereuse_devicehub.db import db
from ereuse_devicehub.resources.device.models import Desktop, Device, GraphicCard, HardDrive, \
RamModule, SolidStateDrive
from ereuse_devicehub.resources.enums import TestHardDriveLength
from ereuse_devicehub.resources.event.models import BenchmarkDataStorage, EraseBasic, EraseSectors, \
EventWithOneDevice, Install, Ready, StepRandom, StepZero, StressTest, TestDataStorage
from tests.conftest import create_user
from ereuse_devicehub.resources.event import models
from tests.conftest import create_user, file
@pytest.mark.usefixtures('app_context')
@ -22,7 +22,7 @@ def test_author():
"""
user = create_user()
g.user = user
e = EventWithOneDevice(device=Device())
e = models.EventWithOneDevice(device=Device())
db.session.add(e)
assert e.author is None
assert e.author_id is None
@ -32,7 +32,7 @@ def test_author():
@pytest.mark.usefixtures('auth_app_context')
def test_erase_basic():
erasure = EraseBasic(
erasure = models.EraseBasic(
device=HardDrive(serial_number='foo', manufacturer='bar', model='foo-bar'),
zeros=True,
start_time=datetime.now(),
@ -41,7 +41,7 @@ def test_erase_basic():
)
db.session.add(erasure)
db.session.commit()
db_erasure = EraseBasic.query.one()
db_erasure = models.EraseBasic.query.one()
assert erasure == db_erasure
assert next(iter(db_erasure.device.events)) == erasure
@ -53,7 +53,7 @@ def test_validate_device_data_storage():
with pytest.raises(TypeError,
message='EraseBasic.device must be a DataStorage '
'but you passed <GraphicCard None model=\'foo-bar\' S/N=\'foo\'>'):
EraseBasic(
models.EraseBasic(
device=GraphicCard(serial_number='foo', manufacturer='bar', model='foo-bar'),
clean_with_zeros=True,
start_time=datetime.now(),
@ -64,27 +64,27 @@ def test_validate_device_data_storage():
@pytest.mark.usefixtures('auth_app_context')
def test_erase_sectors_steps():
erasure = EraseSectors(
erasure = models.EraseSectors(
device=SolidStateDrive(serial_number='foo', manufacturer='bar', model='foo-bar'),
zeros=True,
start_time=datetime.now(),
end_time=datetime.now(),
error=False,
steps=[
StepZero(error=False,
start_time=datetime.now(),
end_time=datetime.now()),
StepRandom(error=False,
start_time=datetime.now(),
end_time=datetime.now()),
StepZero(error=False,
start_time=datetime.now(),
end_time=datetime.now())
models.StepZero(error=False,
start_time=datetime.now(),
end_time=datetime.now()),
models.StepRandom(error=False,
start_time=datetime.now(),
end_time=datetime.now()),
models.StepZero(error=False,
start_time=datetime.now(),
end_time=datetime.now())
]
)
db.session.add(erasure)
db.session.commit()
db_erasure = EraseSectors.query.one()
db_erasure = models.EraseSectors.query.one()
# Steps are in order
assert db_erasure.steps[0].num == 0
assert db_erasure.steps[1].num == 1
@ -93,7 +93,7 @@ def test_erase_sectors_steps():
@pytest.mark.usefixtures('auth_app_context')
def test_test_data_storage():
test = TestDataStorage(
test = models.TestDataStorage(
device=HardDrive(serial_number='foo', manufacturer='bar', model='foo-bar'),
error=False,
elapsed=timedelta(minutes=25),
@ -103,15 +103,15 @@ def test_test_data_storage():
)
db.session.add(test)
db.session.commit()
assert TestDataStorage.query.one()
assert models.TestDataStorage.query.one()
@pytest.mark.usefixtures('auth_app_context')
def test_install():
hdd = HardDrive(serial_number='sn')
install = Install(name='LinuxMint 18.04 es',
elapsed=timedelta(seconds=25),
device=hdd)
install = models.Install(name='LinuxMint 18.04 es',
elapsed=timedelta(seconds=25),
device=hdd)
db.session.add(install)
db.session.commit()
@ -123,7 +123,7 @@ def test_update_components_event_one():
computer.components.add(hdd)
# Add event
test = StressTest(elapsed=timedelta(seconds=1))
test = models.StressTest(elapsed=timedelta(seconds=1))
computer.events_one.add(test)
assert test.device == computer
assert next(iter(test.components)) == hdd, 'Event has to have new components'
@ -147,7 +147,7 @@ def test_update_components_event_multiple():
hdd = HardDrive(serial_number='foo', manufacturer='bar', model='foo-bar')
computer.components.add(hdd)
ready = Ready()
ready = models.Ready()
assert not ready.devices
assert not ready.components
@ -174,7 +174,7 @@ def test_update_parent():
computer.components.add(hdd)
# Add
benchmark = BenchmarkDataStorage()
benchmark = models.BenchmarkDataStorage()
benchmark.device = hdd
assert benchmark.parent == computer
assert not benchmark.components
@ -182,3 +182,23 @@ def test_update_parent():
# Remove
benchmark.device = None
assert not benchmark.parent
@pytest.mark.xfail(reason='No POST view for generic tests')
@pytest.mark.parametrize('event_model', [
models.ToRepair,
models.Repair,
models.ToPrepare,
models.Prepare,
models.ToDispose,
models.Dispose,
models.Ready
])
def test_generic_event(event_model: models.Event, user: UserClient):
"""Tests POSTing all generic events."""
snapshot, _ = user.post(file('basic.snapshot'), res=models.Snapshot)
event = {'type': event_model.t, 'devices': [snapshot['device']['id']]}
event, _ = user.post(event, res=event_model)
assert event['device'][0]['id'] == snapshot['device']['id']
device, _ = user.get(res=Device, item=snapshot['device']['id'])
assert device['events'][0]['id'] == event['id']