Revert "simple fuzzing test for all processes (#28584)"
	
		
	
				
					
				
			This reverts commit 0e98836e857583849aa4e960b097103a4aeb863d.
old-commit-hash: 7783dc602c
			
			
				beeps
			
			
		
							parent
							
								
									83fd21a79e
								
							
						
					
					
						commit
						ffcc2e4c61
					
				
				 4 changed files with 169 additions and 34 deletions
			
			
		| @ -1,30 +1,174 @@ | |||||||
| #!/usr/bin/env python3 | #!/usr/bin/env python3 | ||||||
| from hypothesis import given, HealthCheck, Phase, settings | import sys | ||||||
| import hypothesis.strategies as st |  | ||||||
| from parameterized import parameterized |  | ||||||
| import unittest | import unittest | ||||||
| 
 | 
 | ||||||
|  | import hypothesis.strategies as st | ||||||
|  | import numpy as np | ||||||
|  | from hypothesis import given, settings, note | ||||||
|  | 
 | ||||||
| from cereal import log | from cereal import log | ||||||
| from selfdrive.car.toyota.values import CAR as TOYOTA | from selfdrive.car.toyota.values import CAR as TOYOTA | ||||||
| from selfdrive.test.fuzzy_generation import FuzzyGenerator |  | ||||||
| import selfdrive.test.process_replay.process_replay as pr | import selfdrive.test.process_replay.process_replay as pr | ||||||
| 
 | 
 | ||||||
| # These processes currently fail because of unrealistic data breaking assumptions |  | ||||||
| # that openpilot makes causing error with NaN, inf, int size, array indexing ... |  | ||||||
| # TODO: Make each one testable |  | ||||||
| NOT_TESTED = ['controlsd', 'plannerd', 'calibrationd', 'dmonitoringd', 'paramsd', 'laikad'] |  | ||||||
| TEST_CASES = [(cfg.proc_name, cfg) for cfg in pr.CONFIGS if cfg.proc_name not in NOT_TESTED] |  | ||||||
| 
 | 
 | ||||||
| class TestFuzzProcesses(unittest.TestCase): | def get_process_config(process): | ||||||
|  |   return [cfg for cfg in pr.CONFIGS if cfg.proc_name == process][0] | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def get_event_union_strategy(r, name): | ||||||
|  |   return st.fixed_dictionaries({ | ||||||
|  |     'valid': st.just(True), | ||||||
|  |     'logMonoTime': st.integers(min_value=0, max_value=2**64-1), | ||||||
|  |     name: r[name[0].upper() + name[1:]], | ||||||
|  |   }) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def get_strategy_for_events(event_types, finite=False): | ||||||
|  |   # TODO: generate automatically based on capnp definitions | ||||||
|  |   def floats(**kwargs): | ||||||
|  |     allow_nan = False if finite else None | ||||||
|  |     allow_infinity = False if finite else None | ||||||
|  |     return st.floats(**kwargs, allow_nan=allow_nan, allow_infinity=allow_infinity) | ||||||
|  | 
 | ||||||
|  |   r = {} | ||||||
|  |   r['liveLocationKalman.Measurement'] = st.fixed_dictionaries({ | ||||||
|  |     'value': st.lists(floats(), min_size=3, max_size=3), | ||||||
|  |     'std': st.lists(floats(), min_size=3, max_size=3), | ||||||
|  |     'valid': st.just(True), | ||||||
|  |   }) | ||||||
|  |   r['LiveLocationKalman'] = st.fixed_dictionaries({ | ||||||
|  |     'angularVelocityCalibrated': r['liveLocationKalman.Measurement'], | ||||||
|  |     'inputsOK': st.booleans(), | ||||||
|  |     'posenetOK': st.booleans(), | ||||||
|  |   }) | ||||||
|  |   r['CarState'] = st.fixed_dictionaries({ | ||||||
|  |     'vEgo': floats(width=32), | ||||||
|  |     'vEgoRaw': floats(width=32), | ||||||
|  |     'steeringPressed': st.booleans(), | ||||||
|  |     'steeringAngleDeg': floats(width=32), | ||||||
|  |   }) | ||||||
|  |   r['CameraOdometry'] = st.fixed_dictionaries({ | ||||||
|  |     'frameId': st.integers(min_value=0, max_value=2**32 - 1), | ||||||
|  |     'timestampEof': st.integers(min_value=0, max_value=2**64 - 1), | ||||||
|  |     'trans': st.lists(floats(width=32), min_size=3, max_size=3), | ||||||
|  |     'rot': st.lists(floats(width=32), min_size=3, max_size=3), | ||||||
|  |     'transStd': st.lists(floats(width=32), min_size=3, max_size=3), | ||||||
|  |     'rotStd': st.lists(floats(width=32), min_size=3, max_size=3), | ||||||
|  |   }) | ||||||
|  |   r['SensorEventData.SensorVec'] = st.fixed_dictionaries({ | ||||||
|  |     'v': st.lists(floats(width=32), min_size=3, max_size=3), | ||||||
|  |     'status': st.just(1), | ||||||
|  |   }) | ||||||
|  |   r['SensorEventData_gyro'] = st.fixed_dictionaries({ | ||||||
|  |     'version': st.just(1), | ||||||
|  |     'sensor': st.just(5), | ||||||
|  |     'type': st.just(16), | ||||||
|  |     'timestamp': st.integers(min_value=0, max_value=2**63 - 1), | ||||||
|  |     'source': st.just(8),  # BMX055 | ||||||
|  |     'gyroUncalibrated': r['SensorEventData.SensorVec'], | ||||||
|  |   }) | ||||||
|  |   r['SensorEventData_accel'] = st.fixed_dictionaries({ | ||||||
|  |     'version': st.just(1), | ||||||
|  |     'sensor': st.just(1), | ||||||
|  |     'type': st.just(1), | ||||||
|  |     'timestamp': st.integers(min_value=0, max_value=2**63 - 1), | ||||||
|  |     'source': st.just(8),  # BMX055 | ||||||
|  |     'acceleration': r['SensorEventData.SensorVec'], | ||||||
|  |   }) | ||||||
|  |   r['SensorEvents'] = st.lists(st.one_of(r['SensorEventData_gyro'], r['SensorEventData_accel']), min_size=1) | ||||||
|  |   r['GpsLocationExternal'] = st.fixed_dictionaries({ | ||||||
|  |     'flags': st.just(1), | ||||||
|  |     'latitude': floats(), | ||||||
|  |     'longitude': floats(), | ||||||
|  |     'altitude': floats(), | ||||||
|  |     'speed': floats(width=32), | ||||||
|  |     'bearingDeg': floats(width=32), | ||||||
|  |     'accuracy': floats(width=32), | ||||||
|  |     'timestamp': st.integers(min_value=0, max_value=2**63 - 1), | ||||||
|  |     'source': st.just(6),  # Ublox | ||||||
|  |     'vNED': st.lists(floats(width=32), min_size=3, max_size=3), | ||||||
|  |     'verticalAccuracy': floats(width=32), | ||||||
|  |     'bearingAccuracyDeg': floats(width=32), | ||||||
|  |     'speedAccuracy': floats(width=32), | ||||||
|  |   }) | ||||||
|  |   r['LiveCalibration'] = st.fixed_dictionaries({ | ||||||
|  |     'rpyCalib': st.lists(floats(width=32), min_size=3, max_size=3), | ||||||
|  |   }) | ||||||
|  | 
 | ||||||
|  |   return st.lists(st.one_of(*[get_event_union_strategy(r, n) for n in event_types])) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def get_strategy_for_process(process, finite=False): | ||||||
|  |   return get_strategy_for_events(get_process_config(process).pubs, finite) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def convert_to_lr(msgs): | ||||||
|  |   return [log.Event.new_message(**m).as_reader() for m in msgs] | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def is_finite(d, exclude=[], prefix=""):  # pylint: disable=dangerous-default-value | ||||||
|  |   ret = True | ||||||
|  |   for k, v in d.items(): | ||||||
|  |     name = prefix + f"{k}" | ||||||
|  |     if name in exclude: | ||||||
|  |       continue | ||||||
|  | 
 | ||||||
|  |     if isinstance(v, dict): | ||||||
|  |       if not is_finite(v, exclude, name + "."): | ||||||
|  |         ret = False | ||||||
|  |     else: | ||||||
|  |       try: | ||||||
|  |         if not np.isfinite(v).all(): | ||||||
|  |           note((name, v)) | ||||||
|  |           ret = False | ||||||
|  |       except TypeError: | ||||||
|  |         pass | ||||||
|  | 
 | ||||||
|  |   return ret | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_process(dat, name): | ||||||
|  |   cfg = get_process_config(name) | ||||||
|  |   lr = convert_to_lr(dat) | ||||||
|  |   pr.TIMEOUT = 0.1 | ||||||
|  |   return pr.replay_process(cfg, lr, TOYOTA.COROLLA_TSS2) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TestFuzzy(unittest.TestCase): | ||||||
|  |   @given(get_strategy_for_process('paramsd')) | ||||||
|  |   @settings(deadline=1000) | ||||||
|  |   def test_paramsd(self, dat): | ||||||
|  |     for r in test_process(dat, 'paramsd'): | ||||||
|  |       d = r.liveParameters.to_dict() | ||||||
|  |       assert is_finite(d) | ||||||
|  | 
 | ||||||
|  |   @given(get_strategy_for_process('locationd', finite=True)) | ||||||
|  |   @settings(deadline=1000) | ||||||
|  |   def test_locationd(self, dat): | ||||||
|  |     exclude = [ | ||||||
|  |       'positionGeodetic.std', | ||||||
|  |       'velocityNED.std', | ||||||
|  |       'orientationNED.std', | ||||||
|  |       'calibratedOrientationECEF.std', | ||||||
|  |     ] | ||||||
|  |     for r in test_process(dat, 'locationd'): | ||||||
|  |       d = r.liveLocationKalman.to_dict() | ||||||
|  |       assert is_finite(d, exclude) | ||||||
| 
 | 
 | ||||||
|   @parameterized.expand(TEST_CASES) |  | ||||||
|   @given(st.data()) |  | ||||||
|   @settings(phases=[Phase.generate, Phase.target], max_examples=50, deadline=1000, suppress_health_check=[HealthCheck.too_slow, HealthCheck.data_too_large]) |  | ||||||
|   def test_fuzz_process(self, proc_name, cfg, data): |  | ||||||
|     msgs = data.draw(FuzzyGenerator.get_random_event_msg(required=cfg.pubs, real_floats=True)) |  | ||||||
|     lr = [log.Event.new_message(**m).as_reader() for m in msgs] |  | ||||||
|     cfg.timeout = 5 |  | ||||||
|     pr.replay_process(cfg, lr, TOYOTA.COROLLA_TSS2, disable_progress=True) |  | ||||||
| 
 | 
 | ||||||
| if __name__ == "__main__": | if __name__ == "__main__": | ||||||
|   unittest.main() |   procs = { | ||||||
|  |     'locationd': TestFuzzy().test_locationd, | ||||||
|  |     'paramsd': TestFuzzy().test_paramsd, | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   if len(sys.argv) != 2: | ||||||
|  |     print("Usage: ./test_fuzzy.py <process name>") | ||||||
|  |     sys.exit(0) | ||||||
|  | 
 | ||||||
|  |   proc = sys.argv[1] | ||||||
|  |   if proc not in procs: | ||||||
|  |     print(f"{proc} not available") | ||||||
|  |     sys.exit(0) | ||||||
|  |   else: | ||||||
|  |     procs[proc]() | ||||||
|  | |||||||
					Loading…
					
					
				
		Reference in new issue