Home | History | Annotate | Download | only in integration_tests
      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 
      5 import base64
      6 import logging
      7 import urlparse
      8 
      9 from integration_tests import chrome_proxy_metrics as metrics
     10 from metrics import loading
     11 from telemetry.core import util
     12 from telemetry.page import page_test
     13 
     14 
     15 class ChromeProxyLatency(page_test.PageTest):
     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 ValidateAndMeasurePage(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 
     30 class ChromeProxyDataSaving(page_test.PageTest):
     31   """Chrome proxy data daving measurement."""
     32   def __init__(self, *args, **kwargs):
     33     super(ChromeProxyDataSaving, self).__init__(*args, **kwargs)
     34     self._metrics = metrics.ChromeProxyMetric()
     35 
     36   def WillNavigateToPage(self, page, tab):
     37     tab.ClearCache(force=True)
     38     self._metrics.Start(page, tab)
     39 
     40   def ValidateAndMeasurePage(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 
     47 class ChromeProxyValidation(page_test.PageTest):
     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 = metrics.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 ValidateAndMeasurePage(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 
     95 class 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 
    105 class 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 
    115 class ChromeProxyBlockOnce(ChromeProxyValidation):
    116   """Correctness measurement for block-once responses."""
    117 
    118   def __init__(self):
    119     super(ChromeProxyBlockOnce, self).__init__(restart_after_each_page=True)
    120 
    121   def AddResults(self, tab, results):
    122     self._metrics.AddResultsForBlockOnce(tab, results)
    123 
    124 
    125 class ChromeProxySafebrowsing(ChromeProxyValidation):
    126   """Correctness measurement for safebrowsing."""
    127 
    128   def __init__(self):
    129     super(ChromeProxySafebrowsing, self).__init__()
    130 
    131   def WillNavigateToPage(self, page, tab):
    132     super(ChromeProxySafebrowsing, self).WillNavigateToPage(page, tab)
    133     self._expect_timeout = True
    134 
    135   def AddResults(self, tab, results):
    136     self._metrics.AddResultsForSafebrowsing(tab, results)
    137 
    138 
    139 _FAKE_PROXY_AUTH_VALUE = 'aabbccdd3b7579186c1b0620614fdb1f0000ffff'
    140 _TEST_SERVER = 'chromeproxy-test.appspot.com'
    141 _TEST_SERVER_DEFAULT_URL = 'http://' + _TEST_SERVER + '/default'
    142 
    143 
    144 # We rely on the chromeproxy-test server to facilitate some of the tests.
    145 # The test server code is at <TBD location> and runs at _TEST_SERVER
    146 #
    147 # The test server allow request to override response status, headers, and
    148 # body through query parameters. See GetResponseOverrideURL.
    149 def GetResponseOverrideURL(url, respStatus=0, respHeader="", respBody=""):
    150   """ Compose the request URL with query parameters to override
    151   the chromeproxy-test server response.
    152   """
    153 
    154   queries = []
    155   if respStatus > 0:
    156     queries.append('respStatus=%d' % respStatus)
    157   if respHeader:
    158     queries.append('respHeader=%s' % base64.b64encode(respHeader))
    159   if respBody:
    160     queries.append('respBody=%s' % base64.b64encode(respBody))
    161   if len(queries) == 0:
    162     return url
    163   "&".join(queries)
    164   # url has query already
    165   if urlparse.urlparse(url).query:
    166     return url + '&' + "&".join(queries)
    167   else:
    168     return url + '?' + "&".join(queries)
    169 
    170 
    171 class ChromeProxyHTTPFallbackProbeURL(ChromeProxyValidation):
    172   """Correctness measurement for proxy fallback.
    173 
    174   In this test, the probe URL does not return 'OK'. Chrome is expected
    175   to use the fallback proxy.
    176   """
    177 
    178   def __init__(self):
    179     super(ChromeProxyHTTPFallbackProbeURL, self).__init__()
    180 
    181   def CustomizeBrowserOptions(self, options):
    182     super(ChromeProxyHTTPFallbackProbeURL,
    183           self).CustomizeBrowserOptions(options)
    184     # Use the test server probe URL which returns the response
    185     # body as specified by respBody.
    186     probe_url = GetResponseOverrideURL(
    187         _TEST_SERVER_DEFAULT_URL,
    188         respBody='not OK')
    189     options.AppendExtraBrowserArgs(
    190         '--data-reduction-proxy-probe-url=%s' % probe_url)
    191 
    192   def AddResults(self, tab, results):
    193     self._metrics.AddResultsForHTTPFallback(tab, results)
    194 
    195 
    196 class ChromeProxyHTTPFallbackViaHeader(ChromeProxyValidation):
    197   """Correctness measurement for proxy fallback.
    198 
    199   In this test, the configured proxy is the chromeproxy-test server which
    200   will send back a response without the expected Via header. Chrome is
    201   expected to use the fallback proxy and add the configured proxy to the
    202   bad proxy list.
    203   """
    204 
    205   def __init__(self):
    206     super(ChromeProxyHTTPFallbackViaHeader, self).__init__()
    207 
    208   def CustomizeBrowserOptions(self, options):
    209     super(ChromeProxyHTTPFallbackViaHeader,
    210           self).CustomizeBrowserOptions(options)
    211     options.AppendExtraBrowserArgs('--ignore-certificate-errors')
    212     options.AppendExtraBrowserArgs(
    213         '--spdy-proxy-auth-origin=http://%s' % _TEST_SERVER)
    214     options.AppendExtraBrowserArgs(
    215         '--spdy-proxy-auth-value=%s' % _FAKE_PROXY_AUTH_VALUE)
    216 
    217   def AddResults(self, tab, results):
    218     proxies = [
    219         _TEST_SERVER + ":80",
    220         self._metrics.effective_proxies['fallback'],
    221         self._metrics.effective_proxies['direct']]
    222     bad_proxies = [_TEST_SERVER + ":80", metrics.PROXY_SETTING_HTTP]
    223     self._metrics.AddResultsForHTTPFallback(tab, results, proxies, bad_proxies)
    224 
    225 
    226 class ChromeProxyClientVersion(ChromeProxyValidation):
    227   """Correctness measurement for version directives in Chrome-Proxy header.
    228 
    229   The test verifies that the version information provided in the Chrome-Proxy
    230   request header overrides any version, if specified, that is provided in the
    231   user agent string.
    232   """
    233 
    234   def __init__(self):
    235     super(ChromeProxyClientVersion, self).__init__()
    236 
    237   def CustomizeBrowserOptions(self, options):
    238     super(ChromeProxyClientVersion,
    239           self).CustomizeBrowserOptions(options)
    240     options.AppendExtraBrowserArgs('--user-agent="Chrome/32.0.1700.99"')
    241 
    242   def AddResults(self, tab, results):
    243     self._metrics.AddResultsForClientVersion(tab, results)
    244 
    245 
    246 class ChromeProxySmoke(ChromeProxyValidation):
    247   """Smoke measurement for basic chrome proxy correctness."""
    248 
    249   def __init__(self):
    250     super(ChromeProxySmoke, self).__init__()
    251 
    252   def WillNavigateToPage(self, page, tab):
    253     super(ChromeProxySmoke, self).WillNavigateToPage(page, tab)
    254     if page.name == 'safebrowsing':
    255       self._expect_timeout = True
    256 
    257   def AddResults(self, tab, results):
    258     # Map a page name to its AddResults func.
    259     page_to_metrics = {
    260         'header validation': [self._metrics.AddResultsForHeaderValidation],
    261         'compression: image': [
    262             self._metrics.AddResultsForHeaderValidation,
    263             self._metrics.AddResultsForDataSaving,
    264             ],
    265         'compression: javascript': [
    266             self._metrics.AddResultsForHeaderValidation,
    267             self._metrics.AddResultsForDataSaving,
    268             ],
    269         'compression: css': [
    270             self._metrics.AddResultsForHeaderValidation,
    271             self._metrics.AddResultsForDataSaving,
    272             ],
    273         'bypass': [self._metrics.AddResultsForBypass],
    274         'safebrowsing': [self._metrics.AddResultsForSafebrowsing],
    275         }
    276     if not self._page.name in page_to_metrics:
    277       raise page_test.MeasurementFailure(
    278           'Invalid page name (%s) in smoke. Page name must be one of:\n%s' % (
    279           self._page.name, page_to_metrics.keys()))
    280     for add_result in page_to_metrics[self._page.name]:
    281       add_result(tab, results)
    282