@ -6,11 +6,12 @@ import shutil
import subprocess
import subprocess
import time
import time
import unittest
import unittest
from parameterized import parameterized
from pathlib import Path
from pathlib import Path
from tqdm import trange
from common . params import Params
from common . params import Params
from common . hardware import EON , TICI
from common . hardware import EON , TICI
from common . timeout import Timeout
from selfdrive . test . helpers import with_processes
from selfdrive . test . helpers import with_processes
from selfdrive . loggerd . config import ROOT , CAMERA_FPS
from selfdrive . loggerd . config import ROOT , CAMERA_FPS
@ -21,9 +22,14 @@ if EON:
CAMERAS = {
CAMERAS = {
" fcamera " : FULL_SIZE ,
" fcamera " : FULL_SIZE ,
" dcamera " : 770920 ,
" dcamera " : 770920 ,
" qcamera " : 38533 ,
}
}
elif TICI :
elif TICI :
CAMERAS = { f " { c } camera " : FULL_SIZE for c in [ " f " , " e " , " d " ] }
CAMERAS = { f " { c } camera " : FULL_SIZE for c in [ " f " , " e " , " d " ] }
else :
CAMERAS = { }
ALL_CAMERA_COMBINATIONS = [ ( cameras , ) for cameras in [ CAMERAS , { k : CAMERAS [ k ] for k in CAMERAS if k != ' dcamera ' } ] ]
FRAME_TOLERANCE = 2
FRAME_TOLERANCE = 2
FILE_SIZE_TOLERANCE = 0.25
FILE_SIZE_TOLERANCE = 0.25
@ -37,7 +43,6 @@ class TestLoggerd(unittest.TestCase):
raise unittest . SkipTest
raise unittest . SkipTest
def setUp ( self ) :
def setUp ( self ) :
Params ( ) . put ( " RecordFront " , " 1 " )
self . _clear_logs ( )
self . _clear_logs ( )
self . segment_length = 2
self . segment_length = 2
@ -55,28 +60,27 @@ class TestLoggerd(unittest.TestCase):
last_route = sorted ( Path ( ROOT ) . iterdir ( ) , key = os . path . getmtime ) [ - 1 ]
last_route = sorted ( Path ( ROOT ) . iterdir ( ) , key = os . path . getmtime ) [ - 1 ]
return os . path . join ( ROOT , last_route )
return os . path . join ( ROOT , last_route )
# TODO: this should run faster than real time
@with_processes ( [ ' camerad ' , ' loggerd ' ] , init_time = 5 )
@with_processes ( [ ' camerad ' , ' loggerd ' ] , init_time = 5 )
def test_log_rotation ( self ) :
def _log_data ( self , t ) :
# wait for first seg to start being written
time . sleep ( t )
time . sleep ( 5 )
route_prefix_path = self . _get_latest_segment_path ( ) . rsplit ( " -- " , 1 ) [ 0 ]
# TODO: this should run faster than real time
@parameterized . expand ( ALL_CAMERA_COMBINATIONS )
def test_log_rotation ( self , cameras ) :
print ( " checking targets: " , cameras )
Params ( ) . put ( " RecordFront " , " 1 " if ' dcamera ' in cameras else " 0 " )
time . sleep ( 1 )
num_segments = random . randint ( 80 , 150 )
num_segments = random . randint ( 80 , 150 )
for i in range ( num_segments ) :
self . _log_data ( self . segment_length * num_segments + 5 )
if i < num_segments - 1 :
time . sleep ( 5 )
with Timeout ( self . segment_length * 3 , error_msg = f " timed out waiting for segment { i } " ) :
while True :
seg_num = int ( self . _get_latest_segment_path ( ) . rsplit ( " -- " , 1 ) [ 1 ] )
if seg_num > i :
break
time . sleep ( 0.1 )
else :
time . sleep ( self . segment_length + 2 )
route_prefix_path = self . _get_latest_segment_path ( ) . rsplit ( " -- " , 1 ) [ 0 ]
for i in trange ( num_segments ) :
# check each camera file size
# check each camera file size
for camera , size in CAMERAS . items ( ) :
for camera , size in cameras . items ( ) :
file_path = f " { route_prefix_path } -- { i } / { camera } .hevc "
ext = " ts " if camera == ' qcamera ' else " hevc "
file_path = f " { route_prefix_path } -- { i } / { camera } . { ext } "
# check file size
# check file size
self . assertTrue ( os . path . exists ( file_path ) , f " couldn ' t find { file_path } " )
self . assertTrue ( os . path . exists ( file_path ) , f " couldn ' t find { file_path } " )
@ -84,10 +88,13 @@ class TestLoggerd(unittest.TestCase):
self . assertTrue ( math . isclose ( file_size , size , rel_tol = FILE_SIZE_TOLERANCE ) ,
self . assertTrue ( math . isclose ( file_size , size , rel_tol = FILE_SIZE_TOLERANCE ) ,
f " { camera } failed size check: expected { size } , got { file_size } " )
f " { camera } failed size check: expected { size } , got { file_size } " )
if camera == ' qcamera ' :
continue
# check frame count
# check frame count
cmd = f " ffprobe -v error -count_frames -select_streams v:0 -show_entries stream=nb_read_frames \
cmd = f " ffprobe -v error -count_frames -select_streams v:0 -show_entries stream=nb_read_frames \
- of default = nokey = 1 : noprint_wrappers = 1 { file_path } "
- of default = nokey = 1 : noprint_wrappers = 1 { file_path } "
expected_frames = self . segment_length * CAMERA_FPS
expected_frames = self . segment_length * CAMERA_FPS / / 2 if ( EON and camera == ' dcamera ' ) else self . segment_length * CAMERA_FPS
frame_count = int ( subprocess . check_output ( cmd , shell = True , encoding = ' utf8 ' ) . strip ( ) )
frame_count = int ( subprocess . check_output ( cmd , shell = True , encoding = ' utf8 ' ) . strip ( ) )
self . assertTrue ( abs ( expected_frames - frame_count ) < = FRAME_TOLERANCE ,
self . assertTrue ( abs ( expected_frames - frame_count ) < = FRAME_TOLERANCE ,
f " { camera } failed frame count check: expected { expected_frames } , got { frame_count } " )
f " { camera } failed frame count check: expected { expected_frames } , got { frame_count } " )