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 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
81 def HasChromeProxyLoFi(self): | 82 def HasChromeProxyLoFi(self): |
82 if 'Chrome-Proxy' not in self.response.request_headers: | 83 if 'Chrome-Proxy' not in self.response.request_headers: |
83 return False | 84 return False |
84 chrome_proxy_request_header = self.response.request_headers['Chrome-Proxy'] | 85 chrome_proxy_request_header = self.response.request_headers['Chrome-Proxy'] |
85 values = [v.strip() for v in chrome_proxy_request_header.split(',')] | 86 values = [v.strip() for v in chrome_proxy_request_header.split(',')] |
86 for value in values: | 87 for value in values: |
87 if len(value) == 5 and value == 'q=low': | 88 if len(value) == 5 and value == 'q=low': |
88 return True | 89 return True |
89 return False | 90 return False |
90 | 91 |
92 | |
91 class ChromeProxyMetric(network_metrics.NetworkMetric): | 93 class ChromeProxyMetric(network_metrics.NetworkMetric): |
92 """A Chrome proxy timeline metric.""" | 94 """A Chrome proxy timeline metric.""" |
93 | 95 |
94 def __init__(self): | 96 def __init__(self): |
95 super(ChromeProxyMetric, self).__init__() | 97 super(ChromeProxyMetric, self).__init__() |
96 self.compute_data_saving = True | 98 self.compute_data_saving = True |
97 | 99 |
98 def SetEvents(self, events): | 100 def SetEvents(self, events): |
99 """Used for unittest.""" | 101 """Used for unittest.""" |
100 self._events = events | 102 self._events = events |
(...skipping 472 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
573 via_count += 1 | 575 via_count += 1 |
574 if via_count == 0: | 576 if via_count == 0: |
575 raise ChromeProxyMetricException, ( | 577 raise ChromeProxyMetricException, ( |
576 'Expected at least one response through the proxy after the bypass ' | 578 'Expected at least one response through the proxy after the bypass ' |
577 'expired, but zero such responses were received.') | 579 'expired, but zero such responses were received.') |
578 | 580 |
579 results.AddValue(scalar.ScalarValue( | 581 results.AddValue(scalar.ScalarValue( |
580 results.current_page, 'bypass', 'count', bypass_count)) | 582 results.current_page, 'bypass', 'count', bypass_count)) |
581 results.AddValue(scalar.ScalarValue( | 583 results.AddValue(scalar.ScalarValue( |
582 results.current_page, 'via', 'count', via_count)) | 584 results.current_page, 'via', 'count', via_count)) |
585 | |
586 | |
587 PROXIED = 'proxied' | |
588 DIRECT = 'direct' | |
589 | |
590 class ChromeProxyVideoMetric(network_metrics.NetworkMetric): | |
591 """Metrics for video pages. | |
592 | |
593 Wraps the video metrics produced by videowrapper.js. Also checks a few | |
sclittle
2015/05/12 18:05:40
Which metrics? You don't necessarily need to list
Tom Bergan
2015/05/20 00:42:05
Done.
| |
594 basic HTTP response headers such as Content-Type and Content-Length in | |
595 the video responses. | |
596 """ | |
597 | |
598 def __init__(self, tab): | |
599 super(ChromeProxyVideoMetric, self).__init__() | |
600 with open(os.path.join(os.path.dirname(__file__), 'videowrapper.js')) as f: | |
601 js = f.read() | |
602 tab.ExecuteJavaScript(js) | |
603 | |
604 def Start(self, page, tab): | |
605 tab.ExecuteJavaScript('window.__chromeProxyCreateVideoWrappers()') | |
606 self.videoMetrics = None | |
607 super(ChromeProxyVideoMetric, self).Start(page, tab) | |
608 | |
609 def Stop(self, page, tab): | |
610 tab.WaitForJavaScriptExpression('window.__chromeProxyVideoLoaded', 30) | |
611 m = tab.EvaluateJavaScript('window.__chromeProxyVideoMetrics') | |
612 | |
613 # Now wait for the video to stop playing. | |
614 # Give it 2x the total duration to account for buffering. | |
615 waitTime = 2 * m['video_duration'] | |
616 tab.WaitForJavaScriptExpression('window.__chromeProxyVideoEnded', waitTime) | |
617 | |
618 # Load the final metrics. | |
619 m = tab.EvaluateJavaScript('window.__chromeProxyVideoMetrics') | |
620 self.videoMetrics = m | |
621 # Cast this to an integer as it is often approximate (for an unknown reason) | |
622 m['video_duration'] = int(m['video_duration']) | |
623 super(ChromeProxyVideoMetric, self).Stop(page, tab) | |
624 | |
625 def ResponseFromEvent(self, event): | |
626 return ChromeProxyResponse(event) | |
627 | |
628 def AddResults(self, tab, results): | |
629 raise NotImplementedError | |
630 | |
631 def AddResultsForProxied(self, tab, results): | |
632 return self._AddResultsShared(PROXIED, tab, results) | |
633 | |
634 def AddResultsForDirect(self, tab, results): | |
635 return self._AddResultsShared(DIRECT, tab, results) | |
636 | |
637 def _AddResultsShared(self, kind, tab, results): | |
638 def err(s): | |
639 raise ChromeProxyMetricException, s | |
640 | |
641 # Should have played the video. | |
642 if not self.videoMetrics['ready']: | |
643 err('%s: video not played' % kind) | |
644 | |
645 # Should have an HTTP response for the video. | |
646 wantContentType = 'video/webm' if kind == PROXIED else 'video/mp4' | |
647 found = False | |
648 for r in self.IterResponses(tab): | |
649 resp = r.response | |
650 if kind == DIRECT and r.HasChromeProxyViaHeader(): | |
651 err('%s: page has proxied Via header' % kind) | |
652 if resp.GetHeader('Content-Type') != wantContentType: | |
653 continue | |
654 if found: | |
655 err('%s: multiple video responses' % kind) | |
656 found = True | |
657 | |
658 cl = resp.GetHeader('Content-Length') | |
659 xocl = resp.GetHeader('X-Original-Content-Length') | |
660 if cl != None: | |
661 self.videoMetrics['content_length_header'] = int(cl) | |
662 if xocl != None: | |
663 self.videoMetrics['x_original_content_length_header'] = int(xocl) | |
664 | |
665 # Should have CL always. | |
666 if cl == None: | |
667 err('%s: missing ContentLength' % kind) | |
668 # Proxied: should have CL < XOCL | |
669 # Direct: should not have XOCL | |
670 if kind == PROXIED: | |
671 if xocl == None or int(cl) >= int(xocl): | |
672 err('%s: bigger response (%s > %s)' % (kind, str(cl), str(xocl))) | |
673 else: | |
674 if xocl != None: | |
675 err('%s: has XOriginalContentLength' % kind) | |
676 | |
677 if not found: | |
678 err('%s: missing video response' % kind) | |
679 | |
680 # Finally, add all the metrics to the results. | |
681 for (k,v) in self.videoMetrics.iteritems(): | |
682 k = "%s_%s" % (k, kind) | |
683 results.AddValue(scalar.ScalarValue(results.current_page, k, "", v)) | |
OLD | NEW |