添加无线模块
This commit is contained in:
+116
-10
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user