Sound test (#1820)
	
		
	
				
					
				
			* WIP sound test
* it does something
* refactor
* phone only
* update release files
* test sound card init
* add to CI
* check writes
* increase time
* unused
* only build cereal
* small tolerance
Co-authored-by: Comma Device <device@comma.ai>
old-commit-hash: f1afb3e3ae
			
			
				commatwo_master
			
			
		
							parent
							
								
									06516d0f4c
								
							
						
					
					
						commit
						0d79150606
					
				
				 9 changed files with 147 additions and 70 deletions
			
			
		| @ -1,8 +0,0 @@ | ||||
| import os | ||||
| from nose.tools import nottest | ||||
| 
 | ||||
| def phone_only(x): | ||||
|   if os.path.isfile("/init.qcom.rc"): | ||||
|     return x | ||||
|   else: | ||||
|     return nottest(x) | ||||
| @ -0,0 +1,56 @@ | ||||
| import subprocess | ||||
| from functools import wraps | ||||
| from nose.tools import nottest | ||||
| 
 | ||||
| from common.android import ANDROID | ||||
| from common.apk import update_apks, start_offroad, pm_apply_packages, android_packages | ||||
| from selfdrive.manager import start_managed_process, kill_managed_process, get_running | ||||
| 
 | ||||
| def phone_only(x): | ||||
|   if ANDROID: | ||||
|     return x | ||||
|   else: | ||||
|     return nottest(x) | ||||
| 
 | ||||
| def with_processes(processes): | ||||
|   def wrapper(func): | ||||
|     @wraps(func) | ||||
|     def wrap(): | ||||
|       # start and assert started | ||||
|       [start_managed_process(p) for p in processes] | ||||
|       assert all(get_running()[name].exitcode is None for name in processes) | ||||
| 
 | ||||
|       # call the function | ||||
|       try: | ||||
|         func() | ||||
|         # assert processes are still started | ||||
|         assert all(get_running()[name].exitcode is None for name in processes) | ||||
|       finally: | ||||
|         # kill and assert all stopped | ||||
|         [kill_managed_process(p) for p in processes] | ||||
|         assert len(get_running()) == 0 | ||||
|     return wrap | ||||
|   return wrapper | ||||
| 
 | ||||
| def with_apks(): | ||||
|   def wrapper(func): | ||||
|     @wraps(func) | ||||
|     def wrap(): | ||||
|       update_apks() | ||||
|       pm_apply_packages('enable') | ||||
|       start_offroad() | ||||
| 
 | ||||
|       func() | ||||
| 
 | ||||
|       try: | ||||
|         for package in android_packages: | ||||
|           apk_is_running = (subprocess.call(["pidof", package]) == 0) | ||||
|           assert apk_is_running, package | ||||
|       finally: | ||||
|         pm_apply_packages('disable') | ||||
|         for package in android_packages: | ||||
|           apk_is_not_running = (subprocess.call(["pidof", package]) == 1) | ||||
|           assert apk_is_not_running, package | ||||
|     return wrap | ||||
|   return wrapper | ||||
| 
 | ||||
| @ -0,0 +1,68 @@ | ||||
| #!/usr/bin/env python3 | ||||
| import time | ||||
| import subprocess | ||||
| 
 | ||||
| from cereal import car | ||||
| import cereal.messaging as messaging | ||||
| from selfdrive.test.helpers import phone_only, with_processes | ||||
| from common.android import get_sound_card_online | ||||
| from common.realtime import DT_CTRL | ||||
| 
 | ||||
| AudibleAlert = car.CarControl.HUDControl.AudibleAlert | ||||
| 
 | ||||
| SOUNDS = { | ||||
|   # sound: total writes | ||||
|   AudibleAlert.none: 0, | ||||
|   AudibleAlert.chimeEngage: 85, | ||||
|   AudibleAlert.chimeDisengage: 85, | ||||
|   AudibleAlert.chimeError: 85, | ||||
|   AudibleAlert.chimePrompt: 85, | ||||
|   AudibleAlert.chimeWarning1: 80, | ||||
|   AudibleAlert.chimeWarning2: 107, | ||||
|   AudibleAlert.chimeWarningRepeat: 134, | ||||
|   AudibleAlert.chimeWarning2Repeat: 177, | ||||
| } | ||||
| 
 | ||||
| def get_total_writes(): | ||||
|   audio_flinger = subprocess.check_output('dumpsys media.audio_flinger', shell=True, encoding='utf-8').strip() | ||||
|   write_lines = [l for l in audio_flinger.split('\n') if l.strip().startswith('Total writes')] | ||||
|   return sum([int(l.split(':')[1]) for l in write_lines]) | ||||
| 
 | ||||
| @phone_only | ||||
| def test_sound_card_init(): | ||||
|   assert get_sound_card_online() | ||||
| 
 | ||||
| 
 | ||||
| @phone_only | ||||
| @with_processes(['ui', 'camerad']) | ||||
| def test_alert_sounds(): | ||||
| 
 | ||||
|   pm = messaging.PubMaster(['thermal', 'controlsState']) | ||||
| 
 | ||||
|   # make sure they're all defined | ||||
|   alert_sounds = {v: k for k, v in car.CarControl.HUDControl.AudibleAlert.schema.enumerants.items()} | ||||
|   diff = set(SOUNDS.keys()).symmetric_difference(alert_sounds.keys()) | ||||
|   assert len(diff) == 0, f"not all sounds defined in test: {diff}" | ||||
| 
 | ||||
|   # wait for procs to init | ||||
|   time.sleep(5) | ||||
| 
 | ||||
|   msg = messaging.new_message('thermal') | ||||
|   msg.thermal.started = True | ||||
|   pm.send('thermal', msg) | ||||
| 
 | ||||
|   for sound, expected_writes in SOUNDS.items(): | ||||
|     print(f"testing {alert_sounds[sound]}") | ||||
|     start_writes = get_total_writes() | ||||
| 
 | ||||
|     for _ in range(int(9 / DT_CTRL)): | ||||
|       msg = messaging.new_message('controlsState') | ||||
|       msg.controlsState.enabled = True | ||||
|       msg.controlsState.active = True | ||||
|       msg.controlsState.alertSound = sound | ||||
|       msg.controlsState.alertType = str(sound) | ||||
|       pm.send('controlsState', msg) | ||||
|       time.sleep(DT_CTRL) | ||||
| 
 | ||||
|     actual_writes = get_total_writes() - start_writes | ||||
|     assert abs(expected_writes - actual_writes) <= 2, f"{alert_sounds[sound]}: expected {expected_writes} writes, got {actual_writes}" | ||||
					Loading…
					
					
				
		Reference in new issue