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

Unified Diff: chrome/browser/chrome_service_worker_browsertest.cc

Issue 2916533002: Introduce chrome://flags/#network-prediction-options-for-service-worker
Patch Set: Created 3 years, 7 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
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 1d227068e7e843c62967a4b2d95970aac5e6106f..8dcfaad8adba2f59ec73c5ead6c2703144e20c8b 100644
--- a/chrome/browser/chrome_service_worker_browsertest.cc
+++ b/chrome/browser/chrome_service_worker_browsertest.cc
@@ -12,11 +12,14 @@
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/histogram_tester.h"
#include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
#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"
@@ -32,6 +35,7 @@
#include "content/public/browser/web_contents.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 {
@@ -611,4 +615,284 @@ IN_PROC_BROWSER_TEST_F(ChromeServiceWorkerFetchPPAPIPrivateTest,
ExecutePNACLUrlLoaderTest("OtherCORSCredentials"));
}
+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<
+ 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);
+ switch (GetParam()) {
+ 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());
+ }
+
+ 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 (GetParam()) {
+ 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::PRECONNECT */, 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 (GetParam()) {
+ 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::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

Powered by Google App Engine
This is Rietveld 408576698