Add Tests managing inventories; small bugfixes
This commit is contained in:
parent
6c4c89ac48
commit
15f705dd50
|
@ -1,6 +1,7 @@
|
|||
import os
|
||||
|
||||
import click.testing
|
||||
import ereuse_utils
|
||||
import flask.cli
|
||||
|
||||
from ereuse_devicehub.config import DevicehubConfig
|
||||
|
@ -19,11 +20,35 @@ class DevicehubGroup(flask.cli.FlaskGroup):
|
|||
self.create_app = self.create_app_factory(inventory)
|
||||
return super().main(*args, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def create_app_factory(inventory):
|
||||
return lambda: Devicehub(inventory)
|
||||
@classmethod
|
||||
def create_app_factory(cls, inventory):
|
||||
return lambda: Devicehub(inventory, config=cls.CONFIG())
|
||||
|
||||
|
||||
@click.group(cls=DevicehubGroup)
|
||||
def get_version(ctx, param, value):
|
||||
if not value or ctx.resilient_parsing:
|
||||
return
|
||||
click.echo('Devicehub {}'.format(ereuse_utils.version('ereuse-devicehub')), color=ctx.color)
|
||||
flask.cli.get_version(ctx, param, value)
|
||||
|
||||
|
||||
@click.option('--version',
|
||||
help='Devicehub version.',
|
||||
expose_value=False,
|
||||
callback=get_version,
|
||||
is_flag=True,
|
||||
is_eager=True)
|
||||
@click.group(cls=DevicehubGroup,
|
||||
context_settings=Devicehub.cli_context_settings,
|
||||
add_version_option=False,
|
||||
help="""
|
||||
Manages the Devicehub of the inventory {}.
|
||||
|
||||
Use 'export dhi=xx' to set the inventory that this CLI
|
||||
manages. For example 'export dhi=db1' and then executing
|
||||
'dh tag add' adds a tag in the db1 database. Operations
|
||||
that affect the common database (like creating an user)
|
||||
are not affected by this.
|
||||
""".format(os.environ.get('dhi')))
|
||||
def cli():
|
||||
pass
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import os
|
||||
import uuid
|
||||
from typing import Type
|
||||
|
||||
|
@ -42,12 +43,19 @@ class Devicehub(Teal):
|
|||
super().__init__(config, db, inventory, import_name, static_url_path, static_folder,
|
||||
static_host,
|
||||
host_matching, subdomain_matching, template_folder, instance_path,
|
||||
instance_relative_config, root_path, Auth)
|
||||
instance_relative_config, root_path, False, Auth)
|
||||
self.id = inventory
|
||||
"""The Inventory ID of this instance. In Teal is the app.schema."""
|
||||
self.dummy = Dummy(self)
|
||||
self.cli.command('regenerate-search')(self.regenerate_search)
|
||||
self.cli.command('init-db')(self.init_db)
|
||||
|
||||
@self.cli.group(short_help='Inventory management.',
|
||||
help='Manages the inventory {}.'.format(os.environ.get('dhi')))
|
||||
def inv():
|
||||
pass
|
||||
|
||||
inv.command('add')(self.init_db)
|
||||
inv.command('del')(self.delete_inventory)
|
||||
inv.command('search')(self.regenerate_search)
|
||||
self.before_request(self._prepare_request)
|
||||
|
||||
# noinspection PyMethodOverriding
|
||||
|
@ -82,12 +90,21 @@ class Devicehub(Teal):
|
|||
tag_token: uuid.UUID,
|
||||
erase: bool,
|
||||
common: bool):
|
||||
"""Initializes this inventory with the provided configurations."""
|
||||
"""Creates an inventory.
|
||||
|
||||
This creates the database and adds the inventory to the
|
||||
inventory tables with the passed-in settings, and does nothing if the
|
||||
inventory already exists.
|
||||
|
||||
After you create the inventory you might want to create an user
|
||||
executing *dh user add*.
|
||||
"""
|
||||
assert _app_ctx_stack.top, 'Use an app context.'
|
||||
print('Initializing database...'.ljust(30), end='')
|
||||
with click_spinner.spinner():
|
||||
if erase:
|
||||
self.db.drop_all(common_schema=common)
|
||||
assert not db.has_schema(self.id), 'Schema {} already exists.'.format(self.id)
|
||||
exclude_schema = 'common' if not common else None
|
||||
self._init_db(exclude_schema=exclude_schema)
|
||||
InventoryDef.set_inventory_config(name, org_name, org_id, tag_url, tag_token)
|
||||
|
@ -96,6 +113,20 @@ class Devicehub(Teal):
|
|||
self.db.session.commit()
|
||||
print('done.')
|
||||
|
||||
@click.confirmation_option(prompt='Are you sure you want to delete the inventory {}?'
|
||||
.format(os.environ.get('dhi')))
|
||||
def delete_inventory(self):
|
||||
"""Erases an inventory.
|
||||
|
||||
This removes its private database and its entry in the common
|
||||
inventory.
|
||||
|
||||
This deletes users that have only access to this inventory.
|
||||
"""
|
||||
InventoryDef.delete_inventory()
|
||||
self.db.session.commit()
|
||||
self.db.drop_all(common_schema=False)
|
||||
|
||||
def regenerate_search(self):
|
||||
"""Re-creates from 0 all the search tables."""
|
||||
DeviceSearch.regenerate_search_table(self.db.session)
|
||||
|
|
|
@ -63,27 +63,21 @@ class Dummy:
|
|||
common=True)
|
||||
print('Creating stuff...'.ljust(30), end='')
|
||||
with click_spinner.spinner():
|
||||
out = runner.invoke(args=['create-org', *self.ORG], catch_exceptions=False).output
|
||||
out = runner.invoke('org', 'add', *self.ORG).output
|
||||
org_id = json.loads(out)['id']
|
||||
user = self.user_client('user@dhub.com', '1234')
|
||||
# todo put user's agent into Org
|
||||
for id in self.TAGS:
|
||||
user.post({'id': id}, res=Tag)
|
||||
for id, sec in self.ET:
|
||||
runner.invoke(args=[
|
||||
'create-tag', id,
|
||||
runner.invoke('tag', 'add', id,
|
||||
'-p', 'https://t.devicetag.io',
|
||||
'-s', sec,
|
||||
'-o', org_id
|
||||
],
|
||||
catch_exceptions=False)
|
||||
'-o', org_id)
|
||||
# create tag for pc-laudem
|
||||
runner.invoke(args=[
|
||||
'create-tag', 'tagA',
|
||||
runner.invoke('tag', 'add', 'tagA',
|
||||
'-p', 'https://t.devicetag.io',
|
||||
'-s', 'tagA-secondary'
|
||||
],
|
||||
catch_exceptions=False)
|
||||
'-s', 'tagA-secondary')
|
||||
files = tuple(Path(__file__).parent.joinpath('files').iterdir())
|
||||
print('done.')
|
||||
sample_pc = None # We treat this one as a special sample for demonstrations
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import json
|
||||
|
||||
import click
|
||||
from boltons.typeutils import classproperty
|
||||
from teal.resource import Converters, Resource
|
||||
|
||||
from ereuse_devicehub.db import db
|
||||
|
@ -22,7 +23,7 @@ class OrganizationDef(AgentDef):
|
|||
static_url_path=None,
|
||||
template_folder=None, url_prefix=None, subdomain=None, url_defaults=None,
|
||||
root_path=None):
|
||||
cli_commands = ((self.create_org, 'create-org'),)
|
||||
cli_commands = ((self.create_org, 'add'),)
|
||||
super().__init__(app, import_name, static_folder, static_url_path, template_folder,
|
||||
url_prefix, subdomain, url_defaults, root_path, cli_commands)
|
||||
|
||||
|
@ -44,6 +45,10 @@ class OrganizationDef(AgentDef):
|
|||
print(json.dumps(o, indent=2))
|
||||
return o
|
||||
|
||||
@classproperty
|
||||
def cli_name(cls):
|
||||
return 'org'
|
||||
|
||||
|
||||
class Membership(Resource):
|
||||
SCHEMA = schemas.Membership
|
||||
|
|
|
@ -83,8 +83,13 @@ class Agent(Thing):
|
|||
|
||||
class Organization(JoinedTableMixin, Agent):
|
||||
default_of = db.relationship(Inventory,
|
||||
single_parent=True,
|
||||
uselist=False,
|
||||
lazy=True,
|
||||
backref=backref('org', lazy=True),
|
||||
# We need to use this as we cannot do Inventory.foreign -> Org
|
||||
# as foreign keys can only reference to one table
|
||||
# and we have multiple organization table (one per schema)
|
||||
foreign_keys=[Inventory.org_id],
|
||||
primaryjoin=lambda: Organization.id == Inventory.org_id)
|
||||
|
||||
def __init__(self, name: str, **kwargs) -> None:
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import uuid
|
||||
|
||||
import boltons.urlutils
|
||||
import click
|
||||
import ereuse_utils.cli
|
||||
from flask import current_app
|
||||
from teal.db import ResourceNotFound
|
||||
from teal.resource import Resource
|
||||
|
@ -20,35 +18,8 @@ class InventoryDef(Resource):
|
|||
static_url_path=None,
|
||||
template_folder=None, url_prefix=None, subdomain=None, url_defaults=None,
|
||||
root_path=None):
|
||||
cli_commands = (
|
||||
(self.set_inventory_config_cli, 'set-inventory-config'),
|
||||
)
|
||||
super().__init__(app, import_name, static_folder, static_url_path, template_folder,
|
||||
url_prefix, subdomain, url_defaults, root_path, cli_commands)
|
||||
|
||||
@click.option('--name', '-n',
|
||||
default='Test 1',
|
||||
help='The human name of the inventory.')
|
||||
@click.option('--org-name', '-on',
|
||||
default=None,
|
||||
help='The name of the default organization that owns this inventory.')
|
||||
@click.option('--org-id', '-oi',
|
||||
default=None,
|
||||
help='The Tax ID of the organization.')
|
||||
@click.option('--tag-url', '-tu',
|
||||
type=ereuse_utils.cli.URL(scheme=True, host=True, path=False),
|
||||
default=None,
|
||||
help='The base url (scheme and host) of the tag provider.')
|
||||
@click.option('--tag-token', '-tt',
|
||||
type=click.UUID,
|
||||
default=None,
|
||||
help='The token provided by the tag provider. It is an UUID.')
|
||||
def set_inventory_config_cli(self, **kwargs):
|
||||
"""Sets the inventory configuration. Only updates passed-in
|
||||
values.
|
||||
"""
|
||||
self.set_inventory_config(**kwargs)
|
||||
db.session.commit()
|
||||
url_prefix, subdomain, url_defaults, root_path)
|
||||
|
||||
@classmethod
|
||||
def set_inventory_config(cls,
|
||||
|
@ -72,8 +43,23 @@ class InventoryDef(Resource):
|
|||
except ResourceNotFound:
|
||||
org = Organization(tax_id=org_id, name=org_name)
|
||||
org.default_of = inventory
|
||||
db.session.add(org)
|
||||
if tag_url:
|
||||
inventory.tag_provider = tag_url
|
||||
if tag_token:
|
||||
inventory.tag_token = tag_token
|
||||
|
||||
@classmethod
|
||||
def delete_inventory(cls):
|
||||
"""Removes an inventory alongside with the users that have
|
||||
only access to this inventory.
|
||||
"""
|
||||
from ereuse_devicehub.resources.user.models import User, UserInventory
|
||||
inv = Inventory.query.filter_by(id=current_app.id).one()
|
||||
db.session.delete(inv)
|
||||
db.session.flush()
|
||||
# Remove users that end-up without any inventory
|
||||
# todo this should be done in a trigger / event
|
||||
users = User.query \
|
||||
.filter(User.id.notin_(db.session.query(UserInventory.user_id).distinct()))
|
||||
for user in users:
|
||||
db.session.delete(user)
|
||||
|
|
|
@ -13,7 +13,8 @@ class Inventory(Thing):
|
|||
tag_provider = db.Column(db.URL(), nullable=False)
|
||||
tag_token = db.Column(db.UUID(as_uuid=True), unique=True, nullable=False)
|
||||
tag_token.comment = """The token to access a Tag service."""
|
||||
org_id = db.Column(db.UUID(as_uuid=True), db.ForeignKey('organization.id'), nullable=False)
|
||||
# todo no validation that UUID is from an existing organization
|
||||
org_id = db.Column(db.UUID(as_uuid=True), nullable=False)
|
||||
|
||||
__table_args__ = (
|
||||
db.Index('id_hash', id, postgresql_using='hash'),
|
||||
|
|
|
@ -29,8 +29,8 @@ class TagDef(Resource):
|
|||
template_folder=None, url_prefix=None, subdomain=None, url_defaults=None,
|
||||
root_path=None):
|
||||
cli_commands = (
|
||||
(self.create_tag, 'create-tag'),
|
||||
(self.create_tags_csv, 'create-tags-csv')
|
||||
(self.create_tag, 'add'),
|
||||
(self.create_tags_csv, 'add-csv')
|
||||
)
|
||||
super().__init__(app, import_name, static_folder, static_url_path, template_folder,
|
||||
url_prefix, subdomain, url_defaults, root_path, cli_commands)
|
||||
|
|
|
@ -5,7 +5,6 @@ from flask import current_app
|
|||
from teal.resource import Converters, Resource
|
||||
|
||||
from ereuse_devicehub.db import db
|
||||
from ereuse_devicehub.resources.inventory import Inventory
|
||||
from ereuse_devicehub.resources.user import schemas
|
||||
from ereuse_devicehub.resources.user.models import User
|
||||
from ereuse_devicehub.resources.user.views import UserView, login
|
||||
|
@ -20,7 +19,7 @@ class UserDef(Resource):
|
|||
def __init__(self, app, import_name=__name__.split('.')[0], static_folder=None,
|
||||
static_url_path=None, template_folder=None, url_prefix=None, subdomain=None,
|
||||
url_defaults=None, root_path=None):
|
||||
cli_commands = ((self.create_user, 'create-user'),)
|
||||
cli_commands = ((self.create_user, 'add'),)
|
||||
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'})
|
||||
|
@ -29,7 +28,9 @@ class UserDef(Resource):
|
|||
@option('-i', '--inventory',
|
||||
multiple=True,
|
||||
help='Inventories user has access to. By default this one.')
|
||||
@option('-a', '--agent', help='The name of an agent to create with the user.')
|
||||
@option('-a', '--agent',
|
||||
help='Create too an Individual agent representing this user, '
|
||||
'and give a name to this individual.')
|
||||
@option('-c', '--country', help='The country of the agent (if --agent is set).')
|
||||
@option('-t', '--telephone', help='The telephone of the agent (if --agent is set).')
|
||||
@option('-t', '--tax-id', help='The tax id of the agent (if --agent is set).')
|
||||
|
@ -41,15 +42,16 @@ class UserDef(Resource):
|
|||
country: str = None,
|
||||
telephone: str = None,
|
||||
tax_id: str = None) -> dict:
|
||||
"""Creates an user.
|
||||
"""Create an user.
|
||||
|
||||
If ``--agent`` is passed, it creates an ``Individual`` agent
|
||||
that represents the user.
|
||||
If ``--agent`` is passed, it creates too an ``Individual``
|
||||
agent that represents the user.
|
||||
"""
|
||||
from ereuse_devicehub.resources.agent.models import Individual
|
||||
u = self.SCHEMA(only={'email', 'password'}, exclude=('token',)) \
|
||||
.load({'email': email, 'password': password})
|
||||
if inventory:
|
||||
from ereuse_devicehub.resources.inventory import Inventory
|
||||
inventory = Inventory.query.filter(Inventory.id.in_(inventory))
|
||||
user = User(**u, inventories=inventory)
|
||||
agent = Individual(**current_app.resources[Individual.t].schema.load(
|
||||
|
|
|
@ -5,6 +5,7 @@ from sqlalchemy import Column
|
|||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy_utils import Password
|
||||
|
||||
from ereuse_devicehub.db import db
|
||||
from ereuse_devicehub.resources.agent.models import Individual
|
||||
from ereuse_devicehub.resources.inventory import Inventory
|
||||
from ereuse_devicehub.resources.models import Thing
|
||||
|
@ -30,3 +31,7 @@ class User(Thing):
|
|||
@property
|
||||
def individual(self) -> Union[Individual, None]:
|
||||
pass
|
||||
|
||||
|
||||
class UserInventory(db.Model):
|
||||
pass
|
||||
|
|
|
@ -5,7 +5,7 @@ click==6.7
|
|||
click-spinner==0.1.8
|
||||
colorama==0.3.9
|
||||
colour==0.1.5
|
||||
ereuse-utils[naming, test, session, cli]==0.4.0b20
|
||||
ereuse-utils[naming, test, session, cli]==0.4.0b21
|
||||
Flask==1.0.2
|
||||
Flask-Cors==3.0.6
|
||||
Flask-SQLAlchemy==2.3.2
|
||||
|
@ -24,7 +24,7 @@ requests[security]==2.19.1
|
|||
requests-mock==1.5.2
|
||||
SQLAlchemy==1.2.17
|
||||
SQLAlchemy-Utils==0.33.11
|
||||
teal==0.2.0a35
|
||||
teal==0.2.0a36
|
||||
webargs==4.0.0
|
||||
Werkzeug==0.14.1
|
||||
sqlalchemy-citext==1.3.post0
|
||||
|
|
4
setup.py
4
setup.py
|
@ -29,10 +29,10 @@ setup(
|
|||
long_description=long_description,
|
||||
long_description_content_type='text/markdown',
|
||||
install_requires=[
|
||||
'teal>=0.2.0a35', # teal always first
|
||||
'teal>=0.2.0a36', # teal always first
|
||||
'click',
|
||||
'click-spinner',
|
||||
'ereuse-utils[naming, test, session, cli]>=0.4b20',
|
||||
'ereuse-utils[naming, test, session, cli]>=0.4b21',
|
||||
'hashids',
|
||||
'marshmallow_enum',
|
||||
'psycopg2-binary',
|
||||
|
|
|
@ -62,7 +62,7 @@ def app(request, _app: Devicehub) -> Devicehub:
|
|||
try:
|
||||
with redirect_stdout(io.StringIO()):
|
||||
_init()
|
||||
except (ProgrammingError, IntegrityError):
|
||||
except (ProgrammingError, IntegrityError, AssertionError):
|
||||
print('Database was not correctly emptied. Re-empty and re-installing...')
|
||||
_drop()
|
||||
_init()
|
||||
|
|
|
@ -209,7 +209,7 @@ def test_device_search_regenerate_table(app: DeviceSearch, user: UserClient):
|
|||
i, _ = user.get(res=Device, query=[('search', 'Desktop')])
|
||||
assert not i['items'], 'Truncate deleted all items'
|
||||
runner = app.test_cli_runner()
|
||||
runner.invoke(args=['regenerate-search'], catch_exceptions=False)
|
||||
runner.invoke('inv', 'search')
|
||||
i, _ = user.get(res=Device, query=[('search', 'Desktop')])
|
||||
assert i['items'], 'Regenerated re-made the table'
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@ def noop():
|
|||
|
||||
@pytest.fixture()
|
||||
def dispatcher(app: Devicehub, config: TestConfig) -> PathDispatcher:
|
||||
print('whoho')
|
||||
PathDispatcher.call = Mock(side_effect=lambda *args: args[0])
|
||||
return PathDispatcher(config_cls=config)
|
||||
|
||||
|
|
|
@ -4,6 +4,6 @@ from ereuse_devicehub.devicehub import Devicehub
|
|||
def test_dummy(_app: Devicehub):
|
||||
"""Tests the dummy cli command."""
|
||||
runner = _app.test_cli_runner()
|
||||
runner.invoke(args=['dummy', '--yes'], catch_exceptions=False)
|
||||
runner.invoke('dummy', '--yes')
|
||||
with _app.app_context():
|
||||
_app.db.drop_all()
|
||||
|
|
|
@ -1,19 +1,147 @@
|
|||
from typing import List
|
||||
from uuid import UUID
|
||||
|
||||
import click.testing
|
||||
import pytest
|
||||
from boltons.urlutils import URL
|
||||
|
||||
import ereuse_devicehub.cli
|
||||
from ereuse_devicehub.db import db
|
||||
from ereuse_devicehub.devicehub import Devicehub
|
||||
from ereuse_devicehub.resources.agent.models import Organization
|
||||
from ereuse_devicehub.resources.inventory import Inventory
|
||||
from ereuse_devicehub.resources.user import User
|
||||
from tests.conftest import TestConfig
|
||||
|
||||
@pytest.mark.xfail(reason='Test not developed')
|
||||
def test_create_inventory():
|
||||
"""Tests creating an inventory with an user."""
|
||||
|
||||
|
||||
@pytest.mark.xfail(reason='Test not developed')
|
||||
def test_create_existing_inventory():
|
||||
pass
|
||||
|
||||
|
||||
@pytest.mark.xfail(reason='Test not developed')
|
||||
def test_delete_inventory():
|
||||
"""Tests deleting an inventory without
|
||||
disturbing other inventories (ex. keeping commmon db), and
|
||||
removing its traces in common (no inventory row in inventory table).
|
||||
"""
|
||||
Tests the management of inventories in a multi-inventory environment
|
||||
(several Devicehub instances that point at different schemas).
|
||||
"""
|
||||
|
||||
|
||||
class NoExcCliRunner(click.testing.CliRunner):
|
||||
"""Runner that interfaces with the Devicehub CLI."""
|
||||
|
||||
def invoke(self, *args, input=None, env=None, catch_exceptions=False, color=False,
|
||||
**extra):
|
||||
r = super().invoke(ereuse_devicehub.cli.cli,
|
||||
args, input, env, catch_exceptions, color, **extra)
|
||||
assert r.exit_code == 0, 'CLI code {}: {}'.format(r.exit_code, r.output)
|
||||
return r
|
||||
|
||||
def inv(self, name: str):
|
||||
"""Set an inventory as an environment variable."""
|
||||
self.env = {'dhi': name}
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def cli(config, _app):
|
||||
"""Returns an interface for the dh CLI client,
|
||||
cleaning the database afterwards.
|
||||
"""
|
||||
|
||||
def drop_schemas():
|
||||
with _app.app_context():
|
||||
_app.db.drop_schema(schema='tdb1')
|
||||
_app.db.drop_schema(schema='tdb2')
|
||||
_app.db.drop_schema(schema='common')
|
||||
|
||||
drop_schemas()
|
||||
ereuse_devicehub.cli.DevicehubGroup.CONFIG = TestConfig
|
||||
yield NoExcCliRunner()
|
||||
drop_schemas()
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def tdb1(config):
|
||||
return Devicehub(inventory='tdb1', config=config, db=db)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def tdb2(config):
|
||||
return Devicehub(inventory='tdb2', config=config, db=db)
|
||||
|
||||
|
||||
def test_inventory_create_delete_user(cli, tdb1, tdb2):
|
||||
"""Tests creating two inventories with users, one user has
|
||||
access to the first inventory and the other to both. Finally, deletes
|
||||
the first inventory, deleting only the first user too.
|
||||
"""
|
||||
# Create first DB
|
||||
cli.inv('tdb1')
|
||||
cli.invoke('inv', 'add',
|
||||
'-n', 'Test DB1',
|
||||
'-on', 'ACME DB1',
|
||||
'-oi', 'acme-id',
|
||||
'-tu', 'https://example.com',
|
||||
'-tt', '3c66a6ad-22de-4db6-ac46-d8982522ec40',
|
||||
'--common')
|
||||
|
||||
# Create an user for first DB
|
||||
cli.invoke('user', 'add', 'foo@foo.com', '-a', 'Foo', '-c', 'ES', '-p', 'Such password')
|
||||
|
||||
with tdb1.app_context():
|
||||
# There is a row for the inventory
|
||||
inv = Inventory.query.one() # type: Inventory
|
||||
assert inv.id == 'tdb1'
|
||||
assert inv.name == 'Test DB1'
|
||||
assert inv.tag_provider == URL('https://example.com')
|
||||
assert inv.tag_token == UUID('3c66a6ad-22de-4db6-ac46-d8982522ec40')
|
||||
assert db.has_schema('tdb1')
|
||||
org = Organization.query.one() # type: Organization
|
||||
# assert inv.org_id == org.id
|
||||
assert org.name == 'ACME DB1'
|
||||
assert org.tax_id == 'acme-id'
|
||||
user = User.query.one() # type: User
|
||||
assert user.email == 'foo@foo.com'
|
||||
|
||||
cli.inv('tdb2')
|
||||
# Create a second DB
|
||||
# Note how we don't create common anymore
|
||||
cli.invoke('inv', 'add',
|
||||
'-n', 'Test DB2',
|
||||
'-on', 'ACME DB2',
|
||||
'-oi', 'acme-id-2',
|
||||
'-tu', 'https://example.com',
|
||||
'-tt', 'fbad1c08-ffdc-4a61-be49-464962c186a8')
|
||||
# Create an user for with access for both DB
|
||||
cli.invoke('user', 'add', 'bar@bar.com', '-a', 'Bar', '-p', 'Wow password')
|
||||
|
||||
with tdb2.app_context():
|
||||
inventories = Inventory.query.all() # type: List[Inventory]
|
||||
assert len(inventories) == 2
|
||||
assert inventories[0].id == 'tdb1'
|
||||
assert inventories[1].id == 'tdb2'
|
||||
assert db.has_schema('tdb2')
|
||||
org_db2 = Organization.query.one()
|
||||
assert org_db2 != org
|
||||
assert org_db2.name == 'ACME DB2'
|
||||
users = User.query.all() # type: List[User]
|
||||
assert users[0].email == 'foo@foo.com'
|
||||
assert users[1].email == 'bar@bar.com'
|
||||
|
||||
# Delete tdb1
|
||||
cli.inv('tdb1')
|
||||
cli.invoke('inv', 'del', '--yes')
|
||||
|
||||
with tdb2.app_context():
|
||||
# There is only tdb2 as inventory
|
||||
inv = Inventory.query.one() # type: Inventory
|
||||
assert inv.id == 'tdb2'
|
||||
# User foo@foo.com is deleted because it only
|
||||
# existed in tdb1, but not bar@bar.com which existed
|
||||
# in another inventory too (tdb2)
|
||||
user = User.query.one() # type: User
|
||||
assert user.email == 'bar@bar.com'
|
||||
assert not db.has_schema('tdb1')
|
||||
assert db.has_schema('tdb2')
|
||||
|
||||
|
||||
def test_create_existing_inventory(cli, tdb1):
|
||||
"""Tries to create twice the same inventory."""
|
||||
cli.inv('tdb1')
|
||||
cli.invoke('inv', 'add', '--common')
|
||||
with tdb1.app_context():
|
||||
assert db.has_schema('tdb1')
|
||||
with pytest.raises(AssertionError, message='Schema tdb1 already exists.'):
|
||||
cli.invoke('inv', 'add', '--common')
|
||||
|
|
|
@ -137,7 +137,7 @@ def test_tag_get_device_from_tag_endpoint_multiple_tags(app: Devicehub, user: Us
|
|||
def test_tag_create_tags_cli(app: Devicehub, user: UserClient):
|
||||
"""Checks creating tags with the CLI endpoint."""
|
||||
runner = app.test_cli_runner()
|
||||
runner.invoke(args=['create-tag', 'id1'], catch_exceptions=False)
|
||||
runner.invoke('tag', 'add', 'id1')
|
||||
with app.app_context():
|
||||
tag = Tag.query.one() # type: Tag
|
||||
assert tag.id == 'id1'
|
||||
|
@ -148,8 +148,7 @@ def test_tag_create_etags_cli(app: Devicehub, user: UserClient):
|
|||
"""Creates an eTag through the CLI."""
|
||||
# todo what happens to organization?
|
||||
runner = app.test_cli_runner()
|
||||
runner.invoke(args=['create-tag', '-p', 'https://t.ereuse.org', '-s', 'foo', 'DT-BARBAR'],
|
||||
catch_exceptions=False)
|
||||
runner.invoke('tag', 'add', '-p', 'https://t.ereuse.org', '-s', 'foo', 'DT-BARBAR')
|
||||
with app.app_context():
|
||||
tag = Tag.query.one() # type: Tag
|
||||
assert tag.id == 'dt-barbar'
|
||||
|
@ -222,8 +221,7 @@ def test_tag_create_tags_cli_csv(app: Devicehub, user: UserClient):
|
|||
"""Checks creating tags with the CLI endpoint using a CSV."""
|
||||
csv = pathlib.Path(__file__).parent / 'files' / 'tags-cli.csv'
|
||||
runner = app.test_cli_runner()
|
||||
runner.invoke(args=['create-tags-csv', str(csv)],
|
||||
catch_exceptions=False)
|
||||
runner.invoke('tag', 'add-csv', str(csv))
|
||||
with app.app_context():
|
||||
t1 = Tag.from_an_id('id1').one()
|
||||
t2 = Tag.from_an_id('sec1').one()
|
||||
|
|
Reference in a new issue