Game Features
ci / frontend (push) Successful in 9m13s
ci / backend (push) Failing after 6m40s

This commit is contained in:
khodowany
2026-10-04 23:20:06 -05:00
parent 2759337d16
commit 78b2c383f1
65 changed files with 12650 additions and 563 deletions
+37 -2
View File
@@ -67,7 +67,7 @@ class server_tests(unittest.TestCase):
self.assertEqual(json.loads(body)["code"], "not_found")
self.assertEqual(request(port, "/api/health", "POST")[0], 404)
def test_catalog_rules_and_validation_routes(self):
with running_server() as port:
with running_server("--allow-demo") as port:
self.assertEqual(json.loads(request(port, "/api/catalog")[2])["payload"], {"documents": []})
self.assertEqual(len(json.loads(request(port, "/api/rules")[2])["payload"]["slots"]), 12)
status, _, body = request(port, "/api/capacity", "POST", {"catalog_id": "missing", "players": 12})
@@ -81,7 +81,7 @@ class server_tests(unittest.TestCase):
database = pathlib.Path(directory) / "league.sqlite"
result = subprocess.run([str(SERVER.with_name("fpol_admin")), "--database", str(database), "import", str(demo / "catalog.json"), str(demo / "ratings.json"), str(demo / "results-3.json")], capture_output=True, text=True, timeout=10)
self.assertEqual(result.returncode, 0, result.stderr)
with running_server("--database", database) as port:
with running_server("--database", database, "--allow-demo") as port:
catalog = json.loads(request(port, "/api/catalog")[2])["payload"]
self.assertEqual(len(catalog["documents"]), 3)
status, _, body = request(port, "/api/capacity", "POST", json.loads((demo / "capacity.json").read_text()))
@@ -90,6 +90,41 @@ class server_tests(unittest.TestCase):
status, _, body = request(port, "/api/score-preview", "POST", json.loads((demo / "preview.json").read_text()))
self.assertEqual(status, 200)
self.assertEqual(json.loads(body)["payload"]["total"], 528.24)
def test_authenticated_cookie_headers_origin_and_query(self):
with tempfile.TemporaryDirectory(prefix="fpol_auth_http_") as directory:
database = pathlib.Path(directory) / "league.sqlite"
result = subprocess.run([str(SERVER.with_name("fpol_admin")), "--database", str(database), "create-user", "alice"], input="a strong test password\n", capture_output=True, text=True, timeout=10)
self.assertEqual(result.returncode, 0, result.stderr)
with running_server("--database", database, "--origin", "https://game.example", "--secure-cookies") as port:
def call(path, method="GET", body=None, headers=None):
connection = http.client.HTTPConnection("127.0.0.1", port, timeout=10)
try:
connection.request(method, path, body=json.dumps(body) if body is not None else None, headers={"Content-Type": "application/json", **(headers or {})})
response = connection.getresponse()
return response.status, dict(response.getheaders()), json.loads(response.read())
finally:
connection.close()
login = {"username": "alice", "password": "a strong test password"}
self.assertEqual(call("/api/auth/login", "POST", login)[0], 403)
headers = {"Origin": "https://game.example", "X-Fpol-Request": "1"}
status, response, body = call("/api/auth/login", "POST", login, headers)
self.assertEqual(status, 200)
cookie = response["Set-Cookie"]
self.assertIn("HttpOnly", cookie)
self.assertIn("SameSite=Lax", cookie)
self.assertIn("Secure", cookie)
self.assertEqual(response["Cache-Control"], "no-store")
self.assertNotIn("session_token", body)
headers["Cookie"] = cookie.split(";", 1)[0]
self.assertEqual(call("/api/auth/me", headers=headers)[2]["payload"]["username"], "alice")
self.assertEqual(call("/api/candidates?search=two+words&limit=1", headers=headers)[0], 200)
self.assertEqual(call("/api/candidates?search=%ZZ", headers=headers)[0], 400)
self.assertEqual(call("/api/candidates?limit=1&limit=2", headers=headers)[0], 400)
self.assertEqual(call("/api/auth/logout", "POST", {}, headers)[0], 403)
headers["X-CSRF-Token"] = body["payload"]["csrf"]
self.assertEqual(call("/api/auth/logout", "POST", {}, headers)[0], 200)
self.assertEqual(call("/api/auth/me", headers=headers)[0], 401)
self.assertEqual(call("/api/catalog", headers=headers)[0], 404)
def test_static_assets_and_route_boundaries(self):
with tempfile.TemporaryDirectory(prefix="fpol_web_") as directory:
root = pathlib.Path(directory)