• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
UITestBase()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 
UITestBase(base::MessageLoop::Type msg_loop_type)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 
~UITestBase()109 UITestBase::~UITestBase() {}
110 
SetUp()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 
TearDown()127 void UITestBase::TearDown() {
128   if (launcher_.get())
129     launcher_->TerminateConnection();
130 
131   CheckErrorsAndCrashes();
132 }
133 
automation() const134 AutomationProxy* UITestBase::automation() const {
135   return launcher_->automation();
136 }
137 
action_timeout()138 base::TimeDelta UITestBase::action_timeout() {
139   return automation()->action_timeout();
140 }
141 
action_timeout_ms()142 int UITestBase::action_timeout_ms() {
143   return action_timeout().InMilliseconds();
144 }
145 
set_action_timeout(base::TimeDelta timeout)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 
set_action_timeout_ms(int timeout)152 void UITestBase::set_action_timeout_ms(int timeout) {
153   set_action_timeout(base::TimeDelta::FromMilliseconds(timeout));
154 }
155 
CreateProxyLauncher()156 ProxyLauncher* UITestBase::CreateProxyLauncher() {
157   return new AnonymousProxyLauncher(false);
158 }
159 
DefaultLaunchState()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 
SetLaunchSwitches()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 
SetUpProfile()210 void UITestBase::SetUpProfile() {
211 }
212 
LaunchBrowser()213 void UITestBase::LaunchBrowser() {
214   LaunchBrowser(launch_arguments_, clear_profile_);
215 }
216 
LaunchBrowserAndServer()217 void UITestBase::LaunchBrowserAndServer() {
218   ASSERT_TRUE(launcher_->LaunchBrowserAndServer(DefaultLaunchState(),
219                                                 wait_for_initial_loads_));
220 }
221 
ConnectToRunningBrowser()222 void UITestBase::ConnectToRunningBrowser() {
223   ASSERT_TRUE(launcher_->ConnectToRunningBrowser(wait_for_initial_loads_));
224 }
225 
CloseBrowserAndServer()226 void UITestBase::CloseBrowserAndServer() {
227   if (launcher_.get())
228     launcher_->CloseBrowserAndServer();
229 }
230 
LaunchBrowser(const CommandLine & arguments,bool clear_profile)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 
QuitBrowser()238 void UITestBase::QuitBrowser() {
239   launcher_->QuitBrowser();
240 }
241 
GetActiveTab(int window_index)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 
GetActiveTab()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 
NavigateToURL(const GURL & url)277 void UITestBase::NavigateToURL(const GURL& url) {
278   NavigateToURL(url, 0, GetActiveTabIndex(0));
279 }
280 
NavigateToURL(const GURL & url,int window_index)281 void UITestBase::NavigateToURL(const GURL& url, int window_index) {
282   NavigateToURL(url, window_index, GetActiveTabIndex(window_index));
283 }
284 
NavigateToURL(const GURL & url,int window_index,int tab_index)285 void UITestBase::NavigateToURL(const GURL& url, int window_index, int
286     tab_index) {
287   NavigateToURLBlockUntilNavigationsComplete(url, 1, window_index, tab_index);
288 }
289 
NavigateToURLBlockUntilNavigationsComplete(const GURL & url,int number_of_navigations)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 
NavigateToURLBlockUntilNavigationsComplete(const GURL & url,int number_of_navigations,int window_index,int tab_index)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 
GetActiveTabURL(int window_index)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 
GetActiveTabTitle(int window_index)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 
GetActiveTabIndex(int window_index)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 
GetTabCount()349 int UITestBase::GetTabCount() {
350   return GetTabCount(0);
351 }
352 
GetTabCount(int window_index)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 
WaitUntilTabCount(int tab_count)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 
GetExecutablePath()380 const base::FilePath::CharType* UITestBase::GetExecutablePath() {
381   if (launch_arguments_.HasSwitch(switches::kEnableChromiumBranding))
382     return chrome::kBrowserProcessExecutablePathChromium;
383   return chrome::kBrowserProcessExecutablePath;
384 }
385 
CloseBrowser(BrowserProxy * browser,bool * application_closed) const386 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 
GetCrashCount() const415 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 
CheckErrorsAndCrashes() const434 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 
SetBrowserDirectory(const base::FilePath & dir)472 void UITestBase::SetBrowserDirectory(const base::FilePath& dir) {
473   browser_directory_ = dir;
474 }
475 
AppendBrowserLaunchSwitch(const char * name)476 void UITestBase::AppendBrowserLaunchSwitch(const char* name) {
477   launch_arguments_.AppendSwitch(name);
478 }
479 
AppendBrowserLaunchSwitch(const char * name,const char * value)480 void UITestBase::AppendBrowserLaunchSwitch(const char* name,
481                                            const char* value) {
482   launch_arguments_.AppendSwitchASCII(name, value);
483 }
484 
BeginTracing(const std::string & category_patterns)485 bool UITestBase::BeginTracing(const std::string& category_patterns) {
486   return automation()->BeginTracing(category_patterns);
487 }
488 
EndTracing()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 
SetUp()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 
TearDown()512 void UITest::TearDown() {
513   UITestBase::TearDown();
514   PlatformTest::TearDown();
515 }
516 
CreateProxyLauncher()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 
GetBrowserProcessCount(int * count)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 
LoadDictionaryValueFromPath(const base::FilePath & path)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 
GetLocalState()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 
GetDefaultProfilePreferences()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 
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 base::TimeDelta wait_time)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 
WaitUntilJavaScriptCondition(TabProxy * tab,const std::wstring & frame_xpath,const std::wstring & jscript,base::TimeDelta timeout)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 
WaitUntilCookieValue(TabProxy * tab,const GURL & url,const char * cookie_name,base::TimeDelta timeout,const char * expected_value)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 
WaitUntilCookieNonEmpty(TabProxy * tab,const GURL & url,const char * cookie_name,base::TimeDelta timeout)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 
WaitForFindWindowVisibilityChange(BrowserProxy * browser,bool wait_for_open)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 
TerminateBrowser()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