blob: 31e7091eef03081c352f0afb55e52fc7a5d57159 [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
kalman6f984ae2015-09-18 17:21:585#include "base/bind_helpers.h"
6#include "base/strings/stringprintf.h"
horo1eeddde2015-11-19 05:59:257#include "base/strings/utf_string_conversions.h"
annekao38685502015-07-14 17:46:398#include "chrome/browser/extensions/extension_apitest.h"
rdevlin.croninf5863da2015-09-10 19:21:459#include "chrome/browser/extensions/extension_service.h"
lazyboy561b7de2015-11-19 19:27:3010#include "chrome/browser/notifications/desktop_notification_profile_util.h"
11#include "chrome/browser/push_messaging/push_messaging_app_identifier.h"
12#include "chrome/browser/push_messaging/push_messaging_service_factory.h"
13#include "chrome/browser/push_messaging/push_messaging_service_impl.h"
14#include "chrome/browser/services/gcm/fake_gcm_profile_service.h"
15#include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
annekao1db36fd2015-07-29 17:09:1616#include "chrome/browser/ui/tabs/tab_strip_model.h"
rdevlin.croninf5863da2015-09-10 19:21:4517#include "chrome/test/base/ui_test_utils.h"
sdefresne9fb67692015-08-03 18:48:2218#include "components/version_info/version_info.h"
kalman6f984ae2015-09-18 17:21:5819#include "content/public/browser/navigation_controller.h"
rdevlin.croninf5863da2015-09-10 19:21:4520#include "content/public/browser/navigation_entry.h"
kalman6f984ae2015-09-18 17:21:5821#include "content/public/browser/web_contents.h"
lazyboybd325ae2015-11-18 21:35:2622#include "content/public/common/content_switches.h"
kalman6f984ae2015-09-18 17:21:5823#include "content/public/common/page_type.h"
lazyboybd325ae2015-11-18 21:35:2624#include "content/public/test/background_sync_test_util.h"
annekao1db36fd2015-07-29 17:09:1625#include "content/public/test/browser_test_utils.h"
kalman6f984ae2015-09-18 17:21:5826#include "extensions/browser/extension_host.h"
lazyboyc3e763a2015-12-09 23:09:5827#include "extensions/browser/extension_registry.h"
kalman6f984ae2015-09-18 17:21:5828#include "extensions/browser/process_manager.h"
29#include "extensions/test/background_page_watcher.h"
annekao38685502015-07-14 17:46:3930#include "extensions/test/extension_test_message_listener.h"
horo1eeddde2015-11-19 05:59:2531#include "net/test/embedded_test_server/embedded_test_server.h"
annekao38685502015-07-14 17:46:3932
33namespace extensions {
34
kalman6f984ae2015-09-18 17:21:5835namespace {
36
37// Pass into ServiceWorkerTest::StartTestFromBackgroundPage to indicate that
38// registration is expected to succeed.
39std::string* const kExpectSuccess = nullptr;
40
41void DoNothingWithBool(bool b) {}
42
lazyboy22eddc712015-12-10 21:16:2643// Returns the newly added WebContents.
44content::WebContents* AddTab(Browser* browser, const GURL& url) {
45 int starting_tab_count = browser->tab_strip_model()->count();
46 ui_test_utils::NavigateToURLWithDisposition(
47 browser, url, NEW_FOREGROUND_TAB,
48 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
49 int tab_count = browser->tab_strip_model()->count();
50 EXPECT_EQ(starting_tab_count + 1, tab_count);
51 return browser->tab_strip_model()->GetActiveWebContents();
52}
53
54class WebContentsLoadStopObserver : content::WebContentsObserver {
55 public:
56 explicit WebContentsLoadStopObserver(content::WebContents* web_contents)
57 : content::WebContentsObserver(web_contents),
58 load_stop_observed_(false) {}
59
60 void WaitForLoadStop() {
61 if (load_stop_observed_)
62 return;
63 message_loop_runner_ = new content::MessageLoopRunner;
64 message_loop_runner_->Run();
65 }
66
67 private:
68 void DidStopLoading() override {
69 load_stop_observed_ = true;
70 if (message_loop_runner_)
71 message_loop_runner_->Quit();
72 }
73
74 bool load_stop_observed_;
75 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
76
77 DISALLOW_COPY_AND_ASSIGN(WebContentsLoadStopObserver);
78};
79
kalman6f984ae2015-09-18 17:21:5880} // namespace
81
annekao38685502015-07-14 17:46:3982class ServiceWorkerTest : public ExtensionApiTest {
83 public:
kalman6f984ae2015-09-18 17:21:5884 ServiceWorkerTest() : current_channel_(version_info::Channel::UNKNOWN) {}
annekao38685502015-07-14 17:46:3985
86 ~ServiceWorkerTest() override {}
87
kalman6f984ae2015-09-18 17:21:5888 protected:
89 // Returns the ProcessManager for the test's profile.
90 ProcessManager* process_manager() { return ProcessManager::Get(profile()); }
91
92 // Starts running a test from the background page test extension.
93 //
94 // This registers a service worker with |script_name|, and fetches the
95 // registration result.
96 //
97 // If |error_or_null| is null (kExpectSuccess), success is expected and this
98 // will fail if there is an error.
99 // If |error_or_null| is not null, nothing is assumed, and the error (which
100 // may be empty) is written to it.
101 const Extension* StartTestFromBackgroundPage(const char* script_name,
102 std::string* error_or_null) {
103 const Extension* extension =
104 LoadExtension(test_data_dir_.AppendASCII("service_worker/background"));
105 CHECK(extension);
106 ExtensionHost* background_host =
107 process_manager()->GetBackgroundHostForExtension(extension->id());
108 CHECK(background_host);
109 std::string error;
110 CHECK(content::ExecuteScriptAndExtractString(
111 background_host->host_contents(),
112 base::StringPrintf("test.registerServiceWorker('%s')", script_name),
113 &error));
114 if (error_or_null)
115 *error_or_null = error;
116 else if (!error.empty())
117 ADD_FAILURE() << "Got unexpected error " << error;
118 return extension;
119 }
120
121 // Navigates the browser to a new tab at |url|, waits for it to load, then
122 // returns it.
123 content::WebContents* Navigate(const GURL& url) {
124 ui_test_utils::NavigateToURLWithDisposition(
125 browser(), url, NEW_FOREGROUND_TAB,
126 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
127 content::WebContents* web_contents =
128 browser()->tab_strip_model()->GetActiveWebContents();
129 content::WaitForLoadStop(web_contents);
130 return web_contents;
131 }
132
133 // Navigates the browser to |url| and returns the new tab's page type.
134 content::PageType NavigateAndGetPageType(const GURL& url) {
135 return Navigate(url)->GetController().GetActiveEntry()->GetPageType();
136 }
137
138 // Extracts the innerText from |contents|.
139 std::string ExtractInnerText(content::WebContents* contents) {
140 std::string inner_text;
141 if (!content::ExecuteScriptAndExtractString(
142 contents,
143 "window.domAutomationController.send(document.body.innerText)",
144 &inner_text)) {
145 ADD_FAILURE() << "Failed to get inner text for "
146 << contents->GetVisibleURL();
147 }
148 return inner_text;
149 }
150
151 // Navigates the browser to |url|, then returns the innerText of the new
152 // tab's WebContents' main frame.
153 std::string NavigateAndExtractInnerText(const GURL& url) {
154 return ExtractInnerText(Navigate(url));
155 }
156
annekao38685502015-07-14 17:46:39157 private:
kalman6f984ae2015-09-18 17:21:58158 // Sets the channel to "trunk" since service workers are restricted to trunk.
annekao38685502015-07-14 17:46:39159 ScopedCurrentChannel current_channel_;
kalman6f984ae2015-09-18 17:21:58160
annekao38685502015-07-14 17:46:39161 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerTest);
162};
163
lazyboybd325ae2015-11-18 21:35:26164class ServiceWorkerBackgroundSyncTest : public ServiceWorkerTest {
165 public:
166 ServiceWorkerBackgroundSyncTest() {}
167 ~ServiceWorkerBackgroundSyncTest() override {}
168
169 void SetUpCommandLine(base::CommandLine* command_line) override {
170 // ServiceWorkerRegistration.sync requires experimental flag.
171 command_line->AppendSwitch(
172 switches::kEnableExperimentalWebPlatformFeatures);
173 ServiceWorkerTest::SetUpCommandLine(command_line);
174 }
175
176 void SetUp() override {
177 content::background_sync_test_util::SetIgnoreNetworkChangeNotifier(true);
178 ServiceWorkerTest::SetUp();
179 }
180
181 private:
182 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerBackgroundSyncTest);
183};
184
lazyboy561b7de2015-11-19 19:27:30185class ServiceWorkerPushMessagingTest : public ServiceWorkerTest {
186 public:
187 ServiceWorkerPushMessagingTest()
188 : gcm_service_(nullptr), push_service_(nullptr) {}
189 ~ServiceWorkerPushMessagingTest() override {}
190
191 void GrantNotificationPermissionForTest(const GURL& url) {
192 GURL origin = url.GetOrigin();
193 DesktopNotificationProfileUtil::GrantPermission(profile(), origin);
194 ASSERT_EQ(
195 CONTENT_SETTING_ALLOW,
196 DesktopNotificationProfileUtil::GetContentSetting(profile(), origin));
197 }
198
199 PushMessagingAppIdentifier GetAppIdentifierForServiceWorkerRegistration(
200 int64 service_worker_registration_id,
201 const GURL& origin) {
202 PushMessagingAppIdentifier app_identifier =
203 PushMessagingAppIdentifier::FindByServiceWorker(
204 profile(), origin, service_worker_registration_id);
205
206 EXPECT_FALSE(app_identifier.is_null());
207 return app_identifier;
208 }
209
210 // ExtensionApiTest overrides.
211 void SetUpCommandLine(base::CommandLine* command_line) override {
peter9de96272015-12-04 15:23:27212 command_line->AppendSwitch(
213 switches::kEnableExperimentalWebPlatformFeatures);
lazyboy561b7de2015-11-19 19:27:30214 ServiceWorkerTest::SetUpCommandLine(command_line);
215 }
216 void SetUpOnMainThread() override {
217 gcm_service_ = static_cast<gcm::FakeGCMProfileService*>(
218 gcm::GCMProfileServiceFactory::GetInstance()->SetTestingFactoryAndUse(
219 profile(), &gcm::FakeGCMProfileService::Build));
220 gcm_service_->set_collect(true);
221 push_service_ = PushMessagingServiceFactory::GetForProfile(profile());
222
223 ServiceWorkerTest::SetUpOnMainThread();
224 }
225
226 gcm::FakeGCMProfileService* gcm_service() const { return gcm_service_; }
227 PushMessagingServiceImpl* push_service() const { return push_service_; }
228
229 private:
230 gcm::FakeGCMProfileService* gcm_service_;
231 PushMessagingServiceImpl* push_service_;
232
233 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerPushMessagingTest);
234};
235
kalman6f984ae2015-09-18 17:21:58236IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, RegisterSucceedsOnTrunk) {
237 StartTestFromBackgroundPage("register.js", kExpectSuccess);
annekao38685502015-07-14 17:46:39238}
239
240// This feature is restricted to trunk, so on dev it should have existing
241// behavior - which is for it to fail.
kalman6f984ae2015-09-18 17:21:58242IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, RegisterFailsOnDev) {
annekao38685502015-07-14 17:46:39243 ScopedCurrentChannel current_channel_override(
sdefresne6e883e42015-07-30 08:05:54244 version_info::Channel::DEV);
kalman6f984ae2015-09-18 17:21:58245 std::string error;
246 const Extension* extension =
247 StartTestFromBackgroundPage("register.js", &error);
annekao1db36fd2015-07-29 17:09:16248 EXPECT_EQ(
kalman6f984ae2015-09-18 17:21:58249 "Failed to register a ServiceWorker: The URL protocol of the current "
250 "origin ('chrome-extension://" +
251 extension->id() + "') is not supported.",
252 error);
annekao38685502015-07-14 17:46:39253}
254
lazyboyc3e763a2015-12-09 23:09:58255IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, UpdateRefreshesServiceWorker) {
256 base::ScopedTempDir scoped_temp_dir;
257 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
258 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
259 .AppendASCII("update")
260 .AppendASCII("service_worker.pem");
261 base::FilePath path_v1 = PackExtensionWithOptions(
262 test_data_dir_.AppendASCII("service_worker")
263 .AppendASCII("update")
264 .AppendASCII("v1"),
265 scoped_temp_dir.path().AppendASCII("v1.crx"), pem_path, base::FilePath());
266 base::FilePath path_v2 = PackExtensionWithOptions(
267 test_data_dir_.AppendASCII("service_worker")
268 .AppendASCII("update")
269 .AppendASCII("v2"),
270 scoped_temp_dir.path().AppendASCII("v2.crx"), pem_path, base::FilePath());
271 const char* kId = "hfaanndiiilofhfokeanhddpkfffchdi";
272
273 ExtensionTestMessageListener listener_v1("Pong from version 1", false);
274 listener_v1.set_failure_message("FAILURE_V1");
275 // Install version 1.0 of the extension.
276 ASSERT_TRUE(InstallExtension(path_v1, 1));
277 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
278 ->enabled_extensions()
279 .GetByID(kId));
280 EXPECT_TRUE(listener_v1.WaitUntilSatisfied());
281
282 ExtensionTestMessageListener listener_v2("Pong from version 2", false);
283 listener_v2.set_failure_message("FAILURE_V2");
284
285 // Update to version 2.0.
286 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
287 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
288 ->enabled_extensions()
289 .GetByID(kId));
290 EXPECT_TRUE(listener_v2.WaitUntilSatisfied());
291}
292
lazyboy22eddc712015-12-10 21:16:26293IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, UpdateWithoutSkipWaiting) {
294 base::ScopedTempDir scoped_temp_dir;
295 ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
296 base::FilePath pem_path = test_data_dir_.AppendASCII("service_worker")
297 .AppendASCII("update_without_skip_waiting")
298 .AppendASCII("update_without_skip_waiting.pem");
299 base::FilePath path_v1 = PackExtensionWithOptions(
300 test_data_dir_.AppendASCII("service_worker")
301 .AppendASCII("update_without_skip_waiting")
302 .AppendASCII("v1"),
303 scoped_temp_dir.path().AppendASCII("v1.crx"), pem_path, base::FilePath());
304 base::FilePath path_v2 = PackExtensionWithOptions(
305 test_data_dir_.AppendASCII("service_worker")
306 .AppendASCII("update_without_skip_waiting")
307 .AppendASCII("v2"),
308 scoped_temp_dir.path().AppendASCII("v2.crx"), pem_path, base::FilePath());
309 const char* kId = "mhnnnflgagdakldgjpfcofkiocpdmogl";
310
311 // Install version 1.0 of the extension.
312 ASSERT_TRUE(InstallExtension(path_v1, 1));
313 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
314 ->enabled_extensions()
315 .GetByID(kId));
316 const Extension* extension = extensions::ExtensionRegistry::Get(profile())
317 ->enabled_extensions()
318 .GetByID(kId);
319
320 ExtensionTestMessageListener listener1("Pong from version 1", false);
321 listener1.set_failure_message("FAILURE");
322 content::WebContents* web_contents =
323 AddTab(browser(), extension->GetResourceURL("page.html"));
324 EXPECT_TRUE(listener1.WaitUntilSatisfied());
325
326 // Update to version 2.0.
327 EXPECT_TRUE(UpdateExtension(kId, path_v2, 0));
328 EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())
329 ->enabled_extensions()
330 .GetByID(kId));
331 const Extension* extension_after_update =
332 extensions::ExtensionRegistry::Get(profile())
333 ->enabled_extensions()
334 .GetByID(kId);
335
336 // Service worker version 2 would be installed but it won't be controlling
337 // the extension page yet.
338 ExtensionTestMessageListener listener2("Pong from version 1", false);
339 listener2.set_failure_message("FAILURE");
340 web_contents =
341 AddTab(browser(), extension_after_update->GetResourceURL("page.html"));
342 EXPECT_TRUE(listener2.WaitUntilSatisfied());
343
344 // Navigate the tab away from the extension page so that no clients are
345 // using the service worker.
346 // Note that just closing the tab with WebContentsDestroyedWatcher doesn't
347 // seem to be enough because it returns too early.
348 WebContentsLoadStopObserver navigate_away_observer(web_contents);
349 web_contents->GetController().LoadURL(
350 GURL(url::kAboutBlankURL), content::Referrer(), ui::PAGE_TRANSITION_TYPED,
351 std::string());
352 navigate_away_observer.WaitForLoadStop();
353
354 // Now expect service worker version 2 to control the extension page.
355 ExtensionTestMessageListener listener3("Pong from version 2", false);
356 listener3.set_failure_message("FAILURE");
357 web_contents =
358 AddTab(browser(), extension_after_update->GetResourceURL("page.html"));
359 EXPECT_TRUE(listener3.WaitUntilSatisfied());
360}
361
kalman6f984ae2015-09-18 17:21:58362IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, FetchArbitraryPaths) {
363 const Extension* extension =
364 StartTestFromBackgroundPage("fetch.js", kExpectSuccess);
annekao1db36fd2015-07-29 17:09:16365
kalman6f984ae2015-09-18 17:21:58366 // Open some arbirary paths. Their contents should be what the service worker
367 // responds with, which in this case is the path of the fetch.
368 EXPECT_EQ(
369 "Caught a fetch for /index.html",
370 NavigateAndExtractInnerText(extension->GetResourceURL("index.html")));
371 EXPECT_EQ("Caught a fetch for /path/to/other.html",
372 NavigateAndExtractInnerText(
373 extension->GetResourceURL("path/to/other.html")));
374 EXPECT_EQ("Caught a fetch for /some/text/file.txt",
375 NavigateAndExtractInnerText(
376 extension->GetResourceURL("some/text/file.txt")));
377 EXPECT_EQ("Caught a fetch for /no/file/extension",
378 NavigateAndExtractInnerText(
379 extension->GetResourceURL("no/file/extension")));
380 EXPECT_EQ("Caught a fetch for /",
381 NavigateAndExtractInnerText(extension->GetResourceURL("")));
annekao1db36fd2015-07-29 17:09:16382}
383
kalman6f984ae2015-09-18 17:21:58384IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
385 LoadingBackgroundPageBypassesServiceWorker) {
386 const Extension* extension =
387 StartTestFromBackgroundPage("fetch.js", kExpectSuccess);
annekao49241182015-08-18 17:14:01388
kalman6f984ae2015-09-18 17:21:58389 std::string kExpectedInnerText = "background.html contents for testing.";
annekao49241182015-08-18 17:14:01390
kalman6f984ae2015-09-18 17:21:58391 // Sanity check that the background page has the expected content.
392 ExtensionHost* background_page =
393 process_manager()->GetBackgroundHostForExtension(extension->id());
394 ASSERT_TRUE(background_page);
395 EXPECT_EQ(kExpectedInnerText,
396 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:01397
kalman6f984ae2015-09-18 17:21:58398 // Close the background page.
399 background_page->Close();
400 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
401 background_page = nullptr;
402
403 // Start it again.
404 process_manager()->WakeEventPage(extension->id(),
405 base::Bind(&DoNothingWithBool));
406 BackgroundPageWatcher(process_manager(), extension).WaitForOpen();
407
408 // Content should not have been affected by the fetch, which would otherwise
409 // be "Caught fetch for...".
410 background_page =
411 process_manager()->GetBackgroundHostForExtension(extension->id());
412 ASSERT_TRUE(background_page);
413 content::WaitForLoadStop(background_page->host_contents());
414
415 // TODO(kalman): Everything you've read has been a LIE! It should be:
416 //
417 // EXPECT_EQ(kExpectedInnerText,
418 // ExtractInnerText(background_page->host_contents()));
419 //
420 // but there is a bug, and we're actually *not* bypassing the service worker
421 // for background page loads! For now, let it pass (assert wrong behavior)
422 // because it's not a regression, but this must be fixed eventually.
423 //
424 // Tracked in crbug.com/532720.
425 EXPECT_EQ("Caught a fetch for /background.html",
426 ExtractInnerText(background_page->host_contents()));
annekao49241182015-08-18 17:14:01427}
428
kalman6f984ae2015-09-18 17:21:58429IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
430 ServiceWorkerPostsMessageToBackgroundClient) {
431 const Extension* extension = StartTestFromBackgroundPage(
432 "post_message_to_background_client.js", kExpectSuccess);
annekao533482222015-08-21 23:23:53433
kalman6f984ae2015-09-18 17:21:58434 // The service worker in this test simply posts a message to the background
435 // client it receives from getBackgroundClient().
436 const char* kScript =
437 "var messagePromise = null;\n"
438 "if (test.lastMessageFromServiceWorker) {\n"
439 " messagePromise = Promise.resolve(test.lastMessageFromServiceWorker);\n"
440 "} else {\n"
441 " messagePromise = test.waitForMessage(navigator.serviceWorker);\n"
442 "}\n"
443 "messagePromise.then(function(message) {\n"
444 " window.domAutomationController.send(String(message == 'success'));\n"
445 "})\n";
446 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:53447}
448
kalman6f984ae2015-09-18 17:21:58449IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
450 BackgroundPagePostsMessageToServiceWorker) {
451 const Extension* extension =
452 StartTestFromBackgroundPage("post_message_to_sw.js", kExpectSuccess);
annekao533482222015-08-21 23:23:53453
kalman6f984ae2015-09-18 17:21:58454 // The service worker in this test waits for a message, then echoes it back
455 // by posting a message to the background page via getBackgroundClient().
456 const char* kScript =
457 "var mc = new MessageChannel();\n"
458 "test.waitForMessage(mc.port1).then(function(message) {\n"
459 " window.domAutomationController.send(String(message == 'hello'));\n"
460 "});\n"
461 "test.registeredServiceWorker.postMessage(\n"
462 " {message: 'hello', port: mc.port2}, [mc.port2])\n";
463 EXPECT_EQ("true", ExecuteScriptInBackgroundPage(extension->id(), kScript));
annekao533482222015-08-21 23:23:53464}
465
rdevlin.croninf5863da2015-09-10 19:21:45466IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
467 ServiceWorkerSuspensionOnExtensionUnload) {
kalman6f984ae2015-09-18 17:21:58468 // For this test, only hold onto the extension's ID and URL + a function to
469 // get a resource URL, because we're going to be disabling and uninstalling
470 // it, which will invalidate the pointer.
471 std::string extension_id;
472 GURL extension_url;
473 {
474 const Extension* extension =
475 StartTestFromBackgroundPage("fetch.js", kExpectSuccess);
476 extension_id = extension->id();
477 extension_url = extension->url();
478 }
479 auto get_resource_url = [&extension_url](const std::string& path) {
480 return Extension::GetResourceURL(extension_url, path);
481 };
rdevlin.croninf5863da2015-09-10 19:21:45482
kalman6f984ae2015-09-18 17:21:58483 // Fetch should route to the service worker.
484 EXPECT_EQ("Caught a fetch for /index.html",
485 NavigateAndExtractInnerText(get_resource_url("index.html")));
rdevlin.croninf5863da2015-09-10 19:21:45486
kalman6f984ae2015-09-18 17:21:58487 // Disable the extension. Opening the page should fail.
488 extension_service()->DisableExtension(extension_id,
rdevlin.croninf5863da2015-09-10 19:21:45489 Extension::DISABLE_USER_ACTION);
490 base::RunLoop().RunUntilIdle();
rdevlin.croninf5863da2015-09-10 19:21:45491
kalman6f984ae2015-09-18 17:21:58492 EXPECT_EQ(content::PAGE_TYPE_ERROR,
493 NavigateAndGetPageType(get_resource_url("index.html")));
494 EXPECT_EQ(content::PAGE_TYPE_ERROR,
495 NavigateAndGetPageType(get_resource_url("other.html")));
496
497 // Re-enable the extension. Opening pages should immediately start to succeed
498 // again.
rdevlin.croninf5863da2015-09-10 19:21:45499 extension_service()->EnableExtension(extension_id);
500 base::RunLoop().RunUntilIdle();
501
kalman6f984ae2015-09-18 17:21:58502 EXPECT_EQ("Caught a fetch for /index.html",
503 NavigateAndExtractInnerText(get_resource_url("index.html")));
504 EXPECT_EQ("Caught a fetch for /other.html",
505 NavigateAndExtractInnerText(get_resource_url("other.html")));
506 EXPECT_EQ("Caught a fetch for /another.html",
507 NavigateAndExtractInnerText(get_resource_url("another.html")));
rdevlin.croninf5863da2015-09-10 19:21:45508
kalman6f984ae2015-09-18 17:21:58509 // Uninstall the extension. Opening pages should fail again.
510 base::string16 error;
511 extension_service()->UninstallExtension(
512 extension_id, UninstallReason::UNINSTALL_REASON_FOR_TESTING,
513 base::Bind(&base::DoNothing), &error);
514 base::RunLoop().RunUntilIdle();
515
516 EXPECT_EQ(content::PAGE_TYPE_ERROR,
517 NavigateAndGetPageType(get_resource_url("index.html")));
518 EXPECT_EQ(content::PAGE_TYPE_ERROR,
519 NavigateAndGetPageType(get_resource_url("other.html")));
520 EXPECT_EQ(content::PAGE_TYPE_ERROR,
521 NavigateAndGetPageType(get_resource_url("anotherother.html")));
522 EXPECT_EQ(content::PAGE_TYPE_ERROR,
523 NavigateAndGetPageType(get_resource_url("final.html")));
524}
525
526IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, BackgroundPageIsWokenIfAsleep) {
527 const Extension* extension =
528 StartTestFromBackgroundPage("wake_on_fetch.js", kExpectSuccess);
529
530 // Navigate to special URLs that this test's service worker recognises, each
531 // making a check then populating the response with either "true" or "false".
532 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
533 "background-client-is-awake")));
534 EXPECT_EQ("true", NavigateAndExtractInnerText(
535 extension->GetResourceURL("ping-background-client")));
536 // Ping more than once for good measure.
537 EXPECT_EQ("true", NavigateAndExtractInnerText(
538 extension->GetResourceURL("ping-background-client")));
539
540 // Shut down the event page. The SW should detect that it's closed, but still
541 // be able to ping it.
542 ExtensionHost* background_page =
543 process_manager()->GetBackgroundHostForExtension(extension->id());
544 ASSERT_TRUE(background_page);
545 background_page->Close();
546 BackgroundPageWatcher(process_manager(), extension).WaitForClose();
547
548 EXPECT_EQ("false", NavigateAndExtractInnerText(extension->GetResourceURL(
549 "background-client-is-awake")));
550 EXPECT_EQ("true", NavigateAndExtractInnerText(
551 extension->GetResourceURL("ping-background-client")));
552 EXPECT_EQ("true", NavigateAndExtractInnerText(
553 extension->GetResourceURL("ping-background-client")));
554 EXPECT_EQ("true", NavigateAndExtractInnerText(extension->GetResourceURL(
555 "background-client-is-awake")));
556}
557
558IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
559 GetBackgroundClientFailsWithNoBackgroundPage) {
560 // This extension doesn't have a background page, only a tab at page.html.
561 // The service worker it registers tries to call getBackgroundClient() and
562 // should fail.
563 // Note that this also tests that service workers can be registered from tabs.
564 EXPECT_TRUE(RunExtensionSubtest("service_worker/no_background", "page.html"));
rdevlin.croninf5863da2015-09-10 19:21:45565}
566
lazyboy6ddb7d62015-11-10 23:15:27567IN_PROC_BROWSER_TEST_F(ServiceWorkerTest, NotificationAPI) {
568 EXPECT_TRUE(RunExtensionSubtest("service_worker/notifications/has_permission",
569 "page.html"));
570}
571
lazyboybd325ae2015-11-18 21:35:26572IN_PROC_BROWSER_TEST_F(ServiceWorkerBackgroundSyncTest, Sync) {
573 const Extension* extension = LoadExtensionWithFlags(
574 test_data_dir_.AppendASCII("service_worker/sync"), kFlagNone);
575 ASSERT_TRUE(extension);
576 ui_test_utils::NavigateToURL(browser(),
577 extension->GetResourceURL("page.html"));
578 content::WebContents* web_contents =
579 browser()->tab_strip_model()->GetActiveWebContents();
580
581 // Prevent firing by going offline.
582 content::background_sync_test_util::SetOnline(web_contents, false);
583
584 ExtensionTestMessageListener sync_listener("SYNC: send-chats", false);
585 sync_listener.set_failure_message("FAIL");
586
587 std::string result;
588 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
589 web_contents, "window.runServiceWorker()", &result));
590 ASSERT_EQ("SERVICE_WORKER_READY", result);
591
592 EXPECT_FALSE(sync_listener.was_satisfied());
593 // Resume firing by going online.
594 content::background_sync_test_util::SetOnline(web_contents, true);
595 EXPECT_TRUE(sync_listener.WaitUntilSatisfied());
596}
597
horo1eeddde2015-11-19 05:59:25598IN_PROC_BROWSER_TEST_F(ServiceWorkerTest,
599 FetchFromContentScriptShouldNotGoToServiceWorkerOfPage) {
600 ASSERT_TRUE(StartEmbeddedTestServer());
601 GURL page_url = embedded_test_server()->GetURL(
602 "/extensions/api_test/service_worker/content_script_fetch/"
603 "controlled_page/index.html");
604 content::WebContents* tab =
605 browser()->tab_strip_model()->GetActiveWebContents();
606 ui_test_utils::NavigateToURL(browser(), page_url);
607 content::WaitForLoadStop(tab);
608
609 std::string value;
610 ASSERT_TRUE(
611 content::ExecuteScriptAndExtractString(tab, "register();", &value));
612 EXPECT_EQ("SW controlled", value);
613
614 ASSERT_TRUE(RunExtensionTest("service_worker/content_script_fetch"))
615 << message_;
616}
617
lazyboy561b7de2015-11-19 19:27:30618IN_PROC_BROWSER_TEST_F(ServiceWorkerPushMessagingTest, OnPush) {
619 const Extension* extension = LoadExtensionWithFlags(
620 test_data_dir_.AppendASCII("service_worker/push_messaging"), kFlagNone);
621 ASSERT_TRUE(extension);
622 GURL extension_url = extension->url();
623
624 ASSERT_NO_FATAL_FAILURE(GrantNotificationPermissionForTest(extension_url));
625
626 GURL url = extension->GetResourceURL("page.html");
627 ui_test_utils::NavigateToURL(browser(), url);
628
629 content::WebContents* web_contents =
630 browser()->tab_strip_model()->GetActiveWebContents();
631
632 // Start the ServiceWorker.
633 ExtensionTestMessageListener ready_listener("SERVICE_WORKER_READY", false);
634 ready_listener.set_failure_message("SERVICE_WORKER_FAILURE");
635 const char* kScript = "window.runServiceWorker()";
636 EXPECT_TRUE(content::ExecuteScript(web_contents->GetMainFrame(), kScript));
637 EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
638
639 PushMessagingAppIdentifier app_identifier =
640 GetAppIdentifierForServiceWorkerRegistration(0LL, extension_url);
641 ASSERT_EQ(app_identifier.app_id(), gcm_service()->last_registered_app_id());
642 EXPECT_EQ("1234567890", gcm_service()->last_registered_sender_ids()[0]);
643
644 // Send a push message via gcm and expect the ServiceWorker to receive it.
645 ExtensionTestMessageListener push_message_listener("OK", false);
646 push_message_listener.set_failure_message("FAIL");
647 gcm::IncomingMessage message;
648 message.sender_id = "1234567890";
649 message.raw_data = "testdata";
650 message.decrypted = true;
651 push_service()->OnMessage(app_identifier.app_id(), message);
652 EXPECT_TRUE(push_message_listener.WaitUntilSatisfied());
653}
654
annekao38685502015-07-14 17:46:39655} // namespace extensions