1 // Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights 2 // reserved. Use of this source code is governed by a BSD-style license that 3 // can be found in the LICENSE file. 4 5 #ifndef CEF_TESTS_CEFTESTS_TEST_HANDLER_H_ 6 #define CEF_TESTS_CEFTESTS_TEST_HANDLER_H_ 7 #pragma once 8 9 #include <list> 10 #include <map> 11 #include <string> 12 #include <utility> 13 14 #include "include/base/cef_bind.h" 15 #include "include/base/cef_scoped_ptr.h" 16 #include "include/cef_browser.h" 17 #include "include/cef_client.h" 18 #include "include/cef_frame.h" 19 #include "include/cef_task.h" 20 #include "include/cef_waitable_event.h" 21 #include "tests/ceftests/thread_helper.h" 22 #include "tests/ceftests/track_callback.h" 23 #include "tests/gtest/include/gtest/gtest.h" 24 25 class ResourceContent { 26 public: 27 typedef std::multimap<std::string, std::string> HeaderMap; 28 ResourceContent(const std::string & content,const std::string & mime_type,const HeaderMap & header_map)29 ResourceContent(const std::string& content, 30 const std::string& mime_type, 31 const HeaderMap& header_map) 32 : content_(content), mime_type_(mime_type), header_map_(header_map) {} 33 content()34 const std::string& content() const { return content_; } mimeType()35 const std::string& mimeType() const { return mime_type_; } headerMap()36 const HeaderMap& headerMap() const { return header_map_; } 37 38 private: 39 std::string content_; 40 std::string mime_type_; 41 HeaderMap header_map_; 42 }; 43 44 // Base implementation of CefClient for unit tests. Add new interfaces as needed 45 // by test cases. 46 class TestHandler : public CefClient, 47 public CefDialogHandler, 48 public CefDisplayHandler, 49 public CefDownloadHandler, 50 public CefJSDialogHandler, 51 public CefLifeSpanHandler, 52 public CefLoadHandler, 53 public CefRequestHandler, 54 public CefResourceRequestHandler { 55 public: 56 // Tracks the completion state of related test runs. 57 class CompletionState { 58 public: 59 // |total| is the number of times that TestComplete() must be called before 60 // WaitForTests() will return. 61 explicit CompletionState(int total); 62 63 // Call this method to indicate that a test has completed. 64 void TestComplete(); 65 66 // This method blocks until TestComplete() has been called the required 67 // number of times. 68 void WaitForTests(); 69 total()70 int total() const { return total_; } count()71 int count() const { return count_; } 72 73 private: 74 int total_; 75 int count_; 76 77 // Handle used to notify when the test is complete 78 CefRefPtr<CefWaitableEvent> event_; 79 }; 80 81 // Represents a collection of related tests that need to be run 82 // simultaniously. 83 class Collection { 84 public: 85 // The |completion_state| object must outlive this class. 86 explicit Collection(CompletionState* completion_state); 87 88 // The |test_handler| object must outlive this class and it must share the 89 // same CompletionState object passed to the constructor. 90 void AddTestHandler(TestHandler* test_handler); 91 92 // Manages the test run. 93 // 1. Calls TestHandler::SetupTest() for all of the test objects. 94 // 2. Waits for all TestHandler objects to report that initial setup is 95 // complete by calling TestHandler::SetupComplete(). 96 // 3. Calls TestHandler::RunTest() for all of the test objects. 97 // 4. Waits for all TestHandler objects to report that the test is 98 // complete by calling TestHandler::DestroyTest(). 99 void ExecuteTests(); 100 101 private: 102 CompletionState* completion_state_; 103 104 typedef std::list<TestHandler*> TestHandlerList; 105 TestHandlerList handler_list_; 106 }; 107 108 typedef std::map<int, CefRefPtr<CefBrowser>> BrowserMap; 109 110 // Helper for executing methods using WeakPtr references to TestHandler. 111 class UIThreadHelper { 112 public: 113 UIThreadHelper(); 114 115 // Pass in a |task| with an unretained reference to TestHandler. |task| will 116 // be executed only if TestHandler::DestroyTest has not yet been called. 117 // For example: 118 // GetUIThreadHelper()->PostTask( 119 // base::Bind(&TestHandler::DoSomething, base::Unretained(this))); 120 void PostTask(const base::Closure& task); 121 void PostDelayedTask(const base::Closure& task, int delay_ms); 122 123 private: 124 void TaskHelper(const base::Closure& task); 125 126 // Must be the last member. 127 base::WeakPtrFactory<UIThreadHelper> weak_ptr_factory_; 128 }; 129 130 // The |completion_state| object if specified must outlive this class. 131 explicit TestHandler(CompletionState* completion_state = nullptr); 132 ~TestHandler() override; 133 134 // Implement this method to set up the test. Only used in combination with a 135 // Collection. Call SetupComplete() once the setup is complete. SetupTest()136 virtual void SetupTest() {} 137 138 // Implement this method to run the test. Call DestroyTest() once the test is 139 // complete. 140 virtual void RunTest() = 0; 141 142 // CefClient methods. Add new methods as needed by test cases. GetDialogHandler()143 CefRefPtr<CefDialogHandler> GetDialogHandler() override { return this; } GetDisplayHandler()144 CefRefPtr<CefDisplayHandler> GetDisplayHandler() override { return this; } GetDownloadHandler()145 CefRefPtr<CefDownloadHandler> GetDownloadHandler() override { return this; } GetJSDialogHandler()146 CefRefPtr<CefJSDialogHandler> GetJSDialogHandler() override { return this; } GetLifeSpanHandler()147 CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() override { return this; } GetLoadHandler()148 CefRefPtr<CefLoadHandler> GetLoadHandler() override { return this; } GetRequestHandler()149 CefRefPtr<CefRequestHandler> GetRequestHandler() override { return this; } 150 151 // CefDownloadHandler methods OnBeforeDownload(CefRefPtr<CefBrowser> browser,CefRefPtr<CefDownloadItem> download_item,const CefString & suggested_name,CefRefPtr<CefBeforeDownloadCallback> callback)152 void OnBeforeDownload( 153 CefRefPtr<CefBrowser> browser, 154 CefRefPtr<CefDownloadItem> download_item, 155 const CefString& suggested_name, 156 CefRefPtr<CefBeforeDownloadCallback> callback) override {} 157 158 // CefLifeSpanHandler methods 159 void OnAfterCreated(CefRefPtr<CefBrowser> browser) override; 160 void OnBeforeClose(CefRefPtr<CefBrowser> browser) override; 161 162 // CefRequestHandler methods GetResourceRequestHandler(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,bool is_navigation,bool is_download,const CefString & request_initiator,bool & disable_default_handling)163 CefRefPtr<CefResourceRequestHandler> GetResourceRequestHandler( 164 CefRefPtr<CefBrowser> browser, 165 CefRefPtr<CefFrame> frame, 166 CefRefPtr<CefRequest> request, 167 bool is_navigation, 168 bool is_download, 169 const CefString& request_initiator, 170 bool& disable_default_handling) override { 171 return this; 172 } 173 174 // CefResourceRequestHandler methods 175 CefRefPtr<CefResourceHandler> GetResourceHandler( 176 CefRefPtr<CefBrowser> browser, 177 CefRefPtr<CefFrame> frame, 178 CefRefPtr<CefRequest> request) override; 179 180 void OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser, 181 TerminationStatus status) override; 182 183 // These methods should only be used if at most one non-popup browser exists. 184 CefRefPtr<CefBrowser> GetBrowser(); 185 int GetBrowserId(); 186 187 // Copies the map of all the currently existing browsers into |map|. Must be 188 // called on the UI thread. 189 void GetAllBrowsers(BrowserMap* map); 190 191 // Called by the test function to execute the test. This method blocks until 192 // the test is complete. Do not reference the object after this method 193 // returns. Do not use this method if the CompletionState object is shared by 194 // multiple handlers or when using a Collection object. 195 void ExecuteTest(); 196 197 // Event that will be signaled from the TestHandler destructor. 198 // Used by ReleaseAndWaitForDestructor. SetDestroyEvent(CefRefPtr<CefWaitableEvent> event)199 void SetDestroyEvent(CefRefPtr<CefWaitableEvent> event) { 200 destroy_event_ = event; 201 } 202 203 // If a test will not call DestroyTest() indicate so using this method. SetDestroyTestExpected(bool expected)204 void SetDestroyTestExpected(bool expected) { 205 destroy_test_expected_ = expected; 206 } 207 208 // Returns true if a browser currently exists. HasBrowser()209 static bool HasBrowser() { return browser_count_ > 0; } 210 211 protected: 212 // Indicate that test setup is complete. Only used in combination with a 213 // Collection. 214 virtual void SetupComplete(); 215 216 // Close any existing non-popup browsers. Test completion will be signaled 217 // once all the browsers have closed if 218 // |signal_completion_when_all_browsers_close_| is true (default value). 219 // If no browsers exist then this method will do nothing and 220 // TestComplete() must be called manually. 221 virtual void DestroyTest(); 222 223 // Called on the UI thread if the test times out as a result of calling 224 // SetTestTimeout(). Calls DestroyTest() by default. 225 virtual void OnTestTimeout(int timeout_ms, bool treat_as_error); 226 227 // Called from CreateBrowser() to optionally set per-browser settings. PopulateBrowserSettings(CefBrowserSettings * settings)228 virtual void PopulateBrowserSettings(CefBrowserSettings* settings) {} 229 230 void CreateBrowser(const CefString& url, 231 CefRefPtr<CefRequestContext> request_context = nullptr, 232 CefRefPtr<CefDictionaryValue> extra_info = nullptr); 233 static void CloseBrowser(CefRefPtr<CefBrowser> browser, bool force_close); 234 235 void AddResource(const std::string& url, 236 const std::string& content, 237 const std::string& mime_type); 238 239 void AddResource(const std::string& url, 240 const std::string& content, 241 const std::string& mime_type, 242 const ResourceContent::HeaderMap& header_map); 243 244 void AddResourceEx(const std::string& url, const ResourceContent& content); 245 246 void ClearResources(); 247 SetSignalCompletionWhenAllBrowsersClose(bool val)248 void SetSignalCompletionWhenAllBrowsersClose(bool val) { 249 signal_completion_when_all_browsers_close_ = val; 250 } SignalCompletionWhenAllBrowsersClose()251 bool SignalCompletionWhenAllBrowsersClose() const { 252 return signal_completion_when_all_browsers_close_; 253 } 254 255 // Call OnTestTimeout() after the specified amount of time. 256 void SetTestTimeout(int timeout_ms = 5000, bool treat_as_error = true); 257 258 // Signal that the test is complete. This will be called automatically when 259 // all existing non-popup browsers are closed if 260 // |signal_completion_when_all_browsers_close_| is true (default value). It 261 // is an error to call this method before all browsers have closed. 262 void TestComplete(); 263 264 // Returns the single UIThreadHelper instance, creating it if necessary. Must 265 // be called on the UI thread. 266 UIThreadHelper* GetUIThreadHelper(); 267 268 private: 269 // Used to notify when the test is complete. Can be accessed on any thread. 270 CompletionState* completion_state_; 271 bool completion_state_owned_; 272 273 // Map browser ID to browser object for non-popup browsers. Only accessed on 274 // the UI thread. 275 BrowserMap browser_map_; 276 277 // Values for the first created browser. Modified on the UI thread but can be 278 // accessed on any thread. 279 int first_browser_id_; 280 CefRefPtr<CefBrowser> first_browser_; 281 282 // Map of resources that can be automatically loaded. Only accessed on the 283 // IO thread. 284 typedef std::map<std::string, ResourceContent> ResourceMap; 285 ResourceMap resource_map_; 286 287 // If true test completion will be signaled when all browsers have closed. 288 bool signal_completion_when_all_browsers_close_; 289 290 CefRefPtr<CefWaitableEvent> destroy_event_; 291 292 // Tracks whether DestroyTest() is expected or has been called. 293 bool destroy_test_expected_; 294 bool destroy_test_called_; 295 296 scoped_ptr<UIThreadHelper> ui_thread_helper_; 297 298 // Used to track the number of currently existing browser windows. 299 static int browser_count_; 300 301 DISALLOW_COPY_AND_ASSIGN(TestHandler); 302 }; 303 304 // Release |handler| and wait for the destructor to be called. 305 // This function is used to avoid test state leakage and to verify that 306 // all Handler references have been released on test completion. 307 template <typename T> 308 void ReleaseAndWaitForDestructor(CefRefPtr<T>& handler, int delay_ms = 2000) { 309 CefRefPtr<CefWaitableEvent> event = 310 CefWaitableEvent::CreateWaitableEvent(true, false); 311 handler->SetDestroyEvent(event); 312 T* _handler_ptr = handler.get(); 313 handler = nullptr; 314 bool handler_destructed = event->TimedWait(delay_ms); 315 EXPECT_TRUE(handler_destructed); 316 if (!handler_destructed) { 317 // |event| is a stack variable so clear the reference before returning. 318 _handler_ptr->SetDestroyEvent(nullptr); 319 } 320 } 321 322 // Returns true if the currently running test has failed. 323 bool TestFailed(); 324 325 // Helper macros for executing checks in a method with a boolean return value. 326 // For example: 327 // 328 // bool VerifyVals(bool a, bool b) { 329 // V_DECLARE(); 330 // V_EXPECT_TRUE(a); 331 // V_EXPECT_FALSE(b); 332 // V_RETURN(); 333 // } 334 // 335 // EXPECT_TRUE(VerifyVals(true, false)); 336 337 #define V_DECLARE() \ 338 bool __verify = true; \ 339 bool __result 340 341 #define V_RETURN() return __verify 342 343 #define V_EXPECT_TRUE(condition) \ 344 __result = !!(condition); \ 345 __verify &= __result; \ 346 GTEST_TEST_BOOLEAN_(__result, #condition, false, true, \ 347 GTEST_NONFATAL_FAILURE_) 348 349 #define V_EXPECT_FALSE(condition) \ 350 __result = !!(condition); \ 351 __verify &= !__result; \ 352 GTEST_TEST_BOOLEAN_(!(__result), #condition, true, false, \ 353 GTEST_NONFATAL_FAILURE_) 354 355 #endif // CEF_TESTS_CEFTESTS_TEST_HANDLER_H_ 356