blob: 9248c6e09820481a7dee005e2d7d4bb169ecabe0 [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"
Istiaque Ahmed3dd604232019-08-02 19:22:2118#include "chrome/browser/extensions/api/permissions/permissions_api.h"
Istiaque Ahmed3f692562019-07-26 22:59:2619#include "chrome/browser/extensions/browsertest_util.h"
David Bertoni9026eff2019-05-01 18:04:3120#include "chrome/browser/extensions/crx_installer.h"
Istiaque Ahmed91d6987c2019-06-25 00:09:3321#include "chrome/browser/extensions/extension_action_runner.h"
annekao38685502015-07-14 17:46:3922#include "chrome/browser/extensions/extension_apitest.h"
rdevlin.croninf5863da2015-09-10 19:21:4523#include "chrome/browser/extensions/extension_service.h"
Istiaque Ahmed805f6a83b2017-10-05 01:23:2624#include "chrome/browser/extensions/lazy_background_page_test_util.h"
David Bertoni1d646a152019-04-25 02:09:2225#include "chrome/browser/extensions/unpacked_installer.h"
peter9f4490a2017-01-27 00:58:3626#include "chrome/browser/gcm/gcm_profile_service_factory.h"
miguelg9b502862017-04-24 18:13:5327#include "chrome/browser/notifications/notification_display_service_factory.h"
Istiaque Ahmed242a4102019-06-25 01:47:5728#include "chrome/browser/notifications/notification_display_service_tester.h"
Peter Beverloodd4ef1e2018-06-21 15:41:0429#include "chrome/browser/notifications/notification_permission_context.h"
miguelg9b502862017-04-24 18:13:5330#include "chrome/browser/notifications/stub_notification_display_service.h"
lshang106c1772016-06-06 01:43:2331#include "chrome/browser/permissions/permission_manager.h"
timlohc6911802017-03-01 05:37:0332#include "chrome/browser/permissions/permission_result.h"
lazyboy561b7de2015-11-19 19:27:3033#include "chrome/browser/push_messaging/push_messaging_app_identifier.h"
34#include "chrome/browser/push_messaging/push_messaging_service_factory.h"
35#include "chrome/browser/push_messaging/push_messaging_service_impl.h"
Istiaque Ahmed91d6987c2019-06-25 00:09:3336#include "chrome/browser/ui/extensions/browser_action_test_util.h"
annekao1db36fd2015-07-29 17:09:1637#include "chrome/browser/ui/tabs/tab_strip_model.h"
Trent Apted4267b942017-10-27 03:25:3638#include "chrome/common/chrome_switches.h"
Istiaque Ahmeda14ec482018-08-25 01:02:1839#include "chrome/common/extensions/api/web_navigation.h"
rdevlin.croninf5863da2015-09-10 19:21:4540#include "chrome/test/base/ui_test_utils.h"
timloh9a180ad2017-02-20 07:15:2341#include "components/content_settings/core/common/content_settings_types.h"
Peter Beverloo34139462018-04-10 14:18:0642#include "components/gcm_driver/fake_gcm_profile_service.h"
johnmea5045732016-09-08 17:23:2943#include "components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h"
sdefresne9fb67692015-08-03 18:48:2244#include "components/version_info/version_info.h"
Devlin Cronin59551d82019-03-05 01:28:5945#include "content/public/browser/console_message.h"
kalman6f984ae2015-09-18 17:21:5846#include "content/public/browser/navigation_controller.h"
rdevlin.croninf5863da2015-09-10 19:21:4547#include "content/public/browser/navigation_entry.h"
Istiaque Ahmedd4b67ee2019-03-02 10:53:2048#include "content/public/browser/render_process_host.h"
lazyboy4c82177a2016-10-18 00:04:0949#include "content/public/browser/service_worker_context.h"
Devlin Cronin59551d82019-03-05 01:28:5950#include "content/public/browser/service_worker_context_observer.h"
lazyboy4c82177a2016-10-18 00:04:0951#include "content/public/browser/storage_partition.h"
kalman6f984ae2015-09-18 17:21:5852#include "content/public/browser/web_contents.h"
lazyboybd325ae2015-11-18 21:35:2653#include "content/public/common/content_switches.h"
falkenad185092016-06-16 06:10:0254#include "content/public/common/origin_util.h"
kalman6f984ae2015-09-18 17:21:5855#include "content/public/common/page_type.h"
Istiaque Ahmedd4b67ee2019-03-02 10:53:2056#include "content/public/common/result_codes.h"
lazyboybd325ae2015-11-18 21:35:2657#include "content/public/test/background_sync_test_util.h"
annekao1db36fd2015-07-29 17:09:1658#include "content/public/test/browser_test_utils.h"
lazyboy63b994a2017-06-30 21:20:2359#include "content/public/test/service_worker_test_helpers.h"
Istiaque Ahmed771aa8a22018-06-20 23:40:5360#include "extensions/browser/event_router.h"
kalman6f984ae2015-09-18 17:21:5861#include "extensions/browser/extension_host.h"
lazyboyc3e763a2015-12-09 23:09:5862#include "extensions/browser/extension_registry.h"
kalman6f984ae2015-09-18 17:21:5863#include "extensions/browser/process_manager.h"
Istiaque Ahmed70f76ac2018-11-02 02:59:5564#include "extensions/browser/service_worker_task_queue.h"
Istiaque Ahmeda14ec482018-08-25 01:02:1865#include "extensions/common/api/test.h"
Istiaque Ahmed3dd604232019-08-02 19:22:2166#include "extensions/common/permissions/permissions_data.h"
Istiaque Ahmed771aa8a22018-06-20 23:40:5367#include "extensions/common/value_builder.h"
David Bertoni9026eff2019-05-01 18:04:3168#include "extensions/common/verifier_formats.h"
kalman6f984ae2015-09-18 17:21:5869#include "extensions/test/background_page_watcher.h"
annekao38685502015-07-14 17:46:3970#include "extensions/test/extension_test_message_listener.h"
Istiaque Ahmed805f6a83b2017-10-05 01:23:2671#include "extensions/test/result_catcher.h"
Devlin Cronin59551d82019-03-05 01:28:5972#include "extensions/test/test_extension_dir.h"
falkenad185092016-06-16 06:10:0273#include "net/dns/mock_host_resolver.h"
horo1eeddde2015-11-19 05:59:2574#include "net/test/embedded_test_server/embedded_test_server.h"
Istiaque Ahmed242a4102019-06-25 01:47:5775#include "ui/message_center/public/cpp/notification.h"
lazyboy63b994a2017-06-30 21:20:2376#include "url/url_constants.h"
annekao38685502015-07-14 17:46:3977
78namespace extensions {
79
kalman6f984ae2015-09-18 17:21:5880namespace {
81
lazyboy22eddc712015-12-10 21:16:2682class WebContentsLoadStopObserver : content::WebContentsObserver {
83 public:
84 explicit WebContentsLoadStopObserver(content::WebContents* web_contents)
85 : content::WebContentsObserver(web_contents),
86 load_stop_observed_(false) {}
87
88 void WaitForLoadStop() {
89 if (load_stop_observed_)
90 return;
91 message_loop_runner_ = new content::MessageLoopRunner;
92 message_loop_runner_->Run();
93 }
94
95 private:
96 void DidStopLoading() override {
97 load_stop_observed_ = true;
98 if (message_loop_runner_)
99 message_loop_runner_->Quit();
100 }
101
102 bool load_stop_observed_;
103 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
104
105 DISALLOW_COPY_AND_ASSIGN(WebContentsLoadStopObserver);
106};
107
David Bertoni4d9cf41d2019-06-04 00:06:22108// A known extension ID for tests that specify the key in their
109// manifests.
110constexpr char kTestExtensionId[] = "knldjmfmopnpolahpmmgbagdohdnhkik";
111
kalman6f984ae2015-09-18 17:21:58112} // namespace
113
Devlin Cronin242d19d22019-03-12 18:08:48114class ServiceWorkerTest : public ExtensionApiTest {
annekao38685502015-07-14 17:46:39115 public:
lazyboy20167c22016-05-18 00:59:30116 ServiceWorkerTest() : current_channel_(version_info::Channel::STABLE) {}
Istiaque Ahmed7105f2a2017-10-07 01:11:59117 explicit ServiceWorkerTest(version_info::Channel channel)
118 : current_channel_(channel) {}
annekao38685502015-07-14 17:46:39119
120 ~ServiceWorkerTest() override {}
121
jam1a5b5582017-05-01 16:50:10122 void SetUpOnMainThread() override {
123 ExtensionApiTest::SetUpOnMainThread();
David Bertoni3929f552019-03-28 22:10:36124 host_resolver()->AddRule("*", "127.0.0.1");
jam1a5b5582017-05-01 16:50:10125 }
126
kalman6f984ae2015-09-18 17:21:58127 protected:
128 // Returns the ProcessManager for the test's profile.
129 ProcessManager* process_manager() { return ProcessManager::Get(profile()); }
130
131 // Starts running a test from the background page test extension.
132 //
133 // This registers a service worker with |script_name|, and fetches the
134 // registration result.
Istiaque Ahmed93ff7f42018-08-31 01:42:22135 const Extension* StartTestFromBackgroundPage(const char* script_name) {
Istiaque Ahmed6475f542018-08-28 04:20:21136 ExtensionTestMessageListener ready_listener("ready", false);
kalman6f984ae2015-09-18 17:21:58137 const Extension* extension =
138 LoadExtension(test_data_dir_.AppendASCII("service_worker/background"));
139 CHECK(extension);
Istiaque Ahmed6475f542018-08-28 04:20:21140 CHECK(ready_listener.WaitUntilSatisfied());
141
kalman6f984ae2015-09-18 17:21:58142 ExtensionHost* background_host =
143 process_manager()->GetBackgroundHostForExtension(extension->id());
144 CHECK(background_host);
Istiaque Ahmed6475f542018-08-28 04:20:21145
kalman6f984ae2015-09-18 17:21:58146 std::string error;
147 CHECK(content::ExecuteScriptAndExtractString(
148 background_host->host_contents(),
149 base::StringPrintf("test.registerServiceWorker('%s')", script_name),
150 &error));
Istiaque Ahmed93ff7f42018-08-31 01:42:22151 if (!error.empty())
kalman6f984ae2015-09-18 17:21:58152 ADD_FAILURE() << "Got unexpected error " << error;
153 return extension;
154 }
155
156 // Navigates the browser to a new tab at |url|, waits for it to load, then
157 // returns it.
158 content::WebContents* Navigate(const GURL& url) {
159 ui_test_utils::NavigateToURLWithDisposition(
nick3b04f322016-08-31 19:29:19160 browser(), url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
kalman6f984ae2015-09-18 17:21:58161 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
162 content::WebContents* web_contents =
163 browser()->tab_strip_model()->GetActiveWebContents();
164 content::WaitForLoadStop(web_contents);
165 return web_contents;
166 }
167
168 // Navigates the browser to |url| and returns the new tab's page type.
169 content::PageType NavigateAndGetPageType(const GURL& url) {
clamy1d7a4112018-06-15 15:47:16170 return Navigate(url)
171 ->GetController()
172 .GetLastCommittedEntry()
173 ->GetPageType();
kalman6f984ae2015-09-18 17:21:58174 }
175
176 // Extracts the innerText from |contents|.
177 std::string ExtractInnerText(content::WebContents* contents) {
178 std::string inner_text;
179 if (!content::ExecuteScriptAndExtractString(
180 contents,
181 "window.domAutomationController.send(document.body.innerText)",
182 &inner_text)) {
183 ADD_FAILURE() << "Failed to get inner text for "
184 << contents->GetVisibleURL();
185 }
186 return inner_text;
187 }
188
189 // Navigates the browser to |url|, then returns the innerText of the new
190 // tab's WebContents' main frame.
191 std::string NavigateAndExtractInnerText(const GURL& url) {
192 return ExtractInnerText(Navigate(url));
193 }
194
lazyboy4c82177a2016-10-18 00:04:09195 size_t GetWorkerRefCount(const GURL& origin) {
196 content::ServiceWorkerContext* sw_context =
197 content::BrowserContext::GetDefaultStoragePartition(
198 browser()->profile())
199 ->GetServiceWorkerContext();
200 base::RunLoop run_loop;
201 size_t ref_count = 0;
202 auto set_ref_count = [](size_t* ref_count, base::RunLoop* run_loop,
203 size_t external_request_count) {
204 *ref_count = external_request_count;
205 run_loop->Quit();
206 };
207 sw_context->CountExternalRequestsForTest(
Matt Falkenhagenc5cb4282017-09-07 08:43:42208 origin, base::BindOnce(set_ref_count, &ref_count, &run_loop));
lazyboy4c82177a2016-10-18 00:04:09209 run_loop.Run();
210 return ref_count;
211 }
212
annekao38685502015-07-14 17:46:39213 private:
lazyboy20167c22016-05-18 00:59:30214 // Sets the channel to "stable".
215 // Not useful after we've opened extension Service Workers to stable
216 // channel.
217 // TODO(lazyboy): Remove this when ExtensionServiceWorkersEnabled() is
218 // removed.
annekao38685502015-07-14 17:46:39219 ScopedCurrentChannel current_channel_;
kalman6f984ae2015-09-18 17:21:58220
annekao38685502015-07-14 17:46:39221 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerTest);
222};
223
Istiaque Ahmedccb444022018-06-19 02:11:12224class ServiceWorkerBasedBackgroundTest : public ServiceWorkerTest {
225 public:
226 ServiceWorkerBasedBackgroundTest()
227 : ServiceWorkerTest(
228 // Extensions APIs from SW are only enabled on trunk.
229 // It is important to set the channel early so that this change is
230 // visible in renderers running with service workers (and no
231 // extension).
232 version_info::Channel::UNKNOWN) {}
233 ~ServiceWorkerBasedBackgroundTest() override {}
234
235 void SetUpOnMainThread() override {
236 host_resolver()->AddRule("*", "127.0.0.1");
237 ASSERT_TRUE(embedded_test_server()->Start());
238 ServiceWorkerTest::SetUpOnMainThread();
239 }
240
Istiaque Ahmedd4b67ee2019-03-02 10:53:20241 // Returns the only running worker id for |extension_id|.
242 // Returns base::nullopt if there isn't any worker running or more than one
243 // worker is running for |extension_id|.
244 base::Optional<WorkerId> GetUniqueRunningWorkerId(
245 const ExtensionId& extension_id) {
246 ProcessManager* process_manager = ProcessManager::Get(profile());
247 std::vector<WorkerId> all_workers =
248 process_manager->GetAllWorkersIdsForTesting();
249 base::Optional<WorkerId> running_worker_id;
250 for (const WorkerId& worker_id : all_workers) {
251 if (worker_id.extension_id == extension_id) {
252 if (running_worker_id) // More than one worker present.
253 return base::nullopt;
254 running_worker_id = worker_id;
255 }
256 }
257 return running_worker_id;
258 }
259
David Bertoni023e0ec2019-06-10 17:28:22260 bool ExtensionHasRenderProcessHost(const ExtensionId& extension_id) {
261 ProcessMap* process_map = ProcessMap::Get(browser()->profile());
262 content::RenderProcessHost::iterator it =
263 content::RenderProcessHost::AllHostsIterator();
264 while (!it.IsAtEnd()) {
265 if (process_map->Contains(extension_id, it.GetCurrentValue()->GetID())) {
266 return true;
267 }
268 it.Advance();
269 }
270 return false;
271 }
272
Istiaque Ahmedccb444022018-06-19 02:11:12273 private:
274 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerBasedBackgroundTest);
275};
276
Istiaque Ahmed242a4102019-06-25 01:47:57277class ServiceWorkerBasedBackgroundTestWithNotification
278 : public ServiceWorkerBasedBackgroundTest {
279 public:
280 ServiceWorkerBasedBackgroundTestWithNotification() {}
281 ~ServiceWorkerBasedBackgroundTestWithNotification() override = default;
282
283 void SetUpOnMainThread() override {
284 ServiceWorkerBasedBackgroundTest::SetUpOnMainThread();
285 display_service_tester_ =
286 std::make_unique<NotificationDisplayServiceTester>(
287 browser()->profile());
288 }
289
290 void TearDownOnMainThread() override {
291 display_service_tester_.reset();
292 ServiceWorkerBasedBackgroundTest::TearDownOnMainThread();
293 }
294
295 protected:
296 // Returns a vector with the Notification objects that are being displayed
297 // by the notification display service. Synchronous.
298 std::vector<message_center::Notification> GetDisplayedNotifications() const {
299 return display_service_tester_->GetDisplayedNotificationsForType(
300 NotificationHandler::Type::WEB_PERSISTENT);
301 }
302
303 std::unique_ptr<NotificationDisplayServiceTester> display_service_tester_;
304
305 private:
306 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerBasedBackgroundTestWithNotification);
307};
308
Istiaque Ahmedccb444022018-06-19 02:11:12309// Tests that Service Worker based background pages can be loaded and they can
310// receive extension events.
311// The extension is installed and loaded during this step and it registers
312// an event listener for tabs.onCreated event. The step also verifies that tab
313// creation correctly fires the listener.
Devlin Cronin242d19d22019-03-12 18:08:48314IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, PRE_Basic) {
Istiaque Ahmedccb444022018-06-19 02:11:12315 ExtensionTestMessageListener newtab_listener("CREATED", false);
316 newtab_listener.set_failure_message("CREATE_FAILED");
317 ExtensionTestMessageListener worker_listener("WORKER_RUNNING", false);
318 worker_listener.set_failure_message("NON_WORKER_SCOPE");
319 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
320 "service_worker/worker_based_background/basic"));
321 ASSERT_TRUE(extension);
322 const ExtensionId extension_id = extension->id();
323 EXPECT_TRUE(worker_listener.WaitUntilSatisfied());
324
325 const GURL url = embedded_test_server()->GetURL("/extensions/test_file.html");
Istiaque Ahmed3f692562019-07-26 22:59:26326 content::WebContents* new_web_contents =
327 browsertest_util::AddTab(browser(), url);
Istiaque Ahmedccb444022018-06-19 02:11:12328 EXPECT_TRUE(new_web_contents);
329 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
330
331 // Service Worker extension does not have ExtensionHost.
332 EXPECT_FALSE(process_manager()->GetBackgroundHostForExtension(extension_id));
333}
334
335// After browser restarts, this test step ensures that opening a tab fires
336// tabs.onCreated event listener to the extension without explicitly loading the
337// extension. This is because the extension registered a listener before browser
338// restarted in PRE_Basic.
Devlin Cronin242d19d22019-03-12 18:08:48339IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, Basic) {
Istiaque Ahmedccb444022018-06-19 02:11:12340 ExtensionTestMessageListener newtab_listener("CREATED", false);
341 newtab_listener.set_failure_message("CREATE_FAILED");
342 const GURL url = embedded_test_server()->GetURL("/extensions/test_file.html");
Istiaque Ahmed3f692562019-07-26 22:59:26343 content::WebContents* new_web_contents =
344 browsertest_util::AddTab(browser(), url);
Istiaque Ahmedccb444022018-06-19 02:11:12345 EXPECT_TRUE(new_web_contents);
346 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
347}
348
Istiaque Ahmedbf08f952018-10-02 01:22:04349// Tests chrome.runtime.onInstalled fires for extension service workers.
Devlin Cronin242d19d22019-03-12 18:08:48350IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, OnInstalledEvent) {
Istiaque Ahmedbf08f952018-10-02 01:22:04351 ASSERT_TRUE(RunExtensionTest(
352 "service_worker/worker_based_background/events_on_installed"))
353 << message_;
354}
355
Istiaque Ahmedba8d0652019-05-14 15:17:34356// Tests chrome.runtime.id and chrome.runtime.getURL().
357IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, RuntimeMisc) {
358 ASSERT_TRUE(
359 RunExtensionTest("service_worker/worker_based_background/runtime_misc"))
360 << message_;
361}
362
David Bertoni69982832019-02-13 21:24:21363// Tests chrome.storage APIs.
Devlin Cronin242d19d22019-03-12 18:08:48364IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, StorageSetAndGet) {
David Bertoni69982832019-02-13 21:24:21365 ASSERT_TRUE(
366 RunExtensionTest("service_worker/worker_based_background/storage"))
367 << message_;
368}
369
David Bertoni0665c892019-02-14 00:27:26370// Tests chrome.storage.local and chrome.storage.local APIs.
Devlin Cronin242d19d22019-03-12 18:08:48371IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, StorageNoPermissions) {
David Bertoni0665c892019-02-14 00:27:26372 ASSERT_TRUE(RunExtensionTest(
373 "service_worker/worker_based_background/storage_no_permissions"))
374 << message_;
375}
376
David Bertoni30809312019-02-28 22:56:05377// Tests chrome.tabs APIs.
Devlin Cronin242d19d22019-03-12 18:08:48378IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, TabsBasic) {
David Bertoni30809312019-02-28 22:56:05379 ASSERT_TRUE(
380 RunExtensionTest("service_worker/worker_based_background/tabs_basic"))
381 << message_;
382}
383
David Bertoni46d698892019-02-26 00:29:10384// Tests chrome.tabs events.
Devlin Cronin242d19d22019-03-12 18:08:48385IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, TabsEvents) {
David Bertoni46d698892019-02-26 00:29:10386 ASSERT_TRUE(
387 RunExtensionTest("service_worker/worker_based_background/tabs_events"))
388 << message_;
389}
390
David Bertoni4c7dfcc2019-03-27 23:49:34391// Tests chrome.tabs APIs.
392IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, TabsExecuteScript) {
393 ASSERT_TRUE(RunExtensionTest(
394 "service_worker/worker_based_background/tabs_execute_script"))
395 << message_;
396}
397
David Bertoni37ae0222019-04-04 01:30:54398// Tests chrome.webRequest APIs.
David Bertoni3929f552019-03-28 22:10:36399IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, WebRequest) {
400 ASSERT_TRUE(
401 RunExtensionTest("service_worker/worker_based_background/web_request"))
402 << message_;
403}
404
David Bertoni37ae0222019-04-04 01:30:54405// Tests chrome.webRequest APIs in blocking mode.
406IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, WebRequestBlocking) {
407 // Try to load the page before installing the extension, which should work.
408 const GURL url = embedded_test_server()->GetURL("/extensions/test_file.html");
409 EXPECT_EQ(content::PAGE_TYPE_NORMAL, NavigateAndGetPageType(url));
410
411 // Install the extension and navigate again to the page.
412 ExtensionTestMessageListener ready_listener("ready", false);
413 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII(
414 "service_worker/worker_based_background/web_request_blocking")));
415 ASSERT_TRUE(ready_listener.WaitUntilSatisfied());
416 EXPECT_EQ(content::PAGE_TYPE_ERROR, NavigateAndGetPageType(url));
417}
418
David Bertoni377f52312019-05-21 20:35:03419// Tests chrome.webNavigation APIs.
420IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, FilteredEvents) {
421 ASSERT_TRUE(RunExtensionTest(
422 "service_worker/worker_based_background/filtered_events"))
423 << message_;
424}
425
Istiaque Ahmed70f76ac2018-11-02 02:59:55426// Listens for |message| from extension Service Worker early so that tests can
427// wait for the message on startup (and not miss it).
428class ServiceWorkerWithEarlyMessageListenerTest
429 : public ServiceWorkerBasedBackgroundTest {
Istiaque Ahmedf70ab222018-10-02 03:08:24430 public:
Istiaque Ahmed70f76ac2018-11-02 02:59:55431 explicit ServiceWorkerWithEarlyMessageListenerTest(
432 const std::string& test_message)
433 : test_message_(test_message) {}
434 ~ServiceWorkerWithEarlyMessageListenerTest() override = default;
Istiaque Ahmedf70ab222018-10-02 03:08:24435
Istiaque Ahmed70f76ac2018-11-02 02:59:55436 bool WaitForMessage() { return listener_->WaitUntilSatisfied(); }
Istiaque Ahmedf70ab222018-10-02 03:08:24437
438 void CreatedBrowserMainParts(content::BrowserMainParts* main_parts) override {
439 // At this point, the notification service is initialized but the profile
440 // and extensions have not.
Istiaque Ahmed70f76ac2018-11-02 02:59:55441 listener_ =
442 std::make_unique<ExtensionTestMessageListener>(test_message_, false);
Istiaque Ahmedf70ab222018-10-02 03:08:24443 ServiceWorkerBasedBackgroundTest::CreatedBrowserMainParts(main_parts);
444 }
445
446 private:
Istiaque Ahmed70f76ac2018-11-02 02:59:55447 const std::string test_message_;
Istiaque Ahmedf70ab222018-10-02 03:08:24448 std::unique_ptr<ExtensionTestMessageListener> listener_;
449
Istiaque Ahmed70f76ac2018-11-02 02:59:55450 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerWithEarlyMessageListenerTest);
451};
452
453class ServiceWorkerOnStartupEventTest
454 : public ServiceWorkerWithEarlyMessageListenerTest {
455 public:
456 ServiceWorkerOnStartupEventTest()
457 : ServiceWorkerWithEarlyMessageListenerTest("onStartup event") {}
458 ~ServiceWorkerOnStartupEventTest() override = default;
459
460 private:
461 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerOnStartupEventTest);
Istiaque Ahmedf70ab222018-10-02 03:08:24462};
463
464// Tests "runtime.onStartup" for extension SW.
Devlin Cronin242d19d22019-03-12 18:08:48465IN_PROC_BROWSER_TEST_F(ServiceWorkerOnStartupEventTest, PRE_Event) {
Istiaque Ahmedf70ab222018-10-02 03:08:24466 ASSERT_TRUE(RunExtensionTest(
467 "service_worker/worker_based_background/on_startup_event"))
468 << message_;
469}
470
Devlin Cronin242d19d22019-03-12 18:08:48471IN_PROC_BROWSER_TEST_F(ServiceWorkerOnStartupEventTest, Event) {
Istiaque Ahmed70f76ac2018-11-02 02:59:55472 EXPECT_TRUE(WaitForMessage());
473}
474
475class ServiceWorkerRegistrationAtStartupTest
476 : public ServiceWorkerWithEarlyMessageListenerTest,
477 public ServiceWorkerTaskQueue::TestObserver {
478 public:
479 ServiceWorkerRegistrationAtStartupTest()
480 : ServiceWorkerWithEarlyMessageListenerTest("WORKER_RUNNING") {
481 ServiceWorkerTaskQueue::SetObserverForTest(this);
482 }
483 ~ServiceWorkerRegistrationAtStartupTest() override {
484 ServiceWorkerTaskQueue::SetObserverForTest(nullptr);
485 }
486
487 // ServiceWorkerTaskQueue::TestObserver:
488 void OnActivateExtension(const ExtensionId& extension_id,
489 bool will_register_service_worker) override {
490 if (extension_id != kExtensionId)
491 return;
492
493 will_register_service_worker_ = will_register_service_worker;
494
495 extension_activated_ = true;
496 if (run_loop_)
497 run_loop_->Quit();
498 }
499
500 void WaitForOnActivateExtension() {
501 if (extension_activated_)
502 return;
503 run_loop_ = std::make_unique<base::RunLoop>();
504 run_loop_->Run();
505 }
506
507 bool WillRegisterServiceWorker() {
508 return will_register_service_worker_.value();
509 }
510
511 protected:
512 static const char kExtensionId[];
513
514 private:
515 bool extension_activated_ = false;
516 base::Optional<bool> will_register_service_worker_;
517 std::unique_ptr<base::RunLoop> run_loop_;
518
519 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerRegistrationAtStartupTest);
520};
521
522// Test extension id at
523// api_test/service_worker/worker_based_background/registration_at_startup/.
524const char ServiceWorkerRegistrationAtStartupTest::kExtensionId[] =
525 "gnchfmandajfaiajniicagenfmhdjila";
526
527// Tests that Service Worker registration for existing extension isn't issued
528// upon browser restart.
529// Regression test for https://crbug.com/889687.
Devlin Cronin242d19d22019-03-12 18:08:48530IN_PROC_BROWSER_TEST_F(ServiceWorkerRegistrationAtStartupTest,
Istiaque Ahmed70f76ac2018-11-02 02:59:55531 PRE_ExtensionActivationDoesNotReregister) {
532 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
533 "service_worker/worker_based_background/registration_at_startup"));
534 ASSERT_TRUE(extension);
535 EXPECT_EQ(kExtensionId, extension->id());
536 // Wait for "WORKER_RUNNING" message from the Service Worker.
537 EXPECT_TRUE(WaitForMessage());
538 EXPECT_TRUE(WillRegisterServiceWorker());
539}
540
Devlin Cronin242d19d22019-03-12 18:08:48541IN_PROC_BROWSER_TEST_F(ServiceWorkerRegistrationAtStartupTest,
Istiaque Ahmed70f76ac2018-11-02 02:59:55542 ExtensionActivationDoesNotReregister) {
543 // Since the extension has onStartup listener, the Service Worker will run on
544 // browser start and we'll see "WORKER_RUNNING" message from the worker.
545 EXPECT_TRUE(WaitForMessage());
546 // As the extension activated during first run on PRE_ step, it shouldn't
547 // re-register the Service Worker upon browser restart.
548 EXPECT_FALSE(WillRegisterServiceWorker());
Istiaque Ahmedf70ab222018-10-02 03:08:24549}
550
Istiaque Ahmeda14ec482018-08-25 01:02:18551// Class that dispatches an event to |extension_id| right after a
552// non-lazy listener to the event is added from the extension's Service Worker.
Istiaque Ahmed771aa8a22018-06-20 23:40:53553class EarlyWorkerMessageSender : public EventRouter::Observer {
554 public:
555 EarlyWorkerMessageSender(content::BrowserContext* browser_context,
Istiaque Ahmeda14ec482018-08-25 01:02:18556 const ExtensionId& extension_id,
557 std::unique_ptr<Event> event)
Istiaque Ahmed771aa8a22018-06-20 23:40:53558 : browser_context_(browser_context),
559 event_router_(EventRouter::EventRouter::Get(browser_context_)),
560 extension_id_(extension_id),
Istiaque Ahmeda14ec482018-08-25 01:02:18561 event_(std::move(event)),
Istiaque Ahmed771aa8a22018-06-20 23:40:53562 listener_("PASS", false) {
563 DCHECK(browser_context_);
564 listener_.set_failure_message("FAIL");
Istiaque Ahmeda14ec482018-08-25 01:02:18565 event_router_->RegisterObserver(this, event_->event_name);
Istiaque Ahmed771aa8a22018-06-20 23:40:53566 }
567
568 ~EarlyWorkerMessageSender() override {
569 event_router_->UnregisterObserver(this);
570 }
571
572 // EventRouter::Observer:
573 void OnListenerAdded(const EventListenerInfo& details) override {
Istiaque Ahmeda14ec482018-08-25 01:02:18574 if (!event_ || extension_id_ != details.extension_id ||
575 event_->event_name != details.event_name) {
Istiaque Ahmed771aa8a22018-06-20 23:40:53576 return;
Istiaque Ahmeda14ec482018-08-25 01:02:18577 }
578
Istiaque Ahmed771aa8a22018-06-20 23:40:53579 const bool is_lazy_listener = details.browser_context == nullptr;
580 if (is_lazy_listener) {
581 // Wait for the non-lazy listener as we want to exercise the code to
582 // dispatch the event right after the Service Worker registration is
583 // completing.
584 return;
585 }
Istiaque Ahmeda14ec482018-08-25 01:02:18586 DispatchEvent(std::move(event_));
Istiaque Ahmed771aa8a22018-06-20 23:40:53587 }
588
589 bool SendAndWait() { return listener_.WaitUntilSatisfied(); }
590
591 private:
592 static constexpr const char* const kTestOnMessageEventName = "test.onMessage";
593
Istiaque Ahmeda14ec482018-08-25 01:02:18594 void DispatchEvent(std::unique_ptr<Event> event) {
Istiaque Ahmed771aa8a22018-06-20 23:40:53595 EventRouter::Get(browser_context_)
596 ->DispatchEventToExtension(extension_id_, std::move(event));
597 }
598
599 content::BrowserContext* const browser_context_ = nullptr;
600 EventRouter* const event_router_ = nullptr;
601 const ExtensionId extension_id_;
Istiaque Ahmeda14ec482018-08-25 01:02:18602 std::unique_ptr<Event> event_;
Istiaque Ahmed771aa8a22018-06-20 23:40:53603 ExtensionTestMessageListener listener_;
Istiaque Ahmed771aa8a22018-06-20 23:40:53604
605 DISALLOW_COPY_AND_ASSIGN(EarlyWorkerMessageSender);
606};
607
608// Tests that extension event dispatch works correctly right after extension
609// installation registers its Service Worker.
610// Regression test for: https://crbug.com/850792.
Devlin Cronin242d19d22019-03-12 18:08:48611IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, EarlyEventDispatch) {
Istiaque Ahmed771aa8a22018-06-20 23:40:53612 const ExtensionId kId("pkplfbidichfdicaijlchgnapepdginl");
Istiaque Ahmeda14ec482018-08-25 01:02:18613
614 // Build "test.onMessage" event for dispatch.
615 auto event = std::make_unique<Event>(
616 events::FOR_TEST, extensions::api::test::OnMessage::kEventName,
Lei Zhang582ecd12019-02-13 20:28:54617 base::ListValue::From(base::JSONReader::ReadDeprecated(
Istiaque Ahmeda14ec482018-08-25 01:02:18618 R"([{"data": "hello", "lastMessage": true}])")),
619 profile());
620
621 EarlyWorkerMessageSender sender(profile(), kId, std::move(event));
Istiaque Ahmed771aa8a22018-06-20 23:40:53622 // pkplfbidichfdicaijlchgnapepdginl
623 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
624 "service_worker/worker_based_background/early_event_dispatch"));
625 CHECK(extension);
626 EXPECT_EQ(kId, extension->id());
627 EXPECT_TRUE(sender.SendAndWait());
628}
629
Istiaque Ahmeda14ec482018-08-25 01:02:18630// Tests that filtered events dispatches correctly right after a non-lazy
631// listener is registered for that event (and before the corresponding lazy
632// listener is registered).
Devlin Cronin242d19d22019-03-12 18:08:48633IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
Istiaque Ahmeda14ec482018-08-25 01:02:18634 EarlyFilteredEventDispatch) {
635 const ExtensionId kId("pkplfbidichfdicaijlchgnapepdginl");
636
637 // Add minimal details required to dispatch webNavigation.onCommitted event:
638 extensions::api::web_navigation::OnCommitted::Details details;
639 details.transition_type =
640 extensions::api::web_navigation::TRANSITION_TYPE_TYPED;
641
642 // Build a dummy onCommited event to dispatch.
643 auto on_committed_event = std::make_unique<Event>(
644 events::WEB_NAVIGATION_ON_COMMITTED, "webNavigation.onCommitted",
645 api::web_navigation::OnCommitted::Create(details), profile());
646 // The filter will match the listener filter registered from the extension.
647 EventFilteringInfo info;
648 info.url = GURL("http://foo.com/a.html");
649 on_committed_event->filter_info = info;
650
651 EarlyWorkerMessageSender sender(profile(), kId,
652 std::move(on_committed_event));
653
654 // pkplfbidichfdicaijlchgnapepdginl
655 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
656 "service_worker/worker_based_background/early_filtered_event_dispatch"));
657 ASSERT_TRUE(extension);
658 EXPECT_EQ(kId, extension->id());
659 EXPECT_TRUE(sender.SendAndWait());
660}
661
lazyboybd325ae2015-11-18 21:35:26662class ServiceWorkerBackgroundSyncTest : public ServiceWorkerTest {
663 public:
664 ServiceWorkerBackgroundSyncTest() {}
665 ~ServiceWorkerBackgroundSyncTest() override {}
666
667 void SetUpCommandLine(base::CommandLine* command_line) override {
668 // ServiceWorkerRegistration.sync requires experimental flag.
669 command_line->AppendSwitch(
Istiaque Ahmedea5ed5042017-09-25 19:00:16670 ::switches::kEnableExperimentalWebPlatformFeatures);
lazyboybd325ae2015-11-18 21:35:26671 ServiceWorkerTest::SetUpCommandLine(command_line);
672 }
673
674 void SetUp() override {
Robbie McElrathdb12d8e2018-09-18 21:20:40675 content::background_sync_test_util::SetIgnoreNetworkChanges(true);
lazyboybd325ae2015-11-18 21:35:26676 ServiceWorkerTest::SetUp();
677 }
678
679 private:
680 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerBackgroundSyncTest);
681};
682
lazyboy561b7de2015-11-19 19:27:30683class ServiceWorkerPushMessagingTest : public ServiceWorkerTest {
684 public:
685 ServiceWorkerPushMessagingTest()
Sylvain Defresne212b4b02018-10-11 16:32:05686 : scoped_testing_factory_installer_(
687 base::BindRepeating(&gcm::FakeGCMProfileService::Build)),
688 gcm_driver_(nullptr),
689 push_service_(nullptr) {}
690
lazyboy561b7de2015-11-19 19:27:30691 ~ServiceWorkerPushMessagingTest() override {}
692
693 void GrantNotificationPermissionForTest(const GURL& url) {
Peter Beverloodd4ef1e2018-06-21 15:41:04694 NotificationPermissionContext::UpdatePermission(profile(), url.GetOrigin(),
695 CONTENT_SETTING_ALLOW);
lazyboy561b7de2015-11-19 19:27:30696 }
697
698 PushMessagingAppIdentifier GetAppIdentifierForServiceWorkerRegistration(
avia2f4804a2015-12-24 23:11:13699 int64_t service_worker_registration_id,
lazyboy561b7de2015-11-19 19:27:30700 const GURL& origin) {
701 PushMessagingAppIdentifier app_identifier =
702 PushMessagingAppIdentifier::FindByServiceWorker(
703 profile(), origin, service_worker_registration_id);
704
705 EXPECT_FALSE(app_identifier.is_null());
706 return app_identifier;
707 }
708
709 // ExtensionApiTest overrides.
710 void SetUpCommandLine(base::CommandLine* command_line) override {
peter9de96272015-12-04 15:23:27711 command_line->AppendSwitch(
Istiaque Ahmedea5ed5042017-09-25 19:00:16712 ::switches::kEnableExperimentalWebPlatformFeatures);
lazyboy561b7de2015-11-19 19:27:30713 ServiceWorkerTest::SetUpCommandLine(command_line);
714 }
Tanja Gornak89128fd2018-09-18 08:49:34715
lazyboy561b7de2015-11-19 19:27:30716 void SetUpOnMainThread() override {
miguelg9b502862017-04-24 18:13:53717 NotificationDisplayServiceFactory::GetInstance()->SetTestingFactory(
Sylvain Defresne711ff6b2018-10-04 12:33:54718 profile(),
719 base::BindRepeating(&StubNotificationDisplayService::FactoryForTests));
miguelg9b502862017-04-24 18:13:53720
johnmea5045732016-09-08 17:23:29721 gcm::FakeGCMProfileService* gcm_service =
722 static_cast<gcm::FakeGCMProfileService*>(
Tanja Gornak89128fd2018-09-18 08:49:34723 gcm::GCMProfileServiceFactory::GetForProfile(profile()));
johnmea5045732016-09-08 17:23:29724 gcm_driver_ = static_cast<instance_id::FakeGCMDriverForInstanceID*>(
725 gcm_service->driver());
lazyboy561b7de2015-11-19 19:27:30726 push_service_ = PushMessagingServiceFactory::GetForProfile(profile());
727
728 ServiceWorkerTest::SetUpOnMainThread();
729 }
730
johnmea5045732016-09-08 17:23:29731 instance_id::FakeGCMDriverForInstanceID* gcm_driver() const {
732 return gcm_driver_;
733 }
lazyboy561b7de2015-11-19 19:27:30734 PushMessagingServiceImpl* push_service() const { return push_service_; }
735
736 private:
Sylvain Defresne212b4b02018-10-11 16:32:05737 gcm::GCMProfileServiceFactory::ScopedTestingFactoryInstaller
738 scoped_testing_factory_installer_;
739
johnmea5045732016-09-08 17:23:29740 instance_id::FakeGCMDriverForInstanceID* gcm_driver_;
lazyboy561b7de2015-11-19 19:27:30741 PushMessagingServiceImpl* push_service_;
742
743 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerPushMessagingTest);
744};
745
Istiaque Ahmed805f6a83b2017-10-05 01:23:26746class ServiceWorkerLazyBackgroundTest : public ServiceWorkerTest {
747 public:
Istiaque Ahmed7105f2a2017-10-07 01:11:59748 ServiceWorkerLazyBackgroundTest()
749 : ServiceWorkerTest(
750 // Extensions APIs from SW are only enabled on trunk.
751 // It is important to set the channel early so that this change is
752 // visible in renderers running with service workers (and no
753 // extension).
754 version_info::Channel::UNKNOWN) {}
Istiaque Ahmed805f6a83b2017-10-05 01:23:26755 ~ServiceWorkerLazyBackgroundTest() override {}
756
757 void SetUpCommandLine(base::CommandLine* command_line) override {
758 ServiceWorkerTest::SetUpCommandLine(command_line);
759 // Disable background network activity as it can suddenly bring the Lazy
760 // Background Page alive.
761 command_line->AppendSwitch(::switches::kDisableBackgroundNetworking);
762 command_line->AppendSwitch(::switches::kNoProxyServer);
763 }
764
765 void SetUpInProcessBrowserTestFixture() override {
766 ServiceWorkerTest::SetUpInProcessBrowserTestFixture();
767 // Set shorter delays to prevent test timeouts.
768 ProcessManager::SetEventPageIdleTimeForTesting(1);
769 ProcessManager::SetEventPageSuspendingTimeForTesting(1);
770 }
771
772 private:
773 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerLazyBackgroundTest);
774};
775
Devlin Cronin242d19d22019-03-12 18:08:48776IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, RegisterSucceeds) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22777 StartTestFromBackgroundPage("register.js");
annekao38685502015-07-14 17:46:39778}
779
Devlin Cronin242d19d22019-03-12 18:08:48780IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, UpdateRefreshesServiceWorker) {
Francois Doraye6fb2d02017-10-18 21:29:13781 base::ScopedAllowBlockingForTesting allow_blocking;
lazyboyc3e763a2015-12-09 23:09:58782 base::ScopedTempDir scoped_temp_dir;
783 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
784 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
785 .AppendASCII("update")
786 .AppendASCII("service_worker.pem");
vabr9142fe22016-09-08 13:19:22787 base::FilePath path_v1 =
788 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
789 .AppendASCII("update")
790 .AppendASCII("v1"),
791 scoped_temp_dir.GetPath().AppendASCII("v1.crx"),
792 pem_path, base::FilePath());
793 base::FilePath path_v2 =
794 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
795 .AppendASCII("update")
796 .AppendASCII("v2"),
797 scoped_temp_dir.GetPath().AppendASCII("v2.crx"),
798 pem_path, base::FilePath());
lazyboyc3e763a2015-12-09 23:09:58799 const char* kId = "hfaanndiiilofhfokeanhddpkfffchdi";
800
801 ExtensionTestMessageListener listener_v1("Pong from version 1", false);
802 listener_v1.set_failure_message("FAILURE_V1");
803 // Install version 1.0 of the extension.
804 ASSERT_TRUE(InstallExtension(path_v1, 1));
805 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
806 ->enabled_extensions()
807 .GetByID(kId));
808 EXPECT_TRUE(listener_v1.WaitUntilSatisfied());
809
810 ExtensionTestMessageListener listener_v2("Pong from version 2", false);
811 listener_v2.set_failure_message("FAILURE_V2");
812
813 // Update to version 2.0.
814 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
815 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
816 ->enabled_extensions()
817 .GetByID(kId));
818 EXPECT_TRUE(listener_v2.WaitUntilSatisfied());
819}
820
[email protected]2ef85d562017-09-15 18:41:52821// TODO(crbug.com/765736) Fix the test.
Devlin Cronin242d19d22019-03-12 18:08:48822IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, DISABLED_UpdateWithoutSkipWaiting) {
Francois Doraye6fb2d02017-10-18 21:29:13823 base::ScopedAllowBlockingForTesting allow_blocking;
lazyboy22eddc712015-12-10 21:16:26824 base::ScopedTempDir scoped_temp_dir;
825 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
826 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
827 .AppendASCII("update_without_skip_waiting")
828 .AppendASCII("update_without_skip_waiting.pem");
vabr9142fe22016-09-08 13:19:22829 base::FilePath path_v1 =
830 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
831 .AppendASCII("update_without_skip_waiting")
832 .AppendASCII("v1"),
833 scoped_temp_dir.GetPath().AppendASCII("v1.crx"),
834 pem_path, base::FilePath());
835 base::FilePath path_v2 =
836 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
837 .AppendASCII("update_without_skip_waiting")
838 .AppendASCII("v2"),
839 scoped_temp_dir.GetPath().AppendASCII("v2.crx"),
840 pem_path, base::FilePath());
lazyboy22eddc712015-12-10 21:16:26841 const char* kId = "mhnnnflgagdakldgjpfcofkiocpdmogl";
842
843 // Install version 1.0 of the extension.
844 ASSERT_TRUE(InstallExtension(path_v1, 1));
845 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
846 ->enabled_extensions()
847 .GetByID(kId));
848 const Extension* extension = extensions::ExtensionRegistry::Get(profile())
849 ->enabled_extensions()
850 .GetByID(kId);
851
852 ExtensionTestMessageListener listener1("Pong from version 1", false);
853 listener1.set_failure_message("FAILURE");
Istiaque Ahmed3f692562019-07-26 22:59:26854 content::WebContents* web_contents = browsertest_util::AddTab(
855 browser(), extension->GetResourceURL("page.html"));
lazyboy22eddc712015-12-10 21:16:26856 EXPECT_TRUE(listener1.WaitUntilSatisfied());
857
858 // Update to version 2.0.
859 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
860 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
861 ->enabled_extensions()
862 .GetByID(kId));
863 const Extension* extension_after_update =
864 extensions::ExtensionRegistry::Get(profile())
865 ->enabled_extensions()
866 .GetByID(kId);
867
868 // Service worker version 2 would be installed but it won't be controlling
869 // the extension page yet.
870 ExtensionTestMessageListener listener2("Pong from version 1", false);
871 listener2.set_failure_message("FAILURE");
Istiaque Ahmed3f692562019-07-26 22:59:26872 web_contents = browsertest_util::AddTab(
873 browser(), extension_after_update->GetResourceURL("page.html"));
lazyboy22eddc712015-12-10 21:16:26874 EXPECT_TRUE(listener2.WaitUntilSatisfied());
875
876 // Navigate the tab away from the extension page so that no clients are
877 // using the service worker.
878 // Note that just closing the tab with WebContentsDestroyedWatcher doesn't
879 // seem to be enough because it returns too early.
880 WebContentsLoadStopObserver navigate_away_observer(web_contents);
881 web_contents->GetController().LoadURL(
882 GURL(url::kAboutBlankURL), content::Referrer(), ui::PAGE_TRANSITION_TYPED,
883 std::string());
884 navigate_away_observer.WaitForLoadStop();
885
886 // Now expect service worker version 2 to control the extension page.
887 ExtensionTestMessageListener listener3("Pong from version 2", false);
888 listener3.set_failure_message("FAILURE");
Istiaque Ahmed3f692562019-07-26 22:59:26889 web_contents = browsertest_util::AddTab(
890 browser(), extension_after_update->GetResourceURL("page.html"));
lazyboy22eddc712015-12-10 21:16:26891 EXPECT_TRUE(listener3.WaitUntilSatisfied());
892}
893
Devlin Cronin242d19d22019-03-12 18:08:48894IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, FetchArbitraryPaths) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22895 const Extension* extension = StartTestFromBackgroundPage("fetch.js");
annekao1db36fd2015-07-29 17:09:16896
kalman6f984ae2015-09-18 17:21:58897 // Open some arbirary paths. Their contents should be what the service worker
898 // responds with, which in this case is the path of the fetch.
899 EXPECT_EQ(
900 "Caught a fetch for /index.html",
901 NavigateAndExtractInnerText(extension->GetResourceURL("index.html")));
902 EXPECT_EQ("Caught a fetch for /path/to/other.html",
903 NavigateAndExtractInnerText(
904 extension->GetResourceURL("path/to/other.html")));
905 EXPECT_EQ("Caught a fetch for /some/text/file.txt",
906 NavigateAndExtractInnerText(
907 extension->GetResourceURL("some/text/file.txt")));
908 EXPECT_EQ("Caught a fetch for /no/file/extension",
909 NavigateAndExtractInnerText(
910 extension->GetResourceURL("no/file/extension")));
911 EXPECT_EQ("Caught a fetch for /",
912 NavigateAndExtractInnerText(extension->GetResourceURL("")));
annekao1db36fd2015-07-29 17:09:16913}
914
Devlin Cronin242d19d22019-03-12 18:08:48915IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
Kenichi Ishibashi773b82972018-08-30 07:02:03916 FetchExtensionResourceFromServiceWorker) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22917 const Extension* extension = StartTestFromBackgroundPage("fetch_from_sw.js");
Kenichi Ishibashi773b82972018-08-30 07:02:03918 ASSERT_TRUE(extension);
919
920 // The service worker in this test tries to load 'hello.txt' via fetch()
921 // and sends back the content of the file, which should be 'hello'.
922 const char* kScript = R"(
923 let channel = new MessageChannel();
924 test.waitForMessage(channel.port1).then(message => {
925 window.domAutomationController.send(message);
926 });
927 test.registeredServiceWorker.postMessage(
928 {port: channel.port2}, [channel.port2]);
929 )";
930 EXPECT_EQ("hello", ExecuteScriptInBackgroundPage(extension->id(), kScript));
931}
932
Kenichi Ishibashi09ee5e72018-11-27 07:12:38933// Tests that fetch() from service worker and network fallback
934// go through webRequest.onBeforeRequest API.
Devlin Cronin242d19d22019-03-12 18:08:48935IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, OnBeforeRequest) {
Kenichi Ishibashi09ee5e72018-11-27 07:12:38936 const Extension* extension = LoadExtensionWithFlags(
937 test_data_dir_.AppendASCII("service_worker/webrequest"), kFlagNone);
938 ASSERT_TRUE(extension);
939 ASSERT_TRUE(StartEmbeddedTestServer());
940
941 // Start a service worker and make it control the page.
942 GURL page_url = embedded_test_server()->GetURL(
943 "/extensions/api_test/service_worker/"
944 "webrequest/webpage.html");
945 content::WebContents* web_contents =
946 browser()->tab_strip_model()->GetActiveWebContents();
947 ui_test_utils::NavigateToURL(browser(), page_url);
948 content::WaitForLoadStop(web_contents);
949
950 std::string result;
951 ASSERT_TRUE(content::ExecuteScriptAndExtractString(web_contents,
952 "register();", &result));
953 EXPECT_EQ("ready", result);
954
955 // Initiate a fetch that the service worker doesn't intercept
956 // (network fallback).
957 result.clear();
958 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
959 web_contents, "doFetch('hello.txt?fallthrough');", &result));
960 EXPECT_EQ("hello", result);
961 EXPECT_EQ(
962 "/extensions/api_test/service_worker/webrequest/hello.txt?fallthrough",
963 ExecuteScriptInBackgroundPage(extension->id(), "getLastHookedPath()"));
964
965 // Initiate a fetch that results in calling fetch() in the service worker.
966 result.clear();
967 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
968 web_contents, "doFetch('hello.txt?respondWithFetch');", &result));
969 EXPECT_EQ("hello", result);
970 EXPECT_EQ(
971 "/extensions/api_test/service_worker/webrequest/"
972 "hello.txt?respondWithFetch",
973 ExecuteScriptInBackgroundPage(extension->id(), "getLastHookedPath()"));
974}
975
Devlin Cronin242d19d22019-03-12 18:08:48976IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, SWServedBackgroundPageReceivesEvent) {
lazyboy52c3bcf2016-01-08 00:11:29977 const Extension* extension =
Istiaque Ahmed93ff7f42018-08-31 01:42:22978 StartTestFromBackgroundPage("replace_background.js");
lazyboy52c3bcf2016-01-08 00:11:29979 ExtensionHost* background_page =
980 process_manager()->GetBackgroundHostForExtension(extension->id());
981 ASSERT_TRUE(background_page);
982
983 // Close the background page and start it again so that the service worker
984 // will start controlling pages.
985 background_page->Close();
986 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
987 background_page = nullptr;
Peter Kasting341e1fb2018-02-24 00:03:01988 process_manager()->WakeEventPage(extension->id(), base::DoNothing());
lazyboy52c3bcf2016-01-08 00:11:29989 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
990
991 // Since the SW is now controlling the extension, the SW serves the background
992 // script. page.html sends a message to the background script and we verify
993 // that the SW served background script correctly receives the message/event.
994 ExtensionTestMessageListener listener("onMessage/SW BG.", false);
995 listener.set_failure_message("onMessage/original BG.");
Istiaque Ahmed3f692562019-07-26 22:59:26996 content::WebContents* web_contents = browsertest_util::AddTab(
997 browser(), extension->GetResourceURL("page.html"));
lazyboy52c3bcf2016-01-08 00:11:29998 ASSERT_TRUE(web_contents);
999 EXPECT_TRUE(listener.WaitUntilSatisfied());
1000}
1001
Devlin Cronin242d19d22019-03-12 18:08:481002IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, SWServedBackgroundPage) {
Istiaque Ahmed93ff7f42018-08-31 01:42:221003 const Extension* extension = StartTestFromBackgroundPage("fetch.js");
annekao49241182015-08-18 17:14:011004
kalman6f984ae2015-09-18 17:21:581005 std::string kExpectedInnerText = "background.html contents for testing.";
annekao49241182015-08-18 17:14:011006
kalman6f984ae2015-09-18 17:21:581007 // Sanity check that the background page has the expected content.
1008 ExtensionHost* background_page =
1009 process_manager()->GetBackgroundHostForExtension(extension->id());
1010 ASSERT_TRUE(background_page);
1011 EXPECT_EQ(kExpectedInnerText,
1012 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:011013
kalman6f984ae2015-09-18 17:21:581014 // Close the background page.
1015 background_page->Close();
1016 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
1017 background_page = nullptr;
1018
1019 // Start it again.
Peter Kasting341e1fb2018-02-24 00:03:011020 process_manager()->WakeEventPage(extension->id(), base::DoNothing());
kalman6f984ae2015-09-18 17:21:581021 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
1022
Matt Falkenhagena612fc02018-05-30 00:35:391023 // The service worker should get a fetch event for the background page.
kalman6f984ae2015-09-18 17:21:581024 background_page =
1025 process_manager()->GetBackgroundHostForExtension(extension->id());
1026 ASSERT_TRUE(background_page);
1027 content::WaitForLoadStop(background_page->host_contents());
1028
kalman6f984ae2015-09-18 17:21:581029 EXPECT_EQ("Caught a fetch for /background.html",
1030 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:011031}
1032
Devlin Cronin242d19d22019-03-12 18:08:481033IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:581034 ServiceWorkerPostsMessageToBackgroundClient) {
Istiaque Ahmed93ff7f42018-08-31 01:42:221035 const Extension* extension =
1036 StartTestFromBackgroundPage("post_message_to_background_client.js");
annekao533482222015-08-21 23:23:531037
kalman6f984ae2015-09-18 17:21:581038 // The service worker in this test simply posts a message to the background
1039 // client it receives from getBackgroundClient().
1040 const char* kScript =
1041 "var messagePromise = null;\n"
1042 "if (test.lastMessageFromServiceWorker) {\n"
1043 " messagePromise = Promise.resolve(test.lastMessageFromServiceWorker);\n"
1044 "} else {\n"
1045 " messagePromise = test.waitForMessage(navigator.serviceWorker);\n"
1046 "}\n"
1047 "messagePromise.then(function(message) {\n"
1048 " window.domAutomationController.send(String(message == 'success'));\n"
1049 "})\n";
1050 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:531051}
1052
Devlin Cronin242d19d22019-03-12 18:08:481053IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:581054 BackgroundPagePostsMessageToServiceWorker) {
1055 const Extension* extension =
Istiaque Ahmed93ff7f42018-08-31 01:42:221056 StartTestFromBackgroundPage("post_message_to_sw.js");
annekao533482222015-08-21 23:23:531057
kalman6f984ae2015-09-18 17:21:581058 // The service worker in this test waits for a message, then echoes it back
1059 // by posting a message to the background page via getBackgroundClient().
1060 const char* kScript =
1061 "var mc = new MessageChannel();\n"
1062 "test.waitForMessage(mc.port1).then(function(message) {\n"
1063 " window.domAutomationController.send(String(message == 'hello'));\n"
1064 "});\n"
1065 "test.registeredServiceWorker.postMessage(\n"
1066 " {message: 'hello', port: mc.port2}, [mc.port2])\n";
1067 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:531068}
1069
Devlin Cronin242d19d22019-03-12 18:08:481070IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
rdevlin.croninf5863da2015-09-10 19:21:451071 ServiceWorkerSuspensionOnExtensionUnload) {
kalman6f984ae2015-09-18 17:21:581072 // For this test, only hold onto the extension's ID and URL + a function to
1073 // get a resource URL, because we're going to be disabling and uninstalling
1074 // it, which will invalidate the pointer.
1075 std::string extension_id;
1076 GURL extension_url;
1077 {
Istiaque Ahmed93ff7f42018-08-31 01:42:221078 const Extension* extension = StartTestFromBackgroundPage("fetch.js");
kalman6f984ae2015-09-18 17:21:581079 extension_id = extension->id();
1080 extension_url = extension->url();
1081 }
1082 auto get_resource_url = [&extension_url](const std::string& path) {
1083 return Extension::GetResourceURL(extension_url, path);
1084 };
rdevlin.croninf5863da2015-09-10 19:21:451085
kalman6f984ae2015-09-18 17:21:581086 // Fetch should route to the service worker.
1087 EXPECT_EQ("Caught a fetch for /index.html",
1088 NavigateAndExtractInnerText(get_resource_url("index.html")));
rdevlin.croninf5863da2015-09-10 19:21:451089
kalman6f984ae2015-09-18 17:21:581090 // Disable the extension. Opening the page should fail.
1091 extension_service()->DisableExtension(extension_id,
Minh X. Nguyen45479012017-08-18 21:35:361092 disable_reason::DISABLE_USER_ACTION);
rdevlin.croninf5863da2015-09-10 19:21:451093 base::RunLoop().RunUntilIdle();
rdevlin.croninf5863da2015-09-10 19:21:451094
kalman6f984ae2015-09-18 17:21:581095 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1096 NavigateAndGetPageType(get_resource_url("index.html")));
1097 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1098 NavigateAndGetPageType(get_resource_url("other.html")));
1099
1100 // Re-enable the extension. Opening pages should immediately start to succeed
1101 // again.
rdevlin.croninf5863da2015-09-10 19:21:451102 extension_service()->EnableExtension(extension_id);
1103 base::RunLoop().RunUntilIdle();
1104
kalman6f984ae2015-09-18 17:21:581105 EXPECT_EQ("Caught a fetch for /index.html",
1106 NavigateAndExtractInnerText(get_resource_url("index.html")));
1107 EXPECT_EQ("Caught a fetch for /other.html",
1108 NavigateAndExtractInnerText(get_resource_url("other.html")));
1109 EXPECT_EQ("Caught a fetch for /another.html",
1110 NavigateAndExtractInnerText(get_resource_url("another.html")));
rdevlin.croninf5863da2015-09-10 19:21:451111
kalman6f984ae2015-09-18 17:21:581112 // Uninstall the extension. Opening pages should fail again.
1113 base::string16 error;
1114 extension_service()->UninstallExtension(
Devlin Cronin218df7f2017-11-21 21:41:311115 extension_id, UninstallReason::UNINSTALL_REASON_FOR_TESTING, &error);
kalman6f984ae2015-09-18 17:21:581116 base::RunLoop().RunUntilIdle();
1117
1118 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1119 NavigateAndGetPageType(get_resource_url("index.html")));
1120 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1121 NavigateAndGetPageType(get_resource_url("other.html")));
1122 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1123 NavigateAndGetPageType(get_resource_url("anotherother.html")));
1124 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1125 NavigateAndGetPageType(get_resource_url("final.html")));
1126}
1127
Devlin Cronin242d19d22019-03-12 18:08:481128IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, BackgroundPageIsWokenIfAsleep) {
Istiaque Ahmed93ff7f42018-08-31 01:42:221129 const Extension* extension = StartTestFromBackgroundPage("wake_on_fetch.js");
kalman6f984ae2015-09-18 17:21:581130
1131 // Navigate to special URLs that this test's service worker recognises, each
1132 // making a check then populating the response with either "true" or "false".
1133 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
1134 "background-client-is-awake")));
1135 EXPECT_EQ("true", NavigateAndExtractInnerText(
1136 extension->GetResourceURL("ping-background-client")));
1137 // Ping more than once for good measure.
1138 EXPECT_EQ("true", NavigateAndExtractInnerText(
1139 extension->GetResourceURL("ping-background-client")));
1140
1141 // Shut down the event page. The SW should detect that it's closed, but still
1142 // be able to ping it.
1143 ExtensionHost* background_page =
1144 process_manager()->GetBackgroundHostForExtension(extension->id());
1145 ASSERT_TRUE(background_page);
1146 background_page->Close();
1147 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
1148
1149 EXPECT_EQ("false", NavigateAndExtractInnerText(extension->GetResourceURL(
1150 "background-client-is-awake")));
1151 EXPECT_EQ("true", NavigateAndExtractInnerText(
1152 extension->GetResourceURL("ping-background-client")));
1153 EXPECT_EQ("true", NavigateAndExtractInnerText(
1154 extension->GetResourceURL("ping-background-client")));
1155 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
1156 "background-client-is-awake")));
1157}
1158
Devlin Cronin242d19d22019-03-12 18:08:481159IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:581160 GetBackgroundClientFailsWithNoBackgroundPage) {
1161 // This extension doesn't have a background page, only a tab at page.html.
1162 // The service worker it registers tries to call getBackgroundClient() and
1163 // should fail.
1164 // Note that this also tests that service workers can be registered from tabs.
1165 EXPECT_TRUE(RunExtensionSubtest("service_worker/no_background", "page.html"));
rdevlin.croninf5863da2015-09-10 19:21:451166}
1167
Devlin Cronin242d19d22019-03-12 18:08:481168IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, NotificationAPI) {
lazyboy6ddb7d62015-11-10 23:15:271169 EXPECT_TRUE(RunExtensionSubtest("service_worker/notifications/has_permission",
1170 "page.html"));
1171}
1172
Devlin Cronin242d19d22019-03-12 18:08:481173IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, WebAccessibleResourcesFetch) {
lazyboyaea32c22016-01-04 21:37:071174 EXPECT_TRUE(RunExtensionSubtest(
1175 "service_worker/web_accessible_resources/fetch/", "page.html"));
1176}
1177
David Bertoni9026eff2019-05-01 18:04:311178// Tests that updating a packed extension with modified scripts works
1179// properly -- we expect that the new script will execute, rather than the
1180// previous one.
1181IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, UpdatePackedExtension) {
1182 // Extensions APIs from SW are only enabled on trunk.
1183 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1184 constexpr char kManifest1[] =
1185 R"({
1186 "name": "Test Extension",
1187 "manifest_version": 2,
1188 "version": "0.1",
1189 "background": {"service_worker": "script.js"}
1190 })";
David Bertoni353f0fb42019-05-30 15:53:301191 constexpr char kNewVersionString[] = "0.2";
1192
David Bertoni9026eff2019-05-01 18:04:311193 // This script installs an event listener for updates to the extension with
1194 // a callback that forces itself to reload.
David Bertoni353f0fb42019-05-30 15:53:301195 constexpr char kScript1[] =
David Bertoni9026eff2019-05-01 18:04:311196 R"(
1197 chrome.runtime.onUpdateAvailable.addListener(function(details) {
David Bertoni353f0fb42019-05-30 15:53:301198 chrome.test.assertEq('%s', details.version);
David Bertoni9026eff2019-05-01 18:04:311199 chrome.runtime.reload();
1200 });
1201 chrome.test.sendMessage('ready1');
1202 )";
1203
1204 std::string id;
1205 TestExtensionDir test_dir;
1206
1207 // Write the manifest and script files and load the extension.
1208 test_dir.WriteManifest(kManifest1);
David Bertoni353f0fb42019-05-30 15:53:301209 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"),
1210 base::StringPrintf(kScript1, kNewVersionString));
David Bertoni9026eff2019-05-01 18:04:311211
1212 {
1213 ExtensionTestMessageListener ready_listener("ready1", false);
1214 base::FilePath path = test_dir.Pack();
1215 const Extension* extension = LoadExtension(path);
1216 ASSERT_TRUE(extension);
1217
1218 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
1219 id = extension->id();
1220 }
1221
1222 constexpr char kManifest2[] =
1223 R"({
1224 "name": "Test Extension",
1225 "manifest_version": 2,
David Bertoni353f0fb42019-05-30 15:53:301226 "version": "%s",
David Bertoni9026eff2019-05-01 18:04:311227 "background": {"service_worker": "script.js"}
1228 })";
David Bertoni353f0fb42019-05-30 15:53:301229 constexpr char kScript2[] =
1230 R"(
1231 chrome.runtime.onInstalled.addListener(function(details) {
1232 chrome.test.assertEq('update', details.reason);
1233 chrome.test.sendMessage('onInstalled');
1234 });
1235 chrome.test.sendMessage('ready2');
1236 )";
David Bertoni9026eff2019-05-01 18:04:311237 // Rewrite the manifest and script files with a version change in the manifest
1238 // file. After reloading the extension, the old version of the extension
1239 // should detect the update, force the reload, and the new script should
1240 // execute.
David Bertoni353f0fb42019-05-30 15:53:301241 test_dir.WriteManifest(base::StringPrintf(kManifest2, kNewVersionString));
1242 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"), kScript2);
David Bertoni9026eff2019-05-01 18:04:311243 {
1244 ExtensionTestMessageListener ready_listener("ready2", false);
David Bertoni353f0fb42019-05-30 15:53:301245 ExtensionTestMessageListener on_installed_listener("onInstalled", false);
David Bertoni9026eff2019-05-01 18:04:311246 base::FilePath path = test_dir.Pack();
1247 ExtensionService* const extension_service =
1248 ExtensionSystem::Get(profile())->extension_service();
1249 EXPECT_TRUE(extension_service->UpdateExtension(
1250 CRXFileInfo(id, GetTestVerifierFormat(), path), true, nullptr));
1251 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
1252 EXPECT_EQ("0.2", ExtensionRegistry::Get(profile())
1253 ->enabled_extensions()
1254 .GetByID(id)
1255 ->version()
1256 .GetString());
David Bertoni353f0fb42019-05-30 15:53:301257 EXPECT_TRUE(on_installed_listener.WaitUntilSatisfied());
David Bertoni9026eff2019-05-01 18:04:311258 }
1259}
1260
David Bertoni1d646a152019-04-25 02:09:221261// Tests that updating an unpacked extension with modified scripts works
1262// properly -- we expect that the new script will execute, rather than the
1263// previous one.
1264IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, UpdateUnpackedExtension) {
1265 // Extensions APIs from SW are only enabled on trunk.
1266 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1267 constexpr char kManifest1[] =
1268 R"({
1269 "name": "Test Extension",
1270 "manifest_version": 2,
1271 "version": "0.1",
1272 "background": {"service_worker": "script.js"}
1273 })";
1274 constexpr char kManifest2[] =
1275 R"({
1276 "name": "Test Extension",
1277 "manifest_version": 2,
1278 "version": "0.2",
1279 "background": {"service_worker": "script.js"}
1280 })";
David Bertoni353f0fb42019-05-30 15:53:301281 constexpr char kScript[] =
1282 R"(
1283 chrome.runtime.onInstalled.addListener(function(details) {
1284 chrome.test.assertEq('%s', details.reason);
1285 chrome.test.sendMessage('onInstalled');
1286 });
1287 chrome.test.sendMessage('%s');
1288 )";
David Bertoni1d646a152019-04-25 02:09:221289
1290 std::string id;
1291
1292 ExtensionService* const extension_service =
1293 ExtensionSystem::Get(profile())->extension_service();
1294 scoped_refptr<UnpackedInstaller> installer =
1295 UnpackedInstaller::Create(extension_service);
1296
1297 // Set a completion callback so we can get the ID of the extension.
1298 installer->set_completion_callback(base::BindLambdaForTesting(
1299 [&id](const Extension* extension, const base::FilePath& path,
1300 const std::string& error) {
1301 ASSERT_TRUE(extension);
1302 ASSERT_TRUE(error.empty());
1303 id = extension->id();
1304 }));
1305
1306 TestExtensionDir test_dir;
1307
1308 // Write the manifest and script files and load the extension.
1309 test_dir.WriteManifest(kManifest1);
1310 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"),
David Bertoni353f0fb42019-05-30 15:53:301311 base::StringPrintf(kScript, "install", "ready1"));
David Bertoni1d646a152019-04-25 02:09:221312 {
1313 ExtensionTestMessageListener ready_listener("ready1", false);
David Bertoni353f0fb42019-05-30 15:53:301314 ExtensionTestMessageListener on_installed_listener("onInstalled", false);
David Bertoni1d646a152019-04-25 02:09:221315
1316 installer->Load(test_dir.UnpackedPath());
1317 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
David Bertoni353f0fb42019-05-30 15:53:301318 EXPECT_TRUE(on_installed_listener.WaitUntilSatisfied());
David Bertoni1d646a152019-04-25 02:09:221319 ASSERT_FALSE(id.empty());
1320 }
1321
1322 // Rewrite the script file without a version change in the manifest and reload
1323 // the extension. The new script should execute.
1324 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"),
David Bertoni353f0fb42019-05-30 15:53:301325 base::StringPrintf(kScript, "update", "ready2"));
David Bertoni1d646a152019-04-25 02:09:221326 {
1327 ExtensionTestMessageListener ready_listener("ready2", false);
David Bertoni353f0fb42019-05-30 15:53:301328 ExtensionTestMessageListener on_installed_listener("onInstalled", false);
David Bertoni1d646a152019-04-25 02:09:221329
1330 extension_service->ReloadExtension(id);
1331 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
David Bertoni353f0fb42019-05-30 15:53:301332 EXPECT_TRUE(on_installed_listener.WaitUntilSatisfied());
David Bertoni1d646a152019-04-25 02:09:221333 }
1334
1335 // Rewrite the manifest and script files with a version change in the manifest
1336 // file. After reloading the extension, the new script should execute.
1337 test_dir.WriteManifest(kManifest2);
1338 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"),
David Bertoni353f0fb42019-05-30 15:53:301339 base::StringPrintf(kScript, "update", "ready3"));
David Bertoni1d646a152019-04-25 02:09:221340 {
1341 ExtensionTestMessageListener ready_listener("ready3", false);
David Bertoni353f0fb42019-05-30 15:53:301342 ExtensionTestMessageListener on_installed_listener("onInstalled", false);
David Bertoni1d646a152019-04-25 02:09:221343
1344 extension_service->ReloadExtension(id);
1345 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
David Bertoni353f0fb42019-05-30 15:53:301346 EXPECT_TRUE(on_installed_listener.WaitUntilSatisfied());
David Bertoni1d646a152019-04-25 02:09:221347 }
1348}
1349
lazyboyaea32c22016-01-04 21:37:071350// This test loads a web page that has an iframe pointing to a
1351// chrome-extension:// URL. The URL is listed in the extension's
1352// web_accessible_resources. Initially the iframe is served from the extension's
1353// resource file. After verifying that, we register a Service Worker that
1354// controls the extension. Further requests to the same resource as before
1355// should now be served by the Service Worker.
1356// This test also verifies that if the requested resource exists in the manifest
1357// but is not present in the extension directory, the Service Worker can still
1358// serve the resource file.
Devlin Cronin242d19d22019-03-12 18:08:481359IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, WebAccessibleResourcesIframeSrc) {
lazyboyaea32c22016-01-04 21:37:071360 const Extension* extension = LoadExtensionWithFlags(
1361 test_data_dir_.AppendASCII(
1362 "service_worker/web_accessible_resources/iframe_src"),
1363 kFlagNone);
1364 ASSERT_TRUE(extension);
1365 ASSERT_TRUE(StartEmbeddedTestServer());
falkenad185092016-06-16 06:10:021366
1367 // Service workers can only control secure contexts
1368 // (https://w3c.github.io/webappsec-secure-contexts/). For documents, this
1369 // typically means the document must have a secure origin AND all its ancestor
1370 // frames must have documents with secure origins. However, extension pages
1371 // are considered secure, even if they have an ancestor document that is an
1372 // insecure context (see GetSchemesBypassingSecureContextCheckWhitelist). So
1373 // extension service workers must be able to control an extension page
1374 // embedded in an insecure context. To test this, set up an insecure
1375 // (non-localhost, non-https) URL for the web page. This page will create
1376 // iframes that load extension pages that must be controllable by service
1377 // worker.
falkenad185092016-06-16 06:10:021378 GURL page_url =
1379 embedded_test_server()->GetURL("a.com",
1380 "/extensions/api_test/service_worker/"
1381 "web_accessible_resources/webpage.html");
1382 EXPECT_FALSE(content::IsOriginSecure(page_url));
lazyboyaea32c22016-01-04 21:37:071383
Istiaque Ahmed3f692562019-07-26 22:59:261384 content::WebContents* web_contents =
1385 browsertest_util::AddTab(browser(), page_url);
lazyboyaea32c22016-01-04 21:37:071386 std::string result;
1387 // webpage.html will create an iframe pointing to a resource from |extension|.
1388 // Expect the resource to be served by the extension.
1389 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1390 web_contents, base::StringPrintf("window.testIframe('%s', 'iframe.html')",
1391 extension->id().c_str()),
1392 &result));
1393 EXPECT_EQ("FROM_EXTENSION_RESOURCE", result);
1394
1395 ExtensionTestMessageListener service_worker_ready_listener("SW_READY", false);
1396 EXPECT_TRUE(ExecuteScriptInBackgroundPageNoWait(
1397 extension->id(), "window.registerServiceWorker()"));
1398 EXPECT_TRUE(service_worker_ready_listener.WaitUntilSatisfied());
1399
1400 result.clear();
1401 // webpage.html will create another iframe pointing to a resource from
1402 // |extension| as before. But this time, the resource should be be served
1403 // from the Service Worker.
1404 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1405 web_contents, base::StringPrintf("window.testIframe('%s', 'iframe.html')",
1406 extension->id().c_str()),
1407 &result));
1408 EXPECT_EQ("FROM_SW_RESOURCE", result);
1409
1410 result.clear();
1411 // webpage.html will create yet another iframe pointing to a resource that
1412 // exists in the extension manifest's web_accessible_resources, but is not
1413 // present in the extension directory. Expect the resources of the iframe to
1414 // be served by the Service Worker.
1415 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1416 web_contents,
1417 base::StringPrintf("window.testIframe('%s', 'iframe_non_existent.html')",
1418 extension->id().c_str()),
1419 &result));
1420 EXPECT_EQ("FROM_SW_RESOURCE", result);
1421}
1422
David Bertonide552de2019-06-28 19:51:261423// Verifies that service workers that aren't specified as the background script
1424// for the extension do not have extension API bindings.
1425IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, VerifyNoApiBindings) {
1426 // Extensions APIs from SW are only enabled on trunk.
1427 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1428 const Extension* extension = LoadExtensionWithFlags(
1429 test_data_dir_.AppendASCII("service_worker/verify_no_api_bindings"),
1430 kFlagNone);
1431 ASSERT_TRUE(extension);
1432 ui_test_utils::NavigateToURL(browser(),
1433 extension->GetResourceURL("page.html"));
1434 content::WebContents* web_contents =
1435 browser()->tab_strip_model()->GetActiveWebContents();
1436
1437 // Have the page script start the service worker and wait for that to
1438 // succeed.
1439 ExtensionTestMessageListener worker_start_listener("WORKER STARTED", false);
1440 worker_start_listener.set_failure_message("FAILURE");
1441 ASSERT_TRUE(
1442 content::ExecuteScript(web_contents, "window.runServiceWorker()"));
1443 ASSERT_TRUE(worker_start_listener.WaitUntilSatisfied());
1444
1445 // Kick off the test, which will check the available bindings and fail if
1446 // there is anything unexpected.
1447 ExtensionTestMessageListener worker_listener("SUCCESS", false);
1448 worker_listener.set_failure_message("FAILURE");
1449 ASSERT_TRUE(content::ExecuteScript(web_contents, "window.testSendMessage()"));
1450 EXPECT_TRUE(worker_listener.WaitUntilSatisfied());
1451}
1452
Devlin Cronin242d19d22019-03-12 18:08:481453IN_PROC_BROWSER_TEST_F(ServiceWorkerBackgroundSyncTest, Sync) {
lazyboybd325ae2015-11-18 21:35:261454 const Extension* extension = LoadExtensionWithFlags(
1455 test_data_dir_.AppendASCII("service_worker/sync"), kFlagNone);
1456 ASSERT_TRUE(extension);
1457 ui_test_utils::NavigateToURL(browser(),
1458 extension->GetResourceURL("page.html"));
1459 content::WebContents* web_contents =
1460 browser()->tab_strip_model()->GetActiveWebContents();
1461
1462 // Prevent firing by going offline.
1463 content::background_sync_test_util::SetOnline(web_contents, false);
1464
1465 ExtensionTestMessageListener sync_listener("SYNC: send-chats", false);
1466 sync_listener.set_failure_message("FAIL");
1467
1468 std::string result;
1469 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
1470 web_contents, "window.runServiceWorker()", &result));
1471 ASSERT_EQ("SERVICE_WORKER_READY", result);
1472
1473 EXPECT_FALSE(sync_listener.was_satisfied());
1474 // Resume firing by going online.
1475 content::background_sync_test_util::SetOnline(web_contents, true);
1476 EXPECT_TRUE(sync_listener.WaitUntilSatisfied());
1477}
1478
Devlin Cronin242d19d22019-03-12 18:08:481479IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
horo1eeddde2015-11-19 05:59:251480 FetchFromContentScriptShouldNotGoToServiceWorkerOfPage) {
1481 ASSERT_TRUE(StartEmbeddedTestServer());
1482 GURL page_url = embedded_test_server()->GetURL(
1483 "/extensions/api_test/service_worker/content_script_fetch/"
1484 "controlled_page/index.html");
1485 content::WebContents* tab =
1486 browser()->tab_strip_model()->GetActiveWebContents();
1487 ui_test_utils::NavigateToURL(browser(), page_url);
1488 content::WaitForLoadStop(tab);
1489
1490 std::string value;
1491 ASSERT_TRUE(
1492 content::ExecuteScriptAndExtractString(tab, "register();", &value));
1493 EXPECT_EQ("SW controlled", value);
1494
1495 ASSERT_TRUE(RunExtensionTest("service_worker/content_script_fetch"))
1496 << message_;
1497}
1498
Devlin Cronin242d19d22019-03-12 18:08:481499IN_PROC_BROWSER_TEST_F(ServiceWorkerPushMessagingTest, OnPush) {
lazyboy561b7de2015-11-19 19:27:301500 const Extension* extension = LoadExtensionWithFlags(
1501 test_data_dir_.AppendASCII("service_worker/push_messaging"), kFlagNone);
1502 ASSERT_TRUE(extension);
1503 GURL extension_url = extension->url();
1504
Peter Beverloodd4ef1e2018-06-21 15:41:041505 GrantNotificationPermissionForTest(extension_url);
lazyboy561b7de2015-11-19 19:27:301506
1507 GURL url = extension->GetResourceURL("page.html");
1508 ui_test_utils::NavigateToURL(browser(), url);
1509
1510 content::WebContents* web_contents =
1511 browser()->tab_strip_model()->GetActiveWebContents();
1512
1513 // Start the ServiceWorker.
1514 ExtensionTestMessageListener ready_listener("SERVICE_WORKER_READY", false);
1515 ready_listener.set_failure_message("SERVICE_WORKER_FAILURE");
1516 const char* kScript = "window.runServiceWorker()";
1517 EXPECT_TRUE(content::ExecuteScript(web_contents->GetMainFrame(), kScript));
1518 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
1519
1520 PushMessagingAppIdentifier app_identifier =
1521 GetAppIdentifierForServiceWorkerRegistration(0LL, extension_url);
johnmea5045732016-09-08 17:23:291522 ASSERT_EQ(app_identifier.app_id(), gcm_driver()->last_gettoken_app_id());
1523 EXPECT_EQ("1234567890", gcm_driver()->last_gettoken_authorized_entity());
lazyboy561b7de2015-11-19 19:27:301524
lazyboyd429e2582016-05-20 20:18:521525 base::RunLoop run_loop;
lazyboy561b7de2015-11-19 19:27:301526 // Send a push message via gcm and expect the ServiceWorker to receive it.
1527 ExtensionTestMessageListener push_message_listener("OK", false);
1528 push_message_listener.set_failure_message("FAIL");
1529 gcm::IncomingMessage message;
1530 message.sender_id = "1234567890";
1531 message.raw_data = "testdata";
1532 message.decrypted = true;
lazyboyd429e2582016-05-20 20:18:521533 push_service()->SetMessageCallbackForTesting(run_loop.QuitClosure());
lazyboy561b7de2015-11-19 19:27:301534 push_service()->OnMessage(app_identifier.app_id(), message);
1535 EXPECT_TRUE(push_message_listener.WaitUntilSatisfied());
lazyboyd429e2582016-05-20 20:18:521536 run_loop.Run(); // Wait until the message is handled by push service.
lazyboy561b7de2015-11-19 19:27:301537}
Devlin Cronin242d19d22019-03-12 18:08:481538IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, MimeHandlerView) {
Rob Wue89b90032018-02-16 19:46:081539 ASSERT_TRUE(RunExtensionTest("service_worker/mime_handler_view"));
1540}
1541
David Bertoni3b3597d82019-06-22 02:29:361542// An observer for service worker registration events.
1543class TestRegistrationObserver : public content::ServiceWorkerContextObserver {
David Bertoni22aeae52019-06-10 22:42:531544 public:
David Bertoni3b3597d82019-06-22 02:29:361545 using RegistrationsMap = std::map<GURL, int>;
1546
1547 explicit TestRegistrationObserver(content::ServiceWorkerContext* context)
1548 : context_(context) {
David Bertoni22aeae52019-06-10 22:42:531549 context_->AddObserver(this);
1550 }
1551
David Bertoni3b3597d82019-06-22 02:29:361552 ~TestRegistrationObserver() override {
David Bertoni22aeae52019-06-10 22:42:531553 if (context_) {
1554 context_->RemoveObserver(this);
1555 }
1556 }
1557
David Bertoni3b3597d82019-06-22 02:29:361558 // Wait for the first service worker registration with an extension scheme
1559 // scope to be stored.
1560 void WaitForRegistrationStored() { stored_run_loop_.Run(); }
1561
1562 int GetCompletedCount(const GURL& scope) const {
1563 const auto it = registrations_completed_map_.find(scope);
1564 return it == registrations_completed_map_.end() ? 0 : it->second;
1565 }
1566
1567 private:
1568 // ServiceWorkerContextObserver overrides.
1569 void OnRegistrationCompleted(const GURL& scope) override {
1570 ++registrations_completed_map_[scope];
1571 }
1572
David Bertoni22aeae52019-06-10 22:42:531573 void OnRegistrationStored(int64_t registration_id,
1574 const GURL& scope) override {
1575 if (scope.SchemeIs(kExtensionScheme)) {
David Bertoni3b3597d82019-06-22 02:29:361576 stored_run_loop_.Quit();
David Bertoni22aeae52019-06-10 22:42:531577 }
1578 }
1579
1580 void OnDestruct(content::ServiceWorkerContext* context) override {
1581 context_ = nullptr;
1582 }
1583
David Bertoni3b3597d82019-06-22 02:29:361584 RegistrationsMap registrations_completed_map_;
1585 base::RunLoop stored_run_loop_;
David Bertoni22aeae52019-06-10 22:42:531586 content::ServiceWorkerContext* context_;
David Bertoni22aeae52019-06-10 22:42:531587};
1588
1589IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
1590 EventsToStoppedWorker) {
1591 content::StoragePartition* storage_partition =
1592 content::BrowserContext::GetDefaultStoragePartition(browser()->profile());
1593 content::ServiceWorkerContext* context =
1594 storage_partition->GetServiceWorkerContext();
1595
1596 // Set up an observer to wait for the registration to be stored.
David Bertoni3b3597d82019-06-22 02:29:361597 TestRegistrationObserver observer(context);
David Bertoni22aeae52019-06-10 22:42:531598
1599 ExtensionTestMessageListener event_listener_added("ready", false);
1600 event_listener_added.set_failure_message("ERROR");
1601 const Extension* extension = LoadExtensionWithFlags(
1602 test_data_dir_.AppendASCII(
1603 "service_worker/worker_based_background/events_to_stopped_worker"),
1604 kFlagNone);
1605 ASSERT_TRUE(extension);
1606
David Bertoni3b3597d82019-06-22 02:29:361607 observer.WaitForRegistrationStored();
David Bertoni22aeae52019-06-10 22:42:531608 EXPECT_TRUE(event_listener_added.WaitUntilSatisfied());
1609
1610 // Stop the service worker.
1611 {
1612 base::RunLoop run_loop;
1613 // The service worker is registered at the root scope.
1614 content::StopServiceWorkerForScope(context, extension->url(),
1615 run_loop.QuitClosure());
1616 run_loop.Run();
1617 }
1618
1619 // Navigate to a URL, which should wake up the service worker.
1620 ExtensionTestMessageListener finished_listener("finished", false);
1621 ui_test_utils::NavigateToURL(browser(),
1622 extension->GetResourceURL("page.html"));
1623 EXPECT_TRUE(finished_listener.WaitUntilSatisfied());
1624}
1625
David Bertoni3b3597d82019-06-22 02:29:361626// Tests the restriction on registering service worker scripts at root scope.
1627IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
1628 ServiceWorkerScriptRootScope) {
1629 content::StoragePartition* storage_partition =
1630 content::BrowserContext::GetDefaultStoragePartition(browser()->profile());
1631 content::ServiceWorkerContext* context =
1632 storage_partition->GetServiceWorkerContext();
1633
1634 // Set up an observer to track all SW registrations. We expect only
1635 // one for the extension's root scope. This test attempts to register
1636 // an additional service worker, which will fail.
1637 TestRegistrationObserver observer(context);
1638 ExtensionTestMessageListener registration_listener("REGISTRATION_FAILED",
1639 false);
1640 registration_listener.set_failure_message("WORKER_STARTED");
1641 const Extension* extension = LoadExtensionWithFlags(
1642 test_data_dir_.AppendASCII(
1643 "service_worker/worker_based_background/script_root_scope"),
1644 kFlagNone);
1645 ASSERT_TRUE(extension);
1646
1647 EXPECT_TRUE(registration_listener.WaitUntilSatisfied());
1648 // We expect exactly one registration, which is the one specified in the
1649 // manifest.
1650 EXPECT_EQ(1, observer.GetCompletedCount(extension->url()));
1651}
1652
Devlin Cronin242d19d22019-03-12 18:08:481653IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
Istiaque Ahmedd4b67ee2019-03-02 10:53:201654 ProcessManagerRegistrationOnShutdown) {
1655 // Note that StopServiceWorkerForScope call below expects the worker to be
1656 // completely installed, so wait for the |extension| worker to see "activate"
1657 // event.
1658 ExtensionTestMessageListener activated_listener("WORKER_ACTIVATED", false);
1659 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
1660 "service_worker/worker_based_background/process_manager"));
1661 ASSERT_TRUE(extension);
1662 EXPECT_TRUE(activated_listener.WaitUntilSatisfied());
1663
1664 base::Optional<WorkerId> worker_id =
1665 GetUniqueRunningWorkerId(extension->id());
1666 ASSERT_TRUE(worker_id);
1667 {
1668 // Shutdown the worker.
1669 // TODO(lazyboy): Ideally we'd want to test worker shutdown on idle, do that
1670 // once //content API allows to override test timeouts for Service Workers.
1671 base::RunLoop run_loop;
1672 content::StoragePartition* storage_partition =
1673 content::BrowserContext::GetDefaultStoragePartition(
1674 browser()->profile());
1675 GURL scope = extension->url();
1676 content::StopServiceWorkerForScope(
1677 storage_partition->GetServiceWorkerContext(),
1678 // The service worker is registered at the top level scope.
1679 extension->url(), run_loop.QuitClosure());
1680 run_loop.Run();
1681 }
1682
1683 EXPECT_FALSE(ProcessManager::Get(profile())->HasServiceWorker(*worker_id));
1684}
1685
Devlin Cronin242d19d22019-03-12 18:08:481686IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
Istiaque Ahmedd4b67ee2019-03-02 10:53:201687 ProcessManagerRegistrationOnTerminate) {
1688 // NOTE: It is not necessary to wait for "activate" event from the worker
1689 // for this test, but we're lazily reusing the extension from
1690 // ProcessManagerRegistrationOnShutdown test.
1691 ExtensionTestMessageListener activated_listener("WORKER_ACTIVATED", false);
1692 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
1693 "service_worker/worker_based_background/process_manager"));
1694 ASSERT_TRUE(extension);
1695 EXPECT_TRUE(activated_listener.WaitUntilSatisfied());
1696
1697 base::Optional<WorkerId> worker_id =
1698 GetUniqueRunningWorkerId(extension->id());
1699 ASSERT_TRUE(worker_id);
1700 {
1701 // Terminate worker's RenderProcessHost.
1702 content::RenderProcessHost* worker_render_process_host =
1703 content::RenderProcessHost::FromID(worker_id->render_process_id);
1704 ASSERT_TRUE(worker_render_process_host);
1705 content::RenderProcessHostWatcher process_exit_observer(
1706 worker_render_process_host,
1707 content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1708 worker_render_process_host->Shutdown(content::RESULT_CODE_KILLED);
1709 process_exit_observer.Wait();
1710 }
1711
1712 EXPECT_FALSE(ProcessManager::Get(profile())->HasServiceWorker(*worker_id));
1713}
1714
David Bertoni904dd602019-06-24 21:42:091715// Tests that worker ref count increments while extension API function is
1716// active.
1717IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, WorkerRefCount) {
1718 ExtensionTestMessageListener worker_start_listener("WORKER STARTED", false);
1719
1720 const Extension* extension = LoadExtensionWithFlags(
1721 test_data_dir_.AppendASCII(
1722 "service_worker/worker_based_background/worker_ref_count"),
1723 kFlagNone);
1724 ASSERT_TRUE(extension);
1725 ASSERT_TRUE(worker_start_listener.WaitUntilSatisfied());
1726
1727 ui_test_utils::NavigateToURL(browser(),
1728 extension->GetResourceURL("page.html"));
1729 content::WebContents* web_contents =
1730 browser()->tab_strip_model()->GetActiveWebContents();
1731
1732 // Service worker should have no pending requests because it hasn't performed
1733 // any extension API request yet.
1734 EXPECT_EQ(0u, GetWorkerRefCount(extension->url()));
1735
1736 ExtensionTestMessageListener worker_listener("CHECK_REF_COUNT", true);
1737 worker_listener.set_failure_message("FAILURE");
1738 ASSERT_TRUE(content::ExecuteScript(web_contents, "window.testSendMessage()"));
1739 ASSERT_TRUE(worker_listener.WaitUntilSatisfied());
1740
1741 // Service worker should have exactly one pending request because
1742 // chrome.test.sendMessage() API call is in-flight.
1743 EXPECT_EQ(1u, GetWorkerRefCount(extension->url()));
1744
1745 // Perform another extension API request while one is ongoing.
1746 {
1747 ExtensionTestMessageListener listener("CHECK_REF_COUNT", true);
1748 listener.set_failure_message("FAILURE");
1749 ASSERT_TRUE(
1750 content::ExecuteScript(web_contents, "window.testSendMessage()"));
1751 ASSERT_TRUE(listener.WaitUntilSatisfied());
1752
1753 // Service worker currently has two extension API requests in-flight.
1754 EXPECT_EQ(2u, GetWorkerRefCount(extension->url()));
1755 // Finish executing the nested chrome.test.sendMessage() first.
1756 listener.Reply("Hello world");
1757 }
1758
1759 ExtensionTestMessageListener worker_completion_listener("SUCCESS_FROM_WORKER",
1760 false);
1761 // Finish executing chrome.test.sendMessage().
1762 worker_listener.Reply("Hello world");
1763 EXPECT_TRUE(worker_completion_listener.WaitUntilSatisfied());
1764
1765 // The following block makes sure we have received all the IPCs related to
1766 // ref-count from the worker.
1767 {
1768 // The following roundtrip:
1769 // browser->extension->worker->extension->browser
1770 // will ensure that the worker sent the relevant ref count IPCs.
1771 std::string result;
1772 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1773 web_contents, "window.roundtripToWorker();", &result));
1774 EXPECT_EQ("roundtrip-succeeded", result);
1775
1776 // Ensure IO thread IPCs run.
1777 content::RunAllTasksUntilIdle();
1778 }
1779
1780 // The ref count should drop to 0.
1781 EXPECT_EQ(0u, GetWorkerRefCount(extension->url()));
1782}
1783
David Bertoni4d9cf41d2019-06-04 00:06:221784IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
1785 PRE_EventsAfterRestart) {
1786 ExtensionTestMessageListener event_added_listener("ready", false);
1787 const Extension* extension = LoadExtensionWithFlags(
1788 test_data_dir_.AppendASCII(
1789 "service_worker/worker_based_background/events_to_stopped_extension"),
1790 kFlagNone);
1791 ASSERT_TRUE(extension);
1792 EXPECT_EQ(kTestExtensionId, extension->id());
1793 ProcessManager* pm = ProcessManager::Get(browser()->profile());
1794 // TODO(crbug.com/969884): This will break once keep alive counts
1795 // for service workers are tracked by the Process Manager.
1796 EXPECT_LT(pm->GetLazyKeepaliveCount(extension), 1);
1797 EXPECT_TRUE(pm->GetLazyKeepaliveActivities(extension).empty());
1798 EXPECT_TRUE(event_added_listener.WaitUntilSatisfied());
1799}
1800
1801// After browser restarts, this test step ensures that opening a tab fires
1802// tabs.onCreated event listener to the extension without explicitly loading the
1803// extension. This is because the extension registered a listener for
1804// tabs.onMoved before browser restarted in PRE_EventsAfterRestart.
1805IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, EventsAfterRestart) {
1806 // Verify there is no RenderProcessHost for the extension.
David Bertoni023e0ec2019-06-10 17:28:221807 EXPECT_FALSE(ExtensionHasRenderProcessHost(kTestExtensionId));
David Bertoni4d9cf41d2019-06-04 00:06:221808
1809 ExtensionTestMessageListener moved_tab_listener("moved-tab", false);
1810 // Add a tab, then move it.
1811 content::WebContents* new_web_contents =
Istiaque Ahmed3f692562019-07-26 22:59:261812 browsertest_util::AddTab(browser(), GURL(url::kAboutBlankURL));
David Bertoni4d9cf41d2019-06-04 00:06:221813 EXPECT_TRUE(new_web_contents);
1814 browser()->tab_strip_model()->MoveWebContentsAt(
1815 browser()->tab_strip_model()->count() - 1, 0, false);
1816 EXPECT_TRUE(moved_tab_listener.WaitUntilSatisfied());
1817}
1818
Istiaque Ahmed1e59aec2019-06-05 22:40:241819IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, TabsOnCreated) {
1820 ASSERT_TRUE(RunExtensionTestWithFlags("tabs/lazy_background_on_created",
1821 kFlagRunAsServiceWorkerBasedExtension))
1822 << message_;
1823}
1824
David Bertoni023e0ec2019-06-10 17:28:221825IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
1826 PRE_FilteredEventsAfterRestart) {
1827 ExtensionTestMessageListener listener_added("ready", false);
1828 const Extension* extension = LoadExtensionWithFlags(
1829 test_data_dir_.AppendASCII("service_worker/worker_based_background/"
1830 "filtered_events_after_restart"),
1831 kFlagNone);
1832 ASSERT_TRUE(extension);
1833 EXPECT_EQ(kTestExtensionId, extension->id());
1834 ProcessManager* pm = ProcessManager::Get(browser()->profile());
1835 // TODO(crbug.com/969884): This will break once keep alive counts
1836 // for service workers are tracked by the Process Manager.
1837 EXPECT_LT(pm->GetLazyKeepaliveCount(extension), 1);
1838 EXPECT_TRUE(pm->GetLazyKeepaliveActivities(extension).empty());
1839 EXPECT_TRUE(listener_added.WaitUntilSatisfied());
1840}
1841
1842// After browser restarts, this test step ensures that opening a tab fires
1843// tabs.onCreated event listener to the extension without explicitly loading the
1844// extension. This is because the extension registered a listener for
1845// tabs.onMoved before browser restarted in PRE_EventsAfterRestart.
1846IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
1847 FilteredEventsAfterRestart) {
1848 // Verify there is no RenderProcessHost for the extension.
1849 // TODO(crbug.com/971309): This is currently broken because the test
1850 // infrastructure opens a tab, which dispatches an event to our
1851 // extension, even though the filter doesn't include that URL. The
1852 // referenced bug is about moving filtering into the EventRouter so they
1853 // get filtered before being dispatched.
1854 EXPECT_TRUE(ExtensionHasRenderProcessHost(kTestExtensionId));
1855
1856 // Create a tab to a.html, expect it to navigate to b.html. The service worker
1857 // will see two webNavigation.onCommitted events.
1858 GURL page_url = embedded_test_server()->GetURL(
1859 "/extensions/api_test/service_worker/worker_based_background/"
1860 "filtered_events_after_restart/"
1861 "a.html");
1862 ExtensionTestMessageListener worker_filtered_event_listener(
1863 "PASS_FROM_WORKER", false);
1864 worker_filtered_event_listener.set_failure_message("FAIL_FROM_WORKER");
Istiaque Ahmed3f692562019-07-26 22:59:261865 content::WebContents* web_contents =
1866 browsertest_util::AddTab(browser(), page_url);
David Bertoni023e0ec2019-06-10 17:28:221867 EXPECT_TRUE(web_contents);
1868 EXPECT_TRUE(worker_filtered_event_listener.WaitUntilSatisfied());
1869}
1870
Istiaque Ahmed91d6987c2019-06-25 00:09:331871// Tests that chrome.browserAction.onClicked sees user gesture.
1872IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
1873 BrowserActionUserGesture) {
1874 // First, load |extension| first so that it has browserAction.onClicked
1875 // listener registered.
1876 ExtensionTestMessageListener listener_added("ready", false);
1877 const Extension* extension = LoadExtension(
1878 test_data_dir_.AppendASCII("service_worker/worker_based_background/"
1879 "browser_action"));
1880 ASSERT_TRUE(extension);
1881 EXPECT_TRUE(listener_added.WaitUntilSatisfied());
1882
1883 ResultCatcher catcher;
1884 // Click on browser action to start the test.
1885 {
Istiaque Ahmed3f692562019-07-26 22:59:261886 content::WebContents* web_contents =
1887 browsertest_util::AddTab(browser(), GURL("about:blank"));
Istiaque Ahmed91d6987c2019-06-25 00:09:331888 ASSERT_TRUE(web_contents);
1889 ExtensionActionRunner::GetForWebContents(
1890 browser()->tab_strip_model()->GetActiveWebContents())
1891 ->RunAction(extension, true);
1892 }
1893 EXPECT_TRUE(catcher.GetNextResult()) << message_;
1894}
1895
Istiaque Ahmed242a4102019-06-25 01:47:571896// Tests that Service Worker notification handlers can call extension APIs that
1897// require user gesture to be present.
1898IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTestWithNotification,
1899 ServiceWorkerNotificationClick) {
1900 ResultCatcher catcher;
1901 const Extension* extension = LoadExtension(
1902 test_data_dir_.AppendASCII("service_worker/worker_based_background/"
1903 "notification_click"));
1904 ASSERT_TRUE(extension);
1905 EXPECT_TRUE(catcher.GetNextResult()) << message_;
1906
1907 // Click on the Service Worker notification.
1908 {
1909 std::vector<message_center::Notification> notifications =
1910 GetDisplayedNotifications();
1911 ASSERT_EQ(1u, notifications.size());
1912 display_service_tester_->SimulateClick(
1913 NotificationHandler::Type::WEB_PERSISTENT, notifications[0].id(),
1914 base::nullopt, base::nullopt);
1915 }
1916
1917 EXPECT_TRUE(catcher.GetNextResult()) << message_;
1918}
1919
Istiaque Ahmed3dd604232019-08-02 19:22:211920// Tests chrome.permissions.request API.
1921IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, PermissionsAPI) {
1922 // First, load |extension| first so that it has browserAction.onClicked
1923 // listener registered.
1924 ExtensionTestMessageListener worker_listener("ready", false);
1925 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
1926 "service_worker/worker_based_background/permissions_api"));
1927 ASSERT_TRUE(extension);
1928 const ExtensionId extension_id = extension->id();
1929 EXPECT_TRUE(worker_listener.WaitUntilSatisfied());
1930
1931 // "storage" permission is optional in |extension|, and isn't available right
1932 // away.
1933 EXPECT_FALSE(
1934 extension->permissions_data()->HasAPIPermission(APIPermission::kStorage));
1935
1936 PermissionsRequestFunction::SetAutoConfirmForTests(true);
1937
1938 ResultCatcher catcher;
1939 // Click on browser action to start the test.
1940 {
1941 content::WebContents* web_contents =
1942 browsertest_util::AddTab(browser(), GURL("about:blank"));
1943 ASSERT_TRUE(web_contents);
1944 ExtensionActionRunner::GetForWebContents(
1945 browser()->tab_strip_model()->GetActiveWebContents())
1946 ->RunAction(extension, true);
1947 }
1948 EXPECT_TRUE(catcher.GetNextResult()) << message_;
1949
1950 // Expect the permission ("storage") to be available now.
1951 EXPECT_TRUE(
1952 extension->permissions_data()->HasAPIPermission(APIPermission::kStorage));
1953}
1954
Devlin Cronin59551d82019-03-05 01:28:591955// Tests that console messages logged by extension service workers, both via
1956// the typical console.* methods and via our custom bindings console, are
1957// passed through the normal ServiceWorker console messaging and are
1958// observable.
Devlin Cronin242d19d22019-03-12 18:08:481959IN_PROC_BROWSER_TEST_F(ServiceWorkerLazyBackgroundTest, ConsoleLogging) {
Devlin Cronin59551d82019-03-05 01:28:591960 // A helper class to wait for a particular message to be logged from a
1961 // ServiceWorker.
1962 class ConsoleMessageObserver : public content::ServiceWorkerContextObserver {
1963 public:
1964 ConsoleMessageObserver(content::BrowserContext* browser_context,
1965 const std::string& expected_message)
1966 : expected_message_(base::UTF8ToUTF16(expected_message)),
1967 scoped_observer_(this) {
1968 content::StoragePartition* partition =
1969 content::BrowserContext::GetDefaultStoragePartition(browser_context);
1970 scoped_observer_.Add(partition->GetServiceWorkerContext());
1971 }
1972 ~ConsoleMessageObserver() override = default;
1973
1974 void Wait() { run_loop_.Run(); }
1975
1976 private:
1977 // ServiceWorkerContextObserver:
1978 void OnReportConsoleMessage(
1979 int64_t version_id,
1980 const content::ConsoleMessage& message) override {
1981 // NOTE: We could check the version_id, but it shouldn't be necessary with
1982 // the expected messages we're verifying (they're uncommon enough).
1983 if (message.message != expected_message_)
1984 return;
1985 scoped_observer_.RemoveAll();
1986 run_loop_.QuitWhenIdle();
1987 }
1988
1989 base::string16 expected_message_;
1990 base::RunLoop run_loop_;
1991 ScopedObserver<content::ServiceWorkerContext,
1992 content::ServiceWorkerContextObserver>
1993 scoped_observer_;
1994
1995 DISALLOW_COPY_AND_ASSIGN(ConsoleMessageObserver);
1996 };
1997
1998 TestExtensionDir test_dir;
1999 test_dir.WriteManifest(
2000 R"({
2001 "name": "Test Extension",
2002 "manifest_version": 2,
2003 "version": "0.1",
David Bertoni630837d2019-04-02 21:22:102004 "background": {"service_worker": "script.js"}
Devlin Cronin59551d82019-03-05 01:28:592005 })");
2006 constexpr char kScript[] =
2007 R"(// First, log a message using the normal, built-in blink console.
2008 console.log('test message');
2009 chrome.test.runTests([
2010 function justATest() {
2011 // Next, we use the "Console" object from
2012 // extensions/renderer/console.cc, which is used by custom bindings
2013 // so that it isn't tampered with by untrusted script. The test
2014 // custom bindings log a message whenever a test is passed, so we
2015 // force a log by just passing this test.
2016 chrome.test.succeed();
2017 }
2018 ]);)";
2019 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"), kScript);
2020
2021 // The observer for the built-in blink console.
2022 ConsoleMessageObserver default_console_observer(profile(), "test message");
2023 // The observer for our custom extensions bindings console.
2024 ConsoleMessageObserver custom_console_observer(profile(),
2025 "[SUCCESS] justATest");
2026
2027 const Extension* extension = LoadExtension(test_dir.UnpackedPath());
2028 ASSERT_TRUE(extension);
2029
2030 default_console_observer.Wait();
2031 custom_console_observer.Wait();
2032 // If we receive both messages, we passed!
2033}
2034
annekao38685502015-07-14 17:46:392035} // namespace extensions