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 <memory> 12 #include <string> 13 #include <utility> 14 15 #include "include/base/cef_callback.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::BindOnce(&TestHandler::DoSomething, 120 // base::Unretained(this))); 121 void PostTask(base::OnceClosure task); 122 void PostDelayedTask(base::OnceClosure task, int delay_ms); 123 124 private: 125 void TaskHelper(base::OnceClosure task); 126 127 // Must be the last member. 128 base::WeakPtrFactory<UIThreadHelper> weak_ptr_factory_; 129 }; 130 131 // The |completion_state| object if specified must outlive this class. 132 explicit TestHandler(CompletionState* completion_state = nullptr); 133 ~TestHandler() override; 134 135 // Implement this method to set up the test. Only used in combination with a 136 // Collection. Call SetupComplete() once the setup is complete. SetupTest()137 virtual void SetupTest() {} 138 139 // Implement this method to run the test. Call DestroyTest() once the test is 140 // complete. 141 virtual void RunTest() = 0; 142 143 // CefClient methods. Add new methods as needed by test cases. GetDialogHandler()144 CefRefPtr<CefDialogHandler> GetDialogHandler() override { return this; } GetDisplayHandler()145 CefRefPtr<CefDisplayHandler> GetDisplayHandler() override { return this; } GetDownloadHandler()146 CefRefPtr<CefDownloadHandler> GetDownloadHandler() override { return this; } GetJSDialogHandler()147 CefRefPtr<CefJSDialogHandler> GetJSDialogHandler() override { return this; } GetLifeSpanHandler()148 CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() override { return this; } GetLoadHandler()149 CefRefPtr<CefLoadHandler> GetLoadHandler() override { return this; } GetRequestHandler()150 CefRefPtr<CefRequestHandler> GetRequestHandler() override { return this; } 151 152 // CefDownloadHandler methods OnBeforeDownload(CefRefPtr<CefBrowser> browser,CefRefPtr<CefDownloadItem> download_item,const CefString & suggested_name,CefRefPtr<CefBeforeDownloadCallback> callback)153 void OnBeforeDownload( 154 CefRefPtr<CefBrowser> browser, 155 CefRefPtr<CefDownloadItem> download_item, 156 const CefString& suggested_name, 157 CefRefPtr<CefBeforeDownloadCallback> callback) override {} 158 159 // CefLifeSpanHandler methods 160 void OnAfterCreated(CefRefPtr<CefBrowser> browser) override; 161 void OnBeforeClose(CefRefPtr<CefBrowser> browser) override; 162 163 // 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)164 CefRefPtr<CefResourceRequestHandler> GetResourceRequestHandler( 165 CefRefPtr<CefBrowser> browser, 166 CefRefPtr<CefFrame> frame, 167 CefRefPtr<CefRequest> request, 168 bool is_navigation, 169 bool is_download, 170 const CefString& request_initiator, 171 bool& disable_default_handling) override { 172 return this; 173 } 174 175 // CefResourceRequestHandler methods 176 CefRefPtr<CefResourceHandler> GetResourceHandler( 177 CefRefPtr<CefBrowser> browser, 178 CefRefPtr<CefFrame> frame, 179 CefRefPtr<CefRequest> request) override; 180 181 void OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser, 182 TerminationStatus status) override; 183 184 // These methods should only be used if at most one non-popup browser exists. 185 CefRefPtr<CefBrowser> GetBrowser() const; 186 int GetBrowserId() const; 187 188 // Copies the map of all the currently existing browsers into |map|. Must be 189 // called on the UI thread. 190 void GetAllBrowsers(BrowserMap* map); 191 192 // Called by the test function to execute the test. This method blocks until 193 // the test is complete. Do not reference the object after this method 194 // returns. Do not use this method if the CompletionState object is shared by 195 // multiple handlers or when using a Collection object. 196 void ExecuteTest(); 197 198 // Event that will be signaled from the TestHandler destructor. 199 // Used by ReleaseAndWaitForDestructor. SetDestroyEvent(CefRefPtr<CefWaitableEvent> event)200 void SetDestroyEvent(CefRefPtr<CefWaitableEvent> event) { 201 destroy_event_ = event; 202 } 203 204 // If a test will not call DestroyTest() indicate so using this method. SetDestroyTestExpected(bool expected)205 void SetDestroyTestExpected(bool expected) { 206 destroy_test_expected_ = expected; 207 } 208 209 // Returns true if a browser currently exists. HasBrowser()210 static bool HasBrowser() { return browser_count_ > 0; } 211 212 protected: 213 // Indicate that test setup is complete. Only used in combination with a 214 // Collection. 215 virtual void SetupComplete(); 216 217 // Close any existing non-popup browsers. Test completion will be signaled 218 // once all the browsers have closed if 219 // |signal_completion_when_all_browsers_close_| is true (default value). 220 // If no browsers exist then this method will do nothing and 221 // TestComplete() must be called manually. 222 virtual void DestroyTest(); 223 224 // Called on the UI thread if the test times out as a result of calling 225 // SetTestTimeout(). Calls DestroyTest() by default. 226 virtual void OnTestTimeout(int timeout_ms, bool treat_as_error); 227 228 // Called from CreateBrowser() to optionally set per-browser settings. PopulateBrowserSettings(CefBrowserSettings * settings)229 virtual void PopulateBrowserSettings(CefBrowserSettings* settings) {} 230 231 void CreateBrowser(const CefString& url, 232 CefRefPtr<CefRequestContext> request_context = nullptr, 233 CefRefPtr<CefDictionaryValue> extra_info = nullptr); 234 static void CloseBrowser(CefRefPtr<CefBrowser> browser, bool force_close); 235 236 void AddResource(const std::string& url, 237 const std::string& content, 238 const std::string& mime_type); 239 240 void AddResource(const std::string& url, 241 const std::string& content, 242 const std::string& mime_type, 243 const ResourceContent::HeaderMap& header_map); 244 245 void AddResourceEx(const std::string& url, const ResourceContent& content); 246 247 void ClearResources(); 248 SetSignalCompletionWhenAllBrowsersClose(bool val)249 void SetSignalCompletionWhenAllBrowsersClose(bool val) { 250 signal_completion_when_all_browsers_close_ = val; 251 } SignalCompletionWhenAllBrowsersClose()252 bool SignalCompletionWhenAllBrowsersClose() const { 253 return signal_completion_when_all_browsers_close_; 254 } 255 256 // Call OnTestTimeout() after the specified amount of time. 257 void SetTestTimeout(int timeout_ms = 5000, bool treat_as_error = true); 258 259 // Signal that the test is complete. This will be called automatically when 260 // all existing non-popup browsers are closed if 261 // |signal_completion_when_all_browsers_close_| is true (default value). It 262 // is an error to call this method before all browsers have closed. 263 void TestComplete(); 264 265 // Returns the single UIThreadHelper instance, creating it if necessary. Must 266 // be called on the UI thread. 267 UIThreadHelper* GetUIThreadHelper(); 268 269 private: 270 // Used to notify when the test is complete. Can be accessed on any thread. 271 CompletionState* completion_state_; 272 bool completion_state_owned_; 273 274 // Map browser ID to browser object for non-popup browsers. Only accessed on 275 // the UI thread. 276 BrowserMap browser_map_; 277 278 // Values for the first created browser. Modified on the UI thread but can be 279 // accessed on any thread. 280 int first_browser_id_; 281 CefRefPtr<CefBrowser> first_browser_; 282 283 // Map of resources that can be automatically loaded. Only accessed on the 284 // IO thread. 285 typedef std::map<std::string, ResourceContent> ResourceMap; 286 ResourceMap resource_map_; 287 288 // If true test completion will be signaled when all browsers have closed. 289 bool signal_completion_when_all_browsers_close_; 290 291 CefRefPtr<CefWaitableEvent> destroy_event_; 292 293 // Tracks whether DestroyTest() is expected or has been called. 294 bool destroy_test_expected_; 295 bool destroy_test_called_; 296 297 std::unique_ptr<UIThreadHelper> ui_thread_helper_; 298 299 // Used to track the number of currently existing browser windows. 300 static int browser_count_; 301 302 DISALLOW_COPY_AND_ASSIGN(TestHandler); 303 }; 304 305 // Release |handler| and wait for the destructor to be called. 306 // This function is used to avoid test state leakage and to verify that 307 // all Handler references have been released on test completion. 308 template <typename T> 309 void ReleaseAndWaitForDestructor(CefRefPtr<T>& handler, int delay_ms = 2000) { 310 CefRefPtr<CefWaitableEvent> event = 311 CefWaitableEvent::CreateWaitableEvent(true, false); 312 handler->SetDestroyEvent(event); 313 T* _handler_ptr = handler.get(); 314 handler = nullptr; 315 bool handler_destructed = event->TimedWait(delay_ms); 316 EXPECT_TRUE(handler_destructed); 317 if (!handler_destructed) { 318 // |event| is a stack variable so clear the reference before returning. 319 _handler_ptr->SetDestroyEvent(nullptr); 320 } 321 } 322 323 // Returns true if the currently running test has failed. 324 bool TestFailed(); 325 326 // Helper macros for executing checks in a method with a boolean return value. 327 // For example: 328 // 329 // bool VerifyVals(bool a, bool b) { 330 // V_DECLARE(); 331 // V_EXPECT_TRUE(a); 332 // V_EXPECT_FALSE(b); 333 // V_RETURN(); 334 // } 335 // 336 // EXPECT_TRUE(VerifyVals(true, false)); 337 338 #define V_DECLARE() \ 339 bool __verify = true; \ 340 bool __result 341 342 #define V_RETURN() return __verify 343 344 #define V_EXPECT_TRUE(condition) \ 345 __result = !!(condition); \ 346 __verify &= __result; \ 347 GTEST_TEST_BOOLEAN_(__result, #condition, false, true, \ 348 GTEST_NONFATAL_FAILURE_) 349 350 #define V_EXPECT_FALSE(condition) \ 351 __result = !!(condition); \ 352 __verify &= !__result; \ 353 GTEST_TEST_BOOLEAN_(!(__result), #condition, true, false, \ 354 GTEST_NONFATAL_FAILURE_) 355 356 #endif // CEF_TESTS_CEFTESTS_TEST_HANDLER_H_ 357