blob: 126e32f21d32636b2eaa0e37e9b6f315a16521cf [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 Bertoni98a5da72019-08-23 23:38:2220#include "chrome/browser/extensions/chrome_test_extension_loader.h"
David Bertoni9026eff2019-05-01 18:04:3121#include "chrome/browser/extensions/crx_installer.h"
Istiaque Ahmed91d6987c2019-06-25 00:09:3322#include "chrome/browser/extensions/extension_action_runner.h"
annekao38685502015-07-14 17:46:3923#include "chrome/browser/extensions/extension_apitest.h"
rdevlin.croninf5863da2015-09-10 19:21:4524#include "chrome/browser/extensions/extension_service.h"
Istiaque Ahmed805f6a83b2017-10-05 01:23:2625#include "chrome/browser/extensions/lazy_background_page_test_util.h"
David Bertoni1d646a152019-04-25 02:09:2226#include "chrome/browser/extensions/unpacked_installer.h"
peter9f4490a2017-01-27 00:58:3627#include "chrome/browser/gcm/gcm_profile_service_factory.h"
miguelg9b502862017-04-24 18:13:5328#include "chrome/browser/notifications/notification_display_service_factory.h"
Istiaque Ahmed242a4102019-06-25 01:47:5729#include "chrome/browser/notifications/notification_display_service_tester.h"
Peter Beverloodd4ef1e2018-06-21 15:41:0430#include "chrome/browser/notifications/notification_permission_context.h"
miguelg9b502862017-04-24 18:13:5331#include "chrome/browser/notifications/stub_notification_display_service.h"
lshang106c1772016-06-06 01:43:2332#include "chrome/browser/permissions/permission_manager.h"
timlohc6911802017-03-01 05:37:0333#include "chrome/browser/permissions/permission_result.h"
lazyboy561b7de2015-11-19 19:27:3034#include "chrome/browser/push_messaging/push_messaging_app_identifier.h"
35#include "chrome/browser/push_messaging/push_messaging_service_factory.h"
36#include "chrome/browser/push_messaging/push_messaging_service_impl.h"
Istiaque Ahmed91d6987c2019-06-25 00:09:3337#include "chrome/browser/ui/extensions/browser_action_test_util.h"
annekao1db36fd2015-07-29 17:09:1638#include "chrome/browser/ui/tabs/tab_strip_model.h"
Trent Apted4267b942017-10-27 03:25:3639#include "chrome/common/chrome_switches.h"
Istiaque Ahmeda14ec482018-08-25 01:02:1840#include "chrome/common/extensions/api/web_navigation.h"
rdevlin.croninf5863da2015-09-10 19:21:4541#include "chrome/test/base/ui_test_utils.h"
timloh9a180ad2017-02-20 07:15:2342#include "components/content_settings/core/common/content_settings_types.h"
Peter Beverloo34139462018-04-10 14:18:0643#include "components/gcm_driver/fake_gcm_profile_service.h"
johnmea5045732016-09-08 17:23:2944#include "components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h"
sdefresne9fb67692015-08-03 18:48:2245#include "components/version_info/version_info.h"
Devlin Cronin59551d82019-03-05 01:28:5946#include "content/public/browser/console_message.h"
kalman6f984ae2015-09-18 17:21:5847#include "content/public/browser/navigation_controller.h"
rdevlin.croninf5863da2015-09-10 19:21:4548#include "content/public/browser/navigation_entry.h"
Istiaque Ahmedd4b67ee2019-03-02 10:53:2049#include "content/public/browser/render_process_host.h"
lazyboy4c82177a2016-10-18 00:04:0950#include "content/public/browser/service_worker_context.h"
Devlin Cronin59551d82019-03-05 01:28:5951#include "content/public/browser/service_worker_context_observer.h"
lazyboy4c82177a2016-10-18 00:04:0952#include "content/public/browser/storage_partition.h"
kalman6f984ae2015-09-18 17:21:5853#include "content/public/browser/web_contents.h"
lazyboybd325ae2015-11-18 21:35:2654#include "content/public/common/content_switches.h"
falkenad185092016-06-16 06:10:0255#include "content/public/common/origin_util.h"
kalman6f984ae2015-09-18 17:21:5856#include "content/public/common/page_type.h"
Istiaque Ahmedd4b67ee2019-03-02 10:53:2057#include "content/public/common/result_codes.h"
lazyboybd325ae2015-11-18 21:35:2658#include "content/public/test/background_sync_test_util.h"
annekao1db36fd2015-07-29 17:09:1659#include "content/public/test/browser_test_utils.h"
lazyboy63b994a2017-06-30 21:20:2360#include "content/public/test/service_worker_test_helpers.h"
Istiaque Ahmed771aa8a22018-06-20 23:40:5361#include "extensions/browser/event_router.h"
kalman6f984ae2015-09-18 17:21:5862#include "extensions/browser/extension_host.h"
lazyboyc3e763a2015-12-09 23:09:5863#include "extensions/browser/extension_registry.h"
kalman6f984ae2015-09-18 17:21:5864#include "extensions/browser/process_manager.h"
Istiaque Ahmed70f76ac2018-11-02 02:59:5565#include "extensions/browser/service_worker_task_queue.h"
Istiaque Ahmeda14ec482018-08-25 01:02:1866#include "extensions/common/api/test.h"
David Bertoni98a5da72019-08-23 23:38:2267#include "extensions/common/extensions_client.h"
68#include "extensions/common/manifest_handlers/background_info.h"
Istiaque Ahmed3dd604232019-08-02 19:22:2169#include "extensions/common/permissions/permissions_data.h"
Istiaque Ahmed771aa8a22018-06-20 23:40:5370#include "extensions/common/value_builder.h"
David Bertoni9026eff2019-05-01 18:04:3171#include "extensions/common/verifier_formats.h"
kalman6f984ae2015-09-18 17:21:5872#include "extensions/test/background_page_watcher.h"
annekao38685502015-07-14 17:46:3973#include "extensions/test/extension_test_message_listener.h"
Istiaque Ahmed805f6a83b2017-10-05 01:23:2674#include "extensions/test/result_catcher.h"
Devlin Cronin59551d82019-03-05 01:28:5975#include "extensions/test/test_extension_dir.h"
falkenad185092016-06-16 06:10:0276#include "net/dns/mock_host_resolver.h"
horo1eeddde2015-11-19 05:59:2577#include "net/test/embedded_test_server/embedded_test_server.h"
Istiaque Ahmed242a4102019-06-25 01:47:5778#include "ui/message_center/public/cpp/notification.h"
lazyboy63b994a2017-06-30 21:20:2379#include "url/url_constants.h"
annekao38685502015-07-14 17:46:3980
81namespace extensions {
82
kalman6f984ae2015-09-18 17:21:5883namespace {
84
lazyboy22eddc712015-12-10 21:16:2685class WebContentsLoadStopObserver : content::WebContentsObserver {
86 public:
87 explicit WebContentsLoadStopObserver(content::WebContents* web_contents)
88 : content::WebContentsObserver(web_contents),
89 load_stop_observed_(false) {}
90
91 void WaitForLoadStop() {
92 if (load_stop_observed_)
93 return;
94 message_loop_runner_ = new content::MessageLoopRunner;
95 message_loop_runner_->Run();
96 }
97
98 private:
99 void DidStopLoading() override {
100 load_stop_observed_ = true;
101 if (message_loop_runner_)
102 message_loop_runner_->Quit();
103 }
104
105 bool load_stop_observed_;
106 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
107
108 DISALLOW_COPY_AND_ASSIGN(WebContentsLoadStopObserver);
109};
110
David Bertoni4d9cf41d2019-06-04 00:06:22111// A known extension ID for tests that specify the key in their
112// manifests.
113constexpr char kTestExtensionId[] = "knldjmfmopnpolahpmmgbagdohdnhkik";
114
kalman6f984ae2015-09-18 17:21:58115} // namespace
116
Devlin Cronin242d19d22019-03-12 18:08:48117class ServiceWorkerTest : public ExtensionApiTest {
annekao38685502015-07-14 17:46:39118 public:
lazyboy20167c22016-05-18 00:59:30119 ServiceWorkerTest() : current_channel_(version_info::Channel::STABLE) {}
Istiaque Ahmed7105f2a2017-10-07 01:11:59120 explicit ServiceWorkerTest(version_info::Channel channel)
121 : current_channel_(channel) {}
annekao38685502015-07-14 17:46:39122
123 ~ServiceWorkerTest() override {}
124
jam1a5b5582017-05-01 16:50:10125 void SetUpOnMainThread() override {
126 ExtensionApiTest::SetUpOnMainThread();
David Bertoni3929f552019-03-28 22:10:36127 host_resolver()->AddRule("*", "127.0.0.1");
jam1a5b5582017-05-01 16:50:10128 }
129
kalman6f984ae2015-09-18 17:21:58130 protected:
131 // Returns the ProcessManager for the test's profile.
132 ProcessManager* process_manager() { return ProcessManager::Get(profile()); }
133
134 // Starts running a test from the background page test extension.
135 //
136 // This registers a service worker with |script_name|, and fetches the
137 // registration result.
Istiaque Ahmed93ff7f42018-08-31 01:42:22138 const Extension* StartTestFromBackgroundPage(const char* script_name) {
Istiaque Ahmed6475f542018-08-28 04:20:21139 ExtensionTestMessageListener ready_listener("ready", false);
kalman6f984ae2015-09-18 17:21:58140 const Extension* extension =
141 LoadExtension(test_data_dir_.AppendASCII("service_worker/background"));
142 CHECK(extension);
Istiaque Ahmed6475f542018-08-28 04:20:21143 CHECK(ready_listener.WaitUntilSatisfied());
144
kalman6f984ae2015-09-18 17:21:58145 ExtensionHost* background_host =
146 process_manager()->GetBackgroundHostForExtension(extension->id());
147 CHECK(background_host);
Istiaque Ahmed6475f542018-08-28 04:20:21148
kalman6f984ae2015-09-18 17:21:58149 std::string error;
150 CHECK(content::ExecuteScriptAndExtractString(
151 background_host->host_contents(),
152 base::StringPrintf("test.registerServiceWorker('%s')", script_name),
153 &error));
Istiaque Ahmed93ff7f42018-08-31 01:42:22154 if (!error.empty())
kalman6f984ae2015-09-18 17:21:58155 ADD_FAILURE() << "Got unexpected error " << error;
156 return extension;
157 }
158
159 // Navigates the browser to a new tab at |url|, waits for it to load, then
160 // returns it.
161 content::WebContents* Navigate(const GURL& url) {
162 ui_test_utils::NavigateToURLWithDisposition(
nick3b04f322016-08-31 19:29:19163 browser(), url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
kalman6f984ae2015-09-18 17:21:58164 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
165 content::WebContents* web_contents =
166 browser()->tab_strip_model()->GetActiveWebContents();
167 content::WaitForLoadStop(web_contents);
168 return web_contents;
169 }
170
171 // Navigates the browser to |url| and returns the new tab's page type.
172 content::PageType NavigateAndGetPageType(const GURL& url) {
clamy1d7a4112018-06-15 15:47:16173 return Navigate(url)
174 ->GetController()
175 .GetLastCommittedEntry()
176 ->GetPageType();
kalman6f984ae2015-09-18 17:21:58177 }
178
179 // Extracts the innerText from |contents|.
180 std::string ExtractInnerText(content::WebContents* contents) {
181 std::string inner_text;
182 if (!content::ExecuteScriptAndExtractString(
183 contents,
184 "window.domAutomationController.send(document.body.innerText)",
185 &inner_text)) {
186 ADD_FAILURE() << "Failed to get inner text for "
187 << contents->GetVisibleURL();
188 }
189 return inner_text;
190 }
191
192 // Navigates the browser to |url|, then returns the innerText of the new
193 // tab's WebContents' main frame.
194 std::string NavigateAndExtractInnerText(const GURL& url) {
195 return ExtractInnerText(Navigate(url));
196 }
197
lazyboy4c82177a2016-10-18 00:04:09198 size_t GetWorkerRefCount(const GURL& origin) {
199 content::ServiceWorkerContext* sw_context =
200 content::BrowserContext::GetDefaultStoragePartition(
201 browser()->profile())
202 ->GetServiceWorkerContext();
203 base::RunLoop run_loop;
204 size_t ref_count = 0;
205 auto set_ref_count = [](size_t* ref_count, base::RunLoop* run_loop,
206 size_t external_request_count) {
207 *ref_count = external_request_count;
208 run_loop->Quit();
209 };
210 sw_context->CountExternalRequestsForTest(
Matt Falkenhagenc5cb4282017-09-07 08:43:42211 origin, base::BindOnce(set_ref_count, &ref_count, &run_loop));
lazyboy4c82177a2016-10-18 00:04:09212 run_loop.Run();
213 return ref_count;
214 }
215
annekao38685502015-07-14 17:46:39216 private:
lazyboy20167c22016-05-18 00:59:30217 // Sets the channel to "stable".
218 // Not useful after we've opened extension Service Workers to stable
219 // channel.
220 // TODO(lazyboy): Remove this when ExtensionServiceWorkersEnabled() is
221 // removed.
annekao38685502015-07-14 17:46:39222 ScopedCurrentChannel current_channel_;
kalman6f984ae2015-09-18 17:21:58223
annekao38685502015-07-14 17:46:39224 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerTest);
225};
226
Istiaque Ahmedccb444022018-06-19 02:11:12227class ServiceWorkerBasedBackgroundTest : public ServiceWorkerTest {
228 public:
229 ServiceWorkerBasedBackgroundTest()
230 : ServiceWorkerTest(
231 // Extensions APIs from SW are only enabled on trunk.
232 // It is important to set the channel early so that this change is
233 // visible in renderers running with service workers (and no
234 // extension).
235 version_info::Channel::UNKNOWN) {}
236 ~ServiceWorkerBasedBackgroundTest() override {}
237
238 void SetUpOnMainThread() override {
239 host_resolver()->AddRule("*", "127.0.0.1");
240 ASSERT_TRUE(embedded_test_server()->Start());
241 ServiceWorkerTest::SetUpOnMainThread();
242 }
243
Istiaque Ahmedd4b67ee2019-03-02 10:53:20244 // Returns the only running worker id for |extension_id|.
245 // Returns base::nullopt if there isn't any worker running or more than one
246 // worker is running for |extension_id|.
247 base::Optional<WorkerId> GetUniqueRunningWorkerId(
248 const ExtensionId& extension_id) {
249 ProcessManager* process_manager = ProcessManager::Get(profile());
250 std::vector<WorkerId> all_workers =
251 process_manager->GetAllWorkersIdsForTesting();
252 base::Optional<WorkerId> running_worker_id;
253 for (const WorkerId& worker_id : all_workers) {
254 if (worker_id.extension_id == extension_id) {
255 if (running_worker_id) // More than one worker present.
256 return base::nullopt;
257 running_worker_id = worker_id;
258 }
259 }
260 return running_worker_id;
261 }
262
David Bertoni023e0ec2019-06-10 17:28:22263 bool ExtensionHasRenderProcessHost(const ExtensionId& extension_id) {
264 ProcessMap* process_map = ProcessMap::Get(browser()->profile());
265 content::RenderProcessHost::iterator it =
266 content::RenderProcessHost::AllHostsIterator();
267 while (!it.IsAtEnd()) {
268 if (process_map->Contains(extension_id, it.GetCurrentValue()->GetID())) {
269 return true;
270 }
271 it.Advance();
272 }
273 return false;
274 }
275
Istiaque Ahmedccb444022018-06-19 02:11:12276 private:
277 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerBasedBackgroundTest);
278};
279
Istiaque Ahmed242a4102019-06-25 01:47:57280class ServiceWorkerBasedBackgroundTestWithNotification
281 : public ServiceWorkerBasedBackgroundTest {
282 public:
283 ServiceWorkerBasedBackgroundTestWithNotification() {}
284 ~ServiceWorkerBasedBackgroundTestWithNotification() override = default;
285
286 void SetUpOnMainThread() override {
287 ServiceWorkerBasedBackgroundTest::SetUpOnMainThread();
288 display_service_tester_ =
289 std::make_unique<NotificationDisplayServiceTester>(
290 browser()->profile());
291 }
292
293 void TearDownOnMainThread() override {
294 display_service_tester_.reset();
295 ServiceWorkerBasedBackgroundTest::TearDownOnMainThread();
296 }
297
298 protected:
299 // Returns a vector with the Notification objects that are being displayed
300 // by the notification display service. Synchronous.
301 std::vector<message_center::Notification> GetDisplayedNotifications() const {
302 return display_service_tester_->GetDisplayedNotificationsForType(
303 NotificationHandler::Type::WEB_PERSISTENT);
304 }
305
306 std::unique_ptr<NotificationDisplayServiceTester> display_service_tester_;
307
308 private:
309 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerBasedBackgroundTestWithNotification);
310};
311
Istiaque Ahmedccb444022018-06-19 02:11:12312// Tests that Service Worker based background pages can be loaded and they can
313// receive extension events.
314// The extension is installed and loaded during this step and it registers
315// an event listener for tabs.onCreated event. The step also verifies that tab
316// creation correctly fires the listener.
Devlin Cronin242d19d22019-03-12 18:08:48317IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, PRE_Basic) {
Istiaque Ahmedccb444022018-06-19 02:11:12318 ExtensionTestMessageListener newtab_listener("CREATED", false);
319 newtab_listener.set_failure_message("CREATE_FAILED");
320 ExtensionTestMessageListener worker_listener("WORKER_RUNNING", false);
321 worker_listener.set_failure_message("NON_WORKER_SCOPE");
322 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
323 "service_worker/worker_based_background/basic"));
324 ASSERT_TRUE(extension);
325 const ExtensionId extension_id = extension->id();
326 EXPECT_TRUE(worker_listener.WaitUntilSatisfied());
327
328 const GURL url = embedded_test_server()->GetURL("/extensions/test_file.html");
Istiaque Ahmed3f692562019-07-26 22:59:26329 content::WebContents* new_web_contents =
330 browsertest_util::AddTab(browser(), url);
Istiaque Ahmedccb444022018-06-19 02:11:12331 EXPECT_TRUE(new_web_contents);
332 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
333
334 // Service Worker extension does not have ExtensionHost.
335 EXPECT_FALSE(process_manager()->GetBackgroundHostForExtension(extension_id));
336}
337
338// After browser restarts, this test step ensures that opening a tab fires
339// tabs.onCreated event listener to the extension without explicitly loading the
340// extension. This is because the extension registered a listener before browser
341// restarted in PRE_Basic.
Devlin Cronin242d19d22019-03-12 18:08:48342IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, Basic) {
Istiaque Ahmedccb444022018-06-19 02:11:12343 ExtensionTestMessageListener newtab_listener("CREATED", false);
344 newtab_listener.set_failure_message("CREATE_FAILED");
345 const GURL url = embedded_test_server()->GetURL("/extensions/test_file.html");
Istiaque Ahmed3f692562019-07-26 22:59:26346 content::WebContents* new_web_contents =
347 browsertest_util::AddTab(browser(), url);
Istiaque Ahmedccb444022018-06-19 02:11:12348 EXPECT_TRUE(new_web_contents);
349 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
350}
351
Istiaque Ahmedbf08f952018-10-02 01:22:04352// Tests chrome.runtime.onInstalled fires for extension service workers.
Devlin Cronin242d19d22019-03-12 18:08:48353IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, OnInstalledEvent) {
Istiaque Ahmedbf08f952018-10-02 01:22:04354 ASSERT_TRUE(RunExtensionTest(
355 "service_worker/worker_based_background/events_on_installed"))
356 << message_;
357}
358
Istiaque Ahmedba8d0652019-05-14 15:17:34359// Tests chrome.runtime.id and chrome.runtime.getURL().
360IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, RuntimeMisc) {
361 ASSERT_TRUE(
362 RunExtensionTest("service_worker/worker_based_background/runtime_misc"))
363 << message_;
364}
365
David Bertoni69982832019-02-13 21:24:21366// Tests chrome.storage APIs.
Devlin Cronin242d19d22019-03-12 18:08:48367IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, StorageSetAndGet) {
David Bertoni69982832019-02-13 21:24:21368 ASSERT_TRUE(
369 RunExtensionTest("service_worker/worker_based_background/storage"))
370 << message_;
371}
372
David Bertoni0665c892019-02-14 00:27:26373// Tests chrome.storage.local and chrome.storage.local APIs.
Devlin Cronin242d19d22019-03-12 18:08:48374IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, StorageNoPermissions) {
David Bertoni0665c892019-02-14 00:27:26375 ASSERT_TRUE(RunExtensionTest(
376 "service_worker/worker_based_background/storage_no_permissions"))
377 << message_;
378}
379
David Bertoni30809312019-02-28 22:56:05380// Tests chrome.tabs APIs.
Devlin Cronin242d19d22019-03-12 18:08:48381IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, TabsBasic) {
David Bertoni30809312019-02-28 22:56:05382 ASSERT_TRUE(
383 RunExtensionTest("service_worker/worker_based_background/tabs_basic"))
384 << message_;
385}
386
David Bertoni46d698892019-02-26 00:29:10387// Tests chrome.tabs events.
Devlin Cronin242d19d22019-03-12 18:08:48388IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, TabsEvents) {
David Bertoni46d698892019-02-26 00:29:10389 ASSERT_TRUE(
390 RunExtensionTest("service_worker/worker_based_background/tabs_events"))
391 << message_;
392}
393
David Bertoni4c7dfcc2019-03-27 23:49:34394// Tests chrome.tabs APIs.
395IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, TabsExecuteScript) {
396 ASSERT_TRUE(RunExtensionTest(
397 "service_worker/worker_based_background/tabs_execute_script"))
398 << message_;
399}
400
David Bertoni37ae0222019-04-04 01:30:54401// Tests chrome.webRequest APIs.
Vasilii Sukhanov37fd9f722019-08-26 15:00:07402// Times out on Mac/Win only. https://crbug.com/997686
403#if defined(OS_WIN) || defined(OS_MACOSX)
404#define MAYBE_WebRequest DISABLED_WebRequest
405#else
406#define MAYBE_WebRequest WebRequest
407#endif
408IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, MAYBE_WebRequest) {
David Bertoni3929f552019-03-28 22:10:36409 ASSERT_TRUE(
410 RunExtensionTest("service_worker/worker_based_background/web_request"))
411 << message_;
412}
413
David Bertoni37ae0222019-04-04 01:30:54414// Tests chrome.webRequest APIs in blocking mode.
415IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, WebRequestBlocking) {
416 // Try to load the page before installing the extension, which should work.
417 const GURL url = embedded_test_server()->GetURL("/extensions/test_file.html");
418 EXPECT_EQ(content::PAGE_TYPE_NORMAL, NavigateAndGetPageType(url));
419
420 // Install the extension and navigate again to the page.
421 ExtensionTestMessageListener ready_listener("ready", false);
422 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII(
423 "service_worker/worker_based_background/web_request_blocking")));
424 ASSERT_TRUE(ready_listener.WaitUntilSatisfied());
425 EXPECT_EQ(content::PAGE_TYPE_ERROR, NavigateAndGetPageType(url));
426}
427
David Bertoni377f52312019-05-21 20:35:03428// Tests chrome.webNavigation APIs.
429IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, FilteredEvents) {
430 ASSERT_TRUE(RunExtensionTest(
431 "service_worker/worker_based_background/filtered_events"))
432 << message_;
433}
434
Istiaque Ahmed70f76ac2018-11-02 02:59:55435// Listens for |message| from extension Service Worker early so that tests can
436// wait for the message on startup (and not miss it).
437class ServiceWorkerWithEarlyMessageListenerTest
438 : public ServiceWorkerBasedBackgroundTest {
Istiaque Ahmedf70ab222018-10-02 03:08:24439 public:
Istiaque Ahmed70f76ac2018-11-02 02:59:55440 explicit ServiceWorkerWithEarlyMessageListenerTest(
441 const std::string& test_message)
442 : test_message_(test_message) {}
443 ~ServiceWorkerWithEarlyMessageListenerTest() override = default;
Istiaque Ahmedf70ab222018-10-02 03:08:24444
Istiaque Ahmed70f76ac2018-11-02 02:59:55445 bool WaitForMessage() { return listener_->WaitUntilSatisfied(); }
Istiaque Ahmedf70ab222018-10-02 03:08:24446
447 void CreatedBrowserMainParts(content::BrowserMainParts* main_parts) override {
448 // At this point, the notification service is initialized but the profile
449 // and extensions have not.
Istiaque Ahmed70f76ac2018-11-02 02:59:55450 listener_ =
451 std::make_unique<ExtensionTestMessageListener>(test_message_, false);
Istiaque Ahmedf70ab222018-10-02 03:08:24452 ServiceWorkerBasedBackgroundTest::CreatedBrowserMainParts(main_parts);
453 }
454
455 private:
Istiaque Ahmed70f76ac2018-11-02 02:59:55456 const std::string test_message_;
Istiaque Ahmedf70ab222018-10-02 03:08:24457 std::unique_ptr<ExtensionTestMessageListener> listener_;
458
Istiaque Ahmed70f76ac2018-11-02 02:59:55459 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerWithEarlyMessageListenerTest);
460};
461
462class ServiceWorkerOnStartupEventTest
463 : public ServiceWorkerWithEarlyMessageListenerTest {
464 public:
465 ServiceWorkerOnStartupEventTest()
466 : ServiceWorkerWithEarlyMessageListenerTest("onStartup event") {}
467 ~ServiceWorkerOnStartupEventTest() override = default;
468
469 private:
470 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerOnStartupEventTest);
Istiaque Ahmedf70ab222018-10-02 03:08:24471};
472
473// Tests "runtime.onStartup" for extension SW.
Devlin Cronin242d19d22019-03-12 18:08:48474IN_PROC_BROWSER_TEST_F(ServiceWorkerOnStartupEventTest, PRE_Event) {
Istiaque Ahmedf70ab222018-10-02 03:08:24475 ASSERT_TRUE(RunExtensionTest(
476 "service_worker/worker_based_background/on_startup_event"))
477 << message_;
478}
479
Devlin Cronin242d19d22019-03-12 18:08:48480IN_PROC_BROWSER_TEST_F(ServiceWorkerOnStartupEventTest, Event) {
Istiaque Ahmed70f76ac2018-11-02 02:59:55481 EXPECT_TRUE(WaitForMessage());
482}
483
484class ServiceWorkerRegistrationAtStartupTest
485 : public ServiceWorkerWithEarlyMessageListenerTest,
486 public ServiceWorkerTaskQueue::TestObserver {
487 public:
488 ServiceWorkerRegistrationAtStartupTest()
489 : ServiceWorkerWithEarlyMessageListenerTest("WORKER_RUNNING") {
490 ServiceWorkerTaskQueue::SetObserverForTest(this);
491 }
492 ~ServiceWorkerRegistrationAtStartupTest() override {
493 ServiceWorkerTaskQueue::SetObserverForTest(nullptr);
494 }
495
496 // ServiceWorkerTaskQueue::TestObserver:
497 void OnActivateExtension(const ExtensionId& extension_id,
498 bool will_register_service_worker) override {
499 if (extension_id != kExtensionId)
500 return;
501
502 will_register_service_worker_ = will_register_service_worker;
503
504 extension_activated_ = true;
505 if (run_loop_)
506 run_loop_->Quit();
507 }
508
509 void WaitForOnActivateExtension() {
510 if (extension_activated_)
511 return;
512 run_loop_ = std::make_unique<base::RunLoop>();
513 run_loop_->Run();
514 }
515
516 bool WillRegisterServiceWorker() {
517 return will_register_service_worker_.value();
518 }
519
520 protected:
521 static const char kExtensionId[];
522
523 private:
524 bool extension_activated_ = false;
525 base::Optional<bool> will_register_service_worker_;
526 std::unique_ptr<base::RunLoop> run_loop_;
527
528 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerRegistrationAtStartupTest);
529};
530
531// Test extension id at
532// api_test/service_worker/worker_based_background/registration_at_startup/.
533const char ServiceWorkerRegistrationAtStartupTest::kExtensionId[] =
534 "gnchfmandajfaiajniicagenfmhdjila";
535
536// Tests that Service Worker registration for existing extension isn't issued
537// upon browser restart.
538// Regression test for https://crbug.com/889687.
Devlin Cronin242d19d22019-03-12 18:08:48539IN_PROC_BROWSER_TEST_F(ServiceWorkerRegistrationAtStartupTest,
Istiaque Ahmed70f76ac2018-11-02 02:59:55540 PRE_ExtensionActivationDoesNotReregister) {
541 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
542 "service_worker/worker_based_background/registration_at_startup"));
543 ASSERT_TRUE(extension);
544 EXPECT_EQ(kExtensionId, extension->id());
545 // Wait for "WORKER_RUNNING" message from the Service Worker.
546 EXPECT_TRUE(WaitForMessage());
547 EXPECT_TRUE(WillRegisterServiceWorker());
548}
549
Devlin Cronin242d19d22019-03-12 18:08:48550IN_PROC_BROWSER_TEST_F(ServiceWorkerRegistrationAtStartupTest,
Istiaque Ahmed70f76ac2018-11-02 02:59:55551 ExtensionActivationDoesNotReregister) {
552 // Since the extension has onStartup listener, the Service Worker will run on
553 // browser start and we'll see "WORKER_RUNNING" message from the worker.
554 EXPECT_TRUE(WaitForMessage());
555 // As the extension activated during first run on PRE_ step, it shouldn't
556 // re-register the Service Worker upon browser restart.
557 EXPECT_FALSE(WillRegisterServiceWorker());
Istiaque Ahmedf70ab222018-10-02 03:08:24558}
559
Istiaque Ahmeda14ec482018-08-25 01:02:18560// Class that dispatches an event to |extension_id| right after a
561// non-lazy listener to the event is added from the extension's Service Worker.
Istiaque Ahmed771aa8a22018-06-20 23:40:53562class EarlyWorkerMessageSender : public EventRouter::Observer {
563 public:
564 EarlyWorkerMessageSender(content::BrowserContext* browser_context,
Istiaque Ahmeda14ec482018-08-25 01:02:18565 const ExtensionId& extension_id,
566 std::unique_ptr<Event> event)
Istiaque Ahmed771aa8a22018-06-20 23:40:53567 : browser_context_(browser_context),
568 event_router_(EventRouter::EventRouter::Get(browser_context_)),
569 extension_id_(extension_id),
Istiaque Ahmeda14ec482018-08-25 01:02:18570 event_(std::move(event)),
Istiaque Ahmed771aa8a22018-06-20 23:40:53571 listener_("PASS", false) {
572 DCHECK(browser_context_);
573 listener_.set_failure_message("FAIL");
Istiaque Ahmeda14ec482018-08-25 01:02:18574 event_router_->RegisterObserver(this, event_->event_name);
Istiaque Ahmed771aa8a22018-06-20 23:40:53575 }
576
577 ~EarlyWorkerMessageSender() override {
578 event_router_->UnregisterObserver(this);
579 }
580
581 // EventRouter::Observer:
582 void OnListenerAdded(const EventListenerInfo& details) override {
Istiaque Ahmeda14ec482018-08-25 01:02:18583 if (!event_ || extension_id_ != details.extension_id ||
584 event_->event_name != details.event_name) {
Istiaque Ahmed771aa8a22018-06-20 23:40:53585 return;
Istiaque Ahmeda14ec482018-08-25 01:02:18586 }
587
Istiaque Ahmed771aa8a22018-06-20 23:40:53588 const bool is_lazy_listener = details.browser_context == nullptr;
589 if (is_lazy_listener) {
590 // Wait for the non-lazy listener as we want to exercise the code to
591 // dispatch the event right after the Service Worker registration is
592 // completing.
593 return;
594 }
Istiaque Ahmeda14ec482018-08-25 01:02:18595 DispatchEvent(std::move(event_));
Istiaque Ahmed771aa8a22018-06-20 23:40:53596 }
597
598 bool SendAndWait() { return listener_.WaitUntilSatisfied(); }
599
600 private:
601 static constexpr const char* const kTestOnMessageEventName = "test.onMessage";
602
Istiaque Ahmeda14ec482018-08-25 01:02:18603 void DispatchEvent(std::unique_ptr<Event> event) {
Istiaque Ahmed771aa8a22018-06-20 23:40:53604 EventRouter::Get(browser_context_)
605 ->DispatchEventToExtension(extension_id_, std::move(event));
606 }
607
608 content::BrowserContext* const browser_context_ = nullptr;
609 EventRouter* const event_router_ = nullptr;
610 const ExtensionId extension_id_;
Istiaque Ahmeda14ec482018-08-25 01:02:18611 std::unique_ptr<Event> event_;
Istiaque Ahmed771aa8a22018-06-20 23:40:53612 ExtensionTestMessageListener listener_;
Istiaque Ahmed771aa8a22018-06-20 23:40:53613
614 DISALLOW_COPY_AND_ASSIGN(EarlyWorkerMessageSender);
615};
616
617// Tests that extension event dispatch works correctly right after extension
618// installation registers its Service Worker.
619// Regression test for: https://crbug.com/850792.
Devlin Cronin242d19d22019-03-12 18:08:48620IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, EarlyEventDispatch) {
Istiaque Ahmed771aa8a22018-06-20 23:40:53621 const ExtensionId kId("pkplfbidichfdicaijlchgnapepdginl");
Istiaque Ahmeda14ec482018-08-25 01:02:18622
623 // Build "test.onMessage" event for dispatch.
624 auto event = std::make_unique<Event>(
625 events::FOR_TEST, extensions::api::test::OnMessage::kEventName,
Lei Zhang582ecd12019-02-13 20:28:54626 base::ListValue::From(base::JSONReader::ReadDeprecated(
Istiaque Ahmeda14ec482018-08-25 01:02:18627 R"([{"data": "hello", "lastMessage": true}])")),
628 profile());
629
630 EarlyWorkerMessageSender sender(profile(), kId, std::move(event));
Istiaque Ahmed771aa8a22018-06-20 23:40:53631 // pkplfbidichfdicaijlchgnapepdginl
632 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
633 "service_worker/worker_based_background/early_event_dispatch"));
634 CHECK(extension);
635 EXPECT_EQ(kId, extension->id());
636 EXPECT_TRUE(sender.SendAndWait());
637}
638
Istiaque Ahmeda14ec482018-08-25 01:02:18639// Tests that filtered events dispatches correctly right after a non-lazy
640// listener is registered for that event (and before the corresponding lazy
641// listener is registered).
Devlin Cronin242d19d22019-03-12 18:08:48642IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
Istiaque Ahmeda14ec482018-08-25 01:02:18643 EarlyFilteredEventDispatch) {
644 const ExtensionId kId("pkplfbidichfdicaijlchgnapepdginl");
645
646 // Add minimal details required to dispatch webNavigation.onCommitted event:
647 extensions::api::web_navigation::OnCommitted::Details details;
648 details.transition_type =
649 extensions::api::web_navigation::TRANSITION_TYPE_TYPED;
650
651 // Build a dummy onCommited event to dispatch.
652 auto on_committed_event = std::make_unique<Event>(
653 events::WEB_NAVIGATION_ON_COMMITTED, "webNavigation.onCommitted",
654 api::web_navigation::OnCommitted::Create(details), profile());
655 // The filter will match the listener filter registered from the extension.
656 EventFilteringInfo info;
657 info.url = GURL("http://foo.com/a.html");
658 on_committed_event->filter_info = info;
659
660 EarlyWorkerMessageSender sender(profile(), kId,
661 std::move(on_committed_event));
662
663 // pkplfbidichfdicaijlchgnapepdginl
664 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
665 "service_worker/worker_based_background/early_filtered_event_dispatch"));
666 ASSERT_TRUE(extension);
667 EXPECT_EQ(kId, extension->id());
668 EXPECT_TRUE(sender.SendAndWait());
669}
670
lazyboybd325ae2015-11-18 21:35:26671class ServiceWorkerBackgroundSyncTest : public ServiceWorkerTest {
672 public:
673 ServiceWorkerBackgroundSyncTest() {}
674 ~ServiceWorkerBackgroundSyncTest() override {}
675
676 void SetUpCommandLine(base::CommandLine* command_line) override {
677 // ServiceWorkerRegistration.sync requires experimental flag.
678 command_line->AppendSwitch(
Istiaque Ahmedea5ed5042017-09-25 19:00:16679 ::switches::kEnableExperimentalWebPlatformFeatures);
lazyboybd325ae2015-11-18 21:35:26680 ServiceWorkerTest::SetUpCommandLine(command_line);
681 }
682
683 void SetUp() override {
Robbie McElrathdb12d8e2018-09-18 21:20:40684 content::background_sync_test_util::SetIgnoreNetworkChanges(true);
lazyboybd325ae2015-11-18 21:35:26685 ServiceWorkerTest::SetUp();
686 }
687
688 private:
689 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerBackgroundSyncTest);
690};
691
lazyboy561b7de2015-11-19 19:27:30692class ServiceWorkerPushMessagingTest : public ServiceWorkerTest {
693 public:
694 ServiceWorkerPushMessagingTest()
Sylvain Defresne212b4b02018-10-11 16:32:05695 : scoped_testing_factory_installer_(
696 base::BindRepeating(&gcm::FakeGCMProfileService::Build)),
697 gcm_driver_(nullptr),
698 push_service_(nullptr) {}
699
lazyboy561b7de2015-11-19 19:27:30700 ~ServiceWorkerPushMessagingTest() override {}
701
702 void GrantNotificationPermissionForTest(const GURL& url) {
Peter Beverloodd4ef1e2018-06-21 15:41:04703 NotificationPermissionContext::UpdatePermission(profile(), url.GetOrigin(),
704 CONTENT_SETTING_ALLOW);
lazyboy561b7de2015-11-19 19:27:30705 }
706
707 PushMessagingAppIdentifier GetAppIdentifierForServiceWorkerRegistration(
avia2f4804a2015-12-24 23:11:13708 int64_t service_worker_registration_id,
lazyboy561b7de2015-11-19 19:27:30709 const GURL& origin) {
710 PushMessagingAppIdentifier app_identifier =
711 PushMessagingAppIdentifier::FindByServiceWorker(
712 profile(), origin, service_worker_registration_id);
713
714 EXPECT_FALSE(app_identifier.is_null());
715 return app_identifier;
716 }
717
718 // ExtensionApiTest overrides.
719 void SetUpCommandLine(base::CommandLine* command_line) override {
peter9de96272015-12-04 15:23:27720 command_line->AppendSwitch(
Istiaque Ahmedea5ed5042017-09-25 19:00:16721 ::switches::kEnableExperimentalWebPlatformFeatures);
lazyboy561b7de2015-11-19 19:27:30722 ServiceWorkerTest::SetUpCommandLine(command_line);
723 }
Tanja Gornak89128fd2018-09-18 08:49:34724
lazyboy561b7de2015-11-19 19:27:30725 void SetUpOnMainThread() override {
miguelg9b502862017-04-24 18:13:53726 NotificationDisplayServiceFactory::GetInstance()->SetTestingFactory(
Sylvain Defresne711ff6b2018-10-04 12:33:54727 profile(),
728 base::BindRepeating(&StubNotificationDisplayService::FactoryForTests));
miguelg9b502862017-04-24 18:13:53729
johnmea5045732016-09-08 17:23:29730 gcm::FakeGCMProfileService* gcm_service =
731 static_cast<gcm::FakeGCMProfileService*>(
Tanja Gornak89128fd2018-09-18 08:49:34732 gcm::GCMProfileServiceFactory::GetForProfile(profile()));
johnmea5045732016-09-08 17:23:29733 gcm_driver_ = static_cast<instance_id::FakeGCMDriverForInstanceID*>(
734 gcm_service->driver());
lazyboy561b7de2015-11-19 19:27:30735 push_service_ = PushMessagingServiceFactory::GetForProfile(profile());
736
737 ServiceWorkerTest::SetUpOnMainThread();
738 }
739
johnmea5045732016-09-08 17:23:29740 instance_id::FakeGCMDriverForInstanceID* gcm_driver() const {
741 return gcm_driver_;
742 }
lazyboy561b7de2015-11-19 19:27:30743 PushMessagingServiceImpl* push_service() const { return push_service_; }
744
745 private:
Sylvain Defresne212b4b02018-10-11 16:32:05746 gcm::GCMProfileServiceFactory::ScopedTestingFactoryInstaller
747 scoped_testing_factory_installer_;
748
johnmea5045732016-09-08 17:23:29749 instance_id::FakeGCMDriverForInstanceID* gcm_driver_;
lazyboy561b7de2015-11-19 19:27:30750 PushMessagingServiceImpl* push_service_;
751
752 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerPushMessagingTest);
753};
754
Istiaque Ahmed805f6a83b2017-10-05 01:23:26755class ServiceWorkerLazyBackgroundTest : public ServiceWorkerTest {
756 public:
Istiaque Ahmed7105f2a2017-10-07 01:11:59757 ServiceWorkerLazyBackgroundTest()
758 : ServiceWorkerTest(
759 // Extensions APIs from SW are only enabled on trunk.
760 // It is important to set the channel early so that this change is
761 // visible in renderers running with service workers (and no
762 // extension).
763 version_info::Channel::UNKNOWN) {}
Istiaque Ahmed805f6a83b2017-10-05 01:23:26764 ~ServiceWorkerLazyBackgroundTest() override {}
765
766 void SetUpCommandLine(base::CommandLine* command_line) override {
767 ServiceWorkerTest::SetUpCommandLine(command_line);
768 // Disable background network activity as it can suddenly bring the Lazy
769 // Background Page alive.
770 command_line->AppendSwitch(::switches::kDisableBackgroundNetworking);
771 command_line->AppendSwitch(::switches::kNoProxyServer);
772 }
773
774 void SetUpInProcessBrowserTestFixture() override {
775 ServiceWorkerTest::SetUpInProcessBrowserTestFixture();
776 // Set shorter delays to prevent test timeouts.
777 ProcessManager::SetEventPageIdleTimeForTesting(1);
778 ProcessManager::SetEventPageSuspendingTimeForTesting(1);
779 }
780
781 private:
782 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerLazyBackgroundTest);
783};
784
Devlin Cronin242d19d22019-03-12 18:08:48785IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, RegisterSucceeds) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22786 StartTestFromBackgroundPage("register.js");
annekao38685502015-07-14 17:46:39787}
788
Devlin Cronin242d19d22019-03-12 18:08:48789IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, UpdateRefreshesServiceWorker) {
Francois Doraye6fb2d02017-10-18 21:29:13790 base::ScopedAllowBlockingForTesting allow_blocking;
lazyboyc3e763a2015-12-09 23:09:58791 base::ScopedTempDir scoped_temp_dir;
792 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
793 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
794 .AppendASCII("update")
795 .AppendASCII("service_worker.pem");
vabr9142fe22016-09-08 13:19:22796 base::FilePath path_v1 =
797 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
798 .AppendASCII("update")
799 .AppendASCII("v1"),
800 scoped_temp_dir.GetPath().AppendASCII("v1.crx"),
801 pem_path, base::FilePath());
802 base::FilePath path_v2 =
803 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
804 .AppendASCII("update")
805 .AppendASCII("v2"),
806 scoped_temp_dir.GetPath().AppendASCII("v2.crx"),
807 pem_path, base::FilePath());
lazyboyc3e763a2015-12-09 23:09:58808 const char* kId = "hfaanndiiilofhfokeanhddpkfffchdi";
809
810 ExtensionTestMessageListener listener_v1("Pong from version 1", false);
811 listener_v1.set_failure_message("FAILURE_V1");
812 // Install version 1.0 of the extension.
813 ASSERT_TRUE(InstallExtension(path_v1, 1));
814 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
815 ->enabled_extensions()
816 .GetByID(kId));
817 EXPECT_TRUE(listener_v1.WaitUntilSatisfied());
818
819 ExtensionTestMessageListener listener_v2("Pong from version 2", false);
820 listener_v2.set_failure_message("FAILURE_V2");
821
822 // Update to version 2.0.
823 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
824 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
825 ->enabled_extensions()
826 .GetByID(kId));
827 EXPECT_TRUE(listener_v2.WaitUntilSatisfied());
828}
829
[email protected]2ef85d562017-09-15 18:41:52830// TODO(crbug.com/765736) Fix the test.
Devlin Cronin242d19d22019-03-12 18:08:48831IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, DISABLED_UpdateWithoutSkipWaiting) {
Francois Doraye6fb2d02017-10-18 21:29:13832 base::ScopedAllowBlockingForTesting allow_blocking;
lazyboy22eddc712015-12-10 21:16:26833 base::ScopedTempDir scoped_temp_dir;
834 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
835 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
836 .AppendASCII("update_without_skip_waiting")
837 .AppendASCII("update_without_skip_waiting.pem");
vabr9142fe22016-09-08 13:19:22838 base::FilePath path_v1 =
839 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
840 .AppendASCII("update_without_skip_waiting")
841 .AppendASCII("v1"),
842 scoped_temp_dir.GetPath().AppendASCII("v1.crx"),
843 pem_path, base::FilePath());
844 base::FilePath path_v2 =
845 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
846 .AppendASCII("update_without_skip_waiting")
847 .AppendASCII("v2"),
848 scoped_temp_dir.GetPath().AppendASCII("v2.crx"),
849 pem_path, base::FilePath());
lazyboy22eddc712015-12-10 21:16:26850 const char* kId = "mhnnnflgagdakldgjpfcofkiocpdmogl";
851
852 // Install version 1.0 of the extension.
853 ASSERT_TRUE(InstallExtension(path_v1, 1));
854 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
855 ->enabled_extensions()
856 .GetByID(kId));
857 const Extension* extension = extensions::ExtensionRegistry::Get(profile())
858 ->enabled_extensions()
859 .GetByID(kId);
860
861 ExtensionTestMessageListener listener1("Pong from version 1", false);
862 listener1.set_failure_message("FAILURE");
Istiaque Ahmed3f692562019-07-26 22:59:26863 content::WebContents* web_contents = browsertest_util::AddTab(
864 browser(), extension->GetResourceURL("page.html"));
lazyboy22eddc712015-12-10 21:16:26865 EXPECT_TRUE(listener1.WaitUntilSatisfied());
866
867 // Update to version 2.0.
868 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
869 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
870 ->enabled_extensions()
871 .GetByID(kId));
872 const Extension* extension_after_update =
873 extensions::ExtensionRegistry::Get(profile())
874 ->enabled_extensions()
875 .GetByID(kId);
876
877 // Service worker version 2 would be installed but it won't be controlling
878 // the extension page yet.
879 ExtensionTestMessageListener listener2("Pong from version 1", false);
880 listener2.set_failure_message("FAILURE");
Istiaque Ahmed3f692562019-07-26 22:59:26881 web_contents = browsertest_util::AddTab(
882 browser(), extension_after_update->GetResourceURL("page.html"));
lazyboy22eddc712015-12-10 21:16:26883 EXPECT_TRUE(listener2.WaitUntilSatisfied());
884
885 // Navigate the tab away from the extension page so that no clients are
886 // using the service worker.
887 // Note that just closing the tab with WebContentsDestroyedWatcher doesn't
888 // seem to be enough because it returns too early.
889 WebContentsLoadStopObserver navigate_away_observer(web_contents);
890 web_contents->GetController().LoadURL(
891 GURL(url::kAboutBlankURL), content::Referrer(), ui::PAGE_TRANSITION_TYPED,
892 std::string());
893 navigate_away_observer.WaitForLoadStop();
894
895 // Now expect service worker version 2 to control the extension page.
896 ExtensionTestMessageListener listener3("Pong from version 2", false);
897 listener3.set_failure_message("FAILURE");
Istiaque Ahmed3f692562019-07-26 22:59:26898 web_contents = browsertest_util::AddTab(
899 browser(), extension_after_update->GetResourceURL("page.html"));
lazyboy22eddc712015-12-10 21:16:26900 EXPECT_TRUE(listener3.WaitUntilSatisfied());
901}
902
Devlin Cronin242d19d22019-03-12 18:08:48903IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, FetchArbitraryPaths) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22904 const Extension* extension = StartTestFromBackgroundPage("fetch.js");
annekao1db36fd2015-07-29 17:09:16905
kalman6f984ae2015-09-18 17:21:58906 // Open some arbirary paths. Their contents should be what the service worker
907 // responds with, which in this case is the path of the fetch.
908 EXPECT_EQ(
909 "Caught a fetch for /index.html",
910 NavigateAndExtractInnerText(extension->GetResourceURL("index.html")));
911 EXPECT_EQ("Caught a fetch for /path/to/other.html",
912 NavigateAndExtractInnerText(
913 extension->GetResourceURL("path/to/other.html")));
914 EXPECT_EQ("Caught a fetch for /some/text/file.txt",
915 NavigateAndExtractInnerText(
916 extension->GetResourceURL("some/text/file.txt")));
917 EXPECT_EQ("Caught a fetch for /no/file/extension",
918 NavigateAndExtractInnerText(
919 extension->GetResourceURL("no/file/extension")));
920 EXPECT_EQ("Caught a fetch for /",
921 NavigateAndExtractInnerText(extension->GetResourceURL("")));
annekao1db36fd2015-07-29 17:09:16922}
923
Devlin Cronin242d19d22019-03-12 18:08:48924IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
Kenichi Ishibashi773b82972018-08-30 07:02:03925 FetchExtensionResourceFromServiceWorker) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22926 const Extension* extension = StartTestFromBackgroundPage("fetch_from_sw.js");
Kenichi Ishibashi773b82972018-08-30 07:02:03927 ASSERT_TRUE(extension);
928
929 // The service worker in this test tries to load 'hello.txt' via fetch()
930 // and sends back the content of the file, which should be 'hello'.
931 const char* kScript = R"(
932 let channel = new MessageChannel();
933 test.waitForMessage(channel.port1).then(message => {
934 window.domAutomationController.send(message);
935 });
936 test.registeredServiceWorker.postMessage(
937 {port: channel.port2}, [channel.port2]);
938 )";
939 EXPECT_EQ("hello", ExecuteScriptInBackgroundPage(extension->id(), kScript));
940}
941
Kenichi Ishibashi09ee5e72018-11-27 07:12:38942// Tests that fetch() from service worker and network fallback
943// go through webRequest.onBeforeRequest API.
Devlin Cronin242d19d22019-03-12 18:08:48944IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, OnBeforeRequest) {
Kenichi Ishibashi09ee5e72018-11-27 07:12:38945 const Extension* extension = LoadExtensionWithFlags(
946 test_data_dir_.AppendASCII("service_worker/webrequest"), kFlagNone);
947 ASSERT_TRUE(extension);
948 ASSERT_TRUE(StartEmbeddedTestServer());
949
950 // Start a service worker and make it control the page.
951 GURL page_url = embedded_test_server()->GetURL(
952 "/extensions/api_test/service_worker/"
953 "webrequest/webpage.html");
954 content::WebContents* web_contents =
955 browser()->tab_strip_model()->GetActiveWebContents();
956 ui_test_utils::NavigateToURL(browser(), page_url);
957 content::WaitForLoadStop(web_contents);
958
959 std::string result;
960 ASSERT_TRUE(content::ExecuteScriptAndExtractString(web_contents,
961 "register();", &result));
962 EXPECT_EQ("ready", result);
963
964 // Initiate a fetch that the service worker doesn't intercept
965 // (network fallback).
966 result.clear();
967 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
968 web_contents, "doFetch('hello.txt?fallthrough');", &result));
969 EXPECT_EQ("hello", result);
970 EXPECT_EQ(
971 "/extensions/api_test/service_worker/webrequest/hello.txt?fallthrough",
972 ExecuteScriptInBackgroundPage(extension->id(), "getLastHookedPath()"));
973
974 // Initiate a fetch that results in calling fetch() in the service worker.
975 result.clear();
976 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
977 web_contents, "doFetch('hello.txt?respondWithFetch');", &result));
978 EXPECT_EQ("hello", result);
979 EXPECT_EQ(
980 "/extensions/api_test/service_worker/webrequest/"
981 "hello.txt?respondWithFetch",
982 ExecuteScriptInBackgroundPage(extension->id(), "getLastHookedPath()"));
983}
984
Devlin Cronin242d19d22019-03-12 18:08:48985IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, SWServedBackgroundPageReceivesEvent) {
lazyboy52c3bcf2016-01-08 00:11:29986 const Extension* extension =
Istiaque Ahmed93ff7f42018-08-31 01:42:22987 StartTestFromBackgroundPage("replace_background.js");
lazyboy52c3bcf2016-01-08 00:11:29988 ExtensionHost* background_page =
989 process_manager()->GetBackgroundHostForExtension(extension->id());
990 ASSERT_TRUE(background_page);
991
992 // Close the background page and start it again so that the service worker
993 // will start controlling pages.
994 background_page->Close();
995 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
996 background_page = nullptr;
Peter Kasting341e1fb2018-02-24 00:03:01997 process_manager()->WakeEventPage(extension->id(), base::DoNothing());
lazyboy52c3bcf2016-01-08 00:11:29998 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
999
1000 // Since the SW is now controlling the extension, the SW serves the background
1001 // script. page.html sends a message to the background script and we verify
1002 // that the SW served background script correctly receives the message/event.
1003 ExtensionTestMessageListener listener("onMessage/SW BG.", false);
1004 listener.set_failure_message("onMessage/original BG.");
Istiaque Ahmed3f692562019-07-26 22:59:261005 content::WebContents* web_contents = browsertest_util::AddTab(
1006 browser(), extension->GetResourceURL("page.html"));
lazyboy52c3bcf2016-01-08 00:11:291007 ASSERT_TRUE(web_contents);
1008 EXPECT_TRUE(listener.WaitUntilSatisfied());
1009}
1010
Devlin Cronin242d19d22019-03-12 18:08:481011IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, SWServedBackgroundPage) {
Istiaque Ahmed93ff7f42018-08-31 01:42:221012 const Extension* extension = StartTestFromBackgroundPage("fetch.js");
annekao49241182015-08-18 17:14:011013
kalman6f984ae2015-09-18 17:21:581014 std::string kExpectedInnerText = "background.html contents for testing.";
annekao49241182015-08-18 17:14:011015
kalman6f984ae2015-09-18 17:21:581016 // Sanity check that the background page has the expected content.
1017 ExtensionHost* background_page =
1018 process_manager()->GetBackgroundHostForExtension(extension->id());
1019 ASSERT_TRUE(background_page);
1020 EXPECT_EQ(kExpectedInnerText,
1021 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:011022
kalman6f984ae2015-09-18 17:21:581023 // Close the background page.
1024 background_page->Close();
1025 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
1026 background_page = nullptr;
1027
1028 // Start it again.
Peter Kasting341e1fb2018-02-24 00:03:011029 process_manager()->WakeEventPage(extension->id(), base::DoNothing());
kalman6f984ae2015-09-18 17:21:581030 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
1031
Matt Falkenhagena612fc02018-05-30 00:35:391032 // The service worker should get a fetch event for the background page.
kalman6f984ae2015-09-18 17:21:581033 background_page =
1034 process_manager()->GetBackgroundHostForExtension(extension->id());
1035 ASSERT_TRUE(background_page);
1036 content::WaitForLoadStop(background_page->host_contents());
1037
kalman6f984ae2015-09-18 17:21:581038 EXPECT_EQ("Caught a fetch for /background.html",
1039 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:011040}
1041
Devlin Cronin242d19d22019-03-12 18:08:481042IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:581043 ServiceWorkerPostsMessageToBackgroundClient) {
Istiaque Ahmed93ff7f42018-08-31 01:42:221044 const Extension* extension =
1045 StartTestFromBackgroundPage("post_message_to_background_client.js");
annekao533482222015-08-21 23:23:531046
kalman6f984ae2015-09-18 17:21:581047 // The service worker in this test simply posts a message to the background
1048 // client it receives from getBackgroundClient().
1049 const char* kScript =
1050 "var messagePromise = null;\n"
1051 "if (test.lastMessageFromServiceWorker) {\n"
1052 " messagePromise = Promise.resolve(test.lastMessageFromServiceWorker);\n"
1053 "} else {\n"
1054 " messagePromise = test.waitForMessage(navigator.serviceWorker);\n"
1055 "}\n"
1056 "messagePromise.then(function(message) {\n"
1057 " window.domAutomationController.send(String(message == 'success'));\n"
1058 "})\n";
1059 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:531060}
1061
Devlin Cronin242d19d22019-03-12 18:08:481062IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:581063 BackgroundPagePostsMessageToServiceWorker) {
1064 const Extension* extension =
Istiaque Ahmed93ff7f42018-08-31 01:42:221065 StartTestFromBackgroundPage("post_message_to_sw.js");
annekao533482222015-08-21 23:23:531066
kalman6f984ae2015-09-18 17:21:581067 // The service worker in this test waits for a message, then echoes it back
1068 // by posting a message to the background page via getBackgroundClient().
1069 const char* kScript =
1070 "var mc = new MessageChannel();\n"
1071 "test.waitForMessage(mc.port1).then(function(message) {\n"
1072 " window.domAutomationController.send(String(message == 'hello'));\n"
1073 "});\n"
1074 "test.registeredServiceWorker.postMessage(\n"
1075 " {message: 'hello', port: mc.port2}, [mc.port2])\n";
1076 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:531077}
1078
Devlin Cronin242d19d22019-03-12 18:08:481079IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
rdevlin.croninf5863da2015-09-10 19:21:451080 ServiceWorkerSuspensionOnExtensionUnload) {
kalman6f984ae2015-09-18 17:21:581081 // For this test, only hold onto the extension's ID and URL + a function to
1082 // get a resource URL, because we're going to be disabling and uninstalling
1083 // it, which will invalidate the pointer.
1084 std::string extension_id;
1085 GURL extension_url;
1086 {
Istiaque Ahmed93ff7f42018-08-31 01:42:221087 const Extension* extension = StartTestFromBackgroundPage("fetch.js");
kalman6f984ae2015-09-18 17:21:581088 extension_id = extension->id();
1089 extension_url = extension->url();
1090 }
1091 auto get_resource_url = [&extension_url](const std::string& path) {
1092 return Extension::GetResourceURL(extension_url, path);
1093 };
rdevlin.croninf5863da2015-09-10 19:21:451094
kalman6f984ae2015-09-18 17:21:581095 // Fetch should route to the service worker.
1096 EXPECT_EQ("Caught a fetch for /index.html",
1097 NavigateAndExtractInnerText(get_resource_url("index.html")));
rdevlin.croninf5863da2015-09-10 19:21:451098
kalman6f984ae2015-09-18 17:21:581099 // Disable the extension. Opening the page should fail.
1100 extension_service()->DisableExtension(extension_id,
Minh X. Nguyen45479012017-08-18 21:35:361101 disable_reason::DISABLE_USER_ACTION);
rdevlin.croninf5863da2015-09-10 19:21:451102 base::RunLoop().RunUntilIdle();
rdevlin.croninf5863da2015-09-10 19:21:451103
kalman6f984ae2015-09-18 17:21:581104 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1105 NavigateAndGetPageType(get_resource_url("index.html")));
1106 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1107 NavigateAndGetPageType(get_resource_url("other.html")));
1108
1109 // Re-enable the extension. Opening pages should immediately start to succeed
1110 // again.
rdevlin.croninf5863da2015-09-10 19:21:451111 extension_service()->EnableExtension(extension_id);
1112 base::RunLoop().RunUntilIdle();
1113
kalman6f984ae2015-09-18 17:21:581114 EXPECT_EQ("Caught a fetch for /index.html",
1115 NavigateAndExtractInnerText(get_resource_url("index.html")));
1116 EXPECT_EQ("Caught a fetch for /other.html",
1117 NavigateAndExtractInnerText(get_resource_url("other.html")));
1118 EXPECT_EQ("Caught a fetch for /another.html",
1119 NavigateAndExtractInnerText(get_resource_url("another.html")));
rdevlin.croninf5863da2015-09-10 19:21:451120
kalman6f984ae2015-09-18 17:21:581121 // Uninstall the extension. Opening pages should fail again.
1122 base::string16 error;
1123 extension_service()->UninstallExtension(
Devlin Cronin218df7f2017-11-21 21:41:311124 extension_id, UninstallReason::UNINSTALL_REASON_FOR_TESTING, &error);
kalman6f984ae2015-09-18 17:21:581125 base::RunLoop().RunUntilIdle();
1126
1127 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1128 NavigateAndGetPageType(get_resource_url("index.html")));
1129 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1130 NavigateAndGetPageType(get_resource_url("other.html")));
1131 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1132 NavigateAndGetPageType(get_resource_url("anotherother.html")));
1133 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1134 NavigateAndGetPageType(get_resource_url("final.html")));
1135}
1136
Devlin Cronin242d19d22019-03-12 18:08:481137IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, BackgroundPageIsWokenIfAsleep) {
Istiaque Ahmed93ff7f42018-08-31 01:42:221138 const Extension* extension = StartTestFromBackgroundPage("wake_on_fetch.js");
kalman6f984ae2015-09-18 17:21:581139
1140 // Navigate to special URLs that this test's service worker recognises, each
1141 // making a check then populating the response with either "true" or "false".
1142 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
1143 "background-client-is-awake")));
1144 EXPECT_EQ("true", NavigateAndExtractInnerText(
1145 extension->GetResourceURL("ping-background-client")));
1146 // Ping more than once for good measure.
1147 EXPECT_EQ("true", NavigateAndExtractInnerText(
1148 extension->GetResourceURL("ping-background-client")));
1149
1150 // Shut down the event page. The SW should detect that it's closed, but still
1151 // be able to ping it.
1152 ExtensionHost* background_page =
1153 process_manager()->GetBackgroundHostForExtension(extension->id());
1154 ASSERT_TRUE(background_page);
1155 background_page->Close();
1156 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
1157
1158 EXPECT_EQ("false", NavigateAndExtractInnerText(extension->GetResourceURL(
1159 "background-client-is-awake")));
1160 EXPECT_EQ("true", NavigateAndExtractInnerText(
1161 extension->GetResourceURL("ping-background-client")));
1162 EXPECT_EQ("true", NavigateAndExtractInnerText(
1163 extension->GetResourceURL("ping-background-client")));
1164 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
1165 "background-client-is-awake")));
1166}
1167
Devlin Cronin242d19d22019-03-12 18:08:481168IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:581169 GetBackgroundClientFailsWithNoBackgroundPage) {
1170 // This extension doesn't have a background page, only a tab at page.html.
1171 // The service worker it registers tries to call getBackgroundClient() and
1172 // should fail.
1173 // Note that this also tests that service workers can be registered from tabs.
1174 EXPECT_TRUE(RunExtensionSubtest("service_worker/no_background", "page.html"));
rdevlin.croninf5863da2015-09-10 19:21:451175}
1176
Devlin Cronin242d19d22019-03-12 18:08:481177IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, NotificationAPI) {
lazyboy6ddb7d62015-11-10 23:15:271178 EXPECT_TRUE(RunExtensionSubtest("service_worker/notifications/has_permission",
1179 "page.html"));
1180}
1181
Devlin Cronin242d19d22019-03-12 18:08:481182IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, WebAccessibleResourcesFetch) {
lazyboyaea32c22016-01-04 21:37:071183 EXPECT_TRUE(RunExtensionSubtest(
1184 "service_worker/web_accessible_resources/fetch/", "page.html"));
1185}
1186
David Bertoni9026eff2019-05-01 18:04:311187// Tests that updating a packed extension with modified scripts works
1188// properly -- we expect that the new script will execute, rather than the
1189// previous one.
1190IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, UpdatePackedExtension) {
1191 // Extensions APIs from SW are only enabled on trunk.
1192 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1193 constexpr char kManifest1[] =
1194 R"({
1195 "name": "Test Extension",
1196 "manifest_version": 2,
1197 "version": "0.1",
1198 "background": {"service_worker": "script.js"}
1199 })";
David Bertoni353f0fb42019-05-30 15:53:301200 constexpr char kNewVersionString[] = "0.2";
1201
David Bertoni9026eff2019-05-01 18:04:311202 // This script installs an event listener for updates to the extension with
1203 // a callback that forces itself to reload.
David Bertoni353f0fb42019-05-30 15:53:301204 constexpr char kScript1[] =
David Bertoni9026eff2019-05-01 18:04:311205 R"(
1206 chrome.runtime.onUpdateAvailable.addListener(function(details) {
David Bertoni353f0fb42019-05-30 15:53:301207 chrome.test.assertEq('%s', details.version);
David Bertoni9026eff2019-05-01 18:04:311208 chrome.runtime.reload();
1209 });
1210 chrome.test.sendMessage('ready1');
1211 )";
1212
1213 std::string id;
1214 TestExtensionDir test_dir;
1215
1216 // Write the manifest and script files and load the extension.
1217 test_dir.WriteManifest(kManifest1);
David Bertoni353f0fb42019-05-30 15:53:301218 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"),
1219 base::StringPrintf(kScript1, kNewVersionString));
David Bertoni9026eff2019-05-01 18:04:311220
1221 {
1222 ExtensionTestMessageListener ready_listener("ready1", false);
1223 base::FilePath path = test_dir.Pack();
1224 const Extension* extension = LoadExtension(path);
1225 ASSERT_TRUE(extension);
1226
1227 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
1228 id = extension->id();
1229 }
1230
1231 constexpr char kManifest2[] =
1232 R"({
1233 "name": "Test Extension",
1234 "manifest_version": 2,
David Bertoni353f0fb42019-05-30 15:53:301235 "version": "%s",
David Bertoni9026eff2019-05-01 18:04:311236 "background": {"service_worker": "script.js"}
1237 })";
David Bertoni353f0fb42019-05-30 15:53:301238 constexpr char kScript2[] =
1239 R"(
1240 chrome.runtime.onInstalled.addListener(function(details) {
1241 chrome.test.assertEq('update', details.reason);
1242 chrome.test.sendMessage('onInstalled');
1243 });
1244 chrome.test.sendMessage('ready2');
1245 )";
David Bertoni9026eff2019-05-01 18:04:311246 // Rewrite the manifest and script files with a version change in the manifest
1247 // file. After reloading the extension, the old version of the extension
1248 // should detect the update, force the reload, and the new script should
1249 // execute.
David Bertoni353f0fb42019-05-30 15:53:301250 test_dir.WriteManifest(base::StringPrintf(kManifest2, kNewVersionString));
1251 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"), kScript2);
David Bertoni9026eff2019-05-01 18:04:311252 {
1253 ExtensionTestMessageListener ready_listener("ready2", false);
David Bertoni353f0fb42019-05-30 15:53:301254 ExtensionTestMessageListener on_installed_listener("onInstalled", false);
David Bertoni9026eff2019-05-01 18:04:311255 base::FilePath path = test_dir.Pack();
1256 ExtensionService* const extension_service =
1257 ExtensionSystem::Get(profile())->extension_service();
1258 EXPECT_TRUE(extension_service->UpdateExtension(
1259 CRXFileInfo(id, GetTestVerifierFormat(), path), true, nullptr));
1260 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
1261 EXPECT_EQ("0.2", ExtensionRegistry::Get(profile())
1262 ->enabled_extensions()
1263 .GetByID(id)
1264 ->version()
1265 .GetString());
David Bertoni353f0fb42019-05-30 15:53:301266 EXPECT_TRUE(on_installed_listener.WaitUntilSatisfied());
David Bertoni9026eff2019-05-01 18:04:311267 }
1268}
1269
David Bertoni1d646a152019-04-25 02:09:221270// Tests that updating an unpacked extension with modified scripts works
1271// properly -- we expect that the new script will execute, rather than the
1272// previous one.
1273IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, UpdateUnpackedExtension) {
1274 // Extensions APIs from SW are only enabled on trunk.
1275 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1276 constexpr char kManifest1[] =
1277 R"({
1278 "name": "Test Extension",
1279 "manifest_version": 2,
1280 "version": "0.1",
1281 "background": {"service_worker": "script.js"}
1282 })";
1283 constexpr char kManifest2[] =
1284 R"({
1285 "name": "Test Extension",
1286 "manifest_version": 2,
1287 "version": "0.2",
1288 "background": {"service_worker": "script.js"}
1289 })";
David Bertoni353f0fb42019-05-30 15:53:301290 constexpr char kScript[] =
1291 R"(
1292 chrome.runtime.onInstalled.addListener(function(details) {
1293 chrome.test.assertEq('%s', details.reason);
1294 chrome.test.sendMessage('onInstalled');
1295 });
1296 chrome.test.sendMessage('%s');
1297 )";
David Bertoni1d646a152019-04-25 02:09:221298
1299 std::string id;
1300
1301 ExtensionService* const extension_service =
1302 ExtensionSystem::Get(profile())->extension_service();
1303 scoped_refptr<UnpackedInstaller> installer =
1304 UnpackedInstaller::Create(extension_service);
1305
1306 // Set a completion callback so we can get the ID of the extension.
1307 installer->set_completion_callback(base::BindLambdaForTesting(
1308 [&id](const Extension* extension, const base::FilePath& path,
1309 const std::string& error) {
1310 ASSERT_TRUE(extension);
1311 ASSERT_TRUE(error.empty());
1312 id = extension->id();
1313 }));
1314
1315 TestExtensionDir test_dir;
1316
1317 // Write the manifest and script files and load the extension.
1318 test_dir.WriteManifest(kManifest1);
1319 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"),
David Bertoni353f0fb42019-05-30 15:53:301320 base::StringPrintf(kScript, "install", "ready1"));
David Bertoni1d646a152019-04-25 02:09:221321 {
1322 ExtensionTestMessageListener ready_listener("ready1", false);
David Bertoni353f0fb42019-05-30 15:53:301323 ExtensionTestMessageListener on_installed_listener("onInstalled", false);
David Bertoni1d646a152019-04-25 02:09:221324
1325 installer->Load(test_dir.UnpackedPath());
1326 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
David Bertoni353f0fb42019-05-30 15:53:301327 EXPECT_TRUE(on_installed_listener.WaitUntilSatisfied());
David Bertoni1d646a152019-04-25 02:09:221328 ASSERT_FALSE(id.empty());
1329 }
1330
1331 // Rewrite the script file without a version change in the manifest and reload
1332 // the extension. The new script should execute.
1333 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"),
David Bertoni353f0fb42019-05-30 15:53:301334 base::StringPrintf(kScript, "update", "ready2"));
David Bertoni1d646a152019-04-25 02:09:221335 {
1336 ExtensionTestMessageListener ready_listener("ready2", false);
David Bertoni353f0fb42019-05-30 15:53:301337 ExtensionTestMessageListener on_installed_listener("onInstalled", false);
David Bertoni1d646a152019-04-25 02:09:221338
1339 extension_service->ReloadExtension(id);
1340 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
David Bertoni353f0fb42019-05-30 15:53:301341 EXPECT_TRUE(on_installed_listener.WaitUntilSatisfied());
David Bertoni1d646a152019-04-25 02:09:221342 }
1343
1344 // Rewrite the manifest and script files with a version change in the manifest
1345 // file. After reloading the extension, the new script should execute.
1346 test_dir.WriteManifest(kManifest2);
1347 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"),
David Bertoni353f0fb42019-05-30 15:53:301348 base::StringPrintf(kScript, "update", "ready3"));
David Bertoni1d646a152019-04-25 02:09:221349 {
1350 ExtensionTestMessageListener ready_listener("ready3", false);
David Bertoni353f0fb42019-05-30 15:53:301351 ExtensionTestMessageListener on_installed_listener("onInstalled", false);
David Bertoni1d646a152019-04-25 02:09:221352
1353 extension_service->ReloadExtension(id);
1354 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
David Bertoni353f0fb42019-05-30 15:53:301355 EXPECT_TRUE(on_installed_listener.WaitUntilSatisfied());
David Bertoni1d646a152019-04-25 02:09:221356 }
1357}
1358
lazyboyaea32c22016-01-04 21:37:071359// This test loads a web page that has an iframe pointing to a
1360// chrome-extension:// URL. The URL is listed in the extension's
1361// web_accessible_resources. Initially the iframe is served from the extension's
1362// resource file. After verifying that, we register a Service Worker that
1363// controls the extension. Further requests to the same resource as before
1364// should now be served by the Service Worker.
1365// This test also verifies that if the requested resource exists in the manifest
1366// but is not present in the extension directory, the Service Worker can still
1367// serve the resource file.
Devlin Cronin242d19d22019-03-12 18:08:481368IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, WebAccessibleResourcesIframeSrc) {
lazyboyaea32c22016-01-04 21:37:071369 const Extension* extension = LoadExtensionWithFlags(
1370 test_data_dir_.AppendASCII(
1371 "service_worker/web_accessible_resources/iframe_src"),
1372 kFlagNone);
1373 ASSERT_TRUE(extension);
1374 ASSERT_TRUE(StartEmbeddedTestServer());
falkenad185092016-06-16 06:10:021375
1376 // Service workers can only control secure contexts
1377 // (https://w3c.github.io/webappsec-secure-contexts/). For documents, this
1378 // typically means the document must have a secure origin AND all its ancestor
1379 // frames must have documents with secure origins. However, extension pages
1380 // are considered secure, even if they have an ancestor document that is an
1381 // insecure context (see GetSchemesBypassingSecureContextCheckWhitelist). So
1382 // extension service workers must be able to control an extension page
1383 // embedded in an insecure context. To test this, set up an insecure
1384 // (non-localhost, non-https) URL for the web page. This page will create
1385 // iframes that load extension pages that must be controllable by service
1386 // worker.
falkenad185092016-06-16 06:10:021387 GURL page_url =
1388 embedded_test_server()->GetURL("a.com",
1389 "/extensions/api_test/service_worker/"
1390 "web_accessible_resources/webpage.html");
1391 EXPECT_FALSE(content::IsOriginSecure(page_url));
lazyboyaea32c22016-01-04 21:37:071392
Istiaque Ahmed3f692562019-07-26 22:59:261393 content::WebContents* web_contents =
1394 browsertest_util::AddTab(browser(), page_url);
lazyboyaea32c22016-01-04 21:37:071395 std::string result;
1396 // webpage.html will create an iframe pointing to a resource from |extension|.
1397 // Expect the resource to be served by the extension.
1398 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1399 web_contents, base::StringPrintf("window.testIframe('%s', 'iframe.html')",
1400 extension->id().c_str()),
1401 &result));
1402 EXPECT_EQ("FROM_EXTENSION_RESOURCE", result);
1403
1404 ExtensionTestMessageListener service_worker_ready_listener("SW_READY", false);
1405 EXPECT_TRUE(ExecuteScriptInBackgroundPageNoWait(
1406 extension->id(), "window.registerServiceWorker()"));
1407 EXPECT_TRUE(service_worker_ready_listener.WaitUntilSatisfied());
1408
1409 result.clear();
1410 // webpage.html will create another iframe pointing to a resource from
1411 // |extension| as before. But this time, the resource should be be served
1412 // from the Service Worker.
1413 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1414 web_contents, base::StringPrintf("window.testIframe('%s', 'iframe.html')",
1415 extension->id().c_str()),
1416 &result));
1417 EXPECT_EQ("FROM_SW_RESOURCE", result);
1418
1419 result.clear();
1420 // webpage.html will create yet another iframe pointing to a resource that
1421 // exists in the extension manifest's web_accessible_resources, but is not
1422 // present in the extension directory. Expect the resources of the iframe to
1423 // be served by the Service Worker.
1424 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1425 web_contents,
1426 base::StringPrintf("window.testIframe('%s', 'iframe_non_existent.html')",
1427 extension->id().c_str()),
1428 &result));
1429 EXPECT_EQ("FROM_SW_RESOURCE", result);
1430}
1431
David Bertonide552de2019-06-28 19:51:261432// Verifies that service workers that aren't specified as the background script
1433// for the extension do not have extension API bindings.
1434IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, VerifyNoApiBindings) {
1435 // Extensions APIs from SW are only enabled on trunk.
1436 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1437 const Extension* extension = LoadExtensionWithFlags(
1438 test_data_dir_.AppendASCII("service_worker/verify_no_api_bindings"),
1439 kFlagNone);
1440 ASSERT_TRUE(extension);
1441 ui_test_utils::NavigateToURL(browser(),
1442 extension->GetResourceURL("page.html"));
1443 content::WebContents* web_contents =
1444 browser()->tab_strip_model()->GetActiveWebContents();
1445
1446 // Have the page script start the service worker and wait for that to
1447 // succeed.
1448 ExtensionTestMessageListener worker_start_listener("WORKER STARTED", false);
1449 worker_start_listener.set_failure_message("FAILURE");
1450 ASSERT_TRUE(
1451 content::ExecuteScript(web_contents, "window.runServiceWorker()"));
1452 ASSERT_TRUE(worker_start_listener.WaitUntilSatisfied());
1453
1454 // Kick off the test, which will check the available bindings and fail if
1455 // there is anything unexpected.
1456 ExtensionTestMessageListener worker_listener("SUCCESS", false);
1457 worker_listener.set_failure_message("FAILURE");
1458 ASSERT_TRUE(content::ExecuteScript(web_contents, "window.testSendMessage()"));
1459 EXPECT_TRUE(worker_listener.WaitUntilSatisfied());
1460}
1461
Devlin Cronin242d19d22019-03-12 18:08:481462IN_PROC_BROWSER_TEST_F(ServiceWorkerBackgroundSyncTest, Sync) {
lazyboybd325ae2015-11-18 21:35:261463 const Extension* extension = LoadExtensionWithFlags(
1464 test_data_dir_.AppendASCII("service_worker/sync"), kFlagNone);
1465 ASSERT_TRUE(extension);
1466 ui_test_utils::NavigateToURL(browser(),
1467 extension->GetResourceURL("page.html"));
1468 content::WebContents* web_contents =
1469 browser()->tab_strip_model()->GetActiveWebContents();
1470
1471 // Prevent firing by going offline.
1472 content::background_sync_test_util::SetOnline(web_contents, false);
1473
1474 ExtensionTestMessageListener sync_listener("SYNC: send-chats", false);
1475 sync_listener.set_failure_message("FAIL");
1476
1477 std::string result;
1478 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
1479 web_contents, "window.runServiceWorker()", &result));
1480 ASSERT_EQ("SERVICE_WORKER_READY", result);
1481
1482 EXPECT_FALSE(sync_listener.was_satisfied());
1483 // Resume firing by going online.
1484 content::background_sync_test_util::SetOnline(web_contents, true);
1485 EXPECT_TRUE(sync_listener.WaitUntilSatisfied());
1486}
1487
Devlin Cronin242d19d22019-03-12 18:08:481488IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
horo1eeddde2015-11-19 05:59:251489 FetchFromContentScriptShouldNotGoToServiceWorkerOfPage) {
1490 ASSERT_TRUE(StartEmbeddedTestServer());
1491 GURL page_url = embedded_test_server()->GetURL(
1492 "/extensions/api_test/service_worker/content_script_fetch/"
1493 "controlled_page/index.html");
1494 content::WebContents* tab =
1495 browser()->tab_strip_model()->GetActiveWebContents();
1496 ui_test_utils::NavigateToURL(browser(), page_url);
1497 content::WaitForLoadStop(tab);
1498
1499 std::string value;
1500 ASSERT_TRUE(
1501 content::ExecuteScriptAndExtractString(tab, "register();", &value));
1502 EXPECT_EQ("SW controlled", value);
1503
1504 ASSERT_TRUE(RunExtensionTest("service_worker/content_script_fetch"))
1505 << message_;
1506}
1507
Devlin Cronin242d19d22019-03-12 18:08:481508IN_PROC_BROWSER_TEST_F(ServiceWorkerPushMessagingTest, OnPush) {
lazyboy561b7de2015-11-19 19:27:301509 const Extension* extension = LoadExtensionWithFlags(
1510 test_data_dir_.AppendASCII("service_worker/push_messaging"), kFlagNone);
1511 ASSERT_TRUE(extension);
1512 GURL extension_url = extension->url();
1513
Peter Beverloodd4ef1e2018-06-21 15:41:041514 GrantNotificationPermissionForTest(extension_url);
lazyboy561b7de2015-11-19 19:27:301515
1516 GURL url = extension->GetResourceURL("page.html");
1517 ui_test_utils::NavigateToURL(browser(), url);
1518
1519 content::WebContents* web_contents =
1520 browser()->tab_strip_model()->GetActiveWebContents();
1521
1522 // Start the ServiceWorker.
1523 ExtensionTestMessageListener ready_listener("SERVICE_WORKER_READY", false);
1524 ready_listener.set_failure_message("SERVICE_WORKER_FAILURE");
1525 const char* kScript = "window.runServiceWorker()";
1526 EXPECT_TRUE(content::ExecuteScript(web_contents->GetMainFrame(), kScript));
1527 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
1528
1529 PushMessagingAppIdentifier app_identifier =
1530 GetAppIdentifierForServiceWorkerRegistration(0LL, extension_url);
johnmea5045732016-09-08 17:23:291531 ASSERT_EQ(app_identifier.app_id(), gcm_driver()->last_gettoken_app_id());
1532 EXPECT_EQ("1234567890", gcm_driver()->last_gettoken_authorized_entity());
lazyboy561b7de2015-11-19 19:27:301533
lazyboyd429e2582016-05-20 20:18:521534 base::RunLoop run_loop;
lazyboy561b7de2015-11-19 19:27:301535 // Send a push message via gcm and expect the ServiceWorker to receive it.
1536 ExtensionTestMessageListener push_message_listener("OK", false);
1537 push_message_listener.set_failure_message("FAIL");
1538 gcm::IncomingMessage message;
1539 message.sender_id = "1234567890";
1540 message.raw_data = "testdata";
1541 message.decrypted = true;
lazyboyd429e2582016-05-20 20:18:521542 push_service()->SetMessageCallbackForTesting(run_loop.QuitClosure());
lazyboy561b7de2015-11-19 19:27:301543 push_service()->OnMessage(app_identifier.app_id(), message);
1544 EXPECT_TRUE(push_message_listener.WaitUntilSatisfied());
lazyboyd429e2582016-05-20 20:18:521545 run_loop.Run(); // Wait until the message is handled by push service.
lazyboy561b7de2015-11-19 19:27:301546}
Devlin Cronin242d19d22019-03-12 18:08:481547IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, MimeHandlerView) {
Rob Wue89b90032018-02-16 19:46:081548 ASSERT_TRUE(RunExtensionTest("service_worker/mime_handler_view"));
1549}
1550
David Bertoni3b3597d82019-06-22 02:29:361551// An observer for service worker registration events.
1552class TestRegistrationObserver : public content::ServiceWorkerContextObserver {
David Bertoni22aeae52019-06-10 22:42:531553 public:
David Bertoni3b3597d82019-06-22 02:29:361554 using RegistrationsMap = std::map<GURL, int>;
1555
1556 explicit TestRegistrationObserver(content::ServiceWorkerContext* context)
1557 : context_(context) {
David Bertoni22aeae52019-06-10 22:42:531558 context_->AddObserver(this);
1559 }
1560
David Bertoni3b3597d82019-06-22 02:29:361561 ~TestRegistrationObserver() override {
David Bertoni22aeae52019-06-10 22:42:531562 if (context_) {
1563 context_->RemoveObserver(this);
1564 }
1565 }
1566
David Bertoni3b3597d82019-06-22 02:29:361567 // Wait for the first service worker registration with an extension scheme
1568 // scope to be stored.
1569 void WaitForRegistrationStored() { stored_run_loop_.Run(); }
1570
1571 int GetCompletedCount(const GURL& scope) const {
1572 const auto it = registrations_completed_map_.find(scope);
1573 return it == registrations_completed_map_.end() ? 0 : it->second;
1574 }
1575
1576 private:
1577 // ServiceWorkerContextObserver overrides.
1578 void OnRegistrationCompleted(const GURL& scope) override {
1579 ++registrations_completed_map_[scope];
1580 }
1581
David Bertoni22aeae52019-06-10 22:42:531582 void OnRegistrationStored(int64_t registration_id,
1583 const GURL& scope) override {
1584 if (scope.SchemeIs(kExtensionScheme)) {
David Bertoni3b3597d82019-06-22 02:29:361585 stored_run_loop_.Quit();
David Bertoni22aeae52019-06-10 22:42:531586 }
1587 }
1588
1589 void OnDestruct(content::ServiceWorkerContext* context) override {
1590 context_ = nullptr;
1591 }
1592
David Bertoni3b3597d82019-06-22 02:29:361593 RegistrationsMap registrations_completed_map_;
1594 base::RunLoop stored_run_loop_;
David Bertoni22aeae52019-06-10 22:42:531595 content::ServiceWorkerContext* context_;
David Bertoni22aeae52019-06-10 22:42:531596};
1597
1598IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
1599 EventsToStoppedWorker) {
1600 content::StoragePartition* storage_partition =
1601 content::BrowserContext::GetDefaultStoragePartition(browser()->profile());
1602 content::ServiceWorkerContext* context =
1603 storage_partition->GetServiceWorkerContext();
1604
1605 // Set up an observer to wait for the registration to be stored.
David Bertoni3b3597d82019-06-22 02:29:361606 TestRegistrationObserver observer(context);
David Bertoni22aeae52019-06-10 22:42:531607
1608 ExtensionTestMessageListener event_listener_added("ready", false);
1609 event_listener_added.set_failure_message("ERROR");
1610 const Extension* extension = LoadExtensionWithFlags(
1611 test_data_dir_.AppendASCII(
1612 "service_worker/worker_based_background/events_to_stopped_worker"),
1613 kFlagNone);
1614 ASSERT_TRUE(extension);
1615
David Bertoni3b3597d82019-06-22 02:29:361616 observer.WaitForRegistrationStored();
David Bertoni22aeae52019-06-10 22:42:531617 EXPECT_TRUE(event_listener_added.WaitUntilSatisfied());
1618
1619 // Stop the service worker.
1620 {
1621 base::RunLoop run_loop;
1622 // The service worker is registered at the root scope.
1623 content::StopServiceWorkerForScope(context, extension->url(),
1624 run_loop.QuitClosure());
1625 run_loop.Run();
1626 }
1627
1628 // Navigate to a URL, which should wake up the service worker.
1629 ExtensionTestMessageListener finished_listener("finished", false);
1630 ui_test_utils::NavigateToURL(browser(),
1631 extension->GetResourceURL("page.html"));
1632 EXPECT_TRUE(finished_listener.WaitUntilSatisfied());
1633}
1634
David Bertoni3b3597d82019-06-22 02:29:361635// Tests the restriction on registering service worker scripts at root scope.
1636IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
1637 ServiceWorkerScriptRootScope) {
1638 content::StoragePartition* storage_partition =
1639 content::BrowserContext::GetDefaultStoragePartition(browser()->profile());
1640 content::ServiceWorkerContext* context =
1641 storage_partition->GetServiceWorkerContext();
1642
1643 // Set up an observer to track all SW registrations. We expect only
1644 // one for the extension's root scope. This test attempts to register
1645 // an additional service worker, which will fail.
1646 TestRegistrationObserver observer(context);
1647 ExtensionTestMessageListener registration_listener("REGISTRATION_FAILED",
1648 false);
1649 registration_listener.set_failure_message("WORKER_STARTED");
1650 const Extension* extension = LoadExtensionWithFlags(
1651 test_data_dir_.AppendASCII(
1652 "service_worker/worker_based_background/script_root_scope"),
1653 kFlagNone);
1654 ASSERT_TRUE(extension);
1655
1656 EXPECT_TRUE(registration_listener.WaitUntilSatisfied());
1657 // We expect exactly one registration, which is the one specified in the
1658 // manifest.
1659 EXPECT_EQ(1, observer.GetCompletedCount(extension->url()));
1660}
1661
Devlin Cronin242d19d22019-03-12 18:08:481662IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
Istiaque Ahmedd4b67ee2019-03-02 10:53:201663 ProcessManagerRegistrationOnShutdown) {
1664 // Note that StopServiceWorkerForScope call below expects the worker to be
1665 // completely installed, so wait for the |extension| worker to see "activate"
1666 // event.
1667 ExtensionTestMessageListener activated_listener("WORKER_ACTIVATED", false);
1668 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
1669 "service_worker/worker_based_background/process_manager"));
1670 ASSERT_TRUE(extension);
1671 EXPECT_TRUE(activated_listener.WaitUntilSatisfied());
1672
1673 base::Optional<WorkerId> worker_id =
1674 GetUniqueRunningWorkerId(extension->id());
1675 ASSERT_TRUE(worker_id);
1676 {
1677 // Shutdown the worker.
1678 // TODO(lazyboy): Ideally we'd want to test worker shutdown on idle, do that
1679 // once //content API allows to override test timeouts for Service Workers.
1680 base::RunLoop run_loop;
1681 content::StoragePartition* storage_partition =
1682 content::BrowserContext::GetDefaultStoragePartition(
1683 browser()->profile());
1684 GURL scope = extension->url();
1685 content::StopServiceWorkerForScope(
1686 storage_partition->GetServiceWorkerContext(),
1687 // The service worker is registered at the top level scope.
1688 extension->url(), run_loop.QuitClosure());
1689 run_loop.Run();
1690 }
1691
1692 EXPECT_FALSE(ProcessManager::Get(profile())->HasServiceWorker(*worker_id));
1693}
1694
Devlin Cronin242d19d22019-03-12 18:08:481695IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
Istiaque Ahmedd4b67ee2019-03-02 10:53:201696 ProcessManagerRegistrationOnTerminate) {
1697 // NOTE: It is not necessary to wait for "activate" event from the worker
1698 // for this test, but we're lazily reusing the extension from
1699 // ProcessManagerRegistrationOnShutdown test.
1700 ExtensionTestMessageListener activated_listener("WORKER_ACTIVATED", false);
1701 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
1702 "service_worker/worker_based_background/process_manager"));
1703 ASSERT_TRUE(extension);
1704 EXPECT_TRUE(activated_listener.WaitUntilSatisfied());
1705
1706 base::Optional<WorkerId> worker_id =
1707 GetUniqueRunningWorkerId(extension->id());
1708 ASSERT_TRUE(worker_id);
1709 {
1710 // Terminate worker's RenderProcessHost.
1711 content::RenderProcessHost* worker_render_process_host =
1712 content::RenderProcessHost::FromID(worker_id->render_process_id);
1713 ASSERT_TRUE(worker_render_process_host);
1714 content::RenderProcessHostWatcher process_exit_observer(
1715 worker_render_process_host,
1716 content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1717 worker_render_process_host->Shutdown(content::RESULT_CODE_KILLED);
1718 process_exit_observer.Wait();
1719 }
1720
1721 EXPECT_FALSE(ProcessManager::Get(profile())->HasServiceWorker(*worker_id));
1722}
1723
David Bertoni904dd602019-06-24 21:42:091724// Tests that worker ref count increments while extension API function is
1725// active.
1726IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, WorkerRefCount) {
1727 ExtensionTestMessageListener worker_start_listener("WORKER STARTED", false);
1728
1729 const Extension* extension = LoadExtensionWithFlags(
1730 test_data_dir_.AppendASCII(
1731 "service_worker/worker_based_background/worker_ref_count"),
1732 kFlagNone);
1733 ASSERT_TRUE(extension);
1734 ASSERT_TRUE(worker_start_listener.WaitUntilSatisfied());
1735
1736 ui_test_utils::NavigateToURL(browser(),
1737 extension->GetResourceURL("page.html"));
1738 content::WebContents* web_contents =
1739 browser()->tab_strip_model()->GetActiveWebContents();
1740
1741 // Service worker should have no pending requests because it hasn't performed
1742 // any extension API request yet.
1743 EXPECT_EQ(0u, GetWorkerRefCount(extension->url()));
1744
1745 ExtensionTestMessageListener worker_listener("CHECK_REF_COUNT", true);
1746 worker_listener.set_failure_message("FAILURE");
1747 ASSERT_TRUE(content::ExecuteScript(web_contents, "window.testSendMessage()"));
1748 ASSERT_TRUE(worker_listener.WaitUntilSatisfied());
1749
1750 // Service worker should have exactly one pending request because
1751 // chrome.test.sendMessage() API call is in-flight.
1752 EXPECT_EQ(1u, GetWorkerRefCount(extension->url()));
1753
1754 // Perform another extension API request while one is ongoing.
1755 {
1756 ExtensionTestMessageListener listener("CHECK_REF_COUNT", true);
1757 listener.set_failure_message("FAILURE");
1758 ASSERT_TRUE(
1759 content::ExecuteScript(web_contents, "window.testSendMessage()"));
1760 ASSERT_TRUE(listener.WaitUntilSatisfied());
1761
1762 // Service worker currently has two extension API requests in-flight.
1763 EXPECT_EQ(2u, GetWorkerRefCount(extension->url()));
1764 // Finish executing the nested chrome.test.sendMessage() first.
1765 listener.Reply("Hello world");
1766 }
1767
1768 ExtensionTestMessageListener worker_completion_listener("SUCCESS_FROM_WORKER",
1769 false);
1770 // Finish executing chrome.test.sendMessage().
1771 worker_listener.Reply("Hello world");
1772 EXPECT_TRUE(worker_completion_listener.WaitUntilSatisfied());
1773
1774 // The following block makes sure we have received all the IPCs related to
1775 // ref-count from the worker.
1776 {
1777 // The following roundtrip:
1778 // browser->extension->worker->extension->browser
1779 // will ensure that the worker sent the relevant ref count IPCs.
1780 std::string result;
1781 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1782 web_contents, "window.roundtripToWorker();", &result));
1783 EXPECT_EQ("roundtrip-succeeded", result);
1784
1785 // Ensure IO thread IPCs run.
1786 content::RunAllTasksUntilIdle();
1787 }
1788
1789 // The ref count should drop to 0.
1790 EXPECT_EQ(0u, GetWorkerRefCount(extension->url()));
1791}
1792
David Bertoni4d9cf41d2019-06-04 00:06:221793IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
1794 PRE_EventsAfterRestart) {
1795 ExtensionTestMessageListener event_added_listener("ready", false);
1796 const Extension* extension = LoadExtensionWithFlags(
1797 test_data_dir_.AppendASCII(
1798 "service_worker/worker_based_background/events_to_stopped_extension"),
1799 kFlagNone);
1800 ASSERT_TRUE(extension);
1801 EXPECT_EQ(kTestExtensionId, extension->id());
1802 ProcessManager* pm = ProcessManager::Get(browser()->profile());
1803 // TODO(crbug.com/969884): This will break once keep alive counts
1804 // for service workers are tracked by the Process Manager.
1805 EXPECT_LT(pm->GetLazyKeepaliveCount(extension), 1);
1806 EXPECT_TRUE(pm->GetLazyKeepaliveActivities(extension).empty());
1807 EXPECT_TRUE(event_added_listener.WaitUntilSatisfied());
1808}
1809
1810// After browser restarts, this test step ensures that opening a tab fires
1811// tabs.onCreated event listener to the extension without explicitly loading the
1812// extension. This is because the extension registered a listener for
1813// tabs.onMoved before browser restarted in PRE_EventsAfterRestart.
1814IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, EventsAfterRestart) {
1815 // Verify there is no RenderProcessHost for the extension.
David Bertoni023e0ec2019-06-10 17:28:221816 EXPECT_FALSE(ExtensionHasRenderProcessHost(kTestExtensionId));
David Bertoni4d9cf41d2019-06-04 00:06:221817
1818 ExtensionTestMessageListener moved_tab_listener("moved-tab", false);
1819 // Add a tab, then move it.
1820 content::WebContents* new_web_contents =
Istiaque Ahmed3f692562019-07-26 22:59:261821 browsertest_util::AddTab(browser(), GURL(url::kAboutBlankURL));
David Bertoni4d9cf41d2019-06-04 00:06:221822 EXPECT_TRUE(new_web_contents);
1823 browser()->tab_strip_model()->MoveWebContentsAt(
1824 browser()->tab_strip_model()->count() - 1, 0, false);
1825 EXPECT_TRUE(moved_tab_listener.WaitUntilSatisfied());
1826}
1827
Istiaque Ahmed1e59aec2019-06-05 22:40:241828IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, TabsOnCreated) {
1829 ASSERT_TRUE(RunExtensionTestWithFlags("tabs/lazy_background_on_created",
1830 kFlagRunAsServiceWorkerBasedExtension))
1831 << message_;
1832}
1833
David Bertoni023e0ec2019-06-10 17:28:221834IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
1835 PRE_FilteredEventsAfterRestart) {
1836 ExtensionTestMessageListener listener_added("ready", false);
1837 const Extension* extension = LoadExtensionWithFlags(
1838 test_data_dir_.AppendASCII("service_worker/worker_based_background/"
1839 "filtered_events_after_restart"),
1840 kFlagNone);
1841 ASSERT_TRUE(extension);
1842 EXPECT_EQ(kTestExtensionId, extension->id());
1843 ProcessManager* pm = ProcessManager::Get(browser()->profile());
1844 // TODO(crbug.com/969884): This will break once keep alive counts
1845 // for service workers are tracked by the Process Manager.
1846 EXPECT_LT(pm->GetLazyKeepaliveCount(extension), 1);
1847 EXPECT_TRUE(pm->GetLazyKeepaliveActivities(extension).empty());
1848 EXPECT_TRUE(listener_added.WaitUntilSatisfied());
1849}
1850
1851// After browser restarts, this test step ensures that opening a tab fires
1852// tabs.onCreated event listener to the extension without explicitly loading the
1853// extension. This is because the extension registered a listener for
1854// tabs.onMoved before browser restarted in PRE_EventsAfterRestart.
1855IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
1856 FilteredEventsAfterRestart) {
1857 // Verify there is no RenderProcessHost for the extension.
1858 // TODO(crbug.com/971309): This is currently broken because the test
1859 // infrastructure opens a tab, which dispatches an event to our
1860 // extension, even though the filter doesn't include that URL. The
1861 // referenced bug is about moving filtering into the EventRouter so they
1862 // get filtered before being dispatched.
1863 EXPECT_TRUE(ExtensionHasRenderProcessHost(kTestExtensionId));
1864
1865 // Create a tab to a.html, expect it to navigate to b.html. The service worker
1866 // will see two webNavigation.onCommitted events.
1867 GURL page_url = embedded_test_server()->GetURL(
1868 "/extensions/api_test/service_worker/worker_based_background/"
1869 "filtered_events_after_restart/"
1870 "a.html");
1871 ExtensionTestMessageListener worker_filtered_event_listener(
1872 "PASS_FROM_WORKER", false);
1873 worker_filtered_event_listener.set_failure_message("FAIL_FROM_WORKER");
Istiaque Ahmed3f692562019-07-26 22:59:261874 content::WebContents* web_contents =
1875 browsertest_util::AddTab(browser(), page_url);
David Bertoni023e0ec2019-06-10 17:28:221876 EXPECT_TRUE(web_contents);
1877 EXPECT_TRUE(worker_filtered_event_listener.WaitUntilSatisfied());
1878}
1879
Istiaque Ahmed91d6987c2019-06-25 00:09:331880// Tests that chrome.browserAction.onClicked sees user gesture.
1881IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
1882 BrowserActionUserGesture) {
1883 // First, load |extension| first so that it has browserAction.onClicked
1884 // listener registered.
1885 ExtensionTestMessageListener listener_added("ready", false);
1886 const Extension* extension = LoadExtension(
1887 test_data_dir_.AppendASCII("service_worker/worker_based_background/"
1888 "browser_action"));
1889 ASSERT_TRUE(extension);
1890 EXPECT_TRUE(listener_added.WaitUntilSatisfied());
1891
1892 ResultCatcher catcher;
1893 // Click on browser action to start the test.
1894 {
Istiaque Ahmed3f692562019-07-26 22:59:261895 content::WebContents* web_contents =
1896 browsertest_util::AddTab(browser(), GURL("about:blank"));
Istiaque Ahmed91d6987c2019-06-25 00:09:331897 ASSERT_TRUE(web_contents);
1898 ExtensionActionRunner::GetForWebContents(
1899 browser()->tab_strip_model()->GetActiveWebContents())
1900 ->RunAction(extension, true);
1901 }
1902 EXPECT_TRUE(catcher.GetNextResult()) << message_;
1903}
1904
Istiaque Ahmed242a4102019-06-25 01:47:571905// Tests that Service Worker notification handlers can call extension APIs that
1906// require user gesture to be present.
1907IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTestWithNotification,
1908 ServiceWorkerNotificationClick) {
1909 ResultCatcher catcher;
1910 const Extension* extension = LoadExtension(
1911 test_data_dir_.AppendASCII("service_worker/worker_based_background/"
1912 "notification_click"));
1913 ASSERT_TRUE(extension);
1914 EXPECT_TRUE(catcher.GetNextResult()) << message_;
1915
1916 // Click on the Service Worker notification.
1917 {
1918 std::vector<message_center::Notification> notifications =
1919 GetDisplayedNotifications();
1920 ASSERT_EQ(1u, notifications.size());
1921 display_service_tester_->SimulateClick(
1922 NotificationHandler::Type::WEB_PERSISTENT, notifications[0].id(),
1923 base::nullopt, base::nullopt);
1924 }
1925
1926 EXPECT_TRUE(catcher.GetNextResult()) << message_;
1927}
1928
Istiaque Ahmed3dd604232019-08-02 19:22:211929// Tests chrome.permissions.request API.
1930IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, PermissionsAPI) {
1931 // First, load |extension| first so that it has browserAction.onClicked
1932 // listener registered.
1933 ExtensionTestMessageListener worker_listener("ready", false);
1934 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
1935 "service_worker/worker_based_background/permissions_api"));
1936 ASSERT_TRUE(extension);
1937 const ExtensionId extension_id = extension->id();
1938 EXPECT_TRUE(worker_listener.WaitUntilSatisfied());
1939
1940 // "storage" permission is optional in |extension|, and isn't available right
1941 // away.
1942 EXPECT_FALSE(
1943 extension->permissions_data()->HasAPIPermission(APIPermission::kStorage));
1944
1945 PermissionsRequestFunction::SetAutoConfirmForTests(true);
1946
1947 ResultCatcher catcher;
1948 // Click on browser action to start the test.
1949 {
1950 content::WebContents* web_contents =
1951 browsertest_util::AddTab(browser(), GURL("about:blank"));
1952 ASSERT_TRUE(web_contents);
1953 ExtensionActionRunner::GetForWebContents(
1954 browser()->tab_strip_model()->GetActiveWebContents())
1955 ->RunAction(extension, true);
1956 }
1957 EXPECT_TRUE(catcher.GetNextResult()) << message_;
1958
1959 // Expect the permission ("storage") to be available now.
1960 EXPECT_TRUE(
1961 extension->permissions_data()->HasAPIPermission(APIPermission::kStorage));
1962}
1963
Devlin Cronin59551d82019-03-05 01:28:591964// Tests that console messages logged by extension service workers, both via
1965// the typical console.* methods and via our custom bindings console, are
1966// passed through the normal ServiceWorker console messaging and are
1967// observable.
Devlin Cronin242d19d22019-03-12 18:08:481968IN_PROC_BROWSER_TEST_F(ServiceWorkerLazyBackgroundTest, ConsoleLogging) {
Devlin Cronin59551d82019-03-05 01:28:591969 // A helper class to wait for a particular message to be logged from a
1970 // ServiceWorker.
1971 class ConsoleMessageObserver : public content::ServiceWorkerContextObserver {
1972 public:
1973 ConsoleMessageObserver(content::BrowserContext* browser_context,
1974 const std::string& expected_message)
1975 : expected_message_(base::UTF8ToUTF16(expected_message)),
1976 scoped_observer_(this) {
1977 content::StoragePartition* partition =
1978 content::BrowserContext::GetDefaultStoragePartition(browser_context);
1979 scoped_observer_.Add(partition->GetServiceWorkerContext());
1980 }
1981 ~ConsoleMessageObserver() override = default;
1982
1983 void Wait() { run_loop_.Run(); }
1984
1985 private:
1986 // ServiceWorkerContextObserver:
1987 void OnReportConsoleMessage(
1988 int64_t version_id,
1989 const content::ConsoleMessage& message) override {
1990 // NOTE: We could check the version_id, but it shouldn't be necessary with
1991 // the expected messages we're verifying (they're uncommon enough).
1992 if (message.message != expected_message_)
1993 return;
1994 scoped_observer_.RemoveAll();
1995 run_loop_.QuitWhenIdle();
1996 }
1997
1998 base::string16 expected_message_;
1999 base::RunLoop run_loop_;
2000 ScopedObserver<content::ServiceWorkerContext,
2001 content::ServiceWorkerContextObserver>
2002 scoped_observer_;
2003
2004 DISALLOW_COPY_AND_ASSIGN(ConsoleMessageObserver);
2005 };
2006
2007 TestExtensionDir test_dir;
2008 test_dir.WriteManifest(
2009 R"({
2010 "name": "Test Extension",
2011 "manifest_version": 2,
2012 "version": "0.1",
David Bertoni630837d2019-04-02 21:22:102013 "background": {"service_worker": "script.js"}
Devlin Cronin59551d82019-03-05 01:28:592014 })");
2015 constexpr char kScript[] =
2016 R"(// First, log a message using the normal, built-in blink console.
2017 console.log('test message');
2018 chrome.test.runTests([
2019 function justATest() {
2020 // Next, we use the "Console" object from
2021 // extensions/renderer/console.cc, which is used by custom bindings
2022 // so that it isn't tampered with by untrusted script. The test
2023 // custom bindings log a message whenever a test is passed, so we
2024 // force a log by just passing this test.
2025 chrome.test.succeed();
2026 }
2027 ]);)";
2028 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"), kScript);
2029
2030 // The observer for the built-in blink console.
2031 ConsoleMessageObserver default_console_observer(profile(), "test message");
2032 // The observer for our custom extensions bindings console.
2033 ConsoleMessageObserver custom_console_observer(profile(),
2034 "[SUCCESS] justATest");
2035
2036 const Extension* extension = LoadExtension(test_dir.UnpackedPath());
2037 ASSERT_TRUE(extension);
2038
2039 default_console_observer.Wait();
2040 custom_console_observer.Wait();
2041 // If we receive both messages, we passed!
2042}
2043
David Bertoni98a5da72019-08-23 23:38:222044class ServiceWorkerCheckBindingsTest
2045 : public ServiceWorkerTest,
2046 public testing::WithParamInterface<version_info::Channel> {
2047 public:
2048 ServiceWorkerCheckBindingsTest() : ServiceWorkerTest(GetParam()) {}
2049 ~ServiceWorkerCheckBindingsTest() override {}
2050
2051 private:
2052 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerCheckBindingsTest);
2053};
2054
2055// Load an extension in each allowed channel and check that the expected
2056// bindings are available.
2057IN_PROC_BROWSER_TEST_P(ServiceWorkerCheckBindingsTest, BindingsAvailability) {
2058 scoped_refptr<const Extension> extension;
2059 static constexpr char kManifest[] =
2060 R"({
2061 "name": "Service Worker-based background script",
2062 "version": "0.1",
2063 "manifest_version": 2,
2064 "description": "Test that bindings are available.",
2065 "permissions": ["storage"],
2066 "background": {"service_worker": "worker.js"}
2067 })";
2068 static constexpr char kScript[] =
2069 R"(var chromeAPIAvailable = !!chrome;
2070 var storageAPIAvailable = chromeAPIAvailable && !!chrome.storage;
2071 var tabsAPIAvailable = chromeAPIAvailable && !!chrome.tabs;
2072 var testAPIAvailable = chromeAPIAvailable && !!chrome.test;
2073
2074 if (chromeAPIAvailable && storageAPIAvailable && tabsAPIAvailable &&
2075 testAPIAvailable) {
2076 chrome.test.sendMessage('SUCCESS');
2077 } else {
2078 console.log('chromeAPIAvailable: ' + chromeAPIAvailable);
2079 console.log('storageAPIAvailable: ' + storageAPIAvailable);
2080 console.log('tabsAPIAvailable: ' + tabsAPIAvailable);
2081 console.log('testAPIAvailable: ' + testAPIAvailable);
2082 chrome.test.sendMessage('FAILURE');
2083 })";
2084
2085 if (GetParam() <= version_info::Channel::CANARY) {
2086 TestExtensionDir test_dir;
2087 test_dir.WriteManifest(kManifest);
2088 test_dir.WriteFile(FILE_PATH_LITERAL("worker.js"), kScript);
2089 const base::FilePath path = test_dir.UnpackedPath();
2090
2091 // Wait for the extension to load and the script to finish.
2092 ExtensionTestMessageListener result_listener("SUCCESS", false);
2093 result_listener.set_failure_message("FAILURE");
2094
2095 extension = LoadExtension(test_dir.UnpackedPath());
2096 ASSERT_TRUE(extension.get());
2097 EXPECT_TRUE(BackgroundInfo::IsServiceWorkerBased(extension.get()));
2098 EXPECT_TRUE(result_listener.WaitUntilSatisfied());
2099 }
2100}
2101
2102INSTANTIATE_TEST_SUITE_P(Unknown,
2103 ServiceWorkerCheckBindingsTest,
2104 ::testing::Values(version_info::Channel::UNKNOWN,
2105 version_info::Channel::CANARY));
2106
annekao38685502015-07-14 17:46:392107} // namespace extensions