| # Copyright 2018 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import json |
| import re |
| import time |
| import urllib |
| from common import ParseFlags |
| from common import TestDriver |
| from common import IntegrationTest |
| from decorators import AndroidOnly |
| from decorators import ChromeVersionEqualOrAfterM |
| |
| from selenium.common.exceptions import TimeoutException |
| |
| NAV_THROTTLE_VERSION = "v1_NavThrottle" |
| URL_LOADER_VERSION = "v2_URLLoader" |
| LITEPAGES_REGEXP = r'https://\w+\.litepages\.googlezip\.net/.*' |
| |
| # These are integration tests for server provided previews and the |
| # protocol that supports them. This class is intended as an abstract base class |
| # to allow the two versions of this feature implementation to reuse the same |
| # tests. |
| class HttpsPreviewsBaseClass(): |
| # Abstract function for subclasses to override. |
| def getVersion(self): |
| raise Exception( "Please override this method") |
| |
| def EnableLitePageServerPreviewsAndInit(self, t): |
| version = self.getVersion() |
| |
| # These feature flags are common to both versions. |
| t.EnableChromeFeature('Previews') |
| t.EnableChromeFeature('LitePageServerPreviews') |
| |
| # RLH and NoScript may disable use of LitePageRedirect Previews. |
| t.DisableChromeFeature('ResourceLoadingHints') |
| t.DisableChromeFeature('NoScriptPreviews') |
| |
| if version == NAV_THROTTLE_VERSION: |
| # No additional flags here, but explicitly check it given the else below. |
| pass |
| elif version == URL_LOADER_VERSION: |
| t.EnableChromeFeature('HTTPSServerPreviewsUsingURLLoader') |
| else: |
| raise Exception('"%s" is not a valid version' % version) |
| |
| t.AddChromeArg('--enable-spdy-proxy-auth') |
| t.AddChromeArg('--dont-require-litepage-redirect-infobar') |
| t.AddChromeArg('--ignore-previews-blacklist') |
| t.AddChromeArg('--force-effective-connection-type=2G') |
| t.AddChromeArg('--ignore-litepage-redirect-optimization-blacklist') |
| t.SetExperiment('external_chrome_integration_test') |
| |
| def _AssertShowingLitePage(self, t, expectedText, expectedImages): |
| """Asserts that Chrome has loaded a Lite Page from the litepages server. |
| |
| Args: |
| t: the TestDriver object. |
| expectedText: text that should appear in the HTML response body. |
| expectedImages: the number of images that should be fetched. |
| """ |
| lite_page_responses = 0 |
| image_responses = 0 |
| |
| for response in t.GetHTTPResponses(): |
| content_type = '' |
| if 'content-type' in response.response_headers: |
| content_type = response.response_headers['content-type'] |
| if 'text/html' in content_type: |
| self.assertRegexpMatches(response.url, LITEPAGES_REGEXP) |
| self.assertEqual(200, response.status) |
| lite_page_responses += 1 |
| if ('image/' in content_type |
| and re.match(LITEPAGES_REGEXP, response.url) |
| and 200 == response.status): |
| image_responses += 1 |
| |
| self.assertEqual(1, lite_page_responses) |
| self.assertEqual(expectedImages, image_responses) |
| |
| bodyText = t.ExecuteJavascriptStatement('document.body.innerText') |
| self.assertIn(expectedText, bodyText) |
| |
| self.assertPreviewShownViaHistogram(t, 'LitePageRedirect') |
| |
| def _AssertShowingOriginalPage(self, t, expectedURL, expectedStatus, |
| expectedBypassCount = 1): |
| """Asserts that Chrome has not loaded a Lite Page from the litepages server. |
| |
| Args: |
| t: the TestDriver object. |
| expectedURL: the URL of the mainframe HTML response. |
| expectedStatus: the HTTP response status for the mainframe HTML response. |
| expectBypass: true if we expect a bypass from the litepages server. |
| """ |
| html_responses = 0 |
| |
| for response in t.GetHTTPResponses(): |
| if expectedURL == response.url: |
| self.assertEqual(expectedStatus, response.status) |
| html_responses += 1 |
| |
| bypass_count = t.GetBrowserHistogram( |
| 'Previews.ServerLitePage.ServerResponse', 2) |
| self.assertEqual(1, html_responses) |
| self.assertEqual(expectedBypassCount, bypass_count['count']) |
| self.assertPreviewNotShownViaHistogram(t, 'LitePageRedirect') |
| |
| # Verifies that a Lite Page is not served when the server returns a bypass. |
| @ChromeVersionEqualOrAfterM(74) |
| def testServerReturnsBypass(self): |
| with TestDriver() as t: |
| self.EnableLitePageServerPreviewsAndInit(t) |
| url = 'https://mobilespeed-test.appspot.com/static/litepagetests/bypass.html' |
| t.LoadURL(url) |
| self._AssertShowingOriginalPage(t, url, 200) |
| |
| # Verifies that a Lite Page is not served when the server returns a bypass. |
| # Additionally, verifies that after receiving the host-blacklisted directive, |
| # previews will not be attempted for future navigations on the same host. |
| @ChromeVersionEqualOrAfterM(74) |
| def testServerReturnsBypassWithHostBlacklisted(self): |
| with TestDriver() as t: |
| self.EnableLitePageServerPreviewsAndInit(t) |
| url = 'https://mobilespeed-test2.appspot.com/static/litepagetests/bypass.html' |
| t.LoadURL(url) |
| self._AssertShowingOriginalPage(t, url, 200) |
| # Ensure the reload doesn't use a cached page. |
| t.LoadURL('chrome://settings/clearBrowserData') |
| # This second navigation should not attempt a preview, so the bypass count |
| # should not have been incremented a second time. |
| t.LoadURL(url) |
| self._AssertShowingOriginalPage(t, url, 200, expectedBypassCount = 1) |
| |
| # Verifies that a Lite Page is not served when the server returns a 404. |
| @ChromeVersionEqualOrAfterM(74) |
| def testServerReturns404(self): |
| with TestDriver() as t: |
| self.EnableLitePageServerPreviewsAndInit(t) |
| url = 'https://mobilespeed-test.appspot.com/404' |
| t.LoadURL(url) |
| self._AssertShowingOriginalPage(t, url, 404) |
| |
| # Verifies that a Lite Page is served when enabled and not blacklisted. |
| @ChromeVersionEqualOrAfterM(74) |
| def testServerReturnsLitePage(self): |
| with TestDriver() as t: |
| self.EnableLitePageServerPreviewsAndInit(t) |
| t.LoadURL('https://mobilespeed-test.appspot.com/static/litepagetests/simple.html') |
| self._AssertShowingLitePage(t, 'Hello world', 1) |
| |
| # Verifies that a Lite Page pageload sends a DRP pingback. |
| @ChromeVersionEqualOrAfterM(74) |
| def testPingbackSent(self): |
| with TestDriver() as t: |
| t.AddChromeArg('--enable-data-reduction-proxy-force-pingback') |
| self.EnableLitePageServerPreviewsAndInit(t) |
| |
| # Navigate twice so that the first page sends a pingback. The second page |
| # can be anything since only the first pageload will send a pingback in |
| # this test. |
| t.LoadURL('https://mobilespeed-test.appspot.com/static/litepagetests/simple.html') |
| self._AssertShowingLitePage(t, 'Hello world', 1) |
| t.LoadURL('https://www.google.com') |
| |
| t.SleepUntilHistogramHasEntry("DataReductionProxy.Pingback.Succeeded") |
| # Verify one pingback attempt that was successful. |
| attempted = t.GetBrowserHistogram('DataReductionProxy.Pingback.Attempted') |
| self.assertEqual(1, attempted['count']) |
| succeeded = t.GetBrowserHistogram('DataReductionProxy.Pingback.Succeeded') |
| self.assertEqual(1, succeeded['count']) |
| |
| # Verifies that a Lite Page is served when the main frame response is a |
| # redirect to a URL that is not blacklisted. |
| @ChromeVersionEqualOrAfterM(74) |
| def testServerReturnsLitePageAfterRedirect(self): |
| with TestDriver() as t: |
| self.EnableLitePageServerPreviewsAndInit(t) |
| t.LoadURL('https://mobilespeed-test.appspot.com/redirect-to/static/litepagetests/simple.html') |
| self._AssertShowingLitePage(t, 'Hello world', 1) |
| |
| # Verifies that a bad SSL interstitial is shown (instead of a Lite Page) when |
| # the origin server has bad certificates. |
| @ChromeVersionEqualOrAfterM(74) |
| def testServerShowsBadSSLInterstitial(self): |
| with TestDriver() as t: |
| self.EnableLitePageServerPreviewsAndInit(t) |
| url = 'https://expired.badssl.com/' |
| t.LoadURL(url) |
| self._AssertShowingOriginalPage(t, url, 200) |
| # BadSSL onterstitials are not actually shown in webdriver tests (they |
| # seem to be clicked through automatically). This histogram is incremented |
| # after an interstitial has been clicked. |
| histogram = t.GetBrowserHistogram( |
| 'interstitial.ssl.visited_site_after_warning', 1) |
| self.assertEqual(1, histogram['count']) |
| |
| # Verifies that a safebrowsing interstitial is shown (instead of a Lite Page) |
| # when the URL is marked as malware by safebrowsing. |
| @AndroidOnly |
| @ChromeVersionEqualOrAfterM(74) |
| def testServerShowsSafebrowsingInterstitial(self): |
| with TestDriver() as t: |
| self.EnableLitePageServerPreviewsAndInit(t) |
| try : |
| # LoadURL will timeout when the interstital appears. |
| t.LoadURL('https://testsafebrowsing.appspot.com/s/malware.html') |
| self.fail('expected timeout') |
| except TimeoutException: |
| histogram = t.GetBrowserHistogram('SB2.ResourceTypes2.Unsafe') |
| self.assertEqual(1, histogram['count']) |
| |
| |
| # Verifies that a Lite Page is served, an intervention report has been |
| # sent to the correct reporting endpoint, and the content of this report |
| # is expected. |
| @ChromeVersionEqualOrAfterM(74) |
| def testLitePageWebReport(self): |
| with TestDriver() as t: |
| t.AddChromeArg('--short-reporting-delay') |
| t.UseNetLog() |
| self.EnableLitePageServerPreviewsAndInit(t) |
| |
| t.LoadURL('https://mobilespeed-test.appspot.com/snapshot-test/') |
| |
| # Verify that the request is served by a Lite Page. |
| lite_page_responses = 0 |
| for response in t.GetHTTPResponses(): |
| if re.match(LITEPAGES_REGEXP, response.url) and response.status == 200: |
| lite_page_responses += 1 |
| self.assertEqual(1, lite_page_responses) |
| |
| # Wait for intervention report to be attempted. |
| t.SleepUntilHistogramHasEntry("Net.Reporting.ReportDeliveredAttempts", |
| 120) |
| events = t.StopAndGetNetLog()["events"] |
| |
| # Collect IDs of expected reporting requests. |
| report_request_id = [] |
| for event in events: |
| if "params" not in event: |
| continue |
| if event.get("params") is None: |
| continue |
| if "headers" not in event.get("params"): |
| continue |
| |
| header = event["params"]["headers"] |
| quoted_report_url = urllib.quote_plus( |
| "https://mobilespeed-test.appspot.com/web-reports") |
| if ((":path: /webreports?u=%s" % quoted_report_url) in header |
| and "content-type: application/reports+json" in header): |
| report_request_id.append(event["source"]["id"]) |
| self.assertNotEqual(0, len(report_request_id)) |
| |
| # Verify that at least one reporting request got 200. |
| ok_responses = 0 |
| for id in report_request_id: |
| for event in events: |
| if (event["source"]["id"] != id |
| or not "params" in event |
| or not "headers" in event["params"]): |
| continue |
| |
| for value in event["params"]["headers"]: |
| if ":status: 200" in value: |
| ok_responses += 1 |
| self.assertNotEqual(0, ok_responses) |
| |
| class HttpsPreviewsNavigationThrottle(HttpsPreviewsBaseClass, IntegrationTest): |
| def getVersion(self): |
| return NAV_THROTTLE_VERSION |
| |
| class HttpsPreviewsURLLoader(HttpsPreviewsBaseClass, IntegrationTest): |
| def getVersion(self): |
| return URL_LOADER_VERSION |
| |
| # Verifies that if a streaming preview is being served but needs to be |
| # aborted, changing location.href will load the original page. |
| # |
| # This test only works for the URLLoader version. |
| @ChromeVersionEqualOrAfterM(75) |
| def testChromeStreamingAbort(self): |
| url = 'https://mobilespeed-test.appspot.com/static/litepagetests/simple.html' |
| with TestDriver() as t: |
| self.EnableLitePageServerPreviewsAndInit(t) |
| t.LoadURL(url) |
| self._AssertShowingLitePage(t, 'Hello world', 1) |
| self.assertNotEqual(url, |
| t.ExecuteJavascriptStatement('window.location.href')) |
| |
| # Although this is not a streaming DOM, the critical behavior to be tested |
| # is that once a preview is committed in the renderer, changing |
| # location.href loads the original page. The timing of this call is not |
| # important. |
| t.ExecuteJavascriptStatement('window.location.href += "&abort"') |
| |
| t.SleepUntilHistogramHasEntry('Previews.PageEndReason.LitePageRedirect', |
| 30) |
| |
| self.assertEqual(url, |
| t.ExecuteJavascriptStatement('window.location.href')) |
| |
| if __name__ == '__main__': |
| IntegrationTest.RunAllTests() |