Skip to content

Commit 701b14d

Browse files
committed
new fixtures for asyncpg_engine
1 parent 58cd807 commit 701b14d

File tree

1 file changed

+71
-13
lines changed

1 file changed

+71
-13
lines changed

packages/postgres-database/tests/conftest.py

Lines changed: 71 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
# pylint: disable=unused-variable
55

66
import uuid
7+
import warnings
78
from collections.abc import AsyncIterator, Awaitable, Callable, Iterator
89
from pathlib import Path
910

@@ -37,6 +38,7 @@
3738
user_to_groups,
3839
users,
3940
)
41+
from sqlalchemy.ext.asyncio import AsyncEngine, create_async_engine
4042

4143
pytest_plugins = [
4244
"pytest_simcore.pytest_global_environs",
@@ -81,6 +83,30 @@ def _make(is_async=True) -> Awaitable[Engine] | sa.engine.base.Engine:
8183
return _make
8284

8385

86+
@pytest.fixture
87+
def make_asyncpg_engine(postgres_service: str) -> Callable[[bool], AsyncEngine]:
88+
# NOTE: users is responsible of `await engine.dispose()`
89+
dsn = postgres_service.replace("postgresql://", "postgresql+asyncpg://")
90+
minsize = 1
91+
maxsize = 50
92+
93+
def _(echo: bool):
94+
engine: AsyncEngine = create_async_engine(
95+
dsn,
96+
pool_size=minsize,
97+
max_overflow=maxsize - minsize,
98+
connect_args={
99+
"server_settings": {"application_name": "postgres_database_tests"}
100+
},
101+
pool_pre_ping=True, # https://docs.sqlalchemy.org/en/14/core/pooling.html#dealing-with-disconnects
102+
future=True, # this uses sqlalchemy 2.0 API, shall be removed when sqlalchemy 2.0 is released
103+
echo=echo,
104+
)
105+
return engine
106+
107+
return _
108+
109+
84110
def is_postgres_responsive(dsn) -> bool:
85111
"""Check if something responds to ``url``"""
86112
try:
@@ -107,6 +133,11 @@ def pg_sa_engine(
107133
) -> Iterator[sa.engine.Engine]:
108134
"""
109135
Runs migration to create tables and return a sqlalchemy engine
136+
137+
NOTE: use this fixture to ensure pg db:
138+
- up,
139+
- responsive,
140+
- init (w/ tables) and/or migrated
110141
"""
111142
# NOTE: Using migration to upgrade/downgrade is not
112143
# such a great idea since these tests are used while developing
@@ -142,29 +173,56 @@ def pg_sa_engine(
142173

143174

144175
@pytest.fixture
145-
async def pg_engine(
176+
async def aiopg_engine(
146177
pg_sa_engine: sa.engine.Engine, make_engine: Callable
147178
) -> AsyncIterator[Engine]:
148179
"""
149180
Return an aiopg.sa engine connected to a responsive and migrated pg database
150181
"""
151-
async_engine = await make_engine(is_async=True)
152182

153-
yield async_engine
183+
aiopg_sa_engine = await make_engine(is_async=True)
184+
185+
warnings.warn(
186+
"The 'aiopg_engine' is deprecated since we are replacing `aiopg` library by `sqlalchemy.ext.asyncio`."
187+
"SEE https://github.com/ITISFoundation/osparc-simcore/issues/4529. "
188+
"Please use 'asyncpg_engine' instead.",
189+
DeprecationWarning,
190+
stacklevel=2,
191+
)
192+
193+
yield aiopg_sa_engine
154194

155195
# closes async-engine connections and terminates
156-
async_engine.close()
157-
await async_engine.wait_closed()
158-
async_engine.terminate()
196+
aiopg_sa_engine.close()
197+
await aiopg_sa_engine.wait_closed()
198+
aiopg_sa_engine.terminate()
159199

160200

161201
@pytest.fixture
162-
async def connection(pg_engine: Engine) -> AsyncIterator[SAConnection]:
202+
async def connection(aiopg_engine: Engine) -> AsyncIterator[SAConnection]:
163203
"""Returns an aiopg.sa connection from an engine to a fully furnished and ready pg database"""
164-
async with pg_engine.acquire() as _conn:
204+
async with aiopg_engine.acquire() as _conn:
165205
yield _conn
166206

167207

208+
@pytest.fixture
209+
async def asyncpg_engine(
210+
is_pdb_enabled: bool,
211+
pg_sa_engine: sa.engine.Engine,
212+
make_asyncpg_engine: Callable[[bool], AsyncEngine],
213+
) -> AsyncIterator[AsyncEngine]:
214+
215+
assert (
216+
pg_sa_engine
217+
), "Ensures pg db up, responsive, init (w/ tables) and/or migrated"
218+
219+
_apg_engine = make_asyncpg_engine(is_pdb_enabled)
220+
221+
yield _apg_engine
222+
223+
await _apg_engine.dispose()
224+
225+
168226
#
169227
# FACTORY FIXTURES
170228
#
@@ -240,7 +298,7 @@ async def _creator(conn, group: RowProxy | None = None, **overrides) -> RowProxy
240298

241299
@pytest.fixture
242300
async def create_fake_cluster(
243-
pg_engine: Engine, faker: Faker
301+
aiopg_engine: Engine, faker: Faker
244302
) -> AsyncIterator[Callable[..., Awaitable[int]]]:
245303
cluster_ids = []
246304
assert cluster_to_groups is not None
@@ -254,7 +312,7 @@ async def _creator(**overrides) -> int:
254312
"authentication": faker.pydict(value_types=[str]),
255313
}
256314
insert_values.update(overrides)
257-
async with pg_engine.acquire() as conn:
315+
async with aiopg_engine.acquire() as conn:
258316
cluster_id = await conn.scalar(
259317
clusters.insert().values(**insert_values).returning(clusters.c.id)
260318
)
@@ -265,13 +323,13 @@ async def _creator(**overrides) -> int:
265323
yield _creator
266324

267325
# cleanup
268-
async with pg_engine.acquire() as conn:
326+
async with aiopg_engine.acquire() as conn:
269327
await conn.execute(clusters.delete().where(clusters.c.id.in_(cluster_ids)))
270328

271329

272330
@pytest.fixture
273331
async def create_fake_project(
274-
pg_engine: Engine,
332+
aiopg_engine: Engine,
275333
) -> AsyncIterator[Callable[..., Awaitable[RowProxy]]]:
276334
created_project_uuids = []
277335

@@ -288,7 +346,7 @@ async def _creator(conn, user: RowProxy, **overrides) -> RowProxy:
288346

289347
yield _creator
290348

291-
async with pg_engine.acquire() as conn:
349+
async with aiopg_engine.acquire() as conn:
292350
await conn.execute(
293351
projects.delete().where(projects.c.uuid.in_(created_project_uuids))
294352
)

0 commit comments

Comments
 (0)