from __future__ import annotations import json from pathlib import Path import pytest from fastapi.testclient import TestClient from world_simulator.api.gradio_app import create_gradio_app def test_gradio_app_exposes_game_api(tmp_path: Path) -> None: config_path = _write_config(tmp_path) app = create_gradio_app(config_path=config_path, static_dir=tmp_path / "dist") client = TestClient(app) health = client.get("/health") assert health.status_code == 200 assert health.json()["status"] == "ok" snapshot = client.get("/scene/state?warmup=1") assert snapshot.status_code == 200 assert snapshot.json()["terrain"]["kind"] == "plain_green" tick = client.post("/tick") assert tick.status_code == 200 assert tick.json()["tick"] == 1 def test_gradio_app_serves_missing_frontend_page(tmp_path: Path) -> None: config_path = _write_config(tmp_path) app = create_gradio_app(config_path=config_path, static_dir=tmp_path / "missing-dist") client = TestClient(app) response = client.get("/world") assert response.status_code == 503 assert "frontend is not built" in response.text # The public lobby is served directly at the root path. lobby = client.get("/") assert lobby.status_code == 200 def test_gradio_app_force_deterministic_disables_modal_runtime( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: monkeypatch.setenv("WORLD_SIMULATOR_FORCE_DETERMINISTIC", "1") config_path = _write_modal_config(tmp_path) app = create_gradio_app(config_path=config_path, static_dir=tmp_path / "dist") client = TestClient(app) health = client.get("/health") assert health.status_code == 200 assert health.json()["simulator"] == "deterministic" snapshot = client.get("/scene/state?warmup=1") assert snapshot.status_code == 200 assert snapshot.json()["simulation"]["models"] == [] god_command = client.post("/god-command", json={"command": "make Ada happy"}) assert god_command.status_code == 404 def _write_config(tmp_path: Path) -> Path: config_path = tmp_path / "game.json" config_path.write_text( json.dumps( { "world": { "width": 80, "depth": 80, "terrain": "plain_green", "seed": 42, }, "npcs": {"count": 2}, "simulation": {"tick_ms": 500}, "server": {"host": "127.0.0.1", "port": 8000}, } ), encoding="utf-8", ) return config_path def _write_modal_config(tmp_path: Path) -> Path: config_path = tmp_path / "game.modal.json" config_path.write_text( json.dumps( { "world": { "width": 80, "depth": 80, "terrain": "plain_green", "seed": 42, }, "npcs": {"count": 2}, "simulation": {"tick_ms": 500}, "server": {"host": "127.0.0.1", "port": 8000}, "connector": { "type": "openai_compatible", "base_url": "https://workspace--npc-serve.modal.run/v1", "model": "npc-model", }, "god_console": { "type": "openai_compatible", "base_url": "https://workspace--god-serve.modal.run/v1", "model": "god-model", }, } ), encoding="utf-8", ) return config_path