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 _DOWNLOAD_BASE = ('http://commondatastorage.googleapis.com/' 17 'chromiumos-test-assets-public/') 18 19 20 class audio_CrasSanity(test.test): 21 """Verifies cras sanity using its status, active streams and crashes""" 22 23 version = 1 24 25 _audio = ('audio.mp3', 'audio.wav', 'audio.m4a') 26 _video = ('traffic-1920x1080-8005020218f6b86bfa978e550d04956e.mp4', 27 'traffic-1920x1080-ad53f821ff3cf8ffa7e991c9d2e0b854.vp8.webm', 28 'traffic-1920x1080-83a1e5f8b7944577425f039034e64c76.vp9.webm') 29 30 _check = {'crashes_on_boot': False, 31 'stream_activation': False, 32 'cras_status': False, 33 'crashes_at_end': False 34 } 35 36 def run_once(self): 37 boards_to_skip = ['x86-mario'] 38 dut_board = utils.get_current_board() 39 if dut_board in boards_to_skip: 40 logging.info("Skipping test run on this board.") 41 return 42 # Check for existing cras crashes which might occur during UI bring up. 43 # TODO: (rohitbm) check if we need to reboot the DUT before the test 44 # start to verify cras crashes during boot. 45 existing_crash_reports = self.collect_cras_crash() 46 if len(existing_crash_reports) == 0: 47 self._check['crashes_on_boot'] = True 48 49 # Capturing cras pid before startig the test. 50 cras_pid_1 = utils.get_oldest_pid_by_name('/usr/bin/cras') 51 52 with chrome.Chrome(init_network_controller=True) as self._cr: 53 try: 54 # This will be used on Chrome PFQ since it's using a more recent 55 # version of Chrome. crbug.com/537655. 56 self._cr.browser.platform.SetHTTPServerDirectories(self.bindir) 57 except: 58 # This will be used on ChromeOS CQ since Chrome hasn't uprev'ed 59 # yet. crbug.com/538140. 60 self._cr.browser.SetHTTPServerDirectories(self.bindir) 61 for test_file in self._audio: 62 url = _DOWNLOAD_BASE + 'audio_test/' + test_file 63 self.push_new_stream(self._cr.browser.tabs.New(), url) 64 65 # Capturing cras pid before opening a new set of audio streams. 66 cras_pid_2 = utils.get_oldest_pid_by_name('/usr/bin/cras') 67 for test_file in self._video: 68 url = _DOWNLOAD_BASE + 'traffic/' + test_file 69 self.push_new_stream(self._cr.browser.tabs.New(), url) 70 71 # Let's play audio for sometime to ensure that 72 # long playback is good. 73 time.sleep(10) 74 75 total_tests = len(self._audio) + len(self._video) 76 active_streams = cras_utils.get_active_stream_count() 77 logging.debug( 78 'Number of active streams after opening all tabs: %d.', 79 active_streams) 80 if active_streams >= total_tests: 81 self._check['stream_activation'] = True 82 83 # Capturing cras pid after opening all audio/video streams. 84 cras_pid_3 = utils.get_oldest_pid_by_name('/usr/bin/cras') 85 86 # Close all open audio streams. 87 while total_tests > 0: 88 self._cr.browser.tabs[total_tests].Close() 89 total_tests -= 1 90 time.sleep(1) 91 active_streams = cras_utils.get_active_stream_count() 92 logging.debug( 93 'Number of active streams after closing all tabs: %d.', 94 active_streams) 95 96 # Capturing cras pid after closing all audio/stream streams. 97 cras_pid_4 = utils.get_oldest_pid_by_name('/usr/bin/cras') 98 99 if cras_pid_1 == cras_pid_2 == cras_pid_3 == cras_pid_4: 100 self._check['cras_status'] = True 101 102 new_crash_reports = self.collect_cras_crash() 103 new_reports = list(set(new_crash_reports) - 104 set(existing_crash_reports)) 105 if len(new_reports) == 0: 106 self._check['crashes_at_end'] = True 107 108 err_msg = '' 109 if self._check.values().count(False) > 0: 110 if not self._check['crashes_on_boot']: 111 err_msg = ('1. Found cras crashes on boot: %s.\n' 112 % existing_crash_reports) 113 if not self._check['stream_activation']: 114 err_msg += ('2. CRAS stream count is not matching with ' 115 'number of streams.\n') 116 if not self._check['cras_status']: 117 err_msg += ('CRAS PID changed during the test. CRAS might be ' 118 'crashing while adding/removing streams.\n') 119 if not self._check['crashes_at_end']: 120 err_msg += ('Found cras crashes at the end of the test : %s.' % 121 new_reports) 122 raise error.TestError(err_msg) 123 124 125 def push_new_stream(self, tab, url): 126 """Starts next audio stream from self._streams list. 127 128 @param tab: tab to open an audio stream. 129 @param url: audio/video test url. 130 """ 131 tab.Activate() 132 tab.Navigate(url) 133 tab.ExecuteJavaScript( 134 "document.getElementsByTagName('video')[0].loop=true") 135 tab.ExecuteJavaScript( 136 "document.getElementsByTagName('video')[0].volume=0.1") 137 time.sleep(1) # Adding a delay so cras can update the active count. 138 139 140 def collect_cras_crash(self): 141 """Check for cras crashes. 142 143 @return a list of cras crash reports found. 144 """ 145 146 crash_reports = [] 147 if not os.path.isdir(_CRASH_PATH): 148 logging.debug('No cras crash detected!') 149 else: 150 cras_reports = os.listdir(_CRASH_PATH) 151 crash_reports = [report for report in cras_reports 152 if report.startswith('cras')] 153 return crash_reports 154