Chromium Code Reviews| 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 |