Files
StarPilot/openpilot/starpilot/connect/test_developer.py
T
firestar5683 80fbb4f6db Feature registration
Register vehicle controls, planner modes, UI actions and Galaxy services after their providers exist. Wire the shared runtime entrypoints and cover their combined behavior.

Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com>
Co-authored-by: Daniel Koepping <elkoled@gmail.com>
Co-authored-by: Danny <dannyirwin31@yahoo.com>
Co-authored-by: DimitriChrysafis <Dimitri.chrysafis@gmail.com>
Co-authored-by: Dom <168790843+firestar5683@users.noreply.github.com>
Co-authored-by: Harald Schäfer <harald.the.engineer@gmail.com>
Co-authored-by: Kacper Rączy <gfw.kra@gmail.com>
Co-authored-by: Prabhaav Pillai <prabhaav@msu.edu>
Co-authored-by: dirwin31 <83434411+dirwin31@users.noreply.github.com>
Co-authored-by: firestarsdog <229254897+firestarsdog@users.noreply.github.com>
Co-authored-by: stef <19478336+stefpi@users.noreply.github.com>
Co-authored-by: whoisdomi <dcantu83@gmail.com>

Co-authored-by: Intelli <contact@intelli.software>
Co-authored-by: haraschax <6804392+haraschax@users.noreply.github.com>
Co-authored-by: prabhaavp <prabhaav@msu.edu>
2026-10-14 20:02:39 -05:00

139 lines
6.6 KiB
Python

"""Actual local HTTP and native callback entry points, without cloud activation."""
import http.client
import json
import os
import platform
import uuid
from pathlib import Path
import tempfile
import threading
import unittest
from unittest.mock import MagicMock, patch
from openpilot.starpilot.connect import provider
from openpilot.starpilot.galaxy.access import GalaxyAccessOwner
from openpilot.starpilot.galaxy.server import make_server
class TestDeveloperProviderHTTP(unittest.TestCase):
def test_authenticated_confirmed_offroad_pending_and_stale(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
access = GalaxyAccessOwner(root/'access')
access.configure('password123', lambda: True)
cloud_root = root/'cloud'
class Cloud:
def status(self):
return provider.status(cloud_root)
def select(self, name, revision, authorized):
return provider.select_provider(name, revision, authorized, root=cloud_root, boot=lambda: 'test-boot')
offroad = True
server = make_server(port=0, owner=access, parked=lambda: True, cloud_offroad=lambda: offroad, cloud_provider=Cloud())
worker = threading.Thread(target=server.serve_forever, kwargs={'poll_interval': .01}, daemon=True)
worker.start()
def request(path, payload=None, cookie=None):
connection = http.client.HTTPConnection('127.0.0.1', server.server_port, timeout=3)
headers = {'Forwarded': 'for=203.0.113.8', 'Origin': f'http://127.0.0.1:{server.server_port}', 'Content-Type': 'application/json'}
if cookie:
headers['Cookie'] = cookie
try:
connection.request('GET' if payload is None else 'POST', path, None if payload is None else json.dumps(payload), headers)
response = connection.getresponse()
return response.status, json.loads(response.read()), dict(response.getheaders())
finally:
connection.close()
try:
self.assertEqual(request('/api/connect/provider')[0], 401)
code, _, headers = request('/api/auth/login', {'password': 'password123'})
self.assertEqual(code, 200)
cookie = headers['Set-Cookie'].split(';', 1)[0]
code, state, _ = request('/api/connect/provider', cookie=cookie)
self.assertEqual(code, 200)
self.assertTrue(state['canSelect'])
body = {'provider': 'konik', 'revision': state['revision'], 'confirmed': True}
offroad = False
self.assertEqual(request('/api/connect/provider', body, cookie)[0], 403)
offroad = True
self.assertEqual(request('/api/connect/provider', {**body, 'confirmed': False}, cookie)[0], 409)
code, pending, _ = request('/api/connect/provider', body, cookie)
self.assertEqual(code, 200)
self.assertEqual(pending['active'], 'comma')
self.assertEqual(pending['selected'], 'konik')
self.assertTrue(pending['restartRequired'])
self.assertEqual(request('/api/connect/provider', body, cookie)[0], 409)
finally:
server.shutdown()
server.server_close()
worker.join(2)
class TestNativeProviderCallbacks(unittest.TestCase):
@classmethod
def setUpClass(cls):
# Device msgq subscribers require real publishers before native UIState import.
# The installer test process supplies its isolated OPENPILOT_PREFIX namespace.
cls.namespace = patch.dict(os.environ, {
'OPENPILOT_PREFIX': os.environ.get('OPENPILOT_PREFIX') or 'connect-native-' + uuid.uuid4().hex,
'USE_MSGQ_PREFIX': 'true',
})
cls.namespace.start()
cls.addClassCleanup(cls.namespace.stop)
shm_root = Path('/tmp' if platform.system() == 'Darwin' else '/dev/shm')
(shm_root/('msgq_' + os.environ['OPENPILOT_PREFIX'])).mkdir(exist_ok=True)
from openpilot.cereal import messaging
cls.publishers = messaging.PubMaster([
'modelV2', 'controlsState', 'onroadEvents', 'extrinsicsCalibration', 'radarState',
'deviceState', 'pandaStates', 'carParams', 'driverMonitoringState', 'carState',
'driverStateV2', 'narrowRoadCameraState', 'wideRoadCameraState', 'managerState',
'selfdriveState', 'starpilotSelfdriveState', 'starpilotLateralState', 'starpilotNavigation',
'longitudinalPlan', 'gpsLocationExternal', 'carOutput', 'carControl', 'slcState',
'vehicleParameters', 'testJoystick', 'rawAudioData',
])
@classmethod
def tearDownClass(cls):
del cls.publishers
def test_confirmation_rechecks_offroad_and_revision(self):
from openpilot.starpilot.connect import settings
controls = []
def accept(title, icon, callback):
button = MagicMock()
button.callback = callback
controls.append(button)
return button
with (patch.object(settings.NavScroller, '__init__', lambda self: setattr(self, '_scroller', MagicMock())),
patch.object(settings, 'GreyBigButton'), patch.object(settings, 'BigDialog'),
patch.object(settings, 'BigConfirmationCircleButton', side_effect=accept),
patch.object(settings.gui_app, 'texture'), patch.object(settings.gui_app, 'push_widget'),
patch.object(settings.ui_state, 'is_offroad', return_value=False), patch.object(settings, 'select_provider') as select):
page = settings.CloudProviderConfirmation('konik', 'revision', lambda: None)
page.dismiss = MagicMock()
def refuse(name, revision, authorized):
self.assertEqual((name, revision), ('konik', 'revision'))
if not authorized():
raise ValueError('onroad')
select.side_effect = refuse
controls[0].callback()
page.dismiss.assert_not_called()
with patch.object(settings.ui_state, 'is_offroad', return_value=True):
controls[0].callback()
page.dismiss.assert_called_once()
def test_pairing_url_is_provider_bound_and_offline_avoids_key(self):
from openpilot.selfdrive.ui.widgets import pairing_dialog
page = pairing_dialog.PairingDialog.__new__(pairing_dialog.PairingDialog)
page.qr_texture = None
page.params = MagicMock()
page.params.get.return_value = '0123456789abcdef'
with patch.object(pairing_dialog, 'Api') as api:
api.return_value.get_token.return_value = 'pair-token'
for name, expected in (('comma', 'https://connect.comma.ai'), ('konik', 'https://stable.konik.ai')):
with patch.object(pairing_dialog, 'active_provider', return_value=provider.PROVIDERS[name]):
self.assertEqual(page._get_pairing_url(), expected+'/?pair=pair-token')
api.reset_mock()
with patch.object(pairing_dialog, 'active_provider', return_value=provider.OFFLINE):
with self.assertRaises(RuntimeError):
page._get_pairing_url()
api.assert_not_called()