@ -36,6 +36,7 @@ JOB_ID = int(os.environ.get("JOB_ID", "0")) 
			
		
	
		
		
			
				
					
					INTERNAL_SEG_LIST  =  os . environ . get ( " INTERNAL_SEG_LIST " ,  " " ) INTERNAL_SEG_LIST  =  os . environ . get ( " INTERNAL_SEG_LIST " ,  " " )  
			
		
	
		
		
			
				
					
					INTERNAL_SEG_CNT  =  int ( os . environ . get ( " INTERNAL_SEG_CNT " ,  " 0 " ) ) INTERNAL_SEG_CNT  =  int ( os . environ . get ( " INTERNAL_SEG_CNT " ,  " 0 " ) )  
			
		
	
		
		
			
				
					
					MAX_EXAMPLES  =  int ( os . environ . get ( " MAX_EXAMPLES " ,  " 50 " ) ) MAX_EXAMPLES  =  int ( os . environ . get ( " MAX_EXAMPLES " ,  " 50 " ) )  
			
		
	
		
		
			
				
					
					CI  =  os . environ . get ( " CI " ,  None )  is  not  None  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					def  get_test_cases ( )  - >  List [ Tuple [ str ,  Optional [ CarTestRoute ] ] ] : def  get_test_cases ( )  - >  List [ Tuple [ str ,  Optional [ CarTestRoute ] ] ] :  
			
		
	
	
		
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
					@ -67,7 +68,7 @@ def get_test_cases() -> List[Tuple[str, Optional[CarTestRoute]]]: 
			
		
	
		
		
			
				
					
					class  TestCarModelBase ( unittest . TestCase ) : class  TestCarModelBase ( unittest . TestCase ) :  
			
		
	
		
		
			
				
					
					  car_model :  Optional [ str ]  =  None    car_model :  Optional [ str ]  =  None   
			
		
	
		
		
			
				
					
					  test_route :  Optional [ CarTestRoute ]  =  None    test_route :  Optional [ CarTestRoute ]  =  None   
			
		
	
		
		
			
				
					
					  ci :  bool  =  True    test_route_on_bucket :  bool  =  True   # whether the route is on the preserved CI bucket    
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					  can_msgs :  List [ capnp . lib . capnp . _DynamicStructReader ]    can_msgs :  List [ capnp . lib . capnp . _DynamicStructReader ]   
			
		
	
		
		
			
				
					
					  fingerprint :  dict [ int ,  dict [ int ,  int ] ]    fingerprint :  dict [ int ,  dict [ int ,  int ] ]   
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
						
					 
					@ -75,36 +76,15 @@ class TestCarModelBase(unittest.TestCase): 
			
		
	
		
		
			
				
					
					  car_safety_mode_frame :  Optional [ int ]    car_safety_mode_frame :  Optional [ int ]   
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					  @classmethod    @classmethod   
			
		
	
		
		
			
				
					
					  def  setUpClass ( cls ) :    def  get_logreader ( cls ,  seg ) :   
			
				
				
			
		
	
		
		
			
				
					
					    if  cls . __name__  ==  ' TestCarModel '  or  cls . __name__ . endswith ( ' Base ' ) :   
			
		
	
		
		
			
				
					
					      raise  unittest . SkipTest   
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					    if  ' FILTER '  in  os . environ :   
			
		
	
		
		
			
				
					
					      if  not  cls . car_model . startswith ( tuple ( os . environ . get ( ' FILTER ' ) . split ( ' , ' ) ) ) :   
			
		
	
		
		
			
				
					
					        raise  unittest . SkipTest   
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					    if  cls . test_route  is  None :   
			
		
	
		
		
			
				
					
					      if  cls . car_model  in  non_tested_cars :   
			
		
	
		
		
			
				
					
					        print ( f " Skipping tests for  { cls . car_model } : missing route " )   
			
		
	
		
		
			
				
					
					        raise  unittest . SkipTest   
			
		
	
		
		
			
				
					
					      raise  Exception ( f " missing test route for  { cls . car_model } " )   
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					    test_segs  =  ( 2 ,  1 ,  0 )   
			
		
	
		
		
			
				
					
					    if  cls . test_route . segment  is  not  None :   
			
		
	
		
		
			
				
					
					      test_segs  =  ( cls . test_route . segment , )   
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					    for  seg  in  test_segs :   
			
		
	
		
		
			
				
					
					      try :   
			
		
	
		
		
	
		
		
			
				
					
					    if  len ( INTERNAL_SEG_LIST ) :      if  len ( INTERNAL_SEG_LIST ) :   
			
		
	
		
		
			
				
					
					      route_name  =  RouteName ( cls . test_route . route )        route_name  =  RouteName ( cls . test_route . route )   
			
		
	
		
		
			
				
					
					          lr  =  LogReader ( f " cd:/ { route_name . dongle_id } / { route_name . time_str } / { seg } /rlog.bz2 " )        return  LogReader ( f " cd:/ { route_name . dongle_id } / { route_name . time_str } / { seg } /rlog.bz2 " )   
			
				
				
			
		
	
		
		
			
				
					
					        elif  cls . ci :   
			
		
	
		
		
			
				
					
					          lr  =  LogReader ( get_url ( cls . test_route . route ,  seg ) )   
			
		
	
		
		
	
		
		
			
				
					
					    else :      else :   
			
		
	
		
		
			
				
					
					          lr  =  LogReader ( Route ( cls . test_route . route ) . log_paths ( ) [ seg ] )        return  LogReader ( get_url ( cls . test_route . route ,  seg ) )   
			
				
				
			
		
	
		
		
			
				
					
					      except  Exception :   
			
		
	
		
		
			
				
					
					        continue   
			
		
	
		
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					  @classmethod   
			
		
	
		
		
			
				
					
					  def  get_testing_data_from_logreader ( cls ,  lr ) :   
			
		
	
		
		
			
				
					
					    car_fw  =  [ ]      car_fw  =  [ ]   
			
		
	
		
		
			
				
					
					    can_msgs  =  [ ]      can_msgs  =  [ ]   
			
		
	
		
		
			
				
					
					    cls . elm_frame  =  None      cls . elm_frame  =  None   
			
		
	
	
		
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
					@ -143,9 +123,55 @@ class TestCarModelBase(unittest.TestCase): 
			
		
	
		
		
			
				
					
					          cls . car_safety_mode_frame  =  len ( can_msgs )            cls . car_safety_mode_frame  =  len ( can_msgs )   
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					    if  len ( can_msgs )  >  int ( 50  /  DT_CTRL ) :      if  len ( can_msgs )  >  int ( 50  /  DT_CTRL ) :   
			
		
	
		
		
			
				
					
					        break        return  car_fw ,  can_msgs ,  experimental_long   
			
				
				
			
		
	
		
		
			
				
					
					    else :  
 
			
				
				
			
		
	
		
		
			
				
					
					      raise  Exception ( f " Route:  { repr ( cls . test_route . route ) }  with segments:  { test_segs }  not found or no CAN msgs found. Is it uploaded? " )      raise  Exception ( " no can data found " )   
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					  @classmethod   
			
		
	
		
		
			
				
					
					  def  get_testing_data ( cls ) :   
			
		
	
		
		
			
				
					
					    test_segs  =  ( 2 ,  1 ,  0 )   
			
		
	
		
		
			
				
					
					    if  cls . test_route . segment  is  not  None :   
			
		
	
		
		
			
				
					
					      test_segs  =  ( cls . test_route . segment , )   
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					    # Try the primary method first (CI or internal)   
			
		
	
		
		
			
				
					
					    for  seg  in  test_segs :   
			
		
	
		
		
			
				
					
					      try :   
			
		
	
		
		
			
				
					
					        lr  =  cls . get_logreader ( seg )   
			
		
	
		
		
			
				
					
					        return  cls . get_testing_data_from_logreader ( lr )   
			
		
	
		
		
			
				
					
					      except  Exception :   
			
		
	
		
		
			
				
					
					        pass   
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					    # Route is not in CI bucket, assume either user has access (private), or it is public   
			
		
	
		
		
			
				
					
					    # test_route_on_ci_bucket will fail when running in CI   
			
		
	
		
		
			
				
					
					    if  not  len ( INTERNAL_SEG_LIST ) :   
			
		
	
		
		
			
				
					
					      cls . test_route_on_bucket  =  False   
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					      for  seg  in  test_segs :   
			
		
	
		
		
			
				
					
					        try :   
			
		
	
		
		
			
				
					
					          lr  =  LogReader ( Route ( cls . test_route . route ) . log_paths ( ) [ seg ] )   
			
		
	
		
		
			
				
					
					          return  cls . get_testing_data_from_logreader ( lr )   
			
		
	
		
		
			
				
					
					        except  Exception :   
			
		
	
		
		
			
				
					
					          pass   
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					    raise  Exception ( f " Route:  { repr ( cls . test_route . route ) }  with segments:  { test_segs }  not found or no CAN msgs found. Is it uploaded and public? " )   
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					  @classmethod   
			
		
	
		
		
			
				
					
					  def  setUpClass ( cls ) :   
			
		
	
		
		
			
				
					
					    if  cls . __name__  ==  ' TestCarModel '  or  cls . __name__ . endswith ( ' Base ' ) :   
			
		
	
		
		
			
				
					
					      raise  unittest . SkipTest   
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					    if  ' FILTER '  in  os . environ :   
			
		
	
		
		
			
				
					
					      if  not  cls . car_model . startswith ( tuple ( os . environ . get ( ' FILTER ' ) . split ( ' , ' ) ) ) :   
			
		
	
		
		
			
				
					
					        raise  unittest . SkipTest   
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					    if  cls . test_route  is  None :   
			
		
	
		
		
			
				
					
					      if  cls . car_model  in  non_tested_cars :   
			
		
	
		
		
			
				
					
					        print ( f " Skipping tests for  { cls . car_model } : missing route " )   
			
		
	
		
		
			
				
					
					        raise  unittest . SkipTest   
			
		
	
		
		
			
				
					
					      raise  Exception ( f " missing test route for  { cls . car_model } " )   
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					    car_fw ,  can_msgs ,  experimental_long  =  cls . get_testing_data ( )   
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					    # if relay is expected to be open in the route      # if relay is expected to be open in the route   
			
		
	
		
		
			
				
					
					    cls . openpilot_enabled  =  cls . car_safety_mode_frame  is  not  None      cls . openpilot_enabled  =  cls . car_safety_mode_frame  is  not  None   
			
		
	
	
		
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
					@ -451,6 +477,11 @@ class TestCarModelBase(unittest.TestCase): 
			
		
	
		
		
			
				
					
					    failed_checks  =  { k :  v  for  k ,  v  in  checks . items ( )  if  v  >  0 }      failed_checks  =  { k :  v  for  k ,  v  in  checks . items ( )  if  v  >  0 }   
			
		
	
		
		
			
				
					
					    self . assertFalse ( len ( failed_checks ) ,  f " panda safety doesn ' t agree with openpilot:  { failed_checks } " )      self . assertFalse ( len ( failed_checks ) ,  f " panda safety doesn ' t agree with openpilot:  { failed_checks } " )   
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					  @unittest . skipIf ( not  CI ,  " Accessing non CI-bucket routes is allowed only when not in CI " )   
			
		
	
		
		
			
				
					
					  def  test_route_on_ci_bucket ( self ) :   
			
		
	
		
		
			
				
					
					    self . assertTrue ( self . test_route_on_bucket ,  " Route not on CI bucket.  "  +   
			
		
	
		
		
			
				
					
					                    " This is fine to fail for WIP car ports, just let us know and we can upload your routes to the CI bucket. " )   
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					@parameterized_class ( ( ' car_model ' ,  ' test_route ' ) ,  get_test_cases ( ) ) @parameterized_class ( ( ' car_model ' ,  ' test_route ' ) ,  get_test_cases ( ) )  
			
		
	
		
		
			
				
					
					@pytest . mark . xdist_group_class_property ( ' test_route ' ) @pytest . mark . xdist_group_class_property ( ' test_route ' )