ceftests: Refactor test_server to support both HTTP and HTTPS servers (see issue #3348)
This commit is contained in:
parent
68be2b8938
commit
a4d63010c9
|
@ -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',
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -4,12 +4,9 @@
|
|||
|
||||
#include "tests/ceftests/test_server.h"
|
||||
|
||||
#include <vector>
|
||||
#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 <vector>
|
||||
|
||||
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<CefServer> server) override {
|
||||
server_ = server;
|
||||
NotifyServerCreated(kServerOrigin);
|
||||
}
|
||||
|
||||
void OnServerDestroyed(CefRefPtr<CefServer> server) override {
|
||||
server_ = nullptr;
|
||||
NotifyServerDestroyed();
|
||||
}
|
||||
|
||||
void OnClientConnected(CefRefPtr<CefServer> server,
|
||||
int connection_id) override {
|
||||
EXPECT_TRUE(server->HasConnection());
|
||||
EXPECT_TRUE(server->IsValidConnection(connection_id));
|
||||
}
|
||||
|
||||
void OnClientDisconnected(CefRefPtr<CefServer> server,
|
||||
int connection_id) override {
|
||||
EXPECT_FALSE(server->IsValidConnection(connection_id));
|
||||
}
|
||||
|
||||
void OnHttpRequest(CefRefPtr<CefServer> server,
|
||||
int connection_id,
|
||||
const CefString& client_address,
|
||||
CefRefPtr<CefRequest> request) override {
|
||||
NotifyHttpRequest(server, connection_id, client_address, request);
|
||||
}
|
||||
|
||||
void OnWebSocketRequest(CefRefPtr<CefServer> server,
|
||||
int connection_id,
|
||||
const CefString& client_address,
|
||||
CefRefPtr<CefRequest> request,
|
||||
CefRefPtr<CefCallback> callback) override {}
|
||||
void OnWebSocketConnected(CefRefPtr<CefServer> server,
|
||||
int connection_id) override {}
|
||||
void OnWebSocketMessage(CefRefPtr<CefServer> 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<CefServer> server,
|
||||
int connection_id,
|
||||
const CefString& client_address,
|
||||
CefRefPtr<CefRequest> request);
|
||||
|
||||
CefRefPtr<CefServer> 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<CefServer> server,
|
||||
int connection_id,
|
||||
const CefString& client_address,
|
||||
CefRefPtr<CefRequest> 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<CefServer> server,
|
||||
int connection_id,
|
||||
CefRefPtr<CefResponse> response,
|
||||
const std::string& response_data) {
|
||||
// Execute on the server thread because some methods require it.
|
||||
CefRefPtr<CefTaskRunner> 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<int64>(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<ServerHandler> handler_;
|
||||
std::string origin_;
|
||||
|
||||
using StartDoneCallbackList = std::vector<StartDoneCallback>;
|
||||
StartDoneCallbackList start_callback_list_;
|
||||
|
||||
DoneCallback stop_callback_;
|
||||
|
||||
using ObserverList = std::vector<Observer*>;
|
||||
ObserverList observer_list_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ServerManager);
|
||||
};
|
||||
|
||||
ServerManager* GetServerManager() {
|
||||
return g_manager;
|
||||
CefRefPtr<CefResponse> 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<CefServer> server,
|
||||
int connection_id,
|
||||
const CefString& client_address,
|
||||
CefRefPtr<CefRequest> 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<ObserverRegistration> 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<CefRegistration> AddObserver(Observer* observer,
|
||||
DoneCallback callback) {
|
||||
EXPECT_TRUE(observer);
|
||||
CefRefPtr<ObserverRegistration> registration =
|
||||
new ObserverRegistration(observer);
|
||||
InitializeRegistration(registration, std::move(callback));
|
||||
return registration.get();
|
||||
}
|
||||
|
||||
CefRefPtr<CefRegistration> 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
|
||||
|
|
|
@ -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<CefResponse> Create404Response();
|
||||
|
||||
using StartDoneCallback =
|
||||
base::OnceCallback<void(const std::string& server_origin)>;
|
||||
using ResponseCallback =
|
||||
base::RepeatingCallback<void(CefRefPtr<CefResponse> 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<void(CefRefPtr<CefResponse> 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<CefRequest> 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<CefRegistration> AddObserver(Observer* observer,
|
||||
DoneCallback callback);
|
||||
|
||||
// Combination of AddObserver() followed by Start().
|
||||
CefRefPtr<CefRegistration> 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<CefRegistration> registration_;
|
||||
|
||||
enum class State {
|
||||
NONE,
|
||||
INITIALIZING,
|
||||
INITIALIZED,
|
||||
SHUTTINGDOWN,
|
||||
} state_ = State::NONE;
|
||||
|
||||
base::WeakPtrFactory<ObserverHelper> weak_ptr_factory_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ObserverHelper);
|
||||
};
|
||||
void Stop(base::OnceClosure callback);
|
||||
|
||||
} // namespace test_server
|
||||
|
||||
|
|
|
@ -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<ObserverRegistration> 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<CefRegistration> Manager::AddObserver(Observer* observer,
|
||||
DoneCallback callback,
|
||||
bool https_server) {
|
||||
EXPECT_TRUE(observer);
|
||||
CefRefPtr<ObserverRegistration> registration =
|
||||
new ObserverRegistration(observer, https_server);
|
||||
ObserverRegistration::InitializeRegistration(registration,
|
||||
std::move(callback));
|
||||
return registration.get();
|
||||
}
|
||||
|
||||
// static
|
||||
CefRefPtr<CefRegistration> 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<CefRequest> 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
|
|
@ -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 <string>
|
||||
#include <vector>
|
||||
|
||||
#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<void(const std::string& server_origin)>;
|
||||
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<CefRegistration> AddObserver(Observer* observer,
|
||||
DoneCallback callback,
|
||||
bool https_server);
|
||||
|
||||
// Combination of AddObserver() followed by Start().
|
||||
static CefRefPtr<CefRegistration> 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<CefRequest> request,
|
||||
const ResponseCallback& response_callback) override;
|
||||
|
||||
private:
|
||||
const bool https_server_;
|
||||
|
||||
std::unique_ptr<Runner> runner_;
|
||||
std::string origin_;
|
||||
|
||||
using StartDoneCallbackList = std::vector<StartDoneCallback>;
|
||||
StartDoneCallbackList start_callback_list_;
|
||||
|
||||
DoneCallback stop_callback_;
|
||||
|
||||
using ObserverList = std::vector<Observer*>;
|
||||
ObserverList observer_list_;
|
||||
|
||||
bool stopping_ = false;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Manager);
|
||||
};
|
||||
|
||||
} // namespace test_server
|
||||
|
||||
#endif // CEF_TESTS_CEFTESTS_TEST_SERVER_MANAGER_H_
|
|
@ -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 <vector>
|
||||
|
||||
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
|
|
@ -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 <string>
|
||||
|
||||
#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<CefRequest> 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<CefRegistration> registration_;
|
||||
|
||||
enum class State {
|
||||
NONE,
|
||||
INITIALIZING,
|
||||
INITIALIZED,
|
||||
SHUTTINGDOWN,
|
||||
} state_ = State::NONE;
|
||||
|
||||
base::WeakPtrFactory<ObserverHelper> weak_ptr_factory_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ObserverHelper);
|
||||
};
|
||||
|
||||
} // namespace test_server
|
||||
|
||||
#endif // CEF_TESTS_CEFTESTS_TEST_SERVER_OBSERVER_H_
|
|
@ -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<CefServer> 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<CefServer> server,
|
||||
int connection_id,
|
||||
const CefString& client_address,
|
||||
CefRefPtr<CefRequest> request) override {
|
||||
bool OnHttpRequest(CefRefPtr<CefRequest> 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<CefServer> 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<TestServerObserver> weak_ptr_factory_;
|
||||
|
||||
|
@ -220,7 +163,7 @@ void SignalIfDone(CefRefPtr<CefWaitableEvent> event,
|
|||
|
||||
} // namespace
|
||||
|
||||
TEST(TestServerTest, ObserverHelperSingle) {
|
||||
TEST(TestServerObserverTest, HelperSingle) {
|
||||
CefRefPtr<CefWaitableEvent> event =
|
||||
CefWaitableEvent::CreateWaitableEvent(true, false);
|
||||
|
||||
|
@ -232,7 +175,7 @@ TEST(TestServerTest, ObserverHelperSingle) {
|
|||
EXPECT_TRUE(state.ExpectAll());
|
||||
}
|
||||
|
||||
TEST(TestServerTest, ObserverHelperMultiple) {
|
||||
TEST(TestServerObserverTest, HelperMultiple) {
|
||||
CefRefPtr<CefWaitableEvent> event =
|
||||
CefWaitableEvent::CreateWaitableEvent(true, false);
|
||||
|
|
@ -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> 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
|
|
@ -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 <memory>
|
||||
#include <string>
|
||||
|
||||
#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<CefRequest> 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<Runner> 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<Runner> CreateNormal(Delegate* delegate);
|
||||
|
||||
// Create a Runner based on CefTestServer.
|
||||
static std::unique_ptr<Runner> 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_
|
|
@ -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<CefServer> server) override {
|
||||
EXPECT_TRUE(server->GetTaskRunner()->BelongsToCurrentThread());
|
||||
server_ = server;
|
||||
NotifyServerCreated(kServerOrigin);
|
||||
}
|
||||
|
||||
void OnServerDestroyed(CefRefPtr<CefServer> server) override {
|
||||
EXPECT_TRUE(server->GetTaskRunner()->BelongsToCurrentThread());
|
||||
server_ = nullptr;
|
||||
NotifyServerDestroyed();
|
||||
}
|
||||
|
||||
void OnClientConnected(CefRefPtr<CefServer> server,
|
||||
int connection_id) override {
|
||||
EXPECT_TRUE(server->GetTaskRunner()->BelongsToCurrentThread());
|
||||
EXPECT_TRUE(server->HasConnection());
|
||||
EXPECT_TRUE(server->IsValidConnection(connection_id));
|
||||
}
|
||||
|
||||
void OnClientDisconnected(CefRefPtr<CefServer> server,
|
||||
int connection_id) override {
|
||||
EXPECT_TRUE(server->GetTaskRunner()->BelongsToCurrentThread());
|
||||
EXPECT_FALSE(server->IsValidConnection(connection_id));
|
||||
}
|
||||
|
||||
void OnHttpRequest(CefRefPtr<CefServer> server,
|
||||
int connection_id,
|
||||
const CefString& client_address,
|
||||
CefRefPtr<CefRequest> request) override {
|
||||
EXPECT_TRUE(server->GetTaskRunner()->BelongsToCurrentThread());
|
||||
NotifyHttpRequest(server, connection_id, client_address, request);
|
||||
}
|
||||
|
||||
void OnWebSocketRequest(CefRefPtr<CefServer> server,
|
||||
int connection_id,
|
||||
const CefString& client_address,
|
||||
CefRefPtr<CefRequest> request,
|
||||
CefRefPtr<CefCallback> callback) override {}
|
||||
void OnWebSocketConnected(CefRefPtr<CefServer> server,
|
||||
int connection_id) override {}
|
||||
void OnWebSocketMessage(CefRefPtr<CefServer> 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<CefServer> server,
|
||||
int connection_id,
|
||||
const CefString& client_address,
|
||||
CefRefPtr<CefRequest> 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<CefServer> server,
|
||||
int connection_id,
|
||||
CefRefPtr<CefResponse> response,
|
||||
const std::string& response_data) {
|
||||
// Execute on the server thread because some methods require it.
|
||||
CefRefPtr<CefTaskRunner> 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<int64>(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<CefServer> 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<ServerHandler> handler_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<Runner> Runner::CreateNormal(Delegate* delegate) {
|
||||
return std::make_unique<ServerRunner>(delegate);
|
||||
}
|
||||
|
||||
} // namespace test_server
|
|
@ -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> Runner::CreateTest(Delegate* delegate,
|
||||
bool https_server) {
|
||||
NOTREACHED();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace test_server
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue