blob: c86cd5e58edbda8c95cd1fc09fb51117d3b02a16 [file] [log] [blame]
annekao38685502015-07-14 17:46:391// Copyright 2015 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
avia2f4804a2015-12-24 23:11:135#include <stdint.h>
6
kalman6f984ae2015-09-18 17:21:587#include "base/bind_helpers.h"
avia2f4804a2015-12-24 23:11:138#include "base/macros.h"
Gabriel Charette078e3662017-08-28 22:59:049#include "base/run_loop.h"
kalman6f984ae2015-09-18 17:21:5810#include "base/strings/stringprintf.h"
horo1eeddde2015-11-19 05:59:2511#include "base/strings/utf_string_conversions.h"
jam3f2d3932017-04-26 20:28:5112#include "base/threading/thread_restrictions.h"
annekao38685502015-07-14 17:46:3913#include "chrome/browser/extensions/extension_apitest.h"
rdevlin.croninf5863da2015-09-10 19:21:4514#include "chrome/browser/extensions/extension_service.h"
Istiaque Ahmed805f6a83b2017-10-05 01:23:2615#include "chrome/browser/extensions/lazy_background_page_test_util.h"
peter9f4490a2017-01-27 00:58:3616#include "chrome/browser/gcm/fake_gcm_profile_service.h"
17#include "chrome/browser/gcm/gcm_profile_service_factory.h"
lazyboy561b7de2015-11-19 19:27:3018#include "chrome/browser/notifications/desktop_notification_profile_util.h"
miguelg9b502862017-04-24 18:13:5319#include "chrome/browser/notifications/notification_display_service_factory.h"
20#include "chrome/browser/notifications/stub_notification_display_service.h"
lshang106c1772016-06-06 01:43:2321#include "chrome/browser/permissions/permission_manager.h"
timlohc6911802017-03-01 05:37:0322#include "chrome/browser/permissions/permission_result.h"
lazyboy561b7de2015-11-19 19:27:3023#include "chrome/browser/push_messaging/push_messaging_app_identifier.h"
24#include "chrome/browser/push_messaging/push_messaging_service_factory.h"
25#include "chrome/browser/push_messaging/push_messaging_service_impl.h"
annekao1db36fd2015-07-29 17:09:1626#include "chrome/browser/ui/tabs/tab_strip_model.h"
Istiaque Ahmed805f6a83b2017-10-05 01:23:2627#include "chrome/common/chrome_switches.cc"
rdevlin.croninf5863da2015-09-10 19:21:4528#include "chrome/test/base/ui_test_utils.h"
timloh9a180ad2017-02-20 07:15:2329#include "components/content_settings/core/common/content_settings_types.h"
johnmea5045732016-09-08 17:23:2930#include "components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h"
sdefresne9fb67692015-08-03 18:48:2231#include "components/version_info/version_info.h"
kalman6f984ae2015-09-18 17:21:5832#include "content/public/browser/navigation_controller.h"
rdevlin.croninf5863da2015-09-10 19:21:4533#include "content/public/browser/navigation_entry.h"
lazyboy4c82177a2016-10-18 00:04:0934#include "content/public/browser/service_worker_context.h"
35#include "content/public/browser/storage_partition.h"
kalman6f984ae2015-09-18 17:21:5836#include "content/public/browser/web_contents.h"
lazyboybd325ae2015-11-18 21:35:2637#include "content/public/common/content_switches.h"
falkenad185092016-06-16 06:10:0238#include "content/public/common/origin_util.h"
kalman6f984ae2015-09-18 17:21:5839#include "content/public/common/page_type.h"
lazyboybd325ae2015-11-18 21:35:2640#include "content/public/test/background_sync_test_util.h"
annekao1db36fd2015-07-29 17:09:1641#include "content/public/test/browser_test_utils.h"
lazyboy63b994a2017-06-30 21:20:2342#include "content/public/test/service_worker_test_helpers.h"
kalman6f984ae2015-09-18 17:21:5843#include "extensions/browser/extension_host.h"
lazyboyc3e763a2015-12-09 23:09:5844#include "extensions/browser/extension_registry.h"
kalman6f984ae2015-09-18 17:21:5845#include "extensions/browser/process_manager.h"
Istiaque Ahmedea5ed5042017-09-25 19:00:1646#include "extensions/common/switches.h"
kalman6f984ae2015-09-18 17:21:5847#include "extensions/test/background_page_watcher.h"
annekao38685502015-07-14 17:46:3948#include "extensions/test/extension_test_message_listener.h"
Istiaque Ahmed805f6a83b2017-10-05 01:23:2649#include "extensions/test/result_catcher.h"
falkenad185092016-06-16 06:10:0250#include "net/dns/mock_host_resolver.h"
horo1eeddde2015-11-19 05:59:2551#include "net/test/embedded_test_server/embedded_test_server.h"
lazyboy63b994a2017-06-30 21:20:2352#include "url/url_constants.h"
annekao38685502015-07-14 17:46:3953
54namespace extensions {
55
kalman6f984ae2015-09-18 17:21:5856namespace {
57
58// Pass into ServiceWorkerTest::StartTestFromBackgroundPage to indicate that
59// registration is expected to succeed.
60std::string* const kExpectSuccess = nullptr;
61
62void DoNothingWithBool(bool b) {}
63
lazyboy22eddc712015-12-10 21:16:2664// Returns the newly added WebContents.
65content::WebContents* AddTab(Browser* browser, const GURL& url) {
66 int starting_tab_count = browser->tab_strip_model()->count();
67 ui_test_utils::NavigateToURLWithDisposition(
nick3b04f322016-08-31 19:29:1968 browser, url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
lazyboy22eddc712015-12-10 21:16:2669 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
70 int tab_count = browser->tab_strip_model()->count();
71 EXPECT_EQ(starting_tab_count + 1, tab_count);
72 return browser->tab_strip_model()->GetActiveWebContents();
73}
74
Istiaque Ahmedea5ed5042017-09-25 19:00:1675enum BindingsType { NATIVE_BINDINGS, JAVASCRIPT_BINDINGS };
76
lazyboy22eddc712015-12-10 21:16:2677class WebContentsLoadStopObserver : content::WebContentsObserver {
78 public:
79 explicit WebContentsLoadStopObserver(content::WebContents* web_contents)
80 : content::WebContentsObserver(web_contents),
81 load_stop_observed_(false) {}
82
83 void WaitForLoadStop() {
84 if (load_stop_observed_)
85 return;
86 message_loop_runner_ = new content::MessageLoopRunner;
87 message_loop_runner_->Run();
88 }
89
90 private:
91 void DidStopLoading() override {
92 load_stop_observed_ = true;
93 if (message_loop_runner_)
94 message_loop_runner_->Quit();
95 }
96
97 bool load_stop_observed_;
98 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
99
100 DISALLOW_COPY_AND_ASSIGN(WebContentsLoadStopObserver);
101};
102
kalman6f984ae2015-09-18 17:21:58103} // namespace
104
Istiaque Ahmedea5ed5042017-09-25 19:00:16105class ServiceWorkerTest : public ExtensionApiTest,
106 public ::testing::WithParamInterface<BindingsType> {
annekao38685502015-07-14 17:46:39107 public:
lazyboy20167c22016-05-18 00:59:30108 ServiceWorkerTest() : current_channel_(version_info::Channel::STABLE) {}
annekao38685502015-07-14 17:46:39109
110 ~ServiceWorkerTest() override {}
111
jam1a5b5582017-05-01 16:50:10112 void SetUpOnMainThread() override {
113 ExtensionApiTest::SetUpOnMainThread();
114 host_resolver()->AddRule("a.com", "127.0.0.1");
115 }
116
Istiaque Ahmedea5ed5042017-09-25 19:00:16117 void SetUpCommandLine(base::CommandLine* command_line) override {
118 ExtensionApiTest::SetUpCommandLine(command_line);
119 command_line->AppendSwitchASCII(switches::kNativeCrxBindings,
120 GetParam() == NATIVE_BINDINGS ? "1" : "0");
121 }
122
kalman6f984ae2015-09-18 17:21:58123 protected:
124 // Returns the ProcessManager for the test's profile.
125 ProcessManager* process_manager() { return ProcessManager::Get(profile()); }
126
127 // Starts running a test from the background page test extension.
128 //
129 // This registers a service worker with |script_name|, and fetches the
130 // registration result.
131 //
132 // If |error_or_null| is null (kExpectSuccess), success is expected and this
133 // will fail if there is an error.
134 // If |error_or_null| is not null, nothing is assumed, and the error (which
135 // may be empty) is written to it.
136 const Extension* StartTestFromBackgroundPage(const char* script_name,
137 std::string* error_or_null) {
138 const Extension* extension =
139 LoadExtension(test_data_dir_.AppendASCII("service_worker/background"));
140 CHECK(extension);
141 ExtensionHost* background_host =
142 process_manager()->GetBackgroundHostForExtension(extension->id());
143 CHECK(background_host);
144 std::string error;
145 CHECK(content::ExecuteScriptAndExtractString(
146 background_host->host_contents(),
147 base::StringPrintf("test.registerServiceWorker('%s')", script_name),
148 &error));
149 if (error_or_null)
150 *error_or_null = error;
151 else if (!error.empty())
152 ADD_FAILURE() << "Got unexpected error " << error;
153 return extension;
154 }
155
156 // Navigates the browser to a new tab at |url|, waits for it to load, then
157 // returns it.
158 content::WebContents* Navigate(const GURL& url) {
159 ui_test_utils::NavigateToURLWithDisposition(
nick3b04f322016-08-31 19:29:19160 browser(), url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
kalman6f984ae2015-09-18 17:21:58161 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
162 content::WebContents* web_contents =
163 browser()->tab_strip_model()->GetActiveWebContents();
164 content::WaitForLoadStop(web_contents);
165 return web_contents;
166 }
167
168 // Navigates the browser to |url| and returns the new tab's page type.
169 content::PageType NavigateAndGetPageType(const GURL& url) {
170 return Navigate(url)->GetController().GetActiveEntry()->GetPageType();
171 }
172
173 // Extracts the innerText from |contents|.
174 std::string ExtractInnerText(content::WebContents* contents) {
175 std::string inner_text;
176 if (!content::ExecuteScriptAndExtractString(
177 contents,
178 "window.domAutomationController.send(document.body.innerText)",
179 &inner_text)) {
180 ADD_FAILURE() << "Failed to get inner text for "
181 << contents->GetVisibleURL();
182 }
183 return inner_text;
184 }
185
186 // Navigates the browser to |url|, then returns the innerText of the new
187 // tab's WebContents' main frame.
188 std::string NavigateAndExtractInnerText(const GURL& url) {
189 return ExtractInnerText(Navigate(url));
190 }
191
lazyboy4c82177a2016-10-18 00:04:09192 size_t GetWorkerRefCount(const GURL& origin) {
193 content::ServiceWorkerContext* sw_context =
194 content::BrowserContext::GetDefaultStoragePartition(
195 browser()->profile())
196 ->GetServiceWorkerContext();
197 base::RunLoop run_loop;
198 size_t ref_count = 0;
199 auto set_ref_count = [](size_t* ref_count, base::RunLoop* run_loop,
200 size_t external_request_count) {
201 *ref_count = external_request_count;
202 run_loop->Quit();
203 };
204 sw_context->CountExternalRequestsForTest(
Matt Falkenhagenc5cb4282017-09-07 08:43:42205 origin, base::BindOnce(set_ref_count, &ref_count, &run_loop));
lazyboy4c82177a2016-10-18 00:04:09206 run_loop.Run();
207 return ref_count;
208 }
209
annekao38685502015-07-14 17:46:39210 private:
lazyboy20167c22016-05-18 00:59:30211 // Sets the channel to "stable".
212 // Not useful after we've opened extension Service Workers to stable
213 // channel.
214 // TODO(lazyboy): Remove this when ExtensionServiceWorkersEnabled() is
215 // removed.
annekao38685502015-07-14 17:46:39216 ScopedCurrentChannel current_channel_;
kalman6f984ae2015-09-18 17:21:58217
annekao38685502015-07-14 17:46:39218 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerTest);
219};
220
lazyboybd325ae2015-11-18 21:35:26221class ServiceWorkerBackgroundSyncTest : public ServiceWorkerTest {
222 public:
223 ServiceWorkerBackgroundSyncTest() {}
224 ~ServiceWorkerBackgroundSyncTest() override {}
225
226 void SetUpCommandLine(base::CommandLine* command_line) override {
227 // ServiceWorkerRegistration.sync requires experimental flag.
228 command_line->AppendSwitch(
Istiaque Ahmedea5ed5042017-09-25 19:00:16229 ::switches::kEnableExperimentalWebPlatformFeatures);
lazyboybd325ae2015-11-18 21:35:26230 ServiceWorkerTest::SetUpCommandLine(command_line);
231 }
232
233 void SetUp() override {
234 content::background_sync_test_util::SetIgnoreNetworkChangeNotifier(true);
235 ServiceWorkerTest::SetUp();
236 }
237
238 private:
239 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerBackgroundSyncTest);
240};
241
lazyboy561b7de2015-11-19 19:27:30242class ServiceWorkerPushMessagingTest : public ServiceWorkerTest {
243 public:
244 ServiceWorkerPushMessagingTest()
johnmea5045732016-09-08 17:23:29245 : gcm_driver_(nullptr), push_service_(nullptr) {}
lazyboy561b7de2015-11-19 19:27:30246 ~ServiceWorkerPushMessagingTest() override {}
247
248 void GrantNotificationPermissionForTest(const GURL& url) {
249 GURL origin = url.GetOrigin();
250 DesktopNotificationProfileUtil::GrantPermission(profile(), origin);
timlohc6911802017-03-01 05:37:03251 ASSERT_EQ(CONTENT_SETTING_ALLOW,
252 PermissionManager::Get(profile())
253 ->GetPermissionStatus(CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
254 origin, origin)
255 .content_setting);
lazyboy561b7de2015-11-19 19:27:30256 }
257
258 PushMessagingAppIdentifier GetAppIdentifierForServiceWorkerRegistration(
avia2f4804a2015-12-24 23:11:13259 int64_t service_worker_registration_id,
lazyboy561b7de2015-11-19 19:27:30260 const GURL& origin) {
261 PushMessagingAppIdentifier app_identifier =
262 PushMessagingAppIdentifier::FindByServiceWorker(
263 profile(), origin, service_worker_registration_id);
264
265 EXPECT_FALSE(app_identifier.is_null());
266 return app_identifier;
267 }
268
269 // ExtensionApiTest overrides.
270 void SetUpCommandLine(base::CommandLine* command_line) override {
peter9de96272015-12-04 15:23:27271 command_line->AppendSwitch(
Istiaque Ahmedea5ed5042017-09-25 19:00:16272 ::switches::kEnableExperimentalWebPlatformFeatures);
lazyboy561b7de2015-11-19 19:27:30273 ServiceWorkerTest::SetUpCommandLine(command_line);
274 }
275 void SetUpOnMainThread() override {
miguelg9b502862017-04-24 18:13:53276 NotificationDisplayServiceFactory::GetInstance()->SetTestingFactory(
277 profile(), &StubNotificationDisplayService::FactoryForTests);
278
johnmea5045732016-09-08 17:23:29279 gcm::FakeGCMProfileService* gcm_service =
280 static_cast<gcm::FakeGCMProfileService*>(
281 gcm::GCMProfileServiceFactory::GetInstance()
282 ->SetTestingFactoryAndUse(profile(),
283 &gcm::FakeGCMProfileService::Build));
284 gcm_driver_ = static_cast<instance_id::FakeGCMDriverForInstanceID*>(
285 gcm_service->driver());
lazyboy561b7de2015-11-19 19:27:30286 push_service_ = PushMessagingServiceFactory::GetForProfile(profile());
287
288 ServiceWorkerTest::SetUpOnMainThread();
289 }
290
johnmea5045732016-09-08 17:23:29291 instance_id::FakeGCMDriverForInstanceID* gcm_driver() const {
292 return gcm_driver_;
293 }
lazyboy561b7de2015-11-19 19:27:30294 PushMessagingServiceImpl* push_service() const { return push_service_; }
295
296 private:
johnmea5045732016-09-08 17:23:29297 instance_id::FakeGCMDriverForInstanceID* gcm_driver_;
lazyboy561b7de2015-11-19 19:27:30298 PushMessagingServiceImpl* push_service_;
299
300 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerPushMessagingTest);
301};
302
Istiaque Ahmed805f6a83b2017-10-05 01:23:26303class ServiceWorkerLazyBackgroundTest : public ServiceWorkerTest {
304 public:
305 ServiceWorkerLazyBackgroundTest() {}
306 ~ServiceWorkerLazyBackgroundTest() override {}
307
308 void SetUpCommandLine(base::CommandLine* command_line) override {
309 ServiceWorkerTest::SetUpCommandLine(command_line);
310 // Disable background network activity as it can suddenly bring the Lazy
311 // Background Page alive.
312 command_line->AppendSwitch(::switches::kDisableBackgroundNetworking);
313 command_line->AppendSwitch(::switches::kNoProxyServer);
314 }
315
316 void SetUpInProcessBrowserTestFixture() override {
317 ServiceWorkerTest::SetUpInProcessBrowserTestFixture();
318 // Set shorter delays to prevent test timeouts.
319 ProcessManager::SetEventPageIdleTimeForTesting(1);
320 ProcessManager::SetEventPageSuspendingTimeForTesting(1);
321 }
322
323 private:
324 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerLazyBackgroundTest);
325};
326
Istiaque Ahmedea5ed5042017-09-25 19:00:16327IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, RegisterSucceeds) {
kalman6f984ae2015-09-18 17:21:58328 StartTestFromBackgroundPage("register.js", kExpectSuccess);
annekao38685502015-07-14 17:46:39329}
330
Istiaque Ahmedea5ed5042017-09-25 19:00:16331IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, UpdateRefreshesServiceWorker) {
jam3f2d3932017-04-26 20:28:51332 base::ThreadRestrictions::ScopedAllowIO allow_io;
lazyboyc3e763a2015-12-09 23:09:58333 base::ScopedTempDir scoped_temp_dir;
334 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
335 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
336 .AppendASCII("update")
337 .AppendASCII("service_worker.pem");
vabr9142fe22016-09-08 13:19:22338 base::FilePath path_v1 =
339 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
340 .AppendASCII("update")
341 .AppendASCII("v1"),
342 scoped_temp_dir.GetPath().AppendASCII("v1.crx"),
343 pem_path, base::FilePath());
344 base::FilePath path_v2 =
345 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
346 .AppendASCII("update")
347 .AppendASCII("v2"),
348 scoped_temp_dir.GetPath().AppendASCII("v2.crx"),
349 pem_path, base::FilePath());
lazyboyc3e763a2015-12-09 23:09:58350 const char* kId = "hfaanndiiilofhfokeanhddpkfffchdi";
351
352 ExtensionTestMessageListener listener_v1("Pong from version 1", false);
353 listener_v1.set_failure_message("FAILURE_V1");
354 // Install version 1.0 of the extension.
355 ASSERT_TRUE(InstallExtension(path_v1, 1));
356 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
357 ->enabled_extensions()
358 .GetByID(kId));
359 EXPECT_TRUE(listener_v1.WaitUntilSatisfied());
360
361 ExtensionTestMessageListener listener_v2("Pong from version 2", false);
362 listener_v2.set_failure_message("FAILURE_V2");
363
364 // Update to version 2.0.
365 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
366 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
367 ->enabled_extensions()
368 .GetByID(kId));
369 EXPECT_TRUE(listener_v2.WaitUntilSatisfied());
370}
371
[email protected]2ef85d562017-09-15 18:41:52372// TODO(crbug.com/765736) Fix the test.
Istiaque Ahmedea5ed5042017-09-25 19:00:16373IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, DISABLED_UpdateWithoutSkipWaiting) {
jam3f2d3932017-04-26 20:28:51374 base::ThreadRestrictions::ScopedAllowIO allow_io;
lazyboy22eddc712015-12-10 21:16:26375 base::ScopedTempDir scoped_temp_dir;
376 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
377 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
378 .AppendASCII("update_without_skip_waiting")
379 .AppendASCII("update_without_skip_waiting.pem");
vabr9142fe22016-09-08 13:19:22380 base::FilePath path_v1 =
381 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
382 .AppendASCII("update_without_skip_waiting")
383 .AppendASCII("v1"),
384 scoped_temp_dir.GetPath().AppendASCII("v1.crx"),
385 pem_path, base::FilePath());
386 base::FilePath path_v2 =
387 PackExtensionWithOptions(test_data_dir_.AppendASCII("service_worker")
388 .AppendASCII("update_without_skip_waiting")
389 .AppendASCII("v2"),
390 scoped_temp_dir.GetPath().AppendASCII("v2.crx"),
391 pem_path, base::FilePath());
lazyboy22eddc712015-12-10 21:16:26392 const char* kId = "mhnnnflgagdakldgjpfcofkiocpdmogl";
393
394 // Install version 1.0 of the extension.
395 ASSERT_TRUE(InstallExtension(path_v1, 1));
396 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
397 ->enabled_extensions()
398 .GetByID(kId));
399 const Extension* extension = extensions::ExtensionRegistry::Get(profile())
400 ->enabled_extensions()
401 .GetByID(kId);
402
403 ExtensionTestMessageListener listener1("Pong from version 1", false);
404 listener1.set_failure_message("FAILURE");
405 content::WebContents* web_contents =
406 AddTab(browser(), extension->GetResourceURL("page.html"));
407 EXPECT_TRUE(listener1.WaitUntilSatisfied());
408
409 // Update to version 2.0.
410 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
411 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
412 ->enabled_extensions()
413 .GetByID(kId));
414 const Extension* extension_after_update =
415 extensions::ExtensionRegistry::Get(profile())
416 ->enabled_extensions()
417 .GetByID(kId);
418
419 // Service worker version 2 would be installed but it won't be controlling
420 // the extension page yet.
421 ExtensionTestMessageListener listener2("Pong from version 1", false);
422 listener2.set_failure_message("FAILURE");
423 web_contents =
424 AddTab(browser(), extension_after_update->GetResourceURL("page.html"));
425 EXPECT_TRUE(listener2.WaitUntilSatisfied());
426
427 // Navigate the tab away from the extension page so that no clients are
428 // using the service worker.
429 // Note that just closing the tab with WebContentsDestroyedWatcher doesn't
430 // seem to be enough because it returns too early.
431 WebContentsLoadStopObserver navigate_away_observer(web_contents);
432 web_contents->GetController().LoadURL(
433 GURL(url::kAboutBlankURL), content::Referrer(), ui::PAGE_TRANSITION_TYPED,
434 std::string());
435 navigate_away_observer.WaitForLoadStop();
436
437 // Now expect service worker version 2 to control the extension page.
438 ExtensionTestMessageListener listener3("Pong from version 2", false);
439 listener3.set_failure_message("FAILURE");
440 web_contents =
441 AddTab(browser(), extension_after_update->GetResourceURL("page.html"));
442 EXPECT_TRUE(listener3.WaitUntilSatisfied());
443}
444
Istiaque Ahmedea5ed5042017-09-25 19:00:16445IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, FetchArbitraryPaths) {
kalman6f984ae2015-09-18 17:21:58446 const Extension* extension =
447 StartTestFromBackgroundPage("fetch.js", kExpectSuccess);
annekao1db36fd2015-07-29 17:09:16448
kalman6f984ae2015-09-18 17:21:58449 // Open some arbirary paths. Their contents should be what the service worker
450 // responds with, which in this case is the path of the fetch.
451 EXPECT_EQ(
452 "Caught a fetch for /index.html",
453 NavigateAndExtractInnerText(extension->GetResourceURL("index.html")));
454 EXPECT_EQ("Caught a fetch for /path/to/other.html",
455 NavigateAndExtractInnerText(
456 extension->GetResourceURL("path/to/other.html")));
457 EXPECT_EQ("Caught a fetch for /some/text/file.txt",
458 NavigateAndExtractInnerText(
459 extension->GetResourceURL("some/text/file.txt")));
460 EXPECT_EQ("Caught a fetch for /no/file/extension",
461 NavigateAndExtractInnerText(
462 extension->GetResourceURL("no/file/extension")));
463 EXPECT_EQ("Caught a fetch for /",
464 NavigateAndExtractInnerText(extension->GetResourceURL("")));
annekao1db36fd2015-07-29 17:09:16465}
466
Istiaque Ahmedea5ed5042017-09-25 19:00:16467IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, SWServedBackgroundPageReceivesEvent) {
lazyboy52c3bcf2016-01-08 00:11:29468 const Extension* extension =
469 StartTestFromBackgroundPage("replace_background.js", kExpectSuccess);
470 ExtensionHost* background_page =
471 process_manager()->GetBackgroundHostForExtension(extension->id());
472 ASSERT_TRUE(background_page);
473
474 // Close the background page and start it again so that the service worker
475 // will start controlling pages.
476 background_page->Close();
477 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
478 background_page = nullptr;
479 process_manager()->WakeEventPage(extension->id(),
480 base::Bind(&DoNothingWithBool));
481 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
482
483 // Since the SW is now controlling the extension, the SW serves the background
484 // script. page.html sends a message to the background script and we verify
485 // that the SW served background script correctly receives the message/event.
486 ExtensionTestMessageListener listener("onMessage/SW BG.", false);
487 listener.set_failure_message("onMessage/original BG.");
488 content::WebContents* web_contents =
489 AddTab(browser(), extension->GetResourceURL("page.html"));
490 ASSERT_TRUE(web_contents);
491 EXPECT_TRUE(listener.WaitUntilSatisfied());
492}
493
Istiaque Ahmedea5ed5042017-09-25 19:00:16494IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:58495 LoadingBackgroundPageBypassesServiceWorker) {
496 const Extension* extension =
497 StartTestFromBackgroundPage("fetch.js", kExpectSuccess);
annekao49241182015-08-18 17:14:01498
kalman6f984ae2015-09-18 17:21:58499 std::string kExpectedInnerText = "background.html contents for testing.";
annekao49241182015-08-18 17:14:01500
kalman6f984ae2015-09-18 17:21:58501 // Sanity check that the background page has the expected content.
502 ExtensionHost* background_page =
503 process_manager()->GetBackgroundHostForExtension(extension->id());
504 ASSERT_TRUE(background_page);
505 EXPECT_EQ(kExpectedInnerText,
506 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:01507
kalman6f984ae2015-09-18 17:21:58508 // Close the background page.
509 background_page->Close();
510 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
511 background_page = nullptr;
512
513 // Start it again.
514 process_manager()->WakeEventPage(extension->id(),
515 base::Bind(&DoNothingWithBool));
516 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
517
518 // Content should not have been affected by the fetch, which would otherwise
519 // be "Caught fetch for...".
520 background_page =
521 process_manager()->GetBackgroundHostForExtension(extension->id());
522 ASSERT_TRUE(background_page);
523 content::WaitForLoadStop(background_page->host_contents());
524
525 // TODO(kalman): Everything you've read has been a LIE! It should be:
526 //
527 // EXPECT_EQ(kExpectedInnerText,
528 // ExtractInnerText(background_page->host_contents()));
529 //
530 // but there is a bug, and we're actually *not* bypassing the service worker
531 // for background page loads! For now, let it pass (assert wrong behavior)
532 // because it's not a regression, but this must be fixed eventually.
533 //
534 // Tracked in crbug.com/532720.
535 EXPECT_EQ("Caught a fetch for /background.html",
536 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:01537}
538
Istiaque Ahmedea5ed5042017-09-25 19:00:16539IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:58540 ServiceWorkerPostsMessageToBackgroundClient) {
541 const Extension* extension = StartTestFromBackgroundPage(
542 "post_message_to_background_client.js", kExpectSuccess);
annekao533482222015-08-21 23:23:53543
kalman6f984ae2015-09-18 17:21:58544 // The service worker in this test simply posts a message to the background
545 // client it receives from getBackgroundClient().
546 const char* kScript =
547 "var messagePromise = null;\n"
548 "if (test.lastMessageFromServiceWorker) {\n"
549 " messagePromise = Promise.resolve(test.lastMessageFromServiceWorker);\n"
550 "} else {\n"
551 " messagePromise = test.waitForMessage(navigator.serviceWorker);\n"
552 "}\n"
553 "messagePromise.then(function(message) {\n"
554 " window.domAutomationController.send(String(message == 'success'));\n"
555 "})\n";
556 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:53557}
558
Istiaque Ahmedea5ed5042017-09-25 19:00:16559IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:58560 BackgroundPagePostsMessageToServiceWorker) {
561 const Extension* extension =
562 StartTestFromBackgroundPage("post_message_to_sw.js", kExpectSuccess);
annekao533482222015-08-21 23:23:53563
kalman6f984ae2015-09-18 17:21:58564 // The service worker in this test waits for a message, then echoes it back
565 // by posting a message to the background page via getBackgroundClient().
566 const char* kScript =
567 "var mc = new MessageChannel();\n"
568 "test.waitForMessage(mc.port1).then(function(message) {\n"
569 " window.domAutomationController.send(String(message == 'hello'));\n"
570 "});\n"
571 "test.registeredServiceWorker.postMessage(\n"
572 " {message: 'hello', port: mc.port2}, [mc.port2])\n";
573 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:53574}
575
Istiaque Ahmedea5ed5042017-09-25 19:00:16576IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
rdevlin.croninf5863da2015-09-10 19:21:45577 ServiceWorkerSuspensionOnExtensionUnload) {
kalman6f984ae2015-09-18 17:21:58578 // For this test, only hold onto the extension's ID and URL + a function to
579 // get a resource URL, because we're going to be disabling and uninstalling
580 // it, which will invalidate the pointer.
581 std::string extension_id;
582 GURL extension_url;
583 {
584 const Extension* extension =
585 StartTestFromBackgroundPage("fetch.js", kExpectSuccess);
586 extension_id = extension->id();
587 extension_url = extension->url();
588 }
589 auto get_resource_url = [&extension_url](const std::string& path) {
590 return Extension::GetResourceURL(extension_url, path);
591 };
rdevlin.croninf5863da2015-09-10 19:21:45592
kalman6f984ae2015-09-18 17:21:58593 // Fetch should route to the service worker.
594 EXPECT_EQ("Caught a fetch for /index.html",
595 NavigateAndExtractInnerText(get_resource_url("index.html")));
rdevlin.croninf5863da2015-09-10 19:21:45596
kalman6f984ae2015-09-18 17:21:58597 // Disable the extension. Opening the page should fail.
598 extension_service()->DisableExtension(extension_id,
Minh X. Nguyen45479012017-08-18 21:35:36599 disable_reason::DISABLE_USER_ACTION);
rdevlin.croninf5863da2015-09-10 19:21:45600 base::RunLoop().RunUntilIdle();
rdevlin.croninf5863da2015-09-10 19:21:45601
kalman6f984ae2015-09-18 17:21:58602 EXPECT_EQ(content::PAGE_TYPE_ERROR,
603 NavigateAndGetPageType(get_resource_url("index.html")));
604 EXPECT_EQ(content::PAGE_TYPE_ERROR,
605 NavigateAndGetPageType(get_resource_url("other.html")));
606
607 // Re-enable the extension. Opening pages should immediately start to succeed
608 // again.
rdevlin.croninf5863da2015-09-10 19:21:45609 extension_service()->EnableExtension(extension_id);
610 base::RunLoop().RunUntilIdle();
611
kalman6f984ae2015-09-18 17:21:58612 EXPECT_EQ("Caught a fetch for /index.html",
613 NavigateAndExtractInnerText(get_resource_url("index.html")));
614 EXPECT_EQ("Caught a fetch for /other.html",
615 NavigateAndExtractInnerText(get_resource_url("other.html")));
616 EXPECT_EQ("Caught a fetch for /another.html",
617 NavigateAndExtractInnerText(get_resource_url("another.html")));
rdevlin.croninf5863da2015-09-10 19:21:45618
kalman6f984ae2015-09-18 17:21:58619 // Uninstall the extension. Opening pages should fail again.
620 base::string16 error;
621 extension_service()->UninstallExtension(
622 extension_id, UninstallReason::UNINSTALL_REASON_FOR_TESTING,
623 base::Bind(&base::DoNothing), &error);
624 base::RunLoop().RunUntilIdle();
625
626 EXPECT_EQ(content::PAGE_TYPE_ERROR,
627 NavigateAndGetPageType(get_resource_url("index.html")));
628 EXPECT_EQ(content::PAGE_TYPE_ERROR,
629 NavigateAndGetPageType(get_resource_url("other.html")));
630 EXPECT_EQ(content::PAGE_TYPE_ERROR,
631 NavigateAndGetPageType(get_resource_url("anotherother.html")));
632 EXPECT_EQ(content::PAGE_TYPE_ERROR,
633 NavigateAndGetPageType(get_resource_url("final.html")));
634}
635
Istiaque Ahmedea5ed5042017-09-25 19:00:16636IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, BackgroundPageIsWokenIfAsleep) {
kalman6f984ae2015-09-18 17:21:58637 const Extension* extension =
638 StartTestFromBackgroundPage("wake_on_fetch.js", kExpectSuccess);
639
640 // Navigate to special URLs that this test's service worker recognises, each
641 // making a check then populating the response with either "true" or "false".
642 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
643 "background-client-is-awake")));
644 EXPECT_EQ("true", NavigateAndExtractInnerText(
645 extension->GetResourceURL("ping-background-client")));
646 // Ping more than once for good measure.
647 EXPECT_EQ("true", NavigateAndExtractInnerText(
648 extension->GetResourceURL("ping-background-client")));
649
650 // Shut down the event page. The SW should detect that it's closed, but still
651 // be able to ping it.
652 ExtensionHost* background_page =
653 process_manager()->GetBackgroundHostForExtension(extension->id());
654 ASSERT_TRUE(background_page);
655 background_page->Close();
656 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
657
658 EXPECT_EQ("false", NavigateAndExtractInnerText(extension->GetResourceURL(
659 "background-client-is-awake")));
660 EXPECT_EQ("true", NavigateAndExtractInnerText(
661 extension->GetResourceURL("ping-background-client")));
662 EXPECT_EQ("true", NavigateAndExtractInnerText(
663 extension->GetResourceURL("ping-background-client")));
664 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
665 "background-client-is-awake")));
666}
667
Istiaque Ahmedea5ed5042017-09-25 19:00:16668IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
kalman6f984ae2015-09-18 17:21:58669 GetBackgroundClientFailsWithNoBackgroundPage) {
670 // This extension doesn't have a background page, only a tab at page.html.
671 // The service worker it registers tries to call getBackgroundClient() and
672 // should fail.
673 // Note that this also tests that service workers can be registered from tabs.
674 EXPECT_TRUE(RunExtensionSubtest("service_worker/no_background", "page.html"));
rdevlin.croninf5863da2015-09-10 19:21:45675}
676
Istiaque Ahmedea5ed5042017-09-25 19:00:16677IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, NotificationAPI) {
lazyboy6ddb7d62015-11-10 23:15:27678 EXPECT_TRUE(RunExtensionSubtest("service_worker/notifications/has_permission",
679 "page.html"));
680}
681
Istiaque Ahmedea5ed5042017-09-25 19:00:16682IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, WebAccessibleResourcesFetch) {
lazyboyaea32c22016-01-04 21:37:07683 EXPECT_TRUE(RunExtensionSubtest(
684 "service_worker/web_accessible_resources/fetch/", "page.html"));
685}
686
Istiaque Ahmedea5ed5042017-09-25 19:00:16687IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, TabsCreate) {
lazyboyee4adef2016-05-24 00:55:16688 // Extensions APIs from SW are only enabled on trunk.
689 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
690 const Extension* extension = LoadExtensionWithFlags(
691 test_data_dir_.AppendASCII("service_worker/tabs_create"), kFlagNone);
692 ASSERT_TRUE(extension);
693 ui_test_utils::NavigateToURL(browser(),
694 extension->GetResourceURL("page.html"));
695 content::WebContents* web_contents =
696 browser()->tab_strip_model()->GetActiveWebContents();
697
698 int starting_tab_count = browser()->tab_strip_model()->count();
699 std::string result;
700 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
701 web_contents, "window.runServiceWorker()", &result));
702 ASSERT_EQ("chrome.tabs.create callback", result);
703 EXPECT_EQ(starting_tab_count + 1, browser()->tab_strip_model()->count());
704
705 // Check extension shutdown path.
706 UnloadExtension(extension->id());
707 EXPECT_EQ(starting_tab_count, browser()->tab_strip_model()->count());
708}
709
Istiaque Ahmedea5ed5042017-09-25 19:00:16710IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, Events) {
lazyboye7847242017-06-07 23:29:18711 // Extensions APIs from SW are only enabled on trunk.
712 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
713 const Extension* extension = LoadExtensionWithFlags(
714 test_data_dir_.AppendASCII("service_worker/events"), kFlagNone);
715 ASSERT_TRUE(extension);
716 ui_test_utils::NavigateToURL(browser(),
717 extension->GetResourceURL("page.html"));
718 content::WebContents* web_contents =
719 browser()->tab_strip_model()->GetActiveWebContents();
720 std::string result;
721 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
722 web_contents, "window.runEventTest()", &result));
723 ASSERT_EQ("chrome.tabs.onUpdated callback", result);
724}
725
Istiaque Ahmedea5ed5042017-09-25 19:00:16726IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, EventsToStoppedWorker) {
lazyboy63b994a2017-06-30 21:20:23727 // Extensions APIs from SW are only enabled on trunk.
728 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
729 const Extension* extension = LoadExtensionWithFlags(
730 test_data_dir_.AppendASCII("service_worker/events_to_stopped_worker"),
731 kFlagNone);
732 ASSERT_TRUE(extension);
733 ui_test_utils::NavigateToURL(browser(),
734 extension->GetResourceURL("page.html"));
735 content::WebContents* web_contents =
736 browser()->tab_strip_model()->GetActiveWebContents();
737 {
738 std::string result;
739 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
740 web_contents, "window.runServiceWorker()", &result));
741 ASSERT_EQ("ready", result);
742
743 base::RunLoop run_loop;
744 content::StoragePartition* storage_partition =
745 content::BrowserContext::GetDefaultStoragePartition(
746 browser()->profile());
747 content::StopServiceWorkerForPattern(
748 storage_partition->GetServiceWorkerContext(),
749 // The service worker is registered at the top level scope.
750 extension->url(), run_loop.QuitClosure());
751 run_loop.Run();
752 }
753
754 std::string result;
755 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
756 web_contents, "window.createTabThenUpdate()", &result));
757 ASSERT_EQ("chrome.tabs.onUpdated callback", result);
758}
759
Istiaque Ahmed805f6a83b2017-10-05 01:23:26760// Tests that events to service worker arrives correctly event if the owner
761// extension of the worker is not running.
762IN_PROC_BROWSER_TEST_P(ServiceWorkerLazyBackgroundTest,
763 EventsToStoppedExtension) {
764 // Extensions APIs from SW are only enabled on trunk.
765 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
766
767 LazyBackgroundObserver lazy_observer;
768 ResultCatcher catcher;
769 const Extension* extension = LoadExtensionWithFlags(
770 test_data_dir_.AppendASCII("service_worker/events_to_stopped_extension"),
771 kFlagNone);
772 ASSERT_TRUE(extension);
773 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
774
775 ProcessManager* pm = ProcessManager::Get(browser()->profile());
776 EXPECT_GT(pm->GetLazyKeepaliveCount(extension), 0);
777
778 // |extension|'s background page opens a tab to its resource.
779 content::WebContents* extension_web_contents =
780 browser()->tab_strip_model()->GetActiveWebContents();
781 EXPECT_TRUE(content::WaitForLoadStop(extension_web_contents));
782 EXPECT_EQ(extension->GetResourceURL("page.html").spec(),
783 extension_web_contents->GetURL().spec());
784 {
785 // Let the service worker start and register a listener to
786 // chrome.tabs.onCreated event.
787 ExtensionTestMessageListener add_listener_done("listener-added", false);
788 content::ExecuteScriptAsync(extension_web_contents,
789 "window.runServiceWorkerAsync()");
790 EXPECT_TRUE(add_listener_done.WaitUntilSatisfied());
791
792 base::RunLoop run_loop;
793 content::StoragePartition* storage_partition =
794 content::BrowserContext::GetDefaultStoragePartition(
795 browser()->profile());
796 content::StopServiceWorkerForPattern(
797 storage_partition->GetServiceWorkerContext(),
798 // The service worker is registered at the top level scope.
799 extension->url(), run_loop.QuitClosure());
800 run_loop.Run();
801 }
802
803 // Close the tab to |extension|'s resource. This will also close the
804 // extension's event page.
805 browser()->tab_strip_model()->CloseWebContentsAt(
806 browser()->tab_strip_model()->active_index(), TabStripModel::CLOSE_NONE);
807 lazy_observer.Wait();
808
809 // At this point both the extension worker and extension event page is not
810 // running. Since the worker registered a listener for tabs.onCreated, it
811 // will be started to dispatch the event once we create a tab.
812 ExtensionTestMessageListener newtab_listener("hello-newtab", false);
813 newtab_listener.set_failure_message("WRONG_NEWTAB");
814 content::WebContents* new_web_contents =
815 AddTab(browser(), GURL("about:blank"));
816 EXPECT_TRUE(new_web_contents);
817 EXPECT_TRUE(newtab_listener.WaitUntilSatisfied());
818}
819
lazyboy4c82177a2016-10-18 00:04:09820// Tests that worker ref count increments while extension API function is
821// active.
Istiaque Ahmedea5ed5042017-09-25 19:00:16822IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, WorkerRefCount) {
lazyboy4c82177a2016-10-18 00:04:09823 // Extensions APIs from SW are only enabled on trunk.
824 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
825 const Extension* extension = LoadExtensionWithFlags(
826 test_data_dir_.AppendASCII("service_worker/api_worker_ref_count"),
827 kFlagNone);
828 ASSERT_TRUE(extension);
829 ui_test_utils::NavigateToURL(browser(),
830 extension->GetResourceURL("page.html"));
831 content::WebContents* web_contents =
832 browser()->tab_strip_model()->GetActiveWebContents();
833
834 ExtensionTestMessageListener worker_start_listener("WORKER STARTED", false);
835 worker_start_listener.set_failure_message("FAILURE");
836 ASSERT_TRUE(
837 content::ExecuteScript(web_contents, "window.runServiceWorker()"));
838 ASSERT_TRUE(worker_start_listener.WaitUntilSatisfied());
839
840 // Service worker should have no pending requests because it hasn't peformed
841 // any extension API request yet.
842 EXPECT_EQ(0u, GetWorkerRefCount(extension->url()));
843
844 ExtensionTestMessageListener worker_listener("CHECK_REF_COUNT", true);
845 worker_listener.set_failure_message("FAILURE");
846 ASSERT_TRUE(content::ExecuteScript(web_contents, "window.testSendMessage()"));
847 ASSERT_TRUE(worker_listener.WaitUntilSatisfied());
848
849 // Service worker should have exactly one pending request because
850 // chrome.test.sendMessage() API call is in-flight.
851 EXPECT_EQ(1u, GetWorkerRefCount(extension->url()));
852
853 // Peform another extension API request while one is ongoing.
854 {
855 ExtensionTestMessageListener listener("CHECK_REF_COUNT", true);
856 listener.set_failure_message("FAILURE");
857 ASSERT_TRUE(
858 content::ExecuteScript(web_contents, "window.testSendMessage()"));
859 ASSERT_TRUE(listener.WaitUntilSatisfied());
860
861 // Service worker currently has two extension API requests in-flight.
862 EXPECT_EQ(2u, GetWorkerRefCount(extension->url()));
863 // Finish executing the nested chrome.test.sendMessage() first.
864 listener.Reply("Hello world");
865 }
866
Istiaque Ahmedb57c9752017-08-20 19:08:57867 ExtensionTestMessageListener worker_completion_listener("SUCCESS_FROM_WORKER",
868 false);
lazyboy4c82177a2016-10-18 00:04:09869 // Finish executing chrome.test.sendMessage().
870 worker_listener.Reply("Hello world");
Istiaque Ahmedb57c9752017-08-20 19:08:57871 EXPECT_TRUE(worker_completion_listener.WaitUntilSatisfied());
872
873 // The following block makes sure we have received all the IPCs related to
874 // ref-count from the worker.
875 {
876 // The following roundtrip:
877 // browser->extension->worker->extension->browser
878 // will ensure that the worker sent the relevant ref count IPCs.
879 std::string result;
880 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
881 web_contents, "window.roundtripToWorker();", &result));
882 EXPECT_EQ("roundtrip-succeeded", result);
883
884 // Ensure IO thread IPCs run.
Gabriel Charette01507a22017-09-27 21:30:08885 content::RunAllTasksUntilIdle();
Istiaque Ahmedb57c9752017-08-20 19:08:57886 }
lazyboy4c82177a2016-10-18 00:04:09887
888 // The ref count should drop to 0.
889 EXPECT_EQ(0u, GetWorkerRefCount(extension->url()));
890}
891
lazyboyaea32c22016-01-04 21:37:07892// This test loads a web page that has an iframe pointing to a
893// chrome-extension:// URL. The URL is listed in the extension's
894// web_accessible_resources. Initially the iframe is served from the extension's
895// resource file. After verifying that, we register a Service Worker that
896// controls the extension. Further requests to the same resource as before
897// should now be served by the Service Worker.
898// This test also verifies that if the requested resource exists in the manifest
899// but is not present in the extension directory, the Service Worker can still
900// serve the resource file.
Istiaque Ahmedea5ed5042017-09-25 19:00:16901IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, WebAccessibleResourcesIframeSrc) {
lazyboyaea32c22016-01-04 21:37:07902 const Extension* extension = LoadExtensionWithFlags(
903 test_data_dir_.AppendASCII(
904 "service_worker/web_accessible_resources/iframe_src"),
905 kFlagNone);
906 ASSERT_TRUE(extension);
907 ASSERT_TRUE(StartEmbeddedTestServer());
falkenad185092016-06-16 06:10:02908
909 // Service workers can only control secure contexts
910 // (https://w3c.github.io/webappsec-secure-contexts/). For documents, this
911 // typically means the document must have a secure origin AND all its ancestor
912 // frames must have documents with secure origins. However, extension pages
913 // are considered secure, even if they have an ancestor document that is an
914 // insecure context (see GetSchemesBypassingSecureContextCheckWhitelist). So
915 // extension service workers must be able to control an extension page
916 // embedded in an insecure context. To test this, set up an insecure
917 // (non-localhost, non-https) URL for the web page. This page will create
918 // iframes that load extension pages that must be controllable by service
919 // worker.
falkenad185092016-06-16 06:10:02920 GURL page_url =
921 embedded_test_server()->GetURL("a.com",
922 "/extensions/api_test/service_worker/"
923 "web_accessible_resources/webpage.html");
924 EXPECT_FALSE(content::IsOriginSecure(page_url));
lazyboyaea32c22016-01-04 21:37:07925
926 content::WebContents* web_contents = AddTab(browser(), page_url);
927 std::string result;
928 // webpage.html will create an iframe pointing to a resource from |extension|.
929 // Expect the resource to be served by the extension.
930 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
931 web_contents, base::StringPrintf("window.testIframe('%s', 'iframe.html')",
932 extension->id().c_str()),
933 &result));
934 EXPECT_EQ("FROM_EXTENSION_RESOURCE", result);
935
936 ExtensionTestMessageListener service_worker_ready_listener("SW_READY", false);
937 EXPECT_TRUE(ExecuteScriptInBackgroundPageNoWait(
938 extension->id(), "window.registerServiceWorker()"));
939 EXPECT_TRUE(service_worker_ready_listener.WaitUntilSatisfied());
940
941 result.clear();
942 // webpage.html will create another iframe pointing to a resource from
943 // |extension| as before. But this time, the resource should be be served
944 // from the Service Worker.
945 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
946 web_contents, base::StringPrintf("window.testIframe('%s', 'iframe.html')",
947 extension->id().c_str()),
948 &result));
949 EXPECT_EQ("FROM_SW_RESOURCE", result);
950
951 result.clear();
952 // webpage.html will create yet another iframe pointing to a resource that
953 // exists in the extension manifest's web_accessible_resources, but is not
954 // present in the extension directory. Expect the resources of the iframe to
955 // be served by the Service Worker.
956 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
957 web_contents,
958 base::StringPrintf("window.testIframe('%s', 'iframe_non_existent.html')",
959 extension->id().c_str()),
960 &result));
961 EXPECT_EQ("FROM_SW_RESOURCE", result);
962}
963
Istiaque Ahmedea5ed5042017-09-25 19:00:16964IN_PROC_BROWSER_TEST_P(ServiceWorkerBackgroundSyncTest, Sync) {
lazyboybd325ae2015-11-18 21:35:26965 const Extension* extension = LoadExtensionWithFlags(
966 test_data_dir_.AppendASCII("service_worker/sync"), kFlagNone);
967 ASSERT_TRUE(extension);
968 ui_test_utils::NavigateToURL(browser(),
969 extension->GetResourceURL("page.html"));
970 content::WebContents* web_contents =
971 browser()->tab_strip_model()->GetActiveWebContents();
972
973 // Prevent firing by going offline.
974 content::background_sync_test_util::SetOnline(web_contents, false);
975
976 ExtensionTestMessageListener sync_listener("SYNC: send-chats", false);
977 sync_listener.set_failure_message("FAIL");
978
979 std::string result;
980 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
981 web_contents, "window.runServiceWorker()", &result));
982 ASSERT_EQ("SERVICE_WORKER_READY", result);
983
984 EXPECT_FALSE(sync_listener.was_satisfied());
985 // Resume firing by going online.
986 content::background_sync_test_util::SetOnline(web_contents, true);
987 EXPECT_TRUE(sync_listener.WaitUntilSatisfied());
988}
989
Istiaque Ahmedea5ed5042017-09-25 19:00:16990IN_PROC_BROWSER_TEST_P(ServiceWorkerTest,
horo1eeddde2015-11-19 05:59:25991 FetchFromContentScriptShouldNotGoToServiceWorkerOfPage) {
992 ASSERT_TRUE(StartEmbeddedTestServer());
993 GURL page_url = embedded_test_server()->GetURL(
994 "/extensions/api_test/service_worker/content_script_fetch/"
995 "controlled_page/index.html");
996 content::WebContents* tab =
997 browser()->tab_strip_model()->GetActiveWebContents();
998 ui_test_utils::NavigateToURL(browser(), page_url);
999 content::WaitForLoadStop(tab);
1000
1001 std::string value;
1002 ASSERT_TRUE(
1003 content::ExecuteScriptAndExtractString(tab, "register();", &value));
1004 EXPECT_EQ("SW controlled", value);
1005
1006 ASSERT_TRUE(RunExtensionTest("service_worker/content_script_fetch"))
1007 << message_;
1008}
1009
Istiaque Ahmedea5ed5042017-09-25 19:00:161010IN_PROC_BROWSER_TEST_P(ServiceWorkerPushMessagingTest, OnPush) {
lazyboy561b7de2015-11-19 19:27:301011 const Extension* extension = LoadExtensionWithFlags(
1012 test_data_dir_.AppendASCII("service_worker/push_messaging"), kFlagNone);
1013 ASSERT_TRUE(extension);
1014 GURL extension_url = extension->url();
1015
1016 ASSERT_NO_FATAL_FAILURE(GrantNotificationPermissionForTest(extension_url));
1017
1018 GURL url = extension->GetResourceURL("page.html");
1019 ui_test_utils::NavigateToURL(browser(), url);
1020
1021 content::WebContents* web_contents =
1022 browser()->tab_strip_model()->GetActiveWebContents();
1023
1024 // Start the ServiceWorker.
1025 ExtensionTestMessageListener ready_listener("SERVICE_WORKER_READY", false);
1026 ready_listener.set_failure_message("SERVICE_WORKER_FAILURE");
1027 const char* kScript = "window.runServiceWorker()";
1028 EXPECT_TRUE(content::ExecuteScript(web_contents->GetMainFrame(), kScript));
1029 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
1030
1031 PushMessagingAppIdentifier app_identifier =
1032 GetAppIdentifierForServiceWorkerRegistration(0LL, extension_url);
johnmea5045732016-09-08 17:23:291033 ASSERT_EQ(app_identifier.app_id(), gcm_driver()->last_gettoken_app_id());
1034 EXPECT_EQ("1234567890", gcm_driver()->last_gettoken_authorized_entity());
lazyboy561b7de2015-11-19 19:27:301035
lazyboyd429e2582016-05-20 20:18:521036 base::RunLoop run_loop;
lazyboy561b7de2015-11-19 19:27:301037 // Send a push message via gcm and expect the ServiceWorker to receive it.
1038 ExtensionTestMessageListener push_message_listener("OK", false);
1039 push_message_listener.set_failure_message("FAIL");
1040 gcm::IncomingMessage message;
1041 message.sender_id = "1234567890";
1042 message.raw_data = "testdata";
1043 message.decrypted = true;
lazyboyd429e2582016-05-20 20:18:521044 push_service()->SetMessageCallbackForTesting(run_loop.QuitClosure());
lazyboy561b7de2015-11-19 19:27:301045 push_service()->OnMessage(app_identifier.app_id(), message);
1046 EXPECT_TRUE(push_message_listener.WaitUntilSatisfied());
lazyboyd429e2582016-05-20 20:18:521047 run_loop.Run(); // Wait until the message is handled by push service.
lazyboy561b7de2015-11-19 19:27:301048}
1049
Istiaque Ahmedea5ed5042017-09-25 19:00:161050IN_PROC_BROWSER_TEST_P(ServiceWorkerTest, FilteredEvents) {
Istiaque Ahmed9d1666182017-09-21 23:58:181051 // Extensions APIs from SW are only enabled on trunk.
1052 ScopedCurrentChannel current_channel_override(version_info::Channel::UNKNOWN);
1053 ASSERT_TRUE(RunExtensionTest("service_worker/filtered_events"));
1054}
1055
Istiaque Ahmedea5ed5042017-09-25 19:00:161056// Run with both native and JS-based bindings. This ensures that both stable
1057// (JS) and experimental (native) phases work correctly with worker scripts
1058// while we launch native bindings to stable.
1059INSTANTIATE_TEST_CASE_P(ServiceWorkerTestWithNativeBindings,
1060 ServiceWorkerTest,
1061 ::testing::Values(NATIVE_BINDINGS));
1062INSTANTIATE_TEST_CASE_P(ServiceWorkerTestWithJSBindings,
1063 ServiceWorkerTest,
1064 ::testing::Values(JAVASCRIPT_BINDINGS));
1065INSTANTIATE_TEST_CASE_P(ServiceWorkerBackgroundSyncTestWithNativeBindings,
1066 ServiceWorkerBackgroundSyncTest,
1067 ::testing::Values(NATIVE_BINDINGS));
1068INSTANTIATE_TEST_CASE_P(ServiceWorkerBackgroundSyncTestWithJSBindings,
1069 ServiceWorkerBackgroundSyncTest,
1070 ::testing::Values(JAVASCRIPT_BINDINGS));
1071INSTANTIATE_TEST_CASE_P(ServiceWorkerPushMessagingTestWithNativeBindings,
1072 ServiceWorkerPushMessagingTest,
1073 ::testing::Values(NATIVE_BINDINGS));
1074INSTANTIATE_TEST_CASE_P(ServiceWorkerPushMessagingTestWithJSBindings,
1075 ServiceWorkerPushMessagingTest,
1076 ::testing::Values(JAVASCRIPT_BINDINGS));
Istiaque Ahmed805f6a83b2017-10-05 01:23:261077INSTANTIATE_TEST_CASE_P(ServiceWorkerLazyBackgroundTestWithNativeBindings,
1078 ServiceWorkerLazyBackgroundTest,
1079 ::testing::Values(NATIVE_BINDINGS));
1080INSTANTIATE_TEST_CASE_P(ServiceWorkerLazyBackgroundTestWithJSBindings,
1081 ServiceWorkerLazyBackgroundTest,
1082 ::testing::Values(JAVASCRIPT_BINDINGS));
Istiaque Ahmedea5ed5042017-09-25 19:00:161083
annekao38685502015-07-14 17:46:391084} // namespace extensions