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 #ifndef CONTENT_PUBLIC_TEST_TEST_UTILS_H_ 6 #define CONTENT_PUBLIC_TEST_TEST_UTILS_H_ 7 8 #include "base/callback.h" 9 #include "base/memory/ref_counted.h" 10 #include "base/memory/scoped_ptr.h" 11 #include "base/run_loop.h" 12 #include "content/public/browser/browser_child_process_observer.h" 13 #include "content/public/browser/browser_thread.h" 14 #include "content/public/browser/notification_details.h" 15 #include "content/public/browser/notification_observer.h" 16 #include "content/public/browser/notification_registrar.h" 17 #include "content/public/browser/notification_source.h" 18 19 namespace base { 20 class Value; 21 } // namespace base 22 23 // A collection of functions designed for use with unit and browser tests. 24 25 namespace content { 26 27 class RenderFrameHost; 28 29 // Turns on nestable tasks, runs the message loop, then resets nestable tasks 30 // to what they were originally. Prefer this over MessageLoop::Run for in 31 // process browser tests that need to block until a condition is met. 32 void RunMessageLoop(); 33 34 // Variant of RunMessageLoop that takes RunLoop. 35 void RunThisRunLoop(base::RunLoop* run_loop); 36 37 // Turns on nestable tasks, runs all pending tasks in the message loop, 38 // then resets nestable tasks to what they were originally. Prefer this 39 // over MessageLoop::RunAllPending for in process browser tests to run 40 // all pending tasks. 41 void RunAllPendingInMessageLoop(); 42 43 // Blocks the current thread until all the pending messages in the loop of the 44 // thread |thread_id| have been processed. 45 void RunAllPendingInMessageLoop(BrowserThread::ID thread_id); 46 47 // Runs until both the blocking pool and the current message loop are empty 48 // (have no more scheduled tasks) and no tasks are running. 49 void RunAllBlockingPoolTasksUntilIdle(); 50 51 // Get task to quit the given RunLoop. It allows a few generations of pending 52 // tasks to run as opposed to run_loop->QuitClosure(). 53 base::Closure GetQuitTaskForRunLoop(base::RunLoop* run_loop); 54 55 // Executes the specified JavaScript in the specified frame, and runs a nested 56 // MessageLoop. When the result is available, it is returned. 57 // This should not be used; the use of the ExecuteScript functions in 58 // browser_test_utils is preferable. 59 scoped_ptr<base::Value> ExecuteScriptAndGetValue( 60 RenderFrameHost* render_frame_host, const std::string& script); 61 62 // Helper class to Run and Quit the message loop. Run and Quit can only happen 63 // once per instance. Make a new instance for each use. Calling Quit after Run 64 // has returned is safe and has no effect. 65 class MessageLoopRunner : public base::RefCounted<MessageLoopRunner> { 66 public: 67 MessageLoopRunner(); 68 69 // Run the current MessageLoop unless the quit closure 70 // has already been called. 71 void Run(); 72 73 // Quit the matching call to Run (nested MessageLoops are unaffected). 74 void Quit(); 75 76 // Hand this closure off to code that uses callbacks to notify completion. 77 // Example: 78 // scoped_refptr<MessageLoopRunner> runner = new MessageLoopRunner; 79 // kick_off_some_api(runner->QuitClosure()); 80 // runner->Run(); 81 base::Closure QuitClosure(); 82 83 bool loop_running() const { return loop_running_; } 84 85 private: 86 friend class base::RefCounted<MessageLoopRunner>; 87 ~MessageLoopRunner(); 88 89 // True when the message loop is running. 90 bool loop_running_; 91 92 // True after closure returned by |QuitClosure| has been called. 93 bool quit_closure_called_; 94 95 base::RunLoop run_loop_; 96 97 DISALLOW_COPY_AND_ASSIGN(MessageLoopRunner); 98 }; 99 100 // A WindowedNotificationObserver allows code to wait until a condition is met. 101 // Simple conditions are specified by providing a |notification_type| and a 102 // |source|. When a notification of the expected type from the expected source 103 // is received, the condition is met. 104 // More complex conditions can be specified by providing a |notification_type| 105 // and a |callback|. The callback is called whenever the notification is fired. 106 // If the callback returns |true|, the condition is met. Otherwise, the 107 // condition is not yet met and the callback will be invoked again every time a 108 // notification of the expected type is received until the callback returns 109 // |true|. For convenience, two callback types are defined, one that is provided 110 // with the notification source and details, and one that is not. 111 // 112 // This helper class exists to avoid the following common pattern in tests: 113 // PerformAction() 114 // WaitForCompletionNotification() 115 // The pattern leads to flakiness as there is a window between PerformAction 116 // returning and the observers getting registered, where a notification will be 117 // missed. 118 // 119 // Rather, one can do this: 120 // WindowedNotificationObserver signal(...) 121 // PerformAction() 122 // signal.Wait() 123 class WindowedNotificationObserver : public NotificationObserver { 124 public: 125 // Callback invoked on notifications. Should return |true| when the condition 126 // being waited for is met. For convenience, there is a choice between two 127 // callback types, one that is provided with the notification source and 128 // details, and one that is not. 129 typedef base::Callback<bool(const NotificationSource&, 130 const NotificationDetails&)> 131 ConditionTestCallback; 132 typedef base::Callback<bool(void)> 133 ConditionTestCallbackWithoutSourceAndDetails; 134 135 // Set up to wait for a simple condition. The condition is met when a 136 // notification of the given |notification_type| from the given |source| is 137 // received. To accept notifications from all sources, specify 138 // NotificationService::AllSources() as |source|. 139 WindowedNotificationObserver(int notification_type, 140 const NotificationSource& source); 141 142 // Set up to wait for a complex condition. The condition is met when 143 // |callback| returns |true|. The callback is invoked whenever a notification 144 // of |notification_type| from any source is received. 145 WindowedNotificationObserver(int notification_type, 146 const ConditionTestCallback& callback); 147 WindowedNotificationObserver( 148 int notification_type, 149 const ConditionTestCallbackWithoutSourceAndDetails& callback); 150 151 virtual ~WindowedNotificationObserver(); 152 153 // Adds an additional notification type to wait for. The condition will be met 154 // if any of the registered notification types from their respective sources 155 // is received. 156 void AddNotificationType(int notification_type, 157 const NotificationSource& source); 158 159 // Wait until the specified condition is met. If the condition is already met 160 // (that is, the expected notification has already been received or the 161 // given callback returns |true| already), Wait() returns immediately. 162 void Wait(); 163 164 // Returns NotificationService::AllSources() if we haven't observed a 165 // notification yet. 166 const NotificationSource& source() const { 167 return source_; 168 } 169 170 const NotificationDetails& details() const { 171 return details_; 172 } 173 174 // NotificationObserver: 175 virtual void Observe(int type, 176 const NotificationSource& source, 177 const NotificationDetails& details) OVERRIDE; 178 179 private: 180 bool seen_; 181 bool running_; 182 NotificationRegistrar registrar_; 183 184 ConditionTestCallback callback_; 185 186 NotificationSource source_; 187 NotificationDetails details_; 188 scoped_refptr<MessageLoopRunner> message_loop_runner_; 189 190 DISALLOW_COPY_AND_ASSIGN(WindowedNotificationObserver); 191 }; 192 193 // Unit tests can use code which runs in the utility process by having it run on 194 // an in-process utility thread. This eliminates having two code paths in 195 // production code to deal with unit tests, and also helps with the binary 196 // separation on Windows since chrome.dll doesn't need to call into Blink code 197 // for some utility code to handle the single process case. 198 // Include this class as a member variable in your test harness if you take 199 // advantage of this functionality to ensure that the in-process utility thread 200 // is torn down correctly. See http://crbug.com/316919 for more information. 201 // Note: this class should be declared after the TestBrowserThreadBundle and 202 // ShadowingAtExitManager (if it exists) as it will need to be run before they 203 // are torn down. 204 class InProcessUtilityThreadHelper : public BrowserChildProcessObserver { 205 public: 206 InProcessUtilityThreadHelper(); 207 virtual ~InProcessUtilityThreadHelper(); 208 209 private: 210 virtual void BrowserChildProcessHostConnected( 211 const ChildProcessData& data) OVERRIDE; 212 virtual void BrowserChildProcessHostDisconnected( 213 const ChildProcessData& data) OVERRIDE; 214 215 int child_thread_count_; 216 scoped_refptr<MessageLoopRunner> runner_; 217 218 DISALLOW_COPY_AND_ASSIGN(InProcessUtilityThreadHelper); 219 }; 220 221 } // namespace content 222 223 #endif // CONTENT_PUBLIC_TEST_TEST_UTILS_H_ 224