Index: chrome/browser/extensions/active_script_controller_browsertest.cc |
diff --git a/chrome/browser/extensions/active_script_controller_browsertest.cc b/chrome/browser/extensions/active_script_controller_browsertest.cc |
index 5be5b714ebf3ed821a0e460ea20e349849c76832..cd607ceb1b661a574202c052cd9e88f45b42cc86 100644 |
--- a/chrome/browser/extensions/active_script_controller_browsertest.cc |
+++ b/chrome/browser/extensions/active_script_controller_browsertest.cc |
@@ -18,6 +18,18 @@ |
namespace extensions { |
+namespace { |
+ |
+const char kInjectAttempted[] = "inject attempted"; |
+const char kInjectSucceeded[] = "inject succeeded"; |
+ |
+enum InjectionType { |
+ CONTENT_SCRIPT, |
+ EXECUTE_SCRIPT |
+}; |
+ |
+} // namespace |
+ |
class ActiveScriptControllerBrowserTest : public ExtensionBrowserTest { |
public: |
ActiveScriptControllerBrowserTest() |
@@ -31,7 +43,8 @@ class ActiveScriptTester { |
public: |
ActiveScriptTester(const std::string& name, |
const Extension* extension, |
- bool expect_has_action); |
+ bool requires_consent, |
+ InjectionType type); |
~ActiveScriptTester(); |
testing::AssertionResult Verify(Browser* browser); |
@@ -43,25 +56,39 @@ class ActiveScriptTester { |
// The extension associated with this tester. |
const Extension* extension_; |
- // Whether or not we expect the extension to have an action for script |
- // injection. |
- bool expect_has_action_; |
+ // Whether or not the extension has permission to run the script without |
+ // asking the user. |
+ bool requires_consent_; |
+ |
+ // The type of injection this tester uses. |
+ InjectionType type_; |
// All of these extensions should inject a script (either through content |
// scripts or through chrome.tabs.executeScript()) that sends a message with |
- // their names (for verification). |
- // Be prepared to wait for each extension to inject the script. |
- linked_ptr<ExtensionTestMessageListener> listener_; |
+ // the |kInjectSucceeded| message. |
+ linked_ptr<ExtensionTestMessageListener> inject_attempt_listener_; |
+ |
+ // After trying to inject the script, extensions sending the script via |
+ // chrome.tabs.executeScript() send a |kInjectAttempted| message. |
+ linked_ptr<ExtensionTestMessageListener> inject_success_listener_; |
}; |
ActiveScriptTester::ActiveScriptTester(const std::string& name, |
const Extension* extension, |
- bool expect_has_action) |
+ bool requires_consent, |
+ InjectionType type) |
: name_(name), |
extension_(extension), |
- expect_has_action_(expect_has_action), |
- listener_( |
- new ExtensionTestMessageListener(name, false /* won't reply */)) { |
+ requires_consent_(requires_consent), |
+ type_(type), |
+ inject_attempt_listener_( |
+ new ExtensionTestMessageListener(kInjectAttempted, |
+ false /* won't reply */)), |
+ inject_success_listener_( |
+ new ExtensionTestMessageListener(kInjectSucceeded, |
+ false /* won't reply */)) { |
+ inject_attempt_listener_->set_extension_id(extension->id()); |
+ inject_success_listener_->set_extension_id(extension->id()); |
} |
ActiveScriptTester::~ActiveScriptTester() { |
@@ -71,7 +98,17 @@ testing::AssertionResult ActiveScriptTester::Verify(Browser* browser) { |
if (!extension_) |
return testing::AssertionFailure() << "Could not load extension: " << name_; |
- listener_->WaitUntilSatisfied(); |
+ // If it's not a content script, the Extension lets us know when it has |
+ // attempted to inject the script. |
+ // This means there is a potential for a race condition with content scripts; |
+ // however, since they are all injected at document_start, this shouldn't be |
not at google - send to devlin
2014/05/15 00:12:36
document_start will be an issue actually. if you r
Devlin
2014/05/15 17:45:59
I think this one deserves a bit more thought.
So,
not at google - send to devlin
2014/05/15 18:26:55
I agree, it requires thought, and it's complex eno
|
+ // a problem. If these tests start failing, though, that might be it. |
+ if (type_ == EXECUTE_SCRIPT) |
+ inject_attempt_listener_->WaitUntilSatisfied(); |
+ |
+ // Make sure all running tasks are complete. |
not at google - send to devlin
2014/05/15 00:12:36
what tasks? the active script controller ones?
Devlin
2014/05/15 17:45:59
Yeah. Just making sure that if anything is runnin
|
+ content::RunAllPendingInMessageLoop(); |
+ |
content::WebContents* web_contents = |
browser ? browser->tab_strip_model()->GetActiveWebContents() : NULL; |
@@ -82,16 +119,59 @@ testing::AssertionResult ActiveScriptTester::Verify(Browser* browser) { |
if (!tab_helper) |
return testing::AssertionFailure() << "Could not find tab helper."; |
+ LocationBarController* location_bar_controller = |
+ tab_helper->location_bar_controller(); |
+ if (!location_bar_controller) { |
+ return testing::AssertionFailure() |
+ << "Could not find location bar controller"; |
+ } |
+ |
ActiveScriptController* controller = |
tab_helper->location_bar_controller()->active_script_controller(); |
not at google - send to devlin
2014/05/15 00:12:36
s/tab_helper->location_bar_controller()/location_b
Devlin
2014/05/15 17:45:59
Whoops, done.
|
if (!controller) |
return testing::AssertionFailure() << "Could not find controller."; |
bool has_action = controller->GetActionForExtension(extension_) != NULL; |
- if (expect_has_action_ != has_action) { |
+ |
+ // An extension should have an action displayed iff it requires user consent. |
+ if (requires_consent_ != has_action) { |
+ return testing::AssertionFailure() |
+ << "Improper action status for " << name_ << ": expected " |
+ << requires_consent_ << ", found " << has_action; |
+ } |
+ |
+ // If the extension has permission, we should be able to simply wait for it |
+ // to execute. |
+ if (!requires_consent_) { |
+ inject_success_listener_->WaitUntilSatisfied(); |
+ return testing::AssertionSuccess(); |
+ } |
+ |
+ // Otherwise, we don't have permission, and have to grant it. Ensure the |
+ // script has *not* already executed. |
+ // Currently, it's okay for content scripts to execute, because we don't |
+ // block them. |
+ // TODO(rdevlin.cronin): Fix this. |
+ if (inject_success_listener_->was_satisfied() && type_ != CONTENT_SCRIPT) { |
+ return testing::AssertionFailure() << |
+ name_ << "'s script ran without permission."; |
+ } |
+ |
+ ExtensionAction* action = controller->GetActionForExtension(extension_); |
+ // We've already verified this exists, so just a sanity check. |
+ DCHECK(action); |
not at google - send to devlin
2014/05/15 00:12:36
in theory the action could have disappeared, like
Devlin
2014/05/15 17:45:59
Actually... it can't.
After line 134 (when we che
|
+ |
+ // Grant permission by clicking on the extension action. |
+ location_bar_controller->OnClicked(action); |
+ |
+ // Now, the extension should be able to inject the script. |
+ inject_success_listener_->WaitUntilSatisfied(); |
+ |
+ // The Action should have disappeared. |
+ has_action = controller->GetActionForExtension(extension_) != NULL; |
not at google - send to devlin
2014/05/15 00:12:36
you do this a couple of times. how about a (privat
Devlin
2014/05/15 17:45:59
Done (though the end result is much longer).
|
+ if (has_action) { |
return testing::AssertionFailure() |
- << "Improper action status: expected " << expect_has_action_ |
- << ", found " << has_action; |
+ << "Extension " << name_ << " has lingering action."; |
} |
return testing::AssertionSuccess(); |
@@ -103,28 +183,40 @@ IN_PROC_BROWSER_TEST_F(ActiveScriptControllerBrowserTest, |
test_data_dir_.AppendASCII("active_script"); |
const char* kExtensionNames[] = { |
- "content_scripts_all_hosts", |
"inject_scripts_all_hosts", |
+ "inject_scripts_explicit_hosts", |
+ "content_scripts_all_hosts", |
"content_scripts_explicit_hosts" |
}; |
// First, we load up three extensions: |
- // - An extension with a content script that runs on all hosts, |
// - An extension that injects scripts into all hosts, |
+ // - An extension that injects scripts into explicit hosts, |
+ // - An extension with a content script that runs on all hosts, |
// - An extension with a content script that runs on explicit hosts. |
+ // The extensions that operate on explicit hosts have permission; the ones |
+ // that request all hosts require user consent. |
ActiveScriptTester testers[] = { |
ActiveScriptTester( |
kExtensionNames[0], |
LoadExtension(active_script_path.AppendASCII(kExtensionNames[0])), |
- true /* expect action */), |
+ true /* needs consent */, |
not at google - send to devlin
2014/05/15 00:12:36
how about making this an enum so you don't need to
Devlin
2014/05/15 17:45:59
The reason was because if statements like
if (re
|
+ EXECUTE_SCRIPT), |
ActiveScriptTester( |
kExtensionNames[1], |
LoadExtension(active_script_path.AppendASCII(kExtensionNames[1])), |
- true /* expect action */), |
+ false /* does not need consent */, |
+ EXECUTE_SCRIPT), |
ActiveScriptTester( |
kExtensionNames[2], |
LoadExtension(active_script_path.AppendASCII(kExtensionNames[2])), |
- false /* expect action */) |
+ true /* needs consent */, |
+ CONTENT_SCRIPT), |
+ ActiveScriptTester( |
+ kExtensionNames[3], |
+ LoadExtension(active_script_path.AppendASCII(kExtensionNames[3])), |
+ false /* does not need consent */, |
+ CONTENT_SCRIPT), |
}; |
// Navigate to an URL (which matches the explicit host specified in the |
@@ -135,7 +227,7 @@ IN_PROC_BROWSER_TEST_F(ActiveScriptControllerBrowserTest, |
browser(), embedded_test_server()->GetURL("/extensions/test_file.html")); |
for (size_t i = 0u; i < arraysize(testers); ++i) |
- ASSERT_TRUE(testers[i].Verify(browser())) << kExtensionNames[i]; |
+ EXPECT_TRUE(testers[i].Verify(browser())) << kExtensionNames[i]; |
} |
} // namespace extensions |