blob: 93a67b6435d5a5cb8121272701931eec34153ab5 [file] [log] [blame]
annekao38685502015-07-14 17:46:391// Copyright 2015 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
avia2f4804a2015-12-24 23:11:135#include <stdint.h>
6
Sylvain Defresne4fdc727fd2018-10-04 11:09:467#include "base/bind.h"
kalman6f984ae2015-09-18 17:21:588#include "base/bind_helpers.h"
Istiaque Ahmeda14ec482018-08-25 01:02:189#include "base/json/json_reader.h"
avia2f4804a2015-12-24 23:11:1310#include "base/macros.h"
Istiaque Ahmedd4b67ee2019-03-02 10:53:2011#include "base/optional.h"
Gabriel Charette078e3662017-08-28 22:59:0412#include "base/run_loop.h"
kalman6f984ae2015-09-18 17:21:5813#include "base/strings/stringprintf.h"
horo1eeddde2015-11-19 05:59:2514#include "base/strings/utf_string_conversions.h"
David Bertoni1d646a152019-04-25 02:09:2215#include "base/test/bind_test_util.h"
jam3f2d3932017-04-26 20:28:5116#include "base/threading/thread_restrictions.h"
Olga Sharonova3e13cd92018-02-08 16:43:5617#include "build/build_config.h"
David Bertoni9026eff2019-05-01 18:04:3118#include "chrome/browser/extensions/crx_installer.h"
Istiaque Ahmed91d6987c2019-06-25 00:09:3319#include "chrome/browser/extensions/extension_action_runner.h"
annekao38685502015-07-14 17:46:3920#include "chrome/browser/extensions/extension_apitest.h"
rdevlin.croninf5863da2015-09-10 19:21:4521#include "chrome/browser/extensions/extension_service.h"
Istiaque Ahmed805f6a83b2017-10-05 01:23:2622#include "chrome/browser/extensions/lazy_background_page_test_util.h"
David Bertoni1d646a152019-04-25 02:09:2223#include "chrome/browser/extensions/unpacked_installer.h"
peter9f4490a2017-01-27 00:58:3624#include "chrome/browser/gcm/gcm_profile_service_factory.h"
miguelg9b502862017-04-24 18:13:5325#include "chrome/browser/notifications/notification_display_service_factory.h"
Istiaque Ahmed242a4102019-06-25 01:47:5726#include "chrome/browser/notifications/notification_display_service_tester.h"
Peter Beverloodd4ef1e2018-06-21 15:41:0427#include "chrome/browser/notifications/notification_permission_context.h"
miguelg9b502862017-04-24 18:13:5328#include "chrome/browser/notifications/stub_notification_display_service.h"
lshang106c1772016-06-06 01:43:2329#include "chrome/browser/permissions/permission_manager.h"
timlohc6911802017-03-01 05:37:0330#include "chrome/browser/permissions/permission_result.h"
lazyboy561b7de2015-11-19 19:27:3031#include "chrome/browser/push_messaging/push_messaging_app_identifier.h"
32#include "chrome/browser/push_messaging/push_messaging_service_factory.h"
33#include "chrome/browser/push_messaging/push_messaging_service_impl.h"
Istiaque Ahmed91d6987c2019-06-25 00:09:3334#include "chrome/browser/ui/extensions/browser_action_test_util.h"
annekao1db36fd2015-07-29 17:09:1635#include "chrome/browser/ui/tabs/tab_strip_model.h"
Trent Apted4267b942017-10-27 03:25:3636#include "chrome/common/chrome_switches.h"
Istiaque Ahmeda14ec482018-08-25 01:02:1837#include "chrome/common/extensions/api/web_navigation.h"
rdevlin.croninf5863da2015-09-10 19:21:4538#include "chrome/test/base/ui_test_utils.h"
timloh9a180ad2017-02-20 07:15:2339#include "components/content_settings/core/common/content_settings_types.h"
Peter Beverloo34139462018-04-10 14:18:0640#include "components/gcm_driver/fake_gcm_profile_service.h"
johnmea5045732016-09-08 17:23:2941#include "components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h"
sdefresne9fb67692015-08-03 18:48:2242#include "components/version_info/version_info.h"
Devlin Cronin59551d82019-03-05 01:28:5943#include "content/public/browser/console_message.h"
kalman6f984ae2015-09-18 17:21:5844#include "content/public/browser/navigation_controller.h"
rdevlin.croninf5863da2015-09-10 19:21:4545#include "content/public/browser/navigation_entry.h"
Istiaque Ahmedd4b67ee2019-03-02 10:53:2046#include "content/public/browser/render_process_host.h"
lazyboy4c82177a2016-10-18 00:04:0947#include "content/public/browser/service_worker_context.h"
Devlin Cronin59551d82019-03-05 01:28:5948#include "content/public/browser/service_worker_context_observer.h"
lazyboy4c82177a2016-10-18 00:04:0949#include "content/public/browser/storage_partition.h"
kalman6f984ae2015-09-18 17:21:5850#include "content/public/browser/web_contents.h"
lazyboybd325ae2015-11-18 21:35:2651#include "content/public/common/content_switches.h"
falkenad185092016-06-16 06:10:0252#include "content/public/common/origin_util.h"
kalman6f984ae2015-09-18 17:21:5853#include "content/public/common/page_type.h"
Istiaque Ahmedd4b67ee2019-03-02 10:53:2054#include "content/public/common/result_codes.h"
lazyboybd325ae2015-11-18 21:35:2655#include "content/public/test/background_sync_test_util.h"
annekao1db36fd2015-07-29 17:09:1656#include "content/public/test/browser_test_utils.h"
lazyboy63b994a2017-06-30 21:20:2357#include "content/public/test/service_worker_test_helpers.h"
Istiaque Ahmed771aa8a22018-06-20 23:40:5358#include "extensions/browser/event_router.h"
kalman6f984ae2015-09-18 17:21:5859#include "extensions/browser/extension_host.h"
lazyboyc3e763a2015-12-09 23:09:5860#include "extensions/browser/extension_registry.h"
kalman6f984ae2015-09-18 17:21:5861#include "extensions/browser/process_manager.h"
Istiaque Ahmed70f76ac2018-11-02 02:59:5562#include "extensions/browser/service_worker_task_queue.h"
David Bertoni1dc1b7a2019-06-13 02:44:5963#include "extensions/browser/test_extension_registry_observer.h"
Istiaque Ahmeda14ec482018-08-25 01:02:1864#include "extensions/common/api/test.h"
Istiaque Ahmed771aa8a22018-06-20 23:40:5365#include "extensions/common/value_builder.h"
David Bertoni9026eff2019-05-01 18:04:3166#include "extensions/common/verifier_formats.h"
kalman6f984ae2015-09-18 17:21:5867#include "extensions/test/background_page_watcher.h"
annekao38685502015-07-14 17:46:3968#include "extensions/test/extension_test_message_listener.h"
Istiaque Ahmed805f6a83b2017-10-05 01:23:2669#include "extensions/test/result_catcher.h"
Devlin Cronin59551d82019-03-05 01:28:5970#include "extensions/test/test_extension_dir.h"
falkenad185092016-06-16 06:10:0271#include "net/dns/mock_host_resolver.h"
horo1eeddde2015-11-19 05:59:2572#include "net/test/embedded_test_server/embedded_test_server.h"
Istiaque Ahmed242a4102019-06-25 01:47:5773#include "ui/message_center/public/cpp/notification.h"
lazyboy63b994a2017-06-30 21:20:2374#include "url/url_constants.h"
annekao38685502015-07-14 17:46:3975
76namespace extensions {
77
kalman6f984ae2015-09-18 17:21:5878namespace {
79
lazyboy22eddc712015-12-10 21:16:2680// Returns the newly added WebContents.
81content::WebContents* AddTab(Browser* browser, const GURL& url) {
82 int starting_tab_count = browser->tab_strip_model()->count();
83 ui_test_utils::NavigateToURLWithDisposition(
nick3b04f322016-08-31 19:29:1984 browser, url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
lazyboy22eddc712015-12-10 21:16:2685 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
86 int tab_count = browser->tab_strip_model()->count();
87 EXPECT_EQ(starting_tab_count + 1, tab_count);
88 return browser->tab_strip_model()->GetActiveWebContents();
89}
90
lazyboy22eddc712015-12-10 21:16:2691class WebContentsLoadStopObserver : content::WebContentsObserver {
92 public:
93 explicit WebContentsLoadStopObserver(content::WebContents* web_contents)
94 : content::WebContentsObserver(web_contents),
95 load_stop_observed_(false) {}
96
97 void WaitForLoadStop() {
98 if (load_stop_observed_)
99 return;
100 message_loop_runner_ = new content::MessageLoopRunner;
101 message_loop_runner_->Run();
102 }
103
104 private:
105 void DidStopLoading() override {
106 load_stop_observed_ = true;
107 if (message_loop_runner_)
108 message_loop_runner_->Quit();
109 }
110
111 bool load_stop_observed_;
112 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
113
114 DISALLOW_COPY_AND_ASSIGN(WebContentsLoadStopObserver);
115};
116
David Bertoni4d9cf41d2019-06-04 00:06:22117// A known extension ID for tests that specify the key in their
118// manifests.
119constexpr char kTestExtensionId[] = "knldjmfmopnpolahpmmgbagdohdnhkik";
120
kalman6f984ae2015-09-18 17:21:58121} // namespace
122
Devlin Cronin242d19d22019-03-12 18:08:48123class ServiceWorkerTest : public ExtensionApiTest {
annekao38685502015-07-14 17:46:39124 public:
lazyboy20167c22016-05-18 00:59:30125 ServiceWorkerTest() : current_channel_(version_info::Channel::STABLE) {}
Istiaque Ahmed7105f2a2017-10-07 01:11:59126 explicit ServiceWorkerTest(version_info::Channel channel)
127 : current_channel_(channel) {}
annekao38685502015-07-14 17:46:39128
129 ~ServiceWorkerTest() override {}
130
jam1a5b5582017-05-01 16:50:10131 void SetUpOnMainThread() override {
132 ExtensionApiTest::SetUpOnMainThread();
David Bertoni3929f552019-03-28 22:10:36133 host_resolver()->AddRule("*", "127.0.0.1");
jam1a5b5582017-05-01 16:50:10134 }
135
kalman6f984ae2015-09-18 17:21:58136 protected:
137 // Returns the ProcessManager for the test's profile.
138 ProcessManager* process_manager() { return ProcessManager::Get(profile()); }
139
140 // Starts running a test from the background page test extension.
141 //
142 // This registers a service worker with |script_name|, and fetches the
143 // registration result.
Istiaque Ahmed93ff7f42018-08-31 01:42:22144 const Extension* StartTestFromBackgroundPage(const char* script_name) {
Istiaque Ahmed6475f542018-08-28 04:20:21145 ExtensionTestMessageListener ready_listener("ready", false);
kalman6f984ae2015-09-18 17:21:58146 const Extension* extension =
147 LoadExtension(test_data_dir_.AppendASCII("service_worker/background"));
148 CHECK(extension);
Istiaque Ahmed6475f542018-08-28 04:20:21149 CHECK(ready_listener.WaitUntilSatisfied());
150
kalman6f984ae2015-09-18 17:21:58151 ExtensionHost* background_host =
152 process_manager()->GetBackgroundHostForExtension(extension->id());
153 CHECK(background_host);
Istiaque Ahmed6475f542018-08-28 04:20:21154
kalman6f984ae2015-09-18 17:21:58155 std::string error;
156 CHECK(content::ExecuteScriptAndExtractString(
157 background_host->host_contents(),
158 base::StringPrintf("test.registerServiceWorker('%s')", script_name),
159 &error));
Istiaque Ahmed93ff7f42018-08-31 01:42:22160 if (!error.empty())
kalman6f984ae2015-09-18 17:21:58161 ADD_FAILURE() << "Got unexpected error " << error;
162 return extension;
163 }
164
165 // Navigates the browser to a new tab at |url|, waits for it to load, then
166 // returns it.
167 content::WebContents* Navigate(const GURL& url) {
168 ui_test_utils::NavigateToURLWithDisposition(
nick3b04f322016-08-31 19:29:19169 browser(), url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
kalman6f984ae2015-09-18 17:21:58170 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
171 content::WebContents* web_contents =
172 browser()->tab_strip_model()->GetActiveWebContents();
173 content::WaitForLoadStop(web_contents);
174 return web_contents;
175 }
176
177 // Navigates the browser to |url| and returns the new tab's page type.
178 content::PageType NavigateAndGetPageType(const GURL& url) {
clamy1d7a4112018-06-15 15:47:16179 return Navigate(url)
180 ->GetController()
181 .GetLastCommittedEntry()
182 ->GetPageType();
kalman6f984ae2015-09-18 17:21:58183 }
184
185 // Extracts the innerText from |contents|.
186 std::string ExtractInnerText(content::WebContents* contents) {
187 std::string inner_text;
188 if (!content::ExecuteScriptAndExtractString(
189 contents,
190 "window.domAutomationController.send(document.body.innerText)",
191 &inner_text)) {
192 ADD_FAILURE() << "Failed to get inner text for "
193 << contents->GetVisibleURL();
194 }
195 return inner_text;
196 }
197
198 // Navigates the browser to |url|, then returns the innerText of the new
199 // tab's WebContents' main frame.
200 std::string NavigateAndExtractInnerText(const GURL& url) {
201 return ExtractInnerText(Navigate(url));
202 }
203
lazyboy4c82177a2016-10-18 00:04:09204 size_t GetWorkerRefCount(const GURL& origin) {
205 content::ServiceWorkerContext* sw_context =
206 content::BrowserContext::GetDefaultStoragePartition(
207 browser()->profile())
208 ->GetServiceWorkerContext();
209 base::RunLoop run_loop;
210 size_t ref_count = 0;
211 auto set_ref_count = [](size_t* ref_count, base::RunLoop* run_loop,
212 size_t external_request_count) {
213 *ref_count = external_request_count;
214 run_loop->Quit();
215 };
216 sw_context->CountExternalRequestsForTest(
Matt Falkenhagenc5cb4282017-09-07 08:43:42217 origin, base::BindOnce(set_ref_count, &ref_count, &run_loop));
lazyboy4c82177a2016-10-18 00:04:09218 run_loop.Run();
219 return ref_count;
220 }
221
annekao38685502015-07-14 17:46:39222 private:
lazyboy20167c22016-05-18 00:59:30223 // Sets the channel to "stable".
224 // Not useful after we've opened extension Service Workers to stable
225 // channel.
226 // TODO(lazyboy): Remove this when ExtensionServiceWorkersEnabled() is
227 // removed.
annekao38685502015-07-14 17:46:39228 ScopedCurrentChannel current_channel_;
kalman6f984ae2015-09-18 17:21:58229
annekao38685502015-07-14 17:46:39230 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerTest);
231};
232
Istiaque Ahmedccb444022018-06-19 02:11:12233class ServiceWorkerBasedBackgroundTest : public ServiceWorkerTest {
234 public:
235 ServiceWorkerBasedBackgroundTest()
236 : ServiceWorkerTest(
237 // Extensions APIs from SW are only enabled on trunk.
238 // It is important to set the channel early so that this change is
239 // visible in renderers running with service workers (and no
240 // extension).
241 version_info::Channel::UNKNOWN) {}
242 ~ServiceWorkerBasedBackgroundTest() override {}
243
244 void SetUpOnMainThread() override {
245 host_resolver()->AddRule("*", "127.0.0.1");
246 ASSERT_TRUE(embedded_test_server()->Start());
247 ServiceWorkerTest::SetUpOnMainThread();
248 }
249
Istiaque Ahmedd4b67ee2019-03-02 10:53:20250 // Returns the only running worker id for |extension_id|.
251 // Returns base::nullopt if there isn't any worker running or more than one
252 // worker is running for |extension_id|.
253 base::Optional<WorkerId> GetUniqueRunningWorkerId(
254 const ExtensionId& extension_id) {
255 ProcessManager* process_manager = ProcessManager::Get(profile());
256 std::vector<WorkerId> all_workers =
257 process_manager->GetAllWorkersIdsForTesting();
258 base::Optional<WorkerId> running_worker_id;
259 for (const WorkerId& worker_id : all_workers) {
260 if (worker_id.extension_id == extension_id) {
261 if (running_worker_id) // More than one worker present.
262 return base::nullopt;
263 running_worker_id = worker_id;
264 }
265 }
266 return running_worker_id;
267 }
268
David Bertoni023e0ec2019-06-10 17:28:22269 bool ExtensionHasRenderProcessHost(const ExtensionId& extension_id) {
270 ProcessMap* process_map = ProcessMap::Get(browser()->profile());
271 content::RenderProcessHost::iterator it =
272 content::RenderProcessHost::AllHostsIterator();
273 while (!it.IsAtEnd()) {
274 if (process_map->Contains(extension_id, it.GetCurrentValue()->GetID())) {
275 return true;
276 }
277 it.Advance();
278 }
279 return false;
280 }
281
Istiaque Ahmedccb444022018-06-19 02:11:12282 private:
283 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerBasedBackgroundTest);
284};
285
Istiaque Ahmed242a4102019-06-25 01:47:57286class ServiceWorkerBasedBackgroundTestWithNotification
287 : public ServiceWorkerBasedBackgroundTest {
288 public:
289 ServiceWorkerBasedBackgroundTestWithNotification() {}
290 ~ServiceWorkerBasedBackgroundTestWithNotification() override = default;
291
292 void SetUpOnMainThread() override {
293 ServiceWorkerBasedBackgroundTest::SetUpOnMainThread();
294 display_service_tester_ =
295 std::make_unique<NotificationDisplayServiceTester>(
296 browser()->profile());
297 }
298
299 void TearDownOnMainThread() override {
300 display_service_tester_.reset();
301 ServiceWorkerBasedBackgroundTest::TearDownOnMainThread();
302 }
303
304 protected:
305 // Returns a vector with the Notification objects that are being displayed
306 // by the notification display service. Synchronous.
307 std::vector<message_center::Notification> GetDisplayedNotifications() const {
308 return display_service_tester_->GetDisplayedNotificationsForType(
309 NotificationHandler::Type::WEB_PERSISTENT);
310 }
311
312 std::unique_ptr<NotificationDisplayServiceTester> display_service_tester_;
313
314 private:
315 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerBasedBackgroundTestWithNotification);
316};
317
Istiaque Ahmedccb444022018-06-19 02:11:12318// Tests that Service Worker based background pages can be loaded and they can
319// receive extension events.
320// The extension is installed and loaded during this step and it registers
321// an event listener for tabs.onCreated event. The step also verifies that tab
322// creation correctly fires the listener.
Devlin Cronin242d19d22019-03-12 18:08:48323IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, PRE_Basic) {
Istiaque Ahmedccb444022018-06-19 02:11:12324 ExtensionTestMessageListener newtab_listener("CREATED", false);
325 newtab_listener.set_failure_message("CREATE_FAILED");
326 ExtensionTestMessageListener worker_listener("WORKER_RUNNING", false);
327 worker_listener.set_failure_message("NON_WORKER_SCOPE");
328 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
329 "service_worker/worker_based_background/basic"));
330 ASSERT_TRUE(extension);
331 const ExtensionId extension_id = extension->id();
332 EXPECT_TRUE(worker_listener.WaitUntilSatisfied());
333
334 const GURL url = embedded_test_server()->GetURL("/extensions/test_file.html");
335 content::WebContents* new_web_contents = AddTab(browser(), url);
336 EXPECT_TRUE(new_web_contents);
337 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
338
339 // Service Worker extension does not have ExtensionHost.
340 EXPECT_FALSE(process_manager()->GetBackgroundHostForExtension(extension_id));
341}
342
343// After browser restarts, this test step ensures that opening a tab fires
344// tabs.onCreated event listener to the extension without explicitly loading the
345// extension. This is because the extension registered a listener before browser
346// restarted in PRE_Basic.
Devlin Cronin242d19d22019-03-12 18:08:48347IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, Basic) {
Istiaque Ahmedccb444022018-06-19 02:11:12348 ExtensionTestMessageListener newtab_listener("CREATED", false);
349 newtab_listener.set_failure_message("CREATE_FAILED");
350 const GURL url = embedded_test_server()->GetURL("/extensions/test_file.html");
351 content::WebContents* new_web_contents = AddTab(browser(), url);
352 EXPECT_TRUE(new_web_contents);
353 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
354}
355
Istiaque Ahmedbf08f952018-10-02 01:22:04356// Tests chrome.runtime.onInstalled fires for extension service workers.
Devlin Cronin242d19d22019-03-12 18:08:48357IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, OnInstalledEvent) {
Istiaque Ahmedbf08f952018-10-02 01:22:04358 ASSERT_TRUE(RunExtensionTest(
359 "service_worker/worker_based_background/events_on_installed"))
360 << message_;
361}
362
Istiaque Ahmedba8d0652019-05-14 15:17:34363// Tests chrome.runtime.id and chrome.runtime.getURL().
364IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, RuntimeMisc) {
365 ASSERT_TRUE(
366 RunExtensionTest("service_worker/worker_based_background/runtime_misc"))
367 << message_;
368}
369
David Bertoni69982832019-02-13 21:24:21370// Tests chrome.storage APIs.
Devlin Cronin242d19d22019-03-12 18:08:48371IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, StorageSetAndGet) {
David Bertoni69982832019-02-13 21:24:21372 ASSERT_TRUE(
373 RunExtensionTest("service_worker/worker_based_background/storage"))
374 << message_;
375}
376
David Bertoni0665c892019-02-14 00:27:26377// Tests chrome.storage.local and chrome.storage.local APIs.
Devlin Cronin242d19d22019-03-12 18:08:48378IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, StorageNoPermissions) {
David Bertoni0665c892019-02-14 00:27:26379 ASSERT_TRUE(RunExtensionTest(
380 "service_worker/worker_based_background/storage_no_permissions"))
381 << message_;
382}
383
David Bertoni30809312019-02-28 22:56:05384// Tests chrome.tabs APIs.
Devlin Cronin242d19d22019-03-12 18:08:48385IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, TabsBasic) {
David Bertoni30809312019-02-28 22:56:05386 ASSERT_TRUE(
387 RunExtensionTest("service_worker/worker_based_background/tabs_basic"))
388 << message_;
389}
390
David Bertoni46d698892019-02-26 00:29:10391// Tests chrome.tabs events.
Devlin Cronin242d19d22019-03-12 18:08:48392IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, TabsEvents) {
David Bertoni46d698892019-02-26 00:29:10393 ASSERT_TRUE(
394 RunExtensionTest("service_worker/worker_based_background/tabs_events"))
395 << message_;
396}
397
David Bertoni4c7dfcc2019-03-27 23:49:34398// Tests chrome.tabs APIs.
399IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, TabsExecuteScript) {
400 ASSERT_TRUE(RunExtensionTest(
401 "service_worker/worker_based_background/tabs_execute_script"))
402 << message_;
403}
404
David Bertoni37ae0222019-04-04 01:30:54405// Tests chrome.webRequest APIs.
David Bertoni3929f552019-03-28 22:10:36406IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, WebRequest) {
407 ASSERT_TRUE(
408 RunExtensionTest("service_worker/worker_based_background/web_request"))
409 << message_;
410}
411
David Bertoni37ae0222019-04-04 01:30:54412// Tests chrome.webRequest APIs in blocking mode.
413IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, WebRequestBlocking) {
414 // Try to load the page before installing the extension, which should work.
415 const GURL url = embedded_test_server()->GetURL("/extensions/test_file.html");
416 EXPECT_EQ(content::PAGE_TYPE_NORMAL, NavigateAndGetPageType(url));
417
418 // Install the extension and navigate again to the page.
419 ExtensionTestMessageListener ready_listener("ready", false);
420 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII(
421 "service_worker/worker_based_background/web_request_blocking")));
422 ASSERT_TRUE(ready_listener.WaitUntilSatisfied());
423 EXPECT_EQ(content::PAGE_TYPE_ERROR, NavigateAndGetPageType(url));
424}
425
David Bertoni377f52312019-05-21 20:35:03426// Tests chrome.webNavigation APIs.
427IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, FilteredEvents) {
428 ASSERT_TRUE(RunExtensionTest(
429 "service_worker/worker_based_background/filtered_events"))
430 << message_;
431}
432
Istiaque Ahmed70f76ac2018-11-02 02:59:55433// Listens for |message| from extension Service Worker early so that tests can
434// wait for the message on startup (and not miss it).
435class ServiceWorkerWithEarlyMessageListenerTest
436 : public ServiceWorkerBasedBackgroundTest {
Istiaque Ahmedf70ab222018-10-02 03:08:24437 public:
Istiaque Ahmed70f76ac2018-11-02 02:59:55438 explicit ServiceWorkerWithEarlyMessageListenerTest(
439 const std::string& test_message)
440 : test_message_(test_message) {}
441 ~ServiceWorkerWithEarlyMessageListenerTest() override = default;
Istiaque Ahmedf70ab222018-10-02 03:08:24442
Istiaque Ahmed70f76ac2018-11-02 02:59:55443 bool WaitForMessage() { return listener_->WaitUntilSatisfied(); }
Istiaque Ahmedf70ab222018-10-02 03:08:24444
445 void CreatedBrowserMainParts(content::BrowserMainParts* main_parts) override {
446 // At this point, the notification service is initialized but the profile
447 // and extensions have not.
Istiaque Ahmed70f76ac2018-11-02 02:59:55448 listener_ =
449 std::make_unique<ExtensionTestMessageListener>(test_message_, false);
Istiaque Ahmedf70ab222018-10-02 03:08:24450 ServiceWorkerBasedBackgroundTest::CreatedBrowserMainParts(main_parts);
451 }
452
453 private:
Istiaque Ahmed70f76ac2018-11-02 02:59:55454 const std::string test_message_;
Istiaque Ahmedf70ab222018-10-02 03:08:24455 std::unique_ptr<ExtensionTestMessageListener> listener_;
456
Istiaque Ahmed70f76ac2018-11-02 02:59:55457 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerWithEarlyMessageListenerTest);
458};
459
460class ServiceWorkerOnStartupEventTest
461 : public ServiceWorkerWithEarlyMessageListenerTest {
462 public:
463 ServiceWorkerOnStartupEventTest()
464 : ServiceWorkerWithEarlyMessageListenerTest("onStartup event") {}
465 ~ServiceWorkerOnStartupEventTest() override = default;
466
467 private:
468 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerOnStartupEventTest);
Istiaque Ahmedf70ab222018-10-02 03:08:24469};
470
471// Tests "runtime.onStartup" for extension SW.
Devlin Cronin242d19d22019-03-12 18:08:48472IN_PROC_BROWSER_TEST_F(ServiceWorkerOnStartupEventTest, PRE_Event) {
Istiaque Ahmedf70ab222018-10-02 03:08:24473 ASSERT_TRUE(RunExtensionTest(
474 "service_worker/worker_based_background/on_startup_event"))
475 << message_;
476}
477
Devlin Cronin242d19d22019-03-12 18:08:48478IN_PROC_BROWSER_TEST_F(ServiceWorkerOnStartupEventTest, Event) {
Istiaque Ahmed70f76ac2018-11-02 02:59:55479 EXPECT_TRUE(WaitForMessage());
480}
481
482class ServiceWorkerRegistrationAtStartupTest
483 : public ServiceWorkerWithEarlyMessageListenerTest,
484 public ServiceWorkerTaskQueue::TestObserver {
485 public:
486 ServiceWorkerRegistrationAtStartupTest()
487 : ServiceWorkerWithEarlyMessageListenerTest("WORKER_RUNNING") {
488 ServiceWorkerTaskQueue::SetObserverForTest(this);
489 }
490 ~ServiceWorkerRegistrationAtStartupTest() override {
491 ServiceWorkerTaskQueue::SetObserverForTest(nullptr);
492 }
493
494 // ServiceWorkerTaskQueue::TestObserver:
495 void OnActivateExtension(const ExtensionId& extension_id,
496 bool will_register_service_worker) override {
497 if (extension_id != kExtensionId)
498 return;
499
500 will_register_service_worker_ = will_register_service_worker;
501
502 extension_activated_ = true;
503 if (run_loop_)
504 run_loop_->Quit();
505 }
506
507 void WaitForOnActivateExtension() {
508 if (extension_activated_)
509 return;
510 run_loop_ = std::make_unique<base::RunLoop>();
511 run_loop_->Run();
512 }
513
514 bool WillRegisterServiceWorker() {
515 return will_register_service_worker_.value();
516 }
517
518 protected:
519 static const char kExtensionId[];
520
521 private:
522 bool extension_activated_ = false;
523 base::Optional<bool> will_register_service_worker_;
524 std::unique_ptr<base::RunLoop> run_loop_;
525
526 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerRegistrationAtStartupTest);
527};
528
529// Test extension id at
530// api_test/service_worker/worker_based_background/registration_at_startup/.
531const char ServiceWorkerRegistrationAtStartupTest::kExtensionId[] =
532 "gnchfmandajfaiajniicagenfmhdjila";
533
534// Tests that Service Worker registration for existing extension isn't issued
535// upon browser restart.
536// Regression test for https://crbug.com/889687.
Devlin Cronin242d19d22019-03-12 18:08:48537IN_PROC_BROWSER_TEST_F(ServiceWorkerRegistrationAtStartupTest,
Istiaque Ahmed70f76ac2018-11-02 02:59:55538 PRE_ExtensionActivationDoesNotReregister) {
539 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
540 "service_worker/worker_based_background/registration_at_startup"));
541 ASSERT_TRUE(extension);
542 EXPECT_EQ(kExtensionId, extension->id());
543 // Wait for "WORKER_RUNNING" message from the Service Worker.
544 EXPECT_TRUE(WaitForMessage());
545 EXPECT_TRUE(WillRegisterServiceWorker());
546}
547
Devlin Cronin242d19d22019-03-12 18:08:48548IN_PROC_BROWSER_TEST_F(ServiceWorkerRegistrationAtStartupTest,
Istiaque Ahmed70f76ac2018-11-02 02:59:55549 ExtensionActivationDoesNotReregister) {
550 // Since the extension has onStartup listener, the Service Worker will run on
551 // browser start and we'll see "WORKER_RUNNING" message from the worker.
552 EXPECT_TRUE(WaitForMessage());
553 // As the extension activated during first run on PRE_ step, it shouldn't
554 // re-register the Service Worker upon browser restart.
555 EXPECT_FALSE(WillRegisterServiceWorker());
Istiaque Ahmedf70ab222018-10-02 03:08:24556}
557
Istiaque Ahmeda14ec482018-08-25 01:02:18558// Class that dispatches an event to |extension_id| right after a
559// non-lazy listener to the event is added from the extension's Service Worker.
Istiaque Ahmed771aa8a22018-06-20 23:40:53560class EarlyWorkerMessageSender : public EventRouter::Observer {
561 public:
562 EarlyWorkerMessageSender(content::BrowserContext* browser_context,
Istiaque Ahmeda14ec482018-08-25 01:02:18563 const ExtensionId& extension_id,
564 std::unique_ptr<Event> event)
Istiaque Ahmed771aa8a22018-06-20 23:40:53565 : browser_context_(browser_context),
566 event_router_(EventRouter::EventRouter::Get(browser_context_)),
567 extension_id_(extension_id),
Istiaque Ahmeda14ec482018-08-25 01:02:18568 event_(std::move(event)),
Istiaque Ahmed771aa8a22018-06-20 23:40:53569 listener_("PASS", false) {
570 DCHECK(browser_context_);
571 listener_.set_failure_message("FAIL");
Istiaque Ahmeda14ec482018-08-25 01:02:18572 event_router_->RegisterObserver(this, event_->event_name);
Istiaque Ahmed771aa8a22018-06-20 23:40:53573 }
574
575 ~EarlyWorkerMessageSender() override {
576 event_router_->UnregisterObserver(this);
577 }
578
579 // EventRouter::Observer:
580 void OnListenerAdded(const EventListenerInfo& details) override {
Istiaque Ahmeda14ec482018-08-25 01:02:18581 if (!event_ || extension_id_ != details.extension_id ||
582 event_->event_name != details.event_name) {
Istiaque Ahmed771aa8a22018-06-20 23:40:53583 return;
Istiaque Ahmeda14ec482018-08-25 01:02:18584 }
585
Istiaque Ahmed771aa8a22018-06-20 23:40:53586 const bool is_lazy_listener = details.browser_context == nullptr;
587 if (is_lazy_listener) {
588 // Wait for the non-lazy listener as we want to exercise the code to
589 // dispatch the event right after the Service Worker registration is
590 // completing.
591 return;
592 }
Istiaque Ahmeda14ec482018-08-25 01:02:18593 DispatchEvent(std::move(event_));
Istiaque Ahmed771aa8a22018-06-20 23:40:53594 }
595
596 bool SendAndWait() { return listener_.WaitUntilSatisfied(); }
597
598 private:
599 static constexpr const char* const kTestOnMessageEventName = "test.onMessage";
600
Istiaque Ahmeda14ec482018-08-25 01:02:18601 void DispatchEvent(std::unique_ptr<Event> event) {
Istiaque Ahmed771aa8a22018-06-20 23:40:53602 EventRouter::Get(browser_context_)
603 ->DispatchEventToExtension(extension_id_, std::move(event));
604 }
605
606 content::BrowserContext* const browser_context_ = nullptr;
607 EventRouter* const event_router_ = nullptr;
608 const ExtensionId extension_id_;
Istiaque Ahmeda14ec482018-08-25 01:02:18609 std::unique_ptr<Event> event_;
Istiaque Ahmed771aa8a22018-06-20 23:40:53610 ExtensionTestMessageListener listener_;
Istiaque Ahmed771aa8a22018-06-20 23:40:53611
612 DISALLOW_COPY_AND_ASSIGN(EarlyWorkerMessageSender);
613};
614
615// Tests that extension event dispatch works correctly right after extension
616// installation registers its Service Worker.
617// Regression test for: https://crbug.com/850792.
Devlin Cronin242d19d22019-03-12 18:08:48618IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, EarlyEventDispatch) {
Istiaque Ahmed771aa8a22018-06-20 23:40:53619 const ExtensionId kId("pkplfbidichfdicaijlchgnapepdginl");
Istiaque Ahmeda14ec482018-08-25 01:02:18620
621 // Build "test.onMessage" event for dispatch.
622 auto event = std::make_unique<Event>(
623 events::FOR_TEST, extensions::api::test::OnMessage::kEventName,
Lei Zhang582ecd12019-02-13 20:28:54624 base::ListValue::From(base::JSONReader::ReadDeprecated(
Istiaque Ahmeda14ec482018-08-25 01:02:18625 R"([{"data": "hello", "lastMessage": true}])")),
626 profile());
627
628 EarlyWorkerMessageSender sender(profile(), kId, std::move(event));
Istiaque Ahmed771aa8a22018-06-20 23:40:53629 // pkplfbidichfdicaijlchgnapepdginl
630 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
631 "service_worker/worker_based_background/early_event_dispatch"));
632 CHECK(extension);
633 EXPECT_EQ(kId, extension->id());
634 EXPECT_TRUE(sender.SendAndWait());
635}
636
Istiaque Ahmeda14ec482018-08-25 01:02:18637// Tests that filtered events dispatches correctly right after a non-lazy
638// listener is registered for that event (and before the corresponding lazy
639// listener is registered).
Devlin Cronin242d19d22019-03-12 18:08:48640IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
Istiaque Ahmeda14ec482018-08-25 01:02:18641 EarlyFilteredEventDispatch) {
642 const ExtensionId kId("pkplfbidichfdicaijlchgnapepdginl");
643
644 // Add minimal details required to dispatch webNavigation.onCommitted event:
645 extensions::api::web_navigation::OnCommitted::Details details;
646 details.transition_type =
647 extensions::api::web_navigation::TRANSITION_TYPE_TYPED;
648
649 // Build a dummy onCommited event to dispatch.
650 auto on_committed_event = std::make_unique<Event>(
651 events::WEB_NAVIGATION_ON_COMMITTED, "webNavigation.onCommitted",
652 api::web_navigation::OnCommitted::Create(details), profile());
653 // The filter will match the listener filter registered from the extension.
654 EventFilteringInfo info;
655 info.url = GURL("http://foo.com/a.html");
656 on_committed_event->filter_info = info;
657
658 EarlyWorkerMessageSender sender(profile(), kId,
659 std::move(on_committed_event));
660
661 // pkplfbidichfdicaijlchgnapepdginl
662 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
663 "service_worker/worker_based_background/early_filtered_event_dispatch"));
664 ASSERT_TRUE(extension);
665 EXPECT_EQ(kId, extension->id());
666 EXPECT_TRUE(sender.SendAndWait());
667}
668
lazyboybd325ae2015-11-18 21:35:26669class ServiceWorkerBackgroundSyncTest : public ServiceWorkerTest {
670 public:
671 ServiceWorkerBackgroundSyncTest() {}
672 ~ServiceWorkerBackgroundSyncTest() override {}
673
674 void SetUpCommandLine(base::CommandLine* command_line) override {
675 // ServiceWorkerRegistration.sync requires experimental flag.
676 command_line->AppendSwitch(
Istiaque Ahmedea5ed5042017-09-25 19:00:16677 ::switches::kEnableExperimentalWebPlatformFeatures);
lazyboybd325ae2015-11-18 21:35:26678 ServiceWorkerTest::SetUpCommandLine(command_line);
679 }
680
681 void SetUp() override {
Robbie McElrathdb12d8e2018-09-18 21:20:40682 content::background_sync_test_util::SetIgnoreNetworkChanges(true);
lazyboybd325ae2015-11-18 21:35:26683 ServiceWorkerTest::SetUp();
684 }
685
686 private:
687 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerBackgroundSyncTest);
688};
689
lazyboy561b7de2015-11-19 19:27:30690class ServiceWorkerPushMessagingTest : public ServiceWorkerTest {
691 public:
692 ServiceWorkerPushMessagingTest()
Sylvain Defresne212b4b02018-10-11 16:32:05693 : scoped_testing_factory_installer_(
694 base::BindRepeating(&gcm::FakeGCMProfileService::Build)),
695 gcm_driver_(nullptr),
696 push_service_(nullptr) {}
697
lazyboy561b7de2015-11-19 19:27:30698 ~ServiceWorkerPushMessagingTest() override {}
699
700 void GrantNotificationPermissionForTest(const GURL& url) {
Peter Beverloodd4ef1e2018-06-21 15:41:04701 NotificationPermissionContext::UpdatePermission(profile(), url.GetOrigin(),
702 CONTENT_SETTING_ALLOW);
lazyboy561b7de2015-11-19 19:27:30703 }
704
705 PushMessagingAppIdentifier GetAppIdentifierForServiceWorkerRegistration(
avia2f4804a2015-12-24 23:11:13706 int64_t service_worker_registration_id,
lazyboy561b7de2015-11-19 19:27:30707 const GURL& origin) {
708 PushMessagingAppIdentifier app_identifier =
709 PushMessagingAppIdentifier::FindByServiceWorker(
710 profile(), origin, service_worker_registration_id);
711
712 EXPECT_FALSE(app_identifier.is_null());
713 return app_identifier;
714 }
715
716 // ExtensionApiTest overrides.
717 void SetUpCommandLine(base::CommandLine* command_line) override {
peter9de96272015-12-04 15:23:27718 command_line->AppendSwitch(
Istiaque Ahmedea5ed5042017-09-25 19:00:16719 ::switches::kEnableExperimentalWebPlatformFeatures);
lazyboy561b7de2015-11-19 19:27:30720 ServiceWorkerTest::SetUpCommandLine(command_line);
721 }
Tanja Gornak89128fd2018-09-18 08:49:34722
lazyboy561b7de2015-11-19 19:27:30723 void SetUpOnMainThread() override {
miguelg9b502862017-04-24 18:13:53724 NotificationDisplayServiceFactory::GetInstance()->SetTestingFactory(
Sylvain Defresne711ff6b2018-10-04 12:33:54725 profile(),
726 base::BindRepeating(&StubNotificationDisplayService::FactoryForTests));
miguelg9b502862017-04-24 18:13:53727
johnmea5045732016-09-08 17:23:29728 gcm::FakeGCMProfileService* gcm_service =
729 static_cast<gcm::FakeGCMProfileService*>(
Tanja Gornak89128fd2018-09-18 08:49:34730 gcm::GCMProfileServiceFactory::GetForProfile(profile()));
johnmea5045732016-09-08 17:23:29731 gcm_driver_ = static_cast<instance_id::FakeGCMDriverForInstanceID*>(
732 gcm_service->driver());
lazyboy561b7de2015-11-19 19:27:30733 push_service_ = PushMessagingServiceFactory::GetForProfile(profile());
734
735 ServiceWorkerTest::SetUpOnMainThread();
736 }
737
johnmea5045732016-09-08 17:23:29738 instance_id::FakeGCMDriverForInstanceID* gcm_driver() const {
739 return gcm_driver_;
740 }
lazyboy561b7de2015-11-19 19:27:30741 PushMessagingServiceImpl* push_service() const { return push_service_; }
742
743 private:
Sylvain Defresne212b4b02018-10-11 16:32:05744 gcm::GCMProfileServiceFactory::ScopedTestingFactoryInstaller
745 scoped_testing_factory_installer_;
746
johnmea5045732016-09-08 17:23:29747 instance_id::FakeGCMDriverForInstanceID* gcm_driver_;
lazyboy561b7de2015-11-19 19:27:30748 PushMessagingServiceImpl* push_service_;
749
750 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerPushMessagingTest);
751};
752
Istiaque Ahmed805f6a83b2017-10-05 01:23:26753class ServiceWorkerLazyBackgroundTest : public ServiceWorkerTest {
754 public:
Istiaque Ahmed7105f2a2017-10-07 01:11:59755 ServiceWorkerLazyBackgroundTest()
756 : ServiceWorkerTest(
757 // Extensions APIs from SW are only enabled on trunk.
758 // It is important to set the channel early so that this change is
759 // visible in renderers running with service workers (and no
760 // extension).
761 version_info::Channel::UNKNOWN) {}
Istiaque Ahmed805f6a83b2017-10-05 01:23:26762 ~ServiceWorkerLazyBackgroundTest() override {}
763
764 void SetUpCommandLine(base::CommandLine* command_line) override {
765 ServiceWorkerTest::SetUpCommandLine(command_line);
766 // Disable background network activity as it can suddenly bring the Lazy
767 // Background Page alive.
768 command_line->AppendSwitch(::switches::kDisableBackgroundNetworking);
769 command_line->AppendSwitch(::switches::kNoProxyServer);
770 }
771
772 void SetUpInProcessBrowserTestFixture() override {
773 ServiceWorkerTest::SetUpInProcessBrowserTestFixture();
774 // Set shorter delays to prevent test timeouts.
775 ProcessManager::SetEventPageIdleTimeForTesting(1);
776 ProcessManager::SetEventPageSuspendingTimeForTesting(1);
777 }
778
779 private:
780 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerLazyBackgroundTest);
781};
782
Devlin Cronin242d19d22019-03-12 18:08:48783IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, RegisterSucceeds) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22784 StartTestFromBackgroundPage("register.js");
annekao38685502015-07-14 17:46:39785}
786
Devlin Cronin242d19d22019-03-12 18:08:48787IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, UpdateRefreshesServiceWorker) {
Francois Doraye6fb2d02017-10-18 21:29:13788 base::ScopedAllowBlockingForTesting allow_blocking;
lazyboyc3e763a2015-12-09 23:09:58789 base::ScopedTempDir scoped_temp_dir;
790 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
791 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
792 .AppendASCII("update")
793 .AppendASCII("service_worker.pem");
vabr9142fe22016-09-08 13:19:22794 base::FilePath path_v1 =
795 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
796 .AppendASCII("update")
797 .AppendASCII("v1"),
798 scoped_temp_dir.GetPath().AppendASCII("v1.crx"),
799 pem_path, base::FilePath());
800 base::FilePath path_v2 =
801 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
802 .AppendASCII("update")
803 .AppendASCII("v2"),
804 scoped_temp_dir.GetPath().AppendASCII("v2.crx"),
805 pem_path, base::FilePath());
lazyboyc3e763a2015-12-09 23:09:58806 const char* kId = "hfaanndiiilofhfokeanhddpkfffchdi";
807
808 ExtensionTestMessageListener listener_v1("Pong from version 1", false);
809 listener_v1.set_failure_message("FAILURE_V1");
810 // Install version 1.0 of the extension.
811 ASSERT_TRUE(InstallExtension(path_v1, 1));
812 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
813 ->enabled_extensions()
814 .GetByID(kId));
815 EXPECT_TRUE(listener_v1.WaitUntilSatisfied());
816
817 ExtensionTestMessageListener listener_v2("Pong from version 2", false);
818 listener_v2.set_failure_message("FAILURE_V2");
819
820 // Update to version 2.0.
821 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
822 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
823 ->enabled_extensions()
824 .GetByID(kId));
825 EXPECT_TRUE(listener_v2.WaitUntilSatisfied());
826}
827
[email protected]2ef85d562017-09-15 18:41:52828// TODO(crbug.com/765736) Fix the test.
Devlin Cronin242d19d22019-03-12 18:08:48829IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, DISABLED_UpdateWithoutSkipWaiting) {
Francois Doraye6fb2d02017-10-18 21:29:13830 base::ScopedAllowBlockingForTesting allow_blocking;
lazyboy22eddc712015-12-10 21:16:26831 base::ScopedTempDir scoped_temp_dir;
832 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
833 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
834 .AppendASCII("update_without_skip_waiting")
835 .AppendASCII("update_without_skip_waiting.pem");
vabr9142fe22016-09-08 13:19:22836 base::FilePath path_v1 =
837 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
838 .AppendASCII("update_without_skip_waiting")
839 .AppendASCII("v1"),
840 scoped_temp_dir.GetPath().AppendASCII("v1.crx"),
841 pem_path, base::FilePath());
842 base::FilePath path_v2 =
843 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
844 .AppendASCII("update_without_skip_waiting")
845 .AppendASCII("v2"),
846 scoped_temp_dir.GetPath().AppendASCII("v2.crx"),
847 pem_path, base::FilePath());
lazyboy22eddc712015-12-10 21:16:26848 const char* kId = "mhnnnflgagdakldgjpfcofkiocpdmogl";
849
850 // Install version 1.0 of the extension.
851 ASSERT_TRUE(InstallExtension(path_v1, 1));
852 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
853 ->enabled_extensions()
854 .GetByID(kId));
855 const Extension* extension = extensions::ExtensionRegistry::Get(profile())
856 ->enabled_extensions()
857 .GetByID(kId);
858
859 ExtensionTestMessageListener listener1("Pong from version 1", false);
860 listener1.set_failure_message("FAILURE");
861 content::WebContents* web_contents =
862 AddTab(browser(), extension->GetResourceURL("page.html"));
863 EXPECT_TRUE(listener1.WaitUntilSatisfied());
864
865 // Update to version 2.0.
866 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
867 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
868 ->enabled_extensions()
869 .GetByID(kId));
870 const Extension* extension_after_update =
871 extensions::ExtensionRegistry::Get(profile())
872 ->enabled_extensions()
873 .GetByID(kId);
874
875 // Service worker version 2 would be installed but it won't be controlling
876 // the extension page yet.
877 ExtensionTestMessageListener listener2("Pong from version 1", false);
878 listener2.set_failure_message("FAILURE");
879 web_contents =
880 AddTab(browser(), extension_after_update->GetResourceURL("page.html"));
881 EXPECT_TRUE(listener2.WaitUntilSatisfied());
882
883 // Navigate the tab away from the extension page so that no clients are
884 // using the service worker.
885 // Note that just closing the tab with WebContentsDestroyedWatcher doesn't
886 // seem to be enough because it returns too early.
887 WebContentsLoadStopObserver navigate_away_observer(web_contents);
888 web_contents->GetController().LoadURL(
889 GURL(url::kAboutBlankURL), content::Referrer(), ui::PAGE_TRANSITION_TYPED,
890 std::string());
891 navigate_away_observer.WaitForLoadStop();
892
893 // Now expect service worker version 2 to control the extension page.
894 ExtensionTestMessageListener listener3("Pong from version 2", false);
895 listener3.set_failure_message("FAILURE");
896 web_contents =
897 AddTab(browser(), extension_after_update->GetResourceURL("page.html"));
898 EXPECT_TRUE(listener3.WaitUntilSatisfied());
899}
900
Devlin Cronin242d19d22019-03-12 18:08:48901IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, FetchArbitraryPaths) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22902 const Extension* extension = StartTestFromBackgroundPage("fetch.js");
annekao1db36fd2015-07-29 17:09:16903
kalman6f984ae2015-09-18 17:21:58904 // Open some arbirary paths. Their contents should be what the service worker
905 // responds with, which in this case is the path of the fetch.
906 EXPECT_EQ(
907 "Caught a fetch for /index.html",
908 NavigateAndExtractInnerText(extension->GetResourceURL("index.html")));
909 EXPECT_EQ("Caught a fetch for /path/to/other.html",
910 NavigateAndExtractInnerText(
911 extension->GetResourceURL("path/to/other.html")));
912 EXPECT_EQ("Caught a fetch for /some/text/file.txt",
913 NavigateAndExtractInnerText(
914 extension->GetResourceURL("some/text/file.txt")));
915 EXPECT_EQ("Caught a fetch for /no/file/extension",
916 NavigateAndExtractInnerText(
917 extension->GetResourceURL("no/file/extension")));
918 EXPECT_EQ("Caught a fetch for /",
919 NavigateAndExtractInnerText(extension->GetResourceURL("")));
annekao1db36fd2015-07-29 17:09:16920}
921
Devlin Cronin242d19d22019-03-12 18:08:48922IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
Kenichi Ishibashi773b82972018-08-30 07:02:03923 FetchExtensionResourceFromServiceWorker) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22924 const Extension* extension = StartTestFromBackgroundPage("fetch_from_sw.js");
Kenichi Ishibashi773b82972018-08-30 07:02:03925 ASSERT_TRUE(extension);
926
927 // The service worker in this test tries to load 'hello.txt' via fetch()
928 // and sends back the content of the file, which should be 'hello'.
929 const char* kScript = R"(
930 let channel = new MessageChannel();
931 test.waitForMessage(channel.port1).then(message => {
932 window.domAutomationController.send(message);
933 });
934 test.registeredServiceWorker.postMessage(
935 {port: channel.port2}, [channel.port2]);
936 )";
937 EXPECT_EQ("hello", ExecuteScriptInBackgroundPage(extension->id(), kScript));
938}
939
Kenichi Ishibashi09ee5e72018-11-27 07:12:38940// Tests that fetch() from service worker and network fallback
941// go through webRequest.onBeforeRequest API.
Devlin Cronin242d19d22019-03-12 18:08:48942IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, OnBeforeRequest) {
Kenichi Ishibashi09ee5e72018-11-27 07:12:38943 const Extension* extension = LoadExtensionWithFlags(
944 test_data_dir_.AppendASCII("service_worker/webrequest"), kFlagNone);
945 ASSERT_TRUE(extension);
946 ASSERT_TRUE(StartEmbeddedTestServer());
947
948 // Start a service worker and make it control the page.
949 GURL page_url = embedded_test_server()->GetURL(
950 "/extensions/api_test/service_worker/"
951 "webrequest/webpage.html");
952 content::WebContents* web_contents =
953 browser()->tab_strip_model()->GetActiveWebContents();
954 ui_test_utils::NavigateToURL(browser(), page_url);
955 content::WaitForLoadStop(web_contents);
956
957 std::string result;
958 ASSERT_TRUE(content::ExecuteScriptAndExtractString(web_contents,
959 "register();", &result));
960 EXPECT_EQ("ready", result);
961
962 // Initiate a fetch that the service worker doesn't intercept
963 // (network fallback).
964 result.clear();
965 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
966 web_contents, "doFetch('hello.txt?fallthrough');", &result));
967 EXPECT_EQ("hello", result);
968 EXPECT_EQ(
969 "/extensions/api_test/service_worker/webrequest/hello.txt?fallthrough",
970 ExecuteScriptInBackgroundPage(extension->id(), "getLastHookedPath()"));
971
972 // Initiate a fetch that results in calling fetch() in the service worker.
973 result.clear();
974 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
975 web_contents, "doFetch('hello.txt?respondWithFetch');", &result));
976 EXPECT_EQ("hello", result);
977 EXPECT_EQ(
978 "/extensions/api_test/service_worker/webrequest/"
979 "hello.txt?respondWithFetch",
980 ExecuteScriptInBackgroundPage(extension->id(), "getLastHookedPath()"));
981}
982
Devlin Cronin242d19d22019-03-12 18:08:48983IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, SWServedBackgroundPageReceivesEvent) {
lazyboy52c3bcf2016-01-08 00:11:29984 const Extension* extension =
Istiaque Ahmed93ff7f42018-08-31 01:42:22985 StartTestFromBackgroundPage("replace_background.js");
lazyboy52c3bcf2016-01-08 00:11:29986 ExtensionHost* background_page =
987 process_manager()->GetBackgroundHostForExtension(extension->id());
988 ASSERT_TRUE(background_page);
989
990 // Close the background page and start it again so that the service worker
991 // will start controlling pages.
992 background_page->Close();
993 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
994 background_page = nullptr;
Peter Kasting341e1fb2018-02-24 00:03:01995 process_manager()->WakeEventPage(extension->id(), base::DoNothing());
lazyboy52c3bcf2016-01-08 00:11:29996 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
997
998 // Since the SW is now controlling the extension, the SW serves the background
999 // script. page.html sends a message to the background script and we verify
1000 // that the SW served background script correctly receives the message/event.
1001 ExtensionTestMessageListener listener("onMessage/SW BG.", false);
1002 listener.set_failure_message("onMessage/original BG.");
1003 content::WebContents* web_contents =
1004 AddTab(browser(), extension->GetResourceURL("page.html"));
1005 ASSERT_TRUE(web_contents);
1006 EXPECT_TRUE(listener.WaitUntilSatisfied());
1007}
1008
Devlin Cronin242d19d22019-03-12 18:08:481009IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, SWServedBackgroundPage) {
Istiaque Ahmed93ff7f42018-08-31 01:42:221010 const Extension* extension = StartTestFromBackgroundPage("fetch.js");
annekao49241182015-08-18 17:14:011011
kalman6f984ae2015-09-18 17:21:581012 std::string kExpectedInnerText = "background.html contents for testing.";
annekao49241182015-08-18 17:14:011013
kalman6f984ae2015-09-18 17:21:581014 // Sanity check that the background page has the expected content.
1015 ExtensionHost* background_page =
1016 process_manager()->GetBackgroundHostForExtension(extension->id());
1017 ASSERT_TRUE(background_page);
1018 EXPECT_EQ(kExpectedInnerText,
1019 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:011020
kalman6f984ae2015-09-18 17:21:581021 // Close the background page.
1022 background_page->Close();
1023 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
1024 background_page = nullptr;
1025
1026 // Start it again.
Peter Kasting341e1fb2018-02-24 00:03:011027 process_manager()->WakeEventPage(extension->id(), base::DoNothing());
kalman6f984ae2015-09-18 17:21:581028 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
1029
Matt Falkenhagena612fc02018-05-30 00:35:391030 // The service worker should get a fetch event for the background page.
kalman6f984ae2015-09-18 17:21:581031 background_page =
1032 process_manager()->GetBackgroundHostForExtension(extension->id());
1033 ASSERT_TRUE(background_page);
1034 content::WaitForLoadStop(background_page->host_contents());
1035
kalman6f984ae2015-09-18 17:21:581036 EXPECT_EQ("Caught a fetch for /background.html",
1037 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:011038}
1039
Devlin Cronin242d19d22019-03-12 18:08:481040IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:581041 ServiceWorkerPostsMessageToBackgroundClient) {
Istiaque Ahmed93ff7f42018-08-31 01:42:221042 const Extension* extension =
1043 StartTestFromBackgroundPage("post_message_to_background_client.js");
annekao533482222015-08-21 23:23:531044
kalman6f984ae2015-09-18 17:21:581045 // The service worker in this test simply posts a message to the background
1046 // client it receives from getBackgroundClient().
1047 const char* kScript =
1048 "var messagePromise = null;\n"
1049 "if (test.lastMessageFromServiceWorker) {\n"
1050 " messagePromise = Promise.resolve(test.lastMessageFromServiceWorker);\n"
1051 "} else {\n"
1052 " messagePromise = test.waitForMessage(navigator.serviceWorker);\n"
1053 "}\n"
1054 "messagePromise.then(function(message) {\n"
1055 " window.domAutomationController.send(String(message == 'success'));\n"
1056 "})\n";
1057 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:531058}
1059
Devlin Cronin242d19d22019-03-12 18:08:481060IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:581061 BackgroundPagePostsMessageToServiceWorker) {
1062 const Extension* extension =
Istiaque Ahmed93ff7f42018-08-31 01:42:221063 StartTestFromBackgroundPage("post_message_to_sw.js");
annekao533482222015-08-21 23:23:531064
kalman6f984ae2015-09-18 17:21:581065 // The service worker in this test waits for a message, then echoes it back
1066 // by posting a message to the background page via getBackgroundClient().
1067 const char* kScript =
1068 "var mc = new MessageChannel();\n"
1069 "test.waitForMessage(mc.port1).then(function(message) {\n"
1070 " window.domAutomationController.send(String(message == 'hello'));\n"
1071 "});\n"
1072 "test.registeredServiceWorker.postMessage(\n"
1073 " {message: 'hello', port: mc.port2}, [mc.port2])\n";
1074 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:531075}
1076
Devlin Cronin242d19d22019-03-12 18:08:481077IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
rdevlin.croninf5863da2015-09-10 19:21:451078 ServiceWorkerSuspensionOnExtensionUnload) {
kalman6f984ae2015-09-18 17:21:581079 // For this test, only hold onto the extension's ID and URL + a function to
1080 // get a resource URL, because we're going to be disabling and uninstalling
1081 // it, which will invalidate the pointer.
1082 std::string extension_id;
1083 GURL extension_url;
1084 {
Istiaque Ahmed93ff7f42018-08-31 01:42:221085 const Extension* extension = StartTestFromBackgroundPage("fetch.js");
kalman6f984ae2015-09-18 17:21:581086 extension_id = extension->id();
1087 extension_url = extension->url();
1088 }
1089 auto get_resource_url = [&extension_url](const std::string& path) {
1090 return Extension::GetResourceURL(extension_url, path);
1091 };
rdevlin.croninf5863da2015-09-10 19:21:451092
kalman6f984ae2015-09-18 17:21:581093 // Fetch should route to the service worker.
1094 EXPECT_EQ("Caught a fetch for /index.html",
1095 NavigateAndExtractInnerText(get_resource_url("index.html")));
rdevlin.croninf5863da2015-09-10 19:21:451096
kalman6f984ae2015-09-18 17:21:581097 // Disable the extension. Opening the page should fail.
1098 extension_service()->DisableExtension(extension_id,
Minh X. Nguyen45479012017-08-18 21:35:361099 disable_reason::DISABLE_USER_ACTION);
rdevlin.croninf5863da2015-09-10 19:21:451100 base::RunLoop().RunUntilIdle();
rdevlin.croninf5863da2015-09-10 19:21:451101
kalman6f984ae2015-09-18 17:21:581102 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1103 NavigateAndGetPageType(get_resource_url("index.html")));
1104 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1105 NavigateAndGetPageType(get_resource_url("other.html")));
1106
1107 // Re-enable the extension. Opening pages should immediately start to succeed
1108 // again.
rdevlin.croninf5863da2015-09-10 19:21:451109 extension_service()->EnableExtension(extension_id);
1110 base::RunLoop().RunUntilIdle();
1111
kalman6f984ae2015-09-18 17:21:581112 EXPECT_EQ("Caught a fetch for /index.html",
1113 NavigateAndExtractInnerText(get_resource_url("index.html")));
1114 EXPECT_EQ("Caught a fetch for /other.html",
1115 NavigateAndExtractInnerText(get_resource_url("other.html")));
1116 EXPECT_EQ("Caught a fetch for /another.html",
1117 NavigateAndExtractInnerText(get_resource_url("another.html")));
rdevlin.croninf5863da2015-09-10 19:21:451118
kalman6f984ae2015-09-18 17:21:581119 // Uninstall the extension. Opening pages should fail again.
1120 base::string16 error;
1121 extension_service()->UninstallExtension(
Devlin Cronin218df7f2017-11-21 21:41:311122 extension_id, UninstallReason::UNINSTALL_REASON_FOR_TESTING, &error);
kalman6f984ae2015-09-18 17:21:581123 base::RunLoop().RunUntilIdle();
1124
1125 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1126 NavigateAndGetPageType(get_resource_url("index.html")));
1127 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1128 NavigateAndGetPageType(get_resource_url("other.html")));
1129 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1130 NavigateAndGetPageType(get_resource_url("anotherother.html")));
1131 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1132 NavigateAndGetPageType(get_resource_url("final.html")));
1133}
1134
Devlin Cronin242d19d22019-03-12 18:08:481135IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, BackgroundPageIsWokenIfAsleep) {
Istiaque Ahmed93ff7f42018-08-31 01:42:221136 const Extension* extension = StartTestFromBackgroundPage("wake_on_fetch.js");
kalman6f984ae2015-09-18 17:21:581137
1138 // Navigate to special URLs that this test's service worker recognises, each
1139 // making a check then populating the response with either "true" or "false".
1140 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
1141 "background-client-is-awake")));
1142 EXPECT_EQ("true", NavigateAndExtractInnerText(
1143 extension->GetResourceURL("ping-background-client")));
1144 // Ping more than once for good measure.
1145 EXPECT_EQ("true", NavigateAndExtractInnerText(
1146 extension->GetResourceURL("ping-background-client")));
1147
1148 // Shut down the event page. The SW should detect that it's closed, but still
1149 // be able to ping it.
1150 ExtensionHost* background_page =
1151 process_manager()->GetBackgroundHostForExtension(extension->id());
1152 ASSERT_TRUE(background_page);
1153 background_page->Close();
1154 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
1155
1156 EXPECT_EQ("false", NavigateAndExtractInnerText(extension->GetResourceURL(
1157 "background-client-is-awake")));
1158 EXPECT_EQ("true", NavigateAndExtractInnerText(
1159 extension->GetResourceURL("ping-background-client")));
1160 EXPECT_EQ("true", NavigateAndExtractInnerText(
1161 extension->GetResourceURL("ping-background-client")));
1162 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
1163 "background-client-is-awake")));
1164}
1165
Devlin Cronin242d19d22019-03-12 18:08:481166IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:581167 GetBackgroundClientFailsWithNoBackgroundPage) {
1168 // This extension doesn't have a background page, only a tab at page.html.
1169 // The service worker it registers tries to call getBackgroundClient() and
1170 // should fail.
1171 // Note that this also tests that service workers can be registered from tabs.
1172 EXPECT_TRUE(RunExtensionSubtest("service_worker/no_background", "page.html"));
rdevlin.croninf5863da2015-09-10 19:21:451173}
1174
Devlin Cronin242d19d22019-03-12 18:08:481175IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, NotificationAPI) {
lazyboy6ddb7d62015-11-10 23:15:271176 EXPECT_TRUE(RunExtensionSubtest("service_worker/notifications/has_permission",
1177 "page.html"));
1178}
1179
Devlin Cronin242d19d22019-03-12 18:08:481180IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, WebAccessibleResourcesFetch) {
lazyboyaea32c22016-01-04 21:37:071181 EXPECT_TRUE(RunExtensionSubtest(
1182 "service_worker/web_accessible_resources/fetch/", "page.html"));
1183}
1184
David Bertoni9026eff2019-05-01 18:04:311185// Tests that updating a packed extension with modified scripts works
1186// properly -- we expect that the new script will execute, rather than the
1187// previous one.
1188IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, UpdatePackedExtension) {
1189 // Extensions APIs from SW are only enabled on trunk.
1190 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1191 constexpr char kManifest1[] =
1192 R"({
1193 "name": "Test Extension",
1194 "manifest_version": 2,
1195 "version": "0.1",
1196 "background": {"service_worker": "script.js"}
1197 })";
David Bertoni353f0fb42019-05-30 15:53:301198 constexpr char kNewVersionString[] = "0.2";
1199
David Bertoni9026eff2019-05-01 18:04:311200 // This script installs an event listener for updates to the extension with
1201 // a callback that forces itself to reload.
David Bertoni353f0fb42019-05-30 15:53:301202 constexpr char kScript1[] =
David Bertoni9026eff2019-05-01 18:04:311203 R"(
1204 chrome.runtime.onUpdateAvailable.addListener(function(details) {
David Bertoni353f0fb42019-05-30 15:53:301205 chrome.test.assertEq('%s', details.version);
David Bertoni9026eff2019-05-01 18:04:311206 chrome.runtime.reload();
1207 });
1208 chrome.test.sendMessage('ready1');
1209 )";
1210
1211 std::string id;
1212 TestExtensionDir test_dir;
1213
1214 // Write the manifest and script files and load the extension.
1215 test_dir.WriteManifest(kManifest1);
David Bertoni353f0fb42019-05-30 15:53:301216 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"),
1217 base::StringPrintf(kScript1, kNewVersionString));
David Bertoni9026eff2019-05-01 18:04:311218
1219 {
1220 ExtensionTestMessageListener ready_listener("ready1", false);
1221 base::FilePath path = test_dir.Pack();
1222 const Extension* extension = LoadExtension(path);
1223 ASSERT_TRUE(extension);
1224
1225 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
1226 id = extension->id();
1227 }
1228
1229 constexpr char kManifest2[] =
1230 R"({
1231 "name": "Test Extension",
1232 "manifest_version": 2,
David Bertoni353f0fb42019-05-30 15:53:301233 "version": "%s",
David Bertoni9026eff2019-05-01 18:04:311234 "background": {"service_worker": "script.js"}
1235 })";
David Bertoni353f0fb42019-05-30 15:53:301236 constexpr char kScript2[] =
1237 R"(
1238 chrome.runtime.onInstalled.addListener(function(details) {
1239 chrome.test.assertEq('update', details.reason);
1240 chrome.test.sendMessage('onInstalled');
1241 });
1242 chrome.test.sendMessage('ready2');
1243 )";
David Bertoni9026eff2019-05-01 18:04:311244 // Rewrite the manifest and script files with a version change in the manifest
1245 // file. After reloading the extension, the old version of the extension
1246 // should detect the update, force the reload, and the new script should
1247 // execute.
David Bertoni353f0fb42019-05-30 15:53:301248 test_dir.WriteManifest(base::StringPrintf(kManifest2, kNewVersionString));
1249 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"), kScript2);
David Bertoni9026eff2019-05-01 18:04:311250 {
1251 ExtensionTestMessageListener ready_listener("ready2", false);
David Bertoni353f0fb42019-05-30 15:53:301252 ExtensionTestMessageListener on_installed_listener("onInstalled", false);
David Bertoni9026eff2019-05-01 18:04:311253 base::FilePath path = test_dir.Pack();
1254 ExtensionService* const extension_service =
1255 ExtensionSystem::Get(profile())->extension_service();
1256 EXPECT_TRUE(extension_service->UpdateExtension(
1257 CRXFileInfo(id, GetTestVerifierFormat(), path), true, nullptr));
1258 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
1259 EXPECT_EQ("0.2", ExtensionRegistry::Get(profile())
1260 ->enabled_extensions()
1261 .GetByID(id)
1262 ->version()
1263 .GetString());
David Bertoni353f0fb42019-05-30 15:53:301264 EXPECT_TRUE(on_installed_listener.WaitUntilSatisfied());
David Bertoni9026eff2019-05-01 18:04:311265 }
1266}
1267
David Bertoni1d646a152019-04-25 02:09:221268// Tests that updating an unpacked extension with modified scripts works
1269// properly -- we expect that the new script will execute, rather than the
1270// previous one.
1271IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, UpdateUnpackedExtension) {
1272 // Extensions APIs from SW are only enabled on trunk.
1273 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1274 constexpr char kManifest1[] =
1275 R"({
1276 "name": "Test Extension",
1277 "manifest_version": 2,
1278 "version": "0.1",
1279 "background": {"service_worker": "script.js"}
1280 })";
1281 constexpr char kManifest2[] =
1282 R"({
1283 "name": "Test Extension",
1284 "manifest_version": 2,
1285 "version": "0.2",
1286 "background": {"service_worker": "script.js"}
1287 })";
David Bertoni353f0fb42019-05-30 15:53:301288 constexpr char kScript[] =
1289 R"(
1290 chrome.runtime.onInstalled.addListener(function(details) {
1291 chrome.test.assertEq('%s', details.reason);
1292 chrome.test.sendMessage('onInstalled');
1293 });
1294 chrome.test.sendMessage('%s');
1295 )";
David Bertoni1d646a152019-04-25 02:09:221296
1297 std::string id;
1298
1299 ExtensionService* const extension_service =
1300 ExtensionSystem::Get(profile())->extension_service();
1301 scoped_refptr<UnpackedInstaller> installer =
1302 UnpackedInstaller::Create(extension_service);
1303
1304 // Set a completion callback so we can get the ID of the extension.
1305 installer->set_completion_callback(base::BindLambdaForTesting(
1306 [&id](const Extension* extension, const base::FilePath& path,
1307 const std::string& error) {
1308 ASSERT_TRUE(extension);
1309 ASSERT_TRUE(error.empty());
1310 id = extension->id();
1311 }));
1312
1313 TestExtensionDir test_dir;
1314
1315 // Write the manifest and script files and load the extension.
1316 test_dir.WriteManifest(kManifest1);
1317 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"),
David Bertoni353f0fb42019-05-30 15:53:301318 base::StringPrintf(kScript, "install", "ready1"));
David Bertoni1d646a152019-04-25 02:09:221319 {
1320 ExtensionTestMessageListener ready_listener("ready1", false);
David Bertoni353f0fb42019-05-30 15:53:301321 ExtensionTestMessageListener on_installed_listener("onInstalled", false);
David Bertoni1d646a152019-04-25 02:09:221322
1323 installer->Load(test_dir.UnpackedPath());
1324 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
David Bertoni353f0fb42019-05-30 15:53:301325 EXPECT_TRUE(on_installed_listener.WaitUntilSatisfied());
David Bertoni1d646a152019-04-25 02:09:221326 ASSERT_FALSE(id.empty());
1327 }
1328
1329 // Rewrite the script file without a version change in the manifest and reload
1330 // the extension. The new script should execute.
1331 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"),
David Bertoni353f0fb42019-05-30 15:53:301332 base::StringPrintf(kScript, "update", "ready2"));
David Bertoni1d646a152019-04-25 02:09:221333 {
1334 ExtensionTestMessageListener ready_listener("ready2", false);
David Bertoni353f0fb42019-05-30 15:53:301335 ExtensionTestMessageListener on_installed_listener("onInstalled", false);
David Bertoni1d646a152019-04-25 02:09:221336
1337 extension_service->ReloadExtension(id);
1338 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
David Bertoni353f0fb42019-05-30 15:53:301339 EXPECT_TRUE(on_installed_listener.WaitUntilSatisfied());
David Bertoni1d646a152019-04-25 02:09:221340 }
1341
1342 // Rewrite the manifest and script files with a version change in the manifest
1343 // file. After reloading the extension, the new script should execute.
1344 test_dir.WriteManifest(kManifest2);
1345 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"),
David Bertoni353f0fb42019-05-30 15:53:301346 base::StringPrintf(kScript, "update", "ready3"));
David Bertoni1d646a152019-04-25 02:09:221347 {
1348 ExtensionTestMessageListener ready_listener("ready3", false);
David Bertoni353f0fb42019-05-30 15:53:301349 ExtensionTestMessageListener on_installed_listener("onInstalled", false);
David Bertoni1d646a152019-04-25 02:09:221350
1351 extension_service->ReloadExtension(id);
1352 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
David Bertoni353f0fb42019-05-30 15:53:301353 EXPECT_TRUE(on_installed_listener.WaitUntilSatisfied());
David Bertoni1d646a152019-04-25 02:09:221354 }
1355}
1356
lazyboyaea32c22016-01-04 21:37:071357// This test loads a web page that has an iframe pointing to a
1358// chrome-extension:// URL. The URL is listed in the extension's
1359// web_accessible_resources. Initially the iframe is served from the extension's
1360// resource file. After verifying that, we register a Service Worker that
1361// controls the extension. Further requests to the same resource as before
1362// should now be served by the Service Worker.
1363// This test also verifies that if the requested resource exists in the manifest
1364// but is not present in the extension directory, the Service Worker can still
1365// serve the resource file.
Devlin Cronin242d19d22019-03-12 18:08:481366IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, WebAccessibleResourcesIframeSrc) {
lazyboyaea32c22016-01-04 21:37:071367 const Extension* extension = LoadExtensionWithFlags(
1368 test_data_dir_.AppendASCII(
1369 "service_worker/web_accessible_resources/iframe_src"),
1370 kFlagNone);
1371 ASSERT_TRUE(extension);
1372 ASSERT_TRUE(StartEmbeddedTestServer());
falkenad185092016-06-16 06:10:021373
1374 // Service workers can only control secure contexts
1375 // (https://w3c.github.io/webappsec-secure-contexts/). For documents, this
1376 // typically means the document must have a secure origin AND all its ancestor
1377 // frames must have documents with secure origins. However, extension pages
1378 // are considered secure, even if they have an ancestor document that is an
1379 // insecure context (see GetSchemesBypassingSecureContextCheckWhitelist). So
1380 // extension service workers must be able to control an extension page
1381 // embedded in an insecure context. To test this, set up an insecure
1382 // (non-localhost, non-https) URL for the web page. This page will create
1383 // iframes that load extension pages that must be controllable by service
1384 // worker.
falkenad185092016-06-16 06:10:021385 GURL page_url =
1386 embedded_test_server()->GetURL("a.com",
1387 "/extensions/api_test/service_worker/"
1388 "web_accessible_resources/webpage.html");
1389 EXPECT_FALSE(content::IsOriginSecure(page_url));
lazyboyaea32c22016-01-04 21:37:071390
1391 content::WebContents* web_contents = AddTab(browser(), page_url);
1392 std::string result;
1393 // webpage.html will create an iframe pointing to a resource from |extension|.
1394 // Expect the resource to be served by the extension.
1395 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1396 web_contents, base::StringPrintf("window.testIframe('%s', 'iframe.html')",
1397 extension->id().c_str()),
1398 &result));
1399 EXPECT_EQ("FROM_EXTENSION_RESOURCE", result);
1400
1401 ExtensionTestMessageListener service_worker_ready_listener("SW_READY", false);
1402 EXPECT_TRUE(ExecuteScriptInBackgroundPageNoWait(
1403 extension->id(), "window.registerServiceWorker()"));
1404 EXPECT_TRUE(service_worker_ready_listener.WaitUntilSatisfied());
1405
1406 result.clear();
1407 // webpage.html will create another iframe pointing to a resource from
1408 // |extension| as before. But this time, the resource should be be served
1409 // from the Service Worker.
1410 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1411 web_contents, base::StringPrintf("window.testIframe('%s', 'iframe.html')",
1412 extension->id().c_str()),
1413 &result));
1414 EXPECT_EQ("FROM_SW_RESOURCE", result);
1415
1416 result.clear();
1417 // webpage.html will create yet another iframe pointing to a resource that
1418 // exists in the extension manifest's web_accessible_resources, but is not
1419 // present in the extension directory. Expect the resources of the iframe to
1420 // be served by the Service Worker.
1421 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1422 web_contents,
1423 base::StringPrintf("window.testIframe('%s', 'iframe_non_existent.html')",
1424 extension->id().c_str()),
1425 &result));
1426 EXPECT_EQ("FROM_SW_RESOURCE", result);
1427}
1428
Devlin Cronin242d19d22019-03-12 18:08:481429IN_PROC_BROWSER_TEST_F(ServiceWorkerBackgroundSyncTest, Sync) {
lazyboybd325ae2015-11-18 21:35:261430 const Extension* extension = LoadExtensionWithFlags(
1431 test_data_dir_.AppendASCII("service_worker/sync"), kFlagNone);
1432 ASSERT_TRUE(extension);
1433 ui_test_utils::NavigateToURL(browser(),
1434 extension->GetResourceURL("page.html"));
1435 content::WebContents* web_contents =
1436 browser()->tab_strip_model()->GetActiveWebContents();
1437
1438 // Prevent firing by going offline.
1439 content::background_sync_test_util::SetOnline(web_contents, false);
1440
1441 ExtensionTestMessageListener sync_listener("SYNC: send-chats", false);
1442 sync_listener.set_failure_message("FAIL");
1443
1444 std::string result;
1445 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
1446 web_contents, "window.runServiceWorker()", &result));
1447 ASSERT_EQ("SERVICE_WORKER_READY", result);
1448
1449 EXPECT_FALSE(sync_listener.was_satisfied());
1450 // Resume firing by going online.
1451 content::background_sync_test_util::SetOnline(web_contents, true);
1452 EXPECT_TRUE(sync_listener.WaitUntilSatisfied());
1453}
1454
Devlin Cronin242d19d22019-03-12 18:08:481455IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
horo1eeddde2015-11-19 05:59:251456 FetchFromContentScriptShouldNotGoToServiceWorkerOfPage) {
1457 ASSERT_TRUE(StartEmbeddedTestServer());
1458 GURL page_url = embedded_test_server()->GetURL(
1459 "/extensions/api_test/service_worker/content_script_fetch/"
1460 "controlled_page/index.html");
1461 content::WebContents* tab =
1462 browser()->tab_strip_model()->GetActiveWebContents();
1463 ui_test_utils::NavigateToURL(browser(), page_url);
1464 content::WaitForLoadStop(tab);
1465
1466 std::string value;
1467 ASSERT_TRUE(
1468 content::ExecuteScriptAndExtractString(tab, "register();", &value));
1469 EXPECT_EQ("SW controlled", value);
1470
1471 ASSERT_TRUE(RunExtensionTest("service_worker/content_script_fetch"))
1472 << message_;
1473}
1474
Devlin Cronin242d19d22019-03-12 18:08:481475IN_PROC_BROWSER_TEST_F(ServiceWorkerPushMessagingTest, OnPush) {
lazyboy561b7de2015-11-19 19:27:301476 const Extension* extension = LoadExtensionWithFlags(
1477 test_data_dir_.AppendASCII("service_worker/push_messaging"), kFlagNone);
1478 ASSERT_TRUE(extension);
1479 GURL extension_url = extension->url();
1480
Peter Beverloodd4ef1e2018-06-21 15:41:041481 GrantNotificationPermissionForTest(extension_url);
lazyboy561b7de2015-11-19 19:27:301482
1483 GURL url = extension->GetResourceURL("page.html");
1484 ui_test_utils::NavigateToURL(browser(), url);
1485
1486 content::WebContents* web_contents =
1487 browser()->tab_strip_model()->GetActiveWebContents();
1488
1489 // Start the ServiceWorker.
1490 ExtensionTestMessageListener ready_listener("SERVICE_WORKER_READY", false);
1491 ready_listener.set_failure_message("SERVICE_WORKER_FAILURE");
1492 const char* kScript = "window.runServiceWorker()";
1493 EXPECT_TRUE(content::ExecuteScript(web_contents->GetMainFrame(), kScript));
1494 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
1495
1496 PushMessagingAppIdentifier app_identifier =
1497 GetAppIdentifierForServiceWorkerRegistration(0LL, extension_url);
johnmea5045732016-09-08 17:23:291498 ASSERT_EQ(app_identifier.app_id(), gcm_driver()->last_gettoken_app_id());
1499 EXPECT_EQ("1234567890", gcm_driver()->last_gettoken_authorized_entity());
lazyboy561b7de2015-11-19 19:27:301500
lazyboyd429e2582016-05-20 20:18:521501 base::RunLoop run_loop;
lazyboy561b7de2015-11-19 19:27:301502 // Send a push message via gcm and expect the ServiceWorker to receive it.
1503 ExtensionTestMessageListener push_message_listener("OK", false);
1504 push_message_listener.set_failure_message("FAIL");
1505 gcm::IncomingMessage message;
1506 message.sender_id = "1234567890";
1507 message.raw_data = "testdata";
1508 message.decrypted = true;
lazyboyd429e2582016-05-20 20:18:521509 push_service()->SetMessageCallbackForTesting(run_loop.QuitClosure());
lazyboy561b7de2015-11-19 19:27:301510 push_service()->OnMessage(app_identifier.app_id(), message);
1511 EXPECT_TRUE(push_message_listener.WaitUntilSatisfied());
lazyboyd429e2582016-05-20 20:18:521512 run_loop.Run(); // Wait until the message is handled by push service.
lazyboy561b7de2015-11-19 19:27:301513}
Devlin Cronin242d19d22019-03-12 18:08:481514IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, MimeHandlerView) {
Rob Wue89b90032018-02-16 19:46:081515 ASSERT_TRUE(RunExtensionTest("service_worker/mime_handler_view"));
1516}
1517
David Bertoni3b3597d82019-06-22 02:29:361518// An observer for service worker registration events.
1519class TestRegistrationObserver : public content::ServiceWorkerContextObserver {
David Bertoni22aeae52019-06-10 22:42:531520 public:
David Bertoni3b3597d82019-06-22 02:29:361521 using RegistrationsMap = std::map<GURL, int>;
1522
1523 explicit TestRegistrationObserver(content::ServiceWorkerContext* context)
1524 : context_(context) {
David Bertoni22aeae52019-06-10 22:42:531525 context_->AddObserver(this);
1526 }
1527
David Bertoni3b3597d82019-06-22 02:29:361528 ~TestRegistrationObserver() override {
David Bertoni22aeae52019-06-10 22:42:531529 if (context_) {
1530 context_->RemoveObserver(this);
1531 }
1532 }
1533
David Bertoni3b3597d82019-06-22 02:29:361534 // Wait for the first service worker registration with an extension scheme
1535 // scope to be stored.
1536 void WaitForRegistrationStored() { stored_run_loop_.Run(); }
1537
1538 int GetCompletedCount(const GURL& scope) const {
1539 const auto it = registrations_completed_map_.find(scope);
1540 return it == registrations_completed_map_.end() ? 0 : it->second;
1541 }
1542
1543 private:
1544 // ServiceWorkerContextObserver overrides.
1545 void OnRegistrationCompleted(const GURL& scope) override {
1546 ++registrations_completed_map_[scope];
1547 }
1548
David Bertoni22aeae52019-06-10 22:42:531549 void OnRegistrationStored(int64_t registration_id,
1550 const GURL& scope) override {
1551 if (scope.SchemeIs(kExtensionScheme)) {
David Bertoni3b3597d82019-06-22 02:29:361552 stored_run_loop_.Quit();
David Bertoni22aeae52019-06-10 22:42:531553 }
1554 }
1555
1556 void OnDestruct(content::ServiceWorkerContext* context) override {
1557 context_ = nullptr;
1558 }
1559
David Bertoni3b3597d82019-06-22 02:29:361560 RegistrationsMap registrations_completed_map_;
1561 base::RunLoop stored_run_loop_;
David Bertoni22aeae52019-06-10 22:42:531562 content::ServiceWorkerContext* context_;
David Bertoni22aeae52019-06-10 22:42:531563};
1564
1565IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
1566 EventsToStoppedWorker) {
1567 content::StoragePartition* storage_partition =
1568 content::BrowserContext::GetDefaultStoragePartition(browser()->profile());
1569 content::ServiceWorkerContext* context =
1570 storage_partition->GetServiceWorkerContext();
1571
1572 // Set up an observer to wait for the registration to be stored.
David Bertoni3b3597d82019-06-22 02:29:361573 TestRegistrationObserver observer(context);
David Bertoni22aeae52019-06-10 22:42:531574
1575 ExtensionTestMessageListener event_listener_added("ready", false);
1576 event_listener_added.set_failure_message("ERROR");
1577 const Extension* extension = LoadExtensionWithFlags(
1578 test_data_dir_.AppendASCII(
1579 "service_worker/worker_based_background/events_to_stopped_worker"),
1580 kFlagNone);
1581 ASSERT_TRUE(extension);
1582
David Bertoni3b3597d82019-06-22 02:29:361583 observer.WaitForRegistrationStored();
David Bertoni22aeae52019-06-10 22:42:531584 EXPECT_TRUE(event_listener_added.WaitUntilSatisfied());
1585
1586 // Stop the service worker.
1587 {
1588 base::RunLoop run_loop;
1589 // The service worker is registered at the root scope.
1590 content::StopServiceWorkerForScope(context, extension->url(),
1591 run_loop.QuitClosure());
1592 run_loop.Run();
1593 }
1594
1595 // Navigate to a URL, which should wake up the service worker.
1596 ExtensionTestMessageListener finished_listener("finished", false);
1597 ui_test_utils::NavigateToURL(browser(),
1598 extension->GetResourceURL("page.html"));
1599 EXPECT_TRUE(finished_listener.WaitUntilSatisfied());
1600}
1601
David Bertoni3b3597d82019-06-22 02:29:361602// Tests the restriction on registering service worker scripts at root scope.
1603IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
1604 ServiceWorkerScriptRootScope) {
1605 content::StoragePartition* storage_partition =
1606 content::BrowserContext::GetDefaultStoragePartition(browser()->profile());
1607 content::ServiceWorkerContext* context =
1608 storage_partition->GetServiceWorkerContext();
1609
1610 // Set up an observer to track all SW registrations. We expect only
1611 // one for the extension's root scope. This test attempts to register
1612 // an additional service worker, which will fail.
1613 TestRegistrationObserver observer(context);
1614 ExtensionTestMessageListener registration_listener("REGISTRATION_FAILED",
1615 false);
1616 registration_listener.set_failure_message("WORKER_STARTED");
1617 const Extension* extension = LoadExtensionWithFlags(
1618 test_data_dir_.AppendASCII(
1619 "service_worker/worker_based_background/script_root_scope"),
1620 kFlagNone);
1621 ASSERT_TRUE(extension);
1622
1623 EXPECT_TRUE(registration_listener.WaitUntilSatisfied());
1624 // We expect exactly one registration, which is the one specified in the
1625 // manifest.
1626 EXPECT_EQ(1, observer.GetCompletedCount(extension->url()));
1627}
1628
Devlin Cronin242d19d22019-03-12 18:08:481629IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
Istiaque Ahmedd4b67ee2019-03-02 10:53:201630 ProcessManagerRegistrationOnShutdown) {
1631 // Note that StopServiceWorkerForScope call below expects the worker to be
1632 // completely installed, so wait for the |extension| worker to see "activate"
1633 // event.
1634 ExtensionTestMessageListener activated_listener("WORKER_ACTIVATED", false);
1635 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
1636 "service_worker/worker_based_background/process_manager"));
1637 ASSERT_TRUE(extension);
1638 EXPECT_TRUE(activated_listener.WaitUntilSatisfied());
1639
1640 base::Optional<WorkerId> worker_id =
1641 GetUniqueRunningWorkerId(extension->id());
1642 ASSERT_TRUE(worker_id);
1643 {
1644 // Shutdown the worker.
1645 // TODO(lazyboy): Ideally we'd want to test worker shutdown on idle, do that
1646 // once //content API allows to override test timeouts for Service Workers.
1647 base::RunLoop run_loop;
1648 content::StoragePartition* storage_partition =
1649 content::BrowserContext::GetDefaultStoragePartition(
1650 browser()->profile());
1651 GURL scope = extension->url();
1652 content::StopServiceWorkerForScope(
1653 storage_partition->GetServiceWorkerContext(),
1654 // The service worker is registered at the top level scope.
1655 extension->url(), run_loop.QuitClosure());
1656 run_loop.Run();
1657 }
1658
1659 EXPECT_FALSE(ProcessManager::Get(profile())->HasServiceWorker(*worker_id));
1660}
1661
Devlin Cronin242d19d22019-03-12 18:08:481662IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
Istiaque Ahmedd4b67ee2019-03-02 10:53:201663 ProcessManagerRegistrationOnTerminate) {
1664 // NOTE: It is not necessary to wait for "activate" event from the worker
1665 // for this test, but we're lazily reusing the extension from
1666 // ProcessManagerRegistrationOnShutdown test.
1667 ExtensionTestMessageListener activated_listener("WORKER_ACTIVATED", false);
1668 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
1669 "service_worker/worker_based_background/process_manager"));
1670 ASSERT_TRUE(extension);
1671 EXPECT_TRUE(activated_listener.WaitUntilSatisfied());
1672
1673 base::Optional<WorkerId> worker_id =
1674 GetUniqueRunningWorkerId(extension->id());
1675 ASSERT_TRUE(worker_id);
1676 {
1677 // Terminate worker's RenderProcessHost.
1678 content::RenderProcessHost* worker_render_process_host =
1679 content::RenderProcessHost::FromID(worker_id->render_process_id);
1680 ASSERT_TRUE(worker_render_process_host);
1681 content::RenderProcessHostWatcher process_exit_observer(
1682 worker_render_process_host,
1683 content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1684 worker_render_process_host->Shutdown(content::RESULT_CODE_KILLED);
1685 process_exit_observer.Wait();
1686 }
1687
1688 EXPECT_FALSE(ProcessManager::Get(profile())->HasServiceWorker(*worker_id));
1689}
1690
David Bertoni904dd602019-06-24 21:42:091691// Tests that worker ref count increments while extension API function is
1692// active.
1693IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, WorkerRefCount) {
1694 ExtensionTestMessageListener worker_start_listener("WORKER STARTED", false);
1695
1696 const Extension* extension = LoadExtensionWithFlags(
1697 test_data_dir_.AppendASCII(
1698 "service_worker/worker_based_background/worker_ref_count"),
1699 kFlagNone);
1700 ASSERT_TRUE(extension);
1701 ASSERT_TRUE(worker_start_listener.WaitUntilSatisfied());
1702
1703 ui_test_utils::NavigateToURL(browser(),
1704 extension->GetResourceURL("page.html"));
1705 content::WebContents* web_contents =
1706 browser()->tab_strip_model()->GetActiveWebContents();
1707
1708 // Service worker should have no pending requests because it hasn't performed
1709 // any extension API request yet.
1710 EXPECT_EQ(0u, GetWorkerRefCount(extension->url()));
1711
1712 ExtensionTestMessageListener worker_listener("CHECK_REF_COUNT", true);
1713 worker_listener.set_failure_message("FAILURE");
1714 ASSERT_TRUE(content::ExecuteScript(web_contents, "window.testSendMessage()"));
1715 ASSERT_TRUE(worker_listener.WaitUntilSatisfied());
1716
1717 // Service worker should have exactly one pending request because
1718 // chrome.test.sendMessage() API call is in-flight.
1719 EXPECT_EQ(1u, GetWorkerRefCount(extension->url()));
1720
1721 // Perform another extension API request while one is ongoing.
1722 {
1723 ExtensionTestMessageListener listener("CHECK_REF_COUNT", true);
1724 listener.set_failure_message("FAILURE");
1725 ASSERT_TRUE(
1726 content::ExecuteScript(web_contents, "window.testSendMessage()"));
1727 ASSERT_TRUE(listener.WaitUntilSatisfied());
1728
1729 // Service worker currently has two extension API requests in-flight.
1730 EXPECT_EQ(2u, GetWorkerRefCount(extension->url()));
1731 // Finish executing the nested chrome.test.sendMessage() first.
1732 listener.Reply("Hello world");
1733 }
1734
1735 ExtensionTestMessageListener worker_completion_listener("SUCCESS_FROM_WORKER",
1736 false);
1737 // Finish executing chrome.test.sendMessage().
1738 worker_listener.Reply("Hello world");
1739 EXPECT_TRUE(worker_completion_listener.WaitUntilSatisfied());
1740
1741 // The following block makes sure we have received all the IPCs related to
1742 // ref-count from the worker.
1743 {
1744 // The following roundtrip:
1745 // browser->extension->worker->extension->browser
1746 // will ensure that the worker sent the relevant ref count IPCs.
1747 std::string result;
1748 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1749 web_contents, "window.roundtripToWorker();", &result));
1750 EXPECT_EQ("roundtrip-succeeded", result);
1751
1752 // Ensure IO thread IPCs run.
1753 content::RunAllTasksUntilIdle();
1754 }
1755
1756 // The ref count should drop to 0.
1757 EXPECT_EQ(0u, GetWorkerRefCount(extension->url()));
1758}
1759
David Bertoni1dc1b7a2019-06-13 02:44:591760IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, UninstallSelf) {
1761 constexpr char kManifest[] =
1762 R"({
1763 "name": "Test Extension",
1764 "manifest_version": 2,
1765 "version": "0.1",
1766 "background": {"service_worker": "script.js"}
1767 })";
1768
1769 // This script uninstalls itself.
1770 constexpr char kScript[] =
1771 "chrome.management.uninstallSelf({showConfirmDialog: false});";
1772
1773 TestExtensionDir test_dir;
1774
1775 test_dir.WriteManifest(kManifest);
1776 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"), kScript);
1777
David Bertoni67977a32019-06-13 22:46:011778 // Construct this before loading the extension, since the extension will
David Bertoni1dc1b7a2019-06-13 02:44:591779 // immediately uninstall itself when it loads.
1780 extensions::TestExtensionRegistryObserver observer(
1781 extensions::ExtensionRegistry::Get(browser()->profile()));
1782
1783 base::FilePath path = test_dir.Pack();
1784 scoped_refptr<const Extension> extension = LoadExtension(path);
1785
1786 EXPECT_EQ(extension, observer.WaitForExtensionUninstalled());
1787}
1788
David Bertoni4d9cf41d2019-06-04 00:06:221789IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
1790 PRE_EventsAfterRestart) {
1791 ExtensionTestMessageListener event_added_listener("ready", false);
1792 const Extension* extension = LoadExtensionWithFlags(
1793 test_data_dir_.AppendASCII(
1794 "service_worker/worker_based_background/events_to_stopped_extension"),
1795 kFlagNone);
1796 ASSERT_TRUE(extension);
1797 EXPECT_EQ(kTestExtensionId, extension->id());
1798 ProcessManager* pm = ProcessManager::Get(browser()->profile());
1799 // TODO(crbug.com/969884): This will break once keep alive counts
1800 // for service workers are tracked by the Process Manager.
1801 EXPECT_LT(pm->GetLazyKeepaliveCount(extension), 1);
1802 EXPECT_TRUE(pm->GetLazyKeepaliveActivities(extension).empty());
1803 EXPECT_TRUE(event_added_listener.WaitUntilSatisfied());
1804}
1805
1806// After browser restarts, this test step ensures that opening a tab fires
1807// tabs.onCreated event listener to the extension without explicitly loading the
1808// extension. This is because the extension registered a listener for
1809// tabs.onMoved before browser restarted in PRE_EventsAfterRestart.
1810IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, EventsAfterRestart) {
1811 // Verify there is no RenderProcessHost for the extension.
David Bertoni023e0ec2019-06-10 17:28:221812 EXPECT_FALSE(ExtensionHasRenderProcessHost(kTestExtensionId));
David Bertoni4d9cf41d2019-06-04 00:06:221813
1814 ExtensionTestMessageListener moved_tab_listener("moved-tab", false);
1815 // Add a tab, then move it.
1816 content::WebContents* new_web_contents =
1817 AddTab(browser(), GURL(url::kAboutBlankURL));
1818 EXPECT_TRUE(new_web_contents);
1819 browser()->tab_strip_model()->MoveWebContentsAt(
1820 browser()->tab_strip_model()->count() - 1, 0, false);
1821 EXPECT_TRUE(moved_tab_listener.WaitUntilSatisfied());
1822}
1823
Istiaque Ahmed1e59aec2019-06-05 22:40:241824IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, TabsOnCreated) {
1825 ASSERT_TRUE(RunExtensionTestWithFlags("tabs/lazy_background_on_created",
1826 kFlagRunAsServiceWorkerBasedExtension))
1827 << message_;
1828}
1829
David Bertoni023e0ec2019-06-10 17:28:221830IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
1831 PRE_FilteredEventsAfterRestart) {
1832 ExtensionTestMessageListener listener_added("ready", false);
1833 const Extension* extension = LoadExtensionWithFlags(
1834 test_data_dir_.AppendASCII("service_worker/worker_based_background/"
1835 "filtered_events_after_restart"),
1836 kFlagNone);
1837 ASSERT_TRUE(extension);
1838 EXPECT_EQ(kTestExtensionId, extension->id());
1839 ProcessManager* pm = ProcessManager::Get(browser()->profile());
1840 // TODO(crbug.com/969884): This will break once keep alive counts
1841 // for service workers are tracked by the Process Manager.
1842 EXPECT_LT(pm->GetLazyKeepaliveCount(extension), 1);
1843 EXPECT_TRUE(pm->GetLazyKeepaliveActivities(extension).empty());
1844 EXPECT_TRUE(listener_added.WaitUntilSatisfied());
1845}
1846
1847// After browser restarts, this test step ensures that opening a tab fires
1848// tabs.onCreated event listener to the extension without explicitly loading the
1849// extension. This is because the extension registered a listener for
1850// tabs.onMoved before browser restarted in PRE_EventsAfterRestart.
1851IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
1852 FilteredEventsAfterRestart) {
1853 // Verify there is no RenderProcessHost for the extension.
1854 // TODO(crbug.com/971309): This is currently broken because the test
1855 // infrastructure opens a tab, which dispatches an event to our
1856 // extension, even though the filter doesn't include that URL. The
1857 // referenced bug is about moving filtering into the EventRouter so they
1858 // get filtered before being dispatched.
1859 EXPECT_TRUE(ExtensionHasRenderProcessHost(kTestExtensionId));
1860
1861 // Create a tab to a.html, expect it to navigate to b.html. The service worker
1862 // will see two webNavigation.onCommitted events.
1863 GURL page_url = embedded_test_server()->GetURL(
1864 "/extensions/api_test/service_worker/worker_based_background/"
1865 "filtered_events_after_restart/"
1866 "a.html");
1867 ExtensionTestMessageListener worker_filtered_event_listener(
1868 "PASS_FROM_WORKER", false);
1869 worker_filtered_event_listener.set_failure_message("FAIL_FROM_WORKER");
1870 content::WebContents* web_contents = AddTab(browser(), page_url);
1871 EXPECT_TRUE(web_contents);
1872 EXPECT_TRUE(worker_filtered_event_listener.WaitUntilSatisfied());
1873}
1874
Istiaque Ahmed91d6987c2019-06-25 00:09:331875// Tests that chrome.browserAction.onClicked sees user gesture.
1876IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
1877 BrowserActionUserGesture) {
1878 // First, load |extension| first so that it has browserAction.onClicked
1879 // listener registered.
1880 ExtensionTestMessageListener listener_added("ready", false);
1881 const Extension* extension = LoadExtension(
1882 test_data_dir_.AppendASCII("service_worker/worker_based_background/"
1883 "browser_action"));
1884 ASSERT_TRUE(extension);
1885 EXPECT_TRUE(listener_added.WaitUntilSatisfied());
1886
1887 ResultCatcher catcher;
1888 // Click on browser action to start the test.
1889 {
1890 content::WebContents* web_contents = AddTab(browser(), GURL("about:blank"));
1891 ASSERT_TRUE(web_contents);
1892 ExtensionActionRunner::GetForWebContents(
1893 browser()->tab_strip_model()->GetActiveWebContents())
1894 ->RunAction(extension, true);
1895 }
1896 EXPECT_TRUE(catcher.GetNextResult()) << message_;
1897}
1898
Istiaque Ahmed242a4102019-06-25 01:47:571899// Tests that Service Worker notification handlers can call extension APIs that
1900// require user gesture to be present.
1901IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTestWithNotification,
1902 ServiceWorkerNotificationClick) {
1903 ResultCatcher catcher;
1904 const Extension* extension = LoadExtension(
1905 test_data_dir_.AppendASCII("service_worker/worker_based_background/"
1906 "notification_click"));
1907 ASSERT_TRUE(extension);
1908 EXPECT_TRUE(catcher.GetNextResult()) << message_;
1909
1910 // Click on the Service Worker notification.
1911 {
1912 std::vector<message_center::Notification> notifications =
1913 GetDisplayedNotifications();
1914 ASSERT_EQ(1u, notifications.size());
1915 display_service_tester_->SimulateClick(
1916 NotificationHandler::Type::WEB_PERSISTENT, notifications[0].id(),
1917 base::nullopt, base::nullopt);
1918 }
1919
1920 EXPECT_TRUE(catcher.GetNextResult()) << message_;
1921}
1922
Devlin Cronin59551d82019-03-05 01:28:591923// Tests that console messages logged by extension service workers, both via
1924// the typical console.* methods and via our custom bindings console, are
1925// passed through the normal ServiceWorker console messaging and are
1926// observable.
Devlin Cronin242d19d22019-03-12 18:08:481927IN_PROC_BROWSER_TEST_F(ServiceWorkerLazyBackgroundTest, ConsoleLogging) {
Devlin Cronin59551d82019-03-05 01:28:591928 // A helper class to wait for a particular message to be logged from a
1929 // ServiceWorker.
1930 class ConsoleMessageObserver : public content::ServiceWorkerContextObserver {
1931 public:
1932 ConsoleMessageObserver(content::BrowserContext* browser_context,
1933 const std::string& expected_message)
1934 : expected_message_(base::UTF8ToUTF16(expected_message)),
1935 scoped_observer_(this) {
1936 content::StoragePartition* partition =
1937 content::BrowserContext::GetDefaultStoragePartition(browser_context);
1938 scoped_observer_.Add(partition->GetServiceWorkerContext());
1939 }
1940 ~ConsoleMessageObserver() override = default;
1941
1942 void Wait() { run_loop_.Run(); }
1943
1944 private:
1945 // ServiceWorkerContextObserver:
1946 void OnReportConsoleMessage(
1947 int64_t version_id,
1948 const content::ConsoleMessage& message) override {
1949 // NOTE: We could check the version_id, but it shouldn't be necessary with
1950 // the expected messages we're verifying (they're uncommon enough).
1951 if (message.message != expected_message_)
1952 return;
1953 scoped_observer_.RemoveAll();
1954 run_loop_.QuitWhenIdle();
1955 }
1956
1957 base::string16 expected_message_;
1958 base::RunLoop run_loop_;
1959 ScopedObserver<content::ServiceWorkerContext,
1960 content::ServiceWorkerContextObserver>
1961 scoped_observer_;
1962
1963 DISALLOW_COPY_AND_ASSIGN(ConsoleMessageObserver);
1964 };
1965
1966 TestExtensionDir test_dir;
1967 test_dir.WriteManifest(
1968 R"({
1969 "name": "Test Extension",
1970 "manifest_version": 2,
1971 "version": "0.1",
David Bertoni630837d2019-04-02 21:22:101972 "background": {"service_worker": "script.js"}
Devlin Cronin59551d82019-03-05 01:28:591973 })");
1974 constexpr char kScript[] =
1975 R"(// First, log a message using the normal, built-in blink console.
1976 console.log('test message');
1977 chrome.test.runTests([
1978 function justATest() {
1979 // Next, we use the "Console" object from
1980 // extensions/renderer/console.cc, which is used by custom bindings
1981 // so that it isn't tampered with by untrusted script. The test
1982 // custom bindings log a message whenever a test is passed, so we
1983 // force a log by just passing this test.
1984 chrome.test.succeed();
1985 }
1986 ]);)";
1987 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"), kScript);
1988
1989 // The observer for the built-in blink console.
1990 ConsoleMessageObserver default_console_observer(profile(), "test message");
1991 // The observer for our custom extensions bindings console.
1992 ConsoleMessageObserver custom_console_observer(profile(),
1993 "[SUCCESS] justATest");
1994
1995 const Extension* extension = LoadExtension(test_dir.UnpackedPath());
1996 ASSERT_TRUE(extension);
1997
1998 default_console_observer.Wait();
1999 custom_console_observer.Wait();
2000 // If we receive both messages, we passed!
2001}
2002
annekao38685502015-07-14 17:46:392003} // namespace extensions