Files
Kill_LIFE/test/test_yiacad_backend_contract.py
Clément SAILLANT 5efb380da5 feat: automate yiacad PR review lane (#18)
* feat: automate yiacad pr review lane

* fix: stabilize yiacad review and spec gates

* fix: scope kicad exports to repo hardware

* fix: ignore kicad block library sources in exports

* feat: Add infra VPS monitoring runbook and healthcheck scripts

- Created INFRA_VPS_RUNBOOK_2026.md detailing operational procedures for monitoring VPS services.
- Added infra_vps_healthcheck.sh script for automated health checks on DNS, TLS, TCP, and HTTP for VPS services.
- Introduced infra_vps_security_audit.sh for non-intrusive security checks on external VPS services.
- Established JSON schema for infra VPS inventory in infra_vps.schema.json.
- Developed integration for runtime status reporting in the Next.js API route.
- Implemented Playwright tests for smoke testing the application and ensuring core functionalities.
- Updated Makefile for development dependencies and testing commands.
- Created various test files for unit and end-to-end testing across different components.

* feat(agentics): update mesh agents, gates, prompts, and workflows
2026-03-29 17:14:16 +02:00

96 lines
4.3 KiB
Python

#!/usr/bin/env python3
from __future__ import annotations
import unittest
from unittest.mock import patch
import tools.cad.yiacad_backend as backend
from tools.cad.yiacad_backend import build_context_record, build_uiux_output, detect_integrated_engines
class YiacadBackendContractTests(unittest.TestCase):
def test_build_uiux_output_keeps_engine_status_and_degraded_reasons(self) -> None:
engine_status = detect_integrated_engines()
payload = build_uiux_output(
surface="yiacad-web",
action="review.erc_drc",
execution_mode="background",
status="degraded",
severity="warning",
summary="YiACAD review completed with engine warnings.",
details="KiCad review returned warnings and KiBot is not ready.",
context_ref="project:demo/main",
artifacts=[],
next_steps=["open review center"],
latency_ms=120,
degraded_reasons=["kicad-violations-present", "kibot-runtime-not-ready"],
engine_status=engine_status,
)
self.assertEqual(payload["surface"], "yiacad-web")
self.assertEqual(payload["degraded_reasons"], ["kicad-violations-present", "kibot-runtime-not-ready"])
self.assertIn("kicad", payload["engine_status"])
self.assertIn("freecad", payload["engine_status"])
def test_context_record_exposes_engine_baseline_and_runtime_state(self) -> None:
context = build_context_record(
"yiacad-api",
source_path="hardware/esp32_minimal",
artifacts_dir="artifacts/cad-ai-native/test-run",
)
runtime = context["runtime"]
self.assertEqual(runtime["engine_baseline"]["kicad"], ">=10.0")
self.assertEqual(runtime["engine_baseline"]["freecad"], ">=1.1")
self.assertIn("kicad", runtime["integrated_engines"])
self.assertIn("freecad", runtime["integrated_engines"])
self.assertIn(runtime["integrated_engines"]["kicad"]["status"], {"done", "degraded", "blocked"})
def test_command_output_returns_timeout_instead_of_hanging(self) -> None:
with patch("tools.cad.yiacad_backend.subprocess.run", side_effect=backend.subprocess.TimeoutExpired(cmd=["demo"], timeout=0.1)):
rc, text = backend.command_output(["demo"], timeout_sec=0.1)
self.assertEqual(rc, 124)
self.assertIn("timed out", text)
def test_detect_integrated_engines_uses_freecad_bundle_without_launching_gui(self) -> None:
commands: list[list[str]] = []
def fake_resolve_binary(*candidates):
first = candidates[0]
if first == backend.KICAD_APP_CLI:
return str(backend.KICAD_APP_CLI)
if first == backend.FREECAD_APP_CMD:
return None
if first == backend.FREECAD_APP_GUI:
return str(backend.FREECAD_APP_GUI)
if first == "kibot":
return "/usr/local/bin/kibot"
if first == "pcbnew_do":
return "/usr/local/bin/pcbnew_do"
return None
def fake_command_output(command, timeout_sec=backend.COMMAND_TIMEOUT_SEC):
commands.append(command)
if command[0] == str(backend.KICAD_APP_CLI):
return (0, "10.0.0")
if command[0] == "/usr/local/bin/kibot":
return (0, "KiBot 1.8.5")
if command[0] == "/usr/local/bin/pcbnew_do":
return (0, "pcbnew_do 2.3.5")
raise AssertionError(f"unexpected command: {command}")
with (
patch.object(backend, "resolve_binary", side_effect=fake_resolve_binary),
patch.object(backend, "command_output", side_effect=fake_command_output),
patch.object(backend, "bundle_version", return_value="1.1.0"),
):
engines = backend.detect_integrated_engines()
self.assertEqual(engines["freecad"]["detected_version"], "1.1.0")
self.assertEqual(engines["freecad"]["status"], "done")
self.assertEqual(engines["freecad"]["reason"], "bundle-ready")
self.assertEqual(engines["freecad"]["binary"], str(backend.FREECAD_APP_GUI))
self.assertTrue(all(command[0] != str(backend.FREECAD_APP_GUI) for command in commands))
if __name__ == "__main__":
unittest.main()