• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4
5import base64
6import logging
7import urlparse
8
9from metrics import chrome_proxy
10from metrics import loading
11from telemetry.core import util
12from telemetry.page import page_measurement
13
14
15class ChromeProxyLatency(page_measurement.PageMeasurement):
16  """Chrome proxy latency measurement."""
17
18  def __init__(self, *args, **kwargs):
19    super(ChromeProxyLatency, self).__init__(*args, **kwargs)
20
21  def WillNavigateToPage(self, page, tab):
22    tab.ClearCache(force=True)
23
24  def MeasurePage(self, page, tab, results):
25    # Wait for the load event.
26    tab.WaitForJavaScriptExpression('performance.timing.loadEventStart', 300)
27    loading.LoadingMetric().AddResults(tab, results)
28
29
30class ChromeProxyDataSaving(page_measurement.PageMeasurement):
31  """Chrome proxy data daving measurement."""
32  def __init__(self, *args, **kwargs):
33    super(ChromeProxyDataSaving, self).__init__(*args, **kwargs)
34    self._metrics = chrome_proxy.ChromeProxyMetric()
35
36  def WillNavigateToPage(self, page, tab):
37    tab.ClearCache(force=True)
38    self._metrics.Start(page, tab)
39
40  def MeasurePage(self, page, tab, results):
41    # Wait for the load event.
42    tab.WaitForJavaScriptExpression('performance.timing.loadEventStart', 300)
43    self._metrics.Stop(page, tab)
44    self._metrics.AddResultsForDataSaving(tab, results)
45
46
47class ChromeProxyValidation(page_measurement.PageMeasurement):
48  """Base class for all chrome proxy correctness measurements."""
49
50  def __init__(self, restart_after_each_page=False):
51    super(ChromeProxyValidation, self).__init__(
52        needs_browser_restart_after_each_page=restart_after_each_page)
53    self._metrics = chrome_proxy.ChromeProxyMetric()
54    self._page = None
55    # Whether a timeout exception is expected during the test.
56    self._expect_timeout = False
57
58  def CustomizeBrowserOptions(self, options):
59    # Enable the chrome proxy (data reduction proxy).
60    options.AppendExtraBrowserArgs('--enable-spdy-proxy-auth')
61
62  def WillNavigateToPage(self, page, tab):
63    tab.ClearCache(force=True)
64    assert self._metrics
65    self._metrics.Start(page, tab)
66
67  def MeasurePage(self, page, tab, results):
68    self._page = page
69    # Wait for the load event.
70    tab.WaitForJavaScriptExpression('performance.timing.loadEventStart', 300)
71    assert self._metrics
72    self._metrics.Stop(page, tab)
73    self.AddResults(tab, results)
74
75  def AddResults(self, tab, results):
76    raise NotImplementedError
77
78  def StopBrowserAfterPage(self, browser, page):  # pylint: disable=W0613
79    if hasattr(page, 'restart_after') and page.restart_after:
80      return True
81    return False
82
83  def RunNavigateSteps(self, page, tab):
84    # The redirect from safebrowsing causes a timeout. Ignore that.
85    try:
86      super(ChromeProxyValidation, self).RunNavigateSteps(page, tab)
87    except util.TimeoutException, e:
88      if self._expect_timeout:
89        logging.warning('Navigation timeout on page %s',
90                        page.name if page.name else page.url)
91      else:
92        raise e
93
94
95class ChromeProxyHeaders(ChromeProxyValidation):
96  """Correctness measurement for response headers."""
97
98  def __init__(self):
99    super(ChromeProxyHeaders, self).__init__(restart_after_each_page=True)
100
101  def AddResults(self, tab, results):
102    self._metrics.AddResultsForHeaderValidation(tab, results)
103
104
105class ChromeProxyBypass(ChromeProxyValidation):
106  """Correctness measurement for bypass responses."""
107
108  def __init__(self):
109    super(ChromeProxyBypass, self).__init__(restart_after_each_page=True)
110
111  def AddResults(self, tab, results):
112    self._metrics.AddResultsForBypass(tab, results)
113
114
115class ChromeProxySafebrowsing(ChromeProxyValidation):
116  """Correctness measurement for safebrowsing."""
117
118  def __init__(self):
119    super(ChromeProxySafebrowsing, self).__init__()
120
121  def WillNavigateToPage(self, page, tab):
122    super(ChromeProxySafebrowsing, self).WillNavigateToPage(page, tab)
123    self._expect_timeout = True
124
125  def AddResults(self, tab, results):
126    self._metrics.AddResultsForSafebrowsing(tab, results)
127
128
129_FAKE_PROXY_AUTH_VALUE = 'aabbccdd3b7579186c1b0620614fdb1f0000ffff'
130_TEST_SERVER = 'chromeproxy-test.appspot.com'
131_TEST_SERVER_DEFAULT_URL = 'http://' + _TEST_SERVER + '/default'
132
133
134# We rely on the chromeproxy-test server to facilitate some of the tests.
135# The test server code is at <TBD location> and runs at _TEST_SERVER
136#
137# The test server allow request to override response status, headers, and
138# body through query parameters. See GetResponseOverrideURL.
139def GetResponseOverrideURL(url, respStatus=0, respHeader="", respBody=""):
140  """ Compose the request URL with query parameters to override
141  the chromeproxy-test server response.
142  """
143
144  queries = []
145  if respStatus > 0:
146    queries.append('respStatus=%d' % respStatus)
147  if respHeader:
148    queries.append('respHeader=%s' % base64.b64encode(respHeader))
149  if respBody:
150    queries.append('respBody=%s' % base64.b64encode(respBody))
151  if len(queries) == 0:
152    return url
153  "&".join(queries)
154  # url has query already
155  if urlparse.urlparse(url).query:
156    return url + '&' + "&".join(queries)
157  else:
158    return url + '?' + "&".join(queries)
159
160
161class ChromeProxyHTTPFallbackProbeURL(ChromeProxyValidation):
162  """Correctness measurement for proxy fallback.
163
164  In this test, the probe URL does not return 'OK'. Chrome is expected
165  to use the fallback proxy.
166  """
167
168  def __init__(self):
169    super(ChromeProxyHTTPFallbackProbeURL, self).__init__()
170
171  def CustomizeBrowserOptions(self, options):
172    super(ChromeProxyHTTPFallbackProbeURL,
173          self).CustomizeBrowserOptions(options)
174    # Use the test server probe URL which returns the response
175    # body as specified by respBody.
176    probe_url = GetResponseOverrideURL(
177        _TEST_SERVER_DEFAULT_URL,
178        respBody='not OK')
179    options.AppendExtraBrowserArgs(
180        '--data-reduction-proxy-probe-url=%s' % probe_url)
181
182  def AddResults(self, tab, results):
183    self._metrics.AddResultsForHTTPFallback(tab, results)
184
185
186# Depends on the fix of http://crbug.com/330342.
187class ChromeProxyHTTPFallbackViaHeader(ChromeProxyValidation):
188  """Correctness measurement for proxy fallback.
189
190  In this test, the configured proxy is the chromeproxy-test server which
191  will send back a response without the expected Via header. Chrome is
192  expected to use the fallback proxy and add the configured proxy to the
193  bad proxy list.
194  """
195
196  def __init__(self):
197    super(ChromeProxyHTTPFallbackViaHeader, self).__init__()
198
199  def CustomizeBrowserOptions(self, options):
200    super(ChromeProxyHTTPFallbackViaHeader,
201          self).CustomizeBrowserOptions(options)
202    options.AppendExtraBrowserArgs('--ignore-certificate-errors')
203    options.AppendExtraBrowserArgs(
204        '--spdy-proxy-auth-origin=http://%s' % _TEST_SERVER)
205    options.AppendExtraBrowserArgs(
206        '--spdy-proxy-auth-value=%s' % _FAKE_PROXY_AUTH_VALUE)
207
208  def AddResults(self, tab, results):
209    proxies = [
210        _TEST_SERVER + ":80",
211        self._metrics.effective_proxies['fallback'],
212        self._metrics.effective_proxies['direct']]
213    bad_proxies = [_TEST_SERVER + ":80"]
214    self._metrics.AddResultsForHTTPFallback(tab, results, proxies, bad_proxies)
215
216
217class ChromeProxySmoke(ChromeProxyValidation):
218  """Smoke measurement for basic chrome proxy correctness."""
219
220  def __init__(self):
221    super(ChromeProxySmoke, self).__init__()
222
223  def WillNavigateToPage(self, page, tab):
224    super(ChromeProxySmoke, self).WillNavigateToPage(page, tab)
225    if page.name == 'safebrowsing':
226      self._expect_timeout = True
227
228  def AddResults(self, tab, results):
229    # Map a page name to its AddResults func.
230    page_to_metrics = {
231        'header validation': [self._metrics.AddResultsForHeaderValidation],
232        'compression: image': [
233            self._metrics.AddResultsForHeaderValidation,
234            self._metrics.AddResultsForDataSaving,
235            ],
236        'compression: javascript': [
237            self._metrics.AddResultsForHeaderValidation,
238            self._metrics.AddResultsForDataSaving,
239            ],
240        'compression: css': [
241            self._metrics.AddResultsForHeaderValidation,
242            self._metrics.AddResultsForDataSaving,
243            ],
244        'bypass': [self._metrics.AddResultsForBypass],
245        'safebrowsing': [self._metrics.AddResultsForSafebrowsing],
246        }
247    if not self._page.name in page_to_metrics:
248      raise page_measurement.MeasurementFailure(
249          'Invalid page name (%s) in smoke. Page name must be one of:\n%s' % (
250          self._page.name, page_to_metrics.keys()))
251    for add_result in page_to_metrics[self._page.name]:
252      add_result(tab, results)
253