Home | History | Annotate | Download | only in ui
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/test/ui/ui_test.h"
      6 
      7 #if defined(OS_POSIX)
      8 #include <signal.h>
      9 #include <sys/types.h>
     10 #endif
     11 
     12 #include <set>
     13 #include <vector>
     14 
     15 #include "base/base_switches.h"
     16 #include "base/bind.h"
     17 #include "base/command_line.h"
     18 #include "base/environment.h"
     19 #include "base/file_util.h"
     20 #include "base/files/file_enumerator.h"
     21 #include "base/files/file_path.h"
     22 #include "base/files/scoped_temp_dir.h"
     23 #include "base/json/json_file_value_serializer.h"
     24 #include "base/logging.h"
     25 #include "base/memory/scoped_ptr.h"
     26 #include "base/path_service.h"
     27 #include "base/strings/string_number_conversions.h"
     28 #include "base/strings/string_split.h"
     29 #include "base/strings/utf_string_conversions.h"
     30 #include "base/test/test_file_util.h"
     31 #include "base/test/test_timeouts.h"
     32 #include "base/threading/platform_thread.h"
     33 #include "base/time/time.h"
     34 #include "chrome/app/chrome_command_ids.h"
     35 #include "chrome/browser/profiles/profile_impl.h"
     36 #include "chrome/common/automation_messages.h"
     37 #include "chrome/common/chrome_constants.h"
     38 #include "chrome/common/chrome_paths.h"
     39 #include "chrome/common/chrome_switches.h"
     40 #include "chrome/common/logging_chrome.h"
     41 #include "chrome/common/net/url_fixer_upper.h"
     42 #include "chrome/common/pref_names.h"
     43 #include "chrome/common/url_constants.h"
     44 #include "chrome/test/automation/automation_proxy.h"
     45 #include "chrome/test/automation/browser_proxy.h"
     46 #include "chrome/test/automation/proxy_launcher.h"
     47 #include "chrome/test/automation/tab_proxy.h"
     48 #include "chrome/test/automation/window_proxy.h"
     49 #include "chrome/test/base/chrome_process_util.h"
     50 #include "chrome/test/base/test_launcher_utils.h"
     51 #include "chrome/test/base/test_switches.h"
     52 #include "chrome/test/base/testing_profile.h"
     53 #include "net/base/net_util.h"
     54 #include "ui/gl/gl_implementation.h"
     55 #include "url/gurl.h"
     56 
     57 #if defined(OS_WIN)
     58 #include "base/win/windows_version.h"
     59 #endif
     60 
     61 using base::Time;
     62 using base::TimeDelta;
     63 using base::TimeTicks;
     64 
     65 const wchar_t UITestBase::kFailedNoCrashService[] =
     66 #if defined(OS_WIN)
     67     L"NOTE: This test is expected to fail if crash_service.exe is not "
     68     L"running. Start it manually before running this test (see the build "
     69     L"output directory).";
     70 #elif defined(OS_LINUX)
     71     L"NOTE: This test is expected to fail if breakpad is not built in "
     72     L"or if chromium is not running headless (try CHROME_HEADLESS=1).";
     73 #else
     74     L"NOTE: Crash service not ported to this platform!";
     75 #endif
     76 
     77 UITestBase::UITestBase()
     78     : launch_arguments_(CommandLine::NO_PROGRAM),
     79       expected_errors_(0),
     80       expected_crashes_(0),
     81       homepage_(content::kAboutBlankURL),
     82       wait_for_initial_loads_(true),
     83       dom_automation_enabled_(false),
     84       stats_collection_controller_enabled_(false),
     85       show_window_(false),
     86       clear_profile_(true),
     87       include_testing_id_(true),
     88       enable_file_cookies_(true) {
     89   PathService::Get(chrome::DIR_APP, &browser_directory_);
     90   PathService::Get(chrome::DIR_TEST_DATA, &test_data_directory_);
     91 }
     92 
     93 UITestBase::UITestBase(base::MessageLoop::Type msg_loop_type)
     94     : launch_arguments_(CommandLine::NO_PROGRAM),
     95       expected_errors_(0),
     96       expected_crashes_(0),
     97       wait_for_initial_loads_(true),
     98       dom_automation_enabled_(false),
     99       stats_collection_controller_enabled_(false),
    100       show_window_(false),
    101       clear_profile_(true),
    102       include_testing_id_(true),
    103       enable_file_cookies_(true) {
    104   PathService::Get(chrome::DIR_APP, &browser_directory_);
    105   PathService::Get(chrome::DIR_TEST_DATA, &test_data_directory_);
    106 }
    107 
    108 UITestBase::~UITestBase() {}
    109 
    110 void UITestBase::SetUp() {
    111   // Tests that do a session restore (e.g. SessionRestoreUITest, StartupTest)
    112   // call SetUp() multiple times because they restart the browser mid-test.
    113   // We don't want to reset the ProxyLauncher's state in those cases.
    114   if (!launcher_.get())
    115     launcher_.reset(CreateProxyLauncher());
    116   launcher_->AssertAppNotRunning("Please close any other instances "
    117                                  "of the app before testing.");
    118 
    119   test_start_time_ = Time::NowFromSystemTime();
    120 
    121   SetLaunchSwitches();
    122   ASSERT_TRUE(launcher_->InitializeConnection(DefaultLaunchState(),
    123                                               wait_for_initial_loads_));
    124 }
    125 
    126 void UITestBase::TearDown() {
    127   if (launcher_.get())
    128     launcher_->TerminateConnection();
    129 
    130   CheckErrorsAndCrashes();
    131 }
    132 
    133 AutomationProxy* UITestBase::automation() const {
    134   return launcher_->automation();
    135 }
    136 
    137 base::TimeDelta UITestBase::action_timeout() {
    138   return automation()->action_timeout();
    139 }
    140 
    141 int UITestBase::action_timeout_ms() {
    142   return action_timeout().InMilliseconds();
    143 }
    144 
    145 void UITestBase::set_action_timeout(base::TimeDelta timeout) {
    146   automation()->set_action_timeout(timeout);
    147   VLOG(1) << "Automation action timeout set to "
    148           << timeout.InMilliseconds() << " ms";
    149 }
    150 
    151 void UITestBase::set_action_timeout_ms(int timeout) {
    152   set_action_timeout(base::TimeDelta::FromMilliseconds(timeout));
    153 }
    154 
    155 ProxyLauncher* UITestBase::CreateProxyLauncher() {
    156   return new AnonymousProxyLauncher(false);
    157 }
    158 
    159 ProxyLauncher::LaunchState UITestBase::DefaultLaunchState() {
    160   base::FilePath browser_executable =
    161       browser_directory_.Append(GetExecutablePath());
    162   CommandLine command(browser_executable);
    163   command.AppendArguments(launch_arguments_, false);
    164   base::Closure setup_profile_callback = base::Bind(&UITestBase::SetUpProfile,
    165                                                     base::Unretained(this));
    166   ProxyLauncher::LaunchState state =
    167       { clear_profile_, template_user_data_, setup_profile_callback,
    168         command, include_testing_id_, show_window_ };
    169   return state;
    170 }
    171 
    172 void UITestBase::SetLaunchSwitches() {
    173   // All flags added here should also be added in ExtraChromeFlags() in
    174   // chrome/test/pyautolib/pyauto.py as well to take effect for all tests
    175   // on chromeos.
    176 
    177   // Propagate commandline settings from test_launcher_utils.
    178   test_launcher_utils::PrepareBrowserCommandLineForTests(&launch_arguments_);
    179 
    180   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kWaitForDebugger))
    181     launch_arguments_.AppendSwitch(switches::kWaitForDebugger);
    182 
    183   // We need cookies on file:// for things like the page cycler.
    184   if (enable_file_cookies_)
    185     launch_arguments_.AppendSwitch(switches::kEnableFileCookies);
    186   if (dom_automation_enabled_)
    187     launch_arguments_.AppendSwitch(switches::kDomAutomationController);
    188   if (stats_collection_controller_enabled_)
    189     launch_arguments_.AppendSwitch(switches::kStatsCollectionController);
    190   // Allow off-store extension installs.
    191   launch_arguments_.AppendSwitchASCII(
    192       switches::kEasyOffStoreExtensionInstall, "1");
    193   if (!homepage_.empty()) {
    194     // Pass |homepage_| both as an arg (so that it opens on startup) and to the
    195     // homepage switch (so that the homepage is set).
    196 
    197     if (!launch_arguments_.HasSwitch(switches::kHomePage))
    198       launch_arguments_.AppendSwitchASCII(switches::kHomePage, homepage_);
    199 
    200     if (launch_arguments_.GetArgs().empty() &&
    201         !launch_arguments_.HasSwitch(switches::kRestoreLastSession)) {
    202       launch_arguments_.AppendArg(homepage_);
    203     }
    204   }
    205   if (!test_name_.empty())
    206     launch_arguments_.AppendSwitchASCII(switches::kTestName, test_name_);
    207 }
    208 
    209 void UITestBase::SetUpProfile() {
    210 }
    211 
    212 void UITestBase::LaunchBrowser() {
    213   LaunchBrowser(launch_arguments_, clear_profile_);
    214 }
    215 
    216 void UITestBase::LaunchBrowserAndServer() {
    217   ASSERT_TRUE(launcher_->LaunchBrowserAndServer(DefaultLaunchState(),
    218                                                 wait_for_initial_loads_));
    219 }
    220 
    221 void UITestBase::ConnectToRunningBrowser() {
    222   ASSERT_TRUE(launcher_->ConnectToRunningBrowser(wait_for_initial_loads_));
    223 }
    224 
    225 void UITestBase::CloseBrowserAndServer() {
    226   if (launcher_.get())
    227     launcher_->CloseBrowserAndServer();
    228 }
    229 
    230 void UITestBase::LaunchBrowser(const CommandLine& arguments,
    231                                bool clear_profile) {
    232   ProxyLauncher::LaunchState state = DefaultLaunchState();
    233   state.clear_profile = clear_profile;
    234   ASSERT_TRUE(launcher_->LaunchBrowser(state));
    235 }
    236 
    237 void UITestBase::QuitBrowser() {
    238   launcher_->QuitBrowser();
    239 }
    240 
    241 scoped_refptr<TabProxy> UITestBase::GetActiveTab(int window_index) {
    242   EXPECT_GE(window_index, 0);
    243   int window_count = -1;
    244   // We have to use EXPECT rather than ASSERT here because ASSERT_* only works
    245   // in functions that return void.
    246   EXPECT_TRUE(automation()->GetBrowserWindowCount(&window_count));
    247   if (window_count == -1)
    248     return NULL;
    249   EXPECT_GT(window_count, window_index);
    250   scoped_refptr<BrowserProxy> window_proxy(automation()->
    251       GetBrowserWindow(window_index));
    252   EXPECT_TRUE(window_proxy.get());
    253   if (!window_proxy.get())
    254     return NULL;
    255 
    256   int active_tab_index = -1;
    257   EXPECT_TRUE(window_proxy->GetActiveTabIndex(&active_tab_index));
    258   if (active_tab_index == -1)
    259     return NULL;
    260 
    261   return window_proxy->GetTab(active_tab_index);
    262 }
    263 
    264 scoped_refptr<TabProxy> UITestBase::GetActiveTab() {
    265   scoped_refptr<BrowserProxy> window_proxy(automation()->
    266       GetBrowserWindow(0));
    267   EXPECT_TRUE(window_proxy.get());
    268   if (!window_proxy.get())
    269     return NULL;
    270 
    271   scoped_refptr<TabProxy> tab_proxy = window_proxy->GetActiveTab();
    272   EXPECT_TRUE(tab_proxy.get());
    273   return tab_proxy;
    274 }
    275 
    276 void UITestBase::NavigateToURL(const GURL& url) {
    277   NavigateToURL(url, 0, GetActiveTabIndex(0));
    278 }
    279 
    280 void UITestBase::NavigateToURL(const GURL& url, int window_index) {
    281   NavigateToURL(url, window_index, GetActiveTabIndex(window_index));
    282 }
    283 
    284 void UITestBase::NavigateToURL(const GURL& url, int window_index, int
    285     tab_index) {
    286   NavigateToURLBlockUntilNavigationsComplete(url, 1, window_index, tab_index);
    287 }
    288 
    289 void UITestBase::NavigateToURLBlockUntilNavigationsComplete(
    290     const GURL& url, int number_of_navigations) {
    291   scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
    292   ASSERT_TRUE(tab_proxy.get());
    293   EXPECT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS,
    294             tab_proxy->NavigateToURLBlockUntilNavigationsComplete(
    295                 url, number_of_navigations)) << url.spec();
    296 }
    297 
    298 void UITestBase::NavigateToURLBlockUntilNavigationsComplete(
    299     const GURL& url, int number_of_navigations, int window_index,
    300     int tab_index) {
    301   scoped_refptr<BrowserProxy> window =
    302     automation()->GetBrowserWindow(window_index);
    303   ASSERT_TRUE(window.get());
    304   scoped_refptr<TabProxy> tab_proxy(window->GetTab(tab_index));
    305   ASSERT_TRUE(tab_proxy.get());
    306   EXPECT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS,
    307             tab_proxy->NavigateToURLBlockUntilNavigationsComplete(
    308                 url, number_of_navigations)) << url.spec();
    309 }
    310 
    311 GURL UITestBase::GetActiveTabURL(int window_index) {
    312   scoped_refptr<TabProxy> tab_proxy(GetActiveTab(window_index));
    313   EXPECT_TRUE(tab_proxy.get());
    314   if (!tab_proxy.get())
    315     return GURL();
    316 
    317   GURL url;
    318   bool success = tab_proxy->GetCurrentURL(&url);
    319   EXPECT_TRUE(success);
    320   if (!success)
    321     return GURL();
    322   return url;
    323 }
    324 
    325 std::wstring UITestBase::GetActiveTabTitle(int window_index) {
    326   std::wstring title;
    327   scoped_refptr<TabProxy> tab_proxy(GetActiveTab(window_index));
    328   EXPECT_TRUE(tab_proxy.get());
    329   if (!tab_proxy.get())
    330     return title;
    331 
    332   EXPECT_TRUE(tab_proxy->GetTabTitle(&title));
    333   return title;
    334 }
    335 
    336 int UITestBase::GetActiveTabIndex(int window_index) {
    337   scoped_refptr<BrowserProxy> window_proxy(automation()->
    338       GetBrowserWindow(window_index));
    339   EXPECT_TRUE(window_proxy.get());
    340   if (!window_proxy.get())
    341     return -1;
    342 
    343   int active_tab_index = -1;
    344   EXPECT_TRUE(window_proxy->GetActiveTabIndex(&active_tab_index));
    345   return active_tab_index;
    346 }
    347 
    348 int UITestBase::GetTabCount() {
    349   return GetTabCount(0);
    350 }
    351 
    352 int UITestBase::GetTabCount(int window_index) {
    353   scoped_refptr<BrowserProxy> window(
    354       automation()->GetBrowserWindow(window_index));
    355   EXPECT_TRUE(window.get());
    356   if (!window.get())
    357     return 0;
    358 
    359   int result = 0;
    360   EXPECT_TRUE(window->GetTabCount(&result));
    361 
    362   return result;
    363 }
    364 
    365 void UITestBase::WaitUntilTabCount(int tab_count) {
    366   const int kMaxIntervals = 10;
    367   const TimeDelta kDelay = TestTimeouts::action_timeout() / kMaxIntervals;
    368 
    369   for (int i = 0; i < kMaxIntervals; ++i) {
    370     if (GetTabCount() == tab_count)
    371       return;
    372 
    373     base::PlatformThread::Sleep(kDelay);
    374   }
    375 
    376   ADD_FAILURE() << "Timeout reached in WaitUntilTabCount";
    377 }
    378 
    379 const base::FilePath::CharType* UITestBase::GetExecutablePath() {
    380   if (launch_arguments_.HasSwitch(switches::kEnableChromiumBranding))
    381     return chrome::kBrowserProcessExecutablePathChromium;
    382   return chrome::kBrowserProcessExecutablePath;
    383 }
    384 
    385 bool UITestBase::CloseBrowser(BrowserProxy* browser,
    386                               bool* application_closed) const {
    387   DCHECK(application_closed);
    388   if (!browser->is_valid() || !browser->handle())
    389     return false;
    390 
    391   bool result = true;
    392 
    393   ChromeProcessList processes = GetRunningChromeProcesses(
    394       browser_process_id());
    395 
    396   bool succeeded = automation()->Send(new AutomationMsg_CloseBrowser(
    397       browser->handle(), &result, application_closed));
    398 
    399   if (!succeeded)
    400     return false;
    401 
    402   if (*application_closed) {
    403     int exit_code = -1;
    404     EXPECT_TRUE(launcher_->WaitForBrowserProcessToQuit(
    405         TestTimeouts::action_max_timeout(), &exit_code));
    406     EXPECT_EQ(0, exit_code);  // Expect a clean shutown.
    407     // Ensure no child processes are left dangling.
    408     TerminateAllChromeProcesses(processes);
    409   }
    410 
    411   return result;
    412 }
    413 
    414 int UITestBase::GetCrashCount() const {
    415   base::FilePath crash_dump_path;
    416   PathService::Get(chrome::DIR_CRASH_DUMPS, &crash_dump_path);
    417 
    418   int files_found = 0;
    419   base::FileEnumerator en(crash_dump_path, false, base::FileEnumerator::FILES);
    420   while (!en.Next().empty()) {
    421     if (en.GetInfo().GetLastModifiedTime() > test_start_time_)
    422       files_found++;
    423   }
    424 
    425 #if defined(OS_WIN)
    426   // Each crash creates two dump files on Windows.
    427   return files_found / 2;
    428 #else
    429   return files_found;
    430 #endif
    431 }
    432 
    433 std::string UITestBase::CheckErrorsAndCrashes() const {
    434   // Make sure that we didn't encounter any assertion failures
    435   logging::AssertionList assertions;
    436   logging::GetFatalAssertions(&assertions);
    437 
    438   // If there were errors, get all the error strings for display.
    439   std::wstring failures =
    440       L"The following error(s) occurred in the application during this test:";
    441   if (assertions.size() > expected_errors_) {
    442     logging::AssertionList::const_iterator iter = assertions.begin();
    443     for (; iter != assertions.end(); ++iter) {
    444       failures += L"\n\n";
    445       failures += *iter;
    446     }
    447   }
    448   EXPECT_EQ(expected_errors_, assertions.size()) << failures;
    449 
    450   int actual_crashes = GetCrashCount();
    451 
    452   std::wstring error_msg =
    453       L"Encountered an unexpected crash in the program during this test.";
    454   if (expected_crashes_ > 0 && actual_crashes == 0) {
    455     error_msg += L"  ";
    456     error_msg += kFailedNoCrashService;
    457   }
    458   EXPECT_EQ(expected_crashes_, actual_crashes) << error_msg;
    459 
    460   std::wstring wide_result;
    461   if (expected_errors_ != assertions.size()) {
    462     wide_result += failures;
    463     wide_result += L"\n\n";
    464   }
    465   if (expected_crashes_ != actual_crashes)
    466     wide_result += error_msg;
    467 
    468   return std::string(wide_result.begin(), wide_result.end());
    469 }
    470 
    471 void UITestBase::SetBrowserDirectory(const base::FilePath& dir) {
    472   browser_directory_ = dir;
    473 }
    474 
    475 void UITestBase::AppendBrowserLaunchSwitch(const char* name) {
    476   launch_arguments_.AppendSwitch(name);
    477 }
    478 
    479 void UITestBase::AppendBrowserLaunchSwitch(const char* name,
    480                                            const char* value) {
    481   launch_arguments_.AppendSwitchASCII(name, value);
    482 }
    483 
    484 bool UITestBase::BeginTracing(const std::string& category_patterns) {
    485   return automation()->BeginTracing(category_patterns);
    486 }
    487 
    488 std::string UITestBase::EndTracing() {
    489   std::string json_trace_output;
    490   if (!automation()->EndTracing(&json_trace_output))
    491     return std::string();
    492   return json_trace_output;
    493 }
    494 
    495 // UITest methods
    496 
    497 void UITest::SetUp() {
    498   // Pass the test case name to chrome.exe on the command line to help with
    499   // parsing Purify output.
    500   const testing::TestInfo* const test_info =
    501       testing::UnitTest::GetInstance()->current_test_info();
    502   if (test_info) {
    503     set_test_name(test_info->test_case_name() + std::string(".") +
    504                   test_info->name());
    505   }
    506 
    507   UITestBase::SetUp();
    508   PlatformTest::SetUp();
    509 }
    510 
    511 void UITest::TearDown() {
    512   UITestBase::TearDown();
    513   PlatformTest::TearDown();
    514 }
    515 
    516 ProxyLauncher* UITest::CreateProxyLauncher() {
    517   // Make the AutomationProxy disconnect the channel on the first error,
    518   // so that we avoid spending a lot of time in timeouts. The browser is likely
    519   // hosed if we hit those errors.
    520   return new AnonymousProxyLauncher(true);
    521 }
    522 
    523 bool UITest::GetBrowserProcessCount(int* count) {
    524   *count = 0;
    525   if (!automation()->WaitForProcessLauncherThreadToGoIdle())
    526     return false;
    527   *count = GetRunningChromeProcesses(browser_process_id()).size();
    528   return true;
    529 }
    530 
    531 static DictionaryValue* LoadDictionaryValueFromPath(
    532     const base::FilePath& path) {
    533   if (path.empty())
    534     return NULL;
    535 
    536   JSONFileValueSerializer serializer(path);
    537   scoped_ptr<Value> root_value(serializer.Deserialize(NULL, NULL));
    538   if (!root_value.get() || root_value->GetType() != Value::TYPE_DICTIONARY)
    539     return NULL;
    540 
    541   return static_cast<DictionaryValue*>(root_value.release());
    542 }
    543 
    544 DictionaryValue* UITest::GetLocalState() {
    545   base::FilePath local_state_path;
    546   PathService::Get(chrome::FILE_LOCAL_STATE, &local_state_path);
    547   return LoadDictionaryValueFromPath(local_state_path);
    548 }
    549 
    550 DictionaryValue* UITest::GetDefaultProfilePreferences() {
    551   base::FilePath path;
    552   PathService::Get(chrome::DIR_USER_DATA, &path);
    553   path = path.AppendASCII(TestingProfile::kTestUserProfileDir);
    554   return LoadDictionaryValueFromPath(path.Append(chrome::kPreferencesFilename));
    555 }
    556 
    557 void UITest::WaitForFinish(const std::string &name,
    558                            const std::string &id,
    559                            const GURL &url,
    560                            const std::string& test_complete_cookie,
    561                            const std::string& expected_cookie_value,
    562                            const base::TimeDelta wait_time) {
    563   // The webpage being tested has javascript which sets a cookie
    564   // which signals completion of the test.  The cookie name is
    565   // a concatenation of the test name and the test id.  This allows
    566   // us to run multiple tests within a single webpage and test
    567   // that they all c
    568   std::string cookie_name = name;
    569   cookie_name.append(".");
    570   cookie_name.append(id);
    571   cookie_name.append(".");
    572   cookie_name.append(test_complete_cookie);
    573 
    574   scoped_refptr<TabProxy> tab(GetActiveTab());
    575   ASSERT_TRUE(tab.get());
    576   std::string cookie_value = WaitUntilCookieNonEmpty(tab.get(), url,
    577                                                      cookie_name.c_str(),
    578                                                      wait_time);
    579   EXPECT_EQ(expected_cookie_value, cookie_value);
    580 }
    581 
    582 bool UITest::WaitUntilJavaScriptCondition(TabProxy* tab,
    583                                           const std::wstring& frame_xpath,
    584                                           const std::wstring& jscript,
    585                                           base::TimeDelta timeout) {
    586   const TimeDelta kDelay = TimeDelta::FromMilliseconds(250);
    587   const int kMaxDelays = timeout / kDelay;
    588 
    589   // Wait until the test signals it has completed.
    590   for (int i = 0; i < kMaxDelays; ++i) {
    591     bool done_value = false;
    592     bool success = tab->ExecuteAndExtractBool(frame_xpath, jscript,
    593                                               &done_value);
    594     EXPECT_TRUE(success);
    595     if (!success)
    596       return false;
    597     if (done_value)
    598       return true;
    599 
    600     base::PlatformThread::Sleep(kDelay);
    601   }
    602 
    603   ADD_FAILURE() << "Timeout reached in WaitUntilJavaScriptCondition";
    604   return false;
    605 }
    606 
    607 bool UITest::WaitUntilCookieValue(TabProxy* tab,
    608                                   const GURL& url,
    609                                   const char* cookie_name,
    610                                   base::TimeDelta timeout,
    611                                   const char* expected_value) {
    612   const TimeDelta kDelay = TimeDelta::FromMilliseconds(250);
    613   const int kMaxDelays = timeout / kDelay;
    614 
    615   std::string cookie_value;
    616   for (int i = 0; i < kMaxDelays; ++i) {
    617     EXPECT_TRUE(tab->GetCookieByName(url, cookie_name, &cookie_value));
    618     if (cookie_value == expected_value)
    619       return true;
    620 
    621     base::PlatformThread::Sleep(kDelay);
    622   }
    623 
    624   ADD_FAILURE() << "Timeout reached in WaitUntilCookieValue";
    625   return false;
    626 }
    627 
    628 std::string UITest::WaitUntilCookieNonEmpty(TabProxy* tab,
    629                                             const GURL& url,
    630                                             const char* cookie_name,
    631                                             base::TimeDelta timeout) {
    632   const TimeDelta kDelay = TimeDelta::FromMilliseconds(250);
    633   const int kMaxDelays = timeout / kDelay;
    634 
    635   for (int i = 0; i < kMaxDelays; ++i) {
    636     std::string cookie_value;
    637     EXPECT_TRUE(tab->GetCookieByName(url, cookie_name, &cookie_value));
    638     if (!cookie_value.empty())
    639       return cookie_value;
    640 
    641     base::PlatformThread::Sleep(kDelay);
    642   }
    643 
    644   ADD_FAILURE() << "Timeout reached in WaitUntilCookieNonEmpty";
    645   return std::string();
    646 }
    647 
    648 bool UITest::WaitForFindWindowVisibilityChange(BrowserProxy* browser,
    649                                                bool wait_for_open) {
    650   const int kCycles = 10;
    651   const TimeDelta kDelay = TestTimeouts::action_timeout() / kCycles;
    652   for (int i = 0; i < kCycles; i++) {
    653     bool visible = false;
    654     if (!browser->IsFindWindowFullyVisible(&visible))
    655       return false;  // Some error.
    656     if (visible == wait_for_open)
    657       return true;  // Find window visibility change complete.
    658 
    659     // Give it a chance to catch up.
    660     base::PlatformThread::Sleep(kDelay);
    661   }
    662 
    663   ADD_FAILURE() << "Timeout reached in WaitForFindWindowVisibilityChange";
    664   return false;
    665 }
    666 
    667 void UITest::TerminateBrowser() {
    668   launcher_->TerminateBrowser();
    669 
    670   // Make sure the UMA metrics say we didn't crash.
    671   scoped_ptr<DictionaryValue> local_prefs(GetLocalState());
    672   bool exited_cleanly;
    673   ASSERT_TRUE(local_prefs.get());
    674   ASSERT_TRUE(local_prefs->GetBoolean(prefs::kStabilityExitedCleanly,
    675                                       &exited_cleanly));
    676   ASSERT_TRUE(exited_cleanly);
    677 
    678   // And that session end was successful.
    679   bool session_end_completed;
    680   ASSERT_TRUE(local_prefs->GetBoolean(prefs::kStabilitySessionEndCompleted,
    681                                       &session_end_completed));
    682   ASSERT_TRUE(session_end_completed);
    683 
    684   // Make sure session restore says we didn't crash.
    685   scoped_ptr<DictionaryValue> profile_prefs(GetDefaultProfilePreferences());
    686   ASSERT_TRUE(profile_prefs.get());
    687   std::string exit_type;
    688   ASSERT_TRUE(profile_prefs->GetString(prefs::kSessionExitedCleanly,
    689                                         &exit_type));
    690   EXPECT_EQ(ProfileImpl::kPrefExitTypeNormal, exit_type);
    691 }
    692