ui_test_utils.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
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/base/ui_test_utils.h" 6 7#if defined(OS_WIN) 8#include <windows.h> 9#endif 10 11#include "base/bind.h" 12#include "base/bind_helpers.h" 13#include "base/callback.h" 14#include "base/command_line.h" 15#include "base/file_util.h" 16#include "base/files/file_path.h" 17#include "base/json/json_reader.h" 18#include "base/memory/scoped_ptr.h" 19#include "base/message_loop.h" 20#include "base/path_service.h" 21#include "base/prefs/pref_service.h" 22#include "base/test/test_timeouts.h" 23#include "base/time.h" 24#include "base/utf_string_conversions.h" 25#include "base/values.h" 26#include "chrome/browser/autocomplete/autocomplete_controller.h" 27#include "chrome/browser/bookmarks/bookmark_model.h" 28#include "chrome/browser/bookmarks/bookmark_model_factory.h" 29#include "chrome/browser/browser_process.h" 30#include "chrome/browser/extensions/extension_action.h" 31#include "chrome/browser/history/history_service_factory.h" 32#include "chrome/browser/profiles/profile.h" 33#include "chrome/browser/search_engines/template_url_service.h" 34#include "chrome/browser/search_engines/template_url_service_test_util.h" 35#include "chrome/browser/thumbnails/render_widget_snapshot_taker.h" 36#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h" 37#include "chrome/browser/ui/browser.h" 38#include "chrome/browser/ui/browser_commands.h" 39#include "chrome/browser/ui/browser_finder.h" 40#include "chrome/browser/ui/browser_iterator.h" 41#include "chrome/browser/ui/browser_list.h" 42#include "chrome/browser/ui/browser_navigator.h" 43#include "chrome/browser/ui/browser_window.h" 44#include "chrome/browser/ui/find_bar/find_notification_details.h" 45#include "chrome/browser/ui/find_bar/find_tab_helper.h" 46#include "chrome/browser/ui/host_desktop.h" 47#include "chrome/browser/ui/omnibox/location_bar.h" 48#include "chrome/browser/ui/omnibox/omnibox_view.h" 49#include "chrome/browser/ui/tabs/tab_strip_model.h" 50#include "chrome/common/chrome_notification_types.h" 51#include "chrome/common/chrome_paths.h" 52#include "chrome/common/pref_names.h" 53#include "chrome/test/base/bookmark_load_observer.h" 54#include "content/public/browser/browser_thread.h" 55#include "content/public/browser/dom_operation_notification_details.h" 56#include "content/public/browser/download_item.h" 57#include "content/public/browser/download_manager.h" 58#include "content/public/browser/geolocation_provider.h" 59#include "content/public/browser/navigation_controller.h" 60#include "content/public/browser/navigation_entry.h" 61#include "content/public/browser/notification_service.h" 62#include "content/public/browser/render_process_host.h" 63#include "content/public/browser/render_view_host.h" 64#include "content/public/browser/web_contents.h" 65#include "content/public/browser/web_contents_observer.h" 66#include "content/public/browser/web_contents_view.h" 67#include "content/public/common/geoposition.h" 68#include "content/public/test/browser_test_utils.h" 69#include "content/public/test/download_test_observer.h" 70#include "content/public/test/test_navigation_observer.h" 71#include "content/public/test/test_utils.h" 72#include "net/base/net_util.h" 73#include "net/test/python_utils.h" 74#include "third_party/skia/include/core/SkBitmap.h" 75#include "third_party/skia/include/core/SkColor.h" 76#include "ui/gfx/size.h" 77#include "ui/snapshot/test/snapshot_desktop.h" 78 79#if defined(USE_AURA) 80#include "ash/shell.h" 81#include "ui/aura/root_window.h" 82#endif 83 84using content::BrowserThread; 85using content::DomOperationNotificationDetails; 86using content::NativeWebKeyboardEvent; 87using content::NavigationController; 88using content::NavigationEntry; 89using content::OpenURLParams; 90using content::RenderViewHost; 91using content::RenderWidgetHost; 92using content::Referrer; 93using content::WebContents; 94 95namespace ui_test_utils { 96 97namespace { 98 99class FindInPageNotificationObserver : public content::NotificationObserver { 100 public: 101 explicit FindInPageNotificationObserver(WebContents* parent_tab) 102 : active_match_ordinal_(-1), 103 number_of_matches_(0) { 104 FindTabHelper* find_tab_helper = 105 FindTabHelper::FromWebContents(parent_tab); 106 current_find_request_id_ = find_tab_helper->current_find_request_id(); 107 registrar_.Add(this, chrome::NOTIFICATION_FIND_RESULT_AVAILABLE, 108 content::Source<WebContents>(parent_tab)); 109 message_loop_runner_ = new content::MessageLoopRunner; 110 message_loop_runner_->Run(); 111 } 112 113 int active_match_ordinal() const { return active_match_ordinal_; } 114 int number_of_matches() const { return number_of_matches_; } 115 gfx::Rect selection_rect() const { return selection_rect_; } 116 117 virtual void Observe(int type, const content::NotificationSource& source, 118 const content::NotificationDetails& details) OVERRIDE { 119 if (type == chrome::NOTIFICATION_FIND_RESULT_AVAILABLE) { 120 content::Details<FindNotificationDetails> find_details(details); 121 if (find_details->request_id() == current_find_request_id_) { 122 // We get multiple responses and one of those will contain the ordinal. 123 // This message comes to us before the final update is sent. 124 if (find_details->active_match_ordinal() > -1) { 125 active_match_ordinal_ = find_details->active_match_ordinal(); 126 selection_rect_ = find_details->selection_rect(); 127 } 128 if (find_details->final_update()) { 129 number_of_matches_ = find_details->number_of_matches(); 130 message_loop_runner_->Quit(); 131 } else { 132 DVLOG(1) << "Ignoring, since we only care about the final message"; 133 } 134 } 135 } else { 136 NOTREACHED(); 137 } 138 } 139 140 private: 141 content::NotificationRegistrar registrar_; 142 // We will at some point (before final update) be notified of the ordinal and 143 // we need to preserve it so we can send it later. 144 int active_match_ordinal_; 145 int number_of_matches_; 146 gfx::Rect selection_rect_; 147 // The id of the current find request, obtained from WebContents. Allows us 148 // to monitor when the search completes. 149 int current_find_request_id_; 150 scoped_refptr<content::MessageLoopRunner> message_loop_runner_; 151 152 DISALLOW_COPY_AND_ASSIGN(FindInPageNotificationObserver); 153}; 154 155const char kSnapshotBaseName[] = "ChromiumSnapshot"; 156const char kSnapshotExtension[] = ".png"; 157 158base::FilePath GetSnapshotFileName(const base::FilePath& snapshot_directory) { 159 base::Time::Exploded the_time; 160 161 base::Time::Now().LocalExplode(&the_time); 162 std::string filename(base::StringPrintf("%s%04d%02d%02d%02d%02d%02d%s", 163 kSnapshotBaseName, the_time.year, the_time.month, the_time.day_of_month, 164 the_time.hour, the_time.minute, the_time.second, kSnapshotExtension)); 165 166 base::FilePath snapshot_file = snapshot_directory.AppendASCII(filename); 167 if (file_util::PathExists(snapshot_file)) { 168 int index = 0; 169 std::string suffix; 170 base::FilePath trial_file; 171 do { 172 suffix = base::StringPrintf(" (%d)", ++index); 173 trial_file = snapshot_file.InsertBeforeExtensionASCII(suffix); 174 } while (file_util::PathExists(trial_file)); 175 snapshot_file = trial_file; 176 } 177 return snapshot_file; 178} 179 180} // namespace 181 182bool GetCurrentTabTitle(const Browser* browser, string16* title) { 183 WebContents* web_contents = 184 browser->tab_strip_model()->GetActiveWebContents(); 185 if (!web_contents) 186 return false; 187 NavigationEntry* last_entry = web_contents->GetController().GetActiveEntry(); 188 if (!last_entry) 189 return false; 190 title->assign(last_entry->GetTitleForDisplay(std::string())); 191 return true; 192} 193 194void WaitForNavigations(NavigationController* controller, 195 int number_of_navigations) { 196 content::TestNavigationObserver observer( 197 content::Source<NavigationController>(controller), 198 number_of_navigations); 199 base::RunLoop run_loop; 200 observer.WaitForObservation( 201 base::Bind(&content::RunThisRunLoop, base::Unretained(&run_loop)), 202 content::GetQuitTaskForRunLoop(&run_loop)); 203} 204 205Browser* WaitForBrowserNotInSet(std::set<Browser*> excluded_browsers) { 206 Browser* new_browser = GetBrowserNotInSet(excluded_browsers); 207 if (new_browser == NULL) { 208 BrowserAddedObserver observer; 209 new_browser = observer.WaitForSingleNewBrowser(); 210 // The new browser should never be in |excluded_browsers|. 211 DCHECK(!ContainsKey(excluded_browsers, new_browser)); 212 } 213 return new_browser; 214} 215 216Browser* OpenURLOffTheRecord(Profile* profile, const GURL& url) { 217 chrome::OpenURLOffTheRecord(profile, url, chrome::HOST_DESKTOP_TYPE_NATIVE); 218 Browser* browser = chrome::FindTabbedBrowser( 219 profile->GetOffTheRecordProfile(), 220 false, 221 chrome::HOST_DESKTOP_TYPE_NATIVE); 222 WaitForNavigations( 223 &browser->tab_strip_model()->GetActiveWebContents()->GetController(), 224 1); 225 return browser; 226} 227 228void NavigateToURL(chrome::NavigateParams* params) { 229 content::TestNavigationObserver observer( 230 content::NotificationService::AllSources(), 1); 231 chrome::Navigate(params); 232 base::RunLoop run_loop; 233 observer.WaitForObservation( 234 base::Bind(&content::RunThisRunLoop, base::Unretained(&run_loop)), 235 content::GetQuitTaskForRunLoop(&run_loop)); 236} 237 238void NavigateToURL(Browser* browser, const GURL& url) { 239 NavigateToURLWithDisposition(browser, url, CURRENT_TAB, 240 BROWSER_TEST_WAIT_FOR_NAVIGATION); 241} 242 243// Navigates the specified tab (via |disposition|) of |browser| to |url|, 244// blocking until the |number_of_navigations| specified complete. 245// |disposition| indicates what tab the download occurs in, and 246// |browser_test_flags| controls what to wait for before continuing. 247static void NavigateToURLWithDispositionBlockUntilNavigationsComplete( 248 Browser* browser, 249 const GURL& url, 250 int number_of_navigations, 251 WindowOpenDisposition disposition, 252 int browser_test_flags) { 253 TabStripModel* tab_strip = browser->tab_strip_model(); 254 if (disposition == CURRENT_TAB && tab_strip->GetActiveWebContents()) 255 content::WaitForLoadStop(tab_strip->GetActiveWebContents()); 256 NavigationController* controller = 257 tab_strip->GetActiveWebContents() ? 258 &tab_strip->GetActiveWebContents()->GetController() : NULL; 259 content::TestNavigationObserver same_tab_observer( 260 content::Source<NavigationController>(controller), 261 number_of_navigations); 262 263 std::set<Browser*> initial_browsers; 264 for (chrome::BrowserIterator it; !it.done(); it.Next()) 265 initial_browsers.insert(*it); 266 267 content::WindowedNotificationObserver tab_added_observer( 268 chrome::NOTIFICATION_TAB_ADDED, 269 content::NotificationService::AllSources()); 270 271 browser->OpenURL(OpenURLParams( 272 url, Referrer(), disposition, content::PAGE_TRANSITION_TYPED, false)); 273 if (browser_test_flags & BROWSER_TEST_WAIT_FOR_BROWSER) 274 browser = WaitForBrowserNotInSet(initial_browsers); 275 if (browser_test_flags & BROWSER_TEST_WAIT_FOR_TAB) 276 tab_added_observer.Wait(); 277 if (!(browser_test_flags & BROWSER_TEST_WAIT_FOR_NAVIGATION)) { 278 // Some other flag caused the wait prior to this. 279 return; 280 } 281 WebContents* web_contents = NULL; 282 if (disposition == NEW_BACKGROUND_TAB) { 283 // We've opened up a new tab, but not selected it. 284 TabStripModel* tab_strip = browser->tab_strip_model(); 285 web_contents = tab_strip->GetWebContentsAt(tab_strip->active_index() + 1); 286 EXPECT_TRUE(web_contents != NULL) 287 << " Unable to wait for navigation to \"" << url.spec() 288 << "\" because the new tab is not available yet"; 289 if (!web_contents) 290 return; 291 } else if ((disposition == CURRENT_TAB) || 292 (disposition == NEW_FOREGROUND_TAB) || 293 (disposition == SINGLETON_TAB)) { 294 // The currently selected tab is the right one. 295 web_contents = browser->tab_strip_model()->GetActiveWebContents(); 296 } 297 if (disposition == CURRENT_TAB) { 298 base::RunLoop run_loop; 299 same_tab_observer.WaitForObservation( 300 base::Bind(&content::RunThisRunLoop, base::Unretained(&run_loop)), 301 content::GetQuitTaskForRunLoop(&run_loop)); 302 return; 303 } else if (web_contents) { 304 NavigationController* controller = &web_contents->GetController(); 305 WaitForNavigations(controller, number_of_navigations); 306 return; 307 } 308 EXPECT_TRUE(NULL != web_contents) << " Unable to wait for navigation to \"" 309 << url.spec() << "\"" 310 << " because we can't get the tab contents"; 311} 312 313void NavigateToURLWithDisposition(Browser* browser, 314 const GURL& url, 315 WindowOpenDisposition disposition, 316 int browser_test_flags) { 317 NavigateToURLWithDispositionBlockUntilNavigationsComplete( 318 browser, 319 url, 320 1, 321 disposition, 322 browser_test_flags); 323} 324 325void NavigateToURLBlockUntilNavigationsComplete(Browser* browser, 326 const GURL& url, 327 int number_of_navigations) { 328 NavigateToURLWithDispositionBlockUntilNavigationsComplete( 329 browser, 330 url, 331 number_of_navigations, 332 CURRENT_TAB, 333 BROWSER_TEST_WAIT_FOR_NAVIGATION); 334} 335 336base::FilePath GetTestFilePath(const base::FilePath& dir, 337 const base::FilePath& file) { 338 base::FilePath path; 339 PathService::Get(chrome::DIR_TEST_DATA, &path); 340 return path.Append(dir).Append(file); 341} 342 343GURL GetTestUrl(const base::FilePath& dir, const base::FilePath& file) { 344 return net::FilePathToFileURL(GetTestFilePath(dir, file)); 345} 346 347bool GetRelativeBuildDirectory(base::FilePath* build_dir) { 348 // This function is used to find the build directory so TestServer can serve 349 // built files (nexes, etc). TestServer expects a path relative to the source 350 // root. 351 base::FilePath exe_dir = 352 CommandLine::ForCurrentProcess()->GetProgram().DirName(); 353 base::FilePath src_dir; 354 if (!PathService::Get(base::DIR_SOURCE_ROOT, &src_dir)) 355 return false; 356 357 // We must first generate absolute paths to SRC and EXE and from there 358 // generate a relative path. 359 if (!exe_dir.IsAbsolute()) 360 exe_dir = base::MakeAbsoluteFilePath(exe_dir); 361 if (!src_dir.IsAbsolute()) 362 src_dir = base::MakeAbsoluteFilePath(src_dir); 363 if (!exe_dir.IsAbsolute()) 364 return false; 365 if (!src_dir.IsAbsolute()) 366 return false; 367 368 size_t match, exe_size, src_size; 369 std::vector<base::FilePath::StringType> src_parts, exe_parts; 370 371 // Determine point at which src and exe diverge. 372 exe_dir.GetComponents(&exe_parts); 373 src_dir.GetComponents(&src_parts); 374 exe_size = exe_parts.size(); 375 src_size = src_parts.size(); 376 for (match = 0; match < exe_size && match < src_size; ++match) { 377 if (exe_parts[match] != src_parts[match]) 378 break; 379 } 380 381 // Create a relative path. 382 *build_dir = base::FilePath(); 383 for (size_t tmp_itr = match; tmp_itr < src_size; ++tmp_itr) 384 *build_dir = build_dir->Append(FILE_PATH_LITERAL("..")); 385 for (; match < exe_size; ++match) 386 *build_dir = build_dir->Append(exe_parts[match]); 387 return true; 388} 389 390AppModalDialog* WaitForAppModalDialog() { 391 content::WindowedNotificationObserver observer( 392 chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN, 393 content::NotificationService::AllSources()); 394 observer.Wait(); 395 return content::Source<AppModalDialog>(observer.source()).ptr(); 396} 397 398int FindInPage(WebContents* tab, const string16& search_string, 399 bool forward, bool match_case, int* ordinal, 400 gfx::Rect* selection_rect) { 401 FindTabHelper* find_tab_helper = FindTabHelper::FromWebContents(tab); 402 find_tab_helper->StartFinding(search_string, forward, match_case); 403 FindInPageNotificationObserver observer(tab); 404 if (ordinal) 405 *ordinal = observer.active_match_ordinal(); 406 if (selection_rect) 407 *selection_rect = observer.selection_rect(); 408 return observer.number_of_matches(); 409} 410 411void RegisterAndWait(content::NotificationObserver* observer, 412 int type, 413 const content::NotificationSource& source) { 414 content::NotificationRegistrar registrar; 415 registrar.Add(observer, type, source); 416 content::RunMessageLoop(); 417} 418 419void WaitForBookmarkModelToLoad(BookmarkModel* model) { 420 if (model->loaded()) 421 return; 422 base::RunLoop run_loop; 423 BookmarkLoadObserver observer(content::GetQuitTaskForRunLoop(&run_loop)); 424 model->AddObserver(&observer); 425 content::RunThisRunLoop(&run_loop); 426 model->RemoveObserver(&observer); 427 ASSERT_TRUE(model->loaded()); 428} 429 430void WaitForBookmarkModelToLoad(Profile* profile) { 431 WaitForBookmarkModelToLoad(BookmarkModelFactory::GetForProfile(profile)); 432} 433 434void WaitForTemplateURLServiceToLoad(TemplateURLService* service) { 435 if (service->loaded()) 436 return; 437 service->Load(); 438 TemplateURLServiceTestUtil::BlockTillServiceProcessesRequests(); 439 ASSERT_TRUE(service->loaded()); 440} 441 442void WaitForHistoryToLoad(HistoryService* history_service) { 443 content::WindowedNotificationObserver history_loaded_observer( 444 chrome::NOTIFICATION_HISTORY_LOADED, 445 content::NotificationService::AllSources()); 446 if (!history_service->BackendLoaded()) 447 history_loaded_observer.Wait(); 448} 449 450void DownloadURL(Browser* browser, const GURL& download_url) { 451 base::ScopedTempDir downloads_directory; 452 ASSERT_TRUE(downloads_directory.CreateUniqueTempDir()); 453 browser->profile()->GetPrefs()->SetFilePath( 454 prefs::kDownloadDefaultDirectory, downloads_directory.path()); 455 456 content::DownloadManager* download_manager = 457 content::BrowserContext::GetDownloadManager(browser->profile()); 458 scoped_ptr<content::DownloadTestObserver> observer( 459 new content::DownloadTestObserverTerminal( 460 download_manager, 1, 461 content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_ACCEPT)); 462 463 ui_test_utils::NavigateToURL(browser, download_url); 464 observer->WaitForFinished(); 465} 466 467void SendToOmniboxAndSubmit(LocationBar* location_bar, 468 const std::string& input) { 469 OmniboxView* omnibox = location_bar->GetLocationEntry(); 470 omnibox->model()->OnSetFocus(false); 471 omnibox->SetUserText(ASCIIToUTF16(input)); 472 location_bar->AcceptInput(); 473 while (!omnibox->model()->autocomplete_controller()->done()) { 474 content::WindowedNotificationObserver observer( 475 chrome::NOTIFICATION_AUTOCOMPLETE_CONTROLLER_RESULT_READY, 476 content::NotificationService::AllSources()); 477 observer.Wait(); 478 } 479} 480 481Browser* GetBrowserNotInSet(std::set<Browser*> excluded_browsers) { 482 for (chrome::BrowserIterator it; !it.done(); it.Next()) { 483 if (excluded_browsers.find(*it) == excluded_browsers.end()) 484 return *it; 485 } 486 return NULL; 487} 488 489WindowedTabAddedNotificationObserver::WindowedTabAddedNotificationObserver( 490 const content::NotificationSource& source) 491 : WindowedNotificationObserver(chrome::NOTIFICATION_TAB_ADDED, source), 492 added_tab_(NULL) { 493} 494 495void WindowedTabAddedNotificationObserver::Observe( 496 int type, 497 const content::NotificationSource& source, 498 const content::NotificationDetails& details) { 499 added_tab_ = content::Details<WebContents>(details).ptr(); 500 content::WindowedNotificationObserver::Observe(type, source, details); 501} 502 503UrlLoadObserver::UrlLoadObserver(const GURL& url, 504 const content::NotificationSource& source) 505 : WindowedNotificationObserver(content::NOTIFICATION_LOAD_STOP, source), 506 url_(url) { 507} 508 509UrlLoadObserver::~UrlLoadObserver() {} 510 511void UrlLoadObserver::Observe( 512 int type, 513 const content::NotificationSource& source, 514 const content::NotificationDetails& details) { 515 NavigationController* controller = 516 content::Source<NavigationController>(source).ptr(); 517 if (controller->GetWebContents()->GetURL() != url_) 518 return; 519 520 WindowedNotificationObserver::Observe(type, source, details); 521} 522 523BrowserAddedObserver::BrowserAddedObserver() 524 : notification_observer_( 525 chrome::NOTIFICATION_BROWSER_OPENED, 526 content::NotificationService::AllSources()) { 527 for (chrome::BrowserIterator it; !it.done(); it.Next()) 528 original_browsers_.insert(*it); 529} 530 531BrowserAddedObserver::~BrowserAddedObserver() { 532} 533 534Browser* BrowserAddedObserver::WaitForSingleNewBrowser() { 535 notification_observer_.Wait(); 536 // Ensure that only a single new browser has appeared. 537 EXPECT_EQ(original_browsers_.size() + 1, chrome::GetTotalBrowserCount()); 538 return GetBrowserNotInSet(original_browsers_); 539} 540 541#if defined(OS_WIN) 542 543bool SaveScreenSnapshotToDirectory(const base::FilePath& directory, 544 base::FilePath* screenshot_path) { 545 bool succeeded = false; 546 base::FilePath out_path(GetSnapshotFileName(directory)); 547 548 MONITORINFO monitor_info = {}; 549 monitor_info.cbSize = sizeof(monitor_info); 550 HMONITOR main_monitor = MonitorFromWindow(NULL, MONITOR_DEFAULTTOPRIMARY); 551 if (GetMonitorInfo(main_monitor, &monitor_info)) { 552 RECT& rect = monitor_info.rcMonitor; 553 554 std::vector<unsigned char> png_data; 555 gfx::Rect bounds( 556 gfx::Size(rect.right - rect.left, rect.bottom - rect.top)); 557 if (ui::GrabDesktopSnapshot(bounds, &png_data) && 558 png_data.size() <= INT_MAX) { 559 int bytes = static_cast<int>(png_data.size()); 560 int written = file_util::WriteFile( 561 out_path, reinterpret_cast<char*>(&png_data[0]), bytes); 562 succeeded = (written == bytes); 563 } 564 } 565 566 if (succeeded && screenshot_path != NULL) 567 *screenshot_path = out_path; 568 569 return succeeded; 570} 571 572bool SaveScreenSnapshotToDesktop(base::FilePath* screenshot_path) { 573 base::FilePath desktop; 574 575 return PathService::Get(base::DIR_USER_DESKTOP, &desktop) && 576 SaveScreenSnapshotToDirectory(desktop, screenshot_path); 577} 578 579#endif // defined(OS_WIN) 580 581void OverrideGeolocation(double latitude, double longitude) { 582 content::Geoposition position; 583 position.latitude = latitude; 584 position.longitude = longitude; 585 position.altitude = 0.; 586 position.accuracy = 0.; 587 position.timestamp = base::Time::Now(); 588 scoped_refptr<content::MessageLoopRunner> runner = 589 new content::MessageLoopRunner; 590 591 content::GeolocationProvider::OverrideLocationForTesting( 592 position, runner->QuitClosure()); 593 594 runner->Run(); 595} 596 597HistoryEnumerator::HistoryEnumerator(Profile* profile) { 598 scoped_refptr<content::MessageLoopRunner> message_loop_runner = 599 new content::MessageLoopRunner; 600 601 HistoryService* hs = HistoryServiceFactory::GetForProfile( 602 profile, Profile::EXPLICIT_ACCESS); 603 hs->QueryHistory( 604 string16(), 605 history::QueryOptions(), 606 &consumer_, 607 base::Bind(&HistoryEnumerator::HistoryQueryComplete, 608 base::Unretained(this), message_loop_runner->QuitClosure())); 609 message_loop_runner->Run(); 610} 611 612HistoryEnumerator::~HistoryEnumerator() {} 613 614void HistoryEnumerator::HistoryQueryComplete( 615 const base::Closure& quit_task, 616 HistoryService::Handle request_handle, 617 history::QueryResults* results) { 618 for (size_t i = 0; i < results->size(); ++i) 619 urls_.push_back((*results)[i].url()); 620 quit_task.Run(); 621} 622 623} // namespace ui_test_utils 624