Skip to content

Commit 727993d

Browse files
Pin Pool initialize / acquire fork-guard arms
ISSUE-844 introduced fork-pid guards on Pool's lifecycle methods; ISSUE-942 pinned the close() arm. The initialize() and acquire() arms remained uncovered — a regression that drops either guard would let a forked child silently share the parent's TCP fds with corrupted reads / mixed request-response framing per ISSUE-843's analysis. Add coverage tests that monkeypatch _conn_mod._current_pid (no real fork() needed; same pattern as ISSUE-1093 / ISSUE-966) and assert each guard raises InterfaceError matching "after fork". Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent f5a6ada commit 727993d

1 file changed

Lines changed: 42 additions & 0 deletions

File tree

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
"""Pin: ``ConnectionPool.initialize`` and
2+
``ConnectionPool.acquire`` raise ``InterfaceError`` when called
3+
after fork (creator pid != current pid).
4+
5+
ISSUE-844 introduced these guards; ISSUE-942 pinned the close()
6+
fork branch only. The initialize / acquire arms were uncovered —
7+
a regression that drops either guard would let a forked child
8+
silently share the parent's TCP fds with corrupted reads / mixed
9+
request-response framing.
10+
11+
Use the same monkeypatch pattern as ISSUE-1093 / ISSUE-966 — no
12+
real fork() needed.
13+
"""
14+
15+
import os
16+
17+
import pytest
18+
19+
from dqliteclient import connection as _conn_mod
20+
from dqliteclient.exceptions import InterfaceError
21+
from dqliteclient.pool import ConnectionPool
22+
23+
24+
@pytest.mark.asyncio
25+
async def test_pool_initialize_raises_after_fork(
26+
monkeypatch: pytest.MonkeyPatch,
27+
) -> None:
28+
pool = ConnectionPool(addresses=["h:9001"], min_size=1, max_size=2)
29+
monkeypatch.setattr(_conn_mod, "_current_pid", os.getpid() + 1)
30+
with pytest.raises(InterfaceError, match="after fork"):
31+
await pool.initialize()
32+
33+
34+
@pytest.mark.asyncio
35+
async def test_pool_acquire_raises_after_fork(
36+
monkeypatch: pytest.MonkeyPatch,
37+
) -> None:
38+
pool = ConnectionPool(addresses=["h:9001"], min_size=0, max_size=2)
39+
monkeypatch.setattr(_conn_mod, "_current_pid", os.getpid() + 1)
40+
with pytest.raises(InterfaceError, match="after fork"):
41+
async with pool.acquire():
42+
pytest.fail("should not reach")

0 commit comments

Comments
 (0)