blob: 3b0b2ec3300a222a2197777e8ff2ed027b082cba [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"
kalman6f984ae2015-09-18 17:21:589#include "base/strings/stringprintf.h"
horo1eeddde2015-11-19 05:59:2510#include "base/strings/utf_string_conversions.h"
annekao38685502015-07-14 17:46:3911#include "chrome/browser/extensions/extension_apitest.h"
rdevlin.croninf5863da2015-09-10 19:21:4512#include "chrome/browser/extensions/extension_service.h"
lazyboy561b7de2015-11-19 19:27:3013#include "chrome/browser/notifications/desktop_notification_profile_util.h"
14#include "chrome/browser/push_messaging/push_messaging_app_identifier.h"
15#include "chrome/browser/push_messaging/push_messaging_service_factory.h"
16#include "chrome/browser/push_messaging/push_messaging_service_impl.h"
17#include "chrome/browser/services/gcm/fake_gcm_profile_service.h"
18#include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
annekao1db36fd2015-07-29 17:09:1619#include "chrome/browser/ui/tabs/tab_strip_model.h"
rdevlin.croninf5863da2015-09-10 19:21:4520#include "chrome/test/base/ui_test_utils.h"
sdefresne9fb67692015-08-03 18:48:2221#include "components/version_info/version_info.h"
kalman6f984ae2015-09-18 17:21:5822#include "content/public/browser/navigation_controller.h"
rdevlin.croninf5863da2015-09-10 19:21:4523#include "content/public/browser/navigation_entry.h"
kalman6f984ae2015-09-18 17:21:5824#include "content/public/browser/web_contents.h"
lazyboybd325ae2015-11-18 21:35:2625#include "content/public/common/content_switches.h"
kalman6f984ae2015-09-18 17:21:5826#include "content/public/common/page_type.h"
lazyboybd325ae2015-11-18 21:35:2627#include "content/public/test/background_sync_test_util.h"
annekao1db36fd2015-07-29 17:09:1628#include "content/public/test/browser_test_utils.h"
kalman6f984ae2015-09-18 17:21:5829#include "extensions/browser/extension_host.h"
lazyboyc3e763a2015-12-09 23:09:5830#include "extensions/browser/extension_registry.h"
kalman6f984ae2015-09-18 17:21:5831#include "extensions/browser/process_manager.h"
32#include "extensions/test/background_page_watcher.h"
annekao38685502015-07-14 17:46:3933#include "extensions/test/extension_test_message_listener.h"
horo1eeddde2015-11-19 05:59:2534#include "net/test/embedded_test_server/embedded_test_server.h"
annekao38685502015-07-14 17:46:3935
36namespace extensions {
37
kalman6f984ae2015-09-18 17:21:5838namespace {
39
40// Pass into ServiceWorkerTest::StartTestFromBackgroundPage to indicate that
41// registration is expected to succeed.
42std::string* const kExpectSuccess = nullptr;
43
44void DoNothingWithBool(bool b) {}
45
lazyboy22eddc712015-12-10 21:16:2646// Returns the newly added WebContents.
47content::WebContents* AddTab(Browser* browser, const GURL& url) {
48 int starting_tab_count = browser->tab_strip_model()->count();
49 ui_test_utils::NavigateToURLWithDisposition(
50 browser, url, NEW_FOREGROUND_TAB,
51 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
52 int tab_count = browser->tab_strip_model()->count();
53 EXPECT_EQ(starting_tab_count + 1, tab_count);
54 return browser->tab_strip_model()->GetActiveWebContents();
55}
56
57class WebContentsLoadStopObserver : content::WebContentsObserver {
58 public:
59 explicit WebContentsLoadStopObserver(content::WebContents* web_contents)
60 : content::WebContentsObserver(web_contents),
61 load_stop_observed_(false) {}
62
63 void WaitForLoadStop() {
64 if (load_stop_observed_)
65 return;
66 message_loop_runner_ = new content::MessageLoopRunner;
67 message_loop_runner_->Run();
68 }
69
70 private:
71 void DidStopLoading() override {
72 load_stop_observed_ = true;
73 if (message_loop_runner_)
74 message_loop_runner_->Quit();
75 }
76
77 bool load_stop_observed_;
78 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
79
80 DISALLOW_COPY_AND_ASSIGN(WebContentsLoadStopObserver);
81};
82
kalman6f984ae2015-09-18 17:21:5883} // namespace
84
annekao38685502015-07-14 17:46:3985class ServiceWorkerTest : public ExtensionApiTest {
86 public:
kalman6f984ae2015-09-18 17:21:5887 ServiceWorkerTest() : current_channel_(version_info::Channel::UNKNOWN) {}
annekao38685502015-07-14 17:46:3988
89 ~ServiceWorkerTest() override {}
90
kalman6f984ae2015-09-18 17:21:5891 protected:
92 // Returns the ProcessManager for the test's profile.
93 ProcessManager* process_manager() { return ProcessManager::Get(profile()); }
94
95 // Starts running a test from the background page test extension.
96 //
97 // This registers a service worker with |script_name|, and fetches the
98 // registration result.
99 //
100 // If |error_or_null| is null (kExpectSuccess), success is expected and this
101 // will fail if there is an error.
102 // If |error_or_null| is not null, nothing is assumed, and the error (which
103 // may be empty) is written to it.
104 const Extension* StartTestFromBackgroundPage(const char* script_name,
105 std::string* error_or_null) {
106 const Extension* extension =
107 LoadExtension(test_data_dir_.AppendASCII("service_worker/background"));
108 CHECK(extension);
109 ExtensionHost* background_host =
110 process_manager()->GetBackgroundHostForExtension(extension->id());
111 CHECK(background_host);
112 std::string error;
113 CHECK(content::ExecuteScriptAndExtractString(
114 background_host->host_contents(),
115 base::StringPrintf("test.registerServiceWorker('%s')", script_name),
116 &error));
117 if (error_or_null)
118 *error_or_null = error;
119 else if (!error.empty())
120 ADD_FAILURE() << "Got unexpected error " << error;
121 return extension;
122 }
123
124 // Navigates the browser to a new tab at |url|, waits for it to load, then
125 // returns it.
126 content::WebContents* Navigate(const GURL& url) {
127 ui_test_utils::NavigateToURLWithDisposition(
128 browser(), url, NEW_FOREGROUND_TAB,
129 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
130 content::WebContents* web_contents =
131 browser()->tab_strip_model()->GetActiveWebContents();
132 content::WaitForLoadStop(web_contents);
133 return web_contents;
134 }
135
136 // Navigates the browser to |url| and returns the new tab's page type.
137 content::PageType NavigateAndGetPageType(const GURL& url) {
138 return Navigate(url)->GetController().GetActiveEntry()->GetPageType();
139 }
140
141 // Extracts the innerText from |contents|.
142 std::string ExtractInnerText(content::WebContents* contents) {
143 std::string inner_text;
144 if (!content::ExecuteScriptAndExtractString(
145 contents,
146 "window.domAutomationController.send(document.body.innerText)",
147 &inner_text)) {
148 ADD_FAILURE() << "Failed to get inner text for "
149 << contents->GetVisibleURL();
150 }
151 return inner_text;
152 }
153
154 // Navigates the browser to |url|, then returns the innerText of the new
155 // tab's WebContents' main frame.
156 std::string NavigateAndExtractInnerText(const GURL& url) {
157 return ExtractInnerText(Navigate(url));
158 }
159
annekao38685502015-07-14 17:46:39160 private:
kalman6f984ae2015-09-18 17:21:58161 // Sets the channel to "trunk" since service workers are restricted to trunk.
annekao38685502015-07-14 17:46:39162 ScopedCurrentChannel current_channel_;
kalman6f984ae2015-09-18 17:21:58163
annekao38685502015-07-14 17:46:39164 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerTest);
165};
166
lazyboybd325ae2015-11-18 21:35:26167class ServiceWorkerBackgroundSyncTest : public ServiceWorkerTest {
168 public:
169 ServiceWorkerBackgroundSyncTest() {}
170 ~ServiceWorkerBackgroundSyncTest() override {}
171
172 void SetUpCommandLine(base::CommandLine* command_line) override {
173 // ServiceWorkerRegistration.sync requires experimental flag.
174 command_line->AppendSwitch(
175 switches::kEnableExperimentalWebPlatformFeatures);
176 ServiceWorkerTest::SetUpCommandLine(command_line);
177 }
178
179 void SetUp() override {
180 content::background_sync_test_util::SetIgnoreNetworkChangeNotifier(true);
181 ServiceWorkerTest::SetUp();
182 }
183
184 private:
185 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerBackgroundSyncTest);
186};
187
lazyboy561b7de2015-11-19 19:27:30188class ServiceWorkerPushMessagingTest : public ServiceWorkerTest {
189 public:
190 ServiceWorkerPushMessagingTest()
191 : gcm_service_(nullptr), push_service_(nullptr) {}
192 ~ServiceWorkerPushMessagingTest() override {}
193
194 void GrantNotificationPermissionForTest(const GURL& url) {
195 GURL origin = url.GetOrigin();
196 DesktopNotificationProfileUtil::GrantPermission(profile(), origin);
197 ASSERT_EQ(
198 CONTENT_SETTING_ALLOW,
199 DesktopNotificationProfileUtil::GetContentSetting(profile(), origin));
200 }
201
202 PushMessagingAppIdentifier GetAppIdentifierForServiceWorkerRegistration(
avia2f4804a2015-12-24 23:11:13203 int64_t service_worker_registration_id,
lazyboy561b7de2015-11-19 19:27:30204 const GURL& origin) {
205 PushMessagingAppIdentifier app_identifier =
206 PushMessagingAppIdentifier::FindByServiceWorker(
207 profile(), origin, service_worker_registration_id);
208
209 EXPECT_FALSE(app_identifier.is_null());
210 return app_identifier;
211 }
212
213 // ExtensionApiTest overrides.
214 void SetUpCommandLine(base::CommandLine* command_line) override {
peter9de96272015-12-04 15:23:27215 command_line->AppendSwitch(
216 switches::kEnableExperimentalWebPlatformFeatures);
lazyboy561b7de2015-11-19 19:27:30217 ServiceWorkerTest::SetUpCommandLine(command_line);
218 }
219 void SetUpOnMainThread() override {
220 gcm_service_ = static_cast<gcm::FakeGCMProfileService*>(
221 gcm::GCMProfileServiceFactory::GetInstance()->SetTestingFactoryAndUse(
222 profile(), &gcm::FakeGCMProfileService::Build));
223 gcm_service_->set_collect(true);
224 push_service_ = PushMessagingServiceFactory::GetForProfile(profile());
225
226 ServiceWorkerTest::SetUpOnMainThread();
227 }
228
229 gcm::FakeGCMProfileService* gcm_service() const { return gcm_service_; }
230 PushMessagingServiceImpl* push_service() const { return push_service_; }
231
232 private:
233 gcm::FakeGCMProfileService* gcm_service_;
234 PushMessagingServiceImpl* push_service_;
235
236 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerPushMessagingTest);
237};
238
kalman6f984ae2015-09-18 17:21:58239IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, RegisterSucceedsOnTrunk) {
240 StartTestFromBackgroundPage("register.js", kExpectSuccess);
annekao38685502015-07-14 17:46:39241}
242
243// This feature is restricted to trunk, so on dev it should have existing
244// behavior - which is for it to fail.
kalman6f984ae2015-09-18 17:21:58245IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, RegisterFailsOnDev) {
annekao38685502015-07-14 17:46:39246 ScopedCurrentChannel current_channel_override(
sdefresne6e883e42015-07-30 08:05:54247 version_info::Channel::DEV);
kalman6f984ae2015-09-18 17:21:58248 std::string error;
249 const Extension* extension =
250 StartTestFromBackgroundPage("register.js", &error);
annekao1db36fd2015-07-29 17:09:16251 EXPECT_EQ(
kalman6f984ae2015-09-18 17:21:58252 "Failed to register a ServiceWorker: The URL protocol of the current "
253 "origin ('chrome-extension://" +
254 extension->id() + "') is not supported.",
255 error);
annekao38685502015-07-14 17:46:39256}
257
lazyboyc3e763a2015-12-09 23:09:58258IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, UpdateRefreshesServiceWorker) {
259 base::ScopedTempDir scoped_temp_dir;
260 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
261 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
262 .AppendASCII("update")
263 .AppendASCII("service_worker.pem");
264 base::FilePath path_v1 = PackExtensionWithOptions(
265 test_data_dir_.AppendASCII("service_worker")
266 .AppendASCII("update")
267 .AppendASCII("v1"),
268 scoped_temp_dir.path().AppendASCII("v1.crx"), pem_path, base::FilePath());
269 base::FilePath path_v2 = PackExtensionWithOptions(
270 test_data_dir_.AppendASCII("service_worker")
271 .AppendASCII("update")
272 .AppendASCII("v2"),
273 scoped_temp_dir.path().AppendASCII("v2.crx"), pem_path, base::FilePath());
274 const char* kId = "hfaanndiiilofhfokeanhddpkfffchdi";
275
276 ExtensionTestMessageListener listener_v1("Pong from version 1", false);
277 listener_v1.set_failure_message("FAILURE_V1");
278 // Install version 1.0 of the extension.
279 ASSERT_TRUE(InstallExtension(path_v1, 1));
280 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
281 ->enabled_extensions()
282 .GetByID(kId));
283 EXPECT_TRUE(listener_v1.WaitUntilSatisfied());
284
285 ExtensionTestMessageListener listener_v2("Pong from version 2", false);
286 listener_v2.set_failure_message("FAILURE_V2");
287
288 // Update to version 2.0.
289 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
290 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
291 ->enabled_extensions()
292 .GetByID(kId));
293 EXPECT_TRUE(listener_v2.WaitUntilSatisfied());
294}
295
lazyboy22eddc712015-12-10 21:16:26296IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, UpdateWithoutSkipWaiting) {
297 base::ScopedTempDir scoped_temp_dir;
298 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
299 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
300 .AppendASCII("update_without_skip_waiting")
301 .AppendASCII("update_without_skip_waiting.pem");
302 base::FilePath path_v1 = PackExtensionWithOptions(
303 test_data_dir_.AppendASCII("service_worker")
304 .AppendASCII("update_without_skip_waiting")
305 .AppendASCII("v1"),
306 scoped_temp_dir.path().AppendASCII("v1.crx"), pem_path, base::FilePath());
307 base::FilePath path_v2 = PackExtensionWithOptions(
308 test_data_dir_.AppendASCII("service_worker")
309 .AppendASCII("update_without_skip_waiting")
310 .AppendASCII("v2"),
311 scoped_temp_dir.path().AppendASCII("v2.crx"), pem_path, base::FilePath());
312 const char* kId = "mhnnnflgagdakldgjpfcofkiocpdmogl";
313
314 // Install version 1.0 of the extension.
315 ASSERT_TRUE(InstallExtension(path_v1, 1));
316 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
317 ->enabled_extensions()
318 .GetByID(kId));
319 const Extension* extension = extensions::ExtensionRegistry::Get(profile())
320 ->enabled_extensions()
321 .GetByID(kId);
322
323 ExtensionTestMessageListener listener1("Pong from version 1", false);
324 listener1.set_failure_message("FAILURE");
325 content::WebContents* web_contents =
326 AddTab(browser(), extension->GetResourceURL("page.html"));
327 EXPECT_TRUE(listener1.WaitUntilSatisfied());
328
329 // Update to version 2.0.
330 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
331 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
332 ->enabled_extensions()
333 .GetByID(kId));
334 const Extension* extension_after_update =
335 extensions::ExtensionRegistry::Get(profile())
336 ->enabled_extensions()
337 .GetByID(kId);
338
339 // Service worker version 2 would be installed but it won't be controlling
340 // the extension page yet.
341 ExtensionTestMessageListener listener2("Pong from version 1", false);
342 listener2.set_failure_message("FAILURE");
343 web_contents =
344 AddTab(browser(), extension_after_update->GetResourceURL("page.html"));
345 EXPECT_TRUE(listener2.WaitUntilSatisfied());
346
347 // Navigate the tab away from the extension page so that no clients are
348 // using the service worker.
349 // Note that just closing the tab with WebContentsDestroyedWatcher doesn't
350 // seem to be enough because it returns too early.
351 WebContentsLoadStopObserver navigate_away_observer(web_contents);
352 web_contents->GetController().LoadURL(
353 GURL(url::kAboutBlankURL), content::Referrer(), ui::PAGE_TRANSITION_TYPED,
354 std::string());
355 navigate_away_observer.WaitForLoadStop();
356
357 // Now expect service worker version 2 to control the extension page.
358 ExtensionTestMessageListener listener3("Pong from version 2", false);
359 listener3.set_failure_message("FAILURE");
360 web_contents =
361 AddTab(browser(), extension_after_update->GetResourceURL("page.html"));
362 EXPECT_TRUE(listener3.WaitUntilSatisfied());
363}
364
kalman6f984ae2015-09-18 17:21:58365IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, FetchArbitraryPaths) {
366 const Extension* extension =
367 StartTestFromBackgroundPage("fetch.js", kExpectSuccess);
annekao1db36fd2015-07-29 17:09:16368
kalman6f984ae2015-09-18 17:21:58369 // Open some arbirary paths. Their contents should be what the service worker
370 // responds with, which in this case is the path of the fetch.
371 EXPECT_EQ(
372 "Caught a fetch for /index.html",
373 NavigateAndExtractInnerText(extension->GetResourceURL("index.html")));
374 EXPECT_EQ("Caught a fetch for /path/to/other.html",
375 NavigateAndExtractInnerText(
376 extension->GetResourceURL("path/to/other.html")));
377 EXPECT_EQ("Caught a fetch for /some/text/file.txt",
378 NavigateAndExtractInnerText(
379 extension->GetResourceURL("some/text/file.txt")));
380 EXPECT_EQ("Caught a fetch for /no/file/extension",
381 NavigateAndExtractInnerText(
382 extension->GetResourceURL("no/file/extension")));
383 EXPECT_EQ("Caught a fetch for /",
384 NavigateAndExtractInnerText(extension->GetResourceURL("")));
annekao1db36fd2015-07-29 17:09:16385}
386
lazyboy52c3bcf2016-01-08 00:11:29387IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, SWServedBackgroundPageReceivesEvent) {
388 const Extension* extension =
389 StartTestFromBackgroundPage("replace_background.js", kExpectSuccess);
390 ExtensionHost* background_page =
391 process_manager()->GetBackgroundHostForExtension(extension->id());
392 ASSERT_TRUE(background_page);
393
394 // Close the background page and start it again so that the service worker
395 // will start controlling pages.
396 background_page->Close();
397 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
398 background_page = nullptr;
399 process_manager()->WakeEventPage(extension->id(),
400 base::Bind(&DoNothingWithBool));
401 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
402
403 // Since the SW is now controlling the extension, the SW serves the background
404 // script. page.html sends a message to the background script and we verify
405 // that the SW served background script correctly receives the message/event.
406 ExtensionTestMessageListener listener("onMessage/SW BG.", false);
407 listener.set_failure_message("onMessage/original BG.");
408 content::WebContents* web_contents =
409 AddTab(browser(), extension->GetResourceURL("page.html"));
410 ASSERT_TRUE(web_contents);
411 EXPECT_TRUE(listener.WaitUntilSatisfied());
412}
413
kalman6f984ae2015-09-18 17:21:58414IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
415 LoadingBackgroundPageBypassesServiceWorker) {
416 const Extension* extension =
417 StartTestFromBackgroundPage("fetch.js", kExpectSuccess);
annekao49241182015-08-18 17:14:01418
kalman6f984ae2015-09-18 17:21:58419 std::string kExpectedInnerText = "background.html contents for testing.";
annekao49241182015-08-18 17:14:01420
kalman6f984ae2015-09-18 17:21:58421 // Sanity check that the background page has the expected content.
422 ExtensionHost* background_page =
423 process_manager()->GetBackgroundHostForExtension(extension->id());
424 ASSERT_TRUE(background_page);
425 EXPECT_EQ(kExpectedInnerText,
426 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:01427
kalman6f984ae2015-09-18 17:21:58428 // Close the background page.
429 background_page->Close();
430 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
431 background_page = nullptr;
432
433 // Start it again.
434 process_manager()->WakeEventPage(extension->id(),
435 base::Bind(&DoNothingWithBool));
436 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
437
438 // Content should not have been affected by the fetch, which would otherwise
439 // be "Caught fetch for...".
440 background_page =
441 process_manager()->GetBackgroundHostForExtension(extension->id());
442 ASSERT_TRUE(background_page);
443 content::WaitForLoadStop(background_page->host_contents());
444
445 // TODO(kalman): Everything you've read has been a LIE! It should be:
446 //
447 // EXPECT_EQ(kExpectedInnerText,
448 // ExtractInnerText(background_page->host_contents()));
449 //
450 // but there is a bug, and we're actually *not* bypassing the service worker
451 // for background page loads! For now, let it pass (assert wrong behavior)
452 // because it's not a regression, but this must be fixed eventually.
453 //
454 // Tracked in crbug.com/532720.
455 EXPECT_EQ("Caught a fetch for /background.html",
456 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:01457}
458
kalman6f984ae2015-09-18 17:21:58459IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
460 ServiceWorkerPostsMessageToBackgroundClient) {
461 const Extension* extension = StartTestFromBackgroundPage(
462 "post_message_to_background_client.js", kExpectSuccess);
annekao533482222015-08-21 23:23:53463
kalman6f984ae2015-09-18 17:21:58464 // The service worker in this test simply posts a message to the background
465 // client it receives from getBackgroundClient().
466 const char* kScript =
467 "var messagePromise = null;\n"
468 "if (test.lastMessageFromServiceWorker) {\n"
469 " messagePromise = Promise.resolve(test.lastMessageFromServiceWorker);\n"
470 "} else {\n"
471 " messagePromise = test.waitForMessage(navigator.serviceWorker);\n"
472 "}\n"
473 "messagePromise.then(function(message) {\n"
474 " window.domAutomationController.send(String(message == 'success'));\n"
475 "})\n";
476 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:53477}
478
kalman6f984ae2015-09-18 17:21:58479IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
480 BackgroundPagePostsMessageToServiceWorker) {
481 const Extension* extension =
482 StartTestFromBackgroundPage("post_message_to_sw.js", kExpectSuccess);
annekao533482222015-08-21 23:23:53483
kalman6f984ae2015-09-18 17:21:58484 // The service worker in this test waits for a message, then echoes it back
485 // by posting a message to the background page via getBackgroundClient().
486 const char* kScript =
487 "var mc = new MessageChannel();\n"
488 "test.waitForMessage(mc.port1).then(function(message) {\n"
489 " window.domAutomationController.send(String(message == 'hello'));\n"
490 "});\n"
491 "test.registeredServiceWorker.postMessage(\n"
492 " {message: 'hello', port: mc.port2}, [mc.port2])\n";
493 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:53494}
495
rdevlin.croninf5863da2015-09-10 19:21:45496IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
497 ServiceWorkerSuspensionOnExtensionUnload) {
kalman6f984ae2015-09-18 17:21:58498 // For this test, only hold onto the extension's ID and URL + a function to
499 // get a resource URL, because we're going to be disabling and uninstalling
500 // it, which will invalidate the pointer.
501 std::string extension_id;
502 GURL extension_url;
503 {
504 const Extension* extension =
505 StartTestFromBackgroundPage("fetch.js", kExpectSuccess);
506 extension_id = extension->id();
507 extension_url = extension->url();
508 }
509 auto get_resource_url = [&extension_url](const std::string& path) {
510 return Extension::GetResourceURL(extension_url, path);
511 };
rdevlin.croninf5863da2015-09-10 19:21:45512
kalman6f984ae2015-09-18 17:21:58513 // Fetch should route to the service worker.
514 EXPECT_EQ("Caught a fetch for /index.html",
515 NavigateAndExtractInnerText(get_resource_url("index.html")));
rdevlin.croninf5863da2015-09-10 19:21:45516
kalman6f984ae2015-09-18 17:21:58517 // Disable the extension. Opening the page should fail.
518 extension_service()->DisableExtension(extension_id,
rdevlin.croninf5863da2015-09-10 19:21:45519 Extension::DISABLE_USER_ACTION);
520 base::RunLoop().RunUntilIdle();
rdevlin.croninf5863da2015-09-10 19:21:45521
kalman6f984ae2015-09-18 17:21:58522 EXPECT_EQ(content::PAGE_TYPE_ERROR,
523 NavigateAndGetPageType(get_resource_url("index.html")));
524 EXPECT_EQ(content::PAGE_TYPE_ERROR,
525 NavigateAndGetPageType(get_resource_url("other.html")));
526
527 // Re-enable the extension. Opening pages should immediately start to succeed
528 // again.
rdevlin.croninf5863da2015-09-10 19:21:45529 extension_service()->EnableExtension(extension_id);
530 base::RunLoop().RunUntilIdle();
531
kalman6f984ae2015-09-18 17:21:58532 EXPECT_EQ("Caught a fetch for /index.html",
533 NavigateAndExtractInnerText(get_resource_url("index.html")));
534 EXPECT_EQ("Caught a fetch for /other.html",
535 NavigateAndExtractInnerText(get_resource_url("other.html")));
536 EXPECT_EQ("Caught a fetch for /another.html",
537 NavigateAndExtractInnerText(get_resource_url("another.html")));
rdevlin.croninf5863da2015-09-10 19:21:45538
kalman6f984ae2015-09-18 17:21:58539 // Uninstall the extension. Opening pages should fail again.
540 base::string16 error;
541 extension_service()->UninstallExtension(
542 extension_id, UninstallReason::UNINSTALL_REASON_FOR_TESTING,
543 base::Bind(&base::DoNothing), &error);
544 base::RunLoop().RunUntilIdle();
545
546 EXPECT_EQ(content::PAGE_TYPE_ERROR,
547 NavigateAndGetPageType(get_resource_url("index.html")));
548 EXPECT_EQ(content::PAGE_TYPE_ERROR,
549 NavigateAndGetPageType(get_resource_url("other.html")));
550 EXPECT_EQ(content::PAGE_TYPE_ERROR,
551 NavigateAndGetPageType(get_resource_url("anotherother.html")));
552 EXPECT_EQ(content::PAGE_TYPE_ERROR,
553 NavigateAndGetPageType(get_resource_url("final.html")));
554}
555
556IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, BackgroundPageIsWokenIfAsleep) {
557 const Extension* extension =
558 StartTestFromBackgroundPage("wake_on_fetch.js", kExpectSuccess);
559
560 // Navigate to special URLs that this test's service worker recognises, each
561 // making a check then populating the response with either "true" or "false".
562 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
563 "background-client-is-awake")));
564 EXPECT_EQ("true", NavigateAndExtractInnerText(
565 extension->GetResourceURL("ping-background-client")));
566 // Ping more than once for good measure.
567 EXPECT_EQ("true", NavigateAndExtractInnerText(
568 extension->GetResourceURL("ping-background-client")));
569
570 // Shut down the event page. The SW should detect that it's closed, but still
571 // be able to ping it.
572 ExtensionHost* background_page =
573 process_manager()->GetBackgroundHostForExtension(extension->id());
574 ASSERT_TRUE(background_page);
575 background_page->Close();
576 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
577
578 EXPECT_EQ("false", NavigateAndExtractInnerText(extension->GetResourceURL(
579 "background-client-is-awake")));
580 EXPECT_EQ("true", NavigateAndExtractInnerText(
581 extension->GetResourceURL("ping-background-client")));
582 EXPECT_EQ("true", NavigateAndExtractInnerText(
583 extension->GetResourceURL("ping-background-client")));
584 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
585 "background-client-is-awake")));
586}
587
588IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
589 GetBackgroundClientFailsWithNoBackgroundPage) {
590 // This extension doesn't have a background page, only a tab at page.html.
591 // The service worker it registers tries to call getBackgroundClient() and
592 // should fail.
593 // Note that this also tests that service workers can be registered from tabs.
594 EXPECT_TRUE(RunExtensionSubtest("service_worker/no_background", "page.html"));
rdevlin.croninf5863da2015-09-10 19:21:45595}
596
lazyboy6ddb7d62015-11-10 23:15:27597IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, NotificationAPI) {
598 EXPECT_TRUE(RunExtensionSubtest("service_worker/notifications/has_permission",
599 "page.html"));
600}
601
lazyboyaea32c22016-01-04 21:37:07602IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, WebAccessibleResourcesFetch) {
603 EXPECT_TRUE(RunExtensionSubtest(
604 "service_worker/web_accessible_resources/fetch/", "page.html"));
605}
606
607// This test loads a web page that has an iframe pointing to a
608// chrome-extension:// URL. The URL is listed in the extension's
609// web_accessible_resources. Initially the iframe is served from the extension's
610// resource file. After verifying that, we register a Service Worker that
611// controls the extension. Further requests to the same resource as before
612// should now be served by the Service Worker.
613// This test also verifies that if the requested resource exists in the manifest
614// but is not present in the extension directory, the Service Worker can still
615// serve the resource file.
616IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, WebAccessibleResourcesIframeSrc) {
617 const Extension* extension = LoadExtensionWithFlags(
618 test_data_dir_.AppendASCII(
619 "service_worker/web_accessible_resources/iframe_src"),
620 kFlagNone);
621 ASSERT_TRUE(extension);
622 ASSERT_TRUE(StartEmbeddedTestServer());
623 GURL page_url = embedded_test_server()->GetURL(
624 "/extensions/api_test/service_worker/web_accessible_resources/"
625 "webpage.html");
626
627 content::WebContents* web_contents = AddTab(browser(), page_url);
628 std::string result;
629 // webpage.html will create an iframe pointing to a resource from |extension|.
630 // Expect the resource to be served by the extension.
631 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
632 web_contents, base::StringPrintf("window.testIframe('%s', 'iframe.html')",
633 extension->id().c_str()),
634 &result));
635 EXPECT_EQ("FROM_EXTENSION_RESOURCE", result);
636
637 ExtensionTestMessageListener service_worker_ready_listener("SW_READY", false);
638 EXPECT_TRUE(ExecuteScriptInBackgroundPageNoWait(
639 extension->id(), "window.registerServiceWorker()"));
640 EXPECT_TRUE(service_worker_ready_listener.WaitUntilSatisfied());
641
642 result.clear();
643 // webpage.html will create another iframe pointing to a resource from
644 // |extension| as before. But this time, the resource should be be served
645 // from the Service Worker.
646 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
647 web_contents, base::StringPrintf("window.testIframe('%s', 'iframe.html')",
648 extension->id().c_str()),
649 &result));
650 EXPECT_EQ("FROM_SW_RESOURCE", result);
651
652 result.clear();
653 // webpage.html will create yet another iframe pointing to a resource that
654 // exists in the extension manifest's web_accessible_resources, but is not
655 // present in the extension directory. Expect the resources of the iframe to
656 // be served by the Service Worker.
657 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
658 web_contents,
659 base::StringPrintf("window.testIframe('%s', 'iframe_non_existent.html')",
660 extension->id().c_str()),
661 &result));
662 EXPECT_EQ("FROM_SW_RESOURCE", result);
663}
664
lazyboybd325ae2015-11-18 21:35:26665IN_PROC_BROWSER_TEST_F(ServiceWorkerBackgroundSyncTest, Sync) {
666 const Extension* extension = LoadExtensionWithFlags(
667 test_data_dir_.AppendASCII("service_worker/sync"), kFlagNone);
668 ASSERT_TRUE(extension);
669 ui_test_utils::NavigateToURL(browser(),
670 extension->GetResourceURL("page.html"));
671 content::WebContents* web_contents =
672 browser()->tab_strip_model()->GetActiveWebContents();
673
674 // Prevent firing by going offline.
675 content::background_sync_test_util::SetOnline(web_contents, false);
676
677 ExtensionTestMessageListener sync_listener("SYNC: send-chats", false);
678 sync_listener.set_failure_message("FAIL");
679
680 std::string result;
681 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
682 web_contents, "window.runServiceWorker()", &result));
683 ASSERT_EQ("SERVICE_WORKER_READY", result);
684
685 EXPECT_FALSE(sync_listener.was_satisfied());
686 // Resume firing by going online.
687 content::background_sync_test_util::SetOnline(web_contents, true);
688 EXPECT_TRUE(sync_listener.WaitUntilSatisfied());
689}
690
horo1eeddde2015-11-19 05:59:25691IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
692 FetchFromContentScriptShouldNotGoToServiceWorkerOfPage) {
693 ASSERT_TRUE(StartEmbeddedTestServer());
694 GURL page_url = embedded_test_server()->GetURL(
695 "/extensions/api_test/service_worker/content_script_fetch/"
696 "controlled_page/index.html");
697 content::WebContents* tab =
698 browser()->tab_strip_model()->GetActiveWebContents();
699 ui_test_utils::NavigateToURL(browser(), page_url);
700 content::WaitForLoadStop(tab);
701
702 std::string value;
703 ASSERT_TRUE(
704 content::ExecuteScriptAndExtractString(tab, "register();", &value));
705 EXPECT_EQ("SW controlled", value);
706
707 ASSERT_TRUE(RunExtensionTest("service_worker/content_script_fetch"))
708 << message_;
709}
710
lazyboy561b7de2015-11-19 19:27:30711IN_PROC_BROWSER_TEST_F(ServiceWorkerPushMessagingTest, OnPush) {
712 const Extension* extension = LoadExtensionWithFlags(
713 test_data_dir_.AppendASCII("service_worker/push_messaging"), kFlagNone);
714 ASSERT_TRUE(extension);
715 GURL extension_url = extension->url();
716
717 ASSERT_NO_FATAL_FAILURE(GrantNotificationPermissionForTest(extension_url));
718
719 GURL url = extension->GetResourceURL("page.html");
720 ui_test_utils::NavigateToURL(browser(), url);
721
722 content::WebContents* web_contents =
723 browser()->tab_strip_model()->GetActiveWebContents();
724
725 // Start the ServiceWorker.
726 ExtensionTestMessageListener ready_listener("SERVICE_WORKER_READY", false);
727 ready_listener.set_failure_message("SERVICE_WORKER_FAILURE");
728 const char* kScript = "window.runServiceWorker()";
729 EXPECT_TRUE(content::ExecuteScript(web_contents->GetMainFrame(), kScript));
730 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
731
732 PushMessagingAppIdentifier app_identifier =
733 GetAppIdentifierForServiceWorkerRegistration(0LL, extension_url);
734 ASSERT_EQ(app_identifier.app_id(), gcm_service()->last_registered_app_id());
735 EXPECT_EQ("1234567890", gcm_service()->last_registered_sender_ids()[0]);
736
737 // Send a push message via gcm and expect the ServiceWorker to receive it.
738 ExtensionTestMessageListener push_message_listener("OK", false);
739 push_message_listener.set_failure_message("FAIL");
740 gcm::IncomingMessage message;
741 message.sender_id = "1234567890";
742 message.raw_data = "testdata";
743 message.decrypted = true;
744 push_service()->OnMessage(app_identifier.app_id(), message);
745 EXPECT_TRUE(push_message_listener.WaitUntilSatisfied());
746}
747
annekao38685502015-07-14 17:46:39748} // namespace extensions