diff options
-rw-r--r-- | chrome/browser/automation/automation_extension_function.cc | 13 | ||||
-rw-r--r-- | chrome/browser/automation/automation_extension_function.h | 12 | ||||
-rw-r--r-- | chrome/browser/automation/automation_provider.cc | 5 | ||||
-rw-r--r-- | chrome/browser/automation/automation_provider.h | 3 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_uitest.cc | 27 | ||||
-rw-r--r-- | chrome/test/automation/automation_messages_internal.h | 7 | ||||
-rw-r--r-- | chrome/test/automation/automation_proxy.cc | 5 | ||||
-rw-r--r-- | chrome/test/automation/automation_proxy.h | 15 | ||||
-rw-r--r-- | chrome_frame/chrome_frame_activex.cc | 13 | ||||
-rw-r--r-- | chrome_frame/chrome_frame_automation.cc | 4 | ||||
-rw-r--r-- | chrome_frame/chrome_frame_automation.h | 11 | ||||
-rw-r--r-- | chrome_frame/chrome_frame_npapi.cc | 11 | ||||
-rw-r--r-- | chrome_frame/chrome_frame_npapi_unittest.cc | 7 | ||||
-rw-r--r-- | chrome_frame/chrome_frame_plugin.h | 9 | ||||
-rw-r--r-- | chrome_frame/chrome_tab.idl | 5 | ||||
-rw-r--r-- | chrome_frame/test/chrome_frame_unittests.cc | 3 |
16 files changed, 118 insertions, 32 deletions
diff --git a/chrome/browser/automation/automation_extension_function.cc b/chrome/browser/automation/automation_extension_function.cc index 4bbc89f..70e886a 100644 --- a/chrome/browser/automation/automation_extension_function.cc +++ b/chrome/browser/automation/automation_extension_function.cc @@ -51,10 +51,15 @@ ExtensionFunction* AutomationExtensionFunction::Factory() { return new AutomationExtensionFunction(); } -void AutomationExtensionFunction::SetEnabled(bool enabled) { - if (enabled) { +void AutomationExtensionFunction::SetEnabled( + const std::vector<std::string>& functions_enabled) { + if (functions_enabled.size() > 0) { std::vector<std::string> function_names; - ExtensionFunctionDispatcher::GetAllFunctionNames(&function_names); + if (functions_enabled.size() == 1 && functions_enabled[0] == "*") { + ExtensionFunctionDispatcher::GetAllFunctionNames(&function_names); + } else { + function_names = functions_enabled; + } for (std::vector<std::string>::iterator it = function_names.begin(); it != function_names.end(); it++) { @@ -64,7 +69,7 @@ void AutomationExtensionFunction::SetEnabled(bool enabled) { // current profile is not that. bool result = ExtensionFunctionDispatcher::OverrideFunction( *it, AutomationExtensionFunction::Factory); - DCHECK(result); + LOG_IF(WARNING, !result) << "Failed to override API function: " << *it; } } else { ExtensionFunctionDispatcher::ResetFunctions(); diff --git a/chrome/browser/automation/automation_extension_function.h b/chrome/browser/automation/automation_extension_function.h index f48adff..d6fac7d 100644 --- a/chrome/browser/automation/automation_extension_function.h +++ b/chrome/browser/automation/automation_extension_function.h @@ -27,10 +27,14 @@ class AutomationExtensionFunction : public ExtensionFunction { static ExtensionFunction* Factory(); - // If enabled, we set an instance of this function as the functor - // for all function names in ExtensionFunctionFactoryRegistry. - // If disabled, we restore the initial functions. - static void SetEnabled(bool enabled); + // If the list of enabled functions is non-empty, we enable according to the + // list ("*" means enable all, otherwise we enable individual named + // functions). If empty, we restore the initial functions. + // + // Note that all calls to this function, except a call with the empty list, + // are additive. Functions previously enabled will remain enabled until + // you clear all function forwarding by specifying the empty list. + static void SetEnabled(const std::vector<std::string>& functions_enabled); // Intercepts messages sent from the external host to check if they // are actually responses to extension API calls. If they are, redirects diff --git a/chrome/browser/automation/automation_provider.cc b/chrome/browser/automation/automation_provider.cc index 891b6b7..c28322f 100644 --- a/chrome/browser/automation/automation_provider.cc +++ b/chrome/browser/automation/automation_provider.cc @@ -1901,8 +1901,9 @@ void AutomationProvider::SavePackageShouldPromptUser(bool should_prompt) { SavePackage::SetShouldPromptUser(should_prompt); } -void AutomationProvider::SetEnableExtensionAutomation(bool automation_enabled) { - AutomationExtensionFunction::SetEnabled(automation_enabled); +void AutomationProvider::SetEnableExtensionAutomation( + const std::vector<std::string>& functions_enabled) { + AutomationExtensionFunction::SetEnabled(functions_enabled); } void AutomationProvider::GetWindowTitle(int handle, string16* text) { diff --git a/chrome/browser/automation/automation_provider.h b/chrome/browser/automation/automation_provider.h index 1b5ee7d..44ee790 100644 --- a/chrome/browser/automation/automation_provider.h +++ b/chrome/browser/automation/automation_provider.h @@ -456,7 +456,8 @@ class AutomationProvider : public base::RefCounted<AutomationProvider>, void SavePackageShouldPromptUser(bool should_prompt); // Enables extension automation (for e.g. UITests). - void SetEnableExtensionAutomation(bool automation_enabled); + void SetEnableExtensionAutomation( + const std::vector<std::string>& functions_enabled); void GetWindowTitle(int handle, string16* text); diff --git a/chrome/browser/extensions/extension_uitest.cc b/chrome/browser/extensions/extension_uitest.cc index 5972f9e..4a16cc8 100644 --- a/chrome/browser/extensions/extension_uitest.cc +++ b/chrome/browser/extensions/extension_uitest.cc @@ -33,6 +33,10 @@ static const char kTestDirectoryBrowserEvent[] = // extension API calls so that behavior can be tested deterministically // through code, instead of having to contort the browser into a state // suitable for testing. +// +// By default, makes Chrome forward all Chrome Extension API function calls +// via the automation interface. To override this, call set_functions_enabled() +// with a list of function names that should be forwarded, template <class ParentTestType> class ExtensionUITest : public ParentTestType { public: @@ -41,15 +45,21 @@ class ExtensionUITest : public ParentTestType { filename = filename.AppendASCII(extension_path); launch_arguments_.AppendSwitchWithValue(switches::kLoadExtension, filename.value()); + functions_enabled_.push_back("*"); + } + + void set_functions_enabled( + const std::vector<std::string>& functions_enabled) { + functions_enabled_ = functions_enabled; } void SetUp() { ParentTestType::SetUp(); - automation()->SetEnableExtensionAutomation(true); + automation()->SetEnableExtensionAutomation(functions_enabled_); } void TearDown() { - automation()->SetEnableExtensionAutomation(false); + automation()->SetEnableExtensionAutomation(std::vector<std::string>()); ParentTestType::TearDown(); } @@ -84,6 +94,10 @@ class ExtensionUITest : public ParentTestType { virtual void DoAdditionalPreNavigateSetup(TabProxy* tab) { } + protected: + // Extension API functions that we want to take over. Defaults to all. + std::vector<std::string> functions_enabled_; + private: DISALLOW_COPY_AND_ASSIGN(ExtensionUITest); }; @@ -103,6 +117,15 @@ class SimpleApiCallExtensionTest : public SingleMessageExtensionUITest { : SingleMessageExtensionUITest(kTestDirectorySimpleApiCall) { } + void SetUp() { + // Set just this one function explicitly to be forwarded, as a test of + // the selective forwarding. The next test will leave the default to test + // universal forwarding. + functions_enabled_.clear(); + functions_enabled_.push_back("tabs.remove"); + SingleMessageExtensionUITest::SetUp(); + } + private: DISALLOW_COPY_AND_ASSIGN(SimpleApiCallExtensionTest); }; diff --git a/chrome/test/automation/automation_messages_internal.h b/chrome/test/automation/automation_messages_internal.h index 174e1d0..69e9c51 100644 --- a/chrome/test/automation/automation_messages_internal.h +++ b/chrome/test/automation/automation_messages_internal.h @@ -906,7 +906,10 @@ IPC_BEGIN_MESSAGES(Automation) // Used to put the browser into "extension automation mode" for the // current profile, or turn off the mode. IPC_MESSAGE_ROUTED1(AutomationMsg_SetEnableExtensionAutomation, - bool /* true to enable extension automation */) + std::vector<std::string> /* empty to disable automation, + non-empty to enable automation + of the specified API + functions */) // This message tells the browser to start using the new proxy configuration // represented by the given JSON string. The parameters used in the JSON @@ -1065,7 +1068,7 @@ IPC_BEGIN_MESSAGES(Automation) AutomationMsg_GoForwardBlockUntilNavigationsComplete, int, int, AutomationMsg_NavigationResponseValues) - // This message is used by automaton clients to upload histogram data to the + // This message is used by automation clients to upload histogram data to the // browser process. IPC_MESSAGE_ROUTED1(AutomationMsg_RecordHistograms, std::vector<std::string> /* histogram_list */) diff --git a/chrome/test/automation/automation_proxy.cc b/chrome/test/automation/automation_proxy.cc index 28cfe37..4658bf3 100644 --- a/chrome/test/automation/automation_proxy.cc +++ b/chrome/test/automation/automation_proxy.cc @@ -220,9 +220,10 @@ bool AutomationProxy::SavePackageShouldPromptUser(bool should_prompt) { return Send(new AutomationMsg_SavePackageShouldPromptUser(0, should_prompt)); } -bool AutomationProxy::SetEnableExtensionAutomation(bool enable_automation) { +bool AutomationProxy::SetEnableExtensionAutomation( + const std::vector<std::string>& functions_enabled) { return Send( - new AutomationMsg_SetEnableExtensionAutomation(0, enable_automation)); + new AutomationMsg_SetEnableExtensionAutomation(0, functions_enabled)); } bool AutomationProxy::GetBrowserWindowCount(int* num_windows) { diff --git a/chrome/test/automation/automation_proxy.h b/chrome/test/automation/automation_proxy.h index 1e02cff..cf40606 100644 --- a/chrome/test/automation/automation_proxy.h +++ b/chrome/test/automation/automation_proxy.h @@ -180,11 +180,22 @@ class AutomationProxy : public IPC::Channel::Listener, // sent. bool SavePackageShouldPromptUser(bool should_prompt); - // Turn extension automation mode on and off. When extension automation + // Configure extension automation mode. When extension automation // mode is turned on, the automation host can overtake extension API calls // e.g. to make UI tests for extensions easier to write. Returns true if // the message is successfully sent. - bool SetEnableExtensionAutomation(bool enable_automation); + // + // The parameter can take the following types of values: + // a) An empty list to turn off extension automation. + // b) A list with one item, "*", to turn extension automation on for all + // functions. + // c) A list with one or more items which are the names of Chrome Extension + // API functions that should be forwarded over the automation interface. + // Other functions will continue to be fulfilled as normal. This lets you + // write tests where some functionality continues to function as normal, + // and other functionality is mocked out by the test. + bool SetEnableExtensionAutomation( + const std::vector<std::string>& functions_enabled); // Returns the ID of the automation IPC channel, so that it can be // passed to the app as a launch parameter. diff --git a/chrome_frame/chrome_frame_activex.cc b/chrome_frame/chrome_frame_activex.cc index 78b09fa..16f5dda 100644 --- a/chrome_frame/chrome_frame_activex.cc +++ b/chrome_frame/chrome_frame_activex.cc @@ -337,6 +337,19 @@ HRESULT ChromeFrameActivex::IOleObject_SetClientSite( chrome_extra_arguments.assign(extra_arguments_arg, extra_arguments_arg.Length()); + ScopedBstr automated_functions_arg; + service_hr = service->GetExtensionApisToAutomate( + automated_functions_arg.Receive()); + if (S_OK == service_hr && automated_functions_arg) { + std::string automated_functions( + WideToASCII(static_cast<BSTR>(automated_functions_arg))); + functions_enabled_.clear(); + // SplitString writes one empty entry for blank strings, so we need this + // to allow specifying zero automation of API functions. + if (!automated_functions.empty()) + SplitString(automated_functions, ',', &functions_enabled_); + } + ScopedBstr profile_name_arg; service_hr = service->GetChromeProfileName(profile_name_arg.Receive()); if (S_OK == service_hr && profile_name_arg) diff --git a/chrome_frame/chrome_frame_automation.cc b/chrome_frame/chrome_frame_automation.cc index 17fb43d..2d22bbd 100644 --- a/chrome_frame/chrome_frame_automation.cc +++ b/chrome_frame/chrome_frame_automation.cc @@ -738,11 +738,11 @@ void ChromeFrameAutomationClient::CreateExternalTabComplete(HWND chrome_window, } void ChromeFrameAutomationClient::SetEnableExtensionAutomation( - bool enable_automation) { + const std::vector<std::string>& functions_enabled) { if (!is_initialized()) return; - automation_server_->SetEnableExtensionAutomation(enable_automation); + automation_server_->SetEnableExtensionAutomation(functions_enabled); } // Invoked in launch background thread. diff --git a/chrome_frame/chrome_frame_automation.h b/chrome_frame/chrome_frame_automation.h index e1a34d7..6eca88d 100644 --- a/chrome_frame/chrome_frame_automation.h +++ b/chrome_frame/chrome_frame_automation.h @@ -41,7 +41,8 @@ struct DECLSPEC_NOVTABLE ChromeFrameAutomationProxy { virtual std::string server_version() = 0; virtual void SendProxyConfig(const std::string&) = 0; - virtual void SetEnableExtensionAutomation(bool enable) = 0; + virtual void SetEnableExtensionAutomation( + const std::vector<std::string>& functions_enabled) = 0; protected: ~ChromeFrameAutomationProxy() {} }; @@ -72,8 +73,9 @@ class ChromeFrameAutomationProxyImpl : public ChromeFrameAutomationProxy, AutomationProxy::SendProxyConfig(p); } - virtual void SetEnableExtensionAutomation(bool e) { - AutomationProxy::SetEnableExtensionAutomation(e); + virtual void SetEnableExtensionAutomation( + const std::vector<std::string>& functions_enabled) { + AutomationProxy::SetEnableExtensionAutomation(functions_enabled); } protected: @@ -202,7 +204,8 @@ class ChromeFrameAutomationClient const std::string& target); bool SetProxySettings(const std::string& json_encoded_proxy_settings); - virtual void SetEnableExtensionAutomation(bool enable_automation); + virtual void SetEnableExtensionAutomation( + const std::vector<std::string>& functions_enabled); void FindInPage(const std::wstring& search_string, FindInPageDirection forward, diff --git a/chrome_frame/chrome_frame_npapi.cc b/chrome_frame/chrome_frame_npapi.cc index 6c9791f..ec324e0 100644 --- a/chrome_frame/chrome_frame_npapi.cc +++ b/chrome_frame/chrome_frame_npapi.cc @@ -102,6 +102,10 @@ static const char kPluginChromeExtraArguments[] = "chrome_extra_arguments"; // If privileged mode is enabled, the string value of this argument will // be used as the profile name for our chrome.exe instance. static const char kPluginChromeProfileName[] = "chrome_profile_name"; +// If privileged mode is enabled, this argument will be taken as a +// comma-separated list of API function calls to automate. +static const char kPluginChromeFunctionsAutomatedAttribute[] = + "chrome_functions_automated"; // If chrome network stack is to be used static const char kPluginUseChromeNetwork[] = "usechromenetwork"; @@ -377,6 +381,13 @@ bool ChromeFrameNPAPI::Initialize(NPMIMEType mime_type, NPP instance, chrome_extra_arguments_arg = argv[i]; } else if (LowerCaseEqualsASCII(argn[i], kPluginChromeProfileName)) { chrome_profile_name_arg = argv[i]; + } else if (LowerCaseEqualsASCII(argn[i], + kPluginChromeFunctionsAutomatedAttribute)) { + functions_enabled_.clear(); + // SplitString writes one empty entry for blank strings, so we need this + // to allow specifying zero automation of API functions. + if (argv[i][0] != '\0') + SplitString(argv[i], ',', &functions_enabled_); } else if (LowerCaseEqualsASCII(argn[i], kPluginUseChromeNetwork)) { chrome_network_arg_set = true; chrome_network_arg = atoi(argv[i]) ? true : false; diff --git a/chrome_frame/chrome_frame_npapi_unittest.cc b/chrome_frame/chrome_frame_npapi_unittest.cc index d2c9b4e..b30d5e8 100644 --- a/chrome_frame/chrome_frame_npapi_unittest.cc +++ b/chrome_frame/chrome_frame_npapi_unittest.cc @@ -83,7 +83,8 @@ class MockAutomationClient: public ChromeFrameAutomationClient { MOCK_METHOD6(Initialize, bool(ChromeFrameDelegate*, int, bool, const std::wstring&, const std::wstring&, bool)); - MOCK_METHOD1(SetEnableExtensionAutomation, void(bool)); // NOLINT + MOCK_METHOD1(SetEnableExtensionAutomation, + void(const std::vector<std::string>&)); // NOLINT }; class MockProxyService: public NpProxyService { @@ -219,7 +220,7 @@ TEST_F(TestNPAPIPrivilegedApi, PrivilegedAllowsArgsAndProfile) { L"-bar=far"); // Extra arguments expected // With privileged mode we expect automation to be enabled. - EXPECT_CALL(*mock_automation, SetEnableExtensionAutomation(true)) + EXPECT_CALL(*mock_automation, SetEnableExtensionAutomation(_)) .Times(1); char* argn[] = { @@ -386,7 +387,7 @@ class TestNPAPIPrivilegedProperty: public TestNPAPIPrivilegedApi { // And we should expect SetEnableExtensionAutomation to be called // for privileged tests. - EXPECT_CALL(*mock_automation, SetEnableExtensionAutomation(true)) + EXPECT_CALL(*mock_automation, SetEnableExtensionAutomation(_)) .WillRepeatedly(Return()); // Initializes identifiers. diff --git a/chrome_frame/chrome_frame_plugin.h b/chrome_frame/chrome_frame_plugin.h index b0814bb..fbc3f77 100644 --- a/chrome_frame/chrome_frame_plugin.h +++ b/chrome_frame/chrome_frame_plugin.h @@ -19,6 +19,7 @@ class ChromeFramePlugin : public ChromeFrameDelegateImpl { ChromeFramePlugin() : ignore_setfocus_(false), is_privileged_(false) { + functions_enabled_.push_back("*"); } ~ChromeFramePlugin() { Uninitialize(); @@ -78,7 +79,7 @@ END_MSG_MAP() // Issue the extension automation request if we're privileged to // allow this control to handle extension requests from Chrome. if (is_privileged_) - automation_client_->SetEnableExtensionAutomation(true); + automation_client_->SetEnableExtensionAutomation(functions_enabled_); } virtual bool IsValid() const { @@ -170,7 +171,7 @@ END_MSG_MAP() // modified as well (enable/disable commands, add/remove items). // Override in most-derived class if needed. bool PreProcessContextMenu(HMENU menu) { - // Add an "About" item. + // Add an "About" item. // TODO: The string should be localized and menu should // be modified in ExternalTabContainer:: once we go public. AppendMenu(menu, MF_STRING, IDC_ABOUT_CHROME_FRAME, @@ -208,6 +209,10 @@ END_MSG_MAP() // // When privileged, additional interfaces are made available to the user. bool is_privileged_; + + // List of functions to enable for automation, or a single entry "*" to enable + // all functions for automation. Ignored unless is_privileged_ is true. + std::vector<std::string> functions_enabled_; }; #endif // CHROME_FRAME_CHROME_FRAME_PLUGIN_H_ diff --git a/chrome_frame/chrome_tab.idl b/chrome_frame/chrome_tab.idl index afb364e..c234c29 100644 --- a/chrome_frame/chrome_tab.idl +++ b/chrome_frame/chrome_tab.idl @@ -77,7 +77,7 @@ interface IChromeFrame : IDispatch { [ object, - uuid(679E292F-DBAB-46b8-8693-03084CEF61BE), + uuid(655A11E0-EF63-4fbe-9DF6-C182D2FCD6DC), oleautomation, nonextensible, hidden, @@ -91,6 +91,9 @@ interface IChromeFramePrivileged: IUnknown { HRESULT GetChromeExtraArguments([out] BSTR *args); // The profile name we want to use. HRESULT GetChromeProfileName([out] BSTR *profile_name); + // The comma-separated list of extension API functions you wish to automate. + // Return S_FALSE to leave the default, which is to automate all functions. + HRESULT GetExtensionApisToAutomate([out] BSTR *extension_apis); }; // Expose this service to the ChromeFrame control to trigger privileged diff --git a/chrome_frame/test/chrome_frame_unittests.cc b/chrome_frame/test/chrome_frame_unittests.cc index 5bf33c1..37be881 100644 --- a/chrome_frame/test/chrome_frame_unittests.cc +++ b/chrome_frame/test/chrome_frame_unittests.cc @@ -790,7 +790,8 @@ class MockAutomationProxy : public ChromeFrameAutomationProxy { MOCK_METHOD1(CreateTabProxy, scoped_refptr<TabProxy>(int handle)); MOCK_METHOD0(server_version, std::string(void)); MOCK_METHOD1(SendProxyConfig, void(const std::string&)); - MOCK_METHOD1(SetEnableExtensionAutomation, void(bool enable)); + MOCK_METHOD1(SetEnableExtensionAutomation, + void(const std::vector<std::string>&)); ~MockAutomationProxy() {} }; |