1 # Copyright 2014 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 random 8 import shutil 9 import time 10 11 from autotest_lib.client.bin import test 12 from autotest_lib.client.common_lib.cros import chrome 13 from autotest_lib.client.common_lib import error 14 from autotest_lib.client.cros.audio import cras_utils 15 16 _STRESS_ITERATIONS = 100 # Total number of iterations. 17 _MAX_OPENED_TAB = 20 # Max number of tabs open and playing audio. 18 _RETAIN_TAB = 5 # In case we hit the _MAX_OPENED_TAB limit, 19 # close all except last 5 tabs. 20 _MAX_TABS_TO_OPEN = 10 # Max number of tabs can be opened in one iteration. 21 _CRASH_PATH = '/var/spool/crash' 22 23 24 class audio_ActiveStreamStress(test.test): 25 """Verifies the active audio streams.""" 26 27 version = 1 28 29 _active_stream_count = 0 30 _existing_cras_reports = [] 31 _cr = None 32 # TODO(rohitbm): add more(including video) file types and download them from gs://. 33 _streams = ('audio.mp3', 'audio.wav', 'audio.m4a') 34 _stream_index = 0 35 _tab_count = 0 36 37 def run_once(self): 38 39 # Collect existing cras crash reports. 40 self._existing_cras_reports = self.collect_cras_crash() 41 42 with chrome.Chrome() as self._cr: 43 self._cr.browser.platform.SetHTTPServerDirectories(self.bindir) 44 self.push_new_stream(self._cr.browser.tabs[0]) 45 # TODO(rohitbm): decide whether to perform verification on each 46 # open/close or at end of the iteration. 47 self.verify_active_streams() 48 push_count = 0 49 pop_count = 0 50 51 # Stress test logic: 52 # Test runs for n number of iterations. For one iteration, 53 # a = random(10) tabs(streams) are created and 54 # b = random(a) tabs are closed. If the next iteration finds that, 55 # total number of opened tabs are more than _MAX_OPENED_TAB, 56 # test will close (total opened tabs - 5) tabs. 57 # This will balance number of opened tabs and will allow to close 58 # tabs in a control manner. 59 60 for count in xrange(1, _STRESS_ITERATIONS): 61 if self._tab_count > _MAX_OPENED_TAB: 62 for i in xrange(1, (self._tab_count - _RETAIN_TAB)): 63 pop_count += 1 64 self.pop_stream() 65 logging.info('Total streams closed: %d', pop_count) 66 random_tab = random.randint(1, 10) 67 for i in xrange(1, random_tab): 68 push_count += 1 69 self.push_new_stream(self._cr.browser.tabs.New()) 70 logging.info('Total new streams created: %d', push_count) 71 time.sleep(5) # Delay for active streams to play. 72 for i in xrange(1, random.randint(1, random_tab)): 73 pop_count += 1 74 self.pop_stream() 75 logging.info('Total streams closed: %d', pop_count) 76 77 78 def get_stream_index(self): 79 if self._stream_index == len(self._streams): 80 # Reset the stream index if the index reached to the end. 81 self._stream_index = 0 82 return self._stream_index 83 84 85 def push_new_stream(self, tab): 86 """Starts next audio stream from self._streams list. 87 88 @param tab: tab to open an audio stream. 89 """ 90 self._tab_count += 1 91 tab.Navigate(self._cr.browser.platform.http_server.UrlOf( 92 os.path.join(self.bindir, 93 self._streams[self.get_stream_index()]))) 94 tab.ExecuteJavaScript( 95 "document.getElementsByTagName('video')[0].loop=true") 96 # TODO(rohitbm): add playback verification. 97 self._stream_index += 1 98 self._active_stream_count += 1 99 time.sleep(1) # Adding a delay so cras can update the active count. 100 self.verify_active_streams() 101 102 103 def pop_stream(self): 104 """Turns off the first available stream by closing the first tab.""" 105 if len(self._cr.browser.tabs) > 0: 106 self._cr.browser.tabs[0].Close() 107 self._tab_count -= 1 108 self._active_stream_count -= 1 109 time.sleep(1) # Adding delay so cras can update the active count. 110 self.verify_active_streams() 111 112 113 def verify_active_streams(self): 114 """Verifies test active audio streams with cras active streams.""" 115 cras_stream_count = cras_utils.get_active_stream_count() 116 if self._active_stream_count != cras_stream_count: 117 cras_crash_reports = self.collect_cras_crash() 118 new_reports = list(set(cras_crash_reports) - 119 set(self._existing_cras_reports)) 120 error_msg = ('Active stream count: %d is not matching with ' 121 'cras active stream count: %d. ' 122 'Number of cras crashes %d : %s' % 123 (self._active_stream_count, cras_stream_count, 124 len(new_reports), new_reports)) 125 raise error.TestError(error_msg) 126 127 128 def collect_cras_crash(self): 129 """Check for cras crashes. 130 131 @return a list of cras crash reports found. 132 """ 133 134 crash_reports = [] 135 if not os.path.isdir(_CRASH_PATH): 136 logging.debug('No cras crash detected!') 137 else: 138 cras_reports = os.listdir(_CRASH_PATH) 139 crash_reports = [report for report in cras_reports 140 if report.startswith('cras')] 141 return crash_reports 142