Skip to content

Commit 51ac88e

Browse files
Pin async commit/rollback "no transaction" swallow behaviour
AsyncConnection.commit / rollback silently absorb the server's "cannot commit / rollback - no transaction is active" reply to match the stdlib sqlite3 contract (and the sync Connection path). Only the sync side had explicit tests; add the async counterparts so a regression that widened or narrowed _is_no_transaction_error surfaces immediately, and cover the re-raise path for unrelated OperationalErrors. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 1270fb0 commit 51ac88e

File tree

1 file changed

+70
-0
lines changed

1 file changed

+70
-0
lines changed
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
"""Async commit/rollback "no transaction is active" swallow behaviour.
2+
3+
Mirrors the sync-side tests for ``_is_no_transaction_error``. The
4+
async path has the same silent-no-op contract (matches stdlib
5+
sqlite3); without dedicated tests, a regression that widened or
6+
narrowed the match would surface only via integration.
7+
"""
8+
9+
from unittest.mock import AsyncMock, MagicMock
10+
11+
import pytest
12+
13+
import dqliteclient.exceptions as _client_exc
14+
from dqlitedbapi.aio.connection import AsyncConnection
15+
16+
17+
def _prime(address: str = "localhost:19001") -> AsyncConnection:
18+
"""Build an AsyncConnection with a mocked inner client connection."""
19+
conn = AsyncConnection(address, database="x")
20+
inner = MagicMock()
21+
inner.close = AsyncMock()
22+
inner.execute = AsyncMock()
23+
conn._async_conn = inner
24+
return conn
25+
26+
27+
class TestAsyncCommitNoTxSwallow:
28+
async def test_commit_swallows_no_transaction_error(self) -> None:
29+
conn = _prime()
30+
assert conn._async_conn is not None
31+
conn._async_conn.execute.side_effect = _client_exc.OperationalError(
32+
1, "cannot commit - no transaction is active"
33+
)
34+
await conn.commit() # silent no-op
35+
36+
async def test_rollback_swallows_no_transaction_error(self) -> None:
37+
conn = _prime()
38+
assert conn._async_conn is not None
39+
conn._async_conn.execute.side_effect = _client_exc.OperationalError(
40+
1, "cannot rollback - no transaction is active"
41+
)
42+
await conn.rollback() # silent no-op
43+
44+
async def test_commit_re_raises_other_operational_errors(self) -> None:
45+
conn = _prime()
46+
assert conn._async_conn is not None
47+
conn._async_conn.execute.side_effect = _client_exc.OperationalError(
48+
10, "some unrelated error"
49+
)
50+
with pytest.raises(_client_exc.OperationalError, match="some unrelated error"):
51+
await conn.commit()
52+
53+
async def test_rollback_re_raises_other_operational_errors(self) -> None:
54+
conn = _prime()
55+
assert conn._async_conn is not None
56+
conn._async_conn.execute.side_effect = _client_exc.OperationalError(
57+
10, "some unrelated error"
58+
)
59+
with pytest.raises(_client_exc.OperationalError, match="some unrelated error"):
60+
await conn.rollback()
61+
62+
def test_sync_no_tx_helper_matches(self) -> None:
63+
"""Sanity check for sync/async parity on the helper that drives
64+
both the dbapi sync Connection.commit/rollback and the
65+
AsyncConnection.commit/rollback swallow paths.
66+
"""
67+
from dqlitedbapi.connection import _is_no_transaction_error
68+
69+
exc = _client_exc.OperationalError(1, "cannot commit - no transaction is active")
70+
assert _is_no_transaction_error(exc) is True

0 commit comments

Comments
 (0)