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