Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 #!/usr/bin/env python | |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 3 # Use of this source code is governed by a BSD-style license that can be | |
| 4 # found in the LICENSE file. | |
| 5 | |
| 6 """Seek performance testing for <video>. | |
| 7 | |
| 8 Calculates the short and long seek times for different video formats on | |
| 9 different network constraints. | |
| 10 """ | |
| 11 | |
| 12 import itertools | |
| 13 import logging | |
| 14 import os | |
| 15 import Queue | |
| 16 import string | |
| 17 import threading | |
| 18 | |
| 19 import pyauto_media | |
| 20 import pyauto | |
| 21 import pyauto_utils | |
| 22 | |
| 23 import cns_test_base | |
| 24 from cns_test_base import CNSTestBase | |
| 25 | |
| 26 # Number of threads to use during testing. | |
|
DaleCurtis
2012/04/10 23:00:06
Lots of duplicated defines here. Should refactor a
| |
| 27 _TEST_THREADS = 3 | |
| 28 | |
| 29 # HTML test path; relative to src/chrome/test/data. | |
| 30 _TEST_HTML_PATH = os.path.join('media', 'html', 'media_seek.html') | |
| 31 | |
| 32 # The media files used for testing. | |
| 33 # Path under CNS root folder (pyauto_private/media). | |
| 34 _TEST_VIDEOS = [os.path.join('crowd', name) for name in | |
| 35 ['crowd1080.webm', 'crowd720.webm', 'crowd480.webm', 'crowd360.webm']] | |
| 36 | |
| 37 # Constraints to run tests on. | |
| 38 _TESTS_TO_RUN = { | |
| 39 '512kbps_105ms': [512, 105, 0], | |
| 40 'Wifi_1Mbps_60ms': [1024, 60, 0], | |
| 41 'DSL_1.5Mbps_50ms': [1541, 50, 0], | |
| 42 'Cable_5Mbps_28ms': [5120, 28, 0], | |
| 43 'NoConstraints': [0, 0, 0] | |
| 44 } | |
| 45 | |
| 46 | |
| 47 class TestWorker(threading.Thread): | |
|
DaleCurtis
2012/04/10 23:00:06
This worker code should probably be refactored/abs
| |
| 48 """Worker thread. For each queue entry: opens tab, runs test, closes tab.""" | |
| 49 | |
| 50 # Atomic, monotonically increasing task identifier. Used to ID tabs. | |
| 51 _task_id = itertools.count() | |
| 52 | |
| 53 def __init__(self, pyauto_test, tasks, automation_lock, url): | |
| 54 """Sets up TestWorker class variables. | |
| 55 | |
| 56 Args: | |
| 57 pyauto_test: Reference to a pyauto.PyUITest instance. | |
| 58 tasks: Queue containing (settings, name) tuples. | |
| 59 automation_lock: Global automation lock for pyauto calls. | |
| 60 url: File URL to HTML/JavaScript test code. | |
| 61 """ | |
| 62 threading.Thread.__init__(self) | |
| 63 self._tasks = tasks | |
| 64 self._automation_lock = automation_lock | |
| 65 self._pyauto = pyauto_test | |
| 66 self._url = url | |
| 67 self._uncached_seeks = [] | |
| 68 self._cached_seeks = [] | |
| 69 self._error_msg = '' | |
| 70 self.start() | |
| 71 | |
| 72 def _FindTabLocked(self, url): | |
| 73 """Returns the tab index for the tab belonging to this url. | |
| 74 | |
| 75 self._automation_lock must be owned by caller. | |
| 76 """ | |
| 77 for tab in self._pyauto.GetBrowserInfo()['windows'][0]['tabs']: | |
| 78 if tab['url'] == url: | |
| 79 return tab['index'] | |
| 80 | |
| 81 def _EndTest(self, unique_url): | |
| 82 """Checks if the page has variable value ready or if an error has occured. | |
| 83 | |
| 84 The varaible value must be set to < 0 pre-run. | |
| 85 | |
| 86 Args: | |
| 87 var_name: The variable name to check the metric for. | |
| 88 unique_url: The url of the page to check for the variable's metric. | |
| 89 | |
| 90 Returns: | |
| 91 True is the var_name value is >=0 or if an error_msg exists. | |
| 92 """ | |
| 93 with self._automation_lock: | |
| 94 tab = self._FindTabLocked(unique_url) | |
| 95 self._error_msg = self._pyauto.GetDOMValue('errorMsg', tab_index=tab) | |
| 96 end_test = self._pyauto.GetDOMValue('endTest', tab_index=tab) | |
| 97 if end_test: | |
| 98 self._uncached_seeks = [ | |
| 99 float(value) for value in | |
| 100 self._pyauto.GetDOMValue("longSeeks.join(',')", | |
| 101 tab_index=tab).split(',')] | |
| 102 self._cached_seeks = [ | |
| 103 float(value) for value in | |
| 104 self._pyauto.GetDOMValue("shortSeeks.join(',')", | |
| 105 tab_index=tab).split(',')] | |
| 106 return self._error_msg or end_test | |
| 107 | |
| 108 def run(self): | |
| 109 """Opens tab, starts HTML test, and records metrics for each queue entry. | |
| 110 | |
| 111 No exception handling is done to make sure the main thread exits properly | |
| 112 during Chrome crashes or other failures. Doing otherwise has the potential | |
| 113 to leave the CNS server running in the background. | |
| 114 | |
| 115 For a clean shutdown, put the magic exit value (None, None) in the queue. | |
| 116 """ | |
| 117 # Make the test URL unique so we can figure out our tab index later. | |
| 118 unique_url = '%s?%d' % (self._url, TestWorker._task_id.next()) | |
| 119 with self._automation_lock: | |
| 120 self._pyauto.AppendTab(pyauto.GURL(unique_url)) | |
| 121 | |
| 122 while True: | |
| 123 series_name, settings, file_name = self._tasks.get() | |
| 124 | |
| 125 # Check for magic exit values. | |
| 126 if (series_name, settings, file_name) == (None, None, None): | |
| 127 break | |
| 128 | |
| 129 video_url = cns_test_base.GetFileURL( | |
| 130 file_name, bandwidth=settings[0], latency=settings[1], | |
| 131 loss=settings[2], new_port=True) | |
| 132 | |
| 133 self._uncached_seeks = [] | |
| 134 self._cached_seeks = [] | |
| 135 self._error_msg = '' | |
| 136 # Start the test! | |
| 137 with self._automation_lock: | |
| 138 self._pyauto.CallJavascriptFunc( | |
| 139 'startTest', [video_url], | |
| 140 tab_index=self._FindTabLocked(unique_url)) | |
| 141 logging.debug('Running perf test for %s.', video_url) | |
| 142 | |
| 143 self._pyauto.WaitUntil( | |
| 144 self._EndTest, args=[unique_url], retry_sleep=1, timeout=500, | |
| 145 debug=False) | |
| 146 | |
| 147 if self._error_msg: | |
| 148 logging.error('Error while running the test: %s' % self._error_msg) | |
| 149 else: | |
| 150 graph_name = series_name +'_' + os.path.basename(file_name) | |
| 151 pyauto_utils.PrintPerfResult('seek', 'uncached_' + graph_name, | |
| 152 self._uncached_seeks, 'ms') | |
| 153 pyauto_utils.PrintPerfResult('seek', 'cached_' + graph_name, | |
| 154 self._cached_seeks, 'ms') | |
| 155 | |
| 156 # Close the tab. | |
| 157 with self._automation_lock: | |
| 158 self._pyauto.GetBrowserWindow(0).GetTab( | |
| 159 self._FindTabLocked(unique_url)).Close(True) | |
| 160 | |
| 161 self._tasks.task_done() | |
| 162 | |
| 163 | |
| 164 class MediaSeekPerfTest(CNSTestBase, pyauto.PyUITest): | |
| 165 """PyAuto test container. See file doc string for more information.""" | |
| 166 | |
| 167 def testMediaSeekPerformance(self): | |
| 168 """Launches HTML test which plays each video and records seek stats.""" | |
| 169 # Convert relative test path into an absolute path. | |
| 170 test_url = self.GetFileURLForDataPath(_TEST_HTML_PATH) | |
| 171 | |
| 172 # PyAuto doesn't support threads, so we synchronize all automation calls. | |
| 173 automation_lock = threading.Lock() | |
| 174 | |
| 175 # Spin up worker threads. | |
|
DaleCurtis
2012/04/10 23:00:06
No dummy test necessary anymore?
| |
| 176 tasks = Queue.Queue() | |
| 177 for file_name in _TEST_VIDEOS: | |
| 178 for series_name, settings in _TESTS_TO_RUN.iteritems(): | |
| 179 logging.debug('Add test: %s\tSettings: %s\tMedia: %s', series_name, | |
| 180 settings, file_name) | |
| 181 tasks.put((series_name, settings, file_name)) | |
| 182 | |
| 183 # Add shutdown magic to end of queue. | |
| 184 for thread in xrange(_TEST_THREADS): | |
| 185 tasks.put((None, None, None)) | |
| 186 | |
| 187 threads = [] | |
| 188 for _ in xrange(_TEST_THREADS): | |
| 189 threads.append(TestWorker(self, tasks, automation_lock, test_url)) | |
| 190 | |
| 191 # Wait for threads to exit, gracefully or otherwise. | |
| 192 for thread in threads: | |
| 193 thread.join() | |
| 194 | |
| 195 | |
| 196 if __name__ == '__main__': | |
| 197 pyauto_media.Main() | |
| OLD | NEW |