blob: a052df2c0a07d071557586e5048a1fe456d7cb87 [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.
Makoto Shimazu3a69e2e42019-09-12 07:18:25317//
318// Disabled due to flakiness: https://crbug.com/1003244.
319IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, DISABLED_PRE_Basic) {
Istiaque Ahmedccb444022018-06-19 02:11:12320 ExtensionTestMessageListener newtab_listener("CREATED", false);
321 newtab_listener.set_failure_message("CREATE_FAILED");
322 ExtensionTestMessageListener worker_listener("WORKER_RUNNING", false);
323 worker_listener.set_failure_message("NON_WORKER_SCOPE");
324 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
325 "service_worker/worker_based_background/basic"));
326 ASSERT_TRUE(extension);
327 const ExtensionId extension_id = extension->id();
328 EXPECT_TRUE(worker_listener.WaitUntilSatisfied());
329
330 const GURL url = embedded_test_server()->GetURL("/extensions/test_file.html");
Istiaque Ahmed3f692562019-07-26 22:59:26331 content::WebContents* new_web_contents =
332 browsertest_util::AddTab(browser(), url);
Istiaque Ahmedccb444022018-06-19 02:11:12333 EXPECT_TRUE(new_web_contents);
334 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
335
336 // Service Worker extension does not have ExtensionHost.
337 EXPECT_FALSE(process_manager()->GetBackgroundHostForExtension(extension_id));
338}
339
340// After browser restarts, this test step ensures that opening a tab fires
341// tabs.onCreated event listener to the extension without explicitly loading the
342// extension. This is because the extension registered a listener before browser
343// restarted in PRE_Basic.
Makoto Shimazu3a69e2e42019-09-12 07:18:25344//
345// Disabled due to flakiness: https://crbug.com/1003244.
346IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, DISABLED_Basic) {
Istiaque Ahmedccb444022018-06-19 02:11:12347 ExtensionTestMessageListener newtab_listener("CREATED", false);
348 newtab_listener.set_failure_message("CREATE_FAILED");
349 const GURL url = embedded_test_server()->GetURL("/extensions/test_file.html");
Istiaque Ahmed3f692562019-07-26 22:59:26350 content::WebContents* new_web_contents =
351 browsertest_util::AddTab(browser(), url);
Istiaque Ahmedccb444022018-06-19 02:11:12352 EXPECT_TRUE(new_web_contents);
353 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
354}
355
Istiaque Ahmedbf08f952018-10-02 01:22:04356// Tests chrome.runtime.onInstalled fires for extension service workers.
Devlin Cronin242d19d22019-03-12 18:08:48357IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, OnInstalledEvent) {
Istiaque Ahmedbf08f952018-10-02 01:22:04358 ASSERT_TRUE(RunExtensionTest(
359 "service_worker/worker_based_background/events_on_installed"))
360 << message_;
361}
362
Istiaque Ahmedba8d0652019-05-14 15:17:34363// Tests chrome.runtime.id and chrome.runtime.getURL().
364IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, RuntimeMisc) {
365 ASSERT_TRUE(
366 RunExtensionTest("service_worker/worker_based_background/runtime_misc"))
367 << message_;
368}
369
David Bertoni69982832019-02-13 21:24:21370// Tests chrome.storage APIs.
Devlin Cronin242d19d22019-03-12 18:08:48371IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, StorageSetAndGet) {
David Bertoni69982832019-02-13 21:24:21372 ASSERT_TRUE(
373 RunExtensionTest("service_worker/worker_based_background/storage"))
374 << message_;
375}
376
David Bertoni0665c892019-02-14 00:27:26377// Tests chrome.storage.local and chrome.storage.local APIs.
Devlin Cronin242d19d22019-03-12 18:08:48378IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, StorageNoPermissions) {
David Bertoni0665c892019-02-14 00:27:26379 ASSERT_TRUE(RunExtensionTest(
380 "service_worker/worker_based_background/storage_no_permissions"))
381 << message_;
382}
383
David Bertoni30809312019-02-28 22:56:05384// Tests chrome.tabs APIs.
Devlin Cronin242d19d22019-03-12 18:08:48385IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, TabsBasic) {
David Bertoni30809312019-02-28 22:56:05386 ASSERT_TRUE(
387 RunExtensionTest("service_worker/worker_based_background/tabs_basic"))
388 << message_;
389}
390
David Bertoni46d698892019-02-26 00:29:10391// Tests chrome.tabs events.
Devlin Cronin242d19d22019-03-12 18:08:48392IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, TabsEvents) {
David Bertoni46d698892019-02-26 00:29:10393 ASSERT_TRUE(
394 RunExtensionTest("service_worker/worker_based_background/tabs_events"))
395 << message_;
396}
397
David Bertoni4c7dfcc2019-03-27 23:49:34398// Tests chrome.tabs APIs.
399IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, TabsExecuteScript) {
400 ASSERT_TRUE(RunExtensionTest(
401 "service_worker/worker_based_background/tabs_execute_script"))
402 << message_;
403}
404
David Bertoni37ae0222019-04-04 01:30:54405// Tests chrome.webRequest APIs.
Vasilii Sukhanov37fd9f722019-08-26 15:00:07406// Times out on Mac/Win only. https://crbug.com/997686
407#if defined(OS_WIN) || defined(OS_MACOSX)
408#define MAYBE_WebRequest DISABLED_WebRequest
409#else
410#define MAYBE_WebRequest WebRequest
411#endif
412IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, MAYBE_WebRequest) {
David Bertoni3929f552019-03-28 22:10:36413 ASSERT_TRUE(
414 RunExtensionTest("service_worker/worker_based_background/web_request"))
415 << message_;
416}
417
David Bertoni37ae0222019-04-04 01:30:54418// Tests chrome.webRequest APIs in blocking mode.
419IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, WebRequestBlocking) {
420 // Try to load the page before installing the extension, which should work.
421 const GURL url = embedded_test_server()->GetURL("/extensions/test_file.html");
422 EXPECT_EQ(content::PAGE_TYPE_NORMAL, NavigateAndGetPageType(url));
423
424 // Install the extension and navigate again to the page.
425 ExtensionTestMessageListener ready_listener("ready", false);
426 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII(
427 "service_worker/worker_based_background/web_request_blocking")));
428 ASSERT_TRUE(ready_listener.WaitUntilSatisfied());
429 EXPECT_EQ(content::PAGE_TYPE_ERROR, NavigateAndGetPageType(url));
430}
431
David Bertoni377f52312019-05-21 20:35:03432// Tests chrome.webNavigation APIs.
433IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, FilteredEvents) {
434 ASSERT_TRUE(RunExtensionTest(
435 "service_worker/worker_based_background/filtered_events"))
436 << message_;
437}
438
Istiaque Ahmed70f76ac2018-11-02 02:59:55439// Listens for |message| from extension Service Worker early so that tests can
440// wait for the message on startup (and not miss it).
441class ServiceWorkerWithEarlyMessageListenerTest
442 : public ServiceWorkerBasedBackgroundTest {
Istiaque Ahmedf70ab222018-10-02 03:08:24443 public:
Istiaque Ahmed70f76ac2018-11-02 02:59:55444 explicit ServiceWorkerWithEarlyMessageListenerTest(
445 const std::string& test_message)
446 : test_message_(test_message) {}
447 ~ServiceWorkerWithEarlyMessageListenerTest() override = default;
Istiaque Ahmedf70ab222018-10-02 03:08:24448
Istiaque Ahmed70f76ac2018-11-02 02:59:55449 bool WaitForMessage() { return listener_->WaitUntilSatisfied(); }
Istiaque Ahmedf70ab222018-10-02 03:08:24450
451 void CreatedBrowserMainParts(content::BrowserMainParts* main_parts) override {
452 // At this point, the notification service is initialized but the profile
453 // and extensions have not.
Istiaque Ahmed70f76ac2018-11-02 02:59:55454 listener_ =
455 std::make_unique<ExtensionTestMessageListener>(test_message_, false);
Istiaque Ahmedf70ab222018-10-02 03:08:24456 ServiceWorkerBasedBackgroundTest::CreatedBrowserMainParts(main_parts);
457 }
458
459 private:
Istiaque Ahmed70f76ac2018-11-02 02:59:55460 const std::string test_message_;
Istiaque Ahmedf70ab222018-10-02 03:08:24461 std::unique_ptr<ExtensionTestMessageListener> listener_;
462
Istiaque Ahmed70f76ac2018-11-02 02:59:55463 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerWithEarlyMessageListenerTest);
464};
465
466class ServiceWorkerOnStartupEventTest
467 : public ServiceWorkerWithEarlyMessageListenerTest {
468 public:
469 ServiceWorkerOnStartupEventTest()
470 : ServiceWorkerWithEarlyMessageListenerTest("onStartup event") {}
471 ~ServiceWorkerOnStartupEventTest() override = default;
472
473 private:
474 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerOnStartupEventTest);
Istiaque Ahmedf70ab222018-10-02 03:08:24475};
476
477// Tests "runtime.onStartup" for extension SW.
Devlin Cronin242d19d22019-03-12 18:08:48478IN_PROC_BROWSER_TEST_F(ServiceWorkerOnStartupEventTest, PRE_Event) {
Istiaque Ahmedf70ab222018-10-02 03:08:24479 ASSERT_TRUE(RunExtensionTest(
480 "service_worker/worker_based_background/on_startup_event"))
481 << message_;
482}
483
Devlin Cronin242d19d22019-03-12 18:08:48484IN_PROC_BROWSER_TEST_F(ServiceWorkerOnStartupEventTest, Event) {
Istiaque Ahmed70f76ac2018-11-02 02:59:55485 EXPECT_TRUE(WaitForMessage());
486}
487
488class ServiceWorkerRegistrationAtStartupTest
489 : public ServiceWorkerWithEarlyMessageListenerTest,
490 public ServiceWorkerTaskQueue::TestObserver {
491 public:
492 ServiceWorkerRegistrationAtStartupTest()
493 : ServiceWorkerWithEarlyMessageListenerTest("WORKER_RUNNING") {
494 ServiceWorkerTaskQueue::SetObserverForTest(this);
495 }
496 ~ServiceWorkerRegistrationAtStartupTest() override {
497 ServiceWorkerTaskQueue::SetObserverForTest(nullptr);
498 }
499
500 // ServiceWorkerTaskQueue::TestObserver:
501 void OnActivateExtension(const ExtensionId& extension_id,
502 bool will_register_service_worker) override {
503 if (extension_id != kExtensionId)
504 return;
505
506 will_register_service_worker_ = will_register_service_worker;
507
508 extension_activated_ = true;
509 if (run_loop_)
510 run_loop_->Quit();
511 }
512
513 void WaitForOnActivateExtension() {
514 if (extension_activated_)
515 return;
516 run_loop_ = std::make_unique<base::RunLoop>();
517 run_loop_->Run();
518 }
519
520 bool WillRegisterServiceWorker() {
521 return will_register_service_worker_.value();
522 }
523
524 protected:
525 static const char kExtensionId[];
526
527 private:
528 bool extension_activated_ = false;
529 base::Optional<bool> will_register_service_worker_;
530 std::unique_ptr<base::RunLoop> run_loop_;
531
532 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerRegistrationAtStartupTest);
533};
534
535// Test extension id at
536// api_test/service_worker/worker_based_background/registration_at_startup/.
537const char ServiceWorkerRegistrationAtStartupTest::kExtensionId[] =
538 "gnchfmandajfaiajniicagenfmhdjila";
539
540// Tests that Service Worker registration for existing extension isn't issued
541// upon browser restart.
542// Regression test for https://crbug.com/889687.
Devlin Cronin242d19d22019-03-12 18:08:48543IN_PROC_BROWSER_TEST_F(ServiceWorkerRegistrationAtStartupTest,
Istiaque Ahmed70f76ac2018-11-02 02:59:55544 PRE_ExtensionActivationDoesNotReregister) {
545 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
546 "service_worker/worker_based_background/registration_at_startup"));
547 ASSERT_TRUE(extension);
548 EXPECT_EQ(kExtensionId, extension->id());
549 // Wait for "WORKER_RUNNING" message from the Service Worker.
550 EXPECT_TRUE(WaitForMessage());
551 EXPECT_TRUE(WillRegisterServiceWorker());
552}
553
Devlin Cronin242d19d22019-03-12 18:08:48554IN_PROC_BROWSER_TEST_F(ServiceWorkerRegistrationAtStartupTest,
Istiaque Ahmed70f76ac2018-11-02 02:59:55555 ExtensionActivationDoesNotReregister) {
556 // Since the extension has onStartup listener, the Service Worker will run on
557 // browser start and we'll see "WORKER_RUNNING" message from the worker.
558 EXPECT_TRUE(WaitForMessage());
559 // As the extension activated during first run on PRE_ step, it shouldn't
560 // re-register the Service Worker upon browser restart.
561 EXPECT_FALSE(WillRegisterServiceWorker());
Istiaque Ahmedf70ab222018-10-02 03:08:24562}
563
Istiaque Ahmeda14ec482018-08-25 01:02:18564// Class that dispatches an event to |extension_id| right after a
565// non-lazy listener to the event is added from the extension's Service Worker.
Istiaque Ahmed771aa8a22018-06-20 23:40:53566class EarlyWorkerMessageSender : public EventRouter::Observer {
567 public:
568 EarlyWorkerMessageSender(content::BrowserContext* browser_context,
Istiaque Ahmeda14ec482018-08-25 01:02:18569 const ExtensionId& extension_id,
570 std::unique_ptr<Event> event)
Istiaque Ahmed771aa8a22018-06-20 23:40:53571 : browser_context_(browser_context),
572 event_router_(EventRouter::EventRouter::Get(browser_context_)),
573 extension_id_(extension_id),
Istiaque Ahmeda14ec482018-08-25 01:02:18574 event_(std::move(event)),
Istiaque Ahmed771aa8a22018-06-20 23:40:53575 listener_("PASS", false) {
576 DCHECK(browser_context_);
577 listener_.set_failure_message("FAIL");
Istiaque Ahmeda14ec482018-08-25 01:02:18578 event_router_->RegisterObserver(this, event_->event_name);
Istiaque Ahmed771aa8a22018-06-20 23:40:53579 }
580
581 ~EarlyWorkerMessageSender() override {
582 event_router_->UnregisterObserver(this);
583 }
584
585 // EventRouter::Observer:
586 void OnListenerAdded(const EventListenerInfo& details) override {
Istiaque Ahmeda14ec482018-08-25 01:02:18587 if (!event_ || extension_id_ != details.extension_id ||
588 event_->event_name != details.event_name) {
Istiaque Ahmed771aa8a22018-06-20 23:40:53589 return;
Istiaque Ahmeda14ec482018-08-25 01:02:18590 }
591
Istiaque Ahmed771aa8a22018-06-20 23:40:53592 const bool is_lazy_listener = details.browser_context == nullptr;
593 if (is_lazy_listener) {
594 // Wait for the non-lazy listener as we want to exercise the code to
595 // dispatch the event right after the Service Worker registration is
596 // completing.
597 return;
598 }
Istiaque Ahmeda14ec482018-08-25 01:02:18599 DispatchEvent(std::move(event_));
Istiaque Ahmed771aa8a22018-06-20 23:40:53600 }
601
602 bool SendAndWait() { return listener_.WaitUntilSatisfied(); }
603
604 private:
605 static constexpr const char* const kTestOnMessageEventName = "test.onMessage";
606
Istiaque Ahmeda14ec482018-08-25 01:02:18607 void DispatchEvent(std::unique_ptr<Event> event) {
Istiaque Ahmed771aa8a22018-06-20 23:40:53608 EventRouter::Get(browser_context_)
609 ->DispatchEventToExtension(extension_id_, std::move(event));
610 }
611
612 content::BrowserContext* const browser_context_ = nullptr;
613 EventRouter* const event_router_ = nullptr;
614 const ExtensionId extension_id_;
Istiaque Ahmeda14ec482018-08-25 01:02:18615 std::unique_ptr<Event> event_;
Istiaque Ahmed771aa8a22018-06-20 23:40:53616 ExtensionTestMessageListener listener_;
Istiaque Ahmed771aa8a22018-06-20 23:40:53617
618 DISALLOW_COPY_AND_ASSIGN(EarlyWorkerMessageSender);
619};
620
621// Tests that extension event dispatch works correctly right after extension
622// installation registers its Service Worker.
623// Regression test for: https://crbug.com/850792.
Devlin Cronin242d19d22019-03-12 18:08:48624IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, EarlyEventDispatch) {
Istiaque Ahmed771aa8a22018-06-20 23:40:53625 const ExtensionId kId("pkplfbidichfdicaijlchgnapepdginl");
Istiaque Ahmeda14ec482018-08-25 01:02:18626
627 // Build "test.onMessage" event for dispatch.
628 auto event = std::make_unique<Event>(
629 events::FOR_TEST, extensions::api::test::OnMessage::kEventName,
Lei Zhang582ecd12019-02-13 20:28:54630 base::ListValue::From(base::JSONReader::ReadDeprecated(
Istiaque Ahmeda14ec482018-08-25 01:02:18631 R"([{"data": "hello", "lastMessage": true}])")),
632 profile());
633
634 EarlyWorkerMessageSender sender(profile(), kId, std::move(event));
Istiaque Ahmed771aa8a22018-06-20 23:40:53635 // pkplfbidichfdicaijlchgnapepdginl
636 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
637 "service_worker/worker_based_background/early_event_dispatch"));
638 CHECK(extension);
639 EXPECT_EQ(kId, extension->id());
640 EXPECT_TRUE(sender.SendAndWait());
641}
642
Istiaque Ahmeda14ec482018-08-25 01:02:18643// Tests that filtered events dispatches correctly right after a non-lazy
644// listener is registered for that event (and before the corresponding lazy
645// listener is registered).
Devlin Cronin242d19d22019-03-12 18:08:48646IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
Istiaque Ahmeda14ec482018-08-25 01:02:18647 EarlyFilteredEventDispatch) {
648 const ExtensionId kId("pkplfbidichfdicaijlchgnapepdginl");
649
650 // Add minimal details required to dispatch webNavigation.onCommitted event:
651 extensions::api::web_navigation::OnCommitted::Details details;
652 details.transition_type =
653 extensions::api::web_navigation::TRANSITION_TYPE_TYPED;
654
655 // Build a dummy onCommited event to dispatch.
656 auto on_committed_event = std::make_unique<Event>(
657 events::WEB_NAVIGATION_ON_COMMITTED, "webNavigation.onCommitted",
658 api::web_navigation::OnCommitted::Create(details), profile());
659 // The filter will match the listener filter registered from the extension.
660 EventFilteringInfo info;
661 info.url = GURL("http://foo.com/a.html");
662 on_committed_event->filter_info = info;
663
664 EarlyWorkerMessageSender sender(profile(), kId,
665 std::move(on_committed_event));
666
667 // pkplfbidichfdicaijlchgnapepdginl
668 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
669 "service_worker/worker_based_background/early_filtered_event_dispatch"));
670 ASSERT_TRUE(extension);
671 EXPECT_EQ(kId, extension->id());
672 EXPECT_TRUE(sender.SendAndWait());
673}
674
lazyboybd325ae2015-11-18 21:35:26675class ServiceWorkerBackgroundSyncTest : public ServiceWorkerTest {
676 public:
677 ServiceWorkerBackgroundSyncTest() {}
678 ~ServiceWorkerBackgroundSyncTest() override {}
679
680 void SetUpCommandLine(base::CommandLine* command_line) override {
681 // ServiceWorkerRegistration.sync requires experimental flag.
682 command_line->AppendSwitch(
Istiaque Ahmedea5ed5042017-09-25 19:00:16683 ::switches::kEnableExperimentalWebPlatformFeatures);
lazyboybd325ae2015-11-18 21:35:26684 ServiceWorkerTest::SetUpCommandLine(command_line);
685 }
686
687 void SetUp() override {
Robbie McElrathdb12d8e2018-09-18 21:20:40688 content::background_sync_test_util::SetIgnoreNetworkChanges(true);
lazyboybd325ae2015-11-18 21:35:26689 ServiceWorkerTest::SetUp();
690 }
691
692 private:
693 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerBackgroundSyncTest);
694};
695
lazyboy561b7de2015-11-19 19:27:30696class ServiceWorkerPushMessagingTest : public ServiceWorkerTest {
697 public:
698 ServiceWorkerPushMessagingTest()
Sylvain Defresne212b4b02018-10-11 16:32:05699 : scoped_testing_factory_installer_(
700 base::BindRepeating(&gcm::FakeGCMProfileService::Build)),
701 gcm_driver_(nullptr),
702 push_service_(nullptr) {}
703
lazyboy561b7de2015-11-19 19:27:30704 ~ServiceWorkerPushMessagingTest() override {}
705
706 void GrantNotificationPermissionForTest(const GURL& url) {
Peter Beverloodd4ef1e2018-06-21 15:41:04707 NotificationPermissionContext::UpdatePermission(profile(), url.GetOrigin(),
708 CONTENT_SETTING_ALLOW);
lazyboy561b7de2015-11-19 19:27:30709 }
710
711 PushMessagingAppIdentifier GetAppIdentifierForServiceWorkerRegistration(
avia2f4804a2015-12-24 23:11:13712 int64_t service_worker_registration_id,
lazyboy561b7de2015-11-19 19:27:30713 const GURL& origin) {
714 PushMessagingAppIdentifier app_identifier =
715 PushMessagingAppIdentifier::FindByServiceWorker(
716 profile(), origin, service_worker_registration_id);
717
718 EXPECT_FALSE(app_identifier.is_null());
719 return app_identifier;
720 }
721
722 // ExtensionApiTest overrides.
723 void SetUpCommandLine(base::CommandLine* command_line) override {
peter9de96272015-12-04 15:23:27724 command_line->AppendSwitch(
Istiaque Ahmedea5ed5042017-09-25 19:00:16725 ::switches::kEnableExperimentalWebPlatformFeatures);
lazyboy561b7de2015-11-19 19:27:30726 ServiceWorkerTest::SetUpCommandLine(command_line);
727 }
Tanja Gornak89128fd2018-09-18 08:49:34728
lazyboy561b7de2015-11-19 19:27:30729 void SetUpOnMainThread() override {
miguelg9b502862017-04-24 18:13:53730 NotificationDisplayServiceFactory::GetInstance()->SetTestingFactory(
Sylvain Defresne711ff6b2018-10-04 12:33:54731 profile(),
732 base::BindRepeating(&StubNotificationDisplayService::FactoryForTests));
miguelg9b502862017-04-24 18:13:53733
johnmea5045732016-09-08 17:23:29734 gcm::FakeGCMProfileService* gcm_service =
735 static_cast<gcm::FakeGCMProfileService*>(
Tanja Gornak89128fd2018-09-18 08:49:34736 gcm::GCMProfileServiceFactory::GetForProfile(profile()));
johnmea5045732016-09-08 17:23:29737 gcm_driver_ = static_cast<instance_id::FakeGCMDriverForInstanceID*>(
738 gcm_service->driver());
lazyboy561b7de2015-11-19 19:27:30739 push_service_ = PushMessagingServiceFactory::GetForProfile(profile());
740
741 ServiceWorkerTest::SetUpOnMainThread();
742 }
743
johnmea5045732016-09-08 17:23:29744 instance_id::FakeGCMDriverForInstanceID* gcm_driver() const {
745 return gcm_driver_;
746 }
lazyboy561b7de2015-11-19 19:27:30747 PushMessagingServiceImpl* push_service() const { return push_service_; }
748
749 private:
Sylvain Defresne212b4b02018-10-11 16:32:05750 gcm::GCMProfileServiceFactory::ScopedTestingFactoryInstaller
751 scoped_testing_factory_installer_;
752
johnmea5045732016-09-08 17:23:29753 instance_id::FakeGCMDriverForInstanceID* gcm_driver_;
lazyboy561b7de2015-11-19 19:27:30754 PushMessagingServiceImpl* push_service_;
755
756 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerPushMessagingTest);
757};
758
Istiaque Ahmed805f6a83b2017-10-05 01:23:26759class ServiceWorkerLazyBackgroundTest : public ServiceWorkerTest {
760 public:
Istiaque Ahmed7105f2a2017-10-07 01:11:59761 ServiceWorkerLazyBackgroundTest()
762 : ServiceWorkerTest(
763 // Extensions APIs from SW are only enabled on trunk.
764 // It is important to set the channel early so that this change is
765 // visible in renderers running with service workers (and no
766 // extension).
767 version_info::Channel::UNKNOWN) {}
Istiaque Ahmed805f6a83b2017-10-05 01:23:26768 ~ServiceWorkerLazyBackgroundTest() override {}
769
770 void SetUpCommandLine(base::CommandLine* command_line) override {
771 ServiceWorkerTest::SetUpCommandLine(command_line);
772 // Disable background network activity as it can suddenly bring the Lazy
773 // Background Page alive.
774 command_line->AppendSwitch(::switches::kDisableBackgroundNetworking);
775 command_line->AppendSwitch(::switches::kNoProxyServer);
776 }
777
778 void SetUpInProcessBrowserTestFixture() override {
779 ServiceWorkerTest::SetUpInProcessBrowserTestFixture();
780 // Set shorter delays to prevent test timeouts.
781 ProcessManager::SetEventPageIdleTimeForTesting(1);
782 ProcessManager::SetEventPageSuspendingTimeForTesting(1);
783 }
784
785 private:
786 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerLazyBackgroundTest);
787};
788
Devlin Cronin242d19d22019-03-12 18:08:48789IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, RegisterSucceeds) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22790 StartTestFromBackgroundPage("register.js");
annekao38685502015-07-14 17:46:39791}
792
Devlin Cronin242d19d22019-03-12 18:08:48793IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, UpdateRefreshesServiceWorker) {
Francois Doraye6fb2d02017-10-18 21:29:13794 base::ScopedAllowBlockingForTesting allow_blocking;
lazyboyc3e763a2015-12-09 23:09:58795 base::ScopedTempDir scoped_temp_dir;
796 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
797 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
798 .AppendASCII("update")
799 .AppendASCII("service_worker.pem");
vabr9142fe22016-09-08 13:19:22800 base::FilePath path_v1 =
801 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
802 .AppendASCII("update")
803 .AppendASCII("v1"),
804 scoped_temp_dir.GetPath().AppendASCII("v1.crx"),
805 pem_path, base::FilePath());
806 base::FilePath path_v2 =
807 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
808 .AppendASCII("update")
809 .AppendASCII("v2"),
810 scoped_temp_dir.GetPath().AppendASCII("v2.crx"),
811 pem_path, base::FilePath());
lazyboyc3e763a2015-12-09 23:09:58812 const char* kId = "hfaanndiiilofhfokeanhddpkfffchdi";
813
814 ExtensionTestMessageListener listener_v1("Pong from version 1", false);
815 listener_v1.set_failure_message("FAILURE_V1");
816 // Install version 1.0 of the extension.
817 ASSERT_TRUE(InstallExtension(path_v1, 1));
818 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
819 ->enabled_extensions()
820 .GetByID(kId));
821 EXPECT_TRUE(listener_v1.WaitUntilSatisfied());
822
823 ExtensionTestMessageListener listener_v2("Pong from version 2", false);
824 listener_v2.set_failure_message("FAILURE_V2");
825
826 // Update to version 2.0.
827 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
828 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
829 ->enabled_extensions()
830 .GetByID(kId));
831 EXPECT_TRUE(listener_v2.WaitUntilSatisfied());
832}
833
[email protected]2ef85d562017-09-15 18:41:52834// TODO(crbug.com/765736) Fix the test.
Devlin Cronin242d19d22019-03-12 18:08:48835IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, DISABLED_UpdateWithoutSkipWaiting) {
Francois Doraye6fb2d02017-10-18 21:29:13836 base::ScopedAllowBlockingForTesting allow_blocking;
lazyboy22eddc712015-12-10 21:16:26837 base::ScopedTempDir scoped_temp_dir;
838 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
839 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
840 .AppendASCII("update_without_skip_waiting")
841 .AppendASCII("update_without_skip_waiting.pem");
vabr9142fe22016-09-08 13:19:22842 base::FilePath path_v1 =
843 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
844 .AppendASCII("update_without_skip_waiting")
845 .AppendASCII("v1"),
846 scoped_temp_dir.GetPath().AppendASCII("v1.crx"),
847 pem_path, base::FilePath());
848 base::FilePath path_v2 =
849 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
850 .AppendASCII("update_without_skip_waiting")
851 .AppendASCII("v2"),
852 scoped_temp_dir.GetPath().AppendASCII("v2.crx"),
853 pem_path, base::FilePath());
lazyboy22eddc712015-12-10 21:16:26854 const char* kId = "mhnnnflgagdakldgjpfcofkiocpdmogl";
855
856 // Install version 1.0 of the extension.
857 ASSERT_TRUE(InstallExtension(path_v1, 1));
858 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
859 ->enabled_extensions()
860 .GetByID(kId));
861 const Extension* extension = extensions::ExtensionRegistry::Get(profile())
862 ->enabled_extensions()
863 .GetByID(kId);
864
865 ExtensionTestMessageListener listener1("Pong from version 1", false);
866 listener1.set_failure_message("FAILURE");
Istiaque Ahmed3f692562019-07-26 22:59:26867 content::WebContents* web_contents = browsertest_util::AddTab(
868 browser(), extension->GetResourceURL("page.html"));
lazyboy22eddc712015-12-10 21:16:26869 EXPECT_TRUE(listener1.WaitUntilSatisfied());
870
871 // Update to version 2.0.
872 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
873 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
874 ->enabled_extensions()
875 .GetByID(kId));
876 const Extension* extension_after_update =
877 extensions::ExtensionRegistry::Get(profile())
878 ->enabled_extensions()
879 .GetByID(kId);
880
881 // Service worker version 2 would be installed but it won't be controlling
882 // the extension page yet.
883 ExtensionTestMessageListener listener2("Pong from version 1", false);
884 listener2.set_failure_message("FAILURE");
Istiaque Ahmed3f692562019-07-26 22:59:26885 web_contents = browsertest_util::AddTab(
886 browser(), extension_after_update->GetResourceURL("page.html"));
lazyboy22eddc712015-12-10 21:16:26887 EXPECT_TRUE(listener2.WaitUntilSatisfied());
888
889 // Navigate the tab away from the extension page so that no clients are
890 // using the service worker.
891 // Note that just closing the tab with WebContentsDestroyedWatcher doesn't
892 // seem to be enough because it returns too early.
893 WebContentsLoadStopObserver navigate_away_observer(web_contents);
894 web_contents->GetController().LoadURL(
895 GURL(url::kAboutBlankURL), content::Referrer(), ui::PAGE_TRANSITION_TYPED,
896 std::string());
897 navigate_away_observer.WaitForLoadStop();
898
899 // Now expect service worker version 2 to control the extension page.
900 ExtensionTestMessageListener listener3("Pong from version 2", false);
901 listener3.set_failure_message("FAILURE");
Istiaque Ahmed3f692562019-07-26 22:59:26902 web_contents = browsertest_util::AddTab(
903 browser(), extension_after_update->GetResourceURL("page.html"));
lazyboy22eddc712015-12-10 21:16:26904 EXPECT_TRUE(listener3.WaitUntilSatisfied());
905}
906
Devlin Cronin242d19d22019-03-12 18:08:48907IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, FetchArbitraryPaths) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22908 const Extension* extension = StartTestFromBackgroundPage("fetch.js");
annekao1db36fd2015-07-29 17:09:16909
kalman6f984ae2015-09-18 17:21:58910 // Open some arbirary paths. Their contents should be what the service worker
911 // responds with, which in this case is the path of the fetch.
912 EXPECT_EQ(
913 "Caught a fetch for /index.html",
914 NavigateAndExtractInnerText(extension->GetResourceURL("index.html")));
915 EXPECT_EQ("Caught a fetch for /path/to/other.html",
916 NavigateAndExtractInnerText(
917 extension->GetResourceURL("path/to/other.html")));
918 EXPECT_EQ("Caught a fetch for /some/text/file.txt",
919 NavigateAndExtractInnerText(
920 extension->GetResourceURL("some/text/file.txt")));
921 EXPECT_EQ("Caught a fetch for /no/file/extension",
922 NavigateAndExtractInnerText(
923 extension->GetResourceURL("no/file/extension")));
924 EXPECT_EQ("Caught a fetch for /",
925 NavigateAndExtractInnerText(extension->GetResourceURL("")));
annekao1db36fd2015-07-29 17:09:16926}
927
Devlin Cronin242d19d22019-03-12 18:08:48928IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
Kenichi Ishibashi773b82972018-08-30 07:02:03929 FetchExtensionResourceFromServiceWorker) {
Istiaque Ahmed93ff7f42018-08-31 01:42:22930 const Extension* extension = StartTestFromBackgroundPage("fetch_from_sw.js");
Kenichi Ishibashi773b82972018-08-30 07:02:03931 ASSERT_TRUE(extension);
932
933 // The service worker in this test tries to load 'hello.txt' via fetch()
934 // and sends back the content of the file, which should be 'hello'.
935 const char* kScript = R"(
936 let channel = new MessageChannel();
937 test.waitForMessage(channel.port1).then(message => {
938 window.domAutomationController.send(message);
939 });
940 test.registeredServiceWorker.postMessage(
941 {port: channel.port2}, [channel.port2]);
942 )";
943 EXPECT_EQ("hello", ExecuteScriptInBackgroundPage(extension->id(), kScript));
944}
945
Kenichi Ishibashi09ee5e72018-11-27 07:12:38946// Tests that fetch() from service worker and network fallback
947// go through webRequest.onBeforeRequest API.
Devlin Cronin242d19d22019-03-12 18:08:48948IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, OnBeforeRequest) {
Kenichi Ishibashi09ee5e72018-11-27 07:12:38949 const Extension* extension = LoadExtensionWithFlags(
950 test_data_dir_.AppendASCII("service_worker/webrequest"), kFlagNone);
951 ASSERT_TRUE(extension);
952 ASSERT_TRUE(StartEmbeddedTestServer());
953
954 // Start a service worker and make it control the page.
955 GURL page_url = embedded_test_server()->GetURL(
956 "/extensions/api_test/service_worker/"
957 "webrequest/webpage.html");
958 content::WebContents* web_contents =
959 browser()->tab_strip_model()->GetActiveWebContents();
960 ui_test_utils::NavigateToURL(browser(), page_url);
961 content::WaitForLoadStop(web_contents);
962
963 std::string result;
964 ASSERT_TRUE(content::ExecuteScriptAndExtractString(web_contents,
965 "register();", &result));
966 EXPECT_EQ("ready", result);
967
968 // Initiate a fetch that the service worker doesn't intercept
969 // (network fallback).
970 result.clear();
971 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
972 web_contents, "doFetch('hello.txt?fallthrough');", &result));
973 EXPECT_EQ("hello", result);
974 EXPECT_EQ(
975 "/extensions/api_test/service_worker/webrequest/hello.txt?fallthrough",
976 ExecuteScriptInBackgroundPage(extension->id(), "getLastHookedPath()"));
977
978 // Initiate a fetch that results in calling fetch() in the service worker.
979 result.clear();
980 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
981 web_contents, "doFetch('hello.txt?respondWithFetch');", &result));
982 EXPECT_EQ("hello", result);
983 EXPECT_EQ(
984 "/extensions/api_test/service_worker/webrequest/"
985 "hello.txt?respondWithFetch",
986 ExecuteScriptInBackgroundPage(extension->id(), "getLastHookedPath()"));
987}
988
Devlin Cronin242d19d22019-03-12 18:08:48989IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, SWServedBackgroundPageReceivesEvent) {
lazyboy52c3bcf2016-01-08 00:11:29990 const Extension* extension =
Istiaque Ahmed93ff7f42018-08-31 01:42:22991 StartTestFromBackgroundPage("replace_background.js");
lazyboy52c3bcf2016-01-08 00:11:29992 ExtensionHost* background_page =
993 process_manager()->GetBackgroundHostForExtension(extension->id());
994 ASSERT_TRUE(background_page);
995
996 // Close the background page and start it again so that the service worker
997 // will start controlling pages.
998 background_page->Close();
999 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
1000 background_page = nullptr;
Peter Kasting341e1fb2018-02-24 00:03:011001 process_manager()->WakeEventPage(extension->id(), base::DoNothing());
lazyboy52c3bcf2016-01-08 00:11:291002 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
1003
1004 // Since the SW is now controlling the extension, the SW serves the background
1005 // script. page.html sends a message to the background script and we verify
1006 // that the SW served background script correctly receives the message/event.
1007 ExtensionTestMessageListener listener("onMessage/SW BG.", false);
1008 listener.set_failure_message("onMessage/original BG.");
Istiaque Ahmed3f692562019-07-26 22:59:261009 content::WebContents* web_contents = browsertest_util::AddTab(
1010 browser(), extension->GetResourceURL("page.html"));
lazyboy52c3bcf2016-01-08 00:11:291011 ASSERT_TRUE(web_contents);
1012 EXPECT_TRUE(listener.WaitUntilSatisfied());
1013}
1014
Devlin Cronin242d19d22019-03-12 18:08:481015IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, SWServedBackgroundPage) {
Istiaque Ahmed93ff7f42018-08-31 01:42:221016 const Extension* extension = StartTestFromBackgroundPage("fetch.js");
annekao49241182015-08-18 17:14:011017
kalman6f984ae2015-09-18 17:21:581018 std::string kExpectedInnerText = "background.html contents for testing.";
annekao49241182015-08-18 17:14:011019
kalman6f984ae2015-09-18 17:21:581020 // Sanity check that the background page has the expected content.
1021 ExtensionHost* background_page =
1022 process_manager()->GetBackgroundHostForExtension(extension->id());
1023 ASSERT_TRUE(background_page);
1024 EXPECT_EQ(kExpectedInnerText,
1025 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:011026
kalman6f984ae2015-09-18 17:21:581027 // Close the background page.
1028 background_page->Close();
1029 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
1030 background_page = nullptr;
1031
1032 // Start it again.
Peter Kasting341e1fb2018-02-24 00:03:011033 process_manager()->WakeEventPage(extension->id(), base::DoNothing());
kalman6f984ae2015-09-18 17:21:581034 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
1035
Matt Falkenhagena612fc02018-05-30 00:35:391036 // The service worker should get a fetch event for the background page.
kalman6f984ae2015-09-18 17:21:581037 background_page =
1038 process_manager()->GetBackgroundHostForExtension(extension->id());
1039 ASSERT_TRUE(background_page);
1040 content::WaitForLoadStop(background_page->host_contents());
1041
kalman6f984ae2015-09-18 17:21:581042 EXPECT_EQ("Caught a fetch for /background.html",
1043 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:011044}
1045
Devlin Cronin242d19d22019-03-12 18:08:481046IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:581047 ServiceWorkerPostsMessageToBackgroundClient) {
Istiaque Ahmed93ff7f42018-08-31 01:42:221048 const Extension* extension =
1049 StartTestFromBackgroundPage("post_message_to_background_client.js");
annekao533482222015-08-21 23:23:531050
kalman6f984ae2015-09-18 17:21:581051 // The service worker in this test simply posts a message to the background
1052 // client it receives from getBackgroundClient().
1053 const char* kScript =
1054 "var messagePromise = null;\n"
1055 "if (test.lastMessageFromServiceWorker) {\n"
1056 " messagePromise = Promise.resolve(test.lastMessageFromServiceWorker);\n"
1057 "} else {\n"
1058 " messagePromise = test.waitForMessage(navigator.serviceWorker);\n"
1059 "}\n"
1060 "messagePromise.then(function(message) {\n"
1061 " window.domAutomationController.send(String(message == 'success'));\n"
1062 "})\n";
1063 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:531064}
1065
Devlin Cronin242d19d22019-03-12 18:08:481066IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:581067 BackgroundPagePostsMessageToServiceWorker) {
1068 const Extension* extension =
Istiaque Ahmed93ff7f42018-08-31 01:42:221069 StartTestFromBackgroundPage("post_message_to_sw.js");
annekao533482222015-08-21 23:23:531070
kalman6f984ae2015-09-18 17:21:581071 // The service worker in this test waits for a message, then echoes it back
1072 // by posting a message to the background page via getBackgroundClient().
1073 const char* kScript =
1074 "var mc = new MessageChannel();\n"
1075 "test.waitForMessage(mc.port1).then(function(message) {\n"
1076 " window.domAutomationController.send(String(message == 'hello'));\n"
1077 "});\n"
1078 "test.registeredServiceWorker.postMessage(\n"
1079 " {message: 'hello', port: mc.port2}, [mc.port2])\n";
1080 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:531081}
1082
Devlin Cronin242d19d22019-03-12 18:08:481083IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
rdevlin.croninf5863da2015-09-10 19:21:451084 ServiceWorkerSuspensionOnExtensionUnload) {
kalman6f984ae2015-09-18 17:21:581085 // For this test, only hold onto the extension's ID and URL + a function to
1086 // get a resource URL, because we're going to be disabling and uninstalling
1087 // it, which will invalidate the pointer.
1088 std::string extension_id;
1089 GURL extension_url;
1090 {
Istiaque Ahmed93ff7f42018-08-31 01:42:221091 const Extension* extension = StartTestFromBackgroundPage("fetch.js");
kalman6f984ae2015-09-18 17:21:581092 extension_id = extension->id();
1093 extension_url = extension->url();
1094 }
1095 auto get_resource_url = [&extension_url](const std::string& path) {
1096 return Extension::GetResourceURL(extension_url, path);
1097 };
rdevlin.croninf5863da2015-09-10 19:21:451098
kalman6f984ae2015-09-18 17:21:581099 // Fetch should route to the service worker.
1100 EXPECT_EQ("Caught a fetch for /index.html",
1101 NavigateAndExtractInnerText(get_resource_url("index.html")));
rdevlin.croninf5863da2015-09-10 19:21:451102
kalman6f984ae2015-09-18 17:21:581103 // Disable the extension. Opening the page should fail.
1104 extension_service()->DisableExtension(extension_id,
Minh X. Nguyen45479012017-08-18 21:35:361105 disable_reason::DISABLE_USER_ACTION);
rdevlin.croninf5863da2015-09-10 19:21:451106 base::RunLoop().RunUntilIdle();
rdevlin.croninf5863da2015-09-10 19:21:451107
kalman6f984ae2015-09-18 17:21:581108 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1109 NavigateAndGetPageType(get_resource_url("index.html")));
1110 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1111 NavigateAndGetPageType(get_resource_url("other.html")));
1112
1113 // Re-enable the extension. Opening pages should immediately start to succeed
1114 // again.
rdevlin.croninf5863da2015-09-10 19:21:451115 extension_service()->EnableExtension(extension_id);
1116 base::RunLoop().RunUntilIdle();
1117
kalman6f984ae2015-09-18 17:21:581118 EXPECT_EQ("Caught a fetch for /index.html",
1119 NavigateAndExtractInnerText(get_resource_url("index.html")));
1120 EXPECT_EQ("Caught a fetch for /other.html",
1121 NavigateAndExtractInnerText(get_resource_url("other.html")));
1122 EXPECT_EQ("Caught a fetch for /another.html",
1123 NavigateAndExtractInnerText(get_resource_url("another.html")));
rdevlin.croninf5863da2015-09-10 19:21:451124
kalman6f984ae2015-09-18 17:21:581125 // Uninstall the extension. Opening pages should fail again.
1126 base::string16 error;
1127 extension_service()->UninstallExtension(
Devlin Cronin218df7f2017-11-21 21:41:311128 extension_id, UninstallReason::UNINSTALL_REASON_FOR_TESTING, &error);
kalman6f984ae2015-09-18 17:21:581129 base::RunLoop().RunUntilIdle();
1130
1131 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1132 NavigateAndGetPageType(get_resource_url("index.html")));
1133 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1134 NavigateAndGetPageType(get_resource_url("other.html")));
1135 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1136 NavigateAndGetPageType(get_resource_url("anotherother.html")));
1137 EXPECT_EQ(content::PAGE_TYPE_ERROR,
1138 NavigateAndGetPageType(get_resource_url("final.html")));
1139}
1140
Devlin Cronin242d19d22019-03-12 18:08:481141IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, BackgroundPageIsWokenIfAsleep) {
Istiaque Ahmed93ff7f42018-08-31 01:42:221142 const Extension* extension = StartTestFromBackgroundPage("wake_on_fetch.js");
kalman6f984ae2015-09-18 17:21:581143
1144 // Navigate to special URLs that this test's service worker recognises, each
1145 // making a check then populating the response with either "true" or "false".
1146 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
1147 "background-client-is-awake")));
1148 EXPECT_EQ("true", NavigateAndExtractInnerText(
1149 extension->GetResourceURL("ping-background-client")));
1150 // Ping more than once for good measure.
1151 EXPECT_EQ("true", NavigateAndExtractInnerText(
1152 extension->GetResourceURL("ping-background-client")));
1153
1154 // Shut down the event page. The SW should detect that it's closed, but still
1155 // be able to ping it.
1156 ExtensionHost* background_page =
1157 process_manager()->GetBackgroundHostForExtension(extension->id());
1158 ASSERT_TRUE(background_page);
1159 background_page->Close();
1160 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
1161
1162 EXPECT_EQ("false", NavigateAndExtractInnerText(extension->GetResourceURL(
1163 "background-client-is-awake")));
1164 EXPECT_EQ("true", NavigateAndExtractInnerText(
1165 extension->GetResourceURL("ping-background-client")));
1166 EXPECT_EQ("true", NavigateAndExtractInnerText(
1167 extension->GetResourceURL("ping-background-client")));
1168 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
1169 "background-client-is-awake")));
1170}
1171
Devlin Cronin242d19d22019-03-12 18:08:481172IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:581173 GetBackgroundClientFailsWithNoBackgroundPage) {
1174 // This extension doesn't have a background page, only a tab at page.html.
1175 // The service worker it registers tries to call getBackgroundClient() and
1176 // should fail.
1177 // Note that this also tests that service workers can be registered from tabs.
1178 EXPECT_TRUE(RunExtensionSubtest("service_worker/no_background", "page.html"));
rdevlin.croninf5863da2015-09-10 19:21:451179}
1180
Devlin Cronin242d19d22019-03-12 18:08:481181IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, NotificationAPI) {
lazyboy6ddb7d62015-11-10 23:15:271182 EXPECT_TRUE(RunExtensionSubtest("service_worker/notifications/has_permission",
1183 "page.html"));
1184}
1185
Devlin Cronin242d19d22019-03-12 18:08:481186IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, WebAccessibleResourcesFetch) {
lazyboyaea32c22016-01-04 21:37:071187 EXPECT_TRUE(RunExtensionSubtest(
1188 "service_worker/web_accessible_resources/fetch/", "page.html"));
1189}
1190
David Bertoni9026eff2019-05-01 18:04:311191// Tests that updating a packed extension with modified scripts works
1192// properly -- we expect that the new script will execute, rather than the
1193// previous one.
1194IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, UpdatePackedExtension) {
1195 // Extensions APIs from SW are only enabled on trunk.
1196 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1197 constexpr char kManifest1[] =
1198 R"({
1199 "name": "Test Extension",
1200 "manifest_version": 2,
1201 "version": "0.1",
1202 "background": {"service_worker": "script.js"}
1203 })";
David Bertoni353f0fb42019-05-30 15:53:301204 constexpr char kNewVersionString[] = "0.2";
1205
David Bertoni9026eff2019-05-01 18:04:311206 // This script installs an event listener for updates to the extension with
1207 // a callback that forces itself to reload.
David Bertoni353f0fb42019-05-30 15:53:301208 constexpr char kScript1[] =
David Bertoni9026eff2019-05-01 18:04:311209 R"(
Matt Falkenhagend55b9282019-09-10 23:53:351210 addEventListener('activate', event => {
1211 // TODO(crbug.com/999027, crbug.com/984522): Delaying sending
1212 // 'ready1' until activation seems to reduce the flakiness described
1213 // in the bugs. It'd be better to fix the underlying bugs.
1214 chrome.test.sendMessage('ready1');
1215 });
1216
David Bertoni9026eff2019-05-01 18:04:311217 chrome.runtime.onUpdateAvailable.addListener(function(details) {
David Bertoni353f0fb42019-05-30 15:53:301218 chrome.test.assertEq('%s', details.version);
David Bertoni9026eff2019-05-01 18:04:311219 chrome.runtime.reload();
1220 });
David Bertoni9026eff2019-05-01 18:04:311221 )";
1222
1223 std::string id;
1224 TestExtensionDir test_dir;
1225
1226 // Write the manifest and script files and load the extension.
1227 test_dir.WriteManifest(kManifest1);
David Bertoni353f0fb42019-05-30 15:53:301228 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"),
1229 base::StringPrintf(kScript1, kNewVersionString));
David Bertoni9026eff2019-05-01 18:04:311230
1231 {
1232 ExtensionTestMessageListener ready_listener("ready1", false);
1233 base::FilePath path = test_dir.Pack();
1234 const Extension* extension = LoadExtension(path);
1235 ASSERT_TRUE(extension);
1236
1237 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
1238 id = extension->id();
1239 }
1240
1241 constexpr char kManifest2[] =
1242 R"({
1243 "name": "Test Extension",
1244 "manifest_version": 2,
David Bertoni353f0fb42019-05-30 15:53:301245 "version": "%s",
David Bertoni9026eff2019-05-01 18:04:311246 "background": {"service_worker": "script.js"}
1247 })";
David Bertoni353f0fb42019-05-30 15:53:301248 constexpr char kScript2[] =
1249 R"(
1250 chrome.runtime.onInstalled.addListener(function(details) {
1251 chrome.test.assertEq('update', details.reason);
1252 chrome.test.sendMessage('onInstalled');
1253 });
1254 chrome.test.sendMessage('ready2');
1255 )";
David Bertoni9026eff2019-05-01 18:04:311256 // Rewrite the manifest and script files with a version change in the manifest
1257 // file. After reloading the extension, the old version of the extension
1258 // should detect the update, force the reload, and the new script should
1259 // execute.
David Bertoni353f0fb42019-05-30 15:53:301260 test_dir.WriteManifest(base::StringPrintf(kManifest2, kNewVersionString));
1261 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"), kScript2);
David Bertoni9026eff2019-05-01 18:04:311262 {
1263 ExtensionTestMessageListener ready_listener("ready2", false);
David Bertoni353f0fb42019-05-30 15:53:301264 ExtensionTestMessageListener on_installed_listener("onInstalled", false);
David Bertoni9026eff2019-05-01 18:04:311265 base::FilePath path = test_dir.Pack();
1266 ExtensionService* const extension_service =
1267 ExtensionSystem::Get(profile())->extension_service();
1268 EXPECT_TRUE(extension_service->UpdateExtension(
1269 CRXFileInfo(id, GetTestVerifierFormat(), path), true, nullptr));
1270 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
1271 EXPECT_EQ("0.2", ExtensionRegistry::Get(profile())
1272 ->enabled_extensions()
1273 .GetByID(id)
1274 ->version()
1275 .GetString());
David Bertoni353f0fb42019-05-30 15:53:301276 EXPECT_TRUE(on_installed_listener.WaitUntilSatisfied());
David Bertoni9026eff2019-05-01 18:04:311277 }
1278}
1279
David Bertoni1d646a152019-04-25 02:09:221280// Tests that updating an unpacked extension with modified scripts works
1281// properly -- we expect that the new script will execute, rather than the
1282// previous one.
1283IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, UpdateUnpackedExtension) {
1284 // Extensions APIs from SW are only enabled on trunk.
1285 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1286 constexpr char kManifest1[] =
1287 R"({
1288 "name": "Test Extension",
1289 "manifest_version": 2,
1290 "version": "0.1",
1291 "background": {"service_worker": "script.js"}
1292 })";
1293 constexpr char kManifest2[] =
1294 R"({
1295 "name": "Test Extension",
1296 "manifest_version": 2,
1297 "version": "0.2",
1298 "background": {"service_worker": "script.js"}
1299 })";
David Bertoni353f0fb42019-05-30 15:53:301300 constexpr char kScript[] =
1301 R"(
Matt Falkenhagend55b9282019-09-10 23:53:351302 let activated;
1303 let installed;
1304
1305 addEventListener('activate', event => {
1306 activated = true;
1307 NotifyIfDone();
David Bertoni353f0fb42019-05-30 15:53:301308 });
Matt Falkenhagend55b9282019-09-10 23:53:351309
1310 chrome.runtime.onInstalled.addListener(function(details) {
1311 installed = true;
1312 chrome.test.assertEq('%s', details.reason);
1313 NotifyIfDone();
1314 });
1315
1316 // TODO(crbug.com/999027, crbug.com/984522): Delaying notification
1317 // until activation seems to reduce the flakiness described in the
1318 // bugs. It'd be better to fix the underlying bugs.
1319 function NotifyIfDone() {
1320 if (!activated || !installed)
1321 return;
1322 chrome.test.sendMessage('%s');
1323 chrome.test.sendMessage('onInstalled');
1324 }
David Bertoni353f0fb42019-05-30 15:53:301325 )";
David Bertoni1d646a152019-04-25 02:09:221326
1327 std::string id;
1328
1329 ExtensionService* const extension_service =
1330 ExtensionSystem::Get(profile())->extension_service();
1331 scoped_refptr<UnpackedInstaller> installer =
1332 UnpackedInstaller::Create(extension_service);
1333
1334 // Set a completion callback so we can get the ID of the extension.
1335 installer->set_completion_callback(base::BindLambdaForTesting(
1336 [&id](const Extension* extension, const base::FilePath& path,
1337 const std::string& error) {
1338 ASSERT_TRUE(extension);
1339 ASSERT_TRUE(error.empty());
1340 id = extension->id();
1341 }));
1342
1343 TestExtensionDir test_dir;
1344
1345 // Write the manifest and script files and load the extension.
1346 test_dir.WriteManifest(kManifest1);
1347 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"),
David Bertoni353f0fb42019-05-30 15:53:301348 base::StringPrintf(kScript, "install", "ready1"));
David Bertoni1d646a152019-04-25 02:09:221349 {
1350 ExtensionTestMessageListener ready_listener("ready1", false);
David Bertoni353f0fb42019-05-30 15:53:301351 ExtensionTestMessageListener on_installed_listener("onInstalled", false);
David Bertoni1d646a152019-04-25 02:09:221352
1353 installer->Load(test_dir.UnpackedPath());
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 ASSERT_FALSE(id.empty());
1357 }
1358
1359 // Rewrite the script file without a version change in the manifest and reload
1360 // the extension. The new script should execute.
1361 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"),
David Bertoni353f0fb42019-05-30 15:53:301362 base::StringPrintf(kScript, "update", "ready2"));
David Bertoni1d646a152019-04-25 02:09:221363 {
1364 ExtensionTestMessageListener ready_listener("ready2", false);
David Bertoni353f0fb42019-05-30 15:53:301365 ExtensionTestMessageListener on_installed_listener("onInstalled", false);
David Bertoni1d646a152019-04-25 02:09:221366
1367 extension_service->ReloadExtension(id);
1368 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
David Bertoni353f0fb42019-05-30 15:53:301369 EXPECT_TRUE(on_installed_listener.WaitUntilSatisfied());
David Bertoni1d646a152019-04-25 02:09:221370 }
1371
1372 // Rewrite the manifest and script files with a version change in the manifest
1373 // file. After reloading the extension, the new script should execute.
1374 test_dir.WriteManifest(kManifest2);
1375 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"),
David Bertoni353f0fb42019-05-30 15:53:301376 base::StringPrintf(kScript, "update", "ready3"));
David Bertoni1d646a152019-04-25 02:09:221377 {
1378 ExtensionTestMessageListener ready_listener("ready3", false);
David Bertoni353f0fb42019-05-30 15:53:301379 ExtensionTestMessageListener on_installed_listener("onInstalled", false);
David Bertoni1d646a152019-04-25 02:09:221380
1381 extension_service->ReloadExtension(id);
1382 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
David Bertoni353f0fb42019-05-30 15:53:301383 EXPECT_TRUE(on_installed_listener.WaitUntilSatisfied());
David Bertoni1d646a152019-04-25 02:09:221384 }
1385}
1386
lazyboyaea32c22016-01-04 21:37:071387// This test loads a web page that has an iframe pointing to a
1388// chrome-extension:// URL. The URL is listed in the extension's
1389// web_accessible_resources. Initially the iframe is served from the extension's
1390// resource file. After verifying that, we register a Service Worker that
1391// controls the extension. Further requests to the same resource as before
1392// should now be served by the Service Worker.
1393// This test also verifies that if the requested resource exists in the manifest
1394// but is not present in the extension directory, the Service Worker can still
1395// serve the resource file.
Devlin Cronin242d19d22019-03-12 18:08:481396IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, WebAccessibleResourcesIframeSrc) {
lazyboyaea32c22016-01-04 21:37:071397 const Extension* extension = LoadExtensionWithFlags(
1398 test_data_dir_.AppendASCII(
1399 "service_worker/web_accessible_resources/iframe_src"),
1400 kFlagNone);
1401 ASSERT_TRUE(extension);
1402 ASSERT_TRUE(StartEmbeddedTestServer());
falkenad185092016-06-16 06:10:021403
1404 // Service workers can only control secure contexts
1405 // (https://w3c.github.io/webappsec-secure-contexts/). For documents, this
1406 // typically means the document must have a secure origin AND all its ancestor
1407 // frames must have documents with secure origins. However, extension pages
1408 // are considered secure, even if they have an ancestor document that is an
1409 // insecure context (see GetSchemesBypassingSecureContextCheckWhitelist). So
1410 // extension service workers must be able to control an extension page
1411 // embedded in an insecure context. To test this, set up an insecure
1412 // (non-localhost, non-https) URL for the web page. This page will create
1413 // iframes that load extension pages that must be controllable by service
1414 // worker.
falkenad185092016-06-16 06:10:021415 GURL page_url =
1416 embedded_test_server()->GetURL("a.com",
1417 "/extensions/api_test/service_worker/"
1418 "web_accessible_resources/webpage.html");
1419 EXPECT_FALSE(content::IsOriginSecure(page_url));
lazyboyaea32c22016-01-04 21:37:071420
Istiaque Ahmed3f692562019-07-26 22:59:261421 content::WebContents* web_contents =
1422 browsertest_util::AddTab(browser(), page_url);
lazyboyaea32c22016-01-04 21:37:071423 std::string result;
1424 // webpage.html will create an iframe pointing to a resource from |extension|.
1425 // Expect the resource to be served by the extension.
1426 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1427 web_contents, base::StringPrintf("window.testIframe('%s', 'iframe.html')",
1428 extension->id().c_str()),
1429 &result));
1430 EXPECT_EQ("FROM_EXTENSION_RESOURCE", result);
1431
1432 ExtensionTestMessageListener service_worker_ready_listener("SW_READY", false);
1433 EXPECT_TRUE(ExecuteScriptInBackgroundPageNoWait(
1434 extension->id(), "window.registerServiceWorker()"));
1435 EXPECT_TRUE(service_worker_ready_listener.WaitUntilSatisfied());
1436
1437 result.clear();
1438 // webpage.html will create another iframe pointing to a resource from
1439 // |extension| as before. But this time, the resource should be be served
1440 // from the Service Worker.
1441 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1442 web_contents, base::StringPrintf("window.testIframe('%s', 'iframe.html')",
1443 extension->id().c_str()),
1444 &result));
1445 EXPECT_EQ("FROM_SW_RESOURCE", result);
1446
1447 result.clear();
1448 // webpage.html will create yet another iframe pointing to a resource that
1449 // exists in the extension manifest's web_accessible_resources, but is not
1450 // present in the extension directory. Expect the resources of the iframe to
1451 // be served by the Service Worker.
1452 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1453 web_contents,
1454 base::StringPrintf("window.testIframe('%s', 'iframe_non_existent.html')",
1455 extension->id().c_str()),
1456 &result));
1457 EXPECT_EQ("FROM_SW_RESOURCE", result);
1458}
1459
David Bertonide552de2019-06-28 19:51:261460// Verifies that service workers that aren't specified as the background script
1461// for the extension do not have extension API bindings.
1462IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, VerifyNoApiBindings) {
1463 // Extensions APIs from SW are only enabled on trunk.
1464 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1465 const Extension* extension = LoadExtensionWithFlags(
1466 test_data_dir_.AppendASCII("service_worker/verify_no_api_bindings"),
1467 kFlagNone);
1468 ASSERT_TRUE(extension);
1469 ui_test_utils::NavigateToURL(browser(),
1470 extension->GetResourceURL("page.html"));
1471 content::WebContents* web_contents =
1472 browser()->tab_strip_model()->GetActiveWebContents();
1473
1474 // Have the page script start the service worker and wait for that to
1475 // succeed.
1476 ExtensionTestMessageListener worker_start_listener("WORKER STARTED", false);
1477 worker_start_listener.set_failure_message("FAILURE");
1478 ASSERT_TRUE(
1479 content::ExecuteScript(web_contents, "window.runServiceWorker()"));
1480 ASSERT_TRUE(worker_start_listener.WaitUntilSatisfied());
1481
1482 // Kick off the test, which will check the available bindings and fail if
1483 // there is anything unexpected.
1484 ExtensionTestMessageListener worker_listener("SUCCESS", false);
1485 worker_listener.set_failure_message("FAILURE");
1486 ASSERT_TRUE(content::ExecuteScript(web_contents, "window.testSendMessage()"));
1487 EXPECT_TRUE(worker_listener.WaitUntilSatisfied());
1488}
1489
Devlin Cronin242d19d22019-03-12 18:08:481490IN_PROC_BROWSER_TEST_F(ServiceWorkerBackgroundSyncTest, Sync) {
lazyboybd325ae2015-11-18 21:35:261491 const Extension* extension = LoadExtensionWithFlags(
1492 test_data_dir_.AppendASCII("service_worker/sync"), kFlagNone);
1493 ASSERT_TRUE(extension);
1494 ui_test_utils::NavigateToURL(browser(),
1495 extension->GetResourceURL("page.html"));
1496 content::WebContents* web_contents =
1497 browser()->tab_strip_model()->GetActiveWebContents();
1498
1499 // Prevent firing by going offline.
1500 content::background_sync_test_util::SetOnline(web_contents, false);
1501
1502 ExtensionTestMessageListener sync_listener("SYNC: send-chats", false);
1503 sync_listener.set_failure_message("FAIL");
1504
1505 std::string result;
1506 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
1507 web_contents, "window.runServiceWorker()", &result));
1508 ASSERT_EQ("SERVICE_WORKER_READY", result);
1509
1510 EXPECT_FALSE(sync_listener.was_satisfied());
1511 // Resume firing by going online.
1512 content::background_sync_test_util::SetOnline(web_contents, true);
1513 EXPECT_TRUE(sync_listener.WaitUntilSatisfied());
1514}
1515
Devlin Cronin242d19d22019-03-12 18:08:481516IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
horo1eeddde2015-11-19 05:59:251517 FetchFromContentScriptShouldNotGoToServiceWorkerOfPage) {
1518 ASSERT_TRUE(StartEmbeddedTestServer());
1519 GURL page_url = embedded_test_server()->GetURL(
1520 "/extensions/api_test/service_worker/content_script_fetch/"
1521 "controlled_page/index.html");
1522 content::WebContents* tab =
1523 browser()->tab_strip_model()->GetActiveWebContents();
1524 ui_test_utils::NavigateToURL(browser(), page_url);
1525 content::WaitForLoadStop(tab);
1526
1527 std::string value;
1528 ASSERT_TRUE(
1529 content::ExecuteScriptAndExtractString(tab, "register();", &value));
1530 EXPECT_EQ("SW controlled", value);
1531
1532 ASSERT_TRUE(RunExtensionTest("service_worker/content_script_fetch"))
1533 << message_;
1534}
1535
Devlin Cronin242d19d22019-03-12 18:08:481536IN_PROC_BROWSER_TEST_F(ServiceWorkerPushMessagingTest, OnPush) {
lazyboy561b7de2015-11-19 19:27:301537 const Extension* extension = LoadExtensionWithFlags(
1538 test_data_dir_.AppendASCII("service_worker/push_messaging"), kFlagNone);
1539 ASSERT_TRUE(extension);
1540 GURL extension_url = extension->url();
1541
Peter Beverloodd4ef1e2018-06-21 15:41:041542 GrantNotificationPermissionForTest(extension_url);
lazyboy561b7de2015-11-19 19:27:301543
1544 GURL url = extension->GetResourceURL("page.html");
1545 ui_test_utils::NavigateToURL(browser(), url);
1546
1547 content::WebContents* web_contents =
1548 browser()->tab_strip_model()->GetActiveWebContents();
1549
1550 // Start the ServiceWorker.
1551 ExtensionTestMessageListener ready_listener("SERVICE_WORKER_READY", false);
1552 ready_listener.set_failure_message("SERVICE_WORKER_FAILURE");
1553 const char* kScript = "window.runServiceWorker()";
1554 EXPECT_TRUE(content::ExecuteScript(web_contents->GetMainFrame(), kScript));
1555 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
1556
1557 PushMessagingAppIdentifier app_identifier =
1558 GetAppIdentifierForServiceWorkerRegistration(0LL, extension_url);
johnmea5045732016-09-08 17:23:291559 ASSERT_EQ(app_identifier.app_id(), gcm_driver()->last_gettoken_app_id());
1560 EXPECT_EQ("1234567890", gcm_driver()->last_gettoken_authorized_entity());
lazyboy561b7de2015-11-19 19:27:301561
lazyboyd429e2582016-05-20 20:18:521562 base::RunLoop run_loop;
lazyboy561b7de2015-11-19 19:27:301563 // Send a push message via gcm and expect the ServiceWorker to receive it.
1564 ExtensionTestMessageListener push_message_listener("OK", false);
1565 push_message_listener.set_failure_message("FAIL");
1566 gcm::IncomingMessage message;
1567 message.sender_id = "1234567890";
1568 message.raw_data = "testdata";
1569 message.decrypted = true;
lazyboyd429e2582016-05-20 20:18:521570 push_service()->SetMessageCallbackForTesting(run_loop.QuitClosure());
lazyboy561b7de2015-11-19 19:27:301571 push_service()->OnMessage(app_identifier.app_id(), message);
1572 EXPECT_TRUE(push_message_listener.WaitUntilSatisfied());
lazyboyd429e2582016-05-20 20:18:521573 run_loop.Run(); // Wait until the message is handled by push service.
lazyboy561b7de2015-11-19 19:27:301574}
Devlin Cronin242d19d22019-03-12 18:08:481575IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, MimeHandlerView) {
Rob Wue89b90032018-02-16 19:46:081576 ASSERT_TRUE(RunExtensionTest("service_worker/mime_handler_view"));
1577}
1578
David Bertoni3b3597d82019-06-22 02:29:361579// An observer for service worker registration events.
1580class TestRegistrationObserver : public content::ServiceWorkerContextObserver {
David Bertoni22aeae52019-06-10 22:42:531581 public:
David Bertoni3b3597d82019-06-22 02:29:361582 using RegistrationsMap = std::map<GURL, int>;
1583
1584 explicit TestRegistrationObserver(content::ServiceWorkerContext* context)
1585 : context_(context) {
David Bertoni22aeae52019-06-10 22:42:531586 context_->AddObserver(this);
1587 }
1588
David Bertoni3b3597d82019-06-22 02:29:361589 ~TestRegistrationObserver() override {
David Bertoni22aeae52019-06-10 22:42:531590 if (context_) {
1591 context_->RemoveObserver(this);
1592 }
1593 }
1594
David Bertoni3b3597d82019-06-22 02:29:361595 // Wait for the first service worker registration with an extension scheme
1596 // scope to be stored.
1597 void WaitForRegistrationStored() { stored_run_loop_.Run(); }
1598
1599 int GetCompletedCount(const GURL& scope) const {
1600 const auto it = registrations_completed_map_.find(scope);
1601 return it == registrations_completed_map_.end() ? 0 : it->second;
1602 }
1603
1604 private:
1605 // ServiceWorkerContextObserver overrides.
1606 void OnRegistrationCompleted(const GURL& scope) override {
1607 ++registrations_completed_map_[scope];
1608 }
1609
David Bertoni22aeae52019-06-10 22:42:531610 void OnRegistrationStored(int64_t registration_id,
1611 const GURL& scope) override {
1612 if (scope.SchemeIs(kExtensionScheme)) {
David Bertoni3b3597d82019-06-22 02:29:361613 stored_run_loop_.Quit();
David Bertoni22aeae52019-06-10 22:42:531614 }
1615 }
1616
1617 void OnDestruct(content::ServiceWorkerContext* context) override {
1618 context_ = nullptr;
1619 }
1620
David Bertoni3b3597d82019-06-22 02:29:361621 RegistrationsMap registrations_completed_map_;
1622 base::RunLoop stored_run_loop_;
David Bertoni22aeae52019-06-10 22:42:531623 content::ServiceWorkerContext* context_;
David Bertoni22aeae52019-06-10 22:42:531624};
1625
1626IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
1627 EventsToStoppedWorker) {
1628 content::StoragePartition* storage_partition =
1629 content::BrowserContext::GetDefaultStoragePartition(browser()->profile());
1630 content::ServiceWorkerContext* context =
1631 storage_partition->GetServiceWorkerContext();
1632
1633 // Set up an observer to wait for the registration to be stored.
David Bertoni3b3597d82019-06-22 02:29:361634 TestRegistrationObserver observer(context);
David Bertoni22aeae52019-06-10 22:42:531635
1636 ExtensionTestMessageListener event_listener_added("ready", false);
1637 event_listener_added.set_failure_message("ERROR");
1638 const Extension* extension = LoadExtensionWithFlags(
1639 test_data_dir_.AppendASCII(
1640 "service_worker/worker_based_background/events_to_stopped_worker"),
1641 kFlagNone);
1642 ASSERT_TRUE(extension);
1643
David Bertoni3b3597d82019-06-22 02:29:361644 observer.WaitForRegistrationStored();
David Bertoni22aeae52019-06-10 22:42:531645 EXPECT_TRUE(event_listener_added.WaitUntilSatisfied());
1646
1647 // Stop the service worker.
1648 {
1649 base::RunLoop run_loop;
1650 // The service worker is registered at the root scope.
1651 content::StopServiceWorkerForScope(context, extension->url(),
1652 run_loop.QuitClosure());
1653 run_loop.Run();
1654 }
1655
1656 // Navigate to a URL, which should wake up the service worker.
1657 ExtensionTestMessageListener finished_listener("finished", false);
1658 ui_test_utils::NavigateToURL(browser(),
1659 extension->GetResourceURL("page.html"));
1660 EXPECT_TRUE(finished_listener.WaitUntilSatisfied());
1661}
1662
David Bertoniac01b942019-08-26 23:48:171663namespace {
1664
1665constexpr char kIncognitoManifest[] =
1666 R"({
1667 "name": "Incognito Test Extension",
1668 "version": "0.1",
1669 "manifest_version": 2,
1670 "permissions": ["tabs"],
1671 "background": {"service_worker": "worker.js"},
1672 "incognito": "%s"
1673 })";
1674
1675constexpr char kQueryWorkerScript[] =
1676 R"(var inIncognitoContext = chrome.extension.inIncognitoContext;
1677 var incognitoStr =
1678 inIncognitoContext ? 'incognito' : 'regular';
1679 chrome.test.sendMessage('Script started ' + incognitoStr, function() {
1680 chrome.tabs.query({}, function(tabs) {
1681 let urls = tabs.map(tab => tab.url);
1682 chrome.test.sendMessage(JSON.stringify(urls));
1683 });
1684 });)";
1685
1686constexpr char kTabsOnUpdatedScript[] =
1687 R"(var inIncognitoContext = chrome.extension.inIncognitoContext;
1688 var incognitoStr =
1689 inIncognitoContext ? 'incognito' : 'regular';
1690 var urls = [];
1691
1692 chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
1693 if (changeInfo.status === 'complete') {
1694 urls.push(tab.url);
1695 }
1696 });
1697
1698 chrome.test.sendMessage('Script started ' + incognitoStr, function() {
1699 chrome.test.sendMessage(JSON.stringify(urls));
1700 });)";
1701
1702} // anonymous namespace
1703
1704IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, TabsQuerySplit) {
1705 ExtensionTestMessageListener ready_regular("Script started regular", true);
1706 ExtensionTestMessageListener ready_incognito("Script started incognito",
1707 true);
1708 // Open an incognito window.
1709 Browser* browser_incognito =
1710 OpenURLOffTheRecord(browser()->profile(), GURL("about:blank"));
1711 ASSERT_TRUE(browser_incognito);
1712
1713 TestExtensionDir test_dir;
1714 test_dir.WriteManifest(base::StringPrintf(kIncognitoManifest, "split"));
1715 test_dir.WriteFile(FILE_PATH_LITERAL("worker.js"), kQueryWorkerScript);
1716
1717 const Extension* extension = LoadExtensionIncognito(test_dir.UnpackedPath());
1718 ASSERT_TRUE(extension);
1719
1720 // Wait for the extension's service workers to be ready.
1721 ASSERT_TRUE(ready_regular.WaitUntilSatisfied());
1722 ASSERT_TRUE(ready_incognito.WaitUntilSatisfied());
1723
1724 // Load a new tab in both browsers.
1725 ui_test_utils::NavigateToURL(browser(), GURL("chrome:version"));
1726 ui_test_utils::NavigateToURL(browser_incognito, GURL("chrome:about"));
1727
1728 {
1729 ExtensionTestMessageListener tabs_listener(false);
1730 // The extension waits for the reply to the "ready" sendMessage call
1731 // and replies with the URLs of the tabs.
1732 ready_regular.Reply("");
1733 EXPECT_TRUE(tabs_listener.WaitUntilSatisfied());
1734 EXPECT_EQ(R"(["chrome://version/"])", tabs_listener.message());
1735 }
1736 {
1737 ExtensionTestMessageListener tabs_listener(false);
1738 // Reply to the original message and wait for the return message.
1739 ready_incognito.Reply("");
1740 EXPECT_TRUE(tabs_listener.WaitUntilSatisfied());
1741 EXPECT_EQ(R"(["chrome://about/"])", tabs_listener.message());
1742 }
1743}
1744
1745IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, TabsQuerySpanning) {
1746 ExtensionTestMessageListener ready_listener("Script started regular", true);
1747
1748 // Open an incognito window.
1749 Browser* browser_incognito =
1750 OpenURLOffTheRecord(browser()->profile(), GURL("about:blank"));
1751 ASSERT_TRUE(browser_incognito);
1752
1753 TestExtensionDir test_dir;
1754 test_dir.WriteManifest(base::StringPrintf(kIncognitoManifest, "spanning"));
1755 test_dir.WriteFile(FILE_PATH_LITERAL("worker.js"), kQueryWorkerScript);
1756
1757 const Extension* extension = LoadExtensionIncognito(test_dir.UnpackedPath());
1758 ASSERT_TRUE(extension);
1759
1760 // Wait for the extension's service worker to be ready.
1761 ASSERT_TRUE(ready_listener.WaitUntilSatisfied());
1762
1763 // Load a new tab in both browsers.
1764 ui_test_utils::NavigateToURL(browser(), GURL("chrome:version"));
1765 ui_test_utils::NavigateToURL(browser_incognito, GURL("chrome:about"));
1766
1767 ExtensionTestMessageListener tabs_listener(false);
1768 // The extension waits for the reply to the "ready" sendMessage call
1769 // and replies with the URLs of the tabs.
1770 ready_listener.Reply("");
1771 EXPECT_TRUE(tabs_listener.WaitUntilSatisfied());
1772 EXPECT_EQ(R"(["chrome://version/","chrome://about/"])",
1773 tabs_listener.message());
1774}
1775
1776IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, TabsOnUpdatedSplit) {
1777 ExtensionTestMessageListener ready_regular("Script started regular", true);
1778 ExtensionTestMessageListener ready_incognito("Script started incognito",
1779 true);
1780 // Open an incognito window.
1781 Browser* browser_incognito =
1782 OpenURLOffTheRecord(browser()->profile(), GURL("about:blank"));
1783 ASSERT_TRUE(browser_incognito);
1784
1785 TestExtensionDir test_dir;
1786 test_dir.WriteManifest(base::StringPrintf(kIncognitoManifest, "split"));
1787 test_dir.WriteFile(FILE_PATH_LITERAL("worker.js"), kTabsOnUpdatedScript);
1788
1789 const Extension* extension = LoadExtensionIncognito(test_dir.UnpackedPath());
1790 ASSERT_TRUE(extension);
1791
1792 // Wait for the extension's service workers to be ready.
1793 ASSERT_TRUE(ready_regular.WaitUntilSatisfied());
1794 ASSERT_TRUE(ready_incognito.WaitUntilSatisfied());
1795
1796 // Load a new tab in both browsers.
1797 ui_test_utils::NavigateToURL(browser(), GURL("chrome:version"));
1798 ui_test_utils::NavigateToURL(browser_incognito, GURL("chrome:about"));
1799
1800 {
1801 ExtensionTestMessageListener tabs_listener(false);
1802 // The extension waits for the reply to the "ready" sendMessage call
1803 // and replies with the URLs of the tabs.
1804 ready_regular.Reply("");
1805 EXPECT_TRUE(tabs_listener.WaitUntilSatisfied());
1806 EXPECT_EQ(R"(["chrome://version/"])", tabs_listener.message());
1807 }
1808 {
1809 ExtensionTestMessageListener tabs_listener(false);
1810 // The extension waits for the reply to the "ready" sendMessage call
1811 // and replies with the URLs of the tabs.
1812 ready_incognito.Reply("");
1813 EXPECT_TRUE(tabs_listener.WaitUntilSatisfied());
1814 EXPECT_EQ(R"(["chrome://about/"])", tabs_listener.message());
1815 }
1816}
1817
Makoto Shimazu3a69e2e42019-09-12 07:18:251818// Disabled due to flakiness: https://crbug.com/1003244.
David Bertoniac01b942019-08-26 23:48:171819IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
Makoto Shimazu3a69e2e42019-09-12 07:18:251820 DISABLED_TabsOnUpdatedSpanning) {
David Bertoniac01b942019-08-26 23:48:171821 ExtensionTestMessageListener ready_listener("Script started regular", true);
1822
1823 // Open an incognito window.
1824 Browser* browser_incognito =
1825 OpenURLOffTheRecord(browser()->profile(), GURL("about:blank"));
1826 ASSERT_TRUE(browser_incognito);
1827
1828 TestExtensionDir test_dir;
1829 test_dir.WriteManifest(base::StringPrintf(kIncognitoManifest, "spanning"));
1830 test_dir.WriteFile(FILE_PATH_LITERAL("worker.js"), kTabsOnUpdatedScript);
1831
1832 const Extension* extension = LoadExtensionIncognito(test_dir.UnpackedPath());
1833 ASSERT_TRUE(extension);
1834
1835 // Wait for the extension's service worker to be ready.
1836 ASSERT_TRUE(ready_listener.WaitUntilSatisfied());
1837
1838 // Load a new tab in both browsers.
1839 ui_test_utils::NavigateToURL(browser(), GURL("chrome:version"));
1840 ui_test_utils::NavigateToURL(browser_incognito, GURL("chrome:about"));
1841
1842 ExtensionTestMessageListener tabs_listener(false);
1843 // The extension waits for the reply to the "ready" sendMessage call
1844 // and replies with the URLs of the tabs.
1845 ready_listener.Reply("");
1846 EXPECT_TRUE(tabs_listener.WaitUntilSatisfied());
1847 EXPECT_EQ(R"(["chrome://version/","chrome://about/"])",
1848 tabs_listener.message());
1849}
1850
David Bertoni3b3597d82019-06-22 02:29:361851// Tests the restriction on registering service worker scripts at root scope.
1852IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
1853 ServiceWorkerScriptRootScope) {
1854 content::StoragePartition* storage_partition =
1855 content::BrowserContext::GetDefaultStoragePartition(browser()->profile());
1856 content::ServiceWorkerContext* context =
1857 storage_partition->GetServiceWorkerContext();
1858
1859 // Set up an observer to track all SW registrations. We expect only
1860 // one for the extension's root scope. This test attempts to register
1861 // an additional service worker, which will fail.
1862 TestRegistrationObserver observer(context);
1863 ExtensionTestMessageListener registration_listener("REGISTRATION_FAILED",
1864 false);
1865 registration_listener.set_failure_message("WORKER_STARTED");
1866 const Extension* extension = LoadExtensionWithFlags(
1867 test_data_dir_.AppendASCII(
1868 "service_worker/worker_based_background/script_root_scope"),
1869 kFlagNone);
1870 ASSERT_TRUE(extension);
1871
1872 EXPECT_TRUE(registration_listener.WaitUntilSatisfied());
1873 // We expect exactly one registration, which is the one specified in the
1874 // manifest.
1875 EXPECT_EQ(1, observer.GetCompletedCount(extension->url()));
1876}
1877
Devlin Cronin242d19d22019-03-12 18:08:481878IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
Istiaque Ahmedd4b67ee2019-03-02 10:53:201879 ProcessManagerRegistrationOnShutdown) {
1880 // Note that StopServiceWorkerForScope call below expects the worker to be
1881 // completely installed, so wait for the |extension| worker to see "activate"
1882 // event.
1883 ExtensionTestMessageListener activated_listener("WORKER_ACTIVATED", false);
1884 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
1885 "service_worker/worker_based_background/process_manager"));
1886 ASSERT_TRUE(extension);
1887 EXPECT_TRUE(activated_listener.WaitUntilSatisfied());
1888
1889 base::Optional<WorkerId> worker_id =
1890 GetUniqueRunningWorkerId(extension->id());
1891 ASSERT_TRUE(worker_id);
1892 {
1893 // Shutdown the worker.
1894 // TODO(lazyboy): Ideally we'd want to test worker shutdown on idle, do that
1895 // once //content API allows to override test timeouts for Service Workers.
1896 base::RunLoop run_loop;
1897 content::StoragePartition* storage_partition =
1898 content::BrowserContext::GetDefaultStoragePartition(
1899 browser()->profile());
1900 GURL scope = extension->url();
1901 content::StopServiceWorkerForScope(
1902 storage_partition->GetServiceWorkerContext(),
1903 // The service worker is registered at the top level scope.
1904 extension->url(), run_loop.QuitClosure());
1905 run_loop.Run();
1906 }
1907
1908 EXPECT_FALSE(ProcessManager::Get(profile())->HasServiceWorker(*worker_id));
1909}
1910
Devlin Cronin242d19d22019-03-12 18:08:481911IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
Istiaque Ahmedd4b67ee2019-03-02 10:53:201912 ProcessManagerRegistrationOnTerminate) {
1913 // NOTE: It is not necessary to wait for "activate" event from the worker
1914 // for this test, but we're lazily reusing the extension from
1915 // ProcessManagerRegistrationOnShutdown test.
1916 ExtensionTestMessageListener activated_listener("WORKER_ACTIVATED", false);
1917 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
1918 "service_worker/worker_based_background/process_manager"));
1919 ASSERT_TRUE(extension);
1920 EXPECT_TRUE(activated_listener.WaitUntilSatisfied());
1921
1922 base::Optional<WorkerId> worker_id =
1923 GetUniqueRunningWorkerId(extension->id());
1924 ASSERT_TRUE(worker_id);
1925 {
1926 // Terminate worker's RenderProcessHost.
1927 content::RenderProcessHost* worker_render_process_host =
1928 content::RenderProcessHost::FromID(worker_id->render_process_id);
1929 ASSERT_TRUE(worker_render_process_host);
1930 content::RenderProcessHostWatcher process_exit_observer(
1931 worker_render_process_host,
1932 content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1933 worker_render_process_host->Shutdown(content::RESULT_CODE_KILLED);
1934 process_exit_observer.Wait();
1935 }
1936
1937 EXPECT_FALSE(ProcessManager::Get(profile())->HasServiceWorker(*worker_id));
1938}
1939
David Bertoni904dd602019-06-24 21:42:091940// Tests that worker ref count increments while extension API function is
1941// active.
1942IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, WorkerRefCount) {
1943 ExtensionTestMessageListener worker_start_listener("WORKER STARTED", false);
1944
1945 const Extension* extension = LoadExtensionWithFlags(
1946 test_data_dir_.AppendASCII(
1947 "service_worker/worker_based_background/worker_ref_count"),
1948 kFlagNone);
1949 ASSERT_TRUE(extension);
1950 ASSERT_TRUE(worker_start_listener.WaitUntilSatisfied());
1951
1952 ui_test_utils::NavigateToURL(browser(),
1953 extension->GetResourceURL("page.html"));
1954 content::WebContents* web_contents =
1955 browser()->tab_strip_model()->GetActiveWebContents();
1956
1957 // Service worker should have no pending requests because it hasn't performed
1958 // any extension API request yet.
1959 EXPECT_EQ(0u, GetWorkerRefCount(extension->url()));
1960
1961 ExtensionTestMessageListener worker_listener("CHECK_REF_COUNT", true);
1962 worker_listener.set_failure_message("FAILURE");
1963 ASSERT_TRUE(content::ExecuteScript(web_contents, "window.testSendMessage()"));
1964 ASSERT_TRUE(worker_listener.WaitUntilSatisfied());
1965
1966 // Service worker should have exactly one pending request because
1967 // chrome.test.sendMessage() API call is in-flight.
1968 EXPECT_EQ(1u, GetWorkerRefCount(extension->url()));
1969
1970 // Perform another extension API request while one is ongoing.
1971 {
1972 ExtensionTestMessageListener listener("CHECK_REF_COUNT", true);
1973 listener.set_failure_message("FAILURE");
1974 ASSERT_TRUE(
1975 content::ExecuteScript(web_contents, "window.testSendMessage()"));
1976 ASSERT_TRUE(listener.WaitUntilSatisfied());
1977
1978 // Service worker currently has two extension API requests in-flight.
1979 EXPECT_EQ(2u, GetWorkerRefCount(extension->url()));
1980 // Finish executing the nested chrome.test.sendMessage() first.
1981 listener.Reply("Hello world");
1982 }
1983
1984 ExtensionTestMessageListener worker_completion_listener("SUCCESS_FROM_WORKER",
1985 false);
1986 // Finish executing chrome.test.sendMessage().
1987 worker_listener.Reply("Hello world");
1988 EXPECT_TRUE(worker_completion_listener.WaitUntilSatisfied());
1989
1990 // The following block makes sure we have received all the IPCs related to
1991 // ref-count from the worker.
1992 {
1993 // The following roundtrip:
1994 // browser->extension->worker->extension->browser
1995 // will ensure that the worker sent the relevant ref count IPCs.
1996 std::string result;
1997 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1998 web_contents, "window.roundtripToWorker();", &result));
1999 EXPECT_EQ("roundtrip-succeeded", result);
2000
2001 // Ensure IO thread IPCs run.
2002 content::RunAllTasksUntilIdle();
2003 }
2004
2005 // The ref count should drop to 0.
2006 EXPECT_EQ(0u, GetWorkerRefCount(extension->url()));
2007}
2008
David Bertoni4d9cf41d2019-06-04 00:06:222009IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
2010 PRE_EventsAfterRestart) {
2011 ExtensionTestMessageListener event_added_listener("ready", false);
2012 const Extension* extension = LoadExtensionWithFlags(
2013 test_data_dir_.AppendASCII(
2014 "service_worker/worker_based_background/events_to_stopped_extension"),
2015 kFlagNone);
2016 ASSERT_TRUE(extension);
2017 EXPECT_EQ(kTestExtensionId, extension->id());
2018 ProcessManager* pm = ProcessManager::Get(browser()->profile());
2019 // TODO(crbug.com/969884): This will break once keep alive counts
2020 // for service workers are tracked by the Process Manager.
2021 EXPECT_LT(pm->GetLazyKeepaliveCount(extension), 1);
2022 EXPECT_TRUE(pm->GetLazyKeepaliveActivities(extension).empty());
2023 EXPECT_TRUE(event_added_listener.WaitUntilSatisfied());
2024}
2025
2026// After browser restarts, this test step ensures that opening a tab fires
2027// tabs.onCreated event listener to the extension without explicitly loading the
2028// extension. This is because the extension registered a listener for
2029// tabs.onMoved before browser restarted in PRE_EventsAfterRestart.
2030IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, EventsAfterRestart) {
2031 // Verify there is no RenderProcessHost for the extension.
David Bertoni023e0ec2019-06-10 17:28:222032 EXPECT_FALSE(ExtensionHasRenderProcessHost(kTestExtensionId));
David Bertoni4d9cf41d2019-06-04 00:06:222033
2034 ExtensionTestMessageListener moved_tab_listener("moved-tab", false);
2035 // Add a tab, then move it.
2036 content::WebContents* new_web_contents =
Istiaque Ahmed3f692562019-07-26 22:59:262037 browsertest_util::AddTab(browser(), GURL(url::kAboutBlankURL));
David Bertoni4d9cf41d2019-06-04 00:06:222038 EXPECT_TRUE(new_web_contents);
2039 browser()->tab_strip_model()->MoveWebContentsAt(
2040 browser()->tab_strip_model()->count() - 1, 0, false);
2041 EXPECT_TRUE(moved_tab_listener.WaitUntilSatisfied());
2042}
2043
Istiaque Ahmed1e59aec2019-06-05 22:40:242044IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, TabsOnCreated) {
2045 ASSERT_TRUE(RunExtensionTestWithFlags("tabs/lazy_background_on_created",
2046 kFlagRunAsServiceWorkerBasedExtension))
2047 << message_;
2048}
2049
Makoto Shimazu3a69e2e42019-09-12 07:18:252050// Disabled due to flakiness: https://crbug.com/1003244.
David Bertoni023e0ec2019-06-10 17:28:222051IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
Makoto Shimazu3a69e2e42019-09-12 07:18:252052 DISABLED_PRE_FilteredEventsAfterRestart) {
David Bertoni023e0ec2019-06-10 17:28:222053 ExtensionTestMessageListener listener_added("ready", false);
2054 const Extension* extension = LoadExtensionWithFlags(
2055 test_data_dir_.AppendASCII("service_worker/worker_based_background/"
2056 "filtered_events_after_restart"),
2057 kFlagNone);
2058 ASSERT_TRUE(extension);
2059 EXPECT_EQ(kTestExtensionId, extension->id());
2060 ProcessManager* pm = ProcessManager::Get(browser()->profile());
2061 // TODO(crbug.com/969884): This will break once keep alive counts
2062 // for service workers are tracked by the Process Manager.
2063 EXPECT_LT(pm->GetLazyKeepaliveCount(extension), 1);
2064 EXPECT_TRUE(pm->GetLazyKeepaliveActivities(extension).empty());
2065 EXPECT_TRUE(listener_added.WaitUntilSatisfied());
2066}
2067
2068// After browser restarts, this test step ensures that opening a tab fires
2069// tabs.onCreated event listener to the extension without explicitly loading the
2070// extension. This is because the extension registered a listener for
2071// tabs.onMoved before browser restarted in PRE_EventsAfterRestart.
Makoto Shimazu3a69e2e42019-09-12 07:18:252072//
2073// Disabled due to flakiness: https://crbug.com/1003244.
David Bertoni023e0ec2019-06-10 17:28:222074IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
Makoto Shimazu3a69e2e42019-09-12 07:18:252075 DISABLED_FilteredEventsAfterRestart) {
David Bertoni023e0ec2019-06-10 17:28:222076 // Verify there is no RenderProcessHost for the extension.
2077 // TODO(crbug.com/971309): This is currently broken because the test
2078 // infrastructure opens a tab, which dispatches an event to our
2079 // extension, even though the filter doesn't include that URL. The
2080 // referenced bug is about moving filtering into the EventRouter so they
2081 // get filtered before being dispatched.
2082 EXPECT_TRUE(ExtensionHasRenderProcessHost(kTestExtensionId));
2083
2084 // Create a tab to a.html, expect it to navigate to b.html. The service worker
2085 // will see two webNavigation.onCommitted events.
2086 GURL page_url = embedded_test_server()->GetURL(
2087 "/extensions/api_test/service_worker/worker_based_background/"
2088 "filtered_events_after_restart/"
2089 "a.html");
2090 ExtensionTestMessageListener worker_filtered_event_listener(
2091 "PASS_FROM_WORKER", false);
2092 worker_filtered_event_listener.set_failure_message("FAIL_FROM_WORKER");
Istiaque Ahmed3f692562019-07-26 22:59:262093 content::WebContents* web_contents =
2094 browsertest_util::AddTab(browser(), page_url);
David Bertoni023e0ec2019-06-10 17:28:222095 EXPECT_TRUE(web_contents);
2096 EXPECT_TRUE(worker_filtered_event_listener.WaitUntilSatisfied());
2097}
2098
Istiaque Ahmed91d6987c2019-06-25 00:09:332099// Tests that chrome.browserAction.onClicked sees user gesture.
2100IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
2101 BrowserActionUserGesture) {
2102 // First, load |extension| first so that it has browserAction.onClicked
2103 // listener registered.
2104 ExtensionTestMessageListener listener_added("ready", false);
2105 const Extension* extension = LoadExtension(
2106 test_data_dir_.AppendASCII("service_worker/worker_based_background/"
2107 "browser_action"));
2108 ASSERT_TRUE(extension);
2109 EXPECT_TRUE(listener_added.WaitUntilSatisfied());
2110
2111 ResultCatcher catcher;
2112 // Click on browser action to start the test.
2113 {
Istiaque Ahmed3f692562019-07-26 22:59:262114 content::WebContents* web_contents =
2115 browsertest_util::AddTab(browser(), GURL("about:blank"));
Istiaque Ahmed91d6987c2019-06-25 00:09:332116 ASSERT_TRUE(web_contents);
2117 ExtensionActionRunner::GetForWebContents(
2118 browser()->tab_strip_model()->GetActiveWebContents())
2119 ->RunAction(extension, true);
2120 }
2121 EXPECT_TRUE(catcher.GetNextResult()) << message_;
2122}
2123
Istiaque Ahmed242a4102019-06-25 01:47:572124// Tests that Service Worker notification handlers can call extension APIs that
2125// require user gesture to be present.
2126IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTestWithNotification,
2127 ServiceWorkerNotificationClick) {
2128 ResultCatcher catcher;
2129 const Extension* extension = LoadExtension(
2130 test_data_dir_.AppendASCII("service_worker/worker_based_background/"
2131 "notification_click"));
2132 ASSERT_TRUE(extension);
2133 EXPECT_TRUE(catcher.GetNextResult()) << message_;
2134
2135 // Click on the Service Worker notification.
2136 {
2137 std::vector<message_center::Notification> notifications =
2138 GetDisplayedNotifications();
2139 ASSERT_EQ(1u, notifications.size());
2140 display_service_tester_->SimulateClick(
2141 NotificationHandler::Type::WEB_PERSISTENT, notifications[0].id(),
2142 base::nullopt, base::nullopt);
2143 }
2144
2145 EXPECT_TRUE(catcher.GetNextResult()) << message_;
2146}
2147
Istiaque Ahmed3dd604232019-08-02 19:22:212148// Tests chrome.permissions.request API.
2149IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, PermissionsAPI) {
2150 // First, load |extension| first so that it has browserAction.onClicked
2151 // listener registered.
2152 ExtensionTestMessageListener worker_listener("ready", false);
2153 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
2154 "service_worker/worker_based_background/permissions_api"));
2155 ASSERT_TRUE(extension);
2156 const ExtensionId extension_id = extension->id();
2157 EXPECT_TRUE(worker_listener.WaitUntilSatisfied());
2158
2159 // "storage" permission is optional in |extension|, and isn't available right
2160 // away.
2161 EXPECT_FALSE(
2162 extension->permissions_data()->HasAPIPermission(APIPermission::kStorage));
2163
2164 PermissionsRequestFunction::SetAutoConfirmForTests(true);
2165
2166 ResultCatcher catcher;
2167 // Click on browser action to start the test.
2168 {
2169 content::WebContents* web_contents =
2170 browsertest_util::AddTab(browser(), GURL("about:blank"));
2171 ASSERT_TRUE(web_contents);
2172 ExtensionActionRunner::GetForWebContents(
2173 browser()->tab_strip_model()->GetActiveWebContents())
2174 ->RunAction(extension, true);
2175 }
2176 EXPECT_TRUE(catcher.GetNextResult()) << message_;
2177
2178 // Expect the permission ("storage") to be available now.
2179 EXPECT_TRUE(
2180 extension->permissions_data()->HasAPIPermission(APIPermission::kStorage));
2181}
2182
Devlin Cronin59551d82019-03-05 01:28:592183// Tests that console messages logged by extension service workers, both via
2184// the typical console.* methods and via our custom bindings console, are
2185// passed through the normal ServiceWorker console messaging and are
2186// observable.
Devlin Cronin242d19d22019-03-12 18:08:482187IN_PROC_BROWSER_TEST_F(ServiceWorkerLazyBackgroundTest, ConsoleLogging) {
Devlin Cronin59551d82019-03-05 01:28:592188 // A helper class to wait for a particular message to be logged from a
2189 // ServiceWorker.
2190 class ConsoleMessageObserver : public content::ServiceWorkerContextObserver {
2191 public:
2192 ConsoleMessageObserver(content::BrowserContext* browser_context,
2193 const std::string& expected_message)
2194 : expected_message_(base::UTF8ToUTF16(expected_message)),
2195 scoped_observer_(this) {
2196 content::StoragePartition* partition =
2197 content::BrowserContext::GetDefaultStoragePartition(browser_context);
2198 scoped_observer_.Add(partition->GetServiceWorkerContext());
2199 }
2200 ~ConsoleMessageObserver() override = default;
2201
2202 void Wait() { run_loop_.Run(); }
2203
2204 private:
2205 // ServiceWorkerContextObserver:
2206 void OnReportConsoleMessage(
2207 int64_t version_id,
2208 const content::ConsoleMessage& message) override {
2209 // NOTE: We could check the version_id, but it shouldn't be necessary with
2210 // the expected messages we're verifying (they're uncommon enough).
2211 if (message.message != expected_message_)
2212 return;
2213 scoped_observer_.RemoveAll();
2214 run_loop_.QuitWhenIdle();
2215 }
2216
2217 base::string16 expected_message_;
2218 base::RunLoop run_loop_;
2219 ScopedObserver<content::ServiceWorkerContext,
2220 content::ServiceWorkerContextObserver>
2221 scoped_observer_;
2222
2223 DISALLOW_COPY_AND_ASSIGN(ConsoleMessageObserver);
2224 };
2225
2226 TestExtensionDir test_dir;
2227 test_dir.WriteManifest(
2228 R"({
2229 "name": "Test Extension",
2230 "manifest_version": 2,
2231 "version": "0.1",
David Bertoni630837d2019-04-02 21:22:102232 "background": {"service_worker": "script.js"}
Devlin Cronin59551d82019-03-05 01:28:592233 })");
2234 constexpr char kScript[] =
2235 R"(// First, log a message using the normal, built-in blink console.
2236 console.log('test message');
2237 chrome.test.runTests([
2238 function justATest() {
2239 // Next, we use the "Console" object from
2240 // extensions/renderer/console.cc, which is used by custom bindings
2241 // so that it isn't tampered with by untrusted script. The test
2242 // custom bindings log a message whenever a test is passed, so we
2243 // force a log by just passing this test.
2244 chrome.test.succeed();
2245 }
2246 ]);)";
2247 test_dir.WriteFile(FILE_PATH_LITERAL("script.js"), kScript);
2248
2249 // The observer for the built-in blink console.
2250 ConsoleMessageObserver default_console_observer(profile(), "test message");
2251 // The observer for our custom extensions bindings console.
2252 ConsoleMessageObserver custom_console_observer(profile(),
2253 "[SUCCESS] justATest");
2254
2255 const Extension* extension = LoadExtension(test_dir.UnpackedPath());
2256 ASSERT_TRUE(extension);
2257
2258 default_console_observer.Wait();
2259 custom_console_observer.Wait();
2260 // If we receive both messages, we passed!
2261}
2262
David Bertoni98a5da72019-08-23 23:38:222263class ServiceWorkerCheckBindingsTest
2264 : public ServiceWorkerTest,
2265 public testing::WithParamInterface<version_info::Channel> {
2266 public:
2267 ServiceWorkerCheckBindingsTest() : ServiceWorkerTest(GetParam()) {}
2268 ~ServiceWorkerCheckBindingsTest() override {}
2269
2270 private:
2271 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerCheckBindingsTest);
2272};
2273
2274// Load an extension in each allowed channel and check that the expected
2275// bindings are available.
2276IN_PROC_BROWSER_TEST_P(ServiceWorkerCheckBindingsTest, BindingsAvailability) {
2277 scoped_refptr<const Extension> extension;
2278 static constexpr char kManifest[] =
2279 R"({
2280 "name": "Service Worker-based background script",
2281 "version": "0.1",
2282 "manifest_version": 2,
2283 "description": "Test that bindings are available.",
2284 "permissions": ["storage"],
2285 "background": {"service_worker": "worker.js"}
2286 })";
2287 static constexpr char kScript[] =
2288 R"(var chromeAPIAvailable = !!chrome;
2289 var storageAPIAvailable = chromeAPIAvailable && !!chrome.storage;
2290 var tabsAPIAvailable = chromeAPIAvailable && !!chrome.tabs;
2291 var testAPIAvailable = chromeAPIAvailable && !!chrome.test;
2292
2293 if (chromeAPIAvailable && storageAPIAvailable && tabsAPIAvailable &&
2294 testAPIAvailable) {
2295 chrome.test.sendMessage('SUCCESS');
2296 } else {
2297 console.log('chromeAPIAvailable: ' + chromeAPIAvailable);
2298 console.log('storageAPIAvailable: ' + storageAPIAvailable);
2299 console.log('tabsAPIAvailable: ' + tabsAPIAvailable);
2300 console.log('testAPIAvailable: ' + testAPIAvailable);
2301 chrome.test.sendMessage('FAILURE');
2302 })";
2303
2304 if (GetParam() <= version_info::Channel::CANARY) {
2305 TestExtensionDir test_dir;
2306 test_dir.WriteManifest(kManifest);
2307 test_dir.WriteFile(FILE_PATH_LITERAL("worker.js"), kScript);
2308 const base::FilePath path = test_dir.UnpackedPath();
2309
2310 // Wait for the extension to load and the script to finish.
2311 ExtensionTestMessageListener result_listener("SUCCESS", false);
2312 result_listener.set_failure_message("FAILURE");
2313
2314 extension = LoadExtension(test_dir.UnpackedPath());
2315 ASSERT_TRUE(extension.get());
2316 EXPECT_TRUE(BackgroundInfo::IsServiceWorkerBased(extension.get()));
2317 EXPECT_TRUE(result_listener.WaitUntilSatisfied());
2318 }
2319}
2320
2321INSTANTIATE_TEST_SUITE_P(Unknown,
2322 ServiceWorkerCheckBindingsTest,
2323 ::testing::Values(version_info::Channel::UNKNOWN,
2324 version_info::Channel::CANARY));
2325
annekao38685502015-07-14 17:46:392326} // namespace extensions