You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							179 lines
						
					
					
						
							6.8 KiB
						
					
					
				
			
		
		
	
	
							179 lines
						
					
					
						
							6.8 KiB
						
					
					
				#!/usr/bin/env python3
 | 
						|
import argparse
 | 
						|
import os
 | 
						|
import sys
 | 
						|
from typing import Any
 | 
						|
 | 
						|
from selfdrive.car.car_helpers import interface_names
 | 
						|
from selfdrive.test.process_replay.compare_logs import compare_logs
 | 
						|
from selfdrive.test.process_replay.process_replay import CONFIGS, replay_process
 | 
						|
from tools.lib.logreader import LogReader
 | 
						|
 | 
						|
INJECT_MODEL = 0
 | 
						|
 | 
						|
segments = [
 | 
						|
  ("HONDA", "d83f36766f8012a5|2020-02-05--18-42-21--2"),      # HONDA.CIVIC_BOSCH_DIESEL (BOSCH)
 | 
						|
  ("HONDA", "a74b011b32b51b56|2020-07-26--17-09-36--6"),      # HONDA.CIVIC (NIDEC)
 | 
						|
  ("TOYOTA", "b14c5b4742e6fc85|2020-10-14--11-04-47--4"),     # TOYOTA.RAV4  (LQR)
 | 
						|
  ("TOYOTA", "0982d79ebb0de295|2020-10-18--19-11-36--5"),     # TOYOTA.PRIUS (INDI)
 | 
						|
  ("CHRYSLER", "b6849f5cf2c926b1|2020-02-28--07-29-48--13"),  # CHRYSLER.PACIFICA
 | 
						|
  ("HYUNDAI", "5b7c365c50084530|2020-04-15--16-13-24--3"),    # HYUNDAI.SONATA
 | 
						|
  ("SUBARU", "c321c6b697c5a5ff|2020-06-23--11-04-33--12"),    # SUBARU.FORESTER
 | 
						|
  ("VOLKSWAGEN", "76b83eb0245de90e|2020-03-05--19-16-05--3"), # VW.GOLF
 | 
						|
  ("NISSAN", "fbbfa6af821552b9|2020-03-03--08-09-43--0"),     # NISSAN.XTRAIL
 | 
						|
 | 
						|
  # TODO: update this route
 | 
						|
  ("GM", "7cc2a8365b4dd8a9|2018-12-02--12-10-44--2"),         # GM.ACADIA
 | 
						|
 | 
						|
  # Enable when port is tested and dascamOnly is no longer set
 | 
						|
  #("MAZDA", "32a319f057902bb3|2020-04-27--15-18-58--2"),      # MAZDA.CX5
 | 
						|
]
 | 
						|
 | 
						|
# ford doesn't need to be tested until a full port is done
 | 
						|
excluded_interfaces = ["mock", "ford", "mazda"]
 | 
						|
 | 
						|
BASE_URL = "https://commadataci.blob.core.windows.net/openpilotci/"
 | 
						|
 | 
						|
# run the full test (including checks) when no args given
 | 
						|
FULL_TEST = len(sys.argv) <= 1
 | 
						|
 | 
						|
 | 
						|
def get_segment(segment_name, original=True):
 | 
						|
  route_name, segment_num = segment_name.rsplit("--", 1)
 | 
						|
  if original:
 | 
						|
    rlog_url = BASE_URL + "%s/%s/rlog.bz2" % (route_name.replace("|", "/"), segment_num)
 | 
						|
  else:
 | 
						|
    process_replay_dir = os.path.dirname(os.path.abspath(__file__))
 | 
						|
    model_ref_commit = open(os.path.join(process_replay_dir, "model_ref_commit")).read().strip()
 | 
						|
    rlog_url = BASE_URL + "%s/%s/rlog_%s.bz2" % (route_name.replace("|", "/"), segment_num, model_ref_commit)
 | 
						|
 | 
						|
  return rlog_url
 | 
						|
 | 
						|
 | 
						|
def test_process(cfg, lr, cmp_log_fn, ignore_fields=None, ignore_msgs=None):
 | 
						|
  if ignore_fields is None:
 | 
						|
    ignore_fields = []
 | 
						|
  if ignore_msgs is None:
 | 
						|
    ignore_msgs = []
 | 
						|
  url = BASE_URL + os.path.basename(cmp_log_fn)
 | 
						|
  cmp_log_msgs = list(LogReader(url))
 | 
						|
 | 
						|
  log_msgs = replay_process(cfg, lr)
 | 
						|
 | 
						|
  # check to make sure openpilot is engaged in the route
 | 
						|
  # TODO: update routes so enable check can run
 | 
						|
  #       failed enable check: honda bosch, hyundai, chrysler, and subaru
 | 
						|
  if cfg.proc_name == "controlsd" and FULL_TEST and False:
 | 
						|
    for msg in log_msgs:
 | 
						|
      if msg.which() == "controlsState":
 | 
						|
        if msg.controlsState.active:
 | 
						|
          break
 | 
						|
    else:
 | 
						|
      segment = cmp_log_fn.split("/")[-1].split("_")[0]
 | 
						|
      raise Exception("Route never enabled: %s" % segment)
 | 
						|
 | 
						|
  try:
 | 
						|
    return compare_logs(cmp_log_msgs, log_msgs, ignore_fields+cfg.ignore, ignore_msgs, cfg.tolerance)
 | 
						|
  except Exception as e:
 | 
						|
    return str(e)
 | 
						|
 | 
						|
def format_diff(results, ref_commit):
 | 
						|
  diff1, diff2 = "", ""
 | 
						|
  diff2 += "***** tested against commit %s *****\n" % ref_commit
 | 
						|
 | 
						|
  failed = False
 | 
						|
  for segment, result in list(results.items()):
 | 
						|
    diff1 += "***** results for segment %s *****\n" % segment
 | 
						|
    diff2 += "***** differences for segment %s *****\n" % segment
 | 
						|
 | 
						|
    for proc, diff in list(result.items()):
 | 
						|
      diff1 += "\t%s\n" % proc
 | 
						|
      diff2 += "*** process: %s ***\n" % proc
 | 
						|
 | 
						|
      if isinstance(diff, str):
 | 
						|
        diff1 += "\t\t%s\n" % diff
 | 
						|
        failed = True
 | 
						|
      elif len(diff):
 | 
						|
        cnt = {}
 | 
						|
        for d in diff:
 | 
						|
          diff2 += "\t%s\n" % str(d)
 | 
						|
 | 
						|
          k = str(d[1])
 | 
						|
          cnt[k] = 1 if k not in cnt else cnt[k] + 1
 | 
						|
 | 
						|
        for k, v in sorted(cnt.items()):
 | 
						|
          diff1 += "\t\t%s: %s\n" % (k, v)
 | 
						|
        failed = True
 | 
						|
  return diff1, diff2, failed
 | 
						|
 | 
						|
if __name__ == "__main__":
 | 
						|
 | 
						|
  parser = argparse.ArgumentParser(description="Regression test to identify changes in a process's output")
 | 
						|
 | 
						|
  # whitelist has precedence over blacklist in case both are defined
 | 
						|
  parser.add_argument("--whitelist-procs", type=str, nargs="*", default=[],
 | 
						|
                        help="Whitelist given processes from the test (e.g. controlsd)")
 | 
						|
  parser.add_argument("--whitelist-cars", type=str, nargs="*", default=[],
 | 
						|
                        help="Whitelist given cars from the test (e.g. HONDA)")
 | 
						|
  parser.add_argument("--blacklist-procs", type=str, nargs="*", default=[],
 | 
						|
                        help="Blacklist given processes from the test (e.g. controlsd)")
 | 
						|
  parser.add_argument("--blacklist-cars", type=str, nargs="*", default=[],
 | 
						|
                        help="Blacklist given cars from the test (e.g. HONDA)")
 | 
						|
  parser.add_argument("--ignore-fields", type=str, nargs="*", default=[],
 | 
						|
                        help="Extra fields or msgs to ignore (e.g. carState.events)")
 | 
						|
  parser.add_argument("--ignore-msgs", type=str, nargs="*", default=[],
 | 
						|
                        help="Msgs to ignore (e.g. carEvents)")
 | 
						|
  args = parser.parse_args()
 | 
						|
 | 
						|
  cars_whitelisted = len(args.whitelist_cars) > 0
 | 
						|
  procs_whitelisted = len(args.whitelist_procs) > 0
 | 
						|
 | 
						|
  process_replay_dir = os.path.dirname(os.path.abspath(__file__))
 | 
						|
  try:
 | 
						|
    ref_commit = open(os.path.join(process_replay_dir, "ref_commit")).read().strip()
 | 
						|
  except FileNotFoundError:
 | 
						|
    print("couldn't find reference commit")
 | 
						|
    sys.exit(1)
 | 
						|
 | 
						|
  print("***** testing against commit %s *****" % ref_commit)
 | 
						|
 | 
						|
  # check to make sure all car brands are tested
 | 
						|
  if FULL_TEST:
 | 
						|
    tested_cars = set(c.lower() for c, _ in segments)
 | 
						|
    untested = (set(interface_names) - set(excluded_interfaces)) - tested_cars
 | 
						|
    assert len(untested) == 0, "Cars missing routes: %s" % (str(untested))
 | 
						|
 | 
						|
  results: Any = {}
 | 
						|
  for car_brand, segment in segments:
 | 
						|
    if (cars_whitelisted and car_brand.upper() not in args.whitelist_cars) or \
 | 
						|
       (not cars_whitelisted and car_brand.upper() in args.blacklist_cars):
 | 
						|
      continue
 | 
						|
 | 
						|
    print("***** testing route segment %s *****\n" % segment)
 | 
						|
 | 
						|
    results[segment] = {}
 | 
						|
 | 
						|
    rlog_fn = get_segment(segment)
 | 
						|
    lr = LogReader(rlog_fn)
 | 
						|
 | 
						|
    for cfg in CONFIGS:
 | 
						|
      if (procs_whitelisted and cfg.proc_name not in args.whitelist_procs) or \
 | 
						|
         (not procs_whitelisted and cfg.proc_name in args.blacklist_procs):
 | 
						|
        continue
 | 
						|
 | 
						|
      cmp_log_fn = os.path.join(process_replay_dir, "%s_%s_%s.bz2" % (segment, cfg.proc_name, ref_commit))
 | 
						|
      results[segment][cfg.proc_name] = test_process(cfg, lr, cmp_log_fn, args.ignore_fields, args.ignore_msgs)
 | 
						|
 | 
						|
  diff1, diff2, failed = format_diff(results, ref_commit)
 | 
						|
  with open(os.path.join(process_replay_dir, "diff.txt"), "w") as f:
 | 
						|
    f.write(diff2)
 | 
						|
  print(diff1)
 | 
						|
 | 
						|
  if failed:
 | 
						|
    print("TEST FAILED")
 | 
						|
    print("\n\nTo update the reference logs for this test run:")
 | 
						|
    print("./update_refs.py")
 | 
						|
  else:
 | 
						|
    print("TEST SUCCEEDED")
 | 
						|
 | 
						|
  sys.exit(int(failed))
 | 
						|
 |