blob: 4b47ee65c4166b038ff2fe2803e6903a8803afcc [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"
annekao38685502015-07-14 17:46:3919#include "chrome/browser/extensions/extension_apitest.h"
rdevlin.croninf5863da2015-09-10 19:21:4520#include "chrome/browser/extensions/extension_service.h"
Istiaque Ahmed805f6a83b2017-10-05 01:23:2621#include "chrome/browser/extensions/lazy_background_page_test_util.h"
David Bertoni1d646a152019-04-25 02:09:2222#include "chrome/browser/extensions/unpacked_installer.h"
peter9f4490a2017-01-27 00:58:3623#include "chrome/browser/gcm/gcm_profile_service_factory.h"
miguelg9b502862017-04-24 18:13:5324#include "chrome/browser/notifications/notification_display_service_factory.h"
Peter Beverloodd4ef1e2018-06-21 15:41:0425#include "chrome/browser/notifications/notification_permission_context.h"
miguelg9b502862017-04-24 18:13:5326#include "chrome/browser/notifications/stub_notification_display_service.h"
lshang106c1772016-06-06 01:43:2327#include "chrome/browser/permissions/permission_manager.h"
timlohc6911802017-03-01 05:37:0328#include "chrome/browser/permissions/permission_result.h"
lazyboy561b7de2015-11-19 19:27:3029#include "chrome/browser/push_messaging/push_messaging_app_identifier.h"
30#include "chrome/browser/push_messaging/push_messaging_service_factory.h"
31#include "chrome/browser/push_messaging/push_messaging_service_impl.h"
annekao1db36fd2015-07-29 17:09:1632#include "chrome/browser/ui/tabs/tab_strip_model.h"
Trent Apted4267b942017-10-27 03:25:3633#include "chrome/common/chrome_switches.h"
Istiaque Ahmeda14ec482018-08-25 01:02:1834#include "chrome/common/extensions/api/web_navigation.h"
rdevlin.croninf5863da2015-09-10 19:21:4535#include "chrome/test/base/ui_test_utils.h"
timloh9a180ad2017-02-20 07:15:2336#include "components/content_settings/core/common/content_settings_types.h"
Peter Beverloo34139462018-04-10 14:18:0637#include "components/gcm_driver/fake_gcm_profile_service.h"
johnmea5045732016-09-08 17:23:2938#include "components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h"
sdefresne9fb67692015-08-03 18:48:2239#include "components/version_info/version_info.h"
Devlin Cronin59551d82019-03-05 01:28:5940#include "content/public/browser/console_message.h"
kalman6f984ae2015-09-18 17:21:5841#include "content/public/browser/navigation_controller.h"
rdevlin.croninf5863da2015-09-10 19:21:4542#include "content/public/browser/navigation_entry.h"
Istiaque Ahmedd4b67ee2019-03-02 10:53:2043#include "content/public/browser/render_process_host.h"
lazyboy4c82177a2016-10-18 00:04:0944#include "content/public/browser/service_worker_context.h"
Devlin Cronin59551d82019-03-05 01:28:5945#include "content/public/browser/service_worker_context_observer.h"
lazyboy4c82177a2016-10-18 00:04:0946#include "content/public/browser/storage_partition.h"
kalman6f984ae2015-09-18 17:21:5847#include "content/public/browser/web_contents.h"
lazyboybd325ae2015-11-18 21:35:2648#include "content/public/common/content_switches.h"
falkenad185092016-06-16 06:10:0249#include "content/public/common/origin_util.h"
kalman6f984ae2015-09-18 17:21:5850#include "content/public/common/page_type.h"
Istiaque Ahmedd4b67ee2019-03-02 10:53:2051#include "content/public/common/result_codes.h"
lazyboybd325ae2015-11-18 21:35:2652#include "content/public/test/background_sync_test_util.h"
annekao1db36fd2015-07-29 17:09:1653#include "content/public/test/browser_test_utils.h"
lazyboy63b994a2017-06-30 21:20:2354#include "content/public/test/service_worker_test_helpers.h"
Istiaque Ahmed771aa8a22018-06-20 23:40:5355#include "extensions/browser/event_router.h"
kalman6f984ae2015-09-18 17:21:5856#include "extensions/browser/extension_host.h"
lazyboyc3e763a2015-12-09 23:09:5857#include "extensions/browser/extension_registry.h"
kalman6f984ae2015-09-18 17:21:5858#include "extensions/browser/process_manager.h"
Istiaque Ahmed70f76ac2018-11-02 02:59:5559#include "extensions/browser/service_worker_task_queue.h"
Istiaque Ahmeda14ec482018-08-25 01:02:1860#include "extensions/common/api/test.h"
Istiaque Ahmed771aa8a22018-06-20 23:40:5361#include "extensions/common/value_builder.h"
David Bertoni9026eff2019-05-01 18:04:3162#include "extensions/common/verifier_formats.h"
kalman6f984ae2015-09-18 17:21:5863#include "extensions/test/background_page_watcher.h"
annekao38685502015-07-14 17:46:3964#include "extensions/test/extension_test_message_listener.h"
Istiaque Ahmed805f6a83b2017-10-05 01:23:2665#include "extensions/test/result_catcher.h"
Devlin Cronin59551d82019-03-05 01:28:5966#include "extensions/test/test_extension_dir.h"
falkenad185092016-06-16 06:10:0267#include "net/dns/mock_host_resolver.h"
horo1eeddde2015-11-19 05:59:2568#include "net/test/embedded_test_server/embedded_test_server.h"
lazyboy63b994a2017-06-30 21:20:2369#include "url/url_constants.h"
annekao38685502015-07-14 17:46:3970
71namespace extensions {
72
kalman6f984ae2015-09-18 17:21:5873namespace {
74
lazyboy22eddc712015-12-10 21:16:2675// Returns the newly added WebContents.
76content::WebContents* AddTab(Browser* browser, const GURL& url) {
77 int starting_tab_count = browser->tab_strip_model()->count();
78 ui_test_utils::NavigateToURLWithDisposition(
nick3b04f322016-08-31 19:29:1979 browser, url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
lazyboy22eddc712015-12-10 21:16:2680 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
81 int tab_count = browser->tab_strip_model()->count();
82 EXPECT_EQ(starting_tab_count + 1, tab_count);
83 return browser->tab_strip_model()->GetActiveWebContents();
84}
85
lazyboy22eddc712015-12-10 21:16:2686class WebContentsLoadStopObserver : content::WebContentsObserver {
87 public:
88 explicit WebContentsLoadStopObserver(content::WebContents* web_contents)
89 : content::WebContentsObserver(web_contents),
90 load_stop_observed_(false) {}
91
92 void WaitForLoadStop() {
93 if (load_stop_observed_)
94 return;
95 message_loop_runner_ = new content::MessageLoopRunner;
96 message_loop_runner_->Run();
97 }
98
99 private:
100 void DidStopLoading() override {
101 load_stop_observed_ = true;
102 if (message_loop_runner_)
103 message_loop_runner_->Quit();
104 }
105
106 bool load_stop_observed_;
107 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
108
109 DISALLOW_COPY_AND_ASSIGN(WebContentsLoadStopObserver);
110};
111
David Bertoni4d9cf41d2019-06-04 00:06:22112// A known extension ID for tests that specify the key in their
113// manifests.
114constexpr char kTestExtensionId[] = "knldjmfmopnpolahpmmgbagdohdnhkik";
115
kalman6f984ae2015-09-18 17:21:58116} // namespace
117
Devlin Cronin242d19d22019-03-12 18:08:48118class ServiceWorkerTest : public ExtensionApiTest {
annekao38685502015-07-14 17:46:39119 public:
lazyboy20167c22016-05-18 00:59:30120 ServiceWorkerTest() : current_channel_(version_info::Channel::STABLE) {}
Istiaque Ahmed7105f2a2017-10-07 01:11:59121 explicit ServiceWorkerTest(version_info::Channel channel)
122 : current_channel_(channel) {}
annekao38685502015-07-14 17:46:39123
124 ~ServiceWorkerTest() override {}
125
jam1a5b5582017-05-01 16:50:10126 void SetUpOnMainThread() override {
127 ExtensionApiTest::SetUpOnMainThread();
David Bertoni3929f552019-03-28 22:10:36128 host_resolver()->AddRule("*", "127.0.0.1");
jam1a5b5582017-05-01 16:50:10129 }
130
kalman6f984ae2015-09-18 17:21:58131 protected:
132 // Returns the ProcessManager for the test's profile.
133 ProcessManager* process_manager() { return ProcessManager::Get(profile()); }
134
135 // Starts running a test from the background page test extension.
136 //
137 // This registers a service worker with |script_name|, and fetches the
138 // registration result.
Istiaque Ahmed93ff7f42018-08-31 01:42:22139 const Extension* StartTestFromBackgroundPage(const char* script_name) {
Istiaque Ahmed6475f542018-08-28 04:20:21140 ExtensionTestMessageListener ready_listener("ready", false);
kalman6f984ae2015-09-18 17:21:58141 const Extension* extension =
142 LoadExtension(test_data_dir_.AppendASCII("service_worker/background"));
143 CHECK(extension);
Istiaque Ahmed6475f542018-08-28 04:20:21144 CHECK(ready_listener.WaitUntilSatisfied());
145
kalman6f984ae2015-09-18 17:21:58146 ExtensionHost* background_host =
147 process_manager()->GetBackgroundHostForExtension(extension->id());
148 CHECK(background_host);
Istiaque Ahmed6475f542018-08-28 04:20:21149
kalman6f984ae2015-09-18 17:21:58150 std::string error;
151 CHECK(content::ExecuteScriptAndExtractString(
152 background_host->host_contents(),
153 base::StringPrintf("test.registerServiceWorker('%s')", script_name),
154 &error));
Istiaque Ahmed93ff7f42018-08-31 01:42:22155 if (!error.empty())
kalman6f984ae2015-09-18 17:21:58156 ADD_FAILURE() << "Got unexpected error " << error;
157 return extension;
158 }
159
160 // Navigates the browser to a new tab at |url|, waits for it to load, then
161 // returns it.
162 content::WebContents* Navigate(const GURL& url) {
163 ui_test_utils::NavigateToURLWithDisposition(
nick3b04f322016-08-31 19:29:19164 browser(), url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
kalman6f984ae2015-09-18 17:21:58165 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
166 content::WebContents* web_contents =
167 browser()->tab_strip_model()->GetActiveWebContents();
168 content::WaitForLoadStop(web_contents);
169 return web_contents;
170 }
171
172 // Navigates the browser to |url| and returns the new tab's page type.
173 content::PageType NavigateAndGetPageType(const GURL& url) {
clamy1d7a4112018-06-15 15:47:16174 return Navigate(url)
175 ->GetController()
176 .GetLastCommittedEntry()
177 ->GetPageType();
kalman6f984ae2015-09-18 17:21:58178 }
179
180 // Extracts the innerText from |contents|.
181 std::string ExtractInnerText(content::WebContents* contents) {
182 std::string inner_text;
183 if (!content::ExecuteScriptAndExtractString(
184 contents,
185 "window.domAutomationController.send(document.body.innerText)",
186 &inner_text)) {
187 ADD_FAILURE() << "Failed to get inner text for "
188 << contents->GetVisibleURL();
189 }
190 return inner_text;
191 }
192
193 // Navigates the browser to |url|, then returns the innerText of the new
194 // tab's WebContents' main frame.
195 std::string NavigateAndExtractInnerText(const GURL& url) {
196 return ExtractInnerText(Navigate(url));
197 }
198
lazyboy4c82177a2016-10-18 00:04:09199 size_t GetWorkerRefCount(const GURL& origin) {
200 content::ServiceWorkerContext* sw_context =
201 content::BrowserContext::GetDefaultStoragePartition(
202 browser()->profile())
203 ->GetServiceWorkerContext();
204 base::RunLoop run_loop;
205 size_t ref_count = 0;
206 auto set_ref_count = [](size_t* ref_count, base::RunLoop* run_loop,
207 size_t external_request_count) {
208 *ref_count = external_request_count;
209 run_loop->Quit();
210 };
211 sw_context->CountExternalRequestsForTest(
Matt Falkenhagenc5cb4282017-09-07 08:43:42212 origin, base::BindOnce(set_ref_count, &ref_count, &run_loop));
lazyboy4c82177a2016-10-18 00:04:09213 run_loop.Run();
214 return ref_count;
215 }
216
annekao38685502015-07-14 17:46:39217 private:
lazyboy20167c22016-05-18 00:59:30218 // Sets the channel to "stable".
219 // Not useful after we've opened extension Service Workers to stable
220 // channel.
221 // TODO(lazyboy): Remove this when ExtensionServiceWorkersEnabled() is
222 // removed.
annekao38685502015-07-14 17:46:39223 ScopedCurrentChannel current_channel_;
kalman6f984ae2015-09-18 17:21:58224
annekao38685502015-07-14 17:46:39225 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerTest);
226};
227
Istiaque Ahmedccb444022018-06-19 02:11:12228class ServiceWorkerBasedBackgroundTest : public ServiceWorkerTest {
229 public:
230 ServiceWorkerBasedBackgroundTest()
231 : ServiceWorkerTest(
232 // Extensions APIs from SW are only enabled on trunk.
233 // It is important to set the channel early so that this change is
234 // visible in renderers running with service workers (and no
235 // extension).
236 version_info::Channel::UNKNOWN) {}
237 ~ServiceWorkerBasedBackgroundTest() override {}
238
239 void SetUpOnMainThread() override {
240 host_resolver()->AddRule("*", "127.0.0.1");
241 ASSERT_TRUE(embedded_test_server()->Start());
242 ServiceWorkerTest::SetUpOnMainThread();
243 }
244
Istiaque Ahmedd4b67ee2019-03-02 10:53:20245 // Returns the only running worker id for |extension_id|.
246 // Returns base::nullopt if there isn't any worker running or more than one
247 // worker is running for |extension_id|.
248 base::Optional<WorkerId> GetUniqueRunningWorkerId(
249 const ExtensionId& extension_id) {
250 ProcessManager* process_manager = ProcessManager::Get(profile());
251 std::vector<WorkerId> all_workers =
252 process_manager->GetAllWorkersIdsForTesting();
253 base::Optional<WorkerId> running_worker_id;
254 for (const WorkerId& worker_id : all_workers) {
255 if (worker_id.extension_id == extension_id) {
256 if (running_worker_id) // More than one worker present.
257 return base::nullopt;
258 running_worker_id = worker_id;
259 }
260 }
261 return running_worker_id;
262 }
263
Istiaque Ahmedccb444022018-06-19 02:11:12264 private:
265 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerBasedBackgroundTest);
266};
267
268// Tests that Service Worker based background pages can be loaded and they can
269// receive extension events.
270// The extension is installed and loaded during this step and it registers
271// an event listener for tabs.onCreated event. The step also verifies that tab
272// creation correctly fires the listener.
Devlin Cronin242d19d22019-03-12 18:08:48273IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, PRE_Basic) {
Istiaque Ahmedccb444022018-06-19 02:11:12274 ExtensionTestMessageListener newtab_listener("CREATED", false);
275 newtab_listener.set_failure_message("CREATE_FAILED");
276 ExtensionTestMessageListener worker_listener("WORKER_RUNNING", false);
277 worker_listener.set_failure_message("NON_WORKER_SCOPE");
278 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
279 "service_worker/worker_based_background/basic"));
280 ASSERT_TRUE(extension);
281 const ExtensionId extension_id = extension->id();
282 EXPECT_TRUE(worker_listener.WaitUntilSatisfied());
283
284 const GURL url = embedded_test_server()->GetURL("/extensions/test_file.html");
285 content::WebContents* new_web_contents = AddTab(browser(), url);
286 EXPECT_TRUE(new_web_contents);
287 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
288
289 // Service Worker extension does not have ExtensionHost.
290 EXPECT_FALSE(process_manager()->GetBackgroundHostForExtension(extension_id));
291}
292
293// After browser restarts, this test step ensures that opening a tab fires
294// tabs.onCreated event listener to the extension without explicitly loading the
295// extension. This is because the extension registered a listener before browser
296// restarted in PRE_Basic.
Devlin Cronin242d19d22019-03-12 18:08:48297IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, Basic) {
Istiaque Ahmedccb444022018-06-19 02:11:12298 ExtensionTestMessageListener newtab_listener("CREATED", false);
299 newtab_listener.set_failure_message("CREATE_FAILED");
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
Istiaque Ahmedbf08f952018-10-02 01:22:04306// Tests chrome.runtime.onInstalled fires for extension service workers.
Devlin Cronin242d19d22019-03-12 18:08:48307IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, OnInstalledEvent) {
Istiaque Ahmedbf08f952018-10-02 01:22:04308 ASSERT_TRUE(RunExtensionTest(
309 "service_worker/worker_based_background/events_on_installed"))
310 << message_;
311}
312
Istiaque Ahmedba8d0652019-05-14 15:17:34313// Tests chrome.runtime.id and chrome.runtime.getURL().
314IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, RuntimeMisc) {
315 ASSERT_TRUE(
316 RunExtensionTest("service_worker/worker_based_background/runtime_misc"))
317 << message_;
318}
319
David Bertoni69982832019-02-13 21:24:21320// Tests chrome.storage APIs.
Devlin Cronin242d19d22019-03-12 18:08:48321IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, StorageSetAndGet) {
David Bertoni69982832019-02-13 21:24:21322 ASSERT_TRUE(
323 RunExtensionTest("service_worker/worker_based_background/storage"))
324 << message_;
325}
326
David Bertoni0665c892019-02-14 00:27:26327// Tests chrome.storage.local and chrome.storage.local APIs.
Devlin Cronin242d19d22019-03-12 18:08:48328IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, StorageNoPermissions) {
David Bertoni0665c892019-02-14 00:27:26329 ASSERT_TRUE(RunExtensionTest(
330 "service_worker/worker_based_background/storage_no_permissions"))
331 << message_;
332}
333
David Bertoni30809312019-02-28 22:56:05334// Tests chrome.tabs APIs.
Devlin Cronin242d19d22019-03-12 18:08:48335IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, TabsBasic) {
David Bertoni30809312019-02-28 22:56:05336 ASSERT_TRUE(
337 RunExtensionTest("service_worker/worker_based_background/tabs_basic"))
338 << message_;
339}
340
David Bertoni46d698892019-02-26 00:29:10341// Tests chrome.tabs events.
Devlin Cronin242d19d22019-03-12 18:08:48342IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, TabsEvents) {
David Bertoni46d698892019-02-26 00:29:10343 ASSERT_TRUE(
344 RunExtensionTest("service_worker/worker_based_background/tabs_events"))
345 << message_;
346}
347
David Bertoni4c7dfcc2019-03-27 23:49:34348// Tests chrome.tabs APIs.
349IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, TabsExecuteScript) {
350 ASSERT_TRUE(RunExtensionTest(
351 "service_worker/worker_based_background/tabs_execute_script"))
352 << message_;
353}
354
David Bertoni37ae0222019-04-04 01:30:54355// Tests chrome.webRequest APIs.
David Bertoni3929f552019-03-28 22:10:36356IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, WebRequest) {
357 ASSERT_TRUE(
358 RunExtensionTest("service_worker/worker_based_background/web_request"))
359 << message_;
360}
361
David Bertoni37ae0222019-04-04 01:30:54362// Tests chrome.webRequest APIs in blocking mode.
363IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, WebRequestBlocking) {
364 // Try to load the page before installing the extension, which should work.
365 const GURL url = embedded_test_server()->GetURL("/extensions/test_file.html");
366 EXPECT_EQ(content::PAGE_TYPE_NORMAL, NavigateAndGetPageType(url));
367
368 // Install the extension and navigate again to the page.
369 ExtensionTestMessageListener ready_listener("ready", false);
370 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII(
371 "service_worker/worker_based_background/web_request_blocking")));
372 ASSERT_TRUE(ready_listener.WaitUntilSatisfied());
373 EXPECT_EQ(content::PAGE_TYPE_ERROR, NavigateAndGetPageType(url));
374}
375
David Bertoni377f52312019-05-21 20:35:03376// Tests chrome.webNavigation APIs.
377IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, FilteredEvents) {
378 ASSERT_TRUE(RunExtensionTest(
379 "service_worker/worker_based_background/filtered_events"))
380 << message_;
381}
382
Istiaque Ahmed70f76ac2018-11-02 02:59:55383// Listens for |message| from extension Service Worker early so that tests can
384// wait for the message on startup (and not miss it).
385class ServiceWorkerWithEarlyMessageListenerTest
386 : public ServiceWorkerBasedBackgroundTest {
Istiaque Ahmedf70ab222018-10-02 03:08:24387 public:
Istiaque Ahmed70f76ac2018-11-02 02:59:55388 explicit ServiceWorkerWithEarlyMessageListenerTest(
389 const std::string& test_message)
390 : test_message_(test_message) {}
391 ~ServiceWorkerWithEarlyMessageListenerTest() override = default;
Istiaque Ahmedf70ab222018-10-02 03:08:24392
Istiaque Ahmed70f76ac2018-11-02 02:59:55393 bool WaitForMessage() { return listener_->WaitUntilSatisfied(); }
Istiaque Ahmedf70ab222018-10-02 03:08:24394
395 void CreatedBrowserMainParts(content::BrowserMainParts* main_parts) override {
396 // At this point, the notification service is initialized but the profile
397 // and extensions have not.
Istiaque Ahmed70f76ac2018-11-02 02:59:55398 listener_ =
399 std::make_unique<ExtensionTestMessageListener>(test_message_, false);
Istiaque Ahmedf70ab222018-10-02 03:08:24400 ServiceWorkerBasedBackgroundTest::CreatedBrowserMainParts(main_parts);
401 }
402
403 private:
Istiaque Ahmed70f76ac2018-11-02 02:59:55404 const std::string test_message_;
Istiaque Ahmedf70ab222018-10-02 03:08:24405 std::unique_ptr<ExtensionTestMessageListener> listener_;
406
Istiaque Ahmed70f76ac2018-11-02 02:59:55407 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerWithEarlyMessageListenerTest);
408};
409
410class ServiceWorkerOnStartupEventTest
411 : public ServiceWorkerWithEarlyMessageListenerTest {
412 public:
413 ServiceWorkerOnStartupEventTest()
414 : ServiceWorkerWithEarlyMessageListenerTest("onStartup event") {}
415 ~ServiceWorkerOnStartupEventTest() override = default;
416
417 private:
418 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerOnStartupEventTest);
Istiaque Ahmedf70ab222018-10-02 03:08:24419};
420
421// Tests "runtime.onStartup" for extension SW.
Devlin Cronin242d19d22019-03-12 18:08:48422IN_PROC_BROWSER_TEST_F(ServiceWorkerOnStartupEventTest, PRE_Event) {
Istiaque Ahmedf70ab222018-10-02 03:08:24423 ASSERT_TRUE(RunExtensionTest(
424 "service_worker/worker_based_background/on_startup_event"))
425 << message_;
426}
427
Devlin Cronin242d19d22019-03-12 18:08:48428IN_PROC_BROWSER_TEST_F(ServiceWorkerOnStartupEventTest, Event) {
Istiaque Ahmed70f76ac2018-11-02 02:59:55429 EXPECT_TRUE(WaitForMessage());
430}
431
432class ServiceWorkerRegistrationAtStartupTest
433 : public ServiceWorkerWithEarlyMessageListenerTest,
434 public ServiceWorkerTaskQueue::TestObserver {
435 public:
436 ServiceWorkerRegistrationAtStartupTest()
437 : ServiceWorkerWithEarlyMessageListenerTest("WORKER_RUNNING") {
438 ServiceWorkerTaskQueue::SetObserverForTest(this);
439 }
440 ~ServiceWorkerRegistrationAtStartupTest() override {
441 ServiceWorkerTaskQueue::SetObserverForTest(nullptr);
442 }
443
444 // ServiceWorkerTaskQueue::TestObserver:
445 void OnActivateExtension(const ExtensionId& extension_id,
446 bool will_register_service_worker) override {
447 if (extension_id != kExtensionId)
448 return;
449
450 will_register_service_worker_ = will_register_service_worker;
451
452 extension_activated_ = true;
453 if (run_loop_)
454 run_loop_->Quit();
455 }
456
457 void WaitForOnActivateExtension() {
458 if (extension_activated_)
459 return;
460 run_loop_ = std::make_unique<base::RunLoop>();
461 run_loop_->Run();
462 }
463
464 bool WillRegisterServiceWorker() {
465 return will_register_service_worker_.value();
466 }
467
468 protected:
469 static const char kExtensionId[];
470
471 private:
472 bool extension_activated_ = false;
473 base::Optional<bool> will_register_service_worker_;
474 std::unique_ptr<base::RunLoop> run_loop_;
475
476 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerRegistrationAtStartupTest);
477};
478
479// Test extension id at
480// api_test/service_worker/worker_based_background/registration_at_startup/.
481const char ServiceWorkerRegistrationAtStartupTest::kExtensionId[] =
482 "gnchfmandajfaiajniicagenfmhdjila";
483
484// Tests that Service Worker registration for existing extension isn't issued
485// upon browser restart.
486// Regression test for https://crbug.com/889687.
Devlin Cronin242d19d22019-03-12 18:08:48487IN_PROC_BROWSER_TEST_F(ServiceWorkerRegistrationAtStartupTest,
Istiaque Ahmed70f76ac2018-11-02 02:59:55488 PRE_ExtensionActivationDoesNotReregister) {
489 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
490 "service_worker/worker_based_background/registration_at_startup"));
491 ASSERT_TRUE(extension);
492 EXPECT_EQ(kExtensionId, extension->id());
493 // Wait for "WORKER_RUNNING" message from the Service Worker.
494 EXPECT_TRUE(WaitForMessage());
495 EXPECT_TRUE(WillRegisterServiceWorker());
496}
497
Devlin Cronin242d19d22019-03-12 18:08:48498IN_PROC_BROWSER_TEST_F(ServiceWorkerRegistrationAtStartupTest,
Istiaque Ahmed70f76ac2018-11-02 02:59:55499 ExtensionActivationDoesNotReregister) {
500 // Since the extension has onStartup listener, the Service Worker will run on
501 // browser start and we'll see "WORKER_RUNNING" message from the worker.
502 EXPECT_TRUE(WaitForMessage());
503 // As the extension activated during first run on PRE_ step, it shouldn't
504 // re-register the Service Worker upon browser restart.
505 EXPECT_FALSE(WillRegisterServiceWorker());
Istiaque Ahmedf70ab222018-10-02 03:08:24506}
507
Istiaque Ahmeda14ec482018-08-25 01:02:18508// Class that dispatches an event to |extension_id| right after a
509// non-lazy listener to the event is added from the extension's Service Worker.
Istiaque Ahmed771aa8a22018-06-20 23:40:53510class EarlyWorkerMessageSender : public EventRouter::Observer {
511 public:
512 EarlyWorkerMessageSender(content::BrowserContext* browser_context,
Istiaque Ahmeda14ec482018-08-25 01:02:18513 const ExtensionId& extension_id,
514 std::unique_ptr<Event> event)
Istiaque Ahmed771aa8a22018-06-20 23:40:53515 : browser_context_(browser_context),
516 event_router_(EventRouter::EventRouter::Get(browser_context_)),
517 extension_id_(extension_id),
Istiaque Ahmeda14ec482018-08-25 01:02:18518 event_(std::move(event)),
Istiaque Ahmed771aa8a22018-06-20 23:40:53519 listener_("PASS", false) {
520 DCHECK(browser_context_);
521 listener_.set_failure_message("FAIL");
Istiaque Ahmeda14ec482018-08-25 01:02:18522 event_router_->RegisterObserver(this, event_->event_name);
Istiaque Ahmed771aa8a22018-06-20 23:40:53523 }
524
525 ~EarlyWorkerMessageSender() override {
526 event_router_->UnregisterObserver(this);
527 }
528
529 // EventRouter::Observer:
530 void OnListenerAdded(const EventListenerInfo& details) override {
Istiaque Ahmeda14ec482018-08-25 01:02:18531 if (!event_ || extension_id_ != details.extension_id ||
532 event_->event_name != details.event_name) {
Istiaque Ahmed771aa8a22018-06-20 23:40:53533 return;
Istiaque Ahmeda14ec482018-08-25 01:02:18534 }
535
Istiaque Ahmed771aa8a22018-06-20 23:40:53536 const bool is_lazy_listener = details.browser_context == nullptr;
537 if (is_lazy_listener) {
538 // Wait for the non-lazy listener as we want to exercise the code to
539 // dispatch the event right after the Service Worker registration is
540 // completing.
541 return;
542 }
Istiaque Ahmeda14ec482018-08-25 01:02:18543 DispatchEvent(std::move(event_));
Istiaque Ahmed771aa8a22018-06-20 23:40:53544 }
545
546 bool SendAndWait() { return listener_.WaitUntilSatisfied(); }
547
548 private:
549 static constexpr const char* const kTestOnMessageEventName = "test.onMessage";
550
Istiaque Ahmeda14ec482018-08-25 01:02:18551 void DispatchEvent(std::unique_ptr<Event> event) {
Istiaque Ahmed771aa8a22018-06-20 23:40:53552 EventRouter::Get(browser_context_)
553 ->DispatchEventToExtension(extension_id_, std::move(event));
554 }
555
556 content::BrowserContext* const browser_context_ = nullptr;
557 EventRouter* const event_router_ = nullptr;
558 const ExtensionId extension_id_;
Istiaque Ahmeda14ec482018-08-25 01:02:18559 std::unique_ptr<Event> event_;
Istiaque Ahmed771aa8a22018-06-20 23:40:53560 ExtensionTestMessageListener listener_;
Istiaque Ahmed771aa8a22018-06-20 23:40:53561
562 DISALLOW_COPY_AND_ASSIGN(EarlyWorkerMessageSender);
563};
564
565// Tests that extension event dispatch works correctly right after extension
566// installation registers its Service Worker.
567// Regression test for: https://crbug.com/850792.
Devlin Cronin242d19d22019-03-12 18:08:48568IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, EarlyEventDispatch) {
Istiaque Ahmed771aa8a22018-06-20 23:40:53569 const ExtensionId kId("pkplfbidichfdicaijlchgnapepdginl");
Istiaque Ahmeda14ec482018-08-25 01:02:18570
571 // Build "test.onMessage" event for dispatch.
572 auto event = std::make_unique<Event>(
573 events::FOR_TEST, extensions::api::test::OnMessage::kEventName,
Lei Zhang582ecd12019-02-13 20:28:54574 base::ListValue::From(base::JSONReader::ReadDeprecated(
Istiaque Ahmeda14ec482018-08-25 01:02:18575 R"([{"data": "hello", "lastMessage": true}])")),
576 profile());
577
578 EarlyWorkerMessageSender sender(profile(), kId, std::move(event));
Istiaque Ahmed771aa8a22018-06-20 23:40:53579 // pkplfbidichfdicaijlchgnapepdginl
580 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
581 "service_worker/worker_based_background/early_event_dispatch"));
582 CHECK(extension);
583 EXPECT_EQ(kId, extension->id());
584 EXPECT_TRUE(sender.SendAndWait());
585}
586
Istiaque Ahmeda14ec482018-08-25 01:02:18587// Tests that filtered events dispatches correctly right after a non-lazy
588// listener is registered for that event (and before the corresponding lazy
589// listener is registered).
Devlin Cronin242d19d22019-03-12 18:08:48590IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
Istiaque Ahmeda14ec482018-08-25 01:02:18591 EarlyFilteredEventDispatch) {
592 const ExtensionId kId("pkplfbidichfdicaijlchgnapepdginl");
593
594 // Add minimal details required to dispatch webNavigation.onCommitted event:
595 extensions::api::web_navigation::OnCommitted::Details details;
596 details.transition_type =
597 extensions::api::web_navigation::TRANSITION_TYPE_TYPED;
598
599 // Build a dummy onCommited event to dispatch.
600 auto on_committed_event = std::make_unique<Event>(
601 events::WEB_NAVIGATION_ON_COMMITTED, "webNavigation.onCommitted",
602 api::web_navigation::OnCommitted::Create(details), profile());
603 // The filter will match the listener filter registered from the extension.
604 EventFilteringInfo info;
605 info.url = GURL("http://foo.com/a.html");
606 on_committed_event->filter_info = info;
607
608 EarlyWorkerMessageSender sender(profile(), kId,
609 std::move(on_committed_event));
610
611 // pkplfbidichfdicaijlchgnapepdginl
612 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
613 "service_worker/worker_based_background/early_filtered_event_dispatch"));
614 ASSERT_TRUE(extension);
615 EXPECT_EQ(kId, extension->id());
616 EXPECT_TRUE(sender.SendAndWait());
617}
618
lazyboybd325ae2015-11-18 21:35:26619class ServiceWorkerBackgroundSyncTest : public ServiceWorkerTest {
620 public:
621 ServiceWorkerBackgroundSyncTest() {}
622 ~ServiceWorkerBackgroundSyncTest() override {}
623
624 void SetUpCommandLine(base::CommandLine* command_line) override {
625 // ServiceWorkerRegistration.sync requires experimental flag.
626 command_line->AppendSwitch(
Istiaque Ahmedea5ed5042017-09-25 19:00:16627 ::switches::kEnableExperimentalWebPlatformFeatures);
lazyboybd325ae2015-11-18 21:35:26628 ServiceWorkerTest::SetUpCommandLine(command_line);
629 }
630
631 void SetUp() override {
Robbie McElrathdb12d8e2018-09-18 21:20:40632 content::background_sync_test_util::SetIgnoreNetworkChanges(true);
lazyboybd325ae2015-11-18 21:35:26633 ServiceWorkerTest::SetUp();
634 }
635
636 private:
637 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerBackgroundSyncTest);
638};
639
lazyboy561b7de2015-11-19 19:27:30640class ServiceWorkerPushMessagingTest : public ServiceWorkerTest {
641 public:
642 ServiceWorkerPushMessagingTest()
Sylvain Defresne212b4b02018-10-11 16:32:05643 : scoped_testing_factory_installer_(
644 base::BindRepeating(&gcm::FakeGCMProfileService::Build)),
645 gcm_driver_(nullptr),
646 push_service_(nullptr) {}
647
lazyboy561b7de2015-11-19 19:27:30648 ~ServiceWorkerPushMessagingTest() override {}
649
650 void GrantNotificationPermissionForTest(const GURL& url) {
Peter Beverloodd4ef1e2018-06-21 15:41:04651 NotificationPermissionContext::UpdatePermission(profile(), url.GetOrigin(),
652 CONTENT_SETTING_ALLOW);
lazyboy561b7de2015-11-19 19:27:30653 }
654
655 PushMessagingAppIdentifier GetAppIdentifierForServiceWorkerRegistration(
avia2f4804a2015-12-24 23:11:13656 int64_t service_worker_registration_id,
lazyboy561b7de2015-11-19 19:27:30657 const GURL& origin) {
658 PushMessagingAppIdentifier app_identifier =
659 PushMessagingAppIdentifier::FindByServiceWorker(
660 profile(), origin, service_worker_registration_id);
661
662 EXPECT_FALSE(app_identifier.is_null());
663 return app_identifier;
664 }
665
666 // ExtensionApiTest overrides.
667 void SetUpCommandLine(base::CommandLine* command_line) override {
peter9de96272015-12-04 15:23:27668 command_line->AppendSwitch(
Istiaque Ahmedea5ed5042017-09-25 19:00:16669 ::switches::kEnableExperimentalWebPlatformFeatures);
lazyboy561b7de2015-11-19 19:27:30670 ServiceWorkerTest::SetUpCommandLine(command_line);
671 }
Tanja Gornak89128fd2018-09-18 08:49:34672
lazyboy561b7de2015-11-19 19:27:30673 void SetUpOnMainThread() override {
miguelg9b502862017-04-24 18:13:53674 NotificationDisplayServiceFactory::GetInstance()->SetTestingFactory(
Sylvain Defresne711ff6b2018-10-04 12:33:54675 profile(),
676 base::BindRepeating(&StubNotificationDisplayService::FactoryForTests));
miguelg9b502862017-04-24 18:13:53677
johnmea5045732016-09-08 17:23:29678 gcm::FakeGCMProfileService* gcm_service =
679 static_cast<gcm::FakeGCMProfileService*>(
Tanja Gornak89128fd2018-09-18 08:49:34680 gcm::GCMProfileServiceFactory::GetForProfile(profile()));
johnmea5045732016-09-08 17:23:29681 gcm_driver_ = static_cast<instance_id::FakeGCMDriverForInstanceID*>(
682 gcm_service->driver());
lazyboy561b7de2015-11-19 19:27:30683 push_service_ = PushMessagingServiceFactory::GetForProfile(profile());
684
685 ServiceWorkerTest::SetUpOnMainThread();
686 }
687
johnmea5045732016-09-08 17:23:29688 instance_id::FakeGCMDriverForInstanceID* gcm_driver() const {
689 return gcm_driver_;
690 }
lazyboy561b7de2015-11-19 19:27:30691 PushMessagingServiceImpl* push_service() const { return push_service_; }
692
693 private:
Sylvain Defresne212b4b02018-10-11 16:32:05694 gcm::GCMProfileServiceFactory::ScopedTestingFactoryInstaller
695 scoped_testing_factory_installer_;
696
johnmea5045732016-09-08 17:23:29697 instance_id::FakeGCMDriverForInstanceID* gcm_driver_;
lazyboy561b7de2015-11-19 19:27:30698 PushMessagingServiceImpl* push_service_;
699
700 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerPushMessagingTest);
701};
702
Istiaque Ahmed805f6a83b2017-10-05 01:23:26703class ServiceWorkerLazyBackgroundTest : public ServiceWorkerTest {
704 public:
Istiaque Ahmed7105f2a2017-10-07 01:11:59705 ServiceWorkerLazyBackgroundTest()
706 : ServiceWorkerTest(
707 // Extensions APIs from SW are only enabled on trunk.
708 // It is important to set the channel early so that this change is
709 // visible in renderers running with service workers (and no
710 // extension).
711 version_info::Channel::UNKNOWN) {}
Istiaque Ahmed805f6a83b2017-10-05 01:23:26712 ~ServiceWorkerLazyBackgroundTest() override {}
713
714 void SetUpCommandLine(base::CommandLine* command_line) override {
715 ServiceWorkerTest::SetUpCommandLine(command_line);
716 // Disable background network activity as it can suddenly bring the Lazy
717 // Background Page alive.
718 command_line->AppendSwitch(::switches::kDisableBackgroundNetworking);
719 command_line->AppendSwitch(::switches::kNoProxyServer);
720 }
721
722 void SetUpInProcessBrowserTestFixture() override {
723 ServiceWorkerTest::SetUpInProcessBrowserTestFixture();
724 // Set shorter delays to prevent test timeouts.
725 ProcessManager::SetEventPageIdleTimeForTesting(1);
726 ProcessManager::SetEventPageSuspendingTimeForTesting(1);
727 }
728
729 private:
730 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerLazyBackgroundTest);
731};
732
Devlin Cronin242d19d22019-03-12 18:08:48733IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, RegisterSucceeds) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22734 StartTestFromBackgroundPage("register.js");
annekao38685502015-07-14 17:46:39735}
736
Devlin Cronin242d19d22019-03-12 18:08:48737IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, UpdateRefreshesServiceWorker) {
Francois Doraye6fb2d02017-10-18 21:29:13738 base::ScopedAllowBlockingForTesting allow_blocking;
lazyboyc3e763a2015-12-09 23:09:58739 base::ScopedTempDir scoped_temp_dir;
740 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
741 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
742 .AppendASCII("update")
743 .AppendASCII("service_worker.pem");
vabr9142fe22016-09-08 13:19:22744 base::FilePath path_v1 =
745 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
746 .AppendASCII("update")
747 .AppendASCII("v1"),
748 scoped_temp_dir.GetPath().AppendASCII("v1.crx"),
749 pem_path, base::FilePath());
750 base::FilePath path_v2 =
751 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
752 .AppendASCII("update")
753 .AppendASCII("v2"),
754 scoped_temp_dir.GetPath().AppendASCII("v2.crx"),
755 pem_path, base::FilePath());
lazyboyc3e763a2015-12-09 23:09:58756 const char* kId = "hfaanndiiilofhfokeanhddpkfffchdi";
757
758 ExtensionTestMessageListener listener_v1("Pong from version 1", false);
759 listener_v1.set_failure_message("FAILURE_V1");
760 // Install version 1.0 of the extension.
761 ASSERT_TRUE(InstallExtension(path_v1, 1));
762 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
763 ->enabled_extensions()
764 .GetByID(kId));
765 EXPECT_TRUE(listener_v1.WaitUntilSatisfied());
766
767 ExtensionTestMessageListener listener_v2("Pong from version 2", false);
768 listener_v2.set_failure_message("FAILURE_V2");
769
770 // Update to version 2.0.
771 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
772 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
773 ->enabled_extensions()
774 .GetByID(kId));
775 EXPECT_TRUE(listener_v2.WaitUntilSatisfied());
776}
777
[email protected]2ef85d562017-09-15 18:41:52778// TODO(crbug.com/765736) Fix the test.
Devlin Cronin242d19d22019-03-12 18:08:48779IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, DISABLED_UpdateWithoutSkipWaiting) {
Francois Doraye6fb2d02017-10-18 21:29:13780 base::ScopedAllowBlockingForTesting allow_blocking;
lazyboy22eddc712015-12-10 21:16:26781 base::ScopedTempDir scoped_temp_dir;
782 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
783 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
784 .AppendASCII("update_without_skip_waiting")
785 .AppendASCII("update_without_skip_waiting.pem");
vabr9142fe22016-09-08 13:19:22786 base::FilePath path_v1 =
787 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
788 .AppendASCII("update_without_skip_waiting")
789 .AppendASCII("v1"),
790 scoped_temp_dir.GetPath().AppendASCII("v1.crx"),
791 pem_path, base::FilePath());
792 base::FilePath path_v2 =
793 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
794 .AppendASCII("update_without_skip_waiting")
795 .AppendASCII("v2"),
796 scoped_temp_dir.GetPath().AppendASCII("v2.crx"),
797 pem_path, base::FilePath());
lazyboy22eddc712015-12-10 21:16:26798 const char* kId = "mhnnnflgagdakldgjpfcofkiocpdmogl";
799
800 // Install version 1.0 of the extension.
801 ASSERT_TRUE(InstallExtension(path_v1, 1));
802 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
803 ->enabled_extensions()
804 .GetByID(kId));
805 const Extension* extension = extensions::ExtensionRegistry::Get(profile())
806 ->enabled_extensions()
807 .GetByID(kId);
808
809 ExtensionTestMessageListener listener1("Pong from version 1", false);
810 listener1.set_failure_message("FAILURE");
811 content::WebContents* web_contents =
812 AddTab(browser(), extension->GetResourceURL("page.html"));
813 EXPECT_TRUE(listener1.WaitUntilSatisfied());
814
815 // Update to version 2.0.
816 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
817 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
818 ->enabled_extensions()
819 .GetByID(kId));
820 const Extension* extension_after_update =
821 extensions::ExtensionRegistry::Get(profile())
822 ->enabled_extensions()
823 .GetByID(kId);
824
825 // Service worker version 2 would be installed but it won't be controlling
826 // the extension page yet.
827 ExtensionTestMessageListener listener2("Pong from version 1", false);
828 listener2.set_failure_message("FAILURE");
829 web_contents =
830 AddTab(browser(), extension_after_update->GetResourceURL("page.html"));
831 EXPECT_TRUE(listener2.WaitUntilSatisfied());
832
833 // Navigate the tab away from the extension page so that no clients are
834 // using the service worker.
835 // Note that just closing the tab with WebContentsDestroyedWatcher doesn't
836 // seem to be enough because it returns too early.
837 WebContentsLoadStopObserver navigate_away_observer(web_contents);
838 web_contents->GetController().LoadURL(
839 GURL(url::kAboutBlankURL), content::Referrer(), ui::PAGE_TRANSITION_TYPED,
840 std::string());
841 navigate_away_observer.WaitForLoadStop();
842
843 // Now expect service worker version 2 to control the extension page.
844 ExtensionTestMessageListener listener3("Pong from version 2", false);
845 listener3.set_failure_message("FAILURE");
846 web_contents =
847 AddTab(browser(), extension_after_update->GetResourceURL("page.html"));
848 EXPECT_TRUE(listener3.WaitUntilSatisfied());
849}
850
Devlin Cronin242d19d22019-03-12 18:08:48851IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, FetchArbitraryPaths) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22852 const Extension* extension = StartTestFromBackgroundPage("fetch.js");
annekao1db36fd2015-07-29 17:09:16853
kalman6f984ae2015-09-18 17:21:58854 // Open some arbirary paths. Their contents should be what the service worker
855 // responds with, which in this case is the path of the fetch.
856 EXPECT_EQ(
857 "Caught a fetch for /index.html",
858 NavigateAndExtractInnerText(extension->GetResourceURL("index.html")));
859 EXPECT_EQ("Caught a fetch for /path/to/other.html",
860 NavigateAndExtractInnerText(
861 extension->GetResourceURL("path/to/other.html")));
862 EXPECT_EQ("Caught a fetch for /some/text/file.txt",
863 NavigateAndExtractInnerText(
864 extension->GetResourceURL("some/text/file.txt")));
865 EXPECT_EQ("Caught a fetch for /no/file/extension",
866 NavigateAndExtractInnerText(
867 extension->GetResourceURL("no/file/extension")));
868 EXPECT_EQ("Caught a fetch for /",
869 NavigateAndExtractInnerText(extension->GetResourceURL("")));
annekao1db36fd2015-07-29 17:09:16870}
871
Devlin Cronin242d19d22019-03-12 18:08:48872IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
Kenichi Ishibashi773b82972018-08-30 07:02:03873 FetchExtensionResourceFromServiceWorker) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22874 const Extension* extension = StartTestFromBackgroundPage("fetch_from_sw.js");
Kenichi Ishibashi773b82972018-08-30 07:02:03875 ASSERT_TRUE(extension);
876
877 // The service worker in this test tries to load 'hello.txt' via fetch()
878 // and sends back the content of the file, which should be 'hello'.
879 const char* kScript = R"(
880 let channel = new MessageChannel();
881 test.waitForMessage(channel.port1).then(message => {
882 window.domAutomationController.send(message);
883 });
884 test.registeredServiceWorker.postMessage(
885 {port: channel.port2}, [channel.port2]);
886 )";
887 EXPECT_EQ("hello", ExecuteScriptInBackgroundPage(extension->id(), kScript));
888}
889
Kenichi Ishibashi09ee5e72018-11-27 07:12:38890// Tests that fetch() from service worker and network fallback
891// go through webRequest.onBeforeRequest API.
Devlin Cronin242d19d22019-03-12 18:08:48892IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, OnBeforeRequest) {
Kenichi Ishibashi09ee5e72018-11-27 07:12:38893 const Extension* extension = LoadExtensionWithFlags(
894 test_data_dir_.AppendASCII("service_worker/webrequest"), kFlagNone);
895 ASSERT_TRUE(extension);
896 ASSERT_TRUE(StartEmbeddedTestServer());
897
898 // Start a service worker and make it control the page.
899 GURL page_url = embedded_test_server()->GetURL(
900 "/extensions/api_test/service_worker/"
901 "webrequest/webpage.html");
902 content::WebContents* web_contents =
903 browser()->tab_strip_model()->GetActiveWebContents();
904 ui_test_utils::NavigateToURL(browser(), page_url);
905 content::WaitForLoadStop(web_contents);
906
907 std::string result;
908 ASSERT_TRUE(content::ExecuteScriptAndExtractString(web_contents,
909 "register();", &result));
910 EXPECT_EQ("ready", result);
911
912 // Initiate a fetch that the service worker doesn't intercept
913 // (network fallback).
914 result.clear();
915 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
916 web_contents, "doFetch('hello.txt?fallthrough');", &result));
917 EXPECT_EQ("hello", result);
918 EXPECT_EQ(
919 "/extensions/api_test/service_worker/webrequest/hello.txt?fallthrough",
920 ExecuteScriptInBackgroundPage(extension->id(), "getLastHookedPath()"));
921
922 // Initiate a fetch that results in calling fetch() in the service worker.
923 result.clear();
924 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
925 web_contents, "doFetch('hello.txt?respondWithFetch');", &result));
926 EXPECT_EQ("hello", result);
927 EXPECT_EQ(
928 "/extensions/api_test/service_worker/webrequest/"
929 "hello.txt?respondWithFetch",
930 ExecuteScriptInBackgroundPage(extension->id(), "getLastHookedPath()"));
931}
932
Devlin Cronin242d19d22019-03-12 18:08:48933IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, SWServedBackgroundPageReceivesEvent) {
lazyboy52c3bcf2016-01-08 00:11:29934 const Extension* extension =
Istiaque Ahmed93ff7f42018-08-31 01:42:22935 StartTestFromBackgroundPage("replace_background.js");
lazyboy52c3bcf2016-01-08 00:11:29936 ExtensionHost* background_page =
937 process_manager()->GetBackgroundHostForExtension(extension->id());
938 ASSERT_TRUE(background_page);
939
940 // Close the background page and start it again so that the service worker
941 // will start controlling pages.
942 background_page->Close();
943 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
944 background_page = nullptr;
Peter Kasting341e1fb2018-02-24 00:03:01945 process_manager()->WakeEventPage(extension->id(), base::DoNothing());
lazyboy52c3bcf2016-01-08 00:11:29946 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
947
948 // Since the SW is now controlling the extension, the SW serves the background
949 // script. page.html sends a message to the background script and we verify
950 // that the SW served background script correctly receives the message/event.
951 ExtensionTestMessageListener listener("onMessage/SW BG.", false);
952 listener.set_failure_message("onMessage/original BG.");
953 content::WebContents* web_contents =
954 AddTab(browser(), extension->GetResourceURL("page.html"));
955 ASSERT_TRUE(web_contents);
956 EXPECT_TRUE(listener.WaitUntilSatisfied());
957}
958
Devlin Cronin242d19d22019-03-12 18:08:48959IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, SWServedBackgroundPage) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22960 const Extension* extension = StartTestFromBackgroundPage("fetch.js");
annekao49241182015-08-18 17:14:01961
kalman6f984ae2015-09-18 17:21:58962 std::string kExpectedInnerText = "background.html contents for testing.";
annekao49241182015-08-18 17:14:01963
kalman6f984ae2015-09-18 17:21:58964 // Sanity check that the background page has the expected content.
965 ExtensionHost* background_page =
966 process_manager()->GetBackgroundHostForExtension(extension->id());
967 ASSERT_TRUE(background_page);
968 EXPECT_EQ(kExpectedInnerText,
969 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:01970
kalman6f984ae2015-09-18 17:21:58971 // Close the background page.
972 background_page->Close();
973 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
974 background_page = nullptr;
975
976 // Start it again.
Peter Kasting341e1fb2018-02-24 00:03:01977 process_manager()->WakeEventPage(extension->id(), base::DoNothing());
kalman6f984ae2015-09-18 17:21:58978 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
979
Matt Falkenhagena612fc02018-05-30 00:35:39980 // The service worker should get a fetch event for the background page.
kalman6f984ae2015-09-18 17:21:58981 background_page =
982 process_manager()->GetBackgroundHostForExtension(extension->id());
983 ASSERT_TRUE(background_page);
984 content::WaitForLoadStop(background_page->host_contents());
985
kalman6f984ae2015-09-18 17:21:58986 EXPECT_EQ("Caught a fetch for /background.html",
987 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:01988}
989
Devlin Cronin242d19d22019-03-12 18:08:48990IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:58991 ServiceWorkerPostsMessageToBackgroundClient) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22992 const Extension* extension =
993 StartTestFromBackgroundPage("post_message_to_background_client.js");
annekao533482222015-08-21 23:23:53994
kalman6f984ae2015-09-18 17:21:58995 // The service worker in this test simply posts a message to the background
996 // client it receives from getBackgroundClient().
997 const char* kScript =
998 "var messagePromise = null;\n"
999 "if (test.lastMessageFromServiceWorker) {\n"
1000 " messagePromise = Promise.resolve(test.lastMessageFromServiceWorker);\n"
1001 "} else {\n"
1002 " messagePromise = test.waitForMessage(navigator.serviceWorker);\n"
1003 "}\n"
1004 "messagePromise.then(function(message) {\n"
1005 " window.domAutomationController.send(String(message == 'success'));\n"
1006 "})\n";
1007 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:531008}
1009
Devlin Cronin242d19d22019-03-12 18:08:481010IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:581011 BackgroundPagePostsMessageToServiceWorker) {
1012 const Extension* extension =
Istiaque Ahmed93ff7f42018-08-31 01:42:221013 StartTestFromBackgroundPage("post_message_to_sw.js");
annekao533482222015-08-21 23:23:531014
kalman6f984ae2015-09-18 17:21:581015 // The service worker in this test waits for a message, then echoes it back
1016 // by posting a message to the background page via getBackgroundClient().
1017 const char* kScript =
1018 "var mc = new MessageChannel();\n"
1019 "test.waitForMessage(mc.port1).then(function(message) {\n"
1020 " window.domAutomationController.send(String(message == 'hello'));\n"
1021 "});\n"
1022 "test.registeredServiceWorker.postMessage(\n"
1023 " {message: 'hello', port: mc.port2}, [mc.port2])\n";
1024 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:531025}
1026
Devlin Cronin242d19d22019-03-12 18:08:481027IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
rdevlin.croninf5863da2015-09-10 19:21:451028 ServiceWorkerSuspensionOnExtensionUnload) {
kalman6f984ae2015-09-18 17:21:581029 // For this test, only hold onto the extension's ID and URL + a function to
1030 // get a resource URL, because we're going to be disabling and uninstalling
1031 // it, which will invalidate the pointer.
1032 std::string extension_id;
1033 GURL extension_url;
1034 {
Istiaque Ahmed93ff7f42018-08-31 01:42:221035 const Extension* extension = StartTestFromBackgroundPage("fetch.js");
kalman6f984ae2015-09-18 17:21:581036 extension_id = extension->id();
1037 extension_url = extension->url();
1038 }
1039 auto get_resource_url = [&extension_url](const std::string& path) {
1040 return Extension::GetResourceURL(extension_url, path);
1041 };
rdevlin.croninf5863da2015-09-10 19:21:451042
kalman6f984ae2015-09-18 17:21:581043 // Fetch should route to the service worker.
1044 EXPECT_EQ("Caught a fetch for /index.html",
1045 NavigateAndExtractInnerText(get_resource_url("index.html")));
rdevlin.croninf5863da2015-09-10 19:21:451046
kalman6f984ae2015-09-18 17:21:581047 // Disable the extension. Opening the page should fail.
1048 extension_service()->DisableExtension(extension_id,
Minh X. Nguyen45479012017-08-18 21:35:361049 disable_reason::DISABLE_USER_ACTION);
rdevlin.croninf5863da2015-09-10 19:21:451050 base::RunLoop().RunUntilIdle();
rdevlin.croninf5863da2015-09-10 19:21:451051
kalman6f984ae2015-09-18 17:21:581052 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1053 NavigateAndGetPageType(get_resource_url("index.html")));
1054 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1055 NavigateAndGetPageType(get_resource_url("other.html")));
1056
1057 // Re-enable the extension. Opening pages should immediately start to succeed
1058 // again.
rdevlin.croninf5863da2015-09-10 19:21:451059 extension_service()->EnableExtension(extension_id);
1060 base::RunLoop().RunUntilIdle();
1061
kalman6f984ae2015-09-18 17:21:581062 EXPECT_EQ("Caught a fetch for /index.html",
1063 NavigateAndExtractInnerText(get_resource_url("index.html")));
1064 EXPECT_EQ("Caught a fetch for /other.html",
1065 NavigateAndExtractInnerText(get_resource_url("other.html")));
1066 EXPECT_EQ("Caught a fetch for /another.html",
1067 NavigateAndExtractInnerText(get_resource_url("another.html")));
rdevlin.croninf5863da2015-09-10 19:21:451068
kalman6f984ae2015-09-18 17:21:581069 // Uninstall the extension. Opening pages should fail again.
1070 base::string16 error;
1071 extension_service()->UninstallExtension(
Devlin Cronin218df7f2017-11-21 21:41:311072 extension_id, UninstallReason::UNINSTALL_REASON_FOR_TESTING, &error);
kalman6f984ae2015-09-18 17:21:581073 base::RunLoop().RunUntilIdle();
1074
1075 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1076 NavigateAndGetPageType(get_resource_url("index.html")));
1077 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1078 NavigateAndGetPageType(get_resource_url("other.html")));
1079 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1080 NavigateAndGetPageType(get_resource_url("anotherother.html")));
1081 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1082 NavigateAndGetPageType(get_resource_url("final.html")));
1083}
1084
Devlin Cronin242d19d22019-03-12 18:08:481085IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, BackgroundPageIsWokenIfAsleep) {
Istiaque Ahmed93ff7f42018-08-31 01:42:221086 const Extension* extension = StartTestFromBackgroundPage("wake_on_fetch.js");
kalman6f984ae2015-09-18 17:21:581087
1088 // Navigate to special URLs that this test's service worker recognises, each
1089 // making a check then populating the response with either "true" or "false".
1090 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
1091 "background-client-is-awake")));
1092 EXPECT_EQ("true", NavigateAndExtractInnerText(
1093 extension->GetResourceURL("ping-background-client")));
1094 // Ping more than once for good measure.
1095 EXPECT_EQ("true", NavigateAndExtractInnerText(
1096 extension->GetResourceURL("ping-background-client")));
1097
1098 // Shut down the event page. The SW should detect that it's closed, but still
1099 // be able to ping it.
1100 ExtensionHost* background_page =
1101 process_manager()->GetBackgroundHostForExtension(extension->id());
1102 ASSERT_TRUE(background_page);
1103 background_page->Close();
1104 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
1105
1106 EXPECT_EQ("false", NavigateAndExtractInnerText(extension->GetResourceURL(
1107 "background-client-is-awake")));
1108 EXPECT_EQ("true", NavigateAndExtractInnerText(
1109 extension->GetResourceURL("ping-background-client")));
1110 EXPECT_EQ("true", NavigateAndExtractInnerText(
1111 extension->GetResourceURL("ping-background-client")));
1112 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
1113 "background-client-is-awake")));
1114}
1115
Devlin Cronin242d19d22019-03-12 18:08:481116IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:581117 GetBackgroundClientFailsWithNoBackgroundPage) {
1118 // This extension doesn't have a background page, only a tab at page.html.
1119 // The service worker it registers tries to call getBackgroundClient() and
1120 // should fail.
1121 // Note that this also tests that service workers can be registered from tabs.
1122 EXPECT_TRUE(RunExtensionSubtest("service_worker/no_background", "page.html"));
rdevlin.croninf5863da2015-09-10 19:21:451123}
1124
Devlin Cronin242d19d22019-03-12 18:08:481125IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, NotificationAPI) {
lazyboy6ddb7d62015-11-10 23:15:271126 EXPECT_TRUE(RunExtensionSubtest("service_worker/notifications/has_permission",
1127 "page.html"));
1128}
1129
Devlin Cronin242d19d22019-03-12 18:08:481130IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, WebAccessibleResourcesFetch) {
lazyboyaea32c22016-01-04 21:37:071131 EXPECT_TRUE(RunExtensionSubtest(
1132 "service_worker/web_accessible_resources/fetch/", "page.html"));
1133}
1134
David Bertoni9026eff2019-05-01 18:04:311135// Tests that updating a packed extension with modified scripts works
1136// properly -- we expect that the new script will execute, rather than the
1137// previous one.
1138IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, UpdatePackedExtension) {
1139 // Extensions APIs from SW are only enabled on trunk.
1140 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1141 constexpr char kManifest1[] =
1142 R"({
1143 "name": "Test Extension",
1144 "manifest_version": 2,
1145 "version": "0.1",
1146 "background": {"service_worker": "script.js"}
1147 })";
David Bertoni353f0fb42019-05-30 15:53:301148 constexpr char kNewVersionString[] = "0.2";
1149
David Bertoni9026eff2019-05-01 18:04:311150 // This script installs an event listener for updates to the extension with
1151 // a callback that forces itself to reload.
David Bertoni353f0fb42019-05-30 15:53:301152 constexpr char kScript1[] =
David Bertoni9026eff2019-05-01 18:04:311153 R"(
1154 chrome.runtime.onUpdateAvailable.addListener(function(details) {
David Bertoni353f0fb42019-05-30 15:53:301155 chrome.test.assertEq('%s', details.version);
David Bertoni9026eff2019-05-01 18:04:311156 chrome.runtime.reload();
1157 });
1158 chrome.test.sendMessage('ready1');
1159 )";
1160
1161 std::string id;
1162 TestExtensionDir test_dir;
1163
1164 // Write the manifest and script files and load the extension.
1165 test_dir.WriteManifest(kManifest1);
David Bertoni353f0fb42019-05-30 15:53:301166 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"),
1167 base::StringPrintf(kScript1, kNewVersionString));
David Bertoni9026eff2019-05-01 18:04:311168
1169 {
1170 ExtensionTestMessageListener ready_listener("ready1", false);
1171 base::FilePath path = test_dir.Pack();
1172 const Extension* extension = LoadExtension(path);
1173 ASSERT_TRUE(extension);
1174
1175 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
1176 id = extension->id();
1177 }
1178
1179 constexpr char kManifest2[] =
1180 R"({
1181 "name": "Test Extension",
1182 "manifest_version": 2,
David Bertoni353f0fb42019-05-30 15:53:301183 "version": "%s",
David Bertoni9026eff2019-05-01 18:04:311184 "background": {"service_worker": "script.js"}
1185 })";
David Bertoni353f0fb42019-05-30 15:53:301186 constexpr char kScript2[] =
1187 R"(
1188 chrome.runtime.onInstalled.addListener(function(details) {
1189 chrome.test.assertEq('update', details.reason);
1190 chrome.test.sendMessage('onInstalled');
1191 });
1192 chrome.test.sendMessage('ready2');
1193 )";
David Bertoni9026eff2019-05-01 18:04:311194 // Rewrite the manifest and script files with a version change in the manifest
1195 // file. After reloading the extension, the old version of the extension
1196 // should detect the update, force the reload, and the new script should
1197 // execute.
David Bertoni353f0fb42019-05-30 15:53:301198 test_dir.WriteManifest(base::StringPrintf(kManifest2, kNewVersionString));
1199 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"), kScript2);
David Bertoni9026eff2019-05-01 18:04:311200 {
1201 ExtensionTestMessageListener ready_listener("ready2", false);
David Bertoni353f0fb42019-05-30 15:53:301202 ExtensionTestMessageListener on_installed_listener("onInstalled", false);
David Bertoni9026eff2019-05-01 18:04:311203 base::FilePath path = test_dir.Pack();
1204 ExtensionService* const extension_service =
1205 ExtensionSystem::Get(profile())->extension_service();
1206 EXPECT_TRUE(extension_service->UpdateExtension(
1207 CRXFileInfo(id, GetTestVerifierFormat(), path), true, nullptr));
1208 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
1209 EXPECT_EQ("0.2", ExtensionRegistry::Get(profile())
1210 ->enabled_extensions()
1211 .GetByID(id)
1212 ->version()
1213 .GetString());
David Bertoni353f0fb42019-05-30 15:53:301214 EXPECT_TRUE(on_installed_listener.WaitUntilSatisfied());
David Bertoni9026eff2019-05-01 18:04:311215 }
1216}
1217
David Bertoni1d646a152019-04-25 02:09:221218// Tests that updating an unpacked extension with modified scripts works
1219// properly -- we expect that the new script will execute, rather than the
1220// previous one.
1221IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, UpdateUnpackedExtension) {
1222 // Extensions APIs from SW are only enabled on trunk.
1223 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1224 constexpr char kManifest1[] =
1225 R"({
1226 "name": "Test Extension",
1227 "manifest_version": 2,
1228 "version": "0.1",
1229 "background": {"service_worker": "script.js"}
1230 })";
1231 constexpr char kManifest2[] =
1232 R"({
1233 "name": "Test Extension",
1234 "manifest_version": 2,
1235 "version": "0.2",
1236 "background": {"service_worker": "script.js"}
1237 })";
David Bertoni353f0fb42019-05-30 15:53:301238 constexpr char kScript[] =
1239 R"(
1240 chrome.runtime.onInstalled.addListener(function(details) {
1241 chrome.test.assertEq('%s', details.reason);
1242 chrome.test.sendMessage('onInstalled');
1243 });
1244 chrome.test.sendMessage('%s');
1245 )";
David Bertoni1d646a152019-04-25 02:09:221246
1247 std::string id;
1248
1249 ExtensionService* const extension_service =
1250 ExtensionSystem::Get(profile())->extension_service();
1251 scoped_refptr<UnpackedInstaller> installer =
1252 UnpackedInstaller::Create(extension_service);
1253
1254 // Set a completion callback so we can get the ID of the extension.
1255 installer->set_completion_callback(base::BindLambdaForTesting(
1256 [&id](const Extension* extension, const base::FilePath& path,
1257 const std::string& error) {
1258 ASSERT_TRUE(extension);
1259 ASSERT_TRUE(error.empty());
1260 id = extension->id();
1261 }));
1262
1263 TestExtensionDir test_dir;
1264
1265 // Write the manifest and script files and load the extension.
1266 test_dir.WriteManifest(kManifest1);
1267 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"),
David Bertoni353f0fb42019-05-30 15:53:301268 base::StringPrintf(kScript, "install", "ready1"));
David Bertoni1d646a152019-04-25 02:09:221269 {
1270 ExtensionTestMessageListener ready_listener("ready1", false);
David Bertoni353f0fb42019-05-30 15:53:301271 ExtensionTestMessageListener on_installed_listener("onInstalled", false);
David Bertoni1d646a152019-04-25 02:09:221272
1273 installer->Load(test_dir.UnpackedPath());
1274 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
David Bertoni353f0fb42019-05-30 15:53:301275 EXPECT_TRUE(on_installed_listener.WaitUntilSatisfied());
David Bertoni1d646a152019-04-25 02:09:221276 ASSERT_FALSE(id.empty());
1277 }
1278
1279 // Rewrite the script file without a version change in the manifest and reload
1280 // the extension. The new script should execute.
1281 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"),
David Bertoni353f0fb42019-05-30 15:53:301282 base::StringPrintf(kScript, "update", "ready2"));
David Bertoni1d646a152019-04-25 02:09:221283 {
1284 ExtensionTestMessageListener ready_listener("ready2", false);
David Bertoni353f0fb42019-05-30 15:53:301285 ExtensionTestMessageListener on_installed_listener("onInstalled", false);
David Bertoni1d646a152019-04-25 02:09:221286
1287 extension_service->ReloadExtension(id);
1288 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
David Bertoni353f0fb42019-05-30 15:53:301289 EXPECT_TRUE(on_installed_listener.WaitUntilSatisfied());
David Bertoni1d646a152019-04-25 02:09:221290 }
1291
1292 // Rewrite the manifest and script files with a version change in the manifest
1293 // file. After reloading the extension, the new script should execute.
1294 test_dir.WriteManifest(kManifest2);
1295 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"),
David Bertoni353f0fb42019-05-30 15:53:301296 base::StringPrintf(kScript, "update", "ready3"));
David Bertoni1d646a152019-04-25 02:09:221297 {
1298 ExtensionTestMessageListener ready_listener("ready3", false);
David Bertoni353f0fb42019-05-30 15:53:301299 ExtensionTestMessageListener on_installed_listener("onInstalled", false);
David Bertoni1d646a152019-04-25 02:09:221300
1301 extension_service->ReloadExtension(id);
1302 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
David Bertoni353f0fb42019-05-30 15:53:301303 EXPECT_TRUE(on_installed_listener.WaitUntilSatisfied());
David Bertoni1d646a152019-04-25 02:09:221304 }
1305}
1306
Devlin Cronin242d19d22019-03-12 18:08:481307IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, EventsToStoppedWorker) {
lazyboy63b994a2017-06-30 21:20:231308 // Extensions APIs from SW are only enabled on trunk.
1309 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1310 const Extension* extension = LoadExtensionWithFlags(
1311 test_data_dir_.AppendASCII("service_worker/events_to_stopped_worker"),
1312 kFlagNone);
1313 ASSERT_TRUE(extension);
1314 ui_test_utils::NavigateToURL(browser(),
1315 extension->GetResourceURL("page.html"));
1316 content::WebContents* web_contents =
1317 browser()->tab_strip_model()->GetActiveWebContents();
1318 {
1319 std::string result;
1320 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
1321 web_contents, "window.runServiceWorker()", &result));
1322 ASSERT_EQ("ready", result);
1323
1324 base::RunLoop run_loop;
1325 content::StoragePartition* storage_partition =
1326 content::BrowserContext::GetDefaultStoragePartition(
1327 browser()->profile());
Zhuoyu Qian2266251f2018-10-13 02:59:001328 content::StopServiceWorkerForScope(
lazyboy63b994a2017-06-30 21:20:231329 storage_partition->GetServiceWorkerContext(),
1330 // The service worker is registered at the top level scope.
1331 extension->url(), run_loop.QuitClosure());
1332 run_loop.Run();
1333 }
1334
1335 std::string result;
1336 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
1337 web_contents, "window.createTabThenUpdate()", &result));
1338 ASSERT_EQ("chrome.tabs.onUpdated callback", result);
1339}
1340
Istiaque Ahmed805f6a83b2017-10-05 01:23:261341// Tests that events to service worker arrives correctly event if the owner
1342// extension of the worker is not running.
Devlin Cronin242d19d22019-03-12 18:08:481343IN_PROC_BROWSER_TEST_F(ServiceWorkerLazyBackgroundTest,
Istiaque Ahmedb8e24bdb2018-09-13 15:17:251344 EventsToStoppedExtension) {
Istiaque Ahmed805f6a83b2017-10-05 01:23:261345 LazyBackgroundObserver lazy_observer;
1346 ResultCatcher catcher;
1347 const Extension* extension = LoadExtensionWithFlags(
1348 test_data_dir_.AppendASCII("service_worker/events_to_stopped_extension"),
1349 kFlagNone);
1350 ASSERT_TRUE(extension);
1351 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
1352
1353 ProcessManager* pm = ProcessManager::Get(browser()->profile());
1354 EXPECT_GT(pm->GetLazyKeepaliveCount(extension), 0);
David Bertoni3e1e9fa2018-08-29 20:39:301355 EXPECT_FALSE(pm->GetLazyKeepaliveActivities(extension).empty());
Istiaque Ahmed805f6a83b2017-10-05 01:23:261356
1357 // |extension|'s background page opens a tab to its resource.
1358 content::WebContents* extension_web_contents =
1359 browser()->tab_strip_model()->GetActiveWebContents();
1360 EXPECT_TRUE(content::WaitForLoadStop(extension_web_contents));
1361 EXPECT_EQ(extension->GetResourceURL("page.html").spec(),
1362 extension_web_contents->GetURL().spec());
1363 {
1364 // Let the service worker start and register a listener to
1365 // chrome.tabs.onCreated event.
1366 ExtensionTestMessageListener add_listener_done("listener-added", false);
1367 content::ExecuteScriptAsync(extension_web_contents,
1368 "window.runServiceWorkerAsync()");
1369 EXPECT_TRUE(add_listener_done.WaitUntilSatisfied());
1370
1371 base::RunLoop run_loop;
1372 content::StoragePartition* storage_partition =
1373 content::BrowserContext::GetDefaultStoragePartition(
1374 browser()->profile());
Zhuoyu Qian2266251f2018-10-13 02:59:001375 content::StopServiceWorkerForScope(
Istiaque Ahmed805f6a83b2017-10-05 01:23:261376 storage_partition->GetServiceWorkerContext(),
1377 // The service worker is registered at the top level scope.
1378 extension->url(), run_loop.QuitClosure());
1379 run_loop.Run();
1380 }
1381
1382 // Close the tab to |extension|'s resource. This will also close the
1383 // extension's event page.
1384 browser()->tab_strip_model()->CloseWebContentsAt(
1385 browser()->tab_strip_model()->active_index(), TabStripModel::CLOSE_NONE);
1386 lazy_observer.Wait();
1387
1388 // At this point both the extension worker and extension event page is not
1389 // running. Since the worker registered a listener for tabs.onCreated, it
1390 // will be started to dispatch the event once we create a tab.
1391 ExtensionTestMessageListener newtab_listener("hello-newtab", false);
1392 newtab_listener.set_failure_message("WRONG_NEWTAB");
1393 content::WebContents* new_web_contents =
Istiaque Ahmed7105f2a2017-10-07 01:11:591394 AddTab(browser(), GURL(url::kAboutBlankURL));
1395 EXPECT_TRUE(new_web_contents);
1396 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
1397}
1398
lazyboy4c82177a2016-10-18 00:04:091399// Tests that worker ref count increments while extension API function is
1400// active.
Devlin Cronin242d19d22019-03-12 18:08:481401IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, WorkerRefCount) {
lazyboy4c82177a2016-10-18 00:04:091402 // Extensions APIs from SW are only enabled on trunk.
1403 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1404 const Extension* extension = LoadExtensionWithFlags(
1405 test_data_dir_.AppendASCII("service_worker/api_worker_ref_count"),
1406 kFlagNone);
1407 ASSERT_TRUE(extension);
1408 ui_test_utils::NavigateToURL(browser(),
1409 extension->GetResourceURL("page.html"));
1410 content::WebContents* web_contents =
1411 browser()->tab_strip_model()->GetActiveWebContents();
1412
1413 ExtensionTestMessageListener worker_start_listener("WORKER STARTED", false);
1414 worker_start_listener.set_failure_message("FAILURE");
1415 ASSERT_TRUE(
1416 content::ExecuteScript(web_contents, "window.runServiceWorker()"));
1417 ASSERT_TRUE(worker_start_listener.WaitUntilSatisfied());
1418
1419 // Service worker should have no pending requests because it hasn't peformed
1420 // any extension API request yet.
1421 EXPECT_EQ(0u, GetWorkerRefCount(extension->url()));
1422
1423 ExtensionTestMessageListener worker_listener("CHECK_REF_COUNT", true);
1424 worker_listener.set_failure_message("FAILURE");
1425 ASSERT_TRUE(content::ExecuteScript(web_contents, "window.testSendMessage()"));
1426 ASSERT_TRUE(worker_listener.WaitUntilSatisfied());
1427
1428 // Service worker should have exactly one pending request because
1429 // chrome.test.sendMessage() API call is in-flight.
1430 EXPECT_EQ(1u, GetWorkerRefCount(extension->url()));
1431
1432 // Peform another extension API request while one is ongoing.
1433 {
1434 ExtensionTestMessageListener listener("CHECK_REF_COUNT", true);
1435 listener.set_failure_message("FAILURE");
1436 ASSERT_TRUE(
1437 content::ExecuteScript(web_contents, "window.testSendMessage()"));
1438 ASSERT_TRUE(listener.WaitUntilSatisfied());
1439
1440 // Service worker currently has two extension API requests in-flight.
1441 EXPECT_EQ(2u, GetWorkerRefCount(extension->url()));
1442 // Finish executing the nested chrome.test.sendMessage() first.
1443 listener.Reply("Hello world");
1444 }
1445
Istiaque Ahmedb57c9752017-08-20 19:08:571446 ExtensionTestMessageListener worker_completion_listener("SUCCESS_FROM_WORKER",
1447 false);
lazyboy4c82177a2016-10-18 00:04:091448 // Finish executing chrome.test.sendMessage().
1449 worker_listener.Reply("Hello world");
Istiaque Ahmedb57c9752017-08-20 19:08:571450 EXPECT_TRUE(worker_completion_listener.WaitUntilSatisfied());
1451
1452 // The following block makes sure we have received all the IPCs related to
1453 // ref-count from the worker.
1454 {
1455 // The following roundtrip:
1456 // browser->extension->worker->extension->browser
1457 // will ensure that the worker sent the relevant ref count IPCs.
1458 std::string result;
1459 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1460 web_contents, "window.roundtripToWorker();", &result));
1461 EXPECT_EQ("roundtrip-succeeded", result);
1462
1463 // Ensure IO thread IPCs run.
Gabriel Charette01507a22017-09-27 21:30:081464 content::RunAllTasksUntilIdle();
Istiaque Ahmedb57c9752017-08-20 19:08:571465 }
lazyboy4c82177a2016-10-18 00:04:091466
1467 // The ref count should drop to 0.
1468 EXPECT_EQ(0u, GetWorkerRefCount(extension->url()));
1469}
1470
lazyboyaea32c22016-01-04 21:37:071471// This test loads a web page that has an iframe pointing to a
1472// chrome-extension:// URL. The URL is listed in the extension's
1473// web_accessible_resources. Initially the iframe is served from the extension's
1474// resource file. After verifying that, we register a Service Worker that
1475// controls the extension. Further requests to the same resource as before
1476// should now be served by the Service Worker.
1477// This test also verifies that if the requested resource exists in the manifest
1478// but is not present in the extension directory, the Service Worker can still
1479// serve the resource file.
Devlin Cronin242d19d22019-03-12 18:08:481480IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, WebAccessibleResourcesIframeSrc) {
lazyboyaea32c22016-01-04 21:37:071481 const Extension* extension = LoadExtensionWithFlags(
1482 test_data_dir_.AppendASCII(
1483 "service_worker/web_accessible_resources/iframe_src"),
1484 kFlagNone);
1485 ASSERT_TRUE(extension);
1486 ASSERT_TRUE(StartEmbeddedTestServer());
falkenad185092016-06-16 06:10:021487
1488 // Service workers can only control secure contexts
1489 // (https://w3c.github.io/webappsec-secure-contexts/). For documents, this
1490 // typically means the document must have a secure origin AND all its ancestor
1491 // frames must have documents with secure origins. However, extension pages
1492 // are considered secure, even if they have an ancestor document that is an
1493 // insecure context (see GetSchemesBypassingSecureContextCheckWhitelist). So
1494 // extension service workers must be able to control an extension page
1495 // embedded in an insecure context. To test this, set up an insecure
1496 // (non-localhost, non-https) URL for the web page. This page will create
1497 // iframes that load extension pages that must be controllable by service
1498 // worker.
falkenad185092016-06-16 06:10:021499 GURL page_url =
1500 embedded_test_server()->GetURL("a.com",
1501 "/extensions/api_test/service_worker/"
1502 "web_accessible_resources/webpage.html");
1503 EXPECT_FALSE(content::IsOriginSecure(page_url));
lazyboyaea32c22016-01-04 21:37:071504
1505 content::WebContents* web_contents = AddTab(browser(), page_url);
1506 std::string result;
1507 // webpage.html will create an iframe pointing to a resource from |extension|.
1508 // Expect the resource to be served by the extension.
1509 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1510 web_contents, base::StringPrintf("window.testIframe('%s', 'iframe.html')",
1511 extension->id().c_str()),
1512 &result));
1513 EXPECT_EQ("FROM_EXTENSION_RESOURCE", result);
1514
1515 ExtensionTestMessageListener service_worker_ready_listener("SW_READY", false);
1516 EXPECT_TRUE(ExecuteScriptInBackgroundPageNoWait(
1517 extension->id(), "window.registerServiceWorker()"));
1518 EXPECT_TRUE(service_worker_ready_listener.WaitUntilSatisfied());
1519
1520 result.clear();
1521 // webpage.html will create another iframe pointing to a resource from
1522 // |extension| as before. But this time, the resource should be be served
1523 // from the Service Worker.
1524 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1525 web_contents, base::StringPrintf("window.testIframe('%s', 'iframe.html')",
1526 extension->id().c_str()),
1527 &result));
1528 EXPECT_EQ("FROM_SW_RESOURCE", result);
1529
1530 result.clear();
1531 // webpage.html will create yet another iframe pointing to a resource that
1532 // exists in the extension manifest's web_accessible_resources, but is not
1533 // present in the extension directory. Expect the resources of the iframe to
1534 // be served by the Service Worker.
1535 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1536 web_contents,
1537 base::StringPrintf("window.testIframe('%s', 'iframe_non_existent.html')",
1538 extension->id().c_str()),
1539 &result));
1540 EXPECT_EQ("FROM_SW_RESOURCE", result);
1541}
1542
Devlin Cronin242d19d22019-03-12 18:08:481543IN_PROC_BROWSER_TEST_F(ServiceWorkerBackgroundSyncTest, Sync) {
lazyboybd325ae2015-11-18 21:35:261544 const Extension* extension = LoadExtensionWithFlags(
1545 test_data_dir_.AppendASCII("service_worker/sync"), kFlagNone);
1546 ASSERT_TRUE(extension);
1547 ui_test_utils::NavigateToURL(browser(),
1548 extension->GetResourceURL("page.html"));
1549 content::WebContents* web_contents =
1550 browser()->tab_strip_model()->GetActiveWebContents();
1551
1552 // Prevent firing by going offline.
1553 content::background_sync_test_util::SetOnline(web_contents, false);
1554
1555 ExtensionTestMessageListener sync_listener("SYNC: send-chats", false);
1556 sync_listener.set_failure_message("FAIL");
1557
1558 std::string result;
1559 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
1560 web_contents, "window.runServiceWorker()", &result));
1561 ASSERT_EQ("SERVICE_WORKER_READY", result);
1562
1563 EXPECT_FALSE(sync_listener.was_satisfied());
1564 // Resume firing by going online.
1565 content::background_sync_test_util::SetOnline(web_contents, true);
1566 EXPECT_TRUE(sync_listener.WaitUntilSatisfied());
1567}
1568
Devlin Cronin242d19d22019-03-12 18:08:481569IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
horo1eeddde2015-11-19 05:59:251570 FetchFromContentScriptShouldNotGoToServiceWorkerOfPage) {
1571 ASSERT_TRUE(StartEmbeddedTestServer());
1572 GURL page_url = embedded_test_server()->GetURL(
1573 "/extensions/api_test/service_worker/content_script_fetch/"
1574 "controlled_page/index.html");
1575 content::WebContents* tab =
1576 browser()->tab_strip_model()->GetActiveWebContents();
1577 ui_test_utils::NavigateToURL(browser(), page_url);
1578 content::WaitForLoadStop(tab);
1579
1580 std::string value;
1581 ASSERT_TRUE(
1582 content::ExecuteScriptAndExtractString(tab, "register();", &value));
1583 EXPECT_EQ("SW controlled", value);
1584
1585 ASSERT_TRUE(RunExtensionTest("service_worker/content_script_fetch"))
1586 << message_;
1587}
1588
Devlin Cronin242d19d22019-03-12 18:08:481589IN_PROC_BROWSER_TEST_F(ServiceWorkerPushMessagingTest, OnPush) {
lazyboy561b7de2015-11-19 19:27:301590 const Extension* extension = LoadExtensionWithFlags(
1591 test_data_dir_.AppendASCII("service_worker/push_messaging"), kFlagNone);
1592 ASSERT_TRUE(extension);
1593 GURL extension_url = extension->url();
1594
Peter Beverloodd4ef1e2018-06-21 15:41:041595 GrantNotificationPermissionForTest(extension_url);
lazyboy561b7de2015-11-19 19:27:301596
1597 GURL url = extension->GetResourceURL("page.html");
1598 ui_test_utils::NavigateToURL(browser(), url);
1599
1600 content::WebContents* web_contents =
1601 browser()->tab_strip_model()->GetActiveWebContents();
1602
1603 // Start the ServiceWorker.
1604 ExtensionTestMessageListener ready_listener("SERVICE_WORKER_READY", false);
1605 ready_listener.set_failure_message("SERVICE_WORKER_FAILURE");
1606 const char* kScript = "window.runServiceWorker()";
1607 EXPECT_TRUE(content::ExecuteScript(web_contents->GetMainFrame(), kScript));
1608 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
1609
1610 PushMessagingAppIdentifier app_identifier =
1611 GetAppIdentifierForServiceWorkerRegistration(0LL, extension_url);
johnmea5045732016-09-08 17:23:291612 ASSERT_EQ(app_identifier.app_id(), gcm_driver()->last_gettoken_app_id());
1613 EXPECT_EQ("1234567890", gcm_driver()->last_gettoken_authorized_entity());
lazyboy561b7de2015-11-19 19:27:301614
lazyboyd429e2582016-05-20 20:18:521615 base::RunLoop run_loop;
lazyboy561b7de2015-11-19 19:27:301616 // Send a push message via gcm and expect the ServiceWorker to receive it.
1617 ExtensionTestMessageListener push_message_listener("OK", false);
1618 push_message_listener.set_failure_message("FAIL");
1619 gcm::IncomingMessage message;
1620 message.sender_id = "1234567890";
1621 message.raw_data = "testdata";
1622 message.decrypted = true;
lazyboyd429e2582016-05-20 20:18:521623 push_service()->SetMessageCallbackForTesting(run_loop.QuitClosure());
lazyboy561b7de2015-11-19 19:27:301624 push_service()->OnMessage(app_identifier.app_id(), message);
1625 EXPECT_TRUE(push_message_listener.WaitUntilSatisfied());
lazyboyd429e2582016-05-20 20:18:521626 run_loop.Run(); // Wait until the message is handled by push service.
lazyboy561b7de2015-11-19 19:27:301627}
Devlin Cronin242d19d22019-03-12 18:08:481628IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, MimeHandlerView) {
Rob Wue89b90032018-02-16 19:46:081629 ASSERT_TRUE(RunExtensionTest("service_worker/mime_handler_view"));
1630}
1631
Devlin Cronin242d19d22019-03-12 18:08:481632IN_PROC_BROWSER_TEST_F(ServiceWorkerLazyBackgroundTest,
Istiaque Ahmed9ce21b32017-10-10 20:43:181633 PRE_FilteredEventsAfterRestart) {
1634 LazyBackgroundObserver lazy_observer;
1635 ResultCatcher catcher;
1636 const Extension* extension = LoadExtensionWithFlags(
1637 test_data_dir_.AppendASCII(
1638 "service_worker/filtered_events_after_restart"),
1639 kFlagNone);
1640 ASSERT_TRUE(extension);
1641 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
1642
1643 // |extension|'s background page opens a tab to its resource.
1644 content::WebContents* extension_web_contents =
1645 browser()->tab_strip_model()->GetActiveWebContents();
1646 EXPECT_TRUE(content::WaitForLoadStop(extension_web_contents));
1647 EXPECT_EQ(extension->GetResourceURL("page.html").spec(),
1648 extension_web_contents->GetURL().spec());
1649 {
1650 // Let the service worker start and register a filtered listener to
1651 // chrome.webNavigation.onCommitted event.
1652 ExtensionTestMessageListener add_listener_done("listener-added", false);
1653 add_listener_done.set_failure_message("FAILURE");
1654 content::ExecuteScriptAsync(extension_web_contents,
1655 "window.runServiceWorkerAsync()");
1656 EXPECT_TRUE(add_listener_done.WaitUntilSatisfied());
1657
1658 base::RunLoop run_loop;
1659 content::StoragePartition* storage_partition =
1660 content::BrowserContext::GetDefaultStoragePartition(
1661 browser()->profile());
Zhuoyu Qian2266251f2018-10-13 02:59:001662 content::StopServiceWorkerForScope(
Istiaque Ahmed9ce21b32017-10-10 20:43:181663 storage_partition->GetServiceWorkerContext(),
1664 // The service worker is registered at the top level scope.
1665 extension->url(), run_loop.QuitClosure());
1666 run_loop.Run();
1667 }
1668
1669 // Close the tab to |extension|'s resource. This will also close the
1670 // extension's event page.
1671 browser()->tab_strip_model()->CloseWebContentsAt(
1672 browser()->tab_strip_model()->active_index(), TabStripModel::CLOSE_NONE);
1673 lazy_observer.Wait();
1674}
1675
Devlin Cronin242d19d22019-03-12 18:08:481676IN_PROC_BROWSER_TEST_F(ServiceWorkerLazyBackgroundTest,
Istiaque Ahmedf5712522018-09-20 03:35:471677 FilteredEventsAfterRestart) {
Istiaque Ahmed9ce21b32017-10-10 20:43:181678 // Create a tab to a.html, expect it to navigate to b.html. The service worker
1679 // will see two webNavigation.onCommitted events.
1680 ASSERT_TRUE(StartEmbeddedTestServer());
1681 GURL page_url = embedded_test_server()->GetURL(
1682 "/extensions/api_test/service_worker/filtered_events_after_restart/"
1683 "a.html");
1684 ExtensionTestMessageListener worker_filtered_event_listener(
1685 "PASS_FROM_WORKER", false);
1686 worker_filtered_event_listener.set_failure_message("FAIL_FROM_WORKER");
1687 content::WebContents* web_contents = AddTab(browser(), page_url);
1688 EXPECT_TRUE(web_contents);
1689 EXPECT_TRUE(worker_filtered_event_listener.WaitUntilSatisfied());
1690}
1691
Devlin Cronin242d19d22019-03-12 18:08:481692IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
Istiaque Ahmedd4b67ee2019-03-02 10:53:201693 ProcessManagerRegistrationOnShutdown) {
1694 // Note that StopServiceWorkerForScope call below expects the worker to be
1695 // completely installed, so wait for the |extension| worker to see "activate"
1696 // event.
1697 ExtensionTestMessageListener activated_listener("WORKER_ACTIVATED", false);
1698 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
1699 "service_worker/worker_based_background/process_manager"));
1700 ASSERT_TRUE(extension);
1701 EXPECT_TRUE(activated_listener.WaitUntilSatisfied());
1702
1703 base::Optional<WorkerId> worker_id =
1704 GetUniqueRunningWorkerId(extension->id());
1705 ASSERT_TRUE(worker_id);
1706 {
1707 // Shutdown the worker.
1708 // TODO(lazyboy): Ideally we'd want to test worker shutdown on idle, do that
1709 // once //content API allows to override test timeouts for Service Workers.
1710 base::RunLoop run_loop;
1711 content::StoragePartition* storage_partition =
1712 content::BrowserContext::GetDefaultStoragePartition(
1713 browser()->profile());
1714 GURL scope = extension->url();
1715 content::StopServiceWorkerForScope(
1716 storage_partition->GetServiceWorkerContext(),
1717 // The service worker is registered at the top level scope.
1718 extension->url(), run_loop.QuitClosure());
1719 run_loop.Run();
1720 }
1721
1722 EXPECT_FALSE(ProcessManager::Get(profile())->HasServiceWorker(*worker_id));
1723}
1724
Devlin Cronin242d19d22019-03-12 18:08:481725IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
Istiaque Ahmedd4b67ee2019-03-02 10:53:201726 ProcessManagerRegistrationOnTerminate) {
1727 // NOTE: It is not necessary to wait for "activate" event from the worker
1728 // for this test, but we're lazily reusing the extension from
1729 // ProcessManagerRegistrationOnShutdown test.
1730 ExtensionTestMessageListener activated_listener("WORKER_ACTIVATED", false);
1731 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
1732 "service_worker/worker_based_background/process_manager"));
1733 ASSERT_TRUE(extension);
1734 EXPECT_TRUE(activated_listener.WaitUntilSatisfied());
1735
1736 base::Optional<WorkerId> worker_id =
1737 GetUniqueRunningWorkerId(extension->id());
1738 ASSERT_TRUE(worker_id);
1739 {
1740 // Terminate worker's RenderProcessHost.
1741 content::RenderProcessHost* worker_render_process_host =
1742 content::RenderProcessHost::FromID(worker_id->render_process_id);
1743 ASSERT_TRUE(worker_render_process_host);
1744 content::RenderProcessHostWatcher process_exit_observer(
1745 worker_render_process_host,
1746 content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1747 worker_render_process_host->Shutdown(content::RESULT_CODE_KILLED);
1748 process_exit_observer.Wait();
1749 }
1750
1751 EXPECT_FALSE(ProcessManager::Get(profile())->HasServiceWorker(*worker_id));
1752}
1753
David Bertoni4d9cf41d2019-06-04 00:06:221754IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
1755 PRE_EventsAfterRestart) {
1756 ExtensionTestMessageListener event_added_listener("ready", false);
1757 const Extension* extension = LoadExtensionWithFlags(
1758 test_data_dir_.AppendASCII(
1759 "service_worker/worker_based_background/events_to_stopped_extension"),
1760 kFlagNone);
1761 ASSERT_TRUE(extension);
1762 EXPECT_EQ(kTestExtensionId, extension->id());
1763 ProcessManager* pm = ProcessManager::Get(browser()->profile());
1764 // TODO(crbug.com/969884): This will break once keep alive counts
1765 // for service workers are tracked by the Process Manager.
1766 EXPECT_LT(pm->GetLazyKeepaliveCount(extension), 1);
1767 EXPECT_TRUE(pm->GetLazyKeepaliveActivities(extension).empty());
1768 EXPECT_TRUE(event_added_listener.WaitUntilSatisfied());
1769}
1770
1771// After browser restarts, this test step ensures that opening a tab fires
1772// tabs.onCreated event listener to the extension without explicitly loading the
1773// extension. This is because the extension registered a listener for
1774// tabs.onMoved before browser restarted in PRE_EventsAfterRestart.
1775IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, EventsAfterRestart) {
1776 // Verify there is no RenderProcessHost for the extension.
1777 ProcessMap* process_map = ProcessMap::Get(browser()->profile());
1778 ASSERT_TRUE(process_map);
1779 content::RenderProcessHost::iterator it =
1780 content::RenderProcessHost::AllHostsIterator();
1781 while (!it.IsAtEnd()) {
1782 EXPECT_FALSE(
1783 process_map->Contains(kTestExtensionId, it.GetCurrentValue()->GetID()));
1784 it.Advance();
1785 }
1786
1787 ExtensionTestMessageListener moved_tab_listener("moved-tab", false);
1788 // Add a tab, then move it.
1789 content::WebContents* new_web_contents =
1790 AddTab(browser(), GURL(url::kAboutBlankURL));
1791 EXPECT_TRUE(new_web_contents);
1792 browser()->tab_strip_model()->MoveWebContentsAt(
1793 browser()->tab_strip_model()->count() - 1, 0, false);
1794 EXPECT_TRUE(moved_tab_listener.WaitUntilSatisfied());
1795}
1796
Istiaque Ahmed1e59aec2019-06-05 22:40:241797IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, TabsOnCreated) {
1798 ASSERT_TRUE(RunExtensionTestWithFlags("tabs/lazy_background_on_created",
1799 kFlagRunAsServiceWorkerBasedExtension))
1800 << message_;
1801}
1802
Devlin Cronin59551d82019-03-05 01:28:591803// Tests that console messages logged by extension service workers, both via
1804// the typical console.* methods and via our custom bindings console, are
1805// passed through the normal ServiceWorker console messaging and are
1806// observable.
Devlin Cronin242d19d22019-03-12 18:08:481807IN_PROC_BROWSER_TEST_F(ServiceWorkerLazyBackgroundTest, ConsoleLogging) {
Devlin Cronin59551d82019-03-05 01:28:591808 // A helper class to wait for a particular message to be logged from a
1809 // ServiceWorker.
1810 class ConsoleMessageObserver : public content::ServiceWorkerContextObserver {
1811 public:
1812 ConsoleMessageObserver(content::BrowserContext* browser_context,
1813 const std::string& expected_message)
1814 : expected_message_(base::UTF8ToUTF16(expected_message)),
1815 scoped_observer_(this) {
1816 content::StoragePartition* partition =
1817 content::BrowserContext::GetDefaultStoragePartition(browser_context);
1818 scoped_observer_.Add(partition->GetServiceWorkerContext());
1819 }
1820 ~ConsoleMessageObserver() override = default;
1821
1822 void Wait() { run_loop_.Run(); }
1823
1824 private:
1825 // ServiceWorkerContextObserver:
1826 void OnReportConsoleMessage(
1827 int64_t version_id,
1828 const content::ConsoleMessage& message) override {
1829 // NOTE: We could check the version_id, but it shouldn't be necessary with
1830 // the expected messages we're verifying (they're uncommon enough).
1831 if (message.message != expected_message_)
1832 return;
1833 scoped_observer_.RemoveAll();
1834 run_loop_.QuitWhenIdle();
1835 }
1836
1837 base::string16 expected_message_;
1838 base::RunLoop run_loop_;
1839 ScopedObserver<content::ServiceWorkerContext,
1840 content::ServiceWorkerContextObserver>
1841 scoped_observer_;
1842
1843 DISALLOW_COPY_AND_ASSIGN(ConsoleMessageObserver);
1844 };
1845
1846 TestExtensionDir test_dir;
1847 test_dir.WriteManifest(
1848 R"({
1849 "name": "Test Extension",
1850 "manifest_version": 2,
1851 "version": "0.1",
David Bertoni630837d2019-04-02 21:22:101852 "background": {"service_worker": "script.js"}
Devlin Cronin59551d82019-03-05 01:28:591853 })");
1854 constexpr char kScript[] =
1855 R"(// First, log a message using the normal, built-in blink console.
1856 console.log('test message');
1857 chrome.test.runTests([
1858 function justATest() {
1859 // Next, we use the "Console" object from
1860 // extensions/renderer/console.cc, which is used by custom bindings
1861 // so that it isn't tampered with by untrusted script. The test
1862 // custom bindings log a message whenever a test is passed, so we
1863 // force a log by just passing this test.
1864 chrome.test.succeed();
1865 }
1866 ]);)";
1867 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"), kScript);
1868
1869 // The observer for the built-in blink console.
1870 ConsoleMessageObserver default_console_observer(profile(), "test message");
1871 // The observer for our custom extensions bindings console.
1872 ConsoleMessageObserver custom_console_observer(profile(),
1873 "[SUCCESS] justATest");
1874
1875 const Extension* extension = LoadExtension(test_dir.UnpackedPath());
1876 ASSERT_TRUE(extension);
1877
1878 default_console_observer.Wait();
1879 custom_console_observer.Wait();
1880 // If we receive both messages, we passed!
1881}
1882
annekao38685502015-07-14 17:46:391883} // namespace extensions