Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1138)

Side by Side Diff: chrome/test/functional/media/media_constrained_network_perf.py

Issue 9127009: Constrained Network test does not fail fast under fatal conditions. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: and again... Created 8 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Records metrics on playing media under constrained network conditions. 6 """Records metrics on playing media under constrained network conditions.
7 7
8 Spins up a Constrained Network Server (CNS) and runs through a test matrix of 8 Spins up a Constrained Network Server (CNS) and runs through a test matrix of
9 bandwidth, latency, and packet loss settings. Each run records a 9 bandwidth, latency, and packet loss settings. Each run records a
10 time-to-playback (TTP) and extra-play-percentage (EPP) metric in a format 10 time-to-playback (TTP) and extra-play-percentage (EPP) metric in a format
11 consumable by the Chromium perf bots. 11 consumable by the Chromium perf bots.
12 12
13 Since even a small number of different settings yields a large test matrix, the 13 Since even a small number of different settings yields a large test matrix, the
14 design is threaded... however PyAuto is not, so a global lock is used when calls 14 design is threaded... however PyAuto is not, so a global lock is used when calls
15 into PyAuto are necessary. The number of threads can be set by _TEST_THREADS. 15 into PyAuto are necessary. The number of threads can be set by _TEST_THREADS.
16 16
17 The CNS code is located under: <root>/src/media/tools/constrained_network_server 17 The CNS code is located under: <root>/src/media/tools/constrained_network_server
18 """ 18 """
19 19
20 import itertools 20 import itertools
21 import logging
21 import os 22 import os
22 import Queue 23 import Queue
23 import subprocess 24 import subprocess
24 import sys 25 import sys
25 import threading 26 import threading
27 import urllib2
26 28
27 import pyauto_media 29 import pyauto_media
28 import pyauto 30 import pyauto
29 import pyauto_paths 31 import pyauto_paths
30 import pyauto_utils 32 import pyauto_utils
31 33
32
33 # Settings for each network constraint. 34 # Settings for each network constraint.
34 _BANDWIDTH_SETTINGS_KBPS = {'None': 0, 'Low': 256, 'Medium': 2000, 'High': 5000} 35 _BANDWIDTH_SETTINGS_KBPS = {'None': 0, 'Low': 256, 'Medium': 2000, 'High': 5000}
35 _LATENCY_SETTINGS_MS = {'None': 0, 'Low': 43, 'Medium': 105, 'High': 180} 36 _LATENCY_SETTINGS_MS = {'None': 0, 'Low': 43, 'Medium': 105, 'High': 180}
36 _PACKET_LOSS_SETTINGS_PERCENT = {'None': 0, 'Medium': 2, 'High': 5} 37 _PACKET_LOSS_SETTINGS_PERCENT = {'None': 0, 'Medium': 2, 'High': 5}
37 38
38 # Test constraints are all possible combination of the above settings. Each 39 # Test constraints are all possible combination of the above settings. Each
39 # tuple must be of the form (Bandwidth, Latency, Packet Loss). 40 # tuple must be of the form (Bandwidth, Latency, Packet Loss).
40 _TEST_CONSTRAINTS = itertools.product( 41 _TEST_CONSTRAINTS = itertools.product(
41 _BANDWIDTH_SETTINGS_KBPS.values(), 42 _BANDWIDTH_SETTINGS_KBPS.values(),
42 _LATENCY_SETTINGS_MS.values(), 43 _LATENCY_SETTINGS_MS.values(),
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 pyauto_test: Reference to a pyauto.PyUITest instance. 86 pyauto_test: Reference to a pyauto.PyUITest instance.
86 tasks: Queue containing (settings, name) tuples. 87 tasks: Queue containing (settings, name) tuples.
87 automation_lock: Global automation lock for pyauto calls. 88 automation_lock: Global automation lock for pyauto calls.
88 url: File URL to HTML/JavaScript test code. 89 url: File URL to HTML/JavaScript test code.
89 """ 90 """
90 threading.Thread.__init__(self) 91 threading.Thread.__init__(self)
91 self._tasks = tasks 92 self._tasks = tasks
92 self._automation_lock = automation_lock 93 self._automation_lock = automation_lock
93 self._pyauto = pyauto_test 94 self._pyauto = pyauto_test
94 self._url = url 95 self._url = url
96 self._metrics = {}
95 self.start() 97 self.start()
96 98
97 def _FindTabLocked(self, url): 99 def _FindTabLocked(self, url):
98 """Returns the tab index for the tab belonging to this url. 100 """Returns the tab index for the tab belonging to this url.
99 101
100 self._automation_lock must be owned by caller. 102 self._automation_lock must be owned by caller.
101 """ 103 """
102 for tab in self._pyauto.GetBrowserInfo()['windows'][0]['tabs']: 104 for tab in self._pyauto.GetBrowserInfo()['windows'][0]['tabs']:
103 if tab['url'] == url: 105 if tab['url'] == url:
104 return tab['index'] 106 return tab['index']
105 107
106 def _HaveMetrics(self, unique_url): 108 def _HaveMetric(self, var_name, unique_url):
107 """Returns true if metrics are ready. Set self.{_epp,_ttp} < 0 pre-run.""" 109 """Checks if unique_url page has variable value ready. Set to < 0 pre-run.
110
111 Args:
112 var_name: The variable name to check the metric for.
113 unique_url: The url of the page to check for the variable's metric.
114 """
108 with self._automation_lock: 115 with self._automation_lock:
109 tab = self._FindTabLocked(unique_url) 116 tab = self._FindTabLocked(unique_url)
110 117 self._metrics[var_name] = int(self._pyauto.GetDOMValue(var_name,
111 if self._epp < 0: 118 tab_index=tab))
112 self._epp = int(self._pyauto.GetDOMValue('extra_play_percentage', 119 return self._metrics[var_name] >= 0
113 tab_index=tab))
114 if self._ttp < 0:
115 self._ttp = int(self._pyauto.GetDOMValue('time_to_playback',
116 tab_index=tab))
117 return self._epp >= 0 and self._ttp >= 0
118 120
119 def run(self): 121 def run(self):
120 """Opens tab, starts HTML test, and records metrics for each queue entry. 122 """Opens tab, starts HTML test, and records metrics for each queue entry.
121 123
122 No exception handling is done to make sure the main thread exits properly 124 No exception handling is done to make sure the main thread exits properly
123 during Chrome crashes or other failures. Doing otherwise has the potential 125 during Chrome crashes or other failures. Doing otherwise has the potential
124 to leave the CNS server running in the background. 126 to leave the CNS server running in the background.
125 127
126 For a clean shutdown, put the magic exit value (None, None) in the queue. 128 For a clean shutdown, put the magic exit value (None, None) in the queue.
127 """ 129 """
(...skipping 18 matching lines...) Expand all
146 unique_url = '%s?%d' % (self._url, TestWorker._task_id.next()) 148 unique_url = '%s?%d' % (self._url, TestWorker._task_id.next())
147 149
148 # Start the test! 150 # Start the test!
149 with self._automation_lock: 151 with self._automation_lock:
150 self._pyauto.AppendTab(pyauto.GURL(unique_url)) 152 self._pyauto.AppendTab(pyauto.GURL(unique_url))
151 self._pyauto.CallJavascriptFunc( 153 self._pyauto.CallJavascriptFunc(
152 'startTest', [video_url], tab_index=self._FindTabLocked(unique_url)) 154 'startTest', [video_url], tab_index=self._FindTabLocked(unique_url))
153 155
154 # Wait until the necessary metrics have been collected. Okay to not lock 156 # Wait until the necessary metrics have been collected. Okay to not lock
155 # here since pyauto.WaitUntil doesn't call into Chrome. 157 # here since pyauto.WaitUntil doesn't call into Chrome.
156 self._epp = self._ttp = -1 158 self._metrics['epp'] = self._metrics['ttp'] = -1
157 self._pyauto.WaitUntil( 159 self._pyauto.WaitUntil(
158 self._HaveMetrics, args=[unique_url], retry_sleep=2, 160 self._HaveMetric, args=['ttp', unique_url], retry_sleep=1, timeout=10,
159 timeout=_TEST_VIDEO_DURATION_SEC * 10) 161 debug=False)
160 162
161 # Record results. 163 # Do not wait for epp if ttp is not available.
162 # TODO(dalecurtis): Support reference builds.
163 series_name = ''.join(name) 164 series_name = ''.join(name)
164 pyauto_utils.PrintPerfResult('epp', series_name, self._epp, '%') 165 if self._metrics['ttp'] >= 0:
165 pyauto_utils.PrintPerfResult('ttp', series_name, self._ttp, 'ms') 166 self._pyauto.WaitUntil(
167 self._HaveMetric, args=['epp', unique_url], retry_sleep=2,
168 timeout=_TEST_VIDEO_DURATION_SEC * 10, debug=False)
169
170 # Record results.
171 # TODO(dalecurtis): Support reference builds.
172 pyauto_utils.PrintPerfResult('epp', series_name, self._metrics['epp'],
173 '%')
174 pyauto_utils.PrintPerfResult('ttp', series_name, self._metrics['ttp'],
175 'ms')
176 else:
177 logging.error('Test %s timed-out.', series_name)
166 178
167 # Close the tab. 179 # Close the tab.
168 with self._automation_lock: 180 with self._automation_lock:
169 self._pyauto.GetBrowserWindow(0).GetTab( 181 self._pyauto.GetBrowserWindow(0).GetTab(
170 self._FindTabLocked(unique_url)).Close(True) 182 self._FindTabLocked(unique_url)).Close(True)
171 183
172 # TODO(dalecurtis): Check results for regressions. 184 # TODO(dalecurtis): Check results for regressions.
173 self._tasks.task_done() 185 self._tasks.task_done()
174 186
175 187
188 class ProcessLogger(threading.Thread):
189 """A thread to log a process's stderr output."""
190
191 def __init__(self, process):
192 """Starts the process logger thread.
193
194 Args:
195 process: The process to log.
196 """
197 threading.Thread.__init__(self)
198 self._process = process
199 self.start()
200
201 def run(self):
202 """Adds debug statements for the process's stderr output."""
203 line = True
204 while line:
205 line = self._process.stderr.readline()
206 logging.debug(line)
207
208
176 class MediaConstrainedNetworkPerfTest(pyauto.PyUITest): 209 class MediaConstrainedNetworkPerfTest(pyauto.PyUITest):
177 """PyAuto test container. See file doc string for more information.""" 210 """PyAuto test container. See file doc string for more information."""
178 211
179 def setUp(self): 212 def setUp(self):
180 """Starts the Constrained Network Server (CNS).""" 213 """Starts the Constrained Network Server (CNS)."""
181 cmd = [sys.executable, os.path.join(pyauto_paths.GetSourceDir(), _CNS_PATH), 214 cmd = [sys.executable, os.path.join(pyauto_paths.GetSourceDir(), _CNS_PATH),
182 '--port', str(_CNS_PORT), 215 '--port', str(_CNS_PORT),
183 '--interface', 'lo', 216 '--interface', 'lo',
184 '--www-root', os.path.join( 217 '--www-root', os.path.join(
185 self.DataDir(), 'pyauto_private', 'media')] 218 self.DataDir(), 'pyauto_private', 'media'),
219 '-v']
186 220
187 process = subprocess.Popen(cmd, stderr=subprocess.PIPE) 221 process = subprocess.Popen(cmd, stderr=subprocess.PIPE)
188 222
189 # Wait for server to start up. 223 # Wait for server to start up.
190 line = True 224 line = True
191 while line: 225 while line:
192 line = process.stderr.readline() 226 line = process.stderr.readline()
227 logging.debug(line)
193 if 'STARTED' in line: 228 if 'STARTED' in line:
194 self._server_pid = process.pid 229 self._server_pid = process.pid
195 pyauto.PyUITest.setUp(self) 230 pyauto.PyUITest.setUp(self)
196 return 231 ProcessLogger(process)
232 if self._CanAccessServer():
233 return
234 # Need to call teardown since the server has already started.
235 self.tearDown()
197 self.fail('Failed to start CNS.') 236 self.fail('Failed to start CNS.')
198 237
238 def _CanAccessServer(self):
239 """Checks if the CNS server can serve a file with no network constraints."""
240 test_url = ''.join([_CNS_BASE_URL, 'f=', _TEST_VIDEO])
241 try:
242 return urllib2.urlopen(test_url) is not None
243 except Exception, e:
244 logging.exception(e)
245 return False
246
199 def tearDown(self): 247 def tearDown(self):
200 """Stops the Constrained Network Server (CNS).""" 248 """Stops the Constrained Network Server (CNS)."""
201 pyauto.PyUITest.tearDown(self) 249 pyauto.PyUITest.tearDown(self)
202 self.Kill(self._server_pid) 250 self.Kill(self._server_pid)
203 251
204 def testConstrainedNetworkPerf(self): 252 def testConstrainedNetworkPerf(self):
205 """Starts CNS, spins up worker threads to run through _TEST_CONSTRAINTS.""" 253 """Starts CNS, spins up worker threads to run through _TEST_CONSTRAINTS."""
206 # Convert relative test path into an absolute path. 254 # Convert relative test path into an absolute path.
207 test_url = self.GetFileURLForDataPath(_TEST_HTML_PATH) 255 test_url = self.GetFileURLForDataPath(_TEST_HTML_PATH)
208 256
(...skipping 14 matching lines...) Expand all
223 tasks.put((None, None)) 271 tasks.put((None, None))
224 272
225 # Wait for threads to exit, gracefully or otherwise. 273 # Wait for threads to exit, gracefully or otherwise.
226 for thread in threads: 274 for thread in threads:
227 thread.join() 275 thread.join()
228 276
229 277
230 if __name__ == '__main__': 278 if __name__ == '__main__':
231 # TODO(dalecurtis): Process command line parameters here. 279 # TODO(dalecurtis): Process command line parameters here.
232 pyauto_media.Main() 280 pyauto_media.Main()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698