merge: sync feature/N7Web into feature/N7Web-Tech
# Conflicts: # apps/web-console/service-worker.js # src/cognitive_agent/application/mode_profile.py # src/cognitive_agent/application/mode_scene_catalog.py # src/cognitive_agent/application/seat_service.py # tests/e2e/test_seat_web_api.py # tests/unit/test_assistant_frontend_contract.py # tests/unit/test_vue_frontend_contract.py
This commit is contained in:
@@ -152,6 +152,12 @@ class SeatWebApiTests(unittest.TestCase):
|
||||
with self.assertRaises(urllib.error.HTTPError) as caught:
|
||||
unauthenticated.open(f"{self.base_url}/api/runtime", timeout=3)
|
||||
self.assertEqual(caught.exception.code, 401)
|
||||
with self.assertRaises(urllib.error.HTTPError) as sync_status_denied:
|
||||
unauthenticated.open(
|
||||
f"{self.base_url}/api/mode-profiles/status",
|
||||
timeout=3,
|
||||
)
|
||||
self.assertEqual(sync_status_denied.exception.code, 401)
|
||||
|
||||
with self.assertRaises(urllib.error.HTTPError) as state_denied:
|
||||
unauthenticated.open(
|
||||
@@ -293,7 +299,9 @@ class SeatWebApiTests(unittest.TestCase):
|
||||
self.assertGreaterEqual(catalog["scene_count"], 13)
|
||||
self.assertEqual(catalog["scene_count"], len(catalog["scenes"]))
|
||||
office = next(scene for scene in catalog["scenes"] if scene["id"] == "office")
|
||||
self.assertIn(office["origin"], {"preset", "customized"})
|
||||
self.assertIn(office["origin"], {"preset", "customized", "n7_mqtt"})
|
||||
if office["origin"] == "n7_mqtt":
|
||||
self.assertEqual(office["source_topic"], "from_n7/scenes")
|
||||
self.assertTrue(office["actions"])
|
||||
self.assertIn("capability", office["actions"][0])
|
||||
self.assertNotIn("command_flow", json.dumps(catalog, ensure_ascii=False))
|
||||
@@ -337,6 +345,19 @@ class SeatWebApiTests(unittest.TestCase):
|
||||
self.assertNotIn("hardware_client_id", payload)
|
||||
self.assertNotIn("private-command-bytes", json.dumps(payload))
|
||||
self.assertNotIn("private transport", json.dumps(payload))
|
||||
def test_mode_profile_sync_status_is_lightweight_and_authenticated(self) -> None:
|
||||
with self.opener.open(
|
||||
f"{self.base_url}/api/mode-profiles/status",
|
||||
timeout=3,
|
||||
) as response:
|
||||
payload = json.loads(response.read().decode("utf-8"))
|
||||
|
||||
self.assertEqual(response.status, 200)
|
||||
self.assertIn("catalog_revision", payload)
|
||||
self.assertIn("scene_count", payload)
|
||||
self.assertIn("mode_scene_ingress", payload)
|
||||
self.assertIn("imported_count", payload["mode_scene_ingress"])
|
||||
self.assertNotIn("modes", payload)
|
||||
|
||||
def test_user_mode_delete_endpoint_removes_only_user_profiles(self) -> None:
|
||||
original_registry = self.service.mode_profiles
|
||||
@@ -964,14 +985,14 @@ operations:
|
||||
vite_entry = (web_console_root / "src" / "main.js").read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
with self.opener.open(f"{self.base_url}/app.js?v=dual-seat-141", timeout=3) as response:
|
||||
with self.opener.open(f"{self.base_url}/app.js?v=dual-seat-145-n7-dispatch", 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-9", timeout=3
|
||||
) as response:
|
||||
gesture_script = response.read().decode("utf-8")
|
||||
with self.opener.open(
|
||||
f"{self.base_url}/console-v2.js?v=local-first-76", timeout=3
|
||||
f"{self.base_url}/console-v2.js?v=local-first-77-performance", timeout=3
|
||||
) as response:
|
||||
console_script = response.read().decode("utf-8")
|
||||
with self.opener.open(
|
||||
@@ -991,7 +1012,7 @@ operations:
|
||||
) as response:
|
||||
speech_worklet = response.read().decode("utf-8")
|
||||
with self.opener.open(
|
||||
f"{self.base_url}/self-extension.js?v=pet-settings-52", timeout=3
|
||||
f"{self.base_url}/self-extension.js?v=pet-settings-53-performance", timeout=3
|
||||
) as response:
|
||||
extension_script = response.read().decode("utf-8")
|
||||
with self.opener.open(
|
||||
@@ -1003,7 +1024,7 @@ operations:
|
||||
) as response:
|
||||
assistant_script = response.read().decode("utf-8")
|
||||
with self.opener.open(
|
||||
f"{self.base_url}/energy-monitor.js?v=energy-monitor-4", timeout=3
|
||||
f"{self.base_url}/energy-monitor.js?v=energy-monitor-5-performance", timeout=3
|
||||
) as response:
|
||||
energy_script = response.read().decode("utf-8")
|
||||
with self.opener.open(
|
||||
@@ -1050,10 +1071,10 @@ operations:
|
||||
self.assertIn("CMD 0x431 · FB 0x41A · CH1", template)
|
||||
self.assertIn("CMD 0x431 · FB 0x388 · CH1", template)
|
||||
self.assertNotIn("透明车体 · 实体设备", template)
|
||||
self.assertIn('src="/app.js?v=dual-seat-141"', html)
|
||||
self.assertIn('src="/app.js?v=dual-seat-145-n7-dispatch"', html)
|
||||
self.assertIn('import "../styles.css";', vite_entry)
|
||||
self.assertNotIn('class="vehicle-system-hud"', template)
|
||||
self.assertIn('src="/console-v2.js?v=local-first-76"', html)
|
||||
self.assertIn('src="/console-v2.js?v=local-first-77-performance"', html)
|
||||
self.assertIn('import "../console-v2.css";', vite_entry)
|
||||
self.assertIn('src="/speech-input.js?v=sensevoice-13"', html)
|
||||
self.assertIn('import "../speech-input.css";', vite_entry)
|
||||
@@ -1062,7 +1083,7 @@ operations:
|
||||
self.assertIn('<body class="console-v2">', html)
|
||||
self.assertIn('id="v2BootScreen"', template)
|
||||
self.assertIn('正在加载车机控制与实时状态', template)
|
||||
self.assertIn('src="/self-extension.js?v=pet-settings-52"', html)
|
||||
self.assertIn('src="/self-extension.js?v=pet-settings-53-performance"', html)
|
||||
self.assertIn('import "../self-extension.css";', vite_entry)
|
||||
self.assertNotIn("self-calibration", template)
|
||||
self.assertNotIn("self-repair", template)
|
||||
@@ -1073,7 +1094,7 @@ operations:
|
||||
self.assertIn('import "../assistant-chat.css";', vite_entry)
|
||||
self.assertIn('src="/assistant-chat.js?v=codex-assistant-34"', html)
|
||||
self.assertIn('import "../energy-monitor.css";', vite_entry)
|
||||
self.assertIn('src="/energy-monitor.js?v=energy-monitor-4"', html)
|
||||
self.assertIn('src="/energy-monitor.js?v=energy-monitor-5-performance"', html)
|
||||
self.assertIn('import "../codepen-glass-theme.css";', vite_entry)
|
||||
self.assertEqual(extension_control_status["source_label"], "车端 MQTT")
|
||||
self.assertIn("action_statuses", extension_control_status)
|
||||
@@ -1363,16 +1384,16 @@ operations:
|
||||
self.assertIn('canvas.addEventListener("webglcontextlost"', app_script)
|
||||
self.assertIn('"cognitive-agent:module-change"', app_script)
|
||||
self.assertIn(
|
||||
'const CACHE_VERSION = "cognitive-agent-pad-v318-tech-nfc-routing"',
|
||||
'const CACHE_VERSION = "cognitive-agent-pad-v322-tech-n7-dispatch"',
|
||||
service_worker,
|
||||
)
|
||||
self.assertIn('/console-v2.css?v=delivery-state-69', service_worker)
|
||||
self.assertIn('/console-v2.js?v=local-first-76', service_worker)
|
||||
self.assertIn('/console-v2.js?v=local-first-77-performance', service_worker)
|
||||
self.assertIn('/assistant-chat.css?v=codex-assistant-29', service_worker)
|
||||
self.assertIn('/assistant-chat.js?v=codex-assistant-34', service_worker)
|
||||
self.assertIn('/energy-monitor.css?v=energy-monitor-4', service_worker)
|
||||
self.assertIn('/energy-monitor.js?v=energy-monitor-4', service_worker)
|
||||
self.assertIn('"/app.js?v=dual-seat-141"', service_worker)
|
||||
self.assertIn('/energy-monitor.js?v=energy-monitor-5-performance', service_worker)
|
||||
self.assertIn('"/app.js?v=dual-seat-145-n7-dispatch"', service_worker)
|
||||
self.assertIn('"/speech-input.js?v=sensevoice-13"', service_worker)
|
||||
self.assertIn('"/speech-input.css?v=sensevoice-7"', service_worker)
|
||||
self.assertIn('"/speech-audio-worklet.js?v=sensevoice-5"', service_worker)
|
||||
@@ -1832,7 +1853,7 @@ operations:
|
||||
) as response:
|
||||
extension_script = response.read().decode("utf-8")
|
||||
with self.opener.open(
|
||||
f"{self.base_url}/app.js?v=dual-seat-141", timeout=3
|
||||
f"{self.base_url}/app.js?v=dual-seat-145-n7-dispatch", timeout=3
|
||||
) as response:
|
||||
app_script = response.read().decode("utf-8")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user