mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-11-08 13:33:42 +08:00
90 lines
3.8 KiB
Python
90 lines
3.8 KiB
Python
from dataclasses import replace
|
|
from unittest import mock
|
|
import pytest
|
|
from openpilot.starpilot.flm import effect_trace
|
|
from openpilot.starpilot.flm.tests.test_selected_effect_owner import fixture, NOW
|
|
from openpilot.starpilot.flm.torque_adapter import Admission
|
|
|
|
|
|
def trace():
|
|
owner, p, v, context = fixture()
|
|
owner.prepare(Admission(p, NOW, True, False, True, v), active=True, current_context=context)
|
|
return owner.trace
|
|
|
|
|
|
def test_same_sender_trace_skips_only_duplicate_immutable_validation():
|
|
value = trace()
|
|
with mock.patch('openpilot.starpilot.flm.effect_admission_cache.validated_envelope', side_effect=AssertionError('duplicate immutable validation')):
|
|
assert value.validate() is value
|
|
# A new decoded/receiver object is NOT an identity-cache hit, even if equal.
|
|
decoded = replace(value)
|
|
with mock.patch(
|
|
'openpilot.starpilot.flm.effect_admission_cache.validated_envelope',
|
|
wraps=__import__('openpilot.starpilot.flm.effect_admission_cache', fromlist=['validated_envelope']).validated_envelope,
|
|
) as verify:
|
|
decoded.validate()
|
|
assert verify.call_count == 1
|
|
|
|
|
|
@pytest.mark.parametrize('kind', ['signed_zero', 'mutable_rows', 'hash', 'envelope'])
|
|
def test_changed_trace_or_envelope_never_reuses_sender_proof(kind):
|
|
value = trace()
|
|
if kind == 'signed_zero':
|
|
rows = list(value.applied)
|
|
index = next(i for i, (name, _) in enumerate(rows) if name == 'ff_gain_right')
|
|
rows[index] = (rows[index][0], -0.0)
|
|
object.__setattr__(value, 'applied', tuple(rows))
|
|
elif kind == 'mutable_rows':
|
|
object.__setattr__(value, 'before', tuple(list(row) for row in value.before))
|
|
elif kind == 'hash':
|
|
object.__setattr__(value, 'applied_full_profile_sha256', '0' * 64)
|
|
else:
|
|
# Keep exact envelope object identity but replace a nested immutable field.
|
|
object.__setattr__(value.envelope, 'full_profile_sha256', '0' * 64)
|
|
with pytest.raises(ValueError):
|
|
value.validate()
|
|
|
|
|
|
def test_sender_cache_has_fixed_capacity_and_cannot_retain_receiver_history():
|
|
for _ in range(12):
|
|
trace()
|
|
assert len(effect_trace._SENDER_PROOFS) <= 4
|
|
original = trace()
|
|
for _ in range(5):
|
|
trace()
|
|
assert id(original) not in effect_trace._SENDER_PROOFS
|
|
with mock.patch(
|
|
'openpilot.starpilot.flm.effect_admission_cache.validated_envelope',
|
|
wraps=__import__('openpilot.starpilot.flm.effect_admission_cache', fromlist=['validated_envelope']).validated_envelope,
|
|
) as verify:
|
|
original.validate()
|
|
assert verify.call_count == 1
|
|
|
|
|
|
def test_changed_legal_first_frame_clock_revalidates_instead_of_using_sender_proof():
|
|
value = trace()
|
|
assert value.previous_ns == 0
|
|
# First-frame transition deliberately uses its fixed 10 ms step. Moving its
|
|
# timestamp remains structurally valid, but must never reuse the old proof.
|
|
object.__setattr__(value, 'control_ns', value.control_ns + 10_000_000)
|
|
with mock.patch(
|
|
'openpilot.starpilot.flm.effect_admission_cache.validated_envelope',
|
|
wraps=__import__('openpilot.starpilot.flm.effect_admission_cache', fromlist=['validated_envelope']).validated_envelope,
|
|
) as verify:
|
|
assert value.validate() is value
|
|
assert verify.call_count == 1
|
|
|
|
|
|
def test_changed_clock_past_existing_transition_window_rejects_old_applied_map():
|
|
owner, p, v, context = fixture()
|
|
owner.prepare(Admission(p, NOW, True, False, True, v), active=True, current_context=context)
|
|
owner.prepare(Admission(p, NOW + 10_000_000, True, False, True, v), active=True, current_context=context)
|
|
value = owner.trace
|
|
assert value.previous_ns == NOW
|
|
assert any(coordinate != 0 for _, coordinate in value.applied)
|
|
# The existing step_full contract withdraws all coordinates after 50 ms;
|
|
# retaining the old nonzero map must fail exact transition validation.
|
|
object.__setattr__(value, 'control_ns', value.previous_ns + 50_000_001)
|
|
with pytest.raises(ValueError, match='effect transition or applied hash changed'):
|
|
value.validate()
|