#!/usr/bin/env python3 
 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								import  capnp 
 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								import  contextlib 
 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								import  io 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import  shutil 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import  tempfile 
 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								import  os 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import  unittest 
 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								import  pytest 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import  requests 
 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								from  parameterized  import  parameterized 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								from  unittest  import  mock 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								from  cereal  import  log  as  capnp_log 
 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								from  openpilot . tools . lib . logreader  import  LogIterable ,  LogReader ,  comma_api_source ,  parse_indirect ,  ReadMode ,  InternalUnavailableException 
 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								from  openpilot . tools . lib . route  import  SegmentRange 
 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								from  openpilot . tools . lib . url_file  import  URLFileException 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								NUM_SEGS  =  17   # number of segments in the test route 
 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								ALL_SEGS  =  list ( range ( NUM_SEGS ) ) 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								TEST_ROUTE  =  " 344c5c15b34f2d8a/2024-01-03--09-37-12 " 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								QLOG_FILE  =  " https://commadataci.blob.core.windows.net/openpilotci/0375fdf7b1ce594d/2019-06-13--08-32-25/3/qlog.bz2 " 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								def  noop ( segment :  LogIterable ) : 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  return  segment 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								@contextlib . contextmanager 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								def  setup_source_scenario ( is_internal = False ) : 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  with  ( 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    mock . patch ( " openpilot.tools.lib.logreader.internal_source " )  as  internal_source_mock , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    mock . patch ( " openpilot.tools.lib.logreader.openpilotci_source " )  as  openpilotci_source_mock , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    mock . patch ( " openpilot.tools.lib.logreader.comma_api_source " )  as  comma_api_source_mock , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  is_internal : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      internal_source_mock . return_value  =  [ QLOG_FILE ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    else : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      internal_source_mock . side_effect  =  InternalUnavailableException 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    openpilotci_source_mock . return_value  =  [ None ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    comma_api_source_mock . return_value  =  [ QLOG_FILE ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    yield 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								class  TestLogReader ( unittest . TestCase ) : 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  @parameterized . expand ( [ 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } " ,  ALL_SEGS ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE . replace ( ' / ' ,  ' | ' ) } " ,  ALL_SEGS ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } --0 " ,  [ 0 ] ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } --5 " ,  [ 5 ] ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } /0 " ,  [ 0 ] ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } /5 " ,  [ 5 ] ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } /0:10 " ,  ALL_SEGS [ 0 : 10 ] ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } /0:0 " ,  [ ] ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } /4:6 " ,  ALL_SEGS [ 4 : 6 ] ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } /0:-1 " ,  ALL_SEGS [ 0 : - 1 ] ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } /:5 " ,  ALL_SEGS [ : 5 ] ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } /2: " ,  ALL_SEGS [ 2 : ] ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } /2:-1 " ,  ALL_SEGS [ 2 : - 1 ] ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } /-1 " ,  [ ALL_SEGS [ - 1 ] ] ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } /-2 " ,  [ ALL_SEGS [ - 2 ] ] ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } /-2:-1 " ,  ALL_SEGS [ - 2 : - 1 ] ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } /-4:-2 " ,  ALL_SEGS [ - 4 : - 2 ] ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } /:10:2 " ,  ALL_SEGS [ : 10 : 2 ] ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } /5::2 " ,  ALL_SEGS [ 5 : : 2 ] ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " https://useradmin.comma.ai/?onebox= { TEST_ROUTE } " ,  ALL_SEGS ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " https://useradmin.comma.ai/?onebox= { TEST_ROUTE . replace ( ' / ' ,  ' | ' ) } " ,  ALL_SEGS ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " https://useradmin.comma.ai/?onebox= { TEST_ROUTE . replace ( ' / ' ,  ' % 7C ' ) } " ,  ALL_SEGS ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " https://cabana.comma.ai/?route= { TEST_ROUTE } " ,  ALL_SEGS ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  ] ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  test_indirect_parsing ( self ,  identifier ,  expected ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    parsed ,  _ ,  _  =  parse_indirect ( identifier ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    sr  =  SegmentRange ( parsed ) 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    self . assertListEqual ( list ( sr . seg_idxs ) ,  expected ,  identifier ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  @parameterized . expand ( [ 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } " ,  f " { TEST_ROUTE } " ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE . replace ( ' / ' ,  ' | ' ) } " ,  f " { TEST_ROUTE } " ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } --5 " ,  f " { TEST_ROUTE } /5 " ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } /0/q " ,  f " { TEST_ROUTE } /0/q " ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } /5:6/r " ,  f " { TEST_ROUTE } /5:6/r " ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } /5 " ,  f " { TEST_ROUTE } /5 " ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  ] ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  test_canonical_name ( self ,  identifier ,  expected ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    sr  =  SegmentRange ( identifier ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . assertEqual ( str ( sr ) ,  expected ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  @parameterized . expand ( [ ( True , ) ,  ( False , ) ] ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  @mock . patch ( " openpilot.tools.lib.logreader.file_exists " ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  test_direct_parsing ( self ,  cache_enabled ,  file_exists_mock ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    os . environ [ " FILEREADER_CACHE " ]  =  " 1 "  if  cache_enabled  else  " 0 " 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    qlog  =  tempfile . NamedTemporaryFile ( mode = ' wb ' ,  delete = False ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    with  requests . get ( QLOG_FILE ,  stream = True )  as  r : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      with  qlog  as  f : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        shutil . copyfileobj ( r . raw ,  f ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    for  f  in  [ QLOG_FILE ,  qlog . name ] : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      l  =  len ( list ( LogReader ( f ) ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . assertGreater ( l ,  100 ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    with  self . assertRaises ( URLFileException )  if  not  cache_enabled  else  self . assertRaises ( AssertionError ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      l  =  len ( list ( LogReader ( QLOG_FILE . replace ( " /3/ " ,  " /200/ " ) ) ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    # file_exists should not be called for direct files 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . assertEqual ( file_exists_mock . call_count ,  0 ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  @parameterized . expand ( [ 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } /// " , ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } --- " , ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } /-4:--2 " , ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } /-a " , ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } /j " , ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } /0:1:2:3 " , ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } /:::3 " , ) , 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } 3 " , ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } -3 " , ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } --3a " , ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  ] ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  test_bad_ranges ( self ,  segment_range ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    with  self . assertRaises ( AssertionError ) : 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      _  =  SegmentRange ( segment_range ) . seg_idxs 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  @parameterized . expand ( [ 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } /0 " ,  False ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } /:2 " ,  False ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } /0: " ,  True ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } /-1 " ,  True ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ( f " { TEST_ROUTE } " ,  True ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  ] ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  test_slicing_api_call ( self ,  segment_range ,  api_call ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    with  mock . patch ( " openpilot.tools.lib.route.get_max_seg_number_cached " )  as  max_seg_mock : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      max_seg_mock . return_value  =  NUM_SEGS 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      _  =  SegmentRange ( segment_range ) . seg_idxs 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      self . assertEqual ( api_call ,  max_seg_mock . called ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  @pytest . mark . slow 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  test_modes ( self ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    qlog_len  =  len ( list ( LogReader ( f " { TEST_ROUTE } /0 " ,  ReadMode . QLOG ) ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    rlog_len  =  len ( list ( LogReader ( f " { TEST_ROUTE } /0 " ,  ReadMode . RLOG ) ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . assertLess ( qlog_len  *  6 ,  rlog_len ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  @pytest . mark . slow 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  test_modes_from_name ( self ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    qlog_len  =  len ( list ( LogReader ( f " { TEST_ROUTE } /0/q " ) ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    rlog_len  =  len ( list ( LogReader ( f " { TEST_ROUTE } /0/r " ) ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . assertLess ( qlog_len  *  6 ,  rlog_len ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  @pytest . mark . slow 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  test_list ( self ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    qlog_len  =  len ( list ( LogReader ( f " { TEST_ROUTE } /0/q " ) ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    qlog_len_2  =  len ( list ( LogReader ( [ f " { TEST_ROUTE } /0/q " ,  f " { TEST_ROUTE } /0/q " ] ) ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    self . assertEqual ( qlog_len  *  2 ,  qlog_len_2 ) 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  @pytest . mark . slow 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  @mock . patch ( " openpilot.tools.lib.logreader._LogFileReader " ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  test_multiple_iterations ( self ,  init_mock ) : 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    lr  =  LogReader ( f " { TEST_ROUTE } /0/q " ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    qlog_len1  =  len ( list ( lr ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    qlog_len2  =  len ( list ( lr ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    # ensure we don't create multiple instances of _LogFileReader, which means downloading the files twice 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . assertEqual ( init_mock . call_count ,  1 ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    self . assertEqual ( qlog_len1 ,  qlog_len2 ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  @pytest . mark . slow 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  test_helpers ( self ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    lr  =  LogReader ( f " { TEST_ROUTE } /0/q " ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . assertEqual ( lr . first ( " carParams " ) . carFingerprint ,  " SUBARU OUTBACK 6TH GEN " ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . assertTrue ( 0  <  len ( list ( lr . filter ( " carParams " ) ) )  <  len ( list ( lr ) ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  @parameterized . expand ( [ ( True , ) ,  ( False , ) ] ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  @pytest . mark . slow 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  test_run_across_segments ( self ,  cache_enabled ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    os . environ [ " FILEREADER_CACHE " ]  =  " 1 "  if  cache_enabled  else  " 0 " 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    lr  =  LogReader ( f " { TEST_ROUTE } /0:4 " ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . assertEqual ( len ( lr . run_across_segments ( 4 ,  noop ) ) ,  len ( list ( lr ) ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  @pytest . mark . slow 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  test_auto_mode ( self ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    lr  =  LogReader ( f " { TEST_ROUTE } /0/q " ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    qlog_len  =  len ( list ( lr ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    with  mock . patch ( " openpilot.tools.lib.route.Route.log_paths " )  as  log_paths_mock : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      log_paths_mock . return_value  =  [ None ]  *  NUM_SEGS 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      # Should fall back to qlogs since rlogs are not available 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      with  self . subTest ( " interactive_yes " ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        with  mock . patch ( " sys.stdin " ,  new = io . StringIO ( " y \n " ) ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          lr  =  LogReader ( f " { TEST_ROUTE } /0 " ,  default_mode = ReadMode . AUTO_INTERACTIVE ,  default_source = comma_api_source ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          log_len  =  len ( list ( lr ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        self . assertEqual ( qlog_len ,  log_len ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      with  self . subTest ( " interactive_no " ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        with  mock . patch ( " sys.stdin " ,  new = io . StringIO ( " n \n " ) ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          with  self . assertRaises ( AssertionError ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            lr  =  LogReader ( f " { TEST_ROUTE } /0 " ,  default_mode = ReadMode . AUTO_INTERACTIVE ,  default_source = comma_api_source ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      with  self . subTest ( " non_interactive " ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        lr  =  LogReader ( f " { TEST_ROUTE } /0 " ,  default_mode = ReadMode . AUTO ,  default_source = comma_api_source ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        log_len  =  len ( list ( lr ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        self . assertEqual ( qlog_len ,  log_len ) 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  @parameterized . expand ( [ ( True , ) ,  ( False , ) ] ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  @pytest . mark . slow 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  test_auto_source_scenarios ( self ,  is_internal ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    lr  =  LogReader ( QLOG_FILE ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    qlog_len  =  len ( list ( lr ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    with  setup_source_scenario ( is_internal = is_internal ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      lr  =  LogReader ( f " { TEST_ROUTE } /0/q " ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      log_len  =  len ( list ( lr ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . assertEqual ( qlog_len ,  log_len ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  @pytest . mark . slow 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  test_sort_by_time ( self ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    msgs  =  list ( LogReader ( f " { TEST_ROUTE } /0/q " ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . assertNotEqual ( msgs ,  sorted ( msgs ,  key = lambda  m :  m . logMonoTime ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    msgs  =  list ( LogReader ( f " { TEST_ROUTE } /0/q " ,  sort_by_time = True ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . assertEqual ( msgs ,  sorted ( msgs ,  key = lambda  m :  m . logMonoTime ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  test_only_union_types ( self ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    with  tempfile . NamedTemporaryFile ( )  as  qlog : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      # write valid Event messages 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      num_msgs  =  100 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      with  open ( qlog . name ,  " wb " )  as  f : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        f . write ( b " " . join ( capnp_log . Event . new_message ( ) . to_bytes ( )  for  _  in  range ( num_msgs ) ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      msgs  =  list ( LogReader ( qlog . name ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . assertEqual ( len ( msgs ) ,  num_msgs ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      [ m . which ( )  for  m  in  msgs ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      # append non-union Event message 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      event_msg  =  capnp_log . Event . new_message ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      non_union_bytes  =  bytearray ( event_msg . to_bytes ( ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      non_union_bytes [ event_msg . total_size . word_count  *  8 ]  =  0xff   # set discriminant value out of range using Event word offset 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      with  open ( qlog . name ,  " ab " )  as  f : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        f . write ( non_union_bytes ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      # ensure new message is added, but is not a union type 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      msgs  =  list ( LogReader ( qlog . name ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . assertEqual ( len ( msgs ) ,  num_msgs  +  1 ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      with  self . assertRaises ( capnp . KjException ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        [ m . which ( )  for  m  in  msgs ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      # should not be added when only_union_types=True 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      msgs  =  list ( LogReader ( qlog . name ,  only_union_types = True ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . assertEqual ( len ( msgs ) ,  num_msgs ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      [ m . which ( )  for  m  in  msgs ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								if  __name__  ==  " __main__ " : 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  unittest . main ( )