Files
StarPilot/openpilot/starpilot/drive_state/tests/test_http.py
T
2026-10-22 10:52:58 -05:00

130 lines
6.7 KiB
Python

from unittest.mock import patch
from pathlib import Path
from types import SimpleNamespace as NS
import tempfile
from openpilot.starpilot.galaxy.tests import test_navigation_http as helpers
from openpilot.starpilot.drive_state.owner import DriveStateOwner, Mode
from openpilot.starpilot.drive_state.control import DriveStateControl
from openpilot.starpilot.drive_state.tests.test_owner import Params, BOOT
class ForceHttpTest(helpers.NavigationHttpTest):
close = helpers.NavigationHttpTest.close
request = helpers.NavigationHttpTest.request
def setUp(self):
temporary = tempfile.TemporaryDirectory()
self.addCleanup(temporary.cleanup)
self.params = Params()
self.drive = DriveStateOwner(self.params, Path(temporary.name) / 'drive', alive=lambda _: True)
self.drive.initialize(pid=1, birth=2, boot=BOOT)
self.allowed = True
self.physical = NS(allowed=lambda: self.allowed, status=lambda **kwargs: {"allowed": self.allowed, "reason": None})
self.control = DriveStateControl(self.drive, self.physical, effective=lambda: False)
original = helpers.make_server
with patch.object(helpers, 'make_server', side_effect=lambda **kwargs: original(**kwargs, drive_state=self.control)):
helpers.NavigationHttpTest.setUp(self)
def drive_action(self, mode, remote=False, revision=None, **kwargs):
return self.request(
'/api/drive-state/action',
payload={'mode': mode, 'revision': revision or self.drive.snapshot().revision},
remote=remote,
cookie=self.remote_cookie if remote else self.local_cookie,
**kwargs,
)
def test_local_remote_same_owner_status_actual_not_requested_and_strict_revision(self):
result = self.drive_action('onroad')
self.assertEqual(result[0], 200)
self.assertEqual((result[1]['mode'], result[1]['effective']), ('onroad', 'offroad'))
status = self.request('/api/drive-state/status', remote=True, cookie=self.remote_cookie)
self.assertEqual(status[1]['revision'], result[1]['revision'])
self.assertEqual(self.drive_action('offroad', remote=True)[0], 200)
self.control.change('offroad', self.drive.snapshot().revision, lambda: True)
self.assertEqual(self.drive_action('auto', revision=result[1]['revision'])[0], 409)
def test_galaxy_requires_park_but_onroad_and_auto_remain_recoverable(self):
self.assertEqual(self.drive_action('offroad')[0], 200)
self.control.change('offroad', self.drive.snapshot().revision, lambda: True)
self.allowed = False
self.assertEqual(self.drive_action('onroad')[0], 200)
self.assertEqual(self.drive.snapshot().mode, Mode.ONROAD)
self.assertEqual(self.drive_action('offroad')[0], 409)
self.assertEqual(self.drive.snapshot().mode, Mode.ONROAD)
self.assertEqual(self.drive_action('auto', remote=True)[0], 200)
self.assertEqual(self.drive.snapshot().mode, Mode.AUTO)
def test_auth_origin_schema_and_midcommit_revocation_write_nothing(self):
before = list(self.params.writes)
self.assertEqual(self.request('/api/drive-state/action', payload={'mode': 'onroad', 'revision': self.drive.snapshot().revision})[0], 401)
self.assertEqual(self.drive_action('onroad', origin='https://unrelated.invalid')[0], 403)
self.assertEqual(self.drive_action('badmode')[0], 409)
self.assertEqual(self.params.writes, before)
original_change = self.control.change_galaxy
def revoke_remote(mode, revision, authorized):
self.assertEqual(mode, 'onroad')
self.assertTrue(authorized())
self.pairing.unpair() # Real HTTP credential changes inside the route's effect lock.
self.assertFalse(authorized())
return original_change(mode, revision, authorized)
with patch.object(self.control, 'change_galaxy', side_effect=revoke_remote):
self.assertEqual(self.drive_action('onroad', remote=True)[0], 409)
self.assertEqual(self.params.writes, before)
def test_native_force_offroad_does_not_query_park_permission_during_commit(self):
def unexpected():
raise AssertionError('Local Force Offroad does not require parked admission')
self.physical.allowed = unexpected
self.control.change('offroad', self.drive.snapshot().revision, lambda: True)
self.assertEqual(self.drive.snapshot().mode, Mode.OFFROAD)
def test_galaxy_offroad_rechecks_park_for_local_and_remote_sessions(self):
for remote in (False, True):
self.allowed = False
before = list(self.params.writes)
self.assertEqual(self.drive_action('offroad', remote=remote)[0], 409)
self.assertEqual(self.params.writes, before)
self.allowed = True
self.assertEqual(self.drive_action('offroad', remote=remote)[0], 200)
self.assertEqual(self.drive_action('auto', remote=remote)[0], 200)
def test_authenticated_force_offroad_from_live_onroad_state(self):
self._force_offroad_from_live_onroad_state(True)
def test_authenticated_force_offroad_with_invalid_can_from_onroad(self):
self._force_offroad_from_live_onroad_state(False)
def _force_offroad_from_live_onroad_state(self, can_valid):
from openpilot.starpilot.drive_state.evidence import PhysicalSource
from openpilot.starpilot.drive_state.tests.test_evidence import Messages
from openpilot.starpilot.drive_state.resolver import should_start
messages = Messages()
messages.after_mono_ns = 1_000_000_000
messages.values['deviceState'] = NS(started=True)
self.enterContext(patch.object(messages.values['carState'], 'canValid', can_valid, create=True))
pandas = messages.values['pandaStates']
assert isinstance(pandas, list)
pandas[0].ignitionLine = True
pandas[0].safetyModel = 'hyundai'
physical = PhysicalSource(messages, mono=lambda: 2_100_000_000, boot=lambda: 12_100_000_000)
self.addCleanup(physical.close)
self.control.physical = physical
self.control.effective = lambda: messages.values['deviceState'].started
status = self.request('/api/drive-state/status', remote=True, cookie=self.remote_cookie)
self.assertEqual(status[1]['effective'], 'onroad')
self.assertEqual(status[1]['overrideAllowed'], can_valid)
result = self.drive_action('offroad', remote=True)
self.assertEqual(result[0], 200 if can_valid else 409)
self.control.change('offroad', self.drive.snapshot().revision, lambda: True)
self.assertEqual(self.drive.snapshot().mode, Mode.OFFROAD)
# hardwared consumes this same owner request through the actual resolver.
messages.values['deviceState'].started = should_start(self.drive.snapshot().mode,
{'ignition': True}, {'ready': True}, already_started=True)
self.assertFalse(messages.values['deviceState'].started)
self.assertEqual(self.request('/api/drive-state/status', remote=True, cookie=self.remote_cookie)[1]['effective'],
'offroad')