sunnypilot v2026.002.000

version: sunnypilot v2026.002.000 (staging)
date: 2026-07-21T07:44:02
master commit: 2c334ede443d7391d27575af8c854a095ba702a8
This commit is contained in:
github-actions[bot] committed 2026-07-21 07:44:02 +00:00
commit de77c89cf6
3995 files changed
+1260688

No files matched your search

View File
Whitespace-only changes.
+204
View File
@@ -0,0 +1,204 @@
import multiprocessing
import unittest
import msgq
from parameterized import parameterized_class
from typing import Optional
WAIT_TIMEOUT = 5
def set_event_run(endpoint, identifier):
handle = msgq.fake_event_handle(endpoint, identifier=identifier, override=False)
handle.recv_called_event.set()
def daemon_repub_process_run(prefix: Optional[str] = None):
# Re-apply fake config in the child. Python 3.14+ defaults to forkserver on
# Linux, which does not inherit setenv() calls from the parent.
msgq.toggle_fake_events(True)
if prefix is not None:
msgq.set_fake_prefix(prefix)
else:
msgq.delete_fake_prefix()
pub_sock = msgq.pub_sock("ubloxGnss")
sub_sock = msgq.sub_sock("carState")
frame = -1
while True:
frame += 1
msg = sub_sock.receive(non_blocking=True)
if msg is None:
print("none received")
continue
bts = frame.to_bytes(8, 'little')
pub_sock.send(bts)
class TestEvents(unittest.TestCase):
def test_mutation(self):
handle = msgq.fake_event_handle("carState")
event = handle.recv_called_event
assert not event.peek()
event.set()
assert event.peek()
event.clear()
assert not event.peek()
del event
def test_wait(self):
handle = msgq.fake_event_handle("carState")
event = handle.recv_called_event
event.set()
try:
event.wait(WAIT_TIMEOUT)
assert event.peek()
except RuntimeError:
self.fail("event.wait() timed out")
def test_wait_multiprocess(self):
handle = msgq.fake_event_handle("carState")
event = handle.recv_called_event
p = multiprocessing.Process(target=set_event_run, args=("carState", ""))
p.start()
try:
event.wait(WAIT_TIMEOUT)
assert event.peek()
except RuntimeError:
self.fail("event.wait() timed out")
finally:
p.kill()
p.join()
def test_wait_zero_timeout(self):
handle = msgq.fake_event_handle("carState")
event = handle.recv_called_event
try:
event.wait(0)
self.fail("event.wait() did not time out")
except RuntimeError:
assert not event.peek()
def test_wait_for_one(self):
handles = [msgq.fake_event_handle(s) for s in ("carState", "controlsState")]
handles[1].recv_called_event.set()
assert msgq.wait_for_one_event([h.recv_called_event for h in handles], WAIT_TIMEOUT) == 1
@parameterized_class([{"prefix": None}, {"prefix": "test"}])
class TestFakeSockets(unittest.TestCase):
prefix: Optional[str] = None
def setUp(self):
super().setUp()
msgq.toggle_fake_events(True)
if self.prefix is not None:
msgq.set_fake_prefix(self.prefix)
else:
msgq.delete_fake_prefix()
def tearDown(self):
msgq.toggle_fake_events(False)
msgq.delete_fake_prefix()
super().tearDown()
def test_event_handle_init(self):
handle = msgq.fake_event_handle("controlsState", override=True)
assert not handle.enabled
assert handle.recv_called_event.fd >= 0
assert handle.recv_ready_event.fd >= 0
def test_non_managed_socket_state(self):
# non managed socket should have no event state
_ = msgq.pub_sock("ubloxGnss")
handle = msgq.fake_event_handle("ubloxGnss", override=False)
assert not handle.enabled
assert handle.recv_called_event.fd == -1
assert handle.recv_ready_event.fd == -1
def test_managed_socket_state(self):
# managed socket should not change anything about the state
handle = msgq.fake_event_handle("ubloxGnss")
handle.enabled = True
expected_enabled = handle.enabled
expected_recv_called_fd = handle.recv_called_event.fd
expected_recv_ready_fd = handle.recv_ready_event.fd
_ = msgq.pub_sock("ubloxGnss")
assert handle.enabled == expected_enabled
assert handle.recv_called_event.fd == expected_recv_called_fd
assert handle.recv_ready_event.fd == expected_recv_ready_fd
def test_sockets_enable_disable(self):
carState_handle = msgq.fake_event_handle("ubloxGnss", enable=True)
recv_called = carState_handle.recv_called_event
recv_ready = carState_handle.recv_ready_event
pub_sock = msgq.pub_sock("ubloxGnss")
sub_sock = msgq.sub_sock("ubloxGnss")
try:
carState_handle.enabled = True
recv_ready.set()
pub_sock.send(b"test")
_ = sub_sock.receive()
assert recv_called.peek()
recv_called.clear()
carState_handle.enabled = False
recv_ready.set()
pub_sock.send(b"test")
_ = sub_sock.receive()
assert not recv_called.peek()
except RuntimeError:
self.fail("event.wait() timed out")
def test_synced_pub_sub(self):
carState_handle = msgq.fake_event_handle("carState", enable=True)
recv_called = carState_handle.recv_called_event
recv_ready = carState_handle.recv_ready_event
pub_sock = msgq.pub_sock("carState")
p = multiprocessing.Process(target=daemon_repub_process_run, args=(self.prefix,))
p.start()
sub_sock = msgq.sub_sock("ubloxGnss")
try:
for i in range(10):
recv_called.wait(WAIT_TIMEOUT)
recv_called.clear()
if i == 0:
sub_sock.receive(non_blocking=True)
bts = i.to_bytes(8, 'little')
pub_sock.send(bts)
recv_ready.set()
recv_called.wait(WAIT_TIMEOUT)
msg = sub_sock.receive(non_blocking=True)
assert msg is not None
assert len(msg) == 8
frame = int.from_bytes(msg, 'little')
assert frame == i
except RuntimeError:
self.fail("event.wait() timed out")
finally:
p.kill()
p.join()
+57
View File
@@ -0,0 +1,57 @@
import random
import time
import string
import unittest
import msgq
def random_sock():
return ''.join(random.choices(string.ascii_uppercase + string.digits, k=10))
def random_bytes(length=1000):
return bytes([random.randrange(0xFF) for _ in range(length)])
class TestPubSubSockets(unittest.TestCase):
def test_pub_sub(self):
sock = random_sock()
pub_sock = msgq.pub_sock(sock)
sub_sock = msgq.sub_sock(sock, conflate=False, timeout=None)
for _ in range(100):
msg = random_bytes()
pub_sock.send(msg)
recvd = sub_sock.receive()
assert msg == recvd
def test_conflate(self):
sock = random_sock()
pub_sock = msgq.pub_sock(sock)
for conflate in [True, False]:
num_msgs = random.randint(3, 10)
sub_sock = msgq.sub_sock(sock, conflate=conflate, timeout=None)
sent_msgs = []
for __ in range(num_msgs):
msg = random_bytes()
pub_sock.send(msg)
sent_msgs.append(msg)
recvd_msgs = msgq.drain_sock_raw(sub_sock)
if conflate:
assert len(recvd_msgs) == 1
assert recvd_msgs[0] == sent_msgs[-1]
else:
assert len(recvd_msgs) == len(sent_msgs)
for rec_msg, sent_msg in zip(recvd_msgs, sent_msgs):
assert rec_msg == sent_msg
def test_receive_timeout(self):
sock = random_sock()
timeout_ms = 5
sub_sock = msgq.sub_sock(sock, timeout=timeout_ms)
start_time = time.monotonic()
recvd = sub_sock.receive()
elapsed = time.monotonic() - start_time
assert recvd is None
assert elapsed >= timeout_ms / 1000
assert elapsed < 5 # this can be noisy due to other load on the system
+135
View File
@@ -0,0 +1,135 @@
import unittest
import msgq
import concurrent.futures
SERVICE_NAME = 'myService'
def poller():
context = msgq.Context()
p = msgq.Poller()
sub = msgq.SubSocket()
sub.connect(context, SERVICE_NAME)
p.registerSocket(sub)
socks = p.poll(10000)
r = [s.receive(non_blocking=True) for s in socks]
return r
class TestPoller(unittest.TestCase):
def test_poll_once(self):
context = msgq.Context()
pub = msgq.PubSocket()
pub.connect(context, SERVICE_NAME)
with concurrent.futures.ThreadPoolExecutor() as e:
poll = e.submit(poller)
pub.wait_for_readers()
# Send message
pub.send(b"a")
# Wait for poll result
result = poll.result()
del pub
context.term()
assert result == [b"a"]
def test_poll_and_create_many_subscribers(self):
context = msgq.Context()
pub = msgq.PubSocket()
pub.connect(context, SERVICE_NAME)
with concurrent.futures.ThreadPoolExecutor() as e:
poll = e.submit(poller)
pub.wait_for_readers()
c = msgq.Context()
for _ in range(10):
msgq.SubSocket().connect(c, SERVICE_NAME)
# Send message
pub.send(b"a")
# Wait for poll result
result = poll.result()
del pub
context.term()
assert result == [b"a"]
def test_multiple_publishers_exception(self):
context = msgq.Context()
with self.assertRaises(msgq.MultiplePublishersError):
pub1 = msgq.PubSocket()
pub1.connect(context, SERVICE_NAME)
pub2 = msgq.PubSocket()
pub2.connect(context, SERVICE_NAME)
pub1.send(b"a")
del pub1
del pub2
context.term()
def test_multiple_messages(self):
context = msgq.Context()
pub = msgq.PubSocket()
pub.connect(context, SERVICE_NAME)
sub = msgq.SubSocket()
sub.connect(context, SERVICE_NAME)
pub.wait_for_readers()
for i in range(1, 100):
pub.send(b'a'*i)
msg_seen = False
i = 1
while True:
r = sub.receive(non_blocking=True)
if r is not None:
assert b'a'*i == r
msg_seen = True
i += 1
if r is None and msg_seen:
break
del pub
del sub
context.term()
def test_conflate(self):
context = msgq.Context()
pub = msgq.PubSocket()
pub.connect(context, SERVICE_NAME)
sub = msgq.SubSocket()
sub.connect(context, SERVICE_NAME, conflate=True)
pub.wait_for_readers()
pub.send(b'a')
pub.send(b'b')
assert b'b' == sub.receive()
del pub
del sub
context.term()