Chromium Code Reviews| 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 class ChromeProxyVideoMetric(network_metrics.NetworkMetric): | |
| 566 """A Chrome proxy video metric.""" | |
| 567 def __init__(self, tab): | |
| 568 super(ChromeProxyVideoMetric, self).__init__() | |
| 569 with open(os.path.join(os.path.dirname(__file__), 'videowrapper.js')) as f: | |
| 570 js = f.read() | |
| 571 tab.ExecuteJavaScript(js) | |
| 572 | |
| 573 def Start(self, page, tab): | |
| 574 tab.ExecuteJavaScript('window.__chromeProxyCreateVideoWrappers()') | |
| 575 self.videoMetrics = None | |
| 576 super(ChromeProxyVideoMetric, self).Start(page, tab) | |
| 577 | |
| 578 def Stop(self, page, tab): | |
| 579 tab.WaitForJavaScriptExpression('window.__chromeProxyVideoLoaded', 30) | |
| 580 m = tab.EvaluateJavaScript('window.__chromeProxyVideoMetrics') | |
| 581 # Now wait for the video to stop playing. | |
| 582 # Give it 2x the total duration to account for buffering. | |
| 583 waitTime = 2 * m['video_duration'] | |
| 584 tab.WaitForJavaScriptExpression('window.__chromeProxyVideoEnded', waitTime) | |
| 585 # Load the final metrics. | |
| 586 m = tab.EvaluateJavaScript('window.__chromeProxyVideoMetrics') | |
| 587 self.videoMetrics = m | |
| 588 # Cast this to an integer as it is often approximate (for an unknown reason) | |
| 589 m['video_duration'] = int(m['video_duration']) | |
| 590 super(ChromeProxyVideoMetric, self).Stop(page, tab) | |
| 591 | |
| 592 def ResponseFromEvent(self, event): | |
| 593 return ChromeProxyResponse(event) | |
| 594 | |
| 595 def AddResults(self, tab, results): | |
| 596 raise NotImplementedError | |
| 597 | |
| 598 def AddResultsForProxied(self, tab, results): | |
| 599 return self._AddResultsShared('proxied', tab, results) | |
| 600 | |
| 601 def AddResultsForDirect(self, tab, results): | |
| 602 return self._AddResultsShared('direct', tab, results) | |
| 603 | |
| 604 def _AddResultsShared(self, kind, tab, results): | |
| 605 def err(s): | |
| 606 raise ChromeProxyMetricException, s | |
| 607 | |
| 608 # Should have played the video. | |
| 609 if not self.videoMetrics['ready']: | |
| 610 err('%s: video not played' % kind) | |
| 611 | |
| 612 # Should have an HTTP response for the video. | |
| 613 wantContentType = 'video/webm' if kind == 'proxied' else 'video/mp4' | |
| 614 found = False | |
| 615 for r in self.IterResponses(tab): | |
| 616 resp = r.response | |
| 617 if kind == 'direct' and r.HasChromeProxyViaHeader(): | |
| 618 err('%s: page has proxied Via header' % kind) | |
| 619 if resp.GetHeader('Content-Type') != wantContentType: | |
| 620 continue | |
| 621 if found: | |
|
bolian
2015/04/10 21:00:03
Can we not have restriction of only one video at t
Tom Bergan
2015/04/10 21:14:46
This is a good feature for Dan to add :-)
| |
| 622 err('%s: multiple video responses' % kind) | |
| 623 found = True | |
| 624 cl = resp.GetHeader('Content-Length') | |
| 625 xocl = resp.GetHeader('X-Original-Content-Length') | |
| 626 if cl != None: | |
| 627 self.videoMetrics['content_length_header'] = int(cl) | |
| 628 if xocl != None: | |
| 629 self.videoMetrics['x_original_content_length_header'] = int(xocl) | |
| 630 # Should have CL always. | |
| 631 if cl == None: | |
| 632 err('%s: missing ContentLength' % kind) | |
| 633 # Proxied: should have CL < XOCL | |
| 634 # Direct: should not have XOCL | |
| 635 if kind == 'proxied': | |
| 636 if xocl == None or int(cl) >= int(xocl): | |
| 637 err('%s: bigger response (%s > %s)' % (kind, str(cl), str(xocl))) | |
| 638 else: | |
| 639 if xocl != None: | |
| 640 err('%s: has XOriginalContentLength' % kind) | |
| 641 | |
| 642 if not found: | |
| 643 err('%s: missing video response' % kind) | |
| 644 | |
| 645 # Finally, add all the metrics to the results. | |
| 646 for (k,v) in self.videoMetrics.iteritems(): | |
| 647 k = "%s_%s" % (k, kind) | |
| 648 results.AddValue(scalar.ScalarValue(results.current_page, k, "", v)) | |
| OLD | NEW |