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