browser_test_utils.cc revision 23730a6e56a168d1879203e4b3819bb36e3d8f1f
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 "content/public/test/browser_test_utils.h" 6 7#include "base/command_line.h" 8#include "base/json/json_reader.h" 9#include "base/path_service.h" 10#include "base/process/kill.h" 11#include "base/rand_util.h" 12#include "base/strings/string_number_conversions.h" 13#include "base/strings/utf_string_conversions.h" 14#include "base/synchronization/waitable_event.h" 15#include "base/test/test_timeouts.h" 16#include "base/values.h" 17#include "content/public/browser/browser_context.h" 18#include "content/public/browser/dom_operation_notification_details.h" 19#include "content/public/browser/notification_service.h" 20#include "content/public/browser/notification_types.h" 21#include "content/public/browser/render_frame_host.h" 22#include "content/public/browser/render_process_host.h" 23#include "content/public/browser/render_view_host.h" 24#include "content/public/browser/web_contents.h" 25#include "content/public/browser/web_contents_observer.h" 26#include "content/public/browser/web_contents_view.h" 27#include "content/public/test/test_utils.h" 28#include "grit/webui_resources.h" 29#include "net/base/net_util.h" 30#include "net/cookies/cookie_store.h" 31#include "net/test/python_utils.h" 32#include "net/url_request/url_request_context.h" 33#include "net/url_request/url_request_context_getter.h" 34#include "testing/gtest/include/gtest/gtest.h" 35#include "ui/base/resource/resource_bundle.h" 36#include "ui/events/keycodes/dom4/keycode_converter.h" 37 38namespace content { 39namespace { 40 41class DOMOperationObserver : public NotificationObserver, 42 public WebContentsObserver { 43 public: 44 explicit DOMOperationObserver(RenderViewHost* rvh) 45 : WebContentsObserver(WebContents::FromRenderViewHost(rvh)), 46 did_respond_(false) { 47 registrar_.Add(this, NOTIFICATION_DOM_OPERATION_RESPONSE, 48 Source<WebContents>(web_contents())); 49 message_loop_runner_ = new MessageLoopRunner; 50 } 51 52 virtual void Observe(int type, 53 const NotificationSource& source, 54 const NotificationDetails& details) OVERRIDE { 55 DCHECK(type == NOTIFICATION_DOM_OPERATION_RESPONSE); 56 Details<DomOperationNotificationDetails> dom_op_details(details); 57 response_ = dom_op_details->json; 58 did_respond_ = true; 59 message_loop_runner_->Quit(); 60 } 61 62 // Overridden from WebContentsObserver: 63 virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE { 64 message_loop_runner_->Quit(); 65 } 66 67 bool WaitAndGetResponse(std::string* response) WARN_UNUSED_RESULT { 68 message_loop_runner_->Run(); 69 *response = response_; 70 return did_respond_; 71 } 72 73 private: 74 NotificationRegistrar registrar_; 75 std::string response_; 76 bool did_respond_; 77 scoped_refptr<MessageLoopRunner> message_loop_runner_; 78 79 DISALLOW_COPY_AND_ASSIGN(DOMOperationObserver); 80}; 81 82// Specifying a prototype so that we can add the WARN_UNUSED_RESULT attribute. 83bool ExecuteScriptInFrameHelper( 84 RenderViewHost* render_view_host, 85 const std::string& frame_xpath, 86 const std::string& original_script, 87 scoped_ptr<base::Value>* result) WARN_UNUSED_RESULT; 88 89// Specifying a prototype so that we can add the WARN_UNUSED_RESULT attribute. 90bool ExecuteScriptHelper( 91 RenderFrameHost* render_frame_host, 92 const std::string& original_script, 93 scoped_ptr<base::Value>* result) WARN_UNUSED_RESULT; 94 95// Executes the passed |original_script| in the frame pointed to by 96// |frame_xpath|. If |result| is not NULL, stores the value that the evaluation 97// of the script in |result|. Returns true on success. 98bool ExecuteScriptInFrameHelper(RenderViewHost* render_view_host, 99 const std::string& frame_xpath, 100 const std::string& original_script, 101 scoped_ptr<base::Value>* result) { 102 // TODO(jcampan): we should make the domAutomationController not require an 103 // automation id. 104 std::string script = 105 "window.domAutomationController.setAutomationId(0);" + original_script; 106 DOMOperationObserver dom_op_observer(render_view_host); 107 render_view_host->ExecuteJavascriptInWebFrame(base::UTF8ToUTF16(frame_xpath), 108 base::UTF8ToUTF16(script)); 109 std::string json; 110 if (!dom_op_observer.WaitAndGetResponse(&json)) { 111 DLOG(ERROR) << "Cannot communicate with DOMOperationObserver."; 112 return false; 113 } 114 115 // Nothing more to do for callers that ignore the returned JS value. 116 if (!result) 117 return true; 118 119 base::JSONReader reader(base::JSON_ALLOW_TRAILING_COMMAS); 120 result->reset(reader.ReadToValue(json)); 121 if (!result->get()) { 122 DLOG(ERROR) << reader.GetErrorMessage(); 123 return false; 124 } 125 126 return true; 127} 128 129// Executes the passed |original_script| in the frame specified by 130// |render_frame_host|. If |result| is not NULL, stores the value that the 131// evaluation of the script in |result|. Returns true on success. 132bool ExecuteScriptHelper(RenderFrameHost* render_frame_host, 133 const std::string& original_script, 134 scoped_ptr<base::Value>* result) { 135 // TODO(jcampan): we should make the domAutomationController not require an 136 // automation id. 137 std::string script = 138 "window.domAutomationController.setAutomationId(0);" + original_script; 139 DOMOperationObserver dom_op_observer(render_frame_host->GetRenderViewHost()); 140 render_frame_host->ExecuteJavaScript(base::UTF8ToUTF16(script)); 141 std::string json; 142 if (!dom_op_observer.WaitAndGetResponse(&json)) { 143 DLOG(ERROR) << "Cannot communicate with DOMOperationObserver."; 144 return false; 145 } 146 147 // Nothing more to do for callers that ignore the returned JS value. 148 if (!result) 149 return true; 150 151 base::JSONReader reader(base::JSON_ALLOW_TRAILING_COMMAS); 152 result->reset(reader.ReadToValue(json)); 153 if (!result->get()) { 154 DLOG(ERROR) << reader.GetErrorMessage(); 155 return false; 156 } 157 158 return true; 159} 160 161void BuildSimpleWebKeyEvent(blink::WebInputEvent::Type type, 162 ui::KeyboardCode key_code, 163 int native_key_code, 164 int modifiers, 165 NativeWebKeyboardEvent* event) { 166 event->nativeKeyCode = native_key_code; 167 event->windowsKeyCode = key_code; 168 event->setKeyIdentifierFromWindowsKeyCode(); 169 event->type = type; 170 event->modifiers = modifiers; 171 event->isSystemKey = false; 172 event->timeStampSeconds = base::Time::Now().ToDoubleT(); 173 event->skip_in_browser = true; 174 175 if (type == blink::WebInputEvent::Char || 176 type == blink::WebInputEvent::RawKeyDown) { 177 event->text[0] = key_code; 178 event->unmodifiedText[0] = key_code; 179 } 180} 181 182void InjectRawKeyEvent(WebContents* web_contents, 183 blink::WebInputEvent::Type type, 184 ui::KeyboardCode key_code, 185 int native_key_code, 186 int modifiers) { 187 NativeWebKeyboardEvent event; 188 BuildSimpleWebKeyEvent(type, key_code, native_key_code, modifiers, &event); 189 web_contents->GetRenderViewHost()->ForwardKeyboardEvent(event); 190} 191 192void GetCookiesCallback(std::string* cookies_out, 193 base::WaitableEvent* event, 194 const std::string& cookies) { 195 *cookies_out = cookies; 196 event->Signal(); 197} 198 199void GetCookiesOnIOThread(const GURL& url, 200 net::URLRequestContextGetter* context_getter, 201 base::WaitableEvent* event, 202 std::string* cookies) { 203 net::CookieStore* cookie_store = 204 context_getter->GetURLRequestContext()->cookie_store(); 205 cookie_store->GetCookiesWithOptionsAsync( 206 url, net::CookieOptions(), 207 base::Bind(&GetCookiesCallback, cookies, event)); 208} 209 210void SetCookieCallback(bool* result, 211 base::WaitableEvent* event, 212 bool success) { 213 *result = success; 214 event->Signal(); 215} 216 217void SetCookieOnIOThread(const GURL& url, 218 const std::string& value, 219 net::URLRequestContextGetter* context_getter, 220 base::WaitableEvent* event, 221 bool* result) { 222 net::CookieStore* cookie_store = 223 context_getter->GetURLRequestContext()->cookie_store(); 224 cookie_store->SetCookieWithOptionsAsync( 225 url, value, net::CookieOptions(), 226 base::Bind(&SetCookieCallback, result, event)); 227} 228 229} // namespace 230 231 232GURL GetFileUrlWithQuery(const base::FilePath& path, 233 const std::string& query_string) { 234 GURL url = net::FilePathToFileURL(path); 235 if (!query_string.empty()) { 236 GURL::Replacements replacements; 237 replacements.SetQueryStr(query_string); 238 return url.ReplaceComponents(replacements); 239 } 240 return url; 241} 242 243void WaitForLoadStop(WebContents* web_contents) { 244 WindowedNotificationObserver load_stop_observer( 245 NOTIFICATION_LOAD_STOP, 246 Source<NavigationController>(&web_contents->GetController())); 247 // In many cases, the load may have finished before we get here. Only wait if 248 // the tab still has a pending navigation. 249 if (!web_contents->IsLoading()) 250 return; 251 load_stop_observer.Wait(); 252} 253 254void CrashTab(WebContents* web_contents) { 255 RenderProcessHost* rph = web_contents->GetRenderProcessHost(); 256 RenderProcessHostWatcher watcher( 257 rph, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); 258 base::KillProcess(rph->GetHandle(), 0, false); 259 watcher.Wait(); 260} 261 262void SimulateMouseClick(WebContents* web_contents, 263 int modifiers, 264 blink::WebMouseEvent::Button button) { 265 int x = web_contents->GetView()->GetContainerSize().width() / 2; 266 int y = web_contents->GetView()->GetContainerSize().height() / 2; 267 SimulateMouseClickAt(web_contents, modifiers, button, gfx::Point(x, y)); 268} 269 270void SimulateMouseClickAt(WebContents* web_contents, 271 int modifiers, 272 blink::WebMouseEvent::Button button, 273 const gfx::Point& point) { 274 blink::WebMouseEvent mouse_event; 275 mouse_event.type = blink::WebInputEvent::MouseDown; 276 mouse_event.button = button; 277 mouse_event.x = point.x(); 278 mouse_event.y = point.y(); 279 mouse_event.modifiers = modifiers; 280 // Mac needs globalX/globalY for events to plugins. 281 gfx::Rect offset; 282 web_contents->GetView()->GetContainerBounds(&offset); 283 mouse_event.globalX = point.x() + offset.x(); 284 mouse_event.globalY = point.y() + offset.y(); 285 mouse_event.clickCount = 1; 286 web_contents->GetRenderViewHost()->ForwardMouseEvent(mouse_event); 287 mouse_event.type = blink::WebInputEvent::MouseUp; 288 web_contents->GetRenderViewHost()->ForwardMouseEvent(mouse_event); 289} 290 291void SimulateMouseEvent(WebContents* web_contents, 292 blink::WebInputEvent::Type type, 293 const gfx::Point& point) { 294 blink::WebMouseEvent mouse_event; 295 mouse_event.type = type; 296 mouse_event.x = point.x(); 297 mouse_event.y = point.y(); 298 web_contents->GetRenderViewHost()->ForwardMouseEvent(mouse_event); 299} 300 301void SimulateKeyPress(WebContents* web_contents, 302 ui::KeyboardCode key_code, 303 bool control, 304 bool shift, 305 bool alt, 306 bool command) { 307 SimulateKeyPressWithCode( 308 web_contents, key_code, NULL, control, shift, alt, command); 309} 310 311void SimulateKeyPressWithCode(WebContents* web_contents, 312 ui::KeyboardCode key_code, 313 const char* code, 314 bool control, 315 bool shift, 316 bool alt, 317 bool command) { 318 ui::KeycodeConverter* key_converter = ui::KeycodeConverter::GetInstance(); 319 int native_key_code = key_converter->CodeToNativeKeycode(code); 320 321 int modifiers = 0; 322 323 // The order of these key down events shouldn't matter for our simulation. 324 // For our simulation we can use either the left keys or the right keys. 325 if (control) { 326 modifiers |= blink::WebInputEvent::ControlKey; 327 InjectRawKeyEvent( 328 web_contents, 329 blink::WebInputEvent::RawKeyDown, 330 ui::VKEY_CONTROL, 331 key_converter->CodeToNativeKeycode("ControlLeft"), 332 modifiers); 333 } 334 335 if (shift) { 336 modifiers |= blink::WebInputEvent::ShiftKey; 337 InjectRawKeyEvent( 338 web_contents, 339 blink::WebInputEvent::RawKeyDown, 340 ui::VKEY_SHIFT, 341 key_converter->CodeToNativeKeycode("ShiftLeft"), 342 modifiers); 343 } 344 345 if (alt) { 346 modifiers |= blink::WebInputEvent::AltKey; 347 InjectRawKeyEvent( 348 web_contents, 349 blink::WebInputEvent::RawKeyDown, 350 ui::VKEY_MENU, 351 key_converter->CodeToNativeKeycode("AltLeft"), 352 modifiers); 353 } 354 355 if (command) { 356 modifiers |= blink::WebInputEvent::MetaKey; 357 InjectRawKeyEvent( 358 web_contents, 359 blink::WebInputEvent::RawKeyDown, 360 ui::VKEY_COMMAND, 361 key_converter->CodeToNativeKeycode("OSLeft"), 362 modifiers); 363 } 364 365 InjectRawKeyEvent( 366 web_contents, 367 blink::WebInputEvent::RawKeyDown, 368 key_code, 369 native_key_code, 370 modifiers); 371 372 InjectRawKeyEvent( 373 web_contents, 374 blink::WebInputEvent::Char, 375 key_code, 376 native_key_code, 377 modifiers); 378 379 InjectRawKeyEvent( 380 web_contents, 381 blink::WebInputEvent::KeyUp, 382 key_code, 383 native_key_code, 384 modifiers); 385 386 // The order of these key releases shouldn't matter for our simulation. 387 if (control) { 388 modifiers &= ~blink::WebInputEvent::ControlKey; 389 InjectRawKeyEvent( 390 web_contents, 391 blink::WebInputEvent::KeyUp, 392 ui::VKEY_CONTROL, 393 key_converter->CodeToNativeKeycode("ControlLeft"), 394 modifiers); 395 } 396 397 if (shift) { 398 modifiers &= ~blink::WebInputEvent::ShiftKey; 399 InjectRawKeyEvent( 400 web_contents, 401 blink::WebInputEvent::KeyUp, 402 ui::VKEY_SHIFT, 403 key_converter->CodeToNativeKeycode("ShiftLeft"), 404 modifiers); 405 } 406 407 if (alt) { 408 modifiers &= ~blink::WebInputEvent::AltKey; 409 InjectRawKeyEvent( 410 web_contents, 411 blink::WebInputEvent::KeyUp, 412 ui::VKEY_MENU, 413 key_converter->CodeToNativeKeycode("AltLeft"), 414 modifiers); 415 } 416 417 if (command) { 418 modifiers &= ~blink::WebInputEvent::MetaKey; 419 InjectRawKeyEvent( 420 web_contents, 421 blink::WebInputEvent::KeyUp, 422 ui::VKEY_COMMAND, 423 key_converter->CodeToNativeKeycode("OSLeft"), 424 modifiers); 425 } 426 427 ASSERT_EQ(modifiers, 0); 428} 429 430namespace internal { 431 432ToRenderViewHost::ToRenderViewHost(WebContents* web_contents) 433 : render_view_host_(web_contents->GetRenderViewHost()) { 434} 435 436ToRenderViewHost::ToRenderViewHost(RenderViewHost* render_view_host) 437 : render_view_host_(render_view_host) { 438} 439 440ToRenderFrameHost::ToRenderFrameHost(WebContents* web_contents) 441 : render_frame_host_(web_contents->GetMainFrame()) { 442} 443 444ToRenderFrameHost::ToRenderFrameHost(RenderViewHost* render_view_host) 445 : render_frame_host_(render_view_host->GetMainFrame()) { 446} 447 448ToRenderFrameHost::ToRenderFrameHost(RenderFrameHost* render_frame_host) 449 : render_frame_host_(render_frame_host) { 450} 451 452} // namespace internal 453 454bool ExecuteScriptInFrame(const internal::ToRenderViewHost& adapter, 455 const std::string& frame_xpath, 456 const std::string& original_script) { 457 std::string script = 458 original_script + ";window.domAutomationController.send(0);"; 459 return ExecuteScriptInFrameHelper( 460 adapter.render_view_host(), frame_xpath, script, NULL); 461} 462 463bool ExecuteScriptInFrameAndExtractInt( 464 const internal::ToRenderViewHost& adapter, 465 const std::string& frame_xpath, 466 const std::string& script, 467 int* result) { 468 DCHECK(result); 469 scoped_ptr<base::Value> value; 470 if (!ExecuteScriptInFrameHelper(adapter.render_view_host(), 471 frame_xpath, script, &value) || 472 !value.get()) { 473 return false; 474 } 475 476 return value->GetAsInteger(result); 477} 478 479bool ExecuteScriptInFrameAndExtractBool( 480 const internal::ToRenderViewHost& adapter, 481 const std::string& frame_xpath, 482 const std::string& script, 483 bool* result) { 484 DCHECK(result); 485 scoped_ptr<base::Value> value; 486 if (!ExecuteScriptInFrameHelper(adapter.render_view_host(), 487 frame_xpath, script, &value) || 488 !value.get()) { 489 return false; 490 } 491 492 return value->GetAsBoolean(result); 493} 494 495bool ExecuteScriptInFrameAndExtractString( 496 const internal::ToRenderViewHost& adapter, 497 const std::string& frame_xpath, 498 const std::string& script, 499 std::string* result) { 500 DCHECK(result); 501 scoped_ptr<base::Value> value; 502 if (!ExecuteScriptInFrameHelper(adapter.render_view_host(), 503 frame_xpath, script, &value) || 504 !value.get()) { 505 return false; 506 } 507 508 return value->GetAsString(result); 509} 510 511bool ExecuteScript(const internal::ToRenderFrameHost& adapter, 512 const std::string& script) { 513 std::string new_script = 514 script + ";window.domAutomationController.send(0);"; 515 return ExecuteScriptHelper(adapter.render_frame_host(), new_script, NULL); 516} 517 518bool ExecuteScriptAndExtractInt(const internal::ToRenderFrameHost& adapter, 519 const std::string& script, int* result) { 520 DCHECK(result); 521 scoped_ptr<base::Value> value; 522 if (!ExecuteScriptHelper(adapter.render_frame_host(), script, &value) || 523 !value.get()) { 524 return false; 525 } 526 527 return value->GetAsInteger(result); 528} 529 530bool ExecuteScriptAndExtractBool(const internal::ToRenderFrameHost& adapter, 531 const std::string& script, bool* result) { 532 DCHECK(result); 533 scoped_ptr<base::Value> value; 534 if (!ExecuteScriptHelper(adapter.render_frame_host(), script, &value) || 535 !value.get()) { 536 return false; 537 } 538 539 return value->GetAsBoolean(result); 540} 541 542bool ExecuteScriptAndExtractString(const internal::ToRenderFrameHost& adapter, 543 const std::string& script, 544 std::string* result) { 545 DCHECK(result); 546 scoped_ptr<base::Value> value; 547 if (!ExecuteScriptHelper(adapter.render_frame_host(), script, &value) || 548 !value.get()) { 549 return false; 550 } 551 552 return value->GetAsString(result); 553} 554 555namespace { 556void AddToSetIfFrameMatchesPredicate( 557 std::set<RenderFrameHost*>* frame_set, 558 const base::Callback<bool(RenderFrameHost*)>& predicate, 559 RenderFrameHost* host) { 560 if (predicate.Run(host)) 561 frame_set->insert(host); 562} 563} 564 565RenderFrameHost* FrameMatchingPredicate( 566 WebContents* web_contents, 567 const base::Callback<bool(RenderFrameHost*)>& predicate) { 568 std::set<RenderFrameHost*> frame_set; 569 web_contents->ForEachFrame( 570 base::Bind(&AddToSetIfFrameMatchesPredicate, &frame_set, predicate)); 571 DCHECK_EQ(1U, frame_set.size()); 572 return *frame_set.begin(); 573} 574 575bool FrameMatchesName(const std::string& name, RenderFrameHost* frame) { 576 return frame->GetFrameName() == name; 577} 578 579bool FrameIsChildOfMainFrame(RenderFrameHost* frame) { 580 return frame->GetParent() && !frame->GetParent()->GetParent(); 581} 582 583bool FrameHasSourceUrl(const GURL& url, RenderFrameHost* frame) { 584 return frame->GetLastCommittedURL() == url; 585} 586 587bool ExecuteWebUIResourceTest(WebContents* web_contents, 588 const std::vector<int>& js_resource_ids) { 589 // Inject WebUI test runner script first prior to other scripts required to 590 // run the test as scripts may depend on it being declared. 591 std::vector<int> ids; 592 ids.push_back(IDR_WEBUI_JS_WEBUI_RESOURCE_TEST); 593 ids.insert(ids.end(), js_resource_ids.begin(), js_resource_ids.end()); 594 595 std::string script; 596 for (std::vector<int>::iterator iter = ids.begin(); 597 iter != ids.end(); 598 ++iter) { 599 ResourceBundle::GetSharedInstance().GetRawDataResource(*iter) 600 .AppendToString(&script); 601 script.append("\n"); 602 } 603 if (!ExecuteScript(web_contents, script)) 604 return false; 605 606 DOMMessageQueue message_queue; 607 if (!ExecuteScript(web_contents, "runTests()")) 608 return false; 609 610 std::string message; 611 do { 612 if (!message_queue.WaitForMessage(&message)) 613 return false; 614 } while (message.compare("\"PENDING\"") == 0); 615 616 return message.compare("\"SUCCESS\"") == 0; 617} 618 619std::string GetCookies(BrowserContext* browser_context, const GURL& url) { 620 std::string cookies; 621 base::WaitableEvent event(true, false); 622 net::URLRequestContextGetter* context_getter = 623 browser_context->GetRequestContext(); 624 625 BrowserThread::PostTask( 626 BrowserThread::IO, FROM_HERE, 627 base::Bind(&GetCookiesOnIOThread, url, 628 make_scoped_refptr(context_getter), &event, &cookies)); 629 event.Wait(); 630 return cookies; 631} 632 633bool SetCookie(BrowserContext* browser_context, 634 const GURL& url, 635 const std::string& value) { 636 bool result = false; 637 base::WaitableEvent event(true, false); 638 net::URLRequestContextGetter* context_getter = 639 browser_context->GetRequestContext(); 640 641 BrowserThread::PostTask( 642 BrowserThread::IO, FROM_HERE, 643 base::Bind(&SetCookieOnIOThread, url, value, 644 make_scoped_refptr(context_getter), &event, &result)); 645 event.Wait(); 646 return result; 647} 648 649TitleWatcher::TitleWatcher(WebContents* web_contents, 650 const base::string16& expected_title) 651 : WebContentsObserver(web_contents), 652 message_loop_runner_(new MessageLoopRunner) { 653 EXPECT_TRUE(web_contents != NULL); 654 expected_titles_.push_back(expected_title); 655} 656 657void TitleWatcher::AlsoWaitForTitle(const base::string16& expected_title) { 658 expected_titles_.push_back(expected_title); 659} 660 661TitleWatcher::~TitleWatcher() { 662} 663 664const base::string16& TitleWatcher::WaitAndGetTitle() { 665 TestTitle(); 666 message_loop_runner_->Run(); 667 return observed_title_; 668} 669 670void TitleWatcher::DidStopLoading(RenderViewHost* render_view_host) { 671 // When navigating through the history, the restored NavigationEntry's title 672 // will be used. If the entry ends up having the same title after we return 673 // to it, as will usually be the case, then WebContentsObserver::TitleSet 674 // will then be suppressed, since the NavigationEntry's title hasn't changed. 675 TestTitle(); 676} 677 678void TitleWatcher::TitleWasSet(NavigationEntry* entry, bool explicit_set) { 679 TestTitle(); 680} 681 682void TitleWatcher::TestTitle() { 683 std::vector<base::string16>::const_iterator it = 684 std::find(expected_titles_.begin(), 685 expected_titles_.end(), 686 web_contents()->GetTitle()); 687 if (it == expected_titles_.end()) 688 return; 689 690 observed_title_ = *it; 691 message_loop_runner_->Quit(); 692} 693 694WebContentsDestroyedWatcher::WebContentsDestroyedWatcher( 695 WebContents* web_contents) 696 : WebContentsObserver(web_contents), 697 message_loop_runner_(new MessageLoopRunner) { 698 EXPECT_TRUE(web_contents != NULL); 699} 700 701WebContentsDestroyedWatcher::~WebContentsDestroyedWatcher() { 702} 703 704void WebContentsDestroyedWatcher::Wait() { 705 message_loop_runner_->Run(); 706} 707 708void WebContentsDestroyedWatcher::WebContentsDestroyed( 709 WebContents* web_contents) { 710 message_loop_runner_->Quit(); 711} 712 713RenderProcessHostWatcher::RenderProcessHostWatcher( 714 RenderProcessHost* render_process_host, WatchType type) 715 : render_process_host_(render_process_host), 716 type_(type), 717 message_loop_runner_(new MessageLoopRunner) { 718 render_process_host_->AddObserver(this); 719} 720 721RenderProcessHostWatcher::RenderProcessHostWatcher( 722 WebContents* web_contents, WatchType type) 723 : render_process_host_(web_contents->GetRenderProcessHost()), 724 type_(type), 725 message_loop_runner_(new MessageLoopRunner) { 726 render_process_host_->AddObserver(this); 727} 728 729RenderProcessHostWatcher::~RenderProcessHostWatcher() { 730 if (render_process_host_) 731 render_process_host_->RemoveObserver(this); 732} 733 734void RenderProcessHostWatcher::Wait() { 735 message_loop_runner_->Run(); 736} 737 738void RenderProcessHostWatcher::RenderProcessExited( 739 RenderProcessHost* host, 740 base::ProcessHandle handle, 741 base::TerminationStatus status, 742 int exit_code) { 743 if (type_ == WATCH_FOR_PROCESS_EXIT) 744 message_loop_runner_->Quit(); 745} 746 747void RenderProcessHostWatcher::RenderProcessHostDestroyed( 748 RenderProcessHost* host) { 749 render_process_host_ = NULL; 750 if (type_ == WATCH_FOR_HOST_DESTRUCTION) 751 message_loop_runner_->Quit(); 752} 753 754DOMMessageQueue::DOMMessageQueue() : waiting_for_message_(false) { 755 registrar_.Add(this, NOTIFICATION_DOM_OPERATION_RESPONSE, 756 NotificationService::AllSources()); 757} 758 759DOMMessageQueue::~DOMMessageQueue() {} 760 761void DOMMessageQueue::Observe(int type, 762 const NotificationSource& source, 763 const NotificationDetails& details) { 764 Details<DomOperationNotificationDetails> dom_op_details(details); 765 Source<RenderViewHost> sender(source); 766 message_queue_.push(dom_op_details->json); 767 if (waiting_for_message_) { 768 waiting_for_message_ = false; 769 message_loop_runner_->Quit(); 770 } 771} 772 773void DOMMessageQueue::ClearQueue() { 774 message_queue_ = std::queue<std::string>(); 775} 776 777bool DOMMessageQueue::WaitForMessage(std::string* message) { 778 if (message_queue_.empty()) { 779 waiting_for_message_ = true; 780 // This will be quit when a new message comes in. 781 message_loop_runner_ = new MessageLoopRunner; 782 message_loop_runner_->Run(); 783 } 784 // The queue should not be empty, unless we were quit because of a timeout. 785 if (message_queue_.empty()) 786 return false; 787 if (message) 788 *message = message_queue_.front(); 789 message_queue_.pop(); 790 return true; 791} 792 793} // namespace content 794