| Index: chrome/browser/extensions/api/declarative_content/request_content_script_apitest.cc
|
| diff --git a/chrome/browser/extensions/api/declarative_content/request_content_script_apitest.cc b/chrome/browser/extensions/api/declarative_content/request_content_script_apitest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..0c9b717bc610df81037e2f86b8aa0da49ea9839d
|
| --- /dev/null
|
| +++ b/chrome/browser/extensions/api/declarative_content/request_content_script_apitest.cc
|
| @@ -0,0 +1,223 @@
|
| +// Copyright 2014 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 "base/files/file_path.h"
|
| +#include "base/macros.h"
|
| +#include "base/strings/stringprintf.h"
|
| +#include "chrome/browser/extensions/extension_browsertest.h"
|
| +#include "chrome/browser/extensions/extension_test_message_listener.h"
|
| +#include "chrome/browser/extensions/test_extension_dir.h"
|
| +#include "chrome/browser/ui/browser.h"
|
| +#include "chrome/browser/ui/tabs/tab_strip_model.h"
|
| +#include "chrome/test/base/ui_test_utils.h"
|
| +#include "content/public/test/browser_test_utils.h"
|
| +#include "net/test/embedded_test_server/embedded_test_server.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +namespace extensions {
|
| +
|
| +namespace {
|
| +
|
| +// Manifest permissions injected into |kManifest|:
|
| +const char* kPermissions[] = {
|
| + "*://*/*", // ALL
|
| + "http://127.0.0.1/*", // PARTICULAR
|
| + "http://nowhere.com/*" // NOWHERE
|
| +};
|
| +
|
| +// Script matchers for injected into |kBackgroundScriptSource|:
|
| +const char* kScriptMatchers[] = {
|
| + "{ pageUrl: { hostContains: '' } }", // ALL
|
| + "{ pageUrl: { hostEquals: '127.0.0.1' } }", // PARTICULAR
|
| + "{ pageUrl: { hostEquals: 'nowhere.com' } }" // NOWHERE
|
| +};
|
| +
|
| +enum PermissionOrMatcherType {
|
| + ALL = 0,
|
| + PARTICULAR,
|
| + NOWHERE
|
| +};
|
| +
|
| +// JSON/JS sources:
|
| +const char kManifest[] =
|
| + "{\n"
|
| + " \"name\": \"Test DeclarativeContentScript\",\n"
|
| + " \"manifest_version\": 2,\n"
|
| + " \"version\": \"1.0\",\n"
|
| + " \"description\": \"Test declarative content script interface\",\n"
|
| + " \"permissions\": [\"declarativeContent\", \"%s\"],\n"
|
| + " \"background\": {\n"
|
| + " \"scripts\": [\"background.js\"]\n"
|
| + " }\n"
|
| + "}\n";
|
| +const char kBackgroundScriptSource[] =
|
| + "var declarativeContent = chrome.declarativeContent;\n"
|
| + "var PageStateMatcher = declarativeContent.PageStateMatcher;\n"
|
| + "var RequestContentScript = declarativeContent.RequestContentScript;\n"
|
| + "var onPageChanged = declarativeContent.onPageChanged;\n"
|
| + "onPageChanged.removeRules(undefined, function() {\n"
|
| + " onPageChanged.addRules(\n"
|
| + " [{\n"
|
| + " conditions: [new PageStateMatcher(%s)],\n"
|
| + " actions: [new RequestContentScript({js: ['script.js']}\n"
|
| + " )]\n"
|
| + " }],\n"
|
| + " function(details) {\n"
|
| + " if (!chrome.runtime.lastError)\n"
|
| + " chrome.test.sendMessage('injection setup');\n"
|
| + " }\n"
|
| + " );\n"
|
| + "});\n";
|
| +const char kContentScriptSource[] =
|
| + "chrome.test.sendMessage('injection succeeded');\n";
|
| +
|
| +// Messages from scripts:
|
| +const char kInjectionSetup[] = "injection setup";
|
| +const char kInjectionSucceeded[] = "injection succeeded";
|
| +
|
| +// Runs all pending tasks in the renderer associated with |web_contents|.
|
| +// Returns true on success.
|
| +bool RunAllPendingInRenderer(content::WebContents* web_contents) {
|
| + // TODO(devlin): If too many tests start to need this, move it somewhere
|
| + // common.
|
| + // This is slight hack to achieve a RunPendingInRenderer() method. Since IPCs
|
| + // are sent synchronously, anything started prior to this method will finish
|
| + // before this method returns (as content::ExecuteScript() is synchronous).
|
| + return content::ExecuteScript(web_contents, "1 == 1;");
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +class RequestContentScriptAPITest : public ExtensionBrowserTest {
|
| + public:
|
| + RequestContentScriptAPITest();
|
| + virtual ~RequestContentScriptAPITest() {}
|
| +
|
| + // Performs script injection test on a common local URL using the given
|
| + // |manifest_permission| and |script_matcher|. Does not return until
|
| + // the renderer should have completed its task and any browser-side reactions
|
| + // have been cleared from the task queue.
|
| + testing::AssertionResult RunTest(PermissionOrMatcherType manifest_permission,
|
| + PermissionOrMatcherType script_matcher,
|
| + bool should_inject);
|
| +
|
| + private:
|
| + testing::AssertionResult CreateAndLoadExtension(
|
| + PermissionOrMatcherType manifest_permission,
|
| + PermissionOrMatcherType script_matcher);
|
| +
|
| + scoped_ptr<TestExtensionDir> test_extension_dir_;
|
| + const Extension* extension_;
|
| +};
|
| +
|
| +RequestContentScriptAPITest::RequestContentScriptAPITest()
|
| + : extension_(NULL) {}
|
| +
|
| +testing::AssertionResult RequestContentScriptAPITest::RunTest(
|
| + PermissionOrMatcherType manifest_permission,
|
| + PermissionOrMatcherType script_matcher,
|
| + bool should_inject) {
|
| + if (extension_)
|
| + UnloadExtension(extension_->id());
|
| + testing::AssertionResult result = CreateAndLoadExtension(manifest_permission,
|
| + script_matcher);
|
| + if (!result)
|
| + return result;
|
| +
|
| + // Setup listener for actual injection of script.
|
| + ExtensionTestMessageListener injection_succeeded_listener(
|
| + kInjectionSucceeded,
|
| + false /* won't reply */);
|
| + injection_succeeded_listener.set_extension_id(extension_->id());
|
| +
|
| + ui_test_utils::NavigateToURL(
|
| + browser(),
|
| + embedded_test_server()->GetURL("/extensions/test_file.html"));
|
| +
|
| + content::WebContents* web_contents =
|
| + browser() ? browser()->tab_strip_model()->GetActiveWebContents() : NULL;
|
| + if (!web_contents)
|
| + return testing::AssertionFailure() << "No web contents.";
|
| +
|
| + // Give the extension plenty of time to inject.
|
| + if (!RunAllPendingInRenderer(web_contents))
|
| + return testing::AssertionFailure() << "Could not run pending in renderer.";
|
| +
|
| + // Make sure all running tasks are complete.
|
| + content::RunAllPendingInMessageLoop();
|
| +
|
| + if (injection_succeeded_listener.was_satisfied() != should_inject) {
|
| + return testing::AssertionFailure()
|
| + << (should_inject ?
|
| + "Expected injection, but got none." :
|
| + "Expected no injection, but got one.");
|
| + }
|
| +
|
| + return testing::AssertionSuccess();
|
| +}
|
| +
|
| +testing::AssertionResult RequestContentScriptAPITest::CreateAndLoadExtension(
|
| + PermissionOrMatcherType manifest_permission,
|
| + PermissionOrMatcherType script_matcher) {
|
| + // Setup a listener to note when injection rules have been setup.
|
| + ExtensionTestMessageListener injection_setup_listener(
|
| + kInjectionSetup,
|
| + false /* won't reply */);
|
| +
|
| + std::string manifest = base::StringPrintf(kManifest,
|
| + kPermissions[manifest_permission]);
|
| + std::string background_src = base::StringPrintf(
|
| + kBackgroundScriptSource,
|
| + kScriptMatchers[script_matcher]);
|
| +
|
| + scoped_ptr<TestExtensionDir> dir(new TestExtensionDir);
|
| + dir->WriteManifest(manifest);
|
| + dir->WriteFile(FILE_PATH_LITERAL("background.js"), background_src);
|
| + dir->WriteFile(FILE_PATH_LITERAL("script.js"),
|
| + kContentScriptSource);
|
| +
|
| + const Extension* extension = LoadExtension(dir->unpacked_path());
|
| + if (!extension)
|
| + return testing::AssertionFailure() << "Failed to load extension.";
|
| +
|
| + test_extension_dir_.reset(dir.release());
|
| + extension_ = extension;
|
| +
|
| + // Wait for rules to be setup before navigating to trigger script injection.
|
| + injection_setup_listener.WaitUntilSatisfied();
|
| +
|
| + return testing::AssertionSuccess();
|
| +}
|
| +
|
| +
|
| +// Try different permutations of "match all", "match particular domain (that is
|
| +// visited by test)", and "match nonsense domain (not visited by test)" for
|
| +// both manifest permissions and injection matcher conditions.
|
| +IN_PROC_BROWSER_TEST_F(RequestContentScriptAPITest,
|
| + PermissionMatcherAgreementInjection) {
|
| + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
|
| +
|
| + // Positive tests: permissions and matcher contain conditions that match URL
|
| + // visited during test.
|
| + EXPECT_TRUE(RunTest(ALL, ALL, true));
|
| + EXPECT_TRUE(RunTest(ALL, PARTICULAR, true));
|
| + EXPECT_TRUE(RunTest(PARTICULAR, ALL, true));
|
| + EXPECT_TRUE(RunTest(PARTICULAR, PARTICULAR, true));
|
| +
|
| + // Negative tests: permissions or matcher (or both) contain conditions that
|
| + // do not match URL visited during test.
|
| + EXPECT_TRUE(RunTest(NOWHERE, ALL, false));
|
| + EXPECT_TRUE(RunTest(NOWHERE, PARTICULAR, false));
|
| + EXPECT_TRUE(RunTest(NOWHERE, NOWHERE, false));
|
| + EXPECT_TRUE(RunTest(ALL, NOWHERE, false));
|
| + EXPECT_TRUE(RunTest(PARTICULAR, NOWHERE, false));
|
| +
|
| + // TODO(markdittmer): Add more tests:
|
| + // - Inject script with multiple files
|
| + // - Inject multiple scripts
|
| + // - Match on CSS selector conditions
|
| + // - Match all frames in document containing frames
|
| +}
|
| +
|
| +} // namespace extensions
|
|
|