summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorjoi@chromium.org <joi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-05 01:36:33 +0000
committerjoi@chromium.org <joi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-05 01:36:33 +0000
commitac51ee9169f4e65c3fe76754821fc0864520a612 (patch)
treef9af15fbdcecaa76766c64c23fdc74b2049ab40a /chrome
parentd928a845b0831a17b34e1ac0325517a49b00bcec (diff)
downloadchromium_src-ac51ee9169f4e65c3fe76754821fc0864520a612.zip
chromium_src-ac51ee9169f4e65c3fe76754821fc0864520a612.tar.gz
chromium_src-ac51ee9169f4e65c3fe76754821fc0864520a612.tar.bz2
Get rid of ExternalTabAutomationProxy by switching the extension UI
tests over to ExternalTabUITest. BUG=27326 TEST=ui_tests.exe Review URL: http://codereview.chromium.org/468013 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@33902 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/extensions/extension_uitest.cc409
-rw-r--r--chrome/test/automation/automation_proxy_uitest.cc305
-rw-r--r--chrome/test/automation/automation_proxy_uitest.h172
3 files changed, 275 insertions, 611 deletions
diff --git a/chrome/browser/extensions/extension_uitest.cc b/chrome/browser/extensions/extension_uitest.cc
index 42e2459..83eff72 100644
--- a/chrome/browser/extensions/extension_uitest.cc
+++ b/chrome/browser/extensions/extension_uitest.cc
@@ -15,10 +15,23 @@
#include "chrome/test/automation/automation_proxy_uitest.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_test.h"
+#include "chrome/test/ui_test_utils.h"
#include "googleurl/src/gurl.h"
+#define GMOCK_MUTANT_INCLUDE_LATE_OBJECT_BINDING
+#include "testing/gmock_mutant.h"
namespace {
+using testing::_;
+using testing::CreateFunctor;
+using testing::DoAll;
+using testing::Invoke;
+using testing::InvokeWithoutArgs;
+using testing::SaveArg;
+using testing::WithArgs;
+
+using ui_test_utils::TimedMessageLoopRunner;
+
static const char kTestDirectorySimpleApiCall[] =
"extensions/uitest/simple_api_call";
static const char kTestDirectoryRoundtripApiCall[] =
@@ -26,6 +39,9 @@ static const char kTestDirectoryRoundtripApiCall[] =
static const char kTestDirectoryBrowserEvent[] =
"extensions/uitest/event_sink";
+// TODO(port) Once external tab stuff is ported.
+#if defined(OS_WIN)
+
// Base class to test extensions almost end-to-end by including browser
// startup, manifest parsing, and the actual process model in the
// equation. This would also let you write UITests that test individual
@@ -37,10 +53,10 @@ static const char kTestDirectoryBrowserEvent[] =
// 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 {
+class ExtensionUITest : public ExternalTabUITest {
public:
- explicit ExtensionUITest(const std::string& extension_path) {
+ explicit ExtensionUITest(const std::string& extension_path)
+ : loop_(MessageLoop::current()) {
FilePath filename(test_data_directory_);
filename = filename.AppendASCII(extension_path);
launch_arguments_.AppendSwitchWithValue(switches::kLoadExtension,
@@ -54,76 +70,41 @@ class ExtensionUITest : public ParentTestType {
}
void SetUp() {
- ParentTestType::SetUp();
-
- AutomationProxyForExternalTab* proxy =
- static_cast<AutomationProxyForExternalTab*>(automation());
- HWND external_tab_container = NULL;
- HWND tab_wnd = NULL;
- tab_ = proxy->CreateTabWithHostWindow(false,
- GURL(), &external_tab_container, &tab_wnd);
-
+ ExternalTabUITest::SetUp();
+ tab_ = mock_->CreateTabWithUrl(GURL());
tab_->SetEnableExtensionAutomation(functions_enabled_);
}
void TearDown() {
tab_->SetEnableExtensionAutomation(std::vector<std::string>());
-
- AutomationProxyForExternalTab* proxy =
- static_cast<AutomationProxyForExternalTab*>(automation());
- proxy->DestroyHostWindow();
- proxy->WaitForTabCleanup(tab_, action_max_timeout_ms());
- EXPECT_FALSE(tab_->is_valid());
- tab_.release();
-
- ParentTestType::TearDown();
- }
-
- void TestWithURL(const GURL& url) {
- EXPECT_TRUE(tab_->is_valid());
- if (tab_) {
- AutomationProxyForExternalTab* proxy =
- static_cast<AutomationProxyForExternalTab*>(automation());
-
- // Enter a message loop to allow the tab to be created
- proxy->WaitForNavigation(2000);
- DoAdditionalPreNavigateSetup(tab_.get());
-
- // We explicitly do not make this a toolstrip in the extension manifest,
- // so that the test can control when it gets loaded, and so that we test
- // the intended behavior that tabs should be able to show extension pages
- // (useful for development etc.)
- tab_->NavigateInExternalTab(url, GURL());
- EXPECT_TRUE(proxy->WaitForMessage(action_max_timeout_ms()));
- }
- }
-
- // Override if you need additional stuff before we navigate the page.
- virtual void DoAdditionalPreNavigateSetup(TabProxy* tab) {
+ tab_ = NULL;
+ EXPECT_TRUE(mock_->HostWindowExists()) <<
+ "You shouldn't DestroyHostWindow yourself, or extension automation "
+ "won't be correctly reset. Just exit your message loop.";
+ mock_->DestroyHostWindow();
+ ExternalTabUITest::TearDown();
}
protected:
// Extension API functions that we want to take over. Defaults to all.
std::vector<std::string> functions_enabled_;
+
+ // Message loop for running the async bits of your test.
+ TimedMessageLoopRunner loop_;
+
+ // The external tab.
scoped_refptr<TabProxy> tab_;
private:
DISALLOW_COPY_AND_ASSIGN(ExtensionUITest);
};
-// For tests that only need to check for a single postMessage
-// being received from the tab in Chrome. These tests can send a message
-// to the tab before receiving the new message, but there will not be
-// a chance to respond by sending a message from the test to the tab after
-// the postMessage is received.
-typedef ExtensionUITest<ExternalTabTestType> SingleMessageExtensionUITest;
-
// A test that loads a basic extension that makes an API call that does
// not require a response.
-class SimpleApiCallExtensionTest : public SingleMessageExtensionUITest {
+class ExtensionTestSimpleApiCall : public ExtensionUITest {
public:
- SimpleApiCallExtensionTest()
- : SingleMessageExtensionUITest(kTestDirectorySimpleApiCall) {
+ ExtensionTestSimpleApiCall()
+ : ExtensionUITest(kTestDirectorySimpleApiCall) {
}
void SetUp() {
@@ -132,30 +113,37 @@ class SimpleApiCallExtensionTest : public SingleMessageExtensionUITest {
// universal forwarding.
functions_enabled_.clear();
functions_enabled_.push_back("tabs.remove");
- SingleMessageExtensionUITest::SetUp();
+ ExtensionUITest::SetUp();
}
private:
- DISALLOW_COPY_AND_ASSIGN(SimpleApiCallExtensionTest);
+ DISALLOW_COPY_AND_ASSIGN(ExtensionTestSimpleApiCall);
};
-// TODO(port) Should become portable once ExternalTabMessageLoop is ported.
-#if defined(OS_WIN)
-TEST_F(SimpleApiCallExtensionTest, RunTest) {
+TEST_F(ExtensionTestSimpleApiCall, RunTest) {
namespace keys = extension_automation_constants;
- TestWithURL(GURL(
- "chrome-extension://pmgpglkggjdpkpghhdmbdhababjpcohk/test.html"));
- AutomationProxyForExternalTab* proxy =
- static_cast<AutomationProxyForExternalTab*>(automation());
- ASSERT_GT(proxy->messages_received(), 0);
+ ASSERT_THAT(mock_, testing::NotNull());
+ EXPECT_CALL(*mock_, OnDidNavigate(_, _)).Times(1);
+
+ std::string message_received;
+ EXPECT_CALL(*mock_, OnForwardMessageToExternalHost(
+ _, _, keys::kAutomationOrigin, keys::kAutomationRequestTarget))
+ .WillOnce(DoAll(
+ SaveArg<1>(&message_received),
+ InvokeWithoutArgs(
+ CreateFunctor(&loop_, &TimedMessageLoopRunner::Quit))));
- // Using EXPECT_TRUE rather than EXPECT_EQ as the compiler (VC++) isn't
- // finding the right match for EqHelper.
- EXPECT_TRUE(proxy->origin() == keys::kAutomationOrigin);
- EXPECT_TRUE(proxy->target() == keys::kAutomationRequestTarget);
+ EXPECT_CALL(*mock_, HandleClosed(_));
- scoped_ptr<Value> message_value(base::JSONReader::Read(proxy->message(),
+ ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS, tab_->NavigateInExternalTab(
+ GURL("chrome-extension://pmgpglkggjdpkpghhdmbdhababjpcohk/test.html"),
+ GURL("")));
+
+ loop_.RunFor(2 * action_max_timeout_ms());
+ ASSERT_FALSE(message_received.empty());
+
+ scoped_ptr<Value> message_value(base::JSONReader::Read(message_received,
false));
ASSERT_TRUE(message_value->IsType(Value::TYPE_DICTIONARY));
DictionaryValue* message_dict =
@@ -177,83 +165,46 @@ TEST_F(SimpleApiCallExtensionTest, RunTest) {
&has_callback));
EXPECT_FALSE(has_callback);
}
-#endif // defined(OS_WIN)
-
-// A base class for an automation proxy that checks several messages in
-// a row.
-class MultiMessageAutomationProxy : public AutomationProxyForExternalTab {
- public:
- explicit MultiMessageAutomationProxy(int execution_timeout)
- : AutomationProxyForExternalTab(execution_timeout) {
- }
- // Call when testing with the current tab is finished.
- void Quit() {
- PostQuitMessage(0);
- }
-
- protected:
- virtual void OnMessageReceived(const IPC::Message& msg) {
- IPC_BEGIN_MESSAGE_MAP(MultiMessageAutomationProxy, msg)
- IPC_MESSAGE_HANDLER(AutomationMsg_DidNavigate,
- AutomationProxyForExternalTab::OnDidNavigate)
- IPC_MESSAGE_HANDLER(AutomationMsg_ForwardMessageToExternalHost,
- OnForwardMessageToExternalHost)
- IPC_END_MESSAGE_MAP()
- }
-
- void OnForwardMessageToExternalHost(int handle,
- const std::string& message,
- const std::string& origin,
- const std::string& target) {
- messages_received_++;
- message_ = message;
- origin_ = origin;
- target_ = target;
- HandleMessageFromChrome();
+// A test that loads a basic extension that makes an API call that does
+// not require a response.
+class ExtensionTestRoundtripApiCall : public ExtensionUITest {
+public:
+ ExtensionTestRoundtripApiCall()
+ : ExtensionUITest(kTestDirectoryRoundtripApiCall),
+ messages_received_(0) {
}
- // Override to do your custom checking and initiate any custom actions
- // needed in your particular unit test.
- virtual void HandleMessageFromChrome() = 0;
-};
-
-// This proxy is specific to RoundtripApiCallExtensionTest.
-class RoundtripAutomationProxy : public MultiMessageAutomationProxy {
- public:
- explicit RoundtripAutomationProxy(int execution_timeout)
- : MultiMessageAutomationProxy(execution_timeout),
- tab_(NULL) {
+ 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.getSelected");
+ functions_enabled_.push_back("tabs.remove");
+ ExtensionUITest::SetUp();
}
- // Must set before initiating test.
- TabProxy* tab_;
-
- protected:
- virtual void HandleMessageFromChrome() {
+ void CheckAndSendResponse(const std::string& message) {
namespace keys = extension_automation_constants;
+ ++messages_received_;
ASSERT_TRUE(tab_ != NULL);
ASSERT_TRUE(messages_received_ == 1 || messages_received_ == 2);
- // Using EXPECT_TRUE rather than EXPECT_EQ as the compiler (VC++) isn't
- // finding the right match for EqHelper.
- EXPECT_TRUE(origin_ == keys::kAutomationOrigin);
- EXPECT_TRUE(target_ == keys::kAutomationRequestTarget);
-
- scoped_ptr<Value> message_value(base::JSONReader::Read(message_, false));
+ scoped_ptr<Value> message_value(base::JSONReader::Read(message, false));
ASSERT_TRUE(message_value->IsType(Value::TYPE_DICTIONARY));
DictionaryValue* request_dict =
- static_cast<DictionaryValue*>(message_value.get());
+ static_cast<DictionaryValue*>(message_value.get());
std::string function_name;
ASSERT_TRUE(request_dict->GetString(keys::kAutomationNameKey,
- &function_name));
+ &function_name));
int request_id = -2;
EXPECT_TRUE(request_dict->GetInteger(keys::kAutomationRequestIdKey,
- &request_id));
+ &request_id));
bool has_callback = false;
EXPECT_TRUE(request_dict->GetBoolean(keys::kAutomationHasCallbackKey,
- &has_callback));
+ &has_callback));
if (messages_received_ == 1) {
EXPECT_EQ(function_name, "tabs.getSelected");
@@ -268,7 +219,7 @@ class RoundtripAutomationProxy : public MultiMessageAutomationProxy {
tab_dict.SetInteger(extension_tabs_module_constants::kWindowIdKey, 1);
tab_dict.SetBoolean(extension_tabs_module_constants::kSelectedKey, true);
tab_dict.SetString(extension_tabs_module_constants::kUrlKey,
- "http://www.google.com");
+ "http://www.google.com");
std::string tab_json;
base::JSONWriter::Write(&tab_dict, false, &tab_json);
@@ -279,9 +230,9 @@ class RoundtripAutomationProxy : public MultiMessageAutomationProxy {
base::JSONWriter::Write(&response_dict, false, &response_json);
tab_->HandleMessageFromExternalHost(
- response_json,
- keys::kAutomationOrigin,
- keys::kAutomationResponseTarget);
+ response_json,
+ keys::kAutomationOrigin,
+ keys::kAutomationResponseTarget);
} else if (messages_received_ == 2) {
EXPECT_EQ(function_name, "tabs.remove");
EXPECT_FALSE(has_callback);
@@ -289,76 +240,92 @@ class RoundtripAutomationProxy : public MultiMessageAutomationProxy {
std::string args;
EXPECT_TRUE(request_dict->GetString(keys::kAutomationArgsKey, &args));
EXPECT_NE(args.find("42"), -1);
-
- Quit();
+ loop_.Quit();
} else {
- Quit();
FAIL();
+ loop_.Quit();
}
}
+
+private:
+ int messages_received_;
+ DISALLOW_COPY_AND_ASSIGN(ExtensionTestRoundtripApiCall);
};
-class RoundtripApiCallExtensionTest
- : public ExtensionUITest<
- CustomAutomationProxyTest<RoundtripAutomationProxy>> {
+TEST_F(ExtensionTestRoundtripApiCall, RunTest) {
+ namespace keys = extension_automation_constants;
+
+ ASSERT_THAT(mock_, testing::NotNull());
+ EXPECT_CALL(*mock_, OnDidNavigate(_, _)).Times(1);
+
+ EXPECT_CALL(*mock_, OnForwardMessageToExternalHost(
+ _, _, keys::kAutomationOrigin, keys::kAutomationRequestTarget))
+ .Times(2)
+ .WillRepeatedly(WithArgs<1>(Invoke(
+ CreateFunctor(this,
+ &ExtensionTestRoundtripApiCall::CheckAndSendResponse))));
+
+ EXPECT_CALL(*mock_, HandleClosed(_));
+
+ ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS, tab_->NavigateInExternalTab(
+ GURL("chrome-extension://ofoknjclcmghjfmbncljcnpjmfmldhno/test.html"),
+ GURL("")));
+
+ // CheckAndSendResponse (called by OnForwardMessageToExternalHost)
+ // will end the loop once it has received both of our expected messages.
+ loop_.RunFor(2 * action_max_timeout_ms());
+}
+
+class ExtensionTestBrowserEvents : public ExtensionUITest {
public:
- RoundtripApiCallExtensionTest()
- : ExtensionUITest<
- CustomAutomationProxyTest<
- RoundtripAutomationProxy> >(kTestDirectoryRoundtripApiCall) {
+ ExtensionTestBrowserEvents()
+ : ExtensionUITest(kTestDirectoryBrowserEvent),
+ response_count_(0) {
}
- void DoAdditionalPreNavigateSetup(TabProxy* tab) {
- RoundtripAutomationProxy* proxy =
- static_cast<RoundtripAutomationProxy*>(automation());
- proxy->tab_ = tab;
+ 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("windows.getCurrent");
+ ExtensionUITest::SetUp();
}
- private:
- DISALLOW_COPY_AND_ASSIGN(RoundtripApiCallExtensionTest);
-};
+ // Fire an event of the given name to the test extension.
+ void FireEvent(const char* event_name) {
+ namespace keys = extension_automation_constants;
-// TODO(port) Should become portable once
-// ExternalTabMessageLoop is ported.
-#if defined(OS_WIN)
-TEST_F(RoundtripApiCallExtensionTest, RunTest) {
- TestWithURL(GURL(
- "chrome-extension://ofoknjclcmghjfmbncljcnpjmfmldhno/test.html"));
- RoundtripAutomationProxy* proxy =
- static_cast<RoundtripAutomationProxy*>(automation());
-
- // Validation is done in the RoundtripAutomationProxy, so we just check
- // something basic here.
- EXPECT_EQ(proxy->messages_received(), 2);
-}
-#endif // defined(OS_WIN)
+ ASSERT_TRUE(tab_ != NULL);
-// This proxy is specific to BrowserEventExtensionTest.
-class BrowserEventAutomationProxy : public MultiMessageAutomationProxy {
- public:
- explicit BrowserEventAutomationProxy(int execution_timeout)
- : MultiMessageAutomationProxy(execution_timeout),
- tab_(NULL) {
+ // Build the event message to send to the extension. The only important
+ // part is the name, as the payload is not used by the test extension.
+ std::string message;
+ message += event_name;
+
+ tab_->HandleMessageFromExternalHost(
+ message,
+ keys::kAutomationOrigin,
+ keys::kAutomationBrowserEventRequestTarget);
}
- // Must set before initiating test.
- TabProxy* tab_;
+ void HandleMessageFromChrome(const std::string& message,
+ const std::string& target);
+ protected:
// Counts the number of times we got a given event.
std::map<std::string, int> event_count_;
// Array containing the names of the events to fire to the extension.
static const char* events_[];
- protected:
- // Process a message received from the test extension.
- virtual void HandleMessageFromChrome();
+ // Number of events extension has told us it received.
+ int response_count_;
- // Fire an event of the given name to the test extension.
- void FireEvent(const char* event_name);
+ DISALLOW_COPY_AND_ASSIGN(ExtensionTestBrowserEvents);
};
-const char* BrowserEventAutomationProxy::events_[] = {
+const char* ExtensionTestBrowserEvents::events_[] = {
// Window events.
"[\"windows.onCreated\", \"[{'id':42,'focused':true,'top':0,'left':0,"
"'width':100,'height':100}]\"]",
@@ -399,16 +366,13 @@ const char* BrowserEventAutomationProxy::events_[] = {
"{'childIds':['1', '2', '3']}]\"]"
};
-void BrowserEventAutomationProxy::HandleMessageFromChrome() {
+void ExtensionTestBrowserEvents::HandleMessageFromChrome(
+ const std::string& message,
+ const std::string& target) {
namespace keys = extension_automation_constants;
ASSERT_TRUE(tab_ != NULL);
- std::string message(message());
- std::string origin(origin());
- std::string target(target());
-
ASSERT_TRUE(message.length() > 0);
- ASSERT_STREQ(keys::kAutomationOrigin, origin.c_str());
if (target == keys::kAutomationRequestTarget) {
// This should be a request for the current window. We don't need to
@@ -452,72 +416,59 @@ void BrowserEventAutomationProxy::HandleMessageFromChrome() {
reinterpret_cast<DictionaryValue*>(message_value.get());
std::string event_name;
- ASSERT_TRUE(message_dict->GetString(L"data", &event_name));
+ message_dict->GetString(keys::kAutomationMessageDataKey, &event_name);
if (event_name == "\"ACK\"") {
ASSERT_EQ(0, event_count_.size());
+ } else if (event_name.empty()) {
+ // This must be the post disconnect.
+ int request_id = -1;
+ message_dict->GetInteger(keys::kAutomationRequestIdKey, &request_id);
+ ASSERT_EQ(keys::CHANNEL_CLOSED, request_id);
} else {
++event_count_[event_name];
}
+
+ // Check if we're done.
+ if (event_count_.size() == arraysize(events_)) {
+ loop_.Quit();
+ }
}
}
-void BrowserEventAutomationProxy::FireEvent(const char* event) {
+TEST_F(ExtensionTestBrowserEvents, RunTest) {
+ // This test loads an HTML file that tries to add listeners to a bunch of
+ // chrome.* events and upon adding a listener it posts the name of the event
+ // to the automation layer, which we'll count to make sure the events work.
namespace keys = extension_automation_constants;
- // Build the event message to send to the extension. The only important
- // part is the name, as the payload is not used by the test extension.
- std::string message;
- message += event;
+ ASSERT_THAT(mock_, testing::NotNull());
+ EXPECT_CALL(*mock_, OnDidNavigate(_, _)).Times(1);
- tab_->HandleMessageFromExternalHost(
- message,
- keys::kAutomationOrigin,
- keys::kAutomationBrowserEventRequestTarget);
-}
+ EXPECT_CALL(*mock_, OnForwardMessageToExternalHost(
+ _, _, keys::kAutomationOrigin, _))
+ .WillRepeatedly(WithArgs<1, 3>(Invoke(
+ CreateFunctor(this,
+ &ExtensionTestBrowserEvents::HandleMessageFromChrome))));
-class BrowserEventExtensionTest
- : public ExtensionUITest<
- CustomAutomationProxyTest<BrowserEventAutomationProxy>> {
- public:
- BrowserEventExtensionTest()
- : ExtensionUITest<
- CustomAutomationProxyTest<
- BrowserEventAutomationProxy> >(kTestDirectoryBrowserEvent) {
- }
-
- void DoAdditionalPreNavigateSetup(TabProxy* tab) {
- BrowserEventAutomationProxy* proxy =
- static_cast<BrowserEventAutomationProxy*>(automation());
- proxy->tab_ = tab;
- }
+ EXPECT_CALL(*mock_, HandleClosed(_));
- private:
+ ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS, tab_->NavigateInExternalTab(
+ GURL("chrome-extension://ofoknjclcmghjfmbncljcnpjmfmldhno/test.html"),
+ GURL("")));
- DISALLOW_COPY_AND_ASSIGN(BrowserEventExtensionTest);
-};
-
-// TODO(port) Should become portable once
-// ExternalTabMessageLoop is ported.
-#if defined(OS_WIN)
-TEST_F(BrowserEventExtensionTest, RunTest) {
- // This test loads an HTML file that tries to add listeners to a bunch of
- // chrome.* events and upon adding a listener it posts the name of the event
- // to the automation layer, which we'll count to make sure the events work.
- TestWithURL(GURL(
- "chrome-extension://ofoknjclcmghjfmbncljcnpjmfmldhno/test.html"));
- BrowserEventAutomationProxy* proxy =
- static_cast<BrowserEventAutomationProxy*>(automation());
+ // HandleMessageFromChrome (called by OnForwardMessageToExternalHost) ends
+ // the loop when we've received the number of response messages we expect.
+ loop_.RunFor(2 * action_max_timeout_ms());
// If this assert hits and the actual size is 0 then you need to look at:
// src\chrome\test\data\extensions\uitest\event_sink\test.html and see if
// all the events we are attaching to are valid. Also compare the list against
// the event_names_ string array above.
- EXPECT_EQ(arraysize(BrowserEventAutomationProxy::events_),
- proxy->event_count_.size());
- for (std::map<std::string, int>::iterator i = proxy->event_count_.begin();
- i != proxy->event_count_.end(); ++i) {
+ ASSERT_EQ(arraysize(events_), event_count_.size());
+ for (std::map<std::string, int>::iterator i = event_count_.begin();
+ i != event_count_.end(); ++i) {
const std::pair<std::string, int>& value = *i;
- ASSERT_EQ(1, value.second);
+ EXPECT_EQ(1, value.second);
}
}
#endif // defined(OS_WIN)
diff --git a/chrome/test/automation/automation_proxy_uitest.cc b/chrome/test/automation/automation_proxy_uitest.cc
index 4a9dcdd..561173f 100644
--- a/chrome/test/automation/automation_proxy_uitest.cc
+++ b/chrome/test/automation/automation_proxy_uitest.cc
@@ -29,7 +29,6 @@
#include "chrome/test/ui/ui_test.h"
#include "net/base/net_util.h"
#include "net/url_request/url_request_unittest.h"
-#include "testing/gmock/include/gmock/gmock.h"
#define GMOCK_MUTANT_INCLUDE_LATE_OBJECT_BINDING
#include "testing/gmock_mutant.h"
#include "views/event.h"
@@ -653,289 +652,53 @@ TEST_F(AutomationProxyTest, BlockedPopupTest) {
// TODO(port): Remove HWND if possible
#if defined(OS_WIN)
-static const wchar_t class_name[] = L"External_Tab_UI_Test_Class";
-static const wchar_t window_title[] = L"External Tab Tester";
-AutomationProxyForExternalTab::AutomationProxyForExternalTab(
- int execution_timeout)
+const char simple_data_url[] =
+ "data:text/html,<html><head><title>External tab test</title></head>"
+ "<body>A simple page for testing a floating/invisible tab<br></div>"
+ "</body></html>";
+
+ExternalTabUITestMockClient::ExternalTabUITestMockClient(int execution_timeout)
: AutomationProxy(execution_timeout),
- messages_received_(0),
- navigate_complete_(false),
- quit_after_(QUIT_INVALID),
- host_window_class_(NULL),
host_window_(NULL) {
}
-AutomationProxyForExternalTab::~AutomationProxyForExternalTab() {
- DestroyHostWindow();
- UnregisterClassW(host_window_class_, NULL);
-}
-
-gfx::NativeWindow AutomationProxyForExternalTab::CreateHostWindow() {
- DCHECK(!IsWindow(host_window_));
- if (!host_window_class_) {
- WNDCLASSEX wnd_class = {0};
- wnd_class.cbSize = sizeof(wnd_class);
- wnd_class.style = CS_HREDRAW | CS_VREDRAW;
- wnd_class.lpfnWndProc = DefWindowProc;
- wnd_class.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
- wnd_class.lpszClassName = class_name;
- host_window_class_ = reinterpret_cast<const wchar_t*>(
- RegisterClassEx(&wnd_class));
- if (!host_window_class_) {
- NOTREACHED() << "RegisterClassEx failed. Error: " << GetLastError();
- return false;
- }
- }
-
- unsigned long style = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN;
- host_window_ = CreateWindow(host_window_class_, window_title, style,
- CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL,
- NULL, NULL, NULL);
- if (!host_window_) {
- NOTREACHED() << "CreateWindow failed. Error: " << GetLastError();
- return false;
- }
-
- ShowWindow(host_window_, SW_SHOW);
- return host_window_;
+void ExternalTabUITestMockClient::ReplyStarted(
+ const IPC::AutomationURLResponse* response,
+ int tab_handle, int request_id) {
+ AutomationProxy::Send(new AutomationMsg_RequestStarted(0, tab_handle,
+ request_id, *response));
}
-scoped_refptr<TabProxy> AutomationProxyForExternalTab::CreateTabWithHostWindow(
- bool is_incognito, const GURL& initial_url,
- gfx::NativeWindow* container_wnd, gfx::NativeWindow* tab_wnd) {
- DCHECK(container_wnd);
- DCHECK(tab_wnd);
-
- CreateHostWindow();
- EXPECT_NE(FALSE, ::IsWindow(host_window_));
-
- RECT client_area = {0};
- GetClientRect(host_window_, &client_area);
-
- const IPC::ExternalTabSettings settings = {
- host_window_,
- gfx::Rect(client_area),
- WS_CHILD | WS_VISIBLE,
- is_incognito,
- false,
- false,
- initial_url
- };
-
- scoped_refptr<TabProxy> tab(CreateExternalTab(settings, container_wnd,
- tab_wnd));
-
- EXPECT_TRUE(tab != NULL);
- EXPECT_NE(FALSE, ::IsWindow(*container_wnd));
- EXPECT_NE(FALSE, ::IsWindow(*tab_wnd));
- return tab;
-}
-
-void AutomationProxyForExternalTab::DestroyHostWindow() {
- if (host_window_) {
- DestroyWindow(host_window_);
- host_window_ = NULL;
- }
-}
-
-bool AutomationProxyForExternalTab::WaitForNavigation(int timeout_ms) {
- set_quit_after(AutomationProxyForExternalTab::QUIT_AFTER_NAVIGATION);
- return RunMessageLoop(timeout_ms, NULL);
-}
-
-bool AutomationProxyForExternalTab::WaitForMessage(int timeout_ms) {
- set_quit_after(AutomationProxyForExternalTab::QUIT_AFTER_MESSAGE);
- return RunMessageLoop(timeout_ms, NULL);
-}
-
-bool AutomationProxyForExternalTab::WaitForTabCleanup(TabProxy* tab,
- int timeout_ms) {
- DCHECK(tab);
- base::Time end_time =
- base::Time::Now() + TimeDelta::FromMilliseconds(timeout_ms);
- while (base::Time::Now() < end_time) {
- const int kWaitInterval = 50;
- DWORD wait_result = MsgWaitForMultipleObjects(0, NULL, FALSE, kWaitInterval,
- QS_ALLINPUT);
- if (!tab->is_valid())
- break;
- if (WAIT_OBJECT_0 == wait_result) {
- MSG msg = {0};
- while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- }
- }
-
- return !tab->is_valid();
+void ExternalTabUITestMockClient::ReplyData(
+ const std::string* data, int tab_handle, int request_id) {
+ AutomationProxy::Send(new AutomationMsg_RequestData(0, tab_handle,
+ request_id, *data));
}
-bool AutomationProxyForExternalTab::RunMessageLoop(
- int timeout_ms,
- gfx::NativeWindow window_to_monitor) {
- // If there's no host window then the abort or this loop will be stuck
- // in GetMessage
- if (!IsWindow(host_window_))
- return false;
-
- // Allow the renderers to connect.
- const int kTimerIdQuit = 100;
- const int kTimerIdProcessPendingMessages = 101;
-
- if (!window_to_monitor)
- window_to_monitor = host_window_;
-
- UINT_PTR quit_timer = ::SetTimer(host_window_, kTimerIdQuit,
- timeout_ms, NULL);
- UINT_PTR pump_timer = ::SetTimer(host_window_,
- kTimerIdProcessPendingMessages, 50, NULL);
-
- MSG msg;
- bool quit = false;
- do {
- BOOL ok = ::GetMessage(&msg, NULL, 0, 0);
- if (!ok || ok == -1)
- break;
-
- if (msg.message == WM_TIMER && msg.hwnd == host_window_) {
- switch (msg.wParam) {
- case kTimerIdProcessPendingMessages:
- MessageLoop::current()->RunAllPending();
- break;
- case kTimerIdQuit:
- quit = true;
- break;
- default:
- NOTREACHED() << "invalid timer id";
- break;
- }
- } else if ((msg.message == WM_QUIT) || (msg.message == kQuitLoopMessage)) {
- quit = true;
- } else {
- ::TranslateMessage(&msg);
- ::DispatchMessage(&msg);
- }
- } while (!quit && ::IsWindow(window_to_monitor));
-
- KillTimer(host_window_, quit_timer);
- KillTimer(host_window_, pump_timer);
- quit_after_ = QUIT_INVALID;
- return true;
+void ExternalTabUITestMockClient::ReplyEOF(int tab_handle, int request_id) {
+ AutomationProxy::Send(new AutomationMsg_RequestEnd(0, tab_handle,
+ request_id,
+ URLRequestStatus()));
}
-void AutomationProxyForExternalTab::OnMessageReceived(const IPC::Message& msg) {
- IPC_BEGIN_MESSAGE_MAP(AutomationProxyForExternalTab, msg)
- IPC_MESSAGE_HANDLER(AutomationMsg_DidNavigate, OnDidNavigate)
- IPC_MESSAGE_HANDLER(AutomationMsg_ForwardMessageToExternalHost,
- OnForwardMessageToExternalHost)
- IPC_END_MESSAGE_MAP()
+void ExternalTabUITestMockClient::Reply404(int tab_handle, int request_id) {
+ const IPC::AutomationURLResponse notfound = {"", "HTTP/1.1 404\r\n\r\n"};
+ ReplyStarted(&notfound, tab_handle, request_id);
+ ReplyEOF(tab_handle, request_id);
}
-void AutomationProxyForExternalTab::OnDidNavigate(
- int tab_handle,
- const IPC::NavigationInfo& nav_info) {
- navigate_complete_ = true;
- if (QUIT_AFTER_NAVIGATION == quit_after_)
- QuitLoop();
-}
+void ExternalTabUITestMockClient::InvalidateHandle(
+ const IPC::Message& message) {
+ void* iter = NULL;
+ int handle;
+ ASSERT_TRUE(message.ReadInt(&iter, &handle));
-void AutomationProxyForExternalTab::OnForwardMessageToExternalHost(
- int handle,
- const std::string& message,
- const std::string& origin,
- const std::string& target) {
- messages_received_++;
- message_ = message;
- origin_ = origin;
- target_ = target;
-
- if (QUIT_AFTER_MESSAGE == quit_after_)
- QuitLoop();
+ // Call base class
+ AutomationProxy::InvalidateHandle(message);
+ HandleClosed(handle);
}
-const char simple_data_url[] =
- "data:text/html,<html><head><title>External tab test</title></head>"
- "<body>A simple page for testing a floating/invisible tab<br></div>"
- "</body></html>";
-
-// We have to derive from AutomationProxy in order to hook up
-// OnMessageReceived callbacks.
-class ExternalTabUITestMockClient : public AutomationProxy {
- public:
- explicit ExternalTabUITestMockClient(int execution_timeout)
- : AutomationProxy(execution_timeout),
- host_window_(NULL) {
- }
-
- MOCK_METHOD2(OnDidNavigate, void(int tab_handle,
- const IPC::NavigationInfo& nav_info));
- MOCK_METHOD4(OnForwardMessageToExternalHost, void(int handle,
- const std::string& message, const std::string& origin,
- const std::string& target));
- MOCK_METHOD3(OnRequestStart, void(int tab_handle, int request_id,
- const IPC::AutomationURLRequest& request));
- MOCK_METHOD3(OnRequestRead, void(int tab_handle, int request_id,
- int bytes_to_read));
- MOCK_METHOD3(OnRequestEnd, void(int tab_handle, int request_id,
- const URLRequestStatus& status));
- MOCK_METHOD3(OnSetCookieAsync, void(int tab_handle, const GURL& url,
- const std::string& cookie));
-
-
- MOCK_METHOD1(HandleClosed, void(int handle));
-
-
- // Action helpers for OnRequest* incoming messages. Create the message and
- // delegate sending to the base class. Apparently we do not have wrappers
- // in AutomationProxy for these messages.
- void ReplyStarted(const IPC::AutomationURLResponse* response,
- int tab_handle, int request_id) {
- AutomationProxy::Send(new AutomationMsg_RequestStarted(0, tab_handle,
- request_id, *response));
- }
-
- void ReplyData(const std::string* data, int tab_handle, int request_id) {
- AutomationProxy::Send(new AutomationMsg_RequestData(0, tab_handle,
- request_id, *data));
- }
-
- void ReplyEOF(int tab_handle, int request_id) {
- AutomationProxy::Send(new AutomationMsg_RequestEnd(0, tab_handle,
- request_id,
- URLRequestStatus()));
- }
-
- void Reply404(int tab_handle, int request_id) {
- const IPC::AutomationURLResponse notfound = {"", "HTTP/1.1 404\r\n\r\n"};
- ReplyStarted(&notfound, tab_handle, request_id);
- ReplyEOF(tab_handle, request_id);
- }
-
- // Test setup helpers
- scoped_refptr<TabProxy> CreateHostWindowAndTab(
- const IPC::ExternalTabSettings& settings);
- scoped_refptr<TabProxy> CreateTabWithUrl(const GURL& initial_url);
- void DestroyHostWindow();
-
- static const IPC::ExternalTabSettings default_settings;
- protected:
- HWND host_window_;
-
- // Simple dispatcher to above OnXXX methods.
- virtual void OnMessageReceived(const IPC::Message& msg);
- virtual void InvalidateHandle(const IPC::Message& message) {
- void* iter = NULL;
- int handle;
- ASSERT_TRUE(message.ReadInt(&iter, &handle));
-
- // Call base class
- AutomationProxy::InvalidateHandle(message);
- HandleClosed(handle);
- }
-};
-
// Most of the time we need external tab with these settings.
const IPC::ExternalTabSettings ExternalTabUITestMockClient::default_settings = {
NULL, gfx::Rect(), // will be replaced by CreateHostWindowAndTab
@@ -995,8 +758,14 @@ scoped_refptr<TabProxy> ExternalTabUITestMockClient::CreateTabWithUrl(
void ExternalTabUITestMockClient::DestroyHostWindow() {
::DestroyWindow(host_window_);
+ host_window_ = NULL;
}
+bool ExternalTabUITestMockClient::HostWindowExists() {
+ return (host_window_ != NULL) && ::IsWindow(host_window_);
+}
+
+
// Handy macro
#define QUIT_LOOP(loop) testing::InvokeWithoutArgs(\
CreateFunctor(loop, &TimedMessageLoopRunner::Quit))
diff --git a/chrome/test/automation/automation_proxy_uitest.h b/chrome/test/automation/automation_proxy_uitest.h
index 7fa1a2b..0701c47 100644
--- a/chrome/test/automation/automation_proxy_uitest.h
+++ b/chrome/test/automation/automation_proxy_uitest.h
@@ -14,24 +14,11 @@
#include "chrome/test/automation/automation_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "googleurl/src/gurl.h"
+#include "testing/gmock/include/gmock/gmock.h"
class TabProxy;
class ExternalTabUITestMockClient;
-class ExternalTabUITest : public UITest {
- public:
- // Override UITest's CreateAutomationProxy to provide the unit test
- // with our special implementation of AutomationProxy.
- // This function is called from within UITest::LaunchBrowserAndServer.
- virtual AutomationProxy* CreateAutomationProxy(int execution_timeout);
- protected:
- // Filtered Inet will override automation callbacks for network resources.
- virtual bool ShouldFilterInet() {
- return false;
- }
- ExternalTabUITestMockClient* mock_;
-};
-
// Base class for automation proxy testing.
class AutomationProxyVisibleTest : public UITest {
protected:
@@ -40,114 +27,71 @@ class AutomationProxyVisibleTest : public UITest {
}
};
-// Automation proxy UITest that allows tests to override the automation
-// proxy used by the UITest base class.
-template <class AutomationProxyClass>
-class CustomAutomationProxyTest : public AutomationProxyVisibleTest {
- protected:
- CustomAutomationProxyTest() {
- }
-
- // Override UITest's CreateAutomationProxy to provide our the unit test
- // with our special implementation of AutomationProxy.
- // This function is called from within UITest::LaunchBrowserAndServer.
- virtual AutomationProxy* CreateAutomationProxy(int execution_timeout) {
- AutomationProxyClass* proxy = new AutomationProxyClass(execution_timeout);
- return proxy;
- }
-};
-
-// A single-use AutomationProxy implementation that's good
-// for a single navigation and a single ForwardMessageToExternalHost
-// message. Once the ForwardMessageToExternalHost message is received
-// the class posts a quit message to the thread on which the message
-// was received.
-class AutomationProxyForExternalTab : public AutomationProxy {
+// Used to implement external tab UI tests.
+//
+// We have to derive from AutomationProxy in order to hook up
+// OnMessageReceived callbacks.
+class ExternalTabUITestMockClient : public AutomationProxy {
public:
- // Allows us to reuse this mock for multiple tests. This is done
- // by setting a state to trigger posting of Quit message to the
- // wait loop.
- enum QuitAfter {
- QUIT_INVALID,
- QUIT_AFTER_NAVIGATION,
- QUIT_AFTER_MESSAGE,
- };
-
- explicit AutomationProxyForExternalTab(int execution_timeout);
- ~AutomationProxyForExternalTab();
-
- int messages_received() const {
- return messages_received_;
- }
-
- const std::string& message() const {
- return message_;
- }
-
- const std::string& origin() const {
- return origin_;
- }
-
- const std::string& target() const {
- return target_;
- }
-
- // Creates and sisplays a top-level window, that can be used as a parent
- // to the external tab.window.
- gfx::NativeWindow CreateHostWindow();
- scoped_refptr<TabProxy> CreateTabWithHostWindow(bool is_incognito,
- const GURL& initial_url, gfx::NativeWindow* container_wnd,
- gfx::NativeWindow* tab_wnd);
+ explicit ExternalTabUITestMockClient(int execution_timeout);
+
+ MOCK_METHOD2(OnDidNavigate, void(int tab_handle,
+ const IPC::NavigationInfo& nav_info));
+ MOCK_METHOD4(OnForwardMessageToExternalHost, void(int handle,
+ const std::string& message, const std::string& origin,
+ const std::string& target));
+ MOCK_METHOD3(OnRequestStart, void(int tab_handle, int request_id,
+ const IPC::AutomationURLRequest& request));
+ MOCK_METHOD3(OnRequestRead, void(int tab_handle, int request_id,
+ int bytes_to_read));
+ MOCK_METHOD3(OnRequestEnd, void(int tab_handle, int request_id,
+ const URLRequestStatus& status));
+ MOCK_METHOD3(OnSetCookieAsync, void(int tab_handle, const GURL& url,
+ const std::string& cookie));
+
+ MOCK_METHOD1(HandleClosed, void(int handle));
+
+ // Action helpers for OnRequest* incoming messages. Create the message and
+ // delegate sending to the base class. Apparently we do not have wrappers
+ // in AutomationProxy for these messages.
+ void ReplyStarted(const IPC::AutomationURLResponse* response,
+ int tab_handle, int request_id);
+ void ReplyData(const std::string* data, int tab_handle, int request_id);
+ void ReplyEOF(int tab_handle, int request_id);
+ void Reply404(int tab_handle, int request_id);
+
+ // Test setup helpers
+ scoped_refptr<TabProxy> CreateHostWindowAndTab(
+ const IPC::ExternalTabSettings& settings);
+ scoped_refptr<TabProxy> CreateTabWithUrl(const GURL& initial_url);
+
+ // Destroys the host window.
void DestroyHostWindow();
+ // Returns true if the host window exists.
+ bool HostWindowExists();
- // Wait for the event to happen or timeout
- bool WaitForNavigation(int timeout_ms);
- bool WaitForMessage(int timeout_ms);
- bool WaitForTabCleanup(TabProxy* tab, int timeout_ms);
-
- // Enters a message loop that processes window messages as well
- // as calling MessageLoop::current()->RunAllPending() to process any
- // incoming IPC messages. The timeout_ms parameter is the maximum
- // time the loop will run. To end the loop earlier, post a quit message to
- // the thread.
- bool RunMessageLoop(int timeout_ms, gfx::NativeWindow window_to_monitor);
-
+ static const IPC::ExternalTabSettings default_settings;
protected:
-#if defined(OS_WIN)
- static const int kQuitLoopMessage = WM_APP + 11;
- // Quit the message loop
- void QuitLoop() {
- DCHECK(IsWindow(host_window_));
- // We could post WM_QUIT but lets keep it out of accidental usage
- // by anyone else peeking it.
- PostMessage(host_window_, kQuitLoopMessage, 0, 0);
- }
-#endif // defined(OS_WIN)
-
- // Internal state to flag posting of a quit message to the loop
- void set_quit_after(QuitAfter q) {
- quit_after_ = q;
- }
+ gfx::NativeWindow host_window_;
+ // Simple dispatcher to above OnXXX methods.
virtual void OnMessageReceived(const IPC::Message& msg);
+ virtual void InvalidateHandle(const IPC::Message& message);
+};
- void OnDidNavigate(int tab_handle, const IPC::NavigationInfo& nav_info);
- void OnForwardMessageToExternalHost(int handle,
- const std::string& message,
- const std::string& origin,
- const std::string& target);
-
+// Base your external tab UI tests on this.
+class ExternalTabUITest : public UITest {
+ public:
+ // Override UITest's CreateAutomationProxy to provide the unit test
+ // with our special implementation of AutomationProxy.
+ // This function is called from within UITest::LaunchBrowserAndServer.
+ virtual AutomationProxy* CreateAutomationProxy(int execution_timeout);
protected:
- bool navigate_complete_;
- int messages_received_;
- std::string message_, origin_, target_;
- QuitAfter quit_after_;
- const wchar_t* host_window_class_;
- gfx::NativeWindow host_window_;
+ // Filtered Inet will override automation callbacks for network resources.
+ virtual bool ShouldFilterInet() {
+ return false;
+ }
+ ExternalTabUITestMockClient* mock_;
};
-// A test harness for testing external tabs.
-typedef CustomAutomationProxyTest<AutomationProxyForExternalTab>
- ExternalTabTestType;
-
#endif // CHROME_TEST_AUTOMATION_AUTOMATION_PROXY_UITEST_H_