Adding instrumentation to locate the source of jankiness
[chromium-blink-merge.git] / chrome / test / base / ui_test_utils.cc
blobe017345010e36ad4766e7c5acc50ac8c2b4ae139
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.
5 #include "chrome/test/base/ui_test_utils.h"
7 #if defined(OS_WIN)
8 #include <windows.h>
9 #endif
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/files/file_path.h"
16 #include "base/files/file_util.h"
17 #include "base/json/json_reader.h"
18 #include "base/memory/ref_counted.h"
19 #include "base/memory/scoped_ptr.h"
20 #include "base/path_service.h"
21 #include "base/prefs/pref_service.h"
22 #include "base/strings/stringprintf.h"
23 #include "base/strings/utf_string_conversions.h"
24 #include "base/test/test_timeouts.h"
25 #include "base/time/time.h"
26 #include "base/values.h"
27 #include "chrome/browser/autocomplete/autocomplete_controller.h"
28 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
29 #include "chrome/browser/browser_process.h"
30 #include "chrome/browser/chrome_notification_types.h"
31 #include "chrome/browser/history/history_service_factory.h"
32 #include "chrome/browser/profiles/profile.h"
33 #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h"
34 #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h"
35 #include "chrome/browser/ui/browser.h"
36 #include "chrome/browser/ui/browser_commands.h"
37 #include "chrome/browser/ui/browser_finder.h"
38 #include "chrome/browser/ui/browser_iterator.h"
39 #include "chrome/browser/ui/browser_list.h"
40 #include "chrome/browser/ui/browser_navigator.h"
41 #include "chrome/browser/ui/browser_window.h"
42 #include "chrome/browser/ui/find_bar/find_notification_details.h"
43 #include "chrome/browser/ui/find_bar/find_tab_helper.h"
44 #include "chrome/browser/ui/host_desktop.h"
45 #include "chrome/browser/ui/location_bar/location_bar.h"
46 #include "chrome/browser/ui/omnibox/omnibox_view.h"
47 #include "chrome/browser/ui/tabs/tab_strip_model.h"
48 #include "chrome/common/chrome_paths.h"
49 #include "chrome/common/pref_names.h"
50 #include "chrome/test/base/find_in_page_observer.h"
51 #include "components/bookmarks/browser/bookmark_model.h"
52 #include "components/search_engines/template_url_service.h"
53 #include "content/public/browser/dom_operation_notification_details.h"
54 #include "content/public/browser/download_item.h"
55 #include "content/public/browser/download_manager.h"
56 #include "content/public/browser/geolocation_provider.h"
57 #include "content/public/browser/navigation_controller.h"
58 #include "content/public/browser/navigation_entry.h"
59 #include "content/public/browser/notification_service.h"
60 #include "content/public/browser/render_process_host.h"
61 #include "content/public/browser/render_view_host.h"
62 #include "content/public/browser/web_contents.h"
63 #include "content/public/browser/web_contents_observer.h"
64 #include "content/public/common/geoposition.h"
65 #include "content/public/test/browser_test_utils.h"
66 #include "content/public/test/download_test_observer.h"
67 #include "content/public/test/test_navigation_observer.h"
68 #include "content/public/test/test_utils.h"
69 #include "net/base/filename_util.h"
70 #include "net/cookies/cookie_constants.h"
71 #include "net/cookies/cookie_monster.h"
72 #include "net/cookies/cookie_store.h"
73 #include "net/test/python_utils.h"
74 #include "net/url_request/url_request_context.h"
75 #include "net/url_request/url_request_context_getter.h"
76 #include "third_party/skia/include/core/SkBitmap.h"
77 #include "third_party/skia/include/core/SkColor.h"
78 #include "ui/gfx/size.h"
80 #if defined(USE_AURA)
81 #include "ash/shell.h"
82 #include "ui/aura/window_event_dispatcher.h"
83 #endif
85 using content::DomOperationNotificationDetails;
86 using content::NativeWebKeyboardEvent;
87 using content::NavigationController;
88 using content::NavigationEntry;
89 using content::OpenURLParams;
90 using content::RenderViewHost;
91 using content::RenderWidgetHost;
92 using content::Referrer;
93 using content::WebContents;
95 namespace ui_test_utils {
97 namespace {
99 Browser* WaitForBrowserNotInSet(std::set<Browser*> excluded_browsers) {
100 Browser* new_browser = GetBrowserNotInSet(excluded_browsers);
101 if (new_browser == NULL) {
102 BrowserAddedObserver observer;
103 new_browser = observer.WaitForSingleNewBrowser();
104 // The new browser should never be in |excluded_browsers|.
105 DCHECK(!ContainsKey(excluded_browsers, new_browser));
107 return new_browser;
110 } // namespace
112 bool GetCurrentTabTitle(const Browser* browser, base::string16* title) {
113 WebContents* web_contents =
114 browser->tab_strip_model()->GetActiveWebContents();
115 if (!web_contents)
116 return false;
117 NavigationEntry* last_entry = web_contents->GetController().GetActiveEntry();
118 if (!last_entry)
119 return false;
120 title->assign(last_entry->GetTitleForDisplay(std::string()));
121 return true;
124 Browser* OpenURLOffTheRecord(Profile* profile, const GURL& url) {
125 chrome::HostDesktopType active_desktop = chrome::GetActiveDesktop();
126 chrome::OpenURLOffTheRecord(profile, url, active_desktop);
127 Browser* browser = chrome::FindTabbedBrowser(
128 profile->GetOffTheRecordProfile(), false, active_desktop);
129 content::TestNavigationObserver observer(
130 browser->tab_strip_model()->GetActiveWebContents());
131 observer.Wait();
132 return browser;
135 void NavigateToURL(chrome::NavigateParams* params) {
136 chrome::Navigate(params);
137 content::WaitForLoadStop(params->target_contents);
141 void NavigateToURLWithPost(Browser* browser, const GURL& url) {
142 chrome::NavigateParams params(browser, url,
143 ui::PAGE_TRANSITION_FORM_SUBMIT);
144 params.uses_post = true;
145 NavigateToURL(&params);
148 void NavigateToURL(Browser* browser, const GURL& url) {
149 NavigateToURLWithDisposition(browser, url, CURRENT_TAB,
150 BROWSER_TEST_WAIT_FOR_NAVIGATION);
153 // Navigates the specified tab (via |disposition|) of |browser| to |url|,
154 // blocking until the |number_of_navigations| specified complete.
155 // |disposition| indicates what tab the download occurs in, and
156 // |browser_test_flags| controls what to wait for before continuing.
157 static void NavigateToURLWithDispositionBlockUntilNavigationsComplete(
158 Browser* browser,
159 const GURL& url,
160 int number_of_navigations,
161 WindowOpenDisposition disposition,
162 int browser_test_flags) {
163 TabStripModel* tab_strip = browser->tab_strip_model();
164 if (disposition == CURRENT_TAB && tab_strip->GetActiveWebContents())
165 content::WaitForLoadStop(tab_strip->GetActiveWebContents());
166 content::TestNavigationObserver same_tab_observer(
167 tab_strip->GetActiveWebContents(),
168 number_of_navigations);
170 std::set<Browser*> initial_browsers;
171 for (chrome::BrowserIterator it; !it.done(); it.Next())
172 initial_browsers.insert(*it);
174 content::WindowedNotificationObserver tab_added_observer(
175 chrome::NOTIFICATION_TAB_ADDED,
176 content::NotificationService::AllSources());
178 browser->OpenURL(OpenURLParams(
179 url, Referrer(), disposition, ui::PAGE_TRANSITION_TYPED, false));
180 if (browser_test_flags & BROWSER_TEST_WAIT_FOR_BROWSER)
181 browser = WaitForBrowserNotInSet(initial_browsers);
182 if (browser_test_flags & BROWSER_TEST_WAIT_FOR_TAB)
183 tab_added_observer.Wait();
184 if (!(browser_test_flags & BROWSER_TEST_WAIT_FOR_NAVIGATION)) {
185 // Some other flag caused the wait prior to this.
186 return;
188 WebContents* web_contents = NULL;
189 if (disposition == NEW_BACKGROUND_TAB) {
190 // We've opened up a new tab, but not selected it.
191 TabStripModel* tab_strip = browser->tab_strip_model();
192 web_contents = tab_strip->GetWebContentsAt(tab_strip->active_index() + 1);
193 EXPECT_TRUE(web_contents != NULL)
194 << " Unable to wait for navigation to \"" << url.spec()
195 << "\" because the new tab is not available yet";
196 if (!web_contents)
197 return;
198 } else if ((disposition == CURRENT_TAB) ||
199 (disposition == NEW_FOREGROUND_TAB) ||
200 (disposition == SINGLETON_TAB)) {
201 // The currently selected tab is the right one.
202 web_contents = browser->tab_strip_model()->GetActiveWebContents();
204 if (disposition == CURRENT_TAB) {
205 same_tab_observer.Wait();
206 return;
207 } else if (web_contents) {
208 content::TestNavigationObserver observer(web_contents,
209 number_of_navigations);
210 observer.Wait();
211 return;
213 EXPECT_TRUE(NULL != web_contents) << " Unable to wait for navigation to \""
214 << url.spec() << "\""
215 << " because we can't get the tab contents";
218 void NavigateToURLWithDisposition(Browser* browser,
219 const GURL& url,
220 WindowOpenDisposition disposition,
221 int browser_test_flags) {
222 NavigateToURLWithDispositionBlockUntilNavigationsComplete(
223 browser,
224 url,
226 disposition,
227 browser_test_flags);
230 void NavigateToURLBlockUntilNavigationsComplete(Browser* browser,
231 const GURL& url,
232 int number_of_navigations) {
233 NavigateToURLWithDispositionBlockUntilNavigationsComplete(
234 browser,
235 url,
236 number_of_navigations,
237 CURRENT_TAB,
238 BROWSER_TEST_WAIT_FOR_NAVIGATION);
241 base::FilePath GetTestFilePath(const base::FilePath& dir,
242 const base::FilePath& file) {
243 base::FilePath path;
244 PathService::Get(chrome::DIR_TEST_DATA, &path);
245 return path.Append(dir).Append(file);
248 GURL GetTestUrl(const base::FilePath& dir, const base::FilePath& file) {
249 return net::FilePathToFileURL(GetTestFilePath(dir, file));
252 bool GetRelativeBuildDirectory(base::FilePath* build_dir) {
253 // This function is used to find the build directory so TestServer can serve
254 // built files (nexes, etc). TestServer expects a path relative to the source
255 // root.
256 base::FilePath exe_dir =
257 CommandLine::ForCurrentProcess()->GetProgram().DirName();
258 base::FilePath src_dir;
259 if (!PathService::Get(base::DIR_SOURCE_ROOT, &src_dir))
260 return false;
262 // We must first generate absolute paths to SRC and EXE and from there
263 // generate a relative path.
264 if (!exe_dir.IsAbsolute())
265 exe_dir = base::MakeAbsoluteFilePath(exe_dir);
266 if (!src_dir.IsAbsolute())
267 src_dir = base::MakeAbsoluteFilePath(src_dir);
268 if (!exe_dir.IsAbsolute())
269 return false;
270 if (!src_dir.IsAbsolute())
271 return false;
273 size_t match, exe_size, src_size;
274 std::vector<base::FilePath::StringType> src_parts, exe_parts;
276 // Determine point at which src and exe diverge.
277 exe_dir.GetComponents(&exe_parts);
278 src_dir.GetComponents(&src_parts);
279 exe_size = exe_parts.size();
280 src_size = src_parts.size();
281 for (match = 0; match < exe_size && match < src_size; ++match) {
282 if (exe_parts[match] != src_parts[match])
283 break;
286 // Create a relative path.
287 *build_dir = base::FilePath();
288 for (size_t tmp_itr = match; tmp_itr < src_size; ++tmp_itr)
289 *build_dir = build_dir->Append(FILE_PATH_LITERAL(".."));
290 for (; match < exe_size; ++match)
291 *build_dir = build_dir->Append(exe_parts[match]);
292 return true;
295 AppModalDialog* WaitForAppModalDialog() {
296 AppModalDialogQueue* dialog_queue = AppModalDialogQueue::GetInstance();
297 if (dialog_queue->HasActiveDialog())
298 return dialog_queue->active_dialog();
300 content::WindowedNotificationObserver observer(
301 chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN,
302 content::NotificationService::AllSources());
303 observer.Wait();
304 return content::Source<AppModalDialog>(observer.source()).ptr();
307 int FindInPage(WebContents* tab,
308 const base::string16& search_string,
309 bool forward,
310 bool match_case,
311 int* ordinal,
312 gfx::Rect* selection_rect) {
313 FindTabHelper* find_tab_helper = FindTabHelper::FromWebContents(tab);
314 find_tab_helper->StartFinding(search_string, forward, match_case);
315 FindInPageNotificationObserver observer(tab);
316 observer.Wait();
317 if (ordinal)
318 *ordinal = observer.active_match_ordinal();
319 if (selection_rect)
320 *selection_rect = observer.selection_rect();
321 return observer.number_of_matches();
324 void WaitForTemplateURLServiceToLoad(TemplateURLService* service) {
325 if (service->loaded())
326 return;
327 scoped_refptr<content::MessageLoopRunner> message_loop_runner =
328 new content::MessageLoopRunner;
329 scoped_ptr<TemplateURLService::Subscription> subscription =
330 service->RegisterOnLoadedCallback(
331 message_loop_runner->QuitClosure());
332 service->Load();
333 message_loop_runner->Run();
335 ASSERT_TRUE(service->loaded());
338 void WaitForHistoryToLoad(HistoryService* history_service) {
339 content::WindowedNotificationObserver history_loaded_observer(
340 chrome::NOTIFICATION_HISTORY_LOADED,
341 content::NotificationService::AllSources());
342 if (!history_service->BackendLoaded())
343 history_loaded_observer.Wait();
346 void DownloadURL(Browser* browser, const GURL& download_url) {
347 base::ScopedTempDir downloads_directory;
348 ASSERT_TRUE(downloads_directory.CreateUniqueTempDir());
349 browser->profile()->GetPrefs()->SetFilePath(
350 prefs::kDownloadDefaultDirectory, downloads_directory.path());
352 content::DownloadManager* download_manager =
353 content::BrowserContext::GetDownloadManager(browser->profile());
354 scoped_ptr<content::DownloadTestObserver> observer(
355 new content::DownloadTestObserverTerminal(
356 download_manager, 1,
357 content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_ACCEPT));
359 ui_test_utils::NavigateToURL(browser, download_url);
360 observer->WaitForFinished();
363 void SendToOmniboxAndSubmit(LocationBar* location_bar,
364 const std::string& input) {
365 OmniboxView* omnibox = location_bar->GetOmniboxView();
366 omnibox->model()->OnSetFocus(false);
367 omnibox->SetUserText(base::ASCIIToUTF16(input));
368 location_bar->AcceptInput();
369 while (!omnibox->model()->autocomplete_controller()->done()) {
370 content::WindowedNotificationObserver observer(
371 chrome::NOTIFICATION_AUTOCOMPLETE_CONTROLLER_RESULT_READY,
372 content::NotificationService::AllSources());
373 observer.Wait();
377 Browser* GetBrowserNotInSet(std::set<Browser*> excluded_browsers) {
378 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
379 if (excluded_browsers.find(*it) == excluded_browsers.end())
380 return *it;
382 return NULL;
385 namespace {
387 void GetCookiesCallback(base::WaitableEvent* event,
388 std::string* cookies,
389 const std::string& cookie_line) {
390 *cookies = cookie_line;
391 event->Signal();
394 void GetCookiesOnIOThread(
395 const GURL& url,
396 const scoped_refptr<net::URLRequestContextGetter>& context_getter,
397 base::WaitableEvent* event,
398 std::string* cookies) {
399 context_getter->GetURLRequestContext()->cookie_store()->
400 GetCookiesWithOptionsAsync(
401 url, net::CookieOptions(),
402 base::Bind(&GetCookiesCallback, event, cookies));
405 } // namespace
407 void GetCookies(const GURL& url,
408 WebContents* contents,
409 int* value_size,
410 std::string* value) {
411 *value_size = -1;
412 if (url.is_valid() && contents) {
413 scoped_refptr<net::URLRequestContextGetter> context_getter =
414 contents->GetBrowserContext()->GetRequestContextForRenderProcess(
415 contents->GetRenderProcessHost()->GetID());
416 base::WaitableEvent event(true /* manual reset */,
417 false /* not initially signaled */);
418 CHECK(content::BrowserThread::PostTask(
419 content::BrowserThread::IO, FROM_HERE,
420 base::Bind(&GetCookiesOnIOThread, url, context_getter, &event, value)));
421 event.Wait();
423 *value_size = static_cast<int>(value->size());
427 WindowedTabAddedNotificationObserver::WindowedTabAddedNotificationObserver(
428 const content::NotificationSource& source)
429 : WindowedNotificationObserver(chrome::NOTIFICATION_TAB_ADDED, source),
430 added_tab_(NULL) {
433 void WindowedTabAddedNotificationObserver::Observe(
434 int type,
435 const content::NotificationSource& source,
436 const content::NotificationDetails& details) {
437 added_tab_ = content::Details<WebContents>(details).ptr();
438 content::WindowedNotificationObserver::Observe(type, source, details);
441 UrlLoadObserver::UrlLoadObserver(const GURL& url,
442 const content::NotificationSource& source)
443 : WindowedNotificationObserver(content::NOTIFICATION_LOAD_STOP, source),
444 url_(url) {
447 UrlLoadObserver::~UrlLoadObserver() {}
449 void UrlLoadObserver::Observe(
450 int type,
451 const content::NotificationSource& source,
452 const content::NotificationDetails& details) {
453 NavigationController* controller =
454 content::Source<NavigationController>(source).ptr();
455 if (controller->GetWebContents()->GetURL() != url_)
456 return;
458 WindowedNotificationObserver::Observe(type, source, details);
461 BrowserAddedObserver::BrowserAddedObserver()
462 : notification_observer_(
463 chrome::NOTIFICATION_BROWSER_OPENED,
464 content::NotificationService::AllSources()) {
465 for (chrome::BrowserIterator it; !it.done(); it.Next())
466 original_browsers_.insert(*it);
469 BrowserAddedObserver::~BrowserAddedObserver() {
472 Browser* BrowserAddedObserver::WaitForSingleNewBrowser() {
473 notification_observer_.Wait();
474 // Ensure that only a single new browser has appeared.
475 EXPECT_EQ(original_browsers_.size() + 1, chrome::GetTotalBrowserCount());
476 return GetBrowserNotInSet(original_browsers_);
479 void OverrideGeolocation(double latitude, double longitude) {
480 content::Geoposition position;
481 position.latitude = latitude;
482 position.longitude = longitude;
483 position.altitude = 0.;
484 position.accuracy = 0.;
485 position.timestamp = base::Time::Now();
486 content::GeolocationProvider::GetInstance()->OverrideLocationForTesting(
487 position);
490 HistoryEnumerator::HistoryEnumerator(Profile* profile) {
491 scoped_refptr<content::MessageLoopRunner> message_loop_runner =
492 new content::MessageLoopRunner;
494 HistoryService* hs = HistoryServiceFactory::GetForProfile(
495 profile, Profile::EXPLICIT_ACCESS);
496 hs->QueryHistory(base::string16(),
497 history::QueryOptions(),
498 base::Bind(&HistoryEnumerator::HistoryQueryComplete,
499 base::Unretained(this),
500 message_loop_runner->QuitClosure()),
501 &tracker_);
502 message_loop_runner->Run();
505 HistoryEnumerator::~HistoryEnumerator() {}
507 void HistoryEnumerator::HistoryQueryComplete(
508 const base::Closure& quit_task,
509 history::QueryResults* results) {
510 for (size_t i = 0; i < results->size(); ++i)
511 urls_.push_back((*results)[i].url());
512 quit_task.Run();
515 } // namespace ui_test_utils