Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / active_script_controller_unittest.cc
index 0b40328..f40286b 100644 (file)
@@ -8,6 +8,7 @@
 #include "chrome/browser/extensions/active_script_controller.h"
 #include "chrome/browser/extensions/active_tab_permission_granter.h"
 #include "chrome/browser/extensions/extension_util.h"
+#include "chrome/browser/extensions/permissions_updater.h"
 #include "chrome/browser/extensions/tab_helper.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
@@ -20,6 +21,7 @@
 #include "extensions/common/feature_switch.h"
 #include "extensions/common/id_util.h"
 #include "extensions/common/manifest.h"
+#include "extensions/common/user_script.h"
 #include "extensions/common/value_builder.h"
 
 namespace extensions {
@@ -43,19 +45,28 @@ class ActiveScriptControllerUnitTest : public ChromeRenderViewHostTestHarness {
   // Creates an extension with all hosts permission and adds it to the registry.
   const Extension* AddExtension();
 
-  // Returns the current page id.
-  int GetPageId();
+  // Reloads |extension_| by removing it from the registry and recreating it.
+  const Extension* ReloadExtension();
 
-  // Returns a closure to use as a script execution for a given extension.
-  base::Closure GetExecutionCallbackForExtension(
-      const std::string& extension_id);
+  // Returns true if the |extension| requires user consent before injecting
+  // a script.
+  bool RequiresUserConsent(const Extension* extension) const;
+
+  // Request an injection for the given |extension|.
+  void RequestInjection(const Extension* extension);
 
   // Returns the number of times a given extension has had a script execute.
   size_t GetExecutionCountForExtension(const std::string& extension_id) const;
 
-  ActiveScriptController* controller() { return active_script_controller_; }
+  ActiveScriptController* controller() const {
+    return active_script_controller_;
+  }
 
  private:
+  // Returns a closure to use as a script execution for a given extension.
+  base::Closure GetExecutionCallbackForExtension(
+      const std::string& extension_id);
+
   // Increment the number of executions for the given |extension_id|.
   void IncrementExecutionCount(const std::string& extension_id);
 
@@ -70,6 +81,8 @@ class ActiveScriptControllerUnitTest : public ChromeRenderViewHostTestHarness {
 
   // The map of observed executions, keyed by extension id.
   std::map<std::string, int> extension_executions_;
+
+  scoped_refptr<const Extension> extension_;
 };
 
 ActiveScriptControllerUnitTest::ActiveScriptControllerUnitTest()
@@ -83,38 +96,44 @@ ActiveScriptControllerUnitTest::~ActiveScriptControllerUnitTest() {
 
 const Extension* ActiveScriptControllerUnitTest::AddExtension() {
   const std::string kId = id_util::GenerateId("all_hosts_extension");
-  scoped_refptr<const Extension> extension =
-      ExtensionBuilder()
-          .SetManifest(
-              DictionaryBuilder()
-                  .Set("name", "all_hosts_extension")
-                  .Set("description", "an extension")
-                  .Set("manifest_version", 2)
-                  .Set("version", "1.0.0")
-                  .Set("permissions",
-                       ListBuilder().Append(kAllHostsPermission)))
-          .SetLocation(Manifest::INTERNAL)
-          .SetID(kId)
-          .Build();
-
-  ExtensionRegistry::Get(profile())->AddEnabled(extension);
-  return extension;
+  extension_ = ExtensionBuilder()
+                   .SetManifest(
+                       DictionaryBuilder()
+                           .Set("name", "all_hosts_extension")
+                           .Set("description", "an extension")
+                           .Set("manifest_version", 2)
+                           .Set("version", "1.0.0")
+                           .Set("permissions",
+                                ListBuilder().Append(kAllHostsPermission)))
+                   .SetLocation(Manifest::INTERNAL)
+                   .SetID(kId)
+                   .Build();
+
+  ExtensionRegistry::Get(profile())->AddEnabled(extension_);
+  PermissionsUpdater(profile()).InitializePermissions(extension_);
+  return extension_;
 }
 
-int ActiveScriptControllerUnitTest::GetPageId() {
-  content::NavigationEntry* navigation_entry =
-      web_contents()->GetController().GetVisibleEntry();
-  DCHECK(navigation_entry);  // This should never be NULL.
-  return navigation_entry->GetPageID();
+const Extension* ActiveScriptControllerUnitTest::ReloadExtension() {
+  ExtensionRegistry::Get(profile())->RemoveEnabled(extension_->id());
+  return AddExtension();
 }
 
-base::Closure ActiveScriptControllerUnitTest::GetExecutionCallbackForExtension(
-    const std::string& extension_id) {
-  // We use base unretained here, but if this ever gets executed outside of
-  // this test's lifetime, we have a major problem anyway.
-  return base::Bind(&ActiveScriptControllerUnitTest::IncrementExecutionCount,
-                    base::Unretained(this),
-                    extension_id);
+bool ActiveScriptControllerUnitTest::RequiresUserConsent(
+    const Extension* extension) const {
+  PermissionsData::AccessType access_type =
+      controller()->RequiresUserConsentForScriptInjectionForTesting(
+          extension, UserScript::PROGRAMMATIC_SCRIPT);
+  // We should never downright refuse access in these tests.
+  DCHECK_NE(PermissionsData::ACCESS_DENIED, access_type);
+  return access_type == PermissionsData::ACCESS_WITHHELD;
+}
+
+void ActiveScriptControllerUnitTest::RequestInjection(
+    const Extension* extension) {
+  controller()->RequestScriptInjectionForTesting(
+      extension,
+      GetExecutionCallbackForExtension(extension->id()));
 }
 
 size_t ActiveScriptControllerUnitTest::GetExecutionCountForExtension(
@@ -126,6 +145,15 @@ size_t ActiveScriptControllerUnitTest::GetExecutionCountForExtension(
   return 0u;
 }
 
+base::Closure ActiveScriptControllerUnitTest::GetExecutionCallbackForExtension(
+    const std::string& extension_id) {
+  // We use base unretained here, but if this ever gets executed outside of
+  // this test's lifetime, we have a major problem anyway.
+  return base::Bind(&ActiveScriptControllerUnitTest::IncrementExecutionCount,
+                    base::Unretained(this),
+                    extension_id);
+}
+
 void ActiveScriptControllerUnitTest::IncrementExecutionCount(
     const std::string& extension_id) {
   ++extension_executions_[extension_id];
@@ -157,14 +185,10 @@ TEST_F(ActiveScriptControllerUnitTest, RequestPermissionAndExecute) {
   ASSERT_FALSE(controller()->GetActionForExtension(extension));
 
   // Since the extension requests all_hosts, we should require user consent.
-  EXPECT_TRUE(
-      controller()->RequiresUserConsentForScriptInjection(extension));
+  EXPECT_TRUE(RequiresUserConsent(extension));
 
   // Request an injection. There should be an action visible, but no executions.
-  controller()->RequestScriptInjection(
-      extension,
-      GetPageId(),
-      GetExecutionCallbackForExtension(extension->id()));
+  RequestInjection(extension);
   EXPECT_TRUE(controller()->GetActionForExtension(extension));
   EXPECT_EQ(0u, GetExecutionCountForExtension(extension->id()));
 
@@ -177,28 +201,22 @@ TEST_F(ActiveScriptControllerUnitTest, RequestPermissionAndExecute) {
 
   // Since we already executed on the given page, we shouldn't need permission
   // for a second time.
-  EXPECT_FALSE(
-      controller()->RequiresUserConsentForScriptInjection(extension));
+  EXPECT_FALSE(RequiresUserConsent(extension));
 
   // Reloading should clear those permissions, and we should again require user
   // consent.
   Reload();
-  EXPECT_TRUE(
-      controller()->RequiresUserConsentForScriptInjection(extension));
+  EXPECT_TRUE(RequiresUserConsent(extension));
 
   // Grant access.
-  controller()->RequestScriptInjection(
-      extension,
-      GetPageId(),
-      GetExecutionCallbackForExtension(extension->id()));
+  RequestInjection(extension);
   controller()->OnClicked(extension);
   EXPECT_EQ(2u, GetExecutionCountForExtension(extension->id()));
   EXPECT_FALSE(controller()->GetActionForExtension(extension));
 
   // Navigating to another site should also clear the permissions.
   NavigateAndCommit(GURL("https://www.foo.com"));
-  EXPECT_TRUE(
-      controller()->RequiresUserConsentForScriptInjection(extension));
+  EXPECT_TRUE(RequiresUserConsent(extension));
 }
 
 // Test that injections that are not executed by the time the user navigates are
@@ -212,10 +230,7 @@ TEST_F(ActiveScriptControllerUnitTest, PendingInjectionsRemovedAtNavigation) {
   ASSERT_EQ(0u, GetExecutionCountForExtension(extension->id()));
 
   // Request an injection. There should be an action visible, but no executions.
-  controller()->RequestScriptInjection(
-      extension,
-      GetPageId(),
-      GetExecutionCallbackForExtension(extension->id()));
+  RequestInjection(extension);
   EXPECT_TRUE(controller()->GetActionForExtension(extension));
   EXPECT_EQ(0u, GetExecutionCountForExtension(extension->id()));
 
@@ -226,10 +241,7 @@ TEST_F(ActiveScriptControllerUnitTest, PendingInjectionsRemovedAtNavigation) {
   EXPECT_EQ(0u, GetExecutionCountForExtension(extension->id()));
 
   // Request and accept a new injection.
-  controller()->RequestScriptInjection(
-      extension,
-      GetPageId(),
-      GetExecutionCallbackForExtension(extension->id()));
+  RequestInjection(extension);
   controller()->OnClicked(extension);
 
   // The extension should only have executed once, even though a grand total
@@ -249,12 +261,9 @@ TEST_F(ActiveScriptControllerUnitTest, MultiplePendingInjection) {
 
   const size_t kNumInjections = 3u;
   // Queue multiple pending injections.
-  for (size_t i = 0u; i < kNumInjections; ++i) {
-    controller()->RequestScriptInjection(
-        extension,
-        GetPageId(),
-        GetExecutionCallbackForExtension(extension->id()));
-  }
+  for (size_t i = 0u; i < kNumInjections; ++i)
+    RequestInjection(extension);
+
   EXPECT_EQ(0u, GetExecutionCountForExtension(extension->id()));
 
   controller()->OnClicked(extension);
@@ -278,17 +287,14 @@ TEST_F(ActiveScriptControllerUnitTest, ActiveScriptsUseActiveTabPermissions) {
 
   // Since we have active tab permissions, we shouldn't need user consent
   // anymore.
-  EXPECT_FALSE(controller()->RequiresUserConsentForScriptInjection(extension));
+  EXPECT_FALSE(RequiresUserConsent(extension));
 
   // Also test that granting active tab runs any pending tasks.
   Reload();
   // Navigating should mean we need permission again.
-  EXPECT_TRUE(controller()->RequiresUserConsentForScriptInjection(extension));
+  EXPECT_TRUE(RequiresUserConsent(extension));
 
-  controller()->RequestScriptInjection(
-      extension,
-      GetPageId(),
-      GetExecutionCallbackForExtension(extension->id()));
+  RequestInjection(extension);
   EXPECT_TRUE(controller()->GetActionForExtension(extension));
   EXPECT_EQ(0u, GetExecutionCountForExtension(extension->id()));
 
@@ -306,23 +312,80 @@ TEST_F(ActiveScriptControllerUnitTest, ActiveScriptsCanHaveAllUrlsPref) {
   ASSERT_TRUE(extension);
 
   NavigateAndCommit(GURL("https://www.google.com"));
-  EXPECT_TRUE(controller()->RequiresUserConsentForScriptInjection(extension));
+  EXPECT_TRUE(RequiresUserConsent(extension));
 
   // Enable the extension on all urls.
   util::SetAllowedScriptingOnAllUrls(extension->id(), profile(), true);
 
-  EXPECT_FALSE(controller()->RequiresUserConsentForScriptInjection(extension));
+  EXPECT_FALSE(RequiresUserConsent(extension));
   // This should carry across navigations, and websites.
   NavigateAndCommit(GURL("http://www.foo.com"));
-  EXPECT_FALSE(controller()->RequiresUserConsentForScriptInjection(extension));
+  EXPECT_FALSE(RequiresUserConsent(extension));
 
   // Turning off the preference should have instant effect.
   util::SetAllowedScriptingOnAllUrls(extension->id(), profile(), false);
-  EXPECT_TRUE(controller()->RequiresUserConsentForScriptInjection(extension));
+  EXPECT_TRUE(RequiresUserConsent(extension));
 
   // And should also persist across navigations and websites.
   NavigateAndCommit(GURL("http://www.bar.com"));
-  EXPECT_TRUE(controller()->RequiresUserConsentForScriptInjection(extension));
+  EXPECT_TRUE(RequiresUserConsent(extension));
+}
+
+TEST_F(ActiveScriptControllerUnitTest, TestAlwaysRun) {
+  const Extension* extension = AddExtension();
+  ASSERT_TRUE(extension);
+
+  NavigateAndCommit(GURL("https://www.google.com/?gws_rd=ssl"));
+
+  // Ensure that there aren't any executions pending.
+  ASSERT_EQ(0u, GetExecutionCountForExtension(extension->id()));
+  ASSERT_FALSE(controller()->GetActionForExtension(extension));
+
+  // Since the extension requests all_hosts, we should require user consent.
+  EXPECT_TRUE(RequiresUserConsent(extension));
+
+  // Request an injection. There should be an action visible, but no executions.
+  RequestInjection(extension);
+  EXPECT_TRUE(controller()->GetActionForExtension(extension));
+  EXPECT_EQ(0u, GetExecutionCountForExtension(extension->id()));
+
+  // Allow the extension to always run on this origin.
+  controller()->AlwaysRunOnVisibleOrigin(extension);
+
+  // The extension should execute, and the action should go away.
+  EXPECT_EQ(1u, GetExecutionCountForExtension(extension->id()));
+  EXPECT_FALSE(controller()->GetActionForExtension(extension));
+
+  // Since we already executed on the given page, we shouldn't need permission
+  // for a second time.
+  EXPECT_FALSE(RequiresUserConsent(extension));
+
+  // Navigating to another site that hasn't been granted a persisted permission
+  // should necessitate user consent.
+  NavigateAndCommit(GURL("https://www.foo.com/bar"));
+  EXPECT_TRUE(RequiresUserConsent(extension));
+
+  // We shouldn't need user permission upon returning to the original origin.
+  NavigateAndCommit(GURL("https://www.google.com/foo/bar"));
+  EXPECT_FALSE(RequiresUserConsent(extension));
+
+  // Reloading the extension should not clear any granted host permissions.
+  extension = ReloadExtension();
+  Reload();
+  EXPECT_FALSE(RequiresUserConsent(extension));
+
+  // Different host...
+  NavigateAndCommit(GURL("https://www.foo.com/bar"));
+  EXPECT_TRUE(RequiresUserConsent(extension));
+  // Different scheme...
+  NavigateAndCommit(GURL("http://www.google.com/foo/bar"));
+  EXPECT_TRUE(RequiresUserConsent(extension));
+  // Different subdomain...
+  NavigateAndCommit(GURL("https://en.google.com/foo/bar"));
+  EXPECT_TRUE(RequiresUserConsent(extension));
+  // Only the "always run" origin should be allowed to run without user consent.
+  NavigateAndCommit(GURL("https://www.google.com/foo/bar"));
+  EXPECT_FALSE(RequiresUserConsent(extension));
 }
 
 }  // namespace extensions