Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / content / public / test / 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/test_utils.h"
6
7 #include "base/bind.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/run_loop.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/values.h"
12 #include "content/public/browser/browser_child_process_host_iterator.h"
13 #include "content/public/browser/notification_service.h"
14 #include "content/public/browser/render_frame_host.h"
15 #include "content/public/browser/render_process_host.h"
16 #include "content/public/common/process_type.h"
17 #include "content/public/test/test_launcher.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19
20 namespace content {
21
22 namespace {
23
24 // Number of times to repost a Quit task so that the MessageLoop finishes up
25 // pending tasks and tasks posted by those pending tasks without risking the
26 // potential hang behavior of MessageLoop::QuitWhenIdle.
27 // The criteria for choosing this number: it should be high enough to make the
28 // quit act like QuitWhenIdle, while taking into account that any page which is
29 // animating may be rendering another frame for each quit deferral. For an
30 // animating page, the potential delay to quitting the RunLoop would be
31 // kNumQuitDeferrals * frame_render_time. Some perf tests run slow, such as
32 // 200ms/frame.
33 static const int kNumQuitDeferrals = 10;
34
35 static void DeferredQuitRunLoop(const base::Closure& quit_task,
36                                 int num_quit_deferrals) {
37   if (num_quit_deferrals <= 0) {
38     quit_task.Run();
39   } else {
40     base::MessageLoop::current()->PostTask(
41         FROM_HERE,
42         base::Bind(&DeferredQuitRunLoop, quit_task, num_quit_deferrals - 1));
43   }
44 }
45
46 void RunAllPendingMessageAndSendQuit(BrowserThread::ID thread_id,
47                                      const base::Closure& quit_task) {
48   RunAllPendingInMessageLoop();
49   BrowserThread::PostTask(thread_id, FROM_HERE, quit_task);
50 }
51
52 // Class used to handle result callbacks for ExecuteScriptAndGetValue.
53 class ScriptCallback {
54  public:
55   ScriptCallback() { }
56   virtual ~ScriptCallback() { }
57   void ResultCallback(const base::Value* result);
58
59   scoped_ptr<base::Value> result() { return result_.Pass(); }
60
61  private:
62   scoped_ptr<base::Value> result_;
63
64   DISALLOW_COPY_AND_ASSIGN(ScriptCallback);
65 };
66
67 void ScriptCallback::ResultCallback(const base::Value* result) {
68   if (result)
69     result_.reset(result->DeepCopy());
70   base::MessageLoop::current()->Quit();
71 }
72
73 // Monitors if any task is processed by the message loop.
74 class TaskObserver : public base::MessageLoop::TaskObserver {
75  public:
76   TaskObserver() : processed_(false) {}
77   ~TaskObserver() override {}
78
79   // MessageLoop::TaskObserver overrides.
80   void WillProcessTask(const base::PendingTask& pending_task) override {}
81   void DidProcessTask(const base::PendingTask& pending_task) override {
82     processed_ = true;
83   }
84
85   // Returns true if any task was processed.
86   bool processed() const { return processed_; }
87
88  private:
89   bool processed_;
90   DISALLOW_COPY_AND_ASSIGN(TaskObserver);
91 };
92
93 // Adapter that makes a WindowedNotificationObserver::ConditionTestCallback from
94 // a WindowedNotificationObserver::ConditionTestCallbackWithoutSourceAndDetails
95 // by ignoring the notification source and details.
96 bool IgnoreSourceAndDetails(
97     const WindowedNotificationObserver::
98         ConditionTestCallbackWithoutSourceAndDetails& callback,
99     const NotificationSource& source,
100     const NotificationDetails& details) {
101   return callback.Run();
102 }
103
104 }  // namespace
105
106 void RunMessageLoop() {
107   base::RunLoop run_loop;
108   RunThisRunLoop(&run_loop);
109 }
110
111 void RunThisRunLoop(base::RunLoop* run_loop) {
112   base::MessageLoop::ScopedNestableTaskAllower allow(
113       base::MessageLoop::current());
114
115   // If we're running inside a browser test, we might need to allow the test
116   // launcher to do extra work before/after running a nested message loop.
117   TestLauncherDelegate* delegate = NULL;
118 #if !defined(OS_IOS)
119   delegate = GetCurrentTestLauncherDelegate();
120 #endif
121   if (delegate)
122     delegate->PreRunMessageLoop(run_loop);
123   run_loop->Run();
124   if (delegate)
125     delegate->PostRunMessageLoop();
126 }
127
128 void RunAllPendingInMessageLoop() {
129   base::MessageLoop::current()->PostTask(
130       FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
131   RunMessageLoop();
132 }
133
134 void RunAllPendingInMessageLoop(BrowserThread::ID thread_id) {
135   if (BrowserThread::CurrentlyOn(thread_id)) {
136     RunAllPendingInMessageLoop();
137     return;
138   }
139   BrowserThread::ID current_thread_id;
140   if (!BrowserThread::GetCurrentThreadIdentifier(&current_thread_id)) {
141     NOTREACHED();
142     return;
143   }
144
145   base::RunLoop run_loop;
146   BrowserThread::PostTask(thread_id, FROM_HERE,
147       base::Bind(&RunAllPendingMessageAndSendQuit, current_thread_id,
148                  run_loop.QuitClosure()));
149   RunThisRunLoop(&run_loop);
150 }
151
152 void RunAllBlockingPoolTasksUntilIdle() {
153   while (true) {
154     content::BrowserThread::GetBlockingPool()->FlushForTesting();
155
156     TaskObserver task_observer;
157     base::MessageLoop::current()->AddTaskObserver(&task_observer);
158     base::RunLoop().RunUntilIdle();
159     base::MessageLoop::current()->RemoveTaskObserver(&task_observer);
160
161     if (!task_observer.processed())
162       break;
163   }
164 }
165
166 base::Closure GetQuitTaskForRunLoop(base::RunLoop* run_loop) {
167   return base::Bind(&DeferredQuitRunLoop, run_loop->QuitClosure(),
168                     kNumQuitDeferrals);
169 }
170
171 scoped_ptr<base::Value> ExecuteScriptAndGetValue(
172     RenderFrameHost* render_frame_host, const std::string& script) {
173   ScriptCallback observer;
174
175   render_frame_host->ExecuteJavaScript(
176       base::UTF8ToUTF16(script),
177       base::Bind(&ScriptCallback::ResultCallback, base::Unretained(&observer)));
178   base::MessageLoop* loop = base::MessageLoop::current();
179   loop->Run();
180   return observer.result().Pass();
181 }
182
183 MessageLoopRunner::MessageLoopRunner()
184     : loop_running_(false),
185       quit_closure_called_(false) {
186 }
187
188 MessageLoopRunner::~MessageLoopRunner() {
189 }
190
191 void MessageLoopRunner::Run() {
192   // Do not run the message loop if our quit closure has already been called.
193   // This helps in scenarios where the closure has a chance to run before
194   // we Run explicitly.
195   if (quit_closure_called_)
196     return;
197
198   loop_running_ = true;
199   RunThisRunLoop(&run_loop_);
200 }
201
202 base::Closure MessageLoopRunner::QuitClosure() {
203   return base::Bind(&MessageLoopRunner::Quit, this);
204 }
205
206 void MessageLoopRunner::Quit() {
207   quit_closure_called_ = true;
208
209   // Only run the quit task if we are running the message loop.
210   if (loop_running_) {
211     GetQuitTaskForRunLoop(&run_loop_).Run();
212     loop_running_ = false;
213   }
214 }
215
216 WindowedNotificationObserver::WindowedNotificationObserver(
217     int notification_type,
218     const NotificationSource& source)
219     : seen_(false),
220       running_(false),
221       source_(NotificationService::AllSources()) {
222   AddNotificationType(notification_type, source);
223 }
224
225 WindowedNotificationObserver::WindowedNotificationObserver(
226     int notification_type,
227     const ConditionTestCallback& callback)
228     : seen_(false),
229       running_(false),
230       callback_(callback),
231       source_(NotificationService::AllSources()) {
232   AddNotificationType(notification_type, source_);
233 }
234
235 WindowedNotificationObserver::WindowedNotificationObserver(
236     int notification_type,
237     const ConditionTestCallbackWithoutSourceAndDetails& callback)
238     : seen_(false),
239       running_(false),
240       callback_(base::Bind(&IgnoreSourceAndDetails, callback)),
241       source_(NotificationService::AllSources()) {
242   registrar_.Add(this, notification_type, source_);
243 }
244
245 WindowedNotificationObserver::~WindowedNotificationObserver() {}
246
247 void WindowedNotificationObserver::AddNotificationType(
248     int notification_type,
249     const NotificationSource& source) {
250   registrar_.Add(this, notification_type, source);
251 }
252
253 void WindowedNotificationObserver::Wait() {
254   if (seen_)
255     return;
256
257   running_ = true;
258   message_loop_runner_ = new MessageLoopRunner;
259   message_loop_runner_->Run();
260   EXPECT_TRUE(seen_);
261 }
262
263 void WindowedNotificationObserver::Observe(
264     int type,
265     const NotificationSource& source,
266     const NotificationDetails& details) {
267   source_ = source;
268   details_ = details;
269   if (!callback_.is_null() && !callback_.Run(source, details))
270     return;
271
272   seen_ = true;
273   if (!running_)
274     return;
275
276   message_loop_runner_->Quit();
277   running_ = false;
278 }
279
280 InProcessUtilityThreadHelper::InProcessUtilityThreadHelper()
281     : child_thread_count_(0) {
282   RenderProcessHost::SetRunRendererInProcess(true);
283   BrowserChildProcessObserver::Add(this);
284 }
285
286 InProcessUtilityThreadHelper::~InProcessUtilityThreadHelper() {
287   if (child_thread_count_) {
288     DCHECK(BrowserThread::IsMessageLoopValid(BrowserThread::UI));
289     DCHECK(BrowserThread::IsMessageLoopValid(BrowserThread::IO));
290     runner_ = new MessageLoopRunner;
291     runner_->Run();
292   }
293   BrowserChildProcessObserver::Remove(this);
294   RenderProcessHost::SetRunRendererInProcess(false);
295 }
296
297 void InProcessUtilityThreadHelper::BrowserChildProcessHostConnected(
298     const ChildProcessData& data) {
299   child_thread_count_++;
300 }
301
302 void InProcessUtilityThreadHelper::BrowserChildProcessHostDisconnected(
303     const ChildProcessData& data) {
304   if (--child_thread_count_)
305     return;
306
307   if (runner_.get())
308     runner_->Quit();
309 }
310
311 }  // namespace content