diracx-testing 0.0.1a23__py3-none-any.whl → 0.0.1a25__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- diracx/testing/__init__.py +42 -746
- diracx/testing/entrypoints.py +67 -0
- diracx/testing/mock_osdb.py +19 -14
- diracx/testing/utils.py +704 -0
- {diracx_testing-0.0.1a23.dist-info → diracx_testing-0.0.1a25.dist-info}/METADATA +2 -2
- diracx_testing-0.0.1a25.dist-info/RECORD +11 -0
- {diracx_testing-0.0.1a23.dist-info → diracx_testing-0.0.1a25.dist-info}/WHEEL +1 -1
- diracx_testing-0.0.1a23.dist-info/RECORD +0 -9
- {diracx_testing-0.0.1a23.dist-info → diracx_testing-0.0.1a25.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,67 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import tomllib
|
4
|
+
from collections import defaultdict
|
5
|
+
from importlib.metadata import PackageNotFoundError, distribution, entry_points
|
6
|
+
|
7
|
+
import pytest
|
8
|
+
|
9
|
+
|
10
|
+
def get_installed_entry_points():
|
11
|
+
"""Retrieve the installed entry points from the environment."""
|
12
|
+
entry_pts = entry_points()
|
13
|
+
diracx_eps = defaultdict(dict)
|
14
|
+
for group in entry_pts.groups:
|
15
|
+
if "diracx" in group:
|
16
|
+
for ep in entry_pts.select(group=group):
|
17
|
+
diracx_eps[group][ep.name] = ep.value
|
18
|
+
return dict(diracx_eps)
|
19
|
+
|
20
|
+
|
21
|
+
def get_entry_points_from_toml(toml_file):
|
22
|
+
"""Parse entry points from pyproject.toml."""
|
23
|
+
with open(toml_file, "rb") as f:
|
24
|
+
pyproject = tomllib.load(f)
|
25
|
+
package_name = pyproject["project"]["name"]
|
26
|
+
return package_name, pyproject.get("project", {}).get("entry-points", {})
|
27
|
+
|
28
|
+
|
29
|
+
def get_current_entry_points(repo_base) -> bool:
|
30
|
+
"""Create current entry points dict for comparison."""
|
31
|
+
current_eps = {}
|
32
|
+
for toml_file in repo_base.glob("diracx-*/pyproject.toml"):
|
33
|
+
package_name, entry_pts = get_entry_points_from_toml(f"{toml_file}")
|
34
|
+
# Ignore packages that are not installed
|
35
|
+
try:
|
36
|
+
distribution(package_name)
|
37
|
+
except PackageNotFoundError:
|
38
|
+
continue
|
39
|
+
# Merge the entry points
|
40
|
+
for key, value in entry_pts.items():
|
41
|
+
current_eps[key] = current_eps.get(key, {}) | value
|
42
|
+
return current_eps
|
43
|
+
|
44
|
+
|
45
|
+
@pytest.fixture(scope="session", autouse=True)
|
46
|
+
def verify_entry_points(request, pytestconfig):
|
47
|
+
try:
|
48
|
+
ini_toml_name = tomllib.loads(pytestconfig.inipath.read_text())["project"][
|
49
|
+
"name"
|
50
|
+
]
|
51
|
+
except tomllib.TOMLDecodeError:
|
52
|
+
return
|
53
|
+
if ini_toml_name == "diracx":
|
54
|
+
repo_base = pytestconfig.inipath.parent
|
55
|
+
elif ini_toml_name.startswith("diracx-"):
|
56
|
+
repo_base = pytestconfig.inipath.parent.parent
|
57
|
+
else:
|
58
|
+
return
|
59
|
+
|
60
|
+
installed_eps = get_installed_entry_points()
|
61
|
+
current_eps = get_current_entry_points(repo_base)
|
62
|
+
|
63
|
+
if installed_eps != current_eps:
|
64
|
+
pytest.fail(
|
65
|
+
"Project and installed entry-points are not consistent. "
|
66
|
+
"You should run `pip install -r requirements-dev.txt`",
|
67
|
+
)
|
diracx/testing/mock_osdb.py
CHANGED
@@ -42,8 +42,8 @@ class MockOSDBMixin:
|
|
42
42
|
from diracx.db.sql.utils import DateNowColumn
|
43
43
|
|
44
44
|
# Dynamically create a subclass of BaseSQLDB so we get clearer errors
|
45
|
-
|
46
|
-
self._sql_db =
|
45
|
+
mocked_db = type(f"Mocked{self.__class__.__name__}", (sql_utils.BaseSQLDB,), {})
|
46
|
+
self._sql_db = mocked_db(connection_kwargs["sqlalchemy_dsn"])
|
47
47
|
|
48
48
|
# Dynamically create the table definition based on the fields
|
49
49
|
columns = [
|
@@ -53,16 +53,16 @@ class MockOSDBMixin:
|
|
53
53
|
for field, field_type in self.fields.items():
|
54
54
|
match field_type["type"]:
|
55
55
|
case "date":
|
56
|
-
|
56
|
+
column_type = DateNowColumn
|
57
57
|
case "long":
|
58
|
-
|
58
|
+
column_type = partial(Column, type_=Integer)
|
59
59
|
case "keyword":
|
60
|
-
|
60
|
+
column_type = partial(Column, type_=String(255))
|
61
61
|
case "text":
|
62
|
-
|
62
|
+
column_type = partial(Column, type_=String(64 * 1024))
|
63
63
|
case _:
|
64
64
|
raise NotImplementedError(f"Unknown field type: {field_type=}")
|
65
|
-
columns.append(
|
65
|
+
columns.append(column_type(field, default=None))
|
66
66
|
self._sql_db.metadata = MetaData()
|
67
67
|
self._table = Table("dummy", self._sql_db.metadata, *columns)
|
68
68
|
|
@@ -72,18 +72,22 @@ class MockOSDBMixin:
|
|
72
72
|
yield
|
73
73
|
|
74
74
|
async def __aenter__(self):
|
75
|
-
|
75
|
+
"""Enter the request context.
|
76
|
+
|
77
|
+
This is a no-op as the real OpenSearch class doesn't use transactions.
|
78
|
+
Instead we enter a transaction in each method that needs it.
|
79
|
+
"""
|
76
80
|
return self
|
77
81
|
|
78
82
|
async def __aexit__(self, exc_type, exc_value, traceback):
|
79
|
-
|
83
|
+
pass
|
80
84
|
|
81
85
|
async def create_index_template(self) -> None:
|
82
86
|
async with self._sql_db.engine.begin() as conn:
|
83
87
|
await conn.run_sync(self._sql_db.metadata.create_all)
|
84
88
|
|
85
89
|
async def upsert(self, doc_id, document) -> None:
|
86
|
-
async with self:
|
90
|
+
async with self._sql_db:
|
87
91
|
values = {}
|
88
92
|
for key, value in document.items():
|
89
93
|
if key in self.fields:
|
@@ -106,7 +110,7 @@ class MockOSDBMixin:
|
|
106
110
|
per_page: int = 100,
|
107
111
|
page: int | None = None,
|
108
112
|
) -> tuple[int, list[dict[Any, Any]]]:
|
109
|
-
async with self:
|
113
|
+
async with self._sql_db:
|
110
114
|
# Apply selection
|
111
115
|
if parameters:
|
112
116
|
columns = []
|
@@ -150,7 +154,8 @@ class MockOSDBMixin:
|
|
150
154
|
return results
|
151
155
|
|
152
156
|
async def ping(self):
|
153
|
-
|
157
|
+
async with self._sql_db:
|
158
|
+
return await self._sql_db.ping()
|
154
159
|
|
155
160
|
|
156
161
|
def fake_available_osdb_implementations(name, *, real_available_implementations):
|
@@ -158,6 +163,6 @@ def fake_available_osdb_implementations(name, *, real_available_implementations)
|
|
158
163
|
|
159
164
|
# Dynamically generate a class that inherits from the first implementation
|
160
165
|
# but that also has the MockOSDBMixin
|
161
|
-
|
166
|
+
mock_parameter_db = type(name, (MockOSDBMixin, implementations[0]), {})
|
162
167
|
|
163
|
-
return [
|
168
|
+
return [mock_parameter_db] + implementations
|