mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-11-08 13:33:42 +08:00
129 lines
5.8 KiB
Python
129 lines
5.8 KiB
Python
import http.client
|
|
import json
|
|
from pathlib import Path
|
|
import tempfile
|
|
import threading
|
|
import time
|
|
import unittest
|
|
from typing import TypedDict
|
|
|
|
from openpilot.common.params import Params
|
|
from openpilot.starpilot.galaxy.access import GalaxyAccessOwner
|
|
from openpilot.starpilot.galaxy.onroad_layout import OnroadLayoutOwner
|
|
from openpilot.starpilot.galaxy.server import make_server
|
|
from openpilot.starpilot.ui.layout_preview_transport import PreviewService
|
|
from openpilot.starpilot.ui.onroad_customization import PARAM_KEY, default_document
|
|
from openpilot.starpilot.ui.tests.test_layout_preview_transport import png
|
|
|
|
|
|
class PreviewPayload(TypedDict):
|
|
document: dict
|
|
profile: str
|
|
scene: str
|
|
|
|
|
|
class TestLayoutPreviewHttp(unittest.TestCase):
|
|
def setUp(self):
|
|
temp = tempfile.TemporaryDirectory()
|
|
self.addCleanup(temp.cleanup)
|
|
root = Path(temp.name)
|
|
self.socket_path = root / 'ui.sock'
|
|
self.params = Params(str(root / 'params'))
|
|
self.parked = True
|
|
self.owner = OnroadLayoutOwner(self.params, lambda: self.parked)
|
|
self.rendered = []
|
|
self.preview = PreviewService(lambda payload: self.rendered.append(payload) or png(),
|
|
lambda: self.parked, self.socket_path, active_profile='large')
|
|
self.preview.start()
|
|
self.addCleanup(self.preview.close)
|
|
self.server = make_server(port=0, owner=GalaxyAccessOwner(root / 'access'), layouts=self.owner,
|
|
layout_preview_socket=self.socket_path)
|
|
self.worker = threading.Thread(target=self.server.serve_forever, kwargs={'poll_interval': .01}, daemon=True)
|
|
self.worker.start()
|
|
self.addCleanup(self.stop)
|
|
self.payload: PreviewPayload = {'document': default_document(), 'profile': 'large', 'scene': 'aol'}
|
|
|
|
def stop(self):
|
|
self.server.shutdown()
|
|
self.worker.join(timeout=2)
|
|
self.server.server_close()
|
|
|
|
def request(self, path, payload=None, cookie='', *, origin=None, raw=None):
|
|
connection = http.client.HTTPConnection('127.0.0.1', self.server.server_port, timeout=4)
|
|
headers = {'Cookie': cookie}
|
|
body = raw if raw is not None else json.dumps(payload) if payload is not None else None
|
|
if body is not None:
|
|
headers.update({'Content-Type': 'application/json', 'Origin': origin or f'http://127.0.0.1:{self.server.server_port}'})
|
|
try:
|
|
connection.request('POST' if body is not None else 'GET', path, body=body, headers=headers)
|
|
response = connection.getresponse()
|
|
return response.status, response.read(), dict(response.getheaders())
|
|
finally:
|
|
connection.close()
|
|
|
|
def login(self):
|
|
status, _, headers = self.request('/api/auth/session')
|
|
self.assertEqual(status, 200)
|
|
return headers['Set-Cookie'].split(';', 1)[0]
|
|
|
|
def preview_with_pump(self, cookie):
|
|
outcome = {}
|
|
client = threading.Thread(target=lambda: outcome.setdefault('response', self.request('/api/ui/layout/preview', self.payload, cookie)))
|
|
client.start()
|
|
deadline = time.monotonic() + 4
|
|
while client.is_alive() and time.monotonic() < deadline:
|
|
self.preview.poll()
|
|
client.join(0.01)
|
|
self.assertFalse(client.is_alive())
|
|
return outcome['response']
|
|
|
|
def test_live_profile_png_and_no_saved_write(self):
|
|
cookie = self.login()
|
|
status, body, _ = self.request('/api/ui/layout', cookie=cookie)
|
|
self.assertEqual(status, 200)
|
|
self.assertEqual(json.loads(body)['activeProfile'], 'large')
|
|
status, body, headers = self.preview_with_pump(cookie)
|
|
self.assertEqual(status, 200)
|
|
self.assertEqual(headers['Content-Type'], 'image/png')
|
|
self.assertEqual(headers['Cache-Control'], 'no-store')
|
|
self.assertEqual(body, png())
|
|
self.assertEqual(self.rendered, [self.payload])
|
|
self.assertIsNone(self.params.get(PARAM_KEY))
|
|
self.preview.close()
|
|
status, body, _ = self.request('/api/ui/layout', cookie=cookie)
|
|
self.assertEqual(status, 200)
|
|
self.assertIsNone(json.loads(body)['activeProfile'])
|
|
self.assertEqual(self.request('/api/ui/layout/preview', self.payload, cookie)[0], 503)
|
|
|
|
def test_auth_shape_origin_and_fresh_parked_guards(self):
|
|
cookie = self.login()
|
|
self.assertEqual(self.request('/api/ui/layout/preview', self.payload)[0], 401)
|
|
self.assertEqual(self.request('/api/ui/layout/preview', self.payload, cookie, origin='http://evil.example')[0], 403)
|
|
self.assertEqual(self.request('/api/ui/layout/preview', {**self.payload, 'extra': 1}, cookie)[0], 400)
|
|
self.assertEqual(self.request('/api/ui/layout/preview', {**self.payload, 'scene': 'unknown'}, cookie)[0], 400)
|
|
self.assertEqual(self.request('/api/ui/layout/preview', {**self.payload, 'art': 'widgets'}, cookie)[0], 400)
|
|
self.assertEqual(self.request('/api/ui/layout/preview', {**self.payload, 'document': {'version': 99}}, cookie)[0], 400)
|
|
self.assertEqual(self.request('/api/ui/layout/preview', cookie=cookie,
|
|
raw='{"scene":"aol","scene":"engaged"}')[0], 400)
|
|
self.parked = False
|
|
self.assertEqual(self.request('/api/ui/layout/preview', self.payload, cookie)[0], 403)
|
|
self.assertEqual(self.rendered, [])
|
|
self.parked = True
|
|
self.preview.renderer = lambda payload: (setattr(self, 'parked', False), png())[1]
|
|
self.assertEqual(self.preview_with_pump(cookie)[0], 403)
|
|
self.assertIsNone(self.params.get(PARAM_KEY))
|
|
|
|
def test_sidebar_draft_reaches_renderer_without_saving(self):
|
|
cookie = self.login()
|
|
self.payload['document']['developerSidebar'] = False
|
|
self.assertEqual(self.preview_with_pump(cookie)[0], 200)
|
|
self.assertEqual(self.rendered, [self.payload])
|
|
self.assertIsNone(self.params.get('DeveloperSidebar'))
|
|
self.assertIsNone(self.params.get(PARAM_KEY))
|
|
self.payload['document']['developerSidebar'] = 'Off'
|
|
self.assertEqual(self.request('/api/ui/layout/preview', self.payload, cookie)[0], 400)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|