test_p4_acceptance.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. """P4 acceptance test suite.
  2. Tests all P4 milestones: M1 (AI frontend API), M2 (task dispatch),
  3. M3 (batch scheduler + monitor), M4 (reports + visualization data),
  4. M5 (deployment config).
  5. Run: python scripts/test_p4_acceptance.py
  6. """
  7. import json
  8. import os
  9. import sys
  10. import time
  11. from datetime import datetime
  12. # Add project root to path
  13. sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
  14. PASS = 0
  15. FAIL = 0
  16. RESULTS = []
  17. def test(name, condition, detail=""):
  18. global PASS, FAIL
  19. if condition:
  20. PASS += 1
  21. RESULTS.append(("PASS", name, detail))
  22. print(f" [PASS] {name}")
  23. else:
  24. FAIL += 1
  25. RESULTS.append(("FAIL", name, detail))
  26. print(f" [FAIL] {name} - {detail}")
  27. def test_m1_ai_api():
  28. """P4-M1: AI API endpoints and frontend integration."""
  29. print("\n[P4-M1] AI Frontend Integration")
  30. try:
  31. from web.backend.app.routers import ai, ai_plan, analysis, adaptive, search
  32. test("AI router modules importable", True)
  33. except Exception as e:
  34. test("AI router modules importable", False, str(e))
  35. # Check frontend AI API file
  36. ai_api_path = os.path.join("web", "frontend", "src", "api", "ai.ts")
  37. test("Frontend AI API file exists", os.path.exists(ai_api_path))
  38. # Check AI views
  39. ai_views = ["PlanGenerator.vue", "L0Prescreen.vue", "AdaptiveOptimize.vue",
  40. "ResultAnalysis.vue", "FidelityCalibration.vue", "ExperienceEnhance.vue"]
  41. for view in ai_views:
  42. path = os.path.join("web", "frontend", "src", "views", "ai", view)
  43. test(f"AI view {view} exists", os.path.exists(path))
  44. # Check components
  45. comps = ["ConfidenceBadge.vue", "FeasibilityIndicator.vue"]
  46. for comp in comps:
  47. path = os.path.join("web", "frontend", "src", "components", "ai", comp)
  48. test(f"AI component {comp} exists", os.path.exists(path))
  49. def test_m2_task_dispatch():
  50. """P4-M2: Task management and dispatch."""
  51. print("\n[P4-M2] Task Dispatch and Callback")
  52. try:
  53. from web.backend.app.models.task import Task
  54. test("Task model importable", True)
  55. except Exception as e:
  56. test("Task model importable", False, str(e))
  57. try:
  58. from web.backend.app.services.task_manager import get_task_manager
  59. tm = get_task_manager()
  60. test("TaskManager service instantiable", tm is not None)
  61. except Exception as e:
  62. test("TaskManager service instantiable", False, str(e))
  63. # Check task router
  64. router_path = os.path.join("web", "backend", "app", "routers", "tasks.py")
  65. test("Tasks router exists", os.path.exists(router_path))
  66. # Check frontend task manager
  67. tm_path = os.path.join("web", "frontend", "src", "views", "TaskManager.vue")
  68. test("Frontend TaskManager exists", os.path.exists(tm_path))
  69. # Check local executor
  70. exec_path = os.path.join("scripts", "task_executor.py")
  71. test("Local task executor exists", os.path.exists(exec_path))
  72. def test_m3_batch_scheduler():
  73. """P4-M3: Batch scheduler and monitoring."""
  74. print("\n[P4-M3] Batch Scheduler and Monitoring")
  75. try:
  76. from web.backend.app.services.batch_scheduler import BatchScheduler, get_scheduler
  77. scheduler = get_scheduler()
  78. test("BatchScheduler instantiable", scheduler is not None)
  79. # Test add task
  80. task = scheduler.add_task("test-task-1", "Test Task", priority=5,
  81. parameters=[{"x": 1}, {"x": 2}])
  82. test("Add task to scheduler", task["task_id"] == "test-task-1")
  83. # Test statistics
  84. stats = scheduler.get_statistics()
  85. test("Scheduler statistics has queued_count", "queued_count" in stats)
  86. test("Scheduler statistics has overall_progress", "overall_progress" in stats)
  87. # Cleanup
  88. scheduler.cancel_task("test-task-1")
  89. except Exception as e:
  90. test("BatchScheduler functional", False, str(e))
  91. # Check monitor router
  92. monitor_path = os.path.join("web", "backend", "app", "routers", "monitor.py")
  93. test("Monitor router exists", os.path.exists(monitor_path))
  94. # Check frontend monitor
  95. monitor_vue = os.path.join("web", "frontend", "src", "views", "MonitorDashboard.vue")
  96. test("Frontend MonitorDashboard exists", os.path.exists(monitor_vue))
  97. # Check robust motorcad
  98. robust_path = os.path.join("scripts", "robust_motorcad.py")
  99. test("Robust MotorCAD core exists", os.path.exists(robust_path))
  100. def test_m4_visualization_reports():
  101. """P4-M4: Advanced visualization and reports."""
  102. print("\n[P4-M4] Visualization and Reports")
  103. try:
  104. from web.backend.app.services.report_generator import ReportGenerator, get_report_generator
  105. rg = get_report_generator()
  106. test("ReportGenerator instantiable", rg is not None)
  107. # Test JSON report generation (fallback mode)
  108. task_data = {"task_id": "test-report", "task_name": "Test",
  109. "status": "completed", "plan_data": {"x": 1},
  110. "result_metrics": {"efficiency": 90}}
  111. report_path = rg.generate_report(task_data)
  112. test("Report generated (JSON fallback)", os.path.exists(report_path))
  113. if os.path.exists(report_path):
  114. os.remove(report_path)
  115. except Exception as e:
  116. test("ReportGenerator functional", False, str(e))
  117. # Check reports router
  118. reports_path = os.path.join("web", "backend", "app", "routers", "reports.py")
  119. test("Reports router exists", os.path.exists(reports_path))
  120. # Check frontend visualization
  121. viz_path = os.path.join("web", "frontend", "src", "views", "AdvancedVisualization.vue")
  122. test("Frontend AdvancedVisualization exists", os.path.exists(viz_path))
  123. def test_m5_deployment():
  124. """P4-M5: Deployment configuration."""
  125. print("\n[P4-M5] Deployment and Packaging")
  126. files = {
  127. "Dockerfile": os.path.join("Dockerfile"),
  128. "docker-compose.yml": os.path.join("docker-compose.yml"),
  129. "nginx.conf": os.path.join("nginx.conf"),
  130. "deploy.ps1": os.path.join("deploy.ps1"),
  131. }
  132. for name, path in files.items():
  133. test(f"Deployment file {name} exists", os.path.exists(path))
  134. # Check deploy.ps1 is ASCII only
  135. deploy_path = files["deploy.ps1"]
  136. if os.path.exists(deploy_path):
  137. with open(deploy_path, "r", encoding="utf-8") as f:
  138. content = f.read()
  139. non_ascii = [c for c in content if ord(c) > 127]
  140. test("deploy.ps1 is ASCII-only", len(non_ascii) == 0,
  141. f"{len(non_ascii)} non-ASCII chars" if non_ascii else "")
  142. def test_router_registration():
  143. """Verify all routers are registered in main.py."""
  144. print("\n[Integration] Router Registration")
  145. main_path = os.path.join("web", "backend", "app", "main.py")
  146. if os.path.exists(main_path):
  147. with open(main_path, "r", encoding="utf-8") as f:
  148. content = f.read()
  149. expected_routers = ["tasks", "monitor", "reports"]
  150. for router in expected_routers:
  151. test(f"Router '{router}' imported in main.py", f"import {router}" in content or f", {router}" in content)
  152. test(f"Router '{router}' included in main.py", f"include_router({router}.router)" in content)
  153. else:
  154. test("main.py exists", False)
  155. def main():
  156. print("=" * 60)
  157. print("PCB AFM Simulation System - P4 Acceptance Test")
  158. print(f"Date: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
  159. print("=" * 60)
  160. os.chdir(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
  161. test_m1_ai_api()
  162. test_m2_task_dispatch()
  163. test_m3_batch_scheduler()
  164. test_m4_visualization_reports()
  165. test_m5_deployment()
  166. test_router_registration()
  167. print("\n" + "=" * 60)
  168. print(f"RESULTS: {PASS} passed, {FAIL} failed, {PASS + FAIL} total")
  169. print("=" * 60)
  170. if FAIL > 0:
  171. print("\nFailed tests:")
  172. for status, name, detail in RESULTS:
  173. if status == "FAIL":
  174. print(f" - {name}: {detail}")
  175. sys.exit(1)
  176. else:
  177. print("\nAll tests passed!")
  178. sys.exit(0)
  179. if __name__ == "__main__":
  180. main()