mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-11-14 16:33:59 +08:00
110 lines
5.5 KiB
Python
110 lines
5.5 KiB
Python
from contextlib import ExitStack
|
|
from types import SimpleNamespace
|
|
from unittest import mock
|
|
|
|
import pytest
|
|
|
|
from openpilot.starpilot.system.android_auto import daemon
|
|
from openpilot.starpilot.galaxy.settings import LiveContextSource
|
|
from openpilot.starpilot.drive_state.tests.test_evidence import Messages
|
|
|
|
|
|
def test_configuration_park_authority_is_fresh_and_releases_physical_observer(tmp_path):
|
|
messages = Messages()
|
|
messages.values['pandaStates'][0].ignitionLine = True
|
|
messages.values['pandaStates'][0].controlsAllowed = True
|
|
messages.values['pandaStates'][0].safetyModel = 'gm'
|
|
source = SimpleNamespace(after_mono_ns=1_000_000_000, snapshot=lambda: messages, sock={})
|
|
from openpilot.common.params import Params
|
|
params = Params(str(tmp_path))
|
|
params.put_bool('IsOffroad', False)
|
|
authority = LiveContextSource(params, messages=source, mono_clock=lambda: 2_100_000_000,
|
|
boot_clock=lambda: 12_100_000_000, evidence_wait_ms=0)
|
|
assert not authority.parked()
|
|
assert authority.configuration_allowed()
|
|
for field, value in [('enabled', True), ('active', True)]:
|
|
setattr(messages.values['selfdriveState'], field, value)
|
|
assert not authority.configuration_allowed()
|
|
setattr(messages.values['selfdriveState'], field, False)
|
|
messages.values['carState'].gearShifter = 'drive'
|
|
assert not authority.configuration_allowed()
|
|
messages.values['carState'].gearShifter = 'park'
|
|
messages.valid['carState'] = False
|
|
assert not authority.configuration_allowed()
|
|
messages.valid['carState'] = True
|
|
assert authority.configuration_allowed()
|
|
physical = authority.physical
|
|
authority.close()
|
|
assert physical.closed and physical.messages is None
|
|
assert authority.physical is None
|
|
assert not authority.configuration_allowed()
|
|
|
|
|
|
@pytest.mark.parametrize('bind_failure', [False, True])
|
|
def test_daemon_uses_configuration_authority_and_cleans_up_after_bind_failure(bind_failure):
|
|
with ExitStack() as patches:
|
|
evidence = mock.Mock()
|
|
evidence.start.return_value = evidence
|
|
authority = mock.Mock()
|
|
bluetooth, supervisor, server = mock.Mock(), mock.Mock(), mock.Mock()
|
|
factories = [
|
|
('openpilot.starpilot.galaxy.evidence.EvidenceSource', evidence),
|
|
('openpilot.starpilot.galaxy.settings.LiveContextSource', authority),
|
|
('openpilot.starpilot.system.android_auto.bluetooth_bridge.SharedBluetoothOwner', bluetooth),
|
|
('openpilot.common.params.Params', mock.Mock()),
|
|
('openpilot.starpilot.system.android_auto.daemon.Supervisor', supervisor),
|
|
]
|
|
calls = {name: patches.enter_context(mock.patch(name, return_value=value)) for name, value in factories}
|
|
patches.enter_context(mock.patch.object(daemon.argparse.ArgumentParser, 'parse_args', return_value=SimpleNamespace(once=False)))
|
|
for name in ('unlink', 'chmod'):
|
|
patches.enter_context(mock.patch.object(daemon.os, name))
|
|
patches.enter_context(mock.patch.object(daemon.signal, 'signal'))
|
|
patches.enter_context(mock.patch.object(daemon.threading, 'Thread'))
|
|
factory = patches.enter_context(mock.patch.object(daemon, 'Server', return_value=server,
|
|
side_effect=OSError('bind failed') if bind_failure else None))
|
|
if bind_failure:
|
|
with pytest.raises(OSError, match='bind failed'):
|
|
daemon.main()
|
|
else:
|
|
assert daemon.main() == 0
|
|
server.serve_forever.assert_called_once()
|
|
server.server_close.assert_called_once()
|
|
assert calls['openpilot.starpilot.system.android_auto.bluetooth_bridge.SharedBluetoothOwner'].call_args.args[0] == authority.configuration_allowed
|
|
assert factory.call_args.args[-1] == authority.configuration_allowed
|
|
for resource in (supervisor, bluetooth, authority, evidence):
|
|
resource.close.assert_called_once()
|
|
|
|
|
|
def test_force_offroad_requires_park_but_force_onroad_accepts_movement(tmp_path):
|
|
from openpilot.starpilot.drive_state.evidence import PhysicalSource
|
|
from openpilot.starpilot.drive_state.owner import DriveStateOwner, Mode, Rejected
|
|
from openpilot.starpilot.drive_state.tests.test_owner import Params, BOOT
|
|
messages = Messages()
|
|
messages.after_mono_ns = 1_000_000_000
|
|
messages.values['pandaStates'][0].ignitionLine = True
|
|
messages.values['pandaStates'][0].controlsAllowed = True
|
|
messages.values['pandaStates'][0].safetyModel = 'gm'
|
|
messages.values['deviceState'] = SimpleNamespace(started=True)
|
|
physical = PhysicalSource(messages, mono=lambda: 2_100_000_000, boot=lambda: 12_100_000_000)
|
|
owner = DriveStateOwner(Params(), tmp_path / 'owner', alive=lambda _: True)
|
|
owner.initialize(pid=1, birth=2, boot=BOOT)
|
|
initial_revision = owner.snapshot().revision
|
|
assert initial_revision is not None
|
|
state = owner.request('offroad', expected_revision=initial_revision,
|
|
authorized=lambda: True, override_allowed=physical.allowed)
|
|
assert state.mode == Mode.OFFROAD
|
|
assert state.revision is not None
|
|
owner.request('auto', expected_revision=state.revision, authorized=lambda: True, override_allowed=physical.allowed)
|
|
messages.values['carState'].standstill = False
|
|
revision = owner.snapshot().revision
|
|
assert revision is not None
|
|
with pytest.raises(Rejected):
|
|
owner.request('offroad', expected_revision=revision,
|
|
authorized=lambda: True, override_allowed=physical.allowed)
|
|
assert owner.snapshot().mode == Mode.AUTO
|
|
state = owner.request('onroad', expected_revision=revision,
|
|
authorized=lambda: True, override_allowed=physical.allowed)
|
|
assert state.mode == Mode.ONROAD
|
|
assert state.revision is not None
|
|
physical.close()
|