[verified] feat: complete Ralph task workstreams
This commit is contained in:
@@ -454,6 +454,137 @@ def test_relay_rpc_reuses_connection_for_sequential_requests(monkeypatch):
|
||||
assert connection_attempts == 1
|
||||
|
||||
|
||||
def test_relay_hop_client_preserves_binary_json_and_closes_uncertain_legacy_socket(monkeypatch):
|
||||
"DIP-002: persistent clients correlate both frame formats and never replay a lost response.\n\nTags: gossip, network, relay"
|
||||
|
||||
import websockets.sync.client as wsc # type: ignore[import]
|
||||
from meshnet_node.relay_bridge import decode_binary_frame, encode_binary_frame
|
||||
from meshnet_node.torch_server import _RelayHopClient, _RelayRequestUncertainError
|
||||
|
||||
class FakeSocket:
|
||||
def __init__(self, responses):
|
||||
self.responses = iter(responses)
|
||||
self.sent = []
|
||||
self.closed = False
|
||||
|
||||
def send(self, frame):
|
||||
self.sent.append(frame)
|
||||
|
||||
def recv(self, timeout):
|
||||
response = next(self.responses)
|
||||
if isinstance(response, BaseException):
|
||||
raise response
|
||||
request, _ = decode_binary_frame(self.sent[-1])
|
||||
if isinstance(response, bytes):
|
||||
return encode_binary_frame({
|
||||
"request_id": request["request_id"], "status": 200, "headers": {},
|
||||
}, response)
|
||||
return json.dumps({"request_id": request["request_id"], "status": 200,
|
||||
"headers": {}, "body": response})
|
||||
|
||||
def close(self):
|
||||
self.closed = True
|
||||
|
||||
healthy = FakeSocket([b"binary", "json"])
|
||||
legacy = FakeSocket([b"first", TimeoutError("legacy relay closed")])
|
||||
session_a = FakeSocket([b"a"])
|
||||
session_b = FakeSocket([b"b"])
|
||||
sockets = iter([healthy, legacy, session_a, session_b])
|
||||
monkeypatch.setattr(wsc, "connect", lambda *args, **kwargs: next(sockets))
|
||||
|
||||
client = _RelayHopClient("ws://relay/rpc/peer", timeout=0.01)
|
||||
assert client.request("/forward", b"a", {})[2] == b"binary"
|
||||
assert client.request("/forward", b"b", {})[2] == b"json"
|
||||
first_id = decode_binary_frame(healthy.sent[0])[0]["request_id"]
|
||||
second_id = decode_binary_frame(healthy.sent[1])[0]["request_id"]
|
||||
assert first_id != second_id
|
||||
client.close()
|
||||
|
||||
client = _RelayHopClient("ws://relay/rpc/peer", timeout=0.01)
|
||||
assert client.request("/forward", b"first", {})[2] == b"first"
|
||||
try:
|
||||
client.request("/forward", b"second", {})
|
||||
except _RelayRequestUncertainError:
|
||||
pass
|
||||
else:
|
||||
raise AssertionError("a post-send disconnect must not be retried")
|
||||
assert legacy.closed is True
|
||||
assert client._ws is None
|
||||
|
||||
# Route Sessions own their own requester socket; serialising one client's
|
||||
# calls must not accidentally make another session share it.
|
||||
first = _RelayHopClient("ws://relay/rpc/peer", timeout=0.01)
|
||||
second = _RelayHopClient("ws://relay/rpc/peer", timeout=0.01)
|
||||
assert first.request("/forward", b"a", {})[2] == b"a"
|
||||
assert second.request("/forward", b"b", {})[2] == b"b"
|
||||
assert first._ws is session_a
|
||||
assert second._ws is session_b
|
||||
|
||||
|
||||
def test_relay_rpc_cleans_pending_on_timeout_disconnect_and_cancellation():
|
||||
"DIP-002: every terminal relay RPC path releases its pending response queue.\n\nTags: gossip, network, relay"
|
||||
|
||||
import asyncio
|
||||
|
||||
from meshnet_relay.server import RelayServer
|
||||
|
||||
class Requester:
|
||||
def __init__(self):
|
||||
self.messages = [json.dumps({
|
||||
"request_id": "legacy-id", "method": "POST", "path": "/forward",
|
||||
"headers": {}, "body": "{}",
|
||||
})]
|
||||
self.sent = []
|
||||
|
||||
async def recv(self):
|
||||
if self.messages:
|
||||
return self.messages.pop(0)
|
||||
raise EOFError
|
||||
|
||||
async def send(self, message):
|
||||
self.sent.append(json.loads(message))
|
||||
|
||||
async def close(self, *args):
|
||||
pass
|
||||
|
||||
class Target:
|
||||
async def send(self, message):
|
||||
pass
|
||||
|
||||
async def wait_for_pending(relay):
|
||||
for _ in range(100):
|
||||
if relay._pending_rpc:
|
||||
return
|
||||
await asyncio.sleep(0)
|
||||
raise AssertionError("relay RPC did not register pending state")
|
||||
|
||||
async def exercise(kind):
|
||||
relay = RelayServer(rpc_timeout=0.02, rpc_idle_timeout=0.01)
|
||||
relay.registry.register("peer", "", Target())
|
||||
requester = Requester()
|
||||
task = asyncio.create_task(relay._handle_rpc(requester, "peer"))
|
||||
await wait_for_pending(relay)
|
||||
if kind == "disconnect":
|
||||
relay._fail_pending_for_peer("peer")
|
||||
elif kind == "cancel":
|
||||
task.cancel()
|
||||
if kind == "cancel":
|
||||
try:
|
||||
await task
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
else:
|
||||
await task
|
||||
assert relay._pending_rpc == {}
|
||||
if kind == "timeout":
|
||||
assert requester.sent[-1]["status"] == 504
|
||||
if kind == "disconnect":
|
||||
assert requester.sent[-1]["status"] == 503
|
||||
|
||||
for kind in ("timeout", "disconnect", "cancel"):
|
||||
asyncio.run(exercise(kind))
|
||||
|
||||
|
||||
def test_binary_relay_frame_codecs_interoperate():
|
||||
"Node and relay ship the same binary frame format as separate copies.\n\nTags: gossip, network, relay"
|
||||
|
||||
@@ -478,6 +609,24 @@ def test_binary_relay_frame_codecs_interoperate():
|
||||
raise AssertionError("garbage bytes must not decode as a binary frame")
|
||||
|
||||
|
||||
def test_binary_relay_frame_layout_remains_byte_for_byte_compatible():
|
||||
"""Framing optimizations preserve the MRF1 header-length-body contract.
|
||||
|
||||
Tags: gossip, network, relay, wire
|
||||
"""
|
||||
import json
|
||||
|
||||
from meshnet_node.relay_bridge import BINARY_FRAME_MAGIC, encode_binary_frame
|
||||
|
||||
header = {"request_id": "r-1", "headers": {"X-Meshnet-Shape": "1,1,2"}}
|
||||
body = b"\x01\x02\x03\x04"
|
||||
header_bytes = json.dumps(header, separators=(",", ":")).encode()
|
||||
|
||||
assert encode_binary_frame(header, body) == (
|
||||
BINARY_FRAME_MAGIC + len(header_bytes).to_bytes(4, "big") + header_bytes + body
|
||||
)
|
||||
|
||||
|
||||
def test_activation_compression_round_trips_and_skips_small_bodies():
|
||||
"Pipeline hops zstd-compress large activations; tiny decode bodies pass raw.\n\nTags: gossip, network, relay"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user