#!/usr/bin/env python """relay_stub_test.py -- Phase-1 verification for btconsole.py --relay mode. Spawns the relay with a 3-pilot test egg, then drives stub clients through the whole protocol: console egg delivery, game HELLO/registration, PEER_UP/DOWN, unicast + broadcast routing (route rewrite), UDP HELLO/ACK, UDP forward, UDP->TCP fallback, and the reject paths (bad magic, dup id, out-of-roster, oversize). Exits 0 with 'ALL PASS' or 1 with the first failure. """ import os import socket import struct import subprocess import sys import time HERE = os.path.dirname(os.path.abspath(__file__)) TOOLS = os.path.join(HERE, "..", "tools") CONSOLE_PORT = 27500 GAME_PORT = CONSOLE_PORT + 1 ENV_TCP = " unicast to 3 route, payload = recv_env(b) check(route == 2 and payload == frame, f"B received A's unicast with route rewritten to sender (route={route})") print("== routing: broadcast fan-out ==") c = game_connect() hello(c, 4) for s_, who in ((a, "A"), (b, "B")): route, payload = recv_env(s_) check(route == R_PEER_UP and struct.unpack(" unicast 3 ua.sendto(dg, ("127.0.0.1", GAME_PORT)) fwd, _ = ub.recvfrom(4096) check(fwd == dg, "UDP unicast forwarded verbatim") dg2 = struct.pack(ENV_UDP, R_BCAST, 2, 8) + frame # A -> broadcast ua.sendto(dg2, ("127.0.0.1", GAME_PORT)) fwd2, _ = ub.recvfrom(4096) check(fwd2 == dg2, "UDP broadcast reached B") # C never sent UDP HELLO -> its copy must fall back to TCP. route, payload = recv_env(c) check(route == 2 and payload == frame, "C (no UDP endpoint) got the broadcast via TCP fallback") print("== reject paths ==") bad = game_connect() send_env(bad, R_HELLO, struct.pack(" connection dropped") dup = game_connect() hello(dup, 2) check(dup.recv(1) == b"", "duplicate hostID -> dropped") oor = game_connect() hello(oor, 99) check(oor.recv(1) == b"", "out-of-roster hostID -> dropped") big = game_connect() big.sendall(struct.pack(ENV_TCP, 3, 5000)) check(big.recv(1) == b"", "oversize frame -> dropped") print("== PEER_DOWN ==") c.close() for s_, who in ((a, "A"), (b, "B")): s_.settimeout(5) route, payload = recv_env(s_) check(route == R_PEER_DOWN and struct.unpack("