diff --git a/pyreindexer/tests/conftest.py b/pyreindexer/tests/conftest.py index 6afbc16..4c8deb4 100644 --- a/pyreindexer/tests/conftest.py +++ b/pyreindexer/tests/conftest.py @@ -1,107 +1,96 @@ import shutil + import pytest -from pyreindexer import RxConnector -from tests.helpers.index import * -from tests.helpers.items import * +from tests.helpers.api import ConnectorApi from tests.helpers.log_helper import log_fixture -from tests.helpers.metadata import put_metadata -from tests.helpers.namespace import * from tests.test_data.constants import index_definition, item_definition def pytest_addoption(parser): - parser.addoption("--mode", action="store", default='builtin', help='builtin or cproto') + parser.addoption("--mode", choices=["builtin", "cproto"], default="builtin", help="Connection mode") @pytest.fixture(scope="session", autouse=True) def log_setup(request): - """ Execute once before test run - """ log_fixture.info("Work with pyreindexer connector using {} mode".format(request.config.getoption("--mode"))) @pytest.fixture(scope="session") -def database(request): +def db(request): """ Create a database """ mode = request.config.getoption('--mode') db_name = 'test_db' - if mode == 'builtin': - prefix = 'builtin://tmp/' - elif mode == 'cproto': - prefix = 'cproto://127.0.0.1:6534/' - else: - raise ConnectionError - db = RxConnector(prefix + db_name) - yield db, db_name + prefix = "builtin://tmp/" if mode == "builtin" else "cproto://127.0.0.1:6534/" + db = ConnectorApi(f"{prefix}{db_name}") + yield db db.close() shutil.rmtree('tmp/', ignore_errors=True) @pytest.fixture(scope="function") -def namespace(database): +def namespace(db): """ Create a namespace """ - db, db_name = database ns_name = 'new_ns' - create_namespace(database, ns_name) - yield db, ns_name - drop_namespace(database, ns_name) + db.namespace.open(ns_name) + yield ns_name + db.namespace.drop(ns_name) @pytest.fixture(scope="function") -def index(namespace): +def index(db, namespace): """ Create an index to namespace """ - create_index(namespace, index_definition) + db.index.create(namespace, index_definition) yield - drop_index(namespace, 'id') + db.index.drop(namespace, "id") @pytest.fixture(scope="function") -def item(namespace): +def item(db, namespace): """ Create an item to namespace """ - insert_item(namespace, item_definition) + db.item.insert(namespace, item_definition) yield item_definition - delete_item(namespace, item_definition) + db.item.delete(namespace, item_definition) @pytest.fixture(scope="function") -def items(namespace): +def items(db, namespace): """ Create items to namespace """ - for i in range(10): - insert_item(namespace, {"id": i+1, "val": "testval" + str(i+1)}) - yield - for i in range(10): - delete_item(namespace, {"id": i+1, "val": "testval" + str(i+1)}) + items = [{"id": i, "val": f"testval{i}"} for i in range(10)] + for item in items: + db.item.insert(namespace, item) + yield items + for item in items: + db.item.delete(namespace, item) @pytest.fixture(scope="function") -def metadata(namespace): +def metadata(db, namespace): """ Put metadata to namespace """ key, value = 'key', 'value' - put_metadata(namespace, key, value) + db.meta.put(namespace, key, value) yield key, value @pytest.fixture(scope="function") -def second_namespace_for_join(database): - db, db_name = database +def second_namespace_for_join(db): second_namespace_name = 'test_ns_for_join' - db.namespace_open(second_namespace_name) - db.index_add(second_namespace_name, index_definition) + db.namespace.open(second_namespace_name) + db.index.create(second_namespace_name, index_definition) second_ns_item_definition = {"id": 100, "second_ns_val": "second_ns_testval"} second_ns_item_definition_join = {"id": 1, "second_ns_val": "second_ns_testval_1"} - db.item_insert(second_namespace_name, second_ns_item_definition) - db.item_insert(second_namespace_name, second_ns_item_definition_join) + db.item.insert(second_namespace_name, second_ns_item_definition) + db.item.insert(second_namespace_name, second_ns_item_definition_join) yield second_namespace_name, second_ns_item_definition_join diff --git a/pyreindexer/tests/helpers/api.py b/pyreindexer/tests/helpers/api.py new file mode 100644 index 0000000..3d534d0 --- /dev/null +++ b/pyreindexer/tests/helpers/api.py @@ -0,0 +1,141 @@ +from pyreindexer import RxConnector +from tests.helpers.log_helper import log_api + + +def make_request_and_response_log(method_description, request_msg, res=None) -> str: + return f"{method_description}\n\t[Request] => {request_msg}\n\t[Response] => {res}" + + +def api_method(func): + def wrapped(self, *args, **kwargs): + try: + method_description = func.__doc__.split("\n")[0] + except AttributeError: + raise RuntimeError("Api Method doesn't have a 'docstring' description") + + args_str = ", ".join(repr(a) for a in args) + kwargs_str = ", ".join(f"{k}={v}" for k, v in kwargs.items()) + request_msg = f"Called {func.__name__} with args ({args_str}) and kwargs ({kwargs_str})" + + r = func(self, *args, **kwargs) + log = make_request_and_response_log(method_description, request_msg, r) + log_api.info(log) + return r + + return wrapped + + +class ConnectorApi(RxConnector): + + def __init__(self, dsn): + super().__init__(dsn) + self.namespace = NamespaceApiMethods(self) + self.index = IndexesApiMethods(self) + self.item = ItemApiMethods(self) + self.query = QueryApiMethods(self) + self.meta = MetaApiMethods(self) + + +class NamespaceApiMethods: + def __init__(self, api): + self.api = api + + @api_method + def open(self, ns_name): + """ Open namespace """ + return self.api.namespace_open(ns_name) + + @api_method + def close(self, ns_name): + """ Close namespace """ + return self.api.namespace_close(ns_name) + + @api_method + def drop(self, ns_name): + """ Drop namespace """ + return self.api.namespace_drop(ns_name) + + @api_method + def enumerate(self, enum_not_opened=False): + """ Get namespaces list """ + return self.api.namespaces_enum(enum_not_opened) + + +class IndexesApiMethods: + def __init__(self, api): + self.api = api + + @api_method + def create(self, ns_name, index): + """ Add index """ + return self.api.index_add(ns_name, index) + + @api_method + def update(self, ns_name, index): + """ Update index """ + return self.api.index_update(ns_name, index) + + @api_method + def drop(self, ns_name, index_name): + """ Drop index """ + return self.api.index_drop(ns_name, index_name) + + +class ItemApiMethods: + def __init__(self, api): + self.api = api + + @api_method + def insert(self, ns_name, item, precepts=None): + """ Insert item """ + return self.api.item_insert(ns_name, item, precepts) + + @api_method + def upsert(self, ns_name, item, precepts=None): + """ Upsert item """ + return self.api.item_upsert(ns_name, item, precepts) + + @api_method + def update(self, ns_name, item, precepts=None): + """ Update item """ + return self.api.item_update(ns_name, item, precepts) + + @api_method + def delete(self, ns_name, item): + """ Delete item """ + return self.api.item_delete(ns_name, item) + + +class QueryApiMethods: + def __init__(self, api): + self.api = api + + @api_method + def sql(self, q): + """ Execute SQL query """ + return self.api.select(q) + + +class MetaApiMethods: + def __init__(self, api): + self.api = api + + @api_method + def put(self, ns_name, key, value): + """ Put meta with key and value """ + return self.api.meta_put(ns_name, key, value) + + @api_method + def get(self, ns_name, key): + """ Get meta by key """ + return self.api.meta_get(ns_name, key) + + @api_method + def enumerate(self, ns_name): + """ Get meta keys list """ + return self.api.meta_enum(ns_name) + + @api_method + def delete(self, ns_name, key): + """ Delete meta by key """ + return self.api.meta_delete(ns_name, key) diff --git a/pyreindexer/tests/helpers/base_helper.py b/pyreindexer/tests/helpers/base_helper.py new file mode 100644 index 0000000..e3a7bb2 --- /dev/null +++ b/pyreindexer/tests/helpers/base_helper.py @@ -0,0 +1,12 @@ +def get_ns_items(db, ns_name): + """ Get all items via sql query + """ + return list(db.query.sql(f"SELECT * FROM {ns_name}")) + + +def get_ns_description(db, ns_name): + """ Get information about namespace in database + """ + namespaces_list = db.namespace.enumerate() + ns_entry = [ns for ns in namespaces_list if ns["name"] == ns_name] + return ns_entry diff --git a/pyreindexer/tests/helpers/index.py b/pyreindexer/tests/helpers/index.py deleted file mode 100644 index dea0fe3..0000000 --- a/pyreindexer/tests/helpers/index.py +++ /dev/null @@ -1,28 +0,0 @@ -from tests.helpers.log_helper import log_operation - - -def create_index(namespace, index_def): - """ - Create an index - """ - db, namespace_name = namespace - log_operation.info(f"Create an index to namespace '{namespace_name}', index={index_def}") - db.index_add(namespace_name, index_def) - - -def update_index(namespace, index_def): - """ - Update an index - """ - db, namespace_name = namespace - log_operation.info(f"Update an index to namespace '{namespace_name}', new index={index_def}") - db.index_update(namespace_name, index_def) - - -def drop_index(namespace, index_name): - """ - Drop index from namespace - """ - db, namespace_name = namespace - log_operation.info(f"Drop index from namespace '{namespace_name}', index name = '{index_name}'") - db.index_drop(namespace_name, index_name) diff --git a/pyreindexer/tests/helpers/items.py b/pyreindexer/tests/helpers/items.py deleted file mode 100644 index c83dd26..0000000 --- a/pyreindexer/tests/helpers/items.py +++ /dev/null @@ -1,37 +0,0 @@ -from tests.helpers.log_helper import log_operation - - -def insert_item(namespace, item_def): - """ - Insert item to namespace - """ - db, namespace_name = namespace - log_operation.info(f"Insert item: {item_def} to namespace {namespace_name}") - db.item_insert(namespace_name, item_def) - - -def upsert_item(namespace, item_def): - """ - Insert or update item to namespace - """ - db, namespace_name = namespace - log_operation.info(f"Upsert item: {item_def} to namespace {namespace_name}") - db.item_upsert(namespace_name, item_def) - - -def update_item(namespace, item_def): - """ - Update item to namespace - """ - db, namespace_name = namespace - log_operation.info(f"Update item: {item_def} to namespace {namespace_name}") - db.item_upsert(namespace_name, item_def) - - -def delete_item(namespace, item_def): - """ - Delete item from namespace - """ - db, namespace_name = namespace - log_operation.info(f"Delete item: {item_def} from namespace {namespace_name}") - db.item_delete(namespace_name, item_def) diff --git a/pyreindexer/tests/helpers/log_helper.py b/pyreindexer/tests/helpers/log_helper.py index cc5dd4b..c4304b7 100644 --- a/pyreindexer/tests/helpers/log_helper.py +++ b/pyreindexer/tests/helpers/log_helper.py @@ -11,7 +11,7 @@ class OneLineExceptionFormatter(logging.Formatter): def formatException(self, exc_info): result = super(OneLineExceptionFormatter, self).formatException(exc_info) - return repr(result) # or format into one line however you want to + return repr(result) def format(self, record): result = super(OneLineExceptionFormatter, self).format(record) @@ -21,11 +21,11 @@ def format(self, record): # Create logger -log_operation = logging.getLogger('OPERATION') +log_api = logging.getLogger('API') log_fixture = logging.getLogger('FIXTURE') log_error = logging.getLogger('ERROR') -log_operation.setLevel(logging.INFO) +log_api.setLevel(logging.INFO) log_fixture.setLevel(logging.INFO) log_error.setLevel(logging.ERROR) @@ -41,5 +41,5 @@ def format(self, record): file_handler = logging.FileHandler(log_filename) file_handler.setLevel(logging.INFO) file_handler.setFormatter(formatter) -log_operation.addHandler(file_handler) +log_api.addHandler(file_handler) log_fixture.addHandler(file_handler) diff --git a/pyreindexer/tests/helpers/metadata.py b/pyreindexer/tests/helpers/metadata.py deleted file mode 100644 index 36a1622..0000000 --- a/pyreindexer/tests/helpers/metadata.py +++ /dev/null @@ -1,29 +0,0 @@ -from tests.helpers.log_helper import log_operation - - -def put_metadata(namespace, key, value): - db, namespace_name = namespace - log_operation.info(f"Put metadata '{key}: {value}' to namespace '{namespace_name}'") - db.meta_put(namespace_name, key, value) - return key, value - - -def get_metadata_keys(namespace): - db, namespace_name = namespace - log_operation.info("Get list of metadata keys") - meta_list = db.meta_enum(namespace_name) - return meta_list - - -def get_metadata_by_key(namespace, key): - db, namespace_name = namespace - value = db.meta_get(namespace_name, key) - log_operation.info(f"Get metadata value by key: '{key}: {value}'") - return value - - -def delete_metadata_by_key(namespace, key): - db, namespace_name = namespace - db.meta_delete(namespace_name, key) - log_operation.info(f"Delete metadata value from namespace '{namespace_name}' by key '{key}'") - return key diff --git a/pyreindexer/tests/helpers/namespace.py b/pyreindexer/tests/helpers/namespace.py deleted file mode 100644 index 04e6ee4..0000000 --- a/pyreindexer/tests/helpers/namespace.py +++ /dev/null @@ -1,45 +0,0 @@ -import logging - -from tests.helpers.log_helper import log_operation - - -def create_namespace(database, namespace_name): - """ - Create a namespace - """ - db, db_name = database - log_operation.info(f"Create a namespace with name '{namespace_name}' on database '{db_name}'") - try: - db.namespace_open(namespace_name) - except Exception as e: - logging.error(e) - - -def drop_namespace(database, namespace_name): - """ - Drop a namespace - """ - db, db_name = database - log_operation.info(f"Drop a namespace with name '{namespace_name}' on database '{db_name}'") - db.namespace_drop(namespace_name) - - -def get_namespace_list(database): - """ - Get list of namespaces in database - """ - log_operation.info("Get list of namespaces in database") - db, db_name = database - namespace_list = db.namespaces_enum() - return namespace_list - - -def get_ns_description(database, namespace): - """ - Get information about namespace in database - """ - db, namespace_name = namespace - namespace_list = get_namespace_list(database) - log_operation.info(f"Get information about namespace {namespace_name} in database") - ns_entry = list(filter(lambda ns: ns['name'] == namespace_name, namespace_list)) - return ns_entry diff --git a/pyreindexer/tests/helpers/sql.py b/pyreindexer/tests/helpers/sql.py deleted file mode 100644 index d12821c..0000000 --- a/pyreindexer/tests/helpers/sql.py +++ /dev/null @@ -1,8 +0,0 @@ -from tests.helpers.log_helper import log_operation - - -def sql_query(namespace, query): - db, namespace_name = namespace - item_list = list(db.select(query)) - log_operation.info(f"Execute SQL query: {query}, got result: {item_list}") - return item_list diff --git a/pyreindexer/tests/tests/test_database.py b/pyreindexer/tests/tests/test_database.py index 29e13db..76cf519 100644 --- a/pyreindexer/tests/tests/test_database.py +++ b/pyreindexer/tests/tests/test_database.py @@ -1,22 +1,19 @@ -import pyreindexer from hamcrest import * from tests.test_data.constants import special_namespaces, special_namespaces_cluster class TestCrudDb: - def test_create_db(self): - # Given ("Create empty database") - db_path = '/tmp/test_db' - db = pyreindexer.RxConnector('builtin://' + db_path) + def test_create_db(self, db): # When ("Get namespaces list in created database") - namespace_list = db.namespaces_enum() + namespaces_list = db.namespace.enumerate() # Then ("Check that database contains only special namespaces") - expect_namespaces = special_namespaces - if len(namespace_list) == len(special_namespaces_cluster): - expect_namespaces = special_namespaces_cluster - for namespace in expect_namespaces: - assert_that(namespace_list, has_item(has_entries("name", equal_to(namespace["name"]))), - "Database doesn't contain special namespaces") - assert_that(namespace_list, has_length(equal_to(len(expect_namespaces))), + if len(namespaces_list) == len(special_namespaces_cluster): + expected_namespaces = special_namespaces_cluster # v4 + else: + expected_namespaces = special_namespaces # v3 + assert_that(namespaces_list, has_length(len(expected_namespaces)), "Database doesn't contain special namespaces") + for namespace in expected_namespaces: + assert_that(namespaces_list, has_item(has_entries(name=namespace["name"])), + "Database doesn't contain special namespaces") diff --git a/pyreindexer/tests/tests/test_index.py b/pyreindexer/tests/tests/test_index.py index bc3b973..5887e75 100644 --- a/pyreindexer/tests/tests/test_index.py +++ b/pyreindexer/tests/tests/test_index.py @@ -1,72 +1,67 @@ from hamcrest import * -from tests.helpers.index import * -from tests.helpers.namespace import get_ns_description +from tests.helpers.base_helper import get_ns_description from tests.test_data.constants import index_definition, updated_index_definition class TestCrudIndexes: - def test_initial_namespace_has_no_indexes(self, database, namespace): + def test_initial_namespace_has_no_indexes(self, db, namespace): # Given("Create namespace") # When ("Get namespace information") - ns_entry = get_ns_description(database, namespace) + ns_entry = get_ns_description(db, namespace) # Then ("Check that list of indexes in namespace is empty") - assert_that(ns_entry, has_item(has_entry("indexes", equal_to([]))), - "Index is not empty") + assert_that(ns_entry, has_item(has_entry("indexes", empty())), "Index is not empty") - def test_create_index(self, database, namespace): + def test_create_index(self, db, namespace): # Given("Create namespace") # When ("Add index") - create_index(namespace, index_definition) + db.index.create(namespace, index_definition) # Then ("Check that index is added") - ns_entry = get_ns_description(database, namespace) - assert_that(ns_entry, has_item(has_entry("indexes", has_item(equal_to(index_definition)))), + ns_entry = get_ns_description(db, namespace) + assert_that(ns_entry, has_item(has_entry("indexes", has_item(index_definition))), "Index wasn't created") - drop_index(namespace, 'id') + db.index.drop(namespace, 'id') - def test_update_index(self, database, namespace, index): + def test_update_index(self, db, namespace, index): # Given("Create namespace with index") # When ("Update index") - update_index(namespace, updated_index_definition) + db.index.update(namespace, updated_index_definition) # Then ("Check that index is updated") - ns_entry = get_ns_description(database, namespace) - assert_that(ns_entry, has_item(has_entry("indexes", has_item(equal_to(updated_index_definition)))), + ns_entry = get_ns_description(db, namespace) + assert_that(ns_entry, has_item(has_entry("indexes", has_item(updated_index_definition))), "Index wasn't updated") - def test_delete_index(self, database, namespace): + def test_delete_index(self, db, namespace): # Given("Create namespace with index") - create_index(namespace, index_definition) + db.index.create(namespace, index_definition) # When ("Delete index") - drop_index(namespace, 'id') + db.index.drop(namespace, 'id') # Then ("Check that index is deleted") - ns_entry = get_ns_description(database, namespace) - assert_that(ns_entry, has_item(has_entry("indexes", equal_to([]))), - "Index wasn't deleted") + ns_entry = get_ns_description(db, namespace) + assert_that(ns_entry, has_item(has_entry("indexes", empty())), "Index wasn't deleted") - def test_cannot_add_index_with_same_name(self, database, namespace): + def test_cannot_add_index_with_same_name(self, db, namespace): # Given("Create namespace") # When ("Add index") - create_index(namespace, index_definition) + db.index.create(namespace, index_definition) # Then ("Check that we can't add index with the same name") - assert_that(calling(create_index).with_args(namespace, updated_index_definition), - raises(Exception, matching=has_string(string_contains_in_order( - "Index", "already exists with different settings"))), + assert_that(calling(db.index.create).with_args(namespace, updated_index_definition), + raises(Exception, pattern="Index '.*' already exists with different settings"), "Index with existing name was created") - def test_cannot_update_not_existing_index_in_namespace(self, database, namespace): + def test_cannot_update_not_existing_index_in_namespace(self, db, namespace): # Given ("Create namespace") - db, namespace_name = namespace # When ("Update index") # Then ("Check that we can't update index that was not created") - assert_that(calling(update_index).with_args(namespace, index_definition), - raises(Exception, matching=has_string(f"Index 'id' not found in '{namespace_name}'")), + assert_that(calling(db.index.update).with_args(namespace, index_definition), + raises(Exception, pattern=f"Index 'id' not found in '{namespace}'"), "Not existing index was updated") - def test_cannot_delete_not_existing_index_in_namespace(self, database, namespace): + def test_cannot_delete_not_existing_index_in_namespace(self, db, namespace): # Given ("Create namespace") # When ("Delete index") # Then ("Check that we can't delete index that was not created") index_name = 'id' - assert_that(calling(drop_index).with_args(namespace, index_name), - raises(Exception, matching=has_string(f"Cannot remove index {index_name}: doesn't exist")), + assert_that(calling(db.index.drop).with_args(namespace, index_name), + raises(Exception, pattern=f"Cannot remove index {index_name}: doesn't exist"), "Not existing index was deleted") diff --git a/pyreindexer/tests/tests/test_items.py b/pyreindexer/tests/tests/test_items.py index d732051..151d1d3 100644 --- a/pyreindexer/tests/tests/test_items.py +++ b/pyreindexer/tests/tests/test_items.py @@ -1,94 +1,71 @@ from hamcrest import * -from tests.helpers.items import * +from tests.helpers.base_helper import get_ns_items from tests.test_data.constants import item_definition class TestCrudItems: - def test_initial_namespace_has_no_items(self, namespace, index): + def test_initial_namespace_has_no_items(self, db, namespace, index): # Given("Create namespace with index") - db, namespace_name = namespace # When ("Get namespace information") - select_result = list(db.select(f'SELECT * FROM {namespace_name}')) + select_result = get_ns_items(db, namespace) # Then ("Check that list of items in namespace is empty") - assert_that(select_result, has_length(0), "Item list is not empty") - assert_that(select_result, equal_to([]), "Item list is not empty") + assert_that(select_result, empty(), "Item list is not empty") - def test_create_item_insert(self, namespace, index): + def test_create_item_insert(self, db, namespace, index): # Given("Create namespace with index") - db, namespace_name = namespace # When ("Insert item into namespace") - insert_item(namespace, item_definition) + db.item.insert(namespace, item_definition) # Then ("Check that item is added") - select_result = list(db.select(f'SELECT * FROM {namespace_name}')) - assert_that(select_result, has_length(1), - "Item wasn't created") - assert_that(select_result, has_item(item_definition), - "Item wasn't created" - ) - delete_item(namespace, item_definition) + select_result = get_ns_items(db, namespace) + assert_that(select_result, has_length(1), "Item wasn't created") + assert_that(select_result, has_item(item_definition), "Item wasn't created") - def test_create_item_insert_with_precepts(self, namespace, index): + def test_create_item_insert_with_precepts(self, db, namespace, index): # Given("Create namespace with index") - db, namespace_name = namespace # When ("Insert items into namespace") number_items = 5 for _ in range(number_items): - db.item_insert(namespace_name, {"id": 100, "field": "value"}, ["id=serial()"]) + db.item_insert(namespace, {"id": 100, "field": "value"}, ["id=serial()"]) # Then ("Check that item is added") - select_result = list(db.select(f'SELECT * FROM {namespace_name}')) - assert_that(select_result, has_length(number_items), - "Items wasn't created") + select_result = get_ns_items(db, namespace) + assert_that(select_result, has_length(number_items), "Items wasn't created") for i in range(number_items): - assert_that(select_result[i], equal_to({'id': i + 1, "field": "value"}), - "Items wasn't created") - for i in range(number_items): - db.item_delete(namespace_name, {'id': i}) + assert_that(select_result[i], equal_to({'id': i + 1, "field": "value"}), "Items wasn't created") - def test_create_item_upsert(self, namespace, index): + def test_create_item_upsert(self, db, namespace, index): # Given("Create namespace with index") - db, namespace_name = namespace # When ("Upsert item into namespace") - upsert_item(namespace, item_definition) + db.item.upsert(namespace, item_definition) # Then ("Check that item is added") - select_result = list(db.select(f'SELECT * FROM {namespace_name}')) - assert_that(select_result, has_length(1), - "Item wasn't created") - assert_that(select_result, has_item(item_definition), - "Item wasn't created") - delete_item(namespace, item_definition) + select_result = get_ns_items(db, namespace) + assert_that(select_result, has_length(1), "Item wasn't created") + assert_that(select_result, has_item(item_definition), "Item wasn't created") - def test_update_item_upsert(self, namespace, index, item): + def test_update_item_upsert(self, db, namespace, index, item): # Given("Create namespace with item") - db, namespace_name = namespace # When ("Upsert item") item_definition_updated = {'id': 100, 'val': "new_value"} - upsert_item(namespace, item_definition_updated) + db.item.upsert(namespace, item_definition_updated) # Then ("Check that item is updated") - select_result = list(db.select(f'SELECT * FROM {namespace_name}')) - assert_that(select_result, has_length(1), - "Item wasn't updated") - assert_that(select_result, has_item(item_definition_updated), - "Item wasn't updated") + select_result = get_ns_items(db, namespace) + assert_that(select_result, has_length(1), "Item wasn't updated") + assert_that(select_result, has_item(item_definition_updated), "Item wasn't updated") - def test_update_item_update(self, namespace, index, item): + def test_update_item_update(self, db, namespace, index, item): # Given("Create namespace with item") - db, namespace_name = namespace # When ("Update item") item_definition_updated = {'id': 100, 'val': "new_value"} - update_item(namespace, item_definition_updated) + db.item.update(namespace, item_definition_updated) # Then ("Check that item is updated") - select_result = list(db.select(f'SELECT * FROM {namespace_name}')) + select_result = get_ns_items(db, namespace) assert_that(select_result, has_length(1), "Item wasn't updated") assert_that(select_result, has_item(item_definition_updated), "Item wasn't updated") - def test_delete_item(self, namespace, index): + def test_delete_item(self, db, namespace, index, item): # Given("Create namespace with item") - db, namespace_name = namespace - insert_item(namespace, item_definition) # When ("Delete item") - delete_item(namespace, item_definition) + db.item.delete(namespace, item_definition) # Then ("Check that item is deleted") - select_result = list(db.select(f'SELECT * FROM {namespace_name}')) - assert_that(select_result, has_length(0), "Item wasn't deleted") - assert_that(select_result, equal_to([]), "Item wasn't deleted") + select_result = get_ns_items(db, namespace) + assert_that(select_result, empty(), "Item wasn't deleted") diff --git a/pyreindexer/tests/tests/test_metadata.py b/pyreindexer/tests/tests/test_metadata.py index 22519f7..f37b511 100644 --- a/pyreindexer/tests/tests/test_metadata.py +++ b/pyreindexer/tests/tests/test_metadata.py @@ -1,63 +1,59 @@ from hamcrest import * -from tests.helpers.metadata import * - class TestCrudMetadata: - def test_initial_namespace_has_no_metadata(self, namespace): + def test_initial_namespace_has_no_metadata(self, db, namespace): # Given("Create namespace") # When ("Get list of metadata keys") - meta_list = get_metadata_keys(namespace) + meta_list = db.meta.enumerate(namespace) # Then ("Check that list of metadata is empty") - assert_that(meta_list, has_length(0), "Metadata is not empty") - assert_that(meta_list, equal_to([]), "Metadata is not empty") + assert_that(meta_list, empty(), "Metadata is not empty") - def test_create_metadata(self, namespace): + def test_create_metadata(self, db, namespace): # Given("Create namespace") # When ("Put metadata to namespace") key, value = 'key', 'value' - put_metadata(namespace, key, value) + db.meta.put(namespace, key, value) # Then ("Check that metadata was added") - meta_list = get_metadata_keys(namespace) + meta_list = db.meta.enumerate(namespace) assert_that(meta_list, has_length(1), "Metadata is not created") assert_that(meta_list, has_item(key), "Metadata is not created") - def test_get_metadata_by_key(self, namespace, metadata): + def test_get_metadata_by_key(self, db, namespace, metadata): # Given ("Put metadata to namespace") meta_key, meta_value = metadata # When ("Get metadata by key") - value = get_metadata_by_key(namespace, meta_key) + value = db.meta.get(namespace, meta_key) # Then ("Check that metadata was added") assert_that(value, equal_to(meta_value), "Can't get meta value by key") - def test_get_metadata_keys(self, namespace, metadata): + def test_get_metadata_keys(self, db, namespace, metadata): # Given ("Put metadata to namespace") meta_key, meta_value = metadata # When ("Get list of metadata keys") - meta_list = get_metadata_keys(namespace) + meta_list = db.meta.enumerate(namespace) # Then ("Check that metadata was added") assert_that(meta_list, has_item(meta_key), "Can't get list of meta keys") - def test_update_metadata(self, namespace, metadata): + def test_update_metadata(self, db, namespace, metadata): # Given ("Put metadata to namespace") meta_key, meta_value = metadata # When ("Update metadata") new_meta_value = 'new_value' - put_metadata(namespace, meta_key, new_meta_value) + db.meta.put(namespace, meta_key, new_meta_value) # Then ("Check that metadata was updated") - updated_value = get_metadata_by_key(namespace, meta_key) + updated_value = db.meta.get(namespace, meta_key) assert_that(updated_value, equal_to(new_meta_value), "Can't update metadata") - def test_delete_metadata(self, namespace, metadata): + def test_delete_metadata(self, db, namespace, metadata): # Given ("Put metadata to namespace") meta_key, meta_value = metadata # When ("Delete metadata") - delete_metadata_by_key(namespace, meta_key) + db.meta.delete(namespace, meta_key) # Then ("Check that metadata was removed") - read_value = get_metadata_by_key(namespace, meta_key) + read_value = db.meta.get(namespace, meta_key) assert_that(read_value, equal_to(''), "Can't delete metadata") # When ("Get list of metadata keys") - meta_list = get_metadata_keys(namespace) + meta_list = db.meta.enumerate(namespace) # Then ("Check that list of metadata is empty") - assert_that(meta_list, has_length(0), "Metadata is not empty") - assert_that(meta_list, equal_to([]), "Metadata is not empty") + assert_that(meta_list, empty(), "Metadata is not empty") diff --git a/pyreindexer/tests/tests/test_namespace.py b/pyreindexer/tests/tests/test_namespace.py index d18340d..feee497 100644 --- a/pyreindexer/tests/tests/test_namespace.py +++ b/pyreindexer/tests/tests/test_namespace.py @@ -1,36 +1,33 @@ from hamcrest import * -from tests.helpers.namespace import * - class TestCrudNamespace: - def test_create_ns(self, database): + + def test_create_ns(self, db): # Given("Create namespace in empty database") - namespace_name = 'test_ns' - create_namespace(database, namespace_name) + namespace_name = 'test_ns1' + db.namespace.open(namespace_name) # When ("Get namespaces list in created database") - namespace_list = get_namespace_list(database) + namespace_list = db.namespace.enumerate() # Then ("Check that database contains created namespace") - assert_that(namespace_list, has_item(has_entry("name", equal_to(namespace_name))), + assert_that(namespace_list, has_item(has_entries(name=namespace_name)), "Namespace wasn't created") - drop_namespace(database, namespace_name) + db.namespace.drop(namespace_name) - def test_delete_ns(self, database): - # Given("Create namespace") - namespace_name = 'test_ns' - create_namespace(database, namespace_name) + def test_delete_ns(self, db): + # Given("Create namespace in empty database") + namespace_name = 'test_ns2' + db.namespace.open(namespace_name) # When ("Delete namespace") - drop_namespace(database, namespace_name) + db.namespace.drop(namespace_name) # Then ("Check that namespace was deleted") - namespace_list = get_namespace_list(database) - assert_that(namespace_list, not_(has_item(has_entry("name", equal_to(namespace_name)))), + namespace_list = db.namespace.enumerate() + assert_that(namespace_list, not_(has_item(has_entries(name=namespace_name))), "Namespace wasn't deleted") - def test_cannot_delete_ns_not_created(self, database): - # Given ("Create empty database") + def test_cannot_delete_ns_not_created(self, db): + # Given ("Created empty database") # Then ("Check that we cannot delete namespace that does not exist") namespace_name = 'test_ns' - assert_that(calling(drop_namespace).with_args(database, namespace_name), raises(Exception, matching=has_string( - f"Namespace '{namespace_name}' does not exist"))) - - + assert_that(calling(db.namespace.drop).with_args(namespace_name), + raises(Exception, pattern=f"Namespace '{namespace_name}' does not exist")) diff --git a/pyreindexer/tests/tests/test_sql.py b/pyreindexer/tests/tests/test_sql.py index cf9d0bf..d370220 100644 --- a/pyreindexer/tests/tests/test_sql.py +++ b/pyreindexer/tests/tests/test_sql.py @@ -1,80 +1,72 @@ from hamcrest import * -from tests.helpers.sql import sql_query - class TestSqlQueries: - def test_sql_select(self, namespace, index, item): + def test_sql_select(self, db, namespace, index, item): # Given("Create namespace with item") - db, namespace_name = namespace - item_definition = item # When ("Execute SQL query SELECT") - query = f'SELECT * FROM {namespace_name}' - item_list = sql_query(namespace, query) + query = f"SELECT * FROM {namespace}" + items_list = list(db.query.sql(query)) # Then ("Check that selected item is in result") - assert_that(item_list, has_item(equal_to(item_definition)), "Can't SQL select data") + assert_that(items_list, equal_to([item]), "Can't SQL select data") - def test_sql_select_with_join(self, namespace, second_namespace_for_join, index, items): + def test_sql_select_with_join(self, db, namespace, second_namespace_for_join, index, items): # Given("Create two namespaces") - db, namespace_name = namespace - second_namespace_name, second_ns_item_definition_join = second_namespace_for_join + second_namespace, second_ns_item_definition_join = second_namespace_for_join # When ("Execute SQL query SELECT with JOIN") - query = f'SELECT id FROM {namespace_name} INNER JOIN {second_namespace_name} ON {namespace_name}.id = {second_namespace_name}.id' - item_list = sql_query(namespace, query) + query = f"SELECT id FROM {namespace} INNER JOIN {second_namespace} " \ + f"ON {namespace}.id = {second_namespace}.id" + item_list = list(db.query.sql(query)) # Then ("Check that selected item is in result") - assert_that(item_list, - has_item(equal_to({'id': 1, f'joined_{second_namespace_name}': [second_ns_item_definition_join]})), + item_with_joined = {'id': 1, f'joined_{second_namespace}': [second_ns_item_definition_join]} + assert_that(item_list, equal_to([item_with_joined]), "Can't SQL select data with JOIN") - def test_sql_select_with_condition(self, namespace, index, items): + def test_sql_select_with_condition(self, db, namespace, index, items): # Given("Create namespace with item") - db, namespace_name = namespace # When ("Execute SQL query SELECT") - query = f'SELECT * FROM {namespace_name} WHERE id=3' - item_list = sql_query(namespace, query) + item_id = 3 + query = f"SELECT * FROM {namespace} WHERE id = {item_id}" + items_list = list(db.query.sql(query)) # Then ("Check that selected item is in result") - assert_that(item_list, has_item(equal_to({'id': 3, 'val': 'testval3'})), "Can't SQL select data with condition") + assert_that(items_list, equal_to([items[item_id]]), "Can't SQL select data with condition") - def test_sql_update(self, namespace, index, item): + def test_sql_update(self, db, namespace, index, item): # Given("Create namespace with item") - db, namespace_name = namespace # When ("Execute SQL query UPDATE") - query = f"UPDATE {namespace_name} SET \"val\" = 'new_val' WHERE id = 100" - item_list = sql_query(namespace, query) + item["val"] = "new_val" + query = f"UPDATE {namespace} SET \"val\" = '{item['val']}' WHERE id = 100" + items_list = list(db.query.sql(query)) # Then ("Check that item is updated") - assert_that(item_list, has_item(equal_to({'id': 100, 'val': 'new_val'})), "Can't SQL update data") + assert_that(items_list, equal_to([item]), "Can't SQL update data") - def test_sql_delete(self, namespace, index, item): + def test_sql_delete(self, db, namespace, index, item): # Given("Create namespace with item") - db, namespace_name = namespace # When ("Execute SQL query DELETE") - query_delete = f"DELETE FROM {namespace_name} WHERE id = 100" - sql_query(namespace, query_delete) + query_delete = f"DELETE FROM {namespace} WHERE id = 100" + db.query.sql(query_delete) # Then ("Check that item is deleted") - query_select = f"SELECT * FROM {namespace_name}" - item_list = sql_query(namespace, query_select) - assert_that(item_list, equal_to([]), "Can't SQL delete data") + query_select = f"SELECT * FROM {namespace}" + item_list = list(db.query.sql(query_select)) + assert_that(item_list, empty(), "Can't SQL delete data") - def test_sql_select_with_syntax_error(self, namespace, index, item): + def test_sql_select_with_syntax_error(self, db, namespace, index, item): # Given("Create namespace with item") # When ("Execute SQL query SELECT with incorrect syntax") - query = 'SELECT *' + query = "SELECT *" # Then ("Check that selected item is in result") - assert_that(calling(sql_query).with_args(namespace, query), - raises(Exception, matching=has_string(string_contains_in_order( - "Expected", "but found"))), "Error wasn't raised when syntax was incorrect") + assert_that(calling(db.query.sql).with_args(query), + raises(Exception, pattern="Expected .* but found"), + "Error wasn't raised when syntax was incorrect") - def test_sql_select_with_aggregations(self, namespace, index, items): + def test_sql_select_with_aggregations(self, db, namespace, index, items): # Given("Create namespace with item") - db, namespace_name = namespace # When ("Insert items into namespace") - for _ in range(5): - db.item_insert(namespace_name, {"id": 100}, ["id=serial()"]) - - select_result = db.select(f'SELECT min(id), max(id), avg(id) FROM {namespace_name}').get_agg_results() - assert_that(len(select_result), 3, "The aggregation result must contain 3 elements") + select_result = db.query.sql(f"SELECT min(id), max(id), avg(id), sum(id) FROM {namespace}").get_agg_results() + assert_that(select_result, has_length(4), "The aggregation result does not contain all aggregations") - expected_values = {"min":1,"max":10,"avg":5.5} + ids = [i["id"] for i in items] + expected_values = {"min": min(ids), "max": max(ids), "avg": sum(ids) / len(items), "sum": sum(ids)} # Then ("Check that returned agg results are correct") for agg in select_result: diff --git a/setup.py b/setup.py index adff914..6488ef1 100644 --- a/setup.py +++ b/setup.py @@ -52,7 +52,7 @@ def build_cmake(self, ext): setup(name=PACKAGE_NAME, - version='0.2.38', + version='0.2.42', description='A connector that allows to interact with Reindexer', author='Igor Tulmentyev', author_email='igtulm@gmail.com', @@ -73,32 +73,12 @@ def build_cmake(self, ext): keywords=["reindexer", "in-memory-database", "database", "python", "connector"], package_data={'pyreindexer': [ 'CMakeLists.txt', - 'lib/include/pyobjtools.h', - 'lib/include/pyobjtools.cc', - 'lib/include/queryresults_wrapper.h', - 'lib/src/rawpyreindexer.h', - 'lib/src/rawpyreindexer.cc', - 'lib/src/reindexerinterface.h', - 'lib/src/reindexerinterface.cc', + 'lib/include/*.h', + 'lib/include/*.cc', + 'lib/src/*.h', + 'lib/src/*.cc', 'example/main.py', - 'tests/conftest.py', - 'tests/test_data/constants.py', - 'tests/test_data/__init__.py', - 'tests/tests/test_sql.py', - 'tests/tests/test_index.py', - 'tests/tests/test_items.py', - 'tests/tests/test_database.py', - 'tests/tests/test_namespace.py', - 'tests/tests/test_metadata.py', - 'tests/tests/__init__.py', - 'tests/helpers/namespace.py', - 'tests/helpers/sql.py', - 'tests/helpers/items.py', - 'tests/helpers/index.py', - 'tests/helpers/metadata.py', - 'tests/helpers/log_helper.py', - 'tests/helpers/__init__.py', - 'tests/__init__.py' + 'tests/**/*.py' ]}, python_requires=">=3.6,<3.13", test_suite='tests',