feat: integrate calibration extension and self-repair modules

This commit is contained in:
vee
2026-08-07 23:39:45 +08:00
parent 156b10fda1
commit 3bceb0d5a1
41 changed files with 21310 additions and 314 deletions
+174
View File
@@ -0,0 +1,174 @@
from __future__ import annotations
import json
import threading
import urllib.error
import urllib.request
from http.server import ThreadingHTTPServer
import pytest
from cognitive_agent.application.self_repair import SelfRepairService
from cognitive_agent.auth import AuthConfig, AuthRuntime
from cognitive_agent.server import SeatDemoHandler
def _auth_disabled() -> AuthRuntime:
return AuthRuntime(
AuthConfig(
enabled=False,
username="",
password_hash="",
session_secret=b"",
session_ttl_seconds=3600,
login_attempts=5,
login_window_seconds=300,
requests_per_minute=120,
trust_proxy_headers=False,
)
)
class TestSelfRepairApi:
@classmethod
def setup_class(cls) -> None:
cls.repair = SelfRepairService()
cls.original_repair = SeatDemoHandler.repair
cls.original_auth = SeatDemoHandler.auth
SeatDemoHandler.repair = cls.repair
SeatDemoHandler.auth = _auth_disabled()
cls.server = ThreadingHTTPServer(("127.0.0.1", 0), SeatDemoHandler)
cls.thread = threading.Thread(target=cls.server.serve_forever, daemon=True)
cls.thread.start()
cls.base_url = f"http://127.0.0.1:{cls.server.server_port}"
@classmethod
def teardown_class(cls) -> None:
cls.server.shutdown()
cls.server.server_close()
cls.thread.join(timeout=2)
SeatDemoHandler.repair = cls.original_repair
SeatDemoHandler.auth = cls.original_auth
def request(
self,
path: str,
*,
method: str = "GET",
payload: dict[str, object] | None = None,
role: str | None = "admin",
) -> urllib.request.Request:
headers = {"Accept": "application/json"}
data = None
if role is not None:
headers["X-Cognitive-Agent-Role"] = role
if payload is not None:
headers["Content-Type"] = "application/json"
data = json.dumps(payload).encode("utf-8")
return urllib.request.Request(
f"{self.base_url}{path}", method=method, headers=headers, data=data
)
def test_user_cannot_call_self_repair_api(self) -> None:
for request in (
self.request("/api/self-repair/state", role="user"),
self.request(
"/api/self-repair/healing/start",
method="POST",
payload={"case_id": "FI-FIELD-01", "execution_mode": "shadow"},
role="user",
),
):
with pytest.raises(urllib.error.HTTPError) as caught:
urllib.request.urlopen(request, timeout=3)
assert caught.value.code == 403
body = json.loads(caught.value.read().decode("utf-8"))
assert body["error"] == "admin_required"
def test_admin_can_read_and_start_shadow_repair(self) -> None:
with urllib.request.urlopen(
self.request("/api/self-repair/state"), timeout=3
) as response:
state = json.loads(response.read().decode("utf-8"))
assert state["schema"] == "seat-self-healing-console-state-v1"
assert len(state["scenarios"]) == 6
assert state["hardware"]["connector_enabled_count"] == 21
with urllib.request.urlopen(
self.request(
"/api/self-repair/healing/start",
method="POST",
payload={"case_id": "FI-FIELD-01", "execution_mode": "shadow"},
),
timeout=3,
) as response:
started = json.loads(response.read().decode("utf-8"))["healing"]
assert started["case_id"] == "FI-FIELD-01"
assert started["execution_mode"] == "shadow"
assert started["injection_scope"] == "SHADOW_TELEMETRY_ONLY"
with urllib.request.urlopen(
self.request(
"/api/self-repair/healing/reset",
method="POST",
payload={"execution_mode": "shadow"},
),
timeout=3,
) as response:
reset = json.loads(response.read().decode("utf-8"))
assert reset["ok"] is True
assert reset["healing"]["phase"] == "IDLE"
def test_rule_self_test_is_available_without_hardware(self) -> None:
with urllib.request.urlopen(
self.request(
"/api/self-repair/hardware/self-test", method="POST", payload={}
),
timeout=5,
) as response:
result = json.loads(response.read().decode("utf-8"))
assert result["ok"] is True
assert result["self_test"]["result"] == "PASS"
def test_frontend_assets_and_role_transition_are_served(self) -> None:
with urllib.request.urlopen(f"{self.base_url}/", timeout=3) as response:
html = response.read().decode("utf-8")
with urllib.request.urlopen(
f"{self.base_url}/self-repair.js?v=repair-15", timeout=3
) as response:
script = response.read().decode("utf-8")
with urllib.request.urlopen(
f"{self.base_url}/self-repair.css?v=repair-15", timeout=3
) as response:
styles = response.read().decode("utf-8")
with urllib.request.urlopen(
f"{self.base_url}/self-repair-seat3d.js?v=repair-15", timeout=3
) as response:
seat3d = response.read().decode("utf-8")
with urllib.request.urlopen(
f"{self.base_url}/console-v2.js?v=desktop-refactor-28", timeout=3
) as response:
console_script = response.read().decode("utf-8")
assert 'href="/self-repair.css?v=repair-15"' in html
assert 'src="/self-repair.js?v=repair-15"' in html
assert 'src="/self-repair-seat3d.js?v=repair-15"' in html
assert "量产故障用例" in script
assert "connectorRows" in script
assert "Polling refreshes data only" in script
assert "renderRecords();\n showView(activeView);" not in script
assert "--repair-deep-blue" in styles
assert '.console-v2[data-module="self-repair"] .section-kicker' in styles
assert 'grid-template-areas: "twin cases timeline"' in styles
assert "background: color-mix(in srgb, var(--v2-accent-soft) 82%, white)" in styles
assert ".v2-repair-toolbar button.primary:hover:not(:disabled)" in styles
assert "color: #fff;" in styles
assert "seat-healing-state" in seat3d
assert "function backrestShape" in seat3d
assert "new THREE.CapsuleGeometry" in seat3d
assert 'cssThemeColor("--v2-accent", "#315eaa")' in seat3d
assert 'viewer.addEventListener("pointerdown"' in seat3d
assert 'window.addEventListener("pointermove"' in seat3d
assert 'window.addEventListener("self-repair-seat-reset"' in seat3d
assert '["self-calibration", "self-repair"].includes(module)' in console_script
assert 'roleSelect.disabled = ui.activeModule === "self-repair"' in console_script