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

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: Nits. 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
26 27
27 import pyauto_media 28 import pyauto_media
28 import pyauto 29 import pyauto
29 import pyauto_paths 30 import pyauto_paths
30 import pyauto_utils 31 import pyauto_utils
31 32 import urllib2
DaleCurtis 2012/01/06 23:19:42 This should go under threading.
shadi 2012/01/07 04:56:19 Done.
32 33
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(),
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
96 97
97 def _FindTabLocked(self, url): 98 def _FindTabLocked(self, url):
98 """Returns the tab index for the tab belonging to this url. 99 """Returns the tab index for the tab belonging to this url.
99 100
100 self._automation_lock must be owned by caller. 101 self._automation_lock must be owned by caller.
101 """ 102 """
102 for tab in self._pyauto.GetBrowserInfo()['windows'][0]['tabs']: 103 for tab in self._pyauto.GetBrowserInfo()['windows'][0]['tabs']:
103 if tab['url'] == url: 104 if tab['url'] == url:
104 return tab['index'] 105 return tab['index']
105 106
106 def _HaveMetrics(self, unique_url): 107 def _HaveTTPMetric(self, unique_url):
DaleCurtis 2012/01/06 23:19:42 These methods are very similar, you should create
shadi 2012/01/07 04:56:19 Done.
107 """Returns true if metrics are ready. Set self.{_epp,_ttp} < 0 pre-run.""" 108 """Returns true if ttp metrics is ready. Set self._ttp < 0 pre-run."""
108 with self._automation_lock: 109 with self._automation_lock:
109 tab = self._FindTabLocked(unique_url) 110 tab = self._FindTabLocked(unique_url)
111 self._ttp = int(self._pyauto.GetDOMValue('time_to_playback',
112 tab_index=tab))
DaleCurtis 2012/01/06 23:19:42 Bad indent. Please run gpylint before publishing.
shadi 2012/01/07 04:56:19 Done.
113 return self._ttp >= 0
110 114
111 if self._epp < 0: 115 def _HaveEPPMetric(self, unique_url):
112 self._epp = int(self._pyauto.GetDOMValue('extra_play_percentage', 116 """Returns true if epp metric is ready. Set self._epp < 0 pre-run."""
117 with self._automation_lock:
118 tab = self._FindTabLocked(unique_url)
119 self._epp = int(self._pyauto.GetDOMValue('extra_play_percentage',
113 tab_index=tab)) 120 tab_index=tab))
114 if self._ttp < 0: 121 return self._epp >= 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 122
119 def run(self): 123 def run(self):
120 """Opens tab, starts HTML test, and records metrics for each queue entry. 124 """Opens tab, starts HTML test, and records metrics for each queue entry.
121 125
122 No exception handling is done to make sure the main thread exits properly 126 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 127 during Chrome crashes or other failures. Doing otherwise has the potential
124 to leave the CNS server running in the background. 128 to leave the CNS server running in the background.
125 129
126 For a clean shutdown, put the magic exit value (None, None) in the queue. 130 For a clean shutdown, put the magic exit value (None, None) in the queue.
127 """ 131 """
(...skipping 20 matching lines...) Expand all
148 # Start the test! 152 # Start the test!
149 with self._automation_lock: 153 with self._automation_lock:
150 self._pyauto.AppendTab(pyauto.GURL(unique_url)) 154 self._pyauto.AppendTab(pyauto.GURL(unique_url))
151 self._pyauto.CallJavascriptFunc( 155 self._pyauto.CallJavascriptFunc(
152 'startTest', [video_url], tab_index=self._FindTabLocked(unique_url)) 156 'startTest', [video_url], tab_index=self._FindTabLocked(unique_url))
153 157
154 # Wait until the necessary metrics have been collected. Okay to not lock 158 # Wait until the necessary metrics have been collected. Okay to not lock
155 # here since pyauto.WaitUntil doesn't call into Chrome. 159 # here since pyauto.WaitUntil doesn't call into Chrome.
156 self._epp = self._ttp = -1 160 self._epp = self._ttp = -1
157 self._pyauto.WaitUntil( 161 self._pyauto.WaitUntil(
158 self._HaveMetrics, args=[unique_url], retry_sleep=2, 162 self._HaveTTPMetric, args=[unique_url], retry_sleep=1, timeout= 5,
DaleCurtis 2012/01/06 23:19:42 Bad spacing. Again gpylint is your friend here :)
shadi 2012/01/07 04:56:19 Done.
159 timeout=_TEST_VIDEO_DURATION_SEC * 10) 163 debug=False)
164
165 # Do not wait for epp if ttp is not available.
166 if self._ttp >= 0:
DaleCurtis 2012/01/06 23:19:42 Should we log an error? Skip logging of epp, ttp b
shadi 2012/01/07 04:56:19 Done.
167 self._pyauto.WaitUntil(
168 self._HaveEPPMetric, args=[unique_url], retry_sleep=2,
169 timeout=_TEST_VIDEO_DURATION_SEC * 10, debug=False)
160 170
161 # Record results. 171 # Record results.
162 # TODO(dalecurtis): Support reference builds. 172 # TODO(dalecurtis): Support reference builds.
163 series_name = ''.join(name) 173 series_name = ''.join(name)
164 pyauto_utils.PrintPerfResult('epp', series_name, self._epp, '%') 174 pyauto_utils.PrintPerfResult('epp', series_name, self._epp, '%')
165 pyauto_utils.PrintPerfResult('ttp', series_name, self._ttp, 'ms') 175 pyauto_utils.PrintPerfResult('ttp', series_name, self._ttp, 'ms')
166 176
167 # Close the tab. 177 # Close the tab.
168 with self._automation_lock: 178 with self._automation_lock:
169 self._pyauto.GetBrowserWindow(0).GetTab( 179 self._pyauto.GetBrowserWindow(0).GetTab(
170 self._FindTabLocked(unique_url)).Close(True) 180 self._FindTabLocked(unique_url)).Close(True)
171 181
172 # TODO(dalecurtis): Check results for regressions. 182 # TODO(dalecurtis): Check results for regressions.
173 self._tasks.task_done() 183 self._tasks.task_done()
174 184
175 185
186 class ProcessLogger(threading.Thread):
187 """A thread to log a process's stderr output."""
188 def __init__(self, process):
DaleCurtis 2012/01/06 23:19:42 Need blank line above this. gpylint... :)
shadi 2012/01/07 04:56:19 Done.
189 """Starts the process logger thread.
190
191 Args:
192 process: The process to log.
193 """
194 threading.Thread.__init__(self)
195 self._process = process
196 self.start()
197
198 def run(self):
199 """Adds debug statements for the process's stderr output."""
200 line = True
201 while line:
202 line = self._process.stderr.readline()
203 logging.debug(line)
204
205
176 class MediaConstrainedNetworkPerfTest(pyauto.PyUITest): 206 class MediaConstrainedNetworkPerfTest(pyauto.PyUITest):
177 """PyAuto test container. See file doc string for more information.""" 207 """PyAuto test container. See file doc string for more information."""
178 208
179 def setUp(self): 209 def setUp(self):
180 """Starts the Constrained Network Server (CNS).""" 210 """Starts the Constrained Network Server (CNS)."""
181 cmd = [sys.executable, os.path.join(pyauto_paths.GetSourceDir(), _CNS_PATH), 211 cmd = [sys.executable, os.path.join(pyauto_paths.GetSourceDir(), _CNS_PATH),
182 '--port', str(_CNS_PORT), 212 '--port', str(_CNS_PORT),
183 '--interface', 'lo', 213 '--interface', 'lo',
184 '--www-root', os.path.join( 214 '--www-root', os.path.join(
185 self.DataDir(), 'pyauto_private', 'media')] 215 self.DataDir(), 'pyauto_private', 'media'),
216 '-v']
186 217
187 process = subprocess.Popen(cmd, stderr=subprocess.PIPE) 218 process = subprocess.Popen(cmd, stderr=subprocess.PIPE)
188 219
189 # Wait for server to start up. 220 # Wait for server to start up.
190 line = True 221 line = True
191 while line: 222 while line:
192 line = process.stderr.readline() 223 line = process.stderr.readline()
224 logging.debug(line)
193 if 'STARTED' in line: 225 if 'STARTED' in line:
194 self._server_pid = process.pid 226 self._server_pid = process.pid
195 pyauto.PyUITest.setUp(self) 227 pyauto.PyUITest.setUp(self)
228 ProcessLogger(process)
229 self.CheckServerAccess()
196 return 230 return
197 self.fail('Failed to start CNS.') 231 self.fail('Failed to start CNS.')
198 232
233 def CheckServerAccess(self):
234 """Checks is the CNS server can serve a file with no network constraints."""
235 test_url = ''.join([_CNS_BASE_URL, 'f=' ,_TEST_VIDEO])
236 try:
237 urllib2.urlopen(test_url)
238 except:
239 # Need to call teardown since the server has already started.
240 self.tearDown()
DaleCurtis 2012/01/06 23:19:42 This should be called automatically. Did you find
shadi 2012/01/07 04:56:19 If setup() fails, tearDown() doesn't get called au
241 self.fail('Cannot connect to CNS server.')
DaleCurtis 2012/01/06 23:19:42 Instead of having a new fail here, why not just re
shadi 2012/01/07 04:56:19 Done.
242
199 def tearDown(self): 243 def tearDown(self):
200 """Stops the Constrained Network Server (CNS).""" 244 """Stops the Constrained Network Server (CNS)."""
201 pyauto.PyUITest.tearDown(self) 245 pyauto.PyUITest.tearDown(self)
202 self.Kill(self._server_pid) 246 self.Kill(self._server_pid)
203 247
204 def testConstrainedNetworkPerf(self): 248 def testConstrainedNetworkPerf(self):
205 """Starts CNS, spins up worker threads to run through _TEST_CONSTRAINTS.""" 249 """Starts CNS, spins up worker threads to run through _TEST_CONSTRAINTS."""
206 # Convert relative test path into an absolute path. 250 # Convert relative test path into an absolute path.
207 test_url = self.GetFileURLForDataPath(_TEST_HTML_PATH) 251 test_url = self.GetFileURLForDataPath(_TEST_HTML_PATH)
208 252
(...skipping 14 matching lines...) Expand all
223 tasks.put((None, None)) 267 tasks.put((None, None))
224 268
225 # Wait for threads to exit, gracefully or otherwise. 269 # Wait for threads to exit, gracefully or otherwise.
226 for thread in threads: 270 for thread in threads:
227 thread.join() 271 thread.join()
228 272
229 273
230 if __name__ == '__main__': 274 if __name__ == '__main__':
231 # TODO(dalecurtis): Process command line parameters here. 275 # TODO(dalecurtis): Process command line parameters here.
232 pyauto_media.Main() 276 pyauto_media.Main()
OLDNEW
« no previous file with comments | « no previous file | media/tools/constrained_network_server/cn.py » ('j') | media/tools/constrained_network_server/cns.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698