Spaces:
Sleeping
Sleeping
| """API smoke tests for plan seed, feedback priors, agent auth, rules reschedule.""" | |
| from __future__ import annotations | |
| from pathlib import Path | |
| import pytest | |
| from fastapi.testclient import TestClient | |
| from app.config import get_settings | |
| from app.schedule_math import ev_score | |
| from app.schedule_reschedule import seed_starter_blocks | |
| def client(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> TestClient: | |
| monkeypatch.setenv("DATA_ROOT", str(tmp_path / "data")) | |
| monkeypatch.setenv("AGENT_TOKEN", "test-agent-token") | |
| monkeypatch.setenv("APP_SECRET_KEY", "test-secret-key") | |
| monkeypatch.setenv("APP_PASSWORD", "test-password") | |
| monkeypatch.setenv("ENV", "dev") | |
| get_settings.cache_clear() | |
| from app.main import create_app | |
| c = TestClient(create_app()) | |
| assert c.post("/api/auth/login", json={"password": "test-password"}).status_code == 200 | |
| return c | |
| def test_ev_score_locked_formula() -> None: | |
| base = ev_score(p_done=0.8, utility=1.0, fun=0.5, d_hat_min=30, fse=0.2) | |
| raised = ev_score( | |
| p_done=0.8, | |
| utility=1.0, | |
| fun=0.5, | |
| d_hat_min=30, | |
| fse=0.2, | |
| raise_eta=True, | |
| raise_lambda_f=True, | |
| ) | |
| assert isinstance(base, float) and isinstance(raised, float) | |
| def test_seed_starter_keeps_p0() -> None: | |
| blocks = seed_starter_blocks("2026-07-19", capacity_hint=0.8) | |
| kinds = {b.kind for b in blocks} | |
| assert "food_out" in kinds and "sleep_window" in kinds | |
| assert all(b.locked for b in blocks if b.priority == "P0") | |
| def test_plan_seed_and_feedback_priors(client: TestClient) -> None: | |
| day = "2026-07-19" | |
| r = client.post(f"/api/plan/{day}/seed") | |
| assert r.status_code == 200, r.text | |
| plan = r.json()["data"] | |
| assert plan["blocks"] | |
| assert "capacity_hint" in plan | |
| bid = plan["blocks"][0]["id"] | |
| fb = client.post( | |
| f"/api/plan/{day}/blocks/{bid}/feedback", | |
| json={ | |
| "did": "done", | |
| "actual_min": 20, | |
| "quality": 4, | |
| "fun": 3, | |
| "energy_after": 1, | |
| "would_repeat": "yes", | |
| }, | |
| ) | |
| assert fb.status_code == 200, fb.text | |
| priors = client.get("/api/schedule/priors").json()["data"]["kinds"] | |
| assert any(p.get("n", 0) >= 1 for p in priors) | |
| def test_agent_requires_token(client: TestClient) -> None: | |
| bare = TestClient(client.app) | |
| r = bare.get("/api/agent/context?day=2026-07-19") | |
| assert r.status_code in (401, 403) | |
| ok = bare.get( | |
| "/api/agent/context?day=2026-07-19", | |
| headers={"Authorization": "Bearer test-agent-token"}, | |
| ) | |
| assert ok.status_code == 200 | |
| assert ok.json()["data"]["constraints"]["scope"] == "P1_thin_loop" | |
| def test_reschedule_rules_source(client: TestClient) -> None: | |
| day = "2026-07-20" | |
| client.post(f"/api/plan/{day}/seed") | |
| r = client.post(f"/api/plan/{day}/reschedule", json={"reason": "test", "force": True}) | |
| assert r.status_code == 200, r.text | |
| body = r.json()["data"] | |
| assert body["source"] in ("rules", "openrouter") | |
| p0 = [b for b in body["plan"]["blocks"] if b["priority"] == "P0"] | |
| assert p0 | |