diff options
Diffstat (limited to 'chrome/test/reliability')
-rw-r--r-- | chrome/test/reliability/automated_ui_test_base.cc | 389 | ||||
-rw-r--r-- | chrome/test/reliability/automated_ui_test_base.h | 162 | ||||
-rw-r--r-- | chrome/test/reliability/automated_ui_test_interactive_test.cc | 69 | ||||
-rw-r--r-- | chrome/test/reliability/automated_ui_test_test.cc | 410 | ||||
-rw-r--r-- | chrome/test/reliability/automated_ui_tests.cc | 831 | ||||
-rw-r--r-- | chrome/test/reliability/automated_ui_tests.h | 399 |
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_ |