Spaces:
Runtime error
Runtime error
Commit ·
e6ab3ac
1
Parent(s): efc9c82
test(web): wire-level GET-poll fairness + document single-user concurrency assumption
Browse files- proteus/web/server.py +5 -0
- tests/web/test_server.py +18 -0
proteus/web/server.py
CHANGED
|
@@ -3,6 +3,11 @@
|
|
| 3 |
A pure ``handle_request(method, path, body, registry)`` router (unit-testable
|
| 4 |
without a socket) plus a thin BaseHTTPRequestHandler adapter and a make_server
|
| 5 |
factory. In-memory session registry; local single-user. No new dependencies.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
"""
|
| 7 |
from __future__ import annotations
|
| 8 |
|
|
|
|
| 3 |
A pure ``handle_request(method, path, body, registry)`` router (unit-testable
|
| 4 |
without a socket) plus a thin BaseHTTPRequestHandler adapter and a make_server
|
| 5 |
factory. In-memory session registry; local single-user. No new dependencies.
|
| 6 |
+
|
| 7 |
+
Concurrency: ThreadingHTTPServer serves each request on its own thread, but the
|
| 8 |
+
registry is a plain dict and a session is not locked — this assumes one local
|
| 9 |
+
player (no concurrent ``/act`` on the same session). Sessions are never evicted
|
| 10 |
+
(unbounded for a long-lived server); both are acceptable for single-user play.
|
| 11 |
"""
|
| 12 |
from __future__ import annotations
|
| 13 |
|
tests/web/test_server.py
CHANGED
|
@@ -91,6 +91,24 @@ def test_query_string_is_ignored_in_routing():
|
|
| 91 |
assert status == 200 and "predator_evade" in payload["scenarios"]
|
| 92 |
|
| 93 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 94 |
def test_finish_appends_trace_and_returns_metrics(tmp_path):
|
| 95 |
reg = _registry()
|
| 96 |
_, created, _ = server.handle_request(
|
|
|
|
| 91 |
assert status == 200 and "predator_evade" in payload["scenarios"]
|
| 92 |
|
| 93 |
|
| 94 |
+
def test_get_poll_state_is_fair_mid_game():
|
| 95 |
+
# The GET poll path must be as fair as create/act: no answer keys mid-game.
|
| 96 |
+
reg = _registry()
|
| 97 |
+
_, created, _ = server.handle_request(
|
| 98 |
+
"POST", "/session",
|
| 99 |
+
{"scenario": "predator_evade", "difficulty": "easy", "seed": 42,
|
| 100 |
+
"play_turns": 5, "probe": False}, reg)
|
| 101 |
+
sid = created["session_id"]
|
| 102 |
+
server.handle_request("POST", f"/session/{sid}/act", {"action": "up"}, reg)
|
| 103 |
+
|
| 104 |
+
status, payload, _ = server.handle_request("GET", f"/session/{sid}", None, reg)
|
| 105 |
+
assert status == 200
|
| 106 |
+
st = payload["state"]
|
| 107 |
+
assert st["outcome"] is None and st["review"] is None
|
| 108 |
+
blob = json.dumps(st)
|
| 109 |
+
assert "reward" not in blob and "motive_action" not in blob and "habit" not in blob
|
| 110 |
+
|
| 111 |
+
|
| 112 |
def test_finish_appends_trace_and_returns_metrics(tmp_path):
|
| 113 |
reg = _registry()
|
| 114 |
_, created, _ = server.handle_request(
|