openpilot v0.11.1 release
date: 2026-06-04T09:49:56 master commit: c0ab3550eca2e9daf197c46b7e4b24aa9637cf2e
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
import pytest
|
||||
|
||||
def pytest_addoption(parser):
|
||||
parser.addoption("--test_duration", action="store", default=60, type=int, help="Seconds to run metadrive drive")
|
||||
|
||||
@pytest.fixture
|
||||
def test_duration(request):
|
||||
return request.config.getoption("--test_duration")
|
||||
@@ -0,0 +1,17 @@
|
||||
import pytest
|
||||
import warnings
|
||||
|
||||
# Since metadrive depends on pkg_resources, and pkg_resources is deprecated as an API
|
||||
warnings.filterwarnings("ignore", category=DeprecationWarning)
|
||||
|
||||
from openpilot.tools.sim.bridge.metadrive.metadrive_bridge import MetaDriveBridge
|
||||
from openpilot.tools.sim.tests.test_sim_bridge import TestSimBridgeBase
|
||||
|
||||
@pytest.mark.slow
|
||||
class TestMetaDriveBridge(TestSimBridgeBase):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_create_bridge(self, test_duration):
|
||||
self.test_duration = 30
|
||||
|
||||
def create_bridge(self):
|
||||
return MetaDriveBridge(False, False, self.test_duration, True)
|
||||
@@ -0,0 +1,92 @@
|
||||
import os
|
||||
import subprocess
|
||||
import time
|
||||
import pytest
|
||||
|
||||
from multiprocessing import Queue
|
||||
|
||||
from cereal import messaging
|
||||
from openpilot.common.basedir import BASEDIR
|
||||
from openpilot.tools.sim.bridge.common import QueueMessageType
|
||||
|
||||
SIM_DIR = os.path.join(BASEDIR, "tools/sim")
|
||||
|
||||
class TestSimBridgeBase:
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
if cls is TestSimBridgeBase:
|
||||
raise pytest.skip("Don't run this base class, run test_metadrive_bridge.py instead")
|
||||
|
||||
def setup_method(self):
|
||||
self.processes = []
|
||||
|
||||
def test_driving(self):
|
||||
# Startup manager and bridge.py. Check processes are running, then engage and verify.
|
||||
p_manager = subprocess.Popen("./launch_openpilot.sh", cwd=SIM_DIR)
|
||||
self.processes.append(p_manager)
|
||||
|
||||
sm = messaging.SubMaster(['selfdriveState', 'onroadEvents', 'managerState'])
|
||||
q = Queue()
|
||||
bridge = self.create_bridge()
|
||||
p_bridge = bridge.run(q, retries=10)
|
||||
self.processes.append(p_bridge)
|
||||
|
||||
max_time_per_step = 60
|
||||
|
||||
# Wait for bridge to startup
|
||||
start_waiting = time.monotonic()
|
||||
while not bridge.started.value and time.monotonic() < start_waiting + max_time_per_step:
|
||||
time.sleep(0.1)
|
||||
assert p_bridge.exitcode is None, f"Bridge process should be running, but exited with code {p_bridge.exitcode}"
|
||||
|
||||
start_time = time.monotonic()
|
||||
no_car_events_issues_once = False
|
||||
car_event_issues = []
|
||||
not_running = []
|
||||
while time.monotonic() < start_time + max_time_per_step:
|
||||
sm.update()
|
||||
|
||||
not_running = [p.name for p in sm['managerState'].processes if not p.running and p.shouldBeRunning]
|
||||
car_event_issues = [event.name for event in sm['onroadEvents'] if any([event.noEntry, event.softDisable, event.immediateDisable])]
|
||||
|
||||
if sm.all_alive() and len(car_event_issues) == 0 and len(not_running) == 0:
|
||||
no_car_events_issues_once = True
|
||||
break
|
||||
|
||||
assert no_car_events_issues_once, \
|
||||
f"Failed because no messages received, or CarEvents '{car_event_issues}' or processes not running '{not_running}'"
|
||||
|
||||
start_time = time.monotonic()
|
||||
min_counts_control_active = 100
|
||||
control_active = 0
|
||||
|
||||
while time.monotonic() < start_time + max_time_per_step:
|
||||
sm.update()
|
||||
|
||||
if sm.all_alive() and sm['selfdriveState'].active:
|
||||
control_active += 1
|
||||
|
||||
if control_active == min_counts_control_active:
|
||||
break
|
||||
|
||||
assert min_counts_control_active == control_active, f"Simulator did not engage a minimal of {min_counts_control_active} steps was {control_active}"
|
||||
|
||||
failure_states = []
|
||||
while bridge.started.value:
|
||||
continue
|
||||
|
||||
while not q.empty():
|
||||
state = q.get()
|
||||
if state.type == QueueMessageType.TERMINATION_INFO:
|
||||
done_info = state.info
|
||||
failure_states = [done_state for done_state in done_info if done_state != "timeout" and done_info[done_state]]
|
||||
break
|
||||
assert len(failure_states) == 0, f"Simulator fails to finish a loop. Failure states: {failure_states}"
|
||||
|
||||
def teardown_method(self):
|
||||
print("Test shutting down. CommIssues are acceptable")
|
||||
for p in reversed(self.processes):
|
||||
p.terminate()
|
||||
|
||||
for p in reversed(self.processes):
|
||||
p.kill()
|
||||
Reference in New Issue
Block a user