test_utils.cc revision 9ab5563a3196760eb381d102cbb2bc0f7abc6a50
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/notification_service.h" 13#include "content/public/browser/render_view_host.h" 14#include "content/public/test/test_launcher.h" 15#include "testing/gtest/include/gtest/gtest.h" 16 17namespace content { 18 19namespace { 20 21// Number of times to repost a Quit task so that the MessageLoop finishes up 22// pending tasks and tasks posted by those pending tasks without risking the 23// potential hang behavior of MessageLoop::QuitWhenIdle. 24// The criteria for choosing this number: it should be high enough to make the 25// quit act like QuitWhenIdle, while taking into account that any page which is 26// animating may be rendering another frame for each quit deferral. For an 27// animating page, the potential delay to quitting the RunLoop would be 28// kNumQuitDeferrals * frame_render_time. Some perf tests run slow, such as 29// 200ms/frame. 30static const int kNumQuitDeferrals = 10; 31 32static void DeferredQuitRunLoop(const base::Closure& quit_task, 33 int num_quit_deferrals) { 34 if (num_quit_deferrals <= 0) { 35 quit_task.Run(); 36 } else { 37 base::MessageLoop::current()->PostTask( 38 FROM_HERE, 39 base::Bind(&DeferredQuitRunLoop, quit_task, num_quit_deferrals - 1)); 40 } 41} 42 43void RunAllPendingMessageAndSendQuit(BrowserThread::ID thread_id, 44 const base::Closure& quit_task) { 45 RunAllPendingInMessageLoop(); 46 BrowserThread::PostTask(thread_id, FROM_HERE, quit_task); 47} 48 49// Class used handle result callbacks for ExecuteScriptAndGetValue. 50class ScriptCallback { 51 public: 52 ScriptCallback() { } 53 virtual ~ScriptCallback() { } 54 void ResultCallback(const base::Value* result); 55 56 scoped_ptr<base::Value> result() { return result_.Pass(); } 57 58 private: 59 scoped_ptr<base::Value> result_; 60 61 DISALLOW_COPY_AND_ASSIGN(ScriptCallback); 62}; 63 64void ScriptCallback::ResultCallback(const base::Value* result) { 65 if (result) 66 result_.reset(result->DeepCopy()); 67 base::MessageLoop::current()->Quit(); 68} 69 70} // namespace 71 72void RunMessageLoop() { 73 base::RunLoop run_loop; 74 RunThisRunLoop(&run_loop); 75} 76 77void RunThisRunLoop(base::RunLoop* run_loop) { 78 base::MessageLoop::ScopedNestableTaskAllower allow( 79 base::MessageLoop::current()); 80 81 // If we're running inside a browser test, we might need to allow the test 82 // launcher to do extra work before/after running a nested message loop. 83 TestLauncherDelegate* delegate = NULL; 84#if !defined(OS_IOS) 85 delegate = GetCurrentTestLauncherDelegate(); 86#endif 87 if (delegate) 88 delegate->PreRunMessageLoop(run_loop); 89 run_loop->Run(); 90 if (delegate) 91 delegate->PostRunMessageLoop(); 92} 93 94void RunAllPendingInMessageLoop() { 95 base::MessageLoop::current()->PostTask( 96 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); 97 RunMessageLoop(); 98} 99 100void RunAllPendingInMessageLoop(BrowserThread::ID thread_id) { 101 if (BrowserThread::CurrentlyOn(thread_id)) { 102 RunAllPendingInMessageLoop(); 103 return; 104 } 105 BrowserThread::ID current_thread_id; 106 if (!BrowserThread::GetCurrentThreadIdentifier(¤t_thread_id)) { 107 NOTREACHED(); 108 return; 109 } 110 111 base::RunLoop run_loop; 112 BrowserThread::PostTask(thread_id, FROM_HERE, 113 base::Bind(&RunAllPendingMessageAndSendQuit, current_thread_id, 114 run_loop.QuitClosure())); 115 RunThisRunLoop(&run_loop); 116} 117 118base::Closure GetQuitTaskForRunLoop(base::RunLoop* run_loop) { 119 return base::Bind(&DeferredQuitRunLoop, run_loop->QuitClosure(), 120 kNumQuitDeferrals); 121} 122 123scoped_ptr<base::Value> ExecuteScriptAndGetValue( 124 RenderViewHost* render_view_host, 125 const std::string& script) { 126 ScriptCallback observer; 127 128 render_view_host->ExecuteJavascriptInWebFrameCallbackResult( 129 string16(), // frame_xpath, 130 UTF8ToUTF16(script), 131 base::Bind(&ScriptCallback::ResultCallback, base::Unretained(&observer))); 132 base::MessageLoop* loop = base::MessageLoop::current(); 133 loop->Run(); 134 return observer.result().Pass(); 135} 136 137MessageLoopRunner::MessageLoopRunner() 138 : loop_running_(false), 139 quit_closure_called_(false) { 140} 141 142MessageLoopRunner::~MessageLoopRunner() { 143} 144 145void MessageLoopRunner::Run() { 146 // Do not run the message loop if our quit closure has already been called. 147 // This helps in scenarios where the closure has a chance to run before 148 // we Run explicitly. 149 if (quit_closure_called_) 150 return; 151 152 loop_running_ = true; 153 RunThisRunLoop(&run_loop_); 154} 155 156base::Closure MessageLoopRunner::QuitClosure() { 157 return base::Bind(&MessageLoopRunner::Quit, this); 158} 159 160void MessageLoopRunner::Quit() { 161 quit_closure_called_ = true; 162 163 // Only run the quit task if we are running the message loop. 164 if (loop_running_) { 165 GetQuitTaskForRunLoop(&run_loop_).Run(); 166 loop_running_ = false; 167 } 168} 169 170WindowedNotificationObserver::WindowedNotificationObserver( 171 int notification_type, 172 const NotificationSource& source) 173 : seen_(false), 174 running_(false), 175 source_(NotificationService::AllSources()) { 176 registrar_.Add(this, notification_type, source); 177} 178 179WindowedNotificationObserver::WindowedNotificationObserver( 180 int notification_type, 181 const ConditionTestCallback& callback) 182 : seen_(false), 183 running_(false), 184 callback_(callback), 185 source_(NotificationService::AllSources()) { 186 registrar_.Add(this, notification_type, source_); 187} 188 189WindowedNotificationObserver::~WindowedNotificationObserver() {} 190 191void WindowedNotificationObserver::Wait() { 192 if (seen_) 193 return; 194 195 running_ = true; 196 message_loop_runner_ = new MessageLoopRunner; 197 message_loop_runner_->Run(); 198 EXPECT_TRUE(seen_); 199} 200 201void WindowedNotificationObserver::Observe( 202 int type, 203 const NotificationSource& source, 204 const NotificationDetails& details) { 205 source_ = source; 206 details_ = details; 207 if (!callback_.is_null() && !callback_.Run()) 208 return; 209 210 seen_ = true; 211 if (!running_) 212 return; 213 214 message_loop_runner_->Quit(); 215 running_ = false; 216} 217 218} // namespace content 219