cef/tests/ceftests/test_handler.h

409 lines
14 KiB
C
Raw Normal View History

// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
#ifndef CEF_TESTS_CEFTESTS_TEST_HANDLER_H_
#define CEF_TESTS_CEFTESTS_TEST_HANDLER_H_
#pragma once
#include <atomic>
#include <list>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include "include/base/cef_callback.h"
#include "include/cef_browser.h"
#include "include/cef_client.h"
#include "include/cef_frame.h"
#include "include/cef_task.h"
#include "include/cef_waitable_event.h"
#include "tests/ceftests/thread_helper.h"
#include "tests/ceftests/track_callback.h"
#include "tests/gtest/include/gtest/gtest.h"
Implement Views framework on Windows and Linux (issue #1749). - Add Views header files in a new include/views directory. - Add initial top-level window (CefWindow), control (CefBrowserView, CefLabelButton, CefMenuButton, CefPanel, CefScrollView, CefTextfield) and layout (CefBoxLayout, CefFlowLayout) support. See libcef/browser/views/view_impl.h comments for implementation details. - Add Views example usage in cefclient and cefsimple and Views unit tests in cef_unittests. Pass the `--use-views` command-line flag to cefclient, cefsimple and cef_unittests to run using the Views framework instead of platform APIs. For cefclient and cefsimple this will create the browser window and all related functionality using the Views framework. For cef_unittests this will run all tests (except OSR tests) in a Views-based browser window. Views- specific unit tests (`--gtest_filter=Views*`) will be run even if the the `--use-views` flag is not specified. - Pass the `--hide-frame` command-line flag to cefclient to demo a frameless Views-based browser window. - Pass the `--hide-controls` command-line flag to cefclient to demo a browser window without top controls. This also works in non-Views mode. - Pass the `--enable-high-dpi-support` command-line flag to cef_unittests on Windows to test high-DPI support on a display that supports it. - Add CefImage for reading/writing image file formats. - Add CefBrowser::DownloadImage() for downloading image URLs as a CefImage representation. This is primarily for loading favicons. - Add CefMenuModel::CreateMenuModel() and CefMenuModelDelegate for creating custom menus. This is primarily for use with CefMenuButton. - Add CefBrowser::TryCloseBrowser() helper for closing a browser. Also improve related documentation in cef_life_span_handler.h. - Rename cef_page_range_t to cef_range_t. It is now also used by CefTextfield. - Remove CefLifeSpanHandler::RunModal() which is never called. - Add draggable regions example to cefclient.
2016-01-19 21:09:01 +01:00
class ResourceContent {
public:
typedef std::multimap<std::string, std::string> HeaderMap;
ResourceContent(const std::string& content,
const std::string& mime_type,
const HeaderMap& header_map)
: content_(content), mime_type_(mime_type), header_map_(header_map) {}
const std::string& content() const { return content_; }
const std::string& mimeType() const { return mime_type_; }
const HeaderMap& headerMap() const { return header_map_; }
private:
std::string content_;
std::string mime_type_;
HeaderMap header_map_;
};
// Base implementation of CefClient for unit tests. Add new interfaces as needed
// by test cases.
class TestHandler : public CefClient,
public CefDialogHandler,
public CefDisplayHandler,
public CefDownloadHandler,
public CefJSDialogHandler,
public CefLifeSpanHandler,
public CefLoadHandler,
Implement NetworkService request interception/handling (see issue #2622). Implementation notes: - Chromium change: CookieMonster::SetCookieableSchemes needs to be called immediately after the CookieMonster is created in NetworkContext:: ApplyContextParamsToBuilder. Add a Profile::GetCookieableSchemes method and NetworkContextParams.cookieable_schemes member (set from ProfileNetworkContextService::CreateNetworkContextParams) to support that. - Chromium change: Add a ContentBrowserClient::HandleExternalProtocol variant that exposes additional NetworkService request information. - GetResourceResponseFilter is not yet implemented. API changes: - Resource-related callbacks have been moved from CefRequestHandler to a new CefResourceRequestHandler interface which is returned via the GetResourceRequestHandler method. If the CefRequestHandler declines to handle a resource it can optionally be handled by the CefRequestContextHandler, if any, associated with the loading context. - The OnProtocolExecution callback has been moved from CefRequestHandler to CefResourceRequestHandler and will be called if a custom scheme request is unhandled. - Cookie send/save permission callbacks have been moved from CefRequestHandler and CefResourceHandler to CefResourceRequestHandler. - New methods added to CefResourceHandler that better match NetworkService execution sequence expectations. The old methods are now deprecated. - New methods added to CefRequest and CefResponse. Known behavior changes with the NetworkService implementation: - Modifying the |new_url| parameter in OnResourceRedirect will no longer result in the method being called an additional time (likely a bug in the old implementation). - Modifying the request URL in OnResourceResponse would previously cause a redirect. This behavior is now deprecated because the NetworkService does not support this functionality when using default network loaders. Temporary support has been added in combination with CefResourceHandler usage only. - Other changes to the request object in OnResourceResponse will now cause the request to be restarted. This means that OnBeforeResourceLoad, etc, will be called an additional time with the new request information. - CefResponse::GetMimeType will now be empty for non-200 responses. - Requests using custom schemes can now be handled via CefResourceRequestHandler with the same callback behavior as builtin schemes. - Redirects of custom scheme requests will now be followed as expected. - Default handling of builtin schemes can now be disabled by setting |disable_default_handling| to true in GetResourceRequestHandler. - Unhandled requests (custom scheme or builtin scheme with default handling disabled) will fail with an CefResponse::GetError value of ERR_UNKNOWN_URL_SCHEME. - The CefSchemeHandlerFactory::Create callback will now include cookie headers. To test: - Run `cefclient --enable-network-service`. All resources should load successfully (this tests the transparent proxy capability). - All tests pass with NetworkService disabled. - The following tests pass with NetworkService enabled: - CookieTest.* - FrameTest.* (excluding .*Nav) - NavigationTest.* (excluding .Redirect*) - RequestHandlerTest.* - RequestContextTest.Basic* - RequestContextTest.Popup* - RequestTest.* - ResourceManagerTest.* - ResourceRequestHandlerTest.* (excluding .Filter*) - SchemeHandlerTest.* - StreamResourceHandlerTest.*
2019-04-24 04:50:25 +02:00
public CefRequestHandler,
public CefResourceRequestHandler {
public:
// Tracks the completion state of related test runs.
class CompletionState {
public:
// |total| is the number of times that TestComplete() must be called before
// WaitForTests() will return.
explicit CompletionState(int total);
// Call this method to indicate that a test has completed.
void TestComplete();
// This method blocks until TestComplete() has been called the required
// number of times.
void WaitForTests();
int total() const { return total_; }
int count() const { return count_; }
private:
int total_;
int count_;
// Handle used to notify when the test is complete
CefRefPtr<CefWaitableEvent> event_;
};
// Represents a collection of related tests that need to be run
// simultaniously.
class Collection {
public:
// The |completion_state| object must outlive this class.
explicit Collection(CompletionState* completion_state);
// The |test_handler| object must outlive this class and it must share the
// same CompletionState object passed to the constructor.
void AddTestHandler(TestHandler* test_handler);
// Manages the test run.
// 1. Calls TestHandler::SetupTest() for all of the test objects.
// 2. Waits for all TestHandler objects to report that initial setup is
// complete by calling TestHandler::SetupComplete().
// 3. Calls TestHandler::RunTest() for all of the test objects.
// 4. Waits for all TestHandler objects to report that the test is
// complete by calling TestHandler::DestroyTest().
void ExecuteTests();
private:
CompletionState* completion_state_;
typedef std::list<TestHandler*> TestHandlerList;
TestHandlerList handler_list_;
};
typedef std::map<int, CefRefPtr<CefBrowser>> BrowserMap;
// Helper for executing methods using WeakPtr references to TestHandler.
class UIThreadHelper {
public:
UIThreadHelper();
// Pass in a |task| with an unretained reference to TestHandler. |task| will
// be executed only if TestHandler::DestroyTest has not yet been called.
// For example:
// GetUIThreadHelper()->PostTask(
// base::BindOnce(&TestHandler::DoSomething,
// base::Unretained(this)));
void PostTask(base::OnceClosure task);
void PostDelayedTask(base::OnceClosure task, int delay_ms);
private:
void TaskHelper(base::OnceClosure task);
// Must be the last member.
base::WeakPtrFactory<UIThreadHelper> weak_ptr_factory_;
};
// The |completion_state| object if specified must outlive this class.
explicit TestHandler(CompletionState* completion_state = nullptr);
~TestHandler() override;
// Implement this method to set up the test. Only used in combination with a
// Collection. Call SetupComplete() once the setup is complete.
virtual void SetupTest() {}
// Implement this method to run the test. Call DestroyTest() once the test is
// complete.
virtual void RunTest() = 0;
// CefClient methods. Add new methods as needed by test cases.
CefRefPtr<CefDialogHandler> GetDialogHandler() override { return this; }
CefRefPtr<CefDisplayHandler> GetDisplayHandler() override { return this; }
CefRefPtr<CefDownloadHandler> GetDownloadHandler() override { return this; }
CefRefPtr<CefJSDialogHandler> GetJSDialogHandler() override { return this; }
CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() override { return this; }
CefRefPtr<CefLoadHandler> GetLoadHandler() override { return this; }
CefRefPtr<CefRequestHandler> GetRequestHandler() override { return this; }
// CefDownloadHandler methods
void OnBeforeDownload(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDownloadItem> download_item,
const CefString& suggested_name,
CefRefPtr<CefBeforeDownloadCallback> callback) override {}
// CefLifeSpanHandler methods
void OnAfterCreated(CefRefPtr<CefBrowser> browser) override;
void OnBeforeClose(CefRefPtr<CefBrowser> browser) override;
// CefRequestHandler methods
Implement NetworkService request interception/handling (see issue #2622). Implementation notes: - Chromium change: CookieMonster::SetCookieableSchemes needs to be called immediately after the CookieMonster is created in NetworkContext:: ApplyContextParamsToBuilder. Add a Profile::GetCookieableSchemes method and NetworkContextParams.cookieable_schemes member (set from ProfileNetworkContextService::CreateNetworkContextParams) to support that. - Chromium change: Add a ContentBrowserClient::HandleExternalProtocol variant that exposes additional NetworkService request information. - GetResourceResponseFilter is not yet implemented. API changes: - Resource-related callbacks have been moved from CefRequestHandler to a new CefResourceRequestHandler interface which is returned via the GetResourceRequestHandler method. If the CefRequestHandler declines to handle a resource it can optionally be handled by the CefRequestContextHandler, if any, associated with the loading context. - The OnProtocolExecution callback has been moved from CefRequestHandler to CefResourceRequestHandler and will be called if a custom scheme request is unhandled. - Cookie send/save permission callbacks have been moved from CefRequestHandler and CefResourceHandler to CefResourceRequestHandler. - New methods added to CefResourceHandler that better match NetworkService execution sequence expectations. The old methods are now deprecated. - New methods added to CefRequest and CefResponse. Known behavior changes with the NetworkService implementation: - Modifying the |new_url| parameter in OnResourceRedirect will no longer result in the method being called an additional time (likely a bug in the old implementation). - Modifying the request URL in OnResourceResponse would previously cause a redirect. This behavior is now deprecated because the NetworkService does not support this functionality when using default network loaders. Temporary support has been added in combination with CefResourceHandler usage only. - Other changes to the request object in OnResourceResponse will now cause the request to be restarted. This means that OnBeforeResourceLoad, etc, will be called an additional time with the new request information. - CefResponse::GetMimeType will now be empty for non-200 responses. - Requests using custom schemes can now be handled via CefResourceRequestHandler with the same callback behavior as builtin schemes. - Redirects of custom scheme requests will now be followed as expected. - Default handling of builtin schemes can now be disabled by setting |disable_default_handling| to true in GetResourceRequestHandler. - Unhandled requests (custom scheme or builtin scheme with default handling disabled) will fail with an CefResponse::GetError value of ERR_UNKNOWN_URL_SCHEME. - The CefSchemeHandlerFactory::Create callback will now include cookie headers. To test: - Run `cefclient --enable-network-service`. All resources should load successfully (this tests the transparent proxy capability). - All tests pass with NetworkService disabled. - The following tests pass with NetworkService enabled: - CookieTest.* - FrameTest.* (excluding .*Nav) - NavigationTest.* (excluding .Redirect*) - RequestHandlerTest.* - RequestContextTest.Basic* - RequestContextTest.Popup* - RequestTest.* - ResourceManagerTest.* - ResourceRequestHandlerTest.* (excluding .Filter*) - SchemeHandlerTest.* - StreamResourceHandlerTest.*
2019-04-24 04:50:25 +02:00
CefRefPtr<CefResourceRequestHandler> GetResourceRequestHandler(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,
bool is_navigation,
bool is_download,
const CefString& request_initiator,
bool& disable_default_handling) override {
return this;
}
// CefResourceRequestHandler methods
CefRefPtr<CefResourceHandler> GetResourceHandler(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request) override;
void OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser,
TerminationStatus status) override;
// These methods should only be used if at most one non-popup browser exists.
CefRefPtr<CefBrowser> GetBrowser() const;
int GetBrowserId() const;
// Copies the map of all the currently existing browsers into |map|. Must be
// called on the UI thread.
void GetAllBrowsers(BrowserMap* map);
// Called by the test function to execute the test. This method blocks until
// the test is complete. Do not reference the object after this method
// returns. Do not use this method if the CompletionState object is shared by
// multiple handlers or when using a Collection object.
void ExecuteTest();
// Event that will be signaled from the TestHandler destructor.
// Used by ReleaseAndWaitForDestructor.
void SetDestroyEvent(CefRefPtr<CefWaitableEvent> event) {
destroy_event_ = event;
}
// If a test will not call DestroyTest() indicate so using this method.
void SetDestroyTestExpected(bool expected) {
destroy_test_expected_ = expected;
}
// Called from TestWindowDelegate when Views is enabled.
void OnWindowCreated(int browser_id);
void OnWindowDestroyed(int browser_id);
// Returns true if a TestHandler currently exists.
static bool HasTestHandler() {
return test_handler_count_.load(std::memory_order_relaxed) > 0U;
}
std::string debug_string_prefix() const { return debug_string_prefix_; }
protected:
// Indicate that test setup is complete. Only used in combination with a
// Collection.
virtual void SetupComplete();
// Close any remaining browsers. This may result in a call to TestComplete(),
// depending on the configuration of SetSignalCompletionCount().
virtual void DestroyTest();
// Called on the UI thread if the test times out as a result of calling
// SetTestTimeout(). Calls DestroyTest() by default.
virtual void OnTestTimeout(int timeout_ms, bool treat_as_error);
void CreateBrowser(const CefString& url,
CefRefPtr<CefRequestContext> request_context = nullptr,
CefRefPtr<CefDictionaryValue> extra_info = nullptr);
static void CloseBrowser(CefRefPtr<CefBrowser> browser, bool force_close);
void AddResource(const std::string& url,
const std::string& content,
const std::string& mime_type,
2022-05-25 15:42:41 +02:00
const ResourceContent::HeaderMap& header_map = {});
void AddResourceEx(const std::string& url, const ResourceContent& content);
void ClearResources();
// Specify the number of times that SignalTestCompletion() needs to be
// explicitly called for test completion. Must be configured during test
// initialization before any browsers are created.
// - If the test creates browsers and does not explicitly call
// SignalTestCompletion() then the default value (0) can be used.
// - If the test creates browsers and explicitly calls SignalTestCompletion()
// then set a value >= 1.
// - If the test does not create browsers then it must explicitly call
// SignalTestCompletion() and set a value >= 1.
void SetSignalTestCompletionCount(size_t count);
// Explicitly signal test completion a single time. Used in combination with
// SetSignalTestCompletionCount(). Results in a call to TestComplete() if
// all browsers have closed and this method has been called the expected
// number of times.
void SignalTestCompletion();
// Returns true if SignalTestCompletion() has been called the necessary
// number of times (may be 0), in which case TestComplete() will be called
// automatically when all browsers have closed. Must be called on the
// UI thread.
bool AllowTestCompletionWhenAllBrowsersClose() const;
// Returns true if all browsers have closed. Must be called on the UI
// thread.
bool AllBrowsersClosed() const;
// Call OnTestTimeout() after the specified amount of time.
void SetTestTimeout(int timeout_ms = 5000, bool treat_as_error = true);
// Call prior to CreateBrowser() to configure whether browsers will be created
// as Views-hosted. Defaults to false unless the `--use-views` command-line
// flag is specified.
void SetUseViews(bool use_views);
// Returns the single UIThreadHelper instance, creating it if necessary. Must
// be called on the UI thread.
UIThreadHelper* GetUIThreadHelper();
private:
void MaybeTestComplete();
// Complete the test. It is an error to call this method before all browsers
// have closed.
void TestComplete();
enum NotifyType {
NT_BROWSER,
NT_WINDOW,
};
void OnCreated(int browser_id, NotifyType type, bool views_hosted);
void OnClosed(int browser_id, NotifyType type);
std::string MakeDebugStringPrefix() const;
const std::string debug_string_prefix_;
// Used to notify when the test is complete. Can be accessed on any thread.
CompletionState* completion_state_;
bool completion_state_owned_;
bool use_views_;
// Map of browser ID to browser object. Only accessed on the UI thread.
BrowserMap browser_map_;
struct NotifyStatus {
// True if this particular browser window is Views-hosted (see SetUseViews).
// Some tests create popup or DevTools windows with default handling (e.g.
// not Views-hosted).
bool views_hosted;
// Keyed by NotifyType.
TrackCallback got_created[2];
TrackCallback got_closed[2];
};
// Map of browser ID to current status. Only accessed on the UI thread.
std::map<int, NotifyStatus> browser_status_map_;
// Values for the first created browser. Modified on the UI thread but can be
// accessed on any thread.
int first_browser_id_ = 0;
CefRefPtr<CefBrowser> first_browser_;
// Map of resources that can be automatically loaded. Only accessed on the
// IO thread.
typedef std::map<std::string, ResourceContent> ResourceMap;
ResourceMap resource_map_;
// Number of times that SignalTestCompletion() must be called.
size_t signal_completion_count_ = 0U;
CefRefPtr<CefWaitableEvent> destroy_event_;
// Tracks whether OnTestTimeout() has been called.
bool test_timeout_called_ = false;
// Tracks whether DestroyTest() is expected or has been called.
bool destroy_test_expected_ = true;
bool destroy_test_called_ = false;
std::unique_ptr<UIThreadHelper> ui_thread_helper_;
// Used to track the number of currently existing TestHandlers.
static std::atomic<size_t> test_handler_count_;
Introduce the use of Chromium types (issue #1336). Changes to the CEF public API: - Add base::Bind, base::Callback, base::Lock, base::WeakPtr, scoped_refptr, scoped_ptr and supporting types. - Add include/wrapper/cef_closure_task.h helpers for converting a base::Closure to a CefTask. - Change CefRefPtr to extend scoped_refptr. -- Change CefBase method signatures to match RefCountedThreadSafeBase. - Change IMPLEMENT_REFCOUNTING to use base::AtomicRefCount*. -- Remove the CefAtomic* functions. -- IMPLEMENT_REFCOUNTING now enforces via a compile-time error that the correct class name was passed to the macro. - Change IMPLEMENT_LOCKING to use base::Lock. -- Remove the CefCriticalSection class. -- Deprecate the IMPLEMENT_LOCKING macro. -- base::Lock will DCHECK() in Debug builds if lock usage is reentrant. - Move include/internal/cef_tuple.h to include/base/cef_tuple.h. - Allow an empty |callback| parameter passed to CefBeginTracing. Changes to the CEF implementation: - Fix incorrect names passed to the IMPLEMENT_REFCOUNTING macro. - Fix instances of reentrant locking in the CefXmlObject and CefRequest implementations. - Remove use of the IMPLEMENT_LOCKING macro. Changes to cef_unittests: - Add tests/unittests/chromium_includes.h and always include it first from unit test .cc files to avoid name conflicts with Chromium types. - Fix wrong header include ordering. - Remove use of the IMPLEMENT_LOCKING macro. Changes to cefclient and cefsimple: - Use base::Bind and cef_closure_task.h instead of NewCefRunnable*. - Remove use of the IMPEMENT_LOCKING macro. - Fix incorrect/unnecessary locking. - Add additional runtime thread checks. - Windows: Perform actions on the UI thread instead of the main thread when running in multi-threaded-message-loop mode to avoid excessive locking. git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@1769 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
2014-07-15 00:18:51 +02:00
DISALLOW_COPY_AND_ASSIGN(TestHandler);
};
// Release |handler| and wait for the destructor to be called.
// This function is used to avoid test state leakage and to verify that
// all Handler references have been released on test completion.
template <typename T>
void ReleaseAndWaitForDestructor(CefRefPtr<T>& handler, int delay_ms = 2000) {
CefRefPtr<CefWaitableEvent> event =
CefWaitableEvent::CreateWaitableEvent(true, false);
handler->SetDestroyEvent(event);
T* _handler_ptr = handler.get();
handler = nullptr;
bool handler_destructed = event->TimedWait(delay_ms);
EXPECT_TRUE(handler_destructed);
if (!handler_destructed) {
// |event| is a stack variable so clear the reference before returning.
_handler_ptr->SetDestroyEvent(nullptr);
}
}
// Returns true if the currently running test has failed.
bool TestFailed();
// Helper macros for executing checks in a method with a boolean return value.
// For example:
//
// bool VerifyVals(bool a, bool b) {
// V_DECLARE();
// V_EXPECT_TRUE(a);
// V_EXPECT_FALSE(b);
// V_RETURN();
// }
//
// EXPECT_TRUE(VerifyVals(true, false));
#define V_DECLARE() \
bool __verify = true; \
bool __result
#define V_RETURN() return __verify
#define V_EXPECT_TRUE(condition) \
__result = !!(condition); \
__verify &= __result; \
GTEST_TEST_BOOLEAN_(__result, #condition, false, true, \
GTEST_NONFATAL_FAILURE_)
#define V_EXPECT_FALSE(condition) \
__result = !!(condition); \
__verify &= !__result; \
GTEST_TEST_BOOLEAN_(!(__result), #condition, true, false, \
GTEST_NONFATAL_FAILURE_)
#endif // CEF_TESTS_CEFTESTS_TEST_HANDLER_H_