blob: 96a78420c5c8567cdadbc75cb711739555704bd0 [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"
Elly Fong-Jones4a4f21d2018-05-30 15:04:1629#include "chrome/browser/ui/views_mode_controller.h"
Trent Apted4267b942017-10-27 03:25:3630#include "chrome/common/chrome_switches.h"
Istiaque Ahmeda14ec482018-08-25 01:02:1831#include "chrome/common/extensions/api/web_navigation.h"
rdevlin.croninf5863da2015-09-10 19:21:4532#include "chrome/test/base/ui_test_utils.h"
timloh9a180ad2017-02-20 07:15:2333#include "components/content_settings/core/common/content_settings_types.h"
Peter Beverloo34139462018-04-10 14:18:0634#include "components/gcm_driver/fake_gcm_profile_service.h"
johnmea5045732016-09-08 17:23:2935#include "components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h"
sdefresne9fb67692015-08-03 18:48:2236#include "components/version_info/version_info.h"
kalman6f984ae2015-09-18 17:21:5837#include "content/public/browser/navigation_controller.h"
rdevlin.croninf5863da2015-09-10 19:21:4538#include "content/public/browser/navigation_entry.h"
lazyboy4c82177a2016-10-18 00:04:0939#include "content/public/browser/service_worker_context.h"
40#include "content/public/browser/storage_partition.h"
kalman6f984ae2015-09-18 17:21:5841#include "content/public/browser/web_contents.h"
lazyboybd325ae2015-11-18 21:35:2642#include "content/public/common/content_switches.h"
falkenad185092016-06-16 06:10:0243#include "content/public/common/origin_util.h"
kalman6f984ae2015-09-18 17:21:5844#include "content/public/common/page_type.h"
lazyboybd325ae2015-11-18 21:35:2645#include "content/public/test/background_sync_test_util.h"
annekao1db36fd2015-07-29 17:09:1646#include "content/public/test/browser_test_utils.h"
lazyboy63b994a2017-06-30 21:20:2347#include "content/public/test/service_worker_test_helpers.h"
Istiaque Ahmed771aa8a22018-06-20 23:40:5348#include "extensions/browser/event_router.h"
kalman6f984ae2015-09-18 17:21:5849#include "extensions/browser/extension_host.h"
lazyboyc3e763a2015-12-09 23:09:5850#include "extensions/browser/extension_registry.h"
kalman6f984ae2015-09-18 17:21:5851#include "extensions/browser/process_manager.h"
Istiaque Ahmed70f76ac2018-11-02 02:59:5552#include "extensions/browser/service_worker_task_queue.h"
Istiaque Ahmeda14ec482018-08-25 01:02:1853#include "extensions/common/api/test.h"
Devlin Cronina3fe3d602017-11-22 04:47:4354#include "extensions/common/extension_features.h"
Istiaque Ahmed771aa8a22018-06-20 23:40:5355#include "extensions/common/value_builder.h"
kalman6f984ae2015-09-18 17:21:5856#include "extensions/test/background_page_watcher.h"
annekao38685502015-07-14 17:46:3957#include "extensions/test/extension_test_message_listener.h"
Istiaque Ahmed805f6a83b2017-10-05 01:23:2658#include "extensions/test/result_catcher.h"
falkenad185092016-06-16 06:10:0259#include "net/dns/mock_host_resolver.h"
horo1eeddde2015-11-19 05:59:2560#include "net/test/embedded_test_server/embedded_test_server.h"
lazyboy63b994a2017-06-30 21:20:2361#include "url/url_constants.h"
annekao38685502015-07-14 17:46:3962
63namespace extensions {
64
kalman6f984ae2015-09-18 17:21:5865namespace {
66
lazyboy22eddc712015-12-10 21:16:2667// Returns the newly added WebContents.
68content::WebContents* AddTab(Browser* browser, const GURL& url) {
69 int starting_tab_count = browser->tab_strip_model()->count();
70 ui_test_utils::NavigateToURLWithDisposition(
nick3b04f322016-08-31 19:29:1971 browser, url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
lazyboy22eddc712015-12-10 21:16:2672 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
73 int tab_count = browser->tab_strip_model()->count();
74 EXPECT_EQ(starting_tab_count + 1, tab_count);
75 return browser->tab_strip_model()->GetActiveWebContents();
76}
77
Istiaque Ahmedea5ed5042017-09-25 19:00:1678enum BindingsType { NATIVE_BINDINGS, JAVASCRIPT_BINDINGS };
79
lazyboy22eddc712015-12-10 21:16:2680class WebContentsLoadStopObserver : content::WebContentsObserver {
81 public:
82 explicit WebContentsLoadStopObserver(content::WebContents* web_contents)
83 : content::WebContentsObserver(web_contents),
84 load_stop_observed_(false) {}
85
86 void WaitForLoadStop() {
87 if (load_stop_observed_)
88 return;
89 message_loop_runner_ = new content::MessageLoopRunner;
90 message_loop_runner_->Run();
91 }
92
93 private:
94 void DidStopLoading() override {
95 load_stop_observed_ = true;
96 if (message_loop_runner_)
97 message_loop_runner_->Quit();
98 }
99
100 bool load_stop_observed_;
101 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
102
103 DISALLOW_COPY_AND_ASSIGN(WebContentsLoadStopObserver);
104};
105
Elly Fong-Jones4a4f21d2018-05-30 15:04:16106bool IsMacViewsMode() {
107// Some tests are flaky on Mac: <https://crbug.com/845979>. This helper function
108// is used to skip them.
109#if defined(OS_MACOSX)
110 return !views_mode_controller::IsViewsBrowserCocoa();
111#else
112 return false;
113#endif
114}
115
kalman6f984ae2015-09-18 17:21:58116} // namespace
117
Istiaque Ahmedea5ed5042017-09-25 19:00:16118class ServiceWorkerTest : public ExtensionApiTest,
119 public ::testing::WithParamInterface<BindingsType> {
annekao38685502015-07-14 17:46:39120 public:
lazyboy20167c22016-05-18 00:59:30121 ServiceWorkerTest() : current_channel_(version_info::Channel::STABLE) {}
Istiaque Ahmed7105f2a2017-10-07 01:11:59122 explicit ServiceWorkerTest(version_info::Channel channel)
123 : current_channel_(channel) {}
annekao38685502015-07-14 17:46:39124
125 ~ServiceWorkerTest() override {}
126
Devlin Cronina3fe3d602017-11-22 04:47:43127 void SetUp() override {
128 if (GetParam() == NATIVE_BINDINGS) {
Mostyn Bramley-Mooreb6a37c62018-09-04 21:43:35129 scoped_feature_list_.InitAndEnableFeature(
130 extensions_features::kNativeCrxBindings);
Devlin Cronina3fe3d602017-11-22 04:47:43131 } else {
132 DCHECK_EQ(JAVASCRIPT_BINDINGS, GetParam());
Mostyn Bramley-Mooreb6a37c62018-09-04 21:43:35133 scoped_feature_list_.InitAndDisableFeature(
134 extensions_features::kNativeCrxBindings);
Devlin Cronina3fe3d602017-11-22 04:47:43135 }
136 ExtensionApiTest::SetUp();
137 }
138
jam1a5b5582017-05-01 16:50:10139 void SetUpOnMainThread() override {
140 ExtensionApiTest::SetUpOnMainThread();
141 host_resolver()->AddRule("a.com", "127.0.0.1");
142 }
143
kalman6f984ae2015-09-18 17:21:58144 protected:
145 // Returns the ProcessManager for the test's profile.
146 ProcessManager* process_manager() { return ProcessManager::Get(profile()); }
147
148 // Starts running a test from the background page test extension.
149 //
150 // This registers a service worker with |script_name|, and fetches the
151 // registration result.
Istiaque Ahmed93ff7f42018-08-31 01:42:22152 const Extension* StartTestFromBackgroundPage(const char* script_name) {
Istiaque Ahmed6475f542018-08-28 04:20:21153 ExtensionTestMessageListener ready_listener("ready", false);
kalman6f984ae2015-09-18 17:21:58154 const Extension* extension =
155 LoadExtension(test_data_dir_.AppendASCII("service_worker/background"));
156 CHECK(extension);
Istiaque Ahmed6475f542018-08-28 04:20:21157 CHECK(ready_listener.WaitUntilSatisfied());
158
kalman6f984ae2015-09-18 17:21:58159 ExtensionHost* background_host =
160 process_manager()->GetBackgroundHostForExtension(extension->id());
161 CHECK(background_host);
Istiaque Ahmed6475f542018-08-28 04:20:21162
kalman6f984ae2015-09-18 17:21:58163 std::string error;
164 CHECK(content::ExecuteScriptAndExtractString(
165 background_host->host_contents(),
166 base::StringPrintf("test.registerServiceWorker('%s')", script_name),
167 &error));
Istiaque Ahmed93ff7f42018-08-31 01:42:22168 if (!error.empty())
kalman6f984ae2015-09-18 17:21:58169 ADD_FAILURE() << "Got unexpected error " << error;
170 return extension;
171 }
172
173 // Navigates the browser to a new tab at |url|, waits for it to load, then
174 // returns it.
175 content::WebContents* Navigate(const GURL& url) {
176 ui_test_utils::NavigateToURLWithDisposition(
nick3b04f322016-08-31 19:29:19177 browser(), url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
kalman6f984ae2015-09-18 17:21:58178 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
179 content::WebContents* web_contents =
180 browser()->tab_strip_model()->GetActiveWebContents();
181 content::WaitForLoadStop(web_contents);
182 return web_contents;
183 }
184
185 // Navigates the browser to |url| and returns the new tab's page type.
186 content::PageType NavigateAndGetPageType(const GURL& url) {
clamy1d7a4112018-06-15 15:47:16187 return Navigate(url)
188 ->GetController()
189 .GetLastCommittedEntry()
190 ->GetPageType();
kalman6f984ae2015-09-18 17:21:58191 }
192
193 // Extracts the innerText from |contents|.
194 std::string ExtractInnerText(content::WebContents* contents) {
195 std::string inner_text;
196 if (!content::ExecuteScriptAndExtractString(
197 contents,
198 "window.domAutomationController.send(document.body.innerText)",
199 &inner_text)) {
200 ADD_FAILURE() << "Failed to get inner text for "
201 << contents->GetVisibleURL();
202 }
203 return inner_text;
204 }
205
206 // Navigates the browser to |url|, then returns the innerText of the new
207 // tab's WebContents' main frame.
208 std::string NavigateAndExtractInnerText(const GURL& url) {
209 return ExtractInnerText(Navigate(url));
210 }
211
lazyboy4c82177a2016-10-18 00:04:09212 size_t GetWorkerRefCount(const GURL& origin) {
213 content::ServiceWorkerContext* sw_context =
214 content::BrowserContext::GetDefaultStoragePartition(
215 browser()->profile())
216 ->GetServiceWorkerContext();
217 base::RunLoop run_loop;
218 size_t ref_count = 0;
219 auto set_ref_count = [](size_t* ref_count, base::RunLoop* run_loop,
220 size_t external_request_count) {
221 *ref_count = external_request_count;
222 run_loop->Quit();
223 };
224 sw_context->CountExternalRequestsForTest(
Matt Falkenhagenc5cb4282017-09-07 08:43:42225 origin, base::BindOnce(set_ref_count, &ref_count, &run_loop));
lazyboy4c82177a2016-10-18 00:04:09226 run_loop.Run();
227 return ref_count;
228 }
229
annekao38685502015-07-14 17:46:39230 private:
lazyboy20167c22016-05-18 00:59:30231 // Sets the channel to "stable".
232 // Not useful after we've opened extension Service Workers to stable
233 // channel.
234 // TODO(lazyboy): Remove this when ExtensionServiceWorkersEnabled() is
235 // removed.
annekao38685502015-07-14 17:46:39236 ScopedCurrentChannel current_channel_;
kalman6f984ae2015-09-18 17:21:58237
Devlin Cronina3fe3d602017-11-22 04:47:43238 base::test::ScopedFeatureList scoped_feature_list_;
239
annekao38685502015-07-14 17:46:39240 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerTest);
241};
242
Istiaque Ahmedccb444022018-06-19 02:11:12243class ServiceWorkerBasedBackgroundTest : public ServiceWorkerTest {
244 public:
245 ServiceWorkerBasedBackgroundTest()
246 : ServiceWorkerTest(
247 // Extensions APIs from SW are only enabled on trunk.
248 // It is important to set the channel early so that this change is
249 // visible in renderers running with service workers (and no
250 // extension).
251 version_info::Channel::UNKNOWN) {}
252 ~ServiceWorkerBasedBackgroundTest() override {}
253
254 void SetUpOnMainThread() override {
255 host_resolver()->AddRule("*", "127.0.0.1");
256 ASSERT_TRUE(embedded_test_server()->Start());
257 ServiceWorkerTest::SetUpOnMainThread();
258 }
259
260 private:
261 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerBasedBackgroundTest);
262};
263
264// Tests that Service Worker based background pages can be loaded and they can
265// receive extension events.
266// The extension is installed and loaded during this step and it registers
267// an event listener for tabs.onCreated event. The step also verifies that tab
268// creation correctly fires the listener.
269IN_PROC_BROWSER_TEST_P(ServiceWorkerBasedBackgroundTest, PRE_Basic) {
270 ExtensionTestMessageListener newtab_listener("CREATED", false);
271 newtab_listener.set_failure_message("CREATE_FAILED");
272 ExtensionTestMessageListener worker_listener("WORKER_RUNNING", false);
273 worker_listener.set_failure_message("NON_WORKER_SCOPE");
274 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
275 "service_worker/worker_based_background/basic"));
276 ASSERT_TRUE(extension);
277 const ExtensionId extension_id = extension->id();
278 EXPECT_TRUE(worker_listener.WaitUntilSatisfied());
279
280 const GURL url = embedded_test_server()->GetURL("/extensions/test_file.html");
281 content::WebContents* new_web_contents = AddTab(browser(), url);
282 EXPECT_TRUE(new_web_contents);
283 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
284
285 // Service Worker extension does not have ExtensionHost.
286 EXPECT_FALSE(process_manager()->GetBackgroundHostForExtension(extension_id));
287}
288
289// After browser restarts, this test step ensures that opening a tab fires
290// tabs.onCreated event listener to the extension without explicitly loading the
291// extension. This is because the extension registered a listener before browser
292// restarted in PRE_Basic.
Istiaque Ahmedad376e6b2018-09-13 22:48:25293IN_PROC_BROWSER_TEST_P(ServiceWorkerBasedBackgroundTest, Basic) {
Istiaque Ahmedccb444022018-06-19 02:11:12294 ExtensionTestMessageListener newtab_listener("CREATED", false);
295 newtab_listener.set_failure_message("CREATE_FAILED");
296 const GURL url = embedded_test_server()->GetURL("/extensions/test_file.html");
297 content::WebContents* new_web_contents = AddTab(browser(), url);
298 EXPECT_TRUE(new_web_contents);
299 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
300}
301
Istiaque Ahmedbf08f952018-10-02 01:22:04302// Tests chrome.runtime.onInstalled fires for extension service workers.
303IN_PROC_BROWSER_TEST_P(ServiceWorkerBasedBackgroundTest, OnInstalledEvent) {
304 ASSERT_TRUE(RunExtensionTest(
305 "service_worker/worker_based_background/events_on_installed"))
306 << message_;
307}
308
Istiaque Ahmed70f76ac2018-11-02 02:59:55309// Listens for |message| from extension Service Worker early so that tests can
310// wait for the message on startup (and not miss it).
311class ServiceWorkerWithEarlyMessageListenerTest
312 : public ServiceWorkerBasedBackgroundTest {
Istiaque Ahmedf70ab222018-10-02 03:08:24313 public:
Istiaque Ahmed70f76ac2018-11-02 02:59:55314 explicit ServiceWorkerWithEarlyMessageListenerTest(
315 const std::string& test_message)
316 : test_message_(test_message) {}
317 ~ServiceWorkerWithEarlyMessageListenerTest() override = default;
Istiaque Ahmedf70ab222018-10-02 03:08:24318
Istiaque Ahmed70f76ac2018-11-02 02:59:55319 bool WaitForMessage() { return listener_->WaitUntilSatisfied(); }
Istiaque Ahmedf70ab222018-10-02 03:08:24320
321 void CreatedBrowserMainParts(content::BrowserMainParts* main_parts) override {
322 // At this point, the notification service is initialized but the profile
323 // and extensions have not.
Istiaque Ahmed70f76ac2018-11-02 02:59:55324 listener_ =
325 std::make_unique<ExtensionTestMessageListener>(test_message_, false);
Istiaque Ahmedf70ab222018-10-02 03:08:24326 ServiceWorkerBasedBackgroundTest::CreatedBrowserMainParts(main_parts);
327 }
328
329 private:
Istiaque Ahmed70f76ac2018-11-02 02:59:55330 const std::string test_message_;
Istiaque Ahmedf70ab222018-10-02 03:08:24331 std::unique_ptr<ExtensionTestMessageListener> listener_;
332
Istiaque Ahmed70f76ac2018-11-02 02:59:55333 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerWithEarlyMessageListenerTest);
334};
335
336class ServiceWorkerOnStartupEventTest
337 : public ServiceWorkerWithEarlyMessageListenerTest {
338 public:
339 ServiceWorkerOnStartupEventTest()
340 : ServiceWorkerWithEarlyMessageListenerTest("onStartup event") {}
341 ~ServiceWorkerOnStartupEventTest() override = default;
342
343 private:
344 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerOnStartupEventTest);
Istiaque Ahmedf70ab222018-10-02 03:08:24345};
346
347// Tests "runtime.onStartup" for extension SW.
Istiaque Ahmed70f76ac2018-11-02 02:59:55348IN_PROC_BROWSER_TEST_P(ServiceWorkerOnStartupEventTest, PRE_Event) {
Istiaque Ahmedf70ab222018-10-02 03:08:24349 ASSERT_TRUE(RunExtensionTest(
350 "service_worker/worker_based_background/on_startup_event"))
351 << message_;
352}
353
Istiaque Ahmed70f76ac2018-11-02 02:59:55354IN_PROC_BROWSER_TEST_P(ServiceWorkerOnStartupEventTest, Event) {
355 EXPECT_TRUE(WaitForMessage());
356}
357
358class ServiceWorkerRegistrationAtStartupTest
359 : public ServiceWorkerWithEarlyMessageListenerTest,
360 public ServiceWorkerTaskQueue::TestObserver {
361 public:
362 ServiceWorkerRegistrationAtStartupTest()
363 : ServiceWorkerWithEarlyMessageListenerTest("WORKER_RUNNING") {
364 ServiceWorkerTaskQueue::SetObserverForTest(this);
365 }
366 ~ServiceWorkerRegistrationAtStartupTest() override {
367 ServiceWorkerTaskQueue::SetObserverForTest(nullptr);
368 }
369
370 // ServiceWorkerTaskQueue::TestObserver:
371 void OnActivateExtension(const ExtensionId& extension_id,
372 bool will_register_service_worker) override {
373 if (extension_id != kExtensionId)
374 return;
375
376 will_register_service_worker_ = will_register_service_worker;
377
378 extension_activated_ = true;
379 if (run_loop_)
380 run_loop_->Quit();
381 }
382
383 void WaitForOnActivateExtension() {
384 if (extension_activated_)
385 return;
386 run_loop_ = std::make_unique<base::RunLoop>();
387 run_loop_->Run();
388 }
389
390 bool WillRegisterServiceWorker() {
391 return will_register_service_worker_.value();
392 }
393
394 protected:
395 static const char kExtensionId[];
396
397 private:
398 bool extension_activated_ = false;
399 base::Optional<bool> will_register_service_worker_;
400 std::unique_ptr<base::RunLoop> run_loop_;
401
402 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerRegistrationAtStartupTest);
403};
404
405// Test extension id at
406// api_test/service_worker/worker_based_background/registration_at_startup/.
407const char ServiceWorkerRegistrationAtStartupTest::kExtensionId[] =
408 "gnchfmandajfaiajniicagenfmhdjila";
409
410// Tests that Service Worker registration for existing extension isn't issued
411// upon browser restart.
412// Regression test for https://crbug.com/889687.
413IN_PROC_BROWSER_TEST_P(ServiceWorkerRegistrationAtStartupTest,
414 PRE_ExtensionActivationDoesNotReregister) {
415 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
416 "service_worker/worker_based_background/registration_at_startup"));
417 ASSERT_TRUE(extension);
418 EXPECT_EQ(kExtensionId, extension->id());
419 // Wait for "WORKER_RUNNING" message from the Service Worker.
420 EXPECT_TRUE(WaitForMessage());
421 EXPECT_TRUE(WillRegisterServiceWorker());
422}
423
424IN_PROC_BROWSER_TEST_P(ServiceWorkerRegistrationAtStartupTest,
425 ExtensionActivationDoesNotReregister) {
426 // Since the extension has onStartup listener, the Service Worker will run on
427 // browser start and we'll see "WORKER_RUNNING" message from the worker.
428 EXPECT_TRUE(WaitForMessage());
429 // As the extension activated during first run on PRE_ step, it shouldn't
430 // re-register the Service Worker upon browser restart.
431 EXPECT_FALSE(WillRegisterServiceWorker());
Istiaque Ahmedf70ab222018-10-02 03:08:24432}
433
Istiaque Ahmeda14ec482018-08-25 01:02:18434// Class that dispatches an event to |extension_id| right after a
435// non-lazy listener to the event is added from the extension's Service Worker.
Istiaque Ahmed771aa8a22018-06-20 23:40:53436class EarlyWorkerMessageSender : public EventRouter::Observer {
437 public:
438 EarlyWorkerMessageSender(content::BrowserContext* browser_context,
Istiaque Ahmeda14ec482018-08-25 01:02:18439 const ExtensionId& extension_id,
440 std::unique_ptr<Event> event)
Istiaque Ahmed771aa8a22018-06-20 23:40:53441 : browser_context_(browser_context),
442 event_router_(EventRouter::EventRouter::Get(browser_context_)),
443 extension_id_(extension_id),
Istiaque Ahmeda14ec482018-08-25 01:02:18444 event_(std::move(event)),
Istiaque Ahmed771aa8a22018-06-20 23:40:53445 listener_("PASS", false) {
446 DCHECK(browser_context_);
447 listener_.set_failure_message("FAIL");
Istiaque Ahmeda14ec482018-08-25 01:02:18448 event_router_->RegisterObserver(this, event_->event_name);
Istiaque Ahmed771aa8a22018-06-20 23:40:53449 }
450
451 ~EarlyWorkerMessageSender() override {
452 event_router_->UnregisterObserver(this);
453 }
454
455 // EventRouter::Observer:
456 void OnListenerAdded(const EventListenerInfo& details) override {
Istiaque Ahmeda14ec482018-08-25 01:02:18457 if (!event_ || extension_id_ != details.extension_id ||
458 event_->event_name != details.event_name) {
Istiaque Ahmed771aa8a22018-06-20 23:40:53459 return;
Istiaque Ahmeda14ec482018-08-25 01:02:18460 }
461
Istiaque Ahmed771aa8a22018-06-20 23:40:53462 const bool is_lazy_listener = details.browser_context == nullptr;
463 if (is_lazy_listener) {
464 // Wait for the non-lazy listener as we want to exercise the code to
465 // dispatch the event right after the Service Worker registration is
466 // completing.
467 return;
468 }
Istiaque Ahmeda14ec482018-08-25 01:02:18469 DispatchEvent(std::move(event_));
Istiaque Ahmed771aa8a22018-06-20 23:40:53470 }
471
472 bool SendAndWait() { return listener_.WaitUntilSatisfied(); }
473
474 private:
475 static constexpr const char* const kTestOnMessageEventName = "test.onMessage";
476
Istiaque Ahmeda14ec482018-08-25 01:02:18477 void DispatchEvent(std::unique_ptr<Event> event) {
Istiaque Ahmed771aa8a22018-06-20 23:40:53478 EventRouter::Get(browser_context_)
479 ->DispatchEventToExtension(extension_id_, std::move(event));
480 }
481
482 content::BrowserContext* const browser_context_ = nullptr;
483 EventRouter* const event_router_ = nullptr;
484 const ExtensionId extension_id_;
Istiaque Ahmeda14ec482018-08-25 01:02:18485 std::unique_ptr<Event> event_;
Istiaque Ahmed771aa8a22018-06-20 23:40:53486 ExtensionTestMessageListener listener_;
Istiaque Ahmed771aa8a22018-06-20 23:40:53487
488 DISALLOW_COPY_AND_ASSIGN(EarlyWorkerMessageSender);
489};
490
491// Tests that extension event dispatch works correctly right after extension
492// installation registers its Service Worker.
493// Regression test for: https://crbug.com/850792.
494IN_PROC_BROWSER_TEST_P(ServiceWorkerBasedBackgroundTest, EarlyEventDispatch) {
495 const ExtensionId kId("pkplfbidichfdicaijlchgnapepdginl");
Istiaque Ahmeda14ec482018-08-25 01:02:18496
497 // Build "test.onMessage" event for dispatch.
498 auto event = std::make_unique<Event>(
499 events::FOR_TEST, extensions::api::test::OnMessage::kEventName,
500 base::ListValue::From(base::JSONReader::Read(
501 R"([{"data": "hello", "lastMessage": true}])")),
502 profile());
503
504 EarlyWorkerMessageSender sender(profile(), kId, std::move(event));
Istiaque Ahmed771aa8a22018-06-20 23:40:53505 // pkplfbidichfdicaijlchgnapepdginl
506 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
507 "service_worker/worker_based_background/early_event_dispatch"));
508 CHECK(extension);
509 EXPECT_EQ(kId, extension->id());
510 EXPECT_TRUE(sender.SendAndWait());
511}
512
Istiaque Ahmeda14ec482018-08-25 01:02:18513// Tests that filtered events dispatches correctly right after a non-lazy
514// listener is registered for that event (and before the corresponding lazy
515// listener is registered).
516IN_PROC_BROWSER_TEST_P(ServiceWorkerBasedBackgroundTest,
517 EarlyFilteredEventDispatch) {
518 const ExtensionId kId("pkplfbidichfdicaijlchgnapepdginl");
519
520 // Add minimal details required to dispatch webNavigation.onCommitted event:
521 extensions::api::web_navigation::OnCommitted::Details details;
522 details.transition_type =
523 extensions::api::web_navigation::TRANSITION_TYPE_TYPED;
524
525 // Build a dummy onCommited event to dispatch.
526 auto on_committed_event = std::make_unique<Event>(
527 events::WEB_NAVIGATION_ON_COMMITTED, "webNavigation.onCommitted",
528 api::web_navigation::OnCommitted::Create(details), profile());
529 // The filter will match the listener filter registered from the extension.
530 EventFilteringInfo info;
531 info.url = GURL("http://foo.com/a.html");
532 on_committed_event->filter_info = info;
533
534 EarlyWorkerMessageSender sender(profile(), kId,
535 std::move(on_committed_event));
536
537 // pkplfbidichfdicaijlchgnapepdginl
538 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
539 "service_worker/worker_based_background/early_filtered_event_dispatch"));
540 ASSERT_TRUE(extension);
541 EXPECT_EQ(kId, extension->id());
542 EXPECT_TRUE(sender.SendAndWait());
543}
544
lazyboybd325ae2015-11-18 21:35:26545class ServiceWorkerBackgroundSyncTest : public ServiceWorkerTest {
546 public:
547 ServiceWorkerBackgroundSyncTest() {}
548 ~ServiceWorkerBackgroundSyncTest() override {}
549
550 void SetUpCommandLine(base::CommandLine* command_line) override {
551 // ServiceWorkerRegistration.sync requires experimental flag.
552 command_line->AppendSwitch(
Istiaque Ahmedea5ed5042017-09-25 19:00:16553 ::switches::kEnableExperimentalWebPlatformFeatures);
lazyboybd325ae2015-11-18 21:35:26554 ServiceWorkerTest::SetUpCommandLine(command_line);
555 }
556
557 void SetUp() override {
Robbie McElrathdb12d8e2018-09-18 21:20:40558 content::background_sync_test_util::SetIgnoreNetworkChanges(true);
lazyboybd325ae2015-11-18 21:35:26559 ServiceWorkerTest::SetUp();
560 }
561
562 private:
563 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerBackgroundSyncTest);
564};
565
lazyboy561b7de2015-11-19 19:27:30566class ServiceWorkerPushMessagingTest : public ServiceWorkerTest {
567 public:
568 ServiceWorkerPushMessagingTest()
Sylvain Defresne212b4b02018-10-11 16:32:05569 : scoped_testing_factory_installer_(
570 base::BindRepeating(&gcm::FakeGCMProfileService::Build)),
571 gcm_driver_(nullptr),
572 push_service_(nullptr) {}
573
lazyboy561b7de2015-11-19 19:27:30574 ~ServiceWorkerPushMessagingTest() override {}
575
576 void GrantNotificationPermissionForTest(const GURL& url) {
Peter Beverloodd4ef1e2018-06-21 15:41:04577 NotificationPermissionContext::UpdatePermission(profile(), url.GetOrigin(),
578 CONTENT_SETTING_ALLOW);
lazyboy561b7de2015-11-19 19:27:30579 }
580
581 PushMessagingAppIdentifier GetAppIdentifierForServiceWorkerRegistration(
avia2f4804a2015-12-24 23:11:13582 int64_t service_worker_registration_id,
lazyboy561b7de2015-11-19 19:27:30583 const GURL& origin) {
584 PushMessagingAppIdentifier app_identifier =
585 PushMessagingAppIdentifier::FindByServiceWorker(
586 profile(), origin, service_worker_registration_id);
587
588 EXPECT_FALSE(app_identifier.is_null());
589 return app_identifier;
590 }
591
592 // ExtensionApiTest overrides.
593 void SetUpCommandLine(base::CommandLine* command_line) override {
peter9de96272015-12-04 15:23:27594 command_line->AppendSwitch(
Istiaque Ahmedea5ed5042017-09-25 19:00:16595 ::switches::kEnableExperimentalWebPlatformFeatures);
lazyboy561b7de2015-11-19 19:27:30596 ServiceWorkerTest::SetUpCommandLine(command_line);
597 }
Tanja Gornak89128fd2018-09-18 08:49:34598
lazyboy561b7de2015-11-19 19:27:30599 void SetUpOnMainThread() override {
miguelg9b502862017-04-24 18:13:53600 NotificationDisplayServiceFactory::GetInstance()->SetTestingFactory(
Sylvain Defresne711ff6b2018-10-04 12:33:54601 profile(),
602 base::BindRepeating(&StubNotificationDisplayService::FactoryForTests));
miguelg9b502862017-04-24 18:13:53603
johnmea5045732016-09-08 17:23:29604 gcm::FakeGCMProfileService* gcm_service =
605 static_cast<gcm::FakeGCMProfileService*>(
Tanja Gornak89128fd2018-09-18 08:49:34606 gcm::GCMProfileServiceFactory::GetForProfile(profile()));
johnmea5045732016-09-08 17:23:29607 gcm_driver_ = static_cast<instance_id::FakeGCMDriverForInstanceID*>(
608 gcm_service->driver());
lazyboy561b7de2015-11-19 19:27:30609 push_service_ = PushMessagingServiceFactory::GetForProfile(profile());
610
611 ServiceWorkerTest::SetUpOnMainThread();
612 }
613
johnmea5045732016-09-08 17:23:29614 instance_id::FakeGCMDriverForInstanceID* gcm_driver() const {
615 return gcm_driver_;
616 }
lazyboy561b7de2015-11-19 19:27:30617 PushMessagingServiceImpl* push_service() const { return push_service_; }
618
619 private:
Sylvain Defresne212b4b02018-10-11 16:32:05620 gcm::GCMProfileServiceFactory::ScopedTestingFactoryInstaller
621 scoped_testing_factory_installer_;
622
johnmea5045732016-09-08 17:23:29623 instance_id::FakeGCMDriverForInstanceID* gcm_driver_;
lazyboy561b7de2015-11-19 19:27:30624 PushMessagingServiceImpl* push_service_;
625
626 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerPushMessagingTest);
627};
628
Istiaque Ahmed805f6a83b2017-10-05 01:23:26629class ServiceWorkerLazyBackgroundTest : public ServiceWorkerTest {
630 public:
Istiaque Ahmed7105f2a2017-10-07 01:11:59631 ServiceWorkerLazyBackgroundTest()
632 : ServiceWorkerTest(
633 // Extensions APIs from SW are only enabled on trunk.
634 // It is important to set the channel early so that this change is
635 // visible in renderers running with service workers (and no
636 // extension).
637 version_info::Channel::UNKNOWN) {}
Istiaque Ahmed805f6a83b2017-10-05 01:23:26638 ~ServiceWorkerLazyBackgroundTest() override {}
639
640 void SetUpCommandLine(base::CommandLine* command_line) override {
641 ServiceWorkerTest::SetUpCommandLine(command_line);
642 // Disable background network activity as it can suddenly bring the Lazy
643 // Background Page alive.
644 command_line->AppendSwitch(::switches::kDisableBackgroundNetworking);
645 command_line->AppendSwitch(::switches::kNoProxyServer);
646 }
647
648 void SetUpInProcessBrowserTestFixture() override {
649 ServiceWorkerTest::SetUpInProcessBrowserTestFixture();
650 // Set shorter delays to prevent test timeouts.
651 ProcessManager::SetEventPageIdleTimeForTesting(1);
652 ProcessManager::SetEventPageSuspendingTimeForTesting(1);
653 }
654
655 private:
656 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerLazyBackgroundTest);
657};
658
Istiaque Ahmedea5ed5042017-09-25 19:00:16659IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, RegisterSucceeds) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22660 StartTestFromBackgroundPage("register.js");
annekao38685502015-07-14 17:46:39661}
662
Istiaque Ahmedea5ed5042017-09-25 19:00:16663IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, UpdateRefreshesServiceWorker) {
Francois Doraye6fb2d02017-10-18 21:29:13664 base::ScopedAllowBlockingForTesting allow_blocking;
lazyboyc3e763a2015-12-09 23:09:58665 base::ScopedTempDir scoped_temp_dir;
666 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
667 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
668 .AppendASCII("update")
669 .AppendASCII("service_worker.pem");
vabr9142fe22016-09-08 13:19:22670 base::FilePath path_v1 =
671 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
672 .AppendASCII("update")
673 .AppendASCII("v1"),
674 scoped_temp_dir.GetPath().AppendASCII("v1.crx"),
675 pem_path, base::FilePath());
676 base::FilePath path_v2 =
677 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
678 .AppendASCII("update")
679 .AppendASCII("v2"),
680 scoped_temp_dir.GetPath().AppendASCII("v2.crx"),
681 pem_path, base::FilePath());
lazyboyc3e763a2015-12-09 23:09:58682 const char* kId = "hfaanndiiilofhfokeanhddpkfffchdi";
683
684 ExtensionTestMessageListener listener_v1("Pong from version 1", false);
685 listener_v1.set_failure_message("FAILURE_V1");
686 // Install version 1.0 of the extension.
687 ASSERT_TRUE(InstallExtension(path_v1, 1));
688 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
689 ->enabled_extensions()
690 .GetByID(kId));
691 EXPECT_TRUE(listener_v1.WaitUntilSatisfied());
692
693 ExtensionTestMessageListener listener_v2("Pong from version 2", false);
694 listener_v2.set_failure_message("FAILURE_V2");
695
696 // Update to version 2.0.
697 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
698 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
699 ->enabled_extensions()
700 .GetByID(kId));
701 EXPECT_TRUE(listener_v2.WaitUntilSatisfied());
702}
703
[email protected]2ef85d562017-09-15 18:41:52704// TODO(crbug.com/765736) Fix the test.
Istiaque Ahmedea5ed5042017-09-25 19:00:16705IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, DISABLED_UpdateWithoutSkipWaiting) {
Francois Doraye6fb2d02017-10-18 21:29:13706 base::ScopedAllowBlockingForTesting allow_blocking;
lazyboy22eddc712015-12-10 21:16:26707 base::ScopedTempDir scoped_temp_dir;
708 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
709 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
710 .AppendASCII("update_without_skip_waiting")
711 .AppendASCII("update_without_skip_waiting.pem");
vabr9142fe22016-09-08 13:19:22712 base::FilePath path_v1 =
713 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
714 .AppendASCII("update_without_skip_waiting")
715 .AppendASCII("v1"),
716 scoped_temp_dir.GetPath().AppendASCII("v1.crx"),
717 pem_path, base::FilePath());
718 base::FilePath path_v2 =
719 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
720 .AppendASCII("update_without_skip_waiting")
721 .AppendASCII("v2"),
722 scoped_temp_dir.GetPath().AppendASCII("v2.crx"),
723 pem_path, base::FilePath());
lazyboy22eddc712015-12-10 21:16:26724 const char* kId = "mhnnnflgagdakldgjpfcofkiocpdmogl";
725
726 // Install version 1.0 of the extension.
727 ASSERT_TRUE(InstallExtension(path_v1, 1));
728 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
729 ->enabled_extensions()
730 .GetByID(kId));
731 const Extension* extension = extensions::ExtensionRegistry::Get(profile())
732 ->enabled_extensions()
733 .GetByID(kId);
734
735 ExtensionTestMessageListener listener1("Pong from version 1", false);
736 listener1.set_failure_message("FAILURE");
737 content::WebContents* web_contents =
738 AddTab(browser(), extension->GetResourceURL("page.html"));
739 EXPECT_TRUE(listener1.WaitUntilSatisfied());
740
741 // Update to version 2.0.
742 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
743 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
744 ->enabled_extensions()
745 .GetByID(kId));
746 const Extension* extension_after_update =
747 extensions::ExtensionRegistry::Get(profile())
748 ->enabled_extensions()
749 .GetByID(kId);
750
751 // Service worker version 2 would be installed but it won't be controlling
752 // the extension page yet.
753 ExtensionTestMessageListener listener2("Pong from version 1", false);
754 listener2.set_failure_message("FAILURE");
755 web_contents =
756 AddTab(browser(), extension_after_update->GetResourceURL("page.html"));
757 EXPECT_TRUE(listener2.WaitUntilSatisfied());
758
759 // Navigate the tab away from the extension page so that no clients are
760 // using the service worker.
761 // Note that just closing the tab with WebContentsDestroyedWatcher doesn't
762 // seem to be enough because it returns too early.
763 WebContentsLoadStopObserver navigate_away_observer(web_contents);
764 web_contents->GetController().LoadURL(
765 GURL(url::kAboutBlankURL), content::Referrer(), ui::PAGE_TRANSITION_TYPED,
766 std::string());
767 navigate_away_observer.WaitForLoadStop();
768
769 // Now expect service worker version 2 to control the extension page.
770 ExtensionTestMessageListener listener3("Pong from version 2", false);
771 listener3.set_failure_message("FAILURE");
772 web_contents =
773 AddTab(browser(), extension_after_update->GetResourceURL("page.html"));
774 EXPECT_TRUE(listener3.WaitUntilSatisfied());
775}
776
Istiaque Ahmedea5ed5042017-09-25 19:00:16777IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, FetchArbitraryPaths) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22778 const Extension* extension = StartTestFromBackgroundPage("fetch.js");
annekao1db36fd2015-07-29 17:09:16779
kalman6f984ae2015-09-18 17:21:58780 // Open some arbirary paths. Their contents should be what the service worker
781 // responds with, which in this case is the path of the fetch.
782 EXPECT_EQ(
783 "Caught a fetch for /index.html",
784 NavigateAndExtractInnerText(extension->GetResourceURL("index.html")));
785 EXPECT_EQ("Caught a fetch for /path/to/other.html",
786 NavigateAndExtractInnerText(
787 extension->GetResourceURL("path/to/other.html")));
788 EXPECT_EQ("Caught a fetch for /some/text/file.txt",
789 NavigateAndExtractInnerText(
790 extension->GetResourceURL("some/text/file.txt")));
791 EXPECT_EQ("Caught a fetch for /no/file/extension",
792 NavigateAndExtractInnerText(
793 extension->GetResourceURL("no/file/extension")));
794 EXPECT_EQ("Caught a fetch for /",
795 NavigateAndExtractInnerText(extension->GetResourceURL("")));
annekao1db36fd2015-07-29 17:09:16796}
797
Kenichi Ishibashi773b82972018-08-30 07:02:03798IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
799 FetchExtensionResourceFromServiceWorker) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22800 const Extension* extension = StartTestFromBackgroundPage("fetch_from_sw.js");
Kenichi Ishibashi773b82972018-08-30 07:02:03801 ASSERT_TRUE(extension);
802
803 // The service worker in this test tries to load 'hello.txt' via fetch()
804 // and sends back the content of the file, which should be 'hello'.
805 const char* kScript = R"(
806 let channel = new MessageChannel();
807 test.waitForMessage(channel.port1).then(message => {
808 window.domAutomationController.send(message);
809 });
810 test.registeredServiceWorker.postMessage(
811 {port: channel.port2}, [channel.port2]);
812 )";
813 EXPECT_EQ("hello", ExecuteScriptInBackgroundPage(extension->id(), kScript));
814}
815
Istiaque Ahmedea5ed5042017-09-25 19:00:16816IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, SWServedBackgroundPageReceivesEvent) {
lazyboy52c3bcf2016-01-08 00:11:29817 const Extension* extension =
Istiaque Ahmed93ff7f42018-08-31 01:42:22818 StartTestFromBackgroundPage("replace_background.js");
lazyboy52c3bcf2016-01-08 00:11:29819 ExtensionHost* background_page =
820 process_manager()->GetBackgroundHostForExtension(extension->id());
821 ASSERT_TRUE(background_page);
822
823 // Close the background page and start it again so that the service worker
824 // will start controlling pages.
825 background_page->Close();
826 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
827 background_page = nullptr;
Peter Kasting341e1fb2018-02-24 00:03:01828 process_manager()->WakeEventPage(extension->id(), base::DoNothing());
lazyboy52c3bcf2016-01-08 00:11:29829 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
830
831 // Since the SW is now controlling the extension, the SW serves the background
832 // script. page.html sends a message to the background script and we verify
833 // that the SW served background script correctly receives the message/event.
834 ExtensionTestMessageListener listener("onMessage/SW BG.", false);
835 listener.set_failure_message("onMessage/original BG.");
836 content::WebContents* web_contents =
837 AddTab(browser(), extension->GetResourceURL("page.html"));
838 ASSERT_TRUE(web_contents);
839 EXPECT_TRUE(listener.WaitUntilSatisfied());
840}
841
Matt Falkenhagena612fc02018-05-30 00:35:39842IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, SWServedBackgroundPage) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22843 const Extension* extension = StartTestFromBackgroundPage("fetch.js");
annekao49241182015-08-18 17:14:01844
kalman6f984ae2015-09-18 17:21:58845 std::string kExpectedInnerText = "background.html contents for testing.";
annekao49241182015-08-18 17:14:01846
kalman6f984ae2015-09-18 17:21:58847 // Sanity check that the background page has the expected content.
848 ExtensionHost* background_page =
849 process_manager()->GetBackgroundHostForExtension(extension->id());
850 ASSERT_TRUE(background_page);
851 EXPECT_EQ(kExpectedInnerText,
852 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:01853
kalman6f984ae2015-09-18 17:21:58854 // Close the background page.
855 background_page->Close();
856 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
857 background_page = nullptr;
858
859 // Start it again.
Peter Kasting341e1fb2018-02-24 00:03:01860 process_manager()->WakeEventPage(extension->id(), base::DoNothing());
kalman6f984ae2015-09-18 17:21:58861 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
862
Matt Falkenhagena612fc02018-05-30 00:35:39863 // The service worker should get a fetch event for the background page.
kalman6f984ae2015-09-18 17:21:58864 background_page =
865 process_manager()->GetBackgroundHostForExtension(extension->id());
866 ASSERT_TRUE(background_page);
867 content::WaitForLoadStop(background_page->host_contents());
868
kalman6f984ae2015-09-18 17:21:58869 EXPECT_EQ("Caught a fetch for /background.html",
870 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:01871}
872
Istiaque Ahmedea5ed5042017-09-25 19:00:16873IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:58874 ServiceWorkerPostsMessageToBackgroundClient) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22875 const Extension* extension =
876 StartTestFromBackgroundPage("post_message_to_background_client.js");
annekao533482222015-08-21 23:23:53877
kalman6f984ae2015-09-18 17:21:58878 // The service worker in this test simply posts a message to the background
879 // client it receives from getBackgroundClient().
880 const char* kScript =
881 "var messagePromise = null;\n"
882 "if (test.lastMessageFromServiceWorker) {\n"
883 " messagePromise = Promise.resolve(test.lastMessageFromServiceWorker);\n"
884 "} else {\n"
885 " messagePromise = test.waitForMessage(navigator.serviceWorker);\n"
886 "}\n"
887 "messagePromise.then(function(message) {\n"
888 " window.domAutomationController.send(String(message == 'success'));\n"
889 "})\n";
890 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:53891}
892
Istiaque Ahmedea5ed5042017-09-25 19:00:16893IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:58894 BackgroundPagePostsMessageToServiceWorker) {
895 const Extension* extension =
Istiaque Ahmed93ff7f42018-08-31 01:42:22896 StartTestFromBackgroundPage("post_message_to_sw.js");
annekao533482222015-08-21 23:23:53897
kalman6f984ae2015-09-18 17:21:58898 // The service worker in this test waits for a message, then echoes it back
899 // by posting a message to the background page via getBackgroundClient().
900 const char* kScript =
901 "var mc = new MessageChannel();\n"
902 "test.waitForMessage(mc.port1).then(function(message) {\n"
903 " window.domAutomationController.send(String(message == 'hello'));\n"
904 "});\n"
905 "test.registeredServiceWorker.postMessage(\n"
906 " {message: 'hello', port: mc.port2}, [mc.port2])\n";
907 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:53908}
909
Istiaque Ahmedea5ed5042017-09-25 19:00:16910IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
rdevlin.croninf5863da2015-09-10 19:21:45911 ServiceWorkerSuspensionOnExtensionUnload) {
kalman6f984ae2015-09-18 17:21:58912 // For this test, only hold onto the extension's ID and URL + a function to
913 // get a resource URL, because we're going to be disabling and uninstalling
914 // it, which will invalidate the pointer.
915 std::string extension_id;
916 GURL extension_url;
917 {
Istiaque Ahmed93ff7f42018-08-31 01:42:22918 const Extension* extension = StartTestFromBackgroundPage("fetch.js");
kalman6f984ae2015-09-18 17:21:58919 extension_id = extension->id();
920 extension_url = extension->url();
921 }
922 auto get_resource_url = [&extension_url](const std::string& path) {
923 return Extension::GetResourceURL(extension_url, path);
924 };
rdevlin.croninf5863da2015-09-10 19:21:45925
kalman6f984ae2015-09-18 17:21:58926 // Fetch should route to the service worker.
927 EXPECT_EQ("Caught a fetch for /index.html",
928 NavigateAndExtractInnerText(get_resource_url("index.html")));
rdevlin.croninf5863da2015-09-10 19:21:45929
kalman6f984ae2015-09-18 17:21:58930 // Disable the extension. Opening the page should fail.
931 extension_service()->DisableExtension(extension_id,
Minh X. Nguyen45479012017-08-18 21:35:36932 disable_reason::DISABLE_USER_ACTION);
rdevlin.croninf5863da2015-09-10 19:21:45933 base::RunLoop().RunUntilIdle();
rdevlin.croninf5863da2015-09-10 19:21:45934
kalman6f984ae2015-09-18 17:21:58935 EXPECT_EQ(content::PAGE_TYPE_ERROR,
936 NavigateAndGetPageType(get_resource_url("index.html")));
937 EXPECT_EQ(content::PAGE_TYPE_ERROR,
938 NavigateAndGetPageType(get_resource_url("other.html")));
939
940 // Re-enable the extension. Opening pages should immediately start to succeed
941 // again.
rdevlin.croninf5863da2015-09-10 19:21:45942 extension_service()->EnableExtension(extension_id);
943 base::RunLoop().RunUntilIdle();
944
kalman6f984ae2015-09-18 17:21:58945 EXPECT_EQ("Caught a fetch for /index.html",
946 NavigateAndExtractInnerText(get_resource_url("index.html")));
947 EXPECT_EQ("Caught a fetch for /other.html",
948 NavigateAndExtractInnerText(get_resource_url("other.html")));
949 EXPECT_EQ("Caught a fetch for /another.html",
950 NavigateAndExtractInnerText(get_resource_url("another.html")));
rdevlin.croninf5863da2015-09-10 19:21:45951
kalman6f984ae2015-09-18 17:21:58952 // Uninstall the extension. Opening pages should fail again.
953 base::string16 error;
954 extension_service()->UninstallExtension(
Devlin Cronin218df7f2017-11-21 21:41:31955 extension_id, UninstallReason::UNINSTALL_REASON_FOR_TESTING, &error);
kalman6f984ae2015-09-18 17:21:58956 base::RunLoop().RunUntilIdle();
957
958 EXPECT_EQ(content::PAGE_TYPE_ERROR,
959 NavigateAndGetPageType(get_resource_url("index.html")));
960 EXPECT_EQ(content::PAGE_TYPE_ERROR,
961 NavigateAndGetPageType(get_resource_url("other.html")));
962 EXPECT_EQ(content::PAGE_TYPE_ERROR,
963 NavigateAndGetPageType(get_resource_url("anotherother.html")));
964 EXPECT_EQ(content::PAGE_TYPE_ERROR,
965 NavigateAndGetPageType(get_resource_url("final.html")));
966}
967
Istiaque Ahmedea5ed5042017-09-25 19:00:16968IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, BackgroundPageIsWokenIfAsleep) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22969 const Extension* extension = StartTestFromBackgroundPage("wake_on_fetch.js");
kalman6f984ae2015-09-18 17:21:58970
971 // Navigate to special URLs that this test's service worker recognises, each
972 // making a check then populating the response with either "true" or "false".
973 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
974 "background-client-is-awake")));
975 EXPECT_EQ("true", NavigateAndExtractInnerText(
976 extension->GetResourceURL("ping-background-client")));
977 // Ping more than once for good measure.
978 EXPECT_EQ("true", NavigateAndExtractInnerText(
979 extension->GetResourceURL("ping-background-client")));
980
981 // Shut down the event page. The SW should detect that it's closed, but still
982 // be able to ping it.
983 ExtensionHost* background_page =
984 process_manager()->GetBackgroundHostForExtension(extension->id());
985 ASSERT_TRUE(background_page);
986 background_page->Close();
987 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
988
989 EXPECT_EQ("false", NavigateAndExtractInnerText(extension->GetResourceURL(
990 "background-client-is-awake")));
991 EXPECT_EQ("true", NavigateAndExtractInnerText(
992 extension->GetResourceURL("ping-background-client")));
993 EXPECT_EQ("true", NavigateAndExtractInnerText(
994 extension->GetResourceURL("ping-background-client")));
995 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
996 "background-client-is-awake")));
997}
998
Istiaque Ahmedea5ed5042017-09-25 19:00:16999IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:581000 GetBackgroundClientFailsWithNoBackgroundPage) {
1001 // This extension doesn't have a background page, only a tab at page.html.
1002 // The service worker it registers tries to call getBackgroundClient() and
1003 // should fail.
1004 // Note that this also tests that service workers can be registered from tabs.
1005 EXPECT_TRUE(RunExtensionSubtest("service_worker/no_background", "page.html"));
rdevlin.croninf5863da2015-09-10 19:21:451006}
1007
Istiaque Ahmedea5ed5042017-09-25 19:00:161008IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, NotificationAPI) {
lazyboy6ddb7d62015-11-10 23:15:271009 EXPECT_TRUE(RunExtensionSubtest("service_worker/notifications/has_permission",
1010 "page.html"));
1011}
1012
Istiaque Ahmedea5ed5042017-09-25 19:00:161013IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, WebAccessibleResourcesFetch) {
lazyboyaea32c22016-01-04 21:37:071014 EXPECT_TRUE(RunExtensionSubtest(
1015 "service_worker/web_accessible_resources/fetch/", "page.html"));
1016}
1017
Istiaque Ahmed75ad1d92018-08-30 05:16:541018IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, TabsCreate) {
Elly Fong-Jones4a4f21d2018-05-30 15:04:161019 if (IsMacViewsMode())
1020 return;
lazyboyee4adef2016-05-24 00:55:161021 // Extensions APIs from SW are only enabled on trunk.
1022 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1023 const Extension* extension = LoadExtensionWithFlags(
1024 test_data_dir_.AppendASCII("service_worker/tabs_create"), kFlagNone);
1025 ASSERT_TRUE(extension);
1026 ui_test_utils::NavigateToURL(browser(),
1027 extension->GetResourceURL("page.html"));
1028 content::WebContents* web_contents =
1029 browser()->tab_strip_model()->GetActiveWebContents();
1030
1031 int starting_tab_count = browser()->tab_strip_model()->count();
1032 std::string result;
1033 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
1034 web_contents, "window.runServiceWorker()", &result));
1035 ASSERT_EQ("chrome.tabs.create callback", result);
1036 EXPECT_EQ(starting_tab_count + 1, browser()->tab_strip_model()->count());
1037
1038 // Check extension shutdown path.
1039 UnloadExtension(extension->id());
1040 EXPECT_EQ(starting_tab_count, browser()->tab_strip_model()->count());
1041}
1042
Istiaque Ahmedea5ed5042017-09-25 19:00:161043IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, Events) {
Elly Fong-Jones4a4f21d2018-05-30 15:04:161044 if (IsMacViewsMode())
1045 return;
lazyboye7847242017-06-07 23:29:181046 // Extensions APIs from SW are only enabled on trunk.
1047 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1048 const Extension* extension = LoadExtensionWithFlags(
1049 test_data_dir_.AppendASCII("service_worker/events"), kFlagNone);
1050 ASSERT_TRUE(extension);
1051 ui_test_utils::NavigateToURL(browser(),
1052 extension->GetResourceURL("page.html"));
1053 content::WebContents* web_contents =
1054 browser()->tab_strip_model()->GetActiveWebContents();
1055 std::string result;
1056 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
1057 web_contents, "window.runEventTest()", &result));
1058 ASSERT_EQ("chrome.tabs.onUpdated callback", result);
1059}
1060
Istiaque Ahmedea5ed5042017-09-25 19:00:161061IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, EventsToStoppedWorker) {
lazyboy63b994a2017-06-30 21:20:231062 // Extensions APIs from SW are only enabled on trunk.
1063 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1064 const Extension* extension = LoadExtensionWithFlags(
1065 test_data_dir_.AppendASCII("service_worker/events_to_stopped_worker"),
1066 kFlagNone);
1067 ASSERT_TRUE(extension);
1068 ui_test_utils::NavigateToURL(browser(),
1069 extension->GetResourceURL("page.html"));
1070 content::WebContents* web_contents =
1071 browser()->tab_strip_model()->GetActiveWebContents();
1072 {
1073 std::string result;
1074 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
1075 web_contents, "window.runServiceWorker()", &result));
1076 ASSERT_EQ("ready", result);
1077
1078 base::RunLoop run_loop;
1079 content::StoragePartition* storage_partition =
1080 content::BrowserContext::GetDefaultStoragePartition(
1081 browser()->profile());
Zhuoyu Qian2266251f2018-10-13 02:59:001082 content::StopServiceWorkerForScope(
lazyboy63b994a2017-06-30 21:20:231083 storage_partition->GetServiceWorkerContext(),
1084 // The service worker is registered at the top level scope.
1085 extension->url(), run_loop.QuitClosure());
1086 run_loop.Run();
1087 }
1088
1089 std::string result;
1090 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
1091 web_contents, "window.createTabThenUpdate()", &result));
1092 ASSERT_EQ("chrome.tabs.onUpdated callback", result);
1093}
1094
Istiaque Ahmed805f6a83b2017-10-05 01:23:261095// Tests that events to service worker arrives correctly event if the owner
1096// extension of the worker is not running.
1097IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest,
Istiaque Ahmedb8e24bdb2018-09-13 15:17:251098 EventsToStoppedExtension) {
Istiaque Ahmed805f6a83b2017-10-05 01:23:261099 LazyBackgroundObserver lazy_observer;
1100 ResultCatcher catcher;
1101 const Extension* extension = LoadExtensionWithFlags(
1102 test_data_dir_.AppendASCII("service_worker/events_to_stopped_extension"),
1103 kFlagNone);
1104 ASSERT_TRUE(extension);
1105 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
1106
1107 ProcessManager* pm = ProcessManager::Get(browser()->profile());
1108 EXPECT_GT(pm->GetLazyKeepaliveCount(extension), 0);
David Bertoni3e1e9fa2018-08-29 20:39:301109 EXPECT_FALSE(pm->GetLazyKeepaliveActivities(extension).empty());
Istiaque Ahmed805f6a83b2017-10-05 01:23:261110
1111 // |extension|'s background page opens a tab to its resource.
1112 content::WebContents* extension_web_contents =
1113 browser()->tab_strip_model()->GetActiveWebContents();
1114 EXPECT_TRUE(content::WaitForLoadStop(extension_web_contents));
1115 EXPECT_EQ(extension->GetResourceURL("page.html").spec(),
1116 extension_web_contents->GetURL().spec());
1117 {
1118 // Let the service worker start and register a listener to
1119 // chrome.tabs.onCreated event.
1120 ExtensionTestMessageListener add_listener_done("listener-added", false);
1121 content::ExecuteScriptAsync(extension_web_contents,
1122 "window.runServiceWorkerAsync()");
1123 EXPECT_TRUE(add_listener_done.WaitUntilSatisfied());
1124
1125 base::RunLoop run_loop;
1126 content::StoragePartition* storage_partition =
1127 content::BrowserContext::GetDefaultStoragePartition(
1128 browser()->profile());
Zhuoyu Qian2266251f2018-10-13 02:59:001129 content::StopServiceWorkerForScope(
Istiaque Ahmed805f6a83b2017-10-05 01:23:261130 storage_partition->GetServiceWorkerContext(),
1131 // The service worker is registered at the top level scope.
1132 extension->url(), run_loop.QuitClosure());
1133 run_loop.Run();
1134 }
1135
1136 // Close the tab to |extension|'s resource. This will also close the
1137 // extension's event page.
1138 browser()->tab_strip_model()->CloseWebContentsAt(
1139 browser()->tab_strip_model()->active_index(), TabStripModel::CLOSE_NONE);
1140 lazy_observer.Wait();
1141
1142 // At this point both the extension worker and extension event page is not
1143 // running. Since the worker registered a listener for tabs.onCreated, it
1144 // will be started to dispatch the event once we create a tab.
1145 ExtensionTestMessageListener newtab_listener("hello-newtab", false);
1146 newtab_listener.set_failure_message("WRONG_NEWTAB");
1147 content::WebContents* new_web_contents =
Istiaque Ahmed7105f2a2017-10-07 01:11:591148 AddTab(browser(), GURL(url::kAboutBlankURL));
1149 EXPECT_TRUE(new_web_contents);
1150 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
1151}
1152
1153// Tests that events to service worker correctly after browser restart.
1154// This test is similar to EventsToStoppedExtension, except that the event
1155// delivery is verified after a browser restart.
1156IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest,
1157 PRE_EventsAfterRestart) {
1158 LazyBackgroundObserver lazy_observer;
1159 ResultCatcher catcher;
1160 const Extension* extension = LoadExtensionWithFlags(
1161 test_data_dir_.AppendASCII("service_worker/events_to_stopped_extension"),
1162 kFlagNone);
1163 ASSERT_TRUE(extension);
1164 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
1165
1166 ProcessManager* pm = ProcessManager::Get(browser()->profile());
1167 EXPECT_GT(pm->GetLazyKeepaliveCount(extension), 0);
David Bertoni3e1e9fa2018-08-29 20:39:301168 EXPECT_FALSE(pm->GetLazyKeepaliveActivities(extension).empty());
Istiaque Ahmed7105f2a2017-10-07 01:11:591169
1170 // |extension|'s background page opens a tab to its resource.
1171 content::WebContents* extension_web_contents =
1172 browser()->tab_strip_model()->GetActiveWebContents();
1173 EXPECT_TRUE(content::WaitForLoadStop(extension_web_contents));
1174 EXPECT_EQ(extension->GetResourceURL("page.html").spec(),
1175 extension_web_contents->GetURL().spec());
1176 {
1177 // Let the service worker start and register a listener to
1178 // chrome.tabs.onCreated event.
1179 ExtensionTestMessageListener add_listener_done("listener-added", false);
1180 content::ExecuteScriptAsync(extension_web_contents,
1181 "window.runServiceWorkerAsync()");
1182 EXPECT_TRUE(add_listener_done.WaitUntilSatisfied());
1183
1184 base::RunLoop run_loop;
1185 content::StoragePartition* storage_partition =
1186 content::BrowserContext::GetDefaultStoragePartition(
1187 browser()->profile());
Zhuoyu Qian2266251f2018-10-13 02:59:001188 content::StopServiceWorkerForScope(
Istiaque Ahmed7105f2a2017-10-07 01:11:591189 storage_partition->GetServiceWorkerContext(),
1190 // The service worker is registered at the top level scope.
1191 extension->url(), run_loop.QuitClosure());
1192 run_loop.Run();
1193 }
1194
1195 // Close the tab to |extension|'s resource. This will also close the
1196 // extension's event page.
1197 browser()->tab_strip_model()->CloseWebContentsAt(
1198 browser()->tab_strip_model()->active_index(), TabStripModel::CLOSE_NONE);
1199 lazy_observer.Wait();
1200}
1201
Istiaque Ahmed99aa96d2018-09-13 23:22:081202IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest, EventsAfterRestart) {
Istiaque Ahmed7105f2a2017-10-07 01:11:591203 ExtensionTestMessageListener newtab_listener("hello-newtab", false);
1204 content::WebContents* new_web_contents =
1205 AddTab(browser(), GURL(url::kAboutBlankURL));
Istiaque Ahmed805f6a83b2017-10-05 01:23:261206 EXPECT_TRUE(new_web_contents);
1207 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
1208}
1209
lazyboy4c82177a2016-10-18 00:04:091210// Tests that worker ref count increments while extension API function is
1211// active.
Istiaque Ahmedea5ed5042017-09-25 19:00:161212IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, WorkerRefCount) {
lazyboy4c82177a2016-10-18 00:04:091213 // Extensions APIs from SW are only enabled on trunk.
1214 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1215 const Extension* extension = LoadExtensionWithFlags(
1216 test_data_dir_.AppendASCII("service_worker/api_worker_ref_count"),
1217 kFlagNone);
1218 ASSERT_TRUE(extension);
1219 ui_test_utils::NavigateToURL(browser(),
1220 extension->GetResourceURL("page.html"));
1221 content::WebContents* web_contents =
1222 browser()->tab_strip_model()->GetActiveWebContents();
1223
1224 ExtensionTestMessageListener worker_start_listener("WORKER STARTED", false);
1225 worker_start_listener.set_failure_message("FAILURE");
1226 ASSERT_TRUE(
1227 content::ExecuteScript(web_contents, "window.runServiceWorker()"));
1228 ASSERT_TRUE(worker_start_listener.WaitUntilSatisfied());
1229
1230 // Service worker should have no pending requests because it hasn't peformed
1231 // any extension API request yet.
1232 EXPECT_EQ(0u, GetWorkerRefCount(extension->url()));
1233
1234 ExtensionTestMessageListener worker_listener("CHECK_REF_COUNT", true);
1235 worker_listener.set_failure_message("FAILURE");
1236 ASSERT_TRUE(content::ExecuteScript(web_contents, "window.testSendMessage()"));
1237 ASSERT_TRUE(worker_listener.WaitUntilSatisfied());
1238
1239 // Service worker should have exactly one pending request because
1240 // chrome.test.sendMessage() API call is in-flight.
1241 EXPECT_EQ(1u, GetWorkerRefCount(extension->url()));
1242
1243 // Peform another extension API request while one is ongoing.
1244 {
1245 ExtensionTestMessageListener listener("CHECK_REF_COUNT", true);
1246 listener.set_failure_message("FAILURE");
1247 ASSERT_TRUE(
1248 content::ExecuteScript(web_contents, "window.testSendMessage()"));
1249 ASSERT_TRUE(listener.WaitUntilSatisfied());
1250
1251 // Service worker currently has two extension API requests in-flight.
1252 EXPECT_EQ(2u, GetWorkerRefCount(extension->url()));
1253 // Finish executing the nested chrome.test.sendMessage() first.
1254 listener.Reply("Hello world");
1255 }
1256
Istiaque Ahmedb57c9752017-08-20 19:08:571257 ExtensionTestMessageListener worker_completion_listener("SUCCESS_FROM_WORKER",
1258 false);
lazyboy4c82177a2016-10-18 00:04:091259 // Finish executing chrome.test.sendMessage().
1260 worker_listener.Reply("Hello world");
Istiaque Ahmedb57c9752017-08-20 19:08:571261 EXPECT_TRUE(worker_completion_listener.WaitUntilSatisfied());
1262
1263 // The following block makes sure we have received all the IPCs related to
1264 // ref-count from the worker.
1265 {
1266 // The following roundtrip:
1267 // browser->extension->worker->extension->browser
1268 // will ensure that the worker sent the relevant ref count IPCs.
1269 std::string result;
1270 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1271 web_contents, "window.roundtripToWorker();", &result));
1272 EXPECT_EQ("roundtrip-succeeded", result);
1273
1274 // Ensure IO thread IPCs run.
Gabriel Charette01507a22017-09-27 21:30:081275 content::RunAllTasksUntilIdle();
Istiaque Ahmedb57c9752017-08-20 19:08:571276 }
lazyboy4c82177a2016-10-18 00:04:091277
1278 // The ref count should drop to 0.
1279 EXPECT_EQ(0u, GetWorkerRefCount(extension->url()));
1280}
1281
lazyboyaea32c22016-01-04 21:37:071282// This test loads a web page that has an iframe pointing to a
1283// chrome-extension:// URL. The URL is listed in the extension's
1284// web_accessible_resources. Initially the iframe is served from the extension's
1285// resource file. After verifying that, we register a Service Worker that
1286// controls the extension. Further requests to the same resource as before
1287// should now be served by the Service Worker.
1288// This test also verifies that if the requested resource exists in the manifest
1289// but is not present in the extension directory, the Service Worker can still
1290// serve the resource file.
Istiaque Ahmedea5ed5042017-09-25 19:00:161291IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, WebAccessibleResourcesIframeSrc) {
lazyboyaea32c22016-01-04 21:37:071292 const Extension* extension = LoadExtensionWithFlags(
1293 test_data_dir_.AppendASCII(
1294 "service_worker/web_accessible_resources/iframe_src"),
1295 kFlagNone);
1296 ASSERT_TRUE(extension);
1297 ASSERT_TRUE(StartEmbeddedTestServer());
falkenad185092016-06-16 06:10:021298
1299 // Service workers can only control secure contexts
1300 // (https://w3c.github.io/webappsec-secure-contexts/). For documents, this
1301 // typically means the document must have a secure origin AND all its ancestor
1302 // frames must have documents with secure origins. However, extension pages
1303 // are considered secure, even if they have an ancestor document that is an
1304 // insecure context (see GetSchemesBypassingSecureContextCheckWhitelist). So
1305 // extension service workers must be able to control an extension page
1306 // embedded in an insecure context. To test this, set up an insecure
1307 // (non-localhost, non-https) URL for the web page. This page will create
1308 // iframes that load extension pages that must be controllable by service
1309 // worker.
falkenad185092016-06-16 06:10:021310 GURL page_url =
1311 embedded_test_server()->GetURL("a.com",
1312 "/extensions/api_test/service_worker/"
1313 "web_accessible_resources/webpage.html");
1314 EXPECT_FALSE(content::IsOriginSecure(page_url));
lazyboyaea32c22016-01-04 21:37:071315
1316 content::WebContents* web_contents = AddTab(browser(), page_url);
1317 std::string result;
1318 // webpage.html will create an iframe pointing to a resource from |extension|.
1319 // Expect the resource to be served by the extension.
1320 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1321 web_contents, base::StringPrintf("window.testIframe('%s', 'iframe.html')",
1322 extension->id().c_str()),
1323 &result));
1324 EXPECT_EQ("FROM_EXTENSION_RESOURCE", result);
1325
1326 ExtensionTestMessageListener service_worker_ready_listener("SW_READY", false);
1327 EXPECT_TRUE(ExecuteScriptInBackgroundPageNoWait(
1328 extension->id(), "window.registerServiceWorker()"));
1329 EXPECT_TRUE(service_worker_ready_listener.WaitUntilSatisfied());
1330
1331 result.clear();
1332 // webpage.html will create another iframe pointing to a resource from
1333 // |extension| as before. But this time, the resource should be be served
1334 // from the Service Worker.
1335 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1336 web_contents, base::StringPrintf("window.testIframe('%s', 'iframe.html')",
1337 extension->id().c_str()),
1338 &result));
1339 EXPECT_EQ("FROM_SW_RESOURCE", result);
1340
1341 result.clear();
1342 // webpage.html will create yet another iframe pointing to a resource that
1343 // exists in the extension manifest's web_accessible_resources, but is not
1344 // present in the extension directory. Expect the resources of the iframe to
1345 // be served by the Service Worker.
1346 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1347 web_contents,
1348 base::StringPrintf("window.testIframe('%s', 'iframe_non_existent.html')",
1349 extension->id().c_str()),
1350 &result));
1351 EXPECT_EQ("FROM_SW_RESOURCE", result);
1352}
1353
Istiaque Ahmedea5ed5042017-09-25 19:00:161354IN_PROC_BROWSER_TEST_P(ServiceWorkerBackgroundSyncTest, Sync) {
Elly Fong-Jones4a4f21d2018-05-30 15:04:161355 if (IsMacViewsMode())
1356 return;
lazyboybd325ae2015-11-18 21:35:261357 const Extension* extension = LoadExtensionWithFlags(
1358 test_data_dir_.AppendASCII("service_worker/sync"), kFlagNone);
1359 ASSERT_TRUE(extension);
1360 ui_test_utils::NavigateToURL(browser(),
1361 extension->GetResourceURL("page.html"));
1362 content::WebContents* web_contents =
1363 browser()->tab_strip_model()->GetActiveWebContents();
1364
1365 // Prevent firing by going offline.
1366 content::background_sync_test_util::SetOnline(web_contents, false);
1367
1368 ExtensionTestMessageListener sync_listener("SYNC: send-chats", false);
1369 sync_listener.set_failure_message("FAIL");
1370
1371 std::string result;
1372 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
1373 web_contents, "window.runServiceWorker()", &result));
1374 ASSERT_EQ("SERVICE_WORKER_READY", result);
1375
1376 EXPECT_FALSE(sync_listener.was_satisfied());
1377 // Resume firing by going online.
1378 content::background_sync_test_util::SetOnline(web_contents, true);
1379 EXPECT_TRUE(sync_listener.WaitUntilSatisfied());
1380}
1381
Istiaque Ahmedea5ed5042017-09-25 19:00:161382IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
horo1eeddde2015-11-19 05:59:251383 FetchFromContentScriptShouldNotGoToServiceWorkerOfPage) {
1384 ASSERT_TRUE(StartEmbeddedTestServer());
1385 GURL page_url = embedded_test_server()->GetURL(
1386 "/extensions/api_test/service_worker/content_script_fetch/"
1387 "controlled_page/index.html");
1388 content::WebContents* tab =
1389 browser()->tab_strip_model()->GetActiveWebContents();
1390 ui_test_utils::NavigateToURL(browser(), page_url);
1391 content::WaitForLoadStop(tab);
1392
1393 std::string value;
1394 ASSERT_TRUE(
1395 content::ExecuteScriptAndExtractString(tab, "register();", &value));
1396 EXPECT_EQ("SW controlled", value);
1397
1398 ASSERT_TRUE(RunExtensionTest("service_worker/content_script_fetch"))
1399 << message_;
1400}
1401
Istiaque Ahmedea5ed5042017-09-25 19:00:161402IN_PROC_BROWSER_TEST_P(ServiceWorkerPushMessagingTest, OnPush) {
lazyboy561b7de2015-11-19 19:27:301403 const Extension* extension = LoadExtensionWithFlags(
1404 test_data_dir_.AppendASCII("service_worker/push_messaging"), kFlagNone);
1405 ASSERT_TRUE(extension);
1406 GURL extension_url = extension->url();
1407
Peter Beverloodd4ef1e2018-06-21 15:41:041408 GrantNotificationPermissionForTest(extension_url);
lazyboy561b7de2015-11-19 19:27:301409
1410 GURL url = extension->GetResourceURL("page.html");
1411 ui_test_utils::NavigateToURL(browser(), url);
1412
1413 content::WebContents* web_contents =
1414 browser()->tab_strip_model()->GetActiveWebContents();
1415
1416 // Start the ServiceWorker.
1417 ExtensionTestMessageListener ready_listener("SERVICE_WORKER_READY", false);
1418 ready_listener.set_failure_message("SERVICE_WORKER_FAILURE");
1419 const char* kScript = "window.runServiceWorker()";
1420 EXPECT_TRUE(content::ExecuteScript(web_contents->GetMainFrame(), kScript));
1421 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
1422
1423 PushMessagingAppIdentifier app_identifier =
1424 GetAppIdentifierForServiceWorkerRegistration(0LL, extension_url);
johnmea5045732016-09-08 17:23:291425 ASSERT_EQ(app_identifier.app_id(), gcm_driver()->last_gettoken_app_id());
1426 EXPECT_EQ("1234567890", gcm_driver()->last_gettoken_authorized_entity());
lazyboy561b7de2015-11-19 19:27:301427
lazyboyd429e2582016-05-20 20:18:521428 base::RunLoop run_loop;
lazyboy561b7de2015-11-19 19:27:301429 // Send a push message via gcm and expect the ServiceWorker to receive it.
1430 ExtensionTestMessageListener push_message_listener("OK", false);
1431 push_message_listener.set_failure_message("FAIL");
1432 gcm::IncomingMessage message;
1433 message.sender_id = "1234567890";
1434 message.raw_data = "testdata";
1435 message.decrypted = true;
lazyboyd429e2582016-05-20 20:18:521436 push_service()->SetMessageCallbackForTesting(run_loop.QuitClosure());
lazyboy561b7de2015-11-19 19:27:301437 push_service()->OnMessage(app_identifier.app_id(), message);
1438 EXPECT_TRUE(push_message_listener.WaitUntilSatisfied());
lazyboyd429e2582016-05-20 20:18:521439 run_loop.Run(); // Wait until the message is handled by push service.
lazyboy561b7de2015-11-19 19:27:301440}
1441
Istiaque Ahmedea5ed5042017-09-25 19:00:161442IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, FilteredEvents) {
Istiaque Ahmed9d1666182017-09-21 23:58:181443 // Extensions APIs from SW are only enabled on trunk.
1444 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1445 ASSERT_TRUE(RunExtensionTest("service_worker/filtered_events"));
1446}
1447
Rob Wue89b90032018-02-16 19:46:081448IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, MimeHandlerView) {
1449 ASSERT_TRUE(RunExtensionTest("service_worker/mime_handler_view"));
1450}
1451
Istiaque Ahmed9ce21b32017-10-10 20:43:181452IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest,
1453 PRE_FilteredEventsAfterRestart) {
1454 LazyBackgroundObserver lazy_observer;
1455 ResultCatcher catcher;
1456 const Extension* extension = LoadExtensionWithFlags(
1457 test_data_dir_.AppendASCII(
1458 "service_worker/filtered_events_after_restart"),
1459 kFlagNone);
1460 ASSERT_TRUE(extension);
1461 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
1462
1463 // |extension|'s background page opens a tab to its resource.
1464 content::WebContents* extension_web_contents =
1465 browser()->tab_strip_model()->GetActiveWebContents();
1466 EXPECT_TRUE(content::WaitForLoadStop(extension_web_contents));
1467 EXPECT_EQ(extension->GetResourceURL("page.html").spec(),
1468 extension_web_contents->GetURL().spec());
1469 {
1470 // Let the service worker start and register a filtered listener to
1471 // chrome.webNavigation.onCommitted event.
1472 ExtensionTestMessageListener add_listener_done("listener-added", false);
1473 add_listener_done.set_failure_message("FAILURE");
1474 content::ExecuteScriptAsync(extension_web_contents,
1475 "window.runServiceWorkerAsync()");
1476 EXPECT_TRUE(add_listener_done.WaitUntilSatisfied());
1477
1478 base::RunLoop run_loop;
1479 content::StoragePartition* storage_partition =
1480 content::BrowserContext::GetDefaultStoragePartition(
1481 browser()->profile());
Zhuoyu Qian2266251f2018-10-13 02:59:001482 content::StopServiceWorkerForScope(
Istiaque Ahmed9ce21b32017-10-10 20:43:181483 storage_partition->GetServiceWorkerContext(),
1484 // The service worker is registered at the top level scope.
1485 extension->url(), run_loop.QuitClosure());
1486 run_loop.Run();
1487 }
1488
1489 // Close the tab to |extension|'s resource. This will also close the
1490 // extension's event page.
1491 browser()->tab_strip_model()->CloseWebContentsAt(
1492 browser()->tab_strip_model()->active_index(), TabStripModel::CLOSE_NONE);
1493 lazy_observer.Wait();
1494}
1495
1496IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest,
Istiaque Ahmedf5712522018-09-20 03:35:471497 FilteredEventsAfterRestart) {
Istiaque Ahmed9ce21b32017-10-10 20:43:181498 // Create a tab to a.html, expect it to navigate to b.html. The service worker
1499 // will see two webNavigation.onCommitted events.
1500 ASSERT_TRUE(StartEmbeddedTestServer());
1501 GURL page_url = embedded_test_server()->GetURL(
1502 "/extensions/api_test/service_worker/filtered_events_after_restart/"
1503 "a.html");
1504 ExtensionTestMessageListener worker_filtered_event_listener(
1505 "PASS_FROM_WORKER", false);
1506 worker_filtered_event_listener.set_failure_message("FAIL_FROM_WORKER");
1507 content::WebContents* web_contents = AddTab(browser(), page_url);
1508 EXPECT_TRUE(web_contents);
1509 EXPECT_TRUE(worker_filtered_event_listener.WaitUntilSatisfied());
1510}
1511
Istiaque Ahmedea5ed5042017-09-25 19:00:161512// Run with both native and JS-based bindings. This ensures that both stable
1513// (JS) and experimental (native) phases work correctly with worker scripts
1514// while we launch native bindings to stable.
1515INSTANTIATE_TEST_CASE_P(ServiceWorkerTestWithNativeBindings,
1516 ServiceWorkerTest,
1517 ::testing::Values(NATIVE_BINDINGS));
1518INSTANTIATE_TEST_CASE_P(ServiceWorkerTestWithJSBindings,
1519 ServiceWorkerTest,
1520 ::testing::Values(JAVASCRIPT_BINDINGS));
1521INSTANTIATE_TEST_CASE_P(ServiceWorkerBackgroundSyncTestWithNativeBindings,
1522 ServiceWorkerBackgroundSyncTest,
1523 ::testing::Values(NATIVE_BINDINGS));
1524INSTANTIATE_TEST_CASE_P(ServiceWorkerBackgroundSyncTestWithJSBindings,
1525 ServiceWorkerBackgroundSyncTest,
1526 ::testing::Values(JAVASCRIPT_BINDINGS));
1527INSTANTIATE_TEST_CASE_P(ServiceWorkerPushMessagingTestWithNativeBindings,
1528 ServiceWorkerPushMessagingTest,
1529 ::testing::Values(NATIVE_BINDINGS));
1530INSTANTIATE_TEST_CASE_P(ServiceWorkerPushMessagingTestWithJSBindings,
1531 ServiceWorkerPushMessagingTest,
1532 ::testing::Values(JAVASCRIPT_BINDINGS));
Istiaque Ahmed805f6a83b2017-10-05 01:23:261533INSTANTIATE_TEST_CASE_P(ServiceWorkerLazyBackgroundTestWithNativeBindings,
1534 ServiceWorkerLazyBackgroundTest,
1535 ::testing::Values(NATIVE_BINDINGS));
1536INSTANTIATE_TEST_CASE_P(ServiceWorkerLazyBackgroundTestWithJSBindings,
1537 ServiceWorkerLazyBackgroundTest,
1538 ::testing::Values(JAVASCRIPT_BINDINGS));
Istiaque Ahmedccb444022018-06-19 02:11:121539INSTANTIATE_TEST_CASE_P(ServiceWorkerTestWithNativeBindings,
1540 ServiceWorkerBasedBackgroundTest,
1541 ::testing::Values(NATIVE_BINDINGS));
1542INSTANTIATE_TEST_CASE_P(ServiceWorkerTestWithJSBindings,
1543 ServiceWorkerBasedBackgroundTest,
1544 ::testing::Values(JAVASCRIPT_BINDINGS));
Istiaque Ahmedf70ab222018-10-02 03:08:241545INSTANTIATE_TEST_CASE_P(ServiceWorkerTestWithNativeBindings,
Istiaque Ahmed70f76ac2018-11-02 02:59:551546 ServiceWorkerOnStartupEventTest,
Istiaque Ahmedf70ab222018-10-02 03:08:241547 ::testing::Values(NATIVE_BINDINGS));
1548INSTANTIATE_TEST_CASE_P(ServiceWorkerTestWithJSBindings,
Istiaque Ahmed70f76ac2018-11-02 02:59:551549 ServiceWorkerOnStartupEventTest,
1550 ::testing::Values(JAVASCRIPT_BINDINGS));
1551INSTANTIATE_TEST_CASE_P(ServiceWorkerTestWithNativeBindings,
1552 ServiceWorkerRegistrationAtStartupTest,
1553 ::testing::Values(NATIVE_BINDINGS));
1554INSTANTIATE_TEST_CASE_P(ServiceWorkerTestWithJSBindings,
1555 ServiceWorkerRegistrationAtStartupTest,
Istiaque Ahmedf70ab222018-10-02 03:08:241556 ::testing::Values(JAVASCRIPT_BINDINGS));
Istiaque Ahmedea5ed5042017-09-25 19:00:161557
annekao38685502015-07-14 17:46:391558} // namespace extensions