| // Copyright 2015 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <string> |
| |
| #include "base/auto_reset.h" |
| #include "base/run_loop.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/stringprintf.h" |
| #include "chrome/browser/extensions/extension_browsertest.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/test/base/ui_test_utils.h" |
| #include "content/public/test/browser_test.h" |
| #include "content/public/test/browser_test_utils.h" |
| #include "content/public/test/test_utils.h" |
| #include "extensions/browser/process_manager.h" |
| #include "extensions/browser/process_manager_observer.h" |
| #include "extensions/common/extension.h" |
| #include "extensions/test/extension_background_page_waiter.h" |
| #include "extensions/test/extension_test_message_listener.h" |
| #include "extensions/test/test_extension_dir.h" |
| #include "net/dns/mock_host_resolver.h" |
| #include "net/test/embedded_test_server/embedded_test_server.h" |
| |
| namespace extensions { |
| namespace { |
| |
| // manifest.json: |
| // |
| // This uses single quotes for brevity, which will be replaced by double quotes |
| // when installing the extension. |
| // |
| // Expects a single string replacement of the "background" property, including |
| // trailing comma, or nothing if there is no background page. |
| const char* kManifestJson = |
| "{\n" |
| " %s\n" |
| " 'content_scripts': [{\n" |
| " 'js': ['content_script.js'],\n" |
| " 'matches': ['<all_urls>'],\n" |
| " 'run_at': 'document_start'\n" |
| " }],\n" |
| " 'manifest_version': 2,\n" |
| " 'name': 'wake_event_page_apitest',\n" |
| " 'version': '1'\n" |
| "}\n"; |
| |
| // content_script.js: |
| // |
| // This content script just wakes the event page whenever it runs, then sends a |
| // chrome.test message with the result. |
| // |
| // Note: The wake-event-page function is exposed to content scripts via the |
| // chrome.test API for testing purposes only. In production its intended use |
| // case is from workers. |
| const char* kContentScriptJs = |
| "chrome.test.getWakeEventPage()(function(success) {\n" |
| " chrome.test.sendMessage(success ? 'success' : 'failure');\n" |
| "});\n"; |
| |
| class WakeEventPageTest : public ExtensionBrowserTest { |
| public: |
| WakeEventPageTest() {} |
| |
| WakeEventPageTest(const WakeEventPageTest&) = delete; |
| WakeEventPageTest& operator=(const WakeEventPageTest&) = delete; |
| |
| void SetUpOnMainThread() override { |
| ExtensionBrowserTest::SetUpOnMainThread(); |
| host_resolver()->AddRule("*", "127.0.0.1"); |
| } |
| |
| protected: |
| enum BackgroundPageConfiguration { EVENT, PERSISTENT, NONE }; |
| |
| void RunTest(bool expect_success, |
| BackgroundPageConfiguration bg_config, |
| bool should_close, |
| bool will_be_open) { |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| |
| GURL web_url = embedded_test_server()->GetURL("example.com", "/empty.html"); |
| |
| TestExtensionDir extension_dir; |
| { |
| std::string manifest_json; |
| switch (bg_config) { |
| case EVENT: |
| manifest_json = |
| base::StringPrintf(kManifestJson, |
| " 'background': {\n" |
| " 'persistent': false,\n" |
| " 'scripts': ['background.js']\n" |
| " },"); |
| break; |
| case PERSISTENT: |
| manifest_json = |
| base::StringPrintf(kManifestJson, |
| " 'background': {\n" |
| " 'persistent': true,\n" |
| " 'scripts': ['background.js']\n" |
| " },"); |
| break; |
| case NONE: |
| manifest_json = base::StringPrintf(kManifestJson, ""); |
| break; |
| } |
| base::ReplaceChars(manifest_json, "'", "\"", &manifest_json); |
| extension_dir.WriteManifest(manifest_json); |
| // Empty background page. Closing/opening it is driven by this test. |
| extension_dir.WriteFile(FILE_PATH_LITERAL("background.js"), ""); |
| extension_dir.WriteFile(FILE_PATH_LITERAL("content_script.js"), |
| kContentScriptJs); |
| } |
| |
| // Install the extension, then close its background page if desired. |
| const Extension* extension = LoadExtension(extension_dir.UnpackedPath()); |
| CHECK(extension); |
| |
| // Regardless of |will_be_open|, we haven't closed the background page yet, |
| // so it should always open if it exists. |
| if (bg_config != NONE) |
| ExtensionBackgroundPageWaiter(profile(), *extension) |
| .WaitForBackgroundOpen(); |
| |
| if (should_close) { |
| GetBackgroundPage(extension->id())->Close(); |
| ExtensionBackgroundPageWaiter(profile(), *extension) |
| .WaitForBackgroundClosed(); |
| EXPECT_FALSE(GetBackgroundPage(extension->id())); |
| } |
| |
| // Start a content script to wake up the background page, if it's closed. |
| { |
| ExtensionTestMessageListener listener; |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), web_url)); |
| ASSERT_TRUE(listener.WaitUntilSatisfied()); |
| EXPECT_EQ(expect_success ? "success" : "failure", listener.message()); |
| } |
| |
| EXPECT_EQ(will_be_open, GetBackgroundPage(extension->id()) != nullptr); |
| |
| // Run the content script again. The background page will be awaken iff |
| // |will_be_open| is true, but if not, this is a harmless no-op. |
| { |
| ExtensionTestMessageListener listener; |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), web_url)); |
| ASSERT_TRUE(listener.WaitUntilSatisfied()); |
| EXPECT_EQ(expect_success ? "success" : "failure", listener.message()); |
| } |
| |
| EXPECT_EQ(will_be_open, GetBackgroundPage(extension->id()) != nullptr); |
| } |
| |
| private: |
| ExtensionHost* GetBackgroundPage(const std::string& extension_id) { |
| return process_manager()->GetBackgroundHostForExtension(extension_id); |
| } |
| |
| ProcessManager* process_manager() { return ProcessManager::Get(profile()); } |
| }; |
| |
| IN_PROC_BROWSER_TEST_F(WakeEventPageTest, ClosedEventPage) { |
| RunTest(true /* expect_success */, EVENT, true /* should_close */, |
| true /* will_be_open */); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WakeEventPageTest, OpenEventPage) { |
| RunTest(true /* expect_success */, EVENT, false /* should_close */, |
| true /* will_be_open */); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WakeEventPageTest, ClosedPersistentBackgroundPage) { |
| // Note: this is an odd test, because persistent background pages aren't |
| // supposed to close. Extensions can close them with window.close() but why |
| // would they do that? Test it anyway. |
| RunTest(false /* expect_success */, PERSISTENT, true /* should_close */, |
| false /* will_be_open */); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WakeEventPageTest, OpenPersistentBackgroundPage) { |
| RunTest(true /* expect_success */, PERSISTENT, false /* should_close */, |
| true /* will_be_open */); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WakeEventPageTest, NoBackgroundPage) { |
| RunTest(false /* expect_success */, NONE, false /* should_close */, |
| false /* will_be_open */); |
| } |
| |
| } // namespace |
| } // namespace extensions |