Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3976)

Unified Diff: chrome/browser/chrome_service_worker_browsertest.cc

Issue 2916533002: Introduce chrome://flags/#network-prediction-options-for-service-worker
Patch Set: use StartServiceWorkerForNavigationHint Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/about_flags.cc ('k') | chrome/browser/flag_descriptions.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
« no previous file with comments | « chrome/browser/about_flags.cc ('k') | chrome/browser/flag_descriptions.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698