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 unittest
7
8from integration_tests import chrome_proxy_metrics as metrics
9from integration_tests import network_metrics_unittest as network_unittest
10from metrics import test_page_test_results
11
12
13# Timeline events used in tests.
14# An HTML not via proxy.
15EVENT_HTML_PROXY = network_unittest.NetworkMetricTest.MakeNetworkTimelineEvent(
16    url='http://test.html1',
17    response_headers={
18        'Content-Type': 'text/html',
19        'Content-Length': str(len(network_unittest.HTML_BODY)),
20        },
21    body=network_unittest.HTML_BODY)
22
23# An HTML via proxy with the deprecated Via header.
24EVENT_HTML_PROXY_DEPRECATED_VIA = (
25    network_unittest.NetworkMetricTest.MakeNetworkTimelineEvent(
26    url='http://test.html2',
27    response_headers={
28        'Content-Type': 'text/html',
29        'Content-Encoding': 'gzip',
30        'X-Original-Content-Length': str(len(network_unittest.HTML_BODY)),
31        'Via': (metrics.CHROME_PROXY_VIA_HEADER_DEPRECATED +
32                ',other-via'),
33        },
34    body=network_unittest.HTML_BODY))
35
36# An image via proxy with Via header and it is cached.
37EVENT_IMAGE_PROXY_CACHED = (
38    network_unittest.NetworkMetricTest.MakeNetworkTimelineEvent(
39    url='http://test.image',
40    response_headers={
41        'Content-Type': 'image/jpeg',
42        'Content-Encoding': 'gzip',
43        'X-Original-Content-Length': str(network_unittest.IMAGE_OCL),
44        'Via': '1.1 ' + metrics.CHROME_PROXY_VIA_HEADER,
45        },
46    body=base64.b64encode(network_unittest.IMAGE_BODY),
47    base64_encoded_body=True,
48    served_from_cache=True))
49
50# An image fetched directly.
51EVENT_IMAGE_DIRECT = (
52    network_unittest.NetworkMetricTest.MakeNetworkTimelineEvent(
53    url='http://test.image',
54    response_headers={
55        'Content-Type': 'image/jpeg',
56        'Content-Encoding': 'gzip',
57        },
58    body=base64.b64encode(network_unittest.IMAGE_BODY),
59    base64_encoded_body=True))
60
61# A safe-browsing malware response.
62EVENT_MALWARE_PROXY = (
63    network_unittest.NetworkMetricTest.MakeNetworkTimelineEvent(
64    url='http://test.malware',
65    response_headers={
66        'X-Malware-Url': '1',
67        'Via': '1.1 ' + metrics.CHROME_PROXY_VIA_HEADER,
68        'Location': 'http://test.malware',
69        },
70    status=307))
71
72
73class ChromeProxyMetricTest(unittest.TestCase):
74
75  _test_proxy_info = {}
76
77  def _StubGetProxyInfo(self, info):
78    def stub(unused_tab, unused_url=''):  # pylint: disable=W0613
79      return ChromeProxyMetricTest._test_proxy_info
80    metrics.GetProxyInfoFromNetworkInternals = stub
81    ChromeProxyMetricTest._test_proxy_info = info
82
83  def testChromeProxyResponse(self):
84    # An https non-proxy response.
85    resp = metrics.ChromeProxyResponse(
86        network_unittest.NetworkMetricTest.MakeNetworkTimelineEvent(
87            url='https://test.url',
88            response_headers={
89                'Content-Type': 'text/html',
90                'Content-Length': str(len(network_unittest.HTML_BODY)),
91                'Via': 'some other via',
92                },
93            body=network_unittest.HTML_BODY))
94    self.assertFalse(resp.ShouldHaveChromeProxyViaHeader())
95    self.assertFalse(resp.HasChromeProxyViaHeader())
96    self.assertTrue(resp.IsValidByViaHeader())
97
98    # A proxied JPEG image response
99    resp = metrics.ChromeProxyResponse(
100        network_unittest.NetworkMetricTest.MakeNetworkTimelineEvent(
101            url='http://test.image',
102            response_headers={
103                'Content-Type': 'image/jpeg',
104                'Content-Encoding': 'gzip',
105                'Via': '1.1 ' + metrics.CHROME_PROXY_VIA_HEADER,
106                'X-Original-Content-Length': str(network_unittest.IMAGE_OCL),
107                },
108            body=base64.b64encode(network_unittest.IMAGE_BODY),
109            base64_encoded_body=True))
110    self.assertTrue(resp.ShouldHaveChromeProxyViaHeader())
111    self.assertTrue(resp.HasChromeProxyViaHeader())
112    self.assertTrue(resp.IsValidByViaHeader())
113
114  def testChromeProxyMetricForDataSaving(self):
115    metric = metrics.ChromeProxyMetric()
116    events = [
117        EVENT_HTML_PROXY,
118        EVENT_HTML_PROXY_DEPRECATED_VIA,
119        EVENT_IMAGE_PROXY_CACHED,
120        EVENT_IMAGE_DIRECT]
121    metric.SetEvents(events)
122
123    self.assertTrue(len(events), len(list(metric.IterResponses(None))))
124    results = test_page_test_results.TestPageTestResults(self)
125
126    metric.AddResultsForDataSaving(None, results)
127    results.AssertHasPageSpecificScalarValue('resources_via_proxy', 'count', 2)
128    results.AssertHasPageSpecificScalarValue('resources_from_cache', 'count', 1)
129    results.AssertHasPageSpecificScalarValue('resources_direct', 'count', 2)
130
131  def testChromeProxyMetricForHeaderValidation(self):
132    metric = metrics.ChromeProxyMetric()
133    metric.SetEvents([
134        EVENT_HTML_PROXY,
135        EVENT_HTML_PROXY_DEPRECATED_VIA,
136        EVENT_IMAGE_PROXY_CACHED,
137        EVENT_IMAGE_DIRECT])
138
139    results = test_page_test_results.TestPageTestResults(self)
140
141    missing_via_exception = False
142    try:
143      metric.AddResultsForHeaderValidation(None, results)
144    except metrics.ChromeProxyMetricException:
145      missing_via_exception = True
146    # Only the HTTP image response does not have a valid Via header.
147    self.assertTrue(missing_via_exception)
148
149    # Two events with valid Via headers.
150    metric.SetEvents([
151        EVENT_HTML_PROXY_DEPRECATED_VIA,
152        EVENT_IMAGE_PROXY_CACHED])
153    metric.AddResultsForHeaderValidation(None, results)
154    results.AssertHasPageSpecificScalarValue('checked_via_header', 'count', 2)
155
156  def testChromeProxyMetricForBypass(self):
157    metric = metrics.ChromeProxyMetric()
158    metric.SetEvents([
159        EVENT_HTML_PROXY,
160        EVENT_HTML_PROXY_DEPRECATED_VIA,
161        EVENT_IMAGE_PROXY_CACHED,
162        EVENT_IMAGE_DIRECT])
163    results = test_page_test_results.TestPageTestResults(self)
164
165    bypass_exception = False
166    try:
167      metric.AddResultsForBypass(None, results)
168    except metrics.ChromeProxyMetricException:
169      bypass_exception = True
170    # Two of the first three events have Via headers.
171    self.assertTrue(bypass_exception)
172
173    # Use directly fetched image only. It is treated as bypassed.
174    metric.SetEvents([EVENT_IMAGE_DIRECT])
175    metric.AddResultsForBypass(None, results)
176    results.AssertHasPageSpecificScalarValue('bypass', 'count', 1)
177
178  def testChromeProxyMetricForHTTPFallback(self):
179    metric = metrics.ChromeProxyMetric()
180    metric.SetEvents([
181        EVENT_HTML_PROXY,
182        EVENT_HTML_PROXY_DEPRECATED_VIA])
183    results = test_page_test_results.TestPageTestResults(self)
184
185    fallback_exception = False
186    info = {}
187    info['enabled'] = False
188    self._StubGetProxyInfo(info)
189    try:
190      metric.AddResultsForBypass(None, results)
191    except metrics.ChromeProxyMetricException:
192      fallback_exception = True
193    self.assertTrue(fallback_exception)
194
195    fallback_exception = False
196    info['enabled'] = True
197    info['proxies'] = [
198        'something.else.com:80',
199        metrics.PROXY_SETTING_DIRECT
200        ]
201    self._StubGetProxyInfo(info)
202    try:
203      metric.AddResultsForBypass(None, results)
204    except metrics.ChromeProxyMetricException:
205      fallback_exception = True
206    self.assertTrue(fallback_exception)
207
208    info['enabled'] = True
209    info['proxies'] = [
210        metrics.PROXY_SETTING_HTTP,
211        metrics.PROXY_SETTING_DIRECT
212        ]
213    self._StubGetProxyInfo(info)
214    metric.AddResultsForHTTPFallback(None, results)
215
216  def testChromeProxyMetricForSafebrowsing(self):
217    metric = metrics.ChromeProxyMetric()
218    metric.SetEvents([EVENT_MALWARE_PROXY])
219    results = test_page_test_results.TestPageTestResults(self)
220
221    metric.AddResultsForSafebrowsing(None, results)
222    results.AssertHasPageSpecificScalarValue('safebrowsing', 'boolean', True)
223
224    # Clear results and metrics to test no response for safebrowsing
225    results = test_page_test_results.TestPageTestResults(self)
226    metric.SetEvents([])
227    metric.AddResultsForSafebrowsing(None, results)
228    results.AssertHasPageSpecificScalarValue('safebrowsing', 'boolean', True)
229