[Cronet] Delay StartNetLog and StopNetLog until native request context is initialized
[chromium-blink-merge.git] / tools / chrome_proxy / integration_tests / chrome_proxy_measurements.py
blobee756192ee29968c9c5c94d6f6b2f95f83de2ff6
1 # Copyright 2014 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 import base64
6 import logging
7 import urlparse
9 from integration_tests import chrome_proxy_metrics as metrics
10 from metrics import loading
11 from telemetry.core import exceptions
12 from telemetry.page import page_test
15 class ChromeProxyLatency(page_test.PageTest):
16 """Chrome proxy latency measurement."""
18 def __init__(self, *args, **kwargs):
19 super(ChromeProxyLatency, self).__init__(*args, **kwargs)
20 self._metrics = metrics.ChromeProxyMetric()
22 def CustomizeBrowserOptions(self, options):
23 options.AppendExtraBrowserArgs('--enable-spdy-proxy-auth')
25 def WillNavigateToPage(self, page, tab):
26 tab.ClearCache(force=True)
28 def ValidateAndMeasurePage(self, page, tab, results):
29 # Wait for the load event.
30 tab.WaitForJavaScriptExpression('performance.timing.loadEventStart', 300)
31 self._metrics.AddResultsForLatency(tab, results)
34 class ChromeProxyDataSaving(page_test.PageTest):
35 """Chrome proxy data saving measurement."""
36 def __init__(self, *args, **kwargs):
37 super(ChromeProxyDataSaving, self).__init__(*args, **kwargs)
38 self._metrics = metrics.ChromeProxyMetric()
40 def CustomizeBrowserOptions(self, options):
41 options.AppendExtraBrowserArgs('--enable-spdy-proxy-auth')
43 def WillNavigateToPage(self, page, tab):
44 tab.ClearCache(force=True)
45 self._metrics.Start(page, tab)
47 def ValidateAndMeasurePage(self, page, tab, results):
48 # Wait for the load event.
49 tab.WaitForJavaScriptExpression('performance.timing.loadEventStart', 300)
50 self._metrics.Stop(page, tab)
51 self._metrics.AddResultsForDataSaving(tab, results)
54 class ChromeProxyValidation(page_test.PageTest):
55 """Base class for all chrome proxy correctness measurements."""
57 def __init__(self, restart_after_each_page=False):
58 super(ChromeProxyValidation, self).__init__(
59 needs_browser_restart_after_each_page=restart_after_each_page)
60 self._metrics = metrics.ChromeProxyMetric()
61 self._page = None
62 # Whether a timeout exception is expected during the test.
63 self._expect_timeout = False
65 def CustomizeBrowserOptions(self, options):
66 # Enable the chrome proxy (data reduction proxy).
67 options.AppendExtraBrowserArgs('--enable-spdy-proxy-auth')
69 def WillNavigateToPage(self, page, tab):
70 tab.ClearCache(force=True)
71 assert self._metrics
72 self._metrics.Start(page, tab)
74 def ValidateAndMeasurePage(self, page, tab, results):
75 self._page = page
76 # Wait for the load event.
77 tab.WaitForJavaScriptExpression('performance.timing.loadEventStart', 300)
78 assert self._metrics
79 self._metrics.Stop(page, tab)
80 self.AddResults(tab, results)
82 def AddResults(self, tab, results):
83 raise NotImplementedError
85 def StopBrowserAfterPage(self, browser, page): # pylint: disable=W0613
86 if hasattr(page, 'restart_after') and page.restart_after:
87 return True
88 return False
90 def RunNavigateSteps(self, page, tab):
91 # The redirect from safebrowsing causes a timeout. Ignore that.
92 try:
93 super(ChromeProxyValidation, self).RunNavigateSteps(page, tab)
94 if self._expect_timeout:
95 raise metrics.ChromeProxyMetricException, (
96 'Timeout was expected, but did not occur')
97 except exceptions.TimeoutException as e:
98 if self._expect_timeout:
99 logging.warning('Navigation timeout on page %s',
100 page.name if page.name else page.url)
101 else:
102 raise e
105 class ChromeProxyHeaders(ChromeProxyValidation):
106 """Correctness measurement for response headers."""
108 def __init__(self):
109 super(ChromeProxyHeaders, self).__init__(restart_after_each_page=True)
111 def AddResults(self, tab, results):
112 self._metrics.AddResultsForHeaderValidation(tab, results)
115 class ChromeProxyBypass(ChromeProxyValidation):
116 """Correctness measurement for bypass responses."""
118 def __init__(self):
119 super(ChromeProxyBypass, self).__init__(restart_after_each_page=True)
121 def AddResults(self, tab, results):
122 self._metrics.AddResultsForBypass(tab, results)
125 class ChromeProxyCorsBypass(ChromeProxyValidation):
126 """Correctness measurement for bypass responses for CORS requests."""
128 def __init__(self):
129 super(ChromeProxyCorsBypass, self).__init__(restart_after_each_page=True)
131 def ValidateAndMeasurePage(self, page, tab, results):
132 # The test page sets window.xhrRequestCompleted to true when the XHR fetch
133 # finishes.
134 tab.WaitForJavaScriptExpression('window.xhrRequestCompleted', 300)
135 super(ChromeProxyCorsBypass,
136 self).ValidateAndMeasurePage(page, tab, results)
138 def AddResults(self, tab, results):
139 self._metrics.AddResultsForCorsBypass(tab, results)
142 class ChromeProxyBlockOnce(ChromeProxyValidation):
143 """Correctness measurement for block-once responses."""
145 def __init__(self):
146 super(ChromeProxyBlockOnce, self).__init__(restart_after_each_page=True)
148 def AddResults(self, tab, results):
149 self._metrics.AddResultsForBlockOnce(tab, results)
152 class ChromeProxySafebrowsingOn(ChromeProxyValidation):
153 """Correctness measurement for safebrowsing."""
155 def __init__(self):
156 super(ChromeProxySafebrowsingOn, self).__init__()
158 def WillNavigateToPage(self, page, tab):
159 super(ChromeProxySafebrowsingOn, self).WillNavigateToPage(page, tab)
160 self._expect_timeout = True
162 def AddResults(self, tab, results):
163 self._metrics.AddResultsForSafebrowsingOn(tab, results)
165 class ChromeProxySafebrowsingOff(ChromeProxyValidation):
166 """Correctness measurement for safebrowsing."""
168 def __init__(self):
169 super(ChromeProxySafebrowsingOff, self).__init__()
171 def AddResults(self, tab, results):
172 self._metrics.AddResultsForSafebrowsingOff(tab, results)
174 _FAKE_PROXY_AUTH_VALUE = 'aabbccdd3b7579186c1b0620614fdb1f0000ffff'
175 _TEST_SERVER = 'chromeproxy-test.appspot.com'
176 _TEST_SERVER_DEFAULT_URL = 'http://' + _TEST_SERVER + '/default'
179 # We rely on the chromeproxy-test server to facilitate some of the tests.
180 # The test server code is at <TBD location> and runs at _TEST_SERVER
182 # The test server allow request to override response status, headers, and
183 # body through query parameters. See GetResponseOverrideURL.
184 def GetResponseOverrideURL(url=_TEST_SERVER_DEFAULT_URL, respStatus=0,
185 respHeader="", respBody=""):
186 """ Compose the request URL with query parameters to override
187 the chromeproxy-test server response.
190 queries = []
191 if respStatus > 0:
192 queries.append('respStatus=%d' % respStatus)
193 if respHeader:
194 queries.append('respHeader=%s' % base64.b64encode(respHeader))
195 if respBody:
196 queries.append('respBody=%s' % base64.b64encode(respBody))
197 if len(queries) == 0:
198 return url
199 "&".join(queries)
200 # url has query already
201 if urlparse.urlparse(url).query:
202 return url + '&' + "&".join(queries)
203 else:
204 return url + '?' + "&".join(queries)
207 class ChromeProxyHTTPFallbackProbeURL(ChromeProxyValidation):
208 """Correctness measurement for proxy fallback.
210 In this test, the probe URL does not return 'OK'. Chrome is expected
211 to use the fallback proxy.
214 def __init__(self):
215 super(ChromeProxyHTTPFallbackProbeURL, self).__init__(
216 restart_after_each_page=True)
218 def CustomizeBrowserOptions(self, options):
219 super(ChromeProxyHTTPFallbackProbeURL,
220 self).CustomizeBrowserOptions(options)
221 # Set the secure proxy check URL to the google.com favicon, which will be
222 # interpreted as a secure proxy check failure since the response body is not
223 # "OK". The google.com favicon is used because it will load reliably fast,
224 # and there have been problems with chromeproxy-test.appspot.com being slow
225 # and causing tests to flake.
226 options.AppendExtraBrowserArgs(
227 '--data-reduction-proxy-secure-proxy-check-url='
228 'http://www.google.com/favicon.ico')
230 def AddResults(self, tab, results):
231 self._metrics.AddResultsForHTTPFallback(tab, results)
234 class ChromeProxyHTTPFallbackViaHeader(ChromeProxyValidation):
235 """Correctness measurement for proxy fallback.
237 In this test, the configured proxy is the chromeproxy-test server which
238 will send back a response without the expected Via header. Chrome is
239 expected to use the fallback proxy and add the configured proxy to the
240 bad proxy list.
243 def __init__(self):
244 super(ChromeProxyHTTPFallbackViaHeader, self).__init__(
245 restart_after_each_page=True)
247 def CustomizeBrowserOptions(self, options):
248 super(ChromeProxyHTTPFallbackViaHeader,
249 self).CustomizeBrowserOptions(options)
250 options.AppendExtraBrowserArgs('--ignore-certificate-errors')
251 options.AppendExtraBrowserArgs(
252 '--spdy-proxy-auth-origin=http://%s' % _TEST_SERVER)
254 def AddResults(self, tab, results):
255 self._metrics.AddResultsForHTTPFallback(tab, results)
258 class ChromeProxyClientVersion(ChromeProxyValidation):
259 """Correctness measurement for version directives in Chrome-Proxy header.
261 The test verifies that the version information provided in the Chrome-Proxy
262 request header overrides any version, if specified, that is provided in the
263 user agent string.
266 def __init__(self):
267 super(ChromeProxyClientVersion, self).__init__()
269 def CustomizeBrowserOptions(self, options):
270 super(ChromeProxyClientVersion,
271 self).CustomizeBrowserOptions(options)
272 options.AppendExtraBrowserArgs('--user-agent="Chrome/32.0.1700.99"')
274 def AddResults(self, tab, results):
275 self._metrics.AddResultsForClientVersion(tab, results)
278 class ChromeProxyClientType(ChromeProxyValidation):
279 """Correctness measurement for Chrome-Proxy header client type directives."""
281 def __init__(self):
282 super(ChromeProxyClientType, self).__init__(restart_after_each_page=True)
283 self._chrome_proxy_client_type = None
285 def AddResults(self, tab, results):
286 # Get the Chrome-Proxy client type from the first page in the page set, so
287 # that the client type value can be used to determine which of the later
288 # pages in the page set should be bypassed.
289 if not self._chrome_proxy_client_type:
290 client_type = self._metrics.GetClientTypeFromRequests(tab)
291 if client_type:
292 self._chrome_proxy_client_type = client_type
294 self._metrics.AddResultsForClientType(tab,
295 results,
296 self._chrome_proxy_client_type,
297 self._page.bypass_for_client_type)
300 class ChromeProxyLoFi(ChromeProxyValidation):
301 """Correctness measurement for Lo-Fi in Chrome-Proxy header."""
303 def __init__(self):
304 super(ChromeProxyLoFi, self).__init__(restart_after_each_page=True)
306 def CustomizeBrowserOptions(self, options):
307 super(ChromeProxyLoFi, self).CustomizeBrowserOptions(options)
308 options.AppendExtraBrowserArgs('--enable-data-reduction-proxy-lo-fi')
310 def AddResults(self, tab, results):
311 self._metrics.AddResultsForLoFi(tab, results)
314 class ChromeProxyHTTPToDirectFallback(ChromeProxyValidation):
315 """Correctness measurement for HTTP proxy fallback to direct."""
317 def __init__(self):
318 super(ChromeProxyHTTPToDirectFallback, self).__init__(
319 restart_after_each_page=True)
321 def CustomizeBrowserOptions(self, options):
322 super(ChromeProxyHTTPToDirectFallback,
323 self).CustomizeBrowserOptions(options)
324 # Set the primary proxy to something that will fail to be resolved so that
325 # this test will run using the HTTP fallback proxy.
326 options.AppendExtraBrowserArgs(
327 '--spdy-proxy-auth-origin=http://nonexistent.googlezip.net')
329 def WillNavigateToPage(self, page, tab):
330 super(ChromeProxyHTTPToDirectFallback, self).WillNavigateToPage(page, tab)
331 # Attempt to load a page through the nonexistent primary proxy in order to
332 # cause a proxy fallback, and have this test run starting from the HTTP
333 # fallback proxy.
334 tab.Navigate(_TEST_SERVER_DEFAULT_URL)
335 tab.WaitForJavaScriptExpression('performance.timing.loadEventStart', 300)
337 def AddResults(self, tab, results):
338 self._metrics.AddResultsForHTTPToDirectFallback(tab, results, _TEST_SERVER)
341 class ChromeProxyReenableAfterBypass(ChromeProxyValidation):
342 """Correctness measurement for re-enabling proxies after bypasses.
344 This test loads a page that causes all data reduction proxies to be bypassed
345 for 1 to 5 minutes, then waits 5 minutes and verifies that the proxy is no
346 longer bypassed.
349 def __init__(self):
350 super(ChromeProxyReenableAfterBypass, self).__init__(
351 restart_after_each_page=True)
353 def AddResults(self, tab, results):
354 self._metrics.AddResultsForReenableAfterBypass(
355 tab, results, self._page.bypass_seconds_min,
356 self._page.bypass_seconds_max)
359 class ChromeProxySmoke(ChromeProxyValidation):
360 """Smoke measurement for basic chrome proxy correctness."""
362 def __init__(self):
363 super(ChromeProxySmoke, self).__init__(restart_after_each_page=True)
365 def WillNavigateToPage(self, page, tab):
366 super(ChromeProxySmoke, self).WillNavigateToPage(page, tab)
368 def AddResults(self, tab, results):
369 # Map a page name to its AddResults func.
370 page_to_metrics = {
371 'header validation': [self._metrics.AddResultsForHeaderValidation],
372 'compression: image': [
373 self._metrics.AddResultsForHeaderValidation,
374 self._metrics.AddResultsForDataSaving,
376 'compression: javascript': [
377 self._metrics.AddResultsForHeaderValidation,
378 self._metrics.AddResultsForDataSaving,
380 'compression: css': [
381 self._metrics.AddResultsForHeaderValidation,
382 self._metrics.AddResultsForDataSaving,
384 'bypass': [self._metrics.AddResultsForBypass],
386 if not self._page.name in page_to_metrics:
387 raise page_test.MeasurementFailure(
388 'Invalid page name (%s) in smoke. Page name must be one of:\n%s' % (
389 self._page.name, page_to_metrics.keys()))
390 for add_result in page_to_metrics[self._page.name]:
391 add_result(tab, results)