Content settings: remove some plugin-related code/resources when... there are no...
[chromium-blink-merge.git] / content / public / test / browser_test_utils.cc
blob214b2fd61d678cca452e21f5e3fcde487f0bc5a8
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 "content/public/test/browser_test_utils.h"
7 #include "base/auto_reset.h"
8 #include "base/bind.h"
9 #include "base/command_line.h"
10 #include "base/json/json_reader.h"
11 #include "base/process/kill.h"
12 #include "base/rand_util.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_piece.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "base/synchronization/waitable_event.h"
17 #include "base/test/test_timeouts.h"
18 #include "base/values.h"
19 #include "content/browser/renderer_host/render_widget_host_impl.h"
20 #include "content/browser/web_contents/web_contents_impl.h"
21 #include "content/browser/web_contents/web_contents_view.h"
22 #include "content/common/input/synthetic_web_input_event_builders.h"
23 #include "content/common/view_messages.h"
24 #include "content/public/browser/browser_context.h"
25 #include "content/public/browser/dom_operation_notification_details.h"
26 #include "content/public/browser/histogram_fetcher.h"
27 #include "content/public/browser/navigation_entry.h"
28 #include "content/public/browser/notification_service.h"
29 #include "content/public/browser/notification_types.h"
30 #include "content/public/browser/render_frame_host.h"
31 #include "content/public/browser/render_process_host.h"
32 #include "content/public/browser/render_view_host.h"
33 #include "content/public/browser/web_contents.h"
34 #include "content/public/test/test_utils.h"
35 #include "net/base/filename_util.h"
36 #include "net/cookies/cookie_store.h"
37 #include "net/test/embedded_test_server/embedded_test_server.h"
38 #include "net/test/embedded_test_server/http_request.h"
39 #include "net/test/embedded_test_server/http_response.h"
40 #include "net/test/python_utils.h"
41 #include "net/url_request/url_request_context.h"
42 #include "net/url_request/url_request_context_getter.h"
43 #include "testing/gtest/include/gtest/gtest.h"
44 #include "ui/base/resource/resource_bundle.h"
45 #include "ui/compositor/test/draw_waiter_for_test.h"
46 #include "ui/events/gesture_detection/gesture_configuration.h"
47 #include "ui/events/keycodes/dom/dom_code.h"
48 #include "ui/events/keycodes/dom/keycode_converter.h"
49 #include "ui/events/latency_info.h"
50 #include "ui/resources/grit/webui_resources.h"
52 #if defined(USE_AURA)
53 #include "ui/aura/test/window_event_dispatcher_test_api.h"
54 #include "ui/aura/window.h"
55 #include "ui/aura/window_event_dispatcher.h"
56 #include "ui/aura/window_tree_host.h"
57 #endif // USE_AURA
59 namespace content {
60 namespace {
62 class DOMOperationObserver : public NotificationObserver,
63 public WebContentsObserver {
64 public:
65 explicit DOMOperationObserver(RenderViewHost* rvh)
66 : WebContentsObserver(WebContents::FromRenderViewHost(rvh)),
67 did_respond_(false) {
68 registrar_.Add(this, NOTIFICATION_DOM_OPERATION_RESPONSE,
69 Source<WebContents>(web_contents()));
70 message_loop_runner_ = new MessageLoopRunner;
73 void Observe(int type,
74 const NotificationSource& source,
75 const NotificationDetails& details) override {
76 DCHECK(type == NOTIFICATION_DOM_OPERATION_RESPONSE);
77 Details<DomOperationNotificationDetails> dom_op_details(details);
78 if (!did_respond_) {
79 response_ = dom_op_details->json;
80 did_respond_ = true;
81 message_loop_runner_->Quit();
85 // Overridden from WebContentsObserver:
86 void RenderProcessGone(base::TerminationStatus status) override {
87 message_loop_runner_->Quit();
90 bool WaitAndGetResponse(std::string* response) WARN_UNUSED_RESULT {
91 message_loop_runner_->Run();
92 *response = response_;
93 return did_respond_;
96 private:
97 NotificationRegistrar registrar_;
98 std::string response_;
99 bool did_respond_;
100 scoped_refptr<MessageLoopRunner> message_loop_runner_;
102 DISALLOW_COPY_AND_ASSIGN(DOMOperationObserver);
105 class InterstitialObserver : public content::WebContentsObserver {
106 public:
107 InterstitialObserver(content::WebContents* web_contents,
108 const base::Closure& attach_callback,
109 const base::Closure& detach_callback)
110 : WebContentsObserver(web_contents),
111 attach_callback_(attach_callback),
112 detach_callback_(detach_callback) {
114 ~InterstitialObserver() override {}
116 // WebContentsObserver methods:
117 void DidAttachInterstitialPage() override { attach_callback_.Run(); }
118 void DidDetachInterstitialPage() override { detach_callback_.Run(); }
120 private:
121 base::Closure attach_callback_;
122 base::Closure detach_callback_;
124 DISALLOW_COPY_AND_ASSIGN(InterstitialObserver);
127 // Specifying a prototype so that we can add the WARN_UNUSED_RESULT attribute.
128 bool ExecuteScriptHelper(
129 RenderFrameHost* render_frame_host,
130 const std::string& original_script,
131 scoped_ptr<base::Value>* result) WARN_UNUSED_RESULT;
133 // Executes the passed |original_script| in the frame specified by
134 // |render_frame_host|. If |result| is not NULL, stores the value that the
135 // evaluation of the script in |result|. Returns true on success.
136 bool ExecuteScriptHelper(RenderFrameHost* render_frame_host,
137 const std::string& original_script,
138 scoped_ptr<base::Value>* result) {
139 // TODO(jcampan): we should make the domAutomationController not require an
140 // automation id.
141 std::string script =
142 "window.domAutomationController.setAutomationId(0);" + original_script;
143 DOMOperationObserver dom_op_observer(render_frame_host->GetRenderViewHost());
144 render_frame_host->ExecuteJavaScriptWithUserGestureForTests(
145 base::UTF8ToUTF16(script));
146 std::string json;
147 if (!dom_op_observer.WaitAndGetResponse(&json)) {
148 DLOG(ERROR) << "Cannot communicate with DOMOperationObserver.";
149 return false;
152 // Nothing more to do for callers that ignore the returned JS value.
153 if (!result)
154 return true;
156 base::JSONReader reader(base::JSON_ALLOW_TRAILING_COMMAS);
157 *result = reader.ReadToValue(json);
158 if (!*result) {
159 DLOG(ERROR) << reader.GetErrorMessage();
160 return false;
163 return true;
166 void BuildSimpleWebKeyEvent(blink::WebInputEvent::Type type,
167 ui::KeyboardCode key_code,
168 int native_key_code,
169 int modifiers,
170 NativeWebKeyboardEvent* event) {
171 event->nativeKeyCode = native_key_code;
172 event->windowsKeyCode = key_code;
173 event->setKeyIdentifierFromWindowsKeyCode();
174 event->type = type;
175 event->modifiers = modifiers;
176 event->isSystemKey = false;
177 event->timeStampSeconds = base::Time::Now().ToDoubleT();
178 event->skip_in_browser = true;
180 if (type == blink::WebInputEvent::Char ||
181 type == blink::WebInputEvent::RawKeyDown) {
182 event->text[0] = key_code;
183 event->unmodifiedText[0] = key_code;
187 void InjectRawKeyEvent(WebContents* web_contents,
188 blink::WebInputEvent::Type type,
189 ui::KeyboardCode key_code,
190 int native_key_code,
191 int modifiers) {
192 NativeWebKeyboardEvent event;
193 BuildSimpleWebKeyEvent(type, key_code, native_key_code, modifiers, &event);
194 web_contents->GetRenderViewHost()->ForwardKeyboardEvent(event);
197 void GetCookiesCallback(std::string* cookies_out,
198 base::WaitableEvent* event,
199 const std::string& cookies) {
200 *cookies_out = cookies;
201 event->Signal();
204 void GetCookiesOnIOThread(const GURL& url,
205 net::URLRequestContextGetter* context_getter,
206 base::WaitableEvent* event,
207 std::string* cookies) {
208 net::CookieStore* cookie_store =
209 context_getter->GetURLRequestContext()->cookie_store();
210 cookie_store->GetCookiesWithOptionsAsync(
211 url, net::CookieOptions(),
212 base::Bind(&GetCookiesCallback, cookies, event));
215 void SetCookieCallback(bool* result,
216 base::WaitableEvent* event,
217 bool success) {
218 *result = success;
219 event->Signal();
222 void SetCookieOnIOThread(const GURL& url,
223 const std::string& value,
224 net::URLRequestContextGetter* context_getter,
225 base::WaitableEvent* event,
226 bool* result) {
227 net::CookieStore* cookie_store =
228 context_getter->GetURLRequestContext()->cookie_store();
229 cookie_store->SetCookieWithOptionsAsync(
230 url, value, net::CookieOptions(),
231 base::Bind(&SetCookieCallback, result, event));
234 scoped_ptr<net::test_server::HttpResponse> CrossSiteRedirectResponseHandler(
235 const GURL& server_base_url,
236 const net::test_server::HttpRequest& request) {
237 std::string prefix("/cross-site/");
238 if (!base::StartsWith(request.relative_url, prefix,
239 base::CompareCase::SENSITIVE))
240 return scoped_ptr<net::test_server::HttpResponse>();
242 std::string params = request.relative_url.substr(prefix.length());
244 // A hostname to redirect to must be included in the URL, therefore at least
245 // one '/' character is expected.
246 size_t slash = params.find('/');
247 if (slash == std::string::npos)
248 return scoped_ptr<net::test_server::HttpResponse>();
250 // Replace the host of the URL with the one passed in the URL.
251 GURL::Replacements replace_host;
252 replace_host.SetHostStr(base::StringPiece(params).substr(0, slash));
253 GURL redirect_server = server_base_url.ReplaceComponents(replace_host);
255 // Append the real part of the path to the new URL.
256 std::string path = params.substr(slash + 1);
257 GURL redirect_target(redirect_server.Resolve(path));
258 DCHECK(redirect_target.is_valid());
260 scoped_ptr<net::test_server::BasicHttpResponse> http_response(
261 new net::test_server::BasicHttpResponse);
262 http_response->set_code(net::HTTP_MOVED_PERMANENTLY);
263 http_response->AddCustomHeader("Location", redirect_target.spec());
264 return http_response.Pass();
267 } // namespace
269 bool NavigateIframeToURL(WebContents* web_contents,
270 std::string iframe_id,
271 const GURL& url) {
272 // TODO(creis): This should wait for LOAD_STOP, but cross-site subframe
273 // navigations generate extra DidStartLoading and DidStopLoading messages.
274 // Until we replace swappedout:// with frame proxies, we need to listen for
275 // something else. For now, we trigger NEW_SUBFRAME navigations and listen
276 // for commit. See https://crbug.com/436250.
277 std::string script = base::StringPrintf(
278 "setTimeout(\""
279 "var iframes = document.getElementById('%s');iframes.src='%s';"
280 "\",0)",
281 iframe_id.c_str(), url.spec().c_str());
282 WindowedNotificationObserver load_observer(
283 NOTIFICATION_NAV_ENTRY_COMMITTED,
284 Source<NavigationController>(&web_contents->GetController()));
285 bool result = ExecuteScript(web_contents, script);
286 load_observer.Wait();
287 return result;
290 GURL GetFileUrlWithQuery(const base::FilePath& path,
291 const std::string& query_string) {
292 GURL url = net::FilePathToFileURL(path);
293 if (!query_string.empty()) {
294 GURL::Replacements replacements;
295 replacements.SetQueryStr(query_string);
296 return url.ReplaceComponents(replacements);
298 return url;
301 void WaitForLoadStopWithoutSuccessCheck(WebContents* web_contents) {
302 // In many cases, the load may have finished before we get here. Only wait if
303 // the tab still has a pending navigation.
304 if (web_contents->IsLoading()) {
305 WindowedNotificationObserver load_stop_observer(
306 NOTIFICATION_LOAD_STOP,
307 Source<NavigationController>(&web_contents->GetController()));
308 load_stop_observer.Wait();
312 bool WaitForLoadStop(WebContents* web_contents) {
313 WaitForLoadStopWithoutSuccessCheck(web_contents);
314 return IsLastCommittedEntryOfPageType(web_contents, PAGE_TYPE_NORMAL);
317 bool IsLastCommittedEntryOfPageType(WebContents* web_contents,
318 content::PageType page_type) {
319 NavigationEntry* last_entry =
320 web_contents->GetController().GetLastCommittedEntry();
321 if (!last_entry)
322 return false;
323 return last_entry->GetPageType() == page_type;
326 void CrashTab(WebContents* web_contents) {
327 RenderProcessHost* rph = web_contents->GetRenderProcessHost();
328 RenderProcessHostWatcher watcher(
329 rph, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
330 rph->Shutdown(0, false);
331 watcher.Wait();
334 #if defined(USE_AURA)
335 bool IsResizeComplete(aura::test::WindowEventDispatcherTestApi* dispatcher_test,
336 RenderWidgetHostImpl* widget_host) {
337 return !dispatcher_test->HoldingPointerMoves() &&
338 !widget_host->resize_ack_pending_for_testing();
341 void WaitForResizeComplete(WebContents* web_contents) {
342 aura::Window* content = web_contents->GetContentNativeView();
343 if (!content)
344 return;
346 aura::WindowTreeHost* window_host = content->GetHost();
347 aura::WindowEventDispatcher* dispatcher = window_host->dispatcher();
348 aura::test::WindowEventDispatcherTestApi dispatcher_test(dispatcher);
349 RenderWidgetHostImpl* widget_host =
350 RenderWidgetHostImpl::From(web_contents->GetRenderViewHost());
351 if (!IsResizeComplete(&dispatcher_test, widget_host)) {
352 WindowedNotificationObserver resize_observer(
353 NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
354 base::Bind(IsResizeComplete, &dispatcher_test, widget_host));
355 resize_observer.Wait();
358 #elif defined(OS_ANDROID)
359 bool IsResizeComplete(RenderWidgetHostImpl* widget_host) {
360 return !widget_host->resize_ack_pending_for_testing();
363 void WaitForResizeComplete(WebContents* web_contents) {
364 RenderWidgetHostImpl* widget_host =
365 RenderWidgetHostImpl::From(web_contents->GetRenderViewHost());
366 if (!IsResizeComplete(widget_host)) {
367 WindowedNotificationObserver resize_observer(
368 NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
369 base::Bind(IsResizeComplete, widget_host));
370 resize_observer.Wait();
373 #endif
375 void SimulateMouseClick(WebContents* web_contents,
376 int modifiers,
377 blink::WebMouseEvent::Button button) {
378 int x = web_contents->GetContainerBounds().width() / 2;
379 int y = web_contents->GetContainerBounds().height() / 2;
380 SimulateMouseClickAt(web_contents, modifiers, button, gfx::Point(x, y));
383 void SimulateMouseClickAt(WebContents* web_contents,
384 int modifiers,
385 blink::WebMouseEvent::Button button,
386 const gfx::Point& point) {
387 blink::WebMouseEvent mouse_event;
388 mouse_event.type = blink::WebInputEvent::MouseDown;
389 mouse_event.button = button;
390 mouse_event.x = point.x();
391 mouse_event.y = point.y();
392 mouse_event.modifiers = modifiers;
393 // Mac needs globalX/globalY for events to plugins.
394 gfx::Rect offset = web_contents->GetContainerBounds();
395 mouse_event.globalX = point.x() + offset.x();
396 mouse_event.globalY = point.y() + offset.y();
397 mouse_event.clickCount = 1;
398 web_contents->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
399 mouse_event.type = blink::WebInputEvent::MouseUp;
400 web_contents->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
403 void SimulateMouseEvent(WebContents* web_contents,
404 blink::WebInputEvent::Type type,
405 const gfx::Point& point) {
406 blink::WebMouseEvent mouse_event;
407 mouse_event.type = type;
408 mouse_event.x = point.x();
409 mouse_event.y = point.y();
410 web_contents->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
413 void SimulateTapAt(WebContents* web_contents, const gfx::Point& point) {
414 blink::WebGestureEvent tap;
415 tap.type = blink::WebGestureEvent::GestureTap;
416 tap.x = point.x();
417 tap.y = point.y();
418 tap.modifiers = blink::WebInputEvent::ControlKey;
419 RenderWidgetHostImpl* widget_host =
420 RenderWidgetHostImpl::From(web_contents->GetRenderViewHost());
421 widget_host->ForwardGestureEvent(tap);
424 void SimulateTapWithModifiersAt(WebContents* web_contents,
425 unsigned modifiers,
426 const gfx::Point& point) {
427 blink::WebGestureEvent tap;
428 tap.type = blink::WebGestureEvent::GestureTap;
429 tap.x = point.x();
430 tap.y = point.y();
431 tap.modifiers = modifiers;
432 RenderWidgetHostImpl* widget_host =
433 RenderWidgetHostImpl::From(web_contents->GetRenderViewHost());
434 widget_host->ForwardGestureEvent(tap);
437 void SimulateTouchPressAt(WebContents* web_contents, const gfx::Point& point) {
438 SyntheticWebTouchEvent touch;
439 touch.PressPoint(point.x(), point.y());
440 RenderWidgetHostImpl* widget_host =
441 RenderWidgetHostImpl::From(web_contents->GetRenderViewHost());
442 widget_host->ForwardTouchEventWithLatencyInfo(touch, ui::LatencyInfo());
445 void SimulateKeyPress(WebContents* web_contents,
446 ui::KeyboardCode key_code,
447 bool control,
448 bool shift,
449 bool alt,
450 bool command) {
451 SimulateKeyPressWithCode(
452 web_contents, key_code, NULL, control, shift, alt, command);
455 void SimulateKeyPressWithCode(WebContents* web_contents,
456 ui::KeyboardCode key_code,
457 const char* code,
458 bool control,
459 bool shift,
460 bool alt,
461 bool command) {
462 int native_key_code = ui::KeycodeConverter::DomCodeToNativeKeycode(
463 ui::KeycodeConverter::CodeStringToDomCode(code));
465 int modifiers = 0;
467 // The order of these key down events shouldn't matter for our simulation.
468 // For our simulation we can use either the left keys or the right keys.
469 if (control) {
470 modifiers |= blink::WebInputEvent::ControlKey;
471 InjectRawKeyEvent(
472 web_contents, blink::WebInputEvent::RawKeyDown, ui::VKEY_CONTROL,
473 ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::CONTROL_LEFT),
474 modifiers);
477 if (shift) {
478 modifiers |= blink::WebInputEvent::ShiftKey;
479 InjectRawKeyEvent(
480 web_contents, blink::WebInputEvent::RawKeyDown, ui::VKEY_SHIFT,
481 ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::SHIFT_LEFT),
482 modifiers);
485 if (alt) {
486 modifiers |= blink::WebInputEvent::AltKey;
487 InjectRawKeyEvent(
488 web_contents, blink::WebInputEvent::RawKeyDown, ui::VKEY_MENU,
489 ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::ALT_LEFT),
490 modifiers);
493 if (command) {
494 modifiers |= blink::WebInputEvent::MetaKey;
495 InjectRawKeyEvent(
496 web_contents, blink::WebInputEvent::RawKeyDown, ui::VKEY_COMMAND,
497 ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::OS_LEFT),
498 modifiers);
500 InjectRawKeyEvent(web_contents, blink::WebInputEvent::RawKeyDown, key_code,
501 native_key_code, modifiers);
503 InjectRawKeyEvent(web_contents, blink::WebInputEvent::Char, key_code,
504 native_key_code, modifiers);
506 InjectRawKeyEvent(web_contents, blink::WebInputEvent::KeyUp, key_code,
507 native_key_code, modifiers);
509 // The order of these key releases shouldn't matter for our simulation.
510 if (control) {
511 modifiers &= ~blink::WebInputEvent::ControlKey;
512 InjectRawKeyEvent(
513 web_contents, blink::WebInputEvent::KeyUp, ui::VKEY_CONTROL,
514 ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::CONTROL_LEFT),
515 modifiers);
518 if (shift) {
519 modifiers &= ~blink::WebInputEvent::ShiftKey;
520 InjectRawKeyEvent(
521 web_contents, blink::WebInputEvent::KeyUp, ui::VKEY_SHIFT,
522 ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::SHIFT_LEFT),
523 modifiers);
526 if (alt) {
527 modifiers &= ~blink::WebInputEvent::AltKey;
528 InjectRawKeyEvent(
529 web_contents, blink::WebInputEvent::KeyUp, ui::VKEY_MENU,
530 ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::ALT_LEFT),
531 modifiers);
534 if (command) {
535 modifiers &= ~blink::WebInputEvent::MetaKey;
536 InjectRawKeyEvent(
537 web_contents, blink::WebInputEvent::KeyUp, ui::VKEY_COMMAND,
538 ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::OS_LEFT),
539 modifiers);
542 ASSERT_EQ(modifiers, 0);
545 ToRenderFrameHost::ToRenderFrameHost(WebContents* web_contents)
546 : render_frame_host_(web_contents->GetMainFrame()) {
549 ToRenderFrameHost::ToRenderFrameHost(RenderViewHost* render_view_host)
550 : render_frame_host_(render_view_host->GetMainFrame()) {
553 ToRenderFrameHost::ToRenderFrameHost(RenderFrameHost* render_frame_host)
554 : render_frame_host_(render_frame_host) {
557 bool ExecuteScript(const ToRenderFrameHost& adapter,
558 const std::string& script) {
559 std::string new_script =
560 script + ";window.domAutomationController.send(0);";
561 return ExecuteScriptHelper(adapter.render_frame_host(), new_script, NULL);
564 bool ExecuteScriptAndExtractInt(const ToRenderFrameHost& adapter,
565 const std::string& script, int* result) {
566 DCHECK(result);
567 scoped_ptr<base::Value> value;
568 if (!ExecuteScriptHelper(adapter.render_frame_host(), script, &value) ||
569 !value.get()) {
570 return false;
573 return value->GetAsInteger(result);
576 bool ExecuteScriptAndExtractBool(const ToRenderFrameHost& adapter,
577 const std::string& script, bool* result) {
578 DCHECK(result);
579 scoped_ptr<base::Value> value;
580 if (!ExecuteScriptHelper(adapter.render_frame_host(), script, &value) ||
581 !value.get()) {
582 return false;
585 return value->GetAsBoolean(result);
588 bool ExecuteScriptAndExtractString(const ToRenderFrameHost& adapter,
589 const std::string& script,
590 std::string* result) {
591 DCHECK(result);
592 scoped_ptr<base::Value> value;
593 if (!ExecuteScriptHelper(adapter.render_frame_host(), script, &value) ||
594 !value.get()) {
595 return false;
598 return value->GetAsString(result);
601 namespace {
602 void AddToSetIfFrameMatchesPredicate(
603 std::set<RenderFrameHost*>* frame_set,
604 const base::Callback<bool(RenderFrameHost*)>& predicate,
605 RenderFrameHost* host) {
606 if (predicate.Run(host))
607 frame_set->insert(host);
611 RenderFrameHost* FrameMatchingPredicate(
612 WebContents* web_contents,
613 const base::Callback<bool(RenderFrameHost*)>& predicate) {
614 std::set<RenderFrameHost*> frame_set;
615 web_contents->ForEachFrame(
616 base::Bind(&AddToSetIfFrameMatchesPredicate, &frame_set, predicate));
617 DCHECK_EQ(1U, frame_set.size());
618 return *frame_set.begin();
621 bool FrameMatchesName(const std::string& name, RenderFrameHost* frame) {
622 return frame->GetFrameName() == name;
625 bool FrameIsChildOfMainFrame(RenderFrameHost* frame) {
626 return frame->GetParent() && !frame->GetParent()->GetParent();
629 bool FrameHasSourceUrl(const GURL& url, RenderFrameHost* frame) {
630 return frame->GetLastCommittedURL() == url;
633 bool ExecuteWebUIResourceTest(WebContents* web_contents,
634 const std::vector<int>& js_resource_ids) {
635 // Inject WebUI test runner script first prior to other scripts required to
636 // run the test as scripts may depend on it being declared.
637 std::vector<int> ids;
638 ids.push_back(IDR_WEBUI_JS_WEBUI_RESOURCE_TEST);
639 ids.insert(ids.end(), js_resource_ids.begin(), js_resource_ids.end());
641 std::string script;
642 for (std::vector<int>::iterator iter = ids.begin();
643 iter != ids.end();
644 ++iter) {
645 ResourceBundle::GetSharedInstance().GetRawDataResource(*iter)
646 .AppendToString(&script);
647 script.append("\n");
649 if (!ExecuteScript(web_contents, script))
650 return false;
652 DOMMessageQueue message_queue;
653 if (!ExecuteScript(web_contents, "runTests()"))
654 return false;
656 std::string message;
657 do {
658 if (!message_queue.WaitForMessage(&message))
659 return false;
660 } while (message.compare("\"PENDING\"") == 0);
662 return message.compare("\"SUCCESS\"") == 0;
665 std::string GetCookies(BrowserContext* browser_context, const GURL& url) {
666 std::string cookies;
667 base::WaitableEvent event(true, false);
668 net::URLRequestContextGetter* context_getter =
669 browser_context->GetRequestContext();
671 BrowserThread::PostTask(
672 BrowserThread::IO, FROM_HERE,
673 base::Bind(&GetCookiesOnIOThread, url,
674 make_scoped_refptr(context_getter), &event, &cookies));
675 event.Wait();
676 return cookies;
679 bool SetCookie(BrowserContext* browser_context,
680 const GURL& url,
681 const std::string& value) {
682 bool result = false;
683 base::WaitableEvent event(true, false);
684 net::URLRequestContextGetter* context_getter =
685 browser_context->GetRequestContext();
687 BrowserThread::PostTask(
688 BrowserThread::IO, FROM_HERE,
689 base::Bind(&SetCookieOnIOThread, url, value,
690 make_scoped_refptr(context_getter), &event, &result));
691 event.Wait();
692 return result;
695 void FetchHistogramsFromChildProcesses() {
696 scoped_refptr<content::MessageLoopRunner> runner = new MessageLoopRunner;
698 FetchHistogramsAsynchronously(
699 base::MessageLoop::current(),
700 runner->QuitClosure(),
701 // If this call times out, it means that a child process is not
702 // responding, which is something we should not ignore. The timeout is
703 // set to be longer than the normal browser test timeout so that it will
704 // be prempted by the normal timeout.
705 TestTimeouts::action_max_timeout());
706 runner->Run();
709 void SetupCrossSiteRedirector(
710 net::test_server::EmbeddedTestServer* embedded_test_server) {
711 embedded_test_server->RegisterRequestHandler(
712 base::Bind(&CrossSiteRedirectResponseHandler,
713 embedded_test_server->base_url()));
716 void WaitForInterstitialAttach(content::WebContents* web_contents) {
717 if (web_contents->ShowingInterstitialPage())
718 return;
719 scoped_refptr<content::MessageLoopRunner> loop_runner(
720 new content::MessageLoopRunner);
721 InterstitialObserver observer(web_contents,
722 loop_runner->QuitClosure(),
723 base::Closure());
724 loop_runner->Run();
727 void WaitForInterstitialDetach(content::WebContents* web_contents) {
728 RunTaskAndWaitForInterstitialDetach(web_contents, base::Closure());
731 void RunTaskAndWaitForInterstitialDetach(content::WebContents* web_contents,
732 const base::Closure& task) {
733 if (!web_contents || !web_contents->ShowingInterstitialPage())
734 return;
735 scoped_refptr<content::MessageLoopRunner> loop_runner(
736 new content::MessageLoopRunner);
737 InterstitialObserver observer(web_contents,
738 base::Closure(),
739 loop_runner->QuitClosure());
740 if (!task.is_null())
741 task.Run();
742 // At this point, web_contents may have been deleted.
743 loop_runner->Run();
746 bool WaitForRenderFrameReady(RenderFrameHost* rfh) {
747 if (!rfh)
748 return false;
749 std::string result;
750 EXPECT_TRUE(
751 content::ExecuteScriptAndExtractString(
752 rfh,
753 "(function() {"
754 " var done = false;"
755 " function checkState() {"
756 " if (!done && document.readyState == 'complete') {"
757 " done = true;"
758 " window.domAutomationController.send('pageLoadComplete');"
759 " }"
760 " }"
761 " checkState();"
762 " document.addEventListener('readystatechange', checkState);"
763 "})();",
764 &result));
765 return result == "pageLoadComplete";
768 TitleWatcher::TitleWatcher(WebContents* web_contents,
769 const base::string16& expected_title)
770 : WebContentsObserver(web_contents),
771 message_loop_runner_(new MessageLoopRunner) {
772 EXPECT_TRUE(web_contents != NULL);
773 expected_titles_.push_back(expected_title);
776 void TitleWatcher::AlsoWaitForTitle(const base::string16& expected_title) {
777 expected_titles_.push_back(expected_title);
780 TitleWatcher::~TitleWatcher() {
783 const base::string16& TitleWatcher::WaitAndGetTitle() {
784 TestTitle();
785 message_loop_runner_->Run();
786 return observed_title_;
789 void TitleWatcher::DidStopLoading() {
790 // When navigating through the history, the restored NavigationEntry's title
791 // will be used. If the entry ends up having the same title after we return
792 // to it, as will usually be the case, then WebContentsObserver::TitleSet
793 // will then be suppressed, since the NavigationEntry's title hasn't changed.
794 TestTitle();
797 void TitleWatcher::TitleWasSet(NavigationEntry* entry, bool explicit_set) {
798 TestTitle();
801 void TitleWatcher::TestTitle() {
802 std::vector<base::string16>::const_iterator it =
803 std::find(expected_titles_.begin(),
804 expected_titles_.end(),
805 web_contents()->GetTitle());
806 if (it == expected_titles_.end())
807 return;
809 observed_title_ = *it;
810 message_loop_runner_->Quit();
813 RenderProcessHostWatcher::RenderProcessHostWatcher(
814 RenderProcessHost* render_process_host, WatchType type)
815 : render_process_host_(render_process_host),
816 type_(type),
817 did_exit_normally_(true),
818 message_loop_runner_(new MessageLoopRunner) {
819 render_process_host_->AddObserver(this);
822 RenderProcessHostWatcher::RenderProcessHostWatcher(
823 WebContents* web_contents, WatchType type)
824 : render_process_host_(web_contents->GetRenderProcessHost()),
825 type_(type),
826 did_exit_normally_(true),
827 message_loop_runner_(new MessageLoopRunner) {
828 render_process_host_->AddObserver(this);
831 RenderProcessHostWatcher::~RenderProcessHostWatcher() {
832 if (render_process_host_)
833 render_process_host_->RemoveObserver(this);
836 void RenderProcessHostWatcher::Wait() {
837 message_loop_runner_->Run();
840 void RenderProcessHostWatcher::RenderProcessExited(
841 RenderProcessHost* host,
842 base::TerminationStatus status,
843 int exit_code) {
844 did_exit_normally_ = status == base::TERMINATION_STATUS_NORMAL_TERMINATION;
845 if (type_ == WATCH_FOR_PROCESS_EXIT)
846 message_loop_runner_->Quit();
849 void RenderProcessHostWatcher::RenderProcessHostDestroyed(
850 RenderProcessHost* host) {
851 render_process_host_ = NULL;
852 if (type_ == WATCH_FOR_HOST_DESTRUCTION)
853 message_loop_runner_->Quit();
856 DOMMessageQueue::DOMMessageQueue() {
857 registrar_.Add(this, NOTIFICATION_DOM_OPERATION_RESPONSE,
858 NotificationService::AllSources());
861 DOMMessageQueue::~DOMMessageQueue() {}
863 void DOMMessageQueue::Observe(int type,
864 const NotificationSource& source,
865 const NotificationDetails& details) {
866 Details<DomOperationNotificationDetails> dom_op_details(details);
867 message_queue_.push(dom_op_details->json);
868 if (message_loop_runner_.get())
869 message_loop_runner_->Quit();
872 void DOMMessageQueue::ClearQueue() {
873 message_queue_ = std::queue<std::string>();
876 bool DOMMessageQueue::WaitForMessage(std::string* message) {
877 DCHECK(message);
878 if (message_queue_.empty()) {
879 // This will be quit when a new message comes in.
880 message_loop_runner_ = new MessageLoopRunner;
881 message_loop_runner_->Run();
883 // The queue should not be empty, unless we were quit because of a timeout.
884 if (message_queue_.empty())
885 return false;
886 *message = message_queue_.front();
887 message_queue_.pop();
888 return true;
891 class WebContentsAddedObserver::RenderViewCreatedObserver
892 : public WebContentsObserver {
893 public:
894 explicit RenderViewCreatedObserver(WebContents* web_contents)
895 : WebContentsObserver(web_contents),
896 render_view_created_called_(false),
897 main_frame_created_called_(false) {}
899 // WebContentsObserver:
900 void RenderViewCreated(RenderViewHost* rvh) override {
901 render_view_created_called_ = true;
904 void RenderFrameCreated(RenderFrameHost* rfh) override {
905 if (rfh == web_contents()->GetMainFrame())
906 main_frame_created_called_ = true;
909 bool render_view_created_called_;
910 bool main_frame_created_called_;
913 WebContentsAddedObserver::WebContentsAddedObserver()
914 : web_contents_created_callback_(
915 base::Bind(&WebContentsAddedObserver::WebContentsCreated,
916 base::Unretained(this))),
917 web_contents_(NULL) {
918 WebContentsImpl::FriendZone::AddCreatedCallbackForTesting(
919 web_contents_created_callback_);
922 WebContentsAddedObserver::~WebContentsAddedObserver() {
923 WebContentsImpl::FriendZone::RemoveCreatedCallbackForTesting(
924 web_contents_created_callback_);
927 void WebContentsAddedObserver::WebContentsCreated(WebContents* web_contents) {
928 DCHECK(!web_contents_);
929 web_contents_ = web_contents;
930 child_observer_.reset(new RenderViewCreatedObserver(web_contents));
932 if (runner_.get())
933 runner_->QuitClosure().Run();
936 WebContents* WebContentsAddedObserver::GetWebContents() {
937 if (web_contents_)
938 return web_contents_;
940 runner_ = new MessageLoopRunner();
941 runner_->Run();
942 return web_contents_;
945 bool WebContentsAddedObserver::RenderViewCreatedCalled() {
946 if (child_observer_) {
947 return child_observer_->render_view_created_called_ &&
948 child_observer_->main_frame_created_called_;
950 return false;
953 bool RequestFrame(WebContents* web_contents) {
954 DCHECK(web_contents);
955 return RenderWidgetHostImpl::From(web_contents->GetRenderViewHost())
956 ->ScheduleComposite();
959 FrameWatcher::FrameWatcher()
960 : BrowserMessageFilter(ViewMsgStart), frames_to_wait_(0) {
963 FrameWatcher::~FrameWatcher() {
966 void FrameWatcher::ReceivedFrameSwap() {
967 --frames_to_wait_;
968 if (frames_to_wait_ == 0)
969 quit_.Run();
972 bool FrameWatcher::OnMessageReceived(const IPC::Message& message) {
973 if (message.type() == ViewHostMsg_SwapCompositorFrame::ID) {
974 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
975 base::Bind(&FrameWatcher::ReceivedFrameSwap, this));
977 return false;
980 void FrameWatcher::AttachTo(WebContents* web_contents) {
981 DCHECK(web_contents);
982 RenderWidgetHostImpl* widget_host =
983 RenderWidgetHostImpl::From(web_contents->GetRenderViewHost());
984 widget_host->GetProcess()->AddFilter(this);
987 void FrameWatcher::WaitFrames(int frames_to_wait) {
988 if (frames_to_wait <= 0)
989 return;
990 base::RunLoop run_loop;
991 base::AutoReset<base::Closure> reset_quit(&quit_, run_loop.QuitClosure());
992 base::AutoReset<int> reset_frames_to_wait(&frames_to_wait_, frames_to_wait);
993 run_loop.Run();
996 } // namespace content