|
1 | 1 | #!/usr/bin/env python3
|
2 |
| -"""Run boardd with the BOARDD_LOOPBACK envvar before running this test.""" |
3 |
| - |
4 | 2 | import os
|
5 | 3 | import random
|
6 | 4 | import time
|
| 5 | +from collections import defaultdict |
| 6 | +from functools import wraps |
7 | 7 |
|
| 8 | +import cereal.messaging as messaging |
| 9 | +from cereal import car |
| 10 | +from common.basedir import PARAMS |
| 11 | +from common.params import Params |
| 12 | +from panda import Panda |
8 | 13 | from selfdrive.boardd.boardd import can_list_to_can_capnp
|
9 |
| -from cereal.messaging import drain_sock, pub_sock, sub_sock |
10 |
| - |
11 |
| -def get_test_string(): |
12 |
| - return b"test"+os.urandom(10) |
| 14 | +from selfdrive.car import make_can_msg |
| 15 | +from selfdrive.test.helpers import with_processes |
13 | 16 |
|
14 |
| -BUS = 0 |
15 | 17 |
|
16 |
| -def main(): |
17 |
| - rcv = sub_sock('can') # port 8006 |
18 |
| - snd = pub_sock('sendcan') # port 8017 |
19 |
| - time.sleep(0.3) # wait to bind before send/recv |
| 18 | +def reset_panda(fn): |
| 19 | + @wraps(fn) |
| 20 | + def wrapper(): |
| 21 | + p = Panda() |
| 22 | + for i in [0, 1, 2, 0xFFFF]: |
| 23 | + p.can_clear(i) |
| 24 | + p.reset() |
| 25 | + p.close() |
| 26 | + fn() |
| 27 | + return wrapper |
20 | 28 |
|
21 |
| - for i in range(10): |
22 |
| - print("Loop %d" % i) |
23 |
| - at = random.randint(1024, 2000) |
24 |
| - st = get_test_string()[0:8] |
25 |
| - snd.send(can_list_to_can_capnp([[at, 0, st, 0]], msgtype='sendcan').to_bytes()) |
26 |
| - time.sleep(0.1) |
27 |
| - res = drain_sock(rcv, True) |
28 |
| - assert len(res) == 1 |
| 29 | +os.environ['STARTED'] = '1' |
| 30 | +os.environ['BOARDD_LOOPBACK'] = '1' |
| 31 | +os.environ['PARAMS_PATH'] = PARAMS |
| 32 | +@reset_panda |
| 33 | +@with_processes(['boardd']) |
| 34 | +def test_boardd_loopback(): |
29 | 35 |
|
30 |
| - res = res[0].can |
31 |
| - assert len(res) == 2 |
| 36 | + # wait for boardd to init |
| 37 | + time.sleep(2) |
32 | 38 |
|
33 |
| - msg0, msg1 = res |
| 39 | + # boardd blocks on CarVin and CarParams |
| 40 | + cp = car.CarParams.new_message() |
| 41 | + cp.safetyModel = car.CarParams.SafetyModel.allOutput |
| 42 | + Params().put("CarVin", b"0"*17) |
| 43 | + Params().put("CarParams", cp.to_bytes()) |
34 | 44 |
|
35 |
| - assert msg0.dat == st |
36 |
| - assert msg1.dat == st |
| 45 | + sendcan = messaging.pub_sock('sendcan') |
| 46 | + can = messaging.sub_sock('can', conflate=False, timeout=100) |
37 | 47 |
|
38 |
| - assert msg0.address == at |
39 |
| - assert msg1.address == at |
| 48 | + time.sleep(1) |
40 | 49 |
|
41 |
| - assert msg0.src == 0x80 | BUS |
42 |
| - assert msg1.src == BUS |
| 50 | + for i in range(1000): |
| 51 | + sent_msgs = defaultdict(set) |
| 52 | + for _ in range(random.randrange(10)): |
| 53 | + to_send = [] |
| 54 | + for __ in range(random.randrange(100)): |
| 55 | + bus = random.randrange(3) |
| 56 | + addr = random.randrange(1, 1<<29) |
| 57 | + dat = bytes([random.getrandbits(8) for _ in range(random.randrange(1, 9))]) |
| 58 | + sent_msgs[bus].add((addr, dat)) |
| 59 | + to_send.append(make_can_msg(addr, dat, bus)) |
| 60 | + sendcan.send(can_list_to_can_capnp(to_send, msgtype='sendcan')) |
43 | 61 |
|
44 |
| - print("Success") |
| 62 | + max_recv = 10 |
| 63 | + while max_recv > 0 and any(len(sent_msgs[bus]) for bus in range(3)): |
| 64 | + recvd = messaging.drain_sock(can, wait_for_one=True) |
| 65 | + for msg in recvd: |
| 66 | + for m in msg.can: |
| 67 | + if m.src >= 128: |
| 68 | + k = (m.address, m.dat) |
| 69 | + assert k in sent_msgs[m.src-128] |
| 70 | + sent_msgs[m.src-128].discard(k) |
| 71 | + max_recv -= 1 |
45 | 72 |
|
46 |
| -if __name__ == "__main__": |
47 |
| - main() |
| 73 | + # if a set isn't empty, messages got dropped |
| 74 | + for bus in range(3): |
| 75 | + assert not len(sent_msgs[bus]), f"loop {i}: bus {bus} missing {len(sent_msgs[bus])} messages" |
0 commit comments