summaryrefslogtreecommitdiffstats
path: root/chrome/test/reliability
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/test/reliability')
-rw-r--r--chrome/test/reliability/automated_ui_test_base.cc389
-rw-r--r--chrome/test/reliability/automated_ui_test_base.h162
-rw-r--r--chrome/test/reliability/automated_ui_test_interactive_test.cc69
-rw-r--r--chrome/test/reliability/automated_ui_test_test.cc410
-rw-r--r--chrome/test/reliability/automated_ui_tests.cc831
-rw-r--r--chrome/test/reliability/automated_ui_tests.h399
6 files changed, 2260 insertions, 0 deletions
diff --git a/chrome/test/reliability/automated_ui_test_base.cc b/chrome/test/reliability/automated_ui_test_base.cc
new file mode 100644
index 0000000..1fa7d8b
--- /dev/null
+++ b/chrome/test/reliability/automated_ui_test_base.cc
@@ -0,0 +1,389 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/test/reliability/automated_ui_test_base.h"
+
+#include "base/test/test_timeouts.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/ui/view_ids.h"
+#include "chrome/test/automation/automation_proxy.h"
+#include "chrome/test/automation/browser_proxy.h"
+#include "chrome/test/automation/tab_proxy.h"
+#include "chrome/test/automation/window_proxy.h"
+#include "chrome/test/ui/ui_test.h"
+#include "ui/base/events.h"
+#include "ui/gfx/point.h"
+#include "ui/gfx/rect.h"
+
+AutomatedUITestBase::AutomatedUITestBase() {}
+
+AutomatedUITestBase::~AutomatedUITestBase() {}
+
+void AutomatedUITestBase::LogErrorMessage(const std::string& error) {
+}
+
+void AutomatedUITestBase::LogWarningMessage(const std::string& warning) {
+}
+
+void AutomatedUITestBase::LogInfoMessage(const std::string& info) {
+}
+
+void AutomatedUITestBase::SetUp() {
+ UITest::SetUp();
+ set_active_browser(automation()->GetBrowserWindow(0));
+}
+
+bool AutomatedUITestBase::BackButton() {
+ return RunCommand(IDC_BACK);
+}
+
+bool AutomatedUITestBase::CloseActiveTab() {
+ BrowserProxy* browser = active_browser();
+ int tab_count;
+ if (!browser->GetTabCount(&tab_count)) {
+ LogErrorMessage("get_tab_count_failed");
+ return false;
+ }
+
+ if (tab_count > 1) {
+ return RunCommand(IDC_CLOSE_TAB);
+ } 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;
+ }
+ scoped_refptr<BrowserProxy> browser(automation()->FindTabbedBrowserWindow());
+ if (!browser.get()) {
+ LogErrorMessage("Can't find browser window.");
+ return false;
+ }
+ set_active_browser(browser);
+ return true;
+}
+
+bool AutomatedUITestBase::DuplicateTab() {
+ return RunCommand(IDC_DUPLICATE_TAB);
+}
+
+bool AutomatedUITestBase::DragTabOut() {
+ BrowserProxy* browser = active_browser();
+ if (browser == NULL) {
+ LogErrorMessage("browser_window_not_found");
+ return false;
+ }
+
+ scoped_refptr<WindowProxy> window(
+ GetAndActivateWindowForBrowser(browser));
+ if (window.get() == NULL) {
+ LogErrorMessage("active_window_not_found");
+ return false;
+ }
+
+ int tab_count;
+ if (!browser->GetTabCount(&tab_count)) {
+ LogErrorMessage("get_tab_count_failed");
+ return false;
+ }
+
+ if (tab_count < 2) {
+ LogWarningMessage("not_enough_tabs_to_drag_out");
+ return false;
+ }
+
+ int tab_index;
+ if (!browser->GetActiveTabIndex(&tab_index)) {
+ LogWarningMessage("no_active_tab");
+ return false;
+ }
+
+ if (tab_index < 0) {
+ LogInfoMessage("invalid_active_tab_index");
+ return false;
+ }
+
+ gfx::Rect dragged_tab_bounds;
+ if (!window->GetViewBounds(VIEW_ID_TAB_0 + tab_index,
+ &dragged_tab_bounds, false)) {
+ LogWarningMessage("no_tab_view_found");
+ return false;
+ }
+
+ gfx::Rect urlbar_bounds;
+ if (!window->GetViewBounds(VIEW_ID_LOCATION_BAR,
+ &urlbar_bounds, false)) {
+ LogWarningMessage("no_location_bar_found");
+ return false;
+ }
+
+ // Click on the center of the tab, and drag it downwards.
+ gfx::Point start;
+ gfx::Point end;
+ start.set_x(dragged_tab_bounds.x() + dragged_tab_bounds.width() / 2);
+ start.set_y(dragged_tab_bounds.y() + dragged_tab_bounds.height() / 2);
+ end.set_x(start.x());
+ end.set_y(start.y() + 3 * urlbar_bounds.height());
+
+ if (!browser->SimulateDrag(start, end, ui::EF_LEFT_BUTTON_DOWN, false)) {
+ LogWarningMessage("failed_to_simulate_drag");
+ return false;
+ }
+
+ return true;
+}
+
+bool AutomatedUITestBase::DragActiveTab(bool drag_right) {
+ BrowserProxy* browser = active_browser();
+ if (browser == NULL) {
+ LogErrorMessage("browser_window_not_found");
+ return false;
+ }
+
+ scoped_refptr<WindowProxy> window(
+ GetAndActivateWindowForBrowser(browser));
+ if (window.get() == NULL) {
+ LogErrorMessage("active_window_not_found");
+ return false;
+ }
+
+ int tab_count;
+ if (!browser->GetTabCount(&tab_count)) {
+ LogErrorMessage("get_tab_count_failed");
+ return false;
+ }
+
+ if (tab_count < 2) {
+ LogWarningMessage("not_enough_tabs_to_drag_around");
+ return false;
+ }
+
+ int tab_index;
+ if (!browser->GetActiveTabIndex(&tab_index)) {
+ LogWarningMessage("no_active_tab");
+ return false;
+ }
+
+ gfx::Rect dragged_tab_bounds;
+ if (!window->GetViewBounds(VIEW_ID_TAB_0 + tab_index,
+ &dragged_tab_bounds, false)) {
+ LogWarningMessage("no_tab_view_found");
+ return false;
+ }
+
+ // Click on the center of the tab, and drag it to the left or the right.
+ gfx::Point dragged_tab_point = dragged_tab_bounds.CenterPoint();
+ gfx::Point destination_point = dragged_tab_point;
+
+ int new_tab_index;
+ if (drag_right) {
+ if (tab_index >= (tab_count - 1)) {
+ LogInfoMessage("cant_drag_to_right");
+ return false;
+ }
+ new_tab_index = tab_index + 1;
+ destination_point.Offset(2 * dragged_tab_bounds.width() / 3, 0);
+ } else {
+ if (tab_index <= 0) {
+ LogInfoMessage("cant_drag_to_left");
+ return false;
+ }
+ new_tab_index = tab_index - 1;
+ destination_point.Offset(-2 * dragged_tab_bounds.width() / 3, 0);
+ }
+
+ if (!browser->SimulateDrag(dragged_tab_point, destination_point,
+ ui::EF_LEFT_BUTTON_DOWN, false)) {
+ LogWarningMessage("failed_to_simulate_drag");
+ return false;
+ }
+
+ if (!browser->WaitForTabToBecomeActive(new_tab_index,
+ TestTimeouts::action_timeout_ms())) {
+ LogWarningMessage("failed_to_reindex_tab");
+ return false;
+ }
+
+ return true;
+}
+
+bool AutomatedUITestBase::FindInPage() {
+ if (!RunCommandAsync(IDC_FIND))
+ return false;
+
+ return WaitForFindWindowVisibilityChange(active_browser(), true);
+}
+
+bool AutomatedUITestBase::ForwardButton() {
+ return RunCommand(IDC_FORWARD);
+}
+
+bool AutomatedUITestBase::GoOffTheRecord() {
+ return RunCommand(IDC_NEW_INCOGNITO_WINDOW);
+}
+
+bool AutomatedUITestBase::Home() {
+ return RunCommand(IDC_HOME);
+}
+
+bool AutomatedUITestBase::OpenAndActivateNewBrowserWindow(
+ scoped_refptr<BrowserProxy>* previous_browser) {
+ if (!automation()->OpenNewBrowserWindow(Browser::TYPE_TABBED,
+ true /* SW_SHOWNORMAL */)) {
+ LogWarningMessage("failed_to_open_new_browser_window");
+ return false;
+ }
+ int num_browser_windows;
+ if (!automation()->GetBrowserWindowCount(&num_browser_windows)) {
+ LogErrorMessage("failed_to_get_browser_window_count");
+ return false;
+ }
+ // Get the most recently opened browser window and activate the tab
+ // in order to activate this browser window.
+ scoped_refptr<BrowserProxy> browser(
+ automation()->GetBrowserWindow(num_browser_windows - 1));
+ if (browser.get() == NULL) {
+ LogErrorMessage("browser_window_not_found");
+ return false;
+ }
+ if (!browser->ActivateTab(0)) {
+ LogWarningMessage("failed_to_activate_tab");
+ return false;
+ }
+
+ if (previous_browser) {
+ DCHECK(previous_browser->get() == NULL);
+ active_browser_.swap(*previous_browser);
+ }
+
+ active_browser_.swap(browser);
+ return true;
+}
+
+bool AutomatedUITestBase::Navigate(const GURL& url) {
+ scoped_refptr<TabProxy> tab(GetActiveTab());
+ if (tab.get() == NULL) {
+ LogErrorMessage("active_tab_not_found");
+ return false;
+ }
+ AutomationMsg_NavigationResponseValues result = tab->NavigateToURL(url);
+ if (result != AUTOMATION_MSG_NAVIGATION_SUCCESS) {
+ LogErrorMessage("navigation_failed");
+ return false;
+ }
+
+ return true;
+}
+
+bool AutomatedUITestBase::NewTab() {
+ // Apply accelerator and wait for a new tab to open, if either
+ // fails, return false. Apply Accelerator takes care of logging its failure.
+ return RunCommand(IDC_NEW_TAB);
+}
+
+bool AutomatedUITestBase::ReloadPage() {
+ return RunCommand(IDC_RELOAD);
+}
+
+bool AutomatedUITestBase::RestoreTab() {
+ return RunCommand(IDC_RESTORE_TAB);
+}
+
+bool AutomatedUITestBase::SelectNextTab() {
+ return RunCommand(IDC_SELECT_NEXT_TAB);
+}
+
+bool AutomatedUITestBase::SelectPreviousTab() {
+ return RunCommand(IDC_SELECT_PREVIOUS_TAB);
+}
+
+bool AutomatedUITestBase::ShowBookmarkBar() {
+ bool is_visible;
+ bool is_animating;
+ if (!active_browser()->GetBookmarkBarVisibility(&is_visible,
+ &is_animating)) {
+ return false;
+ }
+
+ if (is_visible) {
+ // If the bar is visible, then issuing the command again will toggle it.
+ return true;
+ }
+
+ if (!RunCommandAsync(IDC_SHOW_BOOKMARK_BAR))
+ return false;
+
+ return WaitForBookmarkBarVisibilityChange(active_browser(), true);
+}
+
+bool AutomatedUITestBase::ShowDownloads() {
+ return RunCommand(IDC_SHOW_DOWNLOADS);
+}
+
+bool AutomatedUITestBase::ShowHistory() {
+ return RunCommand(IDC_SHOW_HISTORY);
+}
+
+bool AutomatedUITestBase::RunCommandAsync(int browser_command) {
+ BrowserProxy* browser = active_browser();
+ if (NULL == browser) {
+ LogErrorMessage("browser_window_not_found");
+ return false;
+ }
+
+ if (!browser->RunCommandAsync(browser_command)) {
+ LogWarningMessage("failure_running_browser_command");
+ return false;
+ }
+ return true;
+}
+
+bool AutomatedUITestBase::RunCommand(int browser_command) {
+ BrowserProxy* browser = active_browser();
+ if (NULL == browser) {
+ LogErrorMessage("browser_window_not_found");
+ return false;
+ }
+
+ if (!browser->RunCommand(browser_command)) {
+ LogWarningMessage("failure_running_browser_command");
+ return false;
+ }
+ return true;
+}
+
+scoped_refptr<TabProxy> AutomatedUITestBase::GetActiveTab() {
+ BrowserProxy* browser = active_browser();
+ if (browser == NULL) {
+ LogErrorMessage("browser_window_not_found");
+ return NULL;
+ }
+
+ return browser->GetActiveTab();
+}
+
+scoped_refptr<WindowProxy> AutomatedUITestBase::GetAndActivateWindowForBrowser(
+ BrowserProxy* browser) {
+ if (!browser->BringToFront()) {
+ LogWarningMessage("failed_to_bring_window_to_front");
+ return NULL;
+ }
+
+ return browser->GetWindow();
+}
diff --git a/chrome/test/reliability/automated_ui_test_base.h b/chrome/test/reliability/automated_ui_test_base.h
new file mode 100644
index 0000000..eefc24a
--- /dev/null
+++ b/chrome/test/reliability/automated_ui_test_base.h
@@ -0,0 +1,162 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_TEST_RELIABILITY_AUTOMATED_UI_TEST_BASE_H_
+#define CHROME_TEST_RELIABILITY_AUTOMATED_UI_TEST_BASE_H_
+#pragma once
+
+#include <string>
+
+#include "chrome/test/ui/ui_test.h"
+
+class WindowProxy;
+
+class AutomatedUITestBase : public UITest {
+ protected:
+ AutomatedUITestBase();
+ virtual ~AutomatedUITestBase();
+
+ virtual void SetUp();
+
+ virtual void LogErrorMessage(const std::string &error);
+ virtual void LogWarningMessage(const std::string &warning);
+ virtual void LogInfoMessage(const std::string &info);
+
+ // Actions
+
+ // NOTE: This list is sorted alphabetically.
+ // All functions are synchronous unless specified with Async.
+
+ // Go back in active tab.
+ // Returns true if successful, false otherwise.
+ bool BackButton();
+
+ // 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.
+ bool DuplicateTab();
+
+ // Drags the active tab. The tab is dragged vertically to remove it from the
+ // tabstrip. Returns true if the tab is dragged, false otherwise.
+ // Note: returning true doesn't necessarily create a new window as the tab
+ // could be dragged in to another window.
+ bool DragTabOut();
+
+ // Drags the active tab.
+ // If |drag_right| is true, if there is a tab to the right of the active tab,
+ // the active tab is dragged to that tabs position. If |drag_right| is false,
+ // if there is a tab to the left of the active tab, the active tab is dragged
+ // to that tabs position. Returns true if the tab is dragged. If it returns
+ // false, the tab is not dragged, probably because no other tab exists to
+ // drag the active tab over.
+ bool DragActiveTab(bool drag_right);
+
+ // Activates "find in page" on the current page. Returns true on success.
+ bool FindInPage();
+
+ // Go forward in active tab.
+ // Returns true if successful, false otherwise.
+ bool ForwardButton();
+
+ // Opens an OffTheRecord browser window.
+ bool GoOffTheRecord();
+
+ // Navigates to the Home page.
+ // Returns true if call to activate the accelerator is successful.
+ bool Home();
+
+ // Navigates the activate tab to given url.
+ bool Navigate(const GURL& url);
+
+ // Opens a new tab in the active window using an accelerator.
+ // Returns true if a new tab is successfully opened.
+ bool NewTab();
+
+ // Opens a new browser window by calling automation()->OpenNewBrowserWindow.
+ // Then activates the tab opened in the new window.
+ // Returns true if window is successfully created.
+ // If optional parameter previous_browser is passed in, it is set to be the
+ // previous browser window when new window is successfully created, and the
+ // caller owns previous_browser.
+ bool OpenAndActivateNewBrowserWindow(
+ scoped_refptr<BrowserProxy>* previous_browser);
+
+ // Reload the active tab.
+ // Returns true if successful, false otherwise.
+ bool ReloadPage();
+
+ // Restores a previously closed tab.
+ // Returns true if the tab is successfully restored.
+ bool RestoreTab();
+
+ // Activates the next tab on the active browser window.
+ // Returns true on success.
+ bool SelectNextTab();
+
+ // Activates the previous tab on the active browser window.
+ // Returns true on success.
+ bool SelectPreviousTab();
+
+ // Displays the bookmark bar.
+ // Returns true on success.
+ bool ShowBookmarkBar();
+
+ // Opens the Downloads page in the current active browser window.
+ // Returns true on success.
+ bool ShowDownloads();
+
+ // Opens the History page in the current active browser window.
+ // Returns true on success.
+ bool ShowHistory();
+
+ // Runs the specified browser command in the current active browser.
+ // See Browser::ExecuteCommandWithDisposition() for the list of commands.
+ // Returns true if the call is successfully dispatched.
+ // Possible failures include the active window is not a browser window or
+ // the message to apply the accelerator fails.
+ bool RunCommandAsync(int browser_command);
+
+ // Runs the specified browser command in the current active browser, wait
+ // and return until the command has finished executing.
+ // See Browser::ExecuteCommandWithDisposition() for the list of commands.
+ // Returns true if the call is successfully dispatched and executed.
+ // Possible failures include the active window is not a browser window, or
+ // the message to apply the accelerator fails, or the command execution
+ // fails.
+ bool RunCommand(int browser_command);
+
+ void set_active_browser(BrowserProxy* browser) {
+ active_browser_ = browser;
+ }
+ 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.
+ scoped_refptr<TabProxy> GetActiveTab();
+
+ // Returns the WindowProxy associated with the given BrowserProxy
+ // (transferring ownership of the pointer to the caller) and brings that
+ // window to the top.
+ scoped_refptr<WindowProxy> GetAndActivateWindowForBrowser(
+ BrowserProxy* browser);
+
+ private:
+ scoped_refptr<BrowserProxy> active_browser_;
+
+ DISALLOW_COPY_AND_ASSIGN(AutomatedUITestBase);
+};
+
+#endif // CHROME_TEST_RELIABILITY_AUTOMATED_UI_TEST_BASE_H_
diff --git a/chrome/test/reliability/automated_ui_test_interactive_test.cc b/chrome/test/reliability/automated_ui_test_interactive_test.cc
new file mode 100644
index 0000000..1879485
--- /dev/null
+++ b/chrome/test/reliability/automated_ui_test_interactive_test.cc
@@ -0,0 +1,69 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_timeouts.h"
+#include "base/threading/platform_thread.h"
+#include "chrome/test/automation/automation_proxy.h"
+#include "chrome/test/automation/browser_proxy.h"
+#include "chrome/test/automation/tab_proxy.h"
+#include "chrome/test/reliability/automated_ui_test_base.h"
+#include "chrome/test/ui/ui_test.h"
+
+TEST_F(AutomatedUITestBase, DragOut) {
+ NewTab();
+ NewTab();
+ ASSERT_TRUE(active_browser()->WaitForTabCountToBecome(3));
+ base::PlatformThread::Sleep(TestTimeouts::action_timeout_ms());
+ ASSERT_TRUE(DragTabOut());
+ int window_count;
+ ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count));
+ ASSERT_EQ(2, window_count);
+}
+
+TEST_F(AutomatedUITestBase, DragLeftRight) {
+ NewTab();
+ NewTab();
+ ASSERT_TRUE(active_browser()->WaitForTabCountToBecome(3));
+ // TODO(phajdan.jr): We need a WaitForTabstripAnimationsToEnd() function.
+ // Every sleep in this file should be replaced with it.
+ base::PlatformThread::Sleep(TestTimeouts::action_timeout_ms());
+
+ scoped_refptr<TabProxy> dragged_tab(active_browser()->GetActiveTab());
+ int tab_index;
+ ASSERT_TRUE(dragged_tab->GetTabIndex(&tab_index));
+ EXPECT_EQ(2, tab_index);
+
+ // Drag the active tab to left. Now it should be the middle tab.
+ ASSERT_TRUE(DragActiveTab(false));
+ // We wait for the animation to be over.
+ base::PlatformThread::Sleep(TestTimeouts::action_timeout_ms());
+ ASSERT_TRUE(dragged_tab->GetTabIndex(&tab_index));
+ EXPECT_EQ(1, tab_index);
+
+ // Drag the active tab to left. Now it should be the leftmost tab.
+ ASSERT_TRUE(DragActiveTab(false));
+ base::PlatformThread::Sleep(TestTimeouts::action_timeout_ms());
+ ASSERT_TRUE(dragged_tab->GetTabIndex(&tab_index));
+ EXPECT_EQ(0, tab_index);
+
+ // Drag the active tab to left. It should fail since the active tab is
+ // already the leftmost tab.
+ ASSERT_FALSE(DragActiveTab(false));
+
+ // Drag the active tab to right. Now it should be the middle tab.
+ ASSERT_TRUE(DragActiveTab(true));
+ base::PlatformThread::Sleep(TestTimeouts::action_timeout_ms());
+ ASSERT_TRUE(dragged_tab->GetTabIndex(&tab_index));
+ EXPECT_EQ(1, tab_index);
+
+ // Drag the active tab to right. Now it should be the rightmost tab.
+ ASSERT_TRUE(DragActiveTab(true));
+ base::PlatformThread::Sleep(TestTimeouts::action_timeout_ms());
+ ASSERT_TRUE(dragged_tab->GetTabIndex(&tab_index));
+ EXPECT_EQ(2, tab_index);
+
+ // Drag the active tab to right. It should fail since the active tab is
+ // already the rightmost tab.
+ ASSERT_FALSE(DragActiveTab(true));
+}
diff --git a/chrome/test/reliability/automated_ui_test_test.cc b/chrome/test/reliability/automated_ui_test_test.cc
new file mode 100644
index 0000000..307caf5
--- /dev/null
+++ b/chrome/test/reliability/automated_ui_test_test.cc
@@ -0,0 +1,410 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/test/automation/automation_proxy.h"
+#include "chrome/test/automation/browser_proxy.h"
+#include "chrome/test/automation/tab_proxy.h"
+#include "chrome/test/reliability/automated_ui_test_base.h"
+#include "chrome/test/ui/ui_test.h"
+#include "googleurl/src/gurl.h"
+#include "net/base/net_util.h"
+
+TEST_F(AutomatedUITestBase, FindInPage) {
+ ASSERT_TRUE(FindInPage());
+ bool is_visible;
+ ASSERT_TRUE(active_browser()->IsFindWindowFullyVisible(&is_visible));
+ EXPECT_TRUE(is_visible);
+}
+
+TEST_F(AutomatedUITestBase, Home) {
+ FilePath path_prefix(test_data_directory_.AppendASCII("session_history"));
+ GURL bot1(net::FilePathToFileURL(path_prefix.AppendASCII("bot1.html")));
+ NavigateToURL(bot1); // To help verify that Home does something.
+
+ ASSERT_TRUE(Home());
+
+ GURL url;
+ ASSERT_TRUE(active_browser()->GetActiveTab()->GetCurrentURL(&url));
+ EXPECT_EQ(GURL(chrome::kAboutBlankURL), url);
+
+ std::wstring title;
+ ASSERT_TRUE(active_browser()->GetActiveTab()->GetTabTitle(&title));
+ EXPECT_EQ(L"about:blank", title);
+}
+
+TEST_F(AutomatedUITestBase, OpenNewTab) {
+ int tab_count;
+ ASSERT_TRUE(active_browser()->GetTabCount(&tab_count));
+ ASSERT_EQ(1, tab_count);
+ NewTab();
+ ASSERT_TRUE(active_browser()->GetTabCount(&tab_count));
+ ASSERT_EQ(2, tab_count);
+ NewTab();
+ ASSERT_TRUE(active_browser()->GetTabCount(&tab_count));
+ ASSERT_EQ(3, tab_count);
+}
+
+TEST_F(AutomatedUITestBase, DuplicateTab) {
+ int tab_count;
+ ASSERT_TRUE(active_browser()->GetTabCount(&tab_count));
+ ASSERT_EQ(1, tab_count);
+ DuplicateTab();
+ ASSERT_TRUE(active_browser()->GetTabCount(&tab_count));
+ ASSERT_EQ(2, tab_count);
+ DuplicateTab();
+ ASSERT_TRUE(active_browser()->GetTabCount(&tab_count));
+ ASSERT_EQ(3, tab_count);
+}
+
+TEST_F(AutomatedUITestBase, RestoreTab) {
+ int tab_count;
+ ASSERT_TRUE(active_browser()->GetTabCount(&tab_count));
+ ASSERT_EQ(1, tab_count);
+ NewTab();
+ ASSERT_TRUE(active_browser()->GetTabCount(&tab_count));
+ ASSERT_EQ(2, tab_count);
+ FilePath path_prefix(test_data_directory_.AppendASCII("session_history"));
+ GURL test_url = net::FilePathToFileURL(path_prefix.AppendASCII("bot1.html"));
+ ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS,
+ GetActiveTab()->NavigateToURL(test_url));
+ CloseActiveTab();
+ ASSERT_TRUE(active_browser()->GetTabCount(&tab_count));
+ ASSERT_EQ(1, tab_count);
+ RestoreTab();
+ ASSERT_TRUE(active_browser()->GetTabCount(&tab_count));
+ ASSERT_EQ(2, tab_count);
+}
+
+// crbug.com/96049
+#if defined(OS_WIN)
+#define MAYBE_CloseTab FLAKY_CloseTab
+#else
+#define MAYBE_CloseTab CloseTab
+#endif
+
+TEST_F(AutomatedUITestBase, MAYBE_CloseTab) {
+ int num_browser_windows;
+ int tab_count;
+ NewTab();
+ ASSERT_TRUE(automation()->GetBrowserWindowCount(&num_browser_windows));
+ ASSERT_EQ(1, num_browser_windows);
+ ASSERT_TRUE(active_browser()->GetTabCount(&tab_count));
+ ASSERT_EQ(2, tab_count);
+
+ ASSERT_TRUE(OpenAndActivateNewBrowserWindow(NULL));
+ NewTab();
+ NewTab();
+ ASSERT_TRUE(active_browser()->GetTabCount(&tab_count));
+ ASSERT_EQ(3, tab_count);
+ ASSERT_TRUE(automation()->GetBrowserWindowCount(&num_browser_windows));
+ ASSERT_EQ(2, num_browser_windows);
+
+ ASSERT_TRUE(CloseActiveTab());
+ ASSERT_TRUE(active_browser()->GetTabCount(&tab_count));
+ ASSERT_EQ(2, tab_count);
+ ASSERT_TRUE(CloseActiveTab());
+ ASSERT_TRUE(active_browser()->GetTabCount(&tab_count));
+ ASSERT_EQ(1, tab_count);
+ num_browser_windows = 0;
+ ASSERT_TRUE(automation()->GetBrowserWindowCount(&num_browser_windows));
+ ASSERT_EQ(2, num_browser_windows);
+
+ // The browser window is closed by closing this tab.
+ ASSERT_TRUE(CloseActiveTab());
+ ASSERT_TRUE(automation()->GetBrowserWindowCount(&num_browser_windows));
+ ASSERT_EQ(1, num_browser_windows);
+ // Active_browser_ is now the first created window.
+ ASSERT_TRUE(active_browser()->GetTabCount(&tab_count));
+ ASSERT_EQ(2, tab_count);
+ ASSERT_TRUE(CloseActiveTab());
+ ASSERT_TRUE(active_browser()->GetTabCount(&tab_count));
+ ASSERT_EQ(1, tab_count);
+
+ // The last tab should not be closed.
+ ASSERT_FALSE(CloseActiveTab());
+ ASSERT_TRUE(active_browser()->GetTabCount(&tab_count));
+ ASSERT_EQ(1, tab_count);
+}
+
+// Flakiness tracked there: http://crbug.com/96049.
+TEST_F(AutomatedUITestBase, FLAKY_OpenBrowserWindow) {
+ int num_browser_windows;
+ int tab_count;
+ ASSERT_TRUE(automation()->GetBrowserWindowCount(&num_browser_windows));
+ ASSERT_EQ(1, num_browser_windows);
+ ASSERT_TRUE(active_browser()->GetTabCount(&tab_count));
+ ASSERT_EQ(1, tab_count);
+
+ scoped_refptr<BrowserProxy> browser_1;
+ ASSERT_TRUE(OpenAndActivateNewBrowserWindow(&browser_1));
+ ASSERT_TRUE(automation()->GetBrowserWindowCount(&num_browser_windows));
+ ASSERT_EQ(2, num_browser_windows);
+ ASSERT_TRUE(active_browser()->GetTabCount(&tab_count));
+ ASSERT_EQ(1, tab_count);
+ NewTab();
+ ASSERT_TRUE(browser_1->GetTabCount(&tab_count));
+ ASSERT_EQ(1, tab_count);
+ ASSERT_TRUE(active_browser()->GetTabCount(&tab_count));
+ ASSERT_EQ(2, tab_count);
+
+ scoped_refptr<BrowserProxy> browser_2;
+ ASSERT_TRUE(OpenAndActivateNewBrowserWindow(&browser_2));
+ ASSERT_TRUE(automation()->GetBrowserWindowCount(&num_browser_windows));
+ ASSERT_EQ(3, num_browser_windows);
+ ASSERT_TRUE(active_browser()->GetTabCount(&tab_count));
+ ASSERT_EQ(1, tab_count);
+ NewTab();
+ NewTab();
+ ASSERT_TRUE(browser_1->GetTabCount(&tab_count));
+ ASSERT_EQ(1, tab_count);
+ ASSERT_TRUE(browser_2->GetTabCount(&tab_count));
+ ASSERT_EQ(2, tab_count);
+ ASSERT_TRUE(active_browser()->GetTabCount(&tab_count));
+ ASSERT_EQ(3, tab_count);
+
+ bool application_closed;
+ CloseBrowser(browser_1.get(), &application_closed);
+ ASSERT_FALSE(application_closed);
+ ASSERT_TRUE(automation()->GetBrowserWindowCount(&num_browser_windows));
+ ASSERT_EQ(2, num_browser_windows);
+ CloseBrowser(browser_2.get(), &application_closed);
+ ASSERT_FALSE(application_closed);
+ ASSERT_TRUE(automation()->GetBrowserWindowCount(&num_browser_windows));
+ ASSERT_EQ(1, num_browser_windows);
+}
+
+// Flaky, see http://crbug.com/96039.
+#if defined(OS_WIN)
+#define MAYBE_CloseBrowserWindow FLAKY_CloseBrowserWindow
+#else
+#define MAYBE_CloseBrowserWindow CloseBrowserWindow
+#endif
+
+TEST_F(AutomatedUITestBase, MAYBE_CloseBrowserWindow) {
+ int tab_count;
+ NewTab();
+ ASSERT_TRUE(active_browser()->GetTabCount(&tab_count));
+ ASSERT_EQ(2, tab_count);
+
+ ASSERT_TRUE(OpenAndActivateNewBrowserWindow(NULL));
+ NewTab();
+ NewTab();
+ ASSERT_TRUE(active_browser()->GetTabCount(&tab_count));
+ ASSERT_EQ(3, tab_count);
+
+ ASSERT_TRUE(OpenAndActivateNewBrowserWindow(NULL));
+ NewTab();
+ NewTab();
+ NewTab();
+ ASSERT_TRUE(active_browser()->GetTabCount(&tab_count));
+ ASSERT_EQ(4, tab_count);
+
+ ASSERT_TRUE(CloseActiveWindow());
+ ASSERT_TRUE(active_browser()->GetTabCount(&tab_count));
+
+ if (tab_count == 2) {
+ ASSERT_TRUE(CloseActiveWindow());
+ ASSERT_TRUE(active_browser()->GetTabCount(&tab_count));
+ ASSERT_EQ(3, tab_count);
+ } else {
+ ASSERT_EQ(3, tab_count);
+ ASSERT_TRUE(CloseActiveWindow());
+ ASSERT_TRUE(active_browser()->GetTabCount(&tab_count));
+ ASSERT_EQ(2, tab_count);
+ }
+
+ ASSERT_FALSE(CloseActiveWindow());
+}
+
+TEST_F(AutomatedUITestBase, IncognitoWindow) {
+ int num_browser_windows;
+ int num_normal_browser_windows;
+ ASSERT_TRUE(automation()->GetBrowserWindowCount(&num_browser_windows));
+ ASSERT_EQ(1, num_browser_windows);
+ ASSERT_TRUE(
+ automation()->GetNormalBrowserWindowCount(&num_normal_browser_windows));
+ ASSERT_EQ(1, num_normal_browser_windows);
+
+ ASSERT_TRUE(GoOffTheRecord());
+ ASSERT_TRUE(GoOffTheRecord());
+ ASSERT_TRUE(automation()->GetBrowserWindowCount(&num_browser_windows));
+ ASSERT_EQ(3, num_browser_windows);
+ ASSERT_TRUE(
+ automation()->GetNormalBrowserWindowCount(&num_normal_browser_windows));
+ ASSERT_EQ(1, num_normal_browser_windows);
+
+ // There is only one normal window so it will not be closed.
+ ASSERT_FALSE(CloseActiveWindow());
+ ASSERT_TRUE(automation()->GetBrowserWindowCount(&num_browser_windows));
+ ASSERT_EQ(3, num_browser_windows);
+ ASSERT_TRUE(
+ automation()->GetNormalBrowserWindowCount(&num_normal_browser_windows));
+ ASSERT_EQ(1, num_normal_browser_windows);
+
+ set_active_browser(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(RunCommand(IDC_CLOSE_WINDOW));
+ set_active_browser(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(RunCommand(IDC_CLOSE_WINDOW));
+ ASSERT_TRUE(automation()->GetBrowserWindowCount(&num_browser_windows));
+ ASSERT_EQ(1, num_browser_windows);
+}
+
+// Flaky, see http://crbug.com/96039.
+#if defined(OS_WIN)
+#define MAYBE_OpenCloseBrowserWindowWithAccelerator \
+ FLAKY_OpenCloseBrowserWindowWithAccelerator
+#else
+#define MAYBE_OpenCloseBrowserWindowWithAccelerator \
+ OpenCloseBrowserWindowWithAccelerator
+#endif
+
+TEST_F(AutomatedUITestBase, MAYBE_OpenCloseBrowserWindowWithAccelerator) {
+ // Note: we don't use RunCommand(IDC_OPEN/CLOSE_WINDOW) to open/close
+ // browser window in automated ui tests. Instead we use
+ // OpenAndActivateNewBrowserWindow and CloseActiveWindow.
+ // There are other parts of UI test that use the accelerators. This is
+ // a unit test for those usage.
+ ASSERT_TRUE(RunCommand(IDC_NEW_WINDOW));
+ int num_browser_windows;
+ ASSERT_TRUE(automation()->GetBrowserWindowCount(&num_browser_windows));
+ ASSERT_EQ(2, num_browser_windows);
+ ASSERT_TRUE(RunCommand(IDC_NEW_WINDOW));
+ ASSERT_TRUE(RunCommand(IDC_NEW_WINDOW));
+ ASSERT_TRUE(RunCommand(IDC_NEW_WINDOW));
+ ASSERT_TRUE(RunCommand(IDC_NEW_WINDOW));
+ ASSERT_TRUE(RunCommand(IDC_NEW_WINDOW));
+ ASSERT_TRUE(automation()->GetBrowserWindowCount(&num_browser_windows));
+ ASSERT_EQ(7, num_browser_windows);
+
+ set_active_browser(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(RunCommand(IDC_CLOSE_WINDOW));
+ ASSERT_TRUE(automation()->GetBrowserWindowCount(&num_browser_windows));
+ ASSERT_EQ(6, num_browser_windows);
+ set_active_browser(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(RunCommand(IDC_CLOSE_WINDOW));
+ set_active_browser(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(RunCommand(IDC_CLOSE_WINDOW));
+ set_active_browser(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(RunCommand(IDC_CLOSE_WINDOW));
+ set_active_browser(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(RunCommand(IDC_CLOSE_WINDOW));
+ set_active_browser(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(RunCommand(IDC_CLOSE_WINDOW));
+ ASSERT_TRUE(automation()->GetBrowserWindowCount(&num_browser_windows));
+ ASSERT_EQ(1, num_browser_windows);
+}
+
+TEST_F(AutomatedUITestBase, Navigate) {
+ FilePath path_prefix(test_data_directory_.AppendASCII("session_history"));
+ GURL url1(net::FilePathToFileURL(path_prefix.AppendASCII("bot1.html")));
+ GURL url2(net::FilePathToFileURL(path_prefix.AppendASCII("bot2.html")));
+ GURL url3(net::FilePathToFileURL(path_prefix.AppendASCII("bot3.html")));
+ GURL url;
+ ASSERT_TRUE(Navigate(url1));
+ ASSERT_TRUE(GetActiveTab()->GetCurrentURL(&url));
+ ASSERT_EQ(url1, url);
+ ASSERT_TRUE(Navigate(url2));
+ ASSERT_TRUE(GetActiveTab()->GetCurrentURL(&url));
+ ASSERT_EQ(url2, url);
+ ASSERT_TRUE(Navigate(url3));
+ ASSERT_TRUE(GetActiveTab()->GetCurrentURL(&url));
+ ASSERT_EQ(url3, url);
+ ASSERT_TRUE(BackButton());
+ ASSERT_TRUE(GetActiveTab()->GetCurrentURL(&url));
+ ASSERT_EQ(url2, url);
+ ASSERT_TRUE(BackButton());
+ ASSERT_TRUE(GetActiveTab()->GetCurrentURL(&url));
+ ASSERT_EQ(url1, url);
+ ASSERT_TRUE(ForwardButton());
+ ASSERT_TRUE(GetActiveTab()->GetCurrentURL(&url));
+ ASSERT_EQ(url2, url);
+ ASSERT_TRUE(ReloadPage());
+ ASSERT_TRUE(GetActiveTab()->GetCurrentURL(&url));
+ ASSERT_EQ(url2, url);
+}
+
+// Flaky, see http://crbug.com/81050.
+#if defined(OS_MACOSX)
+#define MAYBE_SelectTab FLAKY_SelectTab
+#else
+#define MAYBE_SelectTab SelectTab
+#endif
+
+TEST_F(AutomatedUITestBase, MAYBE_SelectTab) {
+ FilePath filename(test_data_directory_);
+ filename = filename.AppendASCII("title2.html");
+ GURL url = net::FilePathToFileURL(filename);
+
+ ASSERT_TRUE(active_browser()->AppendTab(url));
+ ASSERT_TRUE(active_browser()->AppendTab(url));
+
+ int active_tab_index;
+ ASSERT_TRUE(active_browser()->GetActiveTabIndex(&active_tab_index));
+ ASSERT_EQ(2, active_tab_index);
+
+ ASSERT_TRUE(SelectNextTab());
+ ASSERT_TRUE(active_browser()->GetActiveTabIndex(&active_tab_index));
+ ASSERT_EQ(0, active_tab_index);
+
+ ASSERT_TRUE(SelectNextTab());
+ ASSERT_TRUE(active_browser()->GetActiveTabIndex(&active_tab_index));
+ ASSERT_EQ(1, active_tab_index);
+
+ ASSERT_TRUE(SelectPreviousTab());
+ ASSERT_TRUE(active_browser()->GetActiveTabIndex(&active_tab_index));
+ ASSERT_EQ(0, active_tab_index);
+
+ ASSERT_TRUE(SelectPreviousTab());
+ ASSERT_TRUE(active_browser()->GetActiveTabIndex(&active_tab_index));
+ ASSERT_EQ(2, active_tab_index);
+
+ ASSERT_TRUE(SelectPreviousTab());
+ ASSERT_TRUE(active_browser()->GetActiveTabIndex(&active_tab_index));
+ ASSERT_EQ(1, active_tab_index);
+
+ ASSERT_TRUE(SelectNextTab());
+ ASSERT_TRUE(active_browser()->GetActiveTabIndex(&active_tab_index));
+ ASSERT_EQ(2, active_tab_index);
+}
+
+TEST_F(AutomatedUITestBase, ShowBookmarkBar) {
+ ASSERT_TRUE(ShowBookmarkBar());
+ bool is_visible;
+ bool is_animating;
+ ASSERT_TRUE(active_browser()->GetBookmarkBarVisibility(&is_visible,
+ &is_animating));
+ ASSERT_TRUE(is_visible);
+ ASSERT_FALSE(is_animating);
+
+ // Try second time to make sure it won't make the bookmark bar
+ // disappear.
+ ASSERT_TRUE(ShowBookmarkBar());
+ ASSERT_TRUE(active_browser()->GetBookmarkBarVisibility(&is_visible,
+ &is_animating));
+ ASSERT_TRUE(is_visible);
+ ASSERT_FALSE(is_animating);
+}
+
+TEST_F(AutomatedUITestBase, ShowDownloads) {
+ ASSERT_TRUE(ShowDownloads());
+ GURL url;
+ ASSERT_TRUE(GetActiveTab()->GetCurrentURL(&url));
+ ASSERT_EQ(GURL(chrome::kChromeUIDownloadsURL), url);
+}
+
+// Flaky, see http://crbug.com/81050.
+#if defined(OS_MACOSX)
+#define MAYBE_ShowHistory FLAKY_ShowHistory
+#else
+#define MAYBE_ShowHistory ShowHistory
+#endif
+
+TEST_F(AutomatedUITestBase, MAYBE_ShowHistory) {
+ ASSERT_TRUE(ShowHistory());
+ GURL url;
+ ASSERT_TRUE(GetActiveTab()->GetCurrentURL(&url));
+ ASSERT_EQ(GURL(chrome::kChromeUIHistoryURL), url);
+}
diff --git a/chrome/test/reliability/automated_ui_tests.cc b/chrome/test/reliability/automated_ui_tests.cc
new file mode 100644
index 0000000..ca5cad2
--- /dev/null
+++ b/chrome/test/reliability/automated_ui_tests.cc
@@ -0,0 +1,831 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <fstream>
+#include <string>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/environment.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/file_version_info.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/rand_util.h"
+#include "base/string_number_conversions.h"
+#include "base/string_split.h"
+#include "base/string_util.h"
+#include "base/threading/platform_thread.h"
+#include "base/time.h"
+#include "base/i18n/time_formatting.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/character_encoding.h"
+#include "chrome/browser/ui/view_ids.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_version_info.h"
+#include "chrome/common/env_vars.h"
+#include "chrome/common/libxml_utils.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/test/automation/automation_proxy.h"
+#include "chrome/test/automation/browser_proxy.h"
+#include "chrome/test/automation/tab_proxy.h"
+#include "chrome/test/automation/window_proxy.h"
+#include "chrome/test/reliability/automated_ui_tests.h"
+#include "chrome/test/ui/ui_test.h"
+#include "googleurl/src/gurl.h"
+#include "ui/base/keycodes/keyboard_codes.h"
+
+#if defined(TOOLKIT_VIEWS)
+#include "views/view.h"
+#endif
+
+namespace {
+
+const char kReproSwitch[] = "key";
+
+const char kReproRepeatSwitch[] = "num-reproductions";
+
+const char kInputFilePathSwitch[] = "input";
+
+const char kOutputFilePathSwitch[] = "output";
+
+const char kDebugModeSwitch[] = "debug";
+
+const char kWaitSwitch[] = "wait-after-action";
+
+const char kTestLogFilePathSwitch[] = "testlog";
+
+const FilePath::CharType* const kDefaultInputFilePath =
+FILE_PATH_LITERAL("automated_ui_tests.txt");
+
+const FilePath::CharType* const kDefaultOutputFilePath =
+FILE_PATH_LITERAL("automated_ui_tests_error_report.txt");
+
+const FilePath::CharType* const kDefaultTestLogFilePath =
+FILE_PATH_LITERAL("automated_ui_tests_log.txt");
+
+const int kDebuggingTimeoutMsec = 5000;
+
+// How many commands to run when testing a dialog box.
+const int kTestDialogActionsToRun = 7;
+
+// String name of local chrome dll for looking up file information.
+const wchar_t kChromeDll[] = L"chrome.dll";
+
+void SilentRuntimeReportHandler(const std::string& str) {
+}
+
+FilePath GetInputFilePath() {
+ const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
+ if (parsed_command_line.HasSwitch(kInputFilePathSwitch)) {
+ return parsed_command_line.GetSwitchValuePath(kInputFilePathSwitch);
+ } else {
+ return FilePath(kDefaultInputFilePath);
+ }
+}
+
+FilePath GetOutputFilePath() {
+ const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
+ if (parsed_command_line.HasSwitch(kOutputFilePathSwitch)) {
+ return parsed_command_line.GetSwitchValuePath(kOutputFilePathSwitch);
+ } else {
+ return FilePath(kDefaultOutputFilePath);
+ }
+}
+
+FilePath GetTestLogFilePath() {
+ const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
+ if (parsed_command_line.HasSwitch(kTestLogFilePathSwitch)) {
+ return parsed_command_line.GetSwitchValuePath(kTestLogFilePathSwitch);
+ } else {
+ return FilePath(kDefaultTestLogFilePath);
+ }
+}
+
+std::string GetChromeRevision() {
+ // Get Chrome version
+ std::string last_change;
+#if defined(OS_WIN)
+ // Check file version info for chrome dll.
+ scoped_ptr<FileVersionInfo> file_info;
+ file_info.reset(
+ FileVersionInfo::CreateFileVersionInfo(FilePath(kChromeDll)));
+ last_change = WideToASCII(file_info->last_change());
+#elif defined(OS_POSIX)
+ chrome::VersionInfo version_info;
+ last_change = version_info.LastChange();
+#endif // !defined(OS_WIN)
+ return last_change;
+}
+
+void InitTestLog(base::Time start_time) {
+ FilePath path = GetTestLogFilePath();
+ std::ofstream test_log_file;
+ if (!path.empty())
+ test_log_file.open(path.value().c_str(), std::ios::out);
+
+ const std::string time =
+ UTF16ToASCII(base::TimeFormatFriendlyDateAndTime(start_time));
+
+ test_log_file << "Last Change: " << GetChromeRevision() << std::endl;
+ test_log_file << "Test Start: " << time << std::endl;
+ test_log_file.close();
+}
+
+void AppendToTestLog(const std::string& append_string) {
+ FilePath path = GetTestLogFilePath();
+ std::ofstream test_log_file;
+ if (!path.empty()) {
+ test_log_file.open(path.value().c_str(),
+ std::ios::out | std::ios_base::app);
+ }
+
+ test_log_file << append_string << std::endl;
+ test_log_file.close();
+}
+
+double CalculateTestDuration(base::Time start_time) {
+ base::Time time_now = base::Time::Now();
+ return time_now.ToDoubleT() - start_time.ToDoubleT();
+}
+
+} // namespace
+
+// This subset of commands is used to test dialog boxes, which aren't likely
+// to respond to most other commands.
+const std::string kTestDialogPossibleActions[] = {
+ // See FuzzyTestDialog for details on why Enter and SpaceBar must appear first
+ // in this list.
+ "PressEnterKey",
+ "PressSpaceBar",
+ "PressTabKey",
+ "DownArrow"
+};
+
+// The list of dialogs that can be shown.
+const std::string kDialogs[] = {
+ "About",
+ "Options",
+ "TaskManager",
+ "JavaScriptConsole",
+ "ClearBrowsingData",
+ "ImportSettings",
+ "EditSearchEngines",
+ "ViewPasswords"
+};
+
+AutomatedUITest::AutomatedUITest()
+ : test_start_time_(base::Time::NowFromSystemTime()),
+ total_crashes_(0),
+ debug_logging_enabled_(false),
+ post_action_delay_(0) {
+ show_window_ = true;
+ const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
+ if (parsed_command_line.HasSwitch(kDebugModeSwitch))
+ debug_logging_enabled_ = true;
+ if (parsed_command_line.HasSwitch(kWaitSwitch)) {
+ std::string str = parsed_command_line.GetSwitchValueASCII(kWaitSwitch);
+ if (str.empty()) {
+ post_action_delay_ = 1;
+ } else {
+ base::StringToInt(str, &post_action_delay_);
+ }
+ }
+ scoped_ptr<base::Environment> env(base::Environment::Create());
+ if (env->HasVar(env_vars::kHeadless))
+ logging::SetLogReportHandler(SilentRuntimeReportHandler);
+}
+
+AutomatedUITest::~AutomatedUITest() {}
+
+void AutomatedUITest::RunReproduction() {
+ const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
+
+ InitTestLog(test_start_time_);
+ xml_writer_.StartWriting();
+ xml_writer_.StartElement("Report");
+ std::string action_string =
+ parsed_command_line.GetSwitchValueASCII(kReproSwitch);
+
+ int64 num_reproductions = 1;
+ if (parsed_command_line.HasSwitch(kReproRepeatSwitch)) {
+ base::StringToInt64(
+ parsed_command_line.GetSwitchValueASCII(kReproRepeatSwitch),
+ &num_reproductions);
+ }
+ std::vector<std::string> actions;
+ base::SplitString(action_string, ',', &actions);
+ bool did_crash = false;
+ bool command_complete = false;
+
+ for (int64 i = 0; i < num_reproductions && !did_crash; ++i) {
+ bool did_teardown = false;
+ xml_writer_.StartElement("Executed");
+ for (size_t j = 0; j < actions.size(); ++j) {
+ DoAction(actions[j]);
+ if (DidCrash(true)) {
+ did_crash = true;
+ if (j >= (actions.size() - 1))
+ command_complete = true;
+ break;
+ }
+ if (LowerCaseEqualsASCII(actions[j], "teardown"))
+ did_teardown = true;
+ }
+
+ // Force proper teardown after each run, if it didn't already happen. But
+ // don't teardown after crashes.
+ if (!did_teardown && !did_crash)
+ DoAction("TearDown");
+
+ xml_writer_.EndElement(); // End "Executed" element.
+ }
+
+ if (did_crash) {
+ FilePath crash_dump = GetMostRecentCrashDump();
+ FilePath::StringType result =
+ FILE_PATH_LITERAL("*** Crash dump produced. ")
+ FILE_PATH_LITERAL("See result file for more details. Dump = ");
+ result.append(crash_dump.value());
+ result.append(FILE_PATH_LITERAL(" ***\n"));
+ printf("%s", result.c_str());
+ LogCrashResult(crash_dump, command_complete);
+ EXPECT_TRUE(false) << "Crash detected.";
+ } else {
+ printf("*** No crashes. See result file for more details. ***\n");
+ LogSuccessResult();
+ }
+
+ AppendToTestLog(StringPrintf("total_duration_seconds=%f",
+ CalculateTestDuration(test_start_time_)));
+ WriteReportToFile();
+}
+
+
+void AutomatedUITest::RunAutomatedUITest() {
+ InitTestLog(test_start_time_);
+
+ ASSERT_TRUE(InitXMLReader()) << "Error initializing XMLReader";
+ xml_writer_.StartWriting();
+ xml_writer_.StartElement("Report");
+
+ while (init_reader_.Read()) {
+ init_reader_.SkipToElement();
+ std::string node_name = init_reader_.NodeName();
+ if (LowerCaseEqualsASCII(node_name, "command")) {
+ bool no_errors = true;
+ xml_writer_.StartElement("Executed");
+ std::string command_number;
+ if (init_reader_.NodeAttribute("number", &command_number)) {
+ xml_writer_.AddAttribute("command_number", command_number);
+ }
+ xml_writer_.StopIndenting();
+
+ // Starts the browser, logging it as an action.
+ DoAction("SetUp");
+
+ // Record the depth of the root of the command subtree, then advance to
+ // the first element in preparation for parsing.
+ int start_depth = init_reader_.Depth();
+ ASSERT_TRUE(init_reader_.Read()) << "Malformed XML file.";
+ init_reader_.SkipToElement();
+
+ // Check for a crash right after startup.
+ if (DidCrash(true)) {
+ LogCrashResult(GetMostRecentCrashDump(), false);
+ // Try and start up again.
+ CloseBrowserAndServer();
+ LaunchBrowserAndServer();
+ set_active_browser(automation()->GetBrowserWindow(0));
+ if (DidCrash(true)) {
+ no_errors = false;
+ // We crashed again, so skip to the end of the this command.
+ while (init_reader_.Depth() != start_depth) {
+ ASSERT_TRUE(init_reader_.Read()) << "Malformed XML file.";
+ }
+ } else {
+ // We didn't crash, so end the old element, logging a crash for that.
+ // Then start a new element to log this command.
+ xml_writer_.StartIndenting();
+ xml_writer_.EndElement();
+ xml_writer_.StartElement("Executed");
+ xml_writer_.AddAttribute("command_number", command_number);
+ xml_writer_.StopIndenting();
+ xml_writer_.StartElement("SetUp");
+ xml_writer_.EndElement();
+ }
+ }
+ // Parse the command, performing the specified actions and checking
+ // for a crash after each one.
+ while (init_reader_.Depth() != start_depth) {
+ node_name = init_reader_.NodeName();
+
+ DoAction(node_name);
+
+ // Advance to the next element
+ ASSERT_TRUE(init_reader_.Read()) << "Malformed XML file.";
+ init_reader_.SkipToElement();
+ if (DidCrash(true)) {
+ no_errors = false;
+ // This was the last action if we've returned to the initial depth
+ // of the command subtree.
+ bool wasLastAction = init_reader_.Depth() == start_depth;
+ LogCrashResult(GetMostRecentCrashDump(), wasLastAction);
+ // Skip to the beginning of the next command.
+ while (init_reader_.Depth() != start_depth) {
+ ASSERT_TRUE(init_reader_.Read()) << "Malformed XML file.";
+ }
+ }
+ }
+
+ if (no_errors) {
+ // If there were no previous crashes, log our tear down and check for
+ // a crash, log success for the entire command if this doesn't crash.
+ DoAction("TearDown");
+ if (DidCrash(true))
+ LogCrashResult(GetMostRecentCrashDump(), true);
+ else
+ LogSuccessResult();
+ } else {
+ // If there was a previous crash, just tear down without logging, so
+ // that we know what the last command was before we crashed.
+ CloseBrowserAndServer();
+ }
+
+ xml_writer_.StartIndenting();
+ xml_writer_.EndElement(); // End "Executed" element.
+ }
+ }
+
+ AppendToTestLog(StringPrintf("total_duration_seconds=%f",
+ CalculateTestDuration(test_start_time_)));
+
+ // The test is finished so write our report.
+ WriteReportToFile();
+}
+
+bool AutomatedUITest::DoAction(const std::string& action) {
+ bool did_complete_action = false;
+ xml_writer_.StartElement(action);
+ if (debug_logging_enabled_)
+ AppendToOutputFile(action);
+
+ if (LowerCaseEqualsASCII(action, "about")) {
+ did_complete_action = OpenAboutDialog();
+ } else if (LowerCaseEqualsASCII(action, "back")) {
+ did_complete_action = BackButton();
+ } else if (LowerCaseEqualsASCII(action, "changeencoding")) {
+ did_complete_action = ChangeEncoding();
+ } else if (LowerCaseEqualsASCII(action, "closetab")) {
+ did_complete_action = CloseActiveTab();
+ } else if (LowerCaseEqualsASCII(action, "clearbrowsingdata")) {
+ did_complete_action = OpenClearBrowsingDataDialog();
+ } else if (LowerCaseEqualsASCII(action, "crash")) {
+ did_complete_action = ForceCrash();
+ } else if (LowerCaseEqualsASCII(action, "dialog")) {
+ did_complete_action = ExerciseDialog();
+ } else if (LowerCaseEqualsASCII(action, "downarrow")) {
+ did_complete_action = PressDownArrow();
+ } else if (LowerCaseEqualsASCII(action, "downloads")) {
+ did_complete_action = ShowDownloads();
+ } else if (LowerCaseEqualsASCII(action, "dragtableft")) {
+ did_complete_action = DragActiveTab(false);
+ } else if (LowerCaseEqualsASCII(action, "dragtabout")) {
+ did_complete_action = DragTabOut();
+ } else if (LowerCaseEqualsASCII(action, "dragtabright")) {
+ did_complete_action = DragActiveTab(true);
+ } else if (LowerCaseEqualsASCII(action, "duplicatetab")) {
+ did_complete_action = DuplicateTab();
+ } else if (LowerCaseEqualsASCII(action, "editsearchengines")) {
+ did_complete_action = OpenEditSearchEnginesDialog();
+ } else if (LowerCaseEqualsASCII(action, "findinpage")) {
+ did_complete_action = FindInPage();
+ } else if (LowerCaseEqualsASCII(action, "forward")) {
+ did_complete_action = ForwardButton();
+ } else if (LowerCaseEqualsASCII(action, "goofftherecord")) {
+ did_complete_action = GoOffTheRecord();
+ } else if (LowerCaseEqualsASCII(action, "history")) {
+ did_complete_action = ShowHistory();
+ } else if (LowerCaseEqualsASCII(action, "home")) {
+ did_complete_action = Home();
+ } else if (LowerCaseEqualsASCII(action, "importsettings")) {
+ did_complete_action = OpenImportSettingsDialog();
+ } else if (LowerCaseEqualsASCII(action, "javascriptconsole")) {
+ did_complete_action = JavaScriptConsole();
+ } else if (LowerCaseEqualsASCII(action, "navigate")) {
+ std::string url = chrome::kAboutBlankURL;
+ if (init_reader_.NodeAttribute("url", &url)) {
+ xml_writer_.AddAttribute("url", url);
+ }
+ GURL test_url(url);
+ did_complete_action = Navigate(test_url);
+ } else if (LowerCaseEqualsASCII(action, "newtab")) {
+ did_complete_action = NewTab();
+ } else if (LowerCaseEqualsASCII(action, "openwindow")) {
+ did_complete_action = OpenAndActivateNewBrowserWindow(NULL);
+ } else if (LowerCaseEqualsASCII(action, "options")) {
+ did_complete_action = Options();
+ } else if (LowerCaseEqualsASCII(action, "pagedown")) {
+ did_complete_action = PressPageDown();
+ } else if (LowerCaseEqualsASCII(action, "pageup")) {
+ did_complete_action = PressPageUp();
+ } else if (LowerCaseEqualsASCII(action, "pressenterkey")) {
+ did_complete_action = PressEnterKey();
+ } else if (LowerCaseEqualsASCII(action, "pressescapekey")) {
+ did_complete_action = PressEscapeKey();
+ } else if (LowerCaseEqualsASCII(action, "pressspacebar")) {
+ did_complete_action = PressSpaceBar();
+ } else if (LowerCaseEqualsASCII(action, "presstabkey")) {
+ did_complete_action = PressTabKey();
+ } else if (LowerCaseEqualsASCII(action, "reload")) {
+ did_complete_action = ReloadPage();
+ } else if (LowerCaseEqualsASCII(action, "restoretab")) {
+ did_complete_action = RestoreTab();
+ } else if (LowerCaseEqualsASCII(action, "selectnexttab")) {
+ did_complete_action = SelectNextTab();
+ } else if (LowerCaseEqualsASCII(action, "selectprevtab")) {
+ did_complete_action = SelectPreviousTab();
+ } else if (LowerCaseEqualsASCII(action, "showbookmarks")) {
+ did_complete_action = ShowBookmarkBar();
+ } else if (LowerCaseEqualsASCII(action, "setup")) {
+ AutomatedUITestBase::SetUp();
+ did_complete_action = true;
+ } else if (LowerCaseEqualsASCII(action, "sleep")) {
+ // This is for debugging, it probably shouldn't be used real tests.
+ base::PlatformThread::Sleep(kDebuggingTimeoutMsec);
+ did_complete_action = true;
+ } else if (LowerCaseEqualsASCII(action, "star")) {
+ did_complete_action = StarPage();
+ } else if (LowerCaseEqualsASCII(action, "taskmanager")) {
+ did_complete_action = OpenTaskManagerDialog();
+ } else if (LowerCaseEqualsASCII(action, "teardown")) {
+ CloseBrowserAndServer();
+ did_complete_action = true;
+ } else if (LowerCaseEqualsASCII(action, "testaboutchrome")) {
+ did_complete_action = TestAboutChrome();
+ } else if (LowerCaseEqualsASCII(action, "testclearbrowsingdata")) {
+ did_complete_action = TestClearBrowsingData();
+ } else if (LowerCaseEqualsASCII(action, "testeditsearchengines")) {
+ did_complete_action = TestEditSearchEngines();
+ } else if (LowerCaseEqualsASCII(action, "testimportsettings")) {
+ did_complete_action = TestImportSettings();
+ } else if (LowerCaseEqualsASCII(action, "testoptions")) {
+ did_complete_action = TestOptions();
+ } else if (LowerCaseEqualsASCII(action, "testtaskmanager")) {
+ did_complete_action = TestTaskManager();
+ } else if (LowerCaseEqualsASCII(action, "testviewpasswords")) {
+ did_complete_action = TestViewPasswords();
+ } else if (LowerCaseEqualsASCII(action, "uparrow")) {
+ did_complete_action = PressUpArrow();
+ } else if (LowerCaseEqualsASCII(action, "viewpasswords")) {
+ did_complete_action = OpenViewPasswordsDialog();
+ } else if (LowerCaseEqualsASCII(action, "viewsource")) {
+ did_complete_action = ViewSource();
+ } else if (LowerCaseEqualsASCII(action, "zoomplus")) {
+ did_complete_action = ZoomPlus();
+ } else if (LowerCaseEqualsASCII(action, "zoomminus")) {
+ did_complete_action = ZoomMinus();
+ } else {
+ NOTREACHED() << "Unknown command passed into DoAction: "
+ << action.c_str();
+ }
+
+ EXPECT_TRUE(did_complete_action) << action;
+
+ if (!did_complete_action)
+ xml_writer_.AddAttribute("failed_to_complete", "yes");
+ xml_writer_.EndElement();
+
+ if (post_action_delay_)
+ base::PlatformThread::Sleep(1000 * post_action_delay_);
+
+ return did_complete_action;
+}
+
+bool AutomatedUITest::ChangeEncoding() {
+ // Get the encoding list that is used to populate the UI (encoding menu)
+ std::string cur_locale = g_browser_process->GetApplicationLocale();
+ const std::vector<CharacterEncoding::EncodingInfo>* encodings =
+ CharacterEncoding::GetCurrentDisplayEncodings(
+ cur_locale, "ISO-8859-1,windows-1252", "");
+ DCHECK(encodings);
+ DCHECK(!encodings->empty());
+ unsigned len = static_cast<unsigned>(encodings->size());
+
+ // The vector will contain mostly IDC values for encoding commands plus a few
+ // menu separators (0 values). If we hit a separator we just retry.
+ int index = base::RandInt(0, len);
+ while ((*encodings)[index].encoding_id == 0) {
+ index = base::RandInt(0, len);
+ }
+
+ return RunCommandAsync((*encodings)[index].encoding_id);
+}
+
+bool AutomatedUITest::JavaScriptConsole() {
+ return RunCommandAsync(IDC_DEV_TOOLS);
+}
+
+bool AutomatedUITest::OpenAboutDialog() {
+ return RunCommandAsync(IDC_ABOUT);
+}
+
+bool AutomatedUITest::OpenClearBrowsingDataDialog() {
+ return RunCommandAsync(IDC_CLEAR_BROWSING_DATA);
+}
+
+bool AutomatedUITest::OpenEditSearchEnginesDialog() {
+ return RunCommandAsync(IDC_EDIT_SEARCH_ENGINES);
+}
+
+bool AutomatedUITest::OpenImportSettingsDialog() {
+ return RunCommandAsync(IDC_IMPORT_SETTINGS);
+}
+
+bool AutomatedUITest::OpenTaskManagerDialog() {
+ return RunCommandAsync(IDC_TASK_MANAGER);
+}
+
+bool AutomatedUITest::OpenViewPasswordsDialog() {
+ return RunCommandAsync(IDC_VIEW_PASSWORDS);
+}
+
+bool AutomatedUITest::Options() {
+ return RunCommandAsync(IDC_OPTIONS);
+}
+
+bool AutomatedUITest::PressDownArrow() {
+ return SimulateKeyPressInActiveWindow(ui::VKEY_DOWN, 0);
+}
+
+bool AutomatedUITest::PressEnterKey() {
+ return SimulateKeyPressInActiveWindow(ui::VKEY_RETURN, 0);
+}
+
+bool AutomatedUITest::PressEscapeKey() {
+ return SimulateKeyPressInActiveWindow(ui::VKEY_ESCAPE, 0);
+}
+
+bool AutomatedUITest::PressPageDown() {
+ return SimulateKeyPressInActiveWindow(ui::VKEY_PRIOR, 0);
+}
+
+bool AutomatedUITest::PressPageUp() {
+ return SimulateKeyPressInActiveWindow(ui::VKEY_NEXT, 0);
+}
+
+bool AutomatedUITest::PressSpaceBar() {
+ return SimulateKeyPressInActiveWindow(ui::VKEY_SPACE, 0);
+}
+
+bool AutomatedUITest::PressTabKey() {
+ return SimulateKeyPressInActiveWindow(ui::VKEY_TAB, 0);
+}
+
+bool AutomatedUITest::PressUpArrow() {
+ return SimulateKeyPressInActiveWindow(ui::VKEY_UP, 0);
+}
+
+bool AutomatedUITest::StarPage() {
+ return RunCommandAsync(IDC_BOOKMARK_PAGE);
+}
+
+bool AutomatedUITest::ViewSource() {
+ return RunCommandAsync(IDC_VIEW_SOURCE);
+}
+
+bool AutomatedUITest::ZoomMinus() {
+ return RunCommandAsync(IDC_ZOOM_MINUS);
+}
+
+bool AutomatedUITest::ZoomPlus() {
+ return RunCommandAsync(IDC_ZOOM_PLUS);
+}
+
+bool AutomatedUITest::TestAboutChrome() {
+ DoAction("About");
+ return FuzzyTestDialog(kTestDialogActionsToRun);
+}
+
+bool AutomatedUITest::TestClearBrowsingData() {
+ DoAction("ClearBrowsingData");
+ return FuzzyTestDialog(kTestDialogActionsToRun);
+}
+
+bool AutomatedUITest::TestEditSearchEngines() {
+ DoAction("EditSearchEngines");
+ return FuzzyTestDialog(kTestDialogActionsToRun);
+}
+
+bool AutomatedUITest::TestImportSettings() {
+ DoAction("ImportSettings");
+ return FuzzyTestDialog(kTestDialogActionsToRun);
+}
+
+bool AutomatedUITest::TestTaskManager() {
+ DoAction("TaskManager");
+ return FuzzyTestDialog(kTestDialogActionsToRun);
+}
+
+bool AutomatedUITest::TestOptions() {
+ DoAction("Options");
+ return FuzzyTestDialog(kTestDialogActionsToRun);
+}
+
+bool AutomatedUITest::TestViewPasswords() {
+ DoAction("ViewPasswords");
+ return FuzzyTestDialog(kTestDialogActionsToRun);
+}
+
+bool AutomatedUITest::ExerciseDialog() {
+ int index = base::RandInt(0, arraysize(kDialogs) - 1);
+ return DoAction(kDialogs[index]) && FuzzyTestDialog(kTestDialogActionsToRun);
+}
+
+bool AutomatedUITest::FuzzyTestDialog(int num_actions) {
+ bool return_value = true;
+
+ for (int i = 0; i < num_actions; i++) {
+ // We want to make sure the first action performed on the dialog is not
+ // Space or Enter because focus is likely on the Close button. Both Space
+ // and Enter would close the dialog without performing more actions. We
+ // rely on the fact that those two actions are first in the array and set
+ // the lower bound to 2 if i == 0 to skip those two actions.
+ int action_index = base::RandInt(i == 0 ? 2 : 0,
+ arraysize(kTestDialogPossibleActions)
+ - 1);
+ return_value = return_value &&
+ DoAction(kTestDialogPossibleActions[action_index]);
+ if (DidCrash(false))
+ break;
+ }
+ return DoAction("PressEscapeKey") && return_value;
+}
+
+bool AutomatedUITest::ForceCrash() {
+ scoped_refptr<TabProxy> tab(GetActiveTab());
+ GURL test_url(chrome::kAboutCrashURL);
+ AutomationMsg_NavigationResponseValues result = tab->NavigateToURL(test_url);
+ if (result != AUTOMATION_MSG_NAVIGATION_SUCCESS) {
+ AddErrorAttribute("navigation_failed");
+ return false;
+ }
+ return true;
+}
+
+bool AutomatedUITest::SimulateKeyPressInActiveWindow(ui::KeyboardCode key,
+ int flags) {
+ scoped_refptr<WindowProxy> window(automation()->GetActiveWindow());
+ if (window.get() == NULL) {
+ AddErrorAttribute("active_window_not_found");
+ return false;
+ }
+ if (!window->SimulateOSKeyPress(key, flags)) {
+ AddWarningAttribute("failure_simulating_key_press");
+ return false;
+ }
+ return true;
+}
+
+bool AutomatedUITest::InitXMLReader() {
+ FilePath input_path = GetInputFilePath();
+
+ if (!file_util::ReadFileToString(input_path, &xml_init_file_))
+ return false;
+ return init_reader_.Load(xml_init_file_);
+}
+
+bool AutomatedUITest::WriteReportToFile() {
+ FilePath path = GetOutputFilePath();
+ std::ofstream error_file;
+ if (!path.empty())
+ error_file.open(path.value().c_str(), std::ios::out);
+
+ // Closes all open elements and free the writer. This is required
+ // in order to retrieve the contents of the buffer.
+ xml_writer_.StopWriting();
+ error_file << xml_writer_.GetWrittenString();
+ error_file.close();
+ return true;
+}
+
+void AutomatedUITest::AppendToOutputFile(const std::string& append_string) {
+ FilePath path = GetOutputFilePath();
+ std::ofstream error_file;
+ if (!path.empty())
+ error_file.open(path.value().c_str(), std::ios::out | std::ios_base::app);
+
+ error_file << append_string << " ";
+ error_file.close();
+}
+
+void AutomatedUITest::LogCrashResult(const FilePath& crash_dump,
+ bool command_completed) {
+ xml_writer_.StartElement("result");
+ xml_writer_.AddAttribute("test_log_path",
+ GetTestLogFilePath().MaybeAsASCII());
+ xml_writer_.AddAttribute("revision", GetChromeRevision());
+ xml_writer_.StartElement("crash");
+#if defined(OS_WIN)
+ xml_writer_.AddAttribute("crash_dump", WideToASCII(crash_dump.value()));
+#else
+ xml_writer_.AddAttribute("crash_dump", crash_dump.value());
+#endif
+ if (command_completed)
+ xml_writer_.AddAttribute("command_completed", "yes");
+ else
+ xml_writer_.AddAttribute("command_completed", "no");
+ xml_writer_.EndElement();
+ xml_writer_.EndElement();
+}
+
+void AutomatedUITest::LogSuccessResult() {
+ xml_writer_.StartElement("result");
+ xml_writer_.AddAttribute("test_log_path",
+ GetTestLogFilePath().MaybeAsASCII());
+ xml_writer_.AddAttribute("revision", GetChromeRevision());
+ xml_writer_.StartElement("success");
+ xml_writer_.EndElement();
+ xml_writer_.EndElement();
+}
+
+void AutomatedUITest::AddInfoAttribute(const std::string& info) {
+ xml_writer_.AddAttribute("info", info);
+}
+
+void AutomatedUITest::AddWarningAttribute(const std::string& warning) {
+ xml_writer_.AddAttribute("warning", warning);
+}
+
+void AutomatedUITest::AddErrorAttribute(const std::string& error) {
+ xml_writer_.AddAttribute("error", error);
+}
+
+void AutomatedUITest::LogErrorMessage(const std::string& error) {
+ AddErrorAttribute(error);
+}
+
+void AutomatedUITest::LogWarningMessage(const std::string& warning) {
+ AddWarningAttribute(warning);
+}
+
+void AutomatedUITest::LogInfoMessage(const std::string& info) {
+ AddWarningAttribute(info);
+}
+
+FilePath AutomatedUITest::GetMostRecentCrashDump() {
+ FilePath crash_dump_path;
+ FilePath most_recent_file_name;
+ PathService::Get(chrome::DIR_CRASH_DUMPS, &crash_dump_path);
+ base::Time most_recent_file_time;
+
+ bool first_file = true;
+
+ file_util::FileEnumerator enumerator(crash_dump_path,
+ false, // not recursive
+ file_util::FileEnumerator::FILES);
+ for (FilePath path = enumerator.Next(); !path.value().empty();
+ path = enumerator.Next()) {
+ base::PlatformFileInfo file_info;
+ file_util::GetFileInfo(path, &file_info);
+ if (first_file) {
+ most_recent_file_time = file_info.last_modified;
+ most_recent_file_name = path.BaseName();
+ first_file = false;
+ } else if (file_info.last_modified >= most_recent_file_time) {
+ most_recent_file_time = file_info.last_modified;
+ most_recent_file_name = path.BaseName();
+ }
+ }
+ if (most_recent_file_name.empty()) {
+ return FilePath();
+ } else {
+ crash_dump_path = crash_dump_path.Append(most_recent_file_name);
+ return crash_dump_path;
+ }
+}
+
+bool AutomatedUITest::DidCrash(bool update_total_crashes) {
+ int actual_crashes = GetCrashCount();
+
+ // If there are more crash dumps than the total dumps which we have recorded
+ // then this is a new crash.
+ if (actual_crashes > total_crashes_) {
+ if (update_total_crashes)
+ total_crashes_ = actual_crashes;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+TEST_F(AutomatedUITest, TheOneAndOnlyTest) {
+ const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
+ if (parsed_command_line.HasSwitch(kReproSwitch))
+ RunReproduction();
+ else
+ RunAutomatedUITest();
+}
diff --git a/chrome/test/reliability/automated_ui_tests.h b/chrome/test/reliability/automated_ui_tests.h
new file mode 100644
index 0000000..60cba72
--- /dev/null
+++ b/chrome/test/reliability/automated_ui_tests.h
@@ -0,0 +1,399 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_TEST_RELIABILITY_AUTOMATED_UI_TESTS_H_
+#define CHROME_TEST_RELIABILITY_AUTOMATED_UI_TESTS_H_
+#pragma once
+
+// This takes an input file of commands, which consist of a series of
+// actions, and runs every command, reporting the status of each one
+// to an output file once all the commands have been run.
+//
+// The input file should be an XML file that has a root of any name followed
+// by a series of elements named "command" with child elements representing
+// the various actions, in order, to be performed during each command. A
+// command element can optionally include an "number" attribute to identify it.
+//
+// Example:
+// <CommandList>
+// <command number="1"><NewTab/><Navigate/><OpenWindow/><Navigate/><Back/>
+// </command>
+// <command number="2"><NewTab/><Navigate/><Navigate/><Back/><Forward/>
+// </command>
+// <command number="3"><CloseTab/><OpenWindow/><NewTab/><Navigate/><CloseTab/>
+// </command>
+// </CommandList>
+//
+// When the test is finished it will output results to the output file,
+// overwriting any previous version of this file. The output file is an
+// XML file which reports on each command, indicating whether it successfully
+// ran and if there were any errors.
+//
+// Example: (actual output will probably contain more actions per command):
+// <Report>
+// <Executed command_number="1"><NewTab/><Navigate/><result><success/>
+// </result> </Executed>
+// <Executed command_number="2"><Back/><Forward/><result><success/></result>
+// </Executed>
+// <Executed command_number="3"><CloseTab/><result>
+// <crash crash_dump="C:\a_crash.txt" command_completed="no"/></result>
+// </Executed>
+// </Report>
+//
+// A "crash" result will have two attributes, crash_dump, which points
+// to the full path of crash dump associated with this crash, and
+// command_completed which indicates whether or not the last
+// action recorded was the final action of the command.
+//
+// Furthermore, each individual action may contain additional attributes
+// to log non-fatal failures. If the attribute 'failed_to_complete="yes"'
+// is present, then the action did not complete. If that attribute is present,
+// an info, warning, or error attribute will also be present, and will contain
+// a string describing the error. The presence of info means the failure was
+// expected, probably due to a state making the action impossible to perform
+// like trying to close the last remaining window. Warnings usually mean the
+// action couldn't complete for an unknown and unexpected reason, but that the
+// test state is probably fine. Errors are like warnings, but they mean the test
+// state is probably incorrect, and more failures are likely to be caused by
+// the same problem.
+//
+// Example of some failed actions:
+// <CloseTab failed_to_complete="yes" info="would_have_exited_application"/>
+// <Reload failed_to_complete="yes" warning="failed_to_apply_accelerator"/>
+// <Star failed_to_complete="yes" error="browser_window_not_found"/>
+//
+//
+// Switches
+// --input : Specifies the input file, must be an absolute directory.
+// Default is "C:\automated_ui_tests.txt"
+//
+// --output : Specifies the output file, must be an absolute directory.
+// Default is "C:\automated_ui_tests_error_report.txt"
+//
+//
+// Test reproduction options:
+//
+// If you're trying to reproduce the results from crash reports use the
+// following switches
+//
+// --key : Specifies, via a comma delimited list, what actions to run. Examples:
+// --key=SetUp,ZoomPlus,Forward,History,Navigate,Back,TearDown
+// --key=SetUp,ZoomPlus
+// Note, the second key doesn't include a TearDown, that will
+// automatically be added if the result doesn't crash.
+//
+// --num-reproductions : Specifies the number of reproductions to run, the
+// default is 1. Suggested use: run without this flag
+// to see if we reproduce a crash, then run with the flag
+// if there isn't a crash, to see if it might be a rare
+// race condition that causes the crash.
+//
+//
+// Debugging options:
+//
+// --debug : Will append each action that is performed to the output file, as
+// soon as the action is performed. If the program finishes, this file
+// will be overwritten with the normal results. This flag is used to
+// help debug the tests if they are crashing before they get a chance
+// to write their results to file.
+//
+// --wait-after-action : waits the specified amount of time (1s by default)
+// after each action. Useful for debugging.
+
+#include <string>
+
+#include "chrome/test/reliability/automated_ui_test_base.h"
+#include "chrome/test/ui/ui_test.h"
+#include "ui/base/keycodes/keyboard_codes.h"
+
+namespace base {
+class Time;
+}
+
+class AutomatedUITest : public AutomatedUITestBase {
+ protected:
+ AutomatedUITest();
+ virtual ~AutomatedUITest();
+
+ // Runs a reproduction of one set of actions, reporting whether they crash
+ // or not.
+ void RunReproduction();
+
+ // Runs automated UI tests which are read from the input file.
+ // Reports crashes to the output file.
+ void RunAutomatedUITest();
+
+ // Attempts to perform an action based on the input string. See below for
+ // possible actions. Returns true if the action completes, false otherwise.
+ bool DoAction(const std::string& action);
+
+ // Actions ------------------------------------------------------------------
+
+ // NOTE: This list is sorted alphabetically, so that we can easily detect
+ // missing actions.
+
+ // Changes the encoding of the page (the encoding is selected at random
+ // from a list of encodings).
+ // Returns true if call to activate the accelerator is successful.
+ // XML element: <ChangeEncoding/>
+ bool ChangeEncoding();
+
+ // Opens one of the dialogs (chosen randomly) and exercises it.
+ // XML element: <Dialog/>
+ bool ExerciseDialog();
+
+ // Opens the JavaScriptConsole window. While it isn't modal, it takes focus
+ // from the current browser window, so most of the test can't continue until
+ // it is dismissed.
+ // XML element: <JavaScriptConsole/>
+ bool JavaScriptConsole();
+
+ // Opens the About dialog. This dialog is modal so a majority of the test
+ // can't be completed until it is dismissed.
+ // XML element: <About/>
+ bool OpenAboutDialog();
+
+ // Opens the Clear Browsing Data dialog, this dialog is modal so a majority of
+ // the test can't be completed until it is dismissed.
+ // XML element: <ClearBrowsingData/>
+ bool OpenClearBrowsingDataDialog();
+
+ // Opens the Search Engines dialog. While it isn't modal, it takes focus from
+ // the current browser window, so most of the test can't continue until it is
+ // dismissed.
+ // XML element: <EditSearchEngines/>
+ bool OpenEditSearchEnginesDialog();
+
+ // Opens the Import Settings dialog, this dialog is modal so a majority of
+ // the test can't be completed until it is dismissed.
+ // XML element: <ImportSettings/>
+ bool OpenImportSettingsDialog();
+
+ // Opens the Task Manager dialog. While it isn't modal, it takes focus from
+ // the current browser window, so most of the test can't continue until it is
+ // dismissed.
+ // XML element: <TaskManager/>
+ bool OpenTaskManagerDialog();
+
+ // Opens the View Passwords dialog, this dialog is modal so a majority of
+ // the test can't be completed until it is dismissed.
+ // XML element: <ViewPasswords/>
+ bool OpenViewPasswordsDialog();
+
+ // Opens the Options dialog. While it isn't modal, it takes focus from
+ // the current browser window, so most of the test can't continue until it is
+ // dismissed.
+ // XML element: <Options/>
+ bool Options();
+
+ // Simulates a page up key press on the active window.
+ // XML element: <DownArrow/>
+ bool PressDownArrow();
+
+ // Simulates an enter key press on the active window.
+ // XML element: <PressEnterKey/>
+ bool PressEnterKey();
+
+ // Simulates an escape key press on the active window.
+ // XML element: <PressEscapeKey/>
+ bool PressEscapeKey();
+
+ // Simulates a page down key press on the active window.
+ // XML element: <PageDown/>
+ bool PressPageDown();
+
+ // Simulates a page up key press on the active window.
+ // XML element: <PageUp/>
+ bool PressPageUp();
+
+ // Simulates a space bar press on the active window.
+ // XML element: <PressSpaceBar/>
+ bool PressSpaceBar();
+
+ // Simulates a tab key press on the active window.
+ // XML element: <PressTabKey/>
+ bool PressTabKey();
+
+ // Simulates a page up key press on the active window.
+ // XML element: <UpArrow/>
+ bool PressUpArrow();
+
+ // Stars the current page. This opens a dialog that may or may not be
+ // dismissed.
+ // XML element: <Star/>
+ bool StarPage();
+
+ // Views source of the current page.
+ // Returns true if call to activate the accelerator is successful.
+ // XML element: <ViewSource/>
+ bool ViewSource();
+
+ // Decreases the text size on the current active tab.
+ // XML element: <ZoomMinus/>
+ bool ZoomMinus();
+
+ // Increases the text size on the current active tab.
+ // XML element: <ZoomPlus/>
+ bool ZoomPlus();
+
+ // Test Dialog Actions ******************************************************
+ // These are a special set of actions that perform multiple actions on a
+ // specified dialog. They run kTestDialogActionsToRun actions randomly
+ // chosen from test_dialog_possible_actions_ after opening the dialog. They
+ // then always end with a PressEscapeKey action, to attempt to close the
+ // dialog.
+ //
+ // The randomly performed actions are logged as child elements of the
+ // TestDialog action. For example (for kTestDialogActionsToRun = 4):
+ // <TestEditKeywords> <PressTabKey/><PressEnterKey/><DownArrow/>
+ // <DownArrow/><PressEscapeKey/> </TestEditKeywords>
+
+ // Opens About dialog and runs random actions on it.
+ // XML element: <TestAboutChrome/>
+ bool TestAboutChrome();
+
+ // Opens Clear Browsing Data dialog and runs random actions on it.
+ // XML element: <TestClearBrowsingData/>
+ bool TestClearBrowsingData();
+
+ // Opens Edit Keywords dialog and runs random actions on it.
+ // XML element: <TestEditSearchEngines/>
+ bool TestEditSearchEngines();
+
+ // Opens Import Settings dialog and runs random actions on it.
+ // XML element: <TestImportSettings/>
+ bool TestImportSettings();
+
+ // Opens Options dialog and runs random actions on it.
+ // XML element: <TestOptions/>
+ bool TestOptions();
+
+ // Opens Task Manager and runs random actions on it.
+ // This has the possibility of killing both the browser and renderer
+ // processes, which will cause non-fatal errors for the remaining actions
+ // in this command.
+ // XML element: <TestTaskManager/>
+ bool TestTaskManager();
+
+ // Opens View Passwords dialog and runs random actions on it.
+ // XML element: <TestViewPasswords/>
+ bool TestViewPasswords();
+
+ // End Test Dialog Actions **************************************************
+
+ // Runs a limited set of actions designed to test dialogs. Will run
+ // |num_actions| from the set defined in test_dialog_possible_actions_.
+ bool FuzzyTestDialog(int num_actions);
+
+ // Navigates to about:crash.
+ // XML element: <Crash/>
+ bool ForceCrash();
+
+ // Utility functions --------------------------------------------------------
+
+ // Calls SimulateOSKeyPress on the active window. Simulates a key press at
+ // the OS level. |key| is the key pressed and |flags| specifies which
+ // modifiers keys are also pressed (as defined in chrome/views/event.h).
+ bool SimulateKeyPressInActiveWindow(ui::KeyboardCode key, int flags);
+
+ // Opens init file, reads it into the reader, and closes the file.
+ // Returns false if there are any errors.
+ bool InitXMLReader();
+
+ // Closes the xml_writer and outputs the contents of its buffer to
+ // the output file.
+ bool WriteReportToFile();
+
+ // Appends the provided string to the output file.
+ void AppendToOutputFile(const std::string& append_string);
+
+ // Logs a crash to the xml_writer in the form of:
+ // <result><crash crash_dump="|crash_dump|" command_completed="yes/no"/>
+ // </result>
+ // crash_dump - Location of crash dump if applicable.
+ // command_completed - True if all actions in the command were completed
+ // before the crash occured.
+ void LogCrashResult(const FilePath& crash_dump,
+ bool command_completed);
+
+ // Logs a successful command to the xml_writer in the form of:
+ // <result><success/><result/>
+ void LogSuccessResult();
+
+ // Adds the attribute "reason=|reason|" to the current element.
+ // Used to log the reason for a given failure while performing an action.
+ void LogActionFailureReason(const std::string& reason);
+
+ // Adds the attribute 'info="|info|"' to the current element. Used when an
+ // action could not complete for a non-serious issue. Usually because the
+ // state of the test wouldn't allow for a particular action.
+ void AddInfoAttribute(const std::string& info);
+
+ // Adds the attribute "warning=|warning|" to the current element. Used when
+ // an action could not complete because of a potentially troublesome issue.
+ void AddWarningAttribute(const std::string& warning);
+
+ // Adds the attribute "error=|error|" to the current element. Used when an
+ // action could not complete due to an unexpected problem which might
+ // invalidate the results of the entire command (not just the action).
+ // This is usually used when the testing environment isn't acting as we'd
+ // expect. For example, no chrome windows are focused, or key presses aren't
+ // being registered.
+ void AddErrorAttribute(const std::string& error);
+
+ // Returns the full path of the crash dump. This is likely to be the
+ // .txt file, not the actual crash dump. Although they do share
+ // a common name.
+ FilePath GetMostRecentCrashDump();
+
+ // Returns true if the test has produced any new crash logs.
+ // A "new" crash log is one that was produced since DidCrash was last called
+ // with |update_total_crashes| set to true.
+ bool DidCrash(bool update_total_crashes);
+
+ // Override the message logging in AutomatedUITestBase.
+ virtual void LogErrorMessage(const std::string& error);
+ virtual void LogWarningMessage(const std::string& warning);
+ virtual void LogInfoMessage(const std::string& info);
+
+ // Overridden so that UI Test doesn't set up when the tests start.
+ // We use DoAction("SetUp") to set up, because it logs it and makes
+ // it easier to check for crashes when we start the browser.
+ virtual void SetUp() {}
+
+ // Overridden so that UI Test doesn't close the browser (which is already
+ // closed) at the end of the test.
+ // We use DoAction("TearDown") to tear down, because it logs it and makes
+ // it easier to check for crashes when we close the browser.
+ virtual void TearDown() {}
+
+ private:
+ // Parses the init file.
+ XmlReader init_reader_;
+
+ // Builds the output file.
+ XmlWriter xml_writer_;
+
+ // Time the test was started. Used to find crash dumps.
+ base::Time test_start_time_;
+
+ // Number of times the browser has crashed during this run.
+ // Used to check for new crashes.
+ int total_crashes_;
+
+ // Used to init the init_reader_. It must exist as long as the reader does.
+ std::string xml_init_file_;
+
+ // If true, appends the commands to the output file as they are executed.
+ // Used for debugging when automated_ui_tests.cc crashes before it outputs
+ // results.
+ bool debug_logging_enabled_;
+
+ // A delay in second we wait for after each action. Useful for debugging.
+ int post_action_delay_;
+
+ DISALLOW_COPY_AND_ASSIGN(AutomatedUITest);
+};
+
+#endif // CHROME_TEST_RELIABILITY_AUTOMATED_UI_TESTS_H_