Files
StarPilot/openpilot/starpilot/aol/tests/test_availability_intent_continuation.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

83 lines
4.8 KiB
Python

from contextlib import ExitStack
from dataclasses import replace
import pytest
from openpilot.cereal import messaging
from openpilot.common.prefix import OpenpilotPrefix
from openpilot.starpilot.aol.tests import test_ioniq_availability as fixture
from openpilot.starpilot.aol.tests.test_input_deadline_continuity import BASE, intent
from openpilot.starpilot.aol.wire import decode_safety, encode_safety
@pytest.mark.parametrize('condition', ['healthy', 'native_denial', 'native_invalid', 'native_expired',
'inventory', 'epoch', 'hard_event', 'mismatched_event', 'stale_off_proof'])
def test_verified_intent_continuation_past_old_source_bound_has_current_vetoes(condition):
case = fixture.IoniqAvailabilityTests(methodName='runTest')
with ExitStack() as cleanup:
cleanup.callback(case.doCleanups)
cleanup.enter_context(OpenpilotPrefix())
sd, _, drive, card, receive = case._ioniq_availability_callers(full_op=True)
original, _, _ = drive(2, state_stamp=BASE, offset_ns=4_497_535, intent_message=intent(BASE, 3))
assert receive(BASE+4_497_535, axis=sd.pm.messages['aolAxisState'], event=sd.pm.messages['onroadEvents'])
original_deadline = original.validUntilMonoTime
axis, _, command = drive(5, timeout=True, offset_ns=5_399_000, intent_message=intent(BASE, 3))
assert axis.sourceCarStateMonoTime == 0 and not axis.lateralActive and not axis.longitudinalActive
assert not command.latActive and not command.longActive
assert receive(BASE+35_399_000, axis=sd.pm.messages['aolAxisState'], event=sd.pm.messages['onroadEvents'])
feedback = card.aol_transport_feedback
assert feedback.retention_verified
baseline = (feedback.lateral_source_ns, feedback.lateral_baseline_ns)
# Continue with fresh OFF proofs and native grants, beyond the ORIGINAL
# source/command lifetime, while ordinary StateMachine remains responsible.
for tick in range(6, 31):
axis, _, command = drive(tick, timeout=True, intent_message=intent(BASE, 3))
if tick < 30:
assert receive(10_000_000_000+tick*10_000_000,
axis=sd.pm.messages['aolAxisState'], event=sd.pm.messages['onroadEvents'])
now = 10_300_000_000
assert now > baseline[0]+200_000_000 and now > original_deadline
assert not axis.lateralActive and not axis.longitudinalActive
assert not command.latActive and not command.longActive
proof = sd.pm.messages['aolAxisState'].as_builder()
event = sd.pm.messages['onroadEvents'].as_builder()
if condition in ('native_denial', 'native_expired', 'inventory', 'native_invalid'):
native = decode_safety(sd.sm['aolSafetyWire'])
if condition == 'native_denial':
native = replace(native, lateralAllowed=False)
elif condition == 'native_expired':
native = replace(native, observedMonoTime=now-200_000_001, validUntilMonoTime=now-1)
elif condition == 'inventory':
native = replace(native, pandaSerial='other-native',
pandaInventory=tuple(replace(slot, hardwareSerial='other-native') for slot in native.pandaInventory))
message = messaging.new_message('aolSafetyWire', 0, valid=condition != 'native_invalid',
logMonoTime=native.observedMonoTime)
message.aolSafetyWire = encode_safety(native)
sd.sm.update_msgs(now/1e9, [message.as_reader()])
elif condition == 'epoch':
proof.aolAxisState.intentIntegrityEpoch += 1
elif condition == 'hard_event':
event = messaging.new_message('onroadEvents', 1, valid=True, logMonoTime=proof.aolAxisState.faultEventMonoTime)
event.onroadEvents[0].name = 'controlsMismatch'
event.onroadEvents[0].immediateDisable = True
elif condition == 'mismatched_event':
# A new event whose prior unmatched join already exceeded its immutable
# 30ms bound cannot inherit the continuing verified episode indefinitely.
event.logMonoTime = proof.aolAxisState.faultEventMonoTime+1
assert receive(now, axis=proof.as_reader(), event=event.as_reader())
join_start = feedback.retention_started_ns
assert join_start == now
now += 30_000_001
# Keep the OFF proof itself fresh, so failure isolates the prior join
# bound instead of accidentally retesting ordinary proof expiry.
proof.logMonoTime = proof.aolAxisState.observedMonoTime = now
proof.aolAxisState.validUntilMonoTime = now+30_000_000
proof.aolAxisState.sequence += 1
elif condition == 'stale_off_proof':
now = proof.aolAxisState.validUntilMonoTime+1
latched = receive(now, axis=proof.as_reader(), event=event.as_reader())
assert latched == (condition == 'healthy')
assert card.aol_card_intent.allowed_latch == (condition == 'healthy')
if condition == 'healthy':
assert baseline == (feedback.lateral_source_ns, feedback.lateral_baseline_ns)
assert original.validUntilMonoTime == original_deadline