diracx-testing 0.0.1a24__py3-none-any.whl → 0.0.1a26__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- diracx/testing/mock_osdb.py +10 -5
- diracx/testing/utils.py +41 -22
- {diracx_testing-0.0.1a24.dist-info → diracx_testing-0.0.1a26.dist-info}/METADATA +2 -1
- {diracx_testing-0.0.1a24.dist-info → diracx_testing-0.0.1a26.dist-info}/RECORD +6 -6
- {diracx_testing-0.0.1a24.dist-info → diracx_testing-0.0.1a26.dist-info}/WHEEL +0 -0
- {diracx_testing-0.0.1a24.dist-info → diracx_testing-0.0.1a26.dist-info}/top_level.txt +0 -0
diracx/testing/mock_osdb.py
CHANGED
@@ -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):
|
diracx/testing/utils.py
CHANGED
@@ -18,8 +18,8 @@ from typing import TYPE_CHECKING, Generator
|
|
18
18
|
from urllib.parse import parse_qs, urljoin, urlparse
|
19
19
|
from uuid import uuid4
|
20
20
|
|
21
|
+
import httpx
|
21
22
|
import pytest
|
22
|
-
import requests
|
23
23
|
|
24
24
|
if TYPE_CHECKING:
|
25
25
|
from diracx.core.settings import DevelopmentSettings
|
@@ -252,6 +252,7 @@ class ClientFactory:
|
|
252
252
|
assert (
|
253
253
|
self.app.dependency_overrides == {} and self.app.lifetime_functions == []
|
254
254
|
), "configure cannot be nested"
|
255
|
+
|
255
256
|
for k, v in self.all_dependency_overrides.items():
|
256
257
|
|
257
258
|
class_name = k.__self__.__name__
|
@@ -284,17 +285,26 @@ class ClientFactory:
|
|
284
285
|
import sqlalchemy
|
285
286
|
from sqlalchemy.util.concurrency import greenlet_spawn
|
286
287
|
|
288
|
+
from diracx.db.os.utils import BaseOSDB
|
287
289
|
from diracx.db.sql.utils import BaseSQLDB
|
290
|
+
from diracx.testing.mock_osdb import MockOSDBMixin
|
288
291
|
|
289
292
|
for k, v in self.app.dependency_overrides.items():
|
290
|
-
# Ignore dependency overrides which aren't BaseSQLDB.transaction
|
291
|
-
if (
|
292
|
-
|
293
|
-
|
293
|
+
# Ignore dependency overrides which aren't BaseSQLDB.transaction or BaseOSDB.session
|
294
|
+
if isinstance(v, UnavailableDependency) or k.__func__ not in (
|
295
|
+
BaseSQLDB.transaction.__func__,
|
296
|
+
BaseOSDB.session.__func__,
|
294
297
|
):
|
298
|
+
|
295
299
|
continue
|
300
|
+
|
296
301
|
# The first argument of the overridden BaseSQLDB.transaction is the DB object
|
297
302
|
db = v.args[0]
|
303
|
+
# We expect the OS DB to be mocked with sqlite, so use the
|
304
|
+
# internal DB
|
305
|
+
if isinstance(db, MockOSDBMixin):
|
306
|
+
db = db._sql_db
|
307
|
+
|
298
308
|
assert isinstance(db, BaseSQLDB), (k, db)
|
299
309
|
|
300
310
|
# set PRAGMA foreign_keys=ON if sqlite
|
@@ -606,7 +616,7 @@ async def test_login(monkeypatch, capfd, cli_env):
|
|
606
616
|
|
607
617
|
poll_attempts = 0
|
608
618
|
|
609
|
-
def fake_sleep(*args, **kwargs):
|
619
|
+
async def fake_sleep(*args, **kwargs):
|
610
620
|
nonlocal poll_attempts
|
611
621
|
|
612
622
|
# Keep track of the number of times this is called
|
@@ -619,13 +629,13 @@ async def test_login(monkeypatch, capfd, cli_env):
|
|
619
629
|
match = re.search(rf"{cli_env['DIRACX_URL']}[^\n]+", captured.out)
|
620
630
|
assert match, captured
|
621
631
|
|
622
|
-
do_device_flow_with_dex(match.group(), cli_env["DIRACX_CA_PATH"])
|
632
|
+
await do_device_flow_with_dex(match.group(), cli_env["DIRACX_CA_PATH"])
|
623
633
|
|
624
634
|
# Ensure we don't poll forever
|
625
635
|
assert poll_attempts <= 100
|
626
636
|
|
627
637
|
# Reduce the sleep duration to zero to speed up the test
|
628
|
-
|
638
|
+
await unpatched_sleep(0.0)
|
629
639
|
|
630
640
|
# We monkeypatch asyncio.sleep to provide a hook to run the actions that
|
631
641
|
# would normally be done by a user. This includes capturing the login URL
|
@@ -640,7 +650,7 @@ async def test_login(monkeypatch, capfd, cli_env):
|
|
640
650
|
|
641
651
|
# Run the login command
|
642
652
|
with monkeypatch.context() as m:
|
643
|
-
m.setattr("
|
653
|
+
m.setattr("diracx.cli.auth.sleep", fake_sleep)
|
644
654
|
await cli.auth.login(vo="diracAdmin", group=None, property=None)
|
645
655
|
captured = capfd.readouterr()
|
646
656
|
assert "Login successful!" in captured.out
|
@@ -654,7 +664,7 @@ async def test_login(monkeypatch, capfd, cli_env):
|
|
654
664
|
return expected_credentials_path.read_text()
|
655
665
|
|
656
666
|
|
657
|
-
def do_device_flow_with_dex(url: str, ca_path: str) -> None:
|
667
|
+
async def do_device_flow_with_dex(url: str, ca_path: str) -> None:
|
658
668
|
"""Do the device flow with dex."""
|
659
669
|
|
660
670
|
class DexLoginFormParser(HTMLParser):
|
@@ -662,10 +672,14 @@ def do_device_flow_with_dex(url: str, ca_path: str) -> None:
|
|
662
672
|
nonlocal action_url
|
663
673
|
if "form" in str(tag):
|
664
674
|
assert action_url is None
|
665
|
-
action_url = urljoin(login_page_url, dict(attrs)["action"])
|
675
|
+
action_url = urljoin(str(login_page_url), dict(attrs)["action"])
|
666
676
|
|
677
|
+
ssl_context = ssl.create_default_context(cafile=ca_path)
|
678
|
+
client_kwargs = dict(verify=ssl_context, follow_redirects=True)
|
667
679
|
# Get the login page
|
668
|
-
|
680
|
+
async with httpx.AsyncClient(**client_kwargs) as client:
|
681
|
+
r = await client.get(url)
|
682
|
+
|
669
683
|
r.raise_for_status()
|
670
684
|
login_page_url = r.url # This is not the same as URL as we redirect to dex
|
671
685
|
login_page_body = r.text
|
@@ -676,19 +690,24 @@ def do_device_flow_with_dex(url: str, ca_path: str) -> None:
|
|
676
690
|
assert action_url is not None, login_page_body
|
677
691
|
|
678
692
|
# Do the actual login
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
693
|
+
async with httpx.AsyncClient(**client_kwargs) as client:
|
694
|
+
r = await client.post(
|
695
|
+
action_url,
|
696
|
+
data={"login": "admin@example.com", "password": "password"},
|
697
|
+
)
|
698
|
+
|
684
699
|
r.raise_for_status()
|
685
700
|
approval_url = r.url # This is not the same as URL as we redirect to dex
|
686
701
|
# Do the actual approval
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
702
|
+
|
703
|
+
async with httpx.AsyncClient(**client_kwargs) as client:
|
704
|
+
r = await client.post(
|
705
|
+
approval_url,
|
706
|
+
data={
|
707
|
+
"approval": "approve",
|
708
|
+
"req": parse_qs(urlparse(str(r.url)).query)["req"][0],
|
709
|
+
},
|
710
|
+
)
|
692
711
|
|
693
712
|
# This should have redirected to the DiracX page that shows the login is complete
|
694
713
|
assert "Please close the window" in r.text
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: diracx-testing
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.1a26
|
4
4
|
Summary: TODO
|
5
5
|
License: GPL-3.0-only
|
6
6
|
Classifier: Intended Audience :: Science/Research
|
@@ -14,5 +14,6 @@ Requires-Dist: pytest
|
|
14
14
|
Requires-Dist: pytest-asyncio
|
15
15
|
Requires-Dist: pytest-cov
|
16
16
|
Requires-Dist: pytest-xdist
|
17
|
+
Requires-Dist: httpx
|
17
18
|
Provides-Extra: testing
|
18
19
|
Requires-Dist: diracx-testing; extra == "testing"
|
@@ -1,11 +1,11 @@
|
|
1
1
|
diracx/testing/__init__.py,sha256=nGbnGP8m53N9rqHR-hyqDa5vetcsmnQp806HadV6_dE,984
|
2
2
|
diracx/testing/dummy_osdb.py,sha256=bNk3LF8KgMuQx3RVFNYuw4hMmpG2A80sZ58rEZqHo7M,907
|
3
3
|
diracx/testing/entrypoints.py,sha256=MbH0VLUQz96XPdHzb7XWFwYtWEitAqPrrGM1H1FzDLo,2231
|
4
|
-
diracx/testing/mock_osdb.py,sha256=
|
4
|
+
diracx/testing/mock_osdb.py,sha256=hHuvmQZ3212SaSGX11dQv4ki3ZWsmqJZFYwdn6kg2MA,6029
|
5
5
|
diracx/testing/osdb.py,sha256=m6mUBLnGOoQLTCIBie9P2GhmLMybrgzIrlIYfhF1_Ss,3230
|
6
6
|
diracx/testing/routers.py,sha256=UW-TnikMQgcNxF5sUZD5DWoucGiCpP6s8mYmuahDiSc,979
|
7
|
-
diracx/testing/utils.py,sha256=
|
8
|
-
diracx_testing-0.0.
|
9
|
-
diracx_testing-0.0.
|
10
|
-
diracx_testing-0.0.
|
11
|
-
diracx_testing-0.0.
|
7
|
+
diracx/testing/utils.py,sha256=uPI7UssaOkDvaG3Lq1-A-IJCYvhQ1F_HcQsI6N6O-Bw,24417
|
8
|
+
diracx_testing-0.0.1a26.dist-info/METADATA,sha256=Cye4WM98UB1L1irFN3KHkgq4Iqd74Gxi-Ej8U-kc9fw,634
|
9
|
+
diracx_testing-0.0.1a26.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
10
|
+
diracx_testing-0.0.1a26.dist-info/top_level.txt,sha256=vJx10tdRlBX3rF2Psgk5jlwVGZNcL3m_7iQWwgPXt-U,7
|
11
|
+
diracx_testing-0.0.1a26.dist-info/RECORD,,
|
File without changes
|
File without changes
|