Skip to content

Commit 386165c

Browse files
rustyconoverclaude
andcommitted
conformance: add TestConnectionReuse — many calls over one connection
The suite gave each test a fresh connection, so "a persistent transport survives a long run of consecutive calls" was never an explicit part of the conformance contract. A client that fails to consume each response's trailing EOS marker before the next call passes call #1 and fails call #2; that gap went uncaught (it was a real bug in the Java RpcConnection client). Adds TestConnectionReuse with two tests, run against every worker across all transports: - test_many_sequential_unary_calls: 25 rounds of mixed unary calls on one connection. - test_optional_absence_round_trips_repeatedly: absent optionals stay absent across many reused-connection calls (a client must not degrade None to present-but-empty, nor poison a later call). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 5c9f9ed commit 386165c

1 file changed

Lines changed: 47 additions & 0 deletions

File tree

vgi_rpc/conformance/_pytest_suite.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1232,6 +1232,53 @@ def test_multiple_sequential_sessions(self, conformance_conn: ConnFactory) -> No
12321232
assert proxy.echo_string(value="end") == "end"
12331233

12341234

1235+
# ---------------------------------------------------------------------------
1236+
# Connection Reuse
1237+
# ---------------------------------------------------------------------------
1238+
1239+
1240+
class TestConnectionReuse:
1241+
"""Many calls over a single connection.
1242+
1243+
On a persistent transport (pipe / subprocess / Unix socket) one connection
1244+
carries every call, each framed as its own Arrow IPC stream
1245+
``[schema][batch...][EOS]``. A client must fully consume each response —
1246+
through its trailing EOS marker — before issuing the next call, or the
1247+
next call's reader sees the stale EOS and fails (e.g. "Unexpected end of
1248+
input. Missing schema"). The first call always succeeds; a client that
1249+
skips the drain fails on the second. These tests pin that requirement.
1250+
"""
1251+
1252+
def test_many_sequential_unary_calls(self, conformance_conn: ConnFactory) -> None:
1253+
"""A long run of consecutive unary calls on one connection all succeed."""
1254+
with conformance_conn() as proxy:
1255+
for i in range(25):
1256+
assert proxy.echo_string(value=f"call-{i}") == f"call-{i}"
1257+
assert proxy.echo_int(value=i) == i
1258+
assert proxy.add_floats(a=float(i), b=0.5) == pytest.approx(i + 0.5)
1259+
assert proxy.echo_point(point=Point(x=float(i), y=-float(i))) == Point(
1260+
x=float(i), y=-float(i)
1261+
)
1262+
1263+
def test_optional_absence_round_trips_repeatedly(
1264+
self, conformance_conn: ConnFactory
1265+
) -> None:
1266+
"""Absent optionals stay absent across many reused-connection calls.
1267+
1268+
A correct client round-trips an absent optional as the language's
1269+
"absent" value (Python ``None``) every time — never degrading to a
1270+
present-but-empty value, and never poisoning a later call.
1271+
"""
1272+
with conformance_conn() as proxy:
1273+
for i in range(15):
1274+
assert proxy.echo_optional_string(value=None) is None
1275+
assert proxy.echo_optional_string(value=f"v{i}") == f"v{i}"
1276+
assert proxy.echo_optional_int(value=None) is None
1277+
assert proxy.echo_optional_int(value=i) == i
1278+
# A trailing plain unary call must still work after the run.
1279+
assert proxy.echo_string(value="done") == "done"
1280+
1281+
12351282
# ---------------------------------------------------------------------------
12361283
# Cancellation
12371284
# ---------------------------------------------------------------------------

0 commit comments

Comments
 (0)