| Index: chrome/browser/chrome_service_worker_browsertest.cc
|
| diff --git a/chrome/browser/chrome_service_worker_browsertest.cc b/chrome/browser/chrome_service_worker_browsertest.cc
|
| index 74d21d5a66ae2e58bfdf7e5d6fc96193fe4b6914..afbb5ab1614884cde7340d5c673cd85c50f6b3b2 100644
|
| --- a/chrome/browser/chrome_service_worker_browsertest.cc
|
| +++ b/chrome/browser/chrome_service_worker_browsertest.cc
|
| @@ -5,6 +5,8 @@
|
| // This file tests that Service Workers (a Content feature) work in the Chromium
|
| // embedder.
|
|
|
| +#include <tuple>
|
| +
|
| #include "base/bind.h"
|
| #include "base/command_line.h"
|
| #include "base/files/scoped_temp_dir.h"
|
| @@ -18,6 +20,8 @@
|
| #include "chrome/browser/chrome_notification_types.h"
|
| #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
|
| #include "chrome/browser/content_settings/tab_specific_content_settings.h"
|
| +#include "chrome/browser/net/prediction_options.h"
|
| +#include "chrome/browser/net/predictor.h"
|
| #include "chrome/browser/profiles/profile.h"
|
| #include "chrome/browser/ui/browser.h"
|
| #include "chrome/browser/ui/browser_window.h"
|
| @@ -31,8 +35,10 @@
|
| #include "content/public/browser/service_worker_context.h"
|
| #include "content/public/browser/storage_partition.h"
|
| #include "content/public/browser/web_contents.h"
|
| +#include "content/public/common/content_switches.h"
|
| #include "content/public/test/browser_test_utils.h"
|
| #include "net/test/embedded_test_server/embedded_test_server.h"
|
| +#include "net/test/embedded_test_server/embedded_test_server_connection_listener.h"
|
| #include "ppapi/shared_impl/ppapi_switches.h"
|
|
|
| namespace {
|
| @@ -700,4 +706,294 @@ IN_PROC_BROWSER_TEST_F(ChromeServiceWorkerNavigationHintTest, NoFetchHandler) {
|
| false);
|
| }
|
|
|
| +class ConnectionListener
|
| + : public net::test_server::EmbeddedTestServerConnectionListener {
|
| + public:
|
| + ConnectionListener() : task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
|
| + ~ConnectionListener() override {}
|
| +
|
| + void AcceptedSocket(const net::StreamSocket& connection) override {
|
| + base::AutoLock lock(lock_);
|
| + socket_accepted_ = true;
|
| + if (wait_accept_loop_)
|
| + task_runner_->PostTask(FROM_HERE, wait_accept_loop_->QuitClosure());
|
| + }
|
| + void ReadFromSocket(const net::StreamSocket& socket, int rv) override {}
|
| +
|
| + void ResetSocketAcceptedFlag() {
|
| + base::AutoLock lock(lock_);
|
| + socket_accepted_ = false;
|
| + }
|
| +
|
| + bool GetSocketAcceptedFlag() const {
|
| + base::AutoLock lock(lock_);
|
| + return socket_accepted_;
|
| + }
|
| +
|
| + void WaitForSocketAcceptedOnUI() {
|
| + {
|
| + base::AutoLock lock(lock_);
|
| + if (socket_accepted_)
|
| + return;
|
| + wait_accept_loop_.reset(new base::RunLoop());
|
| + }
|
| + wait_accept_loop_->Run();
|
| + }
|
| +
|
| + private:
|
| + scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
|
| +
|
| + // This lock protects the members below, which each are used on both the
|
| + // IO and UI thread. Members declared after the lock are protected by it.
|
| + mutable base::Lock lock_;
|
| + bool socket_accepted_ = false;
|
| + std::unique_ptr<base::RunLoop> wait_accept_loop_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(ConnectionListener);
|
| +};
|
| +
|
| +class ChromeServiceWorkerPredictionOptionsTest
|
| + : public ChromeServiceWorkerTest,
|
| + public ::testing::WithParamInterface<std::tuple<
|
| + bool,
|
| + chrome_browser_net::NetworkPredictionOptionsForServiceWorker>> {
|
| + protected:
|
| + ChromeServiceWorkerPredictionOptionsTest()
|
| + : cross_site_test_server_(new net::EmbeddedTestServer()) {}
|
| + ~ChromeServiceWorkerPredictionOptionsTest() override {}
|
| +
|
| + void SetUpCommandLine(base::CommandLine* command_line) override {
|
| + ChromeServiceWorkerTest::SetUpCommandLine(command_line);
|
| + if (std::get<0>(GetParam()))
|
| + command_line->AppendSwitch(switches::kEnableBrowserSideNavigation);
|
| + switch (Options()) {
|
| + case chrome_browser_net::NetworkPredictionOptionsForServiceWorker::
|
| + PRECONNECT_ONLY:
|
| + command_line->AppendSwitchASCII(
|
| + switches::kNetworkPredictionOptionsForServiceWorker,
|
| + chrome_browser_net::kPreconnectOnly);
|
| + break;
|
| + case chrome_browser_net::NetworkPredictionOptionsForServiceWorker::
|
| + START_SERVICE_WORKER_AND_PRECONNECT:
|
| + command_line->AppendSwitchASCII(
|
| + switches::kNetworkPredictionOptionsForServiceWorker,
|
| + chrome_browser_net::kStartServiceWorkerAndPreconnect);
|
| + break;
|
| + case chrome_browser_net::NetworkPredictionOptionsForServiceWorker::
|
| + START_SERVICE_WORKER_AND_DEFER_PRECONNECT:
|
| + command_line->AppendSwitchASCII(
|
| + switches::kNetworkPredictionOptionsForServiceWorker,
|
| + chrome_browser_net::kStartServiceWorkerAndDeferPreconnect);
|
| + break;
|
| + case chrome_browser_net::NetworkPredictionOptionsForServiceWorker::
|
| + START_SERVICE_WORKER_ONLY:
|
| + command_line->AppendSwitchASCII(
|
| + switches::kNetworkPredictionOptionsForServiceWorker,
|
| + chrome_browser_net::kStartServiceWorkerOnly);
|
| + break;
|
| + }
|
| + }
|
| +
|
| + void SetUpOnMainThread() override {
|
| + WriteServiceWorkerPredictionOptionsTestFiles();
|
| +
|
| + embedded_test_server()->ServeFilesFromDirectory(
|
| + service_worker_dir_.GetPath());
|
| + ASSERT_TRUE(embedded_test_server()->Start());
|
| +
|
| + cross_site_test_server()->ServeFilesFromDirectory(
|
| + service_worker_dir_.GetPath());
|
| + cross_site_connection_listener_.reset(new ConnectionListener());
|
| + cross_site_test_server()->SetConnectionListener(
|
| + cross_site_connection_listener_.get());
|
| + ASSERT_TRUE(cross_site_test_server()->Start());
|
| +
|
| + browser()->profile()->GetNetworkPredictor()->SetPredictorEnabledForTest(
|
| + true);
|
| + }
|
| +
|
| + void InitializeServiceWorkerTest() {
|
| + base::HistogramTester histogram_tester;
|
| + const base::string16 expected_title = base::ASCIIToUTF16("READY");
|
| + content::TitleWatcher title_watcher(
|
| + browser()->tab_strip_model()->GetActiveWebContents(), expected_title);
|
| + ui_test_utils::NavigateToURL(
|
| + browser(), embedded_test_server()->GetURL(
|
| + "/sw_test_page.html?" +
|
| + cross_site_test_server()->GetURL("/test.js").spec()));
|
| + EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
|
| + histogram_tester.ExpectTotalCount("ServiceWorker.StartNewWorker.Status", 1);
|
| + histogram_tester.ExpectBucketCount("ServiceWorker.StartNewWorker.Status",
|
| + 0 /* SERVICE_WORKER_OK */, 1);
|
| +
|
| + // Stop the service worker.
|
| + content::BrowserContext::GetDefaultStoragePartition(browser()->profile())
|
| + ->GetServiceWorkerContext()
|
| + ->StopAllServiceWorkersForOrigin(embedded_test_server()->base_url());
|
| +
|
| + // Disconnect the connection.
|
| + cross_site_test_server()->FlushAllSocketsAndConnectionsOnUIThread();
|
| + EXPECT_TRUE(cross_site_connection_listener()->GetSocketAcceptedFlag());
|
| + cross_site_connection_listener()->ResetSocketAcceptedFlag();
|
| + }
|
| +
|
| + void NavigateToServiceWorkerTestPage() {
|
| + const base::string16 expected_title = base::ASCIIToUTF16("SW");
|
| + content::TitleWatcher title_watcher(
|
| + browser()->tab_strip_model()->GetActiveWebContents(), expected_title);
|
| + ui_test_utils::NavigateToURL(browser(),
|
| + embedded_test_server()->GetURL("/dummy.html"));
|
| + EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
|
| + }
|
| +
|
| + void InitializeNoServiceWorkerTest() {
|
| + const base::string16 expected_title = base::ASCIIToUTF16("READY");
|
| + content::TitleWatcher title_watcher(
|
| + browser()->tab_strip_model()->GetActiveWebContents(), expected_title);
|
| + ui_test_utils::NavigateToURL(
|
| + browser(), embedded_test_server()->GetURL(
|
| + "/no_sw_test_page.html?" +
|
| + cross_site_test_server()->GetURL("/test.js").spec()));
|
| +
|
| + // Disconnect the connection.
|
| + cross_site_test_server()->FlushAllSocketsAndConnectionsOnUIThread();
|
| + EXPECT_TRUE(cross_site_connection_listener()->GetSocketAcceptedFlag());
|
| + cross_site_connection_listener()->ResetSocketAcceptedFlag();
|
| + }
|
| +
|
| + void NavigateToNoServiceWorkerTestPage() {
|
| + const base::string16 expected_title = base::ASCIIToUTF16("READY");
|
| + content::TitleWatcher title_watcher(
|
| + browser()->tab_strip_model()->GetActiveWebContents(), expected_title);
|
| + ui_test_utils::NavigateToURL(
|
| + browser(), embedded_test_server()->GetURL("/no_sw_test_page.html"));
|
| + EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
|
| + }
|
| +
|
| + chrome_browser_net::NetworkPredictionOptionsForServiceWorker Options() const {
|
| + return std::get<1>(GetParam());
|
| + }
|
| +
|
| + net::EmbeddedTestServer* cross_site_test_server() {
|
| + return cross_site_test_server_.get();
|
| + }
|
| +
|
| + ConnectionListener* cross_site_connection_listener() {
|
| + return cross_site_connection_listener_.get();
|
| + }
|
| +
|
| + private:
|
| + void WriteServiceWorkerPredictionOptionsTestFiles() {
|
| + WriteFile(FILE_PATH_LITERAL("test.js"), "document.title = 'READY';");
|
| + WriteFile(FILE_PATH_LITERAL("sw.js"),
|
| + "this.onfetch = function(event) {"
|
| + " event.respondWith(new Response("
|
| + " '<title>SW</title>', "
|
| + " {headers: {'Content-Type': 'text/html'}}));"
|
| + "};");
|
| + WriteFile(FILE_PATH_LITERAL("sw_test_page.html"),
|
| + "<body><script>"
|
| + "navigator.serviceWorker.register('./sw.js', {scope: './'})"
|
| + " .then(reg => {"
|
| + " reg.addEventListener('updatefound', _ => {"
|
| + " var worker = reg.installing;"
|
| + " worker.addEventListener('statechange', _ => {"
|
| + " if (worker.state != 'activated')"
|
| + " return;"
|
| + " var script = document.createElement('script');"
|
| + " script.src = window.location.search.substring(1);"
|
| + " document.body.appendChild(script);"
|
| + " });"
|
| + " });"
|
| + " });"
|
| + "</script></body>");
|
| + WriteFile(FILE_PATH_LITERAL("no_sw_test_page.html"),
|
| + "<body><script>"
|
| + "if (window.location.search != '') {"
|
| + " var script = document.createElement('script');"
|
| + " script.src = window.location.search.substring(1);"
|
| + " document.body.appendChild(script);"
|
| + "} else {"
|
| + " document.title = 'READY';"
|
| + "}"
|
| + "</script></body>");
|
| + }
|
| +
|
| + std::unique_ptr<net::EmbeddedTestServer> cross_site_test_server_;
|
| + std::unique_ptr<ConnectionListener> cross_site_connection_listener_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(ChromeServiceWorkerPredictionOptionsTest);
|
| +};
|
| +
|
| +IN_PROC_BROWSER_TEST_P(ChromeServiceWorkerPredictionOptionsTest,
|
| + ServiceWorkerTest) {
|
| + InitializeServiceWorkerTest();
|
| + base::HistogramTester histogram_tester;
|
| + NavigateToServiceWorkerTestPage();
|
| + histogram_tester.ExpectTotalCount("ServiceWorker.StartWorker.Purpose", 1);
|
| +
|
| + switch (Options()) {
|
| + case chrome_browser_net::NetworkPredictionOptionsForServiceWorker::
|
| + PRECONNECT_ONLY:
|
| + histogram_tester.ExpectBucketCount(
|
| + "ServiceWorker.StartWorker.Purpose",
|
| + 10 /* ServiceWorkerMetrics::EventType::FETCH_MAIN_FRAME */, 1);
|
| + break;
|
| + case chrome_browser_net::NetworkPredictionOptionsForServiceWorker::
|
| + START_SERVICE_WORKER_AND_PRECONNECT:
|
| + case chrome_browser_net::NetworkPredictionOptionsForServiceWorker::
|
| + START_SERVICE_WORKER_AND_DEFER_PRECONNECT:
|
| + case chrome_browser_net::NetworkPredictionOptionsForServiceWorker::
|
| + START_SERVICE_WORKER_ONLY:
|
| + histogram_tester.ExpectBucketCount(
|
| + "ServiceWorker.StartWorker.Purpose",
|
| + 27 /* ServiceWorkerMetrics::EventType::NAVIGATION_HINT */, 1);
|
| + break;
|
| + }
|
| +
|
| + // Note: Wrting a chrome browset test which checks that the preconnection is
|
| + // defered until the service worker startup is too complex. So we only check
|
| + // that the preconnection is accutualy executed.
|
| + switch (Options()) {
|
| + case chrome_browser_net::NetworkPredictionOptionsForServiceWorker::
|
| + PRECONNECT_ONLY:
|
| + case chrome_browser_net::NetworkPredictionOptionsForServiceWorker::
|
| + START_SERVICE_WORKER_AND_PRECONNECT:
|
| + case chrome_browser_net::NetworkPredictionOptionsForServiceWorker::
|
| + START_SERVICE_WORKER_AND_DEFER_PRECONNECT:
|
| + cross_site_connection_listener()->WaitForSocketAcceptedOnUI();
|
| + break;
|
| + case chrome_browser_net::NetworkPredictionOptionsForServiceWorker::
|
| + START_SERVICE_WORKER_ONLY:
|
| + EXPECT_FALSE(cross_site_connection_listener()->GetSocketAcceptedFlag());
|
| + break;
|
| + }
|
| +}
|
| +
|
| +IN_PROC_BROWSER_TEST_P(ChromeServiceWorkerPredictionOptionsTest,
|
| + NoServiceWorkerTest) {
|
| + InitializeNoServiceWorkerTest();
|
| + base::HistogramTester histogram_tester;
|
| + NavigateToNoServiceWorkerTestPage();
|
| + // If there is no service workers, the preconnection must be executed
|
| + // regardless of the options.
|
| + cross_site_connection_listener()->WaitForSocketAcceptedOnUI();
|
| +}
|
| +
|
| +INSTANTIATE_TEST_CASE_P(
|
| + /* no prefix */,
|
| + ChromeServiceWorkerPredictionOptionsTest,
|
| + ::testing::Combine(
|
| + ::testing::Values(false, true),
|
| +
|
| + ::testing::Values(
|
| + chrome_browser_net::NetworkPredictionOptionsForServiceWorker::
|
| + PRECONNECT_ONLY,
|
| + chrome_browser_net::NetworkPredictionOptionsForServiceWorker::
|
| + START_SERVICE_WORKER_AND_PRECONNECT,
|
| + chrome_browser_net::NetworkPredictionOptionsForServiceWorker::
|
| + START_SERVICE_WORKER_AND_DEFER_PRECONNECT,
|
| + chrome_browser_net::NetworkPredictionOptionsForServiceWorker::
|
| + START_SERVICE_WORKER_ONLY)));
|
| +
|
| } // namespace
|
|
|