# Copyright 2014 The Chromium OS Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import logging import os import random import shutil import time from autotest_lib.client.bin import test from autotest_lib.client.common_lib.cros import chrome from autotest_lib.client.common_lib import error from autotest_lib.client.cros.audio import cras_utils _STRESS_ITERATIONS = 100 # Total number of iterations. _MAX_OPENED_TAB = 20 # Max number of tabs open and playing audio. _RETAIN_TAB = 5 # In case we hit the _MAX_OPENED_TAB limit, # close all except last 5 tabs. _MAX_TABS_TO_OPEN = 10 # Max number of tabs can be opened in one iteration. _CRASH_PATH = '/var/spool/crash' class audio_ActiveStreamStress(test.test): """Verifies the active audio streams.""" version = 1 _active_stream_count = 0 _existing_cras_reports = [] _cr = None # TODO(rohitbm): add more(including video) file types and download them from gs://. _streams = ('audio.mp3', 'audio.wav', 'audio.m4a') _stream_index = 0 _tab_count = 0 def run_once(self): # Collect existing cras crash reports. self._existing_cras_reports = self.collect_cras_crash() with chrome.Chrome() as self._cr: self._cr.browser.platform.SetHTTPServerDirectories(self.bindir) self.push_new_stream(self._cr.browser.tabs[0]) # TODO(rohitbm): decide whether to perform verification on each # open/close or at end of the iteration. self.verify_active_streams() push_count = 0 pop_count = 0 # Stress test logic: # Test runs for n number of iterations. For one iteration, # a = random(10) tabs(streams) are created and # b = random(a) tabs are closed. If the next iteration finds that, # total number of opened tabs are more than _MAX_OPENED_TAB, # test will close (total opened tabs - 5) tabs. # This will balance number of opened tabs and will allow to close # tabs in a control manner. for count in xrange(1, _STRESS_ITERATIONS): if self._tab_count > _MAX_OPENED_TAB: for i in xrange(1, (self._tab_count - _RETAIN_TAB)): pop_count += 1 self.pop_stream() logging.info('Total streams closed: %d', pop_count) random_tab = random.randint(1, 10) for i in xrange(1, random_tab): push_count += 1 self.push_new_stream(self._cr.browser.tabs.New()) logging.info('Total new streams created: %d', push_count) time.sleep(5) # Delay for active streams to play. for i in xrange(1, random.randint(1, random_tab)): pop_count += 1 self.pop_stream() logging.info('Total streams closed: %d', pop_count) def get_stream_index(self): if self._stream_index == len(self._streams): # Reset the stream index if the index reached to the end. self._stream_index = 0 return self._stream_index def push_new_stream(self, tab): """Starts next audio stream from self._streams list. @param tab: tab to open an audio stream. """ self._tab_count += 1 tab.Navigate(self._cr.browser.platform.http_server.UrlOf( os.path.join(self.bindir, self._streams[self.get_stream_index()]))) tab.ExecuteJavaScript( "document.getElementsByTagName('video')[0].loop=true") # TODO(rohitbm): add playback verification. self._stream_index += 1 self._active_stream_count += 1 time.sleep(1) # Adding a delay so cras can update the active count. self.verify_active_streams() def pop_stream(self): """Turns off the first available stream by closing the first tab.""" if len(self._cr.browser.tabs) > 0: self._cr.browser.tabs[0].Close() self._tab_count -= 1 self._active_stream_count -= 1 time.sleep(1) # Adding delay so cras can update the active count. self.verify_active_streams() def verify_active_streams(self): """Verifies test active audio streams with cras active streams.""" cras_stream_count = cras_utils.get_active_stream_count() if self._active_stream_count != cras_stream_count: cras_crash_reports = self.collect_cras_crash() new_reports = list(set(cras_crash_reports) - set(self._existing_cras_reports)) error_msg = ('Active stream count: %d is not matching with ' 'cras active stream count: %d. ' 'Number of cras crashes %d : %s' % (self._active_stream_count, cras_stream_count, len(new_reports), new_reports)) raise error.TestError(error_msg) def collect_cras_crash(self): """Check for cras crashes. @return a list of cras crash reports found. """ crash_reports = [] if not os.path.isdir(_CRASH_PATH): logging.debug('No cras crash detected!') else: cras_reports = os.listdir(_CRASH_PATH) crash_reports = [report for report in cras_reports if report.startswith('cras')] return crash_reports