Skip to content

Commit

Permalink
[ref] refactor tests (#15)
Browse files Browse the repository at this point in the history
Refactor tests

---------

Co-authored-by: Nikita Bushmakin <[email protected]>
  • Loading branch information
NikitaEvgen and Nikita Bushmakin authored Nov 8, 2024
1 parent 5effedf commit 169056c
Show file tree
Hide file tree
Showing 16 changed files with 336 additions and 407 deletions.
73 changes: 31 additions & 42 deletions pyreindexer/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -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
141 changes: 141 additions & 0 deletions pyreindexer/tests/helpers/api.py
Original file line number Diff line number Diff line change
@@ -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)
12 changes: 12 additions & 0 deletions pyreindexer/tests/helpers/base_helper.py
Original file line number Diff line number Diff line change
@@ -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
28 changes: 0 additions & 28 deletions pyreindexer/tests/helpers/index.py

This file was deleted.

37 changes: 0 additions & 37 deletions pyreindexer/tests/helpers/items.py

This file was deleted.

8 changes: 4 additions & 4 deletions pyreindexer/tests/helpers/log_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)

Expand All @@ -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)
Loading

0 comments on commit 169056c

Please sign in to comment.