def test_dump(test_db): dumper = Dumper() seeder = dumper._seeder model = test_db.model with DBConn.get_session() as db: count_before = db.query(model).count() assert count_before > 0 dumper.dump_schema(test_db.schema) dumper.dump_schema('system') seeder.drop_models() seeder.create_models() with DBConn.get_session() as db: count_empty = db.query(model).count() assert count_empty == 0 dumper.load_schema('system') dumper.load_schema(test_db.schema) with DBConn.get_session() as db: count_after = db.query(model).count() assert count_after == count_before
def test_connection(): DBConn.reset() with pytest.raises(TypeError): DBConn.Session() DBConn() with DBConn.get_session() as sess: assert sess
def test_abort_request(client, test_db): test_db.entry.triggerList = Triggers([Trigger(Activation.READ, TEAPOT_ID)]) login(client, test_db.admin_user) schema, name = test_db.entry.schema, test_db.entry.tableName table_url = f'/tables/table/{schema}/{name}' entry_url = f'/tables/entry/{schema}/{name}' assert client.get(table_url).status_code == 418 assert client.get(entry_url).status_code == 418 mgr = ScriptManager() mgr.global_triggers.append(Trigger(Activation.TRANSACTION, TEAPOT_ID)) model = test_db.model entry = test_db.entry with DBConn.get_session() as db: item = db.query(model).first() data = model.__marshmallow__().dump(item) key = data[entry.pk.rowName] transaction = {entry.id: {'delete': {key: True}}} response = client.post('/transaction/execute', data=json.dumps({'transaction': transaction}), content_type='application/json') assert response.status_code == 418 client.post('/auth/logout') mgr.global_triggers.append(Trigger(Activation.LOGIN, TEAPOT_ID)) response = client.post('/auth/login', data={ "login": test_db.admin_user.login, "password": test_db.admin_user.password }) assert response.status_code == 418 mgr.global_triggers = Triggers([])
def add_role(self, db=None, **kwargs): Role = self.models['system']['Role'] with DBConn.ensure_session(db) as db: role = Role(**kwargs) db.add(role) db.commit() return role
def test_create(test_db, models): model = test_db.model entry = test_db.entry with DBConn.get_session() as db: count = db.query(model).count() faker = Faker(models, db=db) faked = faker.fake_one(model, db) data = faked.__marshmallow__().dump(faked) db.rollback() transaction = {} transaction[entry.id] = { 'create': { 'dummy_key': { 'newData': data, 'links': [] } } } bad_t = Transaction(db, transaction, role_names=['dummy']) with pytest.raises(InsufficientRightsError): bad_t.execute() assert db.query(model).count() == count t = Transaction(db, transaction) t.execute() assert db.query(model).count() == count + 1
def test_fetch_many(test_db): with DBConn.get_session() as db: obj, criterion = _get_sample(db, test_db) builder = QueryBuilder(db) result = builder.fetch_data(test_db.model, filter_by=[criterion]) assert len(result) > 0
def test_exception_handling(test_db): entry = test_db.entry with DBConn.get_session() as db: transaction = { entry.id: { 'create': { 'dummy_key': { 'newData': { 'jackshit': True, 'jackshit2': '12345' }, 'links': [] } } } } t = Transaction(db, transaction) try: t.execute() except Exception as exp: error, _ = ErrorsParser.parse(exp) assert len(error.info) > 0
def test_integration(config, sample_xml, models, alg_test_options): erd = ERD(sample_xml) alg = Algorithm(erd, options=alg_test_options) alg.run_algorithm() tables = alg.tables gen = Generator(tables, 'er1', add_check=True) gen.generate_folder() gen.generate_system_models() assert len(list(models)) - len(models['system']) == len(tables) manager = HierachyManager() manager.drop() manager.hierarchy.merge(HierachyConstructor(tables, 'er1').construct()) seeder = Seeder(models) seeder.drop_models() seeder.create_models() faker = Faker(models) faker.fake_all(10) firsts = [] with DBConn.get_session() as db: for table in faker.faked_models(): firsts.append(db.query(table).first()) for first in firsts: assert first assert repr(erd) assert repr(alg) assert repr(gen)
def test_db(empty_db): alg, models = empty_db manager = UserManager() hierarchy_manager = HierachyManager() hierarchy_manager.drop() with DBConn.get_session() as db: admin_user = manager.add_user('admin', 'password', db) normal_user = manager.add_user('user', 'password', db) admin_role = manager.add_role(db=db, name='admin', can_reset_password=True, has_sql_access=True, linked_entity_schema='er1', linked_entity_name='user', can_register_all=True) db.add(admin_role) admin_user.roles = [admin_role] db.commit() constuctor = HierachyConstructor(alg.tables, 'er1', admin_role=admin_role) h = constuctor.construct() constuctor.insert_system_pages(h) hierarchy_manager.h.merge(h) faker = Faker(models) faker.fake_all(10) model = next( iter(model for model in models if model.__table__.schema != 'system')) model_name = model.__name__ field_name = next(iter(model.__table__.columns)).name entry = hierarchy_manager.h.get_table_entry(model.__table__.schema, model.__tablename__) if entry is None: logging.warning('Entry not found') logging.info(f"{model.__table__.schema}, {model.__tablename__}") logging.info(hierarchy_manager.h.pretty_xml()) User = namedtuple('User', ['user', 'login', 'password']) admin = User(admin_user, 'admin', 'password') normal = User(normal_user, 'user', 'password') TestData = namedtuple('TestData', [ 'admin_user', 'normal_user', 'model', 'model_name', 'field_name', 'schema', 'hierarchy', 'entry' ]) return TestData(admin_user=admin, normal_user=normal, model=model, entry=entry, hierarchy=hierarchy_manager.h, model_name=model_name, field_name=field_name, schema='er1')
def print_roles(test_db): from ermaket.api.database import DBConn normal, admin = test_db.normal_user.user, test_db.admin_user.user with DBConn.get_session() as db: db.add(normal) db.add(admin) print(f'Normal roles: {normal.role_names}') print(f'Admin roles: {admin.role_names}')
def test_fetch_one(test_db): with DBConn.get_session() as db: obj, criterion = _get_sample(db, test_db) builder = QueryBuilder(db) found_obj = builder.fetch_one(test_db.model, filter_by=[criterion]) assert found_obj['_display'] is not None del found_obj['_display'] assert obj == found_obj
def drop_user(self, name): with DBConn.get_session() as db: try: db.execute(f'DROP OWNED BY {name}') db.execute(f'DROP USER {name}') return True except Exception: return False
def test_marshmallow(models): dumps = [] with DBConn.get_session() as db: for model in iter(models): item = db.query(model).first() obj = model.__marshmallow__(session=db).dump(item) dumps.append(obj) for obj in dumps: assert obj is not None
def password(): data = request.form or request.json with DBConn.get_session() as sess: sess.add(current_user) success = current_user.change_password(data['old_pass'], data['new_pass']) if success: sess.commit() return jsonify({"ok": success})
def _create_users(self): self._users.create_user(self._config.Users['readonly'], ('SELECT', )) self._users.create_user( self._config.Users['sql'], ('SELECT', 'INSERT', 'UPDATE', 'DELETE', 'CREATE') ) self._get_session = { 'readonly': DBConn.make_get_session( user=self._config.Users['readonly']['user'], password=self._config.Users['readonly']['password'] ), 'sql': DBConn.make_get_session( user=self._config.Users['sql']['user'], password=self._config.Users['sql']['password'] ), }
def add_user(self, login, password, db=None, role_names=None): with DBConn.ensure_session(db) as db: user = self._User(login=login) user.set_password(password) db.add(user) roles = self.add_roles(db, role_names) user.roles = roles db.commit() return user
def check_user(self, login, password, db=None): User = self._User with DBConn.ensure_session(db) as db: user = db.query(User).filter(User.login == login).first() if not user: return if not user.check_password(password): return return user
def __init__(self, system_only=False): if DBConn.engine is None: DBConn() self.config = Config() self.schemas = {} self.Base = None self._paths = {} self._import_base() self._system_only = system_only self._import()
def fake_schema(self, schema, entries={}, default_num=5): """Fill the database schema tables with fake data raises ResolveError if could not resolve foreign keys :param schema: schema name :param entries: {model_name: number_of_entries} model_name is generated camelCase :param default_num: number of entries, if t_name is not in entries """ if 'system' in self._models.schemas and not self._silence_system_warn: logging.warning('If the model has references to system tables, ' 'it may be required to fake schema `system` first') generated = {name: 0 for name in self._models[schema].keys()} not_resolved = {name: 0 for name in self._models[schema].keys()} if schema in self._config.Faker['ignore']: for key in self._config.Faker['ignore'][schema]: del generated[key] del not_resolved[key] total = sum([ entries.get(name, default_num) for name in self._models[schema].keys() ]) try: if self._verbose: bar = tqdm.tqdm(total=total) with DBConn.get_session(autoflush=False) as db: self._init_mixer(db) while len(generated) > 0: finished = [] for name, i in generated.items(): if i >= entries.get(name, default_num): finished.append(name) continue model = self._models[schema][name] if self._fake_model(model, db): generated[name] += 1 if self._verbose: bar.update(1) not_resolved[name] = 0 else: not_resolved[name] += 1 if not_resolved[name] > self._max_resolve: raise ResolveError( f"Can't resolve foreign keys for {name}") for name in finished: del generated[name] self._flush_faked(db) finally: if self._verbose: bar.close()
def create_user(self, config, rights): with DBConn.get_session() as db: config = {**self._config.Database, **config} self._try_create_user(config, db) if isinstance(rights, list) or isinstance(rights, tuple): for schema in self._models.schema_names: self._grant_rights_on_schema(config, db, schema, rights) else: for schema, rights_ in rights.items(): self._grant_rights_on_schema(config, db, schema, rights_) db.commit()
def current(): with DBConn.get_session() as sess: sess.add(current_user) user = current_user.__marshmallow__().dump(current_user) return jsonify({ "ok": True, "user": user, "hierarchy": session.get('hierarchy'), "rights": session.get('rights'), "profile_forms": session.get('profile_forms') })
def drop(schema, y): if not y: if not click.confirm("Drop cannot be undone. Continue?"): return DBConn() if schema: seeder = Seeder(None) seeder.drop_models(schema) else: models = Models() seeder = Seeder(models) seeder.drop_models(schema)
def drop_models(self, schema=None): """Drops models :param schema: if given, drops only ones in the given schema """ with DBConn.get_session() as db: if schema is not None: db.execute(f'DROP SCHEMA IF EXISTS {schema} CASCADE') return for schema in self._models.schemas.keys(): db.execute(f'DROP SCHEMA IF EXISTS {schema} CASCADE') db.commit()
def test_update(test_db, models): model = test_db.model entry = test_db.entry not_pk = next( col for col in entry.columns if not col.isPk and not isinstance(col, LinkedTableColumn) ) with DBConn.get_session() as db: item = db.query(model).first() old_data = model.__marshmallow__().dump(item) key = old_data[entry.pk.rowName] faker = Faker(models, db=db) faked = faker.fake_one(model, db) fake_data = faked.__marshmallow__().dump(faked) db.rollback() new_data = old_data.copy() new_data[not_pk.rowName] = fake_data[not_pk.rowName] transaction = { entry.id: { 'update': { key: { 'newData': new_data, 'oldData': old_data } } } } bad_t = Transaction(db, transaction, role_names=['dummy']) with pytest.raises(InsufficientRightsError): bad_t.execute() not_changed_item = db.query(model).filter_by( **{ entry.pk.rowName: key } ).first() assert getattr(not_changed_item, not_pk.rowName) == old_data[not_pk.rowName] t = Transaction(db, transaction) t.execute() changed_item = db.query(model).filter_by(**{ entry.pk.rowName: key }).first() assert getattr(changed_item, not_pk.rowName) == new_data[not_pk.rowName]
def reset_password(self, token, login, password, db=None): with DBConn.ensure_session(db) as db: token_hash = generate_password_hash(token, method='plain') token = db.query(self._Token).get(token_hash) if (token is None or not token.valid or not token.description['purpose'] == 'password' or token.description['login'] != login): return False user = db.query(self._User).get(login) user.set_password(password) token.use() db.commit() return True
def test_faker(self): models = Models() seeder = Seeder(models) faker = Faker(models) seeder.drop_models() seeder.create_models() faker.fake_all(10) assertions = [] with DBConn.get_session() as db: for model in faker.faked_models(): ok = db.query(model).first() is not None assertions.append(ok) [self.assertTrue(ok) for ok in assertions]
def test_init(test_db, config): u1 = config.Users['readonly']['user'] u2 = config.Users['sql']['user'] users = DatabaseUserManager() users.drop_user(u1) users.drop_user(u2) SqlExecutor() with DBConn.get_session() as db: user_select = db.execute( f"SELECT 1 from pg_roles WHERE rolname='{u1}'").first() assert user_select user_select = db.execute( f"SELECT 1 from pg_roles WHERE rolname='{u2}'").first() assert user_select
def register_user(self, token, login, password, db=None): with DBConn.ensure_session(db) as db: token_hash = generate_password_hash(token, method='plain') token = db.query(self._Token).get(token_hash) if (token is None or not token.valid or not token.description['purpose'] == 'registration'): return None user = self.add_user(login, password, role_names=token.description['roles'], db=db) if user is not None: token.use() db.commit() return user
def login(): data = request.form or request.json if not scripts.process_global(Activation.LOGIN): return scripts.return_ with DBConn.get_session() as db: user = manager.check_user(data['login'], data['password'], db) if user: manager.login_user(user, session) login_user(user) return jsonify({"ok": True, **scripts.append_}) return jsonify({ "ok": False, "message": "Incorrect username or password", **scripts.append_ }), 401
def test_transaction(client, test_db): model = test_db.model entry = test_db.entry with DBConn.get_session() as db: item = db.query(model).first() data = model.__marshmallow__().dump(item) key = data[entry.pk.rowName] transaction = {entry.id: {'delete': {key: True}}} login(client, test_db.admin_user) response = client.post('/transaction/execute', data=json.dumps({'transaction': transaction}), content_type='application/json') assert response.status_code == 200