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