| """ |
| End-to-end smoke test for the production API. |
| |
| Usage: |
| python scripts/smoke_test.py # test local (localhost:7860) |
| python scripts/smoke_test.py https://my-space.hf.space # test remote |
| """ |
|
|
| from __future__ import annotations |
|
|
| import json |
| import sys |
| import time |
|
|
| import requests |
|
|
|
|
| def smoke_test(base_url: str) -> bool: |
| """Run smoke tests against the API. Returns True if all pass.""" |
| base = base_url.rstrip("/") |
| passed = 0 |
| failed = 0 |
| results = [] |
|
|
| def check(name: str, method: str, path: str, expected_keys=None, body=None): |
| nonlocal passed, failed |
| url = f"{base}{path}" |
| try: |
| if method == "GET": |
| resp = requests.get(url, timeout=15) |
| else: |
| resp = requests.post(url, json=body, timeout=30) |
|
|
| if resp.status_code == 200: |
| data = resp.json() |
| if expected_keys: |
| missing = [k for k in expected_keys if k not in data] |
| if missing: |
| results.append(f" WARN {name}: missing keys {missing}") |
| passed += 1 |
| return |
| results.append(f" PASS {name}") |
| passed += 1 |
| else: |
| results.append(f" FAIL {name}: HTTP {resp.status_code} — {resp.text[:100]}") |
| failed += 1 |
| except Exception as exc: |
| results.append(f" FAIL {name}: {exc}") |
| failed += 1 |
|
|
| print(f"\nSmoke testing: {base}\n{'='*60}") |
|
|
| check("Health check", |
| "GET", "/api/health", |
| expected_keys=["status", "uptime_seconds"]) |
|
|
| check("Weather current", |
| "GET", "/api/weather/current", |
| expected_keys=["air_temperature_c", "ghi_w_m2"]) |
|
|
| check("Weather history", |
| "GET", "/api/weather/history") |
|
|
| check("Sensor snapshot", |
| "GET", "/api/sensors/snapshot") |
|
|
| check("Energy current", |
| "GET", "/api/energy/current") |
|
|
| check("Energy daily", |
| "GET", "/api/energy/daily/2026-03-17") |
|
|
| check("Photosynthesis current", |
| "GET", "/api/photosynthesis/current") |
|
|
| check("Control status", |
| "GET", "/api/control/status") |
|
|
| check("Control plan", |
| "GET", "/api/control/plan") |
|
|
| check("Biology rules", |
| "GET", "/api/biology/rules", |
| expected_keys=["rules"]) |
|
|
| check("Biology phenology", |
| "GET", "/api/biology/phenology") |
|
|
| check("Chatbot message", |
| "POST", "/api/chatbot/message", |
| expected_keys=["message"], |
| body={"message": "What is the current temperature?", "session_id": "smoke-test"}) |
|
|
| |
| print() |
| for r in results: |
| print(r) |
| print(f"\n{'='*60}") |
| print(f"Results: {passed} passed, {failed} failed out of {passed + failed}") |
|
|
| return failed == 0 |
|
|
|
|
| if __name__ == "__main__": |
| url = sys.argv[1] if len(sys.argv) > 1 else "http://localhost:7860" |
| ok = smoke_test(url) |
| sys.exit(0 if ok else 1) |
|
|