Logo Search packages:      
Sourcecode: chromium-browser version File versions  Download package

ui_test.cc

// Copyright (c) 2010 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/ui/ui_test.h"

#if defined(OS_POSIX)
#include <signal.h>
#include <sys/types.h>
#endif

#include <set>
#include <vector>

#include "app/sql/connection.h"
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/platform_thread.h"
#include "base/process_util.h"
#include "base/scoped_ptr.h"
#include "base/string_util.h"
#include "base/test/test_file_util.h"
#include "base/time.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/debug_flags.h"
#include "chrome/common/logging_chrome.h"
#include "chrome/common/json_value_serializer.h"
#include "chrome/test/automation/automation_messages.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/chrome_process_util.h"
#include "googleurl/src/gurl.h"
#include "net/base/net_util.h"

#if defined(OS_WIN)
#include "base/win_util.h"
#endif


using base::Time;
using base::TimeDelta;
using base::TimeTicks;

// Delay to let browser complete a requested action.
static const int kWaitForActionMsec = 2000;
static const int kWaitForActionMaxMsec = 60000;
// Command execution timeout passed to AutomationProxy.
static const int kCommandExecutionTimeout = 30000;
// Delay to let the browser shut down before trying more brutal methods.
static const int kWaitForTerminateMsec = 30000;
// Passed as value of kTestType.
static const char kUITestType[] = "ui";

const wchar_t UITestBase::kFailedNoCrashService[] =
#if defined(OS_WIN)
    L"NOTE: This test is expected to fail if crash_service.exe is not "
    L"running. Start it manually before running this test (see the build "
    L"output directory).";
#elif defined(OS_LINUX)
    L"NOTE: This test is expected to fail if breakpad is not built in "
    L"or if chromium is not running headless (try CHROME_HEADLESS=1).";
#else
    L"NOTE: Crash service not ported to this platform!";
#endif
bool UITestBase::in_process_renderer_ = false;
bool UITestBase::no_sandbox_ = false;
bool UITestBase::full_memory_dump_ = false;
bool UITestBase::safe_plugins_ = false;
bool UITestBase::show_error_dialogs_ = true;
bool UITestBase::default_use_existing_browser_ = false;
bool UITestBase::dump_histograms_on_exit_ = false;
bool UITestBase::enable_dcheck_ = false;
bool UITestBase::silent_dump_on_dcheck_ = false;
bool UITestBase::disable_breakpad_ = false;
int UITestBase::timeout_ms_ = 20 * 60 * 1000;
std::wstring UITestBase::js_flags_ = L"";
std::wstring UITestBase::log_level_ = L"";

// Specify the time (in milliseconds) that the ui_tests should wait before
// timing out. This is used to specify longer timeouts when running under Purify
// which requires much more time.
const char kUiTestTimeout[] = "ui-test-timeout";
const char kUiTestActionTimeout[] = "ui-test-action-timeout";
const char kUiTestActionMaxTimeout[] = "ui-test-action-max-timeout";
const char kUiTestSleepTimeout[] = "ui-test-sleep-timeout";
const char kUiTestTerminateTimeout[] = "ui-test-terminate-timeout";

const char kExtraChromeFlagsSwitch[] = "extra-chrome-flags";

// By default error dialogs are hidden, which makes debugging failures in the
// slave process frustrating. By passing this in error dialogs are enabled.
const char kEnableErrorDialogs[] = "enable-errdialogs";

// Uncomment this line to have the spawned process wait for the debugger to
// attach.  This only works on Windows.  On posix systems, you can set the
// BROWSER_WRAPPER env variable to wrap the browser process.
// #define WAIT_FOR_DEBUGGER_ON_OPEN 1

UITestBase::UITestBase()
    : launch_arguments_(CommandLine::ARGUMENTS_ONLY),
      expected_errors_(0),
      expected_crashes_(0),
      homepage_(L"about:blank"),
      wait_for_initial_loads_(true),
      dom_automation_enabled_(false),
      process_(0),  // NULL on Windows, 0 PID on POSIX.
      process_id_(-1),
      show_window_(false),
      clear_profile_(true),
      include_testing_id_(true),
      use_existing_browser_(default_use_existing_browser_),
      enable_file_cookies_(true),
      profile_type_(UITestBase::DEFAULT_THEME),
      shutdown_type_(UITestBase::WINDOW_CLOSE),
      test_start_time_(Time::NowFromSystemTime()),
      command_execution_timeout_ms_(kCommandExecutionTimeout),
      action_timeout_ms_(kWaitForActionMsec),
      action_max_timeout_ms_(kWaitForActionMaxMsec),
      sleep_timeout_ms_(kWaitForActionMsec),
      terminate_timeout_ms_(kWaitForTerminateMsec) {
  PathService::Get(chrome::DIR_APP, &browser_directory_);
  PathService::Get(chrome::DIR_TEST_DATA, &test_data_directory_);
}

UITestBase::UITestBase(MessageLoop::Type msg_loop_type)
    : launch_arguments_(CommandLine::ARGUMENTS_ONLY),
      expected_errors_(0),
      expected_crashes_(0),
      homepage_(L"about:blank"),
      wait_for_initial_loads_(true),
      dom_automation_enabled_(false),
      process_(0),  // NULL on Windows, 0 PID on POSIX.
      process_id_(-1),
      show_window_(false),
      clear_profile_(true),
      include_testing_id_(true),
      use_existing_browser_(default_use_existing_browser_),
      enable_file_cookies_(true),
      profile_type_(UITestBase::DEFAULT_THEME),
      shutdown_type_(UITestBase::WINDOW_CLOSE),
      test_start_time_(Time::NowFromSystemTime()),
      command_execution_timeout_ms_(kCommandExecutionTimeout),
      action_timeout_ms_(kWaitForActionMsec),
      action_max_timeout_ms_(kWaitForActionMaxMsec),
      sleep_timeout_ms_(kWaitForActionMsec),
      terminate_timeout_ms_(kWaitForTerminateMsec) {
  PathService::Get(chrome::DIR_APP, &browser_directory_);
  PathService::Get(chrome::DIR_TEST_DATA, &test_data_directory_);
}

UITestBase::~UITestBase() {
}

void UITestBase::SetUp() {
  if (!use_existing_browser_) {
    AssertAppNotRunning(L"Please close any other instances "
                        L"of the app before testing.");
  }

  InitializeTimeouts();
  LaunchBrowserAndServer();
}

void UITestBase::TearDown() {
  CloseBrowserAndServer();

  // Make sure that we didn't encounter any assertion failures
  logging::AssertionList assertions;
  logging::GetFatalAssertions(&assertions);

  // If there were errors, get all the error strings for display.
  std::wstring failures =
    L"The following error(s) occurred in the application during this test:";
  if (assertions.size() > expected_errors_) {
    logging::AssertionList::const_iterator iter = assertions.begin();
    for (; iter != assertions.end(); ++iter) {
      failures.append(L"\n\n");
      failures.append(*iter);
    }
  }
  EXPECT_EQ(expected_errors_, assertions.size()) << failures;

  // Check for crashes during the test
  FilePath crash_dump_path;
  PathService::Get(chrome::DIR_CRASH_DUMPS, &crash_dump_path);
  int actual_crashes =
      file_util::CountFilesCreatedAfter(crash_dump_path, test_start_time_);

#if defined(OS_WIN)
  // Each crash creates two dump files, so we divide by two here.
  actual_crashes /= 2;
#endif

  std::wstring error_msg =
      L"Encountered an unexpected crash in the program during this test.";
  if (expected_crashes_ > 0 && actual_crashes == 0) {
    error_msg += L"  ";
    error_msg += kFailedNoCrashService;
  }
  EXPECT_EQ(expected_crashes_, actual_crashes) << error_msg;
}

// Pick up the various test time out values from the command line.
void UITestBase::InitializeTimeouts() {
  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
  if (command_line.HasSwitch(kUiTestTimeout)) {
    std::wstring timeout_str = command_line.GetSwitchValue(kUiTestTimeout);
    int timeout = StringToInt(WideToUTF16Hack(timeout_str));
    command_execution_timeout_ms_ = std::max(kCommandExecutionTimeout, timeout);
  }

  if (command_line.HasSwitch(kUiTestActionTimeout)) {
    std::wstring act_str = command_line.GetSwitchValue(kUiTestActionTimeout);
    int act_timeout = StringToInt(WideToUTF16Hack(act_str));
    action_timeout_ms_ = std::max(kWaitForActionMsec, act_timeout);
  }

  if (command_line.HasSwitch(kUiTestActionMaxTimeout)) {
    std::wstring action_max_str =
        command_line.GetSwitchValue(kUiTestActionMaxTimeout);
    int max_timeout = StringToInt(WideToUTF16Hack(action_max_str));
    action_max_timeout_ms_ = std::max(kWaitForActionMaxMsec, max_timeout);
  }

  if (CommandLine::ForCurrentProcess()->HasSwitch(kUiTestSleepTimeout)) {
    std::wstring sleep_timeout_str =
        CommandLine::ForCurrentProcess()->GetSwitchValue(kUiTestSleepTimeout);
    int sleep_timeout = StringToInt(WideToUTF16Hack(sleep_timeout_str));
    sleep_timeout_ms_ = std::max(kWaitForActionMsec, sleep_timeout);
  }

  if (CommandLine::ForCurrentProcess()->HasSwitch(kUiTestTerminateTimeout)) {
    std::wstring terminate_timeout_str =
        CommandLine::ForCurrentProcess()->GetSwitchValue(
            kUiTestTerminateTimeout);
    int terminate_timeout = StringToInt(WideToUTF16Hack(terminate_timeout_str));
    terminate_timeout_ms_ = std::max(kWaitForActionMsec, terminate_timeout);
  }
}

AutomationProxy* UITestBase::CreateAutomationProxy(int execution_timeout) {
  // By default we create a plain vanilla AutomationProxy.
  return new AutomationProxy(execution_timeout);
}

void UITestBase::LaunchBrowserAndServer() {
  // Set up IPC testing interface server.
  server_.reset(CreateAutomationProxy(command_execution_timeout_ms_));

  LaunchBrowser(launch_arguments_, clear_profile_);
  server_->WaitForAppLaunch();
  if (wait_for_initial_loads_)
    ASSERT_TRUE(server_->WaitForInitialLoads());
  else
    PlatformThread::Sleep(sleep_timeout_ms());

  EXPECT_TRUE(automation()->SetFilteredInet(ShouldFilterInet()));
}

void UITestBase::CloseBrowserAndServer() {
  QuitBrowser();
  CleanupAppProcesses();

  // Suppress spammy failures that seem to be occurring when running
  // the UI tests in single-process mode.
  // TODO(jhughes): figure out why this is necessary at all, and fix it
  if (!in_process_renderer_)
    AssertAppNotRunning(StringPrintf(
        L"Unable to quit all browser processes. Original PID %d", process_id_));

  server_.reset();  // Shut down IPC testing interface.
}

static CommandLine* CreatePythonCommandLine() {
#if defined(OS_WIN)
  // Get path to python interpreter
  FilePath python_runtime;
  if (!PathService::Get(base::DIR_SOURCE_ROOT, &python_runtime))
    return NULL;
  python_runtime = python_runtime
      .Append(FILE_PATH_LITERAL("third_party"))
      .Append(FILE_PATH_LITERAL("python_24"))
      .Append(FILE_PATH_LITERAL("python.exe"));
  return new CommandLine(python_runtime);
#elif defined(OS_POSIX)
  return new CommandLine(FilePath("python"));
#endif
}

static CommandLine* CreateHttpServerCommandLine() {
  FilePath src_path;
  // Get to 'src' dir.
  PathService::Get(base::DIR_SOURCE_ROOT, &src_path);

  FilePath script_path(src_path);
  script_path = script_path.AppendASCII("third_party");
  script_path = script_path.AppendASCII("WebKit");
  script_path = script_path.AppendASCII("WebKitTools");
  script_path = script_path.AppendASCII("Scripts");
  script_path = script_path.AppendASCII("new-run-webkit-httpd");

  CommandLine* cmd_line = CreatePythonCommandLine();
  cmd_line->AppendLooseValue(script_path.ToWStringHack());
  return cmd_line;
}

static void RunCommand(const CommandLine& cmd_line) {
#if defined(OS_WIN)
  // For Win32, use this 'version' of base::LaunchApp() with bInheritHandles
  // parameter to CreateProcess set to TRUE. This is needed in test harness
  // because it launches all the processes with 'chained' standard i/o pipes.
  STARTUPINFO startup_info = {0};
  startup_info.cb = sizeof(startup_info);
  PROCESS_INFORMATION process_info;
  if (!CreateProcess(
           NULL,
           const_cast<wchar_t*>(cmd_line.command_line_string().c_str()),
           NULL, NULL,
           TRUE,  // Inherit the standard pipes, needed when
                  // running in test harnesses.
           0, NULL, NULL, &startup_info, &process_info))
    return;

  // Handles must be closed or they will leak
  CloseHandle(process_info.hThread);
  WaitForSingleObject(process_info.hProcess, INFINITE);
  CloseHandle(process_info.hProcess);
#else
  base::LaunchApp(cmd_line, true, false, NULL);
#endif
}

void UITestBase::StartHttpServer(const FilePath& root_directory) {
  StartHttpServerWithPort(root_directory, L"");
}

void UITestBase::StartHttpServerWithPort(const FilePath& root_directory,
                                     const std::wstring& port) {
  scoped_ptr<CommandLine> cmd_line(CreateHttpServerCommandLine());
  ASSERT_TRUE(cmd_line.get());
  cmd_line->AppendSwitchWithValue("server", "start");
  cmd_line->AppendSwitch("register_cygwin");
  cmd_line->AppendSwitchWithValue("root", root_directory.ToWStringHack());

  // For Windows 7, if we start the lighttpd server on the foreground mode,
  // it will mess up with the command window and cause conhost.exe to crash. To
  // work around this, we start the http server on the background mode.
#if defined(OS_WIN)
  if (win_util::GetWinVersion() >= win_util::WINVERSION_WIN7)
    cmd_line->AppendSwitch("run_background");
#endif

  if (!port.empty()) {
     cmd_line->AppendSwitchWithValue("port", port);
  }
  RunCommand(*cmd_line.get());
}

void UITestBase::StopHttpServer() {
  scoped_ptr<CommandLine> cmd_line(CreateHttpServerCommandLine());
  ASSERT_TRUE(cmd_line.get());
  cmd_line->AppendSwitchWithValue("server", "stop");
  RunCommand(*cmd_line.get());
}

void UITestBase::LaunchBrowser(const CommandLine& arguments,
                               bool clear_profile) {
#if defined(OS_POSIX)
  const char* alternative_userdir = getenv("CHROME_UI_TESTS_USER_DATA_DIR");
#else
  const FilePath::StringType::value_type* const alternative_userdir = NULL;
#endif

  if (alternative_userdir) {
    user_data_dir_ = FilePath(alternative_userdir);
  } else {
    PathService::Get(chrome::DIR_USER_DATA, &user_data_dir_);
  }

  // Clear user data directory to make sure test environment is consistent
  // We balk on really short (absolute) user_data_dir directory names, because
  // we're worried that they'd accidentally be root or something.
  ASSERT_LT(10, static_cast<int>(user_data_dir_.value().size())) <<
                "The user data directory name passed into this test was too "
                "short to delete safely.  Please check the user-data-dir "
                "argument and try again.";
  if (clear_profile)
    ASSERT_TRUE(file_util::DieFileDie(user_data_dir_, true));

  if (!template_user_data_.empty()) {
    // Recursively copy the template directory to the user_data_dir.
    ASSERT_TRUE(file_util::CopyRecursiveDirNoCache(
        template_user_data_,
        user_data_dir_));
    // If we're using the complex theme data, we need to write the
    // user_data_dir_ to our preferences file.
    if (profile_type_ == UITestBase::COMPLEX_THEME) {
      RewritePreferencesFile(user_data_dir_);
    }

    // Update the history file to include recent dates.
    UpdateHistoryDates();
  }

  ASSERT_TRUE(LaunchBrowserHelper(arguments, use_existing_browser_, false,
                                  &process_));
  process_id_ = base::GetProcId(process_);
}

bool UITestBase::LaunchAnotherBrowserBlockUntilClosed(
    const CommandLine& cmdline) {
  return LaunchBrowserHelper(cmdline, false, true, NULL);
}

void UITestBase::QuitBrowser() {
  if (SESSION_ENDING == shutdown_type_) {
    TerminateBrowser();
    return;
  }

  // There's nothing to do here if the browser is not running.
  if (IsBrowserRunning()) {
    TimeTicks quit_start = TimeTicks::Now();
    EXPECT_TRUE(automation()->SetFilteredInet(false));

    if (WINDOW_CLOSE == shutdown_type_) {
      int window_count = 0;
      EXPECT_TRUE(automation()->GetBrowserWindowCount(&window_count));

      // Synchronously close all but the last browser window. Closing them
      // one-by-one may help with stability.
      while (window_count > 1) {
        scoped_refptr<BrowserProxy> browser_proxy =
            automation()->GetBrowserWindow(0);
        EXPECT_TRUE(browser_proxy.get());
        if (browser_proxy.get()) {
          EXPECT_TRUE(browser_proxy->RunCommand(IDC_CLOSE_WINDOW));
          EXPECT_TRUE(automation()->GetBrowserWindowCount(&window_count));
        } else {
          break;
        }
      }

      // Close the last window asynchronously, because the browser may
      // shutdown faster than it will be able to send a synchronous response
      // to our message.
      scoped_refptr<BrowserProxy> browser_proxy =
          automation()->GetBrowserWindow(0);
      EXPECT_TRUE(browser_proxy.get());
      if (browser_proxy.get()) {
        EXPECT_TRUE(browser_proxy->ApplyAccelerator(IDC_CLOSE_WINDOW));
        browser_proxy = NULL;
      }
    } else if (USER_QUIT == shutdown_type_) {
      scoped_refptr<BrowserProxy> browser_proxy =
          automation()->GetBrowserWindow(0);
      EXPECT_TRUE(browser_proxy.get());
      if (browser_proxy.get()) {
        EXPECT_TRUE(browser_proxy->RunCommandAsync(IDC_EXIT));
      }
    } else {
      NOTREACHED() << "Invalid shutdown type " << shutdown_type_;
    }

    // Now, drop the automation IPC channel so that the automation provider in
    // the browser notices and drops its reference to the browser process.
    automation()->Disconnect();

    // Wait for the browser process to quit. It should quit once all tabs have
    // been closed.
    int timeout = terminate_timeout_ms_;
#ifdef WAIT_FOR_DEBUGGER_ON_OPEN
    timeout = 500000;
#endif
    if (!base::WaitForSingleProcess(process_, timeout)) {
      // We need to force the browser to quit because it didn't quit fast
      // enough. Take no chance and kill every chrome processes.
      CleanupAppProcesses();
    }
    browser_quit_time_ = TimeTicks::Now() - quit_start;
  }

  // Don't forget to close the handle
  base::CloseProcessHandle(process_);
  process_ = base::kNullProcessHandle;
  process_id_ = -1;
}

void UITestBase::TerminateBrowser() {
  if (IsBrowserRunning()) {
    TimeTicks quit_start = TimeTicks::Now();
    EXPECT_TRUE(automation()->SetFilteredInet(false));
#if defined(OS_WIN)
    scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
    ASSERT_TRUE(browser.get());
    ASSERT_TRUE(browser->TerminateSession());
#endif  // defined(OS_WIN)

    // Now, drop the automation IPC channel so that the automation provider in
    // the browser notices and drops its reference to the browser process.
    automation()->Disconnect();

#if defined(OS_POSIX)
    EXPECT_EQ(kill(process_, SIGTERM), 0);
#endif  // OS_POSIX

    // Wait for the browser process to quit.
    int timeout = terminate_timeout_ms_;
#ifdef WAIT_FOR_DEBUGGER_ON_OPEN
    timeout = 500000;
#endif
    if (!base::WaitForSingleProcess(process_, timeout)) {
      // We need to force the browser to quit because it didn't quit fast
      // enough. Take no chance and kill every chrome processes.
      CleanupAppProcesses();
    }
    browser_quit_time_ = TimeTicks::Now() - quit_start;
  }

  // Don't forget to close the handle
  base::CloseProcessHandle(process_);
  process_ = base::kNullProcessHandle;
  process_id_ = -1;
}

void UITestBase::AssertAppNotRunning(const std::wstring& error_message) {
  std::wstring final_error_message(error_message);

  ChromeProcessList processes = GetRunningChromeProcesses(process_id_);
  if (!processes.empty()) {
    final_error_message += L" Leftover PIDs: [";
    for (ChromeProcessList::const_iterator it = processes.begin();
         it != processes.end(); ++it) {
      final_error_message += StringPrintf(L" %d", *it);
    }
    final_error_message += L" ]";
  }
  ASSERT_TRUE(processes.empty()) << final_error_message;
}

void UITestBase::CleanupAppProcesses() {
  TerminateAllChromeProcesses(process_id_);
}

scoped_refptr<TabProxy> UITestBase::GetActiveTab(int window_index) {
  EXPECT_GE(window_index, 0);
  int window_count = -1;
  // We have to use EXPECT rather than ASSERT here because ASSERT_* only works
  // in functions that return void.
  EXPECT_TRUE(automation()->GetBrowserWindowCount(&window_count));
  if (window_count == -1)
    return NULL;
  EXPECT_GT(window_count, window_index);
  scoped_refptr<BrowserProxy> window_proxy(automation()->
      GetBrowserWindow(window_index));
  EXPECT_TRUE(window_proxy.get());
  if (!window_proxy.get())
    return NULL;

  int active_tab_index = -1;
  EXPECT_TRUE(window_proxy->GetActiveTabIndex(&active_tab_index));
  if (active_tab_index == -1)
    return NULL;

  return window_proxy->GetTab(active_tab_index);
}

scoped_refptr<TabProxy> UITestBase::GetActiveTab() {
  scoped_refptr<BrowserProxy> window_proxy(automation()->
      GetBrowserWindow(0));
  EXPECT_TRUE(window_proxy.get());
  if (!window_proxy.get())
    return NULL;

  scoped_refptr<TabProxy> tab_proxy = window_proxy->GetActiveTab();
  EXPECT_TRUE(tab_proxy.get());
  return tab_proxy;
}

void UITestBase::NavigateToURLAsync(const GURL& url) {
  scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
  ASSERT_TRUE(tab_proxy.get());
  ASSERT_TRUE(tab_proxy->NavigateToURLAsync(url));
}

void UITestBase::NavigateToURL(const GURL& url) {
  NavigateToURL(url, 0, GetActiveTabIndex(0));
}

void UITestBase::NavigateToURL(const GURL& url, int window_index, int
    tab_index) {
  NavigateToURLBlockUntilNavigationsComplete(url, 1, window_index, tab_index);
}

void UITestBase::NavigateToURLBlockUntilNavigationsComplete(
    const GURL& url, int number_of_navigations) {
  scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
  ASSERT_TRUE(tab_proxy.get());
  EXPECT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS,
            tab_proxy->NavigateToURLBlockUntilNavigationsComplete(
                url, number_of_navigations)) << url.spec();
}

void UITestBase::NavigateToURLBlockUntilNavigationsComplete(
    const GURL& url, int number_of_navigations, int window_index,
    int tab_index) {
  scoped_refptr<BrowserProxy> window =
    automation()->GetBrowserWindow(window_index);
  ASSERT_TRUE(window.get());
  scoped_refptr<TabProxy> tab_proxy(window->GetTab(tab_index));
  ASSERT_TRUE(tab_proxy.get());
  EXPECT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS,
            tab_proxy->NavigateToURLBlockUntilNavigationsComplete(
                url, number_of_navigations)) << url.spec();
}

bool UITestBase::WaitForDownloadShelfVisible(BrowserProxy* browser) {
  return WaitForDownloadShelfVisibilityChange(browser, true);
}

bool UITestBase::WaitForDownloadShelfInvisible(BrowserProxy* browser) {
  return WaitForDownloadShelfVisibilityChange(browser, false);
}

bool UITestBase::WaitForDownloadShelfVisibilityChange(BrowserProxy* browser,
                                                      bool wait_for_open) {
  const int kCycles = 10;
  for (int i = 0; i < kCycles; i++) {
    // Give it a chance to catch up.
    PlatformThread::Sleep(sleep_timeout_ms() / kCycles);

    bool visible = !wait_for_open;
    if (!browser->IsShelfVisible(&visible))
      continue;
    if (visible == wait_for_open)
      return true;  // Got the download shelf.
  }
  return false;
}

bool UITestBase::WaitForFindWindowVisibilityChange(BrowserProxy* browser,
                                                   bool wait_for_open) {
  const int kCycles = 10;
  for (int i = 0; i < kCycles; i++) {
    bool visible = false;
    if (!browser->IsFindWindowFullyVisible(&visible))
      return false;  // Some error.
    if (visible == wait_for_open)
      return true;  // Find window visibility change complete.

    // Give it a chance to catch up.
    PlatformThread::Sleep(sleep_timeout_ms() / kCycles);
  }
  return false;
}

bool UITestBase::WaitForBookmarkBarVisibilityChange(BrowserProxy* browser,
                                                    bool wait_for_open) {
  const int kCycles = 10;
  for (int i = 0; i < kCycles; i++) {
    bool visible = false;
    bool animating = true;
    if (!browser->GetBookmarkBarVisibility(&visible, &animating))
      return false;  // Some error.
    if (visible == wait_for_open && !animating)
      return true;  // Bookmark bar visibility change complete.

    // Give it a chance to catch up.
    PlatformThread::Sleep(sleep_timeout_ms() / kCycles);
  }
  return false;
}

GURL UITestBase::GetActiveTabURL(int window_index) {
  scoped_refptr<TabProxy> tab_proxy(GetActiveTab(window_index));
  EXPECT_TRUE(tab_proxy.get());
  if (!tab_proxy.get())
    return GURL();

  GURL url;
  bool success = tab_proxy->GetCurrentURL(&url);
  EXPECT_TRUE(success);
  if (!success)
    return GURL();
  return url;
}

std::wstring UITestBase::GetActiveTabTitle(int window_index) {
  std::wstring title;
  scoped_refptr<TabProxy> tab_proxy(GetActiveTab(window_index));
  EXPECT_TRUE(tab_proxy.get());
  if (!tab_proxy.get())
    return title;

  EXPECT_TRUE(tab_proxy->GetTabTitle(&title));
  return title;
}

int UITestBase::GetActiveTabIndex(int window_index) {
  scoped_refptr<BrowserProxy> window_proxy(automation()->
      GetBrowserWindow(window_index));
  EXPECT_TRUE(window_proxy.get());
  if (!window_proxy.get())
    return -1;

  int active_tab_index = -1;
  EXPECT_TRUE(window_proxy->GetActiveTabIndex(&active_tab_index));
  return active_tab_index;
}

bool UITestBase::IsBrowserRunning() {
  return CrashAwareSleep(0);
}

bool UITestBase::CrashAwareSleep(int time_out_ms) {
  return base::CrashAwareSleep(process_, time_out_ms);
}

int UITestBase::GetBrowserProcessCount() {
  return GetRunningChromeProcesses(process_id_).size();
}

static DictionaryValue* LoadDictionaryValueFromPath(const FilePath& path) {
  if (path.empty())
    return NULL;

  JSONFileValueSerializer serializer(path);
  scoped_ptr<Value> root_value(serializer.Deserialize(NULL, NULL));
  if (!root_value.get() || root_value->GetType() != Value::TYPE_DICTIONARY)
    return NULL;

  return static_cast<DictionaryValue*>(root_value.release());
}

DictionaryValue* UITestBase::GetLocalState() {
  FilePath local_state_path;
  PathService::Get(chrome::FILE_LOCAL_STATE, &local_state_path);
  return LoadDictionaryValueFromPath(local_state_path);
}

DictionaryValue* UITestBase::GetDefaultProfilePreferences() {
  FilePath path;
  PathService::Get(chrome::DIR_USER_DATA, &path);
  path = path.AppendASCII(WideToASCII(chrome::kNotSignedInProfile));
  return LoadDictionaryValueFromPath(path.Append(chrome::kPreferencesFilename));
}

int UITestBase::GetTabCount() {
  return GetTabCount(0);
}

int UITestBase::GetTabCount(int window_index) {
  scoped_refptr<BrowserProxy> window(
      automation()->GetBrowserWindow(window_index));
  EXPECT_TRUE(window.get());
  if (!window.get())
    return 0;

  int result = 0;
  EXPECT_TRUE(window->GetTabCount(&result));

  return result;
}

bool UITestBase::WaitUntilCookieValue(TabProxy* tab,
                                      const GURL& url,
                                      const char* cookie_name,
                                      int time_out_ms,
                                      const char* expected_value) {
  const int kIntervalMs = 250;
  const int kMaxIntervals = time_out_ms / kIntervalMs;

  std::string cookie_value;
  for (int i = 0; i < kMaxIntervals; ++i) {
    bool browser_survived = CrashAwareSleep(kIntervalMs);
    EXPECT_TRUE(browser_survived);
    if (!browser_survived)
      return false;

    EXPECT_TRUE(tab->GetCookieByName(url, cookie_name, &cookie_value));
    if (cookie_value == expected_value)
      return true;
  }

  return false;
}

std::string UITestBase::WaitUntilCookieNonEmpty(TabProxy* tab,
                                                const GURL& url,
                                                const char* cookie_name,
                                                int time_out_ms) {
  const int kIntervalMs = 250;
  const int kMaxIntervals = time_out_ms / kIntervalMs;

  for (int i = 0; i < kMaxIntervals; ++i) {
    bool browser_survived = CrashAwareSleep(kIntervalMs);
    EXPECT_TRUE(browser_survived);
    if (!browser_survived)
      return std::string();

    std::string cookie_value;
    EXPECT_TRUE(tab->GetCookieByName(url, cookie_name, &cookie_value));
    if (!cookie_value.empty())
      return cookie_value;
  }

  return std::string();
}

bool UITestBase::WaitUntilJavaScriptCondition(TabProxy* tab,
                                              const std::wstring& frame_xpath,
                                              const std::wstring& jscript,
                                              int time_out_ms) {
  const int kIntervalMs = 250;
  const int kMaxIntervals = time_out_ms / kIntervalMs;

  // Wait until the test signals it has completed.
  for (int i = 0; i < kMaxIntervals; ++i) {
    bool browser_survived = CrashAwareSleep(kIntervalMs);
    EXPECT_TRUE(browser_survived);
    if (!browser_survived)
      return false;

    bool done_value = false;
    bool success = tab->ExecuteAndExtractBool(frame_xpath, jscript,
                                              &done_value);
    EXPECT_TRUE(success);
    if (!success)
      return false;
    if (done_value)
      return true;
  }

  return false;
}

void UITestBase::WaitUntilTabCount(int tab_count) {
  for (int i = 0; i < 10; ++i) {
    PlatformThread::Sleep(sleep_timeout_ms() / 10);
    if (GetTabCount() == tab_count)
      break;
  }
  EXPECT_EQ(tab_count, GetTabCount());
}

FilePath UITestBase::GetDownloadDirectory() {
  scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
  EXPECT_TRUE(tab_proxy.get());
  if (!tab_proxy.get())
    return FilePath();

  FilePath download_directory;
  EXPECT_TRUE(tab_proxy->GetDownloadDirectory(&download_directory));
  return download_directory;
}

void UITestBase::CloseBrowserAsync(BrowserProxy* browser) const {
  ASSERT_TRUE(server_->Send(
      new AutomationMsg_CloseBrowserRequestAsync(0, browser->handle())));
}

bool UITestBase::CloseBrowser(BrowserProxy* browser,
                              bool* application_closed) const {
  DCHECK(application_closed);
  if (!browser->is_valid() || !browser->handle())
    return false;

  bool result = true;

  bool succeeded = server_->Send(new AutomationMsg_CloseBrowser(
      0, browser->handle(), &result, application_closed));

  if (!succeeded)
    return false;

  if (*application_closed) {
    // Let's wait until the process dies (if it is not gone already).
    bool success = base::WaitForSingleProcess(process_, base::kNoTimeout);
    DCHECK(success);
  }

  return result;
}

void UITestBase::WaitForFinish(const std::string &name,
                           const std::string &id,
                           const GURL &url,
                           const std::string& test_complete_cookie,
                           const std::string& expected_cookie_value,
                           const int wait_time) {
  // The webpage being tested has javascript which sets a cookie
  // which signals completion of the test.  The cookie name is
  // a concatenation of the test name and the test id.  This allows
  // us to run multiple tests within a single webpage and test
  // that they all c
  std::string cookie_name = name;
  cookie_name.append(".");
  cookie_name.append(id);
  cookie_name.append(".");
  cookie_name.append(test_complete_cookie);

  scoped_refptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab.get());
  bool test_result = WaitUntilCookieValue(tab.get(), url,
                                          cookie_name.c_str(),
                                          wait_time,
                                          expected_cookie_value.c_str());
  EXPECT_EQ(true, test_result);
}

void UITestBase::PrintResult(const std::string& measurement,
                         const std::string& modifier,
                         const std::string& trace,
                         size_t value,
                         const std::string& units,
                         bool important) {
  PrintResultsImpl(measurement, modifier, trace, UintToString(value),
                   "", "", units, important);
}

void UITestBase::PrintResult(const std::string& measurement,
                         const std::string& modifier,
                         const std::string& trace,
                         const std::string& value,
                         const std::string& units,
                         bool important) {
  PrintResultsImpl(measurement, modifier, trace, value, "", "", units,
                   important);
}

void UITestBase::PrintResultMeanAndError(const std::string& measurement,
                                     const std::string& modifier,
                                     const std::string& trace,
                                     const std::string& mean_and_error,
                                     const std::string& units,
                                     bool important) {
  PrintResultsImpl(measurement, modifier, trace, mean_and_error,
                   "{", "}", units, important);
}

void UITestBase::PrintResultList(const std::string& measurement,
                             const std::string& modifier,
                             const std::string& trace,
                             const std::string& values,
                             const std::string& units,
                             bool important) {
  PrintResultsImpl(measurement, modifier, trace, values,
                   "[", "]", units, important);
}

void UITestBase::PrintResultsImpl(const std::string& measurement,
                              const std::string& modifier,
                              const std::string& trace,
                              const std::string& values,
                              const std::string& prefix,
                              const std::string& suffix,
                              const std::string& units,
                              bool important) {
  // <*>RESULT <graph_name>: <trace_name>= <value> <units>
  // <*>RESULT <graph_name>: <trace_name>= {<mean>, <std deviation>} <units>
  // <*>RESULT <graph_name>: <trace_name>= [<value>,value,value,...,] <units>
  printf("%sRESULT %s%s: %s= %s%s%s %s\n",
         important ? "*" : "", measurement.c_str(), modifier.c_str(),
         trace.c_str(), prefix.c_str(), values.c_str(), suffix.c_str(),
         units.c_str());
}

bool UITestBase::EvictFileFromSystemCacheWrapper(const FilePath& path) {
  for (int i = 0; i < 10; i++) {
    if (file_util::EvictFileFromSystemCache(path))
      return true;
    PlatformThread::Sleep(sleep_timeout_ms() / 10);
  }
  return false;
}

// static
void UITestBase::RewritePreferencesFile(const FilePath& user_data_dir) {
  const FilePath pref_template_path(
      user_data_dir.AppendASCII("Default").AppendASCII("PreferencesTemplate"));
  const FilePath pref_path(
      user_data_dir.AppendASCII("Default").AppendASCII("Preferences"));

  // Read in preferences template.
  std::string pref_string;
  EXPECT_TRUE(file_util::ReadFileToString(pref_template_path, &pref_string));
  string16 format_string = ASCIIToUTF16(pref_string);

  // Make sure temp directory has the proper format for writing to prefs file.
#if defined(OS_POSIX)
  std::wstring user_data_dir_w(ASCIIToWide(user_data_dir.value()));
#elif defined(OS_WIN)
  std::wstring user_data_dir_w(user_data_dir.value());
  // In Windows, the FilePath will write '\' for the path separators; change
  // these to a separator that won't trigger escapes.
  std::replace(user_data_dir_w.begin(),
               user_data_dir_w.end(), '\\', '/');
#endif

  // Rewrite prefs file.
  std::vector<string16> subst;
  subst.push_back(WideToUTF16(user_data_dir_w));
  const std::string prefs_string =
      UTF16ToASCII(ReplaceStringPlaceholders(format_string, subst, NULL));
  EXPECT_TRUE(file_util::WriteFile(pref_path, prefs_string.c_str(),
                                   prefs_string.size()));
  file_util::EvictFileFromSystemCache(pref_path);
}

// static
FilePath UITestBase::ComputeTypicalUserDataSource(ProfileType profile_type) {
  FilePath source_history_file;
  EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA,
                               &source_history_file));
  source_history_file = source_history_file.AppendASCII("profiles");
  switch (profile_type) {
    case UITestBase::DEFAULT_THEME:
      source_history_file = source_history_file.AppendASCII("typical_history");
      break;
    case UITestBase::COMPLEX_THEME:
      source_history_file = source_history_file.AppendASCII("complex_theme");
      break;
    case UITestBase::NATIVE_THEME:
      source_history_file = source_history_file.AppendASCII("gtk_theme");
      break;
    case UITestBase::CUSTOM_FRAME:
      source_history_file = source_history_file.AppendASCII("custom_frame");
      break;
    case UITestBase::CUSTOM_FRAME_NATIVE_THEME:
      source_history_file =
          source_history_file.AppendASCII("custom_frame_gtk_theme");
      break;
    default:
      NOTREACHED();
  }
  return source_history_file;
}

void UITestBase::WaitForGeneratedFileAndCheck(const FilePath& generated_file,
                                          const FilePath& original_file,
                                          bool compare_files,
                                          bool need_equal,
                                          bool delete_generated_file) {
  // Check whether the target file has been generated.
  file_util::FileInfo previous, current;
  bool exist = false;
  const int kCycles = 20;
  for (int i = 0; i < kCycles; ++i) {
    if (exist) {
      file_util::GetFileInfo(generated_file, &current);
      if (current.size == previous.size)
        break;
      previous = current;
    } else if (file_util::PathExists(generated_file)) {
      file_util::GetFileInfo(generated_file, &previous);
      exist = true;
    }
    PlatformThread::Sleep(sleep_timeout_ms() / kCycles);
  }
  EXPECT_TRUE(exist);

  if (compare_files) {
    // Check whether the generated file is equal with original file according to
    // parameter: need_equal.
    int64 generated_file_size = 0;
    int64 original_file_size = 0;

    EXPECT_TRUE(file_util::GetFileSize(generated_file, &generated_file_size));
    EXPECT_TRUE(file_util::GetFileSize(original_file, &original_file_size));
    if (need_equal) {
      EXPECT_EQ(generated_file_size, original_file_size);
      EXPECT_TRUE(file_util::ContentsEqual(generated_file, original_file));
    } else {
      EXPECT_NE(generated_file_size, original_file_size);
      EXPECT_FALSE(file_util::ContentsEqual(generated_file, original_file));
    }
  }
  if (delete_generated_file)
    EXPECT_TRUE(file_util::DieFileDie(generated_file, false));
}

bool UITestBase::LaunchBrowserHelper(const CommandLine& arguments,
                                 bool use_existing_browser,
                                 bool wait,
                                 base::ProcessHandle* process) {
  FilePath command = browser_directory_.Append(
      FilePath::FromWStringHack(chrome::kBrowserProcessExecutablePath));
  CommandLine command_line(command);

  // Add any explicit command line flags passed to the process.
  std::wstring extra_chrome_flags =
      CommandLine::ForCurrentProcess()->GetSwitchValue(kExtraChromeFlagsSwitch);
  if (!extra_chrome_flags.empty()) {
    // Split by spaces and append to command line
    std::vector<std::wstring> flags;
    SplitString(extra_chrome_flags, ' ', &flags);
    for (size_t i = 0; i < flags.size(); ++i)
      command_line.AppendLooseValue(flags[i]);
  }

  // No first-run dialogs, please.
  command_line.AppendSwitch(switches::kNoFirstRun);

  // No default browser check, it would create an info-bar (if we are not the
  // default browser) that could conflicts with some tests expectations.
  command_line.AppendSwitch(switches::kNoDefaultBrowserCheck);

  // This is a UI test.
  command_line.AppendSwitchWithValue(switches::kTestType,
                                     ASCIIToWide(kUITestType));

  // We need cookies on file:// for things like the page cycler.
  if (enable_file_cookies_)
    command_line.AppendSwitch(switches::kEnableFileCookies);

  if (dom_automation_enabled_)
    command_line.AppendSwitch(switches::kDomAutomationController);

  if (include_testing_id_) {
    if (use_existing_browser) {
      // TODO(erikkay): The new switch depends on a browser instance already
      // running, it won't open a new browser window if it's not.  We could fix
      // this by passing an url (e.g. about:blank) on the command line, but
      // I decided to keep using the old switch in the existing use case to
      // minimize changes in behavior.
      command_line.AppendSwitchWithValue(switches::kAutomationClientChannelID,
                                         ASCIIToWide(server_->channel_id()));
    } else {
      command_line.AppendSwitchWithValue(switches::kTestingChannelID,
                                         ASCIIToWide(server_->channel_id()));
    }
  }

  if (!show_error_dialogs_ &&
      !CommandLine::ForCurrentProcess()->HasSwitch(kEnableErrorDialogs)) {
    command_line.AppendSwitch(switches::kNoErrorDialogs);
  }
  if (in_process_renderer_)
    command_line.AppendSwitch(switches::kSingleProcess);
  if (no_sandbox_)
    command_line.AppendSwitch(switches::kNoSandbox);
  if (full_memory_dump_)
    command_line.AppendSwitch(switches::kFullMemoryCrashReport);
  if (safe_plugins_)
    command_line.AppendSwitch(switches::kSafePlugins);
  if (enable_dcheck_)
    command_line.AppendSwitch(switches::kEnableDCHECK);
  if (silent_dump_on_dcheck_)
    command_line.AppendSwitch(switches::kSilentDumpOnDCHECK);
  if (disable_breakpad_)
    command_line.AppendSwitch(switches::kDisableBreakpad);
  if (!homepage_.empty())
    command_line.AppendSwitchWithValue(switches::kHomePage,
                                       homepage_);
  // Don't try to fetch web resources during UI testing.
  command_line.AppendSwitch(switches::kDisableWebResources);

  if (!user_data_dir_.empty())
    command_line.AppendSwitchWithValue(switches::kUserDataDir,
                                       user_data_dir_.ToWStringHack());
  if (!js_flags_.empty())
    command_line.AppendSwitchWithValue(switches::kJavaScriptFlags,
                                       js_flags_);
  if (!log_level_.empty())
    command_line.AppendSwitchWithValue(switches::kLoggingLevel, log_level_);

  command_line.AppendSwitch(switches::kMetricsRecordingOnly);

  if (!CommandLine::ForCurrentProcess()->HasSwitch(kEnableErrorDialogs))
    command_line.AppendSwitch(switches::kEnableLogging);

  if (dump_histograms_on_exit_)
    command_line.AppendSwitch(switches::kDumpHistogramsOnExit);

#ifdef WAIT_FOR_DEBUGGER_ON_OPEN
  command_line.AppendSwitch(switches::kDebugOnStart);
#endif

  if (!ui_test_name_.empty())
    command_line.AppendSwitchWithValue(switches::kTestName,
                                       ui_test_name_);

  // The tests assume that file:// URIs can freely access other file:// URIs.
  command_line.AppendSwitch(switches::kAllowFileAccessFromFiles);

  DebugFlags::ProcessDebugFlags(
      &command_line, ChildProcessInfo::UNKNOWN_PROCESS, false);
  command_line.AppendArguments(arguments, false);

  // TODO(phajdan.jr): Only run it for "main" browser launch.
  browser_launch_time_ = TimeTicks::Now();

#if defined(OS_WIN)
  bool started = base::LaunchApp(command_line,
                                 wait,
                                 !show_window_,
                                 process);
#elif defined(OS_POSIX)
  // Sometimes one needs to run the browser under a special environment
  // (e.g. valgrind) without also running the test harness (e.g. python)
  // under the special environment.  Provide a way to wrap the browser
  // commandline with a special prefix to invoke the special environment.
  const char* browser_wrapper = getenv("BROWSER_WRAPPER");
  if (browser_wrapper) {
    command_line.PrependWrapper(ASCIIToWide(browser_wrapper));
    LOG(INFO) << "BROWSER_WRAPPER was set, prefixing command_line with "
              << browser_wrapper;
  }

  bool started = base::LaunchApp(command_line.argv(),
                                 server_->fds_to_map(),
                                 wait,
                                 process);
#endif
  if (!started)
    return false;

  if (use_existing_browser) {
#if defined(OS_WIN)
    DWORD pid = 0;
    HWND hwnd = FindWindowEx(HWND_MESSAGE, NULL, chrome::kMessageWindowClass,
                             user_data_dir_.value().c_str());
    GetWindowThreadProcessId(hwnd, &pid);
    // This mode doesn't work if we wound up launching a new browser ourselves.
    EXPECT_NE(pid, base::GetProcId(*process));
    CloseHandle(*process);
    *process = OpenProcess(SYNCHRONIZE, false, pid);
#else
  // TODO(port): above code is very Windows-specific; we need to
  // figure out and abstract out how we'll handle finding any existing
  // running process, etc. on other platforms.
  NOTIMPLEMENTED();
#endif
  }

  return true;
}

void UITestBase::UpdateHistoryDates() {
  // Migrate the times in the segment_usage table to yesterday so we get
  // actual thumbnails on the NTP.
  sql::Connection db;
  FilePath history =
      user_data_dir_.AppendASCII("Default").AppendASCII("History");
  // Not all test profiles have a history file.
  if (!file_util::PathExists(history))
    return;

  ASSERT_TRUE(db.Open(history));
  Time yesterday = Time::Now() - TimeDelta::FromDays(1);
  std::string yesterday_str = Int64ToString(yesterday.ToInternalValue());
  std::string query = StringPrintf(
      "UPDATE segment_usage "
      "SET time_slot = %s "
      "WHERE id IN (SELECT id FROM segment_usage WHERE time_slot > 0);",
      yesterday_str.c_str());
  ASSERT_TRUE(db.Execute(query.c_str()));
  db.Close();
  file_util::EvictFileFromSystemCache(history);
}

void UITestBase::PrintIOPerfInfo(const char* test_name) {
  ChromeProcessList chrome_processes(GetRunningChromeProcesses(process_id_));

  size_t read_op_b = 0;
  size_t read_op_r = 0;
  size_t write_op_b = 0;
  size_t write_op_r = 0;
  size_t other_op_b = 0;
  size_t other_op_r = 0;
  size_t total_op_b = 0;
  size_t total_op_r = 0;

  size_t read_byte_b = 0;
  size_t read_byte_r = 0;
  size_t write_byte_b = 0;
  size_t write_byte_r = 0;
  size_t other_byte_b = 0;
  size_t other_byte_r = 0;
  size_t total_byte_b = 0;
  size_t total_byte_r = 0;

  ChromeProcessList::const_iterator it;
  for (it = chrome_processes.begin(); it != chrome_processes.end(); ++it) {
    base::ProcessHandle process_handle;
    if (!base::OpenPrivilegedProcessHandle(*it, &process_handle)) {
      NOTREACHED();
      return;
    }

    // TODO(sgk):  if/when base::ProcessMetrics returns real stats on mac:
    // scoped_ptr<base::ProcessMetrics> process_metrics(
    //     base::ProcessMetrics::CreateProcessMetrics(process_handle));
    scoped_ptr<ChromeTestProcessMetrics> process_metrics(
        ChromeTestProcessMetrics::CreateProcessMetrics(process_handle));
    base::IoCounters io_counters;
    memset(&io_counters, 0, sizeof(io_counters));

    if (process_metrics.get()->GetIOCounters(&io_counters)) {
      // Print out IO performance.  We assume that the values can be
      // converted to size_t (they're reported as ULONGLONG, 64-bit numbers).
      std::string chrome_name = (*it == browser_process_id()) ? "_b" : "_r";

      size_t read_op = static_cast<size_t>(io_counters.ReadOperationCount);
      size_t write_op = static_cast<size_t>(io_counters.WriteOperationCount);
      size_t other_op = static_cast<size_t>(io_counters.OtherOperationCount);
      size_t total_op = static_cast<size_t>(io_counters.ReadOperationCount +
                                            io_counters.WriteOperationCount +
                                            io_counters.OtherOperationCount);

      size_t read_byte = static_cast<size_t>(io_counters.ReadTransferCount
                                             / 1024);
      size_t write_byte = static_cast<size_t>(io_counters.WriteTransferCount
                                              / 1024);
      size_t other_byte = static_cast<size_t>(io_counters.OtherTransferCount
                                              / 1024);
      size_t total_byte = static_cast<size_t>((io_counters.ReadTransferCount +
                                               io_counters.WriteTransferCount +
                                               io_counters.OtherTransferCount)
                                              / 1024);

      if (*it == browser_process_id()) {
        read_op_b = read_op;
        write_op_b = write_op;
        other_op_b = other_op;
        total_op_b = total_op;
        read_byte_b = read_byte;
        write_byte_b = write_byte;
        other_byte_b = other_byte;
        total_byte_b = total_byte;
      } else {
        read_op_r += read_op;
        write_op_r += write_op;
        other_op_r += other_op;
        total_op_r += total_op;
        read_byte_r += read_byte;
        write_byte_r += write_byte;
        other_byte_r += other_byte;
        total_byte_r += total_byte;
      }
    }

    base::CloseProcessHandle(process_handle);
  }

  std::string t_name(test_name);
  PrintResult("read_op_b", "", "r_op_b" + t_name, read_op_b, "", false);
  PrintResult("write_op_b", "", "w_op_b" + t_name, write_op_b, "", false);
  PrintResult("other_op_b", "", "o_op_b" + t_name, other_op_b, "", false);
  PrintResult("total_op_b", "", "IO_op_b" + t_name, total_op_b, "", true);

  PrintResult("read_byte_b", "", "r_b" + t_name, read_byte_b, "kb", false);
  PrintResult("write_byte_b", "", "w_b" + t_name, write_byte_b, "kb", false);
  PrintResult("other_byte_b", "", "o_b" + t_name, other_byte_b, "kb", false);
  PrintResult("total_byte_b", "", "IO_b" + t_name, total_byte_b, "kb", true);

  PrintResult("read_op_r", "", "r_op_r" + t_name, read_op_r, "", false);
  PrintResult("write_op_r", "", "w_op_r" + t_name, write_op_r, "", false);
  PrintResult("other_op_r", "", "o_op_r" + t_name, other_op_r, "", false);
  PrintResult("total_op_r", "", "IO_op_r" + t_name, total_op_r, "", true);

  PrintResult("read_byte_r", "", "r_r" + t_name, read_byte_r, "kb", false);
  PrintResult("write_byte_r", "", "w_r" + t_name, write_byte_r, "kb", false);
  PrintResult("other_byte_r", "", "o_r" + t_name, other_byte_r, "kb", false);
  PrintResult("total_byte_r", "", "IO_r" + t_name, total_byte_r, "kb", true);
}

void UITestBase::PrintMemoryUsageInfo(const char* test_name) {
  ChromeProcessList chrome_processes(GetRunningChromeProcesses(process_id_));

  size_t browser_virtual_size = 0;
  size_t browser_working_set_size = 0;
  size_t renderer_virtual_size = 0;
  size_t renderer_working_set_size = 0;
  size_t total_virtual_size = 0;
  size_t total_working_set_size = 0;
#if defined(OS_WIN)
  size_t browser_peak_virtual_size = 0;
  size_t browser_peak_working_set_size = 0;
  size_t renderer_total_peak_virtual_size = 0;
  size_t renderer_total_peak_working_set_size = 0;
  size_t renderer_single_peak_virtual_size = 0;
  size_t renderer_single_peak_working_set_size = 0;
#endif

  ChromeProcessList::const_iterator it;
  for (it = chrome_processes.begin(); it != chrome_processes.end(); ++it) {
    base::ProcessHandle process_handle;
    if (!base::OpenPrivilegedProcessHandle(*it, &process_handle)) {
      NOTREACHED();
      return;
    }

    // TODO(sgk):  if/when base::ProcessMetrics returns real stats on mac:
    // scoped_ptr<base::ProcessMetrics> process_metrics(
    //     base::ProcessMetrics::CreateProcessMetrics(process_handle));
    scoped_ptr<ChromeTestProcessMetrics> process_metrics(
        ChromeTestProcessMetrics::CreateProcessMetrics(process_handle));

    size_t current_virtual_size = process_metrics->GetPagefileUsage();
    size_t current_working_set_size = process_metrics->GetWorkingSetSize();

    if (*it == browser_process_id()) {
      browser_virtual_size = current_virtual_size;
      browser_working_set_size = current_working_set_size;
    } else {
      renderer_virtual_size += current_virtual_size;
      renderer_working_set_size += current_working_set_size;
    }
    total_virtual_size += current_virtual_size;
    total_working_set_size += current_working_set_size;

#if defined(OS_WIN)
    size_t peak_virtual_size = process_metrics->GetPeakPagefileUsage();
    size_t peak_working_set_size = process_metrics->GetPeakWorkingSetSize();
    if (*it == browser_process_id()) {
      browser_peak_virtual_size = peak_virtual_size;
      browser_peak_working_set_size = peak_working_set_size;
    } else {
      if (peak_virtual_size > renderer_single_peak_virtual_size) {
        renderer_single_peak_virtual_size = peak_virtual_size;
      }
      if (peak_working_set_size > renderer_single_peak_working_set_size) {
        renderer_single_peak_working_set_size = peak_working_set_size;
      }
      renderer_total_peak_virtual_size += peak_virtual_size;
      renderer_total_peak_working_set_size += peak_working_set_size;
    }
#endif

    base::CloseProcessHandle(process_handle);
  }

  std::string trace_name(test_name);
#if defined(OS_WIN)
  PrintResult("vm_peak_b", "", "vm_pk_b" + trace_name,
              browser_peak_virtual_size, "bytes",
              true /* important */);
  PrintResult("ws_peak_b", "", "ws_pk_b" + trace_name,
              browser_peak_working_set_size, "bytes",
              true /* important */);
  PrintResult("vm_peak_r", "", "vm_pk_r" + trace_name,
              renderer_total_peak_virtual_size, "bytes",
              true /* important */);
  PrintResult("ws_peak_r", "", "ws_pk_r" + trace_name,
              renderer_total_peak_working_set_size, "bytes",
              true /* important */);
  PrintResult("vm_single_peak_r", "", "vm_spk_r" + trace_name,
              renderer_single_peak_virtual_size, "bytes",
              true /* important */);
  PrintResult("ws_single_peak_r", "", "ws_spk_r" + trace_name,
              renderer_single_peak_working_set_size, "bytes",
              true /* important */);

  PrintResult("vm_final_b", "", "vm_f_b" + trace_name,
              browser_virtual_size, "bytes",
              false /* not important */);
  PrintResult("ws_final_b", "", "ws_f_b" + trace_name,
              browser_working_set_size, "bytes",
              false /* not important */);
  PrintResult("vm_final_r", "", "vm_f_r" + trace_name,
              renderer_virtual_size, "bytes",
              false /* not important */);
  PrintResult("ws_final_r", "", "ws_f_r" + trace_name,
              renderer_working_set_size, "bytes",
              false /* not important */);
  PrintResult("vm_final_t", "", "vm_f_t" + trace_name,
              total_virtual_size, "bytes",
              false /* not important */);
  PrintResult("ws_final_t", "", "ws_f_t" + trace_name,
              total_working_set_size, "bytes",
              false /* not important */);
#elif defined(OS_LINUX) || defined(OS_MACOSX)
  PrintResult("vm_size_final_b", "", "vm_size_f_b" + trace_name,
              browser_virtual_size, "bytes",
              true /* important */);
  PrintResult("vm_rss_final_b", "", "vm_rss_f_b" + trace_name,
              browser_working_set_size, "bytes",
              true /* important */);
  PrintResult("vm_size_final_r", "", "vm_size_f_r" + trace_name,
              renderer_virtual_size, "bytes",
              true /* important */);
  PrintResult("vm_rss_final_r", "", "vm_rss_f_r" + trace_name,
              renderer_working_set_size, "bytes",
              true /* important */);
  PrintResult("vm_size_final_t", "", "vm_size_f_t" + trace_name,
              total_virtual_size, "bytes",
              true /* important */);
  PrintResult("vm_rss_final_t", "", "vm_rss_f_t" + trace_name,
              total_working_set_size, "bytes",
              true /* important */);
#else
  NOTIMPLEMENTED();
#endif
  PrintResult("processes", "", "proc_" + trace_name,
              chrome_processes.size(), "",
              false /* not important */);
}

void UITestBase::PrintSystemCommitCharge(const char* test_name,
                                     size_t charge,
                                     bool important) {
  std::string trace_name(test_name);
  PrintResult("commit_charge", "", "cc" + trace_name, charge, "kb", important);
}

void UITestBase::UseReferenceBuild() {
  FilePath dir;
  PathService::Get(chrome::DIR_TEST_TOOLS, &dir);
  dir = dir.AppendASCII("reference_build");
#if defined(OS_WIN)
  dir = dir.AppendASCII("chrome");
#elif defined(OS_LINUX)
  dir = dir.AppendASCII("chrome_linux");
#elif defined(OS_MACOSX)
  dir = dir.AppendASCII("chrome_mac");
#endif
  SetBrowserDirectory(dir);
}

void UITestBase::SetBrowserDirectory(const FilePath& dir) {
  browser_directory_ = dir;
}

// UITest methods

void UITest::SetUp() {
  // Pass the test case name to chrome.exe on the command line to help with
  // parsing Purify output.
  const testing::TestInfo* const test_info =
      testing::UnitTest::GetInstance()->current_test_info();
  if (test_info) {
    std::string test_name = test_info->test_case_name();
    test_name += ".";
    test_name += test_info->name();
    set_ui_test_name(ASCIIToWide(test_name));
  }
  UITestBase::SetUp();
  PlatformTest::SetUp();
}

void UITest::TearDown() {
  UITestBase::TearDown();
  PlatformTest::TearDown();
}

Generated by  Doxygen 1.6.0   Back to index