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