Files
StarPilot/openpilot/starpilot/galaxy/tests/test_drive_stats_background.py
T
firestar5683 8cea672429 Drive Statistics
Implement background drive analysis and statistics with explicit worker and persistence ownership.

Co-authored-by: Danny <dannyirwin31@yahoo.com>
Co-authored-by: Prabhaav Pillai <prabhaav@msu.edu>
Co-authored-by: firestarsdog <229254897+firestarsdog@users.noreply.github.com>
2026-10-14 20:02:39 -05:00

92 lines
3.3 KiB
Python

from unittest.mock import Mock
"""Device lifecycle analysis continues with no HTTP clients."""
import tempfile
import threading
import time
from pathlib import Path
from unittest import TestCase
from openpilot.starpilot.galaxy.drive_stats import DriveStatsOwner
class BackgroundHistoryTest(TestCase):
def test_no_browser_pause_resume_and_restart_reuses_completion(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
allowed = threading.Event()
entered = threading.Event()
cancelled = threading.Event()
complete = threading.Event()
calls = []
record = {
'routeId': 'example',
'startTime': 1700000000.0,
'endTime': 1700000060.0,
'distanceMeters': 100.0,
'durationSeconds': 60.0,
'engagedSeconds': 20.0,
'engagedPercent': 100 / 3,
'model': 'test',
'distractedMoments': 0,
'unresponsiveMoments': 0,
'complete': True,
'reason': None,
'segmentCount': 1,
}
class History:
def __init__(self):
self.root = root
def snapshot(self):
return {'routes': [{'routeId': 'example', 'segments': []}]}
def analyze(_root, route, *, permitted):
calls.append(route['routeId'])
entered.set()
if len(calls) == 1:
deadline = time.monotonic() + 2
while permitted() and time.monotonic() < deadline:
time.sleep(0.005)
cancelled.set()
return dict(record, complete=False, reason='Analysis cancelled')
complete.set()
return record
owner = DriveStatsOwner(root=root, store=root / 'cache.json', history=Mock(wraps=History()), analyzer=analyze, permitted=allowed.is_set)
try:
owner.snapshot()
self.assertIsNone(owner._worker, 'dashboard must only read cached status')
owner.start()
owner.start()
self.assertFalse(entered.wait(0.15))
allowed.set()
self.assertTrue(entered.wait(2), 'offroad must start without requests')
allowed.clear()
self.assertTrue(cancelled.wait(0.4), 'onroad must revoke analysis promptly')
time.sleep(0.15)
self.assertFalse(owner._failures, 'interruption is not a corrupt log')
self.assertFalse((root / 'cache.json').exists() and owner._records)
allowed.set()
self.assertTrue(complete.wait(2), 'offroad must resume without requests')
deadline = time.monotonic() + 2
while owner._worker.is_alive() and time.monotonic() < deadline:
time.sleep(0.01)
self.assertEqual(owner.snapshot()['totals']['drives'], 1)
finally:
owner.close()
restored = DriveStatsOwner(root=root, store=root / 'cache.json', history=Mock(wraps=History()), analyzer=analyze, permitted=allowed.is_set)
try:
restored.start()
deadline = time.monotonic() + 2
while restored._worker is None and time.monotonic() < deadline:
time.sleep(0.01)
restored._worker.join(2)
self.assertEqual(calls, ['example', 'example'])
self.assertEqual(restored.snapshot()['totals']['drives'], 1)
finally:
restored.close()
self.assertFalse(owner._scheduler.is_alive())
self.assertFalse(restored._scheduler.is_alive())