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