diff options
Diffstat (limited to 'chrome/browser/extensions/wake_event_page_apitest.cc')
-rw-r--r-- | chrome/browser/extensions/wake_event_page_apitest.cc | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/chrome/browser/extensions/wake_event_page_apitest.cc b/chrome/browser/extensions/wake_event_page_apitest.cc new file mode 100644 index 0000000..456155e --- /dev/null +++ b/chrome/browser/extensions/wake_event_page_apitest.cc @@ -0,0 +1,242 @@ +// 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/scoped_observer.h" +#include "base/strings/string_util.h" +#include "base/strings/stringprintf.h" +#include "chrome/browser/extensions/extension_browsertest.h" +#include "chrome/browser/extensions/test_extension_dir.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/test/base/ui_test_utils.h" +#include "content/public/test/browser_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_test_message_listener.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 BackgroundPageWatcher : public ProcessManagerObserver { + public: + BackgroundPageWatcher(ProcessManager* process_manager, + const Extension* extension) + : process_manager_(process_manager), + extension_id_(extension->id()), + is_waiting_for_open_(false), + is_waiting_for_close_(false) {} + + // Returns when the background page is open. If the background page is + // already open, returns immediately. + void WaitForOpen() { WaitForOpenState(true); } + + // Returns when the background page is closed. If the background page is + // already closed, returns immediately. + void WaitForClose() { WaitForOpenState(false); } + + private: + // Returns when the background page has open state of |wait_for_open|. If the + // background page is already in that state, returns immediately. + void WaitForOpenState(bool wait_for_open) { + if (IsBackgroundPageOpen() == wait_for_open) + return; + ScopedObserver<ProcessManager, ProcessManagerObserver> observer(this); + observer.Add(process_manager_); + bool* flag = wait_for_open ? &is_waiting_for_open_ : &is_waiting_for_close_; + base::AutoReset<bool> set_flag(flag, true); + base::RunLoop run_loop; + base::AutoReset<base::Closure> set_quit_run_loop(&quit_run_loop_, + run_loop.QuitClosure()); + CHECK_EQ(wait_for_open, IsBackgroundPageOpen()); + } + + bool IsBackgroundPageOpen() { + return process_manager_->GetBackgroundHostForExtension(extension_id_) != + nullptr; + } + + void OnBackgroundHostCreated(ExtensionHost* host) override { + if (is_waiting_for_open_ && host->extension()->id() == extension_id_) + quit_run_loop_.Run(); + } + + void OnBackgroundHostClose(const std::string& extension_id) override { + if (is_waiting_for_close_ && extension_id == extension_id_) + quit_run_loop_.Run(); + } + + ProcessManager* const process_manager_; + const std::string extension_id_; + + base::Closure quit_run_loop_; + bool is_waiting_for_open_; + bool is_waiting_for_close_; + + DISALLOW_COPY_AND_ASSIGN(BackgroundPageWatcher); +}; + +class WakeEventPageTest : public ExtensionBrowserTest { + public: + WakeEventPageTest() {} + + 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()->InitializeAndWaitUntilReady()); + + GURL web_url = embedded_test_server()->GetURL("example.com", "/empty.html"); + host_resolver()->AddRule(web_url.host(), "127.0.0.1"); + + 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.unpacked_path()); + 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) + BackgroundPageWatcher(process_manager(), extension).WaitForOpen(); + + if (should_close) { + GetBackgroundPage(extension->id())->Close(); + BackgroundPageWatcher(process_manager(), extension).WaitForClose(); + EXPECT_FALSE(GetBackgroundPage(extension->id())); + } + + // Start a content script to wake up the background page, if it's closed. + { + ExtensionTestMessageListener listener(false /* will_reply */); + 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(false /* will_reply */); + 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()); } + + DISALLOW_COPY_AND_ASSIGN(WakeEventPageTest); +}; + +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 |