添加无线模块

This commit is contained in:
minghanchen
2026-08-19 09:59:36 +08:00
parent 344f662970
commit 52c4dd08f9
33 changed files with 4740 additions and 246 deletions
+116 -10
View File
@@ -10,6 +10,7 @@ import urllib.request
from http.cookiejar import CookieJar
from http.server import ThreadingHTTPServer
from pathlib import Path
from types import SimpleNamespace
from unittest.mock import patch
from cognitive_agent.auth import AuthConfig, AuthRuntime, hash_password
@@ -177,18 +178,18 @@ operations:
def test_static_console_and_runtime_endpoint(self) -> None:
with self.opener.open(f"{self.base_url}/", timeout=3) as response:
html = response.read().decode("utf-8")
with self.opener.open(f"{self.base_url}/app.js?v=dual-seat-82", timeout=3) as response:
with self.opener.open(f"{self.base_url}/app.js?v=dual-seat-89", timeout=3) as response:
app_script = response.read().decode("utf-8")
with self.opener.open(
f"{self.base_url}/gesture-control.js?v=android-pad-7", timeout=3
) as response:
gesture_script = response.read().decode("utf-8")
with self.opener.open(
f"{self.base_url}/console-v2.js?v=desktop-refactor-36", timeout=3
f"{self.base_url}/console-v2.js?v=desktop-refactor-37", timeout=3
) as response:
console_script = response.read().decode("utf-8")
with self.opener.open(
f"{self.base_url}/console-v2.css?v=desktop-refactor-107", timeout=3
f"{self.base_url}/console-v2.css?v=desktop-refactor-108", timeout=3
) as response:
console_styles = response.read().decode("utf-8")
with self.opener.open(
@@ -231,12 +232,12 @@ operations:
self.assertIn("CMD 0x431 · FB 0x41A · CH1", html)
self.assertIn("CMD 0x431 · FB 0x388 · CH1", html)
self.assertNotIn("透明车体 · 实体设备", html)
self.assertIn('src="/app.js?v=dual-seat-82"', html)
self.assertIn('href="/styles.css?v=dual-seat-9"', html)
self.assertIn('src="/app.js?v=dual-seat-89"', html)
self.assertIn('href="/styles.css?v=dual-seat-10"', html)
self.assertIn('src="/gesture-control.js?v=android-pad-7"', html)
self.assertNotIn('class="vehicle-system-hud"', html)
self.assertIn('src="/console-v2.js?v=desktop-refactor-36"', html)
self.assertIn('href="/console-v2.css?v=desktop-refactor-107"', html)
self.assertIn('src="/console-v2.js?v=desktop-refactor-37"', html)
self.assertIn('href="/console-v2.css?v=desktop-refactor-108"', html)
self.assertIn('src="/self-evolution.js?v=seat-weighing-2"', html)
self.assertIn('href="/self-evolution.css?v=seat-weighing-5"', html)
self.assertIn('src="/self-extension.js?v=extension-21"', html)
@@ -399,7 +400,19 @@ operations:
self.assertIn('const dynamicModeOrder = ["rocking_horse", "dynamic_cradle"]', app_script)
self.assertIn('divider.className = "mode-group-divider"', app_script)
self.assertIn(
'mode === "hardware" && !state.runtime?.hardware_execution_allowed',
'mode === "hardware" && !hardwareExecutionReady',
app_script,
)
self.assertIn('data-control-transport="wired_can"', html)
self.assertIn('data-control-transport="wireless_mqtt"', html)
self.assertIn('control_transport: state.controlTransport', app_script)
self.assertIn('const transportField = $("#vehicleTransportField", originalForm)', console_script)
self.assertIn('configStack.append(transportField)', console_script)
self.assertIn('.console-v2 .v2-transport-field .vehicle-transport-options', console_styles)
self.assertIn('button.disabled = false', app_script)
self.assertIn('button.setAttribute("aria-pressed", String(selected))', app_script)
self.assertNotIn(
'availableTransports.find((item) => item.state_configured)?.id',
app_script,
)
self.assertIn("hardwareButton.disabled = !hardwareExecutionReady", app_script)
@@ -484,7 +497,7 @@ operations:
self.assertIn("window.requestAnimationFrame(initSeatTwin)", app_script)
self.assertIn('canvas.addEventListener("webglcontextlost"', app_script)
self.assertIn('"cognitive-agent:module-change"', app_script)
self.assertIn('const CACHE_VERSION = "cognitive-agent-pad-v120"', service_worker)
self.assertIn('const CACHE_VERSION = "cognitive-agent-pad-v128"', service_worker)
self.assertIn('"/self-evolution.js?v=seat-weighing-2"', service_worker)
self.assertIn('"/self-evolution.css?v=seat-weighing-5"', service_worker)
self.assertIn(
@@ -699,7 +712,7 @@ operations:
) as response:
extension_script = response.read().decode("utf-8")
with self.opener.open(
f"{self.base_url}/app.js?v=dual-seat-82", timeout=3
f"{self.base_url}/app.js?v=dual-seat-89", timeout=3
) as response:
app_script = response.read().decode("utf-8")
@@ -1032,10 +1045,103 @@ operations:
synchronize.assert_called_once_with(
"conv-e2e-physical-state",
"denza_n7",
control_transport="wired_can",
hardware_client_id=None,
hardware_access_bypass=True,
)
def test_wireless_passenger_snapshot_uses_mqtt_can0(self) -> None:
physical_state = {
"position": {
"longitudinal": {
"position_pct": 42,
"position_valid": True,
"motion_state": "stopped",
"fault": False,
}
},
"captured_at": "2026-08-18T00:00:00Z",
"complete": True,
"missing": [],
}
executor = SimpleNamespace(read_physical_state=lambda: dict(physical_state))
with (
patch.object(
self.service,
"vehicle_mqtt_settings",
SimpleNamespace(state_configured=True),
),
patch.object(
self.service._vehicle_mqtt_transport,
"bus",
return_value=object(),
) as mqtt_bus,
patch.object(
self.service,
"_new_hardware_executor",
return_value=executor,
) as new_executor,
patch.object(
self.service.hardware_execution,
"reserve",
side_effect=AssertionError(
"wireless cached state must not reserve the physical bench"
),
),
):
payload = self.service.synchronize_hardware_state(
"conv-e2e-wireless-seat-state",
"denza_n7",
control_transport="wireless_mqtt",
hardware_access_bypass=True,
)
bus_factory = new_executor.call_args.args[0]
bus_factory()
mqtt_bus.assert_called_once_with(channel=0, replay_latest=True)
self.assertTrue(new_executor.call_args.kwargs["remote_transport"])
self.assertEqual(payload["source"], "wireless_mqtt_ch0")
self.assertEqual(payload["control_transport"], "wireless_mqtt")
self.assertEqual(
payload["actuator_state"]["passenger"]["position"]["longitudinal"]["position_pct"],
42,
)
def test_wireless_vehicle_snapshot_does_not_reserve_physical_bench(self) -> None:
snapshot = SimpleNamespace(
feedback_states=(),
observed_ids=frozenset(),
captured_at="2026-08-18T00:00:00Z",
capture_sequence=17,
)
with (
patch.object(
self.service,
"vehicle_mqtt_settings",
SimpleNamespace(state_configured=True),
),
patch.object(
self.service._vehicle_mqtt_transport,
"snapshot",
return_value=snapshot,
),
patch.object(
self.service.hardware_execution,
"reserve",
side_effect=AssertionError(
"wireless cached state must not reserve the physical bench"
),
),
):
payload = self.service.synchronize_vehicle_state(
"conv-e2e-wireless-vehicle-state",
"denza_n7",
control_transport="wireless_mqtt",
hardware_access_bypass=True,
)
self.assertEqual(payload["source"], "wireless_mqtt_ch1")
self.assertEqual(payload["capture_sequence"], 17)
def test_gpt_http_failure_falls_back_without_returning_502(self) -> None:
original_api_key = self.service.openai.api_key
self.service.openai.api_key = "test-key"