From a4d63010c9d3967748fd5ab69c31560300cfa698 Mon Sep 17 00:00:00 2001 From: Marshall Greenblatt Date: Sat, 30 Jul 2022 19:53:48 -0400 Subject: [PATCH] ceftests: Refactor test_server to support both HTTP and HTTPS servers (see issue #3348) --- cef_paths2.gypi | 10 +- tests/ceftests/cookie_unittest.cc | 2 +- tests/ceftests/cors_unittest.cc | 2 +- tests/ceftests/test_server.cc | 489 +----------------- tests/ceftests/test_server.h | 90 +--- tests/ceftests/test_server_manager.cc | 282 ++++++++++ tests/ceftests/test_server_manager.h | 98 ++++ tests/ceftests/test_server_observer.cc | 57 ++ tests/ceftests/test_server_observer.h | 82 +++ ...st.cc => test_server_observer_unittest.cc} | 79 +-- tests/ceftests/test_server_runner.cc | 33 ++ tests/ceftests/test_server_runner.h | 68 +++ tests/ceftests/test_server_runner_normal.cc | 196 +++++++ tests/ceftests/test_server_runner_test.cc | 17 + tests/ceftests/urlrequest_unittest.cc | 2 +- tests/shared/common/client_switches.cc | 1 + tests/shared/common/client_switches.h | 1 + 17 files changed, 881 insertions(+), 628 deletions(-) create mode 100644 tests/ceftests/test_server_manager.cc create mode 100644 tests/ceftests/test_server_manager.h create mode 100644 tests/ceftests/test_server_observer.cc create mode 100644 tests/ceftests/test_server_observer.h rename tests/ceftests/{test_server_unittest.cc => test_server_observer_unittest.cc} (68%) create mode 100644 tests/ceftests/test_server_runner.cc create mode 100644 tests/ceftests/test_server_runner.h create mode 100644 tests/ceftests/test_server_runner_normal.cc create mode 100644 tests/ceftests/test_server_runner_test.cc diff --git a/cef_paths2.gypi b/cef_paths2.gypi index 7f430b829..37e83ab5f 100644 --- a/cef_paths2.gypi +++ b/cef_paths2.gypi @@ -524,7 +524,15 @@ 'tests/ceftests/test_request.h', 'tests/ceftests/test_server.cc', 'tests/ceftests/test_server.h', - 'tests/ceftests/test_server_unittest.cc', + 'tests/ceftests/test_server_observer.h', + 'tests/ceftests/test_server_observer.cc', + 'tests/ceftests/test_server_observer_unittest.cc', + 'tests/ceftests/test_server_manager.h', + 'tests/ceftests/test_server_manager.cc', + 'tests/ceftests/test_server_runner.h', + 'tests/ceftests/test_server_runner.cc', + 'tests/ceftests/test_server_runner_normal.cc', + 'tests/ceftests/test_server_runner_test.cc', 'tests/ceftests/test_suite.cc', 'tests/ceftests/test_suite.h', 'tests/ceftests/test_util.cc', diff --git a/tests/ceftests/cookie_unittest.cc b/tests/ceftests/cookie_unittest.cc index 173fa596f..6fa2974dc 100644 --- a/tests/ceftests/cookie_unittest.cc +++ b/tests/ceftests/cookie_unittest.cc @@ -17,7 +17,7 @@ #include "include/wrapper/cef_closure_task.h" #include "tests/ceftests/routing_test_handler.h" #include "tests/ceftests/test_handler.h" -#include "tests/ceftests/test_server.h" +#include "tests/ceftests/test_server_observer.h" #include "tests/ceftests/test_suite.h" #include "tests/ceftests/test_util.h" #include "tests/gtest/include/gtest/gtest.h" diff --git a/tests/ceftests/cors_unittest.cc b/tests/ceftests/cors_unittest.cc index 02b1f7517..c07c03f83 100644 --- a/tests/ceftests/cors_unittest.cc +++ b/tests/ceftests/cors_unittest.cc @@ -13,7 +13,7 @@ #include "include/wrapper/cef_closure_task.h" #include "tests/ceftests/routing_test_handler.h" #include "tests/ceftests/test_request.h" -#include "tests/ceftests/test_server.h" +#include "tests/ceftests/test_server_observer.h" #include "tests/ceftests/test_util.h" #include "tests/shared/browser/client_app_browser.h" diff --git a/tests/ceftests/test_server.cc b/tests/ceftests/test_server.cc index 7bcd564c2..1de1dc553 100644 --- a/tests/ceftests/test_server.cc +++ b/tests/ceftests/test_server.cc @@ -4,12 +4,9 @@ #include "tests/ceftests/test_server.h" -#include +#include "tests/ceftests/test_server_manager.h" -#include "include/cef_server.h" -#include "include/wrapper/cef_closure_task.h" -#include "include/wrapper/cef_helpers.h" -#include "tests/gtest/include/gtest/gtest.h" +#include namespace test_server { @@ -20,476 +17,22 @@ const char kServerScheme[] = "http"; const char kServerOrigin[] = "http://127.0.0.1:8098"; const char kIncompleteDoNotSendData[] = "DO NOT SEND"; -namespace { - -class ServerManager; -ServerManager* g_manager = nullptr; - -// True if Stop() has been called. -bool g_stopping = false; - -// Created on the UI thread and called on the dedicated server thread. -class ServerHandler : public CefServerHandler { - public: - ServerHandler() { - CefServer::CreateServer(kServerAddress, kServerPort, 10, this); - } - - ~ServerHandler() override { - EXPECT_FALSE(server_); - NotifyServerHandlerDeleted(); - } - - void Shutdown() { server_->Shutdown(); } - - protected: - // CefServerHandler methods: - void OnServerCreated(CefRefPtr server) override { - server_ = server; - NotifyServerCreated(kServerOrigin); - } - - void OnServerDestroyed(CefRefPtr server) override { - server_ = nullptr; - NotifyServerDestroyed(); - } - - void OnClientConnected(CefRefPtr server, - int connection_id) override { - EXPECT_TRUE(server->HasConnection()); - EXPECT_TRUE(server->IsValidConnection(connection_id)); - } - - void OnClientDisconnected(CefRefPtr server, - int connection_id) override { - EXPECT_FALSE(server->IsValidConnection(connection_id)); - } - - void OnHttpRequest(CefRefPtr server, - int connection_id, - const CefString& client_address, - CefRefPtr request) override { - NotifyHttpRequest(server, connection_id, client_address, request); - } - - void OnWebSocketRequest(CefRefPtr server, - int connection_id, - const CefString& client_address, - CefRefPtr request, - CefRefPtr callback) override {} - void OnWebSocketConnected(CefRefPtr server, - int connection_id) override {} - void OnWebSocketMessage(CefRefPtr server, - int connection_id, - const void* data, - size_t data_size) override {} - - private: - static void NotifyServerCreated(const std::string& server_origin); - static void NotifyServerDestroyed(); - static void NotifyServerHandlerDeleted(); - static void NotifyHttpRequest(CefRefPtr server, - int connection_id, - const CefString& client_address, - CefRefPtr request); - - CefRefPtr server_; - - IMPLEMENT_REFCOUNTING(ServerHandler); - DISALLOW_COPY_AND_ASSIGN(ServerHandler); -}; - -// Only accessed on the UI thread. Deletes itself after the server is stopped. -class ServerManager { - public: - ServerManager() { - CEF_REQUIRE_UI_THREAD(); - EXPECT_FALSE(g_manager); - g_manager = this; - } - - ~ServerManager() { - CEF_REQUIRE_UI_THREAD(); - EXPECT_TRUE(observer_list_.empty()); - EXPECT_TRUE(start_callback_list_.empty()); - EXPECT_TRUE(stop_callback_.is_null()); - - g_manager = nullptr; - } - - void Start(StartDoneCallback callback) { - CEF_REQUIRE_UI_THREAD(); - if (!origin_.empty()) { - // The server is already running. - std::move(callback).Run(origin_); - return; - } - - // If tests run in parallel, and the server is starting, then there may be - // multiple pending callbacks. - start_callback_list_.push_back(std::move(callback)); - - // Only create the handler a single time. - if (!handler_) { - handler_ = new ServerHandler(); - } - } - - void Stop(DoneCallback callback) { - CEF_REQUIRE_UI_THREAD(); - if (!handler_) { - // The server is not currently running. - std::move(callback).Run(); - return; - } - - // Only 1 stop callback supported. - EXPECT_TRUE(stop_callback_.is_null()); - stop_callback_ = std::move(callback); - - handler_->Shutdown(); - } - - void AddObserver(Observer* observer) { - CEF_REQUIRE_UI_THREAD(); - observer_list_.push_back(observer); - } - - void RemoveObserver(Observer* observer) { - CEF_REQUIRE_UI_THREAD(); - bool found = false; - ObserverList::iterator it = observer_list_.begin(); - for (; it != observer_list_.end(); ++it) { - if (*it == observer) { - observer_list_.erase(it); - found = true; - break; - } - } - EXPECT_TRUE(found); - } - - void NotifyServerCreated(const std::string& server_origin) { - CEF_REQUIRE_UI_THREAD(); - - EXPECT_TRUE(origin_.empty()); - origin_ = server_origin; - - for (auto& callback : start_callback_list_) { - std::move(callback).Run(origin_); - } - start_callback_list_.clear(); - } - - void NotifyServerDestroyed() { - CEF_REQUIRE_UI_THREAD(); - - origin_.clear(); - handler_ = nullptr; - } - - // All server-related objects have been torn down. - void NotifyServerHandlerDeleted() { - CEF_REQUIRE_UI_THREAD(); - - EXPECT_FALSE(stop_callback_.is_null()); - std::move(stop_callback_).Run(); - - delete this; - } - - void NotifyHttpRequest(CefRefPtr server, - int connection_id, - const CefString& client_address, - CefRefPtr request) { - CEF_REQUIRE_UI_THREAD(); - - // TODO(chrome-runtime): Debug why favicon requests don't always have the - // correct resource type. - const std::string& url = request->GetURL(); - if (request->GetResourceType() == RT_FAVICON || - url.find("/favicon.ico") != std::string::npos) { - // We don't currently handle favicon requests. - server->SendHttp404Response(connection_id); - return; - } - - EXPECT_FALSE(observer_list_.empty()) << url; - - // Use a copy in case |observer_list_| is modified during iteration. - ObserverList list = observer_list_; - - bool handled = false; - - auto response_callback = base::BindRepeating(&ServerManager::SendResponse, - server, connection_id); - - ObserverList::const_iterator it = list.begin(); - for (; it != list.end(); ++it) { - if ((*it)->OnHttpRequest(request, response_callback)) { - handled = true; - break; - } - } - - if (!handled) { - server->SendHttp500Response(connection_id, "Unhandled request."); - } - } - - private: - static void SendResponse(CefRefPtr server, - int connection_id, - CefRefPtr response, - const std::string& response_data) { - // Execute on the server thread because some methods require it. - CefRefPtr task_runner = server->GetTaskRunner(); - if (!task_runner->BelongsToCurrentThread()) { - task_runner->PostTask(CefCreateClosureTask( - base::BindOnce(ServerManager::SendResponse, server, connection_id, - response, response_data))); - return; - } - - // No response should be sent yet. - EXPECT_TRUE(server->IsValidConnection(connection_id)); - - const int response_code = response->GetStatus(); - if (response_code <= 0) { - // Intentionally not responding for incomplete request tests. - return; - } - - const CefString& content_type = response->GetMimeType(); - int64 content_length = static_cast(response_data.size()); - - CefResponse::HeaderMap extra_headers; - response->GetHeaderMap(extra_headers); - - server->SendHttpResponse(connection_id, response_code, content_type, - content_length, extra_headers); - - if (response_data == kIncompleteDoNotSendData) { - // Intentionally not sending data for incomplete request tests. - return; - } - - if (content_length != 0) { - server->SendRawData(connection_id, response_data.data(), - response_data.size()); - server->CloseConnection(connection_id); - } - - // The connection should be closed. - EXPECT_FALSE(server->IsValidConnection(connection_id)); - } - - CefRefPtr handler_; - std::string origin_; - - using StartDoneCallbackList = std::vector; - StartDoneCallbackList start_callback_list_; - - DoneCallback stop_callback_; - - using ObserverList = std::vector; - ObserverList observer_list_; - - DISALLOW_COPY_AND_ASSIGN(ServerManager); -}; - -ServerManager* GetServerManager() { - return g_manager; +CefRefPtr Create404Response() { + auto response = CefResponse::Create(); + response->SetStatus(404); + response->SetMimeType("text/html"); + return response; } -ServerManager* GetOrCreateServerManager() { - if (!g_manager) { - new ServerManager(); - EXPECT_TRUE(g_manager); - } - return g_manager; -} - -// static -void ServerHandler::NotifyServerCreated(const std::string& server_origin) { - if (!CefCurrentlyOn(TID_UI)) { - CefPostTask(TID_UI, base::BindOnce(ServerHandler::NotifyServerCreated, - server_origin)); - return; - } - - GetServerManager()->NotifyServerCreated(server_origin); -} - -// static -void ServerHandler::NotifyServerDestroyed() { - if (!CefCurrentlyOn(TID_UI)) { - CefPostTask(TID_UI, base::BindOnce(ServerHandler::NotifyServerDestroyed)); - return; - } - - GetServerManager()->NotifyServerDestroyed(); -} - -// static -void ServerHandler::NotifyServerHandlerDeleted() { - if (!CefCurrentlyOn(TID_UI)) { - CefPostTask(TID_UI, - base::BindOnce(ServerHandler::NotifyServerHandlerDeleted)); - return; - } - - GetServerManager()->NotifyServerHandlerDeleted(); -} - -// static -void ServerHandler::NotifyHttpRequest(CefRefPtr server, - int connection_id, - const CefString& client_address, - CefRefPtr request) { - if (!CefCurrentlyOn(TID_UI)) { - CefPostTask(TID_UI, base::BindOnce(ServerHandler::NotifyHttpRequest, server, - connection_id, client_address, request)); - return; - } - - GetServerManager()->NotifyHttpRequest(server, connection_id, client_address, - request); -} - -// May be created on any thread but will be destroyed on the UI thread. -class ObserverRegistration : public CefRegistration { - public: - explicit ObserverRegistration(Observer* const observer) - : observer_(observer) { - EXPECT_TRUE(observer_); - } - - ~ObserverRegistration() override { - CEF_REQUIRE_UI_THREAD(); - - ServerManager* manager = GetServerManager(); - if (manager) { - manager->RemoveObserver(observer_); - observer_->OnUnregistered(); - } - } - - void Initialize() { - CEF_REQUIRE_UI_THREAD(); - GetOrCreateServerManager()->AddObserver(observer_); - observer_->OnRegistered(); - } - - private: - Observer* const observer_; - - IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(ObserverRegistration); - DISALLOW_COPY_AND_ASSIGN(ObserverRegistration); -}; - -void InitializeRegistration(CefRefPtr registration, - DoneCallback callback) { - if (!CefCurrentlyOn(TID_UI)) { - CefPostTask(TID_UI, base::BindOnce(InitializeRegistration, registration, - std::move(callback))); - return; - } - - EXPECT_FALSE(g_stopping); - - registration->Initialize(); - if (!callback.is_null()) - std::move(callback).Run(); -} - -} // namespace - -void Start(StartDoneCallback callback) { - EXPECT_FALSE(callback.is_null()); - if (!CefCurrentlyOn(TID_UI)) { - CefPostTask(TID_UI, base::BindOnce(Start, std::move(callback))); - return; - } - - EXPECT_FALSE(g_stopping); - - GetOrCreateServerManager()->Start(std::move(callback)); -} - -void Stop(DoneCallback callback) { - EXPECT_FALSE(callback.is_null()); - if (!CefCurrentlyOn(TID_UI)) { - CefPostTask(TID_UI, base::BindOnce(Stop, std::move(callback))); - return; - } - - // Stop will be called one time on test framework shutdown. - EXPECT_FALSE(g_stopping); - g_stopping = true; - - ServerManager* manager = GetServerManager(); - if (manager) { - manager->Stop(std::move(callback)); - } else { - std::move(callback).Run(); - } -} - -CefRefPtr AddObserver(Observer* observer, - DoneCallback callback) { - EXPECT_TRUE(observer); - CefRefPtr registration = - new ObserverRegistration(observer); - InitializeRegistration(registration, std::move(callback)); - return registration.get(); -} - -CefRefPtr AddObserverAndStart(Observer* observer, - StartDoneCallback callback) { - return AddObserver(observer, base::BindOnce(Start, std::move(callback))); -} - -// ObserverHelper - -ObserverHelper::ObserverHelper() : weak_ptr_factory_(this) { - CEF_REQUIRE_UI_THREAD(); -} - -ObserverHelper::~ObserverHelper() { - EXPECT_TRUE(state_ == State::NONE); -} - -void ObserverHelper::Initialize() { - CEF_REQUIRE_UI_THREAD(); - EXPECT_TRUE(state_ == State::NONE); - state_ = State::INITIALIZING; - registration_ = - AddObserverAndStart(this, base::BindOnce(&ObserverHelper::OnStartDone, - weak_ptr_factory_.GetWeakPtr())); -} - -void ObserverHelper::Shutdown() { - CEF_REQUIRE_UI_THREAD(); - EXPECT_TRUE(state_ == State::INITIALIZED); - state_ = State::SHUTTINGDOWN; - registration_ = nullptr; -} - -void ObserverHelper::OnStartDone(const std::string& server_origin) { - EXPECT_TRUE(state_ == State::INITIALIZING); - state_ = State::INITIALIZED; - OnInitialized(server_origin); -} - -void ObserverHelper::OnRegistered() { - EXPECT_TRUE(state_ == State::INITIALIZING); -} - -void ObserverHelper::OnUnregistered() { - EXPECT_TRUE(state_ == State::SHUTTINGDOWN); - state_ = State::NONE; - OnShutdown(); +void Stop(base::OnceClosure callback) { + // Stop both HTTPS and HTTP servers in a chain. + Manager::Stop(base::BindOnce( + [](base::OnceClosure callback) { + Manager::Stop(std::move(callback), + /*https_server=*/false); + }, + std::move(callback)), + /*https_server=*/true); } } // namespace test_server diff --git a/tests/ceftests/test_server.h b/tests/ceftests/test_server.h index 444629fd7..49108905f 100644 --- a/tests/ceftests/test_server.h +++ b/tests/ceftests/test_server.h @@ -23,92 +23,16 @@ extern const char kServerOrigin[]; // Used with incomplete tests for data that should not be sent. extern const char kIncompleteDoNotSendData[]; -using DoneCallback = base::OnceClosure; +// Create a 404 response for passing to ResponseCallback. +CefRefPtr Create404Response(); -using StartDoneCallback = - base::OnceCallback; +using ResponseCallback = + base::RepeatingCallback response, + const std::string& response_data)>; -// Starts the server if it is not currently running, and executes |callback| on -// the UI thread. This method should be called by each test case that relies on -// the server. -void Start(StartDoneCallback callback); - -// Stops the server if it is currently running, and executes |callback| on the +// Stops all servers that are currently running and executes |callback| on the // UI thread. This method will be called by the test framework on shutdown. -void Stop(DoneCallback callback); - -// Observer for server callbacks. Methods will be called on the UI thread. -class Observer { - public: - // Called when this Observer is registered. - virtual void OnRegistered() = 0; - - // Called when this Observer is unregistered. - virtual void OnUnregistered() = 0; - - using ResponseCallback = - base::RepeatingCallback response, - const std::string& response_data)>; - - // Return true and execute |response_callback| either synchronously or - // asynchronously if the request was handled. Do not execute - // |response_callback| when returning false. - virtual bool OnHttpRequest(CefRefPtr request, - const ResponseCallback& response_callback) = 0; - - protected: - virtual ~Observer() {} -}; - -// Add an observer for server callbacks. Remains registered until the returned -// CefRegistration object is destroyed. Registered observers will be executed in -// the order of registration until one returns true to indicate that it handled -// the callback. |callback| will be executed on the UI thread after registration -// is complete. -CefRefPtr AddObserver(Observer* observer, - DoneCallback callback); - -// Combination of AddObserver() followed by Start(). -CefRefPtr AddObserverAndStart(Observer* observer, - StartDoneCallback callback); - -// Helper for managing Observer registration and callbacks. Only used on the UI -// thread. -class ObserverHelper : public Observer { - public: - ObserverHelper(); - ~ObserverHelper() override; - - // Initialize the registration. Results in a call to OnInitialized(). - void Initialize(); - - // Shut down the registration. Results in a call to OnShutdown(). - void Shutdown(); - - // Implement this method to start sending server requests after Initialize(). - virtual void OnInitialized(const std::string& server_origin) = 0; - - // Implement this method to continue the test after Shutdown(). - virtual void OnShutdown() = 0; - - private: - void OnStartDone(const std::string& server_origin); - void OnRegistered() override; - void OnUnregistered() override; - - CefRefPtr registration_; - - enum class State { - NONE, - INITIALIZING, - INITIALIZED, - SHUTTINGDOWN, - } state_ = State::NONE; - - base::WeakPtrFactory weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(ObserverHelper); -}; +void Stop(base::OnceClosure callback); } // namespace test_server diff --git a/tests/ceftests/test_server_manager.cc b/tests/ceftests/test_server_manager.cc new file mode 100644 index 000000000..04c6c0940 --- /dev/null +++ b/tests/ceftests/test_server_manager.cc @@ -0,0 +1,282 @@ +// Copyright (c) 2020 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. + +#include "tests/ceftests/test_server_manager.h" + +#include "include/wrapper/cef_closure_task.h" +#include "include/wrapper/cef_helpers.h" +#include "tests/gtest/include/gtest/gtest.h" + +namespace test_server { + +namespace { + +Manager* g_http_manager = nullptr; +Manager* g_https_manager = nullptr; + +} // namespace + +// May be created on any thread but will be destroyed on the UI thread. +class ObserverRegistration : public CefRegistration { + public: + ObserverRegistration(Observer* observer, bool https_server) + : observer_(observer), https_server_(https_server) { + EXPECT_TRUE(observer_); + } + + ~ObserverRegistration() override { + CEF_REQUIRE_UI_THREAD(); + + if (auto manager = Manager::GetInstance(https_server_)) { + manager->RemoveObserver(observer_); + observer_->OnUnregistered(); + } + } + + void Initialize() { + CEF_REQUIRE_UI_THREAD(); + Manager::GetOrCreateInstance(https_server_)->AddObserver(observer_); + observer_->OnRegistered(); + } + + static void InitializeRegistration( + CefRefPtr registration, + Manager::DoneCallback callback) { + if (!CefCurrentlyOn(TID_UI)) { + CefPostTask(TID_UI, base::BindOnce(InitializeRegistration, registration, + std::move(callback))); + return; + } + + registration->Initialize(); + if (!callback.is_null()) + std::move(callback).Run(); + } + + private: + Observer* const observer_; + const bool https_server_; + + IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(ObserverRegistration); + DISALLOW_COPY_AND_ASSIGN(ObserverRegistration); +}; + +Manager::Manager(bool https_server) : https_server_(https_server) { + CEF_REQUIRE_UI_THREAD(); + + if (https_server) { + DCHECK(!g_https_manager); + g_https_manager = this; + } else { + DCHECK(!g_http_manager); + g_http_manager = this; + } +} + +Manager::~Manager() { + CEF_REQUIRE_UI_THREAD(); + EXPECT_TRUE(observer_list_.empty()); + EXPECT_TRUE(start_callback_list_.empty()); + EXPECT_TRUE(stop_callback_.is_null()); + + if (https_server_) { + g_https_manager = nullptr; + } else { + g_http_manager = nullptr; + } +} + +// static +Manager* Manager::GetInstance(bool https_server) { + return https_server ? g_https_manager : g_http_manager; +} + +// static +Manager* Manager::GetOrCreateInstance(bool https_server) { + if (auto manager = GetInstance(https_server)) { + return manager; + } + + new Manager(https_server); + auto manager = GetInstance(https_server); + DCHECK(manager); + return manager; +} + +// static +void Manager::Start(StartDoneCallback callback, bool https_server) { + EXPECT_FALSE(callback.is_null()); + if (!CefCurrentlyOn(TID_UI)) { + CefPostTask(TID_UI, base::BindOnce(Manager::Start, std::move(callback), + https_server)); + return; + } + + Manager::GetOrCreateInstance(https_server)->StartImpl(std::move(callback)); +} + +// static +void Manager::Stop(DoneCallback callback, bool https_server) { + EXPECT_FALSE(callback.is_null()); + if (!CefCurrentlyOn(TID_UI)) { + CefPostTask(TID_UI, base::BindOnce(Manager::Stop, std::move(callback), + https_server)); + return; + } + + if (auto manager = Manager::GetInstance(https_server)) { + manager->StopImpl(std::move(callback)); + } else { + std::move(callback).Run(); + } +} + +// static +CefRefPtr Manager::AddObserver(Observer* observer, + DoneCallback callback, + bool https_server) { + EXPECT_TRUE(observer); + CefRefPtr registration = + new ObserverRegistration(observer, https_server); + ObserverRegistration::InitializeRegistration(registration, + std::move(callback)); + return registration.get(); +} + +// static +CefRefPtr Manager::AddObserverAndStart( + Observer* observer, + StartDoneCallback callback, + bool https_server) { + return AddObserver( + observer, + base::BindOnce(Manager::Start, std::move(callback), https_server), + https_server); +} + +void Manager::StartImpl(StartDoneCallback callback) { + CEF_REQUIRE_UI_THREAD(); + EXPECT_FALSE(stopping_); + + if (!origin_.empty()) { + // The server is already running. + std::move(callback).Run(origin_); + return; + } + + // If tests run in parallel, and the server is starting, then there may be + // multiple pending callbacks. + start_callback_list_.push_back(std::move(callback)); + + // Only create the runner a single time. + if (!runner_) { + runner_ = Runner::Create(this, https_server_); + runner_->StartServer(); + } +} + +void Manager::StopImpl(DoneCallback callback) { + CEF_REQUIRE_UI_THREAD(); + if (!runner_) { + // The server is not currently running. + std::move(callback).Run(); + return; + } + + // Stop will be called one time on test framework shutdown. + EXPECT_FALSE(stopping_); + stopping_ = true; + + // Only 1 stop callback supported. + EXPECT_TRUE(stop_callback_.is_null()); + stop_callback_ = std::move(callback); + + runner_->ShutdownServer(); +} + +void Manager::AddObserver(Observer* observer) { + CEF_REQUIRE_UI_THREAD(); + EXPECT_FALSE(stopping_); + observer_list_.push_back(observer); +} + +void Manager::RemoveObserver(Observer* observer) { + CEF_REQUIRE_UI_THREAD(); + bool found = false; + ObserverList::iterator it = observer_list_.begin(); + for (; it != observer_list_.end(); ++it) { + if (*it == observer) { + observer_list_.erase(it); + found = true; + break; + } + } + EXPECT_TRUE(found); +} + +void Manager::OnServerCreated(const std::string& server_origin) { + CEF_REQUIRE_UI_THREAD(); + + EXPECT_TRUE(origin_.empty()); + origin_ = server_origin; + + for (auto& callback : start_callback_list_) { + std::move(callback).Run(origin_); + } + start_callback_list_.clear(); +} + +void Manager::OnServerDestroyed() { + CEF_REQUIRE_UI_THREAD(); + + origin_.clear(); + runner_.reset(); +} + +// All server-related objects have been torn down. +void Manager::OnServerHandlerDeleted() { + CEF_REQUIRE_UI_THREAD(); + + EXPECT_FALSE(stop_callback_.is_null()); + std::move(stop_callback_).Run(); + + delete this; +} + +void Manager::OnHttpRequest(CefRefPtr request, + const ResponseCallback& response_callback) { + CEF_REQUIRE_UI_THREAD(); + + // TODO(chrome-runtime): Debug why favicon requests don't always have the + // correct resource type. + const std::string& url = request->GetURL(); + if (request->GetResourceType() == RT_FAVICON || + url.find("/favicon.ico") != std::string::npos) { + // We don't currently handle favicon requests. + response_callback.Run(Create404Response(), std::string()); + return; + } + + EXPECT_FALSE(observer_list_.empty()) << url; + + // Use a copy in case |observer_list_| is modified during iteration. + ObserverList list = observer_list_; + + bool handled = false; + + ObserverList::const_iterator it = list.begin(); + for (; it != list.end(); ++it) { + if ((*it)->OnHttpRequest(request, response_callback)) { + handled = true; + break; + } + } + + if (!handled) { + LOG(WARNING) << "Unhandled request for: " << url; + response_callback.Run(Create404Response(), std::string()); + } +} + +} // namespace test_server diff --git a/tests/ceftests/test_server_manager.h b/tests/ceftests/test_server_manager.h new file mode 100644 index 000000000..632bf7d96 --- /dev/null +++ b/tests/ceftests/test_server_manager.h @@ -0,0 +1,98 @@ +// Copyright (c) 2020 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_SERVER_MANAGER_H_ +#define CEF_TESTS_CEFTESTS_TEST_SERVER_MANAGER_H_ +#pragma once + +#include +#include + +#include "include/base/cef_callback.h" +#include "include/cef_registration.h" +#include "include/cef_request.h" +#include "include/cef_response.h" +#include "tests/ceftests/test_server_observer.h" +#include "tests/ceftests/test_server_runner.h" + +namespace test_server { + +class ObserverRegistration; + +// Static methods are safe to call on any thread. Non-static methods are only +// called on the UI thread. Deletes itself after the server is stopped. Use +// ObserverHelper instead of calling these methods directly. +class Manager : public Runner::Delegate { + public: + using StartDoneCallback = + base::OnceCallback; + using DoneCallback = base::OnceClosure; + + // Starts the server if it is not currently running, and executes |callback| + // on the UI thread. + static void Start(StartDoneCallback callback, bool https_server); + + // Stops the server if it is currently running, and executes |callback| on the + // UI thread. This method will be called by the test framework on shutdown. + static void Stop(DoneCallback callback, bool https_server); + + // Add an observer for server callbacks. Remains registered until the returned + // CefRegistration object is destroyed. Registered observers will be executed + // in the order of registration until one returns true to indicate that it + // handled the callback. |callback| will be executed on the UI thread after + // registration is complete. + static CefRefPtr AddObserver(Observer* observer, + DoneCallback callback, + bool https_server); + + // Combination of AddObserver() followed by Start(). + static CefRefPtr AddObserverAndStart( + Observer* observer, + StartDoneCallback callback, + bool https_server); + + private: + friend class ObserverRegistration; + + explicit Manager(bool https_server); + ~Manager(); + + static Manager* GetInstance(bool https_server); + static Manager* GetOrCreateInstance(bool https_server); + + void StartImpl(StartDoneCallback callback); + void StopImpl(DoneCallback callback); + + void AddObserver(Observer* observer); + void RemoveObserver(Observer* observer); + + // Runner::Delegate methods: + void OnServerCreated(const std::string& server_origin) override; + void OnServerDestroyed() override; + void OnServerHandlerDeleted() override; + void OnHttpRequest(CefRefPtr request, + const ResponseCallback& response_callback) override; + + private: + const bool https_server_; + + std::unique_ptr runner_; + std::string origin_; + + using StartDoneCallbackList = std::vector; + StartDoneCallbackList start_callback_list_; + + DoneCallback stop_callback_; + + using ObserverList = std::vector; + ObserverList observer_list_; + + bool stopping_ = false; + + DISALLOW_COPY_AND_ASSIGN(Manager); +}; + +} // namespace test_server + +#endif // CEF_TESTS_CEFTESTS_TEST_SERVER_MANAGER_H_ diff --git a/tests/ceftests/test_server_observer.cc b/tests/ceftests/test_server_observer.cc new file mode 100644 index 000000000..9422e40cb --- /dev/null +++ b/tests/ceftests/test_server_observer.cc @@ -0,0 +1,57 @@ +// Copyright (c) 2020 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. + +#include "tests/ceftests/test_server.h" + +#include "include/wrapper/cef_helpers.h" +#include "tests/ceftests/test_server_manager.h" +#include "tests/gtest/include/gtest/gtest.h" + +#include + +namespace test_server { + +ObserverHelper::ObserverHelper() : weak_ptr_factory_(this) { + CEF_REQUIRE_UI_THREAD(); +} + +ObserverHelper::~ObserverHelper() { + EXPECT_TRUE(state_ == State::NONE); +} + +void ObserverHelper::Initialize(bool https_server) { + CEF_REQUIRE_UI_THREAD(); + EXPECT_TRUE(state_ == State::NONE); + state_ = State::INITIALIZING; + registration_ = Manager::AddObserverAndStart( + this, + base::BindOnce(&ObserverHelper::OnStartDone, + weak_ptr_factory_.GetWeakPtr()), + https_server); +} + +void ObserverHelper::Shutdown() { + CEF_REQUIRE_UI_THREAD(); + EXPECT_TRUE(state_ == State::INITIALIZED); + state_ = State::SHUTTINGDOWN; + registration_ = nullptr; +} + +void ObserverHelper::OnStartDone(const std::string& server_origin) { + EXPECT_TRUE(state_ == State::INITIALIZING); + state_ = State::INITIALIZED; + OnInitialized(server_origin); +} + +void ObserverHelper::OnRegistered() { + EXPECT_TRUE(state_ == State::INITIALIZING); +} + +void ObserverHelper::OnUnregistered() { + EXPECT_TRUE(state_ == State::SHUTTINGDOWN); + state_ = State::NONE; + OnShutdown(); +} + +} // namespace test_server diff --git a/tests/ceftests/test_server_observer.h b/tests/ceftests/test_server_observer.h new file mode 100644 index 000000000..0e00b4224 --- /dev/null +++ b/tests/ceftests/test_server_observer.h @@ -0,0 +1,82 @@ +// Copyright (c) 2020 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_SERVER_OBSERVER_H_ +#define CEF_TESTS_CEFTESTS_TEST_SERVER_OBSERVER_H_ +#pragma once + +#include + +#include "include/base/cef_callback.h" +#include "include/base/cef_weak_ptr.h" +#include "include/cef_registration.h" +#include "include/cef_request.h" +#include "tests/ceftests/test_server.h" + +namespace test_server { + +// Observer for server callbacks. Methods will be called on the UI thread. +class Observer { + public: + using ResponseCallback = test_server::ResponseCallback; + + // Called when this Observer is registered. + virtual void OnRegistered() = 0; + + // Called when this Observer is unregistered. + virtual void OnUnregistered() = 0; + + // Return true and execute |response_callback| either synchronously or + // asynchronously if the request was handled. Do not execute + // |response_callback| when returning false. + virtual bool OnHttpRequest(CefRefPtr request, + const ResponseCallback& response_callback) = 0; + + protected: + virtual ~Observer() = default; +}; + +// Helper for managing Observer registration and callbacks. Only used on the UI +// thread. +class ObserverHelper : public Observer { + public: + ObserverHelper(); + ~ObserverHelper() override; + + // Initialize the registration. If |https_server| is true an HTTPS server will + // be used, otherwise an HTTP server will be used. Results in a call to + // OnInitialized(). + void Initialize(bool https_server = false); + + // Shut down the registration. Results in a call to OnShutdown(). + void Shutdown(); + + // Implement this method to start sending server requests after Initialize(). + virtual void OnInitialized(const std::string& server_origin) = 0; + + // Implement this method to continue the test after Shutdown(). + virtual void OnShutdown() = 0; + + private: + void OnStartDone(const std::string& server_origin); + void OnRegistered() override; + void OnUnregistered() override; + + CefRefPtr registration_; + + enum class State { + NONE, + INITIALIZING, + INITIALIZED, + SHUTTINGDOWN, + } state_ = State::NONE; + + base::WeakPtrFactory weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(ObserverHelper); +}; + +} // namespace test_server + +#endif // CEF_TESTS_CEFTESTS_TEST_SERVER_OBSERVER_H_ diff --git a/tests/ceftests/test_server_unittest.cc b/tests/ceftests/test_server_observer_unittest.cc similarity index 68% rename from tests/ceftests/test_server_unittest.cc rename to tests/ceftests/test_server_observer_unittest.cc index 7f6bbb28f..309e75c61 100644 --- a/tests/ceftests/test_server_unittest.cc +++ b/tests/ceftests/test_server_observer_unittest.cc @@ -10,7 +10,7 @@ #include "include/wrapper/cef_closure_task.h" #include "include/wrapper/cef_helpers.h" #include "tests/ceftests/test_request.h" -#include "tests/ceftests/test_server.h" +#include "tests/ceftests/test_server_observer.h" #include "tests/ceftests/track_callback.h" #include "tests/gtest/include/gtest/gtest.h" @@ -18,21 +18,16 @@ namespace { struct TestState { TrackCallback got_initialized_; - TrackCallback got_connected_; TrackCallback got_request_; TrackCallback got_response_; - TrackCallback got_disconnected_; TrackCallback got_shutdown_; bool ExpectAll() { EXPECT_TRUE(got_initialized_); - EXPECT_TRUE(got_connected_); EXPECT_TRUE(got_request_); EXPECT_TRUE(got_response_); - EXPECT_TRUE(got_disconnected_); EXPECT_TRUE(got_shutdown_); - return got_initialized_ && got_connected_ && got_request_ && - got_response_ && got_disconnected_ && got_shutdown_; + return got_initialized_ && got_request_ && got_response_ && got_shutdown_; } }; @@ -58,10 +53,8 @@ class TestServerObserver : public test_server::ObserverHelper { void OnInitialized(const std::string& server_origin) override { CEF_REQUIRE_UI_THREAD(); EXPECT_FALSE(state_->got_initialized_); - EXPECT_FALSE(state_->got_connected_); EXPECT_FALSE(state_->got_request_); EXPECT_FALSE(state_->got_response_); - EXPECT_FALSE(state_->got_disconnected_); EXPECT_FALSE(state_->got_shutdown_); state_->got_initialized_.yes(); @@ -77,49 +70,25 @@ class TestServerObserver : public test_server::ObserverHelper { weak_ptr_factory_.GetWeakPtr())); } - bool OnClientConnected(CefRefPtr server, - int connection_id) override { - CEF_REQUIRE_UI_THREAD(); - if (state_->got_connected_) { - // We already got the callback once. Let the next observer get the - // callback. - return false; - } - - EXPECT_TRUE(state_->got_initialized_); - EXPECT_FALSE(state_->got_request_); - EXPECT_FALSE(state_->got_response_); - EXPECT_FALSE(state_->got_disconnected_); - EXPECT_FALSE(state_->got_shutdown_); - - state_->got_connected_.yes(); - - // We don't know if this connection is the one that we're going to - // handle, so continue propagating the callback. - return false; - } - - bool OnHttpRequest(CefRefPtr server, - int connection_id, - const CefString& client_address, - CefRefPtr request) override { + bool OnHttpRequest(CefRefPtr request, + const ResponseCallback& response_callback) override { CEF_REQUIRE_UI_THREAD(); const std::string& url = request->GetURL(); if (url != url_) return false; EXPECT_TRUE(state_->got_initialized_); - EXPECT_TRUE(state_->got_connected_); EXPECT_FALSE(state_->got_request_); EXPECT_FALSE(state_->got_response_); - EXPECT_FALSE(state_->got_disconnected_); EXPECT_FALSE(state_->got_shutdown_); state_->got_request_.yes(); - connection_id_ = connection_id; - server->SendHttp200Response(connection_id, "text/plain", kResponseData, - sizeof(kResponseData) - 1); + auto response = CefResponse::Create(); + response->SetStatus(200); + response->SetMimeType("text/plain"); + + response_callback.Run(response, kResponseData); // Stop propagating the callback. return true; @@ -129,7 +98,6 @@ class TestServerObserver : public test_server::ObserverHelper { CEF_REQUIRE_UI_THREAD(); // Don't test for disconnected, which may race response. EXPECT_TRUE(state_->got_initialized_); - EXPECT_TRUE(state_->got_connected_); EXPECT_TRUE(state_->got_request_); EXPECT_FALSE(state_->got_response_); EXPECT_FALSE(state_->got_shutdown_); @@ -147,35 +115,11 @@ class TestServerObserver : public test_server::ObserverHelper { weak_ptr_factory_.GetWeakPtr())); } - bool OnClientDisconnected(CefRefPtr server, - int connection_id) override { - CEF_REQUIRE_UI_THREAD(); - if (connection_id != connection_id_) { - // Not the connection that we handled. Let the next observer get the - // callback. - return false; - } - - // Don't test for response, which may race disconnected. - EXPECT_TRUE(state_->got_initialized_); - EXPECT_TRUE(state_->got_connected_); - EXPECT_TRUE(state_->got_request_); - EXPECT_FALSE(state_->got_disconnected_); - EXPECT_FALSE(state_->got_shutdown_); - - state_->got_disconnected_.yes(); - - // Stop propagating the callback. - return true; - } - void OnShutdown() override { CEF_REQUIRE_UI_THREAD(); EXPECT_TRUE(state_->got_initialized_); - EXPECT_TRUE(state_->got_connected_); EXPECT_TRUE(state_->got_request_); EXPECT_TRUE(state_->got_response_); - EXPECT_TRUE(state_->got_disconnected_); EXPECT_FALSE(state_->got_shutdown_); state_->got_shutdown_.yes(); @@ -190,7 +134,6 @@ class TestServerObserver : public test_server::ObserverHelper { base::OnceClosure done_callback_; std::string url_; - int connection_id_ = -1; base::WeakPtrFactory weak_ptr_factory_; @@ -220,7 +163,7 @@ void SignalIfDone(CefRefPtr event, } // namespace -TEST(TestServerTest, ObserverHelperSingle) { +TEST(TestServerObserverTest, HelperSingle) { CefRefPtr event = CefWaitableEvent::CreateWaitableEvent(true, false); @@ -232,7 +175,7 @@ TEST(TestServerTest, ObserverHelperSingle) { EXPECT_TRUE(state.ExpectAll()); } -TEST(TestServerTest, ObserverHelperMultiple) { +TEST(TestServerObserverTest, HelperMultiple) { CefRefPtr event = CefWaitableEvent::CreateWaitableEvent(true, false); diff --git a/tests/ceftests/test_server_runner.cc b/tests/ceftests/test_server_runner.cc new file mode 100644 index 000000000..1980bba20 --- /dev/null +++ b/tests/ceftests/test_server_runner.cc @@ -0,0 +1,33 @@ +// Copyright (c) 2020 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. + +#include "tests/ceftests/test_server_runner.h" + +#include "tests/shared/common/client_switches.h" + +#include "include/base/cef_logging.h" +#include "include/cef_command_line.h" + +namespace test_server { + +Runner::Runner(Delegate* delegate) : delegate_(delegate) { + DCHECK(delegate_); +} + +// static +std::unique_ptr Runner::Create(Runner::Delegate* delegate, + bool https_server) { + static bool use_test_http_server = [] { + auto command_line = CefCommandLine::GetGlobalCommandLine(); + return command_line->HasSwitch(client::switches::kUseTestHttpServer); + }(); + + if (https_server || use_test_http_server) { + return CreateTest(delegate, https_server); + } + + return CreateNormal(delegate); +} + +} // namespace test_server diff --git a/tests/ceftests/test_server_runner.h b/tests/ceftests/test_server_runner.h new file mode 100644 index 000000000..250eeb83a --- /dev/null +++ b/tests/ceftests/test_server_runner.h @@ -0,0 +1,68 @@ +// Copyright (c) 2020 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_SERVER_RUNNER_H_ +#define CEF_TESTS_CEFTESTS_TEST_SERVER_RUNNER_H_ +#pragma once + +#include +#include + +#include "include/cef_request.h" +#include "include/internal/cef_types.h" +#include "tests/ceftests/test_server.h" + +namespace test_server { + +// Runs the server. All methods will be called on the UI thread. +class Runner { + public: + // Interface implemented by the Manager that creates/owns the Runner. + class Delegate { + public: + // Server created notification. + virtual void OnServerCreated(const std::string& server_origin) = 0; + + // Server destroyed notification. May delete the Runner. + virtual void OnServerDestroyed() = 0; + + // Server handler deleted notification. May delete the Manager. + virtual void OnServerHandlerDeleted() = 0; + + // Server request notification. + virtual void OnHttpRequest(CefRefPtr request, + const ResponseCallback& response_callback) = 0; + + protected: + virtual ~Delegate() = default; + }; + + // |delegate| will outlive this object. + explicit Runner(Delegate* delegate); + virtual ~Runner() = default; + + // Called by the Manager to create the Runner. + static std::unique_ptr Create(Delegate* delegate, bool https_server); + + // Called by the Manager to create/destroy the server handler. + virtual void StartServer() = 0; + virtual void ShutdownServer() = 0; + + private: + // Create a Runner based on CefServer. + static std::unique_ptr CreateNormal(Delegate* delegate); + + // Create a Runner based on CefTestServer. + static std::unique_ptr CreateTest(Delegate* delegate, + bool https_server); + + protected: + Delegate* const delegate_; + + DISALLOW_COPY_AND_ASSIGN(Runner); +}; + +} // namespace test_server + +#endif // CEF_TESTS_CEFTESTS_TEST_SERVER_RUNNER_H_ diff --git a/tests/ceftests/test_server_runner_normal.cc b/tests/ceftests/test_server_runner_normal.cc new file mode 100644 index 000000000..37b421584 --- /dev/null +++ b/tests/ceftests/test_server_runner_normal.cc @@ -0,0 +1,196 @@ +// Copyright (c) 2020 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. + +#include "tests/ceftests/test_server_runner.h" + +#include "include/cef_server.h" +#include "include/wrapper/cef_closure_task.h" +#include "include/wrapper/cef_helpers.h" +#include "tests/gtest/include/gtest/gtest.h" + +namespace test_server { + +namespace { + +const int kServerBacklog = 10; + +// Created on the UI thread and called on the dedicated server thread. +class ServerHandler : public CefServerHandler { + public: + explicit ServerHandler(Runner::Delegate* delegate) : delegate_(delegate) {} + + ~ServerHandler() override { + CEF_REQUIRE_UI_THREAD(); + EXPECT_FALSE(server_); + delegate_->OnServerHandlerDeleted(); + } + + void Shutdown() { server_->Shutdown(); } + + // CefServerHandler methods: + void OnServerCreated(CefRefPtr server) override { + EXPECT_TRUE(server->GetTaskRunner()->BelongsToCurrentThread()); + server_ = server; + NotifyServerCreated(kServerOrigin); + } + + void OnServerDestroyed(CefRefPtr server) override { + EXPECT_TRUE(server->GetTaskRunner()->BelongsToCurrentThread()); + server_ = nullptr; + NotifyServerDestroyed(); + } + + void OnClientConnected(CefRefPtr server, + int connection_id) override { + EXPECT_TRUE(server->GetTaskRunner()->BelongsToCurrentThread()); + EXPECT_TRUE(server->HasConnection()); + EXPECT_TRUE(server->IsValidConnection(connection_id)); + } + + void OnClientDisconnected(CefRefPtr server, + int connection_id) override { + EXPECT_TRUE(server->GetTaskRunner()->BelongsToCurrentThread()); + EXPECT_FALSE(server->IsValidConnection(connection_id)); + } + + void OnHttpRequest(CefRefPtr server, + int connection_id, + const CefString& client_address, + CefRefPtr request) override { + EXPECT_TRUE(server->GetTaskRunner()->BelongsToCurrentThread()); + NotifyHttpRequest(server, connection_id, client_address, request); + } + + void OnWebSocketRequest(CefRefPtr server, + int connection_id, + const CefString& client_address, + CefRefPtr request, + CefRefPtr callback) override {} + void OnWebSocketConnected(CefRefPtr server, + int connection_id) override {} + void OnWebSocketMessage(CefRefPtr server, + int connection_id, + const void* data, + size_t data_size) override {} + + private: + void NotifyServerCreated(const std::string& server_origin) { + if (!CefCurrentlyOn(TID_UI)) { + CefPostTask(TID_UI, base::BindOnce(&ServerHandler::NotifyServerCreated, + this, server_origin)); + return; + } + + delegate_->OnServerCreated(server_origin); + } + + void NotifyServerDestroyed() { + if (!CefCurrentlyOn(TID_UI)) { + CefPostTask(TID_UI, + base::BindOnce(&ServerHandler::NotifyServerDestroyed, this)); + return; + } + + delegate_->OnServerDestroyed(); + } + + void NotifyHttpRequest(CefRefPtr server, + int connection_id, + const CefString& client_address, + CefRefPtr request) { + if (!CefCurrentlyOn(TID_UI)) { + CefPostTask(TID_UI, base::BindOnce(&ServerHandler::NotifyHttpRequest, + this, server, connection_id, + client_address, request)); + return; + } + + auto response_callback = base::BindRepeating(&ServerHandler::SendResponse, + server, connection_id); + delegate_->OnHttpRequest(request, response_callback); + } + + static void SendResponse(CefRefPtr server, + int connection_id, + CefRefPtr response, + const std::string& response_data) { + // Execute on the server thread because some methods require it. + CefRefPtr task_runner = server->GetTaskRunner(); + if (!task_runner->BelongsToCurrentThread()) { + task_runner->PostTask(CefCreateClosureTask( + base::BindOnce(ServerHandler::SendResponse, server, connection_id, + response, response_data))); + return; + } + + // No response should be sent yet. + EXPECT_TRUE(server->IsValidConnection(connection_id)); + + const int response_code = response->GetStatus(); + if (response_code <= 0) { + // Intentionally not responding for incomplete request tests. + return; + } + + const CefString& content_type = response->GetMimeType(); + int64 content_length = static_cast(response_data.size()); + + CefResponse::HeaderMap extra_headers; + response->GetHeaderMap(extra_headers); + + server->SendHttpResponse(connection_id, response_code, content_type, + content_length, extra_headers); + + if (response_data == kIncompleteDoNotSendData) { + // Intentionally not sending data for incomplete request tests. + return; + } + + if (content_length != 0) { + server->SendRawData(connection_id, response_data.data(), + response_data.size()); + server->CloseConnection(connection_id); + } + + // The connection should be closed. + EXPECT_FALSE(server->IsValidConnection(connection_id)); + } + + Runner::Delegate* const delegate_; + CefRefPtr server_; + + IMPLEMENT_REFCOUNTING(ServerHandler); + DISALLOW_COPY_AND_ASSIGN(ServerHandler); +}; + +class ServerRunner : public Runner { + public: + explicit ServerRunner(Delegate* delegate) : Runner(delegate) {} + + void StartServer() override { + CEF_REQUIRE_UI_THREAD(); + DCHECK(!handler_); + handler_ = new ServerHandler(delegate_); + CefServer::CreateServer(kServerAddress, kServerPort, kServerBacklog, + handler_); + } + + void ShutdownServer() override { + CEF_REQUIRE_UI_THREAD(); + DCHECK(handler_); + handler_->Shutdown(); + handler_ = nullptr; + } + + private: + CefRefPtr handler_; +}; + +} // namespace + +std::unique_ptr Runner::CreateNormal(Delegate* delegate) { + return std::make_unique(delegate); +} + +} // namespace test_server diff --git a/tests/ceftests/test_server_runner_test.cc b/tests/ceftests/test_server_runner_test.cc new file mode 100644 index 000000000..3813edcb0 --- /dev/null +++ b/tests/ceftests/test_server_runner_test.cc @@ -0,0 +1,17 @@ +// Copyright (c) 2022 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. + +#include "tests/ceftests/test_server_runner.h" + +#include "include/base/cef_logging.h" + +namespace test_server { + +std::unique_ptr Runner::CreateTest(Delegate* delegate, + bool https_server) { + NOTREACHED(); + return nullptr; +} + +} // namespace test_server diff --git a/tests/ceftests/urlrequest_unittest.cc b/tests/ceftests/urlrequest_unittest.cc index 2e3cc7c9f..c49729880 100644 --- a/tests/ceftests/urlrequest_unittest.cc +++ b/tests/ceftests/urlrequest_unittest.cc @@ -19,7 +19,7 @@ #include "include/wrapper/cef_scoped_temp_dir.h" #include "tests/ceftests/test_handler.h" #include "tests/ceftests/test_request.h" -#include "tests/ceftests/test_server.h" +#include "tests/ceftests/test_server_observer.h" #include "tests/ceftests/test_suite.h" #include "tests/ceftests/test_util.h" #include "tests/gtest/include/gtest/gtest.h" diff --git a/tests/shared/common/client_switches.cc b/tests/shared/common/client_switches.cc index c56e42779..322451455 100644 --- a/tests/shared/common/client_switches.cc +++ b/tests/shared/common/client_switches.cc @@ -51,6 +51,7 @@ const char kInitialShowState[] = "initial-show-state"; const char kHideChromeStatusBubble[] = "hide-chrome-status-bubble"; const char kUseDefaultPopup[] = "use-default-popup"; const char kUseClientDialogs[] = "use-client-dialogs"; +const char kUseTestHttpServer[] = "use-test-http-server"; } // namespace switches } // namespace client diff --git a/tests/shared/common/client_switches.h b/tests/shared/common/client_switches.h index a9c4923bf..8d9d92b62 100644 --- a/tests/shared/common/client_switches.h +++ b/tests/shared/common/client_switches.h @@ -45,6 +45,7 @@ extern const char kInitialShowState[]; extern const char kHideChromeStatusBubble[]; extern const char kUseDefaultPopup[]; extern const char kUseClientDialogs[]; +extern const char kUseTestHttpServer[]; } // namespace switches } // namespace client