"""Create a venue test game, then verify persistence with --verify after restart.""" import base64 import datetime import json from pathlib import Path import sys import urllib.error import urllib.request root = Path(__file__).resolve().parents[2] / "venue" assert (root / "backend" / "evening_detective_server").is_file(), "Backend artifact missing" assert (root / "backend" / "goose").is_file(), "Migration tool missing" assert (root / "backend" / "dev-user.sql").is_file(), "Account bootstrap SQL missing" assert (root / "frontend" / "dist" / "index.html").is_file(), "Frontend artifact missing" assert list((root / "migrations").glob("*.sql")), "Migrations missing" config = dict( line.split("=", 1) for line in (root / ".env").read_text().splitlines() if line and not line.startswith("#") ) base = "https://evening-detective.crabs-games.art" token = "" opener = urllib.request.build_opener(urllib.request.ProxyHandler({})) def request(path, body=None, raw=False): headers = {"Content-Type": "application/json"} if token: headers["Authorization"] = "Bearer " + token req = urllib.request.Request( base + path, data=None if body is None else json.dumps(body).encode(), headers=headers, ) with opener.open(req, timeout=10) as response: data = response.read() return data if raw else json.loads(data) def verify(state): game = request(f'/api/games/{state["gameID"]}')["game"] teams = game["teams"] assert any( team["ID"] == state["teamID"] and team["participationStatus"] == "confirmed" for team in teams ), "Test team or confirmed participation was not preserved" assert request("/api/files/" + state["filename"], raw=True) == base64.b64decode( state["data"] ), "Uploaded material was not preserved" assert b'
' in request("/games", raw=True), "SPA route failed" try: with opener.open("https://evening-detective-api.crabs-games.art/api/test/ping", timeout=10) as response: assert response.status == 200, "HTTPS API domain failed" token = request( "/api/auth/login", { "email": config["VENUE_USER_EMAIL"], "password": config["VENUE_USER_PASSWORD"], }, )["accessToken"] state_file = root / "packages" / "smoke.json" if "--verify" in sys.argv: state = json.loads(state_file.read_text()) else: scenario = request("/api/scenario", {"name": "TEST venue smoke"})["ID"] start = datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(hours=2) game = request( "/api/games", { "name": "TEST venue smoke", "description": "Disposable offline environment check", "startAt": start.isoformat(), "scenarioID": scenario, "format": "online", }, )["ID"] team = request( "/api/teams", {"gameID": game, "name": "TEST team", "participantsCount": 2}, )["ID"] data = base64.b64encode(b"%PDF-1.4\n%venue-smoke\n%%EOF\n").decode() filename = request( "/api/files/upload", {"filename": "venue-smoke.pdf", "data": data} )["filename"] state = {"gameID": game, "teamID": team, "filename": filename, "data": data} state_file.parent.mkdir(exist_ok=True) state_file.write_text(json.dumps(state)) verify(state) for path, body in [ ("/api/auth/signup", {"username": "Test", "email": "test@venue.invalid", "acceptTerms": True, "acceptPrivacy": True}), ("/api/auth/refresh-password", {"email": config["VENUE_USER_EMAIL"]}), ]: try: request(path, body) except urllib.error.HTTPError as error: assert error.code == 400, "Unexpected disabled operation status" assert json.loads(error.read())["code"] == 9, "Expected FailedPrecondition" else: raise AssertionError("Email-based account operation succeeded locally") print("PASS: login, test game, confirmed team, material, SPA and disabled email operations") except urllib.error.HTTPError as error: # Do not print response bodies: authentication responses may contain credentials. print(f"FAIL: venue API returned HTTP {error.code}", file=sys.stderr) sys.exit(1)