Skip to content

Commit

Permalink
Enhance extension UI testing by enabling you to select which extension
Browse files Browse the repository at this point in the history
APIs to forward (and thus stub out in your test), while others will
keep being fulfilled as per usual.  This lets you build tests that
stub out one piece of behavior while testing that some side effects of
another API happen as expected.

BUG=none
TEST=Run ui_tests.exe

Review URL: http://codereview.chromium.org/314015

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@29919 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
joi@chromium.org committed Oct 23, 2009
1 parent 117fd71 commit 50f5316
Show file tree
Hide file tree
Showing 16 changed files with 118 additions and 32 deletions.
13 changes: 9 additions & 4 deletions chrome/browser/automation/automation_extension_function.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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++) {
Expand All @@ -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();
Expand Down
12 changes: 8 additions & 4 deletions chrome/browser/automation/automation_extension_function.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 3 additions & 2 deletions chrome/browser/automation/automation_provider.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
3 changes: 2 additions & 1 deletion chrome/browser/automation/automation_provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
27 changes: 25 additions & 2 deletions chrome/browser/extensions/extension_uitest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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();
}

Expand Down Expand Up @@ -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);
};
Expand All @@ -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);
};
Expand Down
7 changes: 5 additions & 2 deletions chrome/test/automation/automation_messages_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 */)
Expand Down
5 changes: 3 additions & 2 deletions chrome/test/automation/automation_proxy.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
15 changes: 13 additions & 2 deletions chrome/test/automation/automation_proxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
13 changes: 13 additions & 0 deletions chrome_frame/chrome_frame_activex.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions chrome_frame/chrome_frame_automation.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
11 changes: 7 additions & 4 deletions chrome_frame/chrome_frame_automation.h
Original file line number Diff line number Diff line change
Expand Up @@ -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() {}
};
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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,
Expand Down
11 changes: 11 additions & 0 deletions chrome_frame/chrome_frame_npapi.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -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;
Expand Down
7 changes: 4 additions & 3 deletions chrome_frame/chrome_frame_npapi_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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[] = {
Expand Down Expand Up @@ -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.
Expand Down
9 changes: 7 additions & 2 deletions chrome_frame/chrome_frame_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class ChromeFramePlugin : public ChromeFrameDelegateImpl {
ChromeFramePlugin()
: ignore_setfocus_(false),
is_privileged_(false) {
functions_enabled_.push_back("*");
}
~ChromeFramePlugin() {
Uninitialize();
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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_
Expand Down
5 changes: 4 additions & 1 deletion chrome_frame/chrome_tab.idl
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ interface IChromeFrame : IDispatch {

[
object,
uuid(679E292F-DBAB-46b8-8693-03084CEF61BE),
uuid(655A11E0-EF63-4fbe-9DF6-C182D2FCD6DC),
oleautomation,
nonextensible,
hidden,
Expand All @@ -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
Expand Down
3 changes: 2 additions & 1 deletion chrome_frame/test/chrome_frame_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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() {}
};
Expand Down

0 comments on commit 50f5316

Please sign in to comment.