Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,16 @@ async def db_session(di_container: modern_di.Container) -> typing.AsyncIterator[
try:
yield create_session(connection)
finally:
if connection.in_transaction():
try:
if not transaction.is_active:
pytest.fail(
"db_session: the outer test transaction is no longer active at teardown, so this test's writes "
"were not rolled back. Something committed it instead of nesting a savepoint; check for a "
'session created without join_transaction_mode="create_savepoint".',
pytrace=False,
)
await transaction.rollback()
await connection.close()
await engine.dispose()
di_container.reset_override(ioc.Database.database_engine)
finally:
await connection.close()
await engine.dispose()
di_container.reset_override(ioc.Database.database_engine)
43 changes: 43 additions & 0 deletions tests/test_db_session_fixture.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import pytest


pytest_plugins = ["pytester"]


def test_db_session_teardown_fails_when_outer_transaction_was_committed(pytester: pytest.Pytester) -> None:
pytester.makepyfile(
"""
import sqlalchemy as sa
from sqlalchemy.ext.asyncio import AsyncSession

from tests.conftest import app, db_session, di_container

captured = {}


async def test_commits_outer_transaction(db_session):
captured["connection"] = db_session.bind
session = AsyncSession(db_session.bind, join_transaction_mode="control_fully")
await session.execute(sa.text("SELECT 1"))
await session.commit()
await session.close()


def test_connection_was_still_closed():
assert captured["connection"].closed
""",
)

result = pytester.runpytest_inprocess(
"-p",
"no:cacheprovider",
"-o",
"asyncio_mode=auto",
"-o",
"asyncio_default_fixture_loop_scope=function",
"-W",
"error",
)

result.assert_outcomes(passed=2, errors=1)
result.stdout.fnmatch_lines(["*outer test transaction is no longer active*create_savepoint*"])
Loading