Commit 2449703f authored by huanr@chromium.org's avatar huanr@chromium.org

Making CloseWindow and CloseTab automation API

synchronous and robust.

Adding automation APIs with corresponding
IPC messages to count and find normal browser
windows.


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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15058 0039d316-1c4b-4281-b951-d872f2087c98
parent d4bf3bf8
......@@ -902,10 +902,14 @@ void AutomationProvider::OnMessageReceived(const IPC::Message& message) {
GetRedirectsFrom)
IPC_MESSAGE_HANDLER(AutomationMsg_BrowserWindowCount,
GetBrowserWindowCount)
IPC_MESSAGE_HANDLER(AutomationMsg_NormalBrowserWindowCount,
GetNormalBrowserWindowCount)
IPC_MESSAGE_HANDLER(AutomationMsg_BrowserWindow, GetBrowserWindow)
IPC_MESSAGE_HANDLER(AutomationMsg_LastActiveBrowserWindow,
GetLastActiveBrowserWindow)
IPC_MESSAGE_HANDLER(AutomationMsg_ActiveWindow, GetActiveWindow)
IPC_MESSAGE_HANDLER(AutomationMsg_FindNormalBrowserWindow,
FindNormalBrowserWindow)
IPC_MESSAGE_HANDLER(AutomationMsg_IsWindowActive, IsWindowActive)
IPC_MESSAGE_HANDLER(AutomationMsg_ActivateWindow, ActivateWindow);
#if defined(OS_WIN)
......@@ -1304,6 +1308,11 @@ void AutomationProvider::GetBrowserWindowCount(int* window_count) {
*window_count = static_cast<int>(BrowserList::size());
}
void AutomationProvider::GetNormalBrowserWindowCount(int* window_count) {
*window_count = static_cast<int>(
BrowserList::GetBrowserCountForType(profile_, Browser::TYPE_NORMAL));
}
void AutomationProvider::GetShowingAppModalDialog(bool* showing_dialog,
int* dialog_button) {
AppModalDialog* dialog_delegate = AppModalDialogQueue::active_dialog();
......@@ -1338,7 +1347,6 @@ void AutomationProvider::GetBrowserWindow(int index, int* handle) {
*handle = 0;
if (index >= 0) {
BrowserList::const_iterator iter = BrowserList::begin();
for (; (iter != BrowserList::end()) && (index > 0); ++iter, --index);
if (iter != BrowserList::end()) {
*handle = browser_tracker_->Add(*iter);
......@@ -1346,6 +1354,14 @@ void AutomationProvider::GetBrowserWindow(int index, int* handle) {
}
}
void AutomationProvider::FindNormalBrowserWindow(int* handle) {
*handle = 0;
Browser* browser = BrowserList::FindBrowserWithType(profile_,
Browser::TYPE_NORMAL);
if (browser)
*handle = browser_tracker_->Add(browser);
}
void AutomationProvider::GetLastActiveBrowserWindow(int* handle) {
*handle = 0;
Browser* browser = BrowserList::GetLastActive();
......
......@@ -132,9 +132,13 @@ class AutomationProvider : public base::RefCounted<AutomationProvider>,
int handle,
int* response_value);
void GetBrowserWindowCount(int* window_count);
void GetNormalBrowserWindowCount(int* window_count);
void GetShowingAppModalDialog(bool* showing_dialog, int* dialog_button);
void ClickAppModalDialogButton(int button, bool* success);
// Be aware that the browser window returned might be of non TYPE_NORMAL
// or in incognito mode.
void GetBrowserWindow(int index, int* handle);
void FindNormalBrowserWindow(int* handle);
void GetLastActiveBrowserWindow(int* handle);
void GetActiveWindow(int* handle);
#if defined(OS_WIN)
......
......@@ -25,6 +25,54 @@ void AutomatedUITestBase::SetUp() {
set_active_browser(automation()->GetBrowserWindow(0));
}
bool AutomatedUITestBase::CloseActiveTab() {
BrowserProxy* browser = active_browser();
int tab_count;
bool is_timeout;
browser->GetTabCountWithTimeout(&tab_count,
action_max_timeout_ms(),
&is_timeout);
if (is_timeout) {
LogInfoMessage("get_tab_count_timed_out");
return false;
}
if (tab_count > 1) {
scoped_ptr<TabProxy> tab(GetActiveTab());
// Wait until tab is closed.
return tab->Close(true);
} else if (tab_count == 1) {
// Synchronously close the window if it is not the last window.
return CloseActiveWindow();
} else {
LogInfoMessage("invalid_tab_count");
return false;
}
}
bool AutomatedUITestBase::CloseActiveWindow() {
int browser_windows_count = 0;
if (!automation()->GetNormalBrowserWindowCount(&browser_windows_count))
return false;
// Avoid quitting the application by not closing the last window.
if (browser_windows_count < 2)
return false;
bool application_closed;
CloseBrowser(active_browser(), &application_closed);
if (application_closed) {
LogErrorMessage("Application closed unexpectedly.");
return false;
}
BrowserProxy* browser = automation()->FindNormalBrowserWindow();
if (browser == NULL) {
LogErrorMessage("Can't find browser window.");
return false;
}
set_active_browser(browser);
return true;
}
bool AutomatedUITestBase::DuplicateTab() {
return RunCommand(IDC_DUPLICATE_TAB);
}
......@@ -91,3 +139,18 @@ bool AutomatedUITestBase::RunCommand(int browser_command) {
}
return true;
}
TabProxy* AutomatedUITestBase::GetActiveTab() {
BrowserProxy* browser = active_browser();
if (browser == NULL) {
LogErrorMessage("browser_window_not_found");
return false;
}
bool did_timeout;
TabProxy* tab =
browser->GetActiveTabWithTimeout(action_max_timeout_ms(), &did_timeout);
if (did_timeout)
return NULL;
return tab;
}
......@@ -21,6 +21,18 @@ class AutomatedUITestBase : public UITest {
// Actions
// NOTE: This list is sorted alphabetically.
// All functions are synchronous unless specified with Async.
// Close the selected tab in the current browser window. The function will
// not try close the tab if it is the only tab of the last normal window, so
// the application is not got closed.
// Returns true if the tab is closed, false otherwise.
bool CloseActiveTab();
// Close the current browser window if it is not the only window left.
// (Closing the last window will get application closed.)
// Returns true if the window is closed, false otherwise.
bool CloseActiveWindow();
// Duplicates the current tab.
// Returns true if a duplicated tab is added.
......@@ -59,6 +71,11 @@ class AutomatedUITestBase : public UITest {
}
BrowserProxy* active_browser() const { return active_browser_.get(); }
// Get the selected tab within the current active browser window, then
// create a corresponding TabProxy and transfer the ownership to caller.
// If success return the pointer to the newly created TabProxy and the
// caller owns the TabProxy. Return NULL otherwise.
TabProxy* GetActiveTab();
private:
scoped_ptr<BrowserProxy> active_browser_;
......
......@@ -30,7 +30,7 @@ TEST_F(AutomatedUITestBase, DuplicateTab) {
ASSERT_EQ(3, tab_count);
}
TEST_F(AutomatedUITestBase, OpenCloseBrowserWindow) {
TEST_F(AutomatedUITestBase, OpenBrowserWindow) {
int num_browser_windows;
int tab_count;
automation()->GetBrowserWindowCount(&num_browser_windows);
......@@ -76,3 +76,83 @@ TEST_F(AutomatedUITestBase, OpenCloseBrowserWindow) {
automation()->GetBrowserWindowCount(&num_browser_windows);
ASSERT_EQ(1, num_browser_windows);
}
TEST_F(AutomatedUITestBase, CloseBrowserWindow) {
int tab_count;
NewTab();
active_browser()->GetTabCount(&tab_count);
ASSERT_EQ(2, tab_count);
ASSERT_TRUE(OpenAndActivateNewBrowserWindow(NULL));
NewTab();
NewTab();
active_browser()->GetTabCount(&tab_count);
ASSERT_EQ(3, tab_count);
ASSERT_TRUE(OpenAndActivateNewBrowserWindow(NULL));
NewTab();
NewTab();
NewTab();
active_browser()->GetTabCount(&tab_count);
ASSERT_EQ(4, tab_count);
ASSERT_TRUE(CloseActiveWindow());
active_browser()->GetTabCount(&tab_count);
if (tab_count == 2) {
ASSERT_TRUE(CloseActiveWindow());
active_browser()->GetTabCount(&tab_count);
ASSERT_EQ(3, tab_count);
} else {
ASSERT_EQ(3, tab_count);
ASSERT_TRUE(CloseActiveWindow());
active_browser()->GetTabCount(&tab_count);
ASSERT_EQ(2, tab_count);
}
ASSERT_FALSE(CloseActiveWindow());
}
TEST_F(AutomatedUITestBase, CloseTab) {
int num_browser_windows;
int tab_count;
NewTab();
automation()->GetBrowserWindowCount(&num_browser_windows);
ASSERT_EQ(1, num_browser_windows);
active_browser()->GetTabCount(&tab_count);
ASSERT_EQ(2, tab_count);
ASSERT_TRUE(OpenAndActivateNewBrowserWindow(NULL));
NewTab();
NewTab();
active_browser()->GetTabCount(&tab_count);
ASSERT_EQ(3, tab_count);
automation()->GetBrowserWindowCount(&num_browser_windows);
ASSERT_EQ(2, num_browser_windows);
ASSERT_TRUE(CloseActiveTab());
active_browser()->GetTabCount(&tab_count);
ASSERT_EQ(2, tab_count);
ASSERT_TRUE(CloseActiveTab());
active_browser()->GetTabCount(&tab_count);
ASSERT_EQ(1, tab_count);
num_browser_windows = 0;
automation()->GetBrowserWindowCount(&num_browser_windows);
ASSERT_EQ(2, num_browser_windows);
// The browser window is closed by closing this tab.
ASSERT_TRUE(CloseActiveTab());
automation()->GetBrowserWindowCount(&num_browser_windows);
ASSERT_EQ(1, num_browser_windows);
// Active_browser_ is now the first created window.
active_browser()->GetTabCount(&tab_count);
ASSERT_EQ(2, tab_count);
ASSERT_TRUE(CloseActiveTab());
active_browser()->GetTabCount(&tab_count);
ASSERT_EQ(1, tab_count);
// The last tab should not be closed.
ASSERT_FALSE(CloseActiveTab());
active_browser()->GetTabCount(&tab_count);
ASSERT_EQ(1, tab_count);
}
......@@ -418,44 +418,6 @@ bool AutomatedUITest::ChangeEncoding() {
return RunCommandAsync((*encodings)[index].encoding_id);
}
bool AutomatedUITest::CloseActiveTab() {
bool return_value = false;
BrowserProxy* browser = active_browser();
if (browser == NULL) {
AddErrorAttribute("browser_window_not_found");
return false;
}
int browser_windows_count;
int tab_count;
bool is_timeout;
browser->GetTabCountWithTimeout(&tab_count,
action_max_timeout_ms(),
&is_timeout);
automation()->GetBrowserWindowCount(&browser_windows_count);
// Avoid quitting the application by not closing the last window.
if (tab_count > 1) {
return_value = browser->RunCommandAsync(IDC_CLOSE_TAB);
// Wait for the tab to close before we continue.
if (!browser->WaitForTabCountToBecome(tab_count - 1,
action_max_timeout_ms())) {
AddWarningAttribute("tab_count_failed_to_change");
return false;
}
} else if (tab_count == 1 && browser_windows_count > 1) {
return_value = browser->RunCommandAsync(IDC_CLOSE_TAB);
// Wait for the window to close before we continue.
if (!automation()->WaitForWindowCountToBecome(browser_windows_count - 1,
action_max_timeout_ms())) {
AddWarningAttribute("window_count_failed_to_change");
return false;
}
} else {
AddInfoAttribute("would_have_exited_application");
return false;
}
return return_value;
}
bool AutomatedUITest::FindInPage() {
return RunCommandAsync(IDC_FIND);
}
......@@ -481,18 +443,7 @@ bool AutomatedUITest::JavaScriptDebugger() {
}
bool AutomatedUITest::Navigate() {
BrowserProxy* browser = active_browser();
if (browser == NULL) {
AddErrorAttribute("browser_window_not_found");
return false;
}
bool did_timeout;
scoped_ptr<TabProxy> tab(
browser->GetActiveTabWithTimeout(action_max_timeout_ms(), &did_timeout));
// TODO(devint): This might be masking a bug. I can't think of many
// valid cases where we would get a browser window, but not be able
// to return an active tab. Yet this has happened and has triggered crashes.
// Investigate this.
scoped_ptr<TabProxy> tab(GetActiveTab());
if (tab.get() == NULL) {
AddErrorAttribute("active_tab_not_found");
return false;
......@@ -502,7 +453,7 @@ bool AutomatedUITest::Navigate() {
xml_writer_.AddAttribute("url", url);
}
GURL test_url(url);
did_timeout = false;
bool did_timeout = false;
tab->NavigateToURLWithTimeout(test_url,
command_execution_timeout_ms(),
&did_timeout);
......@@ -679,12 +630,7 @@ bool AutomatedUITest::FuzzyTestDialog(int num_actions) {
}
bool AutomatedUITest::ForceCrash() {
BrowserProxy* browser = active_browser();
if (browser == NULL) {
AddErrorAttribute("browser_window_not_found");
return false;
}
scoped_ptr<TabProxy> tab(browser->GetActiveTab());
scoped_ptr<TabProxy> tab(GetActiveTab());
GURL test_url("about:crash");
bool did_timeout;
tab->NavigateToURLWithTimeout(test_url, kDebuggingTimeoutMsec, &did_timeout);
......
......@@ -141,11 +141,6 @@ class AutomatedUITest : public AutomatedUITestBase {
// XML element: <ChangeEncoding/>
bool ChangeEncoding();
// Uses accelerator to close the active tab if it isn't the only tab.
// Returns false if active tab is the only tab, true otherwise.
// XML element: <CloseTab/>
bool CloseActiveTab();
// Opens one of the dialogs (chosen randomly) and exercises it.
// XML element: <Dialog/>
bool ExerciseDialog();
......
......@@ -895,4 +895,14 @@ IPC_BEGIN_MESSAGES(Automation)
// The return value contains the index, which will be -1 on failure.
IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_TabIndex, int, int)
// This message requests the handle (int64 app-unique identifier) of
// a valid normal browser window, i.e. normal type and non-incognito mode.
// On error, the returned handle value is 0.
IPC_SYNC_MESSAGE_ROUTED0_1(AutomationMsg_FindNormalBrowserWindow, int)
// This message requests the number of normal browser windows, i.e. normal
// type and non-incognito mode that the app currently has open. The return
// value is the number of windows.
IPC_SYNC_MESSAGE_ROUTED0_1(AutomationMsg_NormalBrowserWindowCount, int)
IPC_END_MESSAGES(Automation)
......@@ -299,6 +299,24 @@ bool AutomationProxy::GetBrowserWindowCount(int* num_windows) {
return succeeded;
}
bool AutomationProxy::GetNormalBrowserWindowCount(int* num_windows) {
if (!num_windows) {
NOTREACHED();
return false;
}
bool succeeded = SendWithTimeout(
new AutomationMsg_NormalBrowserWindowCount(0, num_windows),
command_execution_timeout_ms(), NULL);
if (!succeeded) {
DLOG(ERROR) << "GetNormalWindowCount did not complete in a timely fashion";
return false;
}
return succeeded;
}
bool AutomationProxy::WaitForWindowCountToBecome(int count,
int wait_timeout) {
const TimeTicks start = TimeTicks::Now();
......@@ -438,7 +456,6 @@ WindowProxy* AutomationProxy::GetActiveWindow() {
return new WindowProxy(this, tracker_.get(), handle);
}
BrowserProxy* AutomationProxy::GetBrowserWindow(int window_index) {
int handle = 0;
......@@ -456,6 +473,21 @@ BrowserProxy* AutomationProxy::GetBrowserWindow(int window_index) {
return new BrowserProxy(this, tracker_.get(), handle);
}
BrowserProxy* AutomationProxy::FindNormalBrowserWindow() {
int handle = 0;
if (!SendWithTimeout(new AutomationMsg_FindNormalBrowserWindow(0, &handle),
command_execution_timeout_ms(), NULL)) {
return NULL;
}
if (handle == 0) {
return NULL;
}
return new BrowserProxy(this, tracker_.get(), handle);
}
BrowserProxy* AutomationProxy::GetLastActiveBrowserWindow() {
int handle = 0;
......
......@@ -94,6 +94,11 @@ class AutomationProxy : public IPC::Channel::Listener,
// Returns true on success.
bool WaitForWindowCountToBecome(int target_count, int wait_timeout);
// Fills the number of open normal browser windows (normal type and
// non-incognito mode) into the given variable, returning true on success.
// False likely indicates an IPC error.
bool GetNormalBrowserWindowCount(int* num_windows);
// Returns whether an app modal dialog window is showing right now (i.e., a
// javascript alert), and what buttons it contains.
bool GetShowingAppModalDialog(bool* showing_app_modal_dialog,
......@@ -118,6 +123,12 @@ class AutomationProxy : public IPC::Channel::Listener,
// Window numbers are 0-based.
BrowserProxy* GetBrowserWindow(int window_index);
// Finds the first browser window that is not incognito mode and of type
// TYPE_NORMAL, and returns its corresponding BrowserProxy, transferring
// ownership of the pointer to the caller.
// On failure, returns NULL.
BrowserProxy* FindNormalBrowserWindow();
// Returns the BrowserProxy for the browser window which was last active,
// transferring ownership of the pointer to the caller.
// TODO: If there was no last active browser window, or the last active
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment