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 |