blob: a27666969d4af1f926f28603ffeeb31ca5363339 [file] [log] [blame]
annekao38685502015-07-14 17:46:391// Copyright 2015 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
avia2f4804a2015-12-24 23:11:135#include <stdint.h>
6
kalman6f984ae2015-09-18 17:21:587#include "base/bind_helpers.h"
avia2f4804a2015-12-24 23:11:138#include "base/macros.h"
Gabriel Charette078e3662017-08-28 22:59:049#include "base/run_loop.h"
kalman6f984ae2015-09-18 17:21:5810#include "base/strings/stringprintf.h"
horo1eeddde2015-11-19 05:59:2511#include "base/strings/utf_string_conversions.h"
jam3f2d3932017-04-26 20:28:5112#include "base/threading/thread_restrictions.h"
Olga Sharonova3e13cd92018-02-08 16:43:5613#include "build/build_config.h"
annekao38685502015-07-14 17:46:3914#include "chrome/browser/extensions/extension_apitest.h"
rdevlin.croninf5863da2015-09-10 19:21:4515#include "chrome/browser/extensions/extension_service.h"
Istiaque Ahmed805f6a83b2017-10-05 01:23:2616#include "chrome/browser/extensions/lazy_background_page_test_util.h"
peter9f4490a2017-01-27 00:58:3617#include "chrome/browser/gcm/fake_gcm_profile_service.h"
18#include "chrome/browser/gcm/gcm_profile_service_factory.h"
lazyboy561b7de2015-11-19 19:27:3019#include "chrome/browser/notifications/desktop_notification_profile_util.h"
miguelg9b502862017-04-24 18:13:5320#include "chrome/browser/notifications/notification_display_service_factory.h"
21#include "chrome/browser/notifications/stub_notification_display_service.h"
lshang106c1772016-06-06 01:43:2322#include "chrome/browser/permissions/permission_manager.h"
timlohc6911802017-03-01 05:37:0323#include "chrome/browser/permissions/permission_result.h"
lazyboy561b7de2015-11-19 19:27:3024#include "chrome/browser/push_messaging/push_messaging_app_identifier.h"
25#include "chrome/browser/push_messaging/push_messaging_service_factory.h"
26#include "chrome/browser/push_messaging/push_messaging_service_impl.h"
annekao1db36fd2015-07-29 17:09:1627#include "chrome/browser/ui/tabs/tab_strip_model.h"
Trent Apted4267b942017-10-27 03:25:3628#include "chrome/common/chrome_switches.h"
rdevlin.croninf5863da2015-09-10 19:21:4529#include "chrome/test/base/ui_test_utils.h"
timloh9a180ad2017-02-20 07:15:2330#include "components/content_settings/core/common/content_settings_types.h"
johnmea5045732016-09-08 17:23:2931#include "components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h"
sdefresne9fb67692015-08-03 18:48:2232#include "components/version_info/version_info.h"
kalman6f984ae2015-09-18 17:21:5833#include "content/public/browser/navigation_controller.h"
rdevlin.croninf5863da2015-09-10 19:21:4534#include "content/public/browser/navigation_entry.h"
lazyboy4c82177a2016-10-18 00:04:0935#include "content/public/browser/service_worker_context.h"
36#include "content/public/browser/storage_partition.h"
kalman6f984ae2015-09-18 17:21:5837#include "content/public/browser/web_contents.h"
lazyboybd325ae2015-11-18 21:35:2638#include "content/public/common/content_switches.h"
falkenad185092016-06-16 06:10:0239#include "content/public/common/origin_util.h"
kalman6f984ae2015-09-18 17:21:5840#include "content/public/common/page_type.h"
lazyboybd325ae2015-11-18 21:35:2641#include "content/public/test/background_sync_test_util.h"
annekao1db36fd2015-07-29 17:09:1642#include "content/public/test/browser_test_utils.h"
lazyboy63b994a2017-06-30 21:20:2343#include "content/public/test/service_worker_test_helpers.h"
kalman6f984ae2015-09-18 17:21:5844#include "extensions/browser/extension_host.h"
lazyboyc3e763a2015-12-09 23:09:5845#include "extensions/browser/extension_registry.h"
kalman6f984ae2015-09-18 17:21:5846#include "extensions/browser/process_manager.h"
Devlin Cronina3fe3d602017-11-22 04:47:4347#include "extensions/common/extension_features.h"
kalman6f984ae2015-09-18 17:21:5848#include "extensions/test/background_page_watcher.h"
annekao38685502015-07-14 17:46:3949#include "extensions/test/extension_test_message_listener.h"
Istiaque Ahmed805f6a83b2017-10-05 01:23:2650#include "extensions/test/result_catcher.h"
falkenad185092016-06-16 06:10:0251#include "net/dns/mock_host_resolver.h"
horo1eeddde2015-11-19 05:59:2552#include "net/test/embedded_test_server/embedded_test_server.h"
lazyboy63b994a2017-06-30 21:20:2353#include "url/url_constants.h"
annekao38685502015-07-14 17:46:3954
55namespace extensions {
56
kalman6f984ae2015-09-18 17:21:5857namespace {
58
59// Pass into ServiceWorkerTest::StartTestFromBackgroundPage to indicate that
60// registration is expected to succeed.
61std::string* const kExpectSuccess = nullptr;
62
63void DoNothingWithBool(bool b) {}
64
lazyboy22eddc712015-12-10 21:16:2665// Returns the newly added WebContents.
66content::WebContents* AddTab(Browser* browser, const GURL& url) {
67 int starting_tab_count = browser->tab_strip_model()->count();
68 ui_test_utils::NavigateToURLWithDisposition(
nick3b04f322016-08-31 19:29:1969 browser, url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
lazyboy22eddc712015-12-10 21:16:2670 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
71 int tab_count = browser->tab_strip_model()->count();
72 EXPECT_EQ(starting_tab_count + 1, tab_count);
73 return browser->tab_strip_model()->GetActiveWebContents();
74}
75
Istiaque Ahmedea5ed5042017-09-25 19:00:1676enum BindingsType { NATIVE_BINDINGS, JAVASCRIPT_BINDINGS };
77
lazyboy22eddc712015-12-10 21:16:2678class WebContentsLoadStopObserver : content::WebContentsObserver {
79 public:
80 explicit WebContentsLoadStopObserver(content::WebContents* web_contents)
81 : content::WebContentsObserver(web_contents),
82 load_stop_observed_(false) {}
83
84 void WaitForLoadStop() {
85 if (load_stop_observed_)
86 return;
87 message_loop_runner_ = new content::MessageLoopRunner;
88 message_loop_runner_->Run();
89 }
90
91 private:
92 void DidStopLoading() override {
93 load_stop_observed_ = true;
94 if (message_loop_runner_)
95 message_loop_runner_->Quit();
96 }
97
98 bool load_stop_observed_;
99 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
100
101 DISALLOW_COPY_AND_ASSIGN(WebContentsLoadStopObserver);
102};
103
kalman6f984ae2015-09-18 17:21:58104} // namespace
105
Istiaque Ahmedea5ed5042017-09-25 19:00:16106class ServiceWorkerTest : public ExtensionApiTest,
107 public ::testing::WithParamInterface<BindingsType> {
annekao38685502015-07-14 17:46:39108 public:
lazyboy20167c22016-05-18 00:59:30109 ServiceWorkerTest() : current_channel_(version_info::Channel::STABLE) {}
Istiaque Ahmed7105f2a2017-10-07 01:11:59110 explicit ServiceWorkerTest(version_info::Channel channel)
111 : current_channel_(channel) {}
annekao38685502015-07-14 17:46:39112
113 ~ServiceWorkerTest() override {}
114
Devlin Cronina3fe3d602017-11-22 04:47:43115 void SetUp() override {
116 if (GetParam() == NATIVE_BINDINGS) {
117 scoped_feature_list_.InitAndEnableFeature(features::kNativeCrxBindings);
118 } else {
119 DCHECK_EQ(JAVASCRIPT_BINDINGS, GetParam());
120 scoped_feature_list_.InitAndDisableFeature(features::kNativeCrxBindings);
121 }
122 ExtensionApiTest::SetUp();
123 }
124
jam1a5b5582017-05-01 16:50:10125 void SetUpOnMainThread() override {
126 ExtensionApiTest::SetUpOnMainThread();
127 host_resolver()->AddRule("a.com", "127.0.0.1");
128 }
129
kalman6f984ae2015-09-18 17:21:58130 protected:
131 // Returns the ProcessManager for the test's profile.
132 ProcessManager* process_manager() { return ProcessManager::Get(profile()); }
133
134 // Starts running a test from the background page test extension.
135 //
136 // This registers a service worker with |script_name|, and fetches the
137 // registration result.
138 //
139 // If |error_or_null| is null (kExpectSuccess), success is expected and this
140 // will fail if there is an error.
141 // If |error_or_null| is not null, nothing is assumed, and the error (which
142 // may be empty) is written to it.
143 const Extension* StartTestFromBackgroundPage(const char* script_name,
144 std::string* error_or_null) {
145 const Extension* extension =
146 LoadExtension(test_data_dir_.AppendASCII("service_worker/background"));
147 CHECK(extension);
148 ExtensionHost* background_host =
149 process_manager()->GetBackgroundHostForExtension(extension->id());
150 CHECK(background_host);
151 std::string error;
152 CHECK(content::ExecuteScriptAndExtractString(
153 background_host->host_contents(),
154 base::StringPrintf("test.registerServiceWorker('%s')", script_name),
155 &error));
156 if (error_or_null)
157 *error_or_null = error;
158 else if (!error.empty())
159 ADD_FAILURE() << "Got unexpected error " << error;
160 return extension;
161 }
162
163 // Navigates the browser to a new tab at |url|, waits for it to load, then
164 // returns it.
165 content::WebContents* Navigate(const GURL& url) {
166 ui_test_utils::NavigateToURLWithDisposition(
nick3b04f322016-08-31 19:29:19167 browser(), url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
kalman6f984ae2015-09-18 17:21:58168 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
169 content::WebContents* web_contents =
170 browser()->tab_strip_model()->GetActiveWebContents();
171 content::WaitForLoadStop(web_contents);
172 return web_contents;
173 }
174
175 // Navigates the browser to |url| and returns the new tab's page type.
176 content::PageType NavigateAndGetPageType(const GURL& url) {
177 return Navigate(url)->GetController().GetActiveEntry()->GetPageType();
178 }
179
180 // Extracts the innerText from |contents|.
181 std::string ExtractInnerText(content::WebContents* contents) {
182 std::string inner_text;
183 if (!content::ExecuteScriptAndExtractString(
184 contents,
185 "window.domAutomationController.send(document.body.innerText)",
186 &inner_text)) {
187 ADD_FAILURE() << "Failed to get inner text for "
188 << contents->GetVisibleURL();
189 }
190 return inner_text;
191 }
192
193 // Navigates the browser to |url|, then returns the innerText of the new
194 // tab's WebContents' main frame.
195 std::string NavigateAndExtractInnerText(const GURL& url) {
196 return ExtractInnerText(Navigate(url));
197 }
198
lazyboy4c82177a2016-10-18 00:04:09199 size_t GetWorkerRefCount(const GURL& origin) {
200 content::ServiceWorkerContext* sw_context =
201 content::BrowserContext::GetDefaultStoragePartition(
202 browser()->profile())
203 ->GetServiceWorkerContext();
204 base::RunLoop run_loop;
205 size_t ref_count = 0;
206 auto set_ref_count = [](size_t* ref_count, base::RunLoop* run_loop,
207 size_t external_request_count) {
208 *ref_count = external_request_count;
209 run_loop->Quit();
210 };
211 sw_context->CountExternalRequestsForTest(
Matt Falkenhagenc5cb4282017-09-07 08:43:42212 origin, base::BindOnce(set_ref_count, &ref_count, &run_loop));
lazyboy4c82177a2016-10-18 00:04:09213 run_loop.Run();
214 return ref_count;
215 }
216
annekao38685502015-07-14 17:46:39217 private:
lazyboy20167c22016-05-18 00:59:30218 // Sets the channel to "stable".
219 // Not useful after we've opened extension Service Workers to stable
220 // channel.
221 // TODO(lazyboy): Remove this when ExtensionServiceWorkersEnabled() is
222 // removed.
annekao38685502015-07-14 17:46:39223 ScopedCurrentChannel current_channel_;
kalman6f984ae2015-09-18 17:21:58224
Devlin Cronina3fe3d602017-11-22 04:47:43225 base::test::ScopedFeatureList scoped_feature_list_;
226
annekao38685502015-07-14 17:46:39227 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerTest);
228};
229
lazyboybd325ae2015-11-18 21:35:26230class ServiceWorkerBackgroundSyncTest : public ServiceWorkerTest {
231 public:
232 ServiceWorkerBackgroundSyncTest() {}
233 ~ServiceWorkerBackgroundSyncTest() override {}
234
235 void SetUpCommandLine(base::CommandLine* command_line) override {
236 // ServiceWorkerRegistration.sync requires experimental flag.
237 command_line->AppendSwitch(
Istiaque Ahmedea5ed5042017-09-25 19:00:16238 ::switches::kEnableExperimentalWebPlatformFeatures);
lazyboybd325ae2015-11-18 21:35:26239 ServiceWorkerTest::SetUpCommandLine(command_line);
240 }
241
242 void SetUp() override {
243 content::background_sync_test_util::SetIgnoreNetworkChangeNotifier(true);
244 ServiceWorkerTest::SetUp();
245 }
246
247 private:
248 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerBackgroundSyncTest);
249};
250
lazyboy561b7de2015-11-19 19:27:30251class ServiceWorkerPushMessagingTest : public ServiceWorkerTest {
252 public:
253 ServiceWorkerPushMessagingTest()
johnmea5045732016-09-08 17:23:29254 : gcm_driver_(nullptr), push_service_(nullptr) {}
lazyboy561b7de2015-11-19 19:27:30255 ~ServiceWorkerPushMessagingTest() override {}
256
257 void GrantNotificationPermissionForTest(const GURL& url) {
258 GURL origin = url.GetOrigin();
259 DesktopNotificationProfileUtil::GrantPermission(profile(), origin);
timlohc6911802017-03-01 05:37:03260 ASSERT_EQ(CONTENT_SETTING_ALLOW,
261 PermissionManager::Get(profile())
262 ->GetPermissionStatus(CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
263 origin, origin)
264 .content_setting);
lazyboy561b7de2015-11-19 19:27:30265 }
266
267 PushMessagingAppIdentifier GetAppIdentifierForServiceWorkerRegistration(
avia2f4804a2015-12-24 23:11:13268 int64_t service_worker_registration_id,
lazyboy561b7de2015-11-19 19:27:30269 const GURL& origin) {
270 PushMessagingAppIdentifier app_identifier =
271 PushMessagingAppIdentifier::FindByServiceWorker(
272 profile(), origin, service_worker_registration_id);
273
274 EXPECT_FALSE(app_identifier.is_null());
275 return app_identifier;
276 }
277
278 // ExtensionApiTest overrides.
279 void SetUpCommandLine(base::CommandLine* command_line) override {
peter9de96272015-12-04 15:23:27280 command_line->AppendSwitch(
Istiaque Ahmedea5ed5042017-09-25 19:00:16281 ::switches::kEnableExperimentalWebPlatformFeatures);
lazyboy561b7de2015-11-19 19:27:30282 ServiceWorkerTest::SetUpCommandLine(command_line);
283 }
284 void SetUpOnMainThread() override {
miguelg9b502862017-04-24 18:13:53285 NotificationDisplayServiceFactory::GetInstance()->SetTestingFactory(
286 profile(), &StubNotificationDisplayService::FactoryForTests);
287
johnmea5045732016-09-08 17:23:29288 gcm::FakeGCMProfileService* gcm_service =
289 static_cast<gcm::FakeGCMProfileService*>(
290 gcm::GCMProfileServiceFactory::GetInstance()
291 ->SetTestingFactoryAndUse(profile(),
292 &gcm::FakeGCMProfileService::Build));
293 gcm_driver_ = static_cast<instance_id::FakeGCMDriverForInstanceID*>(
294 gcm_service->driver());
lazyboy561b7de2015-11-19 19:27:30295 push_service_ = PushMessagingServiceFactory::GetForProfile(profile());
296
297 ServiceWorkerTest::SetUpOnMainThread();
298 }
299
johnmea5045732016-09-08 17:23:29300 instance_id::FakeGCMDriverForInstanceID* gcm_driver() const {
301 return gcm_driver_;
302 }
lazyboy561b7de2015-11-19 19:27:30303 PushMessagingServiceImpl* push_service() const { return push_service_; }
304
305 private:
johnmea5045732016-09-08 17:23:29306 instance_id::FakeGCMDriverForInstanceID* gcm_driver_;
lazyboy561b7de2015-11-19 19:27:30307 PushMessagingServiceImpl* push_service_;
308
309 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerPushMessagingTest);
310};
311
Istiaque Ahmed805f6a83b2017-10-05 01:23:26312class ServiceWorkerLazyBackgroundTest : public ServiceWorkerTest {
313 public:
Istiaque Ahmed7105f2a2017-10-07 01:11:59314 ServiceWorkerLazyBackgroundTest()
315 : ServiceWorkerTest(
316 // Extensions APIs from SW are only enabled on trunk.
317 // It is important to set the channel early so that this change is
318 // visible in renderers running with service workers (and no
319 // extension).
320 version_info::Channel::UNKNOWN) {}
Istiaque Ahmed805f6a83b2017-10-05 01:23:26321 ~ServiceWorkerLazyBackgroundTest() override {}
322
323 void SetUpCommandLine(base::CommandLine* command_line) override {
324 ServiceWorkerTest::SetUpCommandLine(command_line);
325 // Disable background network activity as it can suddenly bring the Lazy
326 // Background Page alive.
327 command_line->AppendSwitch(::switches::kDisableBackgroundNetworking);
328 command_line->AppendSwitch(::switches::kNoProxyServer);
329 }
330
331 void SetUpInProcessBrowserTestFixture() override {
332 ServiceWorkerTest::SetUpInProcessBrowserTestFixture();
333 // Set shorter delays to prevent test timeouts.
334 ProcessManager::SetEventPageIdleTimeForTesting(1);
335 ProcessManager::SetEventPageSuspendingTimeForTesting(1);
336 }
337
338 private:
339 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerLazyBackgroundTest);
340};
341
Istiaque Ahmedea5ed5042017-09-25 19:00:16342IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, RegisterSucceeds) {
kalman6f984ae2015-09-18 17:21:58343 StartTestFromBackgroundPage("register.js", kExpectSuccess);
annekao38685502015-07-14 17:46:39344}
345
Istiaque Ahmedea5ed5042017-09-25 19:00:16346IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, UpdateRefreshesServiceWorker) {
Francois Doraye6fb2d02017-10-18 21:29:13347 base::ScopedAllowBlockingForTesting allow_blocking;
lazyboyc3e763a2015-12-09 23:09:58348 base::ScopedTempDir scoped_temp_dir;
349 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
350 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
351 .AppendASCII("update")
352 .AppendASCII("service_worker.pem");
vabr9142fe22016-09-08 13:19:22353 base::FilePath path_v1 =
354 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
355 .AppendASCII("update")
356 .AppendASCII("v1"),
357 scoped_temp_dir.GetPath().AppendASCII("v1.crx"),
358 pem_path, base::FilePath());
359 base::FilePath path_v2 =
360 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
361 .AppendASCII("update")
362 .AppendASCII("v2"),
363 scoped_temp_dir.GetPath().AppendASCII("v2.crx"),
364 pem_path, base::FilePath());
lazyboyc3e763a2015-12-09 23:09:58365 const char* kId = "hfaanndiiilofhfokeanhddpkfffchdi";
366
367 ExtensionTestMessageListener listener_v1("Pong from version 1", false);
368 listener_v1.set_failure_message("FAILURE_V1");
369 // Install version 1.0 of the extension.
370 ASSERT_TRUE(InstallExtension(path_v1, 1));
371 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
372 ->enabled_extensions()
373 .GetByID(kId));
374 EXPECT_TRUE(listener_v1.WaitUntilSatisfied());
375
376 ExtensionTestMessageListener listener_v2("Pong from version 2", false);
377 listener_v2.set_failure_message("FAILURE_V2");
378
379 // Update to version 2.0.
380 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
381 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
382 ->enabled_extensions()
383 .GetByID(kId));
384 EXPECT_TRUE(listener_v2.WaitUntilSatisfied());
385}
386
[email protected]2ef85d562017-09-15 18:41:52387// TODO(crbug.com/765736) Fix the test.
Istiaque Ahmedea5ed5042017-09-25 19:00:16388IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, DISABLED_UpdateWithoutSkipWaiting) {
Francois Doraye6fb2d02017-10-18 21:29:13389 base::ScopedAllowBlockingForTesting allow_blocking;
lazyboy22eddc712015-12-10 21:16:26390 base::ScopedTempDir scoped_temp_dir;
391 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
392 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
393 .AppendASCII("update_without_skip_waiting")
394 .AppendASCII("update_without_skip_waiting.pem");
vabr9142fe22016-09-08 13:19:22395 base::FilePath path_v1 =
396 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
397 .AppendASCII("update_without_skip_waiting")
398 .AppendASCII("v1"),
399 scoped_temp_dir.GetPath().AppendASCII("v1.crx"),
400 pem_path, base::FilePath());
401 base::FilePath path_v2 =
402 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
403 .AppendASCII("update_without_skip_waiting")
404 .AppendASCII("v2"),
405 scoped_temp_dir.GetPath().AppendASCII("v2.crx"),
406 pem_path, base::FilePath());
lazyboy22eddc712015-12-10 21:16:26407 const char* kId = "mhnnnflgagdakldgjpfcofkiocpdmogl";
408
409 // Install version 1.0 of the extension.
410 ASSERT_TRUE(InstallExtension(path_v1, 1));
411 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
412 ->enabled_extensions()
413 .GetByID(kId));
414 const Extension* extension = extensions::ExtensionRegistry::Get(profile())
415 ->enabled_extensions()
416 .GetByID(kId);
417
418 ExtensionTestMessageListener listener1("Pong from version 1", false);
419 listener1.set_failure_message("FAILURE");
420 content::WebContents* web_contents =
421 AddTab(browser(), extension->GetResourceURL("page.html"));
422 EXPECT_TRUE(listener1.WaitUntilSatisfied());
423
424 // Update to version 2.0.
425 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
426 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
427 ->enabled_extensions()
428 .GetByID(kId));
429 const Extension* extension_after_update =
430 extensions::ExtensionRegistry::Get(profile())
431 ->enabled_extensions()
432 .GetByID(kId);
433
434 // Service worker version 2 would be installed but it won't be controlling
435 // the extension page yet.
436 ExtensionTestMessageListener listener2("Pong from version 1", false);
437 listener2.set_failure_message("FAILURE");
438 web_contents =
439 AddTab(browser(), extension_after_update->GetResourceURL("page.html"));
440 EXPECT_TRUE(listener2.WaitUntilSatisfied());
441
442 // Navigate the tab away from the extension page so that no clients are
443 // using the service worker.
444 // Note that just closing the tab with WebContentsDestroyedWatcher doesn't
445 // seem to be enough because it returns too early.
446 WebContentsLoadStopObserver navigate_away_observer(web_contents);
447 web_contents->GetController().LoadURL(
448 GURL(url::kAboutBlankURL), content::Referrer(), ui::PAGE_TRANSITION_TYPED,
449 std::string());
450 navigate_away_observer.WaitForLoadStop();
451
452 // Now expect service worker version 2 to control the extension page.
453 ExtensionTestMessageListener listener3("Pong from version 2", false);
454 listener3.set_failure_message("FAILURE");
455 web_contents =
456 AddTab(browser(), extension_after_update->GetResourceURL("page.html"));
457 EXPECT_TRUE(listener3.WaitUntilSatisfied());
458}
459
Istiaque Ahmedea5ed5042017-09-25 19:00:16460IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, FetchArbitraryPaths) {
kalman6f984ae2015-09-18 17:21:58461 const Extension* extension =
462 StartTestFromBackgroundPage("fetch.js", kExpectSuccess);
annekao1db36fd2015-07-29 17:09:16463
kalman6f984ae2015-09-18 17:21:58464 // Open some arbirary paths. Their contents should be what the service worker
465 // responds with, which in this case is the path of the fetch.
466 EXPECT_EQ(
467 "Caught a fetch for /index.html",
468 NavigateAndExtractInnerText(extension->GetResourceURL("index.html")));
469 EXPECT_EQ("Caught a fetch for /path/to/other.html",
470 NavigateAndExtractInnerText(
471 extension->GetResourceURL("path/to/other.html")));
472 EXPECT_EQ("Caught a fetch for /some/text/file.txt",
473 NavigateAndExtractInnerText(
474 extension->GetResourceURL("some/text/file.txt")));
475 EXPECT_EQ("Caught a fetch for /no/file/extension",
476 NavigateAndExtractInnerText(
477 extension->GetResourceURL("no/file/extension")));
478 EXPECT_EQ("Caught a fetch for /",
479 NavigateAndExtractInnerText(extension->GetResourceURL("")));
annekao1db36fd2015-07-29 17:09:16480}
481
Istiaque Ahmedea5ed5042017-09-25 19:00:16482IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, SWServedBackgroundPageReceivesEvent) {
lazyboy52c3bcf2016-01-08 00:11:29483 const Extension* extension =
484 StartTestFromBackgroundPage("replace_background.js", kExpectSuccess);
485 ExtensionHost* background_page =
486 process_manager()->GetBackgroundHostForExtension(extension->id());
487 ASSERT_TRUE(background_page);
488
489 // Close the background page and start it again so that the service worker
490 // will start controlling pages.
491 background_page->Close();
492 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
493 background_page = nullptr;
494 process_manager()->WakeEventPage(extension->id(),
495 base::Bind(&DoNothingWithBool));
496 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
497
498 // Since the SW is now controlling the extension, the SW serves the background
499 // script. page.html sends a message to the background script and we verify
500 // that the SW served background script correctly receives the message/event.
501 ExtensionTestMessageListener listener("onMessage/SW BG.", false);
502 listener.set_failure_message("onMessage/original BG.");
503 content::WebContents* web_contents =
504 AddTab(browser(), extension->GetResourceURL("page.html"));
505 ASSERT_TRUE(web_contents);
506 EXPECT_TRUE(listener.WaitUntilSatisfied());
507}
508
Istiaque Ahmedea5ed5042017-09-25 19:00:16509IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:58510 LoadingBackgroundPageBypassesServiceWorker) {
511 const Extension* extension =
512 StartTestFromBackgroundPage("fetch.js", kExpectSuccess);
annekao49241182015-08-18 17:14:01513
kalman6f984ae2015-09-18 17:21:58514 std::string kExpectedInnerText = "background.html contents for testing.";
annekao49241182015-08-18 17:14:01515
kalman6f984ae2015-09-18 17:21:58516 // Sanity check that the background page has the expected content.
517 ExtensionHost* background_page =
518 process_manager()->GetBackgroundHostForExtension(extension->id());
519 ASSERT_TRUE(background_page);
520 EXPECT_EQ(kExpectedInnerText,
521 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:01522
kalman6f984ae2015-09-18 17:21:58523 // Close the background page.
524 background_page->Close();
525 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
526 background_page = nullptr;
527
528 // Start it again.
529 process_manager()->WakeEventPage(extension->id(),
530 base::Bind(&DoNothingWithBool));
531 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
532
533 // Content should not have been affected by the fetch, which would otherwise
534 // be "Caught fetch for...".
535 background_page =
536 process_manager()->GetBackgroundHostForExtension(extension->id());
537 ASSERT_TRUE(background_page);
538 content::WaitForLoadStop(background_page->host_contents());
539
540 // TODO(kalman): Everything you've read has been a LIE! It should be:
541 //
542 // EXPECT_EQ(kExpectedInnerText,
543 // ExtractInnerText(background_page->host_contents()));
544 //
545 // but there is a bug, and we're actually *not* bypassing the service worker
546 // for background page loads! For now, let it pass (assert wrong behavior)
547 // because it's not a regression, but this must be fixed eventually.
548 //
549 // Tracked in crbug.com/532720.
550 EXPECT_EQ("Caught a fetch for /background.html",
551 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:01552}
553
Istiaque Ahmedea5ed5042017-09-25 19:00:16554IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:58555 ServiceWorkerPostsMessageToBackgroundClient) {
556 const Extension* extension = StartTestFromBackgroundPage(
557 "post_message_to_background_client.js", kExpectSuccess);
annekao533482222015-08-21 23:23:53558
kalman6f984ae2015-09-18 17:21:58559 // The service worker in this test simply posts a message to the background
560 // client it receives from getBackgroundClient().
561 const char* kScript =
562 "var messagePromise = null;\n"
563 "if (test.lastMessageFromServiceWorker) {\n"
564 " messagePromise = Promise.resolve(test.lastMessageFromServiceWorker);\n"
565 "} else {\n"
566 " messagePromise = test.waitForMessage(navigator.serviceWorker);\n"
567 "}\n"
568 "messagePromise.then(function(message) {\n"
569 " window.domAutomationController.send(String(message == 'success'));\n"
570 "})\n";
571 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:53572}
573
Istiaque Ahmedea5ed5042017-09-25 19:00:16574IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:58575 BackgroundPagePostsMessageToServiceWorker) {
576 const Extension* extension =
577 StartTestFromBackgroundPage("post_message_to_sw.js", kExpectSuccess);
annekao533482222015-08-21 23:23:53578
kalman6f984ae2015-09-18 17:21:58579 // The service worker in this test waits for a message, then echoes it back
580 // by posting a message to the background page via getBackgroundClient().
581 const char* kScript =
582 "var mc = new MessageChannel();\n"
583 "test.waitForMessage(mc.port1).then(function(message) {\n"
584 " window.domAutomationController.send(String(message == 'hello'));\n"
585 "});\n"
586 "test.registeredServiceWorker.postMessage(\n"
587 " {message: 'hello', port: mc.port2}, [mc.port2])\n";
588 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:53589}
590
Istiaque Ahmedea5ed5042017-09-25 19:00:16591IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
rdevlin.croninf5863da2015-09-10 19:21:45592 ServiceWorkerSuspensionOnExtensionUnload) {
kalman6f984ae2015-09-18 17:21:58593 // For this test, only hold onto the extension's ID and URL + a function to
594 // get a resource URL, because we're going to be disabling and uninstalling
595 // it, which will invalidate the pointer.
596 std::string extension_id;
597 GURL extension_url;
598 {
599 const Extension* extension =
600 StartTestFromBackgroundPage("fetch.js", kExpectSuccess);
601 extension_id = extension->id();
602 extension_url = extension->url();
603 }
604 auto get_resource_url = [&extension_url](const std::string& path) {
605 return Extension::GetResourceURL(extension_url, path);
606 };
rdevlin.croninf5863da2015-09-10 19:21:45607
kalman6f984ae2015-09-18 17:21:58608 // Fetch should route to the service worker.
609 EXPECT_EQ("Caught a fetch for /index.html",
610 NavigateAndExtractInnerText(get_resource_url("index.html")));
rdevlin.croninf5863da2015-09-10 19:21:45611
kalman6f984ae2015-09-18 17:21:58612 // Disable the extension. Opening the page should fail.
613 extension_service()->DisableExtension(extension_id,
Minh X. Nguyen45479012017-08-18 21:35:36614 disable_reason::DISABLE_USER_ACTION);
rdevlin.croninf5863da2015-09-10 19:21:45615 base::RunLoop().RunUntilIdle();
rdevlin.croninf5863da2015-09-10 19:21:45616
kalman6f984ae2015-09-18 17:21:58617 EXPECT_EQ(content::PAGE_TYPE_ERROR,
618 NavigateAndGetPageType(get_resource_url("index.html")));
619 EXPECT_EQ(content::PAGE_TYPE_ERROR,
620 NavigateAndGetPageType(get_resource_url("other.html")));
621
622 // Re-enable the extension. Opening pages should immediately start to succeed
623 // again.
rdevlin.croninf5863da2015-09-10 19:21:45624 extension_service()->EnableExtension(extension_id);
625 base::RunLoop().RunUntilIdle();
626
kalman6f984ae2015-09-18 17:21:58627 EXPECT_EQ("Caught a fetch for /index.html",
628 NavigateAndExtractInnerText(get_resource_url("index.html")));
629 EXPECT_EQ("Caught a fetch for /other.html",
630 NavigateAndExtractInnerText(get_resource_url("other.html")));
631 EXPECT_EQ("Caught a fetch for /another.html",
632 NavigateAndExtractInnerText(get_resource_url("another.html")));
rdevlin.croninf5863da2015-09-10 19:21:45633
kalman6f984ae2015-09-18 17:21:58634 // Uninstall the extension. Opening pages should fail again.
635 base::string16 error;
636 extension_service()->UninstallExtension(
Devlin Cronin218df7f2017-11-21 21:41:31637 extension_id, UninstallReason::UNINSTALL_REASON_FOR_TESTING, &error);
kalman6f984ae2015-09-18 17:21:58638 base::RunLoop().RunUntilIdle();
639
640 EXPECT_EQ(content::PAGE_TYPE_ERROR,
641 NavigateAndGetPageType(get_resource_url("index.html")));
642 EXPECT_EQ(content::PAGE_TYPE_ERROR,
643 NavigateAndGetPageType(get_resource_url("other.html")));
644 EXPECT_EQ(content::PAGE_TYPE_ERROR,
645 NavigateAndGetPageType(get_resource_url("anotherother.html")));
646 EXPECT_EQ(content::PAGE_TYPE_ERROR,
647 NavigateAndGetPageType(get_resource_url("final.html")));
648}
649
Istiaque Ahmedea5ed5042017-09-25 19:00:16650IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, BackgroundPageIsWokenIfAsleep) {
kalman6f984ae2015-09-18 17:21:58651 const Extension* extension =
652 StartTestFromBackgroundPage("wake_on_fetch.js", kExpectSuccess);
653
654 // Navigate to special URLs that this test's service worker recognises, each
655 // making a check then populating the response with either "true" or "false".
656 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
657 "background-client-is-awake")));
658 EXPECT_EQ("true", NavigateAndExtractInnerText(
659 extension->GetResourceURL("ping-background-client")));
660 // Ping more than once for good measure.
661 EXPECT_EQ("true", NavigateAndExtractInnerText(
662 extension->GetResourceURL("ping-background-client")));
663
664 // Shut down the event page. The SW should detect that it's closed, but still
665 // be able to ping it.
666 ExtensionHost* background_page =
667 process_manager()->GetBackgroundHostForExtension(extension->id());
668 ASSERT_TRUE(background_page);
669 background_page->Close();
670 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
671
672 EXPECT_EQ("false", NavigateAndExtractInnerText(extension->GetResourceURL(
673 "background-client-is-awake")));
674 EXPECT_EQ("true", NavigateAndExtractInnerText(
675 extension->GetResourceURL("ping-background-client")));
676 EXPECT_EQ("true", NavigateAndExtractInnerText(
677 extension->GetResourceURL("ping-background-client")));
678 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
679 "background-client-is-awake")));
680}
681
Istiaque Ahmedea5ed5042017-09-25 19:00:16682IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:58683 GetBackgroundClientFailsWithNoBackgroundPage) {
684 // This extension doesn't have a background page, only a tab at page.html.
685 // The service worker it registers tries to call getBackgroundClient() and
686 // should fail.
687 // Note that this also tests that service workers can be registered from tabs.
688 EXPECT_TRUE(RunExtensionSubtest("service_worker/no_background", "page.html"));
rdevlin.croninf5863da2015-09-10 19:21:45689}
690
Istiaque Ahmedea5ed5042017-09-25 19:00:16691IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, NotificationAPI) {
lazyboy6ddb7d62015-11-10 23:15:27692 EXPECT_TRUE(RunExtensionSubtest("service_worker/notifications/has_permission",
693 "page.html"));
694}
695
Istiaque Ahmedea5ed5042017-09-25 19:00:16696IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, WebAccessibleResourcesFetch) {
lazyboyaea32c22016-01-04 21:37:07697 EXPECT_TRUE(RunExtensionSubtest(
698 "service_worker/web_accessible_resources/fetch/", "page.html"));
699}
700
Olga Sharonova3e13cd92018-02-08 16:43:56701// Flaky on Linux: http://crbug/810397.
702#if defined(OS_LINUX)
703#define MAYBE_TabsCreate DISABLED_TabsCreate
704#else
705#define MAYBE_TabsCreate TabsCreate
706#endif
707IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, MAYBE_TabsCreate) {
lazyboyee4adef2016-05-24 00:55:16708 // Extensions APIs from SW are only enabled on trunk.
709 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
710 const Extension* extension = LoadExtensionWithFlags(
711 test_data_dir_.AppendASCII("service_worker/tabs_create"), kFlagNone);
712 ASSERT_TRUE(extension);
713 ui_test_utils::NavigateToURL(browser(),
714 extension->GetResourceURL("page.html"));
715 content::WebContents* web_contents =
716 browser()->tab_strip_model()->GetActiveWebContents();
717
718 int starting_tab_count = browser()->tab_strip_model()->count();
719 std::string result;
720 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
721 web_contents, "window.runServiceWorker()", &result));
722 ASSERT_EQ("chrome.tabs.create callback", result);
723 EXPECT_EQ(starting_tab_count + 1, browser()->tab_strip_model()->count());
724
725 // Check extension shutdown path.
726 UnloadExtension(extension->id());
727 EXPECT_EQ(starting_tab_count, browser()->tab_strip_model()->count());
728}
729
Istiaque Ahmedea5ed5042017-09-25 19:00:16730IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, Events) {
lazyboye7847242017-06-07 23:29:18731 // Extensions APIs from SW are only enabled on trunk.
732 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
733 const Extension* extension = LoadExtensionWithFlags(
734 test_data_dir_.AppendASCII("service_worker/events"), kFlagNone);
735 ASSERT_TRUE(extension);
736 ui_test_utils::NavigateToURL(browser(),
737 extension->GetResourceURL("page.html"));
738 content::WebContents* web_contents =
739 browser()->tab_strip_model()->GetActiveWebContents();
740 std::string result;
741 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
742 web_contents, "window.runEventTest()", &result));
743 ASSERT_EQ("chrome.tabs.onUpdated callback", result);
744}
745
Istiaque Ahmedea5ed5042017-09-25 19:00:16746IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, EventsToStoppedWorker) {
lazyboy63b994a2017-06-30 21:20:23747 // Extensions APIs from SW are only enabled on trunk.
748 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
749 const Extension* extension = LoadExtensionWithFlags(
750 test_data_dir_.AppendASCII("service_worker/events_to_stopped_worker"),
751 kFlagNone);
752 ASSERT_TRUE(extension);
753 ui_test_utils::NavigateToURL(browser(),
754 extension->GetResourceURL("page.html"));
755 content::WebContents* web_contents =
756 browser()->tab_strip_model()->GetActiveWebContents();
757 {
758 std::string result;
759 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
760 web_contents, "window.runServiceWorker()", &result));
761 ASSERT_EQ("ready", result);
762
763 base::RunLoop run_loop;
764 content::StoragePartition* storage_partition =
765 content::BrowserContext::GetDefaultStoragePartition(
766 browser()->profile());
767 content::StopServiceWorkerForPattern(
768 storage_partition->GetServiceWorkerContext(),
769 // The service worker is registered at the top level scope.
770 extension->url(), run_loop.QuitClosure());
771 run_loop.Run();
772 }
773
774 std::string result;
775 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
776 web_contents, "window.createTabThenUpdate()", &result));
777 ASSERT_EQ("chrome.tabs.onUpdated callback", result);
778}
779
Istiaque Ahmed805f6a83b2017-10-05 01:23:26780// Tests that events to service worker arrives correctly event if the owner
781// extension of the worker is not running.
782IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest,
783 EventsToStoppedExtension) {
Istiaque Ahmed805f6a83b2017-10-05 01:23:26784 LazyBackgroundObserver lazy_observer;
785 ResultCatcher catcher;
786 const Extension* extension = LoadExtensionWithFlags(
787 test_data_dir_.AppendASCII("service_worker/events_to_stopped_extension"),
788 kFlagNone);
789 ASSERT_TRUE(extension);
790 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
791
792 ProcessManager* pm = ProcessManager::Get(browser()->profile());
793 EXPECT_GT(pm->GetLazyKeepaliveCount(extension), 0);
794
795 // |extension|'s background page opens a tab to its resource.
796 content::WebContents* extension_web_contents =
797 browser()->tab_strip_model()->GetActiveWebContents();
798 EXPECT_TRUE(content::WaitForLoadStop(extension_web_contents));
799 EXPECT_EQ(extension->GetResourceURL("page.html").spec(),
800 extension_web_contents->GetURL().spec());
801 {
802 // Let the service worker start and register a listener to
803 // chrome.tabs.onCreated event.
804 ExtensionTestMessageListener add_listener_done("listener-added", false);
805 content::ExecuteScriptAsync(extension_web_contents,
806 "window.runServiceWorkerAsync()");
807 EXPECT_TRUE(add_listener_done.WaitUntilSatisfied());
808
809 base::RunLoop run_loop;
810 content::StoragePartition* storage_partition =
811 content::BrowserContext::GetDefaultStoragePartition(
812 browser()->profile());
813 content::StopServiceWorkerForPattern(
814 storage_partition->GetServiceWorkerContext(),
815 // The service worker is registered at the top level scope.
816 extension->url(), run_loop.QuitClosure());
817 run_loop.Run();
818 }
819
820 // Close the tab to |extension|'s resource. This will also close the
821 // extension's event page.
822 browser()->tab_strip_model()->CloseWebContentsAt(
823 browser()->tab_strip_model()->active_index(), TabStripModel::CLOSE_NONE);
824 lazy_observer.Wait();
825
826 // At this point both the extension worker and extension event page is not
827 // running. Since the worker registered a listener for tabs.onCreated, it
828 // will be started to dispatch the event once we create a tab.
829 ExtensionTestMessageListener newtab_listener("hello-newtab", false);
830 newtab_listener.set_failure_message("WRONG_NEWTAB");
831 content::WebContents* new_web_contents =
Istiaque Ahmed7105f2a2017-10-07 01:11:59832 AddTab(browser(), GURL(url::kAboutBlankURL));
833 EXPECT_TRUE(new_web_contents);
834 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
835}
836
837// Tests that events to service worker correctly after browser restart.
838// This test is similar to EventsToStoppedExtension, except that the event
839// delivery is verified after a browser restart.
840IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest,
841 PRE_EventsAfterRestart) {
842 LazyBackgroundObserver lazy_observer;
843 ResultCatcher catcher;
844 const Extension* extension = LoadExtensionWithFlags(
845 test_data_dir_.AppendASCII("service_worker/events_to_stopped_extension"),
846 kFlagNone);
847 ASSERT_TRUE(extension);
848 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
849
850 ProcessManager* pm = ProcessManager::Get(browser()->profile());
851 EXPECT_GT(pm->GetLazyKeepaliveCount(extension), 0);
852
853 // |extension|'s background page opens a tab to its resource.
854 content::WebContents* extension_web_contents =
855 browser()->tab_strip_model()->GetActiveWebContents();
856 EXPECT_TRUE(content::WaitForLoadStop(extension_web_contents));
857 EXPECT_EQ(extension->GetResourceURL("page.html").spec(),
858 extension_web_contents->GetURL().spec());
859 {
860 // Let the service worker start and register a listener to
861 // chrome.tabs.onCreated event.
862 ExtensionTestMessageListener add_listener_done("listener-added", false);
863 content::ExecuteScriptAsync(extension_web_contents,
864 "window.runServiceWorkerAsync()");
865 EXPECT_TRUE(add_listener_done.WaitUntilSatisfied());
866
867 base::RunLoop run_loop;
868 content::StoragePartition* storage_partition =
869 content::BrowserContext::GetDefaultStoragePartition(
870 browser()->profile());
871 content::StopServiceWorkerForPattern(
872 storage_partition->GetServiceWorkerContext(),
873 // The service worker is registered at the top level scope.
874 extension->url(), run_loop.QuitClosure());
875 run_loop.Run();
876 }
877
878 // Close the tab to |extension|'s resource. This will also close the
879 // extension's event page.
880 browser()->tab_strip_model()->CloseWebContentsAt(
881 browser()->tab_strip_model()->active_index(), TabStripModel::CLOSE_NONE);
882 lazy_observer.Wait();
883}
884
885IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest, EventsAfterRestart) {
886 ExtensionTestMessageListener newtab_listener("hello-newtab", false);
887 content::WebContents* new_web_contents =
888 AddTab(browser(), GURL(url::kAboutBlankURL));
Istiaque Ahmed805f6a83b2017-10-05 01:23:26889 EXPECT_TRUE(new_web_contents);
890 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
891}
892
lazyboy4c82177a2016-10-18 00:04:09893// Tests that worker ref count increments while extension API function is
894// active.
Istiaque Ahmedea5ed5042017-09-25 19:00:16895IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, WorkerRefCount) {
lazyboy4c82177a2016-10-18 00:04:09896 // Extensions APIs from SW are only enabled on trunk.
897 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
898 const Extension* extension = LoadExtensionWithFlags(
899 test_data_dir_.AppendASCII("service_worker/api_worker_ref_count"),
900 kFlagNone);
901 ASSERT_TRUE(extension);
902 ui_test_utils::NavigateToURL(browser(),
903 extension->GetResourceURL("page.html"));
904 content::WebContents* web_contents =
905 browser()->tab_strip_model()->GetActiveWebContents();
906
907 ExtensionTestMessageListener worker_start_listener("WORKER STARTED", false);
908 worker_start_listener.set_failure_message("FAILURE");
909 ASSERT_TRUE(
910 content::ExecuteScript(web_contents, "window.runServiceWorker()"));
911 ASSERT_TRUE(worker_start_listener.WaitUntilSatisfied());
912
913 // Service worker should have no pending requests because it hasn't peformed
914 // any extension API request yet.
915 EXPECT_EQ(0u, GetWorkerRefCount(extension->url()));
916
917 ExtensionTestMessageListener worker_listener("CHECK_REF_COUNT", true);
918 worker_listener.set_failure_message("FAILURE");
919 ASSERT_TRUE(content::ExecuteScript(web_contents, "window.testSendMessage()"));
920 ASSERT_TRUE(worker_listener.WaitUntilSatisfied());
921
922 // Service worker should have exactly one pending request because
923 // chrome.test.sendMessage() API call is in-flight.
924 EXPECT_EQ(1u, GetWorkerRefCount(extension->url()));
925
926 // Peform another extension API request while one is ongoing.
927 {
928 ExtensionTestMessageListener listener("CHECK_REF_COUNT", true);
929 listener.set_failure_message("FAILURE");
930 ASSERT_TRUE(
931 content::ExecuteScript(web_contents, "window.testSendMessage()"));
932 ASSERT_TRUE(listener.WaitUntilSatisfied());
933
934 // Service worker currently has two extension API requests in-flight.
935 EXPECT_EQ(2u, GetWorkerRefCount(extension->url()));
936 // Finish executing the nested chrome.test.sendMessage() first.
937 listener.Reply("Hello world");
938 }
939
Istiaque Ahmedb57c9752017-08-20 19:08:57940 ExtensionTestMessageListener worker_completion_listener("SUCCESS_FROM_WORKER",
941 false);
lazyboy4c82177a2016-10-18 00:04:09942 // Finish executing chrome.test.sendMessage().
943 worker_listener.Reply("Hello world");
Istiaque Ahmedb57c9752017-08-20 19:08:57944 EXPECT_TRUE(worker_completion_listener.WaitUntilSatisfied());
945
946 // The following block makes sure we have received all the IPCs related to
947 // ref-count from the worker.
948 {
949 // The following roundtrip:
950 // browser->extension->worker->extension->browser
951 // will ensure that the worker sent the relevant ref count IPCs.
952 std::string result;
953 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
954 web_contents, "window.roundtripToWorker();", &result));
955 EXPECT_EQ("roundtrip-succeeded", result);
956
957 // Ensure IO thread IPCs run.
Gabriel Charette01507a22017-09-27 21:30:08958 content::RunAllTasksUntilIdle();
Istiaque Ahmedb57c9752017-08-20 19:08:57959 }
lazyboy4c82177a2016-10-18 00:04:09960
961 // The ref count should drop to 0.
962 EXPECT_EQ(0u, GetWorkerRefCount(extension->url()));
963}
964
lazyboyaea32c22016-01-04 21:37:07965// This test loads a web page that has an iframe pointing to a
966// chrome-extension:// URL. The URL is listed in the extension's
967// web_accessible_resources. Initially the iframe is served from the extension's
968// resource file. After verifying that, we register a Service Worker that
969// controls the extension. Further requests to the same resource as before
970// should now be served by the Service Worker.
971// This test also verifies that if the requested resource exists in the manifest
972// but is not present in the extension directory, the Service Worker can still
973// serve the resource file.
Istiaque Ahmedea5ed5042017-09-25 19:00:16974IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, WebAccessibleResourcesIframeSrc) {
lazyboyaea32c22016-01-04 21:37:07975 const Extension* extension = LoadExtensionWithFlags(
976 test_data_dir_.AppendASCII(
977 "service_worker/web_accessible_resources/iframe_src"),
978 kFlagNone);
979 ASSERT_TRUE(extension);
980 ASSERT_TRUE(StartEmbeddedTestServer());
falkenad185092016-06-16 06:10:02981
982 // Service workers can only control secure contexts
983 // (https://w3c.github.io/webappsec-secure-contexts/). For documents, this
984 // typically means the document must have a secure origin AND all its ancestor
985 // frames must have documents with secure origins. However, extension pages
986 // are considered secure, even if they have an ancestor document that is an
987 // insecure context (see GetSchemesBypassingSecureContextCheckWhitelist). So
988 // extension service workers must be able to control an extension page
989 // embedded in an insecure context. To test this, set up an insecure
990 // (non-localhost, non-https) URL for the web page. This page will create
991 // iframes that load extension pages that must be controllable by service
992 // worker.
falkenad185092016-06-16 06:10:02993 GURL page_url =
994 embedded_test_server()->GetURL("a.com",
995 "/extensions/api_test/service_worker/"
996 "web_accessible_resources/webpage.html");
997 EXPECT_FALSE(content::IsOriginSecure(page_url));
lazyboyaea32c22016-01-04 21:37:07998
999 content::WebContents* web_contents = AddTab(browser(), page_url);
1000 std::string result;
1001 // webpage.html will create an iframe pointing to a resource from |extension|.
1002 // Expect the resource to be served by the extension.
1003 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1004 web_contents, base::StringPrintf("window.testIframe('%s', 'iframe.html')",
1005 extension->id().c_str()),
1006 &result));
1007 EXPECT_EQ("FROM_EXTENSION_RESOURCE", result);
1008
1009 ExtensionTestMessageListener service_worker_ready_listener("SW_READY", false);
1010 EXPECT_TRUE(ExecuteScriptInBackgroundPageNoWait(
1011 extension->id(), "window.registerServiceWorker()"));
1012 EXPECT_TRUE(service_worker_ready_listener.WaitUntilSatisfied());
1013
1014 result.clear();
1015 // webpage.html will create another iframe pointing to a resource from
1016 // |extension| as before. But this time, the resource should be be served
1017 // from the Service Worker.
1018 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1019 web_contents, base::StringPrintf("window.testIframe('%s', 'iframe.html')",
1020 extension->id().c_str()),
1021 &result));
1022 EXPECT_EQ("FROM_SW_RESOURCE", result);
1023
1024 result.clear();
1025 // webpage.html will create yet another iframe pointing to a resource that
1026 // exists in the extension manifest's web_accessible_resources, but is not
1027 // present in the extension directory. Expect the resources of the iframe to
1028 // be served by the Service Worker.
1029 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1030 web_contents,
1031 base::StringPrintf("window.testIframe('%s', 'iframe_non_existent.html')",
1032 extension->id().c_str()),
1033 &result));
1034 EXPECT_EQ("FROM_SW_RESOURCE", result);
1035}
1036
Istiaque Ahmedea5ed5042017-09-25 19:00:161037IN_PROC_BROWSER_TEST_P(ServiceWorkerBackgroundSyncTest, Sync) {
lazyboybd325ae2015-11-18 21:35:261038 const Extension* extension = LoadExtensionWithFlags(
1039 test_data_dir_.AppendASCII("service_worker/sync"), kFlagNone);
1040 ASSERT_TRUE(extension);
1041 ui_test_utils::NavigateToURL(browser(),
1042 extension->GetResourceURL("page.html"));
1043 content::WebContents* web_contents =
1044 browser()->tab_strip_model()->GetActiveWebContents();
1045
1046 // Prevent firing by going offline.
1047 content::background_sync_test_util::SetOnline(web_contents, false);
1048
1049 ExtensionTestMessageListener sync_listener("SYNC: send-chats", false);
1050 sync_listener.set_failure_message("FAIL");
1051
1052 std::string result;
1053 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
1054 web_contents, "window.runServiceWorker()", &result));
1055 ASSERT_EQ("SERVICE_WORKER_READY", result);
1056
1057 EXPECT_FALSE(sync_listener.was_satisfied());
1058 // Resume firing by going online.
1059 content::background_sync_test_util::SetOnline(web_contents, true);
1060 EXPECT_TRUE(sync_listener.WaitUntilSatisfied());
1061}
1062
Istiaque Ahmedea5ed5042017-09-25 19:00:161063IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
horo1eeddde2015-11-19 05:59:251064 FetchFromContentScriptShouldNotGoToServiceWorkerOfPage) {
1065 ASSERT_TRUE(StartEmbeddedTestServer());
1066 GURL page_url = embedded_test_server()->GetURL(
1067 "/extensions/api_test/service_worker/content_script_fetch/"
1068 "controlled_page/index.html");
1069 content::WebContents* tab =
1070 browser()->tab_strip_model()->GetActiveWebContents();
1071 ui_test_utils::NavigateToURL(browser(), page_url);
1072 content::WaitForLoadStop(tab);
1073
1074 std::string value;
1075 ASSERT_TRUE(
1076 content::ExecuteScriptAndExtractString(tab, "register();", &value));
1077 EXPECT_EQ("SW controlled", value);
1078
1079 ASSERT_TRUE(RunExtensionTest("service_worker/content_script_fetch"))
1080 << message_;
1081}
1082
Istiaque Ahmedea5ed5042017-09-25 19:00:161083IN_PROC_BROWSER_TEST_P(ServiceWorkerPushMessagingTest, OnPush) {
lazyboy561b7de2015-11-19 19:27:301084 const Extension* extension = LoadExtensionWithFlags(
1085 test_data_dir_.AppendASCII("service_worker/push_messaging"), kFlagNone);
1086 ASSERT_TRUE(extension);
1087 GURL extension_url = extension->url();
1088
1089 ASSERT_NO_FATAL_FAILURE(GrantNotificationPermissionForTest(extension_url));
1090
1091 GURL url = extension->GetResourceURL("page.html");
1092 ui_test_utils::NavigateToURL(browser(), url);
1093
1094 content::WebContents* web_contents =
1095 browser()->tab_strip_model()->GetActiveWebContents();
1096
1097 // Start the ServiceWorker.
1098 ExtensionTestMessageListener ready_listener("SERVICE_WORKER_READY", false);
1099 ready_listener.set_failure_message("SERVICE_WORKER_FAILURE");
1100 const char* kScript = "window.runServiceWorker()";
1101 EXPECT_TRUE(content::ExecuteScript(web_contents->GetMainFrame(), kScript));
1102 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
1103
1104 PushMessagingAppIdentifier app_identifier =
1105 GetAppIdentifierForServiceWorkerRegistration(0LL, extension_url);
johnmea5045732016-09-08 17:23:291106 ASSERT_EQ(app_identifier.app_id(), gcm_driver()->last_gettoken_app_id());
1107 EXPECT_EQ("1234567890", gcm_driver()->last_gettoken_authorized_entity());
lazyboy561b7de2015-11-19 19:27:301108
lazyboyd429e2582016-05-20 20:18:521109 base::RunLoop run_loop;
lazyboy561b7de2015-11-19 19:27:301110 // Send a push message via gcm and expect the ServiceWorker to receive it.
1111 ExtensionTestMessageListener push_message_listener("OK", false);
1112 push_message_listener.set_failure_message("FAIL");
1113 gcm::IncomingMessage message;
1114 message.sender_id = "1234567890";
1115 message.raw_data = "testdata";
1116 message.decrypted = true;
lazyboyd429e2582016-05-20 20:18:521117 push_service()->SetMessageCallbackForTesting(run_loop.QuitClosure());
lazyboy561b7de2015-11-19 19:27:301118 push_service()->OnMessage(app_identifier.app_id(), message);
1119 EXPECT_TRUE(push_message_listener.WaitUntilSatisfied());
lazyboyd429e2582016-05-20 20:18:521120 run_loop.Run(); // Wait until the message is handled by push service.
lazyboy561b7de2015-11-19 19:27:301121}
1122
Istiaque Ahmedea5ed5042017-09-25 19:00:161123IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, FilteredEvents) {
Istiaque Ahmed9d1666182017-09-21 23:58:181124 // Extensions APIs from SW are only enabled on trunk.
1125 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1126 ASSERT_TRUE(RunExtensionTest("service_worker/filtered_events"));
1127}
1128
Istiaque Ahmed9ce21b32017-10-10 20:43:181129IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest,
1130 PRE_FilteredEventsAfterRestart) {
1131 LazyBackgroundObserver lazy_observer;
1132 ResultCatcher catcher;
1133 const Extension* extension = LoadExtensionWithFlags(
1134 test_data_dir_.AppendASCII(
1135 "service_worker/filtered_events_after_restart"),
1136 kFlagNone);
1137 ASSERT_TRUE(extension);
1138 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
1139
1140 // |extension|'s background page opens a tab to its resource.
1141 content::WebContents* extension_web_contents =
1142 browser()->tab_strip_model()->GetActiveWebContents();
1143 EXPECT_TRUE(content::WaitForLoadStop(extension_web_contents));
1144 EXPECT_EQ(extension->GetResourceURL("page.html").spec(),
1145 extension_web_contents->GetURL().spec());
1146 {
1147 // Let the service worker start and register a filtered listener to
1148 // chrome.webNavigation.onCommitted event.
1149 ExtensionTestMessageListener add_listener_done("listener-added", false);
1150 add_listener_done.set_failure_message("FAILURE");
1151 content::ExecuteScriptAsync(extension_web_contents,
1152 "window.runServiceWorkerAsync()");
1153 EXPECT_TRUE(add_listener_done.WaitUntilSatisfied());
1154
1155 base::RunLoop run_loop;
1156 content::StoragePartition* storage_partition =
1157 content::BrowserContext::GetDefaultStoragePartition(
1158 browser()->profile());
1159 content::StopServiceWorkerForPattern(
1160 storage_partition->GetServiceWorkerContext(),
1161 // The service worker is registered at the top level scope.
1162 extension->url(), run_loop.QuitClosure());
1163 run_loop.Run();
1164 }
1165
1166 // Close the tab to |extension|'s resource. This will also close the
1167 // extension's event page.
1168 browser()->tab_strip_model()->CloseWebContentsAt(
1169 browser()->tab_strip_model()->active_index(), TabStripModel::CLOSE_NONE);
1170 lazy_observer.Wait();
1171}
1172
1173IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest,
1174 FilteredEventsAfterRestart) {
1175 // Create a tab to a.html, expect it to navigate to b.html. The service worker
1176 // will see two webNavigation.onCommitted events.
1177 ASSERT_TRUE(StartEmbeddedTestServer());
1178 GURL page_url = embedded_test_server()->GetURL(
1179 "/extensions/api_test/service_worker/filtered_events_after_restart/"
1180 "a.html");
1181 ExtensionTestMessageListener worker_filtered_event_listener(
1182 "PASS_FROM_WORKER", false);
1183 worker_filtered_event_listener.set_failure_message("FAIL_FROM_WORKER");
1184 content::WebContents* web_contents = AddTab(browser(), page_url);
1185 EXPECT_TRUE(web_contents);
1186 EXPECT_TRUE(worker_filtered_event_listener.WaitUntilSatisfied());
1187}
1188
Istiaque Ahmedea5ed5042017-09-25 19:00:161189// Run with both native and JS-based bindings. This ensures that both stable
1190// (JS) and experimental (native) phases work correctly with worker scripts
1191// while we launch native bindings to stable.
1192INSTANTIATE_TEST_CASE_P(ServiceWorkerTestWithNativeBindings,
1193 ServiceWorkerTest,
1194 ::testing::Values(NATIVE_BINDINGS));
1195INSTANTIATE_TEST_CASE_P(ServiceWorkerTestWithJSBindings,
1196 ServiceWorkerTest,
1197 ::testing::Values(JAVASCRIPT_BINDINGS));
1198INSTANTIATE_TEST_CASE_P(ServiceWorkerBackgroundSyncTestWithNativeBindings,
1199 ServiceWorkerBackgroundSyncTest,
1200 ::testing::Values(NATIVE_BINDINGS));
1201INSTANTIATE_TEST_CASE_P(ServiceWorkerBackgroundSyncTestWithJSBindings,
1202 ServiceWorkerBackgroundSyncTest,
1203 ::testing::Values(JAVASCRIPT_BINDINGS));
1204INSTANTIATE_TEST_CASE_P(ServiceWorkerPushMessagingTestWithNativeBindings,
1205 ServiceWorkerPushMessagingTest,
1206 ::testing::Values(NATIVE_BINDINGS));
1207INSTANTIATE_TEST_CASE_P(ServiceWorkerPushMessagingTestWithJSBindings,
1208 ServiceWorkerPushMessagingTest,
1209 ::testing::Values(JAVASCRIPT_BINDINGS));
Istiaque Ahmed805f6a83b2017-10-05 01:23:261210INSTANTIATE_TEST_CASE_P(ServiceWorkerLazyBackgroundTestWithNativeBindings,
1211 ServiceWorkerLazyBackgroundTest,
1212 ::testing::Values(NATIVE_BINDINGS));
1213INSTANTIATE_TEST_CASE_P(ServiceWorkerLazyBackgroundTestWithJSBindings,
1214 ServiceWorkerLazyBackgroundTest,
1215 ::testing::Values(JAVASCRIPT_BINDINGS));
Istiaque Ahmedea5ed5042017-09-25 19:00:161216
annekao38685502015-07-14 17:46:391217} // namespace extensions