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