blob: 167ae76fb6697103d71433cbddfbcde60b7c48b1 [file] [log] [blame]
# 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()