blob: 5532323de0d3d4b8a85e1f8836bb6445299caa1a [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"
Trent Apted4267b942017-10-27 03:25:3627#include "chrome/common/chrome_switches.h"
rdevlin.croninf5863da2015-09-10 19:21:4528#include "chrome/test/base/ui_test_utils.h"
timloh9a180ad2017-02-20 07:15:2329#include "components/content_settings/core/common/content_settings_types.h"
Peter Beverloo34139462018-04-10 14:18:0630#include "components/gcm_driver/fake_gcm_profile_service.h"
johnmea5045732016-09-08 17:23:2931#include "components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h"
sdefresne9fb67692015-08-03 18:48:2232#include "components/version_info/version_info.h"
kalman6f984ae2015-09-18 17:21:5833#include "content/public/browser/navigation_controller.h"
rdevlin.croninf5863da2015-09-10 19:21:4534#include "content/public/browser/navigation_entry.h"
lazyboy4c82177a2016-10-18 00:04:0935#include "content/public/browser/service_worker_context.h"
36#include "content/public/browser/storage_partition.h"
kalman6f984ae2015-09-18 17:21:5837#include "content/public/browser/web_contents.h"
lazyboybd325ae2015-11-18 21:35:2638#include "content/public/common/content_switches.h"
falkenad185092016-06-16 06:10:0239#include "content/public/common/origin_util.h"
kalman6f984ae2015-09-18 17:21:5840#include "content/public/common/page_type.h"
lazyboybd325ae2015-11-18 21:35:2641#include "content/public/test/background_sync_test_util.h"
annekao1db36fd2015-07-29 17:09:1642#include "content/public/test/browser_test_utils.h"
lazyboy63b994a2017-06-30 21:20:2343#include "content/public/test/service_worker_test_helpers.h"
kalman6f984ae2015-09-18 17:21:5844#include "extensions/browser/extension_host.h"
lazyboyc3e763a2015-12-09 23:09:5845#include "extensions/browser/extension_registry.h"
kalman6f984ae2015-09-18 17:21:5846#include "extensions/browser/process_manager.h"
Devlin Cronina3fe3d602017-11-22 04:47:4347#include "extensions/common/extension_features.h"
kalman6f984ae2015-09-18 17:21:5848#include "extensions/test/background_page_watcher.h"
annekao38685502015-07-14 17:46:3949#include "extensions/test/extension_test_message_listener.h"
Istiaque Ahmed805f6a83b2017-10-05 01:23:2650#include "extensions/test/result_catcher.h"
falkenad185092016-06-16 06:10:0251#include "net/dns/mock_host_resolver.h"
horo1eeddde2015-11-19 05:59:2552#include "net/test/embedded_test_server/embedded_test_server.h"
lazyboy63b994a2017-06-30 21:20:2353#include "url/url_constants.h"
annekao38685502015-07-14 17:46:3954
55namespace extensions {
56
kalman6f984ae2015-09-18 17:21:5857namespace {
58
59// Pass into ServiceWorkerTest::StartTestFromBackgroundPage to indicate that
60// registration is expected to succeed.
61std::string* const kExpectSuccess = nullptr;
62
lazyboy22eddc712015-12-10 21:16:2663// Returns the newly added WebContents.
64content::WebContents* AddTab(Browser* browser, const GURL& url) {
65 int starting_tab_count = browser->tab_strip_model()->count();
66 ui_test_utils::NavigateToURLWithDisposition(
nick3b04f322016-08-31 19:29:1967 browser, url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
lazyboy22eddc712015-12-10 21:16:2668 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
69 int tab_count = browser->tab_strip_model()->count();
70 EXPECT_EQ(starting_tab_count + 1, tab_count);
71 return browser->tab_strip_model()->GetActiveWebContents();
72}
73
Istiaque Ahmedea5ed5042017-09-25 19:00:1674enum BindingsType { NATIVE_BINDINGS, JAVASCRIPT_BINDINGS };
75
lazyboy22eddc712015-12-10 21:16:2676class WebContentsLoadStopObserver : content::WebContentsObserver {
77 public:
78 explicit WebContentsLoadStopObserver(content::WebContents* web_contents)
79 : content::WebContentsObserver(web_contents),
80 load_stop_observed_(false) {}
81
82 void WaitForLoadStop() {
83 if (load_stop_observed_)
84 return;
85 message_loop_runner_ = new content::MessageLoopRunner;
86 message_loop_runner_->Run();
87 }
88
89 private:
90 void DidStopLoading() override {
91 load_stop_observed_ = true;
92 if (message_loop_runner_)
93 message_loop_runner_->Quit();
94 }
95
96 bool load_stop_observed_;
97 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
98
99 DISALLOW_COPY_AND_ASSIGN(WebContentsLoadStopObserver);
100};
101
kalman6f984ae2015-09-18 17:21:58102} // namespace
103
Istiaque Ahmedea5ed5042017-09-25 19:00:16104class ServiceWorkerTest : public ExtensionApiTest,
105 public ::testing::WithParamInterface<BindingsType> {
annekao38685502015-07-14 17:46:39106 public:
lazyboy20167c22016-05-18 00:59:30107 ServiceWorkerTest() : current_channel_(version_info::Channel::STABLE) {}
Istiaque Ahmed7105f2a2017-10-07 01:11:59108 explicit ServiceWorkerTest(version_info::Channel channel)
109 : current_channel_(channel) {}
annekao38685502015-07-14 17:46:39110
111 ~ServiceWorkerTest() override {}
112
Devlin Cronina3fe3d602017-11-22 04:47:43113 void SetUp() override {
114 if (GetParam() == NATIVE_BINDINGS) {
115 scoped_feature_list_.InitAndEnableFeature(features::kNativeCrxBindings);
116 } else {
117 DCHECK_EQ(JAVASCRIPT_BINDINGS, GetParam());
118 scoped_feature_list_.InitAndDisableFeature(features::kNativeCrxBindings);
119 }
120 ExtensionApiTest::SetUp();
121 }
122
jam1a5b5582017-05-01 16:50:10123 void SetUpOnMainThread() override {
124 ExtensionApiTest::SetUpOnMainThread();
125 host_resolver()->AddRule("a.com", "127.0.0.1");
126 }
127
kalman6f984ae2015-09-18 17:21:58128 protected:
129 // Returns the ProcessManager for the test's profile.
130 ProcessManager* process_manager() { return ProcessManager::Get(profile()); }
131
132 // Starts running a test from the background page test extension.
133 //
134 // This registers a service worker with |script_name|, and fetches the
135 // registration result.
136 //
137 // If |error_or_null| is null (kExpectSuccess), success is expected and this
138 // will fail if there is an error.
139 // If |error_or_null| is not null, nothing is assumed, and the error (which
140 // may be empty) is written to it.
141 const Extension* StartTestFromBackgroundPage(const char* script_name,
142 std::string* error_or_null) {
143 const Extension* extension =
144 LoadExtension(test_data_dir_.AppendASCII("service_worker/background"));
145 CHECK(extension);
146 ExtensionHost* background_host =
147 process_manager()->GetBackgroundHostForExtension(extension->id());
148 CHECK(background_host);
149 std::string error;
150 CHECK(content::ExecuteScriptAndExtractString(
151 background_host->host_contents(),
152 base::StringPrintf("test.registerServiceWorker('%s')", script_name),
153 &error));
154 if (error_or_null)
155 *error_or_null = error;
156 else if (!error.empty())
157 ADD_FAILURE() << "Got unexpected error " << error;
158 return extension;
159 }
160
161 // Navigates the browser to a new tab at |url|, waits for it to load, then
162 // returns it.
163 content::WebContents* Navigate(const GURL& url) {
164 ui_test_utils::NavigateToURLWithDisposition(
nick3b04f322016-08-31 19:29:19165 browser(), url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
kalman6f984ae2015-09-18 17:21:58166 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
167 content::WebContents* web_contents =
168 browser()->tab_strip_model()->GetActiveWebContents();
169 content::WaitForLoadStop(web_contents);
170 return web_contents;
171 }
172
173 // Navigates the browser to |url| and returns the new tab's page type.
174 content::PageType NavigateAndGetPageType(const GURL& url) {
175 return Navigate(url)->GetController().GetActiveEntry()->GetPageType();
176 }
177
178 // Extracts the innerText from |contents|.
179 std::string ExtractInnerText(content::WebContents* contents) {
180 std::string inner_text;
181 if (!content::ExecuteScriptAndExtractString(
182 contents,
183 "window.domAutomationController.send(document.body.innerText)",
184 &inner_text)) {
185 ADD_FAILURE() << "Failed to get inner text for "
186 << contents->GetVisibleURL();
187 }
188 return inner_text;
189 }
190
191 // Navigates the browser to |url|, then returns the innerText of the new
192 // tab's WebContents' main frame.
193 std::string NavigateAndExtractInnerText(const GURL& url) {
194 return ExtractInnerText(Navigate(url));
195 }
196
lazyboy4c82177a2016-10-18 00:04:09197 size_t GetWorkerRefCount(const GURL& origin) {
198 content::ServiceWorkerContext* sw_context =
199 content::BrowserContext::GetDefaultStoragePartition(
200 browser()->profile())
201 ->GetServiceWorkerContext();
202 base::RunLoop run_loop;
203 size_t ref_count = 0;
204 auto set_ref_count = [](size_t* ref_count, base::RunLoop* run_loop,
205 size_t external_request_count) {
206 *ref_count = external_request_count;
207 run_loop->Quit();
208 };
209 sw_context->CountExternalRequestsForTest(
Matt Falkenhagenc5cb4282017-09-07 08:43:42210 origin, base::BindOnce(set_ref_count, &ref_count, &run_loop));
lazyboy4c82177a2016-10-18 00:04:09211 run_loop.Run();
212 return ref_count;
213 }
214
annekao38685502015-07-14 17:46:39215 private:
lazyboy20167c22016-05-18 00:59:30216 // Sets the channel to "stable".
217 // Not useful after we've opened extension Service Workers to stable
218 // channel.
219 // TODO(lazyboy): Remove this when ExtensionServiceWorkersEnabled() is
220 // removed.
annekao38685502015-07-14 17:46:39221 ScopedCurrentChannel current_channel_;
kalman6f984ae2015-09-18 17:21:58222
Devlin Cronina3fe3d602017-11-22 04:47:43223 base::test::ScopedFeatureList scoped_feature_list_;
224
annekao38685502015-07-14 17:46:39225 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerTest);
226};
227
lazyboybd325ae2015-11-18 21:35:26228class ServiceWorkerBackgroundSyncTest : public ServiceWorkerTest {
229 public:
230 ServiceWorkerBackgroundSyncTest() {}
231 ~ServiceWorkerBackgroundSyncTest() override {}
232
233 void SetUpCommandLine(base::CommandLine* command_line) override {
234 // ServiceWorkerRegistration.sync requires experimental flag.
235 command_line->AppendSwitch(
Istiaque Ahmedea5ed5042017-09-25 19:00:16236 ::switches::kEnableExperimentalWebPlatformFeatures);
lazyboybd325ae2015-11-18 21:35:26237 ServiceWorkerTest::SetUpCommandLine(command_line);
238 }
239
240 void SetUp() override {
241 content::background_sync_test_util::SetIgnoreNetworkChangeNotifier(true);
242 ServiceWorkerTest::SetUp();
243 }
244
245 private:
246 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerBackgroundSyncTest);
247};
248
lazyboy561b7de2015-11-19 19:27:30249class ServiceWorkerPushMessagingTest : public ServiceWorkerTest {
250 public:
251 ServiceWorkerPushMessagingTest()
johnmea5045732016-09-08 17:23:29252 : gcm_driver_(nullptr), push_service_(nullptr) {}
lazyboy561b7de2015-11-19 19:27:30253 ~ServiceWorkerPushMessagingTest() override {}
254
255 void GrantNotificationPermissionForTest(const GURL& url) {
256 GURL origin = url.GetOrigin();
257 DesktopNotificationProfileUtil::GrantPermission(profile(), origin);
timlohc6911802017-03-01 05:37:03258 ASSERT_EQ(CONTENT_SETTING_ALLOW,
259 PermissionManager::Get(profile())
260 ->GetPermissionStatus(CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
261 origin, origin)
262 .content_setting);
lazyboy561b7de2015-11-19 19:27:30263 }
264
265 PushMessagingAppIdentifier GetAppIdentifierForServiceWorkerRegistration(
avia2f4804a2015-12-24 23:11:13266 int64_t service_worker_registration_id,
lazyboy561b7de2015-11-19 19:27:30267 const GURL& origin) {
268 PushMessagingAppIdentifier app_identifier =
269 PushMessagingAppIdentifier::FindByServiceWorker(
270 profile(), origin, service_worker_registration_id);
271
272 EXPECT_FALSE(app_identifier.is_null());
273 return app_identifier;
274 }
275
276 // ExtensionApiTest overrides.
277 void SetUpCommandLine(base::CommandLine* command_line) override {
peter9de96272015-12-04 15:23:27278 command_line->AppendSwitch(
Istiaque Ahmedea5ed5042017-09-25 19:00:16279 ::switches::kEnableExperimentalWebPlatformFeatures);
lazyboy561b7de2015-11-19 19:27:30280 ServiceWorkerTest::SetUpCommandLine(command_line);
281 }
282 void SetUpOnMainThread() override {
miguelg9b502862017-04-24 18:13:53283 NotificationDisplayServiceFactory::GetInstance()->SetTestingFactory(
284 profile(), &StubNotificationDisplayService::FactoryForTests);
285
johnmea5045732016-09-08 17:23:29286 gcm::FakeGCMProfileService* gcm_service =
287 static_cast<gcm::FakeGCMProfileService*>(
288 gcm::GCMProfileServiceFactory::GetInstance()
289 ->SetTestingFactoryAndUse(profile(),
290 &gcm::FakeGCMProfileService::Build));
291 gcm_driver_ = static_cast<instance_id::FakeGCMDriverForInstanceID*>(
292 gcm_service->driver());
lazyboy561b7de2015-11-19 19:27:30293 push_service_ = PushMessagingServiceFactory::GetForProfile(profile());
294
295 ServiceWorkerTest::SetUpOnMainThread();
296 }
297
johnmea5045732016-09-08 17:23:29298 instance_id::FakeGCMDriverForInstanceID* gcm_driver() const {
299 return gcm_driver_;
300 }
lazyboy561b7de2015-11-19 19:27:30301 PushMessagingServiceImpl* push_service() const { return push_service_; }
302
303 private:
johnmea5045732016-09-08 17:23:29304 instance_id::FakeGCMDriverForInstanceID* gcm_driver_;
lazyboy561b7de2015-11-19 19:27:30305 PushMessagingServiceImpl* push_service_;
306
307 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerPushMessagingTest);
308};
309
Istiaque Ahmed805f6a83b2017-10-05 01:23:26310class ServiceWorkerLazyBackgroundTest : public ServiceWorkerTest {
311 public:
Istiaque Ahmed7105f2a2017-10-07 01:11:59312 ServiceWorkerLazyBackgroundTest()
313 : ServiceWorkerTest(
314 // Extensions APIs from SW are only enabled on trunk.
315 // It is important to set the channel early so that this change is
316 // visible in renderers running with service workers (and no
317 // extension).
318 version_info::Channel::UNKNOWN) {}
Istiaque Ahmed805f6a83b2017-10-05 01:23:26319 ~ServiceWorkerLazyBackgroundTest() override {}
320
321 void SetUpCommandLine(base::CommandLine* command_line) override {
322 ServiceWorkerTest::SetUpCommandLine(command_line);
323 // Disable background network activity as it can suddenly bring the Lazy
324 // Background Page alive.
325 command_line->AppendSwitch(::switches::kDisableBackgroundNetworking);
326 command_line->AppendSwitch(::switches::kNoProxyServer);
327 }
328
329 void SetUpInProcessBrowserTestFixture() override {
330 ServiceWorkerTest::SetUpInProcessBrowserTestFixture();
331 // Set shorter delays to prevent test timeouts.
332 ProcessManager::SetEventPageIdleTimeForTesting(1);
333 ProcessManager::SetEventPageSuspendingTimeForTesting(1);
334 }
335
336 private:
337 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerLazyBackgroundTest);
338};
339
Istiaque Ahmedea5ed5042017-09-25 19:00:16340IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, RegisterSucceeds) {
kalman6f984ae2015-09-18 17:21:58341 StartTestFromBackgroundPage("register.js", kExpectSuccess);
annekao38685502015-07-14 17:46:39342}
343
Istiaque Ahmedea5ed5042017-09-25 19:00:16344IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, UpdateRefreshesServiceWorker) {
Francois Doraye6fb2d02017-10-18 21:29:13345 base::ScopedAllowBlockingForTesting allow_blocking;
lazyboyc3e763a2015-12-09 23:09:58346 base::ScopedTempDir scoped_temp_dir;
347 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
348 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
349 .AppendASCII("update")
350 .AppendASCII("service_worker.pem");
vabr9142fe22016-09-08 13:19:22351 base::FilePath path_v1 =
352 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
353 .AppendASCII("update")
354 .AppendASCII("v1"),
355 scoped_temp_dir.GetPath().AppendASCII("v1.crx"),
356 pem_path, base::FilePath());
357 base::FilePath path_v2 =
358 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
359 .AppendASCII("update")
360 .AppendASCII("v2"),
361 scoped_temp_dir.GetPath().AppendASCII("v2.crx"),
362 pem_path, base::FilePath());
lazyboyc3e763a2015-12-09 23:09:58363 const char* kId = "hfaanndiiilofhfokeanhddpkfffchdi";
364
365 ExtensionTestMessageListener listener_v1("Pong from version 1", false);
366 listener_v1.set_failure_message("FAILURE_V1");
367 // Install version 1.0 of the extension.
368 ASSERT_TRUE(InstallExtension(path_v1, 1));
369 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
370 ->enabled_extensions()
371 .GetByID(kId));
372 EXPECT_TRUE(listener_v1.WaitUntilSatisfied());
373
374 ExtensionTestMessageListener listener_v2("Pong from version 2", false);
375 listener_v2.set_failure_message("FAILURE_V2");
376
377 // Update to version 2.0.
378 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
379 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
380 ->enabled_extensions()
381 .GetByID(kId));
382 EXPECT_TRUE(listener_v2.WaitUntilSatisfied());
383}
384
[email protected]2ef85d562017-09-15 18:41:52385// TODO(crbug.com/765736) Fix the test.
Istiaque Ahmedea5ed5042017-09-25 19:00:16386IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, DISABLED_UpdateWithoutSkipWaiting) {
Francois Doraye6fb2d02017-10-18 21:29:13387 base::ScopedAllowBlockingForTesting allow_blocking;
lazyboy22eddc712015-12-10 21:16:26388 base::ScopedTempDir scoped_temp_dir;
389 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
390 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
391 .AppendASCII("update_without_skip_waiting")
392 .AppendASCII("update_without_skip_waiting.pem");
vabr9142fe22016-09-08 13:19:22393 base::FilePath path_v1 =
394 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
395 .AppendASCII("update_without_skip_waiting")
396 .AppendASCII("v1"),
397 scoped_temp_dir.GetPath().AppendASCII("v1.crx"),
398 pem_path, base::FilePath());
399 base::FilePath path_v2 =
400 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
401 .AppendASCII("update_without_skip_waiting")
402 .AppendASCII("v2"),
403 scoped_temp_dir.GetPath().AppendASCII("v2.crx"),
404 pem_path, base::FilePath());
lazyboy22eddc712015-12-10 21:16:26405 const char* kId = "mhnnnflgagdakldgjpfcofkiocpdmogl";
406
407 // Install version 1.0 of the extension.
408 ASSERT_TRUE(InstallExtension(path_v1, 1));
409 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
410 ->enabled_extensions()
411 .GetByID(kId));
412 const Extension* extension = extensions::ExtensionRegistry::Get(profile())
413 ->enabled_extensions()
414 .GetByID(kId);
415
416 ExtensionTestMessageListener listener1("Pong from version 1", false);
417 listener1.set_failure_message("FAILURE");
418 content::WebContents* web_contents =
419 AddTab(browser(), extension->GetResourceURL("page.html"));
420 EXPECT_TRUE(listener1.WaitUntilSatisfied());
421
422 // Update to version 2.0.
423 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
424 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
425 ->enabled_extensions()
426 .GetByID(kId));
427 const Extension* extension_after_update =
428 extensions::ExtensionRegistry::Get(profile())
429 ->enabled_extensions()
430 .GetByID(kId);
431
432 // Service worker version 2 would be installed but it won't be controlling
433 // the extension page yet.
434 ExtensionTestMessageListener listener2("Pong from version 1", false);
435 listener2.set_failure_message("FAILURE");
436 web_contents =
437 AddTab(browser(), extension_after_update->GetResourceURL("page.html"));
438 EXPECT_TRUE(listener2.WaitUntilSatisfied());
439
440 // Navigate the tab away from the extension page so that no clients are
441 // using the service worker.
442 // Note that just closing the tab with WebContentsDestroyedWatcher doesn't
443 // seem to be enough because it returns too early.
444 WebContentsLoadStopObserver navigate_away_observer(web_contents);
445 web_contents->GetController().LoadURL(
446 GURL(url::kAboutBlankURL), content::Referrer(), ui::PAGE_TRANSITION_TYPED,
447 std::string());
448 navigate_away_observer.WaitForLoadStop();
449
450 // Now expect service worker version 2 to control the extension page.
451 ExtensionTestMessageListener listener3("Pong from version 2", false);
452 listener3.set_failure_message("FAILURE");
453 web_contents =
454 AddTab(browser(), extension_after_update->GetResourceURL("page.html"));
455 EXPECT_TRUE(listener3.WaitUntilSatisfied());
456}
457
Istiaque Ahmedea5ed5042017-09-25 19:00:16458IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, FetchArbitraryPaths) {
kalman6f984ae2015-09-18 17:21:58459 const Extension* extension =
460 StartTestFromBackgroundPage("fetch.js", kExpectSuccess);
annekao1db36fd2015-07-29 17:09:16461
kalman6f984ae2015-09-18 17:21:58462 // Open some arbirary paths. Their contents should be what the service worker
463 // responds with, which in this case is the path of the fetch.
464 EXPECT_EQ(
465 "Caught a fetch for /index.html",
466 NavigateAndExtractInnerText(extension->GetResourceURL("index.html")));
467 EXPECT_EQ("Caught a fetch for /path/to/other.html",
468 NavigateAndExtractInnerText(
469 extension->GetResourceURL("path/to/other.html")));
470 EXPECT_EQ("Caught a fetch for /some/text/file.txt",
471 NavigateAndExtractInnerText(
472 extension->GetResourceURL("some/text/file.txt")));
473 EXPECT_EQ("Caught a fetch for /no/file/extension",
474 NavigateAndExtractInnerText(
475 extension->GetResourceURL("no/file/extension")));
476 EXPECT_EQ("Caught a fetch for /",
477 NavigateAndExtractInnerText(extension->GetResourceURL("")));
annekao1db36fd2015-07-29 17:09:16478}
479
Istiaque Ahmedea5ed5042017-09-25 19:00:16480IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, SWServedBackgroundPageReceivesEvent) {
lazyboy52c3bcf2016-01-08 00:11:29481 const Extension* extension =
482 StartTestFromBackgroundPage("replace_background.js", kExpectSuccess);
483 ExtensionHost* background_page =
484 process_manager()->GetBackgroundHostForExtension(extension->id());
485 ASSERT_TRUE(background_page);
486
487 // Close the background page and start it again so that the service worker
488 // will start controlling pages.
489 background_page->Close();
490 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
491 background_page = nullptr;
Peter Kasting341e1fb2018-02-24 00:03:01492 process_manager()->WakeEventPage(extension->id(), base::DoNothing());
lazyboy52c3bcf2016-01-08 00:11:29493 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
494
495 // Since the SW is now controlling the extension, the SW serves the background
496 // script. page.html sends a message to the background script and we verify
497 // that the SW served background script correctly receives the message/event.
498 ExtensionTestMessageListener listener("onMessage/SW BG.", false);
499 listener.set_failure_message("onMessage/original BG.");
500 content::WebContents* web_contents =
501 AddTab(browser(), extension->GetResourceURL("page.html"));
502 ASSERT_TRUE(web_contents);
503 EXPECT_TRUE(listener.WaitUntilSatisfied());
504}
505
Matt Falkenhagena612fc02018-05-30 00:35:39506IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, SWServedBackgroundPage) {
kalman6f984ae2015-09-18 17:21:58507 const Extension* extension =
508 StartTestFromBackgroundPage("fetch.js", kExpectSuccess);
annekao49241182015-08-18 17:14:01509
kalman6f984ae2015-09-18 17:21:58510 std::string kExpectedInnerText = "background.html contents for testing.";
annekao49241182015-08-18 17:14:01511
kalman6f984ae2015-09-18 17:21:58512 // Sanity check that the background page has the expected content.
513 ExtensionHost* background_page =
514 process_manager()->GetBackgroundHostForExtension(extension->id());
515 ASSERT_TRUE(background_page);
516 EXPECT_EQ(kExpectedInnerText,
517 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:01518
kalman6f984ae2015-09-18 17:21:58519 // Close the background page.
520 background_page->Close();
521 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
522 background_page = nullptr;
523
524 // Start it again.
Peter Kasting341e1fb2018-02-24 00:03:01525 process_manager()->WakeEventPage(extension->id(), base::DoNothing());
kalman6f984ae2015-09-18 17:21:58526 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
527
Matt Falkenhagena612fc02018-05-30 00:35:39528 // The service worker should get a fetch event for the background page.
kalman6f984ae2015-09-18 17:21:58529 background_page =
530 process_manager()->GetBackgroundHostForExtension(extension->id());
531 ASSERT_TRUE(background_page);
532 content::WaitForLoadStop(background_page->host_contents());
533
kalman6f984ae2015-09-18 17:21:58534 EXPECT_EQ("Caught a fetch for /background.html",
535 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:01536}
537
Istiaque Ahmedea5ed5042017-09-25 19:00:16538IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:58539 ServiceWorkerPostsMessageToBackgroundClient) {
540 const Extension* extension = StartTestFromBackgroundPage(
541 "post_message_to_background_client.js", kExpectSuccess);
annekao533482222015-08-21 23:23:53542
kalman6f984ae2015-09-18 17:21:58543 // The service worker in this test simply posts a message to the background
544 // client it receives from getBackgroundClient().
545 const char* kScript =
546 "var messagePromise = null;\n"
547 "if (test.lastMessageFromServiceWorker) {\n"
548 " messagePromise = Promise.resolve(test.lastMessageFromServiceWorker);\n"
549 "} else {\n"
550 " messagePromise = test.waitForMessage(navigator.serviceWorker);\n"
551 "}\n"
552 "messagePromise.then(function(message) {\n"
553 " window.domAutomationController.send(String(message == 'success'));\n"
554 "})\n";
555 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:53556}
557
Istiaque Ahmedea5ed5042017-09-25 19:00:16558IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:58559 BackgroundPagePostsMessageToServiceWorker) {
560 const Extension* extension =
561 StartTestFromBackgroundPage("post_message_to_sw.js", kExpectSuccess);
annekao533482222015-08-21 23:23:53562
kalman6f984ae2015-09-18 17:21:58563 // The service worker in this test waits for a message, then echoes it back
564 // by posting a message to the background page via getBackgroundClient().
565 const char* kScript =
566 "var mc = new MessageChannel();\n"
567 "test.waitForMessage(mc.port1).then(function(message) {\n"
568 " window.domAutomationController.send(String(message == 'hello'));\n"
569 "});\n"
570 "test.registeredServiceWorker.postMessage(\n"
571 " {message: 'hello', port: mc.port2}, [mc.port2])\n";
572 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:53573}
574
Istiaque Ahmedea5ed5042017-09-25 19:00:16575IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
rdevlin.croninf5863da2015-09-10 19:21:45576 ServiceWorkerSuspensionOnExtensionUnload) {
kalman6f984ae2015-09-18 17:21:58577 // For this test, only hold onto the extension's ID and URL + a function to
578 // get a resource URL, because we're going to be disabling and uninstalling
579 // it, which will invalidate the pointer.
580 std::string extension_id;
581 GURL extension_url;
582 {
583 const Extension* extension =
584 StartTestFromBackgroundPage("fetch.js", kExpectSuccess);
585 extension_id = extension->id();
586 extension_url = extension->url();
587 }
588 auto get_resource_url = [&extension_url](const std::string& path) {
589 return Extension::GetResourceURL(extension_url, path);
590 };
rdevlin.croninf5863da2015-09-10 19:21:45591
kalman6f984ae2015-09-18 17:21:58592 // Fetch should route to the service worker.
593 EXPECT_EQ("Caught a fetch for /index.html",
594 NavigateAndExtractInnerText(get_resource_url("index.html")));
rdevlin.croninf5863da2015-09-10 19:21:45595
kalman6f984ae2015-09-18 17:21:58596 // Disable the extension. Opening the page should fail.
597 extension_service()->DisableExtension(extension_id,
Minh X. Nguyen45479012017-08-18 21:35:36598 disable_reason::DISABLE_USER_ACTION);
rdevlin.croninf5863da2015-09-10 19:21:45599 base::RunLoop().RunUntilIdle();
rdevlin.croninf5863da2015-09-10 19:21:45600
kalman6f984ae2015-09-18 17:21:58601 EXPECT_EQ(content::PAGE_TYPE_ERROR,
602 NavigateAndGetPageType(get_resource_url("index.html")));
603 EXPECT_EQ(content::PAGE_TYPE_ERROR,
604 NavigateAndGetPageType(get_resource_url("other.html")));
605
606 // Re-enable the extension. Opening pages should immediately start to succeed
607 // again.
rdevlin.croninf5863da2015-09-10 19:21:45608 extension_service()->EnableExtension(extension_id);
609 base::RunLoop().RunUntilIdle();
610
kalman6f984ae2015-09-18 17:21:58611 EXPECT_EQ("Caught a fetch for /index.html",
612 NavigateAndExtractInnerText(get_resource_url("index.html")));
613 EXPECT_EQ("Caught a fetch for /other.html",
614 NavigateAndExtractInnerText(get_resource_url("other.html")));
615 EXPECT_EQ("Caught a fetch for /another.html",
616 NavigateAndExtractInnerText(get_resource_url("another.html")));
rdevlin.croninf5863da2015-09-10 19:21:45617
kalman6f984ae2015-09-18 17:21:58618 // Uninstall the extension. Opening pages should fail again.
619 base::string16 error;
620 extension_service()->UninstallExtension(
Devlin Cronin218df7f2017-11-21 21:41:31621 extension_id, UninstallReason::UNINSTALL_REASON_FOR_TESTING, &error);
kalman6f984ae2015-09-18 17:21:58622 base::RunLoop().RunUntilIdle();
623
624 EXPECT_EQ(content::PAGE_TYPE_ERROR,
625 NavigateAndGetPageType(get_resource_url("index.html")));
626 EXPECT_EQ(content::PAGE_TYPE_ERROR,
627 NavigateAndGetPageType(get_resource_url("other.html")));
628 EXPECT_EQ(content::PAGE_TYPE_ERROR,
629 NavigateAndGetPageType(get_resource_url("anotherother.html")));
630 EXPECT_EQ(content::PAGE_TYPE_ERROR,
631 NavigateAndGetPageType(get_resource_url("final.html")));
632}
633
Istiaque Ahmedea5ed5042017-09-25 19:00:16634IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, BackgroundPageIsWokenIfAsleep) {
kalman6f984ae2015-09-18 17:21:58635 const Extension* extension =
636 StartTestFromBackgroundPage("wake_on_fetch.js", kExpectSuccess);
637
638 // Navigate to special URLs that this test's service worker recognises, each
639 // making a check then populating the response with either "true" or "false".
640 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
641 "background-client-is-awake")));
642 EXPECT_EQ("true", NavigateAndExtractInnerText(
643 extension->GetResourceURL("ping-background-client")));
644 // Ping more than once for good measure.
645 EXPECT_EQ("true", NavigateAndExtractInnerText(
646 extension->GetResourceURL("ping-background-client")));
647
648 // Shut down the event page. The SW should detect that it's closed, but still
649 // be able to ping it.
650 ExtensionHost* background_page =
651 process_manager()->GetBackgroundHostForExtension(extension->id());
652 ASSERT_TRUE(background_page);
653 background_page->Close();
654 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
655
656 EXPECT_EQ("false", NavigateAndExtractInnerText(extension->GetResourceURL(
657 "background-client-is-awake")));
658 EXPECT_EQ("true", NavigateAndExtractInnerText(
659 extension->GetResourceURL("ping-background-client")));
660 EXPECT_EQ("true", NavigateAndExtractInnerText(
661 extension->GetResourceURL("ping-background-client")));
662 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
663 "background-client-is-awake")));
664}
665
Istiaque Ahmedea5ed5042017-09-25 19:00:16666IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:58667 GetBackgroundClientFailsWithNoBackgroundPage) {
668 // This extension doesn't have a background page, only a tab at page.html.
669 // The service worker it registers tries to call getBackgroundClient() and
670 // should fail.
671 // Note that this also tests that service workers can be registered from tabs.
672 EXPECT_TRUE(RunExtensionSubtest("service_worker/no_background", "page.html"));
rdevlin.croninf5863da2015-09-10 19:21:45673}
674
Istiaque Ahmedea5ed5042017-09-25 19:00:16675IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, NotificationAPI) {
lazyboy6ddb7d62015-11-10 23:15:27676 EXPECT_TRUE(RunExtensionSubtest("service_worker/notifications/has_permission",
677 "page.html"));
678}
679
Istiaque Ahmedea5ed5042017-09-25 19:00:16680IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, WebAccessibleResourcesFetch) {
lazyboyaea32c22016-01-04 21:37:07681 EXPECT_TRUE(RunExtensionSubtest(
682 "service_worker/web_accessible_resources/fetch/", "page.html"));
683}
684
Olga Sharonova3e13cd92018-02-08 16:43:56685// Flaky on Linux: http://crbug/810397.
686#if defined(OS_LINUX)
687#define MAYBE_TabsCreate DISABLED_TabsCreate
688#else
689#define MAYBE_TabsCreate TabsCreate
690#endif
691IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, MAYBE_TabsCreate) {
lazyboyee4adef2016-05-24 00:55:16692 // Extensions APIs from SW are only enabled on trunk.
693 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
694 const Extension* extension = LoadExtensionWithFlags(
695 test_data_dir_.AppendASCII("service_worker/tabs_create"), kFlagNone);
696 ASSERT_TRUE(extension);
697 ui_test_utils::NavigateToURL(browser(),
698 extension->GetResourceURL("page.html"));
699 content::WebContents* web_contents =
700 browser()->tab_strip_model()->GetActiveWebContents();
701
702 int starting_tab_count = browser()->tab_strip_model()->count();
703 std::string result;
704 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
705 web_contents, "window.runServiceWorker()", &result));
706 ASSERT_EQ("chrome.tabs.create callback", result);
707 EXPECT_EQ(starting_tab_count + 1, browser()->tab_strip_model()->count());
708
709 // Check extension shutdown path.
710 UnloadExtension(extension->id());
711 EXPECT_EQ(starting_tab_count, browser()->tab_strip_model()->count());
712}
713
Istiaque Ahmedea5ed5042017-09-25 19:00:16714IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, Events) {
lazyboye7847242017-06-07 23:29:18715 // Extensions APIs from SW are only enabled on trunk.
716 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
717 const Extension* extension = LoadExtensionWithFlags(
718 test_data_dir_.AppendASCII("service_worker/events"), kFlagNone);
719 ASSERT_TRUE(extension);
720 ui_test_utils::NavigateToURL(browser(),
721 extension->GetResourceURL("page.html"));
722 content::WebContents* web_contents =
723 browser()->tab_strip_model()->GetActiveWebContents();
724 std::string result;
725 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
726 web_contents, "window.runEventTest()", &result));
727 ASSERT_EQ("chrome.tabs.onUpdated callback", result);
728}
729
Istiaque Ahmedea5ed5042017-09-25 19:00:16730IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, EventsToStoppedWorker) {
lazyboy63b994a2017-06-30 21:20:23731 // Extensions APIs from SW are only enabled on trunk.
732 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
733 const Extension* extension = LoadExtensionWithFlags(
734 test_data_dir_.AppendASCII("service_worker/events_to_stopped_worker"),
735 kFlagNone);
736 ASSERT_TRUE(extension);
737 ui_test_utils::NavigateToURL(browser(),
738 extension->GetResourceURL("page.html"));
739 content::WebContents* web_contents =
740 browser()->tab_strip_model()->GetActiveWebContents();
741 {
742 std::string result;
743 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
744 web_contents, "window.runServiceWorker()", &result));
745 ASSERT_EQ("ready", result);
746
747 base::RunLoop run_loop;
748 content::StoragePartition* storage_partition =
749 content::BrowserContext::GetDefaultStoragePartition(
750 browser()->profile());
751 content::StopServiceWorkerForPattern(
752 storage_partition->GetServiceWorkerContext(),
753 // The service worker is registered at the top level scope.
754 extension->url(), run_loop.QuitClosure());
755 run_loop.Run();
756 }
757
758 std::string result;
759 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
760 web_contents, "window.createTabThenUpdate()", &result));
761 ASSERT_EQ("chrome.tabs.onUpdated callback", result);
762}
763
Istiaque Ahmed805f6a83b2017-10-05 01:23:26764// Tests that events to service worker arrives correctly event if the owner
765// extension of the worker is not running.
766IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest,
Xida Chen1f18f462018-04-24 13:55:54767 DISABLED_EventsToStoppedExtension) {
Istiaque Ahmed805f6a83b2017-10-05 01:23:26768 LazyBackgroundObserver lazy_observer;
769 ResultCatcher catcher;
770 const Extension* extension = LoadExtensionWithFlags(
771 test_data_dir_.AppendASCII("service_worker/events_to_stopped_extension"),
772 kFlagNone);
773 ASSERT_TRUE(extension);
774 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
775
776 ProcessManager* pm = ProcessManager::Get(browser()->profile());
777 EXPECT_GT(pm->GetLazyKeepaliveCount(extension), 0);
778
779 // |extension|'s background page opens a tab to its resource.
780 content::WebContents* extension_web_contents =
781 browser()->tab_strip_model()->GetActiveWebContents();
782 EXPECT_TRUE(content::WaitForLoadStop(extension_web_contents));
783 EXPECT_EQ(extension->GetResourceURL("page.html").spec(),
784 extension_web_contents->GetURL().spec());
785 {
786 // Let the service worker start and register a listener to
787 // chrome.tabs.onCreated event.
788 ExtensionTestMessageListener add_listener_done("listener-added", false);
789 content::ExecuteScriptAsync(extension_web_contents,
790 "window.runServiceWorkerAsync()");
791 EXPECT_TRUE(add_listener_done.WaitUntilSatisfied());
792
793 base::RunLoop run_loop;
794 content::StoragePartition* storage_partition =
795 content::BrowserContext::GetDefaultStoragePartition(
796 browser()->profile());
797 content::StopServiceWorkerForPattern(
798 storage_partition->GetServiceWorkerContext(),
799 // The service worker is registered at the top level scope.
800 extension->url(), run_loop.QuitClosure());
801 run_loop.Run();
802 }
803
804 // Close the tab to |extension|'s resource. This will also close the
805 // extension's event page.
806 browser()->tab_strip_model()->CloseWebContentsAt(
807 browser()->tab_strip_model()->active_index(), TabStripModel::CLOSE_NONE);
808 lazy_observer.Wait();
809
810 // At this point both the extension worker and extension event page is not
811 // running. Since the worker registered a listener for tabs.onCreated, it
812 // will be started to dispatch the event once we create a tab.
813 ExtensionTestMessageListener newtab_listener("hello-newtab", false);
814 newtab_listener.set_failure_message("WRONG_NEWTAB");
815 content::WebContents* new_web_contents =
Istiaque Ahmed7105f2a2017-10-07 01:11:59816 AddTab(browser(), GURL(url::kAboutBlankURL));
817 EXPECT_TRUE(new_web_contents);
818 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
819}
820
821// Tests that events to service worker correctly after browser restart.
822// This test is similar to EventsToStoppedExtension, except that the event
823// delivery is verified after a browser restart.
824IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest,
825 PRE_EventsAfterRestart) {
826 LazyBackgroundObserver lazy_observer;
827 ResultCatcher catcher;
828 const Extension* extension = LoadExtensionWithFlags(
829 test_data_dir_.AppendASCII("service_worker/events_to_stopped_extension"),
830 kFlagNone);
831 ASSERT_TRUE(extension);
832 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
833
834 ProcessManager* pm = ProcessManager::Get(browser()->profile());
835 EXPECT_GT(pm->GetLazyKeepaliveCount(extension), 0);
836
837 // |extension|'s background page opens a tab to its resource.
838 content::WebContents* extension_web_contents =
839 browser()->tab_strip_model()->GetActiveWebContents();
840 EXPECT_TRUE(content::WaitForLoadStop(extension_web_contents));
841 EXPECT_EQ(extension->GetResourceURL("page.html").spec(),
842 extension_web_contents->GetURL().spec());
843 {
844 // Let the service worker start and register a listener to
845 // chrome.tabs.onCreated event.
846 ExtensionTestMessageListener add_listener_done("listener-added", false);
847 content::ExecuteScriptAsync(extension_web_contents,
848 "window.runServiceWorkerAsync()");
849 EXPECT_TRUE(add_listener_done.WaitUntilSatisfied());
850
851 base::RunLoop run_loop;
852 content::StoragePartition* storage_partition =
853 content::BrowserContext::GetDefaultStoragePartition(
854 browser()->profile());
855 content::StopServiceWorkerForPattern(
856 storage_partition->GetServiceWorkerContext(),
857 // The service worker is registered at the top level scope.
858 extension->url(), run_loop.QuitClosure());
859 run_loop.Run();
860 }
861
862 // Close the tab to |extension|'s resource. This will also close the
863 // extension's event page.
864 browser()->tab_strip_model()->CloseWebContentsAt(
865 browser()->tab_strip_model()->active_index(), TabStripModel::CLOSE_NONE);
866 lazy_observer.Wait();
867}
868
Han Leond717ddc2018-05-03 00:33:14869// Flaky: http://crbug/834200.
870IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest,
871 DISABLED_EventsAfterRestart) {
Istiaque Ahmed7105f2a2017-10-07 01:11:59872 ExtensionTestMessageListener newtab_listener("hello-newtab", false);
873 content::WebContents* new_web_contents =
874 AddTab(browser(), GURL(url::kAboutBlankURL));
Istiaque Ahmed805f6a83b2017-10-05 01:23:26875 EXPECT_TRUE(new_web_contents);
876 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
877}
878
lazyboy4c82177a2016-10-18 00:04:09879// Tests that worker ref count increments while extension API function is
880// active.
Istiaque Ahmedea5ed5042017-09-25 19:00:16881IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, WorkerRefCount) {
lazyboy4c82177a2016-10-18 00:04:09882 // Extensions APIs from SW are only enabled on trunk.
883 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
884 const Extension* extension = LoadExtensionWithFlags(
885 test_data_dir_.AppendASCII("service_worker/api_worker_ref_count"),
886 kFlagNone);
887 ASSERT_TRUE(extension);
888 ui_test_utils::NavigateToURL(browser(),
889 extension->GetResourceURL("page.html"));
890 content::WebContents* web_contents =
891 browser()->tab_strip_model()->GetActiveWebContents();
892
893 ExtensionTestMessageListener worker_start_listener("WORKER STARTED", false);
894 worker_start_listener.set_failure_message("FAILURE");
895 ASSERT_TRUE(
896 content::ExecuteScript(web_contents, "window.runServiceWorker()"));
897 ASSERT_TRUE(worker_start_listener.WaitUntilSatisfied());
898
899 // Service worker should have no pending requests because it hasn't peformed
900 // any extension API request yet.
901 EXPECT_EQ(0u, GetWorkerRefCount(extension->url()));
902
903 ExtensionTestMessageListener worker_listener("CHECK_REF_COUNT", true);
904 worker_listener.set_failure_message("FAILURE");
905 ASSERT_TRUE(content::ExecuteScript(web_contents, "window.testSendMessage()"));
906 ASSERT_TRUE(worker_listener.WaitUntilSatisfied());
907
908 // Service worker should have exactly one pending request because
909 // chrome.test.sendMessage() API call is in-flight.
910 EXPECT_EQ(1u, GetWorkerRefCount(extension->url()));
911
912 // Peform another extension API request while one is ongoing.
913 {
914 ExtensionTestMessageListener listener("CHECK_REF_COUNT", true);
915 listener.set_failure_message("FAILURE");
916 ASSERT_TRUE(
917 content::ExecuteScript(web_contents, "window.testSendMessage()"));
918 ASSERT_TRUE(listener.WaitUntilSatisfied());
919
920 // Service worker currently has two extension API requests in-flight.
921 EXPECT_EQ(2u, GetWorkerRefCount(extension->url()));
922 // Finish executing the nested chrome.test.sendMessage() first.
923 listener.Reply("Hello world");
924 }
925
Istiaque Ahmedb57c9752017-08-20 19:08:57926 ExtensionTestMessageListener worker_completion_listener("SUCCESS_FROM_WORKER",
927 false);
lazyboy4c82177a2016-10-18 00:04:09928 // Finish executing chrome.test.sendMessage().
929 worker_listener.Reply("Hello world");
Istiaque Ahmedb57c9752017-08-20 19:08:57930 EXPECT_TRUE(worker_completion_listener.WaitUntilSatisfied());
931
932 // The following block makes sure we have received all the IPCs related to
933 // ref-count from the worker.
934 {
935 // The following roundtrip:
936 // browser->extension->worker->extension->browser
937 // will ensure that the worker sent the relevant ref count IPCs.
938 std::string result;
939 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
940 web_contents, "window.roundtripToWorker();", &result));
941 EXPECT_EQ("roundtrip-succeeded", result);
942
943 // Ensure IO thread IPCs run.
Gabriel Charette01507a22017-09-27 21:30:08944 content::RunAllTasksUntilIdle();
Istiaque Ahmedb57c9752017-08-20 19:08:57945 }
lazyboy4c82177a2016-10-18 00:04:09946
947 // The ref count should drop to 0.
948 EXPECT_EQ(0u, GetWorkerRefCount(extension->url()));
949}
950
lazyboyaea32c22016-01-04 21:37:07951// This test loads a web page that has an iframe pointing to a
952// chrome-extension:// URL. The URL is listed in the extension's
953// web_accessible_resources. Initially the iframe is served from the extension's
954// resource file. After verifying that, we register a Service Worker that
955// controls the extension. Further requests to the same resource as before
956// should now be served by the Service Worker.
957// This test also verifies that if the requested resource exists in the manifest
958// but is not present in the extension directory, the Service Worker can still
959// serve the resource file.
Istiaque Ahmedea5ed5042017-09-25 19:00:16960IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, WebAccessibleResourcesIframeSrc) {
lazyboyaea32c22016-01-04 21:37:07961 const Extension* extension = LoadExtensionWithFlags(
962 test_data_dir_.AppendASCII(
963 "service_worker/web_accessible_resources/iframe_src"),
964 kFlagNone);
965 ASSERT_TRUE(extension);
966 ASSERT_TRUE(StartEmbeddedTestServer());
falkenad185092016-06-16 06:10:02967
968 // Service workers can only control secure contexts
969 // (https://w3c.github.io/webappsec-secure-contexts/). For documents, this
970 // typically means the document must have a secure origin AND all its ancestor
971 // frames must have documents with secure origins. However, extension pages
972 // are considered secure, even if they have an ancestor document that is an
973 // insecure context (see GetSchemesBypassingSecureContextCheckWhitelist). So
974 // extension service workers must be able to control an extension page
975 // embedded in an insecure context. To test this, set up an insecure
976 // (non-localhost, non-https) URL for the web page. This page will create
977 // iframes that load extension pages that must be controllable by service
978 // worker.
falkenad185092016-06-16 06:10:02979 GURL page_url =
980 embedded_test_server()->GetURL("a.com",
981 "/extensions/api_test/service_worker/"
982 "web_accessible_resources/webpage.html");
983 EXPECT_FALSE(content::IsOriginSecure(page_url));
lazyboyaea32c22016-01-04 21:37:07984
985 content::WebContents* web_contents = AddTab(browser(), page_url);
986 std::string result;
987 // webpage.html will create an iframe pointing to a resource from |extension|.
988 // Expect the resource to be served by the extension.
989 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
990 web_contents, base::StringPrintf("window.testIframe('%s', 'iframe.html')",
991 extension->id().c_str()),
992 &result));
993 EXPECT_EQ("FROM_EXTENSION_RESOURCE", result);
994
995 ExtensionTestMessageListener service_worker_ready_listener("SW_READY", false);
996 EXPECT_TRUE(ExecuteScriptInBackgroundPageNoWait(
997 extension->id(), "window.registerServiceWorker()"));
998 EXPECT_TRUE(service_worker_ready_listener.WaitUntilSatisfied());
999
1000 result.clear();
1001 // webpage.html will create another iframe pointing to a resource from
1002 // |extension| as before. But this time, the resource should be be served
1003 // from the Service Worker.
1004 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1005 web_contents, base::StringPrintf("window.testIframe('%s', 'iframe.html')",
1006 extension->id().c_str()),
1007 &result));
1008 EXPECT_EQ("FROM_SW_RESOURCE", result);
1009
1010 result.clear();
1011 // webpage.html will create yet another iframe pointing to a resource that
1012 // exists in the extension manifest's web_accessible_resources, but is not
1013 // present in the extension directory. Expect the resources of the iframe to
1014 // be served by the Service Worker.
1015 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1016 web_contents,
1017 base::StringPrintf("window.testIframe('%s', 'iframe_non_existent.html')",
1018 extension->id().c_str()),
1019 &result));
1020 EXPECT_EQ("FROM_SW_RESOURCE", result);
1021}
1022
Istiaque Ahmedea5ed5042017-09-25 19:00:161023IN_PROC_BROWSER_TEST_P(ServiceWorkerBackgroundSyncTest, Sync) {
lazyboybd325ae2015-11-18 21:35:261024 const Extension* extension = LoadExtensionWithFlags(
1025 test_data_dir_.AppendASCII("service_worker/sync"), kFlagNone);
1026 ASSERT_TRUE(extension);
1027 ui_test_utils::NavigateToURL(browser(),
1028 extension->GetResourceURL("page.html"));
1029 content::WebContents* web_contents =
1030 browser()->tab_strip_model()->GetActiveWebContents();
1031
1032 // Prevent firing by going offline.
1033 content::background_sync_test_util::SetOnline(web_contents, false);
1034
1035 ExtensionTestMessageListener sync_listener("SYNC: send-chats", false);
1036 sync_listener.set_failure_message("FAIL");
1037
1038 std::string result;
1039 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
1040 web_contents, "window.runServiceWorker()", &result));
1041 ASSERT_EQ("SERVICE_WORKER_READY", result);
1042
1043 EXPECT_FALSE(sync_listener.was_satisfied());
1044 // Resume firing by going online.
1045 content::background_sync_test_util::SetOnline(web_contents, true);
1046 EXPECT_TRUE(sync_listener.WaitUntilSatisfied());
1047}
1048
Istiaque Ahmedea5ed5042017-09-25 19:00:161049IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
horo1eeddde2015-11-19 05:59:251050 FetchFromContentScriptShouldNotGoToServiceWorkerOfPage) {
1051 ASSERT_TRUE(StartEmbeddedTestServer());
1052 GURL page_url = embedded_test_server()->GetURL(
1053 "/extensions/api_test/service_worker/content_script_fetch/"
1054 "controlled_page/index.html");
1055 content::WebContents* tab =
1056 browser()->tab_strip_model()->GetActiveWebContents();
1057 ui_test_utils::NavigateToURL(browser(), page_url);
1058 content::WaitForLoadStop(tab);
1059
1060 std::string value;
1061 ASSERT_TRUE(
1062 content::ExecuteScriptAndExtractString(tab, "register();", &value));
1063 EXPECT_EQ("SW controlled", value);
1064
1065 ASSERT_TRUE(RunExtensionTest("service_worker/content_script_fetch"))
1066 << message_;
1067}
1068
Istiaque Ahmedea5ed5042017-09-25 19:00:161069IN_PROC_BROWSER_TEST_P(ServiceWorkerPushMessagingTest, OnPush) {
lazyboy561b7de2015-11-19 19:27:301070 const Extension* extension = LoadExtensionWithFlags(
1071 test_data_dir_.AppendASCII("service_worker/push_messaging"), kFlagNone);
1072 ASSERT_TRUE(extension);
1073 GURL extension_url = extension->url();
1074
1075 ASSERT_NO_FATAL_FAILURE(GrantNotificationPermissionForTest(extension_url));
1076
1077 GURL url = extension->GetResourceURL("page.html");
1078 ui_test_utils::NavigateToURL(browser(), url);
1079
1080 content::WebContents* web_contents =
1081 browser()->tab_strip_model()->GetActiveWebContents();
1082
1083 // Start the ServiceWorker.
1084 ExtensionTestMessageListener ready_listener("SERVICE_WORKER_READY", false);
1085 ready_listener.set_failure_message("SERVICE_WORKER_FAILURE");
1086 const char* kScript = "window.runServiceWorker()";
1087 EXPECT_TRUE(content::ExecuteScript(web_contents->GetMainFrame(), kScript));
1088 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
1089
1090 PushMessagingAppIdentifier app_identifier =
1091 GetAppIdentifierForServiceWorkerRegistration(0LL, extension_url);
johnmea5045732016-09-08 17:23:291092 ASSERT_EQ(app_identifier.app_id(), gcm_driver()->last_gettoken_app_id());
1093 EXPECT_EQ("1234567890", gcm_driver()->last_gettoken_authorized_entity());
lazyboy561b7de2015-11-19 19:27:301094
lazyboyd429e2582016-05-20 20:18:521095 base::RunLoop run_loop;
lazyboy561b7de2015-11-19 19:27:301096 // Send a push message via gcm and expect the ServiceWorker to receive it.
1097 ExtensionTestMessageListener push_message_listener("OK", false);
1098 push_message_listener.set_failure_message("FAIL");
1099 gcm::IncomingMessage message;
1100 message.sender_id = "1234567890";
1101 message.raw_data = "testdata";
1102 message.decrypted = true;
lazyboyd429e2582016-05-20 20:18:521103 push_service()->SetMessageCallbackForTesting(run_loop.QuitClosure());
lazyboy561b7de2015-11-19 19:27:301104 push_service()->OnMessage(app_identifier.app_id(), message);
1105 EXPECT_TRUE(push_message_listener.WaitUntilSatisfied());
lazyboyd429e2582016-05-20 20:18:521106 run_loop.Run(); // Wait until the message is handled by push service.
lazyboy561b7de2015-11-19 19:27:301107}
1108
Istiaque Ahmedea5ed5042017-09-25 19:00:161109IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, FilteredEvents) {
Istiaque Ahmed9d1666182017-09-21 23:58:181110 // Extensions APIs from SW are only enabled on trunk.
1111 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1112 ASSERT_TRUE(RunExtensionTest("service_worker/filtered_events"));
1113}
1114
Rob Wue89b90032018-02-16 19:46:081115IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, MimeHandlerView) {
1116 ASSERT_TRUE(RunExtensionTest("service_worker/mime_handler_view"));
1117}
1118
Istiaque Ahmed9ce21b32017-10-10 20:43:181119IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest,
1120 PRE_FilteredEventsAfterRestart) {
1121 LazyBackgroundObserver lazy_observer;
1122 ResultCatcher catcher;
1123 const Extension* extension = LoadExtensionWithFlags(
1124 test_data_dir_.AppendASCII(
1125 "service_worker/filtered_events_after_restart"),
1126 kFlagNone);
1127 ASSERT_TRUE(extension);
1128 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
1129
1130 // |extension|'s background page opens a tab to its resource.
1131 content::WebContents* extension_web_contents =
1132 browser()->tab_strip_model()->GetActiveWebContents();
1133 EXPECT_TRUE(content::WaitForLoadStop(extension_web_contents));
1134 EXPECT_EQ(extension->GetResourceURL("page.html").spec(),
1135 extension_web_contents->GetURL().spec());
1136 {
1137 // Let the service worker start and register a filtered listener to
1138 // chrome.webNavigation.onCommitted event.
1139 ExtensionTestMessageListener add_listener_done("listener-added", false);
1140 add_listener_done.set_failure_message("FAILURE");
1141 content::ExecuteScriptAsync(extension_web_contents,
1142 "window.runServiceWorkerAsync()");
1143 EXPECT_TRUE(add_listener_done.WaitUntilSatisfied());
1144
1145 base::RunLoop run_loop;
1146 content::StoragePartition* storage_partition =
1147 content::BrowserContext::GetDefaultStoragePartition(
1148 browser()->profile());
1149 content::StopServiceWorkerForPattern(
1150 storage_partition->GetServiceWorkerContext(),
1151 // The service worker is registered at the top level scope.
1152 extension->url(), run_loop.QuitClosure());
1153 run_loop.Run();
1154 }
1155
1156 // Close the tab to |extension|'s resource. This will also close the
1157 // extension's event page.
1158 browser()->tab_strip_model()->CloseWebContentsAt(
1159 browser()->tab_strip_model()->active_index(), TabStripModel::CLOSE_NONE);
1160 lazy_observer.Wait();
1161}
1162
Trent Apted1d8b22d2018-05-28 03:12:381163// Flaky. See https://crbug.com/844821.
Istiaque Ahmed9ce21b32017-10-10 20:43:181164IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest,
Trent Apted1d8b22d2018-05-28 03:12:381165 DISABLED_FilteredEventsAfterRestart) {
Istiaque Ahmed9ce21b32017-10-10 20:43:181166 // Create a tab to a.html, expect it to navigate to b.html. The service worker
1167 // will see two webNavigation.onCommitted events.
1168 ASSERT_TRUE(StartEmbeddedTestServer());
1169 GURL page_url = embedded_test_server()->GetURL(
1170 "/extensions/api_test/service_worker/filtered_events_after_restart/"
1171 "a.html");
1172 ExtensionTestMessageListener worker_filtered_event_listener(
1173 "PASS_FROM_WORKER", false);
1174 worker_filtered_event_listener.set_failure_message("FAIL_FROM_WORKER");
1175 content::WebContents* web_contents = AddTab(browser(), page_url);
1176 EXPECT_TRUE(web_contents);
1177 EXPECT_TRUE(worker_filtered_event_listener.WaitUntilSatisfied());
1178}
1179
Istiaque Ahmedea5ed5042017-09-25 19:00:161180// Run with both native and JS-based bindings. This ensures that both stable
1181// (JS) and experimental (native) phases work correctly with worker scripts
1182// while we launch native bindings to stable.
1183INSTANTIATE_TEST_CASE_P(ServiceWorkerTestWithNativeBindings,
1184 ServiceWorkerTest,
1185 ::testing::Values(NATIVE_BINDINGS));
1186INSTANTIATE_TEST_CASE_P(ServiceWorkerTestWithJSBindings,
1187 ServiceWorkerTest,
1188 ::testing::Values(JAVASCRIPT_BINDINGS));
1189INSTANTIATE_TEST_CASE_P(ServiceWorkerBackgroundSyncTestWithNativeBindings,
1190 ServiceWorkerBackgroundSyncTest,
1191 ::testing::Values(NATIVE_BINDINGS));
1192INSTANTIATE_TEST_CASE_P(ServiceWorkerBackgroundSyncTestWithJSBindings,
1193 ServiceWorkerBackgroundSyncTest,
1194 ::testing::Values(JAVASCRIPT_BINDINGS));
1195INSTANTIATE_TEST_CASE_P(ServiceWorkerPushMessagingTestWithNativeBindings,
1196 ServiceWorkerPushMessagingTest,
1197 ::testing::Values(NATIVE_BINDINGS));
1198INSTANTIATE_TEST_CASE_P(ServiceWorkerPushMessagingTestWithJSBindings,
1199 ServiceWorkerPushMessagingTest,
1200 ::testing::Values(JAVASCRIPT_BINDINGS));
Istiaque Ahmed805f6a83b2017-10-05 01:23:261201INSTANTIATE_TEST_CASE_P(ServiceWorkerLazyBackgroundTestWithNativeBindings,
1202 ServiceWorkerLazyBackgroundTest,
1203 ::testing::Values(NATIVE_BINDINGS));
1204INSTANTIATE_TEST_CASE_P(ServiceWorkerLazyBackgroundTestWithJSBindings,
1205 ServiceWorkerLazyBackgroundTest,
1206 ::testing::Values(JAVASCRIPT_BINDINGS));
Istiaque Ahmedea5ed5042017-09-25 19:00:161207
annekao38685502015-07-14 17:46:391208} // namespace extensions