blob: 7a8377b44effa274aca0e1e29ab0bfb176546c16 [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
kalman6f984ae2015-09-18 17:21:587#include "base/bind_helpers.h"
avia2f4804a2015-12-24 23:11:138#include "base/macros.h"
Gabriel Charette078e3662017-08-28 22:59:049#include "base/run_loop.h"
kalman6f984ae2015-09-18 17:21:5810#include "base/strings/stringprintf.h"
horo1eeddde2015-11-19 05:59:2511#include "base/strings/utf_string_conversions.h"
jam3f2d3932017-04-26 20:28:5112#include "base/threading/thread_restrictions.h"
Olga Sharonova3e13cd92018-02-08 16:43:5613#include "build/build_config.h"
annekao38685502015-07-14 17:46:3914#include "chrome/browser/extensions/extension_apitest.h"
rdevlin.croninf5863da2015-09-10 19:21:4515#include "chrome/browser/extensions/extension_service.h"
Istiaque Ahmed805f6a83b2017-10-05 01:23:2616#include "chrome/browser/extensions/lazy_background_page_test_util.h"
peter9f4490a2017-01-27 00:58:3617#include "chrome/browser/gcm/gcm_profile_service_factory.h"
lazyboy561b7de2015-11-19 19:27:3018#include "chrome/browser/notifications/desktop_notification_profile_util.h"
miguelg9b502862017-04-24 18:13:5319#include "chrome/browser/notifications/notification_display_service_factory.h"
20#include "chrome/browser/notifications/stub_notification_display_service.h"
lshang106c1772016-06-06 01:43:2321#include "chrome/browser/permissions/permission_manager.h"
timlohc6911802017-03-01 05:37:0322#include "chrome/browser/permissions/permission_result.h"
lazyboy561b7de2015-11-19 19:27:3023#include "chrome/browser/push_messaging/push_messaging_app_identifier.h"
24#include "chrome/browser/push_messaging/push_messaging_service_factory.h"
25#include "chrome/browser/push_messaging/push_messaging_service_impl.h"
annekao1db36fd2015-07-29 17:09:1626#include "chrome/browser/ui/tabs/tab_strip_model.h"
Elly Fong-Jones4a4f21d2018-05-30 15:04:1627#include "chrome/browser/ui/views_mode_controller.h"
Trent Apted4267b942017-10-27 03:25:3628#include "chrome/common/chrome_switches.h"
rdevlin.croninf5863da2015-09-10 19:21:4529#include "chrome/test/base/ui_test_utils.h"
timloh9a180ad2017-02-20 07:15:2330#include "components/content_settings/core/common/content_settings_types.h"
Peter Beverloo34139462018-04-10 14:18:0631#include "components/gcm_driver/fake_gcm_profile_service.h"
johnmea5045732016-09-08 17:23:2932#include "components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h"
sdefresne9fb67692015-08-03 18:48:2233#include "components/version_info/version_info.h"
kalman6f984ae2015-09-18 17:21:5834#include "content/public/browser/navigation_controller.h"
rdevlin.croninf5863da2015-09-10 19:21:4535#include "content/public/browser/navigation_entry.h"
lazyboy4c82177a2016-10-18 00:04:0936#include "content/public/browser/service_worker_context.h"
37#include "content/public/browser/storage_partition.h"
kalman6f984ae2015-09-18 17:21:5838#include "content/public/browser/web_contents.h"
lazyboybd325ae2015-11-18 21:35:2639#include "content/public/common/content_switches.h"
falkenad185092016-06-16 06:10:0240#include "content/public/common/origin_util.h"
kalman6f984ae2015-09-18 17:21:5841#include "content/public/common/page_type.h"
lazyboybd325ae2015-11-18 21:35:2642#include "content/public/test/background_sync_test_util.h"
annekao1db36fd2015-07-29 17:09:1643#include "content/public/test/browser_test_utils.h"
lazyboy63b994a2017-06-30 21:20:2344#include "content/public/test/service_worker_test_helpers.h"
kalman6f984ae2015-09-18 17:21:5845#include "extensions/browser/extension_host.h"
lazyboyc3e763a2015-12-09 23:09:5846#include "extensions/browser/extension_registry.h"
kalman6f984ae2015-09-18 17:21:5847#include "extensions/browser/process_manager.h"
Devlin Cronina3fe3d602017-11-22 04:47:4348#include "extensions/common/extension_features.h"
kalman6f984ae2015-09-18 17:21:5849#include "extensions/test/background_page_watcher.h"
annekao38685502015-07-14 17:46:3950#include "extensions/test/extension_test_message_listener.h"
Istiaque Ahmed805f6a83b2017-10-05 01:23:2651#include "extensions/test/result_catcher.h"
falkenad185092016-06-16 06:10:0252#include "net/dns/mock_host_resolver.h"
horo1eeddde2015-11-19 05:59:2553#include "net/test/embedded_test_server/embedded_test_server.h"
lazyboy63b994a2017-06-30 21:20:2354#include "url/url_constants.h"
annekao38685502015-07-14 17:46:3955
56namespace extensions {
57
kalman6f984ae2015-09-18 17:21:5858namespace {
59
60// Pass into ServiceWorkerTest::StartTestFromBackgroundPage to indicate that
61// registration is expected to succeed.
62std::string* const kExpectSuccess = nullptr;
63
lazyboy22eddc712015-12-10 21:16:2664// Returns the newly added WebContents.
65content::WebContents* AddTab(Browser* browser, const GURL& url) {
66 int starting_tab_count = browser->tab_strip_model()->count();
67 ui_test_utils::NavigateToURLWithDisposition(
nick3b04f322016-08-31 19:29:1968 browser, url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
lazyboy22eddc712015-12-10 21:16:2669 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
70 int tab_count = browser->tab_strip_model()->count();
71 EXPECT_EQ(starting_tab_count + 1, tab_count);
72 return browser->tab_strip_model()->GetActiveWebContents();
73}
74
Istiaque Ahmedea5ed5042017-09-25 19:00:1675enum BindingsType { NATIVE_BINDINGS, JAVASCRIPT_BINDINGS };
76
lazyboy22eddc712015-12-10 21:16:2677class WebContentsLoadStopObserver : content::WebContentsObserver {
78 public:
79 explicit WebContentsLoadStopObserver(content::WebContents* web_contents)
80 : content::WebContentsObserver(web_contents),
81 load_stop_observed_(false) {}
82
83 void WaitForLoadStop() {
84 if (load_stop_observed_)
85 return;
86 message_loop_runner_ = new content::MessageLoopRunner;
87 message_loop_runner_->Run();
88 }
89
90 private:
91 void DidStopLoading() override {
92 load_stop_observed_ = true;
93 if (message_loop_runner_)
94 message_loop_runner_->Quit();
95 }
96
97 bool load_stop_observed_;
98 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
99
100 DISALLOW_COPY_AND_ASSIGN(WebContentsLoadStopObserver);
101};
102
Elly Fong-Jones4a4f21d2018-05-30 15:04:16103bool IsMacViewsMode() {
104// Some tests are flaky on Mac: <https://crbug.com/845979>. This helper function
105// is used to skip them.
106#if defined(OS_MACOSX)
107 return !views_mode_controller::IsViewsBrowserCocoa();
108#else
109 return false;
110#endif
111}
112
kalman6f984ae2015-09-18 17:21:58113} // namespace
114
Istiaque Ahmedea5ed5042017-09-25 19:00:16115class ServiceWorkerTest : public ExtensionApiTest,
116 public ::testing::WithParamInterface<BindingsType> {
annekao38685502015-07-14 17:46:39117 public:
lazyboy20167c22016-05-18 00:59:30118 ServiceWorkerTest() : current_channel_(version_info::Channel::STABLE) {}
Istiaque Ahmed7105f2a2017-10-07 01:11:59119 explicit ServiceWorkerTest(version_info::Channel channel)
120 : current_channel_(channel) {}
annekao38685502015-07-14 17:46:39121
122 ~ServiceWorkerTest() override {}
123
Devlin Cronina3fe3d602017-11-22 04:47:43124 void SetUp() override {
125 if (GetParam() == NATIVE_BINDINGS) {
126 scoped_feature_list_.InitAndEnableFeature(features::kNativeCrxBindings);
127 } else {
128 DCHECK_EQ(JAVASCRIPT_BINDINGS, GetParam());
129 scoped_feature_list_.InitAndDisableFeature(features::kNativeCrxBindings);
130 }
131 ExtensionApiTest::SetUp();
132 }
133
jam1a5b5582017-05-01 16:50:10134 void SetUpOnMainThread() override {
135 ExtensionApiTest::SetUpOnMainThread();
136 host_resolver()->AddRule("a.com", "127.0.0.1");
137 }
138
kalman6f984ae2015-09-18 17:21:58139 protected:
140 // Returns the ProcessManager for the test's profile.
141 ProcessManager* process_manager() { return ProcessManager::Get(profile()); }
142
143 // Starts running a test from the background page test extension.
144 //
145 // This registers a service worker with |script_name|, and fetches the
146 // registration result.
147 //
148 // If |error_or_null| is null (kExpectSuccess), success is expected and this
149 // will fail if there is an error.
150 // If |error_or_null| is not null, nothing is assumed, and the error (which
151 // may be empty) is written to it.
152 const Extension* StartTestFromBackgroundPage(const char* script_name,
153 std::string* error_or_null) {
154 const Extension* extension =
155 LoadExtension(test_data_dir_.AppendASCII("service_worker/background"));
156 CHECK(extension);
157 ExtensionHost* background_host =
158 process_manager()->GetBackgroundHostForExtension(extension->id());
159 CHECK(background_host);
160 std::string error;
161 CHECK(content::ExecuteScriptAndExtractString(
162 background_host->host_contents(),
163 base::StringPrintf("test.registerServiceWorker('%s')", script_name),
164 &error));
165 if (error_or_null)
166 *error_or_null = error;
167 else if (!error.empty())
168 ADD_FAILURE() << "Got unexpected error " << error;
169 return extension;
170 }
171
172 // Navigates the browser to a new tab at |url|, waits for it to load, then
173 // returns it.
174 content::WebContents* Navigate(const GURL& url) {
175 ui_test_utils::NavigateToURLWithDisposition(
nick3b04f322016-08-31 19:29:19176 browser(), url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
kalman6f984ae2015-09-18 17:21:58177 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
178 content::WebContents* web_contents =
179 browser()->tab_strip_model()->GetActiveWebContents();
180 content::WaitForLoadStop(web_contents);
181 return web_contents;
182 }
183
184 // Navigates the browser to |url| and returns the new tab's page type.
185 content::PageType NavigateAndGetPageType(const GURL& url) {
clamy1d7a4112018-06-15 15:47:16186 return Navigate(url)
187 ->GetController()
188 .GetLastCommittedEntry()
189 ->GetPageType();
kalman6f984ae2015-09-18 17:21:58190 }
191
192 // Extracts the innerText from |contents|.
193 std::string ExtractInnerText(content::WebContents* contents) {
194 std::string inner_text;
195 if (!content::ExecuteScriptAndExtractString(
196 contents,
197 "window.domAutomationController.send(document.body.innerText)",
198 &inner_text)) {
199 ADD_FAILURE() << "Failed to get inner text for "
200 << contents->GetVisibleURL();
201 }
202 return inner_text;
203 }
204
205 // Navigates the browser to |url|, then returns the innerText of the new
206 // tab's WebContents' main frame.
207 std::string NavigateAndExtractInnerText(const GURL& url) {
208 return ExtractInnerText(Navigate(url));
209 }
210
lazyboy4c82177a2016-10-18 00:04:09211 size_t GetWorkerRefCount(const GURL& origin) {
212 content::ServiceWorkerContext* sw_context =
213 content::BrowserContext::GetDefaultStoragePartition(
214 browser()->profile())
215 ->GetServiceWorkerContext();
216 base::RunLoop run_loop;
217 size_t ref_count = 0;
218 auto set_ref_count = [](size_t* ref_count, base::RunLoop* run_loop,
219 size_t external_request_count) {
220 *ref_count = external_request_count;
221 run_loop->Quit();
222 };
223 sw_context->CountExternalRequestsForTest(
Matt Falkenhagenc5cb4282017-09-07 08:43:42224 origin, base::BindOnce(set_ref_count, &ref_count, &run_loop));
lazyboy4c82177a2016-10-18 00:04:09225 run_loop.Run();
226 return ref_count;
227 }
228
annekao38685502015-07-14 17:46:39229 private:
lazyboy20167c22016-05-18 00:59:30230 // Sets the channel to "stable".
231 // Not useful after we've opened extension Service Workers to stable
232 // channel.
233 // TODO(lazyboy): Remove this when ExtensionServiceWorkersEnabled() is
234 // removed.
annekao38685502015-07-14 17:46:39235 ScopedCurrentChannel current_channel_;
kalman6f984ae2015-09-18 17:21:58236
Devlin Cronina3fe3d602017-11-22 04:47:43237 base::test::ScopedFeatureList scoped_feature_list_;
238
annekao38685502015-07-14 17:46:39239 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerTest);
240};
241
Istiaque Ahmedccb444022018-06-19 02:11:12242class ServiceWorkerBasedBackgroundTest : public ServiceWorkerTest {
243 public:
244 ServiceWorkerBasedBackgroundTest()
245 : ServiceWorkerTest(
246 // Extensions APIs from SW are only enabled on trunk.
247 // It is important to set the channel early so that this change is
248 // visible in renderers running with service workers (and no
249 // extension).
250 version_info::Channel::UNKNOWN) {}
251 ~ServiceWorkerBasedBackgroundTest() override {}
252
253 void SetUpOnMainThread() override {
254 host_resolver()->AddRule("*", "127.0.0.1");
255 ASSERT_TRUE(embedded_test_server()->Start());
256 ServiceWorkerTest::SetUpOnMainThread();
257 }
258
259 private:
260 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerBasedBackgroundTest);
261};
262
263// Tests that Service Worker based background pages can be loaded and they can
264// receive extension events.
265// The extension is installed and loaded during this step and it registers
266// an event listener for tabs.onCreated event. The step also verifies that tab
267// creation correctly fires the listener.
268IN_PROC_BROWSER_TEST_P(ServiceWorkerBasedBackgroundTest, PRE_Basic) {
269 ExtensionTestMessageListener newtab_listener("CREATED", false);
270 newtab_listener.set_failure_message("CREATE_FAILED");
271 ExtensionTestMessageListener worker_listener("WORKER_RUNNING", false);
272 worker_listener.set_failure_message("NON_WORKER_SCOPE");
273 const Extension* extension = LoadExtension(test_data_dir_.AppendASCII(
274 "service_worker/worker_based_background/basic"));
275 ASSERT_TRUE(extension);
276 const ExtensionId extension_id = extension->id();
277 EXPECT_TRUE(worker_listener.WaitUntilSatisfied());
278
279 const GURL url = embedded_test_server()->GetURL("/extensions/test_file.html");
280 content::WebContents* new_web_contents = AddTab(browser(), url);
281 EXPECT_TRUE(new_web_contents);
282 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
283
284 // Service Worker extension does not have ExtensionHost.
285 EXPECT_FALSE(process_manager()->GetBackgroundHostForExtension(extension_id));
286}
287
288// After browser restarts, this test step ensures that opening a tab fires
289// tabs.onCreated event listener to the extension without explicitly loading the
290// extension. This is because the extension registered a listener before browser
291// restarted in PRE_Basic.
292IN_PROC_BROWSER_TEST_P(ServiceWorkerBasedBackgroundTest, Basic) {
293 ExtensionTestMessageListener newtab_listener("CREATED", false);
294 newtab_listener.set_failure_message("CREATE_FAILED");
295 const GURL url = embedded_test_server()->GetURL("/extensions/test_file.html");
296 content::WebContents* new_web_contents = AddTab(browser(), url);
297 EXPECT_TRUE(new_web_contents);
298 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
299}
300
lazyboybd325ae2015-11-18 21:35:26301class ServiceWorkerBackgroundSyncTest : public ServiceWorkerTest {
302 public:
303 ServiceWorkerBackgroundSyncTest() {}
304 ~ServiceWorkerBackgroundSyncTest() override {}
305
306 void SetUpCommandLine(base::CommandLine* command_line) override {
307 // ServiceWorkerRegistration.sync requires experimental flag.
308 command_line->AppendSwitch(
Istiaque Ahmedea5ed5042017-09-25 19:00:16309 ::switches::kEnableExperimentalWebPlatformFeatures);
lazyboybd325ae2015-11-18 21:35:26310 ServiceWorkerTest::SetUpCommandLine(command_line);
311 }
312
313 void SetUp() override {
314 content::background_sync_test_util::SetIgnoreNetworkChangeNotifier(true);
315 ServiceWorkerTest::SetUp();
316 }
317
318 private:
319 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerBackgroundSyncTest);
320};
321
lazyboy561b7de2015-11-19 19:27:30322class ServiceWorkerPushMessagingTest : public ServiceWorkerTest {
323 public:
324 ServiceWorkerPushMessagingTest()
johnmea5045732016-09-08 17:23:29325 : gcm_driver_(nullptr), push_service_(nullptr) {}
lazyboy561b7de2015-11-19 19:27:30326 ~ServiceWorkerPushMessagingTest() override {}
327
328 void GrantNotificationPermissionForTest(const GURL& url) {
329 GURL origin = url.GetOrigin();
330 DesktopNotificationProfileUtil::GrantPermission(profile(), origin);
timlohc6911802017-03-01 05:37:03331 ASSERT_EQ(CONTENT_SETTING_ALLOW,
332 PermissionManager::Get(profile())
333 ->GetPermissionStatus(CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
334 origin, origin)
335 .content_setting);
lazyboy561b7de2015-11-19 19:27:30336 }
337
338 PushMessagingAppIdentifier GetAppIdentifierForServiceWorkerRegistration(
avia2f4804a2015-12-24 23:11:13339 int64_t service_worker_registration_id,
lazyboy561b7de2015-11-19 19:27:30340 const GURL& origin) {
341 PushMessagingAppIdentifier app_identifier =
342 PushMessagingAppIdentifier::FindByServiceWorker(
343 profile(), origin, service_worker_registration_id);
344
345 EXPECT_FALSE(app_identifier.is_null());
346 return app_identifier;
347 }
348
349 // ExtensionApiTest overrides.
350 void SetUpCommandLine(base::CommandLine* command_line) override {
peter9de96272015-12-04 15:23:27351 command_line->AppendSwitch(
Istiaque Ahmedea5ed5042017-09-25 19:00:16352 ::switches::kEnableExperimentalWebPlatformFeatures);
lazyboy561b7de2015-11-19 19:27:30353 ServiceWorkerTest::SetUpCommandLine(command_line);
354 }
355 void SetUpOnMainThread() override {
miguelg9b502862017-04-24 18:13:53356 NotificationDisplayServiceFactory::GetInstance()->SetTestingFactory(
357 profile(), &StubNotificationDisplayService::FactoryForTests);
358
johnmea5045732016-09-08 17:23:29359 gcm::FakeGCMProfileService* gcm_service =
360 static_cast<gcm::FakeGCMProfileService*>(
361 gcm::GCMProfileServiceFactory::GetInstance()
362 ->SetTestingFactoryAndUse(profile(),
363 &gcm::FakeGCMProfileService::Build));
364 gcm_driver_ = static_cast<instance_id::FakeGCMDriverForInstanceID*>(
365 gcm_service->driver());
lazyboy561b7de2015-11-19 19:27:30366 push_service_ = PushMessagingServiceFactory::GetForProfile(profile());
367
368 ServiceWorkerTest::SetUpOnMainThread();
369 }
370
johnmea5045732016-09-08 17:23:29371 instance_id::FakeGCMDriverForInstanceID* gcm_driver() const {
372 return gcm_driver_;
373 }
lazyboy561b7de2015-11-19 19:27:30374 PushMessagingServiceImpl* push_service() const { return push_service_; }
375
376 private:
johnmea5045732016-09-08 17:23:29377 instance_id::FakeGCMDriverForInstanceID* gcm_driver_;
lazyboy561b7de2015-11-19 19:27:30378 PushMessagingServiceImpl* push_service_;
379
380 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerPushMessagingTest);
381};
382
Istiaque Ahmed805f6a83b2017-10-05 01:23:26383class ServiceWorkerLazyBackgroundTest : public ServiceWorkerTest {
384 public:
Istiaque Ahmed7105f2a2017-10-07 01:11:59385 ServiceWorkerLazyBackgroundTest()
386 : ServiceWorkerTest(
387 // Extensions APIs from SW are only enabled on trunk.
388 // It is important to set the channel early so that this change is
389 // visible in renderers running with service workers (and no
390 // extension).
391 version_info::Channel::UNKNOWN) {}
Istiaque Ahmed805f6a83b2017-10-05 01:23:26392 ~ServiceWorkerLazyBackgroundTest() override {}
393
394 void SetUpCommandLine(base::CommandLine* command_line) override {
395 ServiceWorkerTest::SetUpCommandLine(command_line);
396 // Disable background network activity as it can suddenly bring the Lazy
397 // Background Page alive.
398 command_line->AppendSwitch(::switches::kDisableBackgroundNetworking);
399 command_line->AppendSwitch(::switches::kNoProxyServer);
400 }
401
402 void SetUpInProcessBrowserTestFixture() override {
403 ServiceWorkerTest::SetUpInProcessBrowserTestFixture();
404 // Set shorter delays to prevent test timeouts.
405 ProcessManager::SetEventPageIdleTimeForTesting(1);
406 ProcessManager::SetEventPageSuspendingTimeForTesting(1);
407 }
408
409 private:
410 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerLazyBackgroundTest);
411};
412
Istiaque Ahmedea5ed5042017-09-25 19:00:16413IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, RegisterSucceeds) {
kalman6f984ae2015-09-18 17:21:58414 StartTestFromBackgroundPage("register.js", kExpectSuccess);
annekao38685502015-07-14 17:46:39415}
416
Istiaque Ahmedea5ed5042017-09-25 19:00:16417IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, UpdateRefreshesServiceWorker) {
Francois Doraye6fb2d02017-10-18 21:29:13418 base::ScopedAllowBlockingForTesting allow_blocking;
lazyboyc3e763a2015-12-09 23:09:58419 base::ScopedTempDir scoped_temp_dir;
420 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
421 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
422 .AppendASCII("update")
423 .AppendASCII("service_worker.pem");
vabr9142fe22016-09-08 13:19:22424 base::FilePath path_v1 =
425 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
426 .AppendASCII("update")
427 .AppendASCII("v1"),
428 scoped_temp_dir.GetPath().AppendASCII("v1.crx"),
429 pem_path, base::FilePath());
430 base::FilePath path_v2 =
431 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
432 .AppendASCII("update")
433 .AppendASCII("v2"),
434 scoped_temp_dir.GetPath().AppendASCII("v2.crx"),
435 pem_path, base::FilePath());
lazyboyc3e763a2015-12-09 23:09:58436 const char* kId = "hfaanndiiilofhfokeanhddpkfffchdi";
437
438 ExtensionTestMessageListener listener_v1("Pong from version 1", false);
439 listener_v1.set_failure_message("FAILURE_V1");
440 // Install version 1.0 of the extension.
441 ASSERT_TRUE(InstallExtension(path_v1, 1));
442 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
443 ->enabled_extensions()
444 .GetByID(kId));
445 EXPECT_TRUE(listener_v1.WaitUntilSatisfied());
446
447 ExtensionTestMessageListener listener_v2("Pong from version 2", false);
448 listener_v2.set_failure_message("FAILURE_V2");
449
450 // Update to version 2.0.
451 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
452 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
453 ->enabled_extensions()
454 .GetByID(kId));
455 EXPECT_TRUE(listener_v2.WaitUntilSatisfied());
456}
457
[email protected]2ef85d562017-09-15 18:41:52458// TODO(crbug.com/765736) Fix the test.
Istiaque Ahmedea5ed5042017-09-25 19:00:16459IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, DISABLED_UpdateWithoutSkipWaiting) {
Francois Doraye6fb2d02017-10-18 21:29:13460 base::ScopedAllowBlockingForTesting allow_blocking;
lazyboy22eddc712015-12-10 21:16:26461 base::ScopedTempDir scoped_temp_dir;
462 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
463 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
464 .AppendASCII("update_without_skip_waiting")
465 .AppendASCII("update_without_skip_waiting.pem");
vabr9142fe22016-09-08 13:19:22466 base::FilePath path_v1 =
467 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
468 .AppendASCII("update_without_skip_waiting")
469 .AppendASCII("v1"),
470 scoped_temp_dir.GetPath().AppendASCII("v1.crx"),
471 pem_path, base::FilePath());
472 base::FilePath path_v2 =
473 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
474 .AppendASCII("update_without_skip_waiting")
475 .AppendASCII("v2"),
476 scoped_temp_dir.GetPath().AppendASCII("v2.crx"),
477 pem_path, base::FilePath());
lazyboy22eddc712015-12-10 21:16:26478 const char* kId = "mhnnnflgagdakldgjpfcofkiocpdmogl";
479
480 // Install version 1.0 of the extension.
481 ASSERT_TRUE(InstallExtension(path_v1, 1));
482 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
483 ->enabled_extensions()
484 .GetByID(kId));
485 const Extension* extension = extensions::ExtensionRegistry::Get(profile())
486 ->enabled_extensions()
487 .GetByID(kId);
488
489 ExtensionTestMessageListener listener1("Pong from version 1", false);
490 listener1.set_failure_message("FAILURE");
491 content::WebContents* web_contents =
492 AddTab(browser(), extension->GetResourceURL("page.html"));
493 EXPECT_TRUE(listener1.WaitUntilSatisfied());
494
495 // Update to version 2.0.
496 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
497 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
498 ->enabled_extensions()
499 .GetByID(kId));
500 const Extension* extension_after_update =
501 extensions::ExtensionRegistry::Get(profile())
502 ->enabled_extensions()
503 .GetByID(kId);
504
505 // Service worker version 2 would be installed but it won't be controlling
506 // the extension page yet.
507 ExtensionTestMessageListener listener2("Pong from version 1", false);
508 listener2.set_failure_message("FAILURE");
509 web_contents =
510 AddTab(browser(), extension_after_update->GetResourceURL("page.html"));
511 EXPECT_TRUE(listener2.WaitUntilSatisfied());
512
513 // Navigate the tab away from the extension page so that no clients are
514 // using the service worker.
515 // Note that just closing the tab with WebContentsDestroyedWatcher doesn't
516 // seem to be enough because it returns too early.
517 WebContentsLoadStopObserver navigate_away_observer(web_contents);
518 web_contents->GetController().LoadURL(
519 GURL(url::kAboutBlankURL), content::Referrer(), ui::PAGE_TRANSITION_TYPED,
520 std::string());
521 navigate_away_observer.WaitForLoadStop();
522
523 // Now expect service worker version 2 to control the extension page.
524 ExtensionTestMessageListener listener3("Pong from version 2", false);
525 listener3.set_failure_message("FAILURE");
526 web_contents =
527 AddTab(browser(), extension_after_update->GetResourceURL("page.html"));
528 EXPECT_TRUE(listener3.WaitUntilSatisfied());
529}
530
Istiaque Ahmedea5ed5042017-09-25 19:00:16531IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, FetchArbitraryPaths) {
kalman6f984ae2015-09-18 17:21:58532 const Extension* extension =
533 StartTestFromBackgroundPage("fetch.js", kExpectSuccess);
annekao1db36fd2015-07-29 17:09:16534
kalman6f984ae2015-09-18 17:21:58535 // Open some arbirary paths. Their contents should be what the service worker
536 // responds with, which in this case is the path of the fetch.
537 EXPECT_EQ(
538 "Caught a fetch for /index.html",
539 NavigateAndExtractInnerText(extension->GetResourceURL("index.html")));
540 EXPECT_EQ("Caught a fetch for /path/to/other.html",
541 NavigateAndExtractInnerText(
542 extension->GetResourceURL("path/to/other.html")));
543 EXPECT_EQ("Caught a fetch for /some/text/file.txt",
544 NavigateAndExtractInnerText(
545 extension->GetResourceURL("some/text/file.txt")));
546 EXPECT_EQ("Caught a fetch for /no/file/extension",
547 NavigateAndExtractInnerText(
548 extension->GetResourceURL("no/file/extension")));
549 EXPECT_EQ("Caught a fetch for /",
550 NavigateAndExtractInnerText(extension->GetResourceURL("")));
annekao1db36fd2015-07-29 17:09:16551}
552
Istiaque Ahmedea5ed5042017-09-25 19:00:16553IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, SWServedBackgroundPageReceivesEvent) {
lazyboy52c3bcf2016-01-08 00:11:29554 const Extension* extension =
555 StartTestFromBackgroundPage("replace_background.js", kExpectSuccess);
556 ExtensionHost* background_page =
557 process_manager()->GetBackgroundHostForExtension(extension->id());
558 ASSERT_TRUE(background_page);
559
560 // Close the background page and start it again so that the service worker
561 // will start controlling pages.
562 background_page->Close();
563 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
564 background_page = nullptr;
Peter Kasting341e1fb2018-02-24 00:03:01565 process_manager()->WakeEventPage(extension->id(), base::DoNothing());
lazyboy52c3bcf2016-01-08 00:11:29566 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
567
568 // Since the SW is now controlling the extension, the SW serves the background
569 // script. page.html sends a message to the background script and we verify
570 // that the SW served background script correctly receives the message/event.
571 ExtensionTestMessageListener listener("onMessage/SW BG.", false);
572 listener.set_failure_message("onMessage/original BG.");
573 content::WebContents* web_contents =
574 AddTab(browser(), extension->GetResourceURL("page.html"));
575 ASSERT_TRUE(web_contents);
576 EXPECT_TRUE(listener.WaitUntilSatisfied());
577}
578
Matt Falkenhagena612fc02018-05-30 00:35:39579IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, SWServedBackgroundPage) {
kalman6f984ae2015-09-18 17:21:58580 const Extension* extension =
581 StartTestFromBackgroundPage("fetch.js", kExpectSuccess);
annekao49241182015-08-18 17:14:01582
kalman6f984ae2015-09-18 17:21:58583 std::string kExpectedInnerText = "background.html contents for testing.";
annekao49241182015-08-18 17:14:01584
kalman6f984ae2015-09-18 17:21:58585 // Sanity check that the background page has the expected content.
586 ExtensionHost* background_page =
587 process_manager()->GetBackgroundHostForExtension(extension->id());
588 ASSERT_TRUE(background_page);
589 EXPECT_EQ(kExpectedInnerText,
590 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:01591
kalman6f984ae2015-09-18 17:21:58592 // Close the background page.
593 background_page->Close();
594 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
595 background_page = nullptr;
596
597 // Start it again.
Peter Kasting341e1fb2018-02-24 00:03:01598 process_manager()->WakeEventPage(extension->id(), base::DoNothing());
kalman6f984ae2015-09-18 17:21:58599 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
600
Matt Falkenhagena612fc02018-05-30 00:35:39601 // The service worker should get a fetch event for the background page.
kalman6f984ae2015-09-18 17:21:58602 background_page =
603 process_manager()->GetBackgroundHostForExtension(extension->id());
604 ASSERT_TRUE(background_page);
605 content::WaitForLoadStop(background_page->host_contents());
606
kalman6f984ae2015-09-18 17:21:58607 EXPECT_EQ("Caught a fetch for /background.html",
608 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:01609}
610
Istiaque Ahmedea5ed5042017-09-25 19:00:16611IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:58612 ServiceWorkerPostsMessageToBackgroundClient) {
613 const Extension* extension = StartTestFromBackgroundPage(
614 "post_message_to_background_client.js", kExpectSuccess);
annekao533482222015-08-21 23:23:53615
kalman6f984ae2015-09-18 17:21:58616 // The service worker in this test simply posts a message to the background
617 // client it receives from getBackgroundClient().
618 const char* kScript =
619 "var messagePromise = null;\n"
620 "if (test.lastMessageFromServiceWorker) {\n"
621 " messagePromise = Promise.resolve(test.lastMessageFromServiceWorker);\n"
622 "} else {\n"
623 " messagePromise = test.waitForMessage(navigator.serviceWorker);\n"
624 "}\n"
625 "messagePromise.then(function(message) {\n"
626 " window.domAutomationController.send(String(message == 'success'));\n"
627 "})\n";
628 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:53629}
630
Istiaque Ahmedea5ed5042017-09-25 19:00:16631IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:58632 BackgroundPagePostsMessageToServiceWorker) {
633 const Extension* extension =
634 StartTestFromBackgroundPage("post_message_to_sw.js", kExpectSuccess);
annekao533482222015-08-21 23:23:53635
kalman6f984ae2015-09-18 17:21:58636 // The service worker in this test waits for a message, then echoes it back
637 // by posting a message to the background page via getBackgroundClient().
638 const char* kScript =
639 "var mc = new MessageChannel();\n"
640 "test.waitForMessage(mc.port1).then(function(message) {\n"
641 " window.domAutomationController.send(String(message == 'hello'));\n"
642 "});\n"
643 "test.registeredServiceWorker.postMessage(\n"
644 " {message: 'hello', port: mc.port2}, [mc.port2])\n";
645 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:53646}
647
Istiaque Ahmedea5ed5042017-09-25 19:00:16648IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
rdevlin.croninf5863da2015-09-10 19:21:45649 ServiceWorkerSuspensionOnExtensionUnload) {
kalman6f984ae2015-09-18 17:21:58650 // For this test, only hold onto the extension's ID and URL + a function to
651 // get a resource URL, because we're going to be disabling and uninstalling
652 // it, which will invalidate the pointer.
653 std::string extension_id;
654 GURL extension_url;
655 {
656 const Extension* extension =
657 StartTestFromBackgroundPage("fetch.js", kExpectSuccess);
658 extension_id = extension->id();
659 extension_url = extension->url();
660 }
661 auto get_resource_url = [&extension_url](const std::string& path) {
662 return Extension::GetResourceURL(extension_url, path);
663 };
rdevlin.croninf5863da2015-09-10 19:21:45664
kalman6f984ae2015-09-18 17:21:58665 // Fetch should route to the service worker.
666 EXPECT_EQ("Caught a fetch for /index.html",
667 NavigateAndExtractInnerText(get_resource_url("index.html")));
rdevlin.croninf5863da2015-09-10 19:21:45668
kalman6f984ae2015-09-18 17:21:58669 // Disable the extension. Opening the page should fail.
670 extension_service()->DisableExtension(extension_id,
Minh X. Nguyen45479012017-08-18 21:35:36671 disable_reason::DISABLE_USER_ACTION);
rdevlin.croninf5863da2015-09-10 19:21:45672 base::RunLoop().RunUntilIdle();
rdevlin.croninf5863da2015-09-10 19:21:45673
kalman6f984ae2015-09-18 17:21:58674 EXPECT_EQ(content::PAGE_TYPE_ERROR,
675 NavigateAndGetPageType(get_resource_url("index.html")));
676 EXPECT_EQ(content::PAGE_TYPE_ERROR,
677 NavigateAndGetPageType(get_resource_url("other.html")));
678
679 // Re-enable the extension. Opening pages should immediately start to succeed
680 // again.
rdevlin.croninf5863da2015-09-10 19:21:45681 extension_service()->EnableExtension(extension_id);
682 base::RunLoop().RunUntilIdle();
683
kalman6f984ae2015-09-18 17:21:58684 EXPECT_EQ("Caught a fetch for /index.html",
685 NavigateAndExtractInnerText(get_resource_url("index.html")));
686 EXPECT_EQ("Caught a fetch for /other.html",
687 NavigateAndExtractInnerText(get_resource_url("other.html")));
688 EXPECT_EQ("Caught a fetch for /another.html",
689 NavigateAndExtractInnerText(get_resource_url("another.html")));
rdevlin.croninf5863da2015-09-10 19:21:45690
kalman6f984ae2015-09-18 17:21:58691 // Uninstall the extension. Opening pages should fail again.
692 base::string16 error;
693 extension_service()->UninstallExtension(
Devlin Cronin218df7f2017-11-21 21:41:31694 extension_id, UninstallReason::UNINSTALL_REASON_FOR_TESTING, &error);
kalman6f984ae2015-09-18 17:21:58695 base::RunLoop().RunUntilIdle();
696
697 EXPECT_EQ(content::PAGE_TYPE_ERROR,
698 NavigateAndGetPageType(get_resource_url("index.html")));
699 EXPECT_EQ(content::PAGE_TYPE_ERROR,
700 NavigateAndGetPageType(get_resource_url("other.html")));
701 EXPECT_EQ(content::PAGE_TYPE_ERROR,
702 NavigateAndGetPageType(get_resource_url("anotherother.html")));
703 EXPECT_EQ(content::PAGE_TYPE_ERROR,
704 NavigateAndGetPageType(get_resource_url("final.html")));
705}
706
Istiaque Ahmedea5ed5042017-09-25 19:00:16707IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, BackgroundPageIsWokenIfAsleep) {
kalman6f984ae2015-09-18 17:21:58708 const Extension* extension =
709 StartTestFromBackgroundPage("wake_on_fetch.js", kExpectSuccess);
710
711 // Navigate to special URLs that this test's service worker recognises, each
712 // making a check then populating the response with either "true" or "false".
713 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
714 "background-client-is-awake")));
715 EXPECT_EQ("true", NavigateAndExtractInnerText(
716 extension->GetResourceURL("ping-background-client")));
717 // Ping more than once for good measure.
718 EXPECT_EQ("true", NavigateAndExtractInnerText(
719 extension->GetResourceURL("ping-background-client")));
720
721 // Shut down the event page. The SW should detect that it's closed, but still
722 // be able to ping it.
723 ExtensionHost* background_page =
724 process_manager()->GetBackgroundHostForExtension(extension->id());
725 ASSERT_TRUE(background_page);
726 background_page->Close();
727 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
728
729 EXPECT_EQ("false", NavigateAndExtractInnerText(extension->GetResourceURL(
730 "background-client-is-awake")));
731 EXPECT_EQ("true", NavigateAndExtractInnerText(
732 extension->GetResourceURL("ping-background-client")));
733 EXPECT_EQ("true", NavigateAndExtractInnerText(
734 extension->GetResourceURL("ping-background-client")));
735 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
736 "background-client-is-awake")));
737}
738
Istiaque Ahmedea5ed5042017-09-25 19:00:16739IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:58740 GetBackgroundClientFailsWithNoBackgroundPage) {
741 // This extension doesn't have a background page, only a tab at page.html.
742 // The service worker it registers tries to call getBackgroundClient() and
743 // should fail.
744 // Note that this also tests that service workers can be registered from tabs.
745 EXPECT_TRUE(RunExtensionSubtest("service_worker/no_background", "page.html"));
rdevlin.croninf5863da2015-09-10 19:21:45746}
747
Istiaque Ahmedea5ed5042017-09-25 19:00:16748IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, NotificationAPI) {
lazyboy6ddb7d62015-11-10 23:15:27749 EXPECT_TRUE(RunExtensionSubtest("service_worker/notifications/has_permission",
750 "page.html"));
751}
752
Istiaque Ahmedea5ed5042017-09-25 19:00:16753IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, WebAccessibleResourcesFetch) {
lazyboyaea32c22016-01-04 21:37:07754 EXPECT_TRUE(RunExtensionSubtest(
755 "service_worker/web_accessible_resources/fetch/", "page.html"));
756}
757
Olga Sharonova3e13cd92018-02-08 16:43:56758// Flaky on Linux: http://crbug/810397.
759#if defined(OS_LINUX)
760#define MAYBE_TabsCreate DISABLED_TabsCreate
761#else
762#define MAYBE_TabsCreate TabsCreate
763#endif
764IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, MAYBE_TabsCreate) {
Elly Fong-Jones4a4f21d2018-05-30 15:04:16765 if (IsMacViewsMode())
766 return;
lazyboyee4adef2016-05-24 00:55:16767 // Extensions APIs from SW are only enabled on trunk.
768 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
769 const Extension* extension = LoadExtensionWithFlags(
770 test_data_dir_.AppendASCII("service_worker/tabs_create"), kFlagNone);
771 ASSERT_TRUE(extension);
772 ui_test_utils::NavigateToURL(browser(),
773 extension->GetResourceURL("page.html"));
774 content::WebContents* web_contents =
775 browser()->tab_strip_model()->GetActiveWebContents();
776
777 int starting_tab_count = browser()->tab_strip_model()->count();
778 std::string result;
779 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
780 web_contents, "window.runServiceWorker()", &result));
781 ASSERT_EQ("chrome.tabs.create callback", result);
782 EXPECT_EQ(starting_tab_count + 1, browser()->tab_strip_model()->count());
783
784 // Check extension shutdown path.
785 UnloadExtension(extension->id());
786 EXPECT_EQ(starting_tab_count, browser()->tab_strip_model()->count());
787}
788
Istiaque Ahmedea5ed5042017-09-25 19:00:16789IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, Events) {
Elly Fong-Jones4a4f21d2018-05-30 15:04:16790 if (IsMacViewsMode())
791 return;
lazyboye7847242017-06-07 23:29:18792 // Extensions APIs from SW are only enabled on trunk.
793 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
794 const Extension* extension = LoadExtensionWithFlags(
795 test_data_dir_.AppendASCII("service_worker/events"), kFlagNone);
796 ASSERT_TRUE(extension);
797 ui_test_utils::NavigateToURL(browser(),
798 extension->GetResourceURL("page.html"));
799 content::WebContents* web_contents =
800 browser()->tab_strip_model()->GetActiveWebContents();
801 std::string result;
802 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
803 web_contents, "window.runEventTest()", &result));
804 ASSERT_EQ("chrome.tabs.onUpdated callback", result);
805}
806
Istiaque Ahmedea5ed5042017-09-25 19:00:16807IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, EventsToStoppedWorker) {
lazyboy63b994a2017-06-30 21:20:23808 // Extensions APIs from SW are only enabled on trunk.
809 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
810 const Extension* extension = LoadExtensionWithFlags(
811 test_data_dir_.AppendASCII("service_worker/events_to_stopped_worker"),
812 kFlagNone);
813 ASSERT_TRUE(extension);
814 ui_test_utils::NavigateToURL(browser(),
815 extension->GetResourceURL("page.html"));
816 content::WebContents* web_contents =
817 browser()->tab_strip_model()->GetActiveWebContents();
818 {
819 std::string result;
820 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
821 web_contents, "window.runServiceWorker()", &result));
822 ASSERT_EQ("ready", result);
823
824 base::RunLoop run_loop;
825 content::StoragePartition* storage_partition =
826 content::BrowserContext::GetDefaultStoragePartition(
827 browser()->profile());
828 content::StopServiceWorkerForPattern(
829 storage_partition->GetServiceWorkerContext(),
830 // The service worker is registered at the top level scope.
831 extension->url(), run_loop.QuitClosure());
832 run_loop.Run();
833 }
834
835 std::string result;
836 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
837 web_contents, "window.createTabThenUpdate()", &result));
838 ASSERT_EQ("chrome.tabs.onUpdated callback", result);
839}
840
Istiaque Ahmed805f6a83b2017-10-05 01:23:26841// Tests that events to service worker arrives correctly event if the owner
842// extension of the worker is not running.
843IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest,
Xida Chen1f18f462018-04-24 13:55:54844 DISABLED_EventsToStoppedExtension) {
Istiaque Ahmed805f6a83b2017-10-05 01:23:26845 LazyBackgroundObserver lazy_observer;
846 ResultCatcher catcher;
847 const Extension* extension = LoadExtensionWithFlags(
848 test_data_dir_.AppendASCII("service_worker/events_to_stopped_extension"),
849 kFlagNone);
850 ASSERT_TRUE(extension);
851 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
852
853 ProcessManager* pm = ProcessManager::Get(browser()->profile());
854 EXPECT_GT(pm->GetLazyKeepaliveCount(extension), 0);
855
856 // |extension|'s background page opens a tab to its resource.
857 content::WebContents* extension_web_contents =
858 browser()->tab_strip_model()->GetActiveWebContents();
859 EXPECT_TRUE(content::WaitForLoadStop(extension_web_contents));
860 EXPECT_EQ(extension->GetResourceURL("page.html").spec(),
861 extension_web_contents->GetURL().spec());
862 {
863 // Let the service worker start and register a listener to
864 // chrome.tabs.onCreated event.
865 ExtensionTestMessageListener add_listener_done("listener-added", false);
866 content::ExecuteScriptAsync(extension_web_contents,
867 "window.runServiceWorkerAsync()");
868 EXPECT_TRUE(add_listener_done.WaitUntilSatisfied());
869
870 base::RunLoop run_loop;
871 content::StoragePartition* storage_partition =
872 content::BrowserContext::GetDefaultStoragePartition(
873 browser()->profile());
874 content::StopServiceWorkerForPattern(
875 storage_partition->GetServiceWorkerContext(),
876 // The service worker is registered at the top level scope.
877 extension->url(), run_loop.QuitClosure());
878 run_loop.Run();
879 }
880
881 // Close the tab to |extension|'s resource. This will also close the
882 // extension's event page.
883 browser()->tab_strip_model()->CloseWebContentsAt(
884 browser()->tab_strip_model()->active_index(), TabStripModel::CLOSE_NONE);
885 lazy_observer.Wait();
886
887 // At this point both the extension worker and extension event page is not
888 // running. Since the worker registered a listener for tabs.onCreated, it
889 // will be started to dispatch the event once we create a tab.
890 ExtensionTestMessageListener newtab_listener("hello-newtab", false);
891 newtab_listener.set_failure_message("WRONG_NEWTAB");
892 content::WebContents* new_web_contents =
Istiaque Ahmed7105f2a2017-10-07 01:11:59893 AddTab(browser(), GURL(url::kAboutBlankURL));
894 EXPECT_TRUE(new_web_contents);
895 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
896}
897
898// Tests that events to service worker correctly after browser restart.
899// This test is similar to EventsToStoppedExtension, except that the event
900// delivery is verified after a browser restart.
901IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest,
902 PRE_EventsAfterRestart) {
903 LazyBackgroundObserver lazy_observer;
904 ResultCatcher catcher;
905 const Extension* extension = LoadExtensionWithFlags(
906 test_data_dir_.AppendASCII("service_worker/events_to_stopped_extension"),
907 kFlagNone);
908 ASSERT_TRUE(extension);
909 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
910
911 ProcessManager* pm = ProcessManager::Get(browser()->profile());
912 EXPECT_GT(pm->GetLazyKeepaliveCount(extension), 0);
913
914 // |extension|'s background page opens a tab to its resource.
915 content::WebContents* extension_web_contents =
916 browser()->tab_strip_model()->GetActiveWebContents();
917 EXPECT_TRUE(content::WaitForLoadStop(extension_web_contents));
918 EXPECT_EQ(extension->GetResourceURL("page.html").spec(),
919 extension_web_contents->GetURL().spec());
920 {
921 // Let the service worker start and register a listener to
922 // chrome.tabs.onCreated event.
923 ExtensionTestMessageListener add_listener_done("listener-added", false);
924 content::ExecuteScriptAsync(extension_web_contents,
925 "window.runServiceWorkerAsync()");
926 EXPECT_TRUE(add_listener_done.WaitUntilSatisfied());
927
928 base::RunLoop run_loop;
929 content::StoragePartition* storage_partition =
930 content::BrowserContext::GetDefaultStoragePartition(
931 browser()->profile());
932 content::StopServiceWorkerForPattern(
933 storage_partition->GetServiceWorkerContext(),
934 // The service worker is registered at the top level scope.
935 extension->url(), run_loop.QuitClosure());
936 run_loop.Run();
937 }
938
939 // Close the tab to |extension|'s resource. This will also close the
940 // extension's event page.
941 browser()->tab_strip_model()->CloseWebContentsAt(
942 browser()->tab_strip_model()->active_index(), TabStripModel::CLOSE_NONE);
943 lazy_observer.Wait();
944}
945
Han Leond717ddc2018-05-03 00:33:14946// Flaky: http://crbug/834200.
947IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest,
948 DISABLED_EventsAfterRestart) {
Istiaque Ahmed7105f2a2017-10-07 01:11:59949 ExtensionTestMessageListener newtab_listener("hello-newtab", false);
950 content::WebContents* new_web_contents =
951 AddTab(browser(), GURL(url::kAboutBlankURL));
Istiaque Ahmed805f6a83b2017-10-05 01:23:26952 EXPECT_TRUE(new_web_contents);
953 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
954}
955
lazyboy4c82177a2016-10-18 00:04:09956// Tests that worker ref count increments while extension API function is
957// active.
Istiaque Ahmedea5ed5042017-09-25 19:00:16958IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, WorkerRefCount) {
lazyboy4c82177a2016-10-18 00:04:09959 // Extensions APIs from SW are only enabled on trunk.
960 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
961 const Extension* extension = LoadExtensionWithFlags(
962 test_data_dir_.AppendASCII("service_worker/api_worker_ref_count"),
963 kFlagNone);
964 ASSERT_TRUE(extension);
965 ui_test_utils::NavigateToURL(browser(),
966 extension->GetResourceURL("page.html"));
967 content::WebContents* web_contents =
968 browser()->tab_strip_model()->GetActiveWebContents();
969
970 ExtensionTestMessageListener worker_start_listener("WORKER STARTED", false);
971 worker_start_listener.set_failure_message("FAILURE");
972 ASSERT_TRUE(
973 content::ExecuteScript(web_contents, "window.runServiceWorker()"));
974 ASSERT_TRUE(worker_start_listener.WaitUntilSatisfied());
975
976 // Service worker should have no pending requests because it hasn't peformed
977 // any extension API request yet.
978 EXPECT_EQ(0u, GetWorkerRefCount(extension->url()));
979
980 ExtensionTestMessageListener worker_listener("CHECK_REF_COUNT", true);
981 worker_listener.set_failure_message("FAILURE");
982 ASSERT_TRUE(content::ExecuteScript(web_contents, "window.testSendMessage()"));
983 ASSERT_TRUE(worker_listener.WaitUntilSatisfied());
984
985 // Service worker should have exactly one pending request because
986 // chrome.test.sendMessage() API call is in-flight.
987 EXPECT_EQ(1u, GetWorkerRefCount(extension->url()));
988
989 // Peform another extension API request while one is ongoing.
990 {
991 ExtensionTestMessageListener listener("CHECK_REF_COUNT", true);
992 listener.set_failure_message("FAILURE");
993 ASSERT_TRUE(
994 content::ExecuteScript(web_contents, "window.testSendMessage()"));
995 ASSERT_TRUE(listener.WaitUntilSatisfied());
996
997 // Service worker currently has two extension API requests in-flight.
998 EXPECT_EQ(2u, GetWorkerRefCount(extension->url()));
999 // Finish executing the nested chrome.test.sendMessage() first.
1000 listener.Reply("Hello world");
1001 }
1002
Istiaque Ahmedb57c9752017-08-20 19:08:571003 ExtensionTestMessageListener worker_completion_listener("SUCCESS_FROM_WORKER",
1004 false);
lazyboy4c82177a2016-10-18 00:04:091005 // Finish executing chrome.test.sendMessage().
1006 worker_listener.Reply("Hello world");
Istiaque Ahmedb57c9752017-08-20 19:08:571007 EXPECT_TRUE(worker_completion_listener.WaitUntilSatisfied());
1008
1009 // The following block makes sure we have received all the IPCs related to
1010 // ref-count from the worker.
1011 {
1012 // The following roundtrip:
1013 // browser->extension->worker->extension->browser
1014 // will ensure that the worker sent the relevant ref count IPCs.
1015 std::string result;
1016 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1017 web_contents, "window.roundtripToWorker();", &result));
1018 EXPECT_EQ("roundtrip-succeeded", result);
1019
1020 // Ensure IO thread IPCs run.
Gabriel Charette01507a22017-09-27 21:30:081021 content::RunAllTasksUntilIdle();
Istiaque Ahmedb57c9752017-08-20 19:08:571022 }
lazyboy4c82177a2016-10-18 00:04:091023
1024 // The ref count should drop to 0.
1025 EXPECT_EQ(0u, GetWorkerRefCount(extension->url()));
1026}
1027
lazyboyaea32c22016-01-04 21:37:071028// This test loads a web page that has an iframe pointing to a
1029// chrome-extension:// URL. The URL is listed in the extension's
1030// web_accessible_resources. Initially the iframe is served from the extension's
1031// resource file. After verifying that, we register a Service Worker that
1032// controls the extension. Further requests to the same resource as before
1033// should now be served by the Service Worker.
1034// This test also verifies that if the requested resource exists in the manifest
1035// but is not present in the extension directory, the Service Worker can still
1036// serve the resource file.
Istiaque Ahmedea5ed5042017-09-25 19:00:161037IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, WebAccessibleResourcesIframeSrc) {
lazyboyaea32c22016-01-04 21:37:071038 const Extension* extension = LoadExtensionWithFlags(
1039 test_data_dir_.AppendASCII(
1040 "service_worker/web_accessible_resources/iframe_src"),
1041 kFlagNone);
1042 ASSERT_TRUE(extension);
1043 ASSERT_TRUE(StartEmbeddedTestServer());
falkenad185092016-06-16 06:10:021044
1045 // Service workers can only control secure contexts
1046 // (https://w3c.github.io/webappsec-secure-contexts/). For documents, this
1047 // typically means the document must have a secure origin AND all its ancestor
1048 // frames must have documents with secure origins. However, extension pages
1049 // are considered secure, even if they have an ancestor document that is an
1050 // insecure context (see GetSchemesBypassingSecureContextCheckWhitelist). So
1051 // extension service workers must be able to control an extension page
1052 // embedded in an insecure context. To test this, set up an insecure
1053 // (non-localhost, non-https) URL for the web page. This page will create
1054 // iframes that load extension pages that must be controllable by service
1055 // worker.
falkenad185092016-06-16 06:10:021056 GURL page_url =
1057 embedded_test_server()->GetURL("a.com",
1058 "/extensions/api_test/service_worker/"
1059 "web_accessible_resources/webpage.html");
1060 EXPECT_FALSE(content::IsOriginSecure(page_url));
lazyboyaea32c22016-01-04 21:37:071061
1062 content::WebContents* web_contents = AddTab(browser(), page_url);
1063 std::string result;
1064 // webpage.html will create an iframe pointing to a resource from |extension|.
1065 // Expect the resource to be served by the extension.
1066 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1067 web_contents, base::StringPrintf("window.testIframe('%s', 'iframe.html')",
1068 extension->id().c_str()),
1069 &result));
1070 EXPECT_EQ("FROM_EXTENSION_RESOURCE", result);
1071
1072 ExtensionTestMessageListener service_worker_ready_listener("SW_READY", false);
1073 EXPECT_TRUE(ExecuteScriptInBackgroundPageNoWait(
1074 extension->id(), "window.registerServiceWorker()"));
1075 EXPECT_TRUE(service_worker_ready_listener.WaitUntilSatisfied());
1076
1077 result.clear();
1078 // webpage.html will create another iframe pointing to a resource from
1079 // |extension| as before. But this time, the resource should be be served
1080 // from the Service Worker.
1081 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1082 web_contents, base::StringPrintf("window.testIframe('%s', 'iframe.html')",
1083 extension->id().c_str()),
1084 &result));
1085 EXPECT_EQ("FROM_SW_RESOURCE", result);
1086
1087 result.clear();
1088 // webpage.html will create yet another iframe pointing to a resource that
1089 // exists in the extension manifest's web_accessible_resources, but is not
1090 // present in the extension directory. Expect the resources of the iframe to
1091 // be served by the Service Worker.
1092 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1093 web_contents,
1094 base::StringPrintf("window.testIframe('%s', 'iframe_non_existent.html')",
1095 extension->id().c_str()),
1096 &result));
1097 EXPECT_EQ("FROM_SW_RESOURCE", result);
1098}
1099
Istiaque Ahmedea5ed5042017-09-25 19:00:161100IN_PROC_BROWSER_TEST_P(ServiceWorkerBackgroundSyncTest, Sync) {
Elly Fong-Jones4a4f21d2018-05-30 15:04:161101 if (IsMacViewsMode())
1102 return;
lazyboybd325ae2015-11-18 21:35:261103 const Extension* extension = LoadExtensionWithFlags(
1104 test_data_dir_.AppendASCII("service_worker/sync"), kFlagNone);
1105 ASSERT_TRUE(extension);
1106 ui_test_utils::NavigateToURL(browser(),
1107 extension->GetResourceURL("page.html"));
1108 content::WebContents* web_contents =
1109 browser()->tab_strip_model()->GetActiveWebContents();
1110
1111 // Prevent firing by going offline.
1112 content::background_sync_test_util::SetOnline(web_contents, false);
1113
1114 ExtensionTestMessageListener sync_listener("SYNC: send-chats", false);
1115 sync_listener.set_failure_message("FAIL");
1116
1117 std::string result;
1118 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
1119 web_contents, "window.runServiceWorker()", &result));
1120 ASSERT_EQ("SERVICE_WORKER_READY", result);
1121
1122 EXPECT_FALSE(sync_listener.was_satisfied());
1123 // Resume firing by going online.
1124 content::background_sync_test_util::SetOnline(web_contents, true);
1125 EXPECT_TRUE(sync_listener.WaitUntilSatisfied());
1126}
1127
Istiaque Ahmedea5ed5042017-09-25 19:00:161128IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
horo1eeddde2015-11-19 05:59:251129 FetchFromContentScriptShouldNotGoToServiceWorkerOfPage) {
1130 ASSERT_TRUE(StartEmbeddedTestServer());
1131 GURL page_url = embedded_test_server()->GetURL(
1132 "/extensions/api_test/service_worker/content_script_fetch/"
1133 "controlled_page/index.html");
1134 content::WebContents* tab =
1135 browser()->tab_strip_model()->GetActiveWebContents();
1136 ui_test_utils::NavigateToURL(browser(), page_url);
1137 content::WaitForLoadStop(tab);
1138
1139 std::string value;
1140 ASSERT_TRUE(
1141 content::ExecuteScriptAndExtractString(tab, "register();", &value));
1142 EXPECT_EQ("SW controlled", value);
1143
1144 ASSERT_TRUE(RunExtensionTest("service_worker/content_script_fetch"))
1145 << message_;
1146}
1147
Istiaque Ahmedea5ed5042017-09-25 19:00:161148IN_PROC_BROWSER_TEST_P(ServiceWorkerPushMessagingTest, OnPush) {
lazyboy561b7de2015-11-19 19:27:301149 const Extension* extension = LoadExtensionWithFlags(
1150 test_data_dir_.AppendASCII("service_worker/push_messaging"), kFlagNone);
1151 ASSERT_TRUE(extension);
1152 GURL extension_url = extension->url();
1153
1154 ASSERT_NO_FATAL_FAILURE(GrantNotificationPermissionForTest(extension_url));
1155
1156 GURL url = extension->GetResourceURL("page.html");
1157 ui_test_utils::NavigateToURL(browser(), url);
1158
1159 content::WebContents* web_contents =
1160 browser()->tab_strip_model()->GetActiveWebContents();
1161
1162 // Start the ServiceWorker.
1163 ExtensionTestMessageListener ready_listener("SERVICE_WORKER_READY", false);
1164 ready_listener.set_failure_message("SERVICE_WORKER_FAILURE");
1165 const char* kScript = "window.runServiceWorker()";
1166 EXPECT_TRUE(content::ExecuteScript(web_contents->GetMainFrame(), kScript));
1167 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
1168
1169 PushMessagingAppIdentifier app_identifier =
1170 GetAppIdentifierForServiceWorkerRegistration(0LL, extension_url);
johnmea5045732016-09-08 17:23:291171 ASSERT_EQ(app_identifier.app_id(), gcm_driver()->last_gettoken_app_id());
1172 EXPECT_EQ("1234567890", gcm_driver()->last_gettoken_authorized_entity());
lazyboy561b7de2015-11-19 19:27:301173
lazyboyd429e2582016-05-20 20:18:521174 base::RunLoop run_loop;
lazyboy561b7de2015-11-19 19:27:301175 // Send a push message via gcm and expect the ServiceWorker to receive it.
1176 ExtensionTestMessageListener push_message_listener("OK", false);
1177 push_message_listener.set_failure_message("FAIL");
1178 gcm::IncomingMessage message;
1179 message.sender_id = "1234567890";
1180 message.raw_data = "testdata";
1181 message.decrypted = true;
lazyboyd429e2582016-05-20 20:18:521182 push_service()->SetMessageCallbackForTesting(run_loop.QuitClosure());
lazyboy561b7de2015-11-19 19:27:301183 push_service()->OnMessage(app_identifier.app_id(), message);
1184 EXPECT_TRUE(push_message_listener.WaitUntilSatisfied());
lazyboyd429e2582016-05-20 20:18:521185 run_loop.Run(); // Wait until the message is handled by push service.
lazyboy561b7de2015-11-19 19:27:301186}
1187
Istiaque Ahmedea5ed5042017-09-25 19:00:161188IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, FilteredEvents) {
Istiaque Ahmed9d1666182017-09-21 23:58:181189 // Extensions APIs from SW are only enabled on trunk.
1190 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1191 ASSERT_TRUE(RunExtensionTest("service_worker/filtered_events"));
1192}
1193
Rob Wue89b90032018-02-16 19:46:081194IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, MimeHandlerView) {
1195 ASSERT_TRUE(RunExtensionTest("service_worker/mime_handler_view"));
1196}
1197
Istiaque Ahmed9ce21b32017-10-10 20:43:181198IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest,
1199 PRE_FilteredEventsAfterRestart) {
1200 LazyBackgroundObserver lazy_observer;
1201 ResultCatcher catcher;
1202 const Extension* extension = LoadExtensionWithFlags(
1203 test_data_dir_.AppendASCII(
1204 "service_worker/filtered_events_after_restart"),
1205 kFlagNone);
1206 ASSERT_TRUE(extension);
1207 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
1208
1209 // |extension|'s background page opens a tab to its resource.
1210 content::WebContents* extension_web_contents =
1211 browser()->tab_strip_model()->GetActiveWebContents();
1212 EXPECT_TRUE(content::WaitForLoadStop(extension_web_contents));
1213 EXPECT_EQ(extension->GetResourceURL("page.html").spec(),
1214 extension_web_contents->GetURL().spec());
1215 {
1216 // Let the service worker start and register a filtered listener to
1217 // chrome.webNavigation.onCommitted event.
1218 ExtensionTestMessageListener add_listener_done("listener-added", false);
1219 add_listener_done.set_failure_message("FAILURE");
1220 content::ExecuteScriptAsync(extension_web_contents,
1221 "window.runServiceWorkerAsync()");
1222 EXPECT_TRUE(add_listener_done.WaitUntilSatisfied());
1223
1224 base::RunLoop run_loop;
1225 content::StoragePartition* storage_partition =
1226 content::BrowserContext::GetDefaultStoragePartition(
1227 browser()->profile());
1228 content::StopServiceWorkerForPattern(
1229 storage_partition->GetServiceWorkerContext(),
1230 // The service worker is registered at the top level scope.
1231 extension->url(), run_loop.QuitClosure());
1232 run_loop.Run();
1233 }
1234
1235 // Close the tab to |extension|'s resource. This will also close the
1236 // extension's event page.
1237 browser()->tab_strip_model()->CloseWebContentsAt(
1238 browser()->tab_strip_model()->active_index(), TabStripModel::CLOSE_NONE);
1239 lazy_observer.Wait();
1240}
1241
Trent Apted1d8b22d2018-05-28 03:12:381242// Flaky. See https://crbug.com/844821.
Istiaque Ahmed9ce21b32017-10-10 20:43:181243IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest,
Trent Apted1d8b22d2018-05-28 03:12:381244 DISABLED_FilteredEventsAfterRestart) {
Istiaque Ahmed9ce21b32017-10-10 20:43:181245 // Create a tab to a.html, expect it to navigate to b.html. The service worker
1246 // will see two webNavigation.onCommitted events.
1247 ASSERT_TRUE(StartEmbeddedTestServer());
1248 GURL page_url = embedded_test_server()->GetURL(
1249 "/extensions/api_test/service_worker/filtered_events_after_restart/"
1250 "a.html");
1251 ExtensionTestMessageListener worker_filtered_event_listener(
1252 "PASS_FROM_WORKER", false);
1253 worker_filtered_event_listener.set_failure_message("FAIL_FROM_WORKER");
1254 content::WebContents* web_contents = AddTab(browser(), page_url);
1255 EXPECT_TRUE(web_contents);
1256 EXPECT_TRUE(worker_filtered_event_listener.WaitUntilSatisfied());
1257}
1258
Istiaque Ahmedea5ed5042017-09-25 19:00:161259// Run with both native and JS-based bindings. This ensures that both stable
1260// (JS) and experimental (native) phases work correctly with worker scripts
1261// while we launch native bindings to stable.
1262INSTANTIATE_TEST_CASE_P(ServiceWorkerTestWithNativeBindings,
1263 ServiceWorkerTest,
1264 ::testing::Values(NATIVE_BINDINGS));
1265INSTANTIATE_TEST_CASE_P(ServiceWorkerTestWithJSBindings,
1266 ServiceWorkerTest,
1267 ::testing::Values(JAVASCRIPT_BINDINGS));
1268INSTANTIATE_TEST_CASE_P(ServiceWorkerBackgroundSyncTestWithNativeBindings,
1269 ServiceWorkerBackgroundSyncTest,
1270 ::testing::Values(NATIVE_BINDINGS));
1271INSTANTIATE_TEST_CASE_P(ServiceWorkerBackgroundSyncTestWithJSBindings,
1272 ServiceWorkerBackgroundSyncTest,
1273 ::testing::Values(JAVASCRIPT_BINDINGS));
1274INSTANTIATE_TEST_CASE_P(ServiceWorkerPushMessagingTestWithNativeBindings,
1275 ServiceWorkerPushMessagingTest,
1276 ::testing::Values(NATIVE_BINDINGS));
1277INSTANTIATE_TEST_CASE_P(ServiceWorkerPushMessagingTestWithJSBindings,
1278 ServiceWorkerPushMessagingTest,
1279 ::testing::Values(JAVASCRIPT_BINDINGS));
Istiaque Ahmed805f6a83b2017-10-05 01:23:261280INSTANTIATE_TEST_CASE_P(ServiceWorkerLazyBackgroundTestWithNativeBindings,
1281 ServiceWorkerLazyBackgroundTest,
1282 ::testing::Values(NATIVE_BINDINGS));
1283INSTANTIATE_TEST_CASE_P(ServiceWorkerLazyBackgroundTestWithJSBindings,
1284 ServiceWorkerLazyBackgroundTest,
1285 ::testing::Values(JAVASCRIPT_BINDINGS));
Istiaque Ahmedccb444022018-06-19 02:11:121286INSTANTIATE_TEST_CASE_P(ServiceWorkerTestWithNativeBindings,
1287 ServiceWorkerBasedBackgroundTest,
1288 ::testing::Values(NATIVE_BINDINGS));
1289INSTANTIATE_TEST_CASE_P(ServiceWorkerTestWithJSBindings,
1290 ServiceWorkerBasedBackgroundTest,
1291 ::testing::Values(JAVASCRIPT_BINDINGS));
Istiaque Ahmedea5ed5042017-09-25 19:00:161292
annekao38685502015-07-14 17:46:391293} // namespace extensions