blob: 91925b75b4c9d7aacb53b816a2ad236cffe9c919 [file] [log] [blame]
annekao38685502015-07-14 17:46:391// Copyright 2015 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
avia2f4804a2015-12-24 23:11:135#include <stdint.h>
6
Sylvain Defresne4fdc727fd2018-10-04 11:09:467#include "base/bind.h"
kalman6f984ae2015-09-18 17:21:588#include "base/bind_helpers.h"
Istiaque Ahmeda14ec482018-08-25 01:02:189#include "base/json/json_reader.h"
avia2f4804a2015-12-24 23:11:1310#include "base/macros.h"
Gabriel Charette078e3662017-08-28 22:59:0411#include "base/run_loop.h"
kalman6f984ae2015-09-18 17:21:5812#include "base/strings/stringprintf.h"
horo1eeddde2015-11-19 05:59:2513#include "base/strings/utf_string_conversions.h"
jam3f2d3932017-04-26 20:28:5114#include "base/threading/thread_restrictions.h"
Olga Sharonova3e13cd92018-02-08 16:43:5615#include "build/build_config.h"
annekao38685502015-07-14 17:46:3916#include "chrome/browser/extensions/extension_apitest.h"
rdevlin.croninf5863da2015-09-10 19:21:4517#include "chrome/browser/extensions/extension_service.h"
Istiaque Ahmed805f6a83b2017-10-05 01:23:2618#include "chrome/browser/extensions/lazy_background_page_test_util.h"
peter9f4490a2017-01-27 00:58:3619#include "chrome/browser/gcm/gcm_profile_service_factory.h"
miguelg9b502862017-04-24 18:13:5320#include "chrome/browser/notifications/notification_display_service_factory.h"
Peter Beverloodd4ef1e2018-06-21 15:41:0421#include "chrome/browser/notifications/notification_permission_context.h"
miguelg9b502862017-04-24 18:13:5322#include "chrome/browser/notifications/stub_notification_display_service.h"
lshang106c1772016-06-06 01:43:2323#include "chrome/browser/permissions/permission_manager.h"
timlohc6911802017-03-01 05:37:0324#include "chrome/browser/permissions/permission_result.h"
lazyboy561b7de2015-11-19 19:27:3025#include "chrome/browser/push_messaging/push_messaging_app_identifier.h"
26#include "chrome/browser/push_messaging/push_messaging_service_factory.h"
27#include "chrome/browser/push_messaging/push_messaging_service_impl.h"
annekao1db36fd2015-07-29 17:09:1628#include "chrome/browser/ui/tabs/tab_strip_model.h"
Trent Apted4267b942017-10-27 03:25:3629#include "chrome/common/chrome_switches.h"
Istiaque Ahmeda14ec482018-08-25 01:02:1830#include "chrome/common/extensions/api/web_navigation.h"
rdevlin.croninf5863da2015-09-10 19:21:4531#include "chrome/test/base/ui_test_utils.h"
timloh9a180ad2017-02-20 07:15:2332#include "components/content_settings/core/common/content_settings_types.h"
Peter Beverloo34139462018-04-10 14:18:0633#include "components/gcm_driver/fake_gcm_profile_service.h"
johnmea5045732016-09-08 17:23:2934#include "components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h"
sdefresne9fb67692015-08-03 18:48:2235#include "components/version_info/version_info.h"
kalman6f984ae2015-09-18 17:21:5836#include "content/public/browser/navigation_controller.h"
rdevlin.croninf5863da2015-09-10 19:21:4537#include "content/public/browser/navigation_entry.h"
lazyboy4c82177a2016-10-18 00:04:0938#include "content/public/browser/service_worker_context.h"
39#include "content/public/browser/storage_partition.h"
kalman6f984ae2015-09-18 17:21:5840#include "content/public/browser/web_contents.h"
lazyboybd325ae2015-11-18 21:35:2641#include "content/public/common/content_switches.h"
falkenad185092016-06-16 06:10:0242#include "content/public/common/origin_util.h"
kalman6f984ae2015-09-18 17:21:5843#include "content/public/common/page_type.h"
lazyboybd325ae2015-11-18 21:35:2644#include "content/public/test/background_sync_test_util.h"
annekao1db36fd2015-07-29 17:09:1645#include "content/public/test/browser_test_utils.h"
lazyboy63b994a2017-06-30 21:20:2346#include "content/public/test/service_worker_test_helpers.h"
Istiaque Ahmed771aa8a22018-06-20 23:40:5347#include "extensions/browser/event_router.h"
kalman6f984ae2015-09-18 17:21:5848#include "extensions/browser/extension_host.h"
lazyboyc3e763a2015-12-09 23:09:5849#include "extensions/browser/extension_registry.h"
kalman6f984ae2015-09-18 17:21:5850#include "extensions/browser/process_manager.h"
Istiaque Ahmed70f76ac2018-11-02 02:59:5551#include "extensions/browser/service_worker_task_queue.h"
Istiaque Ahmeda14ec482018-08-25 01:02:1852#include "extensions/common/api/test.h"
Devlin Cronina3fe3d602017-11-22 04:47:4353#include "extensions/common/extension_features.h"
Istiaque Ahmed771aa8a22018-06-20 23:40:5354#include "extensions/common/value_builder.h"
kalman6f984ae2015-09-18 17:21:5855#include "extensions/test/background_page_watcher.h"
annekao38685502015-07-14 17:46:3956#include "extensions/test/extension_test_message_listener.h"
Istiaque Ahmed805f6a83b2017-10-05 01:23:2657#include "extensions/test/result_catcher.h"
falkenad185092016-06-16 06:10:0258#include "net/dns/mock_host_resolver.h"
horo1eeddde2015-11-19 05:59:2559#include "net/test/embedded_test_server/embedded_test_server.h"
lazyboy63b994a2017-06-30 21:20:2360#include "url/url_constants.h"
annekao38685502015-07-14 17:46:3961
62namespace extensions {
63
kalman6f984ae2015-09-18 17:21:5864namespace {
65
lazyboy22eddc712015-12-10 21:16:2666// Returns the newly added WebContents.
67content::WebContents* AddTab(Browser* browser, const GURL& url) {
68 int starting_tab_count = browser->tab_strip_model()->count();
69 ui_test_utils::NavigateToURLWithDisposition(
nick3b04f322016-08-31 19:29:1970 browser, url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
lazyboy22eddc712015-12-10 21:16:2671 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
72 int tab_count = browser->tab_strip_model()->count();
73 EXPECT_EQ(starting_tab_count + 1, tab_count);
74 return browser->tab_strip_model()->GetActiveWebContents();
75}
76
Istiaque Ahmedea5ed5042017-09-25 19:00:1677enum BindingsType { NATIVE_BINDINGS, JAVASCRIPT_BINDINGS };
78
lazyboy22eddc712015-12-10 21:16:2679class WebContentsLoadStopObserver : content::WebContentsObserver {
80 public:
81 explicit WebContentsLoadStopObserver(content::WebContents* web_contents)
82 : content::WebContentsObserver(web_contents),
83 load_stop_observed_(false) {}
84
85 void WaitForLoadStop() {
86 if (load_stop_observed_)
87 return;
88 message_loop_runner_ = new content::MessageLoopRunner;
89 message_loop_runner_->Run();
90 }
91
92 private:
93 void DidStopLoading() override {
94 load_stop_observed_ = true;
95 if (message_loop_runner_)
96 message_loop_runner_->Quit();
97 }
98
99 bool load_stop_observed_;
100 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
101
102 DISALLOW_COPY_AND_ASSIGN(WebContentsLoadStopObserver);
103};
104
kalman6f984ae2015-09-18 17:21:58105} // namespace
106
Istiaque Ahmedea5ed5042017-09-25 19:00:16107class ServiceWorkerTest : public ExtensionApiTest,
108 public ::testing::WithParamInterface<BindingsType> {
annekao38685502015-07-14 17:46:39109 public:
lazyboy20167c22016-05-18 00:59:30110 ServiceWorkerTest() : current_channel_(version_info::Channel::STABLE) {}
Istiaque Ahmed7105f2a2017-10-07 01:11:59111 explicit ServiceWorkerTest(version_info::Channel channel)
112 : current_channel_(channel) {}
annekao38685502015-07-14 17:46:39113
114 ~ServiceWorkerTest() override {}
115
Devlin Cronina3fe3d602017-11-22 04:47:43116 void SetUp() override {
117 if (GetParam() == NATIVE_BINDINGS) {
Mostyn Bramley-Mooreb6a37c62018-09-04 21:43:35118 scoped_feature_list_.InitAndEnableFeature(
119 extensions_features::kNativeCrxBindings);
Devlin Cronina3fe3d602017-11-22 04:47:43120 } else {
121 DCHECK_EQ(JAVASCRIPT_BINDINGS, GetParam());
Mostyn Bramley-Mooreb6a37c62018-09-04 21:43:35122 scoped_feature_list_.InitAndDisableFeature(
123 extensions_features::kNativeCrxBindings);
Devlin Cronina3fe3d602017-11-22 04:47:43124 }
125 ExtensionApiTest::SetUp();
126 }
127
jam1a5b5582017-05-01 16:50:10128 void SetUpOnMainThread() override {
129 ExtensionApiTest::SetUpOnMainThread();
130 host_resolver()->AddRule("a.com", "127.0.0.1");
131 }
132
kalman6f984ae2015-09-18 17:21:58133 protected:
134 // Returns the ProcessManager for the test's profile.
135 ProcessManager* process_manager() { return ProcessManager::Get(profile()); }
136
137 // Starts running a test from the background page test extension.
138 //
139 // This registers a service worker with |script_name|, and fetches the
140 // registration result.
Istiaque Ahmed93ff7f42018-08-31 01:42:22141 const Extension* StartTestFromBackgroundPage(const char* script_name) {
Istiaque Ahmed6475f542018-08-28 04:20:21142 ExtensionTestMessageListener ready_listener("ready", false);
kalman6f984ae2015-09-18 17:21:58143 const Extension* extension =
144 LoadExtension(test_data_dir_.AppendASCII("service_worker/background"));
145 CHECK(extension);
Istiaque Ahmed6475f542018-08-28 04:20:21146 CHECK(ready_listener.WaitUntilSatisfied());
147
kalman6f984ae2015-09-18 17:21:58148 ExtensionHost* background_host =
149 process_manager()->GetBackgroundHostForExtension(extension->id());
150 CHECK(background_host);
Istiaque Ahmed6475f542018-08-28 04:20:21151
kalman6f984ae2015-09-18 17:21:58152 std::string error;
153 CHECK(content::ExecuteScriptAndExtractString(
154 background_host->host_contents(),
155 base::StringPrintf("test.registerServiceWorker('%s')", script_name),
156 &error));
Istiaque Ahmed93ff7f42018-08-31 01:42:22157 if (!error.empty())
kalman6f984ae2015-09-18 17:21:58158 ADD_FAILURE() << "Got unexpected error " << error;
159 return extension;
160 }
161
162 // Navigates the browser to a new tab at |url|, waits for it to load, then
163 // returns it.
164 content::WebContents* Navigate(const GURL& url) {
165 ui_test_utils::NavigateToURLWithDisposition(
nick3b04f322016-08-31 19:29:19166 browser(), url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
kalman6f984ae2015-09-18 17:21:58167 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
168 content::WebContents* web_contents =
169 browser()->tab_strip_model()->GetActiveWebContents();
170 content::WaitForLoadStop(web_contents);
171 return web_contents;
172 }
173
174 // Navigates the browser to |url| and returns the new tab's page type.
175 content::PageType NavigateAndGetPageType(const GURL& url) {
clamy1d7a4112018-06-15 15:47:16176 return Navigate(url)
177 ->GetController()
178 .GetLastCommittedEntry()
179 ->GetPageType();
kalman6f984ae2015-09-18 17:21:58180 }
181
182 // Extracts the innerText from |contents|.
183 std::string ExtractInnerText(content::WebContents* contents) {
184 std::string inner_text;
185 if (!content::ExecuteScriptAndExtractString(
186 contents,
187 "window.domAutomationController.send(document.body.innerText)",
188 &inner_text)) {
189 ADD_FAILURE() << "Failed to get inner text for "
190 << contents->GetVisibleURL();
191 }
192 return inner_text;
193 }
194
195 // Navigates the browser to |url|, then returns the innerText of the new
196 // tab's WebContents' main frame.
197 std::string NavigateAndExtractInnerText(const GURL& url) {
198 return ExtractInnerText(Navigate(url));
199 }
200
lazyboy4c82177a2016-10-18 00:04:09201 size_t GetWorkerRefCount(const GURL& origin) {
202 content::ServiceWorkerContext* sw_context =
203 content::BrowserContext::GetDefaultStoragePartition(
204 browser()->profile())
205 ->GetServiceWorkerContext();
206 base::RunLoop run_loop;
207 size_t ref_count = 0;
208 auto set_ref_count = [](size_t* ref_count, base::RunLoop* run_loop,
209 size_t external_request_count) {
210 *ref_count = external_request_count;
211 run_loop->Quit();
212 };
213 sw_context->CountExternalRequestsForTest(
Matt Falkenhagenc5cb4282017-09-07 08:43:42214 origin, base::BindOnce(set_ref_count, &ref_count, &run_loop));
lazyboy4c82177a2016-10-18 00:04:09215 run_loop.Run();
216 return ref_count;
217 }
218
annekao38685502015-07-14 17:46:39219 private:
lazyboy20167c22016-05-18 00:59:30220 // Sets the channel to "stable".
221 // Not useful after we've opened extension Service Workers to stable
222 // channel.
223 // TODO(lazyboy): Remove this when ExtensionServiceWorkersEnabled() is
224 // removed.
annekao38685502015-07-14 17:46:39225 ScopedCurrentChannel current_channel_;
kalman6f984ae2015-09-18 17:21:58226
Devlin Cronina3fe3d602017-11-22 04:47:43227 base::test::ScopedFeatureList scoped_feature_list_;
228
annekao38685502015-07-14 17:46:39229 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerTest);
230};
231
Istiaque Ahmedccb444022018-06-19 02:11:12232class ServiceWorkerBasedBackgroundTest : public ServiceWorkerTest {
233 public:
234 ServiceWorkerBasedBackgroundTest()
235 : ServiceWorkerTest(
236 // Extensions APIs from SW are only enabled on trunk.
237 // It is important to set the channel early so that this change is
238 // visible in renderers running with service workers (and no
239 // extension).
240 version_info::Channel::UNKNOWN) {}
241 ~ServiceWorkerBasedBackgroundTest() override {}
242
243 void SetUpOnMainThread() override {
244 host_resolver()->AddRule("*", "127.0.0.1");
245 ASSERT_TRUE(embedded_test_server()->Start());
246 ServiceWorkerTest::SetUpOnMainThread();
247 }
248
249 private:
250 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerBasedBackgroundTest);
251};
252
253// Tests that Service Worker based background pages can be loaded and they can
254// receive extension events.
255// The extension is installed and loaded during this step and it registers
256// an event listener for tabs.onCreated event. The step also verifies that tab
257// creation correctly fires the listener.
258IN_PROC_BROWSER_TEST_P(ServiceWorkerBasedBackgroundTest, PRE_Basic) {
259 ExtensionTestMessageListener newtab_listener("CREATED", false);
260 newtab_listener.set_failure_message("CREATE_FAILED");
261 ExtensionTestMessageListener worker_listener("WORKER_RUNNING", false);
262 worker_listener.set_failure_message("NON_WORKER_SCOPE");
263 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
264 "service_worker/worker_based_background/basic"));
265 ASSERT_TRUE(extension);
266 const ExtensionId extension_id = extension->id();
267 EXPECT_TRUE(worker_listener.WaitUntilSatisfied());
268
269 const GURL url = embedded_test_server()->GetURL("/extensions/test_file.html");
270 content::WebContents* new_web_contents = AddTab(browser(), url);
271 EXPECT_TRUE(new_web_contents);
272 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
273
274 // Service Worker extension does not have ExtensionHost.
275 EXPECT_FALSE(process_manager()->GetBackgroundHostForExtension(extension_id));
276}
277
278// After browser restarts, this test step ensures that opening a tab fires
279// tabs.onCreated event listener to the extension without explicitly loading the
280// extension. This is because the extension registered a listener before browser
281// restarted in PRE_Basic.
Istiaque Ahmedad376e6b2018-09-13 22:48:25282IN_PROC_BROWSER_TEST_P(ServiceWorkerBasedBackgroundTest, Basic) {
Istiaque Ahmedccb444022018-06-19 02:11:12283 ExtensionTestMessageListener newtab_listener("CREATED", false);
284 newtab_listener.set_failure_message("CREATE_FAILED");
285 const GURL url = embedded_test_server()->GetURL("/extensions/test_file.html");
286 content::WebContents* new_web_contents = AddTab(browser(), url);
287 EXPECT_TRUE(new_web_contents);
288 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
289}
290
Istiaque Ahmedbf08f952018-10-02 01:22:04291// Tests chrome.runtime.onInstalled fires for extension service workers.
292IN_PROC_BROWSER_TEST_P(ServiceWorkerBasedBackgroundTest, OnInstalledEvent) {
293 ASSERT_TRUE(RunExtensionTest(
294 "service_worker/worker_based_background/events_on_installed"))
295 << message_;
296}
297
David Bertoni69982832019-02-13 21:24:21298// Tests chrome.storage APIs.
299IN_PROC_BROWSER_TEST_P(ServiceWorkerBasedBackgroundTest, StorageSetAndGet) {
300 ASSERT_TRUE(
301 RunExtensionTest("service_worker/worker_based_background/storage"))
302 << message_;
303}
304
David Bertoni0665c892019-02-14 00:27:26305// Tests chrome.storage.local and chrome.storage.local APIs.
306IN_PROC_BROWSER_TEST_P(ServiceWorkerBasedBackgroundTest, StorageNoPermissions) {
307 ASSERT_TRUE(RunExtensionTest(
308 "service_worker/worker_based_background/storage_no_permissions"))
309 << message_;
310}
311
David Bertoni46d698892019-02-26 00:29:10312// Tests chrome.tabs events.
313IN_PROC_BROWSER_TEST_P(ServiceWorkerBasedBackgroundTest, TabsEvents) {
314 ASSERT_TRUE(
315 RunExtensionTest("service_worker/worker_based_background/tabs_events"))
316 << message_;
317}
318
Istiaque Ahmed70f76ac2018-11-02 02:59:55319// Listens for |message| from extension Service Worker early so that tests can
320// wait for the message on startup (and not miss it).
321class ServiceWorkerWithEarlyMessageListenerTest
322 : public ServiceWorkerBasedBackgroundTest {
Istiaque Ahmedf70ab222018-10-02 03:08:24323 public:
Istiaque Ahmed70f76ac2018-11-02 02:59:55324 explicit ServiceWorkerWithEarlyMessageListenerTest(
325 const std::string& test_message)
326 : test_message_(test_message) {}
327 ~ServiceWorkerWithEarlyMessageListenerTest() override = default;
Istiaque Ahmedf70ab222018-10-02 03:08:24328
Istiaque Ahmed70f76ac2018-11-02 02:59:55329 bool WaitForMessage() { return listener_->WaitUntilSatisfied(); }
Istiaque Ahmedf70ab222018-10-02 03:08:24330
331 void CreatedBrowserMainParts(content::BrowserMainParts* main_parts) override {
332 // At this point, the notification service is initialized but the profile
333 // and extensions have not.
Istiaque Ahmed70f76ac2018-11-02 02:59:55334 listener_ =
335 std::make_unique<ExtensionTestMessageListener>(test_message_, false);
Istiaque Ahmedf70ab222018-10-02 03:08:24336 ServiceWorkerBasedBackgroundTest::CreatedBrowserMainParts(main_parts);
337 }
338
339 private:
Istiaque Ahmed70f76ac2018-11-02 02:59:55340 const std::string test_message_;
Istiaque Ahmedf70ab222018-10-02 03:08:24341 std::unique_ptr<ExtensionTestMessageListener> listener_;
342
Istiaque Ahmed70f76ac2018-11-02 02:59:55343 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerWithEarlyMessageListenerTest);
344};
345
346class ServiceWorkerOnStartupEventTest
347 : public ServiceWorkerWithEarlyMessageListenerTest {
348 public:
349 ServiceWorkerOnStartupEventTest()
350 : ServiceWorkerWithEarlyMessageListenerTest("onStartup event") {}
351 ~ServiceWorkerOnStartupEventTest() override = default;
352
353 private:
354 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerOnStartupEventTest);
Istiaque Ahmedf70ab222018-10-02 03:08:24355};
356
357// Tests "runtime.onStartup" for extension SW.
Istiaque Ahmed70f76ac2018-11-02 02:59:55358IN_PROC_BROWSER_TEST_P(ServiceWorkerOnStartupEventTest, PRE_Event) {
Istiaque Ahmedf70ab222018-10-02 03:08:24359 ASSERT_TRUE(RunExtensionTest(
360 "service_worker/worker_based_background/on_startup_event"))
361 << message_;
362}
363
Istiaque Ahmed70f76ac2018-11-02 02:59:55364IN_PROC_BROWSER_TEST_P(ServiceWorkerOnStartupEventTest, Event) {
365 EXPECT_TRUE(WaitForMessage());
366}
367
368class ServiceWorkerRegistrationAtStartupTest
369 : public ServiceWorkerWithEarlyMessageListenerTest,
370 public ServiceWorkerTaskQueue::TestObserver {
371 public:
372 ServiceWorkerRegistrationAtStartupTest()
373 : ServiceWorkerWithEarlyMessageListenerTest("WORKER_RUNNING") {
374 ServiceWorkerTaskQueue::SetObserverForTest(this);
375 }
376 ~ServiceWorkerRegistrationAtStartupTest() override {
377 ServiceWorkerTaskQueue::SetObserverForTest(nullptr);
378 }
379
380 // ServiceWorkerTaskQueue::TestObserver:
381 void OnActivateExtension(const ExtensionId& extension_id,
382 bool will_register_service_worker) override {
383 if (extension_id != kExtensionId)
384 return;
385
386 will_register_service_worker_ = will_register_service_worker;
387
388 extension_activated_ = true;
389 if (run_loop_)
390 run_loop_->Quit();
391 }
392
393 void WaitForOnActivateExtension() {
394 if (extension_activated_)
395 return;
396 run_loop_ = std::make_unique<base::RunLoop>();
397 run_loop_->Run();
398 }
399
400 bool WillRegisterServiceWorker() {
401 return will_register_service_worker_.value();
402 }
403
404 protected:
405 static const char kExtensionId[];
406
407 private:
408 bool extension_activated_ = false;
409 base::Optional<bool> will_register_service_worker_;
410 std::unique_ptr<base::RunLoop> run_loop_;
411
412 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerRegistrationAtStartupTest);
413};
414
415// Test extension id at
416// api_test/service_worker/worker_based_background/registration_at_startup/.
417const char ServiceWorkerRegistrationAtStartupTest::kExtensionId[] =
418 "gnchfmandajfaiajniicagenfmhdjila";
419
420// Tests that Service Worker registration for existing extension isn't issued
421// upon browser restart.
422// Regression test for https://crbug.com/889687.
423IN_PROC_BROWSER_TEST_P(ServiceWorkerRegistrationAtStartupTest,
424 PRE_ExtensionActivationDoesNotReregister) {
425 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
426 "service_worker/worker_based_background/registration_at_startup"));
427 ASSERT_TRUE(extension);
428 EXPECT_EQ(kExtensionId, extension->id());
429 // Wait for "WORKER_RUNNING" message from the Service Worker.
430 EXPECT_TRUE(WaitForMessage());
431 EXPECT_TRUE(WillRegisterServiceWorker());
432}
433
434IN_PROC_BROWSER_TEST_P(ServiceWorkerRegistrationAtStartupTest,
435 ExtensionActivationDoesNotReregister) {
436 // Since the extension has onStartup listener, the Service Worker will run on
437 // browser start and we'll see "WORKER_RUNNING" message from the worker.
438 EXPECT_TRUE(WaitForMessage());
439 // As the extension activated during first run on PRE_ step, it shouldn't
440 // re-register the Service Worker upon browser restart.
441 EXPECT_FALSE(WillRegisterServiceWorker());
Istiaque Ahmedf70ab222018-10-02 03:08:24442}
443
Istiaque Ahmeda14ec482018-08-25 01:02:18444// Class that dispatches an event to |extension_id| right after a
445// non-lazy listener to the event is added from the extension's Service Worker.
Istiaque Ahmed771aa8a22018-06-20 23:40:53446class EarlyWorkerMessageSender : public EventRouter::Observer {
447 public:
448 EarlyWorkerMessageSender(content::BrowserContext* browser_context,
Istiaque Ahmeda14ec482018-08-25 01:02:18449 const ExtensionId& extension_id,
450 std::unique_ptr<Event> event)
Istiaque Ahmed771aa8a22018-06-20 23:40:53451 : browser_context_(browser_context),
452 event_router_(EventRouter::EventRouter::Get(browser_context_)),
453 extension_id_(extension_id),
Istiaque Ahmeda14ec482018-08-25 01:02:18454 event_(std::move(event)),
Istiaque Ahmed771aa8a22018-06-20 23:40:53455 listener_("PASS", false) {
456 DCHECK(browser_context_);
457 listener_.set_failure_message("FAIL");
Istiaque Ahmeda14ec482018-08-25 01:02:18458 event_router_->RegisterObserver(this, event_->event_name);
Istiaque Ahmed771aa8a22018-06-20 23:40:53459 }
460
461 ~EarlyWorkerMessageSender() override {
462 event_router_->UnregisterObserver(this);
463 }
464
465 // EventRouter::Observer:
466 void OnListenerAdded(const EventListenerInfo& details) override {
Istiaque Ahmeda14ec482018-08-25 01:02:18467 if (!event_ || extension_id_ != details.extension_id ||
468 event_->event_name != details.event_name) {
Istiaque Ahmed771aa8a22018-06-20 23:40:53469 return;
Istiaque Ahmeda14ec482018-08-25 01:02:18470 }
471
Istiaque Ahmed771aa8a22018-06-20 23:40:53472 const bool is_lazy_listener = details.browser_context == nullptr;
473 if (is_lazy_listener) {
474 // Wait for the non-lazy listener as we want to exercise the code to
475 // dispatch the event right after the Service Worker registration is
476 // completing.
477 return;
478 }
Istiaque Ahmeda14ec482018-08-25 01:02:18479 DispatchEvent(std::move(event_));
Istiaque Ahmed771aa8a22018-06-20 23:40:53480 }
481
482 bool SendAndWait() { return listener_.WaitUntilSatisfied(); }
483
484 private:
485 static constexpr const char* const kTestOnMessageEventName = "test.onMessage";
486
Istiaque Ahmeda14ec482018-08-25 01:02:18487 void DispatchEvent(std::unique_ptr<Event> event) {
Istiaque Ahmed771aa8a22018-06-20 23:40:53488 EventRouter::Get(browser_context_)
489 ->DispatchEventToExtension(extension_id_, std::move(event));
490 }
491
492 content::BrowserContext* const browser_context_ = nullptr;
493 EventRouter* const event_router_ = nullptr;
494 const ExtensionId extension_id_;
Istiaque Ahmeda14ec482018-08-25 01:02:18495 std::unique_ptr<Event> event_;
Istiaque Ahmed771aa8a22018-06-20 23:40:53496 ExtensionTestMessageListener listener_;
Istiaque Ahmed771aa8a22018-06-20 23:40:53497
498 DISALLOW_COPY_AND_ASSIGN(EarlyWorkerMessageSender);
499};
500
501// Tests that extension event dispatch works correctly right after extension
502// installation registers its Service Worker.
503// Regression test for: https://crbug.com/850792.
504IN_PROC_BROWSER_TEST_P(ServiceWorkerBasedBackgroundTest, EarlyEventDispatch) {
505 const ExtensionId kId("pkplfbidichfdicaijlchgnapepdginl");
Istiaque Ahmeda14ec482018-08-25 01:02:18506
507 // Build "test.onMessage" event for dispatch.
508 auto event = std::make_unique<Event>(
509 events::FOR_TEST, extensions::api::test::OnMessage::kEventName,
Lei Zhang582ecd12019-02-13 20:28:54510 base::ListValue::From(base::JSONReader::ReadDeprecated(
Istiaque Ahmeda14ec482018-08-25 01:02:18511 R"([{"data": "hello", "lastMessage": true}])")),
512 profile());
513
514 EarlyWorkerMessageSender sender(profile(), kId, std::move(event));
Istiaque Ahmed771aa8a22018-06-20 23:40:53515 // pkplfbidichfdicaijlchgnapepdginl
516 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
517 "service_worker/worker_based_background/early_event_dispatch"));
518 CHECK(extension);
519 EXPECT_EQ(kId, extension->id());
520 EXPECT_TRUE(sender.SendAndWait());
521}
522
Istiaque Ahmeda14ec482018-08-25 01:02:18523// Tests that filtered events dispatches correctly right after a non-lazy
524// listener is registered for that event (and before the corresponding lazy
525// listener is registered).
526IN_PROC_BROWSER_TEST_P(ServiceWorkerBasedBackgroundTest,
527 EarlyFilteredEventDispatch) {
528 const ExtensionId kId("pkplfbidichfdicaijlchgnapepdginl");
529
530 // Add minimal details required to dispatch webNavigation.onCommitted event:
531 extensions::api::web_navigation::OnCommitted::Details details;
532 details.transition_type =
533 extensions::api::web_navigation::TRANSITION_TYPE_TYPED;
534
535 // Build a dummy onCommited event to dispatch.
536 auto on_committed_event = std::make_unique<Event>(
537 events::WEB_NAVIGATION_ON_COMMITTED, "webNavigation.onCommitted",
538 api::web_navigation::OnCommitted::Create(details), profile());
539 // The filter will match the listener filter registered from the extension.
540 EventFilteringInfo info;
541 info.url = GURL("http://foo.com/a.html");
542 on_committed_event->filter_info = info;
543
544 EarlyWorkerMessageSender sender(profile(), kId,
545 std::move(on_committed_event));
546
547 // pkplfbidichfdicaijlchgnapepdginl
548 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
549 "service_worker/worker_based_background/early_filtered_event_dispatch"));
550 ASSERT_TRUE(extension);
551 EXPECT_EQ(kId, extension->id());
552 EXPECT_TRUE(sender.SendAndWait());
553}
554
lazyboybd325ae2015-11-18 21:35:26555class ServiceWorkerBackgroundSyncTest : public ServiceWorkerTest {
556 public:
557 ServiceWorkerBackgroundSyncTest() {}
558 ~ServiceWorkerBackgroundSyncTest() override {}
559
560 void SetUpCommandLine(base::CommandLine* command_line) override {
561 // ServiceWorkerRegistration.sync requires experimental flag.
562 command_line->AppendSwitch(
Istiaque Ahmedea5ed5042017-09-25 19:00:16563 ::switches::kEnableExperimentalWebPlatformFeatures);
lazyboybd325ae2015-11-18 21:35:26564 ServiceWorkerTest::SetUpCommandLine(command_line);
565 }
566
567 void SetUp() override {
Robbie McElrathdb12d8e2018-09-18 21:20:40568 content::background_sync_test_util::SetIgnoreNetworkChanges(true);
lazyboybd325ae2015-11-18 21:35:26569 ServiceWorkerTest::SetUp();
570 }
571
572 private:
573 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerBackgroundSyncTest);
574};
575
lazyboy561b7de2015-11-19 19:27:30576class ServiceWorkerPushMessagingTest : public ServiceWorkerTest {
577 public:
578 ServiceWorkerPushMessagingTest()
Sylvain Defresne212b4b02018-10-11 16:32:05579 : scoped_testing_factory_installer_(
580 base::BindRepeating(&gcm::FakeGCMProfileService::Build)),
581 gcm_driver_(nullptr),
582 push_service_(nullptr) {}
583
lazyboy561b7de2015-11-19 19:27:30584 ~ServiceWorkerPushMessagingTest() override {}
585
586 void GrantNotificationPermissionForTest(const GURL& url) {
Peter Beverloodd4ef1e2018-06-21 15:41:04587 NotificationPermissionContext::UpdatePermission(profile(), url.GetOrigin(),
588 CONTENT_SETTING_ALLOW);
lazyboy561b7de2015-11-19 19:27:30589 }
590
591 PushMessagingAppIdentifier GetAppIdentifierForServiceWorkerRegistration(
avia2f4804a2015-12-24 23:11:13592 int64_t service_worker_registration_id,
lazyboy561b7de2015-11-19 19:27:30593 const GURL& origin) {
594 PushMessagingAppIdentifier app_identifier =
595 PushMessagingAppIdentifier::FindByServiceWorker(
596 profile(), origin, service_worker_registration_id);
597
598 EXPECT_FALSE(app_identifier.is_null());
599 return app_identifier;
600 }
601
602 // ExtensionApiTest overrides.
603 void SetUpCommandLine(base::CommandLine* command_line) override {
peter9de96272015-12-04 15:23:27604 command_line->AppendSwitch(
Istiaque Ahmedea5ed5042017-09-25 19:00:16605 ::switches::kEnableExperimentalWebPlatformFeatures);
lazyboy561b7de2015-11-19 19:27:30606 ServiceWorkerTest::SetUpCommandLine(command_line);
607 }
Tanja Gornak89128fd2018-09-18 08:49:34608
lazyboy561b7de2015-11-19 19:27:30609 void SetUpOnMainThread() override {
miguelg9b502862017-04-24 18:13:53610 NotificationDisplayServiceFactory::GetInstance()->SetTestingFactory(
Sylvain Defresne711ff6b2018-10-04 12:33:54611 profile(),
612 base::BindRepeating(&StubNotificationDisplayService::FactoryForTests));
miguelg9b502862017-04-24 18:13:53613
johnmea5045732016-09-08 17:23:29614 gcm::FakeGCMProfileService* gcm_service =
615 static_cast<gcm::FakeGCMProfileService*>(
Tanja Gornak89128fd2018-09-18 08:49:34616 gcm::GCMProfileServiceFactory::GetForProfile(profile()));
johnmea5045732016-09-08 17:23:29617 gcm_driver_ = static_cast<instance_id::FakeGCMDriverForInstanceID*>(
618 gcm_service->driver());
lazyboy561b7de2015-11-19 19:27:30619 push_service_ = PushMessagingServiceFactory::GetForProfile(profile());
620
621 ServiceWorkerTest::SetUpOnMainThread();
622 }
623
johnmea5045732016-09-08 17:23:29624 instance_id::FakeGCMDriverForInstanceID* gcm_driver() const {
625 return gcm_driver_;
626 }
lazyboy561b7de2015-11-19 19:27:30627 PushMessagingServiceImpl* push_service() const { return push_service_; }
628
629 private:
Sylvain Defresne212b4b02018-10-11 16:32:05630 gcm::GCMProfileServiceFactory::ScopedTestingFactoryInstaller
631 scoped_testing_factory_installer_;
632
johnmea5045732016-09-08 17:23:29633 instance_id::FakeGCMDriverForInstanceID* gcm_driver_;
lazyboy561b7de2015-11-19 19:27:30634 PushMessagingServiceImpl* push_service_;
635
636 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerPushMessagingTest);
637};
638
Istiaque Ahmed805f6a83b2017-10-05 01:23:26639class ServiceWorkerLazyBackgroundTest : public ServiceWorkerTest {
640 public:
Istiaque Ahmed7105f2a2017-10-07 01:11:59641 ServiceWorkerLazyBackgroundTest()
642 : ServiceWorkerTest(
643 // Extensions APIs from SW are only enabled on trunk.
644 // It is important to set the channel early so that this change is
645 // visible in renderers running with service workers (and no
646 // extension).
647 version_info::Channel::UNKNOWN) {}
Istiaque Ahmed805f6a83b2017-10-05 01:23:26648 ~ServiceWorkerLazyBackgroundTest() override {}
649
650 void SetUpCommandLine(base::CommandLine* command_line) override {
651 ServiceWorkerTest::SetUpCommandLine(command_line);
652 // Disable background network activity as it can suddenly bring the Lazy
653 // Background Page alive.
654 command_line->AppendSwitch(::switches::kDisableBackgroundNetworking);
655 command_line->AppendSwitch(::switches::kNoProxyServer);
656 }
657
658 void SetUpInProcessBrowserTestFixture() override {
659 ServiceWorkerTest::SetUpInProcessBrowserTestFixture();
660 // Set shorter delays to prevent test timeouts.
661 ProcessManager::SetEventPageIdleTimeForTesting(1);
662 ProcessManager::SetEventPageSuspendingTimeForTesting(1);
663 }
664
665 private:
666 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerLazyBackgroundTest);
667};
668
Istiaque Ahmedea5ed5042017-09-25 19:00:16669IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, RegisterSucceeds) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22670 StartTestFromBackgroundPage("register.js");
annekao38685502015-07-14 17:46:39671}
672
Istiaque Ahmedea5ed5042017-09-25 19:00:16673IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, UpdateRefreshesServiceWorker) {
Francois Doraye6fb2d02017-10-18 21:29:13674 base::ScopedAllowBlockingForTesting allow_blocking;
lazyboyc3e763a2015-12-09 23:09:58675 base::ScopedTempDir scoped_temp_dir;
676 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
677 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
678 .AppendASCII("update")
679 .AppendASCII("service_worker.pem");
vabr9142fe22016-09-08 13:19:22680 base::FilePath path_v1 =
681 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
682 .AppendASCII("update")
683 .AppendASCII("v1"),
684 scoped_temp_dir.GetPath().AppendASCII("v1.crx"),
685 pem_path, base::FilePath());
686 base::FilePath path_v2 =
687 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
688 .AppendASCII("update")
689 .AppendASCII("v2"),
690 scoped_temp_dir.GetPath().AppendASCII("v2.crx"),
691 pem_path, base::FilePath());
lazyboyc3e763a2015-12-09 23:09:58692 const char* kId = "hfaanndiiilofhfokeanhddpkfffchdi";
693
694 ExtensionTestMessageListener listener_v1("Pong from version 1", false);
695 listener_v1.set_failure_message("FAILURE_V1");
696 // Install version 1.0 of the extension.
697 ASSERT_TRUE(InstallExtension(path_v1, 1));
698 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
699 ->enabled_extensions()
700 .GetByID(kId));
701 EXPECT_TRUE(listener_v1.WaitUntilSatisfied());
702
703 ExtensionTestMessageListener listener_v2("Pong from version 2", false);
704 listener_v2.set_failure_message("FAILURE_V2");
705
706 // Update to version 2.0.
707 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
708 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
709 ->enabled_extensions()
710 .GetByID(kId));
711 EXPECT_TRUE(listener_v2.WaitUntilSatisfied());
712}
713
[email protected]2ef85d562017-09-15 18:41:52714// TODO(crbug.com/765736) Fix the test.
Istiaque Ahmedea5ed5042017-09-25 19:00:16715IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, DISABLED_UpdateWithoutSkipWaiting) {
Francois Doraye6fb2d02017-10-18 21:29:13716 base::ScopedAllowBlockingForTesting allow_blocking;
lazyboy22eddc712015-12-10 21:16:26717 base::ScopedTempDir scoped_temp_dir;
718 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
719 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
720 .AppendASCII("update_without_skip_waiting")
721 .AppendASCII("update_without_skip_waiting.pem");
vabr9142fe22016-09-08 13:19:22722 base::FilePath path_v1 =
723 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
724 .AppendASCII("update_without_skip_waiting")
725 .AppendASCII("v1"),
726 scoped_temp_dir.GetPath().AppendASCII("v1.crx"),
727 pem_path, base::FilePath());
728 base::FilePath path_v2 =
729 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
730 .AppendASCII("update_without_skip_waiting")
731 .AppendASCII("v2"),
732 scoped_temp_dir.GetPath().AppendASCII("v2.crx"),
733 pem_path, base::FilePath());
lazyboy22eddc712015-12-10 21:16:26734 const char* kId = "mhnnnflgagdakldgjpfcofkiocpdmogl";
735
736 // Install version 1.0 of the extension.
737 ASSERT_TRUE(InstallExtension(path_v1, 1));
738 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
739 ->enabled_extensions()
740 .GetByID(kId));
741 const Extension* extension = extensions::ExtensionRegistry::Get(profile())
742 ->enabled_extensions()
743 .GetByID(kId);
744
745 ExtensionTestMessageListener listener1("Pong from version 1", false);
746 listener1.set_failure_message("FAILURE");
747 content::WebContents* web_contents =
748 AddTab(browser(), extension->GetResourceURL("page.html"));
749 EXPECT_TRUE(listener1.WaitUntilSatisfied());
750
751 // Update to version 2.0.
752 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
753 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
754 ->enabled_extensions()
755 .GetByID(kId));
756 const Extension* extension_after_update =
757 extensions::ExtensionRegistry::Get(profile())
758 ->enabled_extensions()
759 .GetByID(kId);
760
761 // Service worker version 2 would be installed but it won't be controlling
762 // the extension page yet.
763 ExtensionTestMessageListener listener2("Pong from version 1", false);
764 listener2.set_failure_message("FAILURE");
765 web_contents =
766 AddTab(browser(), extension_after_update->GetResourceURL("page.html"));
767 EXPECT_TRUE(listener2.WaitUntilSatisfied());
768
769 // Navigate the tab away from the extension page so that no clients are
770 // using the service worker.
771 // Note that just closing the tab with WebContentsDestroyedWatcher doesn't
772 // seem to be enough because it returns too early.
773 WebContentsLoadStopObserver navigate_away_observer(web_contents);
774 web_contents->GetController().LoadURL(
775 GURL(url::kAboutBlankURL), content::Referrer(), ui::PAGE_TRANSITION_TYPED,
776 std::string());
777 navigate_away_observer.WaitForLoadStop();
778
779 // Now expect service worker version 2 to control the extension page.
780 ExtensionTestMessageListener listener3("Pong from version 2", false);
781 listener3.set_failure_message("FAILURE");
782 web_contents =
783 AddTab(browser(), extension_after_update->GetResourceURL("page.html"));
784 EXPECT_TRUE(listener3.WaitUntilSatisfied());
785}
786
Istiaque Ahmedea5ed5042017-09-25 19:00:16787IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, FetchArbitraryPaths) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22788 const Extension* extension = StartTestFromBackgroundPage("fetch.js");
annekao1db36fd2015-07-29 17:09:16789
kalman6f984ae2015-09-18 17:21:58790 // Open some arbirary paths. Their contents should be what the service worker
791 // responds with, which in this case is the path of the fetch.
792 EXPECT_EQ(
793 "Caught a fetch for /index.html",
794 NavigateAndExtractInnerText(extension->GetResourceURL("index.html")));
795 EXPECT_EQ("Caught a fetch for /path/to/other.html",
796 NavigateAndExtractInnerText(
797 extension->GetResourceURL("path/to/other.html")));
798 EXPECT_EQ("Caught a fetch for /some/text/file.txt",
799 NavigateAndExtractInnerText(
800 extension->GetResourceURL("some/text/file.txt")));
801 EXPECT_EQ("Caught a fetch for /no/file/extension",
802 NavigateAndExtractInnerText(
803 extension->GetResourceURL("no/file/extension")));
804 EXPECT_EQ("Caught a fetch for /",
805 NavigateAndExtractInnerText(extension->GetResourceURL("")));
annekao1db36fd2015-07-29 17:09:16806}
807
Kenichi Ishibashi773b82972018-08-30 07:02:03808IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
809 FetchExtensionResourceFromServiceWorker) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22810 const Extension* extension = StartTestFromBackgroundPage("fetch_from_sw.js");
Kenichi Ishibashi773b82972018-08-30 07:02:03811 ASSERT_TRUE(extension);
812
813 // The service worker in this test tries to load 'hello.txt' via fetch()
814 // and sends back the content of the file, which should be 'hello'.
815 const char* kScript = R"(
816 let channel = new MessageChannel();
817 test.waitForMessage(channel.port1).then(message => {
818 window.domAutomationController.send(message);
819 });
820 test.registeredServiceWorker.postMessage(
821 {port: channel.port2}, [channel.port2]);
822 )";
823 EXPECT_EQ("hello", ExecuteScriptInBackgroundPage(extension->id(), kScript));
824}
825
Kenichi Ishibashi09ee5e72018-11-27 07:12:38826// Tests that fetch() from service worker and network fallback
827// go through webRequest.onBeforeRequest API.
828IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, OnBeforeRequest) {
829 const Extension* extension = LoadExtensionWithFlags(
830 test_data_dir_.AppendASCII("service_worker/webrequest"), kFlagNone);
831 ASSERT_TRUE(extension);
832 ASSERT_TRUE(StartEmbeddedTestServer());
833
834 // Start a service worker and make it control the page.
835 GURL page_url = embedded_test_server()->GetURL(
836 "/extensions/api_test/service_worker/"
837 "webrequest/webpage.html");
838 content::WebContents* web_contents =
839 browser()->tab_strip_model()->GetActiveWebContents();
840 ui_test_utils::NavigateToURL(browser(), page_url);
841 content::WaitForLoadStop(web_contents);
842
843 std::string result;
844 ASSERT_TRUE(content::ExecuteScriptAndExtractString(web_contents,
845 "register();", &result));
846 EXPECT_EQ("ready", result);
847
848 // Initiate a fetch that the service worker doesn't intercept
849 // (network fallback).
850 result.clear();
851 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
852 web_contents, "doFetch('hello.txt?fallthrough');", &result));
853 EXPECT_EQ("hello", result);
854 EXPECT_EQ(
855 "/extensions/api_test/service_worker/webrequest/hello.txt?fallthrough",
856 ExecuteScriptInBackgroundPage(extension->id(), "getLastHookedPath()"));
857
858 // Initiate a fetch that results in calling fetch() in the service worker.
859 result.clear();
860 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
861 web_contents, "doFetch('hello.txt?respondWithFetch');", &result));
862 EXPECT_EQ("hello", result);
863 EXPECT_EQ(
864 "/extensions/api_test/service_worker/webrequest/"
865 "hello.txt?respondWithFetch",
866 ExecuteScriptInBackgroundPage(extension->id(), "getLastHookedPath()"));
867}
868
Istiaque Ahmedea5ed5042017-09-25 19:00:16869IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, SWServedBackgroundPageReceivesEvent) {
lazyboy52c3bcf2016-01-08 00:11:29870 const Extension* extension =
Istiaque Ahmed93ff7f42018-08-31 01:42:22871 StartTestFromBackgroundPage("replace_background.js");
lazyboy52c3bcf2016-01-08 00:11:29872 ExtensionHost* background_page =
873 process_manager()->GetBackgroundHostForExtension(extension->id());
874 ASSERT_TRUE(background_page);
875
876 // Close the background page and start it again so that the service worker
877 // will start controlling pages.
878 background_page->Close();
879 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
880 background_page = nullptr;
Peter Kasting341e1fb2018-02-24 00:03:01881 process_manager()->WakeEventPage(extension->id(), base::DoNothing());
lazyboy52c3bcf2016-01-08 00:11:29882 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
883
884 // Since the SW is now controlling the extension, the SW serves the background
885 // script. page.html sends a message to the background script and we verify
886 // that the SW served background script correctly receives the message/event.
887 ExtensionTestMessageListener listener("onMessage/SW BG.", false);
888 listener.set_failure_message("onMessage/original BG.");
889 content::WebContents* web_contents =
890 AddTab(browser(), extension->GetResourceURL("page.html"));
891 ASSERT_TRUE(web_contents);
892 EXPECT_TRUE(listener.WaitUntilSatisfied());
893}
894
Matt Falkenhagena612fc02018-05-30 00:35:39895IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, SWServedBackgroundPage) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22896 const Extension* extension = StartTestFromBackgroundPage("fetch.js");
annekao49241182015-08-18 17:14:01897
kalman6f984ae2015-09-18 17:21:58898 std::string kExpectedInnerText = "background.html contents for testing.";
annekao49241182015-08-18 17:14:01899
kalman6f984ae2015-09-18 17:21:58900 // Sanity check that the background page has the expected content.
901 ExtensionHost* background_page =
902 process_manager()->GetBackgroundHostForExtension(extension->id());
903 ASSERT_TRUE(background_page);
904 EXPECT_EQ(kExpectedInnerText,
905 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:01906
kalman6f984ae2015-09-18 17:21:58907 // Close the background page.
908 background_page->Close();
909 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
910 background_page = nullptr;
911
912 // Start it again.
Peter Kasting341e1fb2018-02-24 00:03:01913 process_manager()->WakeEventPage(extension->id(), base::DoNothing());
kalman6f984ae2015-09-18 17:21:58914 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
915
Matt Falkenhagena612fc02018-05-30 00:35:39916 // The service worker should get a fetch event for the background page.
kalman6f984ae2015-09-18 17:21:58917 background_page =
918 process_manager()->GetBackgroundHostForExtension(extension->id());
919 ASSERT_TRUE(background_page);
920 content::WaitForLoadStop(background_page->host_contents());
921
kalman6f984ae2015-09-18 17:21:58922 EXPECT_EQ("Caught a fetch for /background.html",
923 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:01924}
925
Istiaque Ahmedea5ed5042017-09-25 19:00:16926IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:58927 ServiceWorkerPostsMessageToBackgroundClient) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22928 const Extension* extension =
929 StartTestFromBackgroundPage("post_message_to_background_client.js");
annekao533482222015-08-21 23:23:53930
kalman6f984ae2015-09-18 17:21:58931 // The service worker in this test simply posts a message to the background
932 // client it receives from getBackgroundClient().
933 const char* kScript =
934 "var messagePromise = null;\n"
935 "if (test.lastMessageFromServiceWorker) {\n"
936 " messagePromise = Promise.resolve(test.lastMessageFromServiceWorker);\n"
937 "} else {\n"
938 " messagePromise = test.waitForMessage(navigator.serviceWorker);\n"
939 "}\n"
940 "messagePromise.then(function(message) {\n"
941 " window.domAutomationController.send(String(message == 'success'));\n"
942 "})\n";
943 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:53944}
945
Istiaque Ahmedea5ed5042017-09-25 19:00:16946IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:58947 BackgroundPagePostsMessageToServiceWorker) {
948 const Extension* extension =
Istiaque Ahmed93ff7f42018-08-31 01:42:22949 StartTestFromBackgroundPage("post_message_to_sw.js");
annekao533482222015-08-21 23:23:53950
kalman6f984ae2015-09-18 17:21:58951 // The service worker in this test waits for a message, then echoes it back
952 // by posting a message to the background page via getBackgroundClient().
953 const char* kScript =
954 "var mc = new MessageChannel();\n"
955 "test.waitForMessage(mc.port1).then(function(message) {\n"
956 " window.domAutomationController.send(String(message == 'hello'));\n"
957 "});\n"
958 "test.registeredServiceWorker.postMessage(\n"
959 " {message: 'hello', port: mc.port2}, [mc.port2])\n";
960 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:53961}
962
Istiaque Ahmedea5ed5042017-09-25 19:00:16963IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
rdevlin.croninf5863da2015-09-10 19:21:45964 ServiceWorkerSuspensionOnExtensionUnload) {
kalman6f984ae2015-09-18 17:21:58965 // For this test, only hold onto the extension's ID and URL + a function to
966 // get a resource URL, because we're going to be disabling and uninstalling
967 // it, which will invalidate the pointer.
968 std::string extension_id;
969 GURL extension_url;
970 {
Istiaque Ahmed93ff7f42018-08-31 01:42:22971 const Extension* extension = StartTestFromBackgroundPage("fetch.js");
kalman6f984ae2015-09-18 17:21:58972 extension_id = extension->id();
973 extension_url = extension->url();
974 }
975 auto get_resource_url = [&extension_url](const std::string& path) {
976 return Extension::GetResourceURL(extension_url, path);
977 };
rdevlin.croninf5863da2015-09-10 19:21:45978
kalman6f984ae2015-09-18 17:21:58979 // Fetch should route to the service worker.
980 EXPECT_EQ("Caught a fetch for /index.html",
981 NavigateAndExtractInnerText(get_resource_url("index.html")));
rdevlin.croninf5863da2015-09-10 19:21:45982
kalman6f984ae2015-09-18 17:21:58983 // Disable the extension. Opening the page should fail.
984 extension_service()->DisableExtension(extension_id,
Minh X. Nguyen45479012017-08-18 21:35:36985 disable_reason::DISABLE_USER_ACTION);
rdevlin.croninf5863da2015-09-10 19:21:45986 base::RunLoop().RunUntilIdle();
rdevlin.croninf5863da2015-09-10 19:21:45987
kalman6f984ae2015-09-18 17:21:58988 EXPECT_EQ(content::PAGE_TYPE_ERROR,
989 NavigateAndGetPageType(get_resource_url("index.html")));
990 EXPECT_EQ(content::PAGE_TYPE_ERROR,
991 NavigateAndGetPageType(get_resource_url("other.html")));
992
993 // Re-enable the extension. Opening pages should immediately start to succeed
994 // again.
rdevlin.croninf5863da2015-09-10 19:21:45995 extension_service()->EnableExtension(extension_id);
996 base::RunLoop().RunUntilIdle();
997
kalman6f984ae2015-09-18 17:21:58998 EXPECT_EQ("Caught a fetch for /index.html",
999 NavigateAndExtractInnerText(get_resource_url("index.html")));
1000 EXPECT_EQ("Caught a fetch for /other.html",
1001 NavigateAndExtractInnerText(get_resource_url("other.html")));
1002 EXPECT_EQ("Caught a fetch for /another.html",
1003 NavigateAndExtractInnerText(get_resource_url("another.html")));
rdevlin.croninf5863da2015-09-10 19:21:451004
kalman6f984ae2015-09-18 17:21:581005 // Uninstall the extension. Opening pages should fail again.
1006 base::string16 error;
1007 extension_service()->UninstallExtension(
Devlin Cronin218df7f2017-11-21 21:41:311008 extension_id, UninstallReason::UNINSTALL_REASON_FOR_TESTING, &error);
kalman6f984ae2015-09-18 17:21:581009 base::RunLoop().RunUntilIdle();
1010
1011 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1012 NavigateAndGetPageType(get_resource_url("index.html")));
1013 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1014 NavigateAndGetPageType(get_resource_url("other.html")));
1015 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1016 NavigateAndGetPageType(get_resource_url("anotherother.html")));
1017 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1018 NavigateAndGetPageType(get_resource_url("final.html")));
1019}
1020
Istiaque Ahmedea5ed5042017-09-25 19:00:161021IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, BackgroundPageIsWokenIfAsleep) {
Istiaque Ahmed93ff7f42018-08-31 01:42:221022 const Extension* extension = StartTestFromBackgroundPage("wake_on_fetch.js");
kalman6f984ae2015-09-18 17:21:581023
1024 // Navigate to special URLs that this test's service worker recognises, each
1025 // making a check then populating the response with either "true" or "false".
1026 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
1027 "background-client-is-awake")));
1028 EXPECT_EQ("true", NavigateAndExtractInnerText(
1029 extension->GetResourceURL("ping-background-client")));
1030 // Ping more than once for good measure.
1031 EXPECT_EQ("true", NavigateAndExtractInnerText(
1032 extension->GetResourceURL("ping-background-client")));
1033
1034 // Shut down the event page. The SW should detect that it's closed, but still
1035 // be able to ping it.
1036 ExtensionHost* background_page =
1037 process_manager()->GetBackgroundHostForExtension(extension->id());
1038 ASSERT_TRUE(background_page);
1039 background_page->Close();
1040 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
1041
1042 EXPECT_EQ("false", NavigateAndExtractInnerText(extension->GetResourceURL(
1043 "background-client-is-awake")));
1044 EXPECT_EQ("true", NavigateAndExtractInnerText(
1045 extension->GetResourceURL("ping-background-client")));
1046 EXPECT_EQ("true", NavigateAndExtractInnerText(
1047 extension->GetResourceURL("ping-background-client")));
1048 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
1049 "background-client-is-awake")));
1050}
1051
Istiaque Ahmedea5ed5042017-09-25 19:00:161052IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:581053 GetBackgroundClientFailsWithNoBackgroundPage) {
1054 // This extension doesn't have a background page, only a tab at page.html.
1055 // The service worker it registers tries to call getBackgroundClient() and
1056 // should fail.
1057 // Note that this also tests that service workers can be registered from tabs.
1058 EXPECT_TRUE(RunExtensionSubtest("service_worker/no_background", "page.html"));
rdevlin.croninf5863da2015-09-10 19:21:451059}
1060
Istiaque Ahmedea5ed5042017-09-25 19:00:161061IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, NotificationAPI) {
lazyboy6ddb7d62015-11-10 23:15:271062 EXPECT_TRUE(RunExtensionSubtest("service_worker/notifications/has_permission",
1063 "page.html"));
1064}
1065
Istiaque Ahmedea5ed5042017-09-25 19:00:161066IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, WebAccessibleResourcesFetch) {
lazyboyaea32c22016-01-04 21:37:071067 EXPECT_TRUE(RunExtensionSubtest(
1068 "service_worker/web_accessible_resources/fetch/", "page.html"));
1069}
1070
Istiaque Ahmed75ad1d92018-08-30 05:16:541071IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, TabsCreate) {
lazyboyee4adef2016-05-24 00:55:161072 // Extensions APIs from SW are only enabled on trunk.
1073 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1074 const Extension* extension = LoadExtensionWithFlags(
1075 test_data_dir_.AppendASCII("service_worker/tabs_create"), kFlagNone);
1076 ASSERT_TRUE(extension);
1077 ui_test_utils::NavigateToURL(browser(),
1078 extension->GetResourceURL("page.html"));
1079 content::WebContents* web_contents =
1080 browser()->tab_strip_model()->GetActiveWebContents();
1081
1082 int starting_tab_count = browser()->tab_strip_model()->count();
1083 std::string result;
1084 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
1085 web_contents, "window.runServiceWorker()", &result));
1086 ASSERT_EQ("chrome.tabs.create callback", result);
1087 EXPECT_EQ(starting_tab_count + 1, browser()->tab_strip_model()->count());
1088
1089 // Check extension shutdown path.
1090 UnloadExtension(extension->id());
1091 EXPECT_EQ(starting_tab_count, browser()->tab_strip_model()->count());
1092}
1093
Istiaque Ahmedea5ed5042017-09-25 19:00:161094IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, Events) {
lazyboye7847242017-06-07 23:29:181095 // Extensions APIs from SW are only enabled on trunk.
1096 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1097 const Extension* extension = LoadExtensionWithFlags(
1098 test_data_dir_.AppendASCII("service_worker/events"), kFlagNone);
1099 ASSERT_TRUE(extension);
1100 ui_test_utils::NavigateToURL(browser(),
1101 extension->GetResourceURL("page.html"));
1102 content::WebContents* web_contents =
1103 browser()->tab_strip_model()->GetActiveWebContents();
1104 std::string result;
1105 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
1106 web_contents, "window.runEventTest()", &result));
1107 ASSERT_EQ("chrome.tabs.onUpdated callback", result);
1108}
1109
Istiaque Ahmedea5ed5042017-09-25 19:00:161110IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, EventsToStoppedWorker) {
lazyboy63b994a2017-06-30 21:20:231111 // Extensions APIs from SW are only enabled on trunk.
1112 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1113 const Extension* extension = LoadExtensionWithFlags(
1114 test_data_dir_.AppendASCII("service_worker/events_to_stopped_worker"),
1115 kFlagNone);
1116 ASSERT_TRUE(extension);
1117 ui_test_utils::NavigateToURL(browser(),
1118 extension->GetResourceURL("page.html"));
1119 content::WebContents* web_contents =
1120 browser()->tab_strip_model()->GetActiveWebContents();
1121 {
1122 std::string result;
1123 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
1124 web_contents, "window.runServiceWorker()", &result));
1125 ASSERT_EQ("ready", result);
1126
1127 base::RunLoop run_loop;
1128 content::StoragePartition* storage_partition =
1129 content::BrowserContext::GetDefaultStoragePartition(
1130 browser()->profile());
Zhuoyu Qian2266251f2018-10-13 02:59:001131 content::StopServiceWorkerForScope(
lazyboy63b994a2017-06-30 21:20:231132 storage_partition->GetServiceWorkerContext(),
1133 // The service worker is registered at the top level scope.
1134 extension->url(), run_loop.QuitClosure());
1135 run_loop.Run();
1136 }
1137
1138 std::string result;
1139 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
1140 web_contents, "window.createTabThenUpdate()", &result));
1141 ASSERT_EQ("chrome.tabs.onUpdated callback", result);
1142}
1143
Istiaque Ahmed805f6a83b2017-10-05 01:23:261144// Tests that events to service worker arrives correctly event if the owner
1145// extension of the worker is not running.
1146IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest,
Istiaque Ahmedb8e24bdb2018-09-13 15:17:251147 EventsToStoppedExtension) {
Istiaque Ahmed805f6a83b2017-10-05 01:23:261148 LazyBackgroundObserver lazy_observer;
1149 ResultCatcher catcher;
1150 const Extension* extension = LoadExtensionWithFlags(
1151 test_data_dir_.AppendASCII("service_worker/events_to_stopped_extension"),
1152 kFlagNone);
1153 ASSERT_TRUE(extension);
1154 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
1155
1156 ProcessManager* pm = ProcessManager::Get(browser()->profile());
1157 EXPECT_GT(pm->GetLazyKeepaliveCount(extension), 0);
David Bertoni3e1e9fa2018-08-29 20:39:301158 EXPECT_FALSE(pm->GetLazyKeepaliveActivities(extension).empty());
Istiaque Ahmed805f6a83b2017-10-05 01:23:261159
1160 // |extension|'s background page opens a tab to its resource.
1161 content::WebContents* extension_web_contents =
1162 browser()->tab_strip_model()->GetActiveWebContents();
1163 EXPECT_TRUE(content::WaitForLoadStop(extension_web_contents));
1164 EXPECT_EQ(extension->GetResourceURL("page.html").spec(),
1165 extension_web_contents->GetURL().spec());
1166 {
1167 // Let the service worker start and register a listener to
1168 // chrome.tabs.onCreated event.
1169 ExtensionTestMessageListener add_listener_done("listener-added", false);
1170 content::ExecuteScriptAsync(extension_web_contents,
1171 "window.runServiceWorkerAsync()");
1172 EXPECT_TRUE(add_listener_done.WaitUntilSatisfied());
1173
1174 base::RunLoop run_loop;
1175 content::StoragePartition* storage_partition =
1176 content::BrowserContext::GetDefaultStoragePartition(
1177 browser()->profile());
Zhuoyu Qian2266251f2018-10-13 02:59:001178 content::StopServiceWorkerForScope(
Istiaque Ahmed805f6a83b2017-10-05 01:23:261179 storage_partition->GetServiceWorkerContext(),
1180 // The service worker is registered at the top level scope.
1181 extension->url(), run_loop.QuitClosure());
1182 run_loop.Run();
1183 }
1184
1185 // Close the tab to |extension|'s resource. This will also close the
1186 // extension's event page.
1187 browser()->tab_strip_model()->CloseWebContentsAt(
1188 browser()->tab_strip_model()->active_index(), TabStripModel::CLOSE_NONE);
1189 lazy_observer.Wait();
1190
1191 // At this point both the extension worker and extension event page is not
1192 // running. Since the worker registered a listener for tabs.onCreated, it
1193 // will be started to dispatch the event once we create a tab.
1194 ExtensionTestMessageListener newtab_listener("hello-newtab", false);
1195 newtab_listener.set_failure_message("WRONG_NEWTAB");
1196 content::WebContents* new_web_contents =
Istiaque Ahmed7105f2a2017-10-07 01:11:591197 AddTab(browser(), GURL(url::kAboutBlankURL));
1198 EXPECT_TRUE(new_web_contents);
1199 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
1200}
1201
1202// Tests that events to service worker correctly after browser restart.
1203// This test is similar to EventsToStoppedExtension, except that the event
1204// delivery is verified after a browser restart.
1205IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest,
1206 PRE_EventsAfterRestart) {
1207 LazyBackgroundObserver lazy_observer;
1208 ResultCatcher catcher;
1209 const Extension* extension = LoadExtensionWithFlags(
1210 test_data_dir_.AppendASCII("service_worker/events_to_stopped_extension"),
1211 kFlagNone);
1212 ASSERT_TRUE(extension);
1213 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
1214
1215 ProcessManager* pm = ProcessManager::Get(browser()->profile());
1216 EXPECT_GT(pm->GetLazyKeepaliveCount(extension), 0);
David Bertoni3e1e9fa2018-08-29 20:39:301217 EXPECT_FALSE(pm->GetLazyKeepaliveActivities(extension).empty());
Istiaque Ahmed7105f2a2017-10-07 01:11:591218
1219 // |extension|'s background page opens a tab to its resource.
1220 content::WebContents* extension_web_contents =
1221 browser()->tab_strip_model()->GetActiveWebContents();
1222 EXPECT_TRUE(content::WaitForLoadStop(extension_web_contents));
1223 EXPECT_EQ(extension->GetResourceURL("page.html").spec(),
1224 extension_web_contents->GetURL().spec());
1225 {
1226 // Let the service worker start and register a listener to
1227 // chrome.tabs.onCreated event.
1228 ExtensionTestMessageListener add_listener_done("listener-added", false);
1229 content::ExecuteScriptAsync(extension_web_contents,
1230 "window.runServiceWorkerAsync()");
1231 EXPECT_TRUE(add_listener_done.WaitUntilSatisfied());
1232
1233 base::RunLoop run_loop;
1234 content::StoragePartition* storage_partition =
1235 content::BrowserContext::GetDefaultStoragePartition(
1236 browser()->profile());
Zhuoyu Qian2266251f2018-10-13 02:59:001237 content::StopServiceWorkerForScope(
Istiaque Ahmed7105f2a2017-10-07 01:11:591238 storage_partition->GetServiceWorkerContext(),
1239 // The service worker is registered at the top level scope.
1240 extension->url(), run_loop.QuitClosure());
1241 run_loop.Run();
1242 }
1243
1244 // Close the tab to |extension|'s resource. This will also close the
1245 // extension's event page.
1246 browser()->tab_strip_model()->CloseWebContentsAt(
1247 browser()->tab_strip_model()->active_index(), TabStripModel::CLOSE_NONE);
1248 lazy_observer.Wait();
1249}
1250
Istiaque Ahmed99aa96d2018-09-13 23:22:081251IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest, EventsAfterRestart) {
Istiaque Ahmed7105f2a2017-10-07 01:11:591252 ExtensionTestMessageListener newtab_listener("hello-newtab", false);
1253 content::WebContents* new_web_contents =
1254 AddTab(browser(), GURL(url::kAboutBlankURL));
Istiaque Ahmed805f6a83b2017-10-05 01:23:261255 EXPECT_TRUE(new_web_contents);
1256 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
1257}
1258
lazyboy4c82177a2016-10-18 00:04:091259// Tests that worker ref count increments while extension API function is
1260// active.
Istiaque Ahmedea5ed5042017-09-25 19:00:161261IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, WorkerRefCount) {
lazyboy4c82177a2016-10-18 00:04:091262 // Extensions APIs from SW are only enabled on trunk.
1263 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1264 const Extension* extension = LoadExtensionWithFlags(
1265 test_data_dir_.AppendASCII("service_worker/api_worker_ref_count"),
1266 kFlagNone);
1267 ASSERT_TRUE(extension);
1268 ui_test_utils::NavigateToURL(browser(),
1269 extension->GetResourceURL("page.html"));
1270 content::WebContents* web_contents =
1271 browser()->tab_strip_model()->GetActiveWebContents();
1272
1273 ExtensionTestMessageListener worker_start_listener("WORKER STARTED", false);
1274 worker_start_listener.set_failure_message("FAILURE");
1275 ASSERT_TRUE(
1276 content::ExecuteScript(web_contents, "window.runServiceWorker()"));
1277 ASSERT_TRUE(worker_start_listener.WaitUntilSatisfied());
1278
1279 // Service worker should have no pending requests because it hasn't peformed
1280 // any extension API request yet.
1281 EXPECT_EQ(0u, GetWorkerRefCount(extension->url()));
1282
1283 ExtensionTestMessageListener worker_listener("CHECK_REF_COUNT", true);
1284 worker_listener.set_failure_message("FAILURE");
1285 ASSERT_TRUE(content::ExecuteScript(web_contents, "window.testSendMessage()"));
1286 ASSERT_TRUE(worker_listener.WaitUntilSatisfied());
1287
1288 // Service worker should have exactly one pending request because
1289 // chrome.test.sendMessage() API call is in-flight.
1290 EXPECT_EQ(1u, GetWorkerRefCount(extension->url()));
1291
1292 // Peform another extension API request while one is ongoing.
1293 {
1294 ExtensionTestMessageListener listener("CHECK_REF_COUNT", true);
1295 listener.set_failure_message("FAILURE");
1296 ASSERT_TRUE(
1297 content::ExecuteScript(web_contents, "window.testSendMessage()"));
1298 ASSERT_TRUE(listener.WaitUntilSatisfied());
1299
1300 // Service worker currently has two extension API requests in-flight.
1301 EXPECT_EQ(2u, GetWorkerRefCount(extension->url()));
1302 // Finish executing the nested chrome.test.sendMessage() first.
1303 listener.Reply("Hello world");
1304 }
1305
Istiaque Ahmedb57c9752017-08-20 19:08:571306 ExtensionTestMessageListener worker_completion_listener("SUCCESS_FROM_WORKER",
1307 false);
lazyboy4c82177a2016-10-18 00:04:091308 // Finish executing chrome.test.sendMessage().
1309 worker_listener.Reply("Hello world");
Istiaque Ahmedb57c9752017-08-20 19:08:571310 EXPECT_TRUE(worker_completion_listener.WaitUntilSatisfied());
1311
1312 // The following block makes sure we have received all the IPCs related to
1313 // ref-count from the worker.
1314 {
1315 // The following roundtrip:
1316 // browser->extension->worker->extension->browser
1317 // will ensure that the worker sent the relevant ref count IPCs.
1318 std::string result;
1319 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1320 web_contents, "window.roundtripToWorker();", &result));
1321 EXPECT_EQ("roundtrip-succeeded", result);
1322
1323 // Ensure IO thread IPCs run.
Gabriel Charette01507a22017-09-27 21:30:081324 content::RunAllTasksUntilIdle();
Istiaque Ahmedb57c9752017-08-20 19:08:571325 }
lazyboy4c82177a2016-10-18 00:04:091326
1327 // The ref count should drop to 0.
1328 EXPECT_EQ(0u, GetWorkerRefCount(extension->url()));
1329}
1330
lazyboyaea32c22016-01-04 21:37:071331// This test loads a web page that has an iframe pointing to a
1332// chrome-extension:// URL. The URL is listed in the extension's
1333// web_accessible_resources. Initially the iframe is served from the extension's
1334// resource file. After verifying that, we register a Service Worker that
1335// controls the extension. Further requests to the same resource as before
1336// should now be served by the Service Worker.
1337// This test also verifies that if the requested resource exists in the manifest
1338// but is not present in the extension directory, the Service Worker can still
1339// serve the resource file.
Istiaque Ahmedea5ed5042017-09-25 19:00:161340IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, WebAccessibleResourcesIframeSrc) {
lazyboyaea32c22016-01-04 21:37:071341 const Extension* extension = LoadExtensionWithFlags(
1342 test_data_dir_.AppendASCII(
1343 "service_worker/web_accessible_resources/iframe_src"),
1344 kFlagNone);
1345 ASSERT_TRUE(extension);
1346 ASSERT_TRUE(StartEmbeddedTestServer());
falkenad185092016-06-16 06:10:021347
1348 // Service workers can only control secure contexts
1349 // (https://w3c.github.io/webappsec-secure-contexts/). For documents, this
1350 // typically means the document must have a secure origin AND all its ancestor
1351 // frames must have documents with secure origins. However, extension pages
1352 // are considered secure, even if they have an ancestor document that is an
1353 // insecure context (see GetSchemesBypassingSecureContextCheckWhitelist). So
1354 // extension service workers must be able to control an extension page
1355 // embedded in an insecure context. To test this, set up an insecure
1356 // (non-localhost, non-https) URL for the web page. This page will create
1357 // iframes that load extension pages that must be controllable by service
1358 // worker.
falkenad185092016-06-16 06:10:021359 GURL page_url =
1360 embedded_test_server()->GetURL("a.com",
1361 "/extensions/api_test/service_worker/"
1362 "web_accessible_resources/webpage.html");
1363 EXPECT_FALSE(content::IsOriginSecure(page_url));
lazyboyaea32c22016-01-04 21:37:071364
1365 content::WebContents* web_contents = AddTab(browser(), page_url);
1366 std::string result;
1367 // webpage.html will create an iframe pointing to a resource from |extension|.
1368 // Expect the resource to be served by the extension.
1369 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1370 web_contents, base::StringPrintf("window.testIframe('%s', 'iframe.html')",
1371 extension->id().c_str()),
1372 &result));
1373 EXPECT_EQ("FROM_EXTENSION_RESOURCE", result);
1374
1375 ExtensionTestMessageListener service_worker_ready_listener("SW_READY", false);
1376 EXPECT_TRUE(ExecuteScriptInBackgroundPageNoWait(
1377 extension->id(), "window.registerServiceWorker()"));
1378 EXPECT_TRUE(service_worker_ready_listener.WaitUntilSatisfied());
1379
1380 result.clear();
1381 // webpage.html will create another iframe pointing to a resource from
1382 // |extension| as before. But this time, the resource should be be served
1383 // from the Service Worker.
1384 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1385 web_contents, base::StringPrintf("window.testIframe('%s', 'iframe.html')",
1386 extension->id().c_str()),
1387 &result));
1388 EXPECT_EQ("FROM_SW_RESOURCE", result);
1389
1390 result.clear();
1391 // webpage.html will create yet another iframe pointing to a resource that
1392 // exists in the extension manifest's web_accessible_resources, but is not
1393 // present in the extension directory. Expect the resources of the iframe to
1394 // be served by the Service Worker.
1395 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1396 web_contents,
1397 base::StringPrintf("window.testIframe('%s', 'iframe_non_existent.html')",
1398 extension->id().c_str()),
1399 &result));
1400 EXPECT_EQ("FROM_SW_RESOURCE", result);
1401}
1402
Istiaque Ahmedea5ed5042017-09-25 19:00:161403IN_PROC_BROWSER_TEST_P(ServiceWorkerBackgroundSyncTest, Sync) {
lazyboybd325ae2015-11-18 21:35:261404 const Extension* extension = LoadExtensionWithFlags(
1405 test_data_dir_.AppendASCII("service_worker/sync"), kFlagNone);
1406 ASSERT_TRUE(extension);
1407 ui_test_utils::NavigateToURL(browser(),
1408 extension->GetResourceURL("page.html"));
1409 content::WebContents* web_contents =
1410 browser()->tab_strip_model()->GetActiveWebContents();
1411
1412 // Prevent firing by going offline.
1413 content::background_sync_test_util::SetOnline(web_contents, false);
1414
1415 ExtensionTestMessageListener sync_listener("SYNC: send-chats", false);
1416 sync_listener.set_failure_message("FAIL");
1417
1418 std::string result;
1419 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
1420 web_contents, "window.runServiceWorker()", &result));
1421 ASSERT_EQ("SERVICE_WORKER_READY", result);
1422
1423 EXPECT_FALSE(sync_listener.was_satisfied());
1424 // Resume firing by going online.
1425 content::background_sync_test_util::SetOnline(web_contents, true);
1426 EXPECT_TRUE(sync_listener.WaitUntilSatisfied());
1427}
1428
Istiaque Ahmedea5ed5042017-09-25 19:00:161429IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
horo1eeddde2015-11-19 05:59:251430 FetchFromContentScriptShouldNotGoToServiceWorkerOfPage) {
1431 ASSERT_TRUE(StartEmbeddedTestServer());
1432 GURL page_url = embedded_test_server()->GetURL(
1433 "/extensions/api_test/service_worker/content_script_fetch/"
1434 "controlled_page/index.html");
1435 content::WebContents* tab =
1436 browser()->tab_strip_model()->GetActiveWebContents();
1437 ui_test_utils::NavigateToURL(browser(), page_url);
1438 content::WaitForLoadStop(tab);
1439
1440 std::string value;
1441 ASSERT_TRUE(
1442 content::ExecuteScriptAndExtractString(tab, "register();", &value));
1443 EXPECT_EQ("SW controlled", value);
1444
1445 ASSERT_TRUE(RunExtensionTest("service_worker/content_script_fetch"))
1446 << message_;
1447}
1448
Istiaque Ahmedea5ed5042017-09-25 19:00:161449IN_PROC_BROWSER_TEST_P(ServiceWorkerPushMessagingTest, OnPush) {
lazyboy561b7de2015-11-19 19:27:301450 const Extension* extension = LoadExtensionWithFlags(
1451 test_data_dir_.AppendASCII("service_worker/push_messaging"), kFlagNone);
1452 ASSERT_TRUE(extension);
1453 GURL extension_url = extension->url();
1454
Peter Beverloodd4ef1e2018-06-21 15:41:041455 GrantNotificationPermissionForTest(extension_url);
lazyboy561b7de2015-11-19 19:27:301456
1457 GURL url = extension->GetResourceURL("page.html");
1458 ui_test_utils::NavigateToURL(browser(), url);
1459
1460 content::WebContents* web_contents =
1461 browser()->tab_strip_model()->GetActiveWebContents();
1462
1463 // Start the ServiceWorker.
1464 ExtensionTestMessageListener ready_listener("SERVICE_WORKER_READY", false);
1465 ready_listener.set_failure_message("SERVICE_WORKER_FAILURE");
1466 const char* kScript = "window.runServiceWorker()";
1467 EXPECT_TRUE(content::ExecuteScript(web_contents->GetMainFrame(), kScript));
1468 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
1469
1470 PushMessagingAppIdentifier app_identifier =
1471 GetAppIdentifierForServiceWorkerRegistration(0LL, extension_url);
johnmea5045732016-09-08 17:23:291472 ASSERT_EQ(app_identifier.app_id(), gcm_driver()->last_gettoken_app_id());
1473 EXPECT_EQ("1234567890", gcm_driver()->last_gettoken_authorized_entity());
lazyboy561b7de2015-11-19 19:27:301474
lazyboyd429e2582016-05-20 20:18:521475 base::RunLoop run_loop;
lazyboy561b7de2015-11-19 19:27:301476 // Send a push message via gcm and expect the ServiceWorker to receive it.
1477 ExtensionTestMessageListener push_message_listener("OK", false);
1478 push_message_listener.set_failure_message("FAIL");
1479 gcm::IncomingMessage message;
1480 message.sender_id = "1234567890";
1481 message.raw_data = "testdata";
1482 message.decrypted = true;
lazyboyd429e2582016-05-20 20:18:521483 push_service()->SetMessageCallbackForTesting(run_loop.QuitClosure());
lazyboy561b7de2015-11-19 19:27:301484 push_service()->OnMessage(app_identifier.app_id(), message);
1485 EXPECT_TRUE(push_message_listener.WaitUntilSatisfied());
lazyboyd429e2582016-05-20 20:18:521486 run_loop.Run(); // Wait until the message is handled by push service.
lazyboy561b7de2015-11-19 19:27:301487}
1488
Istiaque Ahmedea5ed5042017-09-25 19:00:161489IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, FilteredEvents) {
Istiaque Ahmed9d1666182017-09-21 23:58:181490 // Extensions APIs from SW are only enabled on trunk.
1491 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1492 ASSERT_TRUE(RunExtensionTest("service_worker/filtered_events"));
1493}
1494
Rob Wue89b90032018-02-16 19:46:081495IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, MimeHandlerView) {
1496 ASSERT_TRUE(RunExtensionTest("service_worker/mime_handler_view"));
1497}
1498
Istiaque Ahmed9ce21b32017-10-10 20:43:181499IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest,
1500 PRE_FilteredEventsAfterRestart) {
1501 LazyBackgroundObserver lazy_observer;
1502 ResultCatcher catcher;
1503 const Extension* extension = LoadExtensionWithFlags(
1504 test_data_dir_.AppendASCII(
1505 "service_worker/filtered_events_after_restart"),
1506 kFlagNone);
1507 ASSERT_TRUE(extension);
1508 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
1509
1510 // |extension|'s background page opens a tab to its resource.
1511 content::WebContents* extension_web_contents =
1512 browser()->tab_strip_model()->GetActiveWebContents();
1513 EXPECT_TRUE(content::WaitForLoadStop(extension_web_contents));
1514 EXPECT_EQ(extension->GetResourceURL("page.html").spec(),
1515 extension_web_contents->GetURL().spec());
1516 {
1517 // Let the service worker start and register a filtered listener to
1518 // chrome.webNavigation.onCommitted event.
1519 ExtensionTestMessageListener add_listener_done("listener-added", false);
1520 add_listener_done.set_failure_message("FAILURE");
1521 content::ExecuteScriptAsync(extension_web_contents,
1522 "window.runServiceWorkerAsync()");
1523 EXPECT_TRUE(add_listener_done.WaitUntilSatisfied());
1524
1525 base::RunLoop run_loop;
1526 content::StoragePartition* storage_partition =
1527 content::BrowserContext::GetDefaultStoragePartition(
1528 browser()->profile());
Zhuoyu Qian2266251f2018-10-13 02:59:001529 content::StopServiceWorkerForScope(
Istiaque Ahmed9ce21b32017-10-10 20:43:181530 storage_partition->GetServiceWorkerContext(),
1531 // The service worker is registered at the top level scope.
1532 extension->url(), run_loop.QuitClosure());
1533 run_loop.Run();
1534 }
1535
1536 // Close the tab to |extension|'s resource. This will also close the
1537 // extension's event page.
1538 browser()->tab_strip_model()->CloseWebContentsAt(
1539 browser()->tab_strip_model()->active_index(), TabStripModel::CLOSE_NONE);
1540 lazy_observer.Wait();
1541}
1542
1543IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest,
Istiaque Ahmedf5712522018-09-20 03:35:471544 FilteredEventsAfterRestart) {
Istiaque Ahmed9ce21b32017-10-10 20:43:181545 // Create a tab to a.html, expect it to navigate to b.html. The service worker
1546 // will see two webNavigation.onCommitted events.
1547 ASSERT_TRUE(StartEmbeddedTestServer());
1548 GURL page_url = embedded_test_server()->GetURL(
1549 "/extensions/api_test/service_worker/filtered_events_after_restart/"
1550 "a.html");
1551 ExtensionTestMessageListener worker_filtered_event_listener(
1552 "PASS_FROM_WORKER", false);
1553 worker_filtered_event_listener.set_failure_message("FAIL_FROM_WORKER");
1554 content::WebContents* web_contents = AddTab(browser(), page_url);
1555 EXPECT_TRUE(web_contents);
1556 EXPECT_TRUE(worker_filtered_event_listener.WaitUntilSatisfied());
1557}
1558
Istiaque Ahmedea5ed5042017-09-25 19:00:161559// Run with both native and JS-based bindings. This ensures that both stable
1560// (JS) and experimental (native) phases work correctly with worker scripts
1561// while we launch native bindings to stable.
Victor Costan4a060e82019-01-28 18:25:341562INSTANTIATE_TEST_SUITE_P(ServiceWorkerTestWithNativeBindings,
1563 ServiceWorkerTest,
1564 ::testing::Values(NATIVE_BINDINGS));
1565INSTANTIATE_TEST_SUITE_P(ServiceWorkerTestWithJSBindings,
1566 ServiceWorkerTest,
1567 ::testing::Values(JAVASCRIPT_BINDINGS));
1568INSTANTIATE_TEST_SUITE_P(ServiceWorkerBackgroundSyncTestWithNativeBindings,
1569 ServiceWorkerBackgroundSyncTest,
1570 ::testing::Values(NATIVE_BINDINGS));
1571INSTANTIATE_TEST_SUITE_P(ServiceWorkerBackgroundSyncTestWithJSBindings,
1572 ServiceWorkerBackgroundSyncTest,
1573 ::testing::Values(JAVASCRIPT_BINDINGS));
1574INSTANTIATE_TEST_SUITE_P(ServiceWorkerPushMessagingTestWithNativeBindings,
1575 ServiceWorkerPushMessagingTest,
1576 ::testing::Values(NATIVE_BINDINGS));
1577INSTANTIATE_TEST_SUITE_P(ServiceWorkerPushMessagingTestWithJSBindings,
1578 ServiceWorkerPushMessagingTest,
1579 ::testing::Values(JAVASCRIPT_BINDINGS));
1580INSTANTIATE_TEST_SUITE_P(ServiceWorkerLazyBackgroundTestWithNativeBindings,
1581 ServiceWorkerLazyBackgroundTest,
1582 ::testing::Values(NATIVE_BINDINGS));
1583INSTANTIATE_TEST_SUITE_P(ServiceWorkerLazyBackgroundTestWithJSBindings,
1584 ServiceWorkerLazyBackgroundTest,
1585 ::testing::Values(JAVASCRIPT_BINDINGS));
1586INSTANTIATE_TEST_SUITE_P(ServiceWorkerTestWithNativeBindings,
1587 ServiceWorkerBasedBackgroundTest,
1588 ::testing::Values(NATIVE_BINDINGS));
1589INSTANTIATE_TEST_SUITE_P(ServiceWorkerTestWithJSBindings,
1590 ServiceWorkerBasedBackgroundTest,
1591 ::testing::Values(JAVASCRIPT_BINDINGS));
1592INSTANTIATE_TEST_SUITE_P(ServiceWorkerTestWithNativeBindings,
1593 ServiceWorkerOnStartupEventTest,
1594 ::testing::Values(NATIVE_BINDINGS));
1595INSTANTIATE_TEST_SUITE_P(ServiceWorkerTestWithJSBindings,
1596 ServiceWorkerOnStartupEventTest,
1597 ::testing::Values(JAVASCRIPT_BINDINGS));
1598INSTANTIATE_TEST_SUITE_P(ServiceWorkerTestWithNativeBindings,
1599 ServiceWorkerRegistrationAtStartupTest,
1600 ::testing::Values(NATIVE_BINDINGS));
1601INSTANTIATE_TEST_SUITE_P(ServiceWorkerTestWithJSBindings,
1602 ServiceWorkerRegistrationAtStartupTest,
1603 ::testing::Values(JAVASCRIPT_BINDINGS));
Istiaque Ahmedea5ed5042017-09-25 19:00:161604
annekao38685502015-07-14 17:46:391605} // namespace extensions