Boardd loopback test (#1840)
	
		
	
				
					
				
			* start boardd loopback test * let's try this in CI * fix jenkinsfile * remove old * rename * check msgs * should be reliable now * send morepull/214/head
							parent
							
								
									7c4fbb95de
								
							
						
					
					
						commit
						3ab0b49656
					
				
				 4 changed files with 65 additions and 35 deletions
			
			
		@ -1,47 +1,75 @@ | 
				
			|||||||
#!/usr/bin/env python3 | 
					#!/usr/bin/env python3 | 
				
			||||||
"""Run boardd with the BOARDD_LOOPBACK envvar before running this test.""" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import os | 
					import os | 
				
			||||||
import random | 
					import random | 
				
			||||||
import time | 
					import time | 
				
			||||||
 | 
					from collections import defaultdict | 
				
			||||||
 | 
					from functools import wraps | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import cereal.messaging as messaging | 
				
			||||||
 | 
					from cereal import car | 
				
			||||||
 | 
					from common.basedir import PARAMS | 
				
			||||||
 | 
					from common.params import Params | 
				
			||||||
 | 
					from panda import Panda | 
				
			||||||
from selfdrive.boardd.boardd import can_list_to_can_capnp | 
					from selfdrive.boardd.boardd import can_list_to_can_capnp | 
				
			||||||
from cereal.messaging import drain_sock, pub_sock, sub_sock | 
					from selfdrive.car import make_can_msg | 
				
			||||||
 | 
					from selfdrive.test.helpers import with_processes | 
				
			||||||
def get_test_string(): | 
					 | 
				
			||||||
  return b"test"+os.urandom(10) | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
BUS = 0 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
def main(): | 
					def reset_panda(fn): | 
				
			||||||
  rcv = sub_sock('can')  # port 8006 | 
					  @wraps(fn) | 
				
			||||||
  snd = pub_sock('sendcan')  # port 8017 | 
					  def wrapper(): | 
				
			||||||
  time.sleep(0.3)  # wait to bind before send/recv | 
					    p = Panda() | 
				
			||||||
 | 
					    for i in [0, 1, 2, 0xFFFF]: | 
				
			||||||
 | 
					      p.can_clear(i) | 
				
			||||||
 | 
					    p.reset() | 
				
			||||||
 | 
					    p.close() | 
				
			||||||
 | 
					    fn() | 
				
			||||||
 | 
					  return wrapper | 
				
			||||||
 | 
					
 | 
				
			||||||
  for i in range(10): | 
					os.environ['STARTED'] = '1' | 
				
			||||||
    print("Loop %d" % i) | 
					os.environ['BOARDD_LOOPBACK'] = '1' | 
				
			||||||
    at = random.randint(1024, 2000) | 
					os.environ['PARAMS_PATH'] = PARAMS | 
				
			||||||
    st = get_test_string()[0:8] | 
					@reset_panda | 
				
			||||||
    snd.send(can_list_to_can_capnp([[at, 0, st, 0]], msgtype='sendcan').to_bytes()) | 
					@with_processes(['boardd']) | 
				
			||||||
    time.sleep(0.1) | 
					def test_boardd_loopback(): | 
				
			||||||
    res = drain_sock(rcv, True) | 
					 | 
				
			||||||
    assert len(res) == 1 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    res = res[0].can | 
					  # wait for boardd to init | 
				
			||||||
    assert len(res) == 2 | 
					  time.sleep(2) | 
				
			||||||
 | 
					
 | 
				
			||||||
    msg0, msg1 = res | 
					  # boardd blocks on CarVin and CarParams | 
				
			||||||
 | 
					  cp = car.CarParams.new_message() | 
				
			||||||
 | 
					  cp.safetyModel = car.CarParams.SafetyModel.allOutput | 
				
			||||||
 | 
					  Params().put("CarVin", b"0"*17) | 
				
			||||||
 | 
					  Params().put("CarParams", cp.to_bytes()) | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert msg0.dat == st | 
					  sendcan = messaging.pub_sock('sendcan') | 
				
			||||||
    assert msg1.dat == st | 
					  can = messaging.sub_sock('can', conflate=False, timeout=100) | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert msg0.address == at | 
					  time.sleep(1) | 
				
			||||||
    assert msg1.address == at | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert msg0.src == 0x80 | BUS | 
					  for i in range(1000): | 
				
			||||||
    assert msg1.src == BUS | 
					    sent_msgs = defaultdict(set) | 
				
			||||||
 | 
					    for _ in range(random.randrange(10)): | 
				
			||||||
 | 
					      to_send = [] | 
				
			||||||
 | 
					      for __ in range(random.randrange(100)): | 
				
			||||||
 | 
					        bus = random.randrange(3) | 
				
			||||||
 | 
					        addr = random.randrange(1, 1<<29) | 
				
			||||||
 | 
					        dat = bytes([random.getrandbits(8) for _ in range(random.randrange(1, 9))]) | 
				
			||||||
 | 
					        sent_msgs[bus].add((addr, dat)) | 
				
			||||||
 | 
					        to_send.append(make_can_msg(addr, dat, bus)) | 
				
			||||||
 | 
					      sendcan.send(can_list_to_can_capnp(to_send, msgtype='sendcan')) | 
				
			||||||
 | 
					
 | 
				
			||||||
  print("Success") | 
					    max_recv = 10 | 
				
			||||||
 | 
					    while max_recv > 0 and any(len(sent_msgs[bus]) for bus in range(3)): | 
				
			||||||
 | 
					      recvd = messaging.drain_sock(can, wait_for_one=True) | 
				
			||||||
 | 
					      for msg in recvd: | 
				
			||||||
 | 
					        for m in msg.can: | 
				
			||||||
 | 
					          if m.src >= 128: | 
				
			||||||
 | 
					            k = (m.address, m.dat) | 
				
			||||||
 | 
					            assert k in sent_msgs[m.src-128] | 
				
			||||||
 | 
					            sent_msgs[m.src-128].discard(k) | 
				
			||||||
 | 
					      max_recv -= 1 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == "__main__": | 
					    # if a set isn't empty, messages got dropped | 
				
			||||||
  main() | 
					    for bus in range(3): | 
				
			||||||
 | 
					      assert not len(sent_msgs[bus]), f"loop {i}: bus {bus} missing {len(sent_msgs[bus])} messages" | 
				
			||||||
 | 
				
			|||||||
					Loading…
					
					
				
		Reference in new issue