mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-11-08 05:23:41 +08:00
487dfc4bf4
Merge bounded control/output FIFO heads using original publisher headers. Preserve original age, native, source, overflow and malformed-input checks; retain producer order after joins. Validated with actual pinned cloud dependencies and fresh-head regression tests.
135 lines
5.7 KiB
Python
135 lines
5.7 KiB
Python
"""Actual owner scheduling with declared unit transport; NEVER a fit grant.
|
|
|
|
The child output is an opaque proposal deliberately rejected by adapter install.
|
|
Real typed control/output/physical collector/source guards still run. Synthetic
|
|
native health is explicit; this is not controller/native/physical qualification.
|
|
"""
|
|
from openpilot.starpilot.flm.tests._drain_fixture import separate_drain_fixture
|
|
from dataclasses import replace
|
|
from types import SimpleNamespace
|
|
from unittest import mock
|
|
import pytest
|
|
|
|
from openpilot.starpilot.flm import steerlearnerd
|
|
from openpilot.starpilot.flm.event_collection import event_key, event_keys
|
|
from openpilot.starpilot.flm.event_collector import EventFullrateCollector
|
|
from openpilot.starpilot.flm.runtime_adapter_registry import SourceState
|
|
from openpilot.starpilot.flm.tests.test_fullrate_pipeline import (
|
|
BASE, SyntheticAdapter, snapshots, serialized_control, serialized_output,
|
|
)
|
|
|
|
|
|
def exercise(*, failure=None):
|
|
now, phase = [BASE], [-1]
|
|
attempts, sent, collectors, sources = [], [], [], []
|
|
old_key, new_key = ('event','deadband.high'), ('event','center')
|
|
class Adapter(SyntheticAdapter):
|
|
event_collection = True
|
|
raw_storage = False
|
|
target_changed = False
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.envelope = SimpleNamespace(prior_full_profile_sha256='a'*64)
|
|
self.current_physical_valid = False
|
|
self.last_physical_ns = 0
|
|
self.fit_profile = None
|
|
self.key = None
|
|
def prepare_control(self, value):
|
|
return value
|
|
def select_objective(self, value):
|
|
self.key = value
|
|
def install_fit(self, report, *decoded, physical_context):
|
|
attempts.append((phase[0], self.key))
|
|
return False # Opaque unit proposal MUST NOT become a fit or permission.
|
|
def current_admission(self, *args, **kwargs):
|
|
raise AssertionError('unit transport proposal cannot reach live admission')
|
|
class Collector(EventFullrateCollector):
|
|
def __init__(self, adapter):
|
|
super().__init__(adapter)
|
|
self.offered = False
|
|
collectors.append(self)
|
|
def job_snapshot(self, now_ns):
|
|
# Unit fitter transport only; not a forged eligible scientific snapshot.
|
|
if not self.offered and self.ready and self.physical_context is not None:
|
|
self.offered = True
|
|
return {'unit_transport_only':True}
|
|
return None
|
|
class Fitter:
|
|
child = None
|
|
def __init__(self):
|
|
self.token = None
|
|
self.completed = False
|
|
def poll(self, *, token, now_ns):
|
|
if self.child is not None and phase[0] == 1:
|
|
self.child = None
|
|
self.completed = True
|
|
assert token == self.token
|
|
return {'unit_unqualified_proposal':True}
|
|
return None
|
|
def submit(self, snapshot, *, token, now_ns):
|
|
assert snapshot == {'unit_transport_only':True}
|
|
self.child, self.token = object(), token
|
|
return True
|
|
def cancel(self, reason):
|
|
self.child = None
|
|
def close(self, reason):
|
|
self.child = None
|
|
c_sock, a_sock = object(), object()
|
|
fitter, persistence, sm = Fitter(), mock.Mock(), mock.Mock(updated={'deviceMotion': False}, logMonoTime={'deviceMotion': 0})
|
|
def update(timeout=None):
|
|
if timeout == 0:
|
|
return
|
|
phase[0] += 1
|
|
if phase[0] == 7:
|
|
raise StopIteration
|
|
now[0] = BASE + phase[0]*50_000_000
|
|
if phase[0] == 5 and failure == 'prior' and collectors:
|
|
collectors[0].adapter.envelope.prior_full_profile_sha256 = 'd'*64
|
|
sm.update.side_effect = update
|
|
def source(stamp):
|
|
known = not (failure == 'source' and phase[0] >= 5)
|
|
value = SourceState(known,False,'0' if known else '', '2'*64 if known else '',stamp,stamp+500_000_000,
|
|
'b'*64,(0.,0.,0.),configuration_known=known)
|
|
sources.append(value)
|
|
return value
|
|
def rows():
|
|
stamp = now[0]-1_000_000
|
|
control, output, physical = snapshots(stamp)
|
|
control = replace(control,source_receipt_ns=stamp,replay_inputs=(('control_frame',float(5999+phase[0])),))
|
|
return control,output,physical
|
|
def drain(socket, callback, receive, sink, stamp):
|
|
control,output,_ = rows()
|
|
callback(serialized_control(control) if socket is c_sock else serialized_output(output),sink,stamp)
|
|
def physical(*args):
|
|
return None if failure == 'physical' and phase[0] >= 5 else rows()[2]
|
|
def send(service,message):
|
|
row=message.autoSteeringLearning.learning
|
|
sent.append((phase[0],str(row.status),row.runtimeProfile.version))
|
|
publisher=mock.Mock()
|
|
publisher.send.side_effect=send
|
|
proposal=(SimpleNamespace(profile=object()), object())
|
|
with mock.patch.object(steerlearnerd,'drain_pair',separate_drain_fixture(drain)), \
|
|
mock.patch('openpilot.starpilot.flm.event_collector.EventFullrateCollector',Collector), \
|
|
mock.patch('openpilot.starpilot.flm.native_health.current_native_health',
|
|
side_effect=lambda *args: not (failure == 'native' and phase[0] >= 5)):
|
|
with pytest.raises(StopIteration):
|
|
steerlearnerd.run(SimpleNamespace(),sm,c_sock,a_sock,publisher,lambda *args:Adapter(),physical,source,
|
|
event_keys,event_key,lambda report:proposal,persistence,fitter,mock.Mock(),clock=lambda:now[0])
|
|
assert fitter.completed
|
|
assert len(collectors)==1
|
|
assert collectors[0].adapter.key == new_key or failure == 'source'
|
|
assert all(status != 'qualified' and version == 0 for _,status,version in sent)
|
|
assert collectors[0].fit_result is None and collectors[0].last_validation is None
|
|
return attempts, sent, collectors, old_key
|
|
|
|
|
|
def test_completed_old_group_proposal_attempts_own_selector_without_waiting_full_cycle():
|
|
attempts,_,_,old_key=exercise()
|
|
assert attempts == [(5,old_key)]
|
|
|
|
|
|
@pytest.mark.parametrize('failure',('native','physical','source','prior'))
|
|
def test_later_current_or_lineage_failure_never_attempts_or_publishes_unit_proposal(failure):
|
|
attempts,_,_,_=exercise(failure=failure)
|
|
assert attempts == []
|