loggerd: another rotation test (#19742)

* another rotation test

* make encoder test fast

* fix pc

Co-authored-by: Comma Device <device@comma.ai>
old-commit-hash: 5221450f2d
commatwo_master
Adeeb Shihadeh 4 years ago committed by GitHub
parent 65a624db68
commit eaa1489093
  1. 55
      selfdrive/loggerd/tests/test_encoder.py
  2. 28
      selfdrive/loggerd/tests/test_loggerd.py

@ -4,6 +4,7 @@ import os
import random import random
import shutil import shutil
import subprocess import subprocess
import threading
import time import time
import unittest import unittest
from parameterized import parameterized from parameterized import parameterized
@ -18,6 +19,7 @@ from selfdrive.loggerd.config import ROOT, CAMERA_FPS
# baseline file sizes for a 2s segment, in bytes # baseline file sizes for a 2s segment, in bytes
SEGMENT_LENGTH = 2
FULL_SIZE = 1253786 FULL_SIZE = 1253786
if EON: if EON:
CAMERAS = { CAMERAS = {
@ -25,14 +27,12 @@ if EON:
"dcamera": 770920, "dcamera": 770920,
"qcamera": 38533, "qcamera": 38533,
} }
elif TICI:
CAMERAS = {f"{c}camera": FULL_SIZE if c!="q" else 38533 for c in ["f", "e", "d", "q"]}
else: else:
CAMERAS = {} CAMERAS = {f"{c}camera": FULL_SIZE if c!="q" else 38533 for c in ["f", "e", "d", "q"]}
ALL_CAMERA_COMBINATIONS = [(cameras,) for cameras in [CAMERAS, {k:CAMERAS[k] for k in CAMERAS if k!='dcamera'}]] ALL_CAMERA_COMBINATIONS = [(cameras,) for cameras in [CAMERAS, {k:CAMERAS[k] for k in CAMERAS if k!='dcamera'}]]
FRAME_TOLERANCE = 0 # we check frame count, so we don't have to be too strict on size
FILE_SIZE_TOLERANCE = 0.5 FILE_SIZE_TOLERANCE = 0.5
class TestEncoder(unittest.TestCase): class TestEncoder(unittest.TestCase):
@ -45,10 +45,8 @@ class TestEncoder(unittest.TestCase):
def setUp(self): def setUp(self):
self._clear_logs() self._clear_logs()
self.segment_length = 2
os.environ["LOGGERD_TEST"] = "1" os.environ["LOGGERD_TEST"] = "1"
os.environ["LOGGERD_SEGMENT_LENGTH"] = str(self.segment_length) os.environ["LOGGERD_SEGMENT_LENGTH"] = str(SEGMENT_LENGTH)
def tearDown(self): def tearDown(self):
self._clear_logs() self._clear_logs()
@ -63,7 +61,7 @@ class TestEncoder(unittest.TestCase):
# TODO: this should run faster than real time # TODO: this should run faster than real time
@parameterized.expand(ALL_CAMERA_COMBINATIONS) @parameterized.expand(ALL_CAMERA_COMBINATIONS)
@with_processes(['camerad', 'sensord', 'loggerd'], init_time=5) @with_processes(['camerad', 'sensord', 'loggerd'])
def test_log_rotation(self, cameras): def test_log_rotation(self, cameras):
print("checking targets:", cameras) print("checking targets:", cameras)
Params().put("RecordFront", "1" if 'dcamera' in cameras else "0") Params().put("RecordFront", "1" if 'dcamera' in cameras else "0")
@ -73,28 +71,16 @@ class TestEncoder(unittest.TestCase):
num_segments = random.randint(15, 20) # ffprobe is slow on comma two num_segments = random.randint(15, 20) # ffprobe is slow on comma two
# wait for loggerd to make the dir for first segment # wait for loggerd to make the dir for first segment
time.sleep(10)
route_prefix_path = None route_prefix_path = None
with Timeout(30): with Timeout(int(SEGMENT_LENGTH*2)):
while route_prefix_path is None: while route_prefix_path is None:
try: try:
route_prefix_path = self._get_latest_segment_path().rsplit("--", 1)[0] route_prefix_path = self._get_latest_segment_path().rsplit("--", 1)[0]
except Exception: except Exception:
time.sleep(2) time.sleep(0.1)
continue continue
for i in trange(num_segments): def check_seg(i):
# poll for next segment
if i < num_segments - 1:
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)
# check each camera file size # check each camera file size
for camera, size in cameras.items(): for camera, size in cameras.items():
ext = "ts" if camera=='qcamera' else "hevc" ext = "ts" if camera=='qcamera' else "hevc"
@ -109,16 +95,35 @@ class TestEncoder(unittest.TestCase):
if camera == 'qcamera': if camera == 'qcamera':
continue continue
# TODO: this ffprobe call is really slow
# 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 // 2 if (EON and camera=='dcamera') else self.segment_length * CAMERA_FPS expected_frames = SEGMENT_LENGTH * CAMERA_FPS // 2 if (EON and camera=='dcamera') else SEGMENT_LENGTH * CAMERA_FPS
frame_tolerance = FRAME_TOLERANCE+1 if (EON and camera=='dcamera') or i==0 else FRAME_TOLERANCE frame_tolerance = 1 if (EON and camera == 'dcamera') else 0
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}")
shutil.rmtree(f"{route_prefix_path}--{i}") shutil.rmtree(f"{route_prefix_path}--{i}")
def join(ts, timeout):
for t in ts:
t.join(timeout)
threads = []
for i in trange(num_segments):
# poll for next segment
with Timeout(int(SEGMENT_LENGTH*2), error_msg=f"timed out waiting for segment {i}"):
while int(self._get_latest_segment_path().rsplit("--", 1)[1]) <= i:
time.sleep(0.1)
t = threading.Thread(target=check_seg, args=(i, ))
t.start()
threads.append(t)
join(threads, 0.1)
with Timeout(20):
join(threads, None)
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()

@ -15,8 +15,9 @@ from common.basedir import BASEDIR
from common.timeout import Timeout from common.timeout import Timeout
from common.params import Params from common.params import Params
import selfdrive.manager as manager import selfdrive.manager as manager
from selfdrive.hardware import PC from selfdrive.hardware import TICI, PC
from selfdrive.loggerd.config import ROOT from selfdrive.loggerd.config import ROOT
from selfdrive.test.helpers import with_processes
from selfdrive.version import version as VERSION from selfdrive.version import version as VERSION
from tools.lib.logreader import LogReader from tools.lib.logreader import LogReader
@ -95,6 +96,31 @@ class TestLoggerd(unittest.TestCase):
for _, k, v in fake_params: for _, k, v in fake_params:
self.assertEqual(getattr(initData, k), v) self.assertEqual(getattr(initData, k), v)
# TODO: this shouldn't need camerad
@with_processes(['camerad'])
def test_rotation(self):
os.environ["LOGGERD_TEST"] = "1"
Params().put("RecordFront", "1")
expected_files = {"rlog.bz2", "qlog.bz2", "qcamera.ts", "fcamera.hevc", "dcamera.hevc"}
if TICI:
expected_files.add("ecamera.hevc")
for _ in range(5):
num_segs = random.randint(1, 10)
length = random.randint(2, 5)
os.environ["LOGGERD_SEGMENT_LENGTH"] = str(length)
manager.start_managed_process("loggerd")
time.sleep(num_segs * length)
manager.kill_managed_process("loggerd")
route_path = str(self._get_latest_log_dir()).rsplit("--", 1)[0]
for n in range(num_segs):
p = Path(f"{route_path}--{n}")
logged = set([f.name for f in p.iterdir() if f.is_file()])
diff = logged ^ expected_files
self.assertEqual(len(diff), 0)
def test_bootlog(self): def test_bootlog(self):
# generate bootlog with fake launch log # generate bootlog with fake launch log
launch_log = ''.join([str(random.choice(string.printable)) for _ in range(100)]) launch_log = ''.join([str(random.choice(string.printable)) for _ in range(100)])

Loading…
Cancel
Save