1 # Copyright 2015 The Chromium OS Authors. All rights reserved. 2 # Use of this source code is governed by a BSD-style license that can be 3 # found in the LICENSE file. 4 5 import logging 6 import os 7 import time 8 9 from autotest_lib.client.bin import test 10 from autotest_lib.client.bin import utils 11 from autotest_lib.client.common_lib.cros import chrome 12 from autotest_lib.client.common_lib import error 13 from autotest_lib.client.cros.audio import cras_utils 14 15 _CRASH_PATH = '/var/spool/crash' 16 _JS = """ 17 var c = new AudioContext(); 18 var o = c.createOscillator(); 19 o.connect(c.destination); o.start(); 20 """ 21 22 class audio_CrasSanity(test.test): 23 """Verifies cras sanity using its status, active streams and crashes""" 24 25 version = 1 26 _check = {'crashes_on_boot': False, 27 'stream_activation': False, 28 'cras_status': False, 29 'crashes_at_end': False 30 } 31 32 def run_once(self): 33 # Check for existing cras crashes which might occur during UI bring up. 34 # TODO: (rohitbm) check if we need to reboot the DUT before the test 35 # start to verify cras crashes during boot. 36 existing_crash_reports = self.collect_cras_crash() 37 if len(existing_crash_reports) == 0: 38 self._check['crashes_on_boot'] = True 39 40 # Capturing cras pid before startig the test. 41 cras_pid_1 = utils.get_oldest_pid_by_name('/usr/bin/cras') 42 43 with chrome.Chrome(init_network_controller=True) as self._cr: 44 # Push the 1st stream 45 self.push_new_stream(self._cr.browser.tabs.New()) 46 47 # Capturing cras pid before opening a new set of audio streams. 48 cras_pid_2 = utils.get_oldest_pid_by_name('/usr/bin/cras') 49 50 # Push the 2nd stream 51 self.push_new_stream(self._cr.browser.tabs.New()) 52 53 # Let's play audio for sometime to ensure that 54 # long playback is good. 55 time.sleep(10) 56 57 total_tests = 2 58 active_streams = cras_utils.get_active_stream_count() 59 logging.debug( 60 'Number of active streams after opening all tabs: %d.', 61 active_streams) 62 if active_streams >= total_tests: 63 self._check['stream_activation'] = True 64 65 # Capturing cras pid after opening all audio/video streams. 66 cras_pid_3 = utils.get_oldest_pid_by_name('/usr/bin/cras') 67 68 # Close all open audio streams. 69 while total_tests > 0: 70 self._cr.browser.tabs[total_tests].Close() 71 total_tests -= 1 72 time.sleep(1) 73 active_streams = cras_utils.get_active_stream_count() 74 logging.debug( 75 'Number of active streams after closing all tabs: %d.', 76 active_streams) 77 78 # Capturing cras pid after closing all audio/stream streams. 79 cras_pid_4 = utils.get_oldest_pid_by_name('/usr/bin/cras') 80 81 if cras_pid_1 == cras_pid_2 == cras_pid_3 == cras_pid_4: 82 self._check['cras_status'] = True 83 84 new_crash_reports = self.collect_cras_crash() 85 new_reports = list(set(new_crash_reports) - 86 set(existing_crash_reports)) 87 if len(new_reports) == 0: 88 self._check['crashes_at_end'] = True 89 90 err_msg = '' 91 if self._check.values().count(False) > 0: 92 if not self._check['crashes_on_boot']: 93 err_msg = ('1. Found cras crashes on boot: %s.\n' 94 % existing_crash_reports) 95 if not self._check['stream_activation']: 96 err_msg += ('2. CRAS stream count is not matching with ' 97 'number of streams.\n') 98 if not self._check['cras_status']: 99 err_msg += ('CRAS PID changed during the test. CRAS might be ' 100 'crashing while adding/removing streams.\n') 101 if not self._check['crashes_at_end']: 102 err_msg += ('Found cras crashes at the end of the test : %s.' % 103 new_reports) 104 raise error.TestError(err_msg) 105 106 107 def push_new_stream(self, tab): 108 """Starts next audio stream from self._streams list. 109 110 @param tab: tab to open an audio stream. 111 """ 112 tab.Activate() 113 tab.Navigate("file:///") 114 tab.ExecuteJavaScript(_JS) 115 time.sleep(1) # Adding a delay so cras can update the active count. 116 117 118 def collect_cras_crash(self): 119 """Check for cras crashes. 120 121 @return a list of cras crash reports found. 122 """ 123 124 crash_reports = [] 125 if not os.path.isdir(_CRASH_PATH): 126 logging.debug('No cras crash detected!') 127 else: 128 cras_reports = os.listdir(_CRASH_PATH) 129 crash_reports = [report for report in cras_reports 130 if report.startswith('cras')] 131 return crash_reports 132