| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- """P2-M5 acceptance test - verify all backend API endpoints.
- Run while backend is running on http://127.0.0.1:8000.
- All source is ASCII.
- """
- import json
- import urllib.request
- BASE = "http://127.0.0.1:8000"
- passed = 0
- failed = 0
- def api_get(path):
- with urllib.request.urlopen(f"{BASE}{path}", timeout=10) as r:
- return json.loads(r.read())
- def test(name, condition, detail=""):
- global passed, failed
- if condition:
- passed += 1
- print(f" [PASS] {name}")
- else:
- failed += 1
- print(f" [FAIL] {name} {detail}")
- print("=" * 60)
- print("P2-M5 Acceptance Test - Backend API Verification")
- print("=" * 60)
- # 1. Health
- print("\n[1] Health & Core")
- r = api_get("/api/health")
- test("health status ok", r.get("status") == "ok")
- # 2. Projects
- print("\n[2] Projects API")
- r = api_get("/api/projects?limit=5")
- test("projects list returns total", "total" in r, str(r)[:100])
- test("projects list has items", "items" in r)
- # 3. Plans
- print("\n[3] Plans API")
- r = api_get("/api/plans?limit=5")
- test("plans list returns total", "total" in r)
- test("plans list has items", "items" in r)
- # 4. Experience CRUD
- print("\n[4] Experience Library API")
- r = api_get("/api/experience?limit=5")
- test("experience list returns total", "total" in r)
- test("experience list has items", "items" in r)
- # Create a test case
- print(" -- Create test case --")
- test_data = {
- "topology": "SSSR",
- "source_plan_id": "ACCEPTANCE-TEST",
- "params": {"Airgap": 1.0, "RMSCurrent": 20},
- "metrics": {"tavg_nm": 2.5, "efficiency_pct": 85.0, "ripple_pct": 3.0},
- "conclusion": "Acceptance test case",
- "tags": ["acceptance-test"],
- "rating": 3
- }
- req = urllib.request.Request(
- f"{BASE}/api/experience",
- data=json.dumps(test_data).encode(),
- headers={"Content-Type": "application/json"},
- method="POST"
- )
- with urllib.request.urlopen(req, timeout=10) as r:
- created = json.loads(r.read())
- test("create experience returns 201", created.get("id") is not None)
- case_id = created.get("id")
- # Get single case
- r = api_get(f"/api/experience/{case_id}")
- test("get single case", r.get("id") == case_id)
- test("case has params", bool(r.get("params")))
- test("case has metrics", bool(r.get("metrics")))
- # Update case
- print(" -- Update test case --")
- update_data = {"conclusion": "Updated by acceptance test", "rating": 5, "tags": ["acceptance-test", "updated"]}
- req = urllib.request.Request(
- f"{BASE}/api/experience/{case_id}",
- data=json.dumps(update_data).encode(),
- headers={"Content-Type": "application/json"},
- method="PUT"
- )
- with urllib.request.urlopen(req, timeout=10) as r:
- updated = json.loads(r.read())
- test("update case returns updated", updated.get("conclusion") == "Updated by acceptance test")
- test("update rating", updated.get("rating") == 5)
- # Delete test case
- print(" -- Delete test case --")
- req = urllib.request.Request(
- f"{BASE}/api/experience/{case_id}",
- method="DELETE"
- )
- with urllib.request.urlopen(req, timeout=10) as r:
- test("delete case returns 204", r.status == 204)
- # 5. Analytics
- print("\n[5] Analytics API")
- r = api_get("/api/analytics/metrics")
- test("metrics list", len(r.get("metrics", [])) >= 10)
- r = api_get("/api/analytics/experience/stats")
- test("experience stats has total", "total" in r)
- test("experience stats has topology_distribution", "topology_distribution" in r)
- test("experience stats has metric_ranges", "metric_ranges" in r)
- # Similar search
- print(" -- Similar search --")
- req = urllib.request.Request(
- f"{BASE}/api/analytics/experience/similar?top_k=3&tolerance=0.5",
- data=json.dumps({"params": {"Airgap": 1.0, "RMSCurrent": 20}}).encode(),
- headers={"Content-Type": "application/json"},
- method="POST"
- )
- with urllib.request.urlopen(req, timeout=10) as r:
- similar = json.loads(r.read())
- test("similar search returns items", "items" in similar)
- # 6. Scan parameters / Generation
- print("\n[6] Generation / Rule Engine API")
- r = api_get("/api/scan-parameters")
- test("scan parameters list", len(r.get("parameters", [])) >= 5, str(r)[:100])
- # 7. API docs
- print("\n[7] API Documentation")
- try:
- with urllib.request.urlopen(f"{BASE}/docs", timeout=5) as r:
- test("Swagger docs accessible", r.status == 200)
- except Exception as e:
- test("Swagger docs accessible", False, str(e))
- try:
- with urllib.request.urlopen(f"{BASE}/openapi.json", timeout=5) as r:
- spec = json.loads(r.read())
- test("OpenAPI spec has paths", len(spec.get("paths", {})) >= 10)
- test("OpenAPI spec paths count", len(spec.get("paths", {})) >= 15, f"count={len(spec.get('paths',{}))}")
- except Exception as e:
- test("OpenAPI spec accessible", False, str(e))
- # Summary
- print("\n" + "=" * 60)
- print(f"ACCEPTANCE TEST SUMMARY: {passed} passed, {failed} failed")
- print("=" * 60)
- if failed > 0:
- print("\nSome tests failed. Please review.")
- exit(1)
- else:
- print("\nAll backend API acceptance tests passed!")
- exit(0)
|