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.
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
14 class ChromeProxyLatency(page_test
.PageTest
):
15 """Chrome proxy latency measurement."""
17 def __init__(self
, *args
, **kwargs
):
18 super(ChromeProxyLatency
, self
).__init
__(*args
, **kwargs
)
19 self
._metrics
= metrics
.ChromeProxyMetric()
21 def CustomizeBrowserOptions(self
, options
):
22 options
.AppendExtraBrowserArgs('--enable-spdy-proxy-auth')
24 def WillNavigateToPage(self
, page
, tab
):
25 tab
.ClearCache(force
=True)
27 def ValidateAndMeasurePage(self
, page
, tab
, results
):
28 # Wait for the load event.
29 tab
.WaitForJavaScriptExpression('performance.timing.loadEventStart', 300)
30 self
._metrics
.AddResultsForLatency(tab
, results
)
33 class ChromeProxyDataSaving(page_test
.PageTest
):
34 """Chrome proxy data saving measurement."""
35 def __init__(self
, *args
, **kwargs
):
36 super(ChromeProxyDataSaving
, self
).__init
__(*args
, **kwargs
)
37 self
._metrics
= metrics
.ChromeProxyMetric()
39 def CustomizeBrowserOptions(self
, options
):
40 options
.AppendExtraBrowserArgs('--enable-spdy-proxy-auth')
42 def WillNavigateToPage(self
, page
, tab
):
43 tab
.ClearCache(force
=True)
44 self
._metrics
.Start(page
, tab
)
46 def ValidateAndMeasurePage(self
, page
, tab
, results
):
47 # Wait for the load event.
48 tab
.WaitForJavaScriptExpression('performance.timing.loadEventStart', 300)
49 self
._metrics
.Stop(page
, tab
)
50 self
._metrics
.AddResultsForDataSaving(tab
, results
)
53 class ChromeProxyValidation(page_test
.PageTest
):
54 """Base class for all chrome proxy correctness measurements."""
56 # Value of the extra via header. |None| if no extra via header is expected.
57 extra_via_header
= None
59 def __init__(self
, restart_after_each_page
=False):
60 super(ChromeProxyValidation
, self
).__init
__(
61 needs_browser_restart_after_each_page
=restart_after_each_page
)
62 self
._metrics
= metrics
.ChromeProxyMetric()
64 # Whether a timeout exception is expected during the test.
65 self
._expect
_timeout
= False
67 def CustomizeBrowserOptions(self
, options
):
68 # Enable the chrome proxy (data reduction proxy).
69 options
.AppendExtraBrowserArgs('--enable-spdy-proxy-auth')
71 def WillNavigateToPage(self
, page
, tab
):
72 tab
.ClearCache(force
=True)
74 self
._metrics
.Start(page
, tab
)
76 def ValidateAndMeasurePage(self
, page
, tab
, results
):
78 # Wait for the load event.
79 tab
.WaitForJavaScriptExpression('performance.timing.loadEventStart', 300)
81 self
._metrics
.Stop(page
, tab
)
82 if ChromeProxyValidation
.extra_via_header
:
83 self
._metrics
.AddResultsForExtraViaHeader(
84 tab
, results
, ChromeProxyValidation
.extra_via_header
)
85 self
.AddResults(tab
, results
)
87 def AddResults(self
, tab
, results
):
88 raise NotImplementedError
90 def StopBrowserAfterPage(self
, browser
, page
): # pylint: disable=W0613
91 if hasattr(page
, 'restart_after') and page
.restart_after
:
95 def RunNavigateSteps(self
, page
, tab
):
96 # The redirect from safebrowsing causes a timeout. Ignore that.
98 super(ChromeProxyValidation
, self
).RunNavigateSteps(page
, tab
)
99 if self
._expect
_timeout
:
100 raise metrics
.ChromeProxyMetricException
, (
101 'Timeout was expected, but did not occur')
102 except exceptions
.TimeoutException
as e
:
103 if self
._expect
_timeout
:
104 logging
.warning('Navigation timeout on page %s',
105 page
.name
if page
.name
else page
.url
)
110 class ChromeProxyHeaders(ChromeProxyValidation
):
111 """Correctness measurement for response headers."""
114 super(ChromeProxyHeaders
, self
).__init
__(restart_after_each_page
=True)
116 def AddResults(self
, tab
, results
):
117 self
._metrics
.AddResultsForHeaderValidation(tab
, results
)
120 class ChromeProxyBypass(ChromeProxyValidation
):
121 """Correctness measurement for bypass responses."""
124 super(ChromeProxyBypass
, self
).__init
__(restart_after_each_page
=True)
126 def AddResults(self
, tab
, results
):
127 self
._metrics
.AddResultsForBypass(tab
, results
)
130 class ChromeProxyCorsBypass(ChromeProxyValidation
):
131 """Correctness measurement for bypass responses for CORS requests."""
134 super(ChromeProxyCorsBypass
, self
).__init
__(restart_after_each_page
=True)
136 def ValidateAndMeasurePage(self
, page
, tab
, results
):
137 # The test page sets window.xhrRequestCompleted to true when the XHR fetch
139 tab
.WaitForJavaScriptExpression('window.xhrRequestCompleted', 300)
140 super(ChromeProxyCorsBypass
,
141 self
).ValidateAndMeasurePage(page
, tab
, results
)
143 def AddResults(self
, tab
, results
):
144 self
._metrics
.AddResultsForCorsBypass(tab
, results
)
147 class ChromeProxyBlockOnce(ChromeProxyValidation
):
148 """Correctness measurement for block-once responses."""
151 super(ChromeProxyBlockOnce
, self
).__init
__(restart_after_each_page
=True)
153 def AddResults(self
, tab
, results
):
154 self
._metrics
.AddResultsForBlockOnce(tab
, results
)
157 class ChromeProxySafebrowsingOn(ChromeProxyValidation
):
158 """Correctness measurement for safebrowsing."""
161 super(ChromeProxySafebrowsingOn
, self
).__init
__()
163 def WillNavigateToPage(self
, page
, tab
):
164 super(ChromeProxySafebrowsingOn
, self
).WillNavigateToPage(page
, tab
)
165 self
._expect
_timeout
= True
167 def AddResults(self
, tab
, results
):
168 self
._metrics
.AddResultsForSafebrowsingOn(tab
, results
)
170 class ChromeProxySafebrowsingOff(ChromeProxyValidation
):
171 """Correctness measurement for safebrowsing."""
174 super(ChromeProxySafebrowsingOff
, self
).__init
__()
176 def AddResults(self
, tab
, results
):
177 self
._metrics
.AddResultsForSafebrowsingOff(tab
, results
)
179 _FAKE_PROXY_AUTH_VALUE
= 'aabbccdd3b7579186c1b0620614fdb1f0000ffff'
180 _TEST_SERVER
= 'chromeproxy-test.appspot.com'
181 _TEST_SERVER_DEFAULT_URL
= 'http://' + _TEST_SERVER
+ '/default'
184 # We rely on the chromeproxy-test server to facilitate some of the tests.
185 # The test server code is at <TBD location> and runs at _TEST_SERVER
187 # The test server allow request to override response status, headers, and
188 # body through query parameters. See GetResponseOverrideURL.
189 def GetResponseOverrideURL(url
=_TEST_SERVER_DEFAULT_URL
, respStatus
=0,
190 respHeader
="", respBody
=""):
191 """ Compose the request URL with query parameters to override
192 the chromeproxy-test server response.
197 queries
.append('respStatus=%d' % respStatus
)
199 queries
.append('respHeader=%s' % base64
.b64encode(respHeader
))
201 queries
.append('respBody=%s' % base64
.b64encode(respBody
))
202 if len(queries
) == 0:
205 # url has query already
206 if urlparse
.urlparse(url
).query
:
207 return url
+ '&' + "&".join(queries
)
209 return url
+ '?' + "&".join(queries
)
212 class ChromeProxyHTTPFallbackProbeURL(ChromeProxyValidation
):
213 """Correctness measurement for proxy fallback.
215 In this test, the probe URL does not return 'OK'. Chrome is expected
216 to use the fallback proxy.
220 super(ChromeProxyHTTPFallbackProbeURL
, self
).__init
__(
221 restart_after_each_page
=True)
223 def CustomizeBrowserOptions(self
, options
):
224 super(ChromeProxyHTTPFallbackProbeURL
,
225 self
).CustomizeBrowserOptions(options
)
226 # Set the secure proxy check URL to the google.com favicon, which will be
227 # interpreted as a secure proxy check failure since the response body is not
228 # "OK". The google.com favicon is used because it will load reliably fast,
229 # and there have been problems with chromeproxy-test.appspot.com being slow
230 # and causing tests to flake.
231 options
.AppendExtraBrowserArgs(
232 '--data-reduction-proxy-secure-proxy-check-url='
233 'http://www.google.com/favicon.ico')
235 def AddResults(self
, tab
, results
):
236 self
._metrics
.AddResultsForHTTPFallback(tab
, results
)
239 class ChromeProxyHTTPFallbackViaHeader(ChromeProxyValidation
):
240 """Correctness measurement for proxy fallback.
242 In this test, the configured proxy is the chromeproxy-test server which
243 will send back a response without the expected Via header. Chrome is
244 expected to use the fallback proxy and add the configured proxy to the
249 super(ChromeProxyHTTPFallbackViaHeader
, self
).__init
__(
250 restart_after_each_page
=True)
252 def CustomizeBrowserOptions(self
, options
):
253 super(ChromeProxyHTTPFallbackViaHeader
,
254 self
).CustomizeBrowserOptions(options
)
255 options
.AppendExtraBrowserArgs('--ignore-certificate-errors')
256 options
.AppendExtraBrowserArgs(
257 '--spdy-proxy-auth-origin=http://%s' % _TEST_SERVER
)
259 def AddResults(self
, tab
, results
):
260 self
._metrics
.AddResultsForHTTPFallback(tab
, results
)
263 class ChromeProxyClientVersion(ChromeProxyValidation
):
264 """Correctness measurement for version directives in Chrome-Proxy header.
266 The test verifies that the version information provided in the Chrome-Proxy
267 request header overrides any version, if specified, that is provided in the
272 super(ChromeProxyClientVersion
, self
).__init
__()
274 def CustomizeBrowserOptions(self
, options
):
275 super(ChromeProxyClientVersion
,
276 self
).CustomizeBrowserOptions(options
)
277 options
.AppendExtraBrowserArgs('--user-agent="Chrome/32.0.1700.99"')
279 def AddResults(self
, tab
, results
):
280 self
._metrics
.AddResultsForClientVersion(tab
, results
)
283 class ChromeProxyClientType(ChromeProxyValidation
):
284 """Correctness measurement for Chrome-Proxy header client type directives."""
287 super(ChromeProxyClientType
, self
).__init
__(restart_after_each_page
=True)
288 self
._chrome
_proxy
_client
_type
= None
290 def AddResults(self
, tab
, results
):
291 # Get the Chrome-Proxy client type from the first page in the page set, so
292 # that the client type value can be used to determine which of the later
293 # pages in the page set should be bypassed.
294 if not self
._chrome
_proxy
_client
_type
:
295 client_type
= self
._metrics
.GetClientTypeFromRequests(tab
)
297 self
._chrome
_proxy
_client
_type
= client_type
299 self
._metrics
.AddResultsForClientType(tab
,
301 self
._chrome
_proxy
_client
_type
,
302 self
._page
.bypass_for_client_type
)
305 class ChromeProxyLoFi(ChromeProxyValidation
):
306 """Correctness measurement for Lo-Fi in Chrome-Proxy header."""
309 super(ChromeProxyLoFi
, self
).__init
__(restart_after_each_page
=True)
311 def CustomizeBrowserOptions(self
, options
):
312 super(ChromeProxyLoFi
, self
).CustomizeBrowserOptions(options
)
313 options
.AppendExtraBrowserArgs('--enable-data-reduction-proxy-lo-fi')
315 def AddResults(self
, tab
, results
):
316 self
._metrics
.AddResultsForLoFi(tab
, results
)
318 class ChromeProxyExpDirective(ChromeProxyValidation
):
319 """Correctness measurement for experiment directives in Chrome-Proxy header.
321 This test verifies that "exp=test" in the Chrome-Proxy request header
322 causes a bypass on the experiment test page.
326 super(ChromeProxyExpDirective
, self
).__init
__(restart_after_each_page
=True)
328 def CustomizeBrowserOptions(self
, options
):
329 super(ChromeProxyExpDirective
, self
).CustomizeBrowserOptions(options
)
330 options
.AppendExtraBrowserArgs('--data-reduction-proxy-experiment=test')
332 def AddResults(self
, tab
, results
):
333 self
._metrics
.AddResultsForBypass(tab
, results
)
336 class ChromeProxyHTTPToDirectFallback(ChromeProxyValidation
):
337 """Correctness measurement for HTTP proxy fallback to direct."""
340 super(ChromeProxyHTTPToDirectFallback
, self
).__init
__(
341 restart_after_each_page
=True)
343 def CustomizeBrowserOptions(self
, options
):
344 super(ChromeProxyHTTPToDirectFallback
,
345 self
).CustomizeBrowserOptions(options
)
346 # Set the primary proxy to something that will fail to be resolved so that
347 # this test will run using the HTTP fallback proxy.
348 options
.AppendExtraBrowserArgs(
349 '--spdy-proxy-auth-origin=http://nonexistent.googlezip.net')
351 def WillNavigateToPage(self
, page
, tab
):
352 super(ChromeProxyHTTPToDirectFallback
, self
).WillNavigateToPage(page
, tab
)
353 # Attempt to load a page through the nonexistent primary proxy in order to
354 # cause a proxy fallback, and have this test run starting from the HTTP
356 tab
.Navigate(_TEST_SERVER_DEFAULT_URL
)
357 tab
.WaitForJavaScriptExpression('performance.timing.loadEventStart', 300)
359 def AddResults(self
, tab
, results
):
360 self
._metrics
.AddResultsForHTTPToDirectFallback(tab
, results
, _TEST_SERVER
)
363 class ChromeProxyReenableAfterBypass(ChromeProxyValidation
):
364 """Correctness measurement for re-enabling proxies after bypasses.
366 This test loads a page that causes all data reduction proxies to be bypassed
367 for 1 to 5 minutes, then waits 5 minutes and verifies that the proxy is no
372 super(ChromeProxyReenableAfterBypass
, self
).__init
__(
373 restart_after_each_page
=True)
375 def AddResults(self
, tab
, results
):
376 self
._metrics
.AddResultsForReenableAfterBypass(
377 tab
, results
, self
._page
.bypass_seconds_min
,
378 self
._page
.bypass_seconds_max
)
381 class ChromeProxySmoke(ChromeProxyValidation
):
382 """Smoke measurement for basic chrome proxy correctness."""
385 super(ChromeProxySmoke
, self
).__init
__(restart_after_each_page
=True)
387 def WillNavigateToPage(self
, page
, tab
):
388 super(ChromeProxySmoke
, self
).WillNavigateToPage(page
, tab
)
390 def AddResults(self
, tab
, results
):
391 # Map a page name to its AddResults func.
393 'header validation': [self
._metrics
.AddResultsForHeaderValidation
],
394 'compression: image': [
395 self
._metrics
.AddResultsForHeaderValidation
,
396 self
._metrics
.AddResultsForDataSaving
,
398 'compression: javascript': [
399 self
._metrics
.AddResultsForHeaderValidation
,
400 self
._metrics
.AddResultsForDataSaving
,
402 'compression: css': [
403 self
._metrics
.AddResultsForHeaderValidation
,
404 self
._metrics
.AddResultsForDataSaving
,
406 'bypass': [self
._metrics
.AddResultsForBypass
],
408 if not self
._page
.name
in page_to_metrics
:
409 raise page_test
.MeasurementFailure(
410 'Invalid page name (%s) in smoke. Page name must be one of:\n%s' % (
411 self
._page
.name
, page_to_metrics
.keys()))
412 for add_result
in page_to_metrics
[self
._page
.name
]:
413 add_result(tab
, results
)