mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-11-08 13:33:42 +08:00
8cea672429
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>
92 lines
3.3 KiB
Python
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())
|