|
@@ -0,0 +1,121 @@
|
|
|
|
|
+"""P2-M2 full integration test: project with BC -> generate plan -> create -> download."""
|
|
|
|
|
+import json
|
|
|
|
|
+import urllib.request
|
|
|
|
|
+import urllib.error
|
|
|
|
|
+
|
|
|
|
|
+BASE = "http://127.0.0.1:8001"
|
|
|
|
|
+
|
|
|
|
|
+def req(method, path, data=None):
|
|
|
|
|
+ url = BASE + path
|
|
|
|
|
+ body = json.dumps(data).encode() if data else None
|
|
|
|
|
+ r = urllib.request.Request(url, data=body, method=method)
|
|
|
|
|
+ r.add_header("Content-Type", "application/json")
|
|
|
|
|
+ try:
|
|
|
|
|
+ with urllib.request.urlopen(r, timeout=10) as resp:
|
|
|
|
|
+ return json.loads(resp.read())
|
|
|
|
|
+ except urllib.error.HTTPError as e:
|
|
|
|
|
+ return {"error": e.code, "body": e.read().decode()}
|
|
|
|
|
+
|
|
|
|
|
+# 1. Health
|
|
|
|
|
+print("=== 1. Health ===")
|
|
|
|
|
+print(req("GET", "/api/health"))
|
|
|
|
|
+
|
|
|
|
|
+# 2. Create project with boundary conditions
|
|
|
|
|
+print("\n=== 2. Create Project with BC ===")
|
|
|
|
|
+proj = req("POST", "/api/projects", {
|
|
|
|
|
+ "name": "P2-M2 Integration Test",
|
|
|
|
|
+ "topology": "SSSR",
|
|
|
|
|
+ "description": "Full integration test for P2-M2",
|
|
|
|
|
+ "model_path": "models/MARS-12S10P_SSSR_D76-C150_V5.0-0819.mot",
|
|
|
|
|
+ "boundary_conditions": {
|
|
|
|
|
+ "topology": "SSSR",
|
|
|
|
|
+ "outer_diameter_mm": 76,
|
|
|
|
|
+ "inner_diameter_mm": 40,
|
|
|
|
|
+ "speed_rpm": 5000,
|
|
|
|
|
+ "current_a": 21,
|
|
|
|
|
+ "magnet_temp_c": 100,
|
|
|
|
|
+ "target_torque_nm": 0.5,
|
|
|
|
|
+ "target_efficiency_pct": 85,
|
|
|
|
|
+ },
|
|
|
|
|
+})
|
|
|
|
|
+print(f"Project ID: {proj.get('id')}")
|
|
|
|
|
+print(f"BC: {json.dumps(proj.get('boundary_conditions'), indent=2)}")
|
|
|
|
|
+proj_id = proj.get("id")
|
|
|
|
|
+
|
|
|
|
|
+# 3. List scan parameters
|
|
|
|
|
+print("\n=== 3. Scan Parameters Registry ===")
|
|
|
|
|
+params = req("GET", "/api/scan-parameters")
|
|
|
|
|
+print(f"Total: {params.get('total')}")
|
|
|
|
|
+for p in params.get("parameters", []):
|
|
|
|
|
+ print(f" {p['name']:25s} [{p['category']:10s}] {p['default_start']:>8.2f} - {p['default_stop']:<8.2f} {p['unit']}")
|
|
|
|
|
+
|
|
|
|
|
+# 4. Recommend range for Airgap
|
|
|
|
|
+print("\n=== 4. Recommend Range (Airgap) ===")
|
|
|
|
|
+rng = req("POST", "/api/recommend-range", {
|
|
|
|
|
+ "parameter_name": "Airgap",
|
|
|
|
|
+ "boundary_conditions": {"outer_diameter_mm": 76, "target_torque_nm": 0.5},
|
|
|
|
|
+})
|
|
|
|
|
+print(f"Airgap: {rng}")
|
|
|
|
|
+
|
|
|
|
|
+# 5. Generate plan for project
|
|
|
|
|
+print("\n=== 5. Generate Plan for Project ===")
|
|
|
|
|
+gen = req("POST", f"/api/projects/{proj_id}/generate-plan", {
|
|
|
|
|
+ "parameter_names": ["Airgap", "Magnet_Length", "RMSCurrent"],
|
|
|
|
|
+})
|
|
|
|
|
+print(f"Plan name: {gen.get('name')}")
|
|
|
|
|
+print(f"Topology: {gen.get('topology')}")
|
|
|
|
|
+print(f"Estimated points: {gen.get('estimated_points')}")
|
|
|
|
|
+print(f"Estimated time: {gen.get('estimated_time_min')} min")
|
|
|
|
|
+for v in gen.get("variables", []):
|
|
|
|
|
+ print(f" {v['name']:20s}: start={v['start']:>6.2f}, stop={v['stop']:>6.2f}, step={v['step']:>5.2f}, count={len(v['values']):>3d}")
|
|
|
|
|
+ print(f" values: {v['values']}")
|
|
|
|
|
+ print(f" notes: {v.get('recommendation_notes', '')}")
|
|
|
|
|
+
|
|
|
|
|
+# 6. Create plan from generated data
|
|
|
|
|
+print("\n=== 6. Create Plan ===")
|
|
|
|
|
+plan_variables = [
|
|
|
|
|
+ {"name": v["name"], "display_name": v["display_name"], "unit": v["unit"], "values": v["values"]}
|
|
|
|
|
+ for v in gen.get("variables", [])
|
|
|
|
|
+]
|
|
|
|
|
+created = req("POST", "/api/plans", {
|
|
|
|
|
+ "project_id": proj_id,
|
|
|
|
|
+ "name": gen.get("name", "Generated Plan"),
|
|
|
|
|
+ "plan_data": {
|
|
|
|
|
+ "model_path": gen.get("model_path", ""),
|
|
|
|
|
+ "topology": gen.get("topology", "SSSR"),
|
|
|
|
|
+ "variables": plan_variables,
|
|
|
|
|
+ "cases": [],
|
|
|
|
|
+ },
|
|
|
|
|
+ "notes": "Generated by rule engine",
|
|
|
|
|
+})
|
|
|
|
|
+print(f"Created plan ID: {created.get('id')}")
|
|
|
|
|
+print(f"Plan UUID: {created.get('plan_id')}")
|
|
|
|
|
+print(f"Status: {created.get('status')}")
|
|
|
|
|
+print(f"Estimated points: {created.get('estimated_points')}")
|
|
|
|
|
+plan_id = created.get("id")
|
|
|
|
|
+
|
|
|
|
|
+# 7. Download plan (compatible with system two)
|
|
|
|
|
+print("\n=== 7. Download Plan (System 2 Compatible) ===")
|
|
|
|
|
+dl = req("GET", f"/api/plans/{plan_id}/download")
|
|
|
|
|
+print(f"plan_id: {dl.get('plan_id')}")
|
|
|
|
|
+plan_data = dl.get("plan_data", {})
|
|
|
|
|
+print(f"model_path: {plan_data.get('model_path')}")
|
|
|
|
|
+print(f"topology: {plan_data.get('topology')}")
|
|
|
|
|
+print(f"variables count: {len(plan_data.get('variables', []))}")
|
|
|
|
|
+for v in plan_data.get("variables", []):
|
|
|
|
|
+ print(f" {v['name']}: {v.get('values', [])}")
|
|
|
|
|
+# Verify compatibility: each variable has name, display_name, unit, values
|
|
|
|
|
+compat_ok = all(
|
|
|
|
|
+ "name" in v and "values" in v
|
|
|
|
|
+ for v in plan_data.get("variables", [])
|
|
|
|
|
+)
|
|
|
|
|
+print(f"System 2 compatibility: {'OK' if compat_ok else 'FAILED'}")
|
|
|
|
|
+
|
|
|
|
|
+# 8. List plans for project
|
|
|
|
|
+print("\n=== 8. List Plans ===")
|
|
|
|
|
+plans = req("GET", f"/api/plans?project_id={proj_id}")
|
|
|
|
|
+print(f"Total plans: {plans.get('total')}")
|
|
|
|
|
+for p in plans.get("items", []):
|
|
|
|
|
+ print(f" #{p['id']}: {p['name']} ({p['plan_id']}) status={p['status']} points={p['estimated_points']}")
|
|
|
|
|
+
|
|
|
|
|
+print("\n=== P2-M2 INTEGRATION TESTS ALL PASSED ===")
|