mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-11-08 21:43:44 +08:00
120 lines
6.4 KiB
Python
120 lines
6.4 KiB
Python
"""Actual custom Event acknowledgment and historical alert compatibility."""
|
|
|
|
from types import SimpleNamespace as NS
|
|
from dataclasses import replace
|
|
import time
|
|
import unittest
|
|
from unittest.mock import patch
|
|
|
|
from openpilot.cereal import messaging
|
|
from openpilot.starpilot.conditional_mode.consumer import ConsumerResult, ModeConsumer
|
|
from openpilot.starpilot.conditional_mode.effective_status import LIFETIME_NS, observation, publish_ack
|
|
from openpilot.starpilot.conditional_mode.policy import ModeChoice
|
|
from openpilot.starpilot.conditional_mode.status import ModeObservation
|
|
|
|
|
|
NOW = 100_000_000_000
|
|
SESSION = 'a' * 32
|
|
PLANNER = 'b' * 32
|
|
|
|
|
|
def proposal() -> ModeObservation:
|
|
return ModeObservation(PLANNER, 7, NOW - 2_000_000, NOW + 30_000_000, NOW - 1_000_000_000,
|
|
NOW - 20_000_000, NOW - 5_000_000, 3, 'c' * 64, ModeChoice.CEM,
|
|
True, 'proposed', 'cem_speed', 3)
|
|
|
|
|
|
class TestEffectiveStatus(unittest.TestCase):
|
|
def test_actual_selfdrived_publish_joins_emitted_state_and_clears_fallback(self):
|
|
from openpilot.selfdrive.selfdrived.alertmanager import AlertManager
|
|
from openpilot.selfdrive.selfdrived.events import Events
|
|
from openpilot.selfdrive.selfdrived.selfdrived import SelfdriveD, State
|
|
|
|
sent = {}
|
|
daemon = SelfdriveD.__new__(SelfdriveD)
|
|
daemon.enabled = daemon.active = daemon.experimental_mode = True
|
|
daemon.personality = 'standard'
|
|
self.enterContext(patch.object(daemon, "state_machine", NS(state=State.enabled), create=True))
|
|
daemon.events = Events()
|
|
daemon.events_prev = []
|
|
daemon.AM = AlertManager()
|
|
from openpilot.starpilot.aol.runtime import AxisDecision
|
|
daemon.aol_axis_decision = AxisDecision()
|
|
daemon.aol_replay = False
|
|
daemon.conditional_replay = True
|
|
daemon.conditional_ack_session = SESSION
|
|
daemon.conditional_ack_sequence = 0
|
|
sm = type('SM', (dict,), {'frame': 1})()
|
|
self.enterContext(patch.object(daemon, 'sm', sm, create=True))
|
|
current = time.monotonic_ns()
|
|
sm['deviceState'] = NS(startedMonoTime=current - 1_000_000_000)
|
|
self.enterContext(patch.object(daemon, 'pm', NS(send=lambda service, event: sent.__setitem__(service, event.to_bytes())), create=True))
|
|
actual_proposal = replace(proposal(), observed_ns=current - 1_000_000, expires_ns=current + 30_000_000,
|
|
drive_id=current - 1_000_000_000, model_ns=current - 20_000_000,
|
|
car_state_ns=current - 5_000_000)
|
|
daemon.conditional_result = ConsumerResult(True, True, 'proposed')
|
|
daemon.conditional_consumer = ModeConsumer()
|
|
daemon.conditional_consumer.last = actual_proposal
|
|
daemon.publish_selfdriveState(NS(vEgo=12.0))
|
|
state = messaging.log_from_bytes(sent['selfdriveState'])
|
|
ack = messaging.log_from_bytes(sent['starpilotSelfdriveState'])
|
|
value = observation(ack.starpilotSelfdriveState, ack.logMonoTime)
|
|
self.assertIsNotNone(value)
|
|
self.assertEqual(value.selfdrive_state_ns, state.logMonoTime)
|
|
self.assertEqual(value.effective_experimental, state.selfdriveState.experimentalMode)
|
|
self.assertEqual(value.reason, 'cem_speed')
|
|
|
|
daemon.conditional_result = ConsumerResult(False, False, 'unavailable')
|
|
daemon.experimental_mode = False
|
|
daemon.publish_selfdriveState(NS(vEgo=12.0))
|
|
fallback = messaging.log_from_bytes(sent['starpilotSelfdriveState'])
|
|
value = observation(fallback.starpilotSelfdriveState, fallback.logMonoTime)
|
|
self.assertIsNotNone(value)
|
|
self.assertFalse(value.accepted)
|
|
self.assertIsNone(value.reason)
|
|
|
|
def test_serialized_accepted_receipt_binds_actual_mode_and_source_frame(self):
|
|
event = publish_ack(session=SESSION, sequence=4, observed_ns=NOW, selfdrive_state_ns=NOW - 1_000_000,
|
|
drive_id=NOW - 1_000_000_000, effective_experimental=True,
|
|
result=ConsumerResult(True, True, 'proposed'), accepted_proposal=proposal())
|
|
event.starpilotSelfdriveState.alertText1 = 'Keep hands on wheel'
|
|
event.starpilotSelfdriveState.alertStatus = 'userPrompt'
|
|
event.starpilotSelfdriveState.alertSound = 'prompt'
|
|
decoded = messaging.log_from_bytes(event.to_bytes())
|
|
self.assertEqual(decoded.starpilotSelfdriveState.alertText1, 'Keep hands on wheel')
|
|
self.assertEqual(str(decoded.starpilotSelfdriveState.alertStatus), 'userPrompt')
|
|
self.assertEqual(str(decoded.starpilotSelfdriveState.alertSound), 'prompt')
|
|
value = observation(decoded.starpilotSelfdriveState, NOW)
|
|
self.assertIsNotNone(value)
|
|
self.assertTrue(value.accepted)
|
|
self.assertEqual(value.choice, ModeChoice.CEM)
|
|
self.assertEqual(value.selfdrive_state_ns, NOW - 1_000_000)
|
|
self.assertEqual(value.planner_session, PLANNER)
|
|
self.assertEqual(value.reason, 'cem_speed')
|
|
self.assertIsNone(observation(decoded.starpilotSelfdriveState, NOW + LIFETIME_NS + 1))
|
|
|
|
def test_fallback_clears_prior_planner_reason_and_malformed_receipts(self):
|
|
event = publish_ack(session=SESSION, sequence=5, observed_ns=NOW, selfdrive_state_ns=NOW - 1_000_000,
|
|
drive_id=NOW - 1_000_000_000, effective_experimental=False,
|
|
result=ConsumerResult(False, False, 'unavailable'), accepted_proposal=proposal())
|
|
raw = event.to_bytes()
|
|
decoded = messaging.log_from_bytes(raw).starpilotSelfdriveState
|
|
value = observation(decoded, NOW)
|
|
self.assertIsNotNone(value)
|
|
self.assertFalse(value.accepted)
|
|
self.assertIsNone(value.reason)
|
|
self.assertEqual(value.planner_sequence, 0)
|
|
self.assertEqual(value.choice, ModeChoice.STOCK)
|
|
for field, bad in (('version', 2), ('sessionId', ''), ('sequence', 0),
|
|
('sourceSelfdriveStateMonoTime', NOW + 1), ('reason', 'stale reason')):
|
|
changed = messaging.log_from_bytes(raw).as_builder()
|
|
setattr(changed.starpilotSelfdriveState.conditionalModeAck, field, bad)
|
|
with self.subTest(field=field):
|
|
self.assertIsNone(observation(messaging.log_from_bytes(changed.to_bytes()).starpilotSelfdriveState, NOW))
|
|
|
|
def test_accepted_flag_cannot_be_derived_from_cached_proposal(self):
|
|
wrong_mode = publish_ack(session=SESSION, sequence=6, observed_ns=NOW, selfdrive_state_ns=NOW - 1_000_000,
|
|
drive_id=NOW - 1_000_000_000, effective_experimental=False,
|
|
result=ConsumerResult(False, True, 'proposed'), accepted_proposal=proposal())
|
|
self.assertFalse(observation(messaging.log_from_bytes(wrong_mode.to_bytes()).starpilotSelfdriveState, NOW).accepted)
|