-
-
Notifications
You must be signed in to change notification settings - Fork 50
Expand file tree
/
Copy pathfixtures_testcontainer.py
More file actions
99 lines (78 loc) · 2.92 KB
/
fixtures_testcontainer.py
File metadata and controls
99 lines (78 loc) · 2.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import contextlib
import os
import re
from collections.abc import Generator, Iterator
import pytest
import sqlalchemy
from dotenv import load_dotenv
from fastapi.testclient import TestClient
from sqlalchemy import Connection, Engine
from testcontainers.mysql import LogMessageWaitStrategy, MySqlContainer
from main import create_api
from routers.dependencies import expdb_connection, userdb_connection
load_dotenv()
@pytest.fixture(scope="session", autouse=True)
def override_testcontainers_connect() -> None:
"""
Override MySqlContainer._connect once per test session.
Applied automatically everywhere.
"""
def _connect(self: MySqlContainer) -> None:
wait_strategy = LogMessageWaitStrategy(
re.compile(
r".*: ready for connections",
flags=re.DOTALL | re.MULTILINE,
)
)
wait_strategy.wait_until_ready(self)
MySqlContainer._connect = _connect # noqa: SLF001
@pytest.fixture(scope="session")
def mysql_container() -> MySqlContainer:
container = MySqlContainer(
os.environ.get(
"OPENML_DATABASES_OPENML_URL",
"openml/test-database:v0.1.20260204",
),
username=os.environ.get("OPENML_DATABASES_OPENML_USERNAME", ""),
password=os.environ.get("OPENML_DATABASES_OPENML_PASSWORD", ""),
dbname="openml_expdb",
)
container.start()
try:
yield container
finally:
container.stop()
@pytest.fixture
def expdb_test(mysql_container: MySqlContainer) -> Connection:
url = mysql_container.get_connection_url().replace("mysql://", "mysql+pymysql://")
engine = sqlalchemy.create_engine(url)
with engine.begin() as connection: # This starts a transaction
try:
yield connection
finally:
connection.rollback() # Rollback ALL test changes
@contextlib.contextmanager
def automatic_rollback(engine: Engine) -> Iterator[Connection]:
with engine.connect() as connection:
transaction = connection.begin()
yield connection
if transaction.is_active:
transaction.rollback()
@pytest.fixture
def py_api(expdb_test: Connection, user_test: Connection) -> Generator[TestClient, None, None]:
app = create_api()
# We use the lambda definitions because fixtures may not be called directly.
app.dependency_overrides[expdb_connection] = lambda: expdb_test
app.dependency_overrides[userdb_connection] = lambda: user_test
client = TestClient(app)
yield client
client.close()
@pytest.fixture
def user_test(mysql_container: MySqlContainer) -> Connection:
"""Get a connection to the user database using the testcontainer."""
url = mysql_container.get_connection_url()
url = url.replace("mysql://", "mysql+pymysql://")
url = url.replace("openml_expdb", "openml")
engine = sqlalchemy.create_engine(url)
with automatic_rollback(engine) as connection:
yield connection