blob: c594d7b8bdbce47b41fb50506d51dda25cc65d1a [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"
annekao38685502015-07-14 17:46:3913#include "chrome/browser/extensions/extension_apitest.h"
rdevlin.croninf5863da2015-09-10 19:21:4514#include "chrome/browser/extensions/extension_service.h"
Istiaque Ahmed805f6a83b2017-10-05 01:23:2615#include "chrome/browser/extensions/lazy_background_page_test_util.h"
peter9f4490a2017-01-27 00:58:3616#include "chrome/browser/gcm/fake_gcm_profile_service.h"
17#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"
Istiaque Ahmed805f6a83b2017-10-05 01:23:2627#include "chrome/common/chrome_switches.cc"
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"
johnmea5045732016-09-08 17:23:2930#include "components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h"
sdefresne9fb67692015-08-03 18:48:2231#include "components/version_info/version_info.h"
kalman6f984ae2015-09-18 17:21:5832#include "content/public/browser/navigation_controller.h"
rdevlin.croninf5863da2015-09-10 19:21:4533#include "content/public/browser/navigation_entry.h"
lazyboy4c82177a2016-10-18 00:04:0934#include "content/public/browser/service_worker_context.h"
35#include "content/public/browser/storage_partition.h"
kalman6f984ae2015-09-18 17:21:5836#include "content/public/browser/web_contents.h"
lazyboybd325ae2015-11-18 21:35:2637#include "content/public/common/content_switches.h"
falkenad185092016-06-16 06:10:0238#include "content/public/common/origin_util.h"
kalman6f984ae2015-09-18 17:21:5839#include "content/public/common/page_type.h"
lazyboybd325ae2015-11-18 21:35:2640#include "content/public/test/background_sync_test_util.h"
annekao1db36fd2015-07-29 17:09:1641#include "content/public/test/browser_test_utils.h"
lazyboy63b994a2017-06-30 21:20:2342#include "content/public/test/service_worker_test_helpers.h"
kalman6f984ae2015-09-18 17:21:5843#include "extensions/browser/extension_host.h"
lazyboyc3e763a2015-12-09 23:09:5844#include "extensions/browser/extension_registry.h"
kalman6f984ae2015-09-18 17:21:5845#include "extensions/browser/process_manager.h"
Istiaque Ahmedea5ed5042017-09-25 19:00:1646#include "extensions/common/switches.h"
kalman6f984ae2015-09-18 17:21:5847#include "extensions/test/background_page_watcher.h"
annekao38685502015-07-14 17:46:3948#include "extensions/test/extension_test_message_listener.h"
Istiaque Ahmed805f6a83b2017-10-05 01:23:2649#include "extensions/test/result_catcher.h"
falkenad185092016-06-16 06:10:0250#include "net/dns/mock_host_resolver.h"
horo1eeddde2015-11-19 05:59:2551#include "net/test/embedded_test_server/embedded_test_server.h"
lazyboy63b994a2017-06-30 21:20:2352#include "url/url_constants.h"
annekao38685502015-07-14 17:46:3953
54namespace extensions {
55
kalman6f984ae2015-09-18 17:21:5856namespace {
57
58// Pass into ServiceWorkerTest::StartTestFromBackgroundPage to indicate that
59// registration is expected to succeed.
60std::string* const kExpectSuccess = nullptr;
61
62void DoNothingWithBool(bool b) {}
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
kalman6f984ae2015-09-18 17:21:58103} // namespace
104
Istiaque Ahmedea5ed5042017-09-25 19:00:16105class ServiceWorkerTest : public ExtensionApiTest,
106 public ::testing::WithParamInterface<BindingsType> {
annekao38685502015-07-14 17:46:39107 public:
lazyboy20167c22016-05-18 00:59:30108 ServiceWorkerTest() : current_channel_(version_info::Channel::STABLE) {}
Istiaque Ahmed7105f2a2017-10-07 01:11:59109 explicit ServiceWorkerTest(version_info::Channel channel)
110 : current_channel_(channel) {}
annekao38685502015-07-14 17:46:39111
112 ~ServiceWorkerTest() override {}
113
jam1a5b5582017-05-01 16:50:10114 void SetUpOnMainThread() override {
115 ExtensionApiTest::SetUpOnMainThread();
116 host_resolver()->AddRule("a.com", "127.0.0.1");
117 }
118
Istiaque Ahmedea5ed5042017-09-25 19:00:16119 void SetUpCommandLine(base::CommandLine* command_line) override {
120 ExtensionApiTest::SetUpCommandLine(command_line);
121 command_line->AppendSwitchASCII(switches::kNativeCrxBindings,
122 GetParam() == NATIVE_BINDINGS ? "1" : "0");
123 }
124
kalman6f984ae2015-09-18 17:21:58125 protected:
126 // Returns the ProcessManager for the test's profile.
127 ProcessManager* process_manager() { return ProcessManager::Get(profile()); }
128
129 // Starts running a test from the background page test extension.
130 //
131 // This registers a service worker with |script_name|, and fetches the
132 // registration result.
133 //
134 // If |error_or_null| is null (kExpectSuccess), success is expected and this
135 // will fail if there is an error.
136 // If |error_or_null| is not null, nothing is assumed, and the error (which
137 // may be empty) is written to it.
138 const Extension* StartTestFromBackgroundPage(const char* script_name,
139 std::string* error_or_null) {
140 const Extension* extension =
141 LoadExtension(test_data_dir_.AppendASCII("service_worker/background"));
142 CHECK(extension);
143 ExtensionHost* background_host =
144 process_manager()->GetBackgroundHostForExtension(extension->id());
145 CHECK(background_host);
146 std::string error;
147 CHECK(content::ExecuteScriptAndExtractString(
148 background_host->host_contents(),
149 base::StringPrintf("test.registerServiceWorker('%s')", script_name),
150 &error));
151 if (error_or_null)
152 *error_or_null = error;
153 else if (!error.empty())
154 ADD_FAILURE() << "Got unexpected error " << error;
155 return extension;
156 }
157
158 // Navigates the browser to a new tab at |url|, waits for it to load, then
159 // returns it.
160 content::WebContents* Navigate(const GURL& url) {
161 ui_test_utils::NavigateToURLWithDisposition(
nick3b04f322016-08-31 19:29:19162 browser(), url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
kalman6f984ae2015-09-18 17:21:58163 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
164 content::WebContents* web_contents =
165 browser()->tab_strip_model()->GetActiveWebContents();
166 content::WaitForLoadStop(web_contents);
167 return web_contents;
168 }
169
170 // Navigates the browser to |url| and returns the new tab's page type.
171 content::PageType NavigateAndGetPageType(const GURL& url) {
172 return Navigate(url)->GetController().GetActiveEntry()->GetPageType();
173 }
174
175 // Extracts the innerText from |contents|.
176 std::string ExtractInnerText(content::WebContents* contents) {
177 std::string inner_text;
178 if (!content::ExecuteScriptAndExtractString(
179 contents,
180 "window.domAutomationController.send(document.body.innerText)",
181 &inner_text)) {
182 ADD_FAILURE() << "Failed to get inner text for "
183 << contents->GetVisibleURL();
184 }
185 return inner_text;
186 }
187
188 // Navigates the browser to |url|, then returns the innerText of the new
189 // tab's WebContents' main frame.
190 std::string NavigateAndExtractInnerText(const GURL& url) {
191 return ExtractInnerText(Navigate(url));
192 }
193
lazyboy4c82177a2016-10-18 00:04:09194 size_t GetWorkerRefCount(const GURL& origin) {
195 content::ServiceWorkerContext* sw_context =
196 content::BrowserContext::GetDefaultStoragePartition(
197 browser()->profile())
198 ->GetServiceWorkerContext();
199 base::RunLoop run_loop;
200 size_t ref_count = 0;
201 auto set_ref_count = [](size_t* ref_count, base::RunLoop* run_loop,
202 size_t external_request_count) {
203 *ref_count = external_request_count;
204 run_loop->Quit();
205 };
206 sw_context->CountExternalRequestsForTest(
Matt Falkenhagenc5cb4282017-09-07 08:43:42207 origin, base::BindOnce(set_ref_count, &ref_count, &run_loop));
lazyboy4c82177a2016-10-18 00:04:09208 run_loop.Run();
209 return ref_count;
210 }
211
annekao38685502015-07-14 17:46:39212 private:
lazyboy20167c22016-05-18 00:59:30213 // Sets the channel to "stable".
214 // Not useful after we've opened extension Service Workers to stable
215 // channel.
216 // TODO(lazyboy): Remove this when ExtensionServiceWorkersEnabled() is
217 // removed.
annekao38685502015-07-14 17:46:39218 ScopedCurrentChannel current_channel_;
kalman6f984ae2015-09-18 17:21:58219
annekao38685502015-07-14 17:46:39220 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerTest);
221};
222
lazyboybd325ae2015-11-18 21:35:26223class ServiceWorkerBackgroundSyncTest : public ServiceWorkerTest {
224 public:
225 ServiceWorkerBackgroundSyncTest() {}
226 ~ServiceWorkerBackgroundSyncTest() override {}
227
228 void SetUpCommandLine(base::CommandLine* command_line) override {
229 // ServiceWorkerRegistration.sync requires experimental flag.
230 command_line->AppendSwitch(
Istiaque Ahmedea5ed5042017-09-25 19:00:16231 ::switches::kEnableExperimentalWebPlatformFeatures);
lazyboybd325ae2015-11-18 21:35:26232 ServiceWorkerTest::SetUpCommandLine(command_line);
233 }
234
235 void SetUp() override {
236 content::background_sync_test_util::SetIgnoreNetworkChangeNotifier(true);
237 ServiceWorkerTest::SetUp();
238 }
239
240 private:
241 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerBackgroundSyncTest);
242};
243
lazyboy561b7de2015-11-19 19:27:30244class ServiceWorkerPushMessagingTest : public ServiceWorkerTest {
245 public:
246 ServiceWorkerPushMessagingTest()
johnmea5045732016-09-08 17:23:29247 : gcm_driver_(nullptr), push_service_(nullptr) {}
lazyboy561b7de2015-11-19 19:27:30248 ~ServiceWorkerPushMessagingTest() override {}
249
250 void GrantNotificationPermissionForTest(const GURL& url) {
251 GURL origin = url.GetOrigin();
252 DesktopNotificationProfileUtil::GrantPermission(profile(), origin);
timlohc6911802017-03-01 05:37:03253 ASSERT_EQ(CONTENT_SETTING_ALLOW,
254 PermissionManager::Get(profile())
255 ->GetPermissionStatus(CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
256 origin, origin)
257 .content_setting);
lazyboy561b7de2015-11-19 19:27:30258 }
259
260 PushMessagingAppIdentifier GetAppIdentifierForServiceWorkerRegistration(
avia2f4804a2015-12-24 23:11:13261 int64_t service_worker_registration_id,
lazyboy561b7de2015-11-19 19:27:30262 const GURL& origin) {
263 PushMessagingAppIdentifier app_identifier =
264 PushMessagingAppIdentifier::FindByServiceWorker(
265 profile(), origin, service_worker_registration_id);
266
267 EXPECT_FALSE(app_identifier.is_null());
268 return app_identifier;
269 }
270
271 // ExtensionApiTest overrides.
272 void SetUpCommandLine(base::CommandLine* command_line) override {
peter9de96272015-12-04 15:23:27273 command_line->AppendSwitch(
Istiaque Ahmedea5ed5042017-09-25 19:00:16274 ::switches::kEnableExperimentalWebPlatformFeatures);
lazyboy561b7de2015-11-19 19:27:30275 ServiceWorkerTest::SetUpCommandLine(command_line);
276 }
277 void SetUpOnMainThread() override {
miguelg9b502862017-04-24 18:13:53278 NotificationDisplayServiceFactory::GetInstance()->SetTestingFactory(
279 profile(), &StubNotificationDisplayService::FactoryForTests);
280
johnmea5045732016-09-08 17:23:29281 gcm::FakeGCMProfileService* gcm_service =
282 static_cast<gcm::FakeGCMProfileService*>(
283 gcm::GCMProfileServiceFactory::GetInstance()
284 ->SetTestingFactoryAndUse(profile(),
285 &gcm::FakeGCMProfileService::Build));
286 gcm_driver_ = static_cast<instance_id::FakeGCMDriverForInstanceID*>(
287 gcm_service->driver());
lazyboy561b7de2015-11-19 19:27:30288 push_service_ = PushMessagingServiceFactory::GetForProfile(profile());
289
290 ServiceWorkerTest::SetUpOnMainThread();
291 }
292
johnmea5045732016-09-08 17:23:29293 instance_id::FakeGCMDriverForInstanceID* gcm_driver() const {
294 return gcm_driver_;
295 }
lazyboy561b7de2015-11-19 19:27:30296 PushMessagingServiceImpl* push_service() const { return push_service_; }
297
298 private:
johnmea5045732016-09-08 17:23:29299 instance_id::FakeGCMDriverForInstanceID* gcm_driver_;
lazyboy561b7de2015-11-19 19:27:30300 PushMessagingServiceImpl* push_service_;
301
302 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerPushMessagingTest);
303};
304
Istiaque Ahmed805f6a83b2017-10-05 01:23:26305class ServiceWorkerLazyBackgroundTest : public ServiceWorkerTest {
306 public:
Istiaque Ahmed7105f2a2017-10-07 01:11:59307 ServiceWorkerLazyBackgroundTest()
308 : ServiceWorkerTest(
309 // Extensions APIs from SW are only enabled on trunk.
310 // It is important to set the channel early so that this change is
311 // visible in renderers running with service workers (and no
312 // extension).
313 version_info::Channel::UNKNOWN) {}
Istiaque Ahmed805f6a83b2017-10-05 01:23:26314 ~ServiceWorkerLazyBackgroundTest() override {}
315
316 void SetUpCommandLine(base::CommandLine* command_line) override {
317 ServiceWorkerTest::SetUpCommandLine(command_line);
318 // Disable background network activity as it can suddenly bring the Lazy
319 // Background Page alive.
320 command_line->AppendSwitch(::switches::kDisableBackgroundNetworking);
321 command_line->AppendSwitch(::switches::kNoProxyServer);
322 }
323
324 void SetUpInProcessBrowserTestFixture() override {
325 ServiceWorkerTest::SetUpInProcessBrowserTestFixture();
326 // Set shorter delays to prevent test timeouts.
327 ProcessManager::SetEventPageIdleTimeForTesting(1);
328 ProcessManager::SetEventPageSuspendingTimeForTesting(1);
329 }
330
331 private:
332 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerLazyBackgroundTest);
333};
334
Istiaque Ahmedea5ed5042017-09-25 19:00:16335IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, RegisterSucceeds) {
kalman6f984ae2015-09-18 17:21:58336 StartTestFromBackgroundPage("register.js", kExpectSuccess);
annekao38685502015-07-14 17:46:39337}
338
Istiaque Ahmedea5ed5042017-09-25 19:00:16339IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, UpdateRefreshesServiceWorker) {
jam3f2d3932017-04-26 20:28:51340 base::ThreadRestrictions::ScopedAllowIO allow_io;
lazyboyc3e763a2015-12-09 23:09:58341 base::ScopedTempDir scoped_temp_dir;
342 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
343 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
344 .AppendASCII("update")
345 .AppendASCII("service_worker.pem");
vabr9142fe22016-09-08 13:19:22346 base::FilePath path_v1 =
347 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
348 .AppendASCII("update")
349 .AppendASCII("v1"),
350 scoped_temp_dir.GetPath().AppendASCII("v1.crx"),
351 pem_path, base::FilePath());
352 base::FilePath path_v2 =
353 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
354 .AppendASCII("update")
355 .AppendASCII("v2"),
356 scoped_temp_dir.GetPath().AppendASCII("v2.crx"),
357 pem_path, base::FilePath());
lazyboyc3e763a2015-12-09 23:09:58358 const char* kId = "hfaanndiiilofhfokeanhddpkfffchdi";
359
360 ExtensionTestMessageListener listener_v1("Pong from version 1", false);
361 listener_v1.set_failure_message("FAILURE_V1");
362 // Install version 1.0 of the extension.
363 ASSERT_TRUE(InstallExtension(path_v1, 1));
364 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
365 ->enabled_extensions()
366 .GetByID(kId));
367 EXPECT_TRUE(listener_v1.WaitUntilSatisfied());
368
369 ExtensionTestMessageListener listener_v2("Pong from version 2", false);
370 listener_v2.set_failure_message("FAILURE_V2");
371
372 // Update to version 2.0.
373 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
374 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
375 ->enabled_extensions()
376 .GetByID(kId));
377 EXPECT_TRUE(listener_v2.WaitUntilSatisfied());
378}
379
[email protected]2ef85d562017-09-15 18:41:52380// TODO(crbug.com/765736) Fix the test.
Istiaque Ahmedea5ed5042017-09-25 19:00:16381IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, DISABLED_UpdateWithoutSkipWaiting) {
jam3f2d3932017-04-26 20:28:51382 base::ThreadRestrictions::ScopedAllowIO allow_io;
lazyboy22eddc712015-12-10 21:16:26383 base::ScopedTempDir scoped_temp_dir;
384 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
385 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
386 .AppendASCII("update_without_skip_waiting")
387 .AppendASCII("update_without_skip_waiting.pem");
vabr9142fe22016-09-08 13:19:22388 base::FilePath path_v1 =
389 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
390 .AppendASCII("update_without_skip_waiting")
391 .AppendASCII("v1"),
392 scoped_temp_dir.GetPath().AppendASCII("v1.crx"),
393 pem_path, base::FilePath());
394 base::FilePath path_v2 =
395 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
396 .AppendASCII("update_without_skip_waiting")
397 .AppendASCII("v2"),
398 scoped_temp_dir.GetPath().AppendASCII("v2.crx"),
399 pem_path, base::FilePath());
lazyboy22eddc712015-12-10 21:16:26400 const char* kId = "mhnnnflgagdakldgjpfcofkiocpdmogl";
401
402 // Install version 1.0 of the extension.
403 ASSERT_TRUE(InstallExtension(path_v1, 1));
404 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
405 ->enabled_extensions()
406 .GetByID(kId));
407 const Extension* extension = extensions::ExtensionRegistry::Get(profile())
408 ->enabled_extensions()
409 .GetByID(kId);
410
411 ExtensionTestMessageListener listener1("Pong from version 1", false);
412 listener1.set_failure_message("FAILURE");
413 content::WebContents* web_contents =
414 AddTab(browser(), extension->GetResourceURL("page.html"));
415 EXPECT_TRUE(listener1.WaitUntilSatisfied());
416
417 // Update to version 2.0.
418 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
419 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
420 ->enabled_extensions()
421 .GetByID(kId));
422 const Extension* extension_after_update =
423 extensions::ExtensionRegistry::Get(profile())
424 ->enabled_extensions()
425 .GetByID(kId);
426
427 // Service worker version 2 would be installed but it won't be controlling
428 // the extension page yet.
429 ExtensionTestMessageListener listener2("Pong from version 1", false);
430 listener2.set_failure_message("FAILURE");
431 web_contents =
432 AddTab(browser(), extension_after_update->GetResourceURL("page.html"));
433 EXPECT_TRUE(listener2.WaitUntilSatisfied());
434
435 // Navigate the tab away from the extension page so that no clients are
436 // using the service worker.
437 // Note that just closing the tab with WebContentsDestroyedWatcher doesn't
438 // seem to be enough because it returns too early.
439 WebContentsLoadStopObserver navigate_away_observer(web_contents);
440 web_contents->GetController().LoadURL(
441 GURL(url::kAboutBlankURL), content::Referrer(), ui::PAGE_TRANSITION_TYPED,
442 std::string());
443 navigate_away_observer.WaitForLoadStop();
444
445 // Now expect service worker version 2 to control the extension page.
446 ExtensionTestMessageListener listener3("Pong from version 2", false);
447 listener3.set_failure_message("FAILURE");
448 web_contents =
449 AddTab(browser(), extension_after_update->GetResourceURL("page.html"));
450 EXPECT_TRUE(listener3.WaitUntilSatisfied());
451}
452
Istiaque Ahmedea5ed5042017-09-25 19:00:16453IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, FetchArbitraryPaths) {
kalman6f984ae2015-09-18 17:21:58454 const Extension* extension =
455 StartTestFromBackgroundPage("fetch.js", kExpectSuccess);
annekao1db36fd2015-07-29 17:09:16456
kalman6f984ae2015-09-18 17:21:58457 // Open some arbirary paths. Their contents should be what the service worker
458 // responds with, which in this case is the path of the fetch.
459 EXPECT_EQ(
460 "Caught a fetch for /index.html",
461 NavigateAndExtractInnerText(extension->GetResourceURL("index.html")));
462 EXPECT_EQ("Caught a fetch for /path/to/other.html",
463 NavigateAndExtractInnerText(
464 extension->GetResourceURL("path/to/other.html")));
465 EXPECT_EQ("Caught a fetch for /some/text/file.txt",
466 NavigateAndExtractInnerText(
467 extension->GetResourceURL("some/text/file.txt")));
468 EXPECT_EQ("Caught a fetch for /no/file/extension",
469 NavigateAndExtractInnerText(
470 extension->GetResourceURL("no/file/extension")));
471 EXPECT_EQ("Caught a fetch for /",
472 NavigateAndExtractInnerText(extension->GetResourceURL("")));
annekao1db36fd2015-07-29 17:09:16473}
474
Istiaque Ahmedea5ed5042017-09-25 19:00:16475IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, SWServedBackgroundPageReceivesEvent) {
lazyboy52c3bcf2016-01-08 00:11:29476 const Extension* extension =
477 StartTestFromBackgroundPage("replace_background.js", kExpectSuccess);
478 ExtensionHost* background_page =
479 process_manager()->GetBackgroundHostForExtension(extension->id());
480 ASSERT_TRUE(background_page);
481
482 // Close the background page and start it again so that the service worker
483 // will start controlling pages.
484 background_page->Close();
485 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
486 background_page = nullptr;
487 process_manager()->WakeEventPage(extension->id(),
488 base::Bind(&DoNothingWithBool));
489 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
490
491 // Since the SW is now controlling the extension, the SW serves the background
492 // script. page.html sends a message to the background script and we verify
493 // that the SW served background script correctly receives the message/event.
494 ExtensionTestMessageListener listener("onMessage/SW BG.", false);
495 listener.set_failure_message("onMessage/original BG.");
496 content::WebContents* web_contents =
497 AddTab(browser(), extension->GetResourceURL("page.html"));
498 ASSERT_TRUE(web_contents);
499 EXPECT_TRUE(listener.WaitUntilSatisfied());
500}
501
Istiaque Ahmedea5ed5042017-09-25 19:00:16502IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:58503 LoadingBackgroundPageBypassesServiceWorker) {
504 const Extension* extension =
505 StartTestFromBackgroundPage("fetch.js", kExpectSuccess);
annekao49241182015-08-18 17:14:01506
kalman6f984ae2015-09-18 17:21:58507 std::string kExpectedInnerText = "background.html contents for testing.";
annekao49241182015-08-18 17:14:01508
kalman6f984ae2015-09-18 17:21:58509 // Sanity check that the background page has the expected content.
510 ExtensionHost* background_page =
511 process_manager()->GetBackgroundHostForExtension(extension->id());
512 ASSERT_TRUE(background_page);
513 EXPECT_EQ(kExpectedInnerText,
514 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:01515
kalman6f984ae2015-09-18 17:21:58516 // Close the background page.
517 background_page->Close();
518 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
519 background_page = nullptr;
520
521 // Start it again.
522 process_manager()->WakeEventPage(extension->id(),
523 base::Bind(&DoNothingWithBool));
524 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
525
526 // Content should not have been affected by the fetch, which would otherwise
527 // be "Caught fetch for...".
528 background_page =
529 process_manager()->GetBackgroundHostForExtension(extension->id());
530 ASSERT_TRUE(background_page);
531 content::WaitForLoadStop(background_page->host_contents());
532
533 // TODO(kalman): Everything you've read has been a LIE! It should be:
534 //
535 // EXPECT_EQ(kExpectedInnerText,
536 // ExtractInnerText(background_page->host_contents()));
537 //
538 // but there is a bug, and we're actually *not* bypassing the service worker
539 // for background page loads! For now, let it pass (assert wrong behavior)
540 // because it's not a regression, but this must be fixed eventually.
541 //
542 // Tracked in crbug.com/532720.
543 EXPECT_EQ("Caught a fetch for /background.html",
544 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:01545}
546
Istiaque Ahmedea5ed5042017-09-25 19:00:16547IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:58548 ServiceWorkerPostsMessageToBackgroundClient) {
549 const Extension* extension = StartTestFromBackgroundPage(
550 "post_message_to_background_client.js", kExpectSuccess);
annekao533482222015-08-21 23:23:53551
kalman6f984ae2015-09-18 17:21:58552 // The service worker in this test simply posts a message to the background
553 // client it receives from getBackgroundClient().
554 const char* kScript =
555 "var messagePromise = null;\n"
556 "if (test.lastMessageFromServiceWorker) {\n"
557 " messagePromise = Promise.resolve(test.lastMessageFromServiceWorker);\n"
558 "} else {\n"
559 " messagePromise = test.waitForMessage(navigator.serviceWorker);\n"
560 "}\n"
561 "messagePromise.then(function(message) {\n"
562 " window.domAutomationController.send(String(message == 'success'));\n"
563 "})\n";
564 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:53565}
566
Istiaque Ahmedea5ed5042017-09-25 19:00:16567IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:58568 BackgroundPagePostsMessageToServiceWorker) {
569 const Extension* extension =
570 StartTestFromBackgroundPage("post_message_to_sw.js", kExpectSuccess);
annekao533482222015-08-21 23:23:53571
kalman6f984ae2015-09-18 17:21:58572 // The service worker in this test waits for a message, then echoes it back
573 // by posting a message to the background page via getBackgroundClient().
574 const char* kScript =
575 "var mc = new MessageChannel();\n"
576 "test.waitForMessage(mc.port1).then(function(message) {\n"
577 " window.domAutomationController.send(String(message == 'hello'));\n"
578 "});\n"
579 "test.registeredServiceWorker.postMessage(\n"
580 " {message: 'hello', port: mc.port2}, [mc.port2])\n";
581 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:53582}
583
Istiaque Ahmedea5ed5042017-09-25 19:00:16584IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
rdevlin.croninf5863da2015-09-10 19:21:45585 ServiceWorkerSuspensionOnExtensionUnload) {
kalman6f984ae2015-09-18 17:21:58586 // For this test, only hold onto the extension's ID and URL + a function to
587 // get a resource URL, because we're going to be disabling and uninstalling
588 // it, which will invalidate the pointer.
589 std::string extension_id;
590 GURL extension_url;
591 {
592 const Extension* extension =
593 StartTestFromBackgroundPage("fetch.js", kExpectSuccess);
594 extension_id = extension->id();
595 extension_url = extension->url();
596 }
597 auto get_resource_url = [&extension_url](const std::string& path) {
598 return Extension::GetResourceURL(extension_url, path);
599 };
rdevlin.croninf5863da2015-09-10 19:21:45600
kalman6f984ae2015-09-18 17:21:58601 // Fetch should route to the service worker.
602 EXPECT_EQ("Caught a fetch for /index.html",
603 NavigateAndExtractInnerText(get_resource_url("index.html")));
rdevlin.croninf5863da2015-09-10 19:21:45604
kalman6f984ae2015-09-18 17:21:58605 // Disable the extension. Opening the page should fail.
606 extension_service()->DisableExtension(extension_id,
Minh X. Nguyen45479012017-08-18 21:35:36607 disable_reason::DISABLE_USER_ACTION);
rdevlin.croninf5863da2015-09-10 19:21:45608 base::RunLoop().RunUntilIdle();
rdevlin.croninf5863da2015-09-10 19:21:45609
kalman6f984ae2015-09-18 17:21:58610 EXPECT_EQ(content::PAGE_TYPE_ERROR,
611 NavigateAndGetPageType(get_resource_url("index.html")));
612 EXPECT_EQ(content::PAGE_TYPE_ERROR,
613 NavigateAndGetPageType(get_resource_url("other.html")));
614
615 // Re-enable the extension. Opening pages should immediately start to succeed
616 // again.
rdevlin.croninf5863da2015-09-10 19:21:45617 extension_service()->EnableExtension(extension_id);
618 base::RunLoop().RunUntilIdle();
619
kalman6f984ae2015-09-18 17:21:58620 EXPECT_EQ("Caught a fetch for /index.html",
621 NavigateAndExtractInnerText(get_resource_url("index.html")));
622 EXPECT_EQ("Caught a fetch for /other.html",
623 NavigateAndExtractInnerText(get_resource_url("other.html")));
624 EXPECT_EQ("Caught a fetch for /another.html",
625 NavigateAndExtractInnerText(get_resource_url("another.html")));
rdevlin.croninf5863da2015-09-10 19:21:45626
kalman6f984ae2015-09-18 17:21:58627 // Uninstall the extension. Opening pages should fail again.
628 base::string16 error;
629 extension_service()->UninstallExtension(
630 extension_id, UninstallReason::UNINSTALL_REASON_FOR_TESTING,
631 base::Bind(&base::DoNothing), &error);
632 base::RunLoop().RunUntilIdle();
633
634 EXPECT_EQ(content::PAGE_TYPE_ERROR,
635 NavigateAndGetPageType(get_resource_url("index.html")));
636 EXPECT_EQ(content::PAGE_TYPE_ERROR,
637 NavigateAndGetPageType(get_resource_url("other.html")));
638 EXPECT_EQ(content::PAGE_TYPE_ERROR,
639 NavigateAndGetPageType(get_resource_url("anotherother.html")));
640 EXPECT_EQ(content::PAGE_TYPE_ERROR,
641 NavigateAndGetPageType(get_resource_url("final.html")));
642}
643
Istiaque Ahmedea5ed5042017-09-25 19:00:16644IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, BackgroundPageIsWokenIfAsleep) {
kalman6f984ae2015-09-18 17:21:58645 const Extension* extension =
646 StartTestFromBackgroundPage("wake_on_fetch.js", kExpectSuccess);
647
648 // Navigate to special URLs that this test's service worker recognises, each
649 // making a check then populating the response with either "true" or "false".
650 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
651 "background-client-is-awake")));
652 EXPECT_EQ("true", NavigateAndExtractInnerText(
653 extension->GetResourceURL("ping-background-client")));
654 // Ping more than once for good measure.
655 EXPECT_EQ("true", NavigateAndExtractInnerText(
656 extension->GetResourceURL("ping-background-client")));
657
658 // Shut down the event page. The SW should detect that it's closed, but still
659 // be able to ping it.
660 ExtensionHost* background_page =
661 process_manager()->GetBackgroundHostForExtension(extension->id());
662 ASSERT_TRUE(background_page);
663 background_page->Close();
664 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
665
666 EXPECT_EQ("false", NavigateAndExtractInnerText(extension->GetResourceURL(
667 "background-client-is-awake")));
668 EXPECT_EQ("true", NavigateAndExtractInnerText(
669 extension->GetResourceURL("ping-background-client")));
670 EXPECT_EQ("true", NavigateAndExtractInnerText(
671 extension->GetResourceURL("ping-background-client")));
672 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
673 "background-client-is-awake")));
674}
675
Istiaque Ahmedea5ed5042017-09-25 19:00:16676IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:58677 GetBackgroundClientFailsWithNoBackgroundPage) {
678 // This extension doesn't have a background page, only a tab at page.html.
679 // The service worker it registers tries to call getBackgroundClient() and
680 // should fail.
681 // Note that this also tests that service workers can be registered from tabs.
682 EXPECT_TRUE(RunExtensionSubtest("service_worker/no_background", "page.html"));
rdevlin.croninf5863da2015-09-10 19:21:45683}
684
Istiaque Ahmedea5ed5042017-09-25 19:00:16685IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, NotificationAPI) {
lazyboy6ddb7d62015-11-10 23:15:27686 EXPECT_TRUE(RunExtensionSubtest("service_worker/notifications/has_permission",
687 "page.html"));
688}
689
Istiaque Ahmedea5ed5042017-09-25 19:00:16690IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, WebAccessibleResourcesFetch) {
lazyboyaea32c22016-01-04 21:37:07691 EXPECT_TRUE(RunExtensionSubtest(
692 "service_worker/web_accessible_resources/fetch/", "page.html"));
693}
694
Istiaque Ahmedea5ed5042017-09-25 19:00:16695IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, TabsCreate) {
lazyboyee4adef2016-05-24 00:55:16696 // Extensions APIs from SW are only enabled on trunk.
697 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
698 const Extension* extension = LoadExtensionWithFlags(
699 test_data_dir_.AppendASCII("service_worker/tabs_create"), kFlagNone);
700 ASSERT_TRUE(extension);
701 ui_test_utils::NavigateToURL(browser(),
702 extension->GetResourceURL("page.html"));
703 content::WebContents* web_contents =
704 browser()->tab_strip_model()->GetActiveWebContents();
705
706 int starting_tab_count = browser()->tab_strip_model()->count();
707 std::string result;
708 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
709 web_contents, "window.runServiceWorker()", &result));
710 ASSERT_EQ("chrome.tabs.create callback", result);
711 EXPECT_EQ(starting_tab_count + 1, browser()->tab_strip_model()->count());
712
713 // Check extension shutdown path.
714 UnloadExtension(extension->id());
715 EXPECT_EQ(starting_tab_count, browser()->tab_strip_model()->count());
716}
717
Istiaque Ahmedea5ed5042017-09-25 19:00:16718IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, Events) {
lazyboye7847242017-06-07 23:29:18719 // Extensions APIs from SW are only enabled on trunk.
720 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
721 const Extension* extension = LoadExtensionWithFlags(
722 test_data_dir_.AppendASCII("service_worker/events"), kFlagNone);
723 ASSERT_TRUE(extension);
724 ui_test_utils::NavigateToURL(browser(),
725 extension->GetResourceURL("page.html"));
726 content::WebContents* web_contents =
727 browser()->tab_strip_model()->GetActiveWebContents();
728 std::string result;
729 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
730 web_contents, "window.runEventTest()", &result));
731 ASSERT_EQ("chrome.tabs.onUpdated callback", result);
732}
733
Istiaque Ahmedea5ed5042017-09-25 19:00:16734IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, EventsToStoppedWorker) {
lazyboy63b994a2017-06-30 21:20:23735 // Extensions APIs from SW are only enabled on trunk.
736 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
737 const Extension* extension = LoadExtensionWithFlags(
738 test_data_dir_.AppendASCII("service_worker/events_to_stopped_worker"),
739 kFlagNone);
740 ASSERT_TRUE(extension);
741 ui_test_utils::NavigateToURL(browser(),
742 extension->GetResourceURL("page.html"));
743 content::WebContents* web_contents =
744 browser()->tab_strip_model()->GetActiveWebContents();
745 {
746 std::string result;
747 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
748 web_contents, "window.runServiceWorker()", &result));
749 ASSERT_EQ("ready", result);
750
751 base::RunLoop run_loop;
752 content::StoragePartition* storage_partition =
753 content::BrowserContext::GetDefaultStoragePartition(
754 browser()->profile());
755 content::StopServiceWorkerForPattern(
756 storage_partition->GetServiceWorkerContext(),
757 // The service worker is registered at the top level scope.
758 extension->url(), run_loop.QuitClosure());
759 run_loop.Run();
760 }
761
762 std::string result;
763 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
764 web_contents, "window.createTabThenUpdate()", &result));
765 ASSERT_EQ("chrome.tabs.onUpdated callback", result);
766}
767
Istiaque Ahmed805f6a83b2017-10-05 01:23:26768// Tests that events to service worker arrives correctly event if the owner
769// extension of the worker is not running.
770IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest,
771 EventsToStoppedExtension) {
Istiaque Ahmed805f6a83b2017-10-05 01:23:26772 LazyBackgroundObserver lazy_observer;
773 ResultCatcher catcher;
774 const Extension* extension = LoadExtensionWithFlags(
775 test_data_dir_.AppendASCII("service_worker/events_to_stopped_extension"),
776 kFlagNone);
777 ASSERT_TRUE(extension);
778 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
779
780 ProcessManager* pm = ProcessManager::Get(browser()->profile());
781 EXPECT_GT(pm->GetLazyKeepaliveCount(extension), 0);
782
783 // |extension|'s background page opens a tab to its resource.
784 content::WebContents* extension_web_contents =
785 browser()->tab_strip_model()->GetActiveWebContents();
786 EXPECT_TRUE(content::WaitForLoadStop(extension_web_contents));
787 EXPECT_EQ(extension->GetResourceURL("page.html").spec(),
788 extension_web_contents->GetURL().spec());
789 {
790 // Let the service worker start and register a listener to
791 // chrome.tabs.onCreated event.
792 ExtensionTestMessageListener add_listener_done("listener-added", false);
793 content::ExecuteScriptAsync(extension_web_contents,
794 "window.runServiceWorkerAsync()");
795 EXPECT_TRUE(add_listener_done.WaitUntilSatisfied());
796
797 base::RunLoop run_loop;
798 content::StoragePartition* storage_partition =
799 content::BrowserContext::GetDefaultStoragePartition(
800 browser()->profile());
801 content::StopServiceWorkerForPattern(
802 storage_partition->GetServiceWorkerContext(),
803 // The service worker is registered at the top level scope.
804 extension->url(), run_loop.QuitClosure());
805 run_loop.Run();
806 }
807
808 // Close the tab to |extension|'s resource. This will also close the
809 // extension's event page.
810 browser()->tab_strip_model()->CloseWebContentsAt(
811 browser()->tab_strip_model()->active_index(), TabStripModel::CLOSE_NONE);
812 lazy_observer.Wait();
813
814 // At this point both the extension worker and extension event page is not
815 // running. Since the worker registered a listener for tabs.onCreated, it
816 // will be started to dispatch the event once we create a tab.
817 ExtensionTestMessageListener newtab_listener("hello-newtab", false);
818 newtab_listener.set_failure_message("WRONG_NEWTAB");
819 content::WebContents* new_web_contents =
Istiaque Ahmed7105f2a2017-10-07 01:11:59820 AddTab(browser(), GURL(url::kAboutBlankURL));
821 EXPECT_TRUE(new_web_contents);
822 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
823}
824
825// Tests that events to service worker correctly after browser restart.
826// This test is similar to EventsToStoppedExtension, except that the event
827// delivery is verified after a browser restart.
828IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest,
829 PRE_EventsAfterRestart) {
830 LazyBackgroundObserver lazy_observer;
831 ResultCatcher catcher;
832 const Extension* extension = LoadExtensionWithFlags(
833 test_data_dir_.AppendASCII("service_worker/events_to_stopped_extension"),
834 kFlagNone);
835 ASSERT_TRUE(extension);
836 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
837
838 ProcessManager* pm = ProcessManager::Get(browser()->profile());
839 EXPECT_GT(pm->GetLazyKeepaliveCount(extension), 0);
840
841 // |extension|'s background page opens a tab to its resource.
842 content::WebContents* extension_web_contents =
843 browser()->tab_strip_model()->GetActiveWebContents();
844 EXPECT_TRUE(content::WaitForLoadStop(extension_web_contents));
845 EXPECT_EQ(extension->GetResourceURL("page.html").spec(),
846 extension_web_contents->GetURL().spec());
847 {
848 // Let the service worker start and register a listener to
849 // chrome.tabs.onCreated event.
850 ExtensionTestMessageListener add_listener_done("listener-added", false);
851 content::ExecuteScriptAsync(extension_web_contents,
852 "window.runServiceWorkerAsync()");
853 EXPECT_TRUE(add_listener_done.WaitUntilSatisfied());
854
855 base::RunLoop run_loop;
856 content::StoragePartition* storage_partition =
857 content::BrowserContext::GetDefaultStoragePartition(
858 browser()->profile());
859 content::StopServiceWorkerForPattern(
860 storage_partition->GetServiceWorkerContext(),
861 // The service worker is registered at the top level scope.
862 extension->url(), run_loop.QuitClosure());
863 run_loop.Run();
864 }
865
866 // Close the tab to |extension|'s resource. This will also close the
867 // extension's event page.
868 browser()->tab_strip_model()->CloseWebContentsAt(
869 browser()->tab_strip_model()->active_index(), TabStripModel::CLOSE_NONE);
870 lazy_observer.Wait();
871}
872
873IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest, EventsAfterRestart) {
874 ExtensionTestMessageListener newtab_listener("hello-newtab", false);
875 content::WebContents* new_web_contents =
876 AddTab(browser(), GURL(url::kAboutBlankURL));
Istiaque Ahmed805f6a83b2017-10-05 01:23:26877 EXPECT_TRUE(new_web_contents);
878 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
879}
880
lazyboy4c82177a2016-10-18 00:04:09881// Tests that worker ref count increments while extension API function is
882// active.
Istiaque Ahmedea5ed5042017-09-25 19:00:16883IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, WorkerRefCount) {
lazyboy4c82177a2016-10-18 00:04:09884 // Extensions APIs from SW are only enabled on trunk.
885 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
886 const Extension* extension = LoadExtensionWithFlags(
887 test_data_dir_.AppendASCII("service_worker/api_worker_ref_count"),
888 kFlagNone);
889 ASSERT_TRUE(extension);
890 ui_test_utils::NavigateToURL(browser(),
891 extension->GetResourceURL("page.html"));
892 content::WebContents* web_contents =
893 browser()->tab_strip_model()->GetActiveWebContents();
894
895 ExtensionTestMessageListener worker_start_listener("WORKER STARTED", false);
896 worker_start_listener.set_failure_message("FAILURE");
897 ASSERT_TRUE(
898 content::ExecuteScript(web_contents, "window.runServiceWorker()"));
899 ASSERT_TRUE(worker_start_listener.WaitUntilSatisfied());
900
901 // Service worker should have no pending requests because it hasn't peformed
902 // any extension API request yet.
903 EXPECT_EQ(0u, GetWorkerRefCount(extension->url()));
904
905 ExtensionTestMessageListener worker_listener("CHECK_REF_COUNT", true);
906 worker_listener.set_failure_message("FAILURE");
907 ASSERT_TRUE(content::ExecuteScript(web_contents, "window.testSendMessage()"));
908 ASSERT_TRUE(worker_listener.WaitUntilSatisfied());
909
910 // Service worker should have exactly one pending request because
911 // chrome.test.sendMessage() API call is in-flight.
912 EXPECT_EQ(1u, GetWorkerRefCount(extension->url()));
913
914 // Peform another extension API request while one is ongoing.
915 {
916 ExtensionTestMessageListener listener("CHECK_REF_COUNT", true);
917 listener.set_failure_message("FAILURE");
918 ASSERT_TRUE(
919 content::ExecuteScript(web_contents, "window.testSendMessage()"));
920 ASSERT_TRUE(listener.WaitUntilSatisfied());
921
922 // Service worker currently has two extension API requests in-flight.
923 EXPECT_EQ(2u, GetWorkerRefCount(extension->url()));
924 // Finish executing the nested chrome.test.sendMessage() first.
925 listener.Reply("Hello world");
926 }
927
Istiaque Ahmedb57c9752017-08-20 19:08:57928 ExtensionTestMessageListener worker_completion_listener("SUCCESS_FROM_WORKER",
929 false);
lazyboy4c82177a2016-10-18 00:04:09930 // Finish executing chrome.test.sendMessage().
931 worker_listener.Reply("Hello world");
Istiaque Ahmedb57c9752017-08-20 19:08:57932 EXPECT_TRUE(worker_completion_listener.WaitUntilSatisfied());
933
934 // The following block makes sure we have received all the IPCs related to
935 // ref-count from the worker.
936 {
937 // The following roundtrip:
938 // browser->extension->worker->extension->browser
939 // will ensure that the worker sent the relevant ref count IPCs.
940 std::string result;
941 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
942 web_contents, "window.roundtripToWorker();", &result));
943 EXPECT_EQ("roundtrip-succeeded", result);
944
945 // Ensure IO thread IPCs run.
Gabriel Charette01507a22017-09-27 21:30:08946 content::RunAllTasksUntilIdle();
Istiaque Ahmedb57c9752017-08-20 19:08:57947 }
lazyboy4c82177a2016-10-18 00:04:09948
949 // The ref count should drop to 0.
950 EXPECT_EQ(0u, GetWorkerRefCount(extension->url()));
951}
952
lazyboyaea32c22016-01-04 21:37:07953// This test loads a web page that has an iframe pointing to a
954// chrome-extension:// URL. The URL is listed in the extension's
955// web_accessible_resources. Initially the iframe is served from the extension's
956// resource file. After verifying that, we register a Service Worker that
957// controls the extension. Further requests to the same resource as before
958// should now be served by the Service Worker.
959// This test also verifies that if the requested resource exists in the manifest
960// but is not present in the extension directory, the Service Worker can still
961// serve the resource file.
Istiaque Ahmedea5ed5042017-09-25 19:00:16962IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, WebAccessibleResourcesIframeSrc) {
lazyboyaea32c22016-01-04 21:37:07963 const Extension* extension = LoadExtensionWithFlags(
964 test_data_dir_.AppendASCII(
965 "service_worker/web_accessible_resources/iframe_src"),
966 kFlagNone);
967 ASSERT_TRUE(extension);
968 ASSERT_TRUE(StartEmbeddedTestServer());
falkenad185092016-06-16 06:10:02969
970 // Service workers can only control secure contexts
971 // (https://w3c.github.io/webappsec-secure-contexts/). For documents, this
972 // typically means the document must have a secure origin AND all its ancestor
973 // frames must have documents with secure origins. However, extension pages
974 // are considered secure, even if they have an ancestor document that is an
975 // insecure context (see GetSchemesBypassingSecureContextCheckWhitelist). So
976 // extension service workers must be able to control an extension page
977 // embedded in an insecure context. To test this, set up an insecure
978 // (non-localhost, non-https) URL for the web page. This page will create
979 // iframes that load extension pages that must be controllable by service
980 // worker.
falkenad185092016-06-16 06:10:02981 GURL page_url =
982 embedded_test_server()->GetURL("a.com",
983 "/extensions/api_test/service_worker/"
984 "web_accessible_resources/webpage.html");
985 EXPECT_FALSE(content::IsOriginSecure(page_url));
lazyboyaea32c22016-01-04 21:37:07986
987 content::WebContents* web_contents = AddTab(browser(), page_url);
988 std::string result;
989 // webpage.html will create an iframe pointing to a resource from |extension|.
990 // Expect the resource to be served by the extension.
991 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
992 web_contents, base::StringPrintf("window.testIframe('%s', 'iframe.html')",
993 extension->id().c_str()),
994 &result));
995 EXPECT_EQ("FROM_EXTENSION_RESOURCE", result);
996
997 ExtensionTestMessageListener service_worker_ready_listener("SW_READY", false);
998 EXPECT_TRUE(ExecuteScriptInBackgroundPageNoWait(
999 extension->id(), "window.registerServiceWorker()"));
1000 EXPECT_TRUE(service_worker_ready_listener.WaitUntilSatisfied());
1001
1002 result.clear();
1003 // webpage.html will create another iframe pointing to a resource from
1004 // |extension| as before. But this time, the resource should be be served
1005 // from the Service Worker.
1006 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1007 web_contents, base::StringPrintf("window.testIframe('%s', 'iframe.html')",
1008 extension->id().c_str()),
1009 &result));
1010 EXPECT_EQ("FROM_SW_RESOURCE", result);
1011
1012 result.clear();
1013 // webpage.html will create yet another iframe pointing to a resource that
1014 // exists in the extension manifest's web_accessible_resources, but is not
1015 // present in the extension directory. Expect the resources of the iframe to
1016 // be served by the Service Worker.
1017 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1018 web_contents,
1019 base::StringPrintf("window.testIframe('%s', 'iframe_non_existent.html')",
1020 extension->id().c_str()),
1021 &result));
1022 EXPECT_EQ("FROM_SW_RESOURCE", result);
1023}
1024
Istiaque Ahmedea5ed5042017-09-25 19:00:161025IN_PROC_BROWSER_TEST_P(ServiceWorkerBackgroundSyncTest, Sync) {
lazyboybd325ae2015-11-18 21:35:261026 const Extension* extension = LoadExtensionWithFlags(
1027 test_data_dir_.AppendASCII("service_worker/sync"), kFlagNone);
1028 ASSERT_TRUE(extension);
1029 ui_test_utils::NavigateToURL(browser(),
1030 extension->GetResourceURL("page.html"));
1031 content::WebContents* web_contents =
1032 browser()->tab_strip_model()->GetActiveWebContents();
1033
1034 // Prevent firing by going offline.
1035 content::background_sync_test_util::SetOnline(web_contents, false);
1036
1037 ExtensionTestMessageListener sync_listener("SYNC: send-chats", false);
1038 sync_listener.set_failure_message("FAIL");
1039
1040 std::string result;
1041 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
1042 web_contents, "window.runServiceWorker()", &result));
1043 ASSERT_EQ("SERVICE_WORKER_READY", result);
1044
1045 EXPECT_FALSE(sync_listener.was_satisfied());
1046 // Resume firing by going online.
1047 content::background_sync_test_util::SetOnline(web_contents, true);
1048 EXPECT_TRUE(sync_listener.WaitUntilSatisfied());
1049}
1050
Istiaque Ahmedea5ed5042017-09-25 19:00:161051IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
horo1eeddde2015-11-19 05:59:251052 FetchFromContentScriptShouldNotGoToServiceWorkerOfPage) {
1053 ASSERT_TRUE(StartEmbeddedTestServer());
1054 GURL page_url = embedded_test_server()->GetURL(
1055 "/extensions/api_test/service_worker/content_script_fetch/"
1056 "controlled_page/index.html");
1057 content::WebContents* tab =
1058 browser()->tab_strip_model()->GetActiveWebContents();
1059 ui_test_utils::NavigateToURL(browser(), page_url);
1060 content::WaitForLoadStop(tab);
1061
1062 std::string value;
1063 ASSERT_TRUE(
1064 content::ExecuteScriptAndExtractString(tab, "register();", &value));
1065 EXPECT_EQ("SW controlled", value);
1066
1067 ASSERT_TRUE(RunExtensionTest("service_worker/content_script_fetch"))
1068 << message_;
1069}
1070
Istiaque Ahmedea5ed5042017-09-25 19:00:161071IN_PROC_BROWSER_TEST_P(ServiceWorkerPushMessagingTest, OnPush) {
lazyboy561b7de2015-11-19 19:27:301072 const Extension* extension = LoadExtensionWithFlags(
1073 test_data_dir_.AppendASCII("service_worker/push_messaging"), kFlagNone);
1074 ASSERT_TRUE(extension);
1075 GURL extension_url = extension->url();
1076
1077 ASSERT_NO_FATAL_FAILURE(GrantNotificationPermissionForTest(extension_url));
1078
1079 GURL url = extension->GetResourceURL("page.html");
1080 ui_test_utils::NavigateToURL(browser(), url);
1081
1082 content::WebContents* web_contents =
1083 browser()->tab_strip_model()->GetActiveWebContents();
1084
1085 // Start the ServiceWorker.
1086 ExtensionTestMessageListener ready_listener("SERVICE_WORKER_READY", false);
1087 ready_listener.set_failure_message("SERVICE_WORKER_FAILURE");
1088 const char* kScript = "window.runServiceWorker()";
1089 EXPECT_TRUE(content::ExecuteScript(web_contents->GetMainFrame(), kScript));
1090 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
1091
1092 PushMessagingAppIdentifier app_identifier =
1093 GetAppIdentifierForServiceWorkerRegistration(0LL, extension_url);
johnmea5045732016-09-08 17:23:291094 ASSERT_EQ(app_identifier.app_id(), gcm_driver()->last_gettoken_app_id());
1095 EXPECT_EQ("1234567890", gcm_driver()->last_gettoken_authorized_entity());
lazyboy561b7de2015-11-19 19:27:301096
lazyboyd429e2582016-05-20 20:18:521097 base::RunLoop run_loop;
lazyboy561b7de2015-11-19 19:27:301098 // Send a push message via gcm and expect the ServiceWorker to receive it.
1099 ExtensionTestMessageListener push_message_listener("OK", false);
1100 push_message_listener.set_failure_message("FAIL");
1101 gcm::IncomingMessage message;
1102 message.sender_id = "1234567890";
1103 message.raw_data = "testdata";
1104 message.decrypted = true;
lazyboyd429e2582016-05-20 20:18:521105 push_service()->SetMessageCallbackForTesting(run_loop.QuitClosure());
lazyboy561b7de2015-11-19 19:27:301106 push_service()->OnMessage(app_identifier.app_id(), message);
1107 EXPECT_TRUE(push_message_listener.WaitUntilSatisfied());
lazyboyd429e2582016-05-20 20:18:521108 run_loop.Run(); // Wait until the message is handled by push service.
lazyboy561b7de2015-11-19 19:27:301109}
1110
Istiaque Ahmedea5ed5042017-09-25 19:00:161111IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, FilteredEvents) {
Istiaque Ahmed9d1666182017-09-21 23:58:181112 // Extensions APIs from SW are only enabled on trunk.
1113 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1114 ASSERT_TRUE(RunExtensionTest("service_worker/filtered_events"));
1115}
1116
Istiaque Ahmed9ce21b32017-10-10 20:43:181117IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest,
1118 PRE_FilteredEventsAfterRestart) {
1119 LazyBackgroundObserver lazy_observer;
1120 ResultCatcher catcher;
1121 const Extension* extension = LoadExtensionWithFlags(
1122 test_data_dir_.AppendASCII(
1123 "service_worker/filtered_events_after_restart"),
1124 kFlagNone);
1125 ASSERT_TRUE(extension);
1126 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
1127
1128 // |extension|'s background page opens a tab to its resource.
1129 content::WebContents* extension_web_contents =
1130 browser()->tab_strip_model()->GetActiveWebContents();
1131 EXPECT_TRUE(content::WaitForLoadStop(extension_web_contents));
1132 EXPECT_EQ(extension->GetResourceURL("page.html").spec(),
1133 extension_web_contents->GetURL().spec());
1134 {
1135 // Let the service worker start and register a filtered listener to
1136 // chrome.webNavigation.onCommitted event.
1137 ExtensionTestMessageListener add_listener_done("listener-added", false);
1138 add_listener_done.set_failure_message("FAILURE");
1139 content::ExecuteScriptAsync(extension_web_contents,
1140 "window.runServiceWorkerAsync()");
1141 EXPECT_TRUE(add_listener_done.WaitUntilSatisfied());
1142
1143 base::RunLoop run_loop;
1144 content::StoragePartition* storage_partition =
1145 content::BrowserContext::GetDefaultStoragePartition(
1146 browser()->profile());
1147 content::StopServiceWorkerForPattern(
1148 storage_partition->GetServiceWorkerContext(),
1149 // The service worker is registered at the top level scope.
1150 extension->url(), run_loop.QuitClosure());
1151 run_loop.Run();
1152 }
1153
1154 // Close the tab to |extension|'s resource. This will also close the
1155 // extension's event page.
1156 browser()->tab_strip_model()->CloseWebContentsAt(
1157 browser()->tab_strip_model()->active_index(), TabStripModel::CLOSE_NONE);
1158 lazy_observer.Wait();
1159}
1160
1161IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest,
1162 FilteredEventsAfterRestart) {
1163 // Create a tab to a.html, expect it to navigate to b.html. The service worker
1164 // will see two webNavigation.onCommitted events.
1165 ASSERT_TRUE(StartEmbeddedTestServer());
1166 GURL page_url = embedded_test_server()->GetURL(
1167 "/extensions/api_test/service_worker/filtered_events_after_restart/"
1168 "a.html");
1169 ExtensionTestMessageListener worker_filtered_event_listener(
1170 "PASS_FROM_WORKER", false);
1171 worker_filtered_event_listener.set_failure_message("FAIL_FROM_WORKER");
1172 content::WebContents* web_contents = AddTab(browser(), page_url);
1173 EXPECT_TRUE(web_contents);
1174 EXPECT_TRUE(worker_filtered_event_listener.WaitUntilSatisfied());
1175}
1176
Istiaque Ahmedea5ed5042017-09-25 19:00:161177// Run with both native and JS-based bindings. This ensures that both stable
1178// (JS) and experimental (native) phases work correctly with worker scripts
1179// while we launch native bindings to stable.
1180INSTANTIATE_TEST_CASE_P(ServiceWorkerTestWithNativeBindings,
1181 ServiceWorkerTest,
1182 ::testing::Values(NATIVE_BINDINGS));
1183INSTANTIATE_TEST_CASE_P(ServiceWorkerTestWithJSBindings,
1184 ServiceWorkerTest,
1185 ::testing::Values(JAVASCRIPT_BINDINGS));
1186INSTANTIATE_TEST_CASE_P(ServiceWorkerBackgroundSyncTestWithNativeBindings,
1187 ServiceWorkerBackgroundSyncTest,
1188 ::testing::Values(NATIVE_BINDINGS));
1189INSTANTIATE_TEST_CASE_P(ServiceWorkerBackgroundSyncTestWithJSBindings,
1190 ServiceWorkerBackgroundSyncTest,
1191 ::testing::Values(JAVASCRIPT_BINDINGS));
1192INSTANTIATE_TEST_CASE_P(ServiceWorkerPushMessagingTestWithNativeBindings,
1193 ServiceWorkerPushMessagingTest,
1194 ::testing::Values(NATIVE_BINDINGS));
1195INSTANTIATE_TEST_CASE_P(ServiceWorkerPushMessagingTestWithJSBindings,
1196 ServiceWorkerPushMessagingTest,
1197 ::testing::Values(JAVASCRIPT_BINDINGS));
Istiaque Ahmed805f6a83b2017-10-05 01:23:261198INSTANTIATE_TEST_CASE_P(ServiceWorkerLazyBackgroundTestWithNativeBindings,
1199 ServiceWorkerLazyBackgroundTest,
1200 ::testing::Values(NATIVE_BINDINGS));
1201INSTANTIATE_TEST_CASE_P(ServiceWorkerLazyBackgroundTestWithJSBindings,
1202 ServiceWorkerLazyBackgroundTest,
1203 ::testing::Values(JAVASCRIPT_BINDINGS));
Istiaque Ahmedea5ed5042017-09-25 19:00:161204
annekao38685502015-07-14 17:46:391205} // namespace extensions