blob: c69cf2e4ce59d7e1912e2d3a8b34352af2c10b9b [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"
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"
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"
Devlin Cronina3fe3d602017-11-22 04:47:4346#include "extensions/common/extension_features.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
Devlin Cronina3fe3d602017-11-22 04:47:43114 void SetUp() override {
115 if (GetParam() == NATIVE_BINDINGS) {
116 scoped_feature_list_.InitAndEnableFeature(features::kNativeCrxBindings);
117 } else {
118 DCHECK_EQ(JAVASCRIPT_BINDINGS, GetParam());
119 scoped_feature_list_.InitAndDisableFeature(features::kNativeCrxBindings);
120 }
121 ExtensionApiTest::SetUp();
122 }
123
jam1a5b5582017-05-01 16:50:10124 void SetUpOnMainThread() override {
125 ExtensionApiTest::SetUpOnMainThread();
126 host_resolver()->AddRule("a.com", "127.0.0.1");
127 }
128
kalman6f984ae2015-09-18 17:21:58129 protected:
130 // Returns the ProcessManager for the test's profile.
131 ProcessManager* process_manager() { return ProcessManager::Get(profile()); }
132
133 // Starts running a test from the background page test extension.
134 //
135 // This registers a service worker with |script_name|, and fetches the
136 // registration result.
137 //
138 // If |error_or_null| is null (kExpectSuccess), success is expected and this
139 // will fail if there is an error.
140 // If |error_or_null| is not null, nothing is assumed, and the error (which
141 // may be empty) is written to it.
142 const Extension* StartTestFromBackgroundPage(const char* script_name,
143 std::string* error_or_null) {
144 const Extension* extension =
145 LoadExtension(test_data_dir_.AppendASCII("service_worker/background"));
146 CHECK(extension);
147 ExtensionHost* background_host =
148 process_manager()->GetBackgroundHostForExtension(extension->id());
149 CHECK(background_host);
150 std::string error;
151 CHECK(content::ExecuteScriptAndExtractString(
152 background_host->host_contents(),
153 base::StringPrintf("test.registerServiceWorker('%s')", script_name),
154 &error));
155 if (error_or_null)
156 *error_or_null = error;
157 else if (!error.empty())
158 ADD_FAILURE() << "Got unexpected error " << error;
159 return extension;
160 }
161
162 // Navigates the browser to a new tab at |url|, waits for it to load, then
163 // returns it.
164 content::WebContents* Navigate(const GURL& url) {
165 ui_test_utils::NavigateToURLWithDisposition(
nick3b04f322016-08-31 19:29:19166 browser(), url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
kalman6f984ae2015-09-18 17:21:58167 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
168 content::WebContents* web_contents =
169 browser()->tab_strip_model()->GetActiveWebContents();
170 content::WaitForLoadStop(web_contents);
171 return web_contents;
172 }
173
174 // Navigates the browser to |url| and returns the new tab's page type.
175 content::PageType NavigateAndGetPageType(const GURL& url) {
176 return Navigate(url)->GetController().GetActiveEntry()->GetPageType();
177 }
178
179 // Extracts the innerText from |contents|.
180 std::string ExtractInnerText(content::WebContents* contents) {
181 std::string inner_text;
182 if (!content::ExecuteScriptAndExtractString(
183 contents,
184 "window.domAutomationController.send(document.body.innerText)",
185 &inner_text)) {
186 ADD_FAILURE() << "Failed to get inner text for "
187 << contents->GetVisibleURL();
188 }
189 return inner_text;
190 }
191
192 // Navigates the browser to |url|, then returns the innerText of the new
193 // tab's WebContents' main frame.
194 std::string NavigateAndExtractInnerText(const GURL& url) {
195 return ExtractInnerText(Navigate(url));
196 }
197
lazyboy4c82177a2016-10-18 00:04:09198 size_t GetWorkerRefCount(const GURL& origin) {
199 content::ServiceWorkerContext* sw_context =
200 content::BrowserContext::GetDefaultStoragePartition(
201 browser()->profile())
202 ->GetServiceWorkerContext();
203 base::RunLoop run_loop;
204 size_t ref_count = 0;
205 auto set_ref_count = [](size_t* ref_count, base::RunLoop* run_loop,
206 size_t external_request_count) {
207 *ref_count = external_request_count;
208 run_loop->Quit();
209 };
210 sw_context->CountExternalRequestsForTest(
Matt Falkenhagenc5cb4282017-09-07 08:43:42211 origin, base::BindOnce(set_ref_count, &ref_count, &run_loop));
lazyboy4c82177a2016-10-18 00:04:09212 run_loop.Run();
213 return ref_count;
214 }
215
annekao38685502015-07-14 17:46:39216 private:
lazyboy20167c22016-05-18 00:59:30217 // Sets the channel to "stable".
218 // Not useful after we've opened extension Service Workers to stable
219 // channel.
220 // TODO(lazyboy): Remove this when ExtensionServiceWorkersEnabled() is
221 // removed.
annekao38685502015-07-14 17:46:39222 ScopedCurrentChannel current_channel_;
kalman6f984ae2015-09-18 17:21:58223
Devlin Cronina3fe3d602017-11-22 04:47:43224 base::test::ScopedFeatureList scoped_feature_list_;
225
annekao38685502015-07-14 17:46:39226 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerTest);
227};
228
lazyboybd325ae2015-11-18 21:35:26229class ServiceWorkerBackgroundSyncTest : public ServiceWorkerTest {
230 public:
231 ServiceWorkerBackgroundSyncTest() {}
232 ~ServiceWorkerBackgroundSyncTest() override {}
233
234 void SetUpCommandLine(base::CommandLine* command_line) override {
235 // ServiceWorkerRegistration.sync requires experimental flag.
236 command_line->AppendSwitch(
Istiaque Ahmedea5ed5042017-09-25 19:00:16237 ::switches::kEnableExperimentalWebPlatformFeatures);
lazyboybd325ae2015-11-18 21:35:26238 ServiceWorkerTest::SetUpCommandLine(command_line);
239 }
240
241 void SetUp() override {
242 content::background_sync_test_util::SetIgnoreNetworkChangeNotifier(true);
243 ServiceWorkerTest::SetUp();
244 }
245
246 private:
247 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerBackgroundSyncTest);
248};
249
lazyboy561b7de2015-11-19 19:27:30250class ServiceWorkerPushMessagingTest : public ServiceWorkerTest {
251 public:
252 ServiceWorkerPushMessagingTest()
johnmea5045732016-09-08 17:23:29253 : gcm_driver_(nullptr), push_service_(nullptr) {}
lazyboy561b7de2015-11-19 19:27:30254 ~ServiceWorkerPushMessagingTest() override {}
255
256 void GrantNotificationPermissionForTest(const GURL& url) {
257 GURL origin = url.GetOrigin();
258 DesktopNotificationProfileUtil::GrantPermission(profile(), origin);
timlohc6911802017-03-01 05:37:03259 ASSERT_EQ(CONTENT_SETTING_ALLOW,
260 PermissionManager::Get(profile())
261 ->GetPermissionStatus(CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
262 origin, origin)
263 .content_setting);
lazyboy561b7de2015-11-19 19:27:30264 }
265
266 PushMessagingAppIdentifier GetAppIdentifierForServiceWorkerRegistration(
avia2f4804a2015-12-24 23:11:13267 int64_t service_worker_registration_id,
lazyboy561b7de2015-11-19 19:27:30268 const GURL& origin) {
269 PushMessagingAppIdentifier app_identifier =
270 PushMessagingAppIdentifier::FindByServiceWorker(
271 profile(), origin, service_worker_registration_id);
272
273 EXPECT_FALSE(app_identifier.is_null());
274 return app_identifier;
275 }
276
277 // ExtensionApiTest overrides.
278 void SetUpCommandLine(base::CommandLine* command_line) override {
peter9de96272015-12-04 15:23:27279 command_line->AppendSwitch(
Istiaque Ahmedea5ed5042017-09-25 19:00:16280 ::switches::kEnableExperimentalWebPlatformFeatures);
lazyboy561b7de2015-11-19 19:27:30281 ServiceWorkerTest::SetUpCommandLine(command_line);
282 }
283 void SetUpOnMainThread() override {
miguelg9b502862017-04-24 18:13:53284 NotificationDisplayServiceFactory::GetInstance()->SetTestingFactory(
285 profile(), &StubNotificationDisplayService::FactoryForTests);
286
johnmea5045732016-09-08 17:23:29287 gcm::FakeGCMProfileService* gcm_service =
288 static_cast<gcm::FakeGCMProfileService*>(
289 gcm::GCMProfileServiceFactory::GetInstance()
290 ->SetTestingFactoryAndUse(profile(),
291 &gcm::FakeGCMProfileService::Build));
292 gcm_driver_ = static_cast<instance_id::FakeGCMDriverForInstanceID*>(
293 gcm_service->driver());
lazyboy561b7de2015-11-19 19:27:30294 push_service_ = PushMessagingServiceFactory::GetForProfile(profile());
295
296 ServiceWorkerTest::SetUpOnMainThread();
297 }
298
johnmea5045732016-09-08 17:23:29299 instance_id::FakeGCMDriverForInstanceID* gcm_driver() const {
300 return gcm_driver_;
301 }
lazyboy561b7de2015-11-19 19:27:30302 PushMessagingServiceImpl* push_service() const { return push_service_; }
303
304 private:
johnmea5045732016-09-08 17:23:29305 instance_id::FakeGCMDriverForInstanceID* gcm_driver_;
lazyboy561b7de2015-11-19 19:27:30306 PushMessagingServiceImpl* push_service_;
307
308 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerPushMessagingTest);
309};
310
Istiaque Ahmed805f6a83b2017-10-05 01:23:26311class ServiceWorkerLazyBackgroundTest : public ServiceWorkerTest {
312 public:
Istiaque Ahmed7105f2a2017-10-07 01:11:59313 ServiceWorkerLazyBackgroundTest()
314 : ServiceWorkerTest(
315 // Extensions APIs from SW are only enabled on trunk.
316 // It is important to set the channel early so that this change is
317 // visible in renderers running with service workers (and no
318 // extension).
319 version_info::Channel::UNKNOWN) {}
Istiaque Ahmed805f6a83b2017-10-05 01:23:26320 ~ServiceWorkerLazyBackgroundTest() override {}
321
322 void SetUpCommandLine(base::CommandLine* command_line) override {
323 ServiceWorkerTest::SetUpCommandLine(command_line);
324 // Disable background network activity as it can suddenly bring the Lazy
325 // Background Page alive.
326 command_line->AppendSwitch(::switches::kDisableBackgroundNetworking);
327 command_line->AppendSwitch(::switches::kNoProxyServer);
328 }
329
330 void SetUpInProcessBrowserTestFixture() override {
331 ServiceWorkerTest::SetUpInProcessBrowserTestFixture();
332 // Set shorter delays to prevent test timeouts.
333 ProcessManager::SetEventPageIdleTimeForTesting(1);
334 ProcessManager::SetEventPageSuspendingTimeForTesting(1);
335 }
336
337 private:
338 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerLazyBackgroundTest);
339};
340
Istiaque Ahmedea5ed5042017-09-25 19:00:16341IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, RegisterSucceeds) {
kalman6f984ae2015-09-18 17:21:58342 StartTestFromBackgroundPage("register.js", kExpectSuccess);
annekao38685502015-07-14 17:46:39343}
344
Istiaque Ahmedea5ed5042017-09-25 19:00:16345IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, UpdateRefreshesServiceWorker) {
Francois Doraye6fb2d02017-10-18 21:29:13346 base::ScopedAllowBlockingForTesting allow_blocking;
lazyboyc3e763a2015-12-09 23:09:58347 base::ScopedTempDir scoped_temp_dir;
348 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
349 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
350 .AppendASCII("update")
351 .AppendASCII("service_worker.pem");
vabr9142fe22016-09-08 13:19:22352 base::FilePath path_v1 =
353 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
354 .AppendASCII("update")
355 .AppendASCII("v1"),
356 scoped_temp_dir.GetPath().AppendASCII("v1.crx"),
357 pem_path, base::FilePath());
358 base::FilePath path_v2 =
359 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
360 .AppendASCII("update")
361 .AppendASCII("v2"),
362 scoped_temp_dir.GetPath().AppendASCII("v2.crx"),
363 pem_path, base::FilePath());
lazyboyc3e763a2015-12-09 23:09:58364 const char* kId = "hfaanndiiilofhfokeanhddpkfffchdi";
365
366 ExtensionTestMessageListener listener_v1("Pong from version 1", false);
367 listener_v1.set_failure_message("FAILURE_V1");
368 // Install version 1.0 of the extension.
369 ASSERT_TRUE(InstallExtension(path_v1, 1));
370 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
371 ->enabled_extensions()
372 .GetByID(kId));
373 EXPECT_TRUE(listener_v1.WaitUntilSatisfied());
374
375 ExtensionTestMessageListener listener_v2("Pong from version 2", false);
376 listener_v2.set_failure_message("FAILURE_V2");
377
378 // Update to version 2.0.
379 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
380 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
381 ->enabled_extensions()
382 .GetByID(kId));
383 EXPECT_TRUE(listener_v2.WaitUntilSatisfied());
384}
385
[email protected]2ef85d562017-09-15 18:41:52386// TODO(crbug.com/765736) Fix the test.
Istiaque Ahmedea5ed5042017-09-25 19:00:16387IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, DISABLED_UpdateWithoutSkipWaiting) {
Francois Doraye6fb2d02017-10-18 21:29:13388 base::ScopedAllowBlockingForTesting allow_blocking;
lazyboy22eddc712015-12-10 21:16:26389 base::ScopedTempDir scoped_temp_dir;
390 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
391 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
392 .AppendASCII("update_without_skip_waiting")
393 .AppendASCII("update_without_skip_waiting.pem");
vabr9142fe22016-09-08 13:19:22394 base::FilePath path_v1 =
395 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
396 .AppendASCII("update_without_skip_waiting")
397 .AppendASCII("v1"),
398 scoped_temp_dir.GetPath().AppendASCII("v1.crx"),
399 pem_path, base::FilePath());
400 base::FilePath path_v2 =
401 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
402 .AppendASCII("update_without_skip_waiting")
403 .AppendASCII("v2"),
404 scoped_temp_dir.GetPath().AppendASCII("v2.crx"),
405 pem_path, base::FilePath());
lazyboy22eddc712015-12-10 21:16:26406 const char* kId = "mhnnnflgagdakldgjpfcofkiocpdmogl";
407
408 // Install version 1.0 of the extension.
409 ASSERT_TRUE(InstallExtension(path_v1, 1));
410 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
411 ->enabled_extensions()
412 .GetByID(kId));
413 const Extension* extension = extensions::ExtensionRegistry::Get(profile())
414 ->enabled_extensions()
415 .GetByID(kId);
416
417 ExtensionTestMessageListener listener1("Pong from version 1", false);
418 listener1.set_failure_message("FAILURE");
419 content::WebContents* web_contents =
420 AddTab(browser(), extension->GetResourceURL("page.html"));
421 EXPECT_TRUE(listener1.WaitUntilSatisfied());
422
423 // Update to version 2.0.
424 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
425 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
426 ->enabled_extensions()
427 .GetByID(kId));
428 const Extension* extension_after_update =
429 extensions::ExtensionRegistry::Get(profile())
430 ->enabled_extensions()
431 .GetByID(kId);
432
433 // Service worker version 2 would be installed but it won't be controlling
434 // the extension page yet.
435 ExtensionTestMessageListener listener2("Pong from version 1", false);
436 listener2.set_failure_message("FAILURE");
437 web_contents =
438 AddTab(browser(), extension_after_update->GetResourceURL("page.html"));
439 EXPECT_TRUE(listener2.WaitUntilSatisfied());
440
441 // Navigate the tab away from the extension page so that no clients are
442 // using the service worker.
443 // Note that just closing the tab with WebContentsDestroyedWatcher doesn't
444 // seem to be enough because it returns too early.
445 WebContentsLoadStopObserver navigate_away_observer(web_contents);
446 web_contents->GetController().LoadURL(
447 GURL(url::kAboutBlankURL), content::Referrer(), ui::PAGE_TRANSITION_TYPED,
448 std::string());
449 navigate_away_observer.WaitForLoadStop();
450
451 // Now expect service worker version 2 to control the extension page.
452 ExtensionTestMessageListener listener3("Pong from version 2", false);
453 listener3.set_failure_message("FAILURE");
454 web_contents =
455 AddTab(browser(), extension_after_update->GetResourceURL("page.html"));
456 EXPECT_TRUE(listener3.WaitUntilSatisfied());
457}
458
Istiaque Ahmedea5ed5042017-09-25 19:00:16459IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, FetchArbitraryPaths) {
kalman6f984ae2015-09-18 17:21:58460 const Extension* extension =
461 StartTestFromBackgroundPage("fetch.js", kExpectSuccess);
annekao1db36fd2015-07-29 17:09:16462
kalman6f984ae2015-09-18 17:21:58463 // Open some arbirary paths. Their contents should be what the service worker
464 // responds with, which in this case is the path of the fetch.
465 EXPECT_EQ(
466 "Caught a fetch for /index.html",
467 NavigateAndExtractInnerText(extension->GetResourceURL("index.html")));
468 EXPECT_EQ("Caught a fetch for /path/to/other.html",
469 NavigateAndExtractInnerText(
470 extension->GetResourceURL("path/to/other.html")));
471 EXPECT_EQ("Caught a fetch for /some/text/file.txt",
472 NavigateAndExtractInnerText(
473 extension->GetResourceURL("some/text/file.txt")));
474 EXPECT_EQ("Caught a fetch for /no/file/extension",
475 NavigateAndExtractInnerText(
476 extension->GetResourceURL("no/file/extension")));
477 EXPECT_EQ("Caught a fetch for /",
478 NavigateAndExtractInnerText(extension->GetResourceURL("")));
annekao1db36fd2015-07-29 17:09:16479}
480
Istiaque Ahmedea5ed5042017-09-25 19:00:16481IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, SWServedBackgroundPageReceivesEvent) {
lazyboy52c3bcf2016-01-08 00:11:29482 const Extension* extension =
483 StartTestFromBackgroundPage("replace_background.js", kExpectSuccess);
484 ExtensionHost* background_page =
485 process_manager()->GetBackgroundHostForExtension(extension->id());
486 ASSERT_TRUE(background_page);
487
488 // Close the background page and start it again so that the service worker
489 // will start controlling pages.
490 background_page->Close();
491 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
492 background_page = nullptr;
493 process_manager()->WakeEventPage(extension->id(),
494 base::Bind(&DoNothingWithBool));
495 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
496
497 // Since the SW is now controlling the extension, the SW serves the background
498 // script. page.html sends a message to the background script and we verify
499 // that the SW served background script correctly receives the message/event.
500 ExtensionTestMessageListener listener("onMessage/SW BG.", false);
501 listener.set_failure_message("onMessage/original BG.");
502 content::WebContents* web_contents =
503 AddTab(browser(), extension->GetResourceURL("page.html"));
504 ASSERT_TRUE(web_contents);
505 EXPECT_TRUE(listener.WaitUntilSatisfied());
506}
507
Istiaque Ahmedea5ed5042017-09-25 19:00:16508IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:58509 LoadingBackgroundPageBypassesServiceWorker) {
510 const Extension* extension =
511 StartTestFromBackgroundPage("fetch.js", kExpectSuccess);
annekao49241182015-08-18 17:14:01512
kalman6f984ae2015-09-18 17:21:58513 std::string kExpectedInnerText = "background.html contents for testing.";
annekao49241182015-08-18 17:14:01514
kalman6f984ae2015-09-18 17:21:58515 // Sanity check that the background page has the expected content.
516 ExtensionHost* background_page =
517 process_manager()->GetBackgroundHostForExtension(extension->id());
518 ASSERT_TRUE(background_page);
519 EXPECT_EQ(kExpectedInnerText,
520 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:01521
kalman6f984ae2015-09-18 17:21:58522 // Close the background page.
523 background_page->Close();
524 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
525 background_page = nullptr;
526
527 // Start it again.
528 process_manager()->WakeEventPage(extension->id(),
529 base::Bind(&DoNothingWithBool));
530 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
531
532 // Content should not have been affected by the fetch, which would otherwise
533 // be "Caught fetch for...".
534 background_page =
535 process_manager()->GetBackgroundHostForExtension(extension->id());
536 ASSERT_TRUE(background_page);
537 content::WaitForLoadStop(background_page->host_contents());
538
539 // TODO(kalman): Everything you've read has been a LIE! It should be:
540 //
541 // EXPECT_EQ(kExpectedInnerText,
542 // ExtractInnerText(background_page->host_contents()));
543 //
544 // but there is a bug, and we're actually *not* bypassing the service worker
545 // for background page loads! For now, let it pass (assert wrong behavior)
546 // because it's not a regression, but this must be fixed eventually.
547 //
548 // Tracked in crbug.com/532720.
549 EXPECT_EQ("Caught a fetch for /background.html",
550 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:01551}
552
Istiaque Ahmedea5ed5042017-09-25 19:00:16553IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:58554 ServiceWorkerPostsMessageToBackgroundClient) {
555 const Extension* extension = StartTestFromBackgroundPage(
556 "post_message_to_background_client.js", kExpectSuccess);
annekao533482222015-08-21 23:23:53557
kalman6f984ae2015-09-18 17:21:58558 // The service worker in this test simply posts a message to the background
559 // client it receives from getBackgroundClient().
560 const char* kScript =
561 "var messagePromise = null;\n"
562 "if (test.lastMessageFromServiceWorker) {\n"
563 " messagePromise = Promise.resolve(test.lastMessageFromServiceWorker);\n"
564 "} else {\n"
565 " messagePromise = test.waitForMessage(navigator.serviceWorker);\n"
566 "}\n"
567 "messagePromise.then(function(message) {\n"
568 " window.domAutomationController.send(String(message == 'success'));\n"
569 "})\n";
570 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:53571}
572
Istiaque Ahmedea5ed5042017-09-25 19:00:16573IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:58574 BackgroundPagePostsMessageToServiceWorker) {
575 const Extension* extension =
576 StartTestFromBackgroundPage("post_message_to_sw.js", kExpectSuccess);
annekao533482222015-08-21 23:23:53577
kalman6f984ae2015-09-18 17:21:58578 // The service worker in this test waits for a message, then echoes it back
579 // by posting a message to the background page via getBackgroundClient().
580 const char* kScript =
581 "var mc = new MessageChannel();\n"
582 "test.waitForMessage(mc.port1).then(function(message) {\n"
583 " window.domAutomationController.send(String(message == 'hello'));\n"
584 "});\n"
585 "test.registeredServiceWorker.postMessage(\n"
586 " {message: 'hello', port: mc.port2}, [mc.port2])\n";
587 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:53588}
589
Istiaque Ahmedea5ed5042017-09-25 19:00:16590IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
rdevlin.croninf5863da2015-09-10 19:21:45591 ServiceWorkerSuspensionOnExtensionUnload) {
kalman6f984ae2015-09-18 17:21:58592 // For this test, only hold onto the extension's ID and URL + a function to
593 // get a resource URL, because we're going to be disabling and uninstalling
594 // it, which will invalidate the pointer.
595 std::string extension_id;
596 GURL extension_url;
597 {
598 const Extension* extension =
599 StartTestFromBackgroundPage("fetch.js", kExpectSuccess);
600 extension_id = extension->id();
601 extension_url = extension->url();
602 }
603 auto get_resource_url = [&extension_url](const std::string& path) {
604 return Extension::GetResourceURL(extension_url, path);
605 };
rdevlin.croninf5863da2015-09-10 19:21:45606
kalman6f984ae2015-09-18 17:21:58607 // Fetch should route to the service worker.
608 EXPECT_EQ("Caught a fetch for /index.html",
609 NavigateAndExtractInnerText(get_resource_url("index.html")));
rdevlin.croninf5863da2015-09-10 19:21:45610
kalman6f984ae2015-09-18 17:21:58611 // Disable the extension. Opening the page should fail.
612 extension_service()->DisableExtension(extension_id,
Minh X. Nguyen45479012017-08-18 21:35:36613 disable_reason::DISABLE_USER_ACTION);
rdevlin.croninf5863da2015-09-10 19:21:45614 base::RunLoop().RunUntilIdle();
rdevlin.croninf5863da2015-09-10 19:21:45615
kalman6f984ae2015-09-18 17:21:58616 EXPECT_EQ(content::PAGE_TYPE_ERROR,
617 NavigateAndGetPageType(get_resource_url("index.html")));
618 EXPECT_EQ(content::PAGE_TYPE_ERROR,
619 NavigateAndGetPageType(get_resource_url("other.html")));
620
621 // Re-enable the extension. Opening pages should immediately start to succeed
622 // again.
rdevlin.croninf5863da2015-09-10 19:21:45623 extension_service()->EnableExtension(extension_id);
624 base::RunLoop().RunUntilIdle();
625
kalman6f984ae2015-09-18 17:21:58626 EXPECT_EQ("Caught a fetch for /index.html",
627 NavigateAndExtractInnerText(get_resource_url("index.html")));
628 EXPECT_EQ("Caught a fetch for /other.html",
629 NavigateAndExtractInnerText(get_resource_url("other.html")));
630 EXPECT_EQ("Caught a fetch for /another.html",
631 NavigateAndExtractInnerText(get_resource_url("another.html")));
rdevlin.croninf5863da2015-09-10 19:21:45632
kalman6f984ae2015-09-18 17:21:58633 // Uninstall the extension. Opening pages should fail again.
634 base::string16 error;
635 extension_service()->UninstallExtension(
Devlin Cronin218df7f2017-11-21 21:41:31636 extension_id, UninstallReason::UNINSTALL_REASON_FOR_TESTING, &error);
kalman6f984ae2015-09-18 17:21:58637 base::RunLoop().RunUntilIdle();
638
639 EXPECT_EQ(content::PAGE_TYPE_ERROR,
640 NavigateAndGetPageType(get_resource_url("index.html")));
641 EXPECT_EQ(content::PAGE_TYPE_ERROR,
642 NavigateAndGetPageType(get_resource_url("other.html")));
643 EXPECT_EQ(content::PAGE_TYPE_ERROR,
644 NavigateAndGetPageType(get_resource_url("anotherother.html")));
645 EXPECT_EQ(content::PAGE_TYPE_ERROR,
646 NavigateAndGetPageType(get_resource_url("final.html")));
647}
648
Istiaque Ahmedea5ed5042017-09-25 19:00:16649IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, BackgroundPageIsWokenIfAsleep) {
kalman6f984ae2015-09-18 17:21:58650 const Extension* extension =
651 StartTestFromBackgroundPage("wake_on_fetch.js", kExpectSuccess);
652
653 // Navigate to special URLs that this test's service worker recognises, each
654 // making a check then populating the response with either "true" or "false".
655 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
656 "background-client-is-awake")));
657 EXPECT_EQ("true", NavigateAndExtractInnerText(
658 extension->GetResourceURL("ping-background-client")));
659 // Ping more than once for good measure.
660 EXPECT_EQ("true", NavigateAndExtractInnerText(
661 extension->GetResourceURL("ping-background-client")));
662
663 // Shut down the event page. The SW should detect that it's closed, but still
664 // be able to ping it.
665 ExtensionHost* background_page =
666 process_manager()->GetBackgroundHostForExtension(extension->id());
667 ASSERT_TRUE(background_page);
668 background_page->Close();
669 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
670
671 EXPECT_EQ("false", NavigateAndExtractInnerText(extension->GetResourceURL(
672 "background-client-is-awake")));
673 EXPECT_EQ("true", NavigateAndExtractInnerText(
674 extension->GetResourceURL("ping-background-client")));
675 EXPECT_EQ("true", NavigateAndExtractInnerText(
676 extension->GetResourceURL("ping-background-client")));
677 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
678 "background-client-is-awake")));
679}
680
Istiaque Ahmedea5ed5042017-09-25 19:00:16681IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:58682 GetBackgroundClientFailsWithNoBackgroundPage) {
683 // This extension doesn't have a background page, only a tab at page.html.
684 // The service worker it registers tries to call getBackgroundClient() and
685 // should fail.
686 // Note that this also tests that service workers can be registered from tabs.
687 EXPECT_TRUE(RunExtensionSubtest("service_worker/no_background", "page.html"));
rdevlin.croninf5863da2015-09-10 19:21:45688}
689
Istiaque Ahmedea5ed5042017-09-25 19:00:16690IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, NotificationAPI) {
lazyboy6ddb7d62015-11-10 23:15:27691 EXPECT_TRUE(RunExtensionSubtest("service_worker/notifications/has_permission",
692 "page.html"));
693}
694
Istiaque Ahmedea5ed5042017-09-25 19:00:16695IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, WebAccessibleResourcesFetch) {
lazyboyaea32c22016-01-04 21:37:07696 EXPECT_TRUE(RunExtensionSubtest(
697 "service_worker/web_accessible_resources/fetch/", "page.html"));
698}
699
Istiaque Ahmedea5ed5042017-09-25 19:00:16700IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, TabsCreate) {
lazyboyee4adef2016-05-24 00:55:16701 // Extensions APIs from SW are only enabled on trunk.
702 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
703 const Extension* extension = LoadExtensionWithFlags(
704 test_data_dir_.AppendASCII("service_worker/tabs_create"), kFlagNone);
705 ASSERT_TRUE(extension);
706 ui_test_utils::NavigateToURL(browser(),
707 extension->GetResourceURL("page.html"));
708 content::WebContents* web_contents =
709 browser()->tab_strip_model()->GetActiveWebContents();
710
711 int starting_tab_count = browser()->tab_strip_model()->count();
712 std::string result;
713 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
714 web_contents, "window.runServiceWorker()", &result));
715 ASSERT_EQ("chrome.tabs.create callback", result);
716 EXPECT_EQ(starting_tab_count + 1, browser()->tab_strip_model()->count());
717
718 // Check extension shutdown path.
719 UnloadExtension(extension->id());
720 EXPECT_EQ(starting_tab_count, browser()->tab_strip_model()->count());
721}
722
Istiaque Ahmedea5ed5042017-09-25 19:00:16723IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, Events) {
lazyboye7847242017-06-07 23:29:18724 // Extensions APIs from SW are only enabled on trunk.
725 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
726 const Extension* extension = LoadExtensionWithFlags(
727 test_data_dir_.AppendASCII("service_worker/events"), kFlagNone);
728 ASSERT_TRUE(extension);
729 ui_test_utils::NavigateToURL(browser(),
730 extension->GetResourceURL("page.html"));
731 content::WebContents* web_contents =
732 browser()->tab_strip_model()->GetActiveWebContents();
733 std::string result;
734 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
735 web_contents, "window.runEventTest()", &result));
736 ASSERT_EQ("chrome.tabs.onUpdated callback", result);
737}
738
Istiaque Ahmedea5ed5042017-09-25 19:00:16739IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, EventsToStoppedWorker) {
lazyboy63b994a2017-06-30 21:20:23740 // Extensions APIs from SW are only enabled on trunk.
741 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
742 const Extension* extension = LoadExtensionWithFlags(
743 test_data_dir_.AppendASCII("service_worker/events_to_stopped_worker"),
744 kFlagNone);
745 ASSERT_TRUE(extension);
746 ui_test_utils::NavigateToURL(browser(),
747 extension->GetResourceURL("page.html"));
748 content::WebContents* web_contents =
749 browser()->tab_strip_model()->GetActiveWebContents();
750 {
751 std::string result;
752 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
753 web_contents, "window.runServiceWorker()", &result));
754 ASSERT_EQ("ready", result);
755
756 base::RunLoop run_loop;
757 content::StoragePartition* storage_partition =
758 content::BrowserContext::GetDefaultStoragePartition(
759 browser()->profile());
760 content::StopServiceWorkerForPattern(
761 storage_partition->GetServiceWorkerContext(),
762 // The service worker is registered at the top level scope.
763 extension->url(), run_loop.QuitClosure());
764 run_loop.Run();
765 }
766
767 std::string result;
768 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
769 web_contents, "window.createTabThenUpdate()", &result));
770 ASSERT_EQ("chrome.tabs.onUpdated callback", result);
771}
772
Istiaque Ahmed805f6a83b2017-10-05 01:23:26773// Tests that events to service worker arrives correctly event if the owner
774// extension of the worker is not running.
775IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest,
776 EventsToStoppedExtension) {
Istiaque Ahmed805f6a83b2017-10-05 01:23:26777 LazyBackgroundObserver lazy_observer;
778 ResultCatcher catcher;
779 const Extension* extension = LoadExtensionWithFlags(
780 test_data_dir_.AppendASCII("service_worker/events_to_stopped_extension"),
781 kFlagNone);
782 ASSERT_TRUE(extension);
783 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
784
785 ProcessManager* pm = ProcessManager::Get(browser()->profile());
786 EXPECT_GT(pm->GetLazyKeepaliveCount(extension), 0);
787
788 // |extension|'s background page opens a tab to its resource.
789 content::WebContents* extension_web_contents =
790 browser()->tab_strip_model()->GetActiveWebContents();
791 EXPECT_TRUE(content::WaitForLoadStop(extension_web_contents));
792 EXPECT_EQ(extension->GetResourceURL("page.html").spec(),
793 extension_web_contents->GetURL().spec());
794 {
795 // Let the service worker start and register a listener to
796 // chrome.tabs.onCreated event.
797 ExtensionTestMessageListener add_listener_done("listener-added", false);
798 content::ExecuteScriptAsync(extension_web_contents,
799 "window.runServiceWorkerAsync()");
800 EXPECT_TRUE(add_listener_done.WaitUntilSatisfied());
801
802 base::RunLoop run_loop;
803 content::StoragePartition* storage_partition =
804 content::BrowserContext::GetDefaultStoragePartition(
805 browser()->profile());
806 content::StopServiceWorkerForPattern(
807 storage_partition->GetServiceWorkerContext(),
808 // The service worker is registered at the top level scope.
809 extension->url(), run_loop.QuitClosure());
810 run_loop.Run();
811 }
812
813 // Close the tab to |extension|'s resource. This will also close the
814 // extension's event page.
815 browser()->tab_strip_model()->CloseWebContentsAt(
816 browser()->tab_strip_model()->active_index(), TabStripModel::CLOSE_NONE);
817 lazy_observer.Wait();
818
819 // At this point both the extension worker and extension event page is not
820 // running. Since the worker registered a listener for tabs.onCreated, it
821 // will be started to dispatch the event once we create a tab.
822 ExtensionTestMessageListener newtab_listener("hello-newtab", false);
823 newtab_listener.set_failure_message("WRONG_NEWTAB");
824 content::WebContents* new_web_contents =
Istiaque Ahmed7105f2a2017-10-07 01:11:59825 AddTab(browser(), GURL(url::kAboutBlankURL));
826 EXPECT_TRUE(new_web_contents);
827 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
828}
829
830// Tests that events to service worker correctly after browser restart.
831// This test is similar to EventsToStoppedExtension, except that the event
832// delivery is verified after a browser restart.
833IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest,
834 PRE_EventsAfterRestart) {
835 LazyBackgroundObserver lazy_observer;
836 ResultCatcher catcher;
837 const Extension* extension = LoadExtensionWithFlags(
838 test_data_dir_.AppendASCII("service_worker/events_to_stopped_extension"),
839 kFlagNone);
840 ASSERT_TRUE(extension);
841 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
842
843 ProcessManager* pm = ProcessManager::Get(browser()->profile());
844 EXPECT_GT(pm->GetLazyKeepaliveCount(extension), 0);
845
846 // |extension|'s background page opens a tab to its resource.
847 content::WebContents* extension_web_contents =
848 browser()->tab_strip_model()->GetActiveWebContents();
849 EXPECT_TRUE(content::WaitForLoadStop(extension_web_contents));
850 EXPECT_EQ(extension->GetResourceURL("page.html").spec(),
851 extension_web_contents->GetURL().spec());
852 {
853 // Let the service worker start and register a listener to
854 // chrome.tabs.onCreated event.
855 ExtensionTestMessageListener add_listener_done("listener-added", false);
856 content::ExecuteScriptAsync(extension_web_contents,
857 "window.runServiceWorkerAsync()");
858 EXPECT_TRUE(add_listener_done.WaitUntilSatisfied());
859
860 base::RunLoop run_loop;
861 content::StoragePartition* storage_partition =
862 content::BrowserContext::GetDefaultStoragePartition(
863 browser()->profile());
864 content::StopServiceWorkerForPattern(
865 storage_partition->GetServiceWorkerContext(),
866 // The service worker is registered at the top level scope.
867 extension->url(), run_loop.QuitClosure());
868 run_loop.Run();
869 }
870
871 // Close the tab to |extension|'s resource. This will also close the
872 // extension's event page.
873 browser()->tab_strip_model()->CloseWebContentsAt(
874 browser()->tab_strip_model()->active_index(), TabStripModel::CLOSE_NONE);
875 lazy_observer.Wait();
876}
877
878IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest, EventsAfterRestart) {
879 ExtensionTestMessageListener newtab_listener("hello-newtab", false);
880 content::WebContents* new_web_contents =
881 AddTab(browser(), GURL(url::kAboutBlankURL));
Istiaque Ahmed805f6a83b2017-10-05 01:23:26882 EXPECT_TRUE(new_web_contents);
883 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
884}
885
lazyboy4c82177a2016-10-18 00:04:09886// Tests that worker ref count increments while extension API function is
887// active.
Istiaque Ahmedea5ed5042017-09-25 19:00:16888IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, WorkerRefCount) {
lazyboy4c82177a2016-10-18 00:04:09889 // Extensions APIs from SW are only enabled on trunk.
890 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
891 const Extension* extension = LoadExtensionWithFlags(
892 test_data_dir_.AppendASCII("service_worker/api_worker_ref_count"),
893 kFlagNone);
894 ASSERT_TRUE(extension);
895 ui_test_utils::NavigateToURL(browser(),
896 extension->GetResourceURL("page.html"));
897 content::WebContents* web_contents =
898 browser()->tab_strip_model()->GetActiveWebContents();
899
900 ExtensionTestMessageListener worker_start_listener("WORKER STARTED", false);
901 worker_start_listener.set_failure_message("FAILURE");
902 ASSERT_TRUE(
903 content::ExecuteScript(web_contents, "window.runServiceWorker()"));
904 ASSERT_TRUE(worker_start_listener.WaitUntilSatisfied());
905
906 // Service worker should have no pending requests because it hasn't peformed
907 // any extension API request yet.
908 EXPECT_EQ(0u, GetWorkerRefCount(extension->url()));
909
910 ExtensionTestMessageListener worker_listener("CHECK_REF_COUNT", true);
911 worker_listener.set_failure_message("FAILURE");
912 ASSERT_TRUE(content::ExecuteScript(web_contents, "window.testSendMessage()"));
913 ASSERT_TRUE(worker_listener.WaitUntilSatisfied());
914
915 // Service worker should have exactly one pending request because
916 // chrome.test.sendMessage() API call is in-flight.
917 EXPECT_EQ(1u, GetWorkerRefCount(extension->url()));
918
919 // Peform another extension API request while one is ongoing.
920 {
921 ExtensionTestMessageListener listener("CHECK_REF_COUNT", true);
922 listener.set_failure_message("FAILURE");
923 ASSERT_TRUE(
924 content::ExecuteScript(web_contents, "window.testSendMessage()"));
925 ASSERT_TRUE(listener.WaitUntilSatisfied());
926
927 // Service worker currently has two extension API requests in-flight.
928 EXPECT_EQ(2u, GetWorkerRefCount(extension->url()));
929 // Finish executing the nested chrome.test.sendMessage() first.
930 listener.Reply("Hello world");
931 }
932
Istiaque Ahmedb57c9752017-08-20 19:08:57933 ExtensionTestMessageListener worker_completion_listener("SUCCESS_FROM_WORKER",
934 false);
lazyboy4c82177a2016-10-18 00:04:09935 // Finish executing chrome.test.sendMessage().
936 worker_listener.Reply("Hello world");
Istiaque Ahmedb57c9752017-08-20 19:08:57937 EXPECT_TRUE(worker_completion_listener.WaitUntilSatisfied());
938
939 // The following block makes sure we have received all the IPCs related to
940 // ref-count from the worker.
941 {
942 // The following roundtrip:
943 // browser->extension->worker->extension->browser
944 // will ensure that the worker sent the relevant ref count IPCs.
945 std::string result;
946 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
947 web_contents, "window.roundtripToWorker();", &result));
948 EXPECT_EQ("roundtrip-succeeded", result);
949
950 // Ensure IO thread IPCs run.
Gabriel Charette01507a22017-09-27 21:30:08951 content::RunAllTasksUntilIdle();
Istiaque Ahmedb57c9752017-08-20 19:08:57952 }
lazyboy4c82177a2016-10-18 00:04:09953
954 // The ref count should drop to 0.
955 EXPECT_EQ(0u, GetWorkerRefCount(extension->url()));
956}
957
lazyboyaea32c22016-01-04 21:37:07958// This test loads a web page that has an iframe pointing to a
959// chrome-extension:// URL. The URL is listed in the extension's
960// web_accessible_resources. Initially the iframe is served from the extension's
961// resource file. After verifying that, we register a Service Worker that
962// controls the extension. Further requests to the same resource as before
963// should now be served by the Service Worker.
964// This test also verifies that if the requested resource exists in the manifest
965// but is not present in the extension directory, the Service Worker can still
966// serve the resource file.
Istiaque Ahmedea5ed5042017-09-25 19:00:16967IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, WebAccessibleResourcesIframeSrc) {
lazyboyaea32c22016-01-04 21:37:07968 const Extension* extension = LoadExtensionWithFlags(
969 test_data_dir_.AppendASCII(
970 "service_worker/web_accessible_resources/iframe_src"),
971 kFlagNone);
972 ASSERT_TRUE(extension);
973 ASSERT_TRUE(StartEmbeddedTestServer());
falkenad185092016-06-16 06:10:02974
975 // Service workers can only control secure contexts
976 // (https://w3c.github.io/webappsec-secure-contexts/). For documents, this
977 // typically means the document must have a secure origin AND all its ancestor
978 // frames must have documents with secure origins. However, extension pages
979 // are considered secure, even if they have an ancestor document that is an
980 // insecure context (see GetSchemesBypassingSecureContextCheckWhitelist). So
981 // extension service workers must be able to control an extension page
982 // embedded in an insecure context. To test this, set up an insecure
983 // (non-localhost, non-https) URL for the web page. This page will create
984 // iframes that load extension pages that must be controllable by service
985 // worker.
falkenad185092016-06-16 06:10:02986 GURL page_url =
987 embedded_test_server()->GetURL("a.com",
988 "/extensions/api_test/service_worker/"
989 "web_accessible_resources/webpage.html");
990 EXPECT_FALSE(content::IsOriginSecure(page_url));
lazyboyaea32c22016-01-04 21:37:07991
992 content::WebContents* web_contents = AddTab(browser(), page_url);
993 std::string result;
994 // webpage.html will create an iframe pointing to a resource from |extension|.
995 // Expect the resource to be served by the extension.
996 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
997 web_contents, base::StringPrintf("window.testIframe('%s', 'iframe.html')",
998 extension->id().c_str()),
999 &result));
1000 EXPECT_EQ("FROM_EXTENSION_RESOURCE", result);
1001
1002 ExtensionTestMessageListener service_worker_ready_listener("SW_READY", false);
1003 EXPECT_TRUE(ExecuteScriptInBackgroundPageNoWait(
1004 extension->id(), "window.registerServiceWorker()"));
1005 EXPECT_TRUE(service_worker_ready_listener.WaitUntilSatisfied());
1006
1007 result.clear();
1008 // webpage.html will create another iframe pointing to a resource from
1009 // |extension| as before. But this time, the resource should be be served
1010 // from the Service Worker.
1011 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1012 web_contents, base::StringPrintf("window.testIframe('%s', 'iframe.html')",
1013 extension->id().c_str()),
1014 &result));
1015 EXPECT_EQ("FROM_SW_RESOURCE", result);
1016
1017 result.clear();
1018 // webpage.html will create yet another iframe pointing to a resource that
1019 // exists in the extension manifest's web_accessible_resources, but is not
1020 // present in the extension directory. Expect the resources of the iframe to
1021 // be served by the Service Worker.
1022 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1023 web_contents,
1024 base::StringPrintf("window.testIframe('%s', 'iframe_non_existent.html')",
1025 extension->id().c_str()),
1026 &result));
1027 EXPECT_EQ("FROM_SW_RESOURCE", result);
1028}
1029
Istiaque Ahmedea5ed5042017-09-25 19:00:161030IN_PROC_BROWSER_TEST_P(ServiceWorkerBackgroundSyncTest, Sync) {
lazyboybd325ae2015-11-18 21:35:261031 const Extension* extension = LoadExtensionWithFlags(
1032 test_data_dir_.AppendASCII("service_worker/sync"), kFlagNone);
1033 ASSERT_TRUE(extension);
1034 ui_test_utils::NavigateToURL(browser(),
1035 extension->GetResourceURL("page.html"));
1036 content::WebContents* web_contents =
1037 browser()->tab_strip_model()->GetActiveWebContents();
1038
1039 // Prevent firing by going offline.
1040 content::background_sync_test_util::SetOnline(web_contents, false);
1041
1042 ExtensionTestMessageListener sync_listener("SYNC: send-chats", false);
1043 sync_listener.set_failure_message("FAIL");
1044
1045 std::string result;
1046 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
1047 web_contents, "window.runServiceWorker()", &result));
1048 ASSERT_EQ("SERVICE_WORKER_READY", result);
1049
1050 EXPECT_FALSE(sync_listener.was_satisfied());
1051 // Resume firing by going online.
1052 content::background_sync_test_util::SetOnline(web_contents, true);
1053 EXPECT_TRUE(sync_listener.WaitUntilSatisfied());
1054}
1055
Istiaque Ahmedea5ed5042017-09-25 19:00:161056IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
horo1eeddde2015-11-19 05:59:251057 FetchFromContentScriptShouldNotGoToServiceWorkerOfPage) {
1058 ASSERT_TRUE(StartEmbeddedTestServer());
1059 GURL page_url = embedded_test_server()->GetURL(
1060 "/extensions/api_test/service_worker/content_script_fetch/"
1061 "controlled_page/index.html");
1062 content::WebContents* tab =
1063 browser()->tab_strip_model()->GetActiveWebContents();
1064 ui_test_utils::NavigateToURL(browser(), page_url);
1065 content::WaitForLoadStop(tab);
1066
1067 std::string value;
1068 ASSERT_TRUE(
1069 content::ExecuteScriptAndExtractString(tab, "register();", &value));
1070 EXPECT_EQ("SW controlled", value);
1071
1072 ASSERT_TRUE(RunExtensionTest("service_worker/content_script_fetch"))
1073 << message_;
1074}
1075
Istiaque Ahmedea5ed5042017-09-25 19:00:161076IN_PROC_BROWSER_TEST_P(ServiceWorkerPushMessagingTest, OnPush) {
lazyboy561b7de2015-11-19 19:27:301077 const Extension* extension = LoadExtensionWithFlags(
1078 test_data_dir_.AppendASCII("service_worker/push_messaging"), kFlagNone);
1079 ASSERT_TRUE(extension);
1080 GURL extension_url = extension->url();
1081
1082 ASSERT_NO_FATAL_FAILURE(GrantNotificationPermissionForTest(extension_url));
1083
1084 GURL url = extension->GetResourceURL("page.html");
1085 ui_test_utils::NavigateToURL(browser(), url);
1086
1087 content::WebContents* web_contents =
1088 browser()->tab_strip_model()->GetActiveWebContents();
1089
1090 // Start the ServiceWorker.
1091 ExtensionTestMessageListener ready_listener("SERVICE_WORKER_READY", false);
1092 ready_listener.set_failure_message("SERVICE_WORKER_FAILURE");
1093 const char* kScript = "window.runServiceWorker()";
1094 EXPECT_TRUE(content::ExecuteScript(web_contents->GetMainFrame(), kScript));
1095 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
1096
1097 PushMessagingAppIdentifier app_identifier =
1098 GetAppIdentifierForServiceWorkerRegistration(0LL, extension_url);
johnmea5045732016-09-08 17:23:291099 ASSERT_EQ(app_identifier.app_id(), gcm_driver()->last_gettoken_app_id());
1100 EXPECT_EQ("1234567890", gcm_driver()->last_gettoken_authorized_entity());
lazyboy561b7de2015-11-19 19:27:301101
lazyboyd429e2582016-05-20 20:18:521102 base::RunLoop run_loop;
lazyboy561b7de2015-11-19 19:27:301103 // Send a push message via gcm and expect the ServiceWorker to receive it.
1104 ExtensionTestMessageListener push_message_listener("OK", false);
1105 push_message_listener.set_failure_message("FAIL");
1106 gcm::IncomingMessage message;
1107 message.sender_id = "1234567890";
1108 message.raw_data = "testdata";
1109 message.decrypted = true;
lazyboyd429e2582016-05-20 20:18:521110 push_service()->SetMessageCallbackForTesting(run_loop.QuitClosure());
lazyboy561b7de2015-11-19 19:27:301111 push_service()->OnMessage(app_identifier.app_id(), message);
1112 EXPECT_TRUE(push_message_listener.WaitUntilSatisfied());
lazyboyd429e2582016-05-20 20:18:521113 run_loop.Run(); // Wait until the message is handled by push service.
lazyboy561b7de2015-11-19 19:27:301114}
1115
Istiaque Ahmedea5ed5042017-09-25 19:00:161116IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, FilteredEvents) {
Istiaque Ahmed9d1666182017-09-21 23:58:181117 // Extensions APIs from SW are only enabled on trunk.
1118 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1119 ASSERT_TRUE(RunExtensionTest("service_worker/filtered_events"));
1120}
1121
Istiaque Ahmed9ce21b32017-10-10 20:43:181122IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest,
1123 PRE_FilteredEventsAfterRestart) {
1124 LazyBackgroundObserver lazy_observer;
1125 ResultCatcher catcher;
1126 const Extension* extension = LoadExtensionWithFlags(
1127 test_data_dir_.AppendASCII(
1128 "service_worker/filtered_events_after_restart"),
1129 kFlagNone);
1130 ASSERT_TRUE(extension);
1131 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
1132
1133 // |extension|'s background page opens a tab to its resource.
1134 content::WebContents* extension_web_contents =
1135 browser()->tab_strip_model()->GetActiveWebContents();
1136 EXPECT_TRUE(content::WaitForLoadStop(extension_web_contents));
1137 EXPECT_EQ(extension->GetResourceURL("page.html").spec(),
1138 extension_web_contents->GetURL().spec());
1139 {
1140 // Let the service worker start and register a filtered listener to
1141 // chrome.webNavigation.onCommitted event.
1142 ExtensionTestMessageListener add_listener_done("listener-added", false);
1143 add_listener_done.set_failure_message("FAILURE");
1144 content::ExecuteScriptAsync(extension_web_contents,
1145 "window.runServiceWorkerAsync()");
1146 EXPECT_TRUE(add_listener_done.WaitUntilSatisfied());
1147
1148 base::RunLoop run_loop;
1149 content::StoragePartition* storage_partition =
1150 content::BrowserContext::GetDefaultStoragePartition(
1151 browser()->profile());
1152 content::StopServiceWorkerForPattern(
1153 storage_partition->GetServiceWorkerContext(),
1154 // The service worker is registered at the top level scope.
1155 extension->url(), run_loop.QuitClosure());
1156 run_loop.Run();
1157 }
1158
1159 // Close the tab to |extension|'s resource. This will also close the
1160 // extension's event page.
1161 browser()->tab_strip_model()->CloseWebContentsAt(
1162 browser()->tab_strip_model()->active_index(), TabStripModel::CLOSE_NONE);
1163 lazy_observer.Wait();
1164}
1165
1166IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest,
1167 FilteredEventsAfterRestart) {
1168 // Create a tab to a.html, expect it to navigate to b.html. The service worker
1169 // will see two webNavigation.onCommitted events.
1170 ASSERT_TRUE(StartEmbeddedTestServer());
1171 GURL page_url = embedded_test_server()->GetURL(
1172 "/extensions/api_test/service_worker/filtered_events_after_restart/"
1173 "a.html");
1174 ExtensionTestMessageListener worker_filtered_event_listener(
1175 "PASS_FROM_WORKER", false);
1176 worker_filtered_event_listener.set_failure_message("FAIL_FROM_WORKER");
1177 content::WebContents* web_contents = AddTab(browser(), page_url);
1178 EXPECT_TRUE(web_contents);
1179 EXPECT_TRUE(worker_filtered_event_listener.WaitUntilSatisfied());
1180}
1181
Istiaque Ahmedea5ed5042017-09-25 19:00:161182// Run with both native and JS-based bindings. This ensures that both stable
1183// (JS) and experimental (native) phases work correctly with worker scripts
1184// while we launch native bindings to stable.
1185INSTANTIATE_TEST_CASE_P(ServiceWorkerTestWithNativeBindings,
1186 ServiceWorkerTest,
1187 ::testing::Values(NATIVE_BINDINGS));
1188INSTANTIATE_TEST_CASE_P(ServiceWorkerTestWithJSBindings,
1189 ServiceWorkerTest,
1190 ::testing::Values(JAVASCRIPT_BINDINGS));
1191INSTANTIATE_TEST_CASE_P(ServiceWorkerBackgroundSyncTestWithNativeBindings,
1192 ServiceWorkerBackgroundSyncTest,
1193 ::testing::Values(NATIVE_BINDINGS));
1194INSTANTIATE_TEST_CASE_P(ServiceWorkerBackgroundSyncTestWithJSBindings,
1195 ServiceWorkerBackgroundSyncTest,
1196 ::testing::Values(JAVASCRIPT_BINDINGS));
1197INSTANTIATE_TEST_CASE_P(ServiceWorkerPushMessagingTestWithNativeBindings,
1198 ServiceWorkerPushMessagingTest,
1199 ::testing::Values(NATIVE_BINDINGS));
1200INSTANTIATE_TEST_CASE_P(ServiceWorkerPushMessagingTestWithJSBindings,
1201 ServiceWorkerPushMessagingTest,
1202 ::testing::Values(JAVASCRIPT_BINDINGS));
Istiaque Ahmed805f6a83b2017-10-05 01:23:261203INSTANTIATE_TEST_CASE_P(ServiceWorkerLazyBackgroundTestWithNativeBindings,
1204 ServiceWorkerLazyBackgroundTest,
1205 ::testing::Values(NATIVE_BINDINGS));
1206INSTANTIATE_TEST_CASE_P(ServiceWorkerLazyBackgroundTestWithJSBindings,
1207 ServiceWorkerLazyBackgroundTest,
1208 ::testing::Values(JAVASCRIPT_BINDINGS));
Istiaque Ahmedea5ed5042017-09-25 19:00:161209
annekao38685502015-07-14 17:46:391210} // namespace extensions