blob: 9e2077c25ec9dbbe2dcfdf31bf82c85d5d58ebc8 [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"
jam3f2d3932017-04-26 20:28:5115#include "base/threading/thread_restrictions.h"
Olga Sharonova3e13cd92018-02-08 16:43:5616#include "build/build_config.h"
annekao38685502015-07-14 17:46:3917#include "chrome/browser/extensions/extension_apitest.h"
rdevlin.croninf5863da2015-09-10 19:21:4518#include "chrome/browser/extensions/extension_service.h"
Istiaque Ahmed805f6a83b2017-10-05 01:23:2619#include "chrome/browser/extensions/lazy_background_page_test_util.h"
peter9f4490a2017-01-27 00:58:3620#include "chrome/browser/gcm/gcm_profile_service_factory.h"
miguelg9b502862017-04-24 18:13:5321#include "chrome/browser/notifications/notification_display_service_factory.h"
Peter Beverloodd4ef1e2018-06-21 15:41:0422#include "chrome/browser/notifications/notification_permission_context.h"
miguelg9b502862017-04-24 18:13:5323#include "chrome/browser/notifications/stub_notification_display_service.h"
lshang106c1772016-06-06 01:43:2324#include "chrome/browser/permissions/permission_manager.h"
timlohc6911802017-03-01 05:37:0325#include "chrome/browser/permissions/permission_result.h"
lazyboy561b7de2015-11-19 19:27:3026#include "chrome/browser/push_messaging/push_messaging_app_identifier.h"
27#include "chrome/browser/push_messaging/push_messaging_service_factory.h"
28#include "chrome/browser/push_messaging/push_messaging_service_impl.h"
annekao1db36fd2015-07-29 17:09:1629#include "chrome/browser/ui/tabs/tab_strip_model.h"
Trent Apted4267b942017-10-27 03:25:3630#include "chrome/common/chrome_switches.h"
Istiaque Ahmeda14ec482018-08-25 01:02:1831#include "chrome/common/extensions/api/web_navigation.h"
rdevlin.croninf5863da2015-09-10 19:21:4532#include "chrome/test/base/ui_test_utils.h"
timloh9a180ad2017-02-20 07:15:2333#include "components/content_settings/core/common/content_settings_types.h"
Peter Beverloo34139462018-04-10 14:18:0634#include "components/gcm_driver/fake_gcm_profile_service.h"
johnmea5045732016-09-08 17:23:2935#include "components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h"
sdefresne9fb67692015-08-03 18:48:2236#include "components/version_info/version_info.h"
Devlin Cronin59551d82019-03-05 01:28:5937#include "content/public/browser/console_message.h"
kalman6f984ae2015-09-18 17:21:5838#include "content/public/browser/navigation_controller.h"
rdevlin.croninf5863da2015-09-10 19:21:4539#include "content/public/browser/navigation_entry.h"
Istiaque Ahmedd4b67ee2019-03-02 10:53:2040#include "content/public/browser/render_process_host.h"
lazyboy4c82177a2016-10-18 00:04:0941#include "content/public/browser/service_worker_context.h"
Devlin Cronin59551d82019-03-05 01:28:5942#include "content/public/browser/service_worker_context_observer.h"
lazyboy4c82177a2016-10-18 00:04:0943#include "content/public/browser/storage_partition.h"
kalman6f984ae2015-09-18 17:21:5844#include "content/public/browser/web_contents.h"
lazyboybd325ae2015-11-18 21:35:2645#include "content/public/common/content_switches.h"
falkenad185092016-06-16 06:10:0246#include "content/public/common/origin_util.h"
kalman6f984ae2015-09-18 17:21:5847#include "content/public/common/page_type.h"
Istiaque Ahmedd4b67ee2019-03-02 10:53:2048#include "content/public/common/result_codes.h"
lazyboybd325ae2015-11-18 21:35:2649#include "content/public/test/background_sync_test_util.h"
annekao1db36fd2015-07-29 17:09:1650#include "content/public/test/browser_test_utils.h"
lazyboy63b994a2017-06-30 21:20:2351#include "content/public/test/service_worker_test_helpers.h"
Istiaque Ahmed771aa8a22018-06-20 23:40:5352#include "extensions/browser/event_router.h"
kalman6f984ae2015-09-18 17:21:5853#include "extensions/browser/extension_host.h"
lazyboyc3e763a2015-12-09 23:09:5854#include "extensions/browser/extension_registry.h"
kalman6f984ae2015-09-18 17:21:5855#include "extensions/browser/process_manager.h"
Istiaque Ahmed70f76ac2018-11-02 02:59:5556#include "extensions/browser/service_worker_task_queue.h"
Istiaque Ahmeda14ec482018-08-25 01:02:1857#include "extensions/common/api/test.h"
Istiaque Ahmed771aa8a22018-06-20 23:40:5358#include "extensions/common/value_builder.h"
kalman6f984ae2015-09-18 17:21:5859#include "extensions/test/background_page_watcher.h"
annekao38685502015-07-14 17:46:3960#include "extensions/test/extension_test_message_listener.h"
Istiaque Ahmed805f6a83b2017-10-05 01:23:2661#include "extensions/test/result_catcher.h"
Devlin Cronin59551d82019-03-05 01:28:5962#include "extensions/test/test_extension_dir.h"
falkenad185092016-06-16 06:10:0263#include "net/dns/mock_host_resolver.h"
horo1eeddde2015-11-19 05:59:2564#include "net/test/embedded_test_server/embedded_test_server.h"
lazyboy63b994a2017-06-30 21:20:2365#include "url/url_constants.h"
annekao38685502015-07-14 17:46:3966
67namespace extensions {
68
kalman6f984ae2015-09-18 17:21:5869namespace {
70
lazyboy22eddc712015-12-10 21:16:2671// Returns the newly added WebContents.
72content::WebContents* AddTab(Browser* browser, const GURL& url) {
73 int starting_tab_count = browser->tab_strip_model()->count();
74 ui_test_utils::NavigateToURLWithDisposition(
nick3b04f322016-08-31 19:29:1975 browser, url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
lazyboy22eddc712015-12-10 21:16:2676 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
77 int tab_count = browser->tab_strip_model()->count();
78 EXPECT_EQ(starting_tab_count + 1, tab_count);
79 return browser->tab_strip_model()->GetActiveWebContents();
80}
81
lazyboy22eddc712015-12-10 21:16:2682class WebContentsLoadStopObserver : content::WebContentsObserver {
83 public:
84 explicit WebContentsLoadStopObserver(content::WebContents* web_contents)
85 : content::WebContentsObserver(web_contents),
86 load_stop_observed_(false) {}
87
88 void WaitForLoadStop() {
89 if (load_stop_observed_)
90 return;
91 message_loop_runner_ = new content::MessageLoopRunner;
92 message_loop_runner_->Run();
93 }
94
95 private:
96 void DidStopLoading() override {
97 load_stop_observed_ = true;
98 if (message_loop_runner_)
99 message_loop_runner_->Quit();
100 }
101
102 bool load_stop_observed_;
103 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
104
105 DISALLOW_COPY_AND_ASSIGN(WebContentsLoadStopObserver);
106};
107
kalman6f984ae2015-09-18 17:21:58108} // namespace
109
Devlin Cronin242d19d22019-03-12 18:08:48110class ServiceWorkerTest : public ExtensionApiTest {
annekao38685502015-07-14 17:46:39111 public:
lazyboy20167c22016-05-18 00:59:30112 ServiceWorkerTest() : current_channel_(version_info::Channel::STABLE) {}
Istiaque Ahmed7105f2a2017-10-07 01:11:59113 explicit ServiceWorkerTest(version_info::Channel channel)
114 : current_channel_(channel) {}
annekao38685502015-07-14 17:46:39115
116 ~ServiceWorkerTest() override {}
117
jam1a5b5582017-05-01 16:50:10118 void SetUpOnMainThread() override {
119 ExtensionApiTest::SetUpOnMainThread();
David Bertoni3929f552019-03-28 22:10:36120 host_resolver()->AddRule("*", "127.0.0.1");
jam1a5b5582017-05-01 16:50:10121 }
122
kalman6f984ae2015-09-18 17:21:58123 protected:
124 // Returns the ProcessManager for the test's profile.
125 ProcessManager* process_manager() { return ProcessManager::Get(profile()); }
126
127 // Starts running a test from the background page test extension.
128 //
129 // This registers a service worker with |script_name|, and fetches the
130 // registration result.
Istiaque Ahmed93ff7f42018-08-31 01:42:22131 const Extension* StartTestFromBackgroundPage(const char* script_name) {
Istiaque Ahmed6475f542018-08-28 04:20:21132 ExtensionTestMessageListener ready_listener("ready", false);
kalman6f984ae2015-09-18 17:21:58133 const Extension* extension =
134 LoadExtension(test_data_dir_.AppendASCII("service_worker/background"));
135 CHECK(extension);
Istiaque Ahmed6475f542018-08-28 04:20:21136 CHECK(ready_listener.WaitUntilSatisfied());
137
kalman6f984ae2015-09-18 17:21:58138 ExtensionHost* background_host =
139 process_manager()->GetBackgroundHostForExtension(extension->id());
140 CHECK(background_host);
Istiaque Ahmed6475f542018-08-28 04:20:21141
kalman6f984ae2015-09-18 17:21:58142 std::string error;
143 CHECK(content::ExecuteScriptAndExtractString(
144 background_host->host_contents(),
145 base::StringPrintf("test.registerServiceWorker('%s')", script_name),
146 &error));
Istiaque Ahmed93ff7f42018-08-31 01:42:22147 if (!error.empty())
kalman6f984ae2015-09-18 17:21:58148 ADD_FAILURE() << "Got unexpected error " << error;
149 return extension;
150 }
151
152 // Navigates the browser to a new tab at |url|, waits for it to load, then
153 // returns it.
154 content::WebContents* Navigate(const GURL& url) {
155 ui_test_utils::NavigateToURLWithDisposition(
nick3b04f322016-08-31 19:29:19156 browser(), url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
kalman6f984ae2015-09-18 17:21:58157 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
158 content::WebContents* web_contents =
159 browser()->tab_strip_model()->GetActiveWebContents();
160 content::WaitForLoadStop(web_contents);
161 return web_contents;
162 }
163
164 // Navigates the browser to |url| and returns the new tab's page type.
165 content::PageType NavigateAndGetPageType(const GURL& url) {
clamy1d7a4112018-06-15 15:47:16166 return Navigate(url)
167 ->GetController()
168 .GetLastCommittedEntry()
169 ->GetPageType();
kalman6f984ae2015-09-18 17:21:58170 }
171
172 // Extracts the innerText from |contents|.
173 std::string ExtractInnerText(content::WebContents* contents) {
174 std::string inner_text;
175 if (!content::ExecuteScriptAndExtractString(
176 contents,
177 "window.domAutomationController.send(document.body.innerText)",
178 &inner_text)) {
179 ADD_FAILURE() << "Failed to get inner text for "
180 << contents->GetVisibleURL();
181 }
182 return inner_text;
183 }
184
185 // Navigates the browser to |url|, then returns the innerText of the new
186 // tab's WebContents' main frame.
187 std::string NavigateAndExtractInnerText(const GURL& url) {
188 return ExtractInnerText(Navigate(url));
189 }
190
lazyboy4c82177a2016-10-18 00:04:09191 size_t GetWorkerRefCount(const GURL& origin) {
192 content::ServiceWorkerContext* sw_context =
193 content::BrowserContext::GetDefaultStoragePartition(
194 browser()->profile())
195 ->GetServiceWorkerContext();
196 base::RunLoop run_loop;
197 size_t ref_count = 0;
198 auto set_ref_count = [](size_t* ref_count, base::RunLoop* run_loop,
199 size_t external_request_count) {
200 *ref_count = external_request_count;
201 run_loop->Quit();
202 };
203 sw_context->CountExternalRequestsForTest(
Matt Falkenhagenc5cb4282017-09-07 08:43:42204 origin, base::BindOnce(set_ref_count, &ref_count, &run_loop));
lazyboy4c82177a2016-10-18 00:04:09205 run_loop.Run();
206 return ref_count;
207 }
208
annekao38685502015-07-14 17:46:39209 private:
lazyboy20167c22016-05-18 00:59:30210 // Sets the channel to "stable".
211 // Not useful after we've opened extension Service Workers to stable
212 // channel.
213 // TODO(lazyboy): Remove this when ExtensionServiceWorkersEnabled() is
214 // removed.
annekao38685502015-07-14 17:46:39215 ScopedCurrentChannel current_channel_;
kalman6f984ae2015-09-18 17:21:58216
annekao38685502015-07-14 17:46:39217 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerTest);
218};
219
Istiaque Ahmedccb444022018-06-19 02:11:12220class ServiceWorkerBasedBackgroundTest : public ServiceWorkerTest {
221 public:
222 ServiceWorkerBasedBackgroundTest()
223 : ServiceWorkerTest(
224 // Extensions APIs from SW are only enabled on trunk.
225 // It is important to set the channel early so that this change is
226 // visible in renderers running with service workers (and no
227 // extension).
228 version_info::Channel::UNKNOWN) {}
229 ~ServiceWorkerBasedBackgroundTest() override {}
230
231 void SetUpOnMainThread() override {
232 host_resolver()->AddRule("*", "127.0.0.1");
233 ASSERT_TRUE(embedded_test_server()->Start());
234 ServiceWorkerTest::SetUpOnMainThread();
235 }
236
Istiaque Ahmedd4b67ee2019-03-02 10:53:20237 // Returns the only running worker id for |extension_id|.
238 // Returns base::nullopt if there isn't any worker running or more than one
239 // worker is running for |extension_id|.
240 base::Optional<WorkerId> GetUniqueRunningWorkerId(
241 const ExtensionId& extension_id) {
242 ProcessManager* process_manager = ProcessManager::Get(profile());
243 std::vector<WorkerId> all_workers =
244 process_manager->GetAllWorkersIdsForTesting();
245 base::Optional<WorkerId> running_worker_id;
246 for (const WorkerId& worker_id : all_workers) {
247 if (worker_id.extension_id == extension_id) {
248 if (running_worker_id) // More than one worker present.
249 return base::nullopt;
250 running_worker_id = worker_id;
251 }
252 }
253 return running_worker_id;
254 }
255
Istiaque Ahmedccb444022018-06-19 02:11:12256 private:
257 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerBasedBackgroundTest);
258};
259
260// Tests that Service Worker based background pages can be loaded and they can
261// receive extension events.
262// The extension is installed and loaded during this step and it registers
263// an event listener for tabs.onCreated event. The step also verifies that tab
264// creation correctly fires the listener.
Devlin Cronin242d19d22019-03-12 18:08:48265IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, PRE_Basic) {
Istiaque Ahmedccb444022018-06-19 02:11:12266 ExtensionTestMessageListener newtab_listener("CREATED", false);
267 newtab_listener.set_failure_message("CREATE_FAILED");
268 ExtensionTestMessageListener worker_listener("WORKER_RUNNING", false);
269 worker_listener.set_failure_message("NON_WORKER_SCOPE");
270 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
271 "service_worker/worker_based_background/basic"));
272 ASSERT_TRUE(extension);
273 const ExtensionId extension_id = extension->id();
274 EXPECT_TRUE(worker_listener.WaitUntilSatisfied());
275
276 const GURL url = embedded_test_server()->GetURL("/extensions/test_file.html");
277 content::WebContents* new_web_contents = AddTab(browser(), url);
278 EXPECT_TRUE(new_web_contents);
279 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
280
281 // Service Worker extension does not have ExtensionHost.
282 EXPECT_FALSE(process_manager()->GetBackgroundHostForExtension(extension_id));
283}
284
285// After browser restarts, this test step ensures that opening a tab fires
286// tabs.onCreated event listener to the extension without explicitly loading the
287// extension. This is because the extension registered a listener before browser
288// restarted in PRE_Basic.
Devlin Cronin242d19d22019-03-12 18:08:48289IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, Basic) {
Istiaque Ahmedccb444022018-06-19 02:11:12290 ExtensionTestMessageListener newtab_listener("CREATED", false);
291 newtab_listener.set_failure_message("CREATE_FAILED");
292 const GURL url = embedded_test_server()->GetURL("/extensions/test_file.html");
293 content::WebContents* new_web_contents = AddTab(browser(), url);
294 EXPECT_TRUE(new_web_contents);
295 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
296}
297
Istiaque Ahmedbf08f952018-10-02 01:22:04298// Tests chrome.runtime.onInstalled fires for extension service workers.
Devlin Cronin242d19d22019-03-12 18:08:48299IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, OnInstalledEvent) {
Istiaque Ahmedbf08f952018-10-02 01:22:04300 ASSERT_TRUE(RunExtensionTest(
301 "service_worker/worker_based_background/events_on_installed"))
302 << message_;
303}
304
David Bertoni69982832019-02-13 21:24:21305// Tests chrome.storage APIs.
Devlin Cronin242d19d22019-03-12 18:08:48306IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, StorageSetAndGet) {
David Bertoni69982832019-02-13 21:24:21307 ASSERT_TRUE(
308 RunExtensionTest("service_worker/worker_based_background/storage"))
309 << message_;
310}
311
David Bertoni0665c892019-02-14 00:27:26312// Tests chrome.storage.local and chrome.storage.local APIs.
Devlin Cronin242d19d22019-03-12 18:08:48313IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, StorageNoPermissions) {
David Bertoni0665c892019-02-14 00:27:26314 ASSERT_TRUE(RunExtensionTest(
315 "service_worker/worker_based_background/storage_no_permissions"))
316 << message_;
317}
318
David Bertoni30809312019-02-28 22:56:05319// Tests chrome.tabs APIs.
Devlin Cronin242d19d22019-03-12 18:08:48320IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, TabsBasic) {
David Bertoni30809312019-02-28 22:56:05321 ASSERT_TRUE(
322 RunExtensionTest("service_worker/worker_based_background/tabs_basic"))
323 << message_;
324}
325
David Bertoni46d698892019-02-26 00:29:10326// Tests chrome.tabs events.
Devlin Cronin242d19d22019-03-12 18:08:48327IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, TabsEvents) {
David Bertoni46d698892019-02-26 00:29:10328 ASSERT_TRUE(
329 RunExtensionTest("service_worker/worker_based_background/tabs_events"))
330 << message_;
331}
332
David Bertoni4c7dfcc2019-03-27 23:49:34333// Tests chrome.tabs APIs.
334IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, TabsExecuteScript) {
335 ASSERT_TRUE(RunExtensionTest(
336 "service_worker/worker_based_background/tabs_execute_script"))
337 << message_;
338}
339
David Bertoni37ae0222019-04-04 01:30:54340// Tests chrome.webRequest APIs.
David Bertoni3929f552019-03-28 22:10:36341IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, WebRequest) {
342 ASSERT_TRUE(
343 RunExtensionTest("service_worker/worker_based_background/web_request"))
344 << message_;
345}
346
David Bertoni37ae0222019-04-04 01:30:54347// Tests chrome.webRequest APIs in blocking mode.
348IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, WebRequestBlocking) {
349 // Try to load the page before installing the extension, which should work.
350 const GURL url = embedded_test_server()->GetURL("/extensions/test_file.html");
351 EXPECT_EQ(content::PAGE_TYPE_NORMAL, NavigateAndGetPageType(url));
352
353 // Install the extension and navigate again to the page.
354 ExtensionTestMessageListener ready_listener("ready", false);
355 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII(
356 "service_worker/worker_based_background/web_request_blocking")));
357 ASSERT_TRUE(ready_listener.WaitUntilSatisfied());
358 EXPECT_EQ(content::PAGE_TYPE_ERROR, NavigateAndGetPageType(url));
359}
360
Istiaque Ahmed70f76ac2018-11-02 02:59:55361// Listens for |message| from extension Service Worker early so that tests can
362// wait for the message on startup (and not miss it).
363class ServiceWorkerWithEarlyMessageListenerTest
364 : public ServiceWorkerBasedBackgroundTest {
Istiaque Ahmedf70ab222018-10-02 03:08:24365 public:
Istiaque Ahmed70f76ac2018-11-02 02:59:55366 explicit ServiceWorkerWithEarlyMessageListenerTest(
367 const std::string& test_message)
368 : test_message_(test_message) {}
369 ~ServiceWorkerWithEarlyMessageListenerTest() override = default;
Istiaque Ahmedf70ab222018-10-02 03:08:24370
Istiaque Ahmed70f76ac2018-11-02 02:59:55371 bool WaitForMessage() { return listener_->WaitUntilSatisfied(); }
Istiaque Ahmedf70ab222018-10-02 03:08:24372
373 void CreatedBrowserMainParts(content::BrowserMainParts* main_parts) override {
374 // At this point, the notification service is initialized but the profile
375 // and extensions have not.
Istiaque Ahmed70f76ac2018-11-02 02:59:55376 listener_ =
377 std::make_unique<ExtensionTestMessageListener>(test_message_, false);
Istiaque Ahmedf70ab222018-10-02 03:08:24378 ServiceWorkerBasedBackgroundTest::CreatedBrowserMainParts(main_parts);
379 }
380
381 private:
Istiaque Ahmed70f76ac2018-11-02 02:59:55382 const std::string test_message_;
Istiaque Ahmedf70ab222018-10-02 03:08:24383 std::unique_ptr<ExtensionTestMessageListener> listener_;
384
Istiaque Ahmed70f76ac2018-11-02 02:59:55385 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerWithEarlyMessageListenerTest);
386};
387
388class ServiceWorkerOnStartupEventTest
389 : public ServiceWorkerWithEarlyMessageListenerTest {
390 public:
391 ServiceWorkerOnStartupEventTest()
392 : ServiceWorkerWithEarlyMessageListenerTest("onStartup event") {}
393 ~ServiceWorkerOnStartupEventTest() override = default;
394
395 private:
396 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerOnStartupEventTest);
Istiaque Ahmedf70ab222018-10-02 03:08:24397};
398
399// Tests "runtime.onStartup" for extension SW.
Devlin Cronin242d19d22019-03-12 18:08:48400IN_PROC_BROWSER_TEST_F(ServiceWorkerOnStartupEventTest, PRE_Event) {
Istiaque Ahmedf70ab222018-10-02 03:08:24401 ASSERT_TRUE(RunExtensionTest(
402 "service_worker/worker_based_background/on_startup_event"))
403 << message_;
404}
405
Devlin Cronin242d19d22019-03-12 18:08:48406IN_PROC_BROWSER_TEST_F(ServiceWorkerOnStartupEventTest, Event) {
Istiaque Ahmed70f76ac2018-11-02 02:59:55407 EXPECT_TRUE(WaitForMessage());
408}
409
410class ServiceWorkerRegistrationAtStartupTest
411 : public ServiceWorkerWithEarlyMessageListenerTest,
412 public ServiceWorkerTaskQueue::TestObserver {
413 public:
414 ServiceWorkerRegistrationAtStartupTest()
415 : ServiceWorkerWithEarlyMessageListenerTest("WORKER_RUNNING") {
416 ServiceWorkerTaskQueue::SetObserverForTest(this);
417 }
418 ~ServiceWorkerRegistrationAtStartupTest() override {
419 ServiceWorkerTaskQueue::SetObserverForTest(nullptr);
420 }
421
422 // ServiceWorkerTaskQueue::TestObserver:
423 void OnActivateExtension(const ExtensionId& extension_id,
424 bool will_register_service_worker) override {
425 if (extension_id != kExtensionId)
426 return;
427
428 will_register_service_worker_ = will_register_service_worker;
429
430 extension_activated_ = true;
431 if (run_loop_)
432 run_loop_->Quit();
433 }
434
435 void WaitForOnActivateExtension() {
436 if (extension_activated_)
437 return;
438 run_loop_ = std::make_unique<base::RunLoop>();
439 run_loop_->Run();
440 }
441
442 bool WillRegisterServiceWorker() {
443 return will_register_service_worker_.value();
444 }
445
446 protected:
447 static const char kExtensionId[];
448
449 private:
450 bool extension_activated_ = false;
451 base::Optional<bool> will_register_service_worker_;
452 std::unique_ptr<base::RunLoop> run_loop_;
453
454 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerRegistrationAtStartupTest);
455};
456
457// Test extension id at
458// api_test/service_worker/worker_based_background/registration_at_startup/.
459const char ServiceWorkerRegistrationAtStartupTest::kExtensionId[] =
460 "gnchfmandajfaiajniicagenfmhdjila";
461
462// Tests that Service Worker registration for existing extension isn't issued
463// upon browser restart.
464// Regression test for https://crbug.com/889687.
Devlin Cronin242d19d22019-03-12 18:08:48465IN_PROC_BROWSER_TEST_F(ServiceWorkerRegistrationAtStartupTest,
Istiaque Ahmed70f76ac2018-11-02 02:59:55466 PRE_ExtensionActivationDoesNotReregister) {
467 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
468 "service_worker/worker_based_background/registration_at_startup"));
469 ASSERT_TRUE(extension);
470 EXPECT_EQ(kExtensionId, extension->id());
471 // Wait for "WORKER_RUNNING" message from the Service Worker.
472 EXPECT_TRUE(WaitForMessage());
473 EXPECT_TRUE(WillRegisterServiceWorker());
474}
475
Devlin Cronin242d19d22019-03-12 18:08:48476IN_PROC_BROWSER_TEST_F(ServiceWorkerRegistrationAtStartupTest,
Istiaque Ahmed70f76ac2018-11-02 02:59:55477 ExtensionActivationDoesNotReregister) {
478 // Since the extension has onStartup listener, the Service Worker will run on
479 // browser start and we'll see "WORKER_RUNNING" message from the worker.
480 EXPECT_TRUE(WaitForMessage());
481 // As the extension activated during first run on PRE_ step, it shouldn't
482 // re-register the Service Worker upon browser restart.
483 EXPECT_FALSE(WillRegisterServiceWorker());
Istiaque Ahmedf70ab222018-10-02 03:08:24484}
485
Istiaque Ahmeda14ec482018-08-25 01:02:18486// Class that dispatches an event to |extension_id| right after a
487// non-lazy listener to the event is added from the extension's Service Worker.
Istiaque Ahmed771aa8a22018-06-20 23:40:53488class EarlyWorkerMessageSender : public EventRouter::Observer {
489 public:
490 EarlyWorkerMessageSender(content::BrowserContext* browser_context,
Istiaque Ahmeda14ec482018-08-25 01:02:18491 const ExtensionId& extension_id,
492 std::unique_ptr<Event> event)
Istiaque Ahmed771aa8a22018-06-20 23:40:53493 : browser_context_(browser_context),
494 event_router_(EventRouter::EventRouter::Get(browser_context_)),
495 extension_id_(extension_id),
Istiaque Ahmeda14ec482018-08-25 01:02:18496 event_(std::move(event)),
Istiaque Ahmed771aa8a22018-06-20 23:40:53497 listener_("PASS", false) {
498 DCHECK(browser_context_);
499 listener_.set_failure_message("FAIL");
Istiaque Ahmeda14ec482018-08-25 01:02:18500 event_router_->RegisterObserver(this, event_->event_name);
Istiaque Ahmed771aa8a22018-06-20 23:40:53501 }
502
503 ~EarlyWorkerMessageSender() override {
504 event_router_->UnregisterObserver(this);
505 }
506
507 // EventRouter::Observer:
508 void OnListenerAdded(const EventListenerInfo& details) override {
Istiaque Ahmeda14ec482018-08-25 01:02:18509 if (!event_ || extension_id_ != details.extension_id ||
510 event_->event_name != details.event_name) {
Istiaque Ahmed771aa8a22018-06-20 23:40:53511 return;
Istiaque Ahmeda14ec482018-08-25 01:02:18512 }
513
Istiaque Ahmed771aa8a22018-06-20 23:40:53514 const bool is_lazy_listener = details.browser_context == nullptr;
515 if (is_lazy_listener) {
516 // Wait for the non-lazy listener as we want to exercise the code to
517 // dispatch the event right after the Service Worker registration is
518 // completing.
519 return;
520 }
Istiaque Ahmeda14ec482018-08-25 01:02:18521 DispatchEvent(std::move(event_));
Istiaque Ahmed771aa8a22018-06-20 23:40:53522 }
523
524 bool SendAndWait() { return listener_.WaitUntilSatisfied(); }
525
526 private:
527 static constexpr const char* const kTestOnMessageEventName = "test.onMessage";
528
Istiaque Ahmeda14ec482018-08-25 01:02:18529 void DispatchEvent(std::unique_ptr<Event> event) {
Istiaque Ahmed771aa8a22018-06-20 23:40:53530 EventRouter::Get(browser_context_)
531 ->DispatchEventToExtension(extension_id_, std::move(event));
532 }
533
534 content::BrowserContext* const browser_context_ = nullptr;
535 EventRouter* const event_router_ = nullptr;
536 const ExtensionId extension_id_;
Istiaque Ahmeda14ec482018-08-25 01:02:18537 std::unique_ptr<Event> event_;
Istiaque Ahmed771aa8a22018-06-20 23:40:53538 ExtensionTestMessageListener listener_;
Istiaque Ahmed771aa8a22018-06-20 23:40:53539
540 DISALLOW_COPY_AND_ASSIGN(EarlyWorkerMessageSender);
541};
542
543// Tests that extension event dispatch works correctly right after extension
544// installation registers its Service Worker.
545// Regression test for: https://crbug.com/850792.
Devlin Cronin242d19d22019-03-12 18:08:48546IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, EarlyEventDispatch) {
Istiaque Ahmed771aa8a22018-06-20 23:40:53547 const ExtensionId kId("pkplfbidichfdicaijlchgnapepdginl");
Istiaque Ahmeda14ec482018-08-25 01:02:18548
549 // Build "test.onMessage" event for dispatch.
550 auto event = std::make_unique<Event>(
551 events::FOR_TEST, extensions::api::test::OnMessage::kEventName,
Lei Zhang582ecd12019-02-13 20:28:54552 base::ListValue::From(base::JSONReader::ReadDeprecated(
Istiaque Ahmeda14ec482018-08-25 01:02:18553 R"([{"data": "hello", "lastMessage": true}])")),
554 profile());
555
556 EarlyWorkerMessageSender sender(profile(), kId, std::move(event));
Istiaque Ahmed771aa8a22018-06-20 23:40:53557 // pkplfbidichfdicaijlchgnapepdginl
558 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
559 "service_worker/worker_based_background/early_event_dispatch"));
560 CHECK(extension);
561 EXPECT_EQ(kId, extension->id());
562 EXPECT_TRUE(sender.SendAndWait());
563}
564
Istiaque Ahmeda14ec482018-08-25 01:02:18565// Tests that filtered events dispatches correctly right after a non-lazy
566// listener is registered for that event (and before the corresponding lazy
567// listener is registered).
Devlin Cronin242d19d22019-03-12 18:08:48568IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
Istiaque Ahmeda14ec482018-08-25 01:02:18569 EarlyFilteredEventDispatch) {
570 const ExtensionId kId("pkplfbidichfdicaijlchgnapepdginl");
571
572 // Add minimal details required to dispatch webNavigation.onCommitted event:
573 extensions::api::web_navigation::OnCommitted::Details details;
574 details.transition_type =
575 extensions::api::web_navigation::TRANSITION_TYPE_TYPED;
576
577 // Build a dummy onCommited event to dispatch.
578 auto on_committed_event = std::make_unique<Event>(
579 events::WEB_NAVIGATION_ON_COMMITTED, "webNavigation.onCommitted",
580 api::web_navigation::OnCommitted::Create(details), profile());
581 // The filter will match the listener filter registered from the extension.
582 EventFilteringInfo info;
583 info.url = GURL("http://foo.com/a.html");
584 on_committed_event->filter_info = info;
585
586 EarlyWorkerMessageSender sender(profile(), kId,
587 std::move(on_committed_event));
588
589 // pkplfbidichfdicaijlchgnapepdginl
590 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
591 "service_worker/worker_based_background/early_filtered_event_dispatch"));
592 ASSERT_TRUE(extension);
593 EXPECT_EQ(kId, extension->id());
594 EXPECT_TRUE(sender.SendAndWait());
595}
596
lazyboybd325ae2015-11-18 21:35:26597class ServiceWorkerBackgroundSyncTest : public ServiceWorkerTest {
598 public:
599 ServiceWorkerBackgroundSyncTest() {}
600 ~ServiceWorkerBackgroundSyncTest() override {}
601
602 void SetUpCommandLine(base::CommandLine* command_line) override {
603 // ServiceWorkerRegistration.sync requires experimental flag.
604 command_line->AppendSwitch(
Istiaque Ahmedea5ed5042017-09-25 19:00:16605 ::switches::kEnableExperimentalWebPlatformFeatures);
lazyboybd325ae2015-11-18 21:35:26606 ServiceWorkerTest::SetUpCommandLine(command_line);
607 }
608
609 void SetUp() override {
Robbie McElrathdb12d8e2018-09-18 21:20:40610 content::background_sync_test_util::SetIgnoreNetworkChanges(true);
lazyboybd325ae2015-11-18 21:35:26611 ServiceWorkerTest::SetUp();
612 }
613
614 private:
615 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerBackgroundSyncTest);
616};
617
lazyboy561b7de2015-11-19 19:27:30618class ServiceWorkerPushMessagingTest : public ServiceWorkerTest {
619 public:
620 ServiceWorkerPushMessagingTest()
Sylvain Defresne212b4b02018-10-11 16:32:05621 : scoped_testing_factory_installer_(
622 base::BindRepeating(&gcm::FakeGCMProfileService::Build)),
623 gcm_driver_(nullptr),
624 push_service_(nullptr) {}
625
lazyboy561b7de2015-11-19 19:27:30626 ~ServiceWorkerPushMessagingTest() override {}
627
628 void GrantNotificationPermissionForTest(const GURL& url) {
Peter Beverloodd4ef1e2018-06-21 15:41:04629 NotificationPermissionContext::UpdatePermission(profile(), url.GetOrigin(),
630 CONTENT_SETTING_ALLOW);
lazyboy561b7de2015-11-19 19:27:30631 }
632
633 PushMessagingAppIdentifier GetAppIdentifierForServiceWorkerRegistration(
avia2f4804a2015-12-24 23:11:13634 int64_t service_worker_registration_id,
lazyboy561b7de2015-11-19 19:27:30635 const GURL& origin) {
636 PushMessagingAppIdentifier app_identifier =
637 PushMessagingAppIdentifier::FindByServiceWorker(
638 profile(), origin, service_worker_registration_id);
639
640 EXPECT_FALSE(app_identifier.is_null());
641 return app_identifier;
642 }
643
644 // ExtensionApiTest overrides.
645 void SetUpCommandLine(base::CommandLine* command_line) override {
peter9de96272015-12-04 15:23:27646 command_line->AppendSwitch(
Istiaque Ahmedea5ed5042017-09-25 19:00:16647 ::switches::kEnableExperimentalWebPlatformFeatures);
lazyboy561b7de2015-11-19 19:27:30648 ServiceWorkerTest::SetUpCommandLine(command_line);
649 }
Tanja Gornak89128fd2018-09-18 08:49:34650
lazyboy561b7de2015-11-19 19:27:30651 void SetUpOnMainThread() override {
miguelg9b502862017-04-24 18:13:53652 NotificationDisplayServiceFactory::GetInstance()->SetTestingFactory(
Sylvain Defresne711ff6b2018-10-04 12:33:54653 profile(),
654 base::BindRepeating(&StubNotificationDisplayService::FactoryForTests));
miguelg9b502862017-04-24 18:13:53655
johnmea5045732016-09-08 17:23:29656 gcm::FakeGCMProfileService* gcm_service =
657 static_cast<gcm::FakeGCMProfileService*>(
Tanja Gornak89128fd2018-09-18 08:49:34658 gcm::GCMProfileServiceFactory::GetForProfile(profile()));
johnmea5045732016-09-08 17:23:29659 gcm_driver_ = static_cast<instance_id::FakeGCMDriverForInstanceID*>(
660 gcm_service->driver());
lazyboy561b7de2015-11-19 19:27:30661 push_service_ = PushMessagingServiceFactory::GetForProfile(profile());
662
663 ServiceWorkerTest::SetUpOnMainThread();
664 }
665
johnmea5045732016-09-08 17:23:29666 instance_id::FakeGCMDriverForInstanceID* gcm_driver() const {
667 return gcm_driver_;
668 }
lazyboy561b7de2015-11-19 19:27:30669 PushMessagingServiceImpl* push_service() const { return push_service_; }
670
671 private:
Sylvain Defresne212b4b02018-10-11 16:32:05672 gcm::GCMProfileServiceFactory::ScopedTestingFactoryInstaller
673 scoped_testing_factory_installer_;
674
johnmea5045732016-09-08 17:23:29675 instance_id::FakeGCMDriverForInstanceID* gcm_driver_;
lazyboy561b7de2015-11-19 19:27:30676 PushMessagingServiceImpl* push_service_;
677
678 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerPushMessagingTest);
679};
680
Istiaque Ahmed805f6a83b2017-10-05 01:23:26681class ServiceWorkerLazyBackgroundTest : public ServiceWorkerTest {
682 public:
Istiaque Ahmed7105f2a2017-10-07 01:11:59683 ServiceWorkerLazyBackgroundTest()
684 : ServiceWorkerTest(
685 // Extensions APIs from SW are only enabled on trunk.
686 // It is important to set the channel early so that this change is
687 // visible in renderers running with service workers (and no
688 // extension).
689 version_info::Channel::UNKNOWN) {}
Istiaque Ahmed805f6a83b2017-10-05 01:23:26690 ~ServiceWorkerLazyBackgroundTest() override {}
691
692 void SetUpCommandLine(base::CommandLine* command_line) override {
693 ServiceWorkerTest::SetUpCommandLine(command_line);
694 // Disable background network activity as it can suddenly bring the Lazy
695 // Background Page alive.
696 command_line->AppendSwitch(::switches::kDisableBackgroundNetworking);
697 command_line->AppendSwitch(::switches::kNoProxyServer);
698 }
699
700 void SetUpInProcessBrowserTestFixture() override {
701 ServiceWorkerTest::SetUpInProcessBrowserTestFixture();
702 // Set shorter delays to prevent test timeouts.
703 ProcessManager::SetEventPageIdleTimeForTesting(1);
704 ProcessManager::SetEventPageSuspendingTimeForTesting(1);
705 }
706
707 private:
708 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerLazyBackgroundTest);
709};
710
Devlin Cronin242d19d22019-03-12 18:08:48711IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, RegisterSucceeds) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22712 StartTestFromBackgroundPage("register.js");
annekao38685502015-07-14 17:46:39713}
714
Devlin Cronin242d19d22019-03-12 18:08:48715IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, UpdateRefreshesServiceWorker) {
Francois Doraye6fb2d02017-10-18 21:29:13716 base::ScopedAllowBlockingForTesting allow_blocking;
lazyboyc3e763a2015-12-09 23:09:58717 base::ScopedTempDir scoped_temp_dir;
718 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
719 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
720 .AppendASCII("update")
721 .AppendASCII("service_worker.pem");
vabr9142fe22016-09-08 13:19:22722 base::FilePath path_v1 =
723 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
724 .AppendASCII("update")
725 .AppendASCII("v1"),
726 scoped_temp_dir.GetPath().AppendASCII("v1.crx"),
727 pem_path, base::FilePath());
728 base::FilePath path_v2 =
729 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
730 .AppendASCII("update")
731 .AppendASCII("v2"),
732 scoped_temp_dir.GetPath().AppendASCII("v2.crx"),
733 pem_path, base::FilePath());
lazyboyc3e763a2015-12-09 23:09:58734 const char* kId = "hfaanndiiilofhfokeanhddpkfffchdi";
735
736 ExtensionTestMessageListener listener_v1("Pong from version 1", false);
737 listener_v1.set_failure_message("FAILURE_V1");
738 // Install version 1.0 of the extension.
739 ASSERT_TRUE(InstallExtension(path_v1, 1));
740 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
741 ->enabled_extensions()
742 .GetByID(kId));
743 EXPECT_TRUE(listener_v1.WaitUntilSatisfied());
744
745 ExtensionTestMessageListener listener_v2("Pong from version 2", false);
746 listener_v2.set_failure_message("FAILURE_V2");
747
748 // Update to version 2.0.
749 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
750 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
751 ->enabled_extensions()
752 .GetByID(kId));
753 EXPECT_TRUE(listener_v2.WaitUntilSatisfied());
754}
755
[email protected]2ef85d562017-09-15 18:41:52756// TODO(crbug.com/765736) Fix the test.
Devlin Cronin242d19d22019-03-12 18:08:48757IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, DISABLED_UpdateWithoutSkipWaiting) {
Francois Doraye6fb2d02017-10-18 21:29:13758 base::ScopedAllowBlockingForTesting allow_blocking;
lazyboy22eddc712015-12-10 21:16:26759 base::ScopedTempDir scoped_temp_dir;
760 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
761 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
762 .AppendASCII("update_without_skip_waiting")
763 .AppendASCII("update_without_skip_waiting.pem");
vabr9142fe22016-09-08 13:19:22764 base::FilePath path_v1 =
765 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
766 .AppendASCII("update_without_skip_waiting")
767 .AppendASCII("v1"),
768 scoped_temp_dir.GetPath().AppendASCII("v1.crx"),
769 pem_path, base::FilePath());
770 base::FilePath path_v2 =
771 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
772 .AppendASCII("update_without_skip_waiting")
773 .AppendASCII("v2"),
774 scoped_temp_dir.GetPath().AppendASCII("v2.crx"),
775 pem_path, base::FilePath());
lazyboy22eddc712015-12-10 21:16:26776 const char* kId = "mhnnnflgagdakldgjpfcofkiocpdmogl";
777
778 // Install version 1.0 of the extension.
779 ASSERT_TRUE(InstallExtension(path_v1, 1));
780 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
781 ->enabled_extensions()
782 .GetByID(kId));
783 const Extension* extension = extensions::ExtensionRegistry::Get(profile())
784 ->enabled_extensions()
785 .GetByID(kId);
786
787 ExtensionTestMessageListener listener1("Pong from version 1", false);
788 listener1.set_failure_message("FAILURE");
789 content::WebContents* web_contents =
790 AddTab(browser(), extension->GetResourceURL("page.html"));
791 EXPECT_TRUE(listener1.WaitUntilSatisfied());
792
793 // Update to version 2.0.
794 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
795 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
796 ->enabled_extensions()
797 .GetByID(kId));
798 const Extension* extension_after_update =
799 extensions::ExtensionRegistry::Get(profile())
800 ->enabled_extensions()
801 .GetByID(kId);
802
803 // Service worker version 2 would be installed but it won't be controlling
804 // the extension page yet.
805 ExtensionTestMessageListener listener2("Pong from version 1", false);
806 listener2.set_failure_message("FAILURE");
807 web_contents =
808 AddTab(browser(), extension_after_update->GetResourceURL("page.html"));
809 EXPECT_TRUE(listener2.WaitUntilSatisfied());
810
811 // Navigate the tab away from the extension page so that no clients are
812 // using the service worker.
813 // Note that just closing the tab with WebContentsDestroyedWatcher doesn't
814 // seem to be enough because it returns too early.
815 WebContentsLoadStopObserver navigate_away_observer(web_contents);
816 web_contents->GetController().LoadURL(
817 GURL(url::kAboutBlankURL), content::Referrer(), ui::PAGE_TRANSITION_TYPED,
818 std::string());
819 navigate_away_observer.WaitForLoadStop();
820
821 // Now expect service worker version 2 to control the extension page.
822 ExtensionTestMessageListener listener3("Pong from version 2", false);
823 listener3.set_failure_message("FAILURE");
824 web_contents =
825 AddTab(browser(), extension_after_update->GetResourceURL("page.html"));
826 EXPECT_TRUE(listener3.WaitUntilSatisfied());
827}
828
Devlin Cronin242d19d22019-03-12 18:08:48829IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, FetchArbitraryPaths) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22830 const Extension* extension = StartTestFromBackgroundPage("fetch.js");
annekao1db36fd2015-07-29 17:09:16831
kalman6f984ae2015-09-18 17:21:58832 // Open some arbirary paths. Their contents should be what the service worker
833 // responds with, which in this case is the path of the fetch.
834 EXPECT_EQ(
835 "Caught a fetch for /index.html",
836 NavigateAndExtractInnerText(extension->GetResourceURL("index.html")));
837 EXPECT_EQ("Caught a fetch for /path/to/other.html",
838 NavigateAndExtractInnerText(
839 extension->GetResourceURL("path/to/other.html")));
840 EXPECT_EQ("Caught a fetch for /some/text/file.txt",
841 NavigateAndExtractInnerText(
842 extension->GetResourceURL("some/text/file.txt")));
843 EXPECT_EQ("Caught a fetch for /no/file/extension",
844 NavigateAndExtractInnerText(
845 extension->GetResourceURL("no/file/extension")));
846 EXPECT_EQ("Caught a fetch for /",
847 NavigateAndExtractInnerText(extension->GetResourceURL("")));
annekao1db36fd2015-07-29 17:09:16848}
849
Devlin Cronin242d19d22019-03-12 18:08:48850IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
Kenichi Ishibashi773b82972018-08-30 07:02:03851 FetchExtensionResourceFromServiceWorker) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22852 const Extension* extension = StartTestFromBackgroundPage("fetch_from_sw.js");
Kenichi Ishibashi773b82972018-08-30 07:02:03853 ASSERT_TRUE(extension);
854
855 // The service worker in this test tries to load 'hello.txt' via fetch()
856 // and sends back the content of the file, which should be 'hello'.
857 const char* kScript = R"(
858 let channel = new MessageChannel();
859 test.waitForMessage(channel.port1).then(message => {
860 window.domAutomationController.send(message);
861 });
862 test.registeredServiceWorker.postMessage(
863 {port: channel.port2}, [channel.port2]);
864 )";
865 EXPECT_EQ("hello", ExecuteScriptInBackgroundPage(extension->id(), kScript));
866}
867
Kenichi Ishibashi09ee5e72018-11-27 07:12:38868// Tests that fetch() from service worker and network fallback
869// go through webRequest.onBeforeRequest API.
Devlin Cronin242d19d22019-03-12 18:08:48870IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, OnBeforeRequest) {
Kenichi Ishibashi09ee5e72018-11-27 07:12:38871 const Extension* extension = LoadExtensionWithFlags(
872 test_data_dir_.AppendASCII("service_worker/webrequest"), kFlagNone);
873 ASSERT_TRUE(extension);
874 ASSERT_TRUE(StartEmbeddedTestServer());
875
876 // Start a service worker and make it control the page.
877 GURL page_url = embedded_test_server()->GetURL(
878 "/extensions/api_test/service_worker/"
879 "webrequest/webpage.html");
880 content::WebContents* web_contents =
881 browser()->tab_strip_model()->GetActiveWebContents();
882 ui_test_utils::NavigateToURL(browser(), page_url);
883 content::WaitForLoadStop(web_contents);
884
885 std::string result;
886 ASSERT_TRUE(content::ExecuteScriptAndExtractString(web_contents,
887 "register();", &result));
888 EXPECT_EQ("ready", result);
889
890 // Initiate a fetch that the service worker doesn't intercept
891 // (network fallback).
892 result.clear();
893 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
894 web_contents, "doFetch('hello.txt?fallthrough');", &result));
895 EXPECT_EQ("hello", result);
896 EXPECT_EQ(
897 "/extensions/api_test/service_worker/webrequest/hello.txt?fallthrough",
898 ExecuteScriptInBackgroundPage(extension->id(), "getLastHookedPath()"));
899
900 // Initiate a fetch that results in calling fetch() in the service worker.
901 result.clear();
902 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
903 web_contents, "doFetch('hello.txt?respondWithFetch');", &result));
904 EXPECT_EQ("hello", result);
905 EXPECT_EQ(
906 "/extensions/api_test/service_worker/webrequest/"
907 "hello.txt?respondWithFetch",
908 ExecuteScriptInBackgroundPage(extension->id(), "getLastHookedPath()"));
909}
910
Devlin Cronin242d19d22019-03-12 18:08:48911IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, SWServedBackgroundPageReceivesEvent) {
lazyboy52c3bcf2016-01-08 00:11:29912 const Extension* extension =
Istiaque Ahmed93ff7f42018-08-31 01:42:22913 StartTestFromBackgroundPage("replace_background.js");
lazyboy52c3bcf2016-01-08 00:11:29914 ExtensionHost* background_page =
915 process_manager()->GetBackgroundHostForExtension(extension->id());
916 ASSERT_TRUE(background_page);
917
918 // Close the background page and start it again so that the service worker
919 // will start controlling pages.
920 background_page->Close();
921 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
922 background_page = nullptr;
Peter Kasting341e1fb2018-02-24 00:03:01923 process_manager()->WakeEventPage(extension->id(), base::DoNothing());
lazyboy52c3bcf2016-01-08 00:11:29924 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
925
926 // Since the SW is now controlling the extension, the SW serves the background
927 // script. page.html sends a message to the background script and we verify
928 // that the SW served background script correctly receives the message/event.
929 ExtensionTestMessageListener listener("onMessage/SW BG.", false);
930 listener.set_failure_message("onMessage/original BG.");
931 content::WebContents* web_contents =
932 AddTab(browser(), extension->GetResourceURL("page.html"));
933 ASSERT_TRUE(web_contents);
934 EXPECT_TRUE(listener.WaitUntilSatisfied());
935}
936
Devlin Cronin242d19d22019-03-12 18:08:48937IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, SWServedBackgroundPage) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22938 const Extension* extension = StartTestFromBackgroundPage("fetch.js");
annekao49241182015-08-18 17:14:01939
kalman6f984ae2015-09-18 17:21:58940 std::string kExpectedInnerText = "background.html contents for testing.";
annekao49241182015-08-18 17:14:01941
kalman6f984ae2015-09-18 17:21:58942 // Sanity check that the background page has the expected content.
943 ExtensionHost* background_page =
944 process_manager()->GetBackgroundHostForExtension(extension->id());
945 ASSERT_TRUE(background_page);
946 EXPECT_EQ(kExpectedInnerText,
947 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:01948
kalman6f984ae2015-09-18 17:21:58949 // Close the background page.
950 background_page->Close();
951 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
952 background_page = nullptr;
953
954 // Start it again.
Peter Kasting341e1fb2018-02-24 00:03:01955 process_manager()->WakeEventPage(extension->id(), base::DoNothing());
kalman6f984ae2015-09-18 17:21:58956 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
957
Matt Falkenhagena612fc02018-05-30 00:35:39958 // The service worker should get a fetch event for the background page.
kalman6f984ae2015-09-18 17:21:58959 background_page =
960 process_manager()->GetBackgroundHostForExtension(extension->id());
961 ASSERT_TRUE(background_page);
962 content::WaitForLoadStop(background_page->host_contents());
963
kalman6f984ae2015-09-18 17:21:58964 EXPECT_EQ("Caught a fetch for /background.html",
965 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:01966}
967
Devlin Cronin242d19d22019-03-12 18:08:48968IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:58969 ServiceWorkerPostsMessageToBackgroundClient) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22970 const Extension* extension =
971 StartTestFromBackgroundPage("post_message_to_background_client.js");
annekao533482222015-08-21 23:23:53972
kalman6f984ae2015-09-18 17:21:58973 // The service worker in this test simply posts a message to the background
974 // client it receives from getBackgroundClient().
975 const char* kScript =
976 "var messagePromise = null;\n"
977 "if (test.lastMessageFromServiceWorker) {\n"
978 " messagePromise = Promise.resolve(test.lastMessageFromServiceWorker);\n"
979 "} else {\n"
980 " messagePromise = test.waitForMessage(navigator.serviceWorker);\n"
981 "}\n"
982 "messagePromise.then(function(message) {\n"
983 " window.domAutomationController.send(String(message == 'success'));\n"
984 "})\n";
985 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:53986}
987
Devlin Cronin242d19d22019-03-12 18:08:48988IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:58989 BackgroundPagePostsMessageToServiceWorker) {
990 const Extension* extension =
Istiaque Ahmed93ff7f42018-08-31 01:42:22991 StartTestFromBackgroundPage("post_message_to_sw.js");
annekao533482222015-08-21 23:23:53992
kalman6f984ae2015-09-18 17:21:58993 // The service worker in this test waits for a message, then echoes it back
994 // by posting a message to the background page via getBackgroundClient().
995 const char* kScript =
996 "var mc = new MessageChannel();\n"
997 "test.waitForMessage(mc.port1).then(function(message) {\n"
998 " window.domAutomationController.send(String(message == 'hello'));\n"
999 "});\n"
1000 "test.registeredServiceWorker.postMessage(\n"
1001 " {message: 'hello', port: mc.port2}, [mc.port2])\n";
1002 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:531003}
1004
Devlin Cronin242d19d22019-03-12 18:08:481005IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
rdevlin.croninf5863da2015-09-10 19:21:451006 ServiceWorkerSuspensionOnExtensionUnload) {
kalman6f984ae2015-09-18 17:21:581007 // For this test, only hold onto the extension's ID and URL + a function to
1008 // get a resource URL, because we're going to be disabling and uninstalling
1009 // it, which will invalidate the pointer.
1010 std::string extension_id;
1011 GURL extension_url;
1012 {
Istiaque Ahmed93ff7f42018-08-31 01:42:221013 const Extension* extension = StartTestFromBackgroundPage("fetch.js");
kalman6f984ae2015-09-18 17:21:581014 extension_id = extension->id();
1015 extension_url = extension->url();
1016 }
1017 auto get_resource_url = [&extension_url](const std::string& path) {
1018 return Extension::GetResourceURL(extension_url, path);
1019 };
rdevlin.croninf5863da2015-09-10 19:21:451020
kalman6f984ae2015-09-18 17:21:581021 // Fetch should route to the service worker.
1022 EXPECT_EQ("Caught a fetch for /index.html",
1023 NavigateAndExtractInnerText(get_resource_url("index.html")));
rdevlin.croninf5863da2015-09-10 19:21:451024
kalman6f984ae2015-09-18 17:21:581025 // Disable the extension. Opening the page should fail.
1026 extension_service()->DisableExtension(extension_id,
Minh X. Nguyen45479012017-08-18 21:35:361027 disable_reason::DISABLE_USER_ACTION);
rdevlin.croninf5863da2015-09-10 19:21:451028 base::RunLoop().RunUntilIdle();
rdevlin.croninf5863da2015-09-10 19:21:451029
kalman6f984ae2015-09-18 17:21:581030 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1031 NavigateAndGetPageType(get_resource_url("index.html")));
1032 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1033 NavigateAndGetPageType(get_resource_url("other.html")));
1034
1035 // Re-enable the extension. Opening pages should immediately start to succeed
1036 // again.
rdevlin.croninf5863da2015-09-10 19:21:451037 extension_service()->EnableExtension(extension_id);
1038 base::RunLoop().RunUntilIdle();
1039
kalman6f984ae2015-09-18 17:21:581040 EXPECT_EQ("Caught a fetch for /index.html",
1041 NavigateAndExtractInnerText(get_resource_url("index.html")));
1042 EXPECT_EQ("Caught a fetch for /other.html",
1043 NavigateAndExtractInnerText(get_resource_url("other.html")));
1044 EXPECT_EQ("Caught a fetch for /another.html",
1045 NavigateAndExtractInnerText(get_resource_url("another.html")));
rdevlin.croninf5863da2015-09-10 19:21:451046
kalman6f984ae2015-09-18 17:21:581047 // Uninstall the extension. Opening pages should fail again.
1048 base::string16 error;
1049 extension_service()->UninstallExtension(
Devlin Cronin218df7f2017-11-21 21:41:311050 extension_id, UninstallReason::UNINSTALL_REASON_FOR_TESTING, &error);
kalman6f984ae2015-09-18 17:21:581051 base::RunLoop().RunUntilIdle();
1052
1053 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1054 NavigateAndGetPageType(get_resource_url("index.html")));
1055 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1056 NavigateAndGetPageType(get_resource_url("other.html")));
1057 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1058 NavigateAndGetPageType(get_resource_url("anotherother.html")));
1059 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1060 NavigateAndGetPageType(get_resource_url("final.html")));
1061}
1062
Devlin Cronin242d19d22019-03-12 18:08:481063IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, BackgroundPageIsWokenIfAsleep) {
Istiaque Ahmed93ff7f42018-08-31 01:42:221064 const Extension* extension = StartTestFromBackgroundPage("wake_on_fetch.js");
kalman6f984ae2015-09-18 17:21:581065
1066 // Navigate to special URLs that this test's service worker recognises, each
1067 // making a check then populating the response with either "true" or "false".
1068 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
1069 "background-client-is-awake")));
1070 EXPECT_EQ("true", NavigateAndExtractInnerText(
1071 extension->GetResourceURL("ping-background-client")));
1072 // Ping more than once for good measure.
1073 EXPECT_EQ("true", NavigateAndExtractInnerText(
1074 extension->GetResourceURL("ping-background-client")));
1075
1076 // Shut down the event page. The SW should detect that it's closed, but still
1077 // be able to ping it.
1078 ExtensionHost* background_page =
1079 process_manager()->GetBackgroundHostForExtension(extension->id());
1080 ASSERT_TRUE(background_page);
1081 background_page->Close();
1082 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
1083
1084 EXPECT_EQ("false", NavigateAndExtractInnerText(extension->GetResourceURL(
1085 "background-client-is-awake")));
1086 EXPECT_EQ("true", NavigateAndExtractInnerText(
1087 extension->GetResourceURL("ping-background-client")));
1088 EXPECT_EQ("true", NavigateAndExtractInnerText(
1089 extension->GetResourceURL("ping-background-client")));
1090 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
1091 "background-client-is-awake")));
1092}
1093
Devlin Cronin242d19d22019-03-12 18:08:481094IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:581095 GetBackgroundClientFailsWithNoBackgroundPage) {
1096 // This extension doesn't have a background page, only a tab at page.html.
1097 // The service worker it registers tries to call getBackgroundClient() and
1098 // should fail.
1099 // Note that this also tests that service workers can be registered from tabs.
1100 EXPECT_TRUE(RunExtensionSubtest("service_worker/no_background", "page.html"));
rdevlin.croninf5863da2015-09-10 19:21:451101}
1102
Devlin Cronin242d19d22019-03-12 18:08:481103IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, NotificationAPI) {
lazyboy6ddb7d62015-11-10 23:15:271104 EXPECT_TRUE(RunExtensionSubtest("service_worker/notifications/has_permission",
1105 "page.html"));
1106}
1107
Devlin Cronin242d19d22019-03-12 18:08:481108IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, WebAccessibleResourcesFetch) {
lazyboyaea32c22016-01-04 21:37:071109 EXPECT_TRUE(RunExtensionSubtest(
1110 "service_worker/web_accessible_resources/fetch/", "page.html"));
1111}
1112
Devlin Cronin242d19d22019-03-12 18:08:481113IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, TabsCreate) {
lazyboyee4adef2016-05-24 00:55:161114 // Extensions APIs from SW are only enabled on trunk.
1115 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1116 const Extension* extension = LoadExtensionWithFlags(
1117 test_data_dir_.AppendASCII("service_worker/tabs_create"), kFlagNone);
1118 ASSERT_TRUE(extension);
1119 ui_test_utils::NavigateToURL(browser(),
1120 extension->GetResourceURL("page.html"));
1121 content::WebContents* web_contents =
1122 browser()->tab_strip_model()->GetActiveWebContents();
1123
1124 int starting_tab_count = browser()->tab_strip_model()->count();
1125 std::string result;
1126 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
1127 web_contents, "window.runServiceWorker()", &result));
1128 ASSERT_EQ("chrome.tabs.create callback", result);
1129 EXPECT_EQ(starting_tab_count + 1, browser()->tab_strip_model()->count());
1130
1131 // Check extension shutdown path.
1132 UnloadExtension(extension->id());
1133 EXPECT_EQ(starting_tab_count, browser()->tab_strip_model()->count());
1134}
1135
Devlin Cronin242d19d22019-03-12 18:08:481136IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, Events) {
lazyboye7847242017-06-07 23:29:181137 // Extensions APIs from SW are only enabled on trunk.
1138 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1139 const Extension* extension = LoadExtensionWithFlags(
1140 test_data_dir_.AppendASCII("service_worker/events"), kFlagNone);
1141 ASSERT_TRUE(extension);
1142 ui_test_utils::NavigateToURL(browser(),
1143 extension->GetResourceURL("page.html"));
1144 content::WebContents* web_contents =
1145 browser()->tab_strip_model()->GetActiveWebContents();
1146 std::string result;
1147 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
1148 web_contents, "window.runEventTest()", &result));
1149 ASSERT_EQ("chrome.tabs.onUpdated callback", result);
1150}
1151
Devlin Cronin242d19d22019-03-12 18:08:481152IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, EventsToStoppedWorker) {
lazyboy63b994a2017-06-30 21:20:231153 // Extensions APIs from SW are only enabled on trunk.
1154 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1155 const Extension* extension = LoadExtensionWithFlags(
1156 test_data_dir_.AppendASCII("service_worker/events_to_stopped_worker"),
1157 kFlagNone);
1158 ASSERT_TRUE(extension);
1159 ui_test_utils::NavigateToURL(browser(),
1160 extension->GetResourceURL("page.html"));
1161 content::WebContents* web_contents =
1162 browser()->tab_strip_model()->GetActiveWebContents();
1163 {
1164 std::string result;
1165 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
1166 web_contents, "window.runServiceWorker()", &result));
1167 ASSERT_EQ("ready", result);
1168
1169 base::RunLoop run_loop;
1170 content::StoragePartition* storage_partition =
1171 content::BrowserContext::GetDefaultStoragePartition(
1172 browser()->profile());
Zhuoyu Qian2266251f2018-10-13 02:59:001173 content::StopServiceWorkerForScope(
lazyboy63b994a2017-06-30 21:20:231174 storage_partition->GetServiceWorkerContext(),
1175 // The service worker is registered at the top level scope.
1176 extension->url(), run_loop.QuitClosure());
1177 run_loop.Run();
1178 }
1179
1180 std::string result;
1181 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
1182 web_contents, "window.createTabThenUpdate()", &result));
1183 ASSERT_EQ("chrome.tabs.onUpdated callback", result);
1184}
1185
Istiaque Ahmed805f6a83b2017-10-05 01:23:261186// Tests that events to service worker arrives correctly event if the owner
1187// extension of the worker is not running.
Devlin Cronin242d19d22019-03-12 18:08:481188IN_PROC_BROWSER_TEST_F(ServiceWorkerLazyBackgroundTest,
Istiaque Ahmedb8e24bdb2018-09-13 15:17:251189 EventsToStoppedExtension) {
Istiaque Ahmed805f6a83b2017-10-05 01:23:261190 LazyBackgroundObserver lazy_observer;
1191 ResultCatcher catcher;
1192 const Extension* extension = LoadExtensionWithFlags(
1193 test_data_dir_.AppendASCII("service_worker/events_to_stopped_extension"),
1194 kFlagNone);
1195 ASSERT_TRUE(extension);
1196 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
1197
1198 ProcessManager* pm = ProcessManager::Get(browser()->profile());
1199 EXPECT_GT(pm->GetLazyKeepaliveCount(extension), 0);
David Bertoni3e1e9fa2018-08-29 20:39:301200 EXPECT_FALSE(pm->GetLazyKeepaliveActivities(extension).empty());
Istiaque Ahmed805f6a83b2017-10-05 01:23:261201
1202 // |extension|'s background page opens a tab to its resource.
1203 content::WebContents* extension_web_contents =
1204 browser()->tab_strip_model()->GetActiveWebContents();
1205 EXPECT_TRUE(content::WaitForLoadStop(extension_web_contents));
1206 EXPECT_EQ(extension->GetResourceURL("page.html").spec(),
1207 extension_web_contents->GetURL().spec());
1208 {
1209 // Let the service worker start and register a listener to
1210 // chrome.tabs.onCreated event.
1211 ExtensionTestMessageListener add_listener_done("listener-added", false);
1212 content::ExecuteScriptAsync(extension_web_contents,
1213 "window.runServiceWorkerAsync()");
1214 EXPECT_TRUE(add_listener_done.WaitUntilSatisfied());
1215
1216 base::RunLoop run_loop;
1217 content::StoragePartition* storage_partition =
1218 content::BrowserContext::GetDefaultStoragePartition(
1219 browser()->profile());
Zhuoyu Qian2266251f2018-10-13 02:59:001220 content::StopServiceWorkerForScope(
Istiaque Ahmed805f6a83b2017-10-05 01:23:261221 storage_partition->GetServiceWorkerContext(),
1222 // The service worker is registered at the top level scope.
1223 extension->url(), run_loop.QuitClosure());
1224 run_loop.Run();
1225 }
1226
1227 // Close the tab to |extension|'s resource. This will also close the
1228 // extension's event page.
1229 browser()->tab_strip_model()->CloseWebContentsAt(
1230 browser()->tab_strip_model()->active_index(), TabStripModel::CLOSE_NONE);
1231 lazy_observer.Wait();
1232
1233 // At this point both the extension worker and extension event page is not
1234 // running. Since the worker registered a listener for tabs.onCreated, it
1235 // will be started to dispatch the event once we create a tab.
1236 ExtensionTestMessageListener newtab_listener("hello-newtab", false);
1237 newtab_listener.set_failure_message("WRONG_NEWTAB");
1238 content::WebContents* new_web_contents =
Istiaque Ahmed7105f2a2017-10-07 01:11:591239 AddTab(browser(), GURL(url::kAboutBlankURL));
1240 EXPECT_TRUE(new_web_contents);
1241 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
1242}
1243
1244// Tests that events to service worker correctly after browser restart.
1245// This test is similar to EventsToStoppedExtension, except that the event
1246// delivery is verified after a browser restart.
Devlin Cronin242d19d22019-03-12 18:08:481247IN_PROC_BROWSER_TEST_F(ServiceWorkerLazyBackgroundTest,
Istiaque Ahmed7105f2a2017-10-07 01:11:591248 PRE_EventsAfterRestart) {
1249 LazyBackgroundObserver lazy_observer;
1250 ResultCatcher catcher;
1251 const Extension* extension = LoadExtensionWithFlags(
1252 test_data_dir_.AppendASCII("service_worker/events_to_stopped_extension"),
1253 kFlagNone);
1254 ASSERT_TRUE(extension);
1255 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
1256
1257 ProcessManager* pm = ProcessManager::Get(browser()->profile());
1258 EXPECT_GT(pm->GetLazyKeepaliveCount(extension), 0);
David Bertoni3e1e9fa2018-08-29 20:39:301259 EXPECT_FALSE(pm->GetLazyKeepaliveActivities(extension).empty());
Istiaque Ahmed7105f2a2017-10-07 01:11:591260
1261 // |extension|'s background page opens a tab to its resource.
1262 content::WebContents* extension_web_contents =
1263 browser()->tab_strip_model()->GetActiveWebContents();
1264 EXPECT_TRUE(content::WaitForLoadStop(extension_web_contents));
1265 EXPECT_EQ(extension->GetResourceURL("page.html").spec(),
1266 extension_web_contents->GetURL().spec());
1267 {
1268 // Let the service worker start and register a listener to
1269 // chrome.tabs.onCreated event.
1270 ExtensionTestMessageListener add_listener_done("listener-added", false);
1271 content::ExecuteScriptAsync(extension_web_contents,
1272 "window.runServiceWorkerAsync()");
1273 EXPECT_TRUE(add_listener_done.WaitUntilSatisfied());
1274
1275 base::RunLoop run_loop;
1276 content::StoragePartition* storage_partition =
1277 content::BrowserContext::GetDefaultStoragePartition(
1278 browser()->profile());
Zhuoyu Qian2266251f2018-10-13 02:59:001279 content::StopServiceWorkerForScope(
Istiaque Ahmed7105f2a2017-10-07 01:11:591280 storage_partition->GetServiceWorkerContext(),
1281 // The service worker is registered at the top level scope.
1282 extension->url(), run_loop.QuitClosure());
1283 run_loop.Run();
1284 }
1285
1286 // Close the tab to |extension|'s resource. This will also close the
1287 // extension's event page.
1288 browser()->tab_strip_model()->CloseWebContentsAt(
1289 browser()->tab_strip_model()->active_index(), TabStripModel::CLOSE_NONE);
1290 lazy_observer.Wait();
1291}
1292
Devlin Cronin242d19d22019-03-12 18:08:481293IN_PROC_BROWSER_TEST_F(ServiceWorkerLazyBackgroundTest, EventsAfterRestart) {
Istiaque Ahmed7105f2a2017-10-07 01:11:591294 ExtensionTestMessageListener newtab_listener("hello-newtab", false);
1295 content::WebContents* new_web_contents =
1296 AddTab(browser(), GURL(url::kAboutBlankURL));
Istiaque Ahmed805f6a83b2017-10-05 01:23:261297 EXPECT_TRUE(new_web_contents);
1298 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
1299}
1300
lazyboy4c82177a2016-10-18 00:04:091301// Tests that worker ref count increments while extension API function is
1302// active.
Devlin Cronin242d19d22019-03-12 18:08:481303IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, WorkerRefCount) {
lazyboy4c82177a2016-10-18 00:04:091304 // Extensions APIs from SW are only enabled on trunk.
1305 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1306 const Extension* extension = LoadExtensionWithFlags(
1307 test_data_dir_.AppendASCII("service_worker/api_worker_ref_count"),
1308 kFlagNone);
1309 ASSERT_TRUE(extension);
1310 ui_test_utils::NavigateToURL(browser(),
1311 extension->GetResourceURL("page.html"));
1312 content::WebContents* web_contents =
1313 browser()->tab_strip_model()->GetActiveWebContents();
1314
1315 ExtensionTestMessageListener worker_start_listener("WORKER STARTED", false);
1316 worker_start_listener.set_failure_message("FAILURE");
1317 ASSERT_TRUE(
1318 content::ExecuteScript(web_contents, "window.runServiceWorker()"));
1319 ASSERT_TRUE(worker_start_listener.WaitUntilSatisfied());
1320
1321 // Service worker should have no pending requests because it hasn't peformed
1322 // any extension API request yet.
1323 EXPECT_EQ(0u, GetWorkerRefCount(extension->url()));
1324
1325 ExtensionTestMessageListener worker_listener("CHECK_REF_COUNT", true);
1326 worker_listener.set_failure_message("FAILURE");
1327 ASSERT_TRUE(content::ExecuteScript(web_contents, "window.testSendMessage()"));
1328 ASSERT_TRUE(worker_listener.WaitUntilSatisfied());
1329
1330 // Service worker should have exactly one pending request because
1331 // chrome.test.sendMessage() API call is in-flight.
1332 EXPECT_EQ(1u, GetWorkerRefCount(extension->url()));
1333
1334 // Peform another extension API request while one is ongoing.
1335 {
1336 ExtensionTestMessageListener listener("CHECK_REF_COUNT", true);
1337 listener.set_failure_message("FAILURE");
1338 ASSERT_TRUE(
1339 content::ExecuteScript(web_contents, "window.testSendMessage()"));
1340 ASSERT_TRUE(listener.WaitUntilSatisfied());
1341
1342 // Service worker currently has two extension API requests in-flight.
1343 EXPECT_EQ(2u, GetWorkerRefCount(extension->url()));
1344 // Finish executing the nested chrome.test.sendMessage() first.
1345 listener.Reply("Hello world");
1346 }
1347
Istiaque Ahmedb57c9752017-08-20 19:08:571348 ExtensionTestMessageListener worker_completion_listener("SUCCESS_FROM_WORKER",
1349 false);
lazyboy4c82177a2016-10-18 00:04:091350 // Finish executing chrome.test.sendMessage().
1351 worker_listener.Reply("Hello world");
Istiaque Ahmedb57c9752017-08-20 19:08:571352 EXPECT_TRUE(worker_completion_listener.WaitUntilSatisfied());
1353
1354 // The following block makes sure we have received all the IPCs related to
1355 // ref-count from the worker.
1356 {
1357 // The following roundtrip:
1358 // browser->extension->worker->extension->browser
1359 // will ensure that the worker sent the relevant ref count IPCs.
1360 std::string result;
1361 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1362 web_contents, "window.roundtripToWorker();", &result));
1363 EXPECT_EQ("roundtrip-succeeded", result);
1364
1365 // Ensure IO thread IPCs run.
Gabriel Charette01507a22017-09-27 21:30:081366 content::RunAllTasksUntilIdle();
Istiaque Ahmedb57c9752017-08-20 19:08:571367 }
lazyboy4c82177a2016-10-18 00:04:091368
1369 // The ref count should drop to 0.
1370 EXPECT_EQ(0u, GetWorkerRefCount(extension->url()));
1371}
1372
lazyboyaea32c22016-01-04 21:37:071373// This test loads a web page that has an iframe pointing to a
1374// chrome-extension:// URL. The URL is listed in the extension's
1375// web_accessible_resources. Initially the iframe is served from the extension's
1376// resource file. After verifying that, we register a Service Worker that
1377// controls the extension. Further requests to the same resource as before
1378// should now be served by the Service Worker.
1379// This test also verifies that if the requested resource exists in the manifest
1380// but is not present in the extension directory, the Service Worker can still
1381// serve the resource file.
Devlin Cronin242d19d22019-03-12 18:08:481382IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, WebAccessibleResourcesIframeSrc) {
lazyboyaea32c22016-01-04 21:37:071383 const Extension* extension = LoadExtensionWithFlags(
1384 test_data_dir_.AppendASCII(
1385 "service_worker/web_accessible_resources/iframe_src"),
1386 kFlagNone);
1387 ASSERT_TRUE(extension);
1388 ASSERT_TRUE(StartEmbeddedTestServer());
falkenad185092016-06-16 06:10:021389
1390 // Service workers can only control secure contexts
1391 // (https://w3c.github.io/webappsec-secure-contexts/). For documents, this
1392 // typically means the document must have a secure origin AND all its ancestor
1393 // frames must have documents with secure origins. However, extension pages
1394 // are considered secure, even if they have an ancestor document that is an
1395 // insecure context (see GetSchemesBypassingSecureContextCheckWhitelist). So
1396 // extension service workers must be able to control an extension page
1397 // embedded in an insecure context. To test this, set up an insecure
1398 // (non-localhost, non-https) URL for the web page. This page will create
1399 // iframes that load extension pages that must be controllable by service
1400 // worker.
falkenad185092016-06-16 06:10:021401 GURL page_url =
1402 embedded_test_server()->GetURL("a.com",
1403 "/extensions/api_test/service_worker/"
1404 "web_accessible_resources/webpage.html");
1405 EXPECT_FALSE(content::IsOriginSecure(page_url));
lazyboyaea32c22016-01-04 21:37:071406
1407 content::WebContents* web_contents = AddTab(browser(), page_url);
1408 std::string result;
1409 // webpage.html will create an iframe pointing to a resource from |extension|.
1410 // Expect the resource to be served by the extension.
1411 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1412 web_contents, base::StringPrintf("window.testIframe('%s', 'iframe.html')",
1413 extension->id().c_str()),
1414 &result));
1415 EXPECT_EQ("FROM_EXTENSION_RESOURCE", result);
1416
1417 ExtensionTestMessageListener service_worker_ready_listener("SW_READY", false);
1418 EXPECT_TRUE(ExecuteScriptInBackgroundPageNoWait(
1419 extension->id(), "window.registerServiceWorker()"));
1420 EXPECT_TRUE(service_worker_ready_listener.WaitUntilSatisfied());
1421
1422 result.clear();
1423 // webpage.html will create another iframe pointing to a resource from
1424 // |extension| as before. But this time, the resource should be be served
1425 // from the Service Worker.
1426 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1427 web_contents, base::StringPrintf("window.testIframe('%s', 'iframe.html')",
1428 extension->id().c_str()),
1429 &result));
1430 EXPECT_EQ("FROM_SW_RESOURCE", result);
1431
1432 result.clear();
1433 // webpage.html will create yet another iframe pointing to a resource that
1434 // exists in the extension manifest's web_accessible_resources, but is not
1435 // present in the extension directory. Expect the resources of the iframe to
1436 // be served by the Service Worker.
1437 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1438 web_contents,
1439 base::StringPrintf("window.testIframe('%s', 'iframe_non_existent.html')",
1440 extension->id().c_str()),
1441 &result));
1442 EXPECT_EQ("FROM_SW_RESOURCE", result);
1443}
1444
Devlin Cronin242d19d22019-03-12 18:08:481445IN_PROC_BROWSER_TEST_F(ServiceWorkerBackgroundSyncTest, Sync) {
lazyboybd325ae2015-11-18 21:35:261446 const Extension* extension = LoadExtensionWithFlags(
1447 test_data_dir_.AppendASCII("service_worker/sync"), kFlagNone);
1448 ASSERT_TRUE(extension);
1449 ui_test_utils::NavigateToURL(browser(),
1450 extension->GetResourceURL("page.html"));
1451 content::WebContents* web_contents =
1452 browser()->tab_strip_model()->GetActiveWebContents();
1453
1454 // Prevent firing by going offline.
1455 content::background_sync_test_util::SetOnline(web_contents, false);
1456
1457 ExtensionTestMessageListener sync_listener("SYNC: send-chats", false);
1458 sync_listener.set_failure_message("FAIL");
1459
1460 std::string result;
1461 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
1462 web_contents, "window.runServiceWorker()", &result));
1463 ASSERT_EQ("SERVICE_WORKER_READY", result);
1464
1465 EXPECT_FALSE(sync_listener.was_satisfied());
1466 // Resume firing by going online.
1467 content::background_sync_test_util::SetOnline(web_contents, true);
1468 EXPECT_TRUE(sync_listener.WaitUntilSatisfied());
1469}
1470
Devlin Cronin242d19d22019-03-12 18:08:481471IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
horo1eeddde2015-11-19 05:59:251472 FetchFromContentScriptShouldNotGoToServiceWorkerOfPage) {
1473 ASSERT_TRUE(StartEmbeddedTestServer());
1474 GURL page_url = embedded_test_server()->GetURL(
1475 "/extensions/api_test/service_worker/content_script_fetch/"
1476 "controlled_page/index.html");
1477 content::WebContents* tab =
1478 browser()->tab_strip_model()->GetActiveWebContents();
1479 ui_test_utils::NavigateToURL(browser(), page_url);
1480 content::WaitForLoadStop(tab);
1481
1482 std::string value;
1483 ASSERT_TRUE(
1484 content::ExecuteScriptAndExtractString(tab, "register();", &value));
1485 EXPECT_EQ("SW controlled", value);
1486
1487 ASSERT_TRUE(RunExtensionTest("service_worker/content_script_fetch"))
1488 << message_;
1489}
1490
Devlin Cronin242d19d22019-03-12 18:08:481491IN_PROC_BROWSER_TEST_F(ServiceWorkerPushMessagingTest, OnPush) {
lazyboy561b7de2015-11-19 19:27:301492 const Extension* extension = LoadExtensionWithFlags(
1493 test_data_dir_.AppendASCII("service_worker/push_messaging"), kFlagNone);
1494 ASSERT_TRUE(extension);
1495 GURL extension_url = extension->url();
1496
Peter Beverloodd4ef1e2018-06-21 15:41:041497 GrantNotificationPermissionForTest(extension_url);
lazyboy561b7de2015-11-19 19:27:301498
1499 GURL url = extension->GetResourceURL("page.html");
1500 ui_test_utils::NavigateToURL(browser(), url);
1501
1502 content::WebContents* web_contents =
1503 browser()->tab_strip_model()->GetActiveWebContents();
1504
1505 // Start the ServiceWorker.
1506 ExtensionTestMessageListener ready_listener("SERVICE_WORKER_READY", false);
1507 ready_listener.set_failure_message("SERVICE_WORKER_FAILURE");
1508 const char* kScript = "window.runServiceWorker()";
1509 EXPECT_TRUE(content::ExecuteScript(web_contents->GetMainFrame(), kScript));
1510 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
1511
1512 PushMessagingAppIdentifier app_identifier =
1513 GetAppIdentifierForServiceWorkerRegistration(0LL, extension_url);
johnmea5045732016-09-08 17:23:291514 ASSERT_EQ(app_identifier.app_id(), gcm_driver()->last_gettoken_app_id());
1515 EXPECT_EQ("1234567890", gcm_driver()->last_gettoken_authorized_entity());
lazyboy561b7de2015-11-19 19:27:301516
lazyboyd429e2582016-05-20 20:18:521517 base::RunLoop run_loop;
lazyboy561b7de2015-11-19 19:27:301518 // Send a push message via gcm and expect the ServiceWorker to receive it.
1519 ExtensionTestMessageListener push_message_listener("OK", false);
1520 push_message_listener.set_failure_message("FAIL");
1521 gcm::IncomingMessage message;
1522 message.sender_id = "1234567890";
1523 message.raw_data = "testdata";
1524 message.decrypted = true;
lazyboyd429e2582016-05-20 20:18:521525 push_service()->SetMessageCallbackForTesting(run_loop.QuitClosure());
lazyboy561b7de2015-11-19 19:27:301526 push_service()->OnMessage(app_identifier.app_id(), message);
1527 EXPECT_TRUE(push_message_listener.WaitUntilSatisfied());
lazyboyd429e2582016-05-20 20:18:521528 run_loop.Run(); // Wait until the message is handled by push service.
lazyboy561b7de2015-11-19 19:27:301529}
1530
Devlin Cronin242d19d22019-03-12 18:08:481531IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, FilteredEvents) {
Istiaque Ahmed9d1666182017-09-21 23:58:181532 // Extensions APIs from SW are only enabled on trunk.
1533 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1534 ASSERT_TRUE(RunExtensionTest("service_worker/filtered_events"));
1535}
1536
Devlin Cronin242d19d22019-03-12 18:08:481537IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, MimeHandlerView) {
Rob Wue89b90032018-02-16 19:46:081538 ASSERT_TRUE(RunExtensionTest("service_worker/mime_handler_view"));
1539}
1540
Devlin Cronin242d19d22019-03-12 18:08:481541IN_PROC_BROWSER_TEST_F(ServiceWorkerLazyBackgroundTest,
Istiaque Ahmed9ce21b32017-10-10 20:43:181542 PRE_FilteredEventsAfterRestart) {
1543 LazyBackgroundObserver lazy_observer;
1544 ResultCatcher catcher;
1545 const Extension* extension = LoadExtensionWithFlags(
1546 test_data_dir_.AppendASCII(
1547 "service_worker/filtered_events_after_restart"),
1548 kFlagNone);
1549 ASSERT_TRUE(extension);
1550 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
1551
1552 // |extension|'s background page opens a tab to its resource.
1553 content::WebContents* extension_web_contents =
1554 browser()->tab_strip_model()->GetActiveWebContents();
1555 EXPECT_TRUE(content::WaitForLoadStop(extension_web_contents));
1556 EXPECT_EQ(extension->GetResourceURL("page.html").spec(),
1557 extension_web_contents->GetURL().spec());
1558 {
1559 // Let the service worker start and register a filtered listener to
1560 // chrome.webNavigation.onCommitted event.
1561 ExtensionTestMessageListener add_listener_done("listener-added", false);
1562 add_listener_done.set_failure_message("FAILURE");
1563 content::ExecuteScriptAsync(extension_web_contents,
1564 "window.runServiceWorkerAsync()");
1565 EXPECT_TRUE(add_listener_done.WaitUntilSatisfied());
1566
1567 base::RunLoop run_loop;
1568 content::StoragePartition* storage_partition =
1569 content::BrowserContext::GetDefaultStoragePartition(
1570 browser()->profile());
Zhuoyu Qian2266251f2018-10-13 02:59:001571 content::StopServiceWorkerForScope(
Istiaque Ahmed9ce21b32017-10-10 20:43:181572 storage_partition->GetServiceWorkerContext(),
1573 // The service worker is registered at the top level scope.
1574 extension->url(), run_loop.QuitClosure());
1575 run_loop.Run();
1576 }
1577
1578 // Close the tab to |extension|'s resource. This will also close the
1579 // extension's event page.
1580 browser()->tab_strip_model()->CloseWebContentsAt(
1581 browser()->tab_strip_model()->active_index(), TabStripModel::CLOSE_NONE);
1582 lazy_observer.Wait();
1583}
1584
Devlin Cronin242d19d22019-03-12 18:08:481585IN_PROC_BROWSER_TEST_F(ServiceWorkerLazyBackgroundTest,
Istiaque Ahmedf5712522018-09-20 03:35:471586 FilteredEventsAfterRestart) {
Istiaque Ahmed9ce21b32017-10-10 20:43:181587 // Create a tab to a.html, expect it to navigate to b.html. The service worker
1588 // will see two webNavigation.onCommitted events.
1589 ASSERT_TRUE(StartEmbeddedTestServer());
1590 GURL page_url = embedded_test_server()->GetURL(
1591 "/extensions/api_test/service_worker/filtered_events_after_restart/"
1592 "a.html");
1593 ExtensionTestMessageListener worker_filtered_event_listener(
1594 "PASS_FROM_WORKER", false);
1595 worker_filtered_event_listener.set_failure_message("FAIL_FROM_WORKER");
1596 content::WebContents* web_contents = AddTab(browser(), page_url);
1597 EXPECT_TRUE(web_contents);
1598 EXPECT_TRUE(worker_filtered_event_listener.WaitUntilSatisfied());
1599}
1600
Devlin Cronin242d19d22019-03-12 18:08:481601IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
Istiaque Ahmedd4b67ee2019-03-02 10:53:201602 ProcessManagerRegistrationOnShutdown) {
1603 // Note that StopServiceWorkerForScope call below expects the worker to be
1604 // completely installed, so wait for the |extension| worker to see "activate"
1605 // event.
1606 ExtensionTestMessageListener activated_listener("WORKER_ACTIVATED", false);
1607 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
1608 "service_worker/worker_based_background/process_manager"));
1609 ASSERT_TRUE(extension);
1610 EXPECT_TRUE(activated_listener.WaitUntilSatisfied());
1611
1612 base::Optional<WorkerId> worker_id =
1613 GetUniqueRunningWorkerId(extension->id());
1614 ASSERT_TRUE(worker_id);
1615 {
1616 // Shutdown the worker.
1617 // TODO(lazyboy): Ideally we'd want to test worker shutdown on idle, do that
1618 // once //content API allows to override test timeouts for Service Workers.
1619 base::RunLoop run_loop;
1620 content::StoragePartition* storage_partition =
1621 content::BrowserContext::GetDefaultStoragePartition(
1622 browser()->profile());
1623 GURL scope = extension->url();
1624 content::StopServiceWorkerForScope(
1625 storage_partition->GetServiceWorkerContext(),
1626 // The service worker is registered at the top level scope.
1627 extension->url(), run_loop.QuitClosure());
1628 run_loop.Run();
1629 }
1630
1631 EXPECT_FALSE(ProcessManager::Get(profile())->HasServiceWorker(*worker_id));
1632}
1633
Devlin Cronin242d19d22019-03-12 18:08:481634IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
Istiaque Ahmedd4b67ee2019-03-02 10:53:201635 ProcessManagerRegistrationOnTerminate) {
1636 // NOTE: It is not necessary to wait for "activate" event from the worker
1637 // for this test, but we're lazily reusing the extension from
1638 // ProcessManagerRegistrationOnShutdown test.
1639 ExtensionTestMessageListener activated_listener("WORKER_ACTIVATED", false);
1640 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
1641 "service_worker/worker_based_background/process_manager"));
1642 ASSERT_TRUE(extension);
1643 EXPECT_TRUE(activated_listener.WaitUntilSatisfied());
1644
1645 base::Optional<WorkerId> worker_id =
1646 GetUniqueRunningWorkerId(extension->id());
1647 ASSERT_TRUE(worker_id);
1648 {
1649 // Terminate worker's RenderProcessHost.
1650 content::RenderProcessHost* worker_render_process_host =
1651 content::RenderProcessHost::FromID(worker_id->render_process_id);
1652 ASSERT_TRUE(worker_render_process_host);
1653 content::RenderProcessHostWatcher process_exit_observer(
1654 worker_render_process_host,
1655 content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1656 worker_render_process_host->Shutdown(content::RESULT_CODE_KILLED);
1657 process_exit_observer.Wait();
1658 }
1659
1660 EXPECT_FALSE(ProcessManager::Get(profile())->HasServiceWorker(*worker_id));
1661}
1662
Devlin Cronin59551d82019-03-05 01:28:591663// Tests that console messages logged by extension service workers, both via
1664// the typical console.* methods and via our custom bindings console, are
1665// passed through the normal ServiceWorker console messaging and are
1666// observable.
Devlin Cronin242d19d22019-03-12 18:08:481667IN_PROC_BROWSER_TEST_F(ServiceWorkerLazyBackgroundTest, ConsoleLogging) {
Devlin Cronin59551d82019-03-05 01:28:591668 // A helper class to wait for a particular message to be logged from a
1669 // ServiceWorker.
1670 class ConsoleMessageObserver : public content::ServiceWorkerContextObserver {
1671 public:
1672 ConsoleMessageObserver(content::BrowserContext* browser_context,
1673 const std::string& expected_message)
1674 : expected_message_(base::UTF8ToUTF16(expected_message)),
1675 scoped_observer_(this) {
1676 content::StoragePartition* partition =
1677 content::BrowserContext::GetDefaultStoragePartition(browser_context);
1678 scoped_observer_.Add(partition->GetServiceWorkerContext());
1679 }
1680 ~ConsoleMessageObserver() override = default;
1681
1682 void Wait() { run_loop_.Run(); }
1683
1684 private:
1685 // ServiceWorkerContextObserver:
1686 void OnReportConsoleMessage(
1687 int64_t version_id,
1688 const content::ConsoleMessage& message) override {
1689 // NOTE: We could check the version_id, but it shouldn't be necessary with
1690 // the expected messages we're verifying (they're uncommon enough).
1691 if (message.message != expected_message_)
1692 return;
1693 scoped_observer_.RemoveAll();
1694 run_loop_.QuitWhenIdle();
1695 }
1696
1697 base::string16 expected_message_;
1698 base::RunLoop run_loop_;
1699 ScopedObserver<content::ServiceWorkerContext,
1700 content::ServiceWorkerContextObserver>
1701 scoped_observer_;
1702
1703 DISALLOW_COPY_AND_ASSIGN(ConsoleMessageObserver);
1704 };
1705
1706 TestExtensionDir test_dir;
1707 test_dir.WriteManifest(
1708 R"({
1709 "name": "Test Extension",
1710 "manifest_version": 2,
1711 "version": "0.1",
David Bertoni630837d2019-04-02 21:22:101712 "background": {"service_worker": "script.js"}
Devlin Cronin59551d82019-03-05 01:28:591713 })");
1714 constexpr char kScript[] =
1715 R"(// First, log a message using the normal, built-in blink console.
1716 console.log('test message');
1717 chrome.test.runTests([
1718 function justATest() {
1719 // Next, we use the "Console" object from
1720 // extensions/renderer/console.cc, which is used by custom bindings
1721 // so that it isn't tampered with by untrusted script. The test
1722 // custom bindings log a message whenever a test is passed, so we
1723 // force a log by just passing this test.
1724 chrome.test.succeed();
1725 }
1726 ]);)";
1727 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"), kScript);
1728
1729 // The observer for the built-in blink console.
1730 ConsoleMessageObserver default_console_observer(profile(), "test message");
1731 // The observer for our custom extensions bindings console.
1732 ConsoleMessageObserver custom_console_observer(profile(),
1733 "[SUCCESS] justATest");
1734
1735 const Extension* extension = LoadExtension(test_dir.UnpackedPath());
1736 ASSERT_TRUE(extension);
1737
1738 default_console_observer.Wait();
1739 custom_console_observer.Wait();
1740 // If we receive both messages, we passed!
1741}
1742
annekao38685502015-07-14 17:46:391743} // namespace extensions