Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / public / test / test_utils.cc
blob53d5055dc3c7a1014a6dae02680d7014ad17b6df
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/public/test/test_utils.h"
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"
20 namespace content {
22 namespace {
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;
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));
46 void RunAllPendingMessageAndSendQuit(BrowserThread::ID thread_id,
47 const base::Closure& quit_task) {
48 RunAllPendingInMessageLoop();
49 BrowserThread::PostTask(thread_id, FROM_HERE, quit_task);
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);
59 scoped_ptr<base::Value> result() { return result_.Pass(); }
61 private:
62 scoped_ptr<base::Value> result_;
64 DISALLOW_COPY_AND_ASSIGN(ScriptCallback);
67 void ScriptCallback::ResultCallback(const base::Value* result) {
68 if (result)
69 result_.reset(result->DeepCopy());
70 base::MessageLoop::current()->Quit();
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 virtual ~TaskObserver() {}
79 // MessageLoop::TaskObserver overrides.
80 virtual void WillProcessTask(const base::PendingTask& pending_task) OVERRIDE {
82 virtual void DidProcessTask(const base::PendingTask& pending_task) OVERRIDE {
83 processed_ = true;
86 // Returns true if any task was processed.
87 bool processed() const { return processed_; }
89 private:
90 bool processed_;
91 DISALLOW_COPY_AND_ASSIGN(TaskObserver);
94 // Adapter that makes a WindowedNotificationObserver::ConditionTestCallback from
95 // a WindowedNotificationObserver::ConditionTestCallbackWithoutSourceAndDetails
96 // by ignoring the notification source and details.
97 bool IgnoreSourceAndDetails(
98 const WindowedNotificationObserver::
99 ConditionTestCallbackWithoutSourceAndDetails& callback,
100 const NotificationSource& source,
101 const NotificationDetails& details) {
102 return callback.Run();
105 } // namespace
107 void RunMessageLoop() {
108 base::RunLoop run_loop;
109 RunThisRunLoop(&run_loop);
112 void RunThisRunLoop(base::RunLoop* run_loop) {
113 base::MessageLoop::ScopedNestableTaskAllower allow(
114 base::MessageLoop::current());
116 // If we're running inside a browser test, we might need to allow the test
117 // launcher to do extra work before/after running a nested message loop.
118 TestLauncherDelegate* delegate = NULL;
119 #if !defined(OS_IOS)
120 delegate = GetCurrentTestLauncherDelegate();
121 #endif
122 if (delegate)
123 delegate->PreRunMessageLoop(run_loop);
124 run_loop->Run();
125 if (delegate)
126 delegate->PostRunMessageLoop();
129 void RunAllPendingInMessageLoop() {
130 base::MessageLoop::current()->PostTask(
131 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
132 RunMessageLoop();
135 void RunAllPendingInMessageLoop(BrowserThread::ID thread_id) {
136 if (BrowserThread::CurrentlyOn(thread_id)) {
137 RunAllPendingInMessageLoop();
138 return;
140 BrowserThread::ID current_thread_id;
141 if (!BrowserThread::GetCurrentThreadIdentifier(&current_thread_id)) {
142 NOTREACHED();
143 return;
146 base::RunLoop run_loop;
147 BrowserThread::PostTask(thread_id, FROM_HERE,
148 base::Bind(&RunAllPendingMessageAndSendQuit, current_thread_id,
149 run_loop.QuitClosure()));
150 RunThisRunLoop(&run_loop);
153 void RunAllBlockingPoolTasksUntilIdle() {
154 while (true) {
155 content::BrowserThread::GetBlockingPool()->FlushForTesting();
157 TaskObserver task_observer;
158 base::MessageLoop::current()->AddTaskObserver(&task_observer);
159 base::RunLoop().RunUntilIdle();
160 base::MessageLoop::current()->RemoveTaskObserver(&task_observer);
162 if (!task_observer.processed())
163 break;
167 base::Closure GetQuitTaskForRunLoop(base::RunLoop* run_loop) {
168 return base::Bind(&DeferredQuitRunLoop, run_loop->QuitClosure(),
169 kNumQuitDeferrals);
172 scoped_ptr<base::Value> ExecuteScriptAndGetValue(
173 RenderFrameHost* render_frame_host, const std::string& script) {
174 ScriptCallback observer;
176 render_frame_host->ExecuteJavaScript(
177 base::UTF8ToUTF16(script),
178 base::Bind(&ScriptCallback::ResultCallback, base::Unretained(&observer)));
179 base::MessageLoop* loop = base::MessageLoop::current();
180 loop->Run();
181 return observer.result().Pass();
184 MessageLoopRunner::MessageLoopRunner()
185 : loop_running_(false),
186 quit_closure_called_(false) {
189 MessageLoopRunner::~MessageLoopRunner() {
192 void MessageLoopRunner::Run() {
193 // Do not run the message loop if our quit closure has already been called.
194 // This helps in scenarios where the closure has a chance to run before
195 // we Run explicitly.
196 if (quit_closure_called_)
197 return;
199 loop_running_ = true;
200 RunThisRunLoop(&run_loop_);
203 base::Closure MessageLoopRunner::QuitClosure() {
204 return base::Bind(&MessageLoopRunner::Quit, this);
207 void MessageLoopRunner::Quit() {
208 quit_closure_called_ = true;
210 // Only run the quit task if we are running the message loop.
211 if (loop_running_) {
212 GetQuitTaskForRunLoop(&run_loop_).Run();
213 loop_running_ = false;
217 WindowedNotificationObserver::WindowedNotificationObserver(
218 int notification_type,
219 const NotificationSource& source)
220 : seen_(false),
221 running_(false),
222 source_(NotificationService::AllSources()) {
223 AddNotificationType(notification_type, source);
226 WindowedNotificationObserver::WindowedNotificationObserver(
227 int notification_type,
228 const ConditionTestCallback& callback)
229 : seen_(false),
230 running_(false),
231 callback_(callback),
232 source_(NotificationService::AllSources()) {
233 AddNotificationType(notification_type, source_);
236 WindowedNotificationObserver::WindowedNotificationObserver(
237 int notification_type,
238 const ConditionTestCallbackWithoutSourceAndDetails& callback)
239 : seen_(false),
240 running_(false),
241 callback_(base::Bind(&IgnoreSourceAndDetails, callback)),
242 source_(NotificationService::AllSources()) {
243 registrar_.Add(this, notification_type, source_);
246 WindowedNotificationObserver::~WindowedNotificationObserver() {}
248 void WindowedNotificationObserver::AddNotificationType(
249 int notification_type,
250 const NotificationSource& source) {
251 registrar_.Add(this, notification_type, source);
254 void WindowedNotificationObserver::Wait() {
255 if (seen_)
256 return;
258 running_ = true;
259 message_loop_runner_ = new MessageLoopRunner;
260 message_loop_runner_->Run();
261 EXPECT_TRUE(seen_);
264 void WindowedNotificationObserver::Observe(
265 int type,
266 const NotificationSource& source,
267 const NotificationDetails& details) {
268 source_ = source;
269 details_ = details;
270 if (!callback_.is_null() && !callback_.Run(source, details))
271 return;
273 seen_ = true;
274 if (!running_)
275 return;
277 message_loop_runner_->Quit();
278 running_ = false;
281 InProcessUtilityThreadHelper::InProcessUtilityThreadHelper()
282 : child_thread_count_(0) {
283 RenderProcessHost::SetRunRendererInProcess(true);
284 BrowserChildProcessObserver::Add(this);
287 InProcessUtilityThreadHelper::~InProcessUtilityThreadHelper() {
288 if (child_thread_count_) {
289 DCHECK(BrowserThread::IsMessageLoopValid(BrowserThread::UI));
290 DCHECK(BrowserThread::IsMessageLoopValid(BrowserThread::IO));
291 runner_ = new MessageLoopRunner;
292 runner_->Run();
294 BrowserChildProcessObserver::Remove(this);
295 RenderProcessHost::SetRunRendererInProcess(false);
298 void InProcessUtilityThreadHelper::BrowserChildProcessHostConnected(
299 const ChildProcessData& data) {
300 child_thread_count_++;
303 void InProcessUtilityThreadHelper::BrowserChildProcessHostDisconnected(
304 const ChildProcessData& data) {
305 if (--child_thread_count_)
306 return;
308 if (runner_.get())
309 runner_->Quit();
312 } // namespace content