blob: f134939fca591515e5a2c56885408850467f8dd2 [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"
David Bertoni1dc1b7a2019-06-13 02:44:5960#include "extensions/browser/test_extension_registry_observer.h"
Istiaque Ahmeda14ec482018-08-25 01:02:1861#include "extensions/common/api/test.h"
Istiaque Ahmed771aa8a22018-06-20 23:40:5362#include "extensions/common/value_builder.h"
David Bertoni9026eff2019-05-01 18:04:3163#include "extensions/common/verifier_formats.h"
kalman6f984ae2015-09-18 17:21:5864#include "extensions/test/background_page_watcher.h"
annekao38685502015-07-14 17:46:3965#include "extensions/test/extension_test_message_listener.h"
Istiaque Ahmed805f6a83b2017-10-05 01:23:2666#include "extensions/test/result_catcher.h"
Devlin Cronin59551d82019-03-05 01:28:5967#include "extensions/test/test_extension_dir.h"
falkenad185092016-06-16 06:10:0268#include "net/dns/mock_host_resolver.h"
horo1eeddde2015-11-19 05:59:2569#include "net/test/embedded_test_server/embedded_test_server.h"
lazyboy63b994a2017-06-30 21:20:2370#include "url/url_constants.h"
annekao38685502015-07-14 17:46:3971
72namespace extensions {
73
kalman6f984ae2015-09-18 17:21:5874namespace {
75
lazyboy22eddc712015-12-10 21:16:2676// Returns the newly added WebContents.
77content::WebContents* AddTab(Browser* browser, const GURL& url) {
78 int starting_tab_count = browser->tab_strip_model()->count();
79 ui_test_utils::NavigateToURLWithDisposition(
nick3b04f322016-08-31 19:29:1980 browser, url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
lazyboy22eddc712015-12-10 21:16:2681 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
82 int tab_count = browser->tab_strip_model()->count();
83 EXPECT_EQ(starting_tab_count + 1, tab_count);
84 return browser->tab_strip_model()->GetActiveWebContents();
85}
86
lazyboy22eddc712015-12-10 21:16:2687class WebContentsLoadStopObserver : content::WebContentsObserver {
88 public:
89 explicit WebContentsLoadStopObserver(content::WebContents* web_contents)
90 : content::WebContentsObserver(web_contents),
91 load_stop_observed_(false) {}
92
93 void WaitForLoadStop() {
94 if (load_stop_observed_)
95 return;
96 message_loop_runner_ = new content::MessageLoopRunner;
97 message_loop_runner_->Run();
98 }
99
100 private:
101 void DidStopLoading() override {
102 load_stop_observed_ = true;
103 if (message_loop_runner_)
104 message_loop_runner_->Quit();
105 }
106
107 bool load_stop_observed_;
108 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
109
110 DISALLOW_COPY_AND_ASSIGN(WebContentsLoadStopObserver);
111};
112
David Bertoni4d9cf41d2019-06-04 00:06:22113// A known extension ID for tests that specify the key in their
114// manifests.
115constexpr char kTestExtensionId[] = "knldjmfmopnpolahpmmgbagdohdnhkik";
116
kalman6f984ae2015-09-18 17:21:58117} // namespace
118
Devlin Cronin242d19d22019-03-12 18:08:48119class ServiceWorkerTest : public ExtensionApiTest {
annekao38685502015-07-14 17:46:39120 public:
lazyboy20167c22016-05-18 00:59:30121 ServiceWorkerTest() : current_channel_(version_info::Channel::STABLE) {}
Istiaque Ahmed7105f2a2017-10-07 01:11:59122 explicit ServiceWorkerTest(version_info::Channel channel)
123 : current_channel_(channel) {}
annekao38685502015-07-14 17:46:39124
125 ~ServiceWorkerTest() override {}
126
jam1a5b5582017-05-01 16:50:10127 void SetUpOnMainThread() override {
128 ExtensionApiTest::SetUpOnMainThread();
David Bertoni3929f552019-03-28 22:10:36129 host_resolver()->AddRule("*", "127.0.0.1");
jam1a5b5582017-05-01 16:50:10130 }
131
kalman6f984ae2015-09-18 17:21:58132 protected:
133 // Returns the ProcessManager for the test's profile.
134 ProcessManager* process_manager() { return ProcessManager::Get(profile()); }
135
136 // Starts running a test from the background page test extension.
137 //
138 // This registers a service worker with |script_name|, and fetches the
139 // registration result.
Istiaque Ahmed93ff7f42018-08-31 01:42:22140 const Extension* StartTestFromBackgroundPage(const char* script_name) {
Istiaque Ahmed6475f542018-08-28 04:20:21141 ExtensionTestMessageListener ready_listener("ready", false);
kalman6f984ae2015-09-18 17:21:58142 const Extension* extension =
143 LoadExtension(test_data_dir_.AppendASCII("service_worker/background"));
144 CHECK(extension);
Istiaque Ahmed6475f542018-08-28 04:20:21145 CHECK(ready_listener.WaitUntilSatisfied());
146
kalman6f984ae2015-09-18 17:21:58147 ExtensionHost* background_host =
148 process_manager()->GetBackgroundHostForExtension(extension->id());
149 CHECK(background_host);
Istiaque Ahmed6475f542018-08-28 04:20:21150
kalman6f984ae2015-09-18 17:21:58151 std::string error;
152 CHECK(content::ExecuteScriptAndExtractString(
153 background_host->host_contents(),
154 base::StringPrintf("test.registerServiceWorker('%s')", script_name),
155 &error));
Istiaque Ahmed93ff7f42018-08-31 01:42:22156 if (!error.empty())
kalman6f984ae2015-09-18 17:21:58157 ADD_FAILURE() << "Got unexpected error " << error;
158 return extension;
159 }
160
161 // Navigates the browser to a new tab at |url|, waits for it to load, then
162 // returns it.
163 content::WebContents* Navigate(const GURL& url) {
164 ui_test_utils::NavigateToURLWithDisposition(
nick3b04f322016-08-31 19:29:19165 browser(), url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
kalman6f984ae2015-09-18 17:21:58166 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
167 content::WebContents* web_contents =
168 browser()->tab_strip_model()->GetActiveWebContents();
169 content::WaitForLoadStop(web_contents);
170 return web_contents;
171 }
172
173 // Navigates the browser to |url| and returns the new tab's page type.
174 content::PageType NavigateAndGetPageType(const GURL& url) {
clamy1d7a4112018-06-15 15:47:16175 return Navigate(url)
176 ->GetController()
177 .GetLastCommittedEntry()
178 ->GetPageType();
kalman6f984ae2015-09-18 17:21:58179 }
180
181 // Extracts the innerText from |contents|.
182 std::string ExtractInnerText(content::WebContents* contents) {
183 std::string inner_text;
184 if (!content::ExecuteScriptAndExtractString(
185 contents,
186 "window.domAutomationController.send(document.body.innerText)",
187 &inner_text)) {
188 ADD_FAILURE() << "Failed to get inner text for "
189 << contents->GetVisibleURL();
190 }
191 return inner_text;
192 }
193
194 // Navigates the browser to |url|, then returns the innerText of the new
195 // tab's WebContents' main frame.
196 std::string NavigateAndExtractInnerText(const GURL& url) {
197 return ExtractInnerText(Navigate(url));
198 }
199
lazyboy4c82177a2016-10-18 00:04:09200 size_t GetWorkerRefCount(const GURL& origin) {
201 content::ServiceWorkerContext* sw_context =
202 content::BrowserContext::GetDefaultStoragePartition(
203 browser()->profile())
204 ->GetServiceWorkerContext();
205 base::RunLoop run_loop;
206 size_t ref_count = 0;
207 auto set_ref_count = [](size_t* ref_count, base::RunLoop* run_loop,
208 size_t external_request_count) {
209 *ref_count = external_request_count;
210 run_loop->Quit();
211 };
212 sw_context->CountExternalRequestsForTest(
Matt Falkenhagenc5cb4282017-09-07 08:43:42213 origin, base::BindOnce(set_ref_count, &ref_count, &run_loop));
lazyboy4c82177a2016-10-18 00:04:09214 run_loop.Run();
215 return ref_count;
216 }
217
annekao38685502015-07-14 17:46:39218 private:
lazyboy20167c22016-05-18 00:59:30219 // Sets the channel to "stable".
220 // Not useful after we've opened extension Service Workers to stable
221 // channel.
222 // TODO(lazyboy): Remove this when ExtensionServiceWorkersEnabled() is
223 // removed.
annekao38685502015-07-14 17:46:39224 ScopedCurrentChannel current_channel_;
kalman6f984ae2015-09-18 17:21:58225
annekao38685502015-07-14 17:46:39226 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerTest);
227};
228
Istiaque Ahmedccb444022018-06-19 02:11:12229class ServiceWorkerBasedBackgroundTest : public ServiceWorkerTest {
230 public:
231 ServiceWorkerBasedBackgroundTest()
232 : ServiceWorkerTest(
233 // Extensions APIs from SW are only enabled on trunk.
234 // It is important to set the channel early so that this change is
235 // visible in renderers running with service workers (and no
236 // extension).
237 version_info::Channel::UNKNOWN) {}
238 ~ServiceWorkerBasedBackgroundTest() override {}
239
240 void SetUpOnMainThread() override {
241 host_resolver()->AddRule("*", "127.0.0.1");
242 ASSERT_TRUE(embedded_test_server()->Start());
243 ServiceWorkerTest::SetUpOnMainThread();
244 }
245
Istiaque Ahmedd4b67ee2019-03-02 10:53:20246 // Returns the only running worker id for |extension_id|.
247 // Returns base::nullopt if there isn't any worker running or more than one
248 // worker is running for |extension_id|.
249 base::Optional<WorkerId> GetUniqueRunningWorkerId(
250 const ExtensionId& extension_id) {
251 ProcessManager* process_manager = ProcessManager::Get(profile());
252 std::vector<WorkerId> all_workers =
253 process_manager->GetAllWorkersIdsForTesting();
254 base::Optional<WorkerId> running_worker_id;
255 for (const WorkerId& worker_id : all_workers) {
256 if (worker_id.extension_id == extension_id) {
257 if (running_worker_id) // More than one worker present.
258 return base::nullopt;
259 running_worker_id = worker_id;
260 }
261 }
262 return running_worker_id;
263 }
264
David Bertoni023e0ec2019-06-10 17:28:22265 bool ExtensionHasRenderProcessHost(const ExtensionId& extension_id) {
266 ProcessMap* process_map = ProcessMap::Get(browser()->profile());
267 content::RenderProcessHost::iterator it =
268 content::RenderProcessHost::AllHostsIterator();
269 while (!it.IsAtEnd()) {
270 if (process_map->Contains(extension_id, it.GetCurrentValue()->GetID())) {
271 return true;
272 }
273 it.Advance();
274 }
275 return false;
276 }
277
Istiaque Ahmedccb444022018-06-19 02:11:12278 private:
279 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerBasedBackgroundTest);
280};
281
282// Tests that Service Worker based background pages can be loaded and they can
283// receive extension events.
284// The extension is installed and loaded during this step and it registers
285// an event listener for tabs.onCreated event. The step also verifies that tab
286// creation correctly fires the listener.
Devlin Cronin242d19d22019-03-12 18:08:48287IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, PRE_Basic) {
Istiaque Ahmedccb444022018-06-19 02:11:12288 ExtensionTestMessageListener newtab_listener("CREATED", false);
289 newtab_listener.set_failure_message("CREATE_FAILED");
290 ExtensionTestMessageListener worker_listener("WORKER_RUNNING", false);
291 worker_listener.set_failure_message("NON_WORKER_SCOPE");
292 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
293 "service_worker/worker_based_background/basic"));
294 ASSERT_TRUE(extension);
295 const ExtensionId extension_id = extension->id();
296 EXPECT_TRUE(worker_listener.WaitUntilSatisfied());
297
298 const GURL url = embedded_test_server()->GetURL("/extensions/test_file.html");
299 content::WebContents* new_web_contents = AddTab(browser(), url);
300 EXPECT_TRUE(new_web_contents);
301 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
302
303 // Service Worker extension does not have ExtensionHost.
304 EXPECT_FALSE(process_manager()->GetBackgroundHostForExtension(extension_id));
305}
306
307// After browser restarts, this test step ensures that opening a tab fires
308// tabs.onCreated event listener to the extension without explicitly loading the
309// extension. This is because the extension registered a listener before browser
310// restarted in PRE_Basic.
Devlin Cronin242d19d22019-03-12 18:08:48311IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, Basic) {
Istiaque Ahmedccb444022018-06-19 02:11:12312 ExtensionTestMessageListener newtab_listener("CREATED", false);
313 newtab_listener.set_failure_message("CREATE_FAILED");
314 const GURL url = embedded_test_server()->GetURL("/extensions/test_file.html");
315 content::WebContents* new_web_contents = AddTab(browser(), url);
316 EXPECT_TRUE(new_web_contents);
317 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
318}
319
Istiaque Ahmedbf08f952018-10-02 01:22:04320// Tests chrome.runtime.onInstalled fires for extension service workers.
Devlin Cronin242d19d22019-03-12 18:08:48321IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, OnInstalledEvent) {
Istiaque Ahmedbf08f952018-10-02 01:22:04322 ASSERT_TRUE(RunExtensionTest(
323 "service_worker/worker_based_background/events_on_installed"))
324 << message_;
325}
326
Istiaque Ahmedba8d0652019-05-14 15:17:34327// Tests chrome.runtime.id and chrome.runtime.getURL().
328IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, RuntimeMisc) {
329 ASSERT_TRUE(
330 RunExtensionTest("service_worker/worker_based_background/runtime_misc"))
331 << message_;
332}
333
David Bertoni69982832019-02-13 21:24:21334// Tests chrome.storage APIs.
Devlin Cronin242d19d22019-03-12 18:08:48335IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, StorageSetAndGet) {
David Bertoni69982832019-02-13 21:24:21336 ASSERT_TRUE(
337 RunExtensionTest("service_worker/worker_based_background/storage"))
338 << message_;
339}
340
David Bertoni0665c892019-02-14 00:27:26341// Tests chrome.storage.local and chrome.storage.local APIs.
Devlin Cronin242d19d22019-03-12 18:08:48342IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, StorageNoPermissions) {
David Bertoni0665c892019-02-14 00:27:26343 ASSERT_TRUE(RunExtensionTest(
344 "service_worker/worker_based_background/storage_no_permissions"))
345 << message_;
346}
347
David Bertoni30809312019-02-28 22:56:05348// Tests chrome.tabs APIs.
Devlin Cronin242d19d22019-03-12 18:08:48349IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, TabsBasic) {
David Bertoni30809312019-02-28 22:56:05350 ASSERT_TRUE(
351 RunExtensionTest("service_worker/worker_based_background/tabs_basic"))
352 << message_;
353}
354
David Bertoni46d698892019-02-26 00:29:10355// Tests chrome.tabs events.
Devlin Cronin242d19d22019-03-12 18:08:48356IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, TabsEvents) {
David Bertoni46d698892019-02-26 00:29:10357 ASSERT_TRUE(
358 RunExtensionTest("service_worker/worker_based_background/tabs_events"))
359 << message_;
360}
361
David Bertoni4c7dfcc2019-03-27 23:49:34362// Tests chrome.tabs APIs.
363IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, TabsExecuteScript) {
364 ASSERT_TRUE(RunExtensionTest(
365 "service_worker/worker_based_background/tabs_execute_script"))
366 << message_;
367}
368
David Bertoni37ae0222019-04-04 01:30:54369// Tests chrome.webRequest APIs.
David Bertoni3929f552019-03-28 22:10:36370IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, WebRequest) {
371 ASSERT_TRUE(
372 RunExtensionTest("service_worker/worker_based_background/web_request"))
373 << message_;
374}
375
David Bertoni37ae0222019-04-04 01:30:54376// Tests chrome.webRequest APIs in blocking mode.
377IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, WebRequestBlocking) {
378 // Try to load the page before installing the extension, which should work.
379 const GURL url = embedded_test_server()->GetURL("/extensions/test_file.html");
380 EXPECT_EQ(content::PAGE_TYPE_NORMAL, NavigateAndGetPageType(url));
381
382 // Install the extension and navigate again to the page.
383 ExtensionTestMessageListener ready_listener("ready", false);
384 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII(
385 "service_worker/worker_based_background/web_request_blocking")));
386 ASSERT_TRUE(ready_listener.WaitUntilSatisfied());
387 EXPECT_EQ(content::PAGE_TYPE_ERROR, NavigateAndGetPageType(url));
388}
389
David Bertoni377f52312019-05-21 20:35:03390// Tests chrome.webNavigation APIs.
391IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, FilteredEvents) {
392 ASSERT_TRUE(RunExtensionTest(
393 "service_worker/worker_based_background/filtered_events"))
394 << message_;
395}
396
Istiaque Ahmed70f76ac2018-11-02 02:59:55397// Listens for |message| from extension Service Worker early so that tests can
398// wait for the message on startup (and not miss it).
399class ServiceWorkerWithEarlyMessageListenerTest
400 : public ServiceWorkerBasedBackgroundTest {
Istiaque Ahmedf70ab222018-10-02 03:08:24401 public:
Istiaque Ahmed70f76ac2018-11-02 02:59:55402 explicit ServiceWorkerWithEarlyMessageListenerTest(
403 const std::string& test_message)
404 : test_message_(test_message) {}
405 ~ServiceWorkerWithEarlyMessageListenerTest() override = default;
Istiaque Ahmedf70ab222018-10-02 03:08:24406
Istiaque Ahmed70f76ac2018-11-02 02:59:55407 bool WaitForMessage() { return listener_->WaitUntilSatisfied(); }
Istiaque Ahmedf70ab222018-10-02 03:08:24408
409 void CreatedBrowserMainParts(content::BrowserMainParts* main_parts) override {
410 // At this point, the notification service is initialized but the profile
411 // and extensions have not.
Istiaque Ahmed70f76ac2018-11-02 02:59:55412 listener_ =
413 std::make_unique<ExtensionTestMessageListener>(test_message_, false);
Istiaque Ahmedf70ab222018-10-02 03:08:24414 ServiceWorkerBasedBackgroundTest::CreatedBrowserMainParts(main_parts);
415 }
416
417 private:
Istiaque Ahmed70f76ac2018-11-02 02:59:55418 const std::string test_message_;
Istiaque Ahmedf70ab222018-10-02 03:08:24419 std::unique_ptr<ExtensionTestMessageListener> listener_;
420
Istiaque Ahmed70f76ac2018-11-02 02:59:55421 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerWithEarlyMessageListenerTest);
422};
423
424class ServiceWorkerOnStartupEventTest
425 : public ServiceWorkerWithEarlyMessageListenerTest {
426 public:
427 ServiceWorkerOnStartupEventTest()
428 : ServiceWorkerWithEarlyMessageListenerTest("onStartup event") {}
429 ~ServiceWorkerOnStartupEventTest() override = default;
430
431 private:
432 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerOnStartupEventTest);
Istiaque Ahmedf70ab222018-10-02 03:08:24433};
434
435// Tests "runtime.onStartup" for extension SW.
Devlin Cronin242d19d22019-03-12 18:08:48436IN_PROC_BROWSER_TEST_F(ServiceWorkerOnStartupEventTest, PRE_Event) {
Istiaque Ahmedf70ab222018-10-02 03:08:24437 ASSERT_TRUE(RunExtensionTest(
438 "service_worker/worker_based_background/on_startup_event"))
439 << message_;
440}
441
Devlin Cronin242d19d22019-03-12 18:08:48442IN_PROC_BROWSER_TEST_F(ServiceWorkerOnStartupEventTest, Event) {
Istiaque Ahmed70f76ac2018-11-02 02:59:55443 EXPECT_TRUE(WaitForMessage());
444}
445
446class ServiceWorkerRegistrationAtStartupTest
447 : public ServiceWorkerWithEarlyMessageListenerTest,
448 public ServiceWorkerTaskQueue::TestObserver {
449 public:
450 ServiceWorkerRegistrationAtStartupTest()
451 : ServiceWorkerWithEarlyMessageListenerTest("WORKER_RUNNING") {
452 ServiceWorkerTaskQueue::SetObserverForTest(this);
453 }
454 ~ServiceWorkerRegistrationAtStartupTest() override {
455 ServiceWorkerTaskQueue::SetObserverForTest(nullptr);
456 }
457
458 // ServiceWorkerTaskQueue::TestObserver:
459 void OnActivateExtension(const ExtensionId& extension_id,
460 bool will_register_service_worker) override {
461 if (extension_id != kExtensionId)
462 return;
463
464 will_register_service_worker_ = will_register_service_worker;
465
466 extension_activated_ = true;
467 if (run_loop_)
468 run_loop_->Quit();
469 }
470
471 void WaitForOnActivateExtension() {
472 if (extension_activated_)
473 return;
474 run_loop_ = std::make_unique<base::RunLoop>();
475 run_loop_->Run();
476 }
477
478 bool WillRegisterServiceWorker() {
479 return will_register_service_worker_.value();
480 }
481
482 protected:
483 static const char kExtensionId[];
484
485 private:
486 bool extension_activated_ = false;
487 base::Optional<bool> will_register_service_worker_;
488 std::unique_ptr<base::RunLoop> run_loop_;
489
490 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerRegistrationAtStartupTest);
491};
492
493// Test extension id at
494// api_test/service_worker/worker_based_background/registration_at_startup/.
495const char ServiceWorkerRegistrationAtStartupTest::kExtensionId[] =
496 "gnchfmandajfaiajniicagenfmhdjila";
497
498// Tests that Service Worker registration for existing extension isn't issued
499// upon browser restart.
500// Regression test for https://crbug.com/889687.
Devlin Cronin242d19d22019-03-12 18:08:48501IN_PROC_BROWSER_TEST_F(ServiceWorkerRegistrationAtStartupTest,
Istiaque Ahmed70f76ac2018-11-02 02:59:55502 PRE_ExtensionActivationDoesNotReregister) {
503 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
504 "service_worker/worker_based_background/registration_at_startup"));
505 ASSERT_TRUE(extension);
506 EXPECT_EQ(kExtensionId, extension->id());
507 // Wait for "WORKER_RUNNING" message from the Service Worker.
508 EXPECT_TRUE(WaitForMessage());
509 EXPECT_TRUE(WillRegisterServiceWorker());
510}
511
Devlin Cronin242d19d22019-03-12 18:08:48512IN_PROC_BROWSER_TEST_F(ServiceWorkerRegistrationAtStartupTest,
Istiaque Ahmed70f76ac2018-11-02 02:59:55513 ExtensionActivationDoesNotReregister) {
514 // Since the extension has onStartup listener, the Service Worker will run on
515 // browser start and we'll see "WORKER_RUNNING" message from the worker.
516 EXPECT_TRUE(WaitForMessage());
517 // As the extension activated during first run on PRE_ step, it shouldn't
518 // re-register the Service Worker upon browser restart.
519 EXPECT_FALSE(WillRegisterServiceWorker());
Istiaque Ahmedf70ab222018-10-02 03:08:24520}
521
Istiaque Ahmeda14ec482018-08-25 01:02:18522// Class that dispatches an event to |extension_id| right after a
523// non-lazy listener to the event is added from the extension's Service Worker.
Istiaque Ahmed771aa8a22018-06-20 23:40:53524class EarlyWorkerMessageSender : public EventRouter::Observer {
525 public:
526 EarlyWorkerMessageSender(content::BrowserContext* browser_context,
Istiaque Ahmeda14ec482018-08-25 01:02:18527 const ExtensionId& extension_id,
528 std::unique_ptr<Event> event)
Istiaque Ahmed771aa8a22018-06-20 23:40:53529 : browser_context_(browser_context),
530 event_router_(EventRouter::EventRouter::Get(browser_context_)),
531 extension_id_(extension_id),
Istiaque Ahmeda14ec482018-08-25 01:02:18532 event_(std::move(event)),
Istiaque Ahmed771aa8a22018-06-20 23:40:53533 listener_("PASS", false) {
534 DCHECK(browser_context_);
535 listener_.set_failure_message("FAIL");
Istiaque Ahmeda14ec482018-08-25 01:02:18536 event_router_->RegisterObserver(this, event_->event_name);
Istiaque Ahmed771aa8a22018-06-20 23:40:53537 }
538
539 ~EarlyWorkerMessageSender() override {
540 event_router_->UnregisterObserver(this);
541 }
542
543 // EventRouter::Observer:
544 void OnListenerAdded(const EventListenerInfo& details) override {
Istiaque Ahmeda14ec482018-08-25 01:02:18545 if (!event_ || extension_id_ != details.extension_id ||
546 event_->event_name != details.event_name) {
Istiaque Ahmed771aa8a22018-06-20 23:40:53547 return;
Istiaque Ahmeda14ec482018-08-25 01:02:18548 }
549
Istiaque Ahmed771aa8a22018-06-20 23:40:53550 const bool is_lazy_listener = details.browser_context == nullptr;
551 if (is_lazy_listener) {
552 // Wait for the non-lazy listener as we want to exercise the code to
553 // dispatch the event right after the Service Worker registration is
554 // completing.
555 return;
556 }
Istiaque Ahmeda14ec482018-08-25 01:02:18557 DispatchEvent(std::move(event_));
Istiaque Ahmed771aa8a22018-06-20 23:40:53558 }
559
560 bool SendAndWait() { return listener_.WaitUntilSatisfied(); }
561
562 private:
563 static constexpr const char* const kTestOnMessageEventName = "test.onMessage";
564
Istiaque Ahmeda14ec482018-08-25 01:02:18565 void DispatchEvent(std::unique_ptr<Event> event) {
Istiaque Ahmed771aa8a22018-06-20 23:40:53566 EventRouter::Get(browser_context_)
567 ->DispatchEventToExtension(extension_id_, std::move(event));
568 }
569
570 content::BrowserContext* const browser_context_ = nullptr;
571 EventRouter* const event_router_ = nullptr;
572 const ExtensionId extension_id_;
Istiaque Ahmeda14ec482018-08-25 01:02:18573 std::unique_ptr<Event> event_;
Istiaque Ahmed771aa8a22018-06-20 23:40:53574 ExtensionTestMessageListener listener_;
Istiaque Ahmed771aa8a22018-06-20 23:40:53575
576 DISALLOW_COPY_AND_ASSIGN(EarlyWorkerMessageSender);
577};
578
579// Tests that extension event dispatch works correctly right after extension
580// installation registers its Service Worker.
581// Regression test for: https://crbug.com/850792.
Devlin Cronin242d19d22019-03-12 18:08:48582IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, EarlyEventDispatch) {
Istiaque Ahmed771aa8a22018-06-20 23:40:53583 const ExtensionId kId("pkplfbidichfdicaijlchgnapepdginl");
Istiaque Ahmeda14ec482018-08-25 01:02:18584
585 // Build "test.onMessage" event for dispatch.
586 auto event = std::make_unique<Event>(
587 events::FOR_TEST, extensions::api::test::OnMessage::kEventName,
Lei Zhang582ecd12019-02-13 20:28:54588 base::ListValue::From(base::JSONReader::ReadDeprecated(
Istiaque Ahmeda14ec482018-08-25 01:02:18589 R"([{"data": "hello", "lastMessage": true}])")),
590 profile());
591
592 EarlyWorkerMessageSender sender(profile(), kId, std::move(event));
Istiaque Ahmed771aa8a22018-06-20 23:40:53593 // pkplfbidichfdicaijlchgnapepdginl
594 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
595 "service_worker/worker_based_background/early_event_dispatch"));
596 CHECK(extension);
597 EXPECT_EQ(kId, extension->id());
598 EXPECT_TRUE(sender.SendAndWait());
599}
600
Istiaque Ahmeda14ec482018-08-25 01:02:18601// Tests that filtered events dispatches correctly right after a non-lazy
602// listener is registered for that event (and before the corresponding lazy
603// listener is registered).
Devlin Cronin242d19d22019-03-12 18:08:48604IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
Istiaque Ahmeda14ec482018-08-25 01:02:18605 EarlyFilteredEventDispatch) {
606 const ExtensionId kId("pkplfbidichfdicaijlchgnapepdginl");
607
608 // Add minimal details required to dispatch webNavigation.onCommitted event:
609 extensions::api::web_navigation::OnCommitted::Details details;
610 details.transition_type =
611 extensions::api::web_navigation::TRANSITION_TYPE_TYPED;
612
613 // Build a dummy onCommited event to dispatch.
614 auto on_committed_event = std::make_unique<Event>(
615 events::WEB_NAVIGATION_ON_COMMITTED, "webNavigation.onCommitted",
616 api::web_navigation::OnCommitted::Create(details), profile());
617 // The filter will match the listener filter registered from the extension.
618 EventFilteringInfo info;
619 info.url = GURL("http://foo.com/a.html");
620 on_committed_event->filter_info = info;
621
622 EarlyWorkerMessageSender sender(profile(), kId,
623 std::move(on_committed_event));
624
625 // pkplfbidichfdicaijlchgnapepdginl
626 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
627 "service_worker/worker_based_background/early_filtered_event_dispatch"));
628 ASSERT_TRUE(extension);
629 EXPECT_EQ(kId, extension->id());
630 EXPECT_TRUE(sender.SendAndWait());
631}
632
lazyboybd325ae2015-11-18 21:35:26633class ServiceWorkerBackgroundSyncTest : public ServiceWorkerTest {
634 public:
635 ServiceWorkerBackgroundSyncTest() {}
636 ~ServiceWorkerBackgroundSyncTest() override {}
637
638 void SetUpCommandLine(base::CommandLine* command_line) override {
639 // ServiceWorkerRegistration.sync requires experimental flag.
640 command_line->AppendSwitch(
Istiaque Ahmedea5ed5042017-09-25 19:00:16641 ::switches::kEnableExperimentalWebPlatformFeatures);
lazyboybd325ae2015-11-18 21:35:26642 ServiceWorkerTest::SetUpCommandLine(command_line);
643 }
644
645 void SetUp() override {
Robbie McElrathdb12d8e2018-09-18 21:20:40646 content::background_sync_test_util::SetIgnoreNetworkChanges(true);
lazyboybd325ae2015-11-18 21:35:26647 ServiceWorkerTest::SetUp();
648 }
649
650 private:
651 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerBackgroundSyncTest);
652};
653
lazyboy561b7de2015-11-19 19:27:30654class ServiceWorkerPushMessagingTest : public ServiceWorkerTest {
655 public:
656 ServiceWorkerPushMessagingTest()
Sylvain Defresne212b4b02018-10-11 16:32:05657 : scoped_testing_factory_installer_(
658 base::BindRepeating(&gcm::FakeGCMProfileService::Build)),
659 gcm_driver_(nullptr),
660 push_service_(nullptr) {}
661
lazyboy561b7de2015-11-19 19:27:30662 ~ServiceWorkerPushMessagingTest() override {}
663
664 void GrantNotificationPermissionForTest(const GURL& url) {
Peter Beverloodd4ef1e2018-06-21 15:41:04665 NotificationPermissionContext::UpdatePermission(profile(), url.GetOrigin(),
666 CONTENT_SETTING_ALLOW);
lazyboy561b7de2015-11-19 19:27:30667 }
668
669 PushMessagingAppIdentifier GetAppIdentifierForServiceWorkerRegistration(
avia2f4804a2015-12-24 23:11:13670 int64_t service_worker_registration_id,
lazyboy561b7de2015-11-19 19:27:30671 const GURL& origin) {
672 PushMessagingAppIdentifier app_identifier =
673 PushMessagingAppIdentifier::FindByServiceWorker(
674 profile(), origin, service_worker_registration_id);
675
676 EXPECT_FALSE(app_identifier.is_null());
677 return app_identifier;
678 }
679
680 // ExtensionApiTest overrides.
681 void SetUpCommandLine(base::CommandLine* command_line) override {
peter9de96272015-12-04 15:23:27682 command_line->AppendSwitch(
Istiaque Ahmedea5ed5042017-09-25 19:00:16683 ::switches::kEnableExperimentalWebPlatformFeatures);
lazyboy561b7de2015-11-19 19:27:30684 ServiceWorkerTest::SetUpCommandLine(command_line);
685 }
Tanja Gornak89128fd2018-09-18 08:49:34686
lazyboy561b7de2015-11-19 19:27:30687 void SetUpOnMainThread() override {
miguelg9b502862017-04-24 18:13:53688 NotificationDisplayServiceFactory::GetInstance()->SetTestingFactory(
Sylvain Defresne711ff6b2018-10-04 12:33:54689 profile(),
690 base::BindRepeating(&StubNotificationDisplayService::FactoryForTests));
miguelg9b502862017-04-24 18:13:53691
johnmea5045732016-09-08 17:23:29692 gcm::FakeGCMProfileService* gcm_service =
693 static_cast<gcm::FakeGCMProfileService*>(
Tanja Gornak89128fd2018-09-18 08:49:34694 gcm::GCMProfileServiceFactory::GetForProfile(profile()));
johnmea5045732016-09-08 17:23:29695 gcm_driver_ = static_cast<instance_id::FakeGCMDriverForInstanceID*>(
696 gcm_service->driver());
lazyboy561b7de2015-11-19 19:27:30697 push_service_ = PushMessagingServiceFactory::GetForProfile(profile());
698
699 ServiceWorkerTest::SetUpOnMainThread();
700 }
701
johnmea5045732016-09-08 17:23:29702 instance_id::FakeGCMDriverForInstanceID* gcm_driver() const {
703 return gcm_driver_;
704 }
lazyboy561b7de2015-11-19 19:27:30705 PushMessagingServiceImpl* push_service() const { return push_service_; }
706
707 private:
Sylvain Defresne212b4b02018-10-11 16:32:05708 gcm::GCMProfileServiceFactory::ScopedTestingFactoryInstaller
709 scoped_testing_factory_installer_;
710
johnmea5045732016-09-08 17:23:29711 instance_id::FakeGCMDriverForInstanceID* gcm_driver_;
lazyboy561b7de2015-11-19 19:27:30712 PushMessagingServiceImpl* push_service_;
713
714 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerPushMessagingTest);
715};
716
Istiaque Ahmed805f6a83b2017-10-05 01:23:26717class ServiceWorkerLazyBackgroundTest : public ServiceWorkerTest {
718 public:
Istiaque Ahmed7105f2a2017-10-07 01:11:59719 ServiceWorkerLazyBackgroundTest()
720 : ServiceWorkerTest(
721 // Extensions APIs from SW are only enabled on trunk.
722 // It is important to set the channel early so that this change is
723 // visible in renderers running with service workers (and no
724 // extension).
725 version_info::Channel::UNKNOWN) {}
Istiaque Ahmed805f6a83b2017-10-05 01:23:26726 ~ServiceWorkerLazyBackgroundTest() override {}
727
728 void SetUpCommandLine(base::CommandLine* command_line) override {
729 ServiceWorkerTest::SetUpCommandLine(command_line);
730 // Disable background network activity as it can suddenly bring the Lazy
731 // Background Page alive.
732 command_line->AppendSwitch(::switches::kDisableBackgroundNetworking);
733 command_line->AppendSwitch(::switches::kNoProxyServer);
734 }
735
736 void SetUpInProcessBrowserTestFixture() override {
737 ServiceWorkerTest::SetUpInProcessBrowserTestFixture();
738 // Set shorter delays to prevent test timeouts.
739 ProcessManager::SetEventPageIdleTimeForTesting(1);
740 ProcessManager::SetEventPageSuspendingTimeForTesting(1);
741 }
742
743 private:
744 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerLazyBackgroundTest);
745};
746
Devlin Cronin242d19d22019-03-12 18:08:48747IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, RegisterSucceeds) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22748 StartTestFromBackgroundPage("register.js");
annekao38685502015-07-14 17:46:39749}
750
Devlin Cronin242d19d22019-03-12 18:08:48751IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, UpdateRefreshesServiceWorker) {
Francois Doraye6fb2d02017-10-18 21:29:13752 base::ScopedAllowBlockingForTesting allow_blocking;
lazyboyc3e763a2015-12-09 23:09:58753 base::ScopedTempDir scoped_temp_dir;
754 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
755 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
756 .AppendASCII("update")
757 .AppendASCII("service_worker.pem");
vabr9142fe22016-09-08 13:19:22758 base::FilePath path_v1 =
759 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
760 .AppendASCII("update")
761 .AppendASCII("v1"),
762 scoped_temp_dir.GetPath().AppendASCII("v1.crx"),
763 pem_path, base::FilePath());
764 base::FilePath path_v2 =
765 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
766 .AppendASCII("update")
767 .AppendASCII("v2"),
768 scoped_temp_dir.GetPath().AppendASCII("v2.crx"),
769 pem_path, base::FilePath());
lazyboyc3e763a2015-12-09 23:09:58770 const char* kId = "hfaanndiiilofhfokeanhddpkfffchdi";
771
772 ExtensionTestMessageListener listener_v1("Pong from version 1", false);
773 listener_v1.set_failure_message("FAILURE_V1");
774 // Install version 1.0 of the extension.
775 ASSERT_TRUE(InstallExtension(path_v1, 1));
776 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
777 ->enabled_extensions()
778 .GetByID(kId));
779 EXPECT_TRUE(listener_v1.WaitUntilSatisfied());
780
781 ExtensionTestMessageListener listener_v2("Pong from version 2", false);
782 listener_v2.set_failure_message("FAILURE_V2");
783
784 // Update to version 2.0.
785 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
786 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
787 ->enabled_extensions()
788 .GetByID(kId));
789 EXPECT_TRUE(listener_v2.WaitUntilSatisfied());
790}
791
[email protected]2ef85d562017-09-15 18:41:52792// TODO(crbug.com/765736) Fix the test.
Devlin Cronin242d19d22019-03-12 18:08:48793IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, DISABLED_UpdateWithoutSkipWaiting) {
Francois Doraye6fb2d02017-10-18 21:29:13794 base::ScopedAllowBlockingForTesting allow_blocking;
lazyboy22eddc712015-12-10 21:16:26795 base::ScopedTempDir scoped_temp_dir;
796 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
797 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
798 .AppendASCII("update_without_skip_waiting")
799 .AppendASCII("update_without_skip_waiting.pem");
vabr9142fe22016-09-08 13:19:22800 base::FilePath path_v1 =
801 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
802 .AppendASCII("update_without_skip_waiting")
803 .AppendASCII("v1"),
804 scoped_temp_dir.GetPath().AppendASCII("v1.crx"),
805 pem_path, base::FilePath());
806 base::FilePath path_v2 =
807 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
808 .AppendASCII("update_without_skip_waiting")
809 .AppendASCII("v2"),
810 scoped_temp_dir.GetPath().AppendASCII("v2.crx"),
811 pem_path, base::FilePath());
lazyboy22eddc712015-12-10 21:16:26812 const char* kId = "mhnnnflgagdakldgjpfcofkiocpdmogl";
813
814 // Install version 1.0 of the extension.
815 ASSERT_TRUE(InstallExtension(path_v1, 1));
816 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
817 ->enabled_extensions()
818 .GetByID(kId));
819 const Extension* extension = extensions::ExtensionRegistry::Get(profile())
820 ->enabled_extensions()
821 .GetByID(kId);
822
823 ExtensionTestMessageListener listener1("Pong from version 1", false);
824 listener1.set_failure_message("FAILURE");
825 content::WebContents* web_contents =
826 AddTab(browser(), extension->GetResourceURL("page.html"));
827 EXPECT_TRUE(listener1.WaitUntilSatisfied());
828
829 // Update to version 2.0.
830 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
831 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
832 ->enabled_extensions()
833 .GetByID(kId));
834 const Extension* extension_after_update =
835 extensions::ExtensionRegistry::Get(profile())
836 ->enabled_extensions()
837 .GetByID(kId);
838
839 // Service worker version 2 would be installed but it won't be controlling
840 // the extension page yet.
841 ExtensionTestMessageListener listener2("Pong from version 1", false);
842 listener2.set_failure_message("FAILURE");
843 web_contents =
844 AddTab(browser(), extension_after_update->GetResourceURL("page.html"));
845 EXPECT_TRUE(listener2.WaitUntilSatisfied());
846
847 // Navigate the tab away from the extension page so that no clients are
848 // using the service worker.
849 // Note that just closing the tab with WebContentsDestroyedWatcher doesn't
850 // seem to be enough because it returns too early.
851 WebContentsLoadStopObserver navigate_away_observer(web_contents);
852 web_contents->GetController().LoadURL(
853 GURL(url::kAboutBlankURL), content::Referrer(), ui::PAGE_TRANSITION_TYPED,
854 std::string());
855 navigate_away_observer.WaitForLoadStop();
856
857 // Now expect service worker version 2 to control the extension page.
858 ExtensionTestMessageListener listener3("Pong from version 2", false);
859 listener3.set_failure_message("FAILURE");
860 web_contents =
861 AddTab(browser(), extension_after_update->GetResourceURL("page.html"));
862 EXPECT_TRUE(listener3.WaitUntilSatisfied());
863}
864
Devlin Cronin242d19d22019-03-12 18:08:48865IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, FetchArbitraryPaths) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22866 const Extension* extension = StartTestFromBackgroundPage("fetch.js");
annekao1db36fd2015-07-29 17:09:16867
kalman6f984ae2015-09-18 17:21:58868 // Open some arbirary paths. Their contents should be what the service worker
869 // responds with, which in this case is the path of the fetch.
870 EXPECT_EQ(
871 "Caught a fetch for /index.html",
872 NavigateAndExtractInnerText(extension->GetResourceURL("index.html")));
873 EXPECT_EQ("Caught a fetch for /path/to/other.html",
874 NavigateAndExtractInnerText(
875 extension->GetResourceURL("path/to/other.html")));
876 EXPECT_EQ("Caught a fetch for /some/text/file.txt",
877 NavigateAndExtractInnerText(
878 extension->GetResourceURL("some/text/file.txt")));
879 EXPECT_EQ("Caught a fetch for /no/file/extension",
880 NavigateAndExtractInnerText(
881 extension->GetResourceURL("no/file/extension")));
882 EXPECT_EQ("Caught a fetch for /",
883 NavigateAndExtractInnerText(extension->GetResourceURL("")));
annekao1db36fd2015-07-29 17:09:16884}
885
Devlin Cronin242d19d22019-03-12 18:08:48886IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
Kenichi Ishibashi773b82972018-08-30 07:02:03887 FetchExtensionResourceFromServiceWorker) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22888 const Extension* extension = StartTestFromBackgroundPage("fetch_from_sw.js");
Kenichi Ishibashi773b82972018-08-30 07:02:03889 ASSERT_TRUE(extension);
890
891 // The service worker in this test tries to load 'hello.txt' via fetch()
892 // and sends back the content of the file, which should be 'hello'.
893 const char* kScript = R"(
894 let channel = new MessageChannel();
895 test.waitForMessage(channel.port1).then(message => {
896 window.domAutomationController.send(message);
897 });
898 test.registeredServiceWorker.postMessage(
899 {port: channel.port2}, [channel.port2]);
900 )";
901 EXPECT_EQ("hello", ExecuteScriptInBackgroundPage(extension->id(), kScript));
902}
903
Kenichi Ishibashi09ee5e72018-11-27 07:12:38904// Tests that fetch() from service worker and network fallback
905// go through webRequest.onBeforeRequest API.
Devlin Cronin242d19d22019-03-12 18:08:48906IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, OnBeforeRequest) {
Kenichi Ishibashi09ee5e72018-11-27 07:12:38907 const Extension* extension = LoadExtensionWithFlags(
908 test_data_dir_.AppendASCII("service_worker/webrequest"), kFlagNone);
909 ASSERT_TRUE(extension);
910 ASSERT_TRUE(StartEmbeddedTestServer());
911
912 // Start a service worker and make it control the page.
913 GURL page_url = embedded_test_server()->GetURL(
914 "/extensions/api_test/service_worker/"
915 "webrequest/webpage.html");
916 content::WebContents* web_contents =
917 browser()->tab_strip_model()->GetActiveWebContents();
918 ui_test_utils::NavigateToURL(browser(), page_url);
919 content::WaitForLoadStop(web_contents);
920
921 std::string result;
922 ASSERT_TRUE(content::ExecuteScriptAndExtractString(web_contents,
923 "register();", &result));
924 EXPECT_EQ("ready", result);
925
926 // Initiate a fetch that the service worker doesn't intercept
927 // (network fallback).
928 result.clear();
929 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
930 web_contents, "doFetch('hello.txt?fallthrough');", &result));
931 EXPECT_EQ("hello", result);
932 EXPECT_EQ(
933 "/extensions/api_test/service_worker/webrequest/hello.txt?fallthrough",
934 ExecuteScriptInBackgroundPage(extension->id(), "getLastHookedPath()"));
935
936 // Initiate a fetch that results in calling fetch() in the service worker.
937 result.clear();
938 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
939 web_contents, "doFetch('hello.txt?respondWithFetch');", &result));
940 EXPECT_EQ("hello", result);
941 EXPECT_EQ(
942 "/extensions/api_test/service_worker/webrequest/"
943 "hello.txt?respondWithFetch",
944 ExecuteScriptInBackgroundPage(extension->id(), "getLastHookedPath()"));
945}
946
Devlin Cronin242d19d22019-03-12 18:08:48947IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, SWServedBackgroundPageReceivesEvent) {
lazyboy52c3bcf2016-01-08 00:11:29948 const Extension* extension =
Istiaque Ahmed93ff7f42018-08-31 01:42:22949 StartTestFromBackgroundPage("replace_background.js");
lazyboy52c3bcf2016-01-08 00:11:29950 ExtensionHost* background_page =
951 process_manager()->GetBackgroundHostForExtension(extension->id());
952 ASSERT_TRUE(background_page);
953
954 // Close the background page and start it again so that the service worker
955 // will start controlling pages.
956 background_page->Close();
957 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
958 background_page = nullptr;
Peter Kasting341e1fb2018-02-24 00:03:01959 process_manager()->WakeEventPage(extension->id(), base::DoNothing());
lazyboy52c3bcf2016-01-08 00:11:29960 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
961
962 // Since the SW is now controlling the extension, the SW serves the background
963 // script. page.html sends a message to the background script and we verify
964 // that the SW served background script correctly receives the message/event.
965 ExtensionTestMessageListener listener("onMessage/SW BG.", false);
966 listener.set_failure_message("onMessage/original BG.");
967 content::WebContents* web_contents =
968 AddTab(browser(), extension->GetResourceURL("page.html"));
969 ASSERT_TRUE(web_contents);
970 EXPECT_TRUE(listener.WaitUntilSatisfied());
971}
972
Devlin Cronin242d19d22019-03-12 18:08:48973IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, SWServedBackgroundPage) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22974 const Extension* extension = StartTestFromBackgroundPage("fetch.js");
annekao49241182015-08-18 17:14:01975
kalman6f984ae2015-09-18 17:21:58976 std::string kExpectedInnerText = "background.html contents for testing.";
annekao49241182015-08-18 17:14:01977
kalman6f984ae2015-09-18 17:21:58978 // Sanity check that the background page has the expected content.
979 ExtensionHost* background_page =
980 process_manager()->GetBackgroundHostForExtension(extension->id());
981 ASSERT_TRUE(background_page);
982 EXPECT_EQ(kExpectedInnerText,
983 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:01984
kalman6f984ae2015-09-18 17:21:58985 // Close the background page.
986 background_page->Close();
987 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
988 background_page = nullptr;
989
990 // Start it again.
Peter Kasting341e1fb2018-02-24 00:03:01991 process_manager()->WakeEventPage(extension->id(), base::DoNothing());
kalman6f984ae2015-09-18 17:21:58992 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
993
Matt Falkenhagena612fc02018-05-30 00:35:39994 // The service worker should get a fetch event for the background page.
kalman6f984ae2015-09-18 17:21:58995 background_page =
996 process_manager()->GetBackgroundHostForExtension(extension->id());
997 ASSERT_TRUE(background_page);
998 content::WaitForLoadStop(background_page->host_contents());
999
kalman6f984ae2015-09-18 17:21:581000 EXPECT_EQ("Caught a fetch for /background.html",
1001 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:011002}
1003
Devlin Cronin242d19d22019-03-12 18:08:481004IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:581005 ServiceWorkerPostsMessageToBackgroundClient) {
Istiaque Ahmed93ff7f42018-08-31 01:42:221006 const Extension* extension =
1007 StartTestFromBackgroundPage("post_message_to_background_client.js");
annekao533482222015-08-21 23:23:531008
kalman6f984ae2015-09-18 17:21:581009 // The service worker in this test simply posts a message to the background
1010 // client it receives from getBackgroundClient().
1011 const char* kScript =
1012 "var messagePromise = null;\n"
1013 "if (test.lastMessageFromServiceWorker) {\n"
1014 " messagePromise = Promise.resolve(test.lastMessageFromServiceWorker);\n"
1015 "} else {\n"
1016 " messagePromise = test.waitForMessage(navigator.serviceWorker);\n"
1017 "}\n"
1018 "messagePromise.then(function(message) {\n"
1019 " window.domAutomationController.send(String(message == 'success'));\n"
1020 "})\n";
1021 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:531022}
1023
Devlin Cronin242d19d22019-03-12 18:08:481024IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:581025 BackgroundPagePostsMessageToServiceWorker) {
1026 const Extension* extension =
Istiaque Ahmed93ff7f42018-08-31 01:42:221027 StartTestFromBackgroundPage("post_message_to_sw.js");
annekao533482222015-08-21 23:23:531028
kalman6f984ae2015-09-18 17:21:581029 // The service worker in this test waits for a message, then echoes it back
1030 // by posting a message to the background page via getBackgroundClient().
1031 const char* kScript =
1032 "var mc = new MessageChannel();\n"
1033 "test.waitForMessage(mc.port1).then(function(message) {\n"
1034 " window.domAutomationController.send(String(message == 'hello'));\n"
1035 "});\n"
1036 "test.registeredServiceWorker.postMessage(\n"
1037 " {message: 'hello', port: mc.port2}, [mc.port2])\n";
1038 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:531039}
1040
Devlin Cronin242d19d22019-03-12 18:08:481041IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
rdevlin.croninf5863da2015-09-10 19:21:451042 ServiceWorkerSuspensionOnExtensionUnload) {
kalman6f984ae2015-09-18 17:21:581043 // For this test, only hold onto the extension's ID and URL + a function to
1044 // get a resource URL, because we're going to be disabling and uninstalling
1045 // it, which will invalidate the pointer.
1046 std::string extension_id;
1047 GURL extension_url;
1048 {
Istiaque Ahmed93ff7f42018-08-31 01:42:221049 const Extension* extension = StartTestFromBackgroundPage("fetch.js");
kalman6f984ae2015-09-18 17:21:581050 extension_id = extension->id();
1051 extension_url = extension->url();
1052 }
1053 auto get_resource_url = [&extension_url](const std::string& path) {
1054 return Extension::GetResourceURL(extension_url, path);
1055 };
rdevlin.croninf5863da2015-09-10 19:21:451056
kalman6f984ae2015-09-18 17:21:581057 // Fetch should route to the service worker.
1058 EXPECT_EQ("Caught a fetch for /index.html",
1059 NavigateAndExtractInnerText(get_resource_url("index.html")));
rdevlin.croninf5863da2015-09-10 19:21:451060
kalman6f984ae2015-09-18 17:21:581061 // Disable the extension. Opening the page should fail.
1062 extension_service()->DisableExtension(extension_id,
Minh X. Nguyen45479012017-08-18 21:35:361063 disable_reason::DISABLE_USER_ACTION);
rdevlin.croninf5863da2015-09-10 19:21:451064 base::RunLoop().RunUntilIdle();
rdevlin.croninf5863da2015-09-10 19:21:451065
kalman6f984ae2015-09-18 17:21:581066 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1067 NavigateAndGetPageType(get_resource_url("index.html")));
1068 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1069 NavigateAndGetPageType(get_resource_url("other.html")));
1070
1071 // Re-enable the extension. Opening pages should immediately start to succeed
1072 // again.
rdevlin.croninf5863da2015-09-10 19:21:451073 extension_service()->EnableExtension(extension_id);
1074 base::RunLoop().RunUntilIdle();
1075
kalman6f984ae2015-09-18 17:21:581076 EXPECT_EQ("Caught a fetch for /index.html",
1077 NavigateAndExtractInnerText(get_resource_url("index.html")));
1078 EXPECT_EQ("Caught a fetch for /other.html",
1079 NavigateAndExtractInnerText(get_resource_url("other.html")));
1080 EXPECT_EQ("Caught a fetch for /another.html",
1081 NavigateAndExtractInnerText(get_resource_url("another.html")));
rdevlin.croninf5863da2015-09-10 19:21:451082
kalman6f984ae2015-09-18 17:21:581083 // Uninstall the extension. Opening pages should fail again.
1084 base::string16 error;
1085 extension_service()->UninstallExtension(
Devlin Cronin218df7f2017-11-21 21:41:311086 extension_id, UninstallReason::UNINSTALL_REASON_FOR_TESTING, &error);
kalman6f984ae2015-09-18 17:21:581087 base::RunLoop().RunUntilIdle();
1088
1089 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1090 NavigateAndGetPageType(get_resource_url("index.html")));
1091 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1092 NavigateAndGetPageType(get_resource_url("other.html")));
1093 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1094 NavigateAndGetPageType(get_resource_url("anotherother.html")));
1095 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1096 NavigateAndGetPageType(get_resource_url("final.html")));
1097}
1098
Devlin Cronin242d19d22019-03-12 18:08:481099IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, BackgroundPageIsWokenIfAsleep) {
Istiaque Ahmed93ff7f42018-08-31 01:42:221100 const Extension* extension = StartTestFromBackgroundPage("wake_on_fetch.js");
kalman6f984ae2015-09-18 17:21:581101
1102 // Navigate to special URLs that this test's service worker recognises, each
1103 // making a check then populating the response with either "true" or "false".
1104 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
1105 "background-client-is-awake")));
1106 EXPECT_EQ("true", NavigateAndExtractInnerText(
1107 extension->GetResourceURL("ping-background-client")));
1108 // Ping more than once for good measure.
1109 EXPECT_EQ("true", NavigateAndExtractInnerText(
1110 extension->GetResourceURL("ping-background-client")));
1111
1112 // Shut down the event page. The SW should detect that it's closed, but still
1113 // be able to ping it.
1114 ExtensionHost* background_page =
1115 process_manager()->GetBackgroundHostForExtension(extension->id());
1116 ASSERT_TRUE(background_page);
1117 background_page->Close();
1118 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
1119
1120 EXPECT_EQ("false", NavigateAndExtractInnerText(extension->GetResourceURL(
1121 "background-client-is-awake")));
1122 EXPECT_EQ("true", NavigateAndExtractInnerText(
1123 extension->GetResourceURL("ping-background-client")));
1124 EXPECT_EQ("true", NavigateAndExtractInnerText(
1125 extension->GetResourceURL("ping-background-client")));
1126 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
1127 "background-client-is-awake")));
1128}
1129
Devlin Cronin242d19d22019-03-12 18:08:481130IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:581131 GetBackgroundClientFailsWithNoBackgroundPage) {
1132 // This extension doesn't have a background page, only a tab at page.html.
1133 // The service worker it registers tries to call getBackgroundClient() and
1134 // should fail.
1135 // Note that this also tests that service workers can be registered from tabs.
1136 EXPECT_TRUE(RunExtensionSubtest("service_worker/no_background", "page.html"));
rdevlin.croninf5863da2015-09-10 19:21:451137}
1138
Devlin Cronin242d19d22019-03-12 18:08:481139IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, NotificationAPI) {
lazyboy6ddb7d62015-11-10 23:15:271140 EXPECT_TRUE(RunExtensionSubtest("service_worker/notifications/has_permission",
1141 "page.html"));
1142}
1143
Devlin Cronin242d19d22019-03-12 18:08:481144IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, WebAccessibleResourcesFetch) {
lazyboyaea32c22016-01-04 21:37:071145 EXPECT_TRUE(RunExtensionSubtest(
1146 "service_worker/web_accessible_resources/fetch/", "page.html"));
1147}
1148
David Bertoni9026eff2019-05-01 18:04:311149// Tests that updating a packed extension with modified scripts works
1150// properly -- we expect that the new script will execute, rather than the
1151// previous one.
1152IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, UpdatePackedExtension) {
1153 // Extensions APIs from SW are only enabled on trunk.
1154 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1155 constexpr char kManifest1[] =
1156 R"({
1157 "name": "Test Extension",
1158 "manifest_version": 2,
1159 "version": "0.1",
1160 "background": {"service_worker": "script.js"}
1161 })";
David Bertoni353f0fb42019-05-30 15:53:301162 constexpr char kNewVersionString[] = "0.2";
1163
David Bertoni9026eff2019-05-01 18:04:311164 // This script installs an event listener for updates to the extension with
1165 // a callback that forces itself to reload.
David Bertoni353f0fb42019-05-30 15:53:301166 constexpr char kScript1[] =
David Bertoni9026eff2019-05-01 18:04:311167 R"(
1168 chrome.runtime.onUpdateAvailable.addListener(function(details) {
David Bertoni353f0fb42019-05-30 15:53:301169 chrome.test.assertEq('%s', details.version);
David Bertoni9026eff2019-05-01 18:04:311170 chrome.runtime.reload();
1171 });
1172 chrome.test.sendMessage('ready1');
1173 )";
1174
1175 std::string id;
1176 TestExtensionDir test_dir;
1177
1178 // Write the manifest and script files and load the extension.
1179 test_dir.WriteManifest(kManifest1);
David Bertoni353f0fb42019-05-30 15:53:301180 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"),
1181 base::StringPrintf(kScript1, kNewVersionString));
David Bertoni9026eff2019-05-01 18:04:311182
1183 {
1184 ExtensionTestMessageListener ready_listener("ready1", false);
1185 base::FilePath path = test_dir.Pack();
1186 const Extension* extension = LoadExtension(path);
1187 ASSERT_TRUE(extension);
1188
1189 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
1190 id = extension->id();
1191 }
1192
1193 constexpr char kManifest2[] =
1194 R"({
1195 "name": "Test Extension",
1196 "manifest_version": 2,
David Bertoni353f0fb42019-05-30 15:53:301197 "version": "%s",
David Bertoni9026eff2019-05-01 18:04:311198 "background": {"service_worker": "script.js"}
1199 })";
David Bertoni353f0fb42019-05-30 15:53:301200 constexpr char kScript2[] =
1201 R"(
1202 chrome.runtime.onInstalled.addListener(function(details) {
1203 chrome.test.assertEq('update', details.reason);
1204 chrome.test.sendMessage('onInstalled');
1205 });
1206 chrome.test.sendMessage('ready2');
1207 )";
David Bertoni9026eff2019-05-01 18:04:311208 // Rewrite the manifest and script files with a version change in the manifest
1209 // file. After reloading the extension, the old version of the extension
1210 // should detect the update, force the reload, and the new script should
1211 // execute.
David Bertoni353f0fb42019-05-30 15:53:301212 test_dir.WriteManifest(base::StringPrintf(kManifest2, kNewVersionString));
1213 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"), kScript2);
David Bertoni9026eff2019-05-01 18:04:311214 {
1215 ExtensionTestMessageListener ready_listener("ready2", false);
David Bertoni353f0fb42019-05-30 15:53:301216 ExtensionTestMessageListener on_installed_listener("onInstalled", false);
David Bertoni9026eff2019-05-01 18:04:311217 base::FilePath path = test_dir.Pack();
1218 ExtensionService* const extension_service =
1219 ExtensionSystem::Get(profile())->extension_service();
1220 EXPECT_TRUE(extension_service->UpdateExtension(
1221 CRXFileInfo(id, GetTestVerifierFormat(), path), true, nullptr));
1222 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
1223 EXPECT_EQ("0.2", ExtensionRegistry::Get(profile())
1224 ->enabled_extensions()
1225 .GetByID(id)
1226 ->version()
1227 .GetString());
David Bertoni353f0fb42019-05-30 15:53:301228 EXPECT_TRUE(on_installed_listener.WaitUntilSatisfied());
David Bertoni9026eff2019-05-01 18:04:311229 }
1230}
1231
David Bertoni1d646a152019-04-25 02:09:221232// Tests that updating an unpacked extension with modified scripts works
1233// properly -- we expect that the new script will execute, rather than the
1234// previous one.
1235IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, UpdateUnpackedExtension) {
1236 // Extensions APIs from SW are only enabled on trunk.
1237 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1238 constexpr char kManifest1[] =
1239 R"({
1240 "name": "Test Extension",
1241 "manifest_version": 2,
1242 "version": "0.1",
1243 "background": {"service_worker": "script.js"}
1244 })";
1245 constexpr char kManifest2[] =
1246 R"({
1247 "name": "Test Extension",
1248 "manifest_version": 2,
1249 "version": "0.2",
1250 "background": {"service_worker": "script.js"}
1251 })";
David Bertoni353f0fb42019-05-30 15:53:301252 constexpr char kScript[] =
1253 R"(
1254 chrome.runtime.onInstalled.addListener(function(details) {
1255 chrome.test.assertEq('%s', details.reason);
1256 chrome.test.sendMessage('onInstalled');
1257 });
1258 chrome.test.sendMessage('%s');
1259 )";
David Bertoni1d646a152019-04-25 02:09:221260
1261 std::string id;
1262
1263 ExtensionService* const extension_service =
1264 ExtensionSystem::Get(profile())->extension_service();
1265 scoped_refptr<UnpackedInstaller> installer =
1266 UnpackedInstaller::Create(extension_service);
1267
1268 // Set a completion callback so we can get the ID of the extension.
1269 installer->set_completion_callback(base::BindLambdaForTesting(
1270 [&id](const Extension* extension, const base::FilePath& path,
1271 const std::string& error) {
1272 ASSERT_TRUE(extension);
1273 ASSERT_TRUE(error.empty());
1274 id = extension->id();
1275 }));
1276
1277 TestExtensionDir test_dir;
1278
1279 // Write the manifest and script files and load the extension.
1280 test_dir.WriteManifest(kManifest1);
1281 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"),
David Bertoni353f0fb42019-05-30 15:53:301282 base::StringPrintf(kScript, "install", "ready1"));
David Bertoni1d646a152019-04-25 02:09:221283 {
1284 ExtensionTestMessageListener ready_listener("ready1", false);
David Bertoni353f0fb42019-05-30 15:53:301285 ExtensionTestMessageListener on_installed_listener("onInstalled", false);
David Bertoni1d646a152019-04-25 02:09:221286
1287 installer->Load(test_dir.UnpackedPath());
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 ASSERT_FALSE(id.empty());
1291 }
1292
1293 // Rewrite the script file without a version change in the manifest and reload
1294 // the extension. The new script should execute.
1295 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"),
David Bertoni353f0fb42019-05-30 15:53:301296 base::StringPrintf(kScript, "update", "ready2"));
David Bertoni1d646a152019-04-25 02:09:221297 {
1298 ExtensionTestMessageListener ready_listener("ready2", 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 // Rewrite the manifest and script files with a version change in the manifest
1307 // file. After reloading the extension, the new script should execute.
1308 test_dir.WriteManifest(kManifest2);
1309 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"),
David Bertoni353f0fb42019-05-30 15:53:301310 base::StringPrintf(kScript, "update", "ready3"));
David Bertoni1d646a152019-04-25 02:09:221311 {
1312 ExtensionTestMessageListener ready_listener("ready3", false);
David Bertoni353f0fb42019-05-30 15:53:301313 ExtensionTestMessageListener on_installed_listener("onInstalled", false);
David Bertoni1d646a152019-04-25 02:09:221314
1315 extension_service->ReloadExtension(id);
1316 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
David Bertoni353f0fb42019-05-30 15:53:301317 EXPECT_TRUE(on_installed_listener.WaitUntilSatisfied());
David Bertoni1d646a152019-04-25 02:09:221318 }
1319}
1320
lazyboy4c82177a2016-10-18 00:04:091321// Tests that worker ref count increments while extension API function is
1322// active.
Devlin Cronin242d19d22019-03-12 18:08:481323IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, WorkerRefCount) {
lazyboy4c82177a2016-10-18 00:04:091324 // Extensions APIs from SW are only enabled on trunk.
1325 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1326 const Extension* extension = LoadExtensionWithFlags(
1327 test_data_dir_.AppendASCII("service_worker/api_worker_ref_count"),
1328 kFlagNone);
1329 ASSERT_TRUE(extension);
1330 ui_test_utils::NavigateToURL(browser(),
1331 extension->GetResourceURL("page.html"));
1332 content::WebContents* web_contents =
1333 browser()->tab_strip_model()->GetActiveWebContents();
1334
1335 ExtensionTestMessageListener worker_start_listener("WORKER STARTED", false);
1336 worker_start_listener.set_failure_message("FAILURE");
1337 ASSERT_TRUE(
1338 content::ExecuteScript(web_contents, "window.runServiceWorker()"));
1339 ASSERT_TRUE(worker_start_listener.WaitUntilSatisfied());
1340
1341 // Service worker should have no pending requests because it hasn't peformed
1342 // any extension API request yet.
1343 EXPECT_EQ(0u, GetWorkerRefCount(extension->url()));
1344
1345 ExtensionTestMessageListener worker_listener("CHECK_REF_COUNT", true);
1346 worker_listener.set_failure_message("FAILURE");
1347 ASSERT_TRUE(content::ExecuteScript(web_contents, "window.testSendMessage()"));
1348 ASSERT_TRUE(worker_listener.WaitUntilSatisfied());
1349
1350 // Service worker should have exactly one pending request because
1351 // chrome.test.sendMessage() API call is in-flight.
1352 EXPECT_EQ(1u, GetWorkerRefCount(extension->url()));
1353
1354 // Peform another extension API request while one is ongoing.
1355 {
1356 ExtensionTestMessageListener listener("CHECK_REF_COUNT", true);
1357 listener.set_failure_message("FAILURE");
1358 ASSERT_TRUE(
1359 content::ExecuteScript(web_contents, "window.testSendMessage()"));
1360 ASSERT_TRUE(listener.WaitUntilSatisfied());
1361
1362 // Service worker currently has two extension API requests in-flight.
1363 EXPECT_EQ(2u, GetWorkerRefCount(extension->url()));
1364 // Finish executing the nested chrome.test.sendMessage() first.
1365 listener.Reply("Hello world");
1366 }
1367
Istiaque Ahmedb57c9752017-08-20 19:08:571368 ExtensionTestMessageListener worker_completion_listener("SUCCESS_FROM_WORKER",
1369 false);
lazyboy4c82177a2016-10-18 00:04:091370 // Finish executing chrome.test.sendMessage().
1371 worker_listener.Reply("Hello world");
Istiaque Ahmedb57c9752017-08-20 19:08:571372 EXPECT_TRUE(worker_completion_listener.WaitUntilSatisfied());
1373
1374 // The following block makes sure we have received all the IPCs related to
1375 // ref-count from the worker.
1376 {
1377 // The following roundtrip:
1378 // browser->extension->worker->extension->browser
1379 // will ensure that the worker sent the relevant ref count IPCs.
1380 std::string result;
1381 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1382 web_contents, "window.roundtripToWorker();", &result));
1383 EXPECT_EQ("roundtrip-succeeded", result);
1384
1385 // Ensure IO thread IPCs run.
Gabriel Charette01507a22017-09-27 21:30:081386 content::RunAllTasksUntilIdle();
Istiaque Ahmedb57c9752017-08-20 19:08:571387 }
lazyboy4c82177a2016-10-18 00:04:091388
1389 // The ref count should drop to 0.
1390 EXPECT_EQ(0u, GetWorkerRefCount(extension->url()));
1391}
1392
lazyboyaea32c22016-01-04 21:37:071393// This test loads a web page that has an iframe pointing to a
1394// chrome-extension:// URL. The URL is listed in the extension's
1395// web_accessible_resources. Initially the iframe is served from the extension's
1396// resource file. After verifying that, we register a Service Worker that
1397// controls the extension. Further requests to the same resource as before
1398// should now be served by the Service Worker.
1399// This test also verifies that if the requested resource exists in the manifest
1400// but is not present in the extension directory, the Service Worker can still
1401// serve the resource file.
Devlin Cronin242d19d22019-03-12 18:08:481402IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, WebAccessibleResourcesIframeSrc) {
lazyboyaea32c22016-01-04 21:37:071403 const Extension* extension = LoadExtensionWithFlags(
1404 test_data_dir_.AppendASCII(
1405 "service_worker/web_accessible_resources/iframe_src"),
1406 kFlagNone);
1407 ASSERT_TRUE(extension);
1408 ASSERT_TRUE(StartEmbeddedTestServer());
falkenad185092016-06-16 06:10:021409
1410 // Service workers can only control secure contexts
1411 // (https://w3c.github.io/webappsec-secure-contexts/). For documents, this
1412 // typically means the document must have a secure origin AND all its ancestor
1413 // frames must have documents with secure origins. However, extension pages
1414 // are considered secure, even if they have an ancestor document that is an
1415 // insecure context (see GetSchemesBypassingSecureContextCheckWhitelist). So
1416 // extension service workers must be able to control an extension page
1417 // embedded in an insecure context. To test this, set up an insecure
1418 // (non-localhost, non-https) URL for the web page. This page will create
1419 // iframes that load extension pages that must be controllable by service
1420 // worker.
falkenad185092016-06-16 06:10:021421 GURL page_url =
1422 embedded_test_server()->GetURL("a.com",
1423 "/extensions/api_test/service_worker/"
1424 "web_accessible_resources/webpage.html");
1425 EXPECT_FALSE(content::IsOriginSecure(page_url));
lazyboyaea32c22016-01-04 21:37:071426
1427 content::WebContents* web_contents = AddTab(browser(), page_url);
1428 std::string result;
1429 // webpage.html will create an iframe pointing to a resource from |extension|.
1430 // Expect the resource to be served by the extension.
1431 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1432 web_contents, base::StringPrintf("window.testIframe('%s', 'iframe.html')",
1433 extension->id().c_str()),
1434 &result));
1435 EXPECT_EQ("FROM_EXTENSION_RESOURCE", result);
1436
1437 ExtensionTestMessageListener service_worker_ready_listener("SW_READY", false);
1438 EXPECT_TRUE(ExecuteScriptInBackgroundPageNoWait(
1439 extension->id(), "window.registerServiceWorker()"));
1440 EXPECT_TRUE(service_worker_ready_listener.WaitUntilSatisfied());
1441
1442 result.clear();
1443 // webpage.html will create another iframe pointing to a resource from
1444 // |extension| as before. But this time, the resource should be be served
1445 // from the Service Worker.
1446 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1447 web_contents, base::StringPrintf("window.testIframe('%s', 'iframe.html')",
1448 extension->id().c_str()),
1449 &result));
1450 EXPECT_EQ("FROM_SW_RESOURCE", result);
1451
1452 result.clear();
1453 // webpage.html will create yet another iframe pointing to a resource that
1454 // exists in the extension manifest's web_accessible_resources, but is not
1455 // present in the extension directory. Expect the resources of the iframe to
1456 // be served by the Service Worker.
1457 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1458 web_contents,
1459 base::StringPrintf("window.testIframe('%s', 'iframe_non_existent.html')",
1460 extension->id().c_str()),
1461 &result));
1462 EXPECT_EQ("FROM_SW_RESOURCE", result);
1463}
1464
Devlin Cronin242d19d22019-03-12 18:08:481465IN_PROC_BROWSER_TEST_F(ServiceWorkerBackgroundSyncTest, Sync) {
lazyboybd325ae2015-11-18 21:35:261466 const Extension* extension = LoadExtensionWithFlags(
1467 test_data_dir_.AppendASCII("service_worker/sync"), kFlagNone);
1468 ASSERT_TRUE(extension);
1469 ui_test_utils::NavigateToURL(browser(),
1470 extension->GetResourceURL("page.html"));
1471 content::WebContents* web_contents =
1472 browser()->tab_strip_model()->GetActiveWebContents();
1473
1474 // Prevent firing by going offline.
1475 content::background_sync_test_util::SetOnline(web_contents, false);
1476
1477 ExtensionTestMessageListener sync_listener("SYNC: send-chats", false);
1478 sync_listener.set_failure_message("FAIL");
1479
1480 std::string result;
1481 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
1482 web_contents, "window.runServiceWorker()", &result));
1483 ASSERT_EQ("SERVICE_WORKER_READY", result);
1484
1485 EXPECT_FALSE(sync_listener.was_satisfied());
1486 // Resume firing by going online.
1487 content::background_sync_test_util::SetOnline(web_contents, true);
1488 EXPECT_TRUE(sync_listener.WaitUntilSatisfied());
1489}
1490
Devlin Cronin242d19d22019-03-12 18:08:481491IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
horo1eeddde2015-11-19 05:59:251492 FetchFromContentScriptShouldNotGoToServiceWorkerOfPage) {
1493 ASSERT_TRUE(StartEmbeddedTestServer());
1494 GURL page_url = embedded_test_server()->GetURL(
1495 "/extensions/api_test/service_worker/content_script_fetch/"
1496 "controlled_page/index.html");
1497 content::WebContents* tab =
1498 browser()->tab_strip_model()->GetActiveWebContents();
1499 ui_test_utils::NavigateToURL(browser(), page_url);
1500 content::WaitForLoadStop(tab);
1501
1502 std::string value;
1503 ASSERT_TRUE(
1504 content::ExecuteScriptAndExtractString(tab, "register();", &value));
1505 EXPECT_EQ("SW controlled", value);
1506
1507 ASSERT_TRUE(RunExtensionTest("service_worker/content_script_fetch"))
1508 << message_;
1509}
1510
Devlin Cronin242d19d22019-03-12 18:08:481511IN_PROC_BROWSER_TEST_F(ServiceWorkerPushMessagingTest, OnPush) {
lazyboy561b7de2015-11-19 19:27:301512 const Extension* extension = LoadExtensionWithFlags(
1513 test_data_dir_.AppendASCII("service_worker/push_messaging"), kFlagNone);
1514 ASSERT_TRUE(extension);
1515 GURL extension_url = extension->url();
1516
Peter Beverloodd4ef1e2018-06-21 15:41:041517 GrantNotificationPermissionForTest(extension_url);
lazyboy561b7de2015-11-19 19:27:301518
1519 GURL url = extension->GetResourceURL("page.html");
1520 ui_test_utils::NavigateToURL(browser(), url);
1521
1522 content::WebContents* web_contents =
1523 browser()->tab_strip_model()->GetActiveWebContents();
1524
1525 // Start the ServiceWorker.
1526 ExtensionTestMessageListener ready_listener("SERVICE_WORKER_READY", false);
1527 ready_listener.set_failure_message("SERVICE_WORKER_FAILURE");
1528 const char* kScript = "window.runServiceWorker()";
1529 EXPECT_TRUE(content::ExecuteScript(web_contents->GetMainFrame(), kScript));
1530 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
1531
1532 PushMessagingAppIdentifier app_identifier =
1533 GetAppIdentifierForServiceWorkerRegistration(0LL, extension_url);
johnmea5045732016-09-08 17:23:291534 ASSERT_EQ(app_identifier.app_id(), gcm_driver()->last_gettoken_app_id());
1535 EXPECT_EQ("1234567890", gcm_driver()->last_gettoken_authorized_entity());
lazyboy561b7de2015-11-19 19:27:301536
lazyboyd429e2582016-05-20 20:18:521537 base::RunLoop run_loop;
lazyboy561b7de2015-11-19 19:27:301538 // Send a push message via gcm and expect the ServiceWorker to receive it.
1539 ExtensionTestMessageListener push_message_listener("OK", false);
1540 push_message_listener.set_failure_message("FAIL");
1541 gcm::IncomingMessage message;
1542 message.sender_id = "1234567890";
1543 message.raw_data = "testdata";
1544 message.decrypted = true;
lazyboyd429e2582016-05-20 20:18:521545 push_service()->SetMessageCallbackForTesting(run_loop.QuitClosure());
lazyboy561b7de2015-11-19 19:27:301546 push_service()->OnMessage(app_identifier.app_id(), message);
1547 EXPECT_TRUE(push_message_listener.WaitUntilSatisfied());
lazyboyd429e2582016-05-20 20:18:521548 run_loop.Run(); // Wait until the message is handled by push service.
lazyboy561b7de2015-11-19 19:27:301549}
Devlin Cronin242d19d22019-03-12 18:08:481550IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, MimeHandlerView) {
Rob Wue89b90032018-02-16 19:46:081551 ASSERT_TRUE(RunExtensionTest("service_worker/mime_handler_view"));
1552}
1553
David Bertoni22aeae52019-06-10 22:42:531554// An observer to block on service worker registration stored.
1555class RegistrationStoredObserver
1556 : public content::ServiceWorkerContextObserver {
1557 public:
1558 RegistrationStoredObserver(content::ServiceWorkerContext* context,
1559 base::OnceClosure callback)
1560 : context_(context), registered_callback_(std::move(callback)) {
1561 context_->AddObserver(this);
1562 }
1563
1564 ~RegistrationStoredObserver() override {
1565 if (context_) {
1566 context_->RemoveObserver(this);
1567 }
1568 }
1569
1570 void OnRegistrationStored(int64_t registration_id,
1571 const GURL& scope) override {
1572 if (scope.SchemeIs(kExtensionScheme)) {
1573 std::move(registered_callback_).Run();
1574 }
1575 }
1576
1577 void OnDestruct(content::ServiceWorkerContext* context) override {
1578 context_ = nullptr;
1579 }
1580
1581 private:
1582 content::ServiceWorkerContext* context_;
1583 base::OnceClosure registered_callback_;
1584};
1585
1586IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
1587 EventsToStoppedWorker) {
1588 content::StoragePartition* storage_partition =
1589 content::BrowserContext::GetDefaultStoragePartition(browser()->profile());
1590 content::ServiceWorkerContext* context =
1591 storage_partition->GetServiceWorkerContext();
1592
1593 // Set up an observer to wait for the registration to be stored.
1594 base::RunLoop registration_loop;
1595 RegistrationStoredObserver observer(context, registration_loop.QuitClosure());
1596
1597 ExtensionTestMessageListener event_listener_added("ready", false);
1598 event_listener_added.set_failure_message("ERROR");
1599 const Extension* extension = LoadExtensionWithFlags(
1600 test_data_dir_.AppendASCII(
1601 "service_worker/worker_based_background/events_to_stopped_worker"),
1602 kFlagNone);
1603 ASSERT_TRUE(extension);
1604
1605 // Wait for service worker registration to be stored.
1606 registration_loop.Run();
1607 EXPECT_TRUE(event_listener_added.WaitUntilSatisfied());
1608
1609 // Stop the service worker.
1610 {
1611 base::RunLoop run_loop;
1612 // The service worker is registered at the root scope.
1613 content::StopServiceWorkerForScope(context, extension->url(),
1614 run_loop.QuitClosure());
1615 run_loop.Run();
1616 }
1617
1618 // Navigate to a URL, which should wake up the service worker.
1619 ExtensionTestMessageListener finished_listener("finished", false);
1620 ui_test_utils::NavigateToURL(browser(),
1621 extension->GetResourceURL("page.html"));
1622 EXPECT_TRUE(finished_listener.WaitUntilSatisfied());
1623}
1624
Devlin Cronin242d19d22019-03-12 18:08:481625IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
Istiaque Ahmedd4b67ee2019-03-02 10:53:201626 ProcessManagerRegistrationOnShutdown) {
1627 // Note that StopServiceWorkerForScope call below expects the worker to be
1628 // completely installed, so wait for the |extension| worker to see "activate"
1629 // event.
1630 ExtensionTestMessageListener activated_listener("WORKER_ACTIVATED", false);
1631 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
1632 "service_worker/worker_based_background/process_manager"));
1633 ASSERT_TRUE(extension);
1634 EXPECT_TRUE(activated_listener.WaitUntilSatisfied());
1635
1636 base::Optional<WorkerId> worker_id =
1637 GetUniqueRunningWorkerId(extension->id());
1638 ASSERT_TRUE(worker_id);
1639 {
1640 // Shutdown the worker.
1641 // TODO(lazyboy): Ideally we'd want to test worker shutdown on idle, do that
1642 // once //content API allows to override test timeouts for Service Workers.
1643 base::RunLoop run_loop;
1644 content::StoragePartition* storage_partition =
1645 content::BrowserContext::GetDefaultStoragePartition(
1646 browser()->profile());
1647 GURL scope = extension->url();
1648 content::StopServiceWorkerForScope(
1649 storage_partition->GetServiceWorkerContext(),
1650 // The service worker is registered at the top level scope.
1651 extension->url(), run_loop.QuitClosure());
1652 run_loop.Run();
1653 }
1654
1655 EXPECT_FALSE(ProcessManager::Get(profile())->HasServiceWorker(*worker_id));
1656}
1657
Devlin Cronin242d19d22019-03-12 18:08:481658IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
Istiaque Ahmedd4b67ee2019-03-02 10:53:201659 ProcessManagerRegistrationOnTerminate) {
1660 // NOTE: It is not necessary to wait for "activate" event from the worker
1661 // for this test, but we're lazily reusing the extension from
1662 // ProcessManagerRegistrationOnShutdown test.
1663 ExtensionTestMessageListener activated_listener("WORKER_ACTIVATED", false);
1664 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
1665 "service_worker/worker_based_background/process_manager"));
1666 ASSERT_TRUE(extension);
1667 EXPECT_TRUE(activated_listener.WaitUntilSatisfied());
1668
1669 base::Optional<WorkerId> worker_id =
1670 GetUniqueRunningWorkerId(extension->id());
1671 ASSERT_TRUE(worker_id);
1672 {
1673 // Terminate worker's RenderProcessHost.
1674 content::RenderProcessHost* worker_render_process_host =
1675 content::RenderProcessHost::FromID(worker_id->render_process_id);
1676 ASSERT_TRUE(worker_render_process_host);
1677 content::RenderProcessHostWatcher process_exit_observer(
1678 worker_render_process_host,
1679 content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1680 worker_render_process_host->Shutdown(content::RESULT_CODE_KILLED);
1681 process_exit_observer.Wait();
1682 }
1683
1684 EXPECT_FALSE(ProcessManager::Get(profile())->HasServiceWorker(*worker_id));
1685}
1686
David Bertoni1dc1b7a2019-06-13 02:44:591687IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, UninstallSelf) {
1688 constexpr char kManifest[] =
1689 R"({
1690 "name": "Test Extension",
1691 "manifest_version": 2,
1692 "version": "0.1",
1693 "background": {"service_worker": "script.js"}
1694 })";
1695
1696 // This script uninstalls itself.
1697 constexpr char kScript[] =
1698 "chrome.management.uninstallSelf({showConfirmDialog: false});";
1699
1700 TestExtensionDir test_dir;
1701
1702 test_dir.WriteManifest(kManifest);
1703 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"), kScript);
1704
David Bertoni67977a32019-06-13 22:46:011705 // Construct this before loading the extension, since the extension will
David Bertoni1dc1b7a2019-06-13 02:44:591706 // immediately uninstall itself when it loads.
1707 extensions::TestExtensionRegistryObserver observer(
1708 extensions::ExtensionRegistry::Get(browser()->profile()));
1709
1710 base::FilePath path = test_dir.Pack();
1711 scoped_refptr<const Extension> extension = LoadExtension(path);
1712
1713 EXPECT_EQ(extension, observer.WaitForExtensionUninstalled());
1714}
1715
David Bertoni4d9cf41d2019-06-04 00:06:221716IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
1717 PRE_EventsAfterRestart) {
1718 ExtensionTestMessageListener event_added_listener("ready", false);
1719 const Extension* extension = LoadExtensionWithFlags(
1720 test_data_dir_.AppendASCII(
1721 "service_worker/worker_based_background/events_to_stopped_extension"),
1722 kFlagNone);
1723 ASSERT_TRUE(extension);
1724 EXPECT_EQ(kTestExtensionId, extension->id());
1725 ProcessManager* pm = ProcessManager::Get(browser()->profile());
1726 // TODO(crbug.com/969884): This will break once keep alive counts
1727 // for service workers are tracked by the Process Manager.
1728 EXPECT_LT(pm->GetLazyKeepaliveCount(extension), 1);
1729 EXPECT_TRUE(pm->GetLazyKeepaliveActivities(extension).empty());
1730 EXPECT_TRUE(event_added_listener.WaitUntilSatisfied());
1731}
1732
1733// After browser restarts, this test step ensures that opening a tab fires
1734// tabs.onCreated event listener to the extension without explicitly loading the
1735// extension. This is because the extension registered a listener for
1736// tabs.onMoved before browser restarted in PRE_EventsAfterRestart.
1737IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, EventsAfterRestart) {
1738 // Verify there is no RenderProcessHost for the extension.
David Bertoni023e0ec2019-06-10 17:28:221739 EXPECT_FALSE(ExtensionHasRenderProcessHost(kTestExtensionId));
David Bertoni4d9cf41d2019-06-04 00:06:221740
1741 ExtensionTestMessageListener moved_tab_listener("moved-tab", false);
1742 // Add a tab, then move it.
1743 content::WebContents* new_web_contents =
1744 AddTab(browser(), GURL(url::kAboutBlankURL));
1745 EXPECT_TRUE(new_web_contents);
1746 browser()->tab_strip_model()->MoveWebContentsAt(
1747 browser()->tab_strip_model()->count() - 1, 0, false);
1748 EXPECT_TRUE(moved_tab_listener.WaitUntilSatisfied());
1749}
1750
Istiaque Ahmed1e59aec2019-06-05 22:40:241751IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, TabsOnCreated) {
1752 ASSERT_TRUE(RunExtensionTestWithFlags("tabs/lazy_background_on_created",
1753 kFlagRunAsServiceWorkerBasedExtension))
1754 << message_;
1755}
1756
David Bertoni023e0ec2019-06-10 17:28:221757IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
1758 PRE_FilteredEventsAfterRestart) {
1759 ExtensionTestMessageListener listener_added("ready", false);
1760 const Extension* extension = LoadExtensionWithFlags(
1761 test_data_dir_.AppendASCII("service_worker/worker_based_background/"
1762 "filtered_events_after_restart"),
1763 kFlagNone);
1764 ASSERT_TRUE(extension);
1765 EXPECT_EQ(kTestExtensionId, extension->id());
1766 ProcessManager* pm = ProcessManager::Get(browser()->profile());
1767 // TODO(crbug.com/969884): This will break once keep alive counts
1768 // for service workers are tracked by the Process Manager.
1769 EXPECT_LT(pm->GetLazyKeepaliveCount(extension), 1);
1770 EXPECT_TRUE(pm->GetLazyKeepaliveActivities(extension).empty());
1771 EXPECT_TRUE(listener_added.WaitUntilSatisfied());
1772}
1773
1774// After browser restarts, this test step ensures that opening a tab fires
1775// tabs.onCreated event listener to the extension without explicitly loading the
1776// extension. This is because the extension registered a listener for
1777// tabs.onMoved before browser restarted in PRE_EventsAfterRestart.
1778IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
1779 FilteredEventsAfterRestart) {
1780 // Verify there is no RenderProcessHost for the extension.
1781 // TODO(crbug.com/971309): This is currently broken because the test
1782 // infrastructure opens a tab, which dispatches an event to our
1783 // extension, even though the filter doesn't include that URL. The
1784 // referenced bug is about moving filtering into the EventRouter so they
1785 // get filtered before being dispatched.
1786 EXPECT_TRUE(ExtensionHasRenderProcessHost(kTestExtensionId));
1787
1788 // Create a tab to a.html, expect it to navigate to b.html. The service worker
1789 // will see two webNavigation.onCommitted events.
1790 GURL page_url = embedded_test_server()->GetURL(
1791 "/extensions/api_test/service_worker/worker_based_background/"
1792 "filtered_events_after_restart/"
1793 "a.html");
1794 ExtensionTestMessageListener worker_filtered_event_listener(
1795 "PASS_FROM_WORKER", false);
1796 worker_filtered_event_listener.set_failure_message("FAIL_FROM_WORKER");
1797 content::WebContents* web_contents = AddTab(browser(), page_url);
1798 EXPECT_TRUE(web_contents);
1799 EXPECT_TRUE(worker_filtered_event_listener.WaitUntilSatisfied());
1800}
1801
Devlin Cronin59551d82019-03-05 01:28:591802// Tests that console messages logged by extension service workers, both via
1803// the typical console.* methods and via our custom bindings console, are
1804// passed through the normal ServiceWorker console messaging and are
1805// observable.
Devlin Cronin242d19d22019-03-12 18:08:481806IN_PROC_BROWSER_TEST_F(ServiceWorkerLazyBackgroundTest, ConsoleLogging) {
Devlin Cronin59551d82019-03-05 01:28:591807 // A helper class to wait for a particular message to be logged from a
1808 // ServiceWorker.
1809 class ConsoleMessageObserver : public content::ServiceWorkerContextObserver {
1810 public:
1811 ConsoleMessageObserver(content::BrowserContext* browser_context,
1812 const std::string& expected_message)
1813 : expected_message_(base::UTF8ToUTF16(expected_message)),
1814 scoped_observer_(this) {
1815 content::StoragePartition* partition =
1816 content::BrowserContext::GetDefaultStoragePartition(browser_context);
1817 scoped_observer_.Add(partition->GetServiceWorkerContext());
1818 }
1819 ~ConsoleMessageObserver() override = default;
1820
1821 void Wait() { run_loop_.Run(); }
1822
1823 private:
1824 // ServiceWorkerContextObserver:
1825 void OnReportConsoleMessage(
1826 int64_t version_id,
1827 const content::ConsoleMessage& message) override {
1828 // NOTE: We could check the version_id, but it shouldn't be necessary with
1829 // the expected messages we're verifying (they're uncommon enough).
1830 if (message.message != expected_message_)
1831 return;
1832 scoped_observer_.RemoveAll();
1833 run_loop_.QuitWhenIdle();
1834 }
1835
1836 base::string16 expected_message_;
1837 base::RunLoop run_loop_;
1838 ScopedObserver<content::ServiceWorkerContext,
1839 content::ServiceWorkerContextObserver>
1840 scoped_observer_;
1841
1842 DISALLOW_COPY_AND_ASSIGN(ConsoleMessageObserver);
1843 };
1844
1845 TestExtensionDir test_dir;
1846 test_dir.WriteManifest(
1847 R"({
1848 "name": "Test Extension",
1849 "manifest_version": 2,
1850 "version": "0.1",
David Bertoni630837d2019-04-02 21:22:101851 "background": {"service_worker": "script.js"}
Devlin Cronin59551d82019-03-05 01:28:591852 })");
1853 constexpr char kScript[] =
1854 R"(// First, log a message using the normal, built-in blink console.
1855 console.log('test message');
1856 chrome.test.runTests([
1857 function justATest() {
1858 // Next, we use the "Console" object from
1859 // extensions/renderer/console.cc, which is used by custom bindings
1860 // so that it isn't tampered with by untrusted script. The test
1861 // custom bindings log a message whenever a test is passed, so we
1862 // force a log by just passing this test.
1863 chrome.test.succeed();
1864 }
1865 ]);)";
1866 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"), kScript);
1867
1868 // The observer for the built-in blink console.
1869 ConsoleMessageObserver default_console_observer(profile(), "test message");
1870 // The observer for our custom extensions bindings console.
1871 ConsoleMessageObserver custom_console_observer(profile(),
1872 "[SUCCESS] justATest");
1873
1874 const Extension* extension = LoadExtension(test_dir.UnpackedPath());
1875 ASSERT_TRUE(extension);
1876
1877 default_console_observer.Wait();
1878 custom_console_observer.Wait();
1879 // If we receive both messages, we passed!
1880}
1881
annekao38685502015-07-14 17:46:391882} // namespace extensions