Files
firestar5683 8b7c2b5f36 oo buddy boy
2026-07-20 13:18:27 -05:00

342 lines
12 KiB
Python

import json
from openpilot.common.params import ParamKeyType
from test_dashboard_stats import MODULE_DIR, _install_server_import_stubs
def _load_server_module():
import importlib.util
_install_server_import_stubs()
spec = importlib.util.spec_from_file_location("navigation_params_server", MODULE_DIR / "the_galaxy.py")
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
the_galaxy = _load_server_module()
class FakeParamsBackend:
def __init__(self, key_types=None, default_values=None, values=None):
self.key_types = key_types or {}
self.default_values = default_values or {}
self.values = values or {}
self.writes = []
def get_key_type(self, key):
return self.key_types[key]
def get_default_value(self, key):
return self.default_values.get(key)
def put(self, key, value):
self.writes.append((key, value))
self.values[key] = value
def put_bool(self, key, value):
self.writes.append((key, bool(value)))
self.values[key] = bool(value)
def get(self, key, block=False):
return self.values.get(key)
class WritableFakeParams:
def __init__(self, values=None):
self.values = dict(values or {})
self.writes = []
self.removals = []
def get(self, key, encoding=None, default=None, block=False):
del encoding, block
return self.values.get(key, default)
def get_bool(self, key):
value = self.values.get(key, False)
if isinstance(value, bool):
return value
return str(value).strip().lower() in ("1", "true", "yes", "on")
def put(self, key, value):
self.writes.append((key, value))
self.values[key] = value
def put_bool(self, key, value):
self.writes.append((key, bool(value)))
self.values[key] = bool(value)
def get_int(self, key, default=0):
return int(self.values.get(key, default))
def put_int(self, key, value):
self.writes.append((key, int(value)))
self.values[key] = int(value)
def remove(self, key):
self.removals.append(key)
self.values.pop(key, None)
def _params_client(monkeypatch, values, device_type):
fake_params = WritableFakeParams(values)
monkeypatch.setattr(the_galaxy, "params", fake_params)
monkeypatch.setattr(
the_galaxy,
"_get_param_type_info",
lambda: ({"UseOldUI", "TryRaylibUI"}, {"UseOldUI": bool, "TryRaylibUI": bool}),
)
monkeypatch.setattr(the_galaxy.HARDWARE, "get_device_type", lambda: device_type)
monkeypatch.setattr(the_galaxy.Paths, "comma_home", lambda: "/tmp/dashboard-test-home", raising=False)
assert the_galaxy._import_galaxy_web_symbols()
app = the_galaxy.Flask(f"params_test_{device_type}")
the_galaxy.setup(app)
return app.test_client(), fake_params
def test_params_compat_accepts_json_strings_for_json_keys():
backend = FakeParamsBackend(
key_types={"FavoriteDestinations": ParamKeyType.JSON},
default_values={"FavoriteDestinations": []},
)
compat = the_galaxy.ParamsCompat(backend)
compat.put("FavoriteDestinations", json.dumps([{"name": "Home"}]))
assert backend.writes == [("FavoriteDestinations", [{"name": "Home"}])]
def test_params_compat_syncs_lead_indicator_inverse_key():
backend = FakeParamsBackend()
compat = the_galaxy.ParamsCompat(backend)
compat.put_bool("LeadIndicator", True)
assert backend.writes == [("LeadIndicator", True), ("HideLeadMarker", False)]
def test_params_compat_syncs_hide_lead_marker_inverse_key():
backend = FakeParamsBackend()
compat = the_galaxy.ParamsCompat(backend)
compat.put_bool("HideLeadMarker", True)
assert backend.writes == [("HideLeadMarker", True), ("LeadIndicator", False)]
def test_navigation_last_position_uses_recent_persisted_fix(monkeypatch):
recent_payload = json.dumps({
"latitude": 41.0,
"longitude": -87.0,
"hasFix": True,
"updatedAtSec": 10_000.0,
})
memory_backend = FakeParamsBackend(values={"LastGPSPosition": ""})
persisted_backend = FakeParamsBackend(values={"LastGPSPosition": recent_payload})
monkeypatch.setattr(the_galaxy, "params_memory", the_galaxy.ParamsCompat(memory_backend))
monkeypatch.setattr(the_galaxy, "params", the_galaxy.ParamsCompat(persisted_backend))
monkeypatch.setattr(the_galaxy.time, "time", lambda: 10_300.0)
monkeypatch.setattr(the_galaxy, "system_time_valid", lambda: True)
position = the_galaxy._get_navigation_last_position()
assert position["latitude"] == 41.0
assert position["longitude"] == -87.0
def test_navigation_last_position_rejects_stale_persisted_fix(monkeypatch):
stale_payload = json.dumps({
"latitude": 41.0,
"longitude": -87.0,
"hasFix": True,
"updatedAtSec": 10_000.0,
})
memory_backend = FakeParamsBackend(values={"LastGPSPosition": ""})
persisted_backend = FakeParamsBackend(values={"LastGPSPosition": stale_payload})
monkeypatch.setattr(the_galaxy, "params_memory", the_galaxy.ParamsCompat(memory_backend))
monkeypatch.setattr(the_galaxy, "params", the_galaxy.ParamsCompat(persisted_backend))
monkeypatch.setattr(the_galaxy.time, "time", lambda: 10_000.0 + the_galaxy.NAVIGATION_PERSISTED_LOCATION_MAX_AGE_SECONDS + 1.0)
monkeypatch.setattr(the_galaxy, "system_time_valid", lambda: True)
assert the_galaxy._get_navigation_last_position() is None
def test_save_longitudinal_maneuver_status_writes_json_param_as_dict(monkeypatch):
fake_params = WritableFakeParams()
monkeypatch.setattr(the_galaxy, "params", fake_params)
saved = the_galaxy._save_longitudinal_maneuver_status({
"state": "armed",
"history": ["", "Started"],
})
assert fake_params.writes == [("LongitudinalManeuverStatus", saved)]
assert isinstance(fake_params.writes[0][1], dict)
assert saved["history"] == ["Started"]
def test_save_lateral_maneuver_status_writes_json_param_as_dict(monkeypatch):
fake_params = WritableFakeParams()
monkeypatch.setattr(the_galaxy, "params", fake_params)
saved = the_galaxy._save_lateral_maneuver_status({
"state": "armed",
"history": ["", "Started"],
})
assert fake_params.writes == [("LateralManeuverStatus", saved)]
assert isinstance(fake_params.writes[0][1], dict)
assert saved["history"] == ["Started"]
def test_galaxy_session_value_matches_cookie_format():
assert the_galaxy._build_galaxy_session_value(
"testGalaxySlug01",
"a" * 64,
) == f"testGalaxySlug01%3A{'a' * 64}"
def test_configured_favorite_slot_values_only_reads_selected_keys(monkeypatch):
fake_params = WritableFakeParams({
"NavDesiresAllowed": False,
"RedneckCruise": True,
"UnusedToggle": True,
})
monkeypatch.setattr(the_galaxy, "params", fake_params)
values = the_galaxy._configured_favorite_slot_values([
{"enabled": True, "key": "NavDesiresAllowed"},
{"enabled": False, "key": "RedneckCruise"},
{"enabled": False, "key": None},
])
assert values == {"NavDesiresAllowed": False, "RedneckCruise": True}
def test_favorite_values_endpoint_returns_current_selected_value(monkeypatch):
client, _ = _params_client(monkeypatch, {"UseOldUI": False}, "tici")
monkeypatch.setattr(the_galaxy, "_get_favorite_slot_options", lambda: [{"key": "UseOldUI"}])
monkeypatch.setattr(
the_galaxy,
"normalize_favorite_slots",
lambda *args, **kwargs: [{"enabled": True, "key": "UseOldUI"}],
)
response = client.get("/api/favorites/values")
assert response.status_code == 200
assert response.get_json() == {"values": {"UseOldUI": False}}
def test_favorite_slot_options_include_virtual_cruise_actions(monkeypatch):
monkeypatch.setattr(the_galaxy, "_favorite_slot_options", None)
monkeypatch.setattr(the_galaxy, "_get_param_type_info", lambda: (set(), {}))
options = the_galaxy._get_favorite_slot_options()
option_keys = {option["key"] for option in options}
assert "__starpilot_favorite_action__:distance_decrease" in option_keys
assert "__starpilot_favorite_action__:distance_increase" in option_keys
def test_favorite_action_endpoint_increments_virtual_button_counter(monkeypatch):
client, _ = _params_client(monkeypatch, {}, "tici")
fake_memory = WritableFakeParams()
monkeypatch.setattr(the_galaxy, "params_memory", fake_memory)
response = client.post("/api/favorites/action", json={"key": "__starpilot_favorite_action__:distance_increase"})
assert response.status_code == 200
assert fake_memory.get_int("FavoriteVirtualAccelCruiseCounter") == 1
def test_use_old_ui_is_noop_on_c4_mici(monkeypatch):
client, fake_params = _params_client(monkeypatch, {"UseOldUI": False, "IsOnroad": False}, "mici")
response = client.put("/api/params", json={"key": "UseOldUI", "value": True})
payload = response.get_json()
assert response.status_code == 200
assert payload["updated"] == {"UseOldUI": False, "TryRaylibUI": False}
assert fake_params.values["UseOldUI"] is False
assert fake_params.writes == []
def test_use_old_ui_writes_on_big_device_offroad(monkeypatch):
client, fake_params = _params_client(monkeypatch, {"UseOldUI": False, "TryRaylibUI": True, "IsOnroad": False}, "tici")
response = client.put("/api/params", json={"key": "UseOldUI", "value": True})
payload = response.get_json()
assert response.status_code == 200
assert payload["updated"] == {"UseOldUI": True, "TryRaylibUI": False}
assert fake_params.values["UseOldUI"] is True
assert fake_params.values["TryRaylibUI"] is False
assert fake_params.writes == [("UseOldUI", True), ("TryRaylibUI", False)]
def test_use_old_ui_rejects_big_device_onroad_change(monkeypatch):
client, fake_params = _params_client(monkeypatch, {"UseOldUI": False, "TryRaylibUI": True, "IsOnroad": True}, "tici")
response = client.put("/api/params", json={"key": "UseOldUI", "value": True})
assert response.status_code == 403
assert response.get_json()["error"] == "Cannot change Use Old UI while driving."
assert fake_params.values["UseOldUI"] is False
assert fake_params.values["TryRaylibUI"] is True
assert fake_params.writes == []
def test_legacy_try_raylib_ui_payload_updates_use_old_ui(monkeypatch):
client, fake_params = _params_client(monkeypatch, {"UseOldUI": True, "TryRaylibUI": False, "IsOnroad": False}, "tici")
response = client.put("/api/params", json={"key": "TryRaylibUI", "value": True})
payload = response.get_json()
assert response.status_code == 200
assert payload["updated"] == {"UseOldUI": False, "TryRaylibUI": True}
assert fake_params.values["UseOldUI"] is False
assert fake_params.values["TryRaylibUI"] is True
assert fake_params.writes == [("UseOldUI", False), ("TryRaylibUI", True)]
def test_curve_speed_controller_reset_clears_learned_data_offroad(monkeypatch):
client, fake_params = _params_client(monkeypatch, {
"IsOnroad": False,
"CalibratedLateralAcceleration": 2.73,
"CalibrationProgress": 48.0,
"CurvatureData": {"0.01": {"average": 2.73, "count": 12}},
}, "tici")
response = client.post("/api/curve_speed_controller/reset")
assert response.status_code == 200
assert response.get_json()["updated"] == {
"CalibratedLateralAcceleration": 2.0,
"CalibrationProgress": 0.0,
}
assert fake_params.values["CalibratedLateralAcceleration"] == 2.0
assert "CalibrationProgress" not in fake_params.values
assert "CurvatureData" not in fake_params.values
assert fake_params.removals == ["CalibrationProgress", "CurvatureData"]
def test_curve_speed_controller_reset_rejected_onroad(monkeypatch):
client, fake_params = _params_client(monkeypatch, {
"IsOnroad": True,
"CalibratedLateralAcceleration": 2.73,
"CalibrationProgress": 48.0,
"CurvatureData": {"0.01": {"average": 2.73, "count": 12}},
}, "tici")
response = client.post("/api/curve_speed_controller/reset")
assert response.status_code == 403
assert response.get_json()["error"] == "Curve Speed Controller data can only be reset while parked."
assert fake_params.writes == []
assert fake_params.removals == []