OLD | NEW |
---|---|
1 # Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 import logging | 5 import logging |
6 import os | |
6 import time | 7 import time |
7 | 8 |
8 from integration_tests import network_metrics | 9 from integration_tests import network_metrics |
9 from telemetry.page import page_test | 10 from telemetry.page import page_test |
10 from telemetry.value import scalar | 11 from telemetry.value import scalar |
11 | 12 |
12 | 13 |
13 class ChromeProxyMetricException(page_test.MeasurementFailure): | 14 class ChromeProxyMetricException(page_test.MeasurementFailure): |
14 pass | 15 pass |
15 | 16 |
16 | 17 |
17 CHROME_PROXY_VIA_HEADER = 'Chrome-Compression-Proxy' | 18 CHROME_PROXY_VIA_HEADER = 'Chrome-Compression-Proxy' |
18 | 19 |
19 | 20 |
20 class ChromeProxyResponse(network_metrics.HTTPResponse): | 21 class ChromeProxyResponse(network_metrics.HTTPResponse): |
21 """ Represents an HTTP response from a timeleine event.""" | 22 """ Represents an HTTP response from a timeline event.""" |
22 def __init__(self, event): | 23 def __init__(self, event): |
23 super(ChromeProxyResponse, self).__init__(event) | 24 super(ChromeProxyResponse, self).__init__(event) |
24 | 25 |
25 def ShouldHaveChromeProxyViaHeader(self): | 26 def ShouldHaveChromeProxyViaHeader(self): |
26 resp = self.response | 27 resp = self.response |
27 # Ignore https and data url | 28 # Ignore https and data url |
28 if resp.url.startswith('https') or resp.url.startswith('data:'): | 29 if resp.url.startswith('https') or resp.url.startswith('data:'): |
29 return False | 30 return False |
30 # Ignore 304 Not Modified and cache hit. | 31 # Ignore 304 Not Modified and cache hit. |
31 if resp.status == 304 or resp.served_from_cache: | 32 if resp.status == 304 or resp.served_from_cache: |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
74 def HasChromeProxyLoFi(self): | 75 def HasChromeProxyLoFi(self): |
75 if 'Chrome-Proxy' not in self.response.request_headers: | 76 if 'Chrome-Proxy' not in self.response.request_headers: |
76 return False | 77 return False |
77 chrome_proxy_request_header = self.response.request_headers['Chrome-Proxy'] | 78 chrome_proxy_request_header = self.response.request_headers['Chrome-Proxy'] |
78 values = [v.strip() for v in chrome_proxy_request_header.split(',')] | 79 values = [v.strip() for v in chrome_proxy_request_header.split(',')] |
79 for value in values: | 80 for value in values: |
80 if len(value) == 5 and value == 'q=low': | 81 if len(value) == 5 and value == 'q=low': |
81 return True | 82 return True |
82 return False | 83 return False |
83 | 84 |
85 | |
84 class ChromeProxyMetric(network_metrics.NetworkMetric): | 86 class ChromeProxyMetric(network_metrics.NetworkMetric): |
85 """A Chrome proxy timeline metric.""" | 87 """A Chrome proxy timeline metric.""" |
86 | 88 |
87 def __init__(self): | 89 def __init__(self): |
88 super(ChromeProxyMetric, self).__init__() | 90 super(ChromeProxyMetric, self).__init__() |
89 self.compute_data_saving = True | 91 self.compute_data_saving = True |
90 | 92 |
91 def SetEvents(self, events): | 93 def SetEvents(self, events): |
92 """Used for unittest.""" | 94 """Used for unittest.""" |
93 self._events = events | 95 self._events = events |
(...skipping 458 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
552 via_count += 1 | 554 via_count += 1 |
553 if via_count == 0: | 555 if via_count == 0: |
554 raise ChromeProxyMetricException, ( | 556 raise ChromeProxyMetricException, ( |
555 'Expected at least one response through the proxy after the bypass ' | 557 'Expected at least one response through the proxy after the bypass ' |
556 'expired, but zero such responses were received.') | 558 'expired, but zero such responses were received.') |
557 | 559 |
558 results.AddValue(scalar.ScalarValue( | 560 results.AddValue(scalar.ScalarValue( |
559 results.current_page, 'bypass', 'count', bypass_count)) | 561 results.current_page, 'bypass', 'count', bypass_count)) |
560 results.AddValue(scalar.ScalarValue( | 562 results.AddValue(scalar.ScalarValue( |
561 results.current_page, 'via', 'count', via_count)) | 563 results.current_page, 'via', 'count', via_count)) |
564 | |
565 | |
566 PROXIED = 'proxied' | |
567 DIRECT = 'direct' | |
568 | |
569 class ChromeProxyVideoMetric(network_metrics.NetworkMetric): | |
570 """Wraps the video metrics produced by videowrapper.js. Also checks a few | |
sclittle
2015/04/11 00:13:02
See style guide: https://google-styleguide.googlec
Tom Bergan
2015/05/01 23:48:28
Done.
| |
571 basic HTTP response headers such as Content-Type and Content-Length for | |
572 the video responses. | |
573 """ | |
574 | |
575 def __init__(self, tab): | |
576 super(ChromeProxyVideoMetric, self).__init__() | |
577 with open(os.path.join(os.path.dirname(__file__), 'videowrapper.js')) as f: | |
578 js = f.read() | |
579 tab.ExecuteJavaScript(js) | |
580 | |
581 def Start(self, page, tab): | |
582 tab.ExecuteJavaScript('window.__chromeProxyCreateVideoWrappers()') | |
583 self.videoMetrics = None | |
584 super(ChromeProxyVideoMetric, self).Start(page, tab) | |
585 | |
586 def Stop(self, page, tab): | |
587 tab.WaitForJavaScriptExpression('window.__chromeProxyVideoLoaded', 30) | |
588 m = tab.EvaluateJavaScript('window.__chromeProxyVideoMetrics') | |
589 | |
590 # Now wait for the video to stop playing. | |
591 # Give it 2x the total duration to account for buffering. | |
592 waitTime = 2 * m['video_duration'] | |
593 tab.WaitForJavaScriptExpression('window.__chromeProxyVideoEnded', waitTime) | |
594 | |
595 # Load the final metrics. | |
596 m = tab.EvaluateJavaScript('window.__chromeProxyVideoMetrics') | |
597 self.videoMetrics = m | |
598 # Cast this to an integer as it is often approximate (for an unknown reason) | |
599 m['video_duration'] = int(m['video_duration']) | |
600 super(ChromeProxyVideoMetric, self).Stop(page, tab) | |
601 | |
602 def ResponseFromEvent(self, event): | |
603 return ChromeProxyResponse(event) | |
604 | |
605 def AddResults(self, tab, results): | |
606 raise NotImplementedError | |
607 | |
608 def AddResultsForProxied(self, tab, results): | |
609 return self._AddResultsShared(PROXIED, tab, results) | |
610 | |
611 def AddResultsForDirect(self, tab, results): | |
612 return self._AddResultsShared(DIRECT, tab, results) | |
613 | |
614 def _AddResultsShared(self, kind, tab, results): | |
615 def err(s): | |
616 raise ChromeProxyMetricException, s | |
617 | |
618 # Should have played the video. | |
619 if not self.videoMetrics['ready']: | |
620 err('%s: video not played' % kind) | |
621 | |
622 # Should have an HTTP response for the video. | |
623 wantContentType = 'video/webm' if kind == PROXIED else 'video/mp4' | |
624 found = False | |
625 for r in self.IterResponses(tab): | |
626 resp = r.response | |
627 if kind == DIRECT and r.HasChromeProxyViaHeader(): | |
628 err('%s: page has proxied Via header' % kind) | |
629 if resp.GetHeader('Content-Type') != wantContentType: | |
630 continue | |
631 if found: | |
632 err('%s: multiple video responses' % kind) | |
633 found = True | |
634 | |
635 cl = resp.GetHeader('Content-Length') | |
636 xocl = resp.GetHeader('X-Original-Content-Length') | |
637 if cl != None: | |
638 self.videoMetrics['content_length_header'] = int(cl) | |
639 if xocl != None: | |
640 self.videoMetrics['x_original_content_length_header'] = int(xocl) | |
641 | |
642 # Should have CL always. | |
643 if cl == None: | |
644 err('%s: missing ContentLength' % kind) | |
645 # Proxied: should have CL < XOCL | |
646 # Direct: should not have XOCL | |
647 if kind == PROXIED: | |
648 if xocl == None or int(cl) >= int(xocl): | |
649 err('%s: bigger response (%s > %s)' % (kind, str(cl), str(xocl))) | |
650 else: | |
651 if xocl != None: | |
652 err('%s: has XOriginalContentLength' % kind) | |
653 | |
654 if not found: | |
655 err('%s: missing video response' % kind) | |
656 | |
657 # Finally, add all the metrics to the results. | |
658 for (k,v) in self.videoMetrics.iteritems(): | |
sclittle
2015/04/11 00:13:02
Could you just call results.AddValue(...) inline a
Tom Bergan
2015/05/01 23:48:28
This dict is used by ChromeProxyVideoValidation (i
| |
659 k = "%s_%s" % (k, kind) | |
660 results.AddValue(scalar.ScalarValue(results.current_page, k, "", v)) | |
OLD | NEW |