blob: 80cf208b07cfd4716ea15cd6efc8e43d01145ce8 [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"
Istiaque Ahmedd4b67ee2019-03-02 10:53:2011#include "base/optional.h"
Gabriel Charette078e3662017-08-28 22:59:0412#include "base/run_loop.h"
kalman6f984ae2015-09-18 17:21:5813#include "base/strings/stringprintf.h"
horo1eeddde2015-11-19 05:59:2514#include "base/strings/utf_string_conversions.h"
David Bertoni1d646a152019-04-25 02:09:2215#include "base/test/bind_test_util.h"
jam3f2d3932017-04-26 20:28:5116#include "base/threading/thread_restrictions.h"
Olga Sharonova3e13cd92018-02-08 16:43:5617#include "build/build_config.h"
David Bertoni9026eff2019-05-01 18:04:3118#include "chrome/browser/extensions/crx_installer.h"
Istiaque Ahmed91d6987c2019-06-25 00:09:3319#include "chrome/browser/extensions/extension_action_runner.h"
annekao38685502015-07-14 17:46:3920#include "chrome/browser/extensions/extension_apitest.h"
rdevlin.croninf5863da2015-09-10 19:21:4521#include "chrome/browser/extensions/extension_service.h"
Istiaque Ahmed805f6a83b2017-10-05 01:23:2622#include "chrome/browser/extensions/lazy_background_page_test_util.h"
David Bertoni1d646a152019-04-25 02:09:2223#include "chrome/browser/extensions/unpacked_installer.h"
peter9f4490a2017-01-27 00:58:3624#include "chrome/browser/gcm/gcm_profile_service_factory.h"
miguelg9b502862017-04-24 18:13:5325#include "chrome/browser/notifications/notification_display_service_factory.h"
Peter Beverloodd4ef1e2018-06-21 15:41:0426#include "chrome/browser/notifications/notification_permission_context.h"
miguelg9b502862017-04-24 18:13:5327#include "chrome/browser/notifications/stub_notification_display_service.h"
lshang106c1772016-06-06 01:43:2328#include "chrome/browser/permissions/permission_manager.h"
timlohc6911802017-03-01 05:37:0329#include "chrome/browser/permissions/permission_result.h"
lazyboy561b7de2015-11-19 19:27:3030#include "chrome/browser/push_messaging/push_messaging_app_identifier.h"
31#include "chrome/browser/push_messaging/push_messaging_service_factory.h"
32#include "chrome/browser/push_messaging/push_messaging_service_impl.h"
Istiaque Ahmed91d6987c2019-06-25 00:09:3333#include "chrome/browser/ui/extensions/browser_action_test_util.h"
annekao1db36fd2015-07-29 17:09:1634#include "chrome/browser/ui/tabs/tab_strip_model.h"
Trent Apted4267b942017-10-27 03:25:3635#include "chrome/common/chrome_switches.h"
Istiaque Ahmeda14ec482018-08-25 01:02:1836#include "chrome/common/extensions/api/web_navigation.h"
rdevlin.croninf5863da2015-09-10 19:21:4537#include "chrome/test/base/ui_test_utils.h"
timloh9a180ad2017-02-20 07:15:2338#include "components/content_settings/core/common/content_settings_types.h"
Peter Beverloo34139462018-04-10 14:18:0639#include "components/gcm_driver/fake_gcm_profile_service.h"
johnmea5045732016-09-08 17:23:2940#include "components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h"
sdefresne9fb67692015-08-03 18:48:2241#include "components/version_info/version_info.h"
Devlin Cronin59551d82019-03-05 01:28:5942#include "content/public/browser/console_message.h"
kalman6f984ae2015-09-18 17:21:5843#include "content/public/browser/navigation_controller.h"
rdevlin.croninf5863da2015-09-10 19:21:4544#include "content/public/browser/navigation_entry.h"
Istiaque Ahmedd4b67ee2019-03-02 10:53:2045#include "content/public/browser/render_process_host.h"
lazyboy4c82177a2016-10-18 00:04:0946#include "content/public/browser/service_worker_context.h"
Devlin Cronin59551d82019-03-05 01:28:5947#include "content/public/browser/service_worker_context_observer.h"
lazyboy4c82177a2016-10-18 00:04:0948#include "content/public/browser/storage_partition.h"
kalman6f984ae2015-09-18 17:21:5849#include "content/public/browser/web_contents.h"
lazyboybd325ae2015-11-18 21:35:2650#include "content/public/common/content_switches.h"
falkenad185092016-06-16 06:10:0251#include "content/public/common/origin_util.h"
kalman6f984ae2015-09-18 17:21:5852#include "content/public/common/page_type.h"
Istiaque Ahmedd4b67ee2019-03-02 10:53:2053#include "content/public/common/result_codes.h"
lazyboybd325ae2015-11-18 21:35:2654#include "content/public/test/background_sync_test_util.h"
annekao1db36fd2015-07-29 17:09:1655#include "content/public/test/browser_test_utils.h"
lazyboy63b994a2017-06-30 21:20:2356#include "content/public/test/service_worker_test_helpers.h"
Istiaque Ahmed771aa8a22018-06-20 23:40:5357#include "extensions/browser/event_router.h"
kalman6f984ae2015-09-18 17:21:5858#include "extensions/browser/extension_host.h"
lazyboyc3e763a2015-12-09 23:09:5859#include "extensions/browser/extension_registry.h"
kalman6f984ae2015-09-18 17:21:5860#include "extensions/browser/process_manager.h"
Istiaque Ahmed70f76ac2018-11-02 02:59:5561#include "extensions/browser/service_worker_task_queue.h"
David Bertoni1dc1b7a2019-06-13 02:44:5962#include "extensions/browser/test_extension_registry_observer.h"
Istiaque Ahmeda14ec482018-08-25 01:02:1863#include "extensions/common/api/test.h"
Istiaque Ahmed771aa8a22018-06-20 23:40:5364#include "extensions/common/value_builder.h"
David Bertoni9026eff2019-05-01 18:04:3165#include "extensions/common/verifier_formats.h"
kalman6f984ae2015-09-18 17:21:5866#include "extensions/test/background_page_watcher.h"
annekao38685502015-07-14 17:46:3967#include "extensions/test/extension_test_message_listener.h"
Istiaque Ahmed805f6a83b2017-10-05 01:23:2668#include "extensions/test/result_catcher.h"
Devlin Cronin59551d82019-03-05 01:28:5969#include "extensions/test/test_extension_dir.h"
falkenad185092016-06-16 06:10:0270#include "net/dns/mock_host_resolver.h"
horo1eeddde2015-11-19 05:59:2571#include "net/test/embedded_test_server/embedded_test_server.h"
lazyboy63b994a2017-06-30 21:20:2372#include "url/url_constants.h"
annekao38685502015-07-14 17:46:3973
74namespace extensions {
75
kalman6f984ae2015-09-18 17:21:5876namespace {
77
lazyboy22eddc712015-12-10 21:16:2678// Returns the newly added WebContents.
79content::WebContents* AddTab(Browser* browser, const GURL& url) {
80 int starting_tab_count = browser->tab_strip_model()->count();
81 ui_test_utils::NavigateToURLWithDisposition(
nick3b04f322016-08-31 19:29:1982 browser, url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
lazyboy22eddc712015-12-10 21:16:2683 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
84 int tab_count = browser->tab_strip_model()->count();
85 EXPECT_EQ(starting_tab_count + 1, tab_count);
86 return browser->tab_strip_model()->GetActiveWebContents();
87}
88
lazyboy22eddc712015-12-10 21:16:2689class WebContentsLoadStopObserver : content::WebContentsObserver {
90 public:
91 explicit WebContentsLoadStopObserver(content::WebContents* web_contents)
92 : content::WebContentsObserver(web_contents),
93 load_stop_observed_(false) {}
94
95 void WaitForLoadStop() {
96 if (load_stop_observed_)
97 return;
98 message_loop_runner_ = new content::MessageLoopRunner;
99 message_loop_runner_->Run();
100 }
101
102 private:
103 void DidStopLoading() override {
104 load_stop_observed_ = true;
105 if (message_loop_runner_)
106 message_loop_runner_->Quit();
107 }
108
109 bool load_stop_observed_;
110 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
111
112 DISALLOW_COPY_AND_ASSIGN(WebContentsLoadStopObserver);
113};
114
David Bertoni4d9cf41d2019-06-04 00:06:22115// A known extension ID for tests that specify the key in their
116// manifests.
117constexpr char kTestExtensionId[] = "knldjmfmopnpolahpmmgbagdohdnhkik";
118
kalman6f984ae2015-09-18 17:21:58119} // namespace
120
Devlin Cronin242d19d22019-03-12 18:08:48121class ServiceWorkerTest : public ExtensionApiTest {
annekao38685502015-07-14 17:46:39122 public:
lazyboy20167c22016-05-18 00:59:30123 ServiceWorkerTest() : current_channel_(version_info::Channel::STABLE) {}
Istiaque Ahmed7105f2a2017-10-07 01:11:59124 explicit ServiceWorkerTest(version_info::Channel channel)
125 : current_channel_(channel) {}
annekao38685502015-07-14 17:46:39126
127 ~ServiceWorkerTest() override {}
128
jam1a5b5582017-05-01 16:50:10129 void SetUpOnMainThread() override {
130 ExtensionApiTest::SetUpOnMainThread();
David Bertoni3929f552019-03-28 22:10:36131 host_resolver()->AddRule("*", "127.0.0.1");
jam1a5b5582017-05-01 16:50:10132 }
133
kalman6f984ae2015-09-18 17:21:58134 protected:
135 // Returns the ProcessManager for the test's profile.
136 ProcessManager* process_manager() { return ProcessManager::Get(profile()); }
137
138 // Starts running a test from the background page test extension.
139 //
140 // This registers a service worker with |script_name|, and fetches the
141 // registration result.
Istiaque Ahmed93ff7f42018-08-31 01:42:22142 const Extension* StartTestFromBackgroundPage(const char* script_name) {
Istiaque Ahmed6475f542018-08-28 04:20:21143 ExtensionTestMessageListener ready_listener("ready", false);
kalman6f984ae2015-09-18 17:21:58144 const Extension* extension =
145 LoadExtension(test_data_dir_.AppendASCII("service_worker/background"));
146 CHECK(extension);
Istiaque Ahmed6475f542018-08-28 04:20:21147 CHECK(ready_listener.WaitUntilSatisfied());
148
kalman6f984ae2015-09-18 17:21:58149 ExtensionHost* background_host =
150 process_manager()->GetBackgroundHostForExtension(extension->id());
151 CHECK(background_host);
Istiaque Ahmed6475f542018-08-28 04:20:21152
kalman6f984ae2015-09-18 17:21:58153 std::string error;
154 CHECK(content::ExecuteScriptAndExtractString(
155 background_host->host_contents(),
156 base::StringPrintf("test.registerServiceWorker('%s')", script_name),
157 &error));
Istiaque Ahmed93ff7f42018-08-31 01:42:22158 if (!error.empty())
kalman6f984ae2015-09-18 17:21:58159 ADD_FAILURE() << "Got unexpected error " << error;
160 return extension;
161 }
162
163 // Navigates the browser to a new tab at |url|, waits for it to load, then
164 // returns it.
165 content::WebContents* Navigate(const GURL& url) {
166 ui_test_utils::NavigateToURLWithDisposition(
nick3b04f322016-08-31 19:29:19167 browser(), url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
kalman6f984ae2015-09-18 17:21:58168 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
169 content::WebContents* web_contents =
170 browser()->tab_strip_model()->GetActiveWebContents();
171 content::WaitForLoadStop(web_contents);
172 return web_contents;
173 }
174
175 // Navigates the browser to |url| and returns the new tab's page type.
176 content::PageType NavigateAndGetPageType(const GURL& url) {
clamy1d7a4112018-06-15 15:47:16177 return Navigate(url)
178 ->GetController()
179 .GetLastCommittedEntry()
180 ->GetPageType();
kalman6f984ae2015-09-18 17:21:58181 }
182
183 // Extracts the innerText from |contents|.
184 std::string ExtractInnerText(content::WebContents* contents) {
185 std::string inner_text;
186 if (!content::ExecuteScriptAndExtractString(
187 contents,
188 "window.domAutomationController.send(document.body.innerText)",
189 &inner_text)) {
190 ADD_FAILURE() << "Failed to get inner text for "
191 << contents->GetVisibleURL();
192 }
193 return inner_text;
194 }
195
196 // Navigates the browser to |url|, then returns the innerText of the new
197 // tab's WebContents' main frame.
198 std::string NavigateAndExtractInnerText(const GURL& url) {
199 return ExtractInnerText(Navigate(url));
200 }
201
lazyboy4c82177a2016-10-18 00:04:09202 size_t GetWorkerRefCount(const GURL& origin) {
203 content::ServiceWorkerContext* sw_context =
204 content::BrowserContext::GetDefaultStoragePartition(
205 browser()->profile())
206 ->GetServiceWorkerContext();
207 base::RunLoop run_loop;
208 size_t ref_count = 0;
209 auto set_ref_count = [](size_t* ref_count, base::RunLoop* run_loop,
210 size_t external_request_count) {
211 *ref_count = external_request_count;
212 run_loop->Quit();
213 };
214 sw_context->CountExternalRequestsForTest(
Matt Falkenhagenc5cb4282017-09-07 08:43:42215 origin, base::BindOnce(set_ref_count, &ref_count, &run_loop));
lazyboy4c82177a2016-10-18 00:04:09216 run_loop.Run();
217 return ref_count;
218 }
219
annekao38685502015-07-14 17:46:39220 private:
lazyboy20167c22016-05-18 00:59:30221 // Sets the channel to "stable".
222 // Not useful after we've opened extension Service Workers to stable
223 // channel.
224 // TODO(lazyboy): Remove this when ExtensionServiceWorkersEnabled() is
225 // removed.
annekao38685502015-07-14 17:46:39226 ScopedCurrentChannel current_channel_;
kalman6f984ae2015-09-18 17:21:58227
annekao38685502015-07-14 17:46:39228 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerTest);
229};
230
Istiaque Ahmedccb444022018-06-19 02:11:12231class ServiceWorkerBasedBackgroundTest : public ServiceWorkerTest {
232 public:
233 ServiceWorkerBasedBackgroundTest()
234 : ServiceWorkerTest(
235 // Extensions APIs from SW are only enabled on trunk.
236 // It is important to set the channel early so that this change is
237 // visible in renderers running with service workers (and no
238 // extension).
239 version_info::Channel::UNKNOWN) {}
240 ~ServiceWorkerBasedBackgroundTest() override {}
241
242 void SetUpOnMainThread() override {
243 host_resolver()->AddRule("*", "127.0.0.1");
244 ASSERT_TRUE(embedded_test_server()->Start());
245 ServiceWorkerTest::SetUpOnMainThread();
246 }
247
Istiaque Ahmedd4b67ee2019-03-02 10:53:20248 // Returns the only running worker id for |extension_id|.
249 // Returns base::nullopt if there isn't any worker running or more than one
250 // worker is running for |extension_id|.
251 base::Optional<WorkerId> GetUniqueRunningWorkerId(
252 const ExtensionId& extension_id) {
253 ProcessManager* process_manager = ProcessManager::Get(profile());
254 std::vector<WorkerId> all_workers =
255 process_manager->GetAllWorkersIdsForTesting();
256 base::Optional<WorkerId> running_worker_id;
257 for (const WorkerId& worker_id : all_workers) {
258 if (worker_id.extension_id == extension_id) {
259 if (running_worker_id) // More than one worker present.
260 return base::nullopt;
261 running_worker_id = worker_id;
262 }
263 }
264 return running_worker_id;
265 }
266
David Bertoni023e0ec2019-06-10 17:28:22267 bool ExtensionHasRenderProcessHost(const ExtensionId& extension_id) {
268 ProcessMap* process_map = ProcessMap::Get(browser()->profile());
269 content::RenderProcessHost::iterator it =
270 content::RenderProcessHost::AllHostsIterator();
271 while (!it.IsAtEnd()) {
272 if (process_map->Contains(extension_id, it.GetCurrentValue()->GetID())) {
273 return true;
274 }
275 it.Advance();
276 }
277 return false;
278 }
279
Istiaque Ahmedccb444022018-06-19 02:11:12280 private:
281 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerBasedBackgroundTest);
282};
283
284// Tests that Service Worker based background pages can be loaded and they can
285// receive extension events.
286// The extension is installed and loaded during this step and it registers
287// an event listener for tabs.onCreated event. The step also verifies that tab
288// creation correctly fires the listener.
Devlin Cronin242d19d22019-03-12 18:08:48289IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, PRE_Basic) {
Istiaque Ahmedccb444022018-06-19 02:11:12290 ExtensionTestMessageListener newtab_listener("CREATED", false);
291 newtab_listener.set_failure_message("CREATE_FAILED");
292 ExtensionTestMessageListener worker_listener("WORKER_RUNNING", false);
293 worker_listener.set_failure_message("NON_WORKER_SCOPE");
294 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
295 "service_worker/worker_based_background/basic"));
296 ASSERT_TRUE(extension);
297 const ExtensionId extension_id = extension->id();
298 EXPECT_TRUE(worker_listener.WaitUntilSatisfied());
299
300 const GURL url = embedded_test_server()->GetURL("/extensions/test_file.html");
301 content::WebContents* new_web_contents = AddTab(browser(), url);
302 EXPECT_TRUE(new_web_contents);
303 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
304
305 // Service Worker extension does not have ExtensionHost.
306 EXPECT_FALSE(process_manager()->GetBackgroundHostForExtension(extension_id));
307}
308
309// After browser restarts, this test step ensures that opening a tab fires
310// tabs.onCreated event listener to the extension without explicitly loading the
311// extension. This is because the extension registered a listener before browser
312// restarted in PRE_Basic.
Devlin Cronin242d19d22019-03-12 18:08:48313IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, Basic) {
Istiaque Ahmedccb444022018-06-19 02:11:12314 ExtensionTestMessageListener newtab_listener("CREATED", false);
315 newtab_listener.set_failure_message("CREATE_FAILED");
316 const GURL url = embedded_test_server()->GetURL("/extensions/test_file.html");
317 content::WebContents* new_web_contents = AddTab(browser(), url);
318 EXPECT_TRUE(new_web_contents);
319 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
320}
321
Istiaque Ahmedbf08f952018-10-02 01:22:04322// Tests chrome.runtime.onInstalled fires for extension service workers.
Devlin Cronin242d19d22019-03-12 18:08:48323IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, OnInstalledEvent) {
Istiaque Ahmedbf08f952018-10-02 01:22:04324 ASSERT_TRUE(RunExtensionTest(
325 "service_worker/worker_based_background/events_on_installed"))
326 << message_;
327}
328
Istiaque Ahmedba8d0652019-05-14 15:17:34329// Tests chrome.runtime.id and chrome.runtime.getURL().
330IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, RuntimeMisc) {
331 ASSERT_TRUE(
332 RunExtensionTest("service_worker/worker_based_background/runtime_misc"))
333 << message_;
334}
335
David Bertoni69982832019-02-13 21:24:21336// Tests chrome.storage APIs.
Devlin Cronin242d19d22019-03-12 18:08:48337IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, StorageSetAndGet) {
David Bertoni69982832019-02-13 21:24:21338 ASSERT_TRUE(
339 RunExtensionTest("service_worker/worker_based_background/storage"))
340 << message_;
341}
342
David Bertoni0665c892019-02-14 00:27:26343// Tests chrome.storage.local and chrome.storage.local APIs.
Devlin Cronin242d19d22019-03-12 18:08:48344IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, StorageNoPermissions) {
David Bertoni0665c892019-02-14 00:27:26345 ASSERT_TRUE(RunExtensionTest(
346 "service_worker/worker_based_background/storage_no_permissions"))
347 << message_;
348}
349
David Bertoni30809312019-02-28 22:56:05350// Tests chrome.tabs APIs.
Devlin Cronin242d19d22019-03-12 18:08:48351IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, TabsBasic) {
David Bertoni30809312019-02-28 22:56:05352 ASSERT_TRUE(
353 RunExtensionTest("service_worker/worker_based_background/tabs_basic"))
354 << message_;
355}
356
David Bertoni46d698892019-02-26 00:29:10357// Tests chrome.tabs events.
Devlin Cronin242d19d22019-03-12 18:08:48358IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, TabsEvents) {
David Bertoni46d698892019-02-26 00:29:10359 ASSERT_TRUE(
360 RunExtensionTest("service_worker/worker_based_background/tabs_events"))
361 << message_;
362}
363
David Bertoni4c7dfcc2019-03-27 23:49:34364// Tests chrome.tabs APIs.
365IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, TabsExecuteScript) {
366 ASSERT_TRUE(RunExtensionTest(
367 "service_worker/worker_based_background/tabs_execute_script"))
368 << message_;
369}
370
David Bertoni37ae0222019-04-04 01:30:54371// Tests chrome.webRequest APIs.
David Bertoni3929f552019-03-28 22:10:36372IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, WebRequest) {
373 ASSERT_TRUE(
374 RunExtensionTest("service_worker/worker_based_background/web_request"))
375 << message_;
376}
377
David Bertoni37ae0222019-04-04 01:30:54378// Tests chrome.webRequest APIs in blocking mode.
379IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, WebRequestBlocking) {
380 // Try to load the page before installing the extension, which should work.
381 const GURL url = embedded_test_server()->GetURL("/extensions/test_file.html");
382 EXPECT_EQ(content::PAGE_TYPE_NORMAL, NavigateAndGetPageType(url));
383
384 // Install the extension and navigate again to the page.
385 ExtensionTestMessageListener ready_listener("ready", false);
386 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII(
387 "service_worker/worker_based_background/web_request_blocking")));
388 ASSERT_TRUE(ready_listener.WaitUntilSatisfied());
389 EXPECT_EQ(content::PAGE_TYPE_ERROR, NavigateAndGetPageType(url));
390}
391
David Bertoni377f52312019-05-21 20:35:03392// Tests chrome.webNavigation APIs.
393IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, FilteredEvents) {
394 ASSERT_TRUE(RunExtensionTest(
395 "service_worker/worker_based_background/filtered_events"))
396 << message_;
397}
398
Istiaque Ahmed70f76ac2018-11-02 02:59:55399// Listens for |message| from extension Service Worker early so that tests can
400// wait for the message on startup (and not miss it).
401class ServiceWorkerWithEarlyMessageListenerTest
402 : public ServiceWorkerBasedBackgroundTest {
Istiaque Ahmedf70ab222018-10-02 03:08:24403 public:
Istiaque Ahmed70f76ac2018-11-02 02:59:55404 explicit ServiceWorkerWithEarlyMessageListenerTest(
405 const std::string& test_message)
406 : test_message_(test_message) {}
407 ~ServiceWorkerWithEarlyMessageListenerTest() override = default;
Istiaque Ahmedf70ab222018-10-02 03:08:24408
Istiaque Ahmed70f76ac2018-11-02 02:59:55409 bool WaitForMessage() { return listener_->WaitUntilSatisfied(); }
Istiaque Ahmedf70ab222018-10-02 03:08:24410
411 void CreatedBrowserMainParts(content::BrowserMainParts* main_parts) override {
412 // At this point, the notification service is initialized but the profile
413 // and extensions have not.
Istiaque Ahmed70f76ac2018-11-02 02:59:55414 listener_ =
415 std::make_unique<ExtensionTestMessageListener>(test_message_, false);
Istiaque Ahmedf70ab222018-10-02 03:08:24416 ServiceWorkerBasedBackgroundTest::CreatedBrowserMainParts(main_parts);
417 }
418
419 private:
Istiaque Ahmed70f76ac2018-11-02 02:59:55420 const std::string test_message_;
Istiaque Ahmedf70ab222018-10-02 03:08:24421 std::unique_ptr<ExtensionTestMessageListener> listener_;
422
Istiaque Ahmed70f76ac2018-11-02 02:59:55423 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerWithEarlyMessageListenerTest);
424};
425
426class ServiceWorkerOnStartupEventTest
427 : public ServiceWorkerWithEarlyMessageListenerTest {
428 public:
429 ServiceWorkerOnStartupEventTest()
430 : ServiceWorkerWithEarlyMessageListenerTest("onStartup event") {}
431 ~ServiceWorkerOnStartupEventTest() override = default;
432
433 private:
434 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerOnStartupEventTest);
Istiaque Ahmedf70ab222018-10-02 03:08:24435};
436
437// Tests "runtime.onStartup" for extension SW.
Devlin Cronin242d19d22019-03-12 18:08:48438IN_PROC_BROWSER_TEST_F(ServiceWorkerOnStartupEventTest, PRE_Event) {
Istiaque Ahmedf70ab222018-10-02 03:08:24439 ASSERT_TRUE(RunExtensionTest(
440 "service_worker/worker_based_background/on_startup_event"))
441 << message_;
442}
443
Devlin Cronin242d19d22019-03-12 18:08:48444IN_PROC_BROWSER_TEST_F(ServiceWorkerOnStartupEventTest, Event) {
Istiaque Ahmed70f76ac2018-11-02 02:59:55445 EXPECT_TRUE(WaitForMessage());
446}
447
448class ServiceWorkerRegistrationAtStartupTest
449 : public ServiceWorkerWithEarlyMessageListenerTest,
450 public ServiceWorkerTaskQueue::TestObserver {
451 public:
452 ServiceWorkerRegistrationAtStartupTest()
453 : ServiceWorkerWithEarlyMessageListenerTest("WORKER_RUNNING") {
454 ServiceWorkerTaskQueue::SetObserverForTest(this);
455 }
456 ~ServiceWorkerRegistrationAtStartupTest() override {
457 ServiceWorkerTaskQueue::SetObserverForTest(nullptr);
458 }
459
460 // ServiceWorkerTaskQueue::TestObserver:
461 void OnActivateExtension(const ExtensionId& extension_id,
462 bool will_register_service_worker) override {
463 if (extension_id != kExtensionId)
464 return;
465
466 will_register_service_worker_ = will_register_service_worker;
467
468 extension_activated_ = true;
469 if (run_loop_)
470 run_loop_->Quit();
471 }
472
473 void WaitForOnActivateExtension() {
474 if (extension_activated_)
475 return;
476 run_loop_ = std::make_unique<base::RunLoop>();
477 run_loop_->Run();
478 }
479
480 bool WillRegisterServiceWorker() {
481 return will_register_service_worker_.value();
482 }
483
484 protected:
485 static const char kExtensionId[];
486
487 private:
488 bool extension_activated_ = false;
489 base::Optional<bool> will_register_service_worker_;
490 std::unique_ptr<base::RunLoop> run_loop_;
491
492 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerRegistrationAtStartupTest);
493};
494
495// Test extension id at
496// api_test/service_worker/worker_based_background/registration_at_startup/.
497const char ServiceWorkerRegistrationAtStartupTest::kExtensionId[] =
498 "gnchfmandajfaiajniicagenfmhdjila";
499
500// Tests that Service Worker registration for existing extension isn't issued
501// upon browser restart.
502// Regression test for https://crbug.com/889687.
Devlin Cronin242d19d22019-03-12 18:08:48503IN_PROC_BROWSER_TEST_F(ServiceWorkerRegistrationAtStartupTest,
Istiaque Ahmed70f76ac2018-11-02 02:59:55504 PRE_ExtensionActivationDoesNotReregister) {
505 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
506 "service_worker/worker_based_background/registration_at_startup"));
507 ASSERT_TRUE(extension);
508 EXPECT_EQ(kExtensionId, extension->id());
509 // Wait for "WORKER_RUNNING" message from the Service Worker.
510 EXPECT_TRUE(WaitForMessage());
511 EXPECT_TRUE(WillRegisterServiceWorker());
512}
513
Devlin Cronin242d19d22019-03-12 18:08:48514IN_PROC_BROWSER_TEST_F(ServiceWorkerRegistrationAtStartupTest,
Istiaque Ahmed70f76ac2018-11-02 02:59:55515 ExtensionActivationDoesNotReregister) {
516 // Since the extension has onStartup listener, the Service Worker will run on
517 // browser start and we'll see "WORKER_RUNNING" message from the worker.
518 EXPECT_TRUE(WaitForMessage());
519 // As the extension activated during first run on PRE_ step, it shouldn't
520 // re-register the Service Worker upon browser restart.
521 EXPECT_FALSE(WillRegisterServiceWorker());
Istiaque Ahmedf70ab222018-10-02 03:08:24522}
523
Istiaque Ahmeda14ec482018-08-25 01:02:18524// Class that dispatches an event to |extension_id| right after a
525// non-lazy listener to the event is added from the extension's Service Worker.
Istiaque Ahmed771aa8a22018-06-20 23:40:53526class EarlyWorkerMessageSender : public EventRouter::Observer {
527 public:
528 EarlyWorkerMessageSender(content::BrowserContext* browser_context,
Istiaque Ahmeda14ec482018-08-25 01:02:18529 const ExtensionId& extension_id,
530 std::unique_ptr<Event> event)
Istiaque Ahmed771aa8a22018-06-20 23:40:53531 : browser_context_(browser_context),
532 event_router_(EventRouter::EventRouter::Get(browser_context_)),
533 extension_id_(extension_id),
Istiaque Ahmeda14ec482018-08-25 01:02:18534 event_(std::move(event)),
Istiaque Ahmed771aa8a22018-06-20 23:40:53535 listener_("PASS", false) {
536 DCHECK(browser_context_);
537 listener_.set_failure_message("FAIL");
Istiaque Ahmeda14ec482018-08-25 01:02:18538 event_router_->RegisterObserver(this, event_->event_name);
Istiaque Ahmed771aa8a22018-06-20 23:40:53539 }
540
541 ~EarlyWorkerMessageSender() override {
542 event_router_->UnregisterObserver(this);
543 }
544
545 // EventRouter::Observer:
546 void OnListenerAdded(const EventListenerInfo& details) override {
Istiaque Ahmeda14ec482018-08-25 01:02:18547 if (!event_ || extension_id_ != details.extension_id ||
548 event_->event_name != details.event_name) {
Istiaque Ahmed771aa8a22018-06-20 23:40:53549 return;
Istiaque Ahmeda14ec482018-08-25 01:02:18550 }
551
Istiaque Ahmed771aa8a22018-06-20 23:40:53552 const bool is_lazy_listener = details.browser_context == nullptr;
553 if (is_lazy_listener) {
554 // Wait for the non-lazy listener as we want to exercise the code to
555 // dispatch the event right after the Service Worker registration is
556 // completing.
557 return;
558 }
Istiaque Ahmeda14ec482018-08-25 01:02:18559 DispatchEvent(std::move(event_));
Istiaque Ahmed771aa8a22018-06-20 23:40:53560 }
561
562 bool SendAndWait() { return listener_.WaitUntilSatisfied(); }
563
564 private:
565 static constexpr const char* const kTestOnMessageEventName = "test.onMessage";
566
Istiaque Ahmeda14ec482018-08-25 01:02:18567 void DispatchEvent(std::unique_ptr<Event> event) {
Istiaque Ahmed771aa8a22018-06-20 23:40:53568 EventRouter::Get(browser_context_)
569 ->DispatchEventToExtension(extension_id_, std::move(event));
570 }
571
572 content::BrowserContext* const browser_context_ = nullptr;
573 EventRouter* const event_router_ = nullptr;
574 const ExtensionId extension_id_;
Istiaque Ahmeda14ec482018-08-25 01:02:18575 std::unique_ptr<Event> event_;
Istiaque Ahmed771aa8a22018-06-20 23:40:53576 ExtensionTestMessageListener listener_;
Istiaque Ahmed771aa8a22018-06-20 23:40:53577
578 DISALLOW_COPY_AND_ASSIGN(EarlyWorkerMessageSender);
579};
580
581// Tests that extension event dispatch works correctly right after extension
582// installation registers its Service Worker.
583// Regression test for: https://crbug.com/850792.
Devlin Cronin242d19d22019-03-12 18:08:48584IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, EarlyEventDispatch) {
Istiaque Ahmed771aa8a22018-06-20 23:40:53585 const ExtensionId kId("pkplfbidichfdicaijlchgnapepdginl");
Istiaque Ahmeda14ec482018-08-25 01:02:18586
587 // Build "test.onMessage" event for dispatch.
588 auto event = std::make_unique<Event>(
589 events::FOR_TEST, extensions::api::test::OnMessage::kEventName,
Lei Zhang582ecd12019-02-13 20:28:54590 base::ListValue::From(base::JSONReader::ReadDeprecated(
Istiaque Ahmeda14ec482018-08-25 01:02:18591 R"([{"data": "hello", "lastMessage": true}])")),
592 profile());
593
594 EarlyWorkerMessageSender sender(profile(), kId, std::move(event));
Istiaque Ahmed771aa8a22018-06-20 23:40:53595 // pkplfbidichfdicaijlchgnapepdginl
596 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
597 "service_worker/worker_based_background/early_event_dispatch"));
598 CHECK(extension);
599 EXPECT_EQ(kId, extension->id());
600 EXPECT_TRUE(sender.SendAndWait());
601}
602
Istiaque Ahmeda14ec482018-08-25 01:02:18603// Tests that filtered events dispatches correctly right after a non-lazy
604// listener is registered for that event (and before the corresponding lazy
605// listener is registered).
Devlin Cronin242d19d22019-03-12 18:08:48606IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
Istiaque Ahmeda14ec482018-08-25 01:02:18607 EarlyFilteredEventDispatch) {
608 const ExtensionId kId("pkplfbidichfdicaijlchgnapepdginl");
609
610 // Add minimal details required to dispatch webNavigation.onCommitted event:
611 extensions::api::web_navigation::OnCommitted::Details details;
612 details.transition_type =
613 extensions::api::web_navigation::TRANSITION_TYPE_TYPED;
614
615 // Build a dummy onCommited event to dispatch.
616 auto on_committed_event = std::make_unique<Event>(
617 events::WEB_NAVIGATION_ON_COMMITTED, "webNavigation.onCommitted",
618 api::web_navigation::OnCommitted::Create(details), profile());
619 // The filter will match the listener filter registered from the extension.
620 EventFilteringInfo info;
621 info.url = GURL("http://foo.com/a.html");
622 on_committed_event->filter_info = info;
623
624 EarlyWorkerMessageSender sender(profile(), kId,
625 std::move(on_committed_event));
626
627 // pkplfbidichfdicaijlchgnapepdginl
628 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
629 "service_worker/worker_based_background/early_filtered_event_dispatch"));
630 ASSERT_TRUE(extension);
631 EXPECT_EQ(kId, extension->id());
632 EXPECT_TRUE(sender.SendAndWait());
633}
634
lazyboybd325ae2015-11-18 21:35:26635class ServiceWorkerBackgroundSyncTest : public ServiceWorkerTest {
636 public:
637 ServiceWorkerBackgroundSyncTest() {}
638 ~ServiceWorkerBackgroundSyncTest() override {}
639
640 void SetUpCommandLine(base::CommandLine* command_line) override {
641 // ServiceWorkerRegistration.sync requires experimental flag.
642 command_line->AppendSwitch(
Istiaque Ahmedea5ed5042017-09-25 19:00:16643 ::switches::kEnableExperimentalWebPlatformFeatures);
lazyboybd325ae2015-11-18 21:35:26644 ServiceWorkerTest::SetUpCommandLine(command_line);
645 }
646
647 void SetUp() override {
Robbie McElrathdb12d8e2018-09-18 21:20:40648 content::background_sync_test_util::SetIgnoreNetworkChanges(true);
lazyboybd325ae2015-11-18 21:35:26649 ServiceWorkerTest::SetUp();
650 }
651
652 private:
653 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerBackgroundSyncTest);
654};
655
lazyboy561b7de2015-11-19 19:27:30656class ServiceWorkerPushMessagingTest : public ServiceWorkerTest {
657 public:
658 ServiceWorkerPushMessagingTest()
Sylvain Defresne212b4b02018-10-11 16:32:05659 : scoped_testing_factory_installer_(
660 base::BindRepeating(&gcm::FakeGCMProfileService::Build)),
661 gcm_driver_(nullptr),
662 push_service_(nullptr) {}
663
lazyboy561b7de2015-11-19 19:27:30664 ~ServiceWorkerPushMessagingTest() override {}
665
666 void GrantNotificationPermissionForTest(const GURL& url) {
Peter Beverloodd4ef1e2018-06-21 15:41:04667 NotificationPermissionContext::UpdatePermission(profile(), url.GetOrigin(),
668 CONTENT_SETTING_ALLOW);
lazyboy561b7de2015-11-19 19:27:30669 }
670
671 PushMessagingAppIdentifier GetAppIdentifierForServiceWorkerRegistration(
avia2f4804a2015-12-24 23:11:13672 int64_t service_worker_registration_id,
lazyboy561b7de2015-11-19 19:27:30673 const GURL& origin) {
674 PushMessagingAppIdentifier app_identifier =
675 PushMessagingAppIdentifier::FindByServiceWorker(
676 profile(), origin, service_worker_registration_id);
677
678 EXPECT_FALSE(app_identifier.is_null());
679 return app_identifier;
680 }
681
682 // ExtensionApiTest overrides.
683 void SetUpCommandLine(base::CommandLine* command_line) override {
peter9de96272015-12-04 15:23:27684 command_line->AppendSwitch(
Istiaque Ahmedea5ed5042017-09-25 19:00:16685 ::switches::kEnableExperimentalWebPlatformFeatures);
lazyboy561b7de2015-11-19 19:27:30686 ServiceWorkerTest::SetUpCommandLine(command_line);
687 }
Tanja Gornak89128fd2018-09-18 08:49:34688
lazyboy561b7de2015-11-19 19:27:30689 void SetUpOnMainThread() override {
miguelg9b502862017-04-24 18:13:53690 NotificationDisplayServiceFactory::GetInstance()->SetTestingFactory(
Sylvain Defresne711ff6b2018-10-04 12:33:54691 profile(),
692 base::BindRepeating(&StubNotificationDisplayService::FactoryForTests));
miguelg9b502862017-04-24 18:13:53693
johnmea5045732016-09-08 17:23:29694 gcm::FakeGCMProfileService* gcm_service =
695 static_cast<gcm::FakeGCMProfileService*>(
Tanja Gornak89128fd2018-09-18 08:49:34696 gcm::GCMProfileServiceFactory::GetForProfile(profile()));
johnmea5045732016-09-08 17:23:29697 gcm_driver_ = static_cast<instance_id::FakeGCMDriverForInstanceID*>(
698 gcm_service->driver());
lazyboy561b7de2015-11-19 19:27:30699 push_service_ = PushMessagingServiceFactory::GetForProfile(profile());
700
701 ServiceWorkerTest::SetUpOnMainThread();
702 }
703
johnmea5045732016-09-08 17:23:29704 instance_id::FakeGCMDriverForInstanceID* gcm_driver() const {
705 return gcm_driver_;
706 }
lazyboy561b7de2015-11-19 19:27:30707 PushMessagingServiceImpl* push_service() const { return push_service_; }
708
709 private:
Sylvain Defresne212b4b02018-10-11 16:32:05710 gcm::GCMProfileServiceFactory::ScopedTestingFactoryInstaller
711 scoped_testing_factory_installer_;
712
johnmea5045732016-09-08 17:23:29713 instance_id::FakeGCMDriverForInstanceID* gcm_driver_;
lazyboy561b7de2015-11-19 19:27:30714 PushMessagingServiceImpl* push_service_;
715
716 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerPushMessagingTest);
717};
718
Istiaque Ahmed805f6a83b2017-10-05 01:23:26719class ServiceWorkerLazyBackgroundTest : public ServiceWorkerTest {
720 public:
Istiaque Ahmed7105f2a2017-10-07 01:11:59721 ServiceWorkerLazyBackgroundTest()
722 : ServiceWorkerTest(
723 // Extensions APIs from SW are only enabled on trunk.
724 // It is important to set the channel early so that this change is
725 // visible in renderers running with service workers (and no
726 // extension).
727 version_info::Channel::UNKNOWN) {}
Istiaque Ahmed805f6a83b2017-10-05 01:23:26728 ~ServiceWorkerLazyBackgroundTest() override {}
729
730 void SetUpCommandLine(base::CommandLine* command_line) override {
731 ServiceWorkerTest::SetUpCommandLine(command_line);
732 // Disable background network activity as it can suddenly bring the Lazy
733 // Background Page alive.
734 command_line->AppendSwitch(::switches::kDisableBackgroundNetworking);
735 command_line->AppendSwitch(::switches::kNoProxyServer);
736 }
737
738 void SetUpInProcessBrowserTestFixture() override {
739 ServiceWorkerTest::SetUpInProcessBrowserTestFixture();
740 // Set shorter delays to prevent test timeouts.
741 ProcessManager::SetEventPageIdleTimeForTesting(1);
742 ProcessManager::SetEventPageSuspendingTimeForTesting(1);
743 }
744
745 private:
746 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerLazyBackgroundTest);
747};
748
Devlin Cronin242d19d22019-03-12 18:08:48749IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, RegisterSucceeds) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22750 StartTestFromBackgroundPage("register.js");
annekao38685502015-07-14 17:46:39751}
752
Devlin Cronin242d19d22019-03-12 18:08:48753IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, UpdateRefreshesServiceWorker) {
Francois Doraye6fb2d02017-10-18 21:29:13754 base::ScopedAllowBlockingForTesting allow_blocking;
lazyboyc3e763a2015-12-09 23:09:58755 base::ScopedTempDir scoped_temp_dir;
756 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
757 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
758 .AppendASCII("update")
759 .AppendASCII("service_worker.pem");
vabr9142fe22016-09-08 13:19:22760 base::FilePath path_v1 =
761 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
762 .AppendASCII("update")
763 .AppendASCII("v1"),
764 scoped_temp_dir.GetPath().AppendASCII("v1.crx"),
765 pem_path, base::FilePath());
766 base::FilePath path_v2 =
767 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
768 .AppendASCII("update")
769 .AppendASCII("v2"),
770 scoped_temp_dir.GetPath().AppendASCII("v2.crx"),
771 pem_path, base::FilePath());
lazyboyc3e763a2015-12-09 23:09:58772 const char* kId = "hfaanndiiilofhfokeanhddpkfffchdi";
773
774 ExtensionTestMessageListener listener_v1("Pong from version 1", false);
775 listener_v1.set_failure_message("FAILURE_V1");
776 // Install version 1.0 of the extension.
777 ASSERT_TRUE(InstallExtension(path_v1, 1));
778 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
779 ->enabled_extensions()
780 .GetByID(kId));
781 EXPECT_TRUE(listener_v1.WaitUntilSatisfied());
782
783 ExtensionTestMessageListener listener_v2("Pong from version 2", false);
784 listener_v2.set_failure_message("FAILURE_V2");
785
786 // Update to version 2.0.
787 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
788 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
789 ->enabled_extensions()
790 .GetByID(kId));
791 EXPECT_TRUE(listener_v2.WaitUntilSatisfied());
792}
793
[email protected]2ef85d562017-09-15 18:41:52794// TODO(crbug.com/765736) Fix the test.
Devlin Cronin242d19d22019-03-12 18:08:48795IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, DISABLED_UpdateWithoutSkipWaiting) {
Francois Doraye6fb2d02017-10-18 21:29:13796 base::ScopedAllowBlockingForTesting allow_blocking;
lazyboy22eddc712015-12-10 21:16:26797 base::ScopedTempDir scoped_temp_dir;
798 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
799 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
800 .AppendASCII("update_without_skip_waiting")
801 .AppendASCII("update_without_skip_waiting.pem");
vabr9142fe22016-09-08 13:19:22802 base::FilePath path_v1 =
803 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
804 .AppendASCII("update_without_skip_waiting")
805 .AppendASCII("v1"),
806 scoped_temp_dir.GetPath().AppendASCII("v1.crx"),
807 pem_path, base::FilePath());
808 base::FilePath path_v2 =
809 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
810 .AppendASCII("update_without_skip_waiting")
811 .AppendASCII("v2"),
812 scoped_temp_dir.GetPath().AppendASCII("v2.crx"),
813 pem_path, base::FilePath());
lazyboy22eddc712015-12-10 21:16:26814 const char* kId = "mhnnnflgagdakldgjpfcofkiocpdmogl";
815
816 // Install version 1.0 of the extension.
817 ASSERT_TRUE(InstallExtension(path_v1, 1));
818 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
819 ->enabled_extensions()
820 .GetByID(kId));
821 const Extension* extension = extensions::ExtensionRegistry::Get(profile())
822 ->enabled_extensions()
823 .GetByID(kId);
824
825 ExtensionTestMessageListener listener1("Pong from version 1", false);
826 listener1.set_failure_message("FAILURE");
827 content::WebContents* web_contents =
828 AddTab(browser(), extension->GetResourceURL("page.html"));
829 EXPECT_TRUE(listener1.WaitUntilSatisfied());
830
831 // Update to version 2.0.
832 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
833 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
834 ->enabled_extensions()
835 .GetByID(kId));
836 const Extension* extension_after_update =
837 extensions::ExtensionRegistry::Get(profile())
838 ->enabled_extensions()
839 .GetByID(kId);
840
841 // Service worker version 2 would be installed but it won't be controlling
842 // the extension page yet.
843 ExtensionTestMessageListener listener2("Pong from version 1", false);
844 listener2.set_failure_message("FAILURE");
845 web_contents =
846 AddTab(browser(), extension_after_update->GetResourceURL("page.html"));
847 EXPECT_TRUE(listener2.WaitUntilSatisfied());
848
849 // Navigate the tab away from the extension page so that no clients are
850 // using the service worker.
851 // Note that just closing the tab with WebContentsDestroyedWatcher doesn't
852 // seem to be enough because it returns too early.
853 WebContentsLoadStopObserver navigate_away_observer(web_contents);
854 web_contents->GetController().LoadURL(
855 GURL(url::kAboutBlankURL), content::Referrer(), ui::PAGE_TRANSITION_TYPED,
856 std::string());
857 navigate_away_observer.WaitForLoadStop();
858
859 // Now expect service worker version 2 to control the extension page.
860 ExtensionTestMessageListener listener3("Pong from version 2", false);
861 listener3.set_failure_message("FAILURE");
862 web_contents =
863 AddTab(browser(), extension_after_update->GetResourceURL("page.html"));
864 EXPECT_TRUE(listener3.WaitUntilSatisfied());
865}
866
Devlin Cronin242d19d22019-03-12 18:08:48867IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, FetchArbitraryPaths) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22868 const Extension* extension = StartTestFromBackgroundPage("fetch.js");
annekao1db36fd2015-07-29 17:09:16869
kalman6f984ae2015-09-18 17:21:58870 // Open some arbirary paths. Their contents should be what the service worker
871 // responds with, which in this case is the path of the fetch.
872 EXPECT_EQ(
873 "Caught a fetch for /index.html",
874 NavigateAndExtractInnerText(extension->GetResourceURL("index.html")));
875 EXPECT_EQ("Caught a fetch for /path/to/other.html",
876 NavigateAndExtractInnerText(
877 extension->GetResourceURL("path/to/other.html")));
878 EXPECT_EQ("Caught a fetch for /some/text/file.txt",
879 NavigateAndExtractInnerText(
880 extension->GetResourceURL("some/text/file.txt")));
881 EXPECT_EQ("Caught a fetch for /no/file/extension",
882 NavigateAndExtractInnerText(
883 extension->GetResourceURL("no/file/extension")));
884 EXPECT_EQ("Caught a fetch for /",
885 NavigateAndExtractInnerText(extension->GetResourceURL("")));
annekao1db36fd2015-07-29 17:09:16886}
887
Devlin Cronin242d19d22019-03-12 18:08:48888IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
Kenichi Ishibashi773b82972018-08-30 07:02:03889 FetchExtensionResourceFromServiceWorker) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22890 const Extension* extension = StartTestFromBackgroundPage("fetch_from_sw.js");
Kenichi Ishibashi773b82972018-08-30 07:02:03891 ASSERT_TRUE(extension);
892
893 // The service worker in this test tries to load 'hello.txt' via fetch()
894 // and sends back the content of the file, which should be 'hello'.
895 const char* kScript = R"(
896 let channel = new MessageChannel();
897 test.waitForMessage(channel.port1).then(message => {
898 window.domAutomationController.send(message);
899 });
900 test.registeredServiceWorker.postMessage(
901 {port: channel.port2}, [channel.port2]);
902 )";
903 EXPECT_EQ("hello", ExecuteScriptInBackgroundPage(extension->id(), kScript));
904}
905
Kenichi Ishibashi09ee5e72018-11-27 07:12:38906// Tests that fetch() from service worker and network fallback
907// go through webRequest.onBeforeRequest API.
Devlin Cronin242d19d22019-03-12 18:08:48908IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, OnBeforeRequest) {
Kenichi Ishibashi09ee5e72018-11-27 07:12:38909 const Extension* extension = LoadExtensionWithFlags(
910 test_data_dir_.AppendASCII("service_worker/webrequest"), kFlagNone);
911 ASSERT_TRUE(extension);
912 ASSERT_TRUE(StartEmbeddedTestServer());
913
914 // Start a service worker and make it control the page.
915 GURL page_url = embedded_test_server()->GetURL(
916 "/extensions/api_test/service_worker/"
917 "webrequest/webpage.html");
918 content::WebContents* web_contents =
919 browser()->tab_strip_model()->GetActiveWebContents();
920 ui_test_utils::NavigateToURL(browser(), page_url);
921 content::WaitForLoadStop(web_contents);
922
923 std::string result;
924 ASSERT_TRUE(content::ExecuteScriptAndExtractString(web_contents,
925 "register();", &result));
926 EXPECT_EQ("ready", result);
927
928 // Initiate a fetch that the service worker doesn't intercept
929 // (network fallback).
930 result.clear();
931 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
932 web_contents, "doFetch('hello.txt?fallthrough');", &result));
933 EXPECT_EQ("hello", result);
934 EXPECT_EQ(
935 "/extensions/api_test/service_worker/webrequest/hello.txt?fallthrough",
936 ExecuteScriptInBackgroundPage(extension->id(), "getLastHookedPath()"));
937
938 // Initiate a fetch that results in calling fetch() in the service worker.
939 result.clear();
940 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
941 web_contents, "doFetch('hello.txt?respondWithFetch');", &result));
942 EXPECT_EQ("hello", result);
943 EXPECT_EQ(
944 "/extensions/api_test/service_worker/webrequest/"
945 "hello.txt?respondWithFetch",
946 ExecuteScriptInBackgroundPage(extension->id(), "getLastHookedPath()"));
947}
948
Devlin Cronin242d19d22019-03-12 18:08:48949IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, SWServedBackgroundPageReceivesEvent) {
lazyboy52c3bcf2016-01-08 00:11:29950 const Extension* extension =
Istiaque Ahmed93ff7f42018-08-31 01:42:22951 StartTestFromBackgroundPage("replace_background.js");
lazyboy52c3bcf2016-01-08 00:11:29952 ExtensionHost* background_page =
953 process_manager()->GetBackgroundHostForExtension(extension->id());
954 ASSERT_TRUE(background_page);
955
956 // Close the background page and start it again so that the service worker
957 // will start controlling pages.
958 background_page->Close();
959 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
960 background_page = nullptr;
Peter Kasting341e1fb2018-02-24 00:03:01961 process_manager()->WakeEventPage(extension->id(), base::DoNothing());
lazyboy52c3bcf2016-01-08 00:11:29962 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
963
964 // Since the SW is now controlling the extension, the SW serves the background
965 // script. page.html sends a message to the background script and we verify
966 // that the SW served background script correctly receives the message/event.
967 ExtensionTestMessageListener listener("onMessage/SW BG.", false);
968 listener.set_failure_message("onMessage/original BG.");
969 content::WebContents* web_contents =
970 AddTab(browser(), extension->GetResourceURL("page.html"));
971 ASSERT_TRUE(web_contents);
972 EXPECT_TRUE(listener.WaitUntilSatisfied());
973}
974
Devlin Cronin242d19d22019-03-12 18:08:48975IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, SWServedBackgroundPage) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22976 const Extension* extension = StartTestFromBackgroundPage("fetch.js");
annekao49241182015-08-18 17:14:01977
kalman6f984ae2015-09-18 17:21:58978 std::string kExpectedInnerText = "background.html contents for testing.";
annekao49241182015-08-18 17:14:01979
kalman6f984ae2015-09-18 17:21:58980 // Sanity check that the background page has the expected content.
981 ExtensionHost* background_page =
982 process_manager()->GetBackgroundHostForExtension(extension->id());
983 ASSERT_TRUE(background_page);
984 EXPECT_EQ(kExpectedInnerText,
985 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:01986
kalman6f984ae2015-09-18 17:21:58987 // Close the background page.
988 background_page->Close();
989 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
990 background_page = nullptr;
991
992 // Start it again.
Peter Kasting341e1fb2018-02-24 00:03:01993 process_manager()->WakeEventPage(extension->id(), base::DoNothing());
kalman6f984ae2015-09-18 17:21:58994 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
995
Matt Falkenhagena612fc02018-05-30 00:35:39996 // The service worker should get a fetch event for the background page.
kalman6f984ae2015-09-18 17:21:58997 background_page =
998 process_manager()->GetBackgroundHostForExtension(extension->id());
999 ASSERT_TRUE(background_page);
1000 content::WaitForLoadStop(background_page->host_contents());
1001
kalman6f984ae2015-09-18 17:21:581002 EXPECT_EQ("Caught a fetch for /background.html",
1003 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:011004}
1005
Devlin Cronin242d19d22019-03-12 18:08:481006IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:581007 ServiceWorkerPostsMessageToBackgroundClient) {
Istiaque Ahmed93ff7f42018-08-31 01:42:221008 const Extension* extension =
1009 StartTestFromBackgroundPage("post_message_to_background_client.js");
annekao533482222015-08-21 23:23:531010
kalman6f984ae2015-09-18 17:21:581011 // The service worker in this test simply posts a message to the background
1012 // client it receives from getBackgroundClient().
1013 const char* kScript =
1014 "var messagePromise = null;\n"
1015 "if (test.lastMessageFromServiceWorker) {\n"
1016 " messagePromise = Promise.resolve(test.lastMessageFromServiceWorker);\n"
1017 "} else {\n"
1018 " messagePromise = test.waitForMessage(navigator.serviceWorker);\n"
1019 "}\n"
1020 "messagePromise.then(function(message) {\n"
1021 " window.domAutomationController.send(String(message == 'success'));\n"
1022 "})\n";
1023 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:531024}
1025
Devlin Cronin242d19d22019-03-12 18:08:481026IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:581027 BackgroundPagePostsMessageToServiceWorker) {
1028 const Extension* extension =
Istiaque Ahmed93ff7f42018-08-31 01:42:221029 StartTestFromBackgroundPage("post_message_to_sw.js");
annekao533482222015-08-21 23:23:531030
kalman6f984ae2015-09-18 17:21:581031 // The service worker in this test waits for a message, then echoes it back
1032 // by posting a message to the background page via getBackgroundClient().
1033 const char* kScript =
1034 "var mc = new MessageChannel();\n"
1035 "test.waitForMessage(mc.port1).then(function(message) {\n"
1036 " window.domAutomationController.send(String(message == 'hello'));\n"
1037 "});\n"
1038 "test.registeredServiceWorker.postMessage(\n"
1039 " {message: 'hello', port: mc.port2}, [mc.port2])\n";
1040 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:531041}
1042
Devlin Cronin242d19d22019-03-12 18:08:481043IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
rdevlin.croninf5863da2015-09-10 19:21:451044 ServiceWorkerSuspensionOnExtensionUnload) {
kalman6f984ae2015-09-18 17:21:581045 // For this test, only hold onto the extension's ID and URL + a function to
1046 // get a resource URL, because we're going to be disabling and uninstalling
1047 // it, which will invalidate the pointer.
1048 std::string extension_id;
1049 GURL extension_url;
1050 {
Istiaque Ahmed93ff7f42018-08-31 01:42:221051 const Extension* extension = StartTestFromBackgroundPage("fetch.js");
kalman6f984ae2015-09-18 17:21:581052 extension_id = extension->id();
1053 extension_url = extension->url();
1054 }
1055 auto get_resource_url = [&extension_url](const std::string& path) {
1056 return Extension::GetResourceURL(extension_url, path);
1057 };
rdevlin.croninf5863da2015-09-10 19:21:451058
kalman6f984ae2015-09-18 17:21:581059 // Fetch should route to the service worker.
1060 EXPECT_EQ("Caught a fetch for /index.html",
1061 NavigateAndExtractInnerText(get_resource_url("index.html")));
rdevlin.croninf5863da2015-09-10 19:21:451062
kalman6f984ae2015-09-18 17:21:581063 // Disable the extension. Opening the page should fail.
1064 extension_service()->DisableExtension(extension_id,
Minh X. Nguyen45479012017-08-18 21:35:361065 disable_reason::DISABLE_USER_ACTION);
rdevlin.croninf5863da2015-09-10 19:21:451066 base::RunLoop().RunUntilIdle();
rdevlin.croninf5863da2015-09-10 19:21:451067
kalman6f984ae2015-09-18 17:21:581068 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1069 NavigateAndGetPageType(get_resource_url("index.html")));
1070 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1071 NavigateAndGetPageType(get_resource_url("other.html")));
1072
1073 // Re-enable the extension. Opening pages should immediately start to succeed
1074 // again.
rdevlin.croninf5863da2015-09-10 19:21:451075 extension_service()->EnableExtension(extension_id);
1076 base::RunLoop().RunUntilIdle();
1077
kalman6f984ae2015-09-18 17:21:581078 EXPECT_EQ("Caught a fetch for /index.html",
1079 NavigateAndExtractInnerText(get_resource_url("index.html")));
1080 EXPECT_EQ("Caught a fetch for /other.html",
1081 NavigateAndExtractInnerText(get_resource_url("other.html")));
1082 EXPECT_EQ("Caught a fetch for /another.html",
1083 NavigateAndExtractInnerText(get_resource_url("another.html")));
rdevlin.croninf5863da2015-09-10 19:21:451084
kalman6f984ae2015-09-18 17:21:581085 // Uninstall the extension. Opening pages should fail again.
1086 base::string16 error;
1087 extension_service()->UninstallExtension(
Devlin Cronin218df7f2017-11-21 21:41:311088 extension_id, UninstallReason::UNINSTALL_REASON_FOR_TESTING, &error);
kalman6f984ae2015-09-18 17:21:581089 base::RunLoop().RunUntilIdle();
1090
1091 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1092 NavigateAndGetPageType(get_resource_url("index.html")));
1093 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1094 NavigateAndGetPageType(get_resource_url("other.html")));
1095 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1096 NavigateAndGetPageType(get_resource_url("anotherother.html")));
1097 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1098 NavigateAndGetPageType(get_resource_url("final.html")));
1099}
1100
Devlin Cronin242d19d22019-03-12 18:08:481101IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, BackgroundPageIsWokenIfAsleep) {
Istiaque Ahmed93ff7f42018-08-31 01:42:221102 const Extension* extension = StartTestFromBackgroundPage("wake_on_fetch.js");
kalman6f984ae2015-09-18 17:21:581103
1104 // Navigate to special URLs that this test's service worker recognises, each
1105 // making a check then populating the response with either "true" or "false".
1106 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
1107 "background-client-is-awake")));
1108 EXPECT_EQ("true", NavigateAndExtractInnerText(
1109 extension->GetResourceURL("ping-background-client")));
1110 // Ping more than once for good measure.
1111 EXPECT_EQ("true", NavigateAndExtractInnerText(
1112 extension->GetResourceURL("ping-background-client")));
1113
1114 // Shut down the event page. The SW should detect that it's closed, but still
1115 // be able to ping it.
1116 ExtensionHost* background_page =
1117 process_manager()->GetBackgroundHostForExtension(extension->id());
1118 ASSERT_TRUE(background_page);
1119 background_page->Close();
1120 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
1121
1122 EXPECT_EQ("false", NavigateAndExtractInnerText(extension->GetResourceURL(
1123 "background-client-is-awake")));
1124 EXPECT_EQ("true", NavigateAndExtractInnerText(
1125 extension->GetResourceURL("ping-background-client")));
1126 EXPECT_EQ("true", NavigateAndExtractInnerText(
1127 extension->GetResourceURL("ping-background-client")));
1128 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
1129 "background-client-is-awake")));
1130}
1131
Devlin Cronin242d19d22019-03-12 18:08:481132IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:581133 GetBackgroundClientFailsWithNoBackgroundPage) {
1134 // This extension doesn't have a background page, only a tab at page.html.
1135 // The service worker it registers tries to call getBackgroundClient() and
1136 // should fail.
1137 // Note that this also tests that service workers can be registered from tabs.
1138 EXPECT_TRUE(RunExtensionSubtest("service_worker/no_background", "page.html"));
rdevlin.croninf5863da2015-09-10 19:21:451139}
1140
Devlin Cronin242d19d22019-03-12 18:08:481141IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, NotificationAPI) {
lazyboy6ddb7d62015-11-10 23:15:271142 EXPECT_TRUE(RunExtensionSubtest("service_worker/notifications/has_permission",
1143 "page.html"));
1144}
1145
Devlin Cronin242d19d22019-03-12 18:08:481146IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, WebAccessibleResourcesFetch) {
lazyboyaea32c22016-01-04 21:37:071147 EXPECT_TRUE(RunExtensionSubtest(
1148 "service_worker/web_accessible_resources/fetch/", "page.html"));
1149}
1150
David Bertoni9026eff2019-05-01 18:04:311151// Tests that updating a packed extension with modified scripts works
1152// properly -- we expect that the new script will execute, rather than the
1153// previous one.
1154IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, UpdatePackedExtension) {
1155 // Extensions APIs from SW are only enabled on trunk.
1156 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1157 constexpr char kManifest1[] =
1158 R"({
1159 "name": "Test Extension",
1160 "manifest_version": 2,
1161 "version": "0.1",
1162 "background": {"service_worker": "script.js"}
1163 })";
David Bertoni353f0fb42019-05-30 15:53:301164 constexpr char kNewVersionString[] = "0.2";
1165
David Bertoni9026eff2019-05-01 18:04:311166 // This script installs an event listener for updates to the extension with
1167 // a callback that forces itself to reload.
David Bertoni353f0fb42019-05-30 15:53:301168 constexpr char kScript1[] =
David Bertoni9026eff2019-05-01 18:04:311169 R"(
1170 chrome.runtime.onUpdateAvailable.addListener(function(details) {
David Bertoni353f0fb42019-05-30 15:53:301171 chrome.test.assertEq('%s', details.version);
David Bertoni9026eff2019-05-01 18:04:311172 chrome.runtime.reload();
1173 });
1174 chrome.test.sendMessage('ready1');
1175 )";
1176
1177 std::string id;
1178 TestExtensionDir test_dir;
1179
1180 // Write the manifest and script files and load the extension.
1181 test_dir.WriteManifest(kManifest1);
David Bertoni353f0fb42019-05-30 15:53:301182 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"),
1183 base::StringPrintf(kScript1, kNewVersionString));
David Bertoni9026eff2019-05-01 18:04:311184
1185 {
1186 ExtensionTestMessageListener ready_listener("ready1", false);
1187 base::FilePath path = test_dir.Pack();
1188 const Extension* extension = LoadExtension(path);
1189 ASSERT_TRUE(extension);
1190
1191 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
1192 id = extension->id();
1193 }
1194
1195 constexpr char kManifest2[] =
1196 R"({
1197 "name": "Test Extension",
1198 "manifest_version": 2,
David Bertoni353f0fb42019-05-30 15:53:301199 "version": "%s",
David Bertoni9026eff2019-05-01 18:04:311200 "background": {"service_worker": "script.js"}
1201 })";
David Bertoni353f0fb42019-05-30 15:53:301202 constexpr char kScript2[] =
1203 R"(
1204 chrome.runtime.onInstalled.addListener(function(details) {
1205 chrome.test.assertEq('update', details.reason);
1206 chrome.test.sendMessage('onInstalled');
1207 });
1208 chrome.test.sendMessage('ready2');
1209 )";
David Bertoni9026eff2019-05-01 18:04:311210 // Rewrite the manifest and script files with a version change in the manifest
1211 // file. After reloading the extension, the old version of the extension
1212 // should detect the update, force the reload, and the new script should
1213 // execute.
David Bertoni353f0fb42019-05-30 15:53:301214 test_dir.WriteManifest(base::StringPrintf(kManifest2, kNewVersionString));
1215 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"), kScript2);
David Bertoni9026eff2019-05-01 18:04:311216 {
1217 ExtensionTestMessageListener ready_listener("ready2", false);
David Bertoni353f0fb42019-05-30 15:53:301218 ExtensionTestMessageListener on_installed_listener("onInstalled", false);
David Bertoni9026eff2019-05-01 18:04:311219 base::FilePath path = test_dir.Pack();
1220 ExtensionService* const extension_service =
1221 ExtensionSystem::Get(profile())->extension_service();
1222 EXPECT_TRUE(extension_service->UpdateExtension(
1223 CRXFileInfo(id, GetTestVerifierFormat(), path), true, nullptr));
1224 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
1225 EXPECT_EQ("0.2", ExtensionRegistry::Get(profile())
1226 ->enabled_extensions()
1227 .GetByID(id)
1228 ->version()
1229 .GetString());
David Bertoni353f0fb42019-05-30 15:53:301230 EXPECT_TRUE(on_installed_listener.WaitUntilSatisfied());
David Bertoni9026eff2019-05-01 18:04:311231 }
1232}
1233
David Bertoni1d646a152019-04-25 02:09:221234// Tests that updating an unpacked extension with modified scripts works
1235// properly -- we expect that the new script will execute, rather than the
1236// previous one.
1237IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, UpdateUnpackedExtension) {
1238 // Extensions APIs from SW are only enabled on trunk.
1239 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1240 constexpr char kManifest1[] =
1241 R"({
1242 "name": "Test Extension",
1243 "manifest_version": 2,
1244 "version": "0.1",
1245 "background": {"service_worker": "script.js"}
1246 })";
1247 constexpr char kManifest2[] =
1248 R"({
1249 "name": "Test Extension",
1250 "manifest_version": 2,
1251 "version": "0.2",
1252 "background": {"service_worker": "script.js"}
1253 })";
David Bertoni353f0fb42019-05-30 15:53:301254 constexpr char kScript[] =
1255 R"(
1256 chrome.runtime.onInstalled.addListener(function(details) {
1257 chrome.test.assertEq('%s', details.reason);
1258 chrome.test.sendMessage('onInstalled');
1259 });
1260 chrome.test.sendMessage('%s');
1261 )";
David Bertoni1d646a152019-04-25 02:09:221262
1263 std::string id;
1264
1265 ExtensionService* const extension_service =
1266 ExtensionSystem::Get(profile())->extension_service();
1267 scoped_refptr<UnpackedInstaller> installer =
1268 UnpackedInstaller::Create(extension_service);
1269
1270 // Set a completion callback so we can get the ID of the extension.
1271 installer->set_completion_callback(base::BindLambdaForTesting(
1272 [&id](const Extension* extension, const base::FilePath& path,
1273 const std::string& error) {
1274 ASSERT_TRUE(extension);
1275 ASSERT_TRUE(error.empty());
1276 id = extension->id();
1277 }));
1278
1279 TestExtensionDir test_dir;
1280
1281 // Write the manifest and script files and load the extension.
1282 test_dir.WriteManifest(kManifest1);
1283 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"),
David Bertoni353f0fb42019-05-30 15:53:301284 base::StringPrintf(kScript, "install", "ready1"));
David Bertoni1d646a152019-04-25 02:09:221285 {
1286 ExtensionTestMessageListener ready_listener("ready1", false);
David Bertoni353f0fb42019-05-30 15:53:301287 ExtensionTestMessageListener on_installed_listener("onInstalled", false);
David Bertoni1d646a152019-04-25 02:09:221288
1289 installer->Load(test_dir.UnpackedPath());
1290 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
David Bertoni353f0fb42019-05-30 15:53:301291 EXPECT_TRUE(on_installed_listener.WaitUntilSatisfied());
David Bertoni1d646a152019-04-25 02:09:221292 ASSERT_FALSE(id.empty());
1293 }
1294
1295 // Rewrite the script file without a version change in the manifest and reload
1296 // the extension. The new script should execute.
1297 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"),
David Bertoni353f0fb42019-05-30 15:53:301298 base::StringPrintf(kScript, "update", "ready2"));
David Bertoni1d646a152019-04-25 02:09:221299 {
1300 ExtensionTestMessageListener ready_listener("ready2", false);
David Bertoni353f0fb42019-05-30 15:53:301301 ExtensionTestMessageListener on_installed_listener("onInstalled", false);
David Bertoni1d646a152019-04-25 02:09:221302
1303 extension_service->ReloadExtension(id);
1304 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
David Bertoni353f0fb42019-05-30 15:53:301305 EXPECT_TRUE(on_installed_listener.WaitUntilSatisfied());
David Bertoni1d646a152019-04-25 02:09:221306 }
1307
1308 // Rewrite the manifest and script files with a version change in the manifest
1309 // file. After reloading the extension, the new script should execute.
1310 test_dir.WriteManifest(kManifest2);
1311 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"),
David Bertoni353f0fb42019-05-30 15:53:301312 base::StringPrintf(kScript, "update", "ready3"));
David Bertoni1d646a152019-04-25 02:09:221313 {
1314 ExtensionTestMessageListener ready_listener("ready3", false);
David Bertoni353f0fb42019-05-30 15:53:301315 ExtensionTestMessageListener on_installed_listener("onInstalled", false);
David Bertoni1d646a152019-04-25 02:09:221316
1317 extension_service->ReloadExtension(id);
1318 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
David Bertoni353f0fb42019-05-30 15:53:301319 EXPECT_TRUE(on_installed_listener.WaitUntilSatisfied());
David Bertoni1d646a152019-04-25 02:09:221320 }
1321}
1322
lazyboyaea32c22016-01-04 21:37:071323// This test loads a web page that has an iframe pointing to a
1324// chrome-extension:// URL. The URL is listed in the extension's
1325// web_accessible_resources. Initially the iframe is served from the extension's
1326// resource file. After verifying that, we register a Service Worker that
1327// controls the extension. Further requests to the same resource as before
1328// should now be served by the Service Worker.
1329// This test also verifies that if the requested resource exists in the manifest
1330// but is not present in the extension directory, the Service Worker can still
1331// serve the resource file.
Devlin Cronin242d19d22019-03-12 18:08:481332IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, WebAccessibleResourcesIframeSrc) {
lazyboyaea32c22016-01-04 21:37:071333 const Extension* extension = LoadExtensionWithFlags(
1334 test_data_dir_.AppendASCII(
1335 "service_worker/web_accessible_resources/iframe_src"),
1336 kFlagNone);
1337 ASSERT_TRUE(extension);
1338 ASSERT_TRUE(StartEmbeddedTestServer());
falkenad185092016-06-16 06:10:021339
1340 // Service workers can only control secure contexts
1341 // (https://w3c.github.io/webappsec-secure-contexts/). For documents, this
1342 // typically means the document must have a secure origin AND all its ancestor
1343 // frames must have documents with secure origins. However, extension pages
1344 // are considered secure, even if they have an ancestor document that is an
1345 // insecure context (see GetSchemesBypassingSecureContextCheckWhitelist). So
1346 // extension service workers must be able to control an extension page
1347 // embedded in an insecure context. To test this, set up an insecure
1348 // (non-localhost, non-https) URL for the web page. This page will create
1349 // iframes that load extension pages that must be controllable by service
1350 // worker.
falkenad185092016-06-16 06:10:021351 GURL page_url =
1352 embedded_test_server()->GetURL("a.com",
1353 "/extensions/api_test/service_worker/"
1354 "web_accessible_resources/webpage.html");
1355 EXPECT_FALSE(content::IsOriginSecure(page_url));
lazyboyaea32c22016-01-04 21:37:071356
1357 content::WebContents* web_contents = AddTab(browser(), page_url);
1358 std::string result;
1359 // webpage.html will create an iframe pointing to a resource from |extension|.
1360 // Expect the resource to be served by the extension.
1361 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1362 web_contents, base::StringPrintf("window.testIframe('%s', 'iframe.html')",
1363 extension->id().c_str()),
1364 &result));
1365 EXPECT_EQ("FROM_EXTENSION_RESOURCE", result);
1366
1367 ExtensionTestMessageListener service_worker_ready_listener("SW_READY", false);
1368 EXPECT_TRUE(ExecuteScriptInBackgroundPageNoWait(
1369 extension->id(), "window.registerServiceWorker()"));
1370 EXPECT_TRUE(service_worker_ready_listener.WaitUntilSatisfied());
1371
1372 result.clear();
1373 // webpage.html will create another iframe pointing to a resource from
1374 // |extension| as before. But this time, the resource should be be served
1375 // from the Service Worker.
1376 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1377 web_contents, base::StringPrintf("window.testIframe('%s', 'iframe.html')",
1378 extension->id().c_str()),
1379 &result));
1380 EXPECT_EQ("FROM_SW_RESOURCE", result);
1381
1382 result.clear();
1383 // webpage.html will create yet another iframe pointing to a resource that
1384 // exists in the extension manifest's web_accessible_resources, but is not
1385 // present in the extension directory. Expect the resources of the iframe to
1386 // be served by the Service Worker.
1387 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1388 web_contents,
1389 base::StringPrintf("window.testIframe('%s', 'iframe_non_existent.html')",
1390 extension->id().c_str()),
1391 &result));
1392 EXPECT_EQ("FROM_SW_RESOURCE", result);
1393}
1394
Devlin Cronin242d19d22019-03-12 18:08:481395IN_PROC_BROWSER_TEST_F(ServiceWorkerBackgroundSyncTest, Sync) {
lazyboybd325ae2015-11-18 21:35:261396 const Extension* extension = LoadExtensionWithFlags(
1397 test_data_dir_.AppendASCII("service_worker/sync"), kFlagNone);
1398 ASSERT_TRUE(extension);
1399 ui_test_utils::NavigateToURL(browser(),
1400 extension->GetResourceURL("page.html"));
1401 content::WebContents* web_contents =
1402 browser()->tab_strip_model()->GetActiveWebContents();
1403
1404 // Prevent firing by going offline.
1405 content::background_sync_test_util::SetOnline(web_contents, false);
1406
1407 ExtensionTestMessageListener sync_listener("SYNC: send-chats", false);
1408 sync_listener.set_failure_message("FAIL");
1409
1410 std::string result;
1411 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
1412 web_contents, "window.runServiceWorker()", &result));
1413 ASSERT_EQ("SERVICE_WORKER_READY", result);
1414
1415 EXPECT_FALSE(sync_listener.was_satisfied());
1416 // Resume firing by going online.
1417 content::background_sync_test_util::SetOnline(web_contents, true);
1418 EXPECT_TRUE(sync_listener.WaitUntilSatisfied());
1419}
1420
Devlin Cronin242d19d22019-03-12 18:08:481421IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
horo1eeddde2015-11-19 05:59:251422 FetchFromContentScriptShouldNotGoToServiceWorkerOfPage) {
1423 ASSERT_TRUE(StartEmbeddedTestServer());
1424 GURL page_url = embedded_test_server()->GetURL(
1425 "/extensions/api_test/service_worker/content_script_fetch/"
1426 "controlled_page/index.html");
1427 content::WebContents* tab =
1428 browser()->tab_strip_model()->GetActiveWebContents();
1429 ui_test_utils::NavigateToURL(browser(), page_url);
1430 content::WaitForLoadStop(tab);
1431
1432 std::string value;
1433 ASSERT_TRUE(
1434 content::ExecuteScriptAndExtractString(tab, "register();", &value));
1435 EXPECT_EQ("SW controlled", value);
1436
1437 ASSERT_TRUE(RunExtensionTest("service_worker/content_script_fetch"))
1438 << message_;
1439}
1440
Devlin Cronin242d19d22019-03-12 18:08:481441IN_PROC_BROWSER_TEST_F(ServiceWorkerPushMessagingTest, OnPush) {
lazyboy561b7de2015-11-19 19:27:301442 const Extension* extension = LoadExtensionWithFlags(
1443 test_data_dir_.AppendASCII("service_worker/push_messaging"), kFlagNone);
1444 ASSERT_TRUE(extension);
1445 GURL extension_url = extension->url();
1446
Peter Beverloodd4ef1e2018-06-21 15:41:041447 GrantNotificationPermissionForTest(extension_url);
lazyboy561b7de2015-11-19 19:27:301448
1449 GURL url = extension->GetResourceURL("page.html");
1450 ui_test_utils::NavigateToURL(browser(), url);
1451
1452 content::WebContents* web_contents =
1453 browser()->tab_strip_model()->GetActiveWebContents();
1454
1455 // Start the ServiceWorker.
1456 ExtensionTestMessageListener ready_listener("SERVICE_WORKER_READY", false);
1457 ready_listener.set_failure_message("SERVICE_WORKER_FAILURE");
1458 const char* kScript = "window.runServiceWorker()";
1459 EXPECT_TRUE(content::ExecuteScript(web_contents->GetMainFrame(), kScript));
1460 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
1461
1462 PushMessagingAppIdentifier app_identifier =
1463 GetAppIdentifierForServiceWorkerRegistration(0LL, extension_url);
johnmea5045732016-09-08 17:23:291464 ASSERT_EQ(app_identifier.app_id(), gcm_driver()->last_gettoken_app_id());
1465 EXPECT_EQ("1234567890", gcm_driver()->last_gettoken_authorized_entity());
lazyboy561b7de2015-11-19 19:27:301466
lazyboyd429e2582016-05-20 20:18:521467 base::RunLoop run_loop;
lazyboy561b7de2015-11-19 19:27:301468 // Send a push message via gcm and expect the ServiceWorker to receive it.
1469 ExtensionTestMessageListener push_message_listener("OK", false);
1470 push_message_listener.set_failure_message("FAIL");
1471 gcm::IncomingMessage message;
1472 message.sender_id = "1234567890";
1473 message.raw_data = "testdata";
1474 message.decrypted = true;
lazyboyd429e2582016-05-20 20:18:521475 push_service()->SetMessageCallbackForTesting(run_loop.QuitClosure());
lazyboy561b7de2015-11-19 19:27:301476 push_service()->OnMessage(app_identifier.app_id(), message);
1477 EXPECT_TRUE(push_message_listener.WaitUntilSatisfied());
lazyboyd429e2582016-05-20 20:18:521478 run_loop.Run(); // Wait until the message is handled by push service.
lazyboy561b7de2015-11-19 19:27:301479}
Devlin Cronin242d19d22019-03-12 18:08:481480IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, MimeHandlerView) {
Rob Wue89b90032018-02-16 19:46:081481 ASSERT_TRUE(RunExtensionTest("service_worker/mime_handler_view"));
1482}
1483
David Bertoni3b3597d82019-06-22 02:29:361484// An observer for service worker registration events.
1485class TestRegistrationObserver : public content::ServiceWorkerContextObserver {
David Bertoni22aeae52019-06-10 22:42:531486 public:
David Bertoni3b3597d82019-06-22 02:29:361487 using RegistrationsMap = std::map<GURL, int>;
1488
1489 explicit TestRegistrationObserver(content::ServiceWorkerContext* context)
1490 : context_(context) {
David Bertoni22aeae52019-06-10 22:42:531491 context_->AddObserver(this);
1492 }
1493
David Bertoni3b3597d82019-06-22 02:29:361494 ~TestRegistrationObserver() override {
David Bertoni22aeae52019-06-10 22:42:531495 if (context_) {
1496 context_->RemoveObserver(this);
1497 }
1498 }
1499
David Bertoni3b3597d82019-06-22 02:29:361500 // Wait for the first service worker registration with an extension scheme
1501 // scope to be stored.
1502 void WaitForRegistrationStored() { stored_run_loop_.Run(); }
1503
1504 int GetCompletedCount(const GURL& scope) const {
1505 const auto it = registrations_completed_map_.find(scope);
1506 return it == registrations_completed_map_.end() ? 0 : it->second;
1507 }
1508
1509 private:
1510 // ServiceWorkerContextObserver overrides.
1511 void OnRegistrationCompleted(const GURL& scope) override {
1512 ++registrations_completed_map_[scope];
1513 }
1514
David Bertoni22aeae52019-06-10 22:42:531515 void OnRegistrationStored(int64_t registration_id,
1516 const GURL& scope) override {
1517 if (scope.SchemeIs(kExtensionScheme)) {
David Bertoni3b3597d82019-06-22 02:29:361518 stored_run_loop_.Quit();
David Bertoni22aeae52019-06-10 22:42:531519 }
1520 }
1521
1522 void OnDestruct(content::ServiceWorkerContext* context) override {
1523 context_ = nullptr;
1524 }
1525
David Bertoni3b3597d82019-06-22 02:29:361526 RegistrationsMap registrations_completed_map_;
1527 base::RunLoop stored_run_loop_;
David Bertoni22aeae52019-06-10 22:42:531528 content::ServiceWorkerContext* context_;
David Bertoni22aeae52019-06-10 22:42:531529};
1530
1531IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
1532 EventsToStoppedWorker) {
1533 content::StoragePartition* storage_partition =
1534 content::BrowserContext::GetDefaultStoragePartition(browser()->profile());
1535 content::ServiceWorkerContext* context =
1536 storage_partition->GetServiceWorkerContext();
1537
1538 // Set up an observer to wait for the registration to be stored.
David Bertoni3b3597d82019-06-22 02:29:361539 TestRegistrationObserver observer(context);
David Bertoni22aeae52019-06-10 22:42:531540
1541 ExtensionTestMessageListener event_listener_added("ready", false);
1542 event_listener_added.set_failure_message("ERROR");
1543 const Extension* extension = LoadExtensionWithFlags(
1544 test_data_dir_.AppendASCII(
1545 "service_worker/worker_based_background/events_to_stopped_worker"),
1546 kFlagNone);
1547 ASSERT_TRUE(extension);
1548
David Bertoni3b3597d82019-06-22 02:29:361549 observer.WaitForRegistrationStored();
David Bertoni22aeae52019-06-10 22:42:531550 EXPECT_TRUE(event_listener_added.WaitUntilSatisfied());
1551
1552 // Stop the service worker.
1553 {
1554 base::RunLoop run_loop;
1555 // The service worker is registered at the root scope.
1556 content::StopServiceWorkerForScope(context, extension->url(),
1557 run_loop.QuitClosure());
1558 run_loop.Run();
1559 }
1560
1561 // Navigate to a URL, which should wake up the service worker.
1562 ExtensionTestMessageListener finished_listener("finished", false);
1563 ui_test_utils::NavigateToURL(browser(),
1564 extension->GetResourceURL("page.html"));
1565 EXPECT_TRUE(finished_listener.WaitUntilSatisfied());
1566}
1567
David Bertoni3b3597d82019-06-22 02:29:361568// Tests the restriction on registering service worker scripts at root scope.
1569IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
1570 ServiceWorkerScriptRootScope) {
1571 content::StoragePartition* storage_partition =
1572 content::BrowserContext::GetDefaultStoragePartition(browser()->profile());
1573 content::ServiceWorkerContext* context =
1574 storage_partition->GetServiceWorkerContext();
1575
1576 // Set up an observer to track all SW registrations. We expect only
1577 // one for the extension's root scope. This test attempts to register
1578 // an additional service worker, which will fail.
1579 TestRegistrationObserver observer(context);
1580 ExtensionTestMessageListener registration_listener("REGISTRATION_FAILED",
1581 false);
1582 registration_listener.set_failure_message("WORKER_STARTED");
1583 const Extension* extension = LoadExtensionWithFlags(
1584 test_data_dir_.AppendASCII(
1585 "service_worker/worker_based_background/script_root_scope"),
1586 kFlagNone);
1587 ASSERT_TRUE(extension);
1588
1589 EXPECT_TRUE(registration_listener.WaitUntilSatisfied());
1590 // We expect exactly one registration, which is the one specified in the
1591 // manifest.
1592 EXPECT_EQ(1, observer.GetCompletedCount(extension->url()));
1593}
1594
Devlin Cronin242d19d22019-03-12 18:08:481595IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
Istiaque Ahmedd4b67ee2019-03-02 10:53:201596 ProcessManagerRegistrationOnShutdown) {
1597 // Note that StopServiceWorkerForScope call below expects the worker to be
1598 // completely installed, so wait for the |extension| worker to see "activate"
1599 // event.
1600 ExtensionTestMessageListener activated_listener("WORKER_ACTIVATED", false);
1601 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
1602 "service_worker/worker_based_background/process_manager"));
1603 ASSERT_TRUE(extension);
1604 EXPECT_TRUE(activated_listener.WaitUntilSatisfied());
1605
1606 base::Optional<WorkerId> worker_id =
1607 GetUniqueRunningWorkerId(extension->id());
1608 ASSERT_TRUE(worker_id);
1609 {
1610 // Shutdown the worker.
1611 // TODO(lazyboy): Ideally we'd want to test worker shutdown on idle, do that
1612 // once //content API allows to override test timeouts for Service Workers.
1613 base::RunLoop run_loop;
1614 content::StoragePartition* storage_partition =
1615 content::BrowserContext::GetDefaultStoragePartition(
1616 browser()->profile());
1617 GURL scope = extension->url();
1618 content::StopServiceWorkerForScope(
1619 storage_partition->GetServiceWorkerContext(),
1620 // The service worker is registered at the top level scope.
1621 extension->url(), run_loop.QuitClosure());
1622 run_loop.Run();
1623 }
1624
1625 EXPECT_FALSE(ProcessManager::Get(profile())->HasServiceWorker(*worker_id));
1626}
1627
Devlin Cronin242d19d22019-03-12 18:08:481628IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
Istiaque Ahmedd4b67ee2019-03-02 10:53:201629 ProcessManagerRegistrationOnTerminate) {
1630 // NOTE: It is not necessary to wait for "activate" event from the worker
1631 // for this test, but we're lazily reusing the extension from
1632 // ProcessManagerRegistrationOnShutdown test.
1633 ExtensionTestMessageListener activated_listener("WORKER_ACTIVATED", false);
1634 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
1635 "service_worker/worker_based_background/process_manager"));
1636 ASSERT_TRUE(extension);
1637 EXPECT_TRUE(activated_listener.WaitUntilSatisfied());
1638
1639 base::Optional<WorkerId> worker_id =
1640 GetUniqueRunningWorkerId(extension->id());
1641 ASSERT_TRUE(worker_id);
1642 {
1643 // Terminate worker's RenderProcessHost.
1644 content::RenderProcessHost* worker_render_process_host =
1645 content::RenderProcessHost::FromID(worker_id->render_process_id);
1646 ASSERT_TRUE(worker_render_process_host);
1647 content::RenderProcessHostWatcher process_exit_observer(
1648 worker_render_process_host,
1649 content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1650 worker_render_process_host->Shutdown(content::RESULT_CODE_KILLED);
1651 process_exit_observer.Wait();
1652 }
1653
1654 EXPECT_FALSE(ProcessManager::Get(profile())->HasServiceWorker(*worker_id));
1655}
1656
David Bertoni904dd602019-06-24 21:42:091657// Tests that worker ref count increments while extension API function is
1658// active.
1659IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, WorkerRefCount) {
1660 ExtensionTestMessageListener worker_start_listener("WORKER STARTED", false);
1661
1662 const Extension* extension = LoadExtensionWithFlags(
1663 test_data_dir_.AppendASCII(
1664 "service_worker/worker_based_background/worker_ref_count"),
1665 kFlagNone);
1666 ASSERT_TRUE(extension);
1667 ASSERT_TRUE(worker_start_listener.WaitUntilSatisfied());
1668
1669 ui_test_utils::NavigateToURL(browser(),
1670 extension->GetResourceURL("page.html"));
1671 content::WebContents* web_contents =
1672 browser()->tab_strip_model()->GetActiveWebContents();
1673
1674 // Service worker should have no pending requests because it hasn't performed
1675 // any extension API request yet.
1676 EXPECT_EQ(0u, GetWorkerRefCount(extension->url()));
1677
1678 ExtensionTestMessageListener worker_listener("CHECK_REF_COUNT", true);
1679 worker_listener.set_failure_message("FAILURE");
1680 ASSERT_TRUE(content::ExecuteScript(web_contents, "window.testSendMessage()"));
1681 ASSERT_TRUE(worker_listener.WaitUntilSatisfied());
1682
1683 // Service worker should have exactly one pending request because
1684 // chrome.test.sendMessage() API call is in-flight.
1685 EXPECT_EQ(1u, GetWorkerRefCount(extension->url()));
1686
1687 // Perform another extension API request while one is ongoing.
1688 {
1689 ExtensionTestMessageListener listener("CHECK_REF_COUNT", true);
1690 listener.set_failure_message("FAILURE");
1691 ASSERT_TRUE(
1692 content::ExecuteScript(web_contents, "window.testSendMessage()"));
1693 ASSERT_TRUE(listener.WaitUntilSatisfied());
1694
1695 // Service worker currently has two extension API requests in-flight.
1696 EXPECT_EQ(2u, GetWorkerRefCount(extension->url()));
1697 // Finish executing the nested chrome.test.sendMessage() first.
1698 listener.Reply("Hello world");
1699 }
1700
1701 ExtensionTestMessageListener worker_completion_listener("SUCCESS_FROM_WORKER",
1702 false);
1703 // Finish executing chrome.test.sendMessage().
1704 worker_listener.Reply("Hello world");
1705 EXPECT_TRUE(worker_completion_listener.WaitUntilSatisfied());
1706
1707 // The following block makes sure we have received all the IPCs related to
1708 // ref-count from the worker.
1709 {
1710 // The following roundtrip:
1711 // browser->extension->worker->extension->browser
1712 // will ensure that the worker sent the relevant ref count IPCs.
1713 std::string result;
1714 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1715 web_contents, "window.roundtripToWorker();", &result));
1716 EXPECT_EQ("roundtrip-succeeded", result);
1717
1718 // Ensure IO thread IPCs run.
1719 content::RunAllTasksUntilIdle();
1720 }
1721
1722 // The ref count should drop to 0.
1723 EXPECT_EQ(0u, GetWorkerRefCount(extension->url()));
1724}
1725
David Bertoni1dc1b7a2019-06-13 02:44:591726IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, UninstallSelf) {
1727 constexpr char kManifest[] =
1728 R"({
1729 "name": "Test Extension",
1730 "manifest_version": 2,
1731 "version": "0.1",
1732 "background": {"service_worker": "script.js"}
1733 })";
1734
1735 // This script uninstalls itself.
1736 constexpr char kScript[] =
1737 "chrome.management.uninstallSelf({showConfirmDialog: false});";
1738
1739 TestExtensionDir test_dir;
1740
1741 test_dir.WriteManifest(kManifest);
1742 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"), kScript);
1743
David Bertoni67977a32019-06-13 22:46:011744 // Construct this before loading the extension, since the extension will
David Bertoni1dc1b7a2019-06-13 02:44:591745 // immediately uninstall itself when it loads.
1746 extensions::TestExtensionRegistryObserver observer(
1747 extensions::ExtensionRegistry::Get(browser()->profile()));
1748
1749 base::FilePath path = test_dir.Pack();
1750 scoped_refptr<const Extension> extension = LoadExtension(path);
1751
1752 EXPECT_EQ(extension, observer.WaitForExtensionUninstalled());
1753}
1754
David Bertoni4d9cf41d2019-06-04 00:06:221755IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
1756 PRE_EventsAfterRestart) {
1757 ExtensionTestMessageListener event_added_listener("ready", false);
1758 const Extension* extension = LoadExtensionWithFlags(
1759 test_data_dir_.AppendASCII(
1760 "service_worker/worker_based_background/events_to_stopped_extension"),
1761 kFlagNone);
1762 ASSERT_TRUE(extension);
1763 EXPECT_EQ(kTestExtensionId, extension->id());
1764 ProcessManager* pm = ProcessManager::Get(browser()->profile());
1765 // TODO(crbug.com/969884): This will break once keep alive counts
1766 // for service workers are tracked by the Process Manager.
1767 EXPECT_LT(pm->GetLazyKeepaliveCount(extension), 1);
1768 EXPECT_TRUE(pm->GetLazyKeepaliveActivities(extension).empty());
1769 EXPECT_TRUE(event_added_listener.WaitUntilSatisfied());
1770}
1771
1772// After browser restarts, this test step ensures that opening a tab fires
1773// tabs.onCreated event listener to the extension without explicitly loading the
1774// extension. This is because the extension registered a listener for
1775// tabs.onMoved before browser restarted in PRE_EventsAfterRestart.
1776IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, EventsAfterRestart) {
1777 // Verify there is no RenderProcessHost for the extension.
David Bertoni023e0ec2019-06-10 17:28:221778 EXPECT_FALSE(ExtensionHasRenderProcessHost(kTestExtensionId));
David Bertoni4d9cf41d2019-06-04 00:06:221779
1780 ExtensionTestMessageListener moved_tab_listener("moved-tab", false);
1781 // Add a tab, then move it.
1782 content::WebContents* new_web_contents =
1783 AddTab(browser(), GURL(url::kAboutBlankURL));
1784 EXPECT_TRUE(new_web_contents);
1785 browser()->tab_strip_model()->MoveWebContentsAt(
1786 browser()->tab_strip_model()->count() - 1, 0, false);
1787 EXPECT_TRUE(moved_tab_listener.WaitUntilSatisfied());
1788}
1789
Istiaque Ahmed1e59aec2019-06-05 22:40:241790IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, TabsOnCreated) {
1791 ASSERT_TRUE(RunExtensionTestWithFlags("tabs/lazy_background_on_created",
1792 kFlagRunAsServiceWorkerBasedExtension))
1793 << message_;
1794}
1795
David Bertoni023e0ec2019-06-10 17:28:221796IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
1797 PRE_FilteredEventsAfterRestart) {
1798 ExtensionTestMessageListener listener_added("ready", false);
1799 const Extension* extension = LoadExtensionWithFlags(
1800 test_data_dir_.AppendASCII("service_worker/worker_based_background/"
1801 "filtered_events_after_restart"),
1802 kFlagNone);
1803 ASSERT_TRUE(extension);
1804 EXPECT_EQ(kTestExtensionId, extension->id());
1805 ProcessManager* pm = ProcessManager::Get(browser()->profile());
1806 // TODO(crbug.com/969884): This will break once keep alive counts
1807 // for service workers are tracked by the Process Manager.
1808 EXPECT_LT(pm->GetLazyKeepaliveCount(extension), 1);
1809 EXPECT_TRUE(pm->GetLazyKeepaliveActivities(extension).empty());
1810 EXPECT_TRUE(listener_added.WaitUntilSatisfied());
1811}
1812
1813// After browser restarts, this test step ensures that opening a tab fires
1814// tabs.onCreated event listener to the extension without explicitly loading the
1815// extension. This is because the extension registered a listener for
1816// tabs.onMoved before browser restarted in PRE_EventsAfterRestart.
1817IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
1818 FilteredEventsAfterRestart) {
1819 // Verify there is no RenderProcessHost for the extension.
1820 // TODO(crbug.com/971309): This is currently broken because the test
1821 // infrastructure opens a tab, which dispatches an event to our
1822 // extension, even though the filter doesn't include that URL. The
1823 // referenced bug is about moving filtering into the EventRouter so they
1824 // get filtered before being dispatched.
1825 EXPECT_TRUE(ExtensionHasRenderProcessHost(kTestExtensionId));
1826
1827 // Create a tab to a.html, expect it to navigate to b.html. The service worker
1828 // will see two webNavigation.onCommitted events.
1829 GURL page_url = embedded_test_server()->GetURL(
1830 "/extensions/api_test/service_worker/worker_based_background/"
1831 "filtered_events_after_restart/"
1832 "a.html");
1833 ExtensionTestMessageListener worker_filtered_event_listener(
1834 "PASS_FROM_WORKER", false);
1835 worker_filtered_event_listener.set_failure_message("FAIL_FROM_WORKER");
1836 content::WebContents* web_contents = AddTab(browser(), page_url);
1837 EXPECT_TRUE(web_contents);
1838 EXPECT_TRUE(worker_filtered_event_listener.WaitUntilSatisfied());
1839}
1840
Istiaque Ahmed91d6987c2019-06-25 00:09:331841// Tests that chrome.browserAction.onClicked sees user gesture.
1842IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
1843 BrowserActionUserGesture) {
1844 // First, load |extension| first so that it has browserAction.onClicked
1845 // listener registered.
1846 ExtensionTestMessageListener listener_added("ready", false);
1847 const Extension* extension = LoadExtension(
1848 test_data_dir_.AppendASCII("service_worker/worker_based_background/"
1849 "browser_action"));
1850 ASSERT_TRUE(extension);
1851 EXPECT_TRUE(listener_added.WaitUntilSatisfied());
1852
1853 ResultCatcher catcher;
1854 // Click on browser action to start the test.
1855 {
1856 content::WebContents* web_contents = AddTab(browser(), GURL("about:blank"));
1857 ASSERT_TRUE(web_contents);
1858 ExtensionActionRunner::GetForWebContents(
1859 browser()->tab_strip_model()->GetActiveWebContents())
1860 ->RunAction(extension, true);
1861 }
1862 EXPECT_TRUE(catcher.GetNextResult()) << message_;
1863}
1864
Devlin Cronin59551d82019-03-05 01:28:591865// Tests that console messages logged by extension service workers, both via
1866// the typical console.* methods and via our custom bindings console, are
1867// passed through the normal ServiceWorker console messaging and are
1868// observable.
Devlin Cronin242d19d22019-03-12 18:08:481869IN_PROC_BROWSER_TEST_F(ServiceWorkerLazyBackgroundTest, ConsoleLogging) {
Devlin Cronin59551d82019-03-05 01:28:591870 // A helper class to wait for a particular message to be logged from a
1871 // ServiceWorker.
1872 class ConsoleMessageObserver : public content::ServiceWorkerContextObserver {
1873 public:
1874 ConsoleMessageObserver(content::BrowserContext* browser_context,
1875 const std::string& expected_message)
1876 : expected_message_(base::UTF8ToUTF16(expected_message)),
1877 scoped_observer_(this) {
1878 content::StoragePartition* partition =
1879 content::BrowserContext::GetDefaultStoragePartition(browser_context);
1880 scoped_observer_.Add(partition->GetServiceWorkerContext());
1881 }
1882 ~ConsoleMessageObserver() override = default;
1883
1884 void Wait() { run_loop_.Run(); }
1885
1886 private:
1887 // ServiceWorkerContextObserver:
1888 void OnReportConsoleMessage(
1889 int64_t version_id,
1890 const content::ConsoleMessage& message) override {
1891 // NOTE: We could check the version_id, but it shouldn't be necessary with
1892 // the expected messages we're verifying (they're uncommon enough).
1893 if (message.message != expected_message_)
1894 return;
1895 scoped_observer_.RemoveAll();
1896 run_loop_.QuitWhenIdle();
1897 }
1898
1899 base::string16 expected_message_;
1900 base::RunLoop run_loop_;
1901 ScopedObserver<content::ServiceWorkerContext,
1902 content::ServiceWorkerContextObserver>
1903 scoped_observer_;
1904
1905 DISALLOW_COPY_AND_ASSIGN(ConsoleMessageObserver);
1906 };
1907
1908 TestExtensionDir test_dir;
1909 test_dir.WriteManifest(
1910 R"({
1911 "name": "Test Extension",
1912 "manifest_version": 2,
1913 "version": "0.1",
David Bertoni630837d2019-04-02 21:22:101914 "background": {"service_worker": "script.js"}
Devlin Cronin59551d82019-03-05 01:28:591915 })");
1916 constexpr char kScript[] =
1917 R"(// First, log a message using the normal, built-in blink console.
1918 console.log('test message');
1919 chrome.test.runTests([
1920 function justATest() {
1921 // Next, we use the "Console" object from
1922 // extensions/renderer/console.cc, which is used by custom bindings
1923 // so that it isn't tampered with by untrusted script. The test
1924 // custom bindings log a message whenever a test is passed, so we
1925 // force a log by just passing this test.
1926 chrome.test.succeed();
1927 }
1928 ]);)";
1929 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"), kScript);
1930
1931 // The observer for the built-in blink console.
1932 ConsoleMessageObserver default_console_observer(profile(), "test message");
1933 // The observer for our custom extensions bindings console.
1934 ConsoleMessageObserver custom_console_observer(profile(),
1935 "[SUCCESS] justATest");
1936
1937 const Extension* extension = LoadExtension(test_dir.UnpackedPath());
1938 ASSERT_TRUE(extension);
1939
1940 default_console_observer.Wait();
1941 custom_console_observer.Wait();
1942 // If we receive both messages, we passed!
1943}
1944
annekao38685502015-07-14 17:46:391945} // namespace extensions