ceftests: Add shared test_request and test_server implementations

To reduce text execution time and flakyness this change also
introduces a global test server that is initialized when needed
and torn down after all tests have completed.
This commit is contained in:
Marshall Greenblatt 2020-08-19 18:27:27 -04:00
parent d63e5bbd8a
commit b09cd1a197
10 changed files with 1201 additions and 315 deletions

View File

@ -520,6 +520,11 @@
'tests/ceftests/task_unittest.cc',
'tests/ceftests/test_handler.cc',
'tests/ceftests/test_handler.h',
'tests/ceftests/test_request.cc',
'tests/ceftests/test_request.h',
'tests/ceftests/test_server.cc',
'tests/ceftests/test_server.h',
'tests/ceftests/test_server_unittest.cc',
'tests/ceftests/test_suite.cc',
'tests/ceftests/test_suite.h',
'tests/ceftests/test_util.cc',
@ -588,6 +593,10 @@
'tests/ceftests/urlrequest_unittest.cc',
'tests/ceftests/test_handler.cc',
'tests/ceftests/test_handler.h',
'tests/ceftests/test_request.cc',
'tests/ceftests/test_request.h',
'tests/ceftests/test_server.cc',
'tests/ceftests/test_server.h',
'tests/ceftests/test_suite.cc',
'tests/ceftests/test_suite.h',
'tests/ceftests/test_util.cc',

View File

@ -15,6 +15,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_suite.h"
#include "tests/ceftests/test_util.h"
#include "tests/gtest/include/gtest/gtest.h"
@ -1050,30 +1051,29 @@ namespace {
const char kCookieAccessScheme[] = "http";
const char kCookieAccessDomain[] = "test-cookies.com";
const char kCookieAccessServerIP[] = "127.0.0.1";
const uint16 kCookieAccessServerPort = 8099;
const char* kCookieAccessServerAddress = test_server::kServerAddress;
const uint16 kCookieAccessServerPort = test_server::kServerPort;
std::string GetCookieAccessOrigin(const std::string& scheme,
bool server_backend) {
std::stringstream ss;
if (server_backend) {
ss << scheme << "://" << kCookieAccessServerIP << ":"
ss << scheme << "://" << kCookieAccessServerAddress << ":"
<< kCookieAccessServerPort;
} else {
ss << scheme << "://" << kCookieAccessDomain;
}
ss << "/";
return ss.str();
}
std::string GetCookieAccessUrl1(const std::string& scheme,
bool server_backend) {
return GetCookieAccessOrigin(scheme, server_backend) + "cookie1.html";
return GetCookieAccessOrigin(scheme, server_backend) + "/cookie1.html";
}
std::string GetCookieAccessUrl2(const std::string& scheme,
bool server_backend) {
return GetCookieAccessOrigin(scheme, server_backend) + "cookie2.html";
return GetCookieAccessOrigin(scheme, server_backend) + "/cookie2.html";
}
void TestCookieString(const std::string& cookie_str,
@ -1248,7 +1248,7 @@ class CookieAccessSchemeHandlerFactory : public CefSchemeHandlerFactory,
};
// HTTP server handler.
class CookieAccessServerHandler : public CefServerHandler,
class CookieAccessServerHandler : public test_server::ObserverHelper,
public CookieAccessResponseHandler {
public:
CookieAccessServerHandler()
@ -1288,8 +1288,7 @@ class CookieAccessServerHandler : public CefServerHandler,
EXPECT_TRUE(complete_callback_.is_null());
complete_callback_ = complete_callback;
CefServer::CreateServer(kCookieAccessServerIP, kCookieAccessServerPort, 10,
this);
Initialize();
}
// Results in a call to VerifyResults() and eventual execution of the
@ -1301,73 +1300,60 @@ class CookieAccessServerHandler : public CefServerHandler,
EXPECT_TRUE(complete_callback_.is_null());
complete_callback_ = complete_callback;
EXPECT_TRUE(server_);
if (server_)
server_->Shutdown();
Shutdown();
}
void OnServerCreated(CefRefPtr<CefServer> server) override {
EXPECT_TRUE(server);
EXPECT_TRUE(server->IsRunning());
EXPECT_FALSE(server->HasConnection());
void OnInitialized(const std::string& server_origin) override {
EXPECT_UI_THREAD();
EXPECT_STREQ(server_origin.c_str(),
GetCookieAccessOrigin(kCookieAccessScheme, true).c_str());
EXPECT_FALSE(got_server_created_);
got_server_created_.yes();
EXPECT_FALSE(server_);
server_ = server;
EXPECT_FALSE(server_runner_);
server_runner_ = server_->GetTaskRunner();
EXPECT_TRUE(server_runner_);
EXPECT_TRUE(server_runner_->BelongsToCurrentThread());
CefPostTask(
TID_UI,
base::Bind(&CookieAccessServerHandler::RunCompleteCallback, this));
RunCompleteCallback();
}
void OnServerDestroyed(CefRefPtr<CefServer> server) override {
EXPECT_TRUE(VerifyServer(server));
EXPECT_FALSE(server->IsRunning());
EXPECT_FALSE(server->HasConnection());
void OnShutdown() override {
EXPECT_UI_THREAD();
EXPECT_FALSE(got_server_destroyed_);
got_server_destroyed_.yes();
server_ = nullptr;
VerifyResults();
delete this;
}
void OnClientConnected(CefRefPtr<CefServer> server,
bool OnClientConnected(CefRefPtr<CefServer> server,
int connection_id) override {
EXPECT_TRUE(VerifyServer(server));
EXPECT_TRUE(server->HasConnection());
EXPECT_TRUE(server->IsValidConnection(connection_id));
EXPECT_UI_THREAD();
EXPECT_TRUE(connection_id_set_.find(connection_id) ==
connection_id_set_.end());
connection_id_set_.insert(connection_id);
actual_connection_ct_++;
return true;
}
void OnClientDisconnected(CefRefPtr<CefServer> server,
bool OnClientDisconnected(CefRefPtr<CefServer> server,
int connection_id) override {
EXPECT_TRUE(VerifyServer(server));
EXPECT_FALSE(server->IsValidConnection(connection_id));
EXPECT_UI_THREAD();
ConnectionIdSet::iterator it = connection_id_set_.find(connection_id);
EXPECT_TRUE(it != connection_id_set_.end());
connection_id_set_.erase(it);
return true;
}
void OnHttpRequest(CefRefPtr<CefServer> server,
bool OnHttpRequest(CefRefPtr<CefServer> server,
int connection_id,
const CefString& client_address,
CefRefPtr<CefRequest> request) override {
EXPECT_TRUE(VerifyServer(server));
EXPECT_UI_THREAD();
EXPECT_TRUE(VerifyConnection(connection_id));
EXPECT_FALSE(client_address.empty());
@ -1378,50 +1364,16 @@ class CookieAccessServerHandler : public CefServerHandler,
HandleRequest(server, connection_id, request);
actual_http_request_ct_++;
}
void OnWebSocketRequest(CefRefPtr<CefServer> server,
int connection_id,
const CefString& client_address,
CefRefPtr<CefRequest> request,
CefRefPtr<CefCallback> callback) override {
NOTREACHED();
}
void OnWebSocketConnected(CefRefPtr<CefServer> server,
int connection_id) override {
NOTREACHED();
}
void OnWebSocketMessage(CefRefPtr<CefServer> server,
int connection_id,
const void* data,
size_t data_size) override {
NOTREACHED();
return true;
}
private:
bool RunningOnServerThread() {
return server_runner_ && server_runner_->BelongsToCurrentThread();
}
bool VerifyServer(CefRefPtr<CefServer> server) {
V_DECLARE();
V_EXPECT_TRUE(RunningOnServerThread());
V_EXPECT_TRUE(server);
V_EXPECT_TRUE(server_);
V_EXPECT_TRUE(server->GetAddress().ToString() ==
server_->GetAddress().ToString());
V_RETURN();
}
bool VerifyConnection(int connection_id) {
return connection_id_set_.find(connection_id) != connection_id_set_.end();
}
void VerifyResults() {
EXPECT_TRUE(RunningOnServerThread());
EXPECT_TRUE(got_server_created_);
EXPECT_TRUE(got_server_destroyed_);
EXPECT_TRUE(connection_id_set_.empty());
@ -1453,10 +1405,19 @@ class CookieAccessServerHandler : public CefServerHandler,
}
}
void SendResponse(CefRefPtr<CefServer> server,
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::Bind(CookieAccessServerHandler::SendResponse, server,
connection_id, response, response_data)));
return;
}
int response_code = response->GetStatus();
const CefString& content_type = response->GetMimeType();
int64 content_length = static_cast<int64>(response_data.size());
@ -1489,8 +1450,6 @@ class CookieAccessServerHandler : public CefServerHandler,
typedef std::map<std::string, CookieAccessData*> ResponseDataMap;
ResponseDataMap data_map_;
CefRefPtr<CefServer> server_;
CefRefPtr<CefTaskRunner> server_runner_;
bool initialized_;
// Only accessed on the UI thread.
@ -1512,7 +1471,6 @@ class CookieAccessServerHandler : public CefServerHandler,
std::string request_log_;
IMPLEMENT_REFCOUNTING(CookieAccessServerHandler);
DISALLOW_COPY_AND_ASSIGN(CookieAccessServerHandler);
};
@ -1833,7 +1791,7 @@ class CookieAccessTestHandler : public RoutingTestHandler,
EXPECT_FALSE(server_handler_);
server_handler_ = new CookieAccessServerHandler();
AddResponses(server_handler_.get());
AddResponses(server_handler_);
server_handler_->CreateServer(complete_callback);
}
@ -1911,6 +1869,7 @@ class CookieAccessTestHandler : public RoutingTestHandler,
void ShutdownServer(const base::Closure& complete_callback) {
EXPECT_TRUE(server_handler_);
// |server_handler_| will delete itself after shutdown.
server_handler_->ShutdownServer(complete_callback);
server_handler_ = nullptr;
}
@ -1933,7 +1892,7 @@ class CookieAccessTestHandler : public RoutingTestHandler,
CefRefPtr<CefRequestContext> context_;
CefRefPtr<CefCookieManager> cookie_manager_;
CefRefPtr<CookieAccessServerHandler> server_handler_;
CookieAccessServerHandler* server_handler_ = nullptr;
CefRefPtr<CookieAccessSchemeHandlerFactory> scheme_factory_;
CookieAccessData data1_;
@ -2292,7 +2251,7 @@ class CookieRestartTestHandler : public RoutingTestHandler,
EXPECT_FALSE(server_handler_);
server_handler_ = new CookieAccessServerHandler();
AddResponses(server_handler_.get());
AddResponses(server_handler_);
// 2 requests for each URL.
server_handler_->SetExpectedRequestCount(4);
server_handler_->CreateServer(complete_callback);
@ -2351,6 +2310,7 @@ class CookieRestartTestHandler : public RoutingTestHandler,
void ShutdownServer(const base::Closure& complete_callback) {
EXPECT_TRUE(server_handler_);
// |server_handler_| will delete itself after shutdown.
server_handler_->ShutdownServer(complete_callback);
server_handler_ = nullptr;
}
@ -2360,7 +2320,7 @@ class CookieRestartTestHandler : public RoutingTestHandler,
CefRefPtr<CefRequestContext> context_;
CefRefPtr<CefCookieManager> cookie_manager_;
CefRefPtr<CookieAccessServerHandler> server_handler_;
CookieAccessServerHandler* server_handler_ = nullptr;
CookieAccessData data1_;
CookieAccessData data2_;

View File

@ -20,9 +20,11 @@
#include "include/cef_app.h"
#include "include/cef_task.h"
#include "include/cef_thread.h"
#include "include/cef_waitable_event.h"
#include "include/wrapper/cef_closure_task.h"
#include "include/wrapper/cef_helpers.h"
#include "tests/ceftests/test_handler.h"
#include "tests/ceftests/test_server.h"
#include "tests/ceftests/test_suite.h"
#include "tests/shared/browser/client_app_browser.h"
#include "tests/shared/browser/main_message_loop_external_pump.h"
@ -48,6 +50,7 @@
namespace {
void QuitMessageLoop() {
CEF_REQUIRE_UI_THREAD();
client::MainMessageLoop* message_loop = client::MainMessageLoop::Get();
if (message_loop)
message_loop->Quit();
@ -74,8 +77,8 @@ void RunTestsOnTestThread() {
while (TestHandler::HasBrowser())
sleep(100);
// Quit the CEF message loop.
CefPostTask(TID_UI, base::Bind(&QuitMessageLoop));
// Wait for the test server to stop, and then quit the CEF message loop.
test_server::Stop(base::Bind(QuitMessageLoop));
}
// Called on the UI thread.
@ -201,6 +204,12 @@ int main(int argc, char* argv[]) {
if (settings.multi_threaded_message_loop) {
// Run the test suite on the main thread.
retval = test_suite.Run();
// Wait for the test server to stop.
CefRefPtr<CefWaitableEvent> event =
CefWaitableEvent::CreateWaitableEvent(true, false);
test_server::Stop(base::Bind(&CefWaitableEvent::Signal, event));
event->Wait();
} else {
// Create and start the test thread.
CefRefPtr<CefThread> thread = CefThread::CreateThread("test_thread");

View File

@ -20,6 +20,7 @@
namespace {
// Must use a different port than test_server.cc.
const char kTestServerAddress[] = "127.0.0.1";
const uint16 kTestServerPort = 8099;
const int kTestTimeout = 5000;
@ -27,7 +28,7 @@ const int kTestTimeout = 5000;
std::string GetTestServerOrigin(bool is_websocket) {
std::stringstream ss;
ss << (is_websocket ? "ws://" : "http://") << kTestServerAddress << ":"
<< kTestServerPort << "/";
<< kTestServerPort;
return ss.str();
}
@ -793,7 +794,7 @@ CefRefPtr<CefRequest> CreateTestServerRequest(
const std::string& content_type = std::string(),
const CefRequest::HeaderMap& extra_headers = CefRequest::HeaderMap()) {
CefRefPtr<CefRequest> request = CefRequest::Create();
request->SetURL(GetTestServerOrigin(false) + path);
request->SetURL(GetTestServerOrigin(false) + "/" + path);
request->SetMethod(method);
CefRequest::HeaderMap header_map;
@ -1277,7 +1278,7 @@ class EchoWebSocketRequestHandler : public TestServerHandler::WsRequestHandler {
explicit EchoWebSocketRequestHandler(int expected_message_ct)
: expected_message_ct_(expected_message_ct), actual_message_ct_(0) {}
std::string GetWebSocketUrl() { return GetTestServerOrigin(true) + "echo"; }
std::string GetWebSocketUrl() { return GetTestServerOrigin(true) + "/echo"; }
bool HandleRequest(CefRefPtr<CefServer> server,
int connection_id,

View File

@ -0,0 +1,109 @@
// 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_request.h"
#include "include/cef_urlrequest.h"
#include "include/wrapper/cef_closure_task.h"
#include "include/wrapper/cef_helpers.h"
namespace test_request {
namespace {
// Implementation of CefURLRequestClient that stores response information.
class RequestClient : public CefURLRequestClient, public State {
public:
RequestClient(const bool has_credentials,
const std::string& username,
const std::string& password,
const RequestDoneCallback& done_callback)
: has_credentials_(has_credentials),
username_(username),
password_(password),
done_callback_(done_callback) {
DCHECK(!done_callback_.is_null());
}
void OnUploadProgress(CefRefPtr<CefURLRequest> request,
int64 current,
int64 total) override {
upload_progress_ct_++;
upload_total_ = total;
}
void OnDownloadProgress(CefRefPtr<CefURLRequest> request,
int64 current,
int64 total) override {
response_ = request->GetResponse();
DCHECK(response_.get());
DCHECK(response_->IsReadOnly());
download_progress_ct_++;
download_total_ = total;
}
void OnDownloadData(CefRefPtr<CefURLRequest> request,
const void* data,
size_t data_length) override {
response_ = request->GetResponse();
DCHECK(response_.get());
DCHECK(response_->IsReadOnly());
download_data_ct_++;
download_data_ += std::string(static_cast<const char*>(data), data_length);
}
bool GetAuthCredentials(bool isProxy,
const CefString& host,
int port,
const CefString& realm,
const CefString& scheme,
CefRefPtr<CefAuthCallback> callback) override {
auth_credentials_ct_++;
if (has_credentials_) {
callback->Continue(username_, password_);
return true;
}
return false;
}
void OnRequestComplete(CefRefPtr<CefURLRequest> request) override {
request_complete_ct_++;
request_ = request->GetRequest();
DCHECK(request_->IsReadOnly());
status_ = request->GetRequestStatus();
error_code_ = request->GetRequestError();
response_was_cached_ = request->ResponseWasCached();
response_ = request->GetResponse();
if (response_) {
DCHECK(response_->IsReadOnly());
}
done_callback_.Run(*this);
}
private:
const bool has_credentials_;
const std::string username_;
const std::string password_;
const RequestDoneCallback done_callback_;
IMPLEMENT_REFCOUNTING(RequestClient);
};
} // namespace
void Send(const SendConfig& config, const RequestDoneCallback& callback) {
DCHECK(config.request_);
CefRefPtr<RequestClient> client = new RequestClient(
config.has_credentials_, config.username_, config.password_, callback);
if (config.frame_) {
config.frame_->CreateURLRequest(config.request_, client.get());
} else {
CefURLRequest::Create(config.request_, client.get(),
config.request_context_);
}
}
} // namespace test_request

View File

@ -0,0 +1,69 @@
// 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_REQUEST_H_
#define CEF_TESTS_CEFTESTS_TEST_REQUEST_H_
#pragma once
#include <string>
#include "include/base/cef_bind.h"
#include "include/cef_frame.h"
#include "include/cef_request.h"
#include "include/cef_request_context.h"
#include "include/cef_response.h"
namespace test_request {
// Stores all state passed to CefURLRequestClient.
struct State {
public:
// Number of times each callback is executed.
int upload_progress_ct_ = 0;
int download_progress_ct_ = 0;
int download_data_ct_ = 0;
int auth_credentials_ct_ = 0;
int request_complete_ct_ = 0;
// From OnUploadProgress.
int64 upload_total_ = 0;
// From OnDownloadProgress.
int64 download_total_ = 0;
// From OnDownloadData.
std::string download_data_;
// From OnRequestComplete.
CefRefPtr<CefRequest> request_;
cef_urlrequest_status_t status_ = UR_UNKNOWN;
cef_errorcode_t error_code_ = ERR_NONE;
CefRefPtr<CefResponse> response_;
bool response_was_cached_ = false;
};
typedef base::Callback<void(const State& state)> RequestDoneCallback;
struct SendConfig {
// Send using |frame_| or |request_context_| if non-nullptr.
// Sends using the global request context if both are nullptr.
CefRefPtr<CefFrame> frame_;
CefRefPtr<CefRequestContext> request_context_;
// The request to send.
CefRefPtr<CefRequest> request_;
// Returned via GetAuthCredentials if |has_credentials_| is true.
bool has_credentials_ = false;
std::string username_;
std::string password_;
};
// Send a request. |callback| will be executed on the calling thread after the
// request completes.
void Send(const SendConfig& config, const RequestDoneCallback& callback);
} // namespace test_request
#endif // CEF_TESTS_CEFTESTS_TEST_REQUEST_H_

View File

@ -0,0 +1,492 @@
// 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 <vector>
#include "include/wrapper/cef_closure_task.h"
#include "include/wrapper/cef_helpers.h"
namespace test_server {
// Must use a different port than server_unittest.cc.
const char kServerAddress[] = "127.0.0.1";
const uint16 kServerPort = 8098;
const char kServerScheme[] = "http";
const char kServerOrigin[] = "http://127.0.0.1:8098";
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 {
DCHECK(!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 {
DCHECK(server->HasConnection());
DCHECK(server->IsValidConnection(connection_id));
NotifyClientConnected(server, connection_id);
}
void OnClientDisconnected(CefRefPtr<CefServer> server,
int connection_id) override {
DCHECK(!server->IsValidConnection(connection_id));
NotifyClientDisconnected(server, 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 NotifyClientConnected(CefRefPtr<CefServer> server,
int connection_id);
static void NotifyClientDisconnected(CefRefPtr<CefServer> server,
int connection_id);
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();
DCHECK(!g_manager);
g_manager = this;
}
~ServerManager() {
CEF_REQUIRE_UI_THREAD();
DCHECK(observer_list_.empty());
DCHECK(start_callback_list_.empty());
DCHECK(stop_callback_.is_null());
g_manager = nullptr;
}
void Start(const StartDoneCallback& callback) {
CEF_REQUIRE_UI_THREAD();
if (!origin_.empty()) {
// The server is already running.
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(callback);
// Only create the handler a single time.
if (!handler_) {
handler_ = new ServerHandler();
}
}
void Stop(const DoneCallback& callback) {
CEF_REQUIRE_UI_THREAD();
if (!handler_) {
// The server is not currently running.
callback.Run();
return;
}
// Only 1 stop callback supported.
DCHECK(stop_callback_.is_null());
stop_callback_ = 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;
}
}
DCHECK(found);
}
void NotifyServerCreated(const std::string& server_origin) {
CEF_REQUIRE_UI_THREAD();
DCHECK(origin_.empty());
origin_ = server_origin;
StartDoneCallbackList::const_iterator it = start_callback_list_.begin();
for (; it != start_callback_list_.end(); ++it) {
(*it).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();
DCHECK(!stop_callback_.is_null());
stop_callback_.Run();
stop_callback_.Reset();
delete this;
}
void NotifyClientConnected(CefRefPtr<CefServer> server, int connection_id) {
CEF_REQUIRE_UI_THREAD();
DCHECK(!observer_list_.empty());
// Use a copy in case |observer_list_| is modified during iteration.
ObserverList list = observer_list_;
ObserverList::const_iterator it = list.begin();
for (; it != list.end(); ++it) {
if ((*it)->OnClientConnected(server, connection_id)) {
break;
}
}
}
void NotifyClientDisconnected(CefRefPtr<CefServer> server,
int connection_id) {
CEF_REQUIRE_UI_THREAD();
DCHECK(!observer_list_.empty());
// Use a copy in case |observer_list_| is modified during iteration.
ObserverList list = observer_list_;
ObserverList::const_iterator it = list.begin();
for (; it != list.end(); ++it) {
if ((*it)->OnClientDisconnected(server, connection_id)) {
break;
}
}
}
void NotifyHttpRequest(CefRefPtr<CefServer> server,
int connection_id,
const CefString& client_address,
CefRefPtr<CefRequest> request) {
CEF_REQUIRE_UI_THREAD();
DCHECK(!observer_list_.empty());
// Use a copy in case |observer_list_| is modified during iteration.
ObserverList list = observer_list_;
ObserverList::const_iterator it = list.begin();
for (; it != list.end(); ++it) {
if ((*it)->OnHttpRequest(server, connection_id, client_address,
request)) {
break;
}
}
}
private:
CefRefPtr<ServerHandler> handler_;
std::string origin_;
typedef std::vector<StartDoneCallback> StartDoneCallbackList;
StartDoneCallbackList start_callback_list_;
DoneCallback stop_callback_;
typedef std::vector<Observer*> ObserverList;
ObserverList observer_list_;
DISALLOW_COPY_AND_ASSIGN(ServerManager);
};
ServerManager* GetServerManager() {
return g_manager;
}
ServerManager* GetOrCreateServerManager() {
if (!g_manager) {
new ServerManager();
DCHECK(g_manager);
}
return g_manager;
}
// static
void ServerHandler::NotifyServerCreated(const std::string& server_origin) {
if (!CefCurrentlyOn(TID_UI)) {
CefPostTask(TID_UI,
base::Bind(ServerHandler::NotifyServerCreated, server_origin));
return;
}
GetServerManager()->NotifyServerCreated(server_origin);
}
// static
void ServerHandler::NotifyServerDestroyed() {
if (!CefCurrentlyOn(TID_UI)) {
CefPostTask(TID_UI, base::Bind(ServerHandler::NotifyServerDestroyed));
return;
}
GetServerManager()->NotifyServerDestroyed();
}
// static
void ServerHandler::NotifyServerHandlerDeleted() {
if (!CefCurrentlyOn(TID_UI)) {
CefPostTask(TID_UI, base::Bind(ServerHandler::NotifyServerHandlerDeleted));
return;
}
GetServerManager()->NotifyServerHandlerDeleted();
}
// static
void ServerHandler::NotifyClientConnected(CefRefPtr<CefServer> server,
int connection_id) {
if (!CefCurrentlyOn(TID_UI)) {
CefPostTask(TID_UI, base::Bind(ServerHandler::NotifyClientConnected, server,
connection_id));
return;
}
GetServerManager()->NotifyClientConnected(server, connection_id);
}
// static
void ServerHandler::NotifyClientDisconnected(CefRefPtr<CefServer> server,
int connection_id) {
if (!CefCurrentlyOn(TID_UI)) {
CefPostTask(TID_UI, base::Bind(ServerHandler::NotifyClientDisconnected,
server, connection_id));
return;
}
GetServerManager()->NotifyClientDisconnected(server, connection_id);
}
// 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::Bind(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) {
DCHECK(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,
const DoneCallback& callback) {
if (!CefCurrentlyOn(TID_UI)) {
CefPostTask(TID_UI,
base::Bind(InitializeRegistration, registration, callback));
return;
}
DCHECK(!g_stopping);
registration->Initialize();
if (!callback.is_null())
callback.Run();
}
} // namespace
void Start(const StartDoneCallback& callback) {
DCHECK(!callback.is_null());
if (!CefCurrentlyOn(TID_UI)) {
CefPostTask(TID_UI, base::Bind(Start, callback));
return;
}
DCHECK(!g_stopping);
GetOrCreateServerManager()->Start(callback);
}
void Stop(const DoneCallback& callback) {
DCHECK(!callback.is_null());
if (!CefCurrentlyOn(TID_UI)) {
CefPostTask(TID_UI, base::Bind(Stop, callback));
return;
}
// Stop will be called one time on test framework shutdown.
DCHECK(!g_stopping);
g_stopping = true;
ServerManager* manager = GetServerManager();
if (manager) {
manager->Stop(callback);
} else {
callback.Run();
}
}
CefRefPtr<CefRegistration> AddObserver(Observer* observer,
const DoneCallback& callback) {
DCHECK(observer);
CefRefPtr<ObserverRegistration> registration =
new ObserverRegistration(observer);
InitializeRegistration(registration, callback);
return registration.get();
}
CefRefPtr<CefRegistration> AddObserverAndStart(
Observer* observer,
const StartDoneCallback& callback) {
return AddObserver(observer, base::Bind(Start, callback));
}
// ObserverHelper
ObserverHelper::ObserverHelper() : weak_ptr_factory_(this) {
CEF_REQUIRE_UI_THREAD();
}
ObserverHelper::~ObserverHelper() {
DCHECK(state_ == State::NONE);
}
void ObserverHelper::Initialize() {
CEF_REQUIRE_UI_THREAD();
DCHECK(state_ == State::NONE);
state_ = State::INITIALIZING;
registration_ = AddObserverAndStart(
this,
base::Bind(&ObserverHelper::OnStartDone, weak_ptr_factory_.GetWeakPtr()));
}
void ObserverHelper::Shutdown() {
CEF_REQUIRE_UI_THREAD();
DCHECK(state_ == State::INITIALIZED);
state_ = State::SHUTTINGDOWN;
registration_ = nullptr;
}
void ObserverHelper::OnStartDone(const std::string& server_origin) {
DCHECK(state_ == State::INITIALIZING);
state_ = State::INITIALIZED;
OnInitialized(server_origin);
}
void ObserverHelper::OnRegistered() {
DCHECK(state_ == State::INITIALIZING);
}
void ObserverHelper::OnUnregistered() {
DCHECK(state_ == State::SHUTTINGDOWN);
state_ = State::NONE;
OnShutdown();
}
} // namespace test_server

View File

@ -0,0 +1,119 @@
// 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_H_
#define CEF_TESTS_CEFTESTS_TEST_SERVER_H_
#pragma once
#include <string>
#include "include/base/cef_bind.h"
#include "include/cef_registration.h"
#include "include/cef_request.h"
#include "include/cef_server.h"
namespace test_server {
extern const char kServerAddress[];
extern const uint16 kServerPort;
extern const char kServerScheme[];
extern const char kServerOrigin[];
typedef base::Closure DoneCallback;
typedef base::Callback<void(const std::string& server_origin)>
StartDoneCallback;
// 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(const StartDoneCallback& callback);
// 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.
void Stop(const DoneCallback& callback);
// Observer for CefServerHandler 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;
// See CefServerHandler documentation for usage. Return true if the callback
// was handled.
virtual bool OnClientConnected(CefRefPtr<CefServer> server,
int connection_id) {
return false;
}
virtual bool OnClientDisconnected(CefRefPtr<CefServer> server,
int connection_id) {
return false;
}
virtual bool OnHttpRequest(CefRefPtr<CefServer> server,
int connection_id,
const CefString& client_address,
CefRefPtr<CefRequest> request) = 0;
protected:
virtual ~Observer() {}
};
// Add an observer for CefServerHandler 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,
const DoneCallback& callback);
// Combination of AddObserver() followed by Start().
CefRefPtr<CefRegistration> AddObserverAndStart(
Observer* observer,
const StartDoneCallback& callback);
// Helper for managing Observer registration and callbacks. Only used on the UI
// thread.
class ObserverHelper : 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);
};
} // namespace test_server
#endif // CEF_TESTS_CEFTESTS_TEST_SERVER_H_

View File

@ -0,0 +1,257 @@
// 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 <sstream>
#include "include/cef_task.h"
#include "include/cef_waitable_event.h"
#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/track_callback.h"
#include "tests/gtest/include/gtest/gtest.h"
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_;
}
};
const char kResponseData[] = "Test data";
class TestServerObserver : public test_server::ObserverHelper {
public:
TestServerObserver(TestState* state,
const std::string& path,
const base::Closure& done_callback)
: state_(state),
path_(path),
done_callback_(done_callback),
weak_ptr_factory_(this) {
DCHECK(state);
DCHECK(!path.empty());
DCHECK(!done_callback_.is_null());
Initialize();
}
~TestServerObserver() override { done_callback_.Run(); }
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();
url_ = server_origin + path_;
// Send a request to the server.
test_request::SendConfig config;
config.request_ = CefRequest::Create();
config.request_->SetURL(url_);
test_request::Send(config,
base::Bind(&TestServerObserver::OnRequestResponse,
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 {
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);
// Stop propagating the callback.
return true;
}
void OnRequestResponse(const test_request::State& state) {
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_);
state_->got_response_.yes();
EXPECT_STREQ(url_.c_str(), state.request_->GetURL().ToString().c_str());
EXPECT_EQ(UR_SUCCESS, state.status_);
EXPECT_EQ(ERR_NONE, state.error_code_);
EXPECT_EQ(200, state.response_->GetStatus());
EXPECT_STREQ(kResponseData, state.download_data_.c_str());
// Trigger shutdown asynchronously.
CefPostTask(TID_UI, base::Bind(&TestServerObserver::Shutdown,
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();
// End the test.
delete this;
}
private:
TestState* const state_;
const std::string path_;
const base::Closure done_callback_;
std::string url_;
int connection_id_ = -1;
base::WeakPtrFactory<TestServerObserver> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(TestServerObserver);
};
void CreateObserverOnUIThread(TestState* state,
const std::string& path,
const base::Closure& done_callback) {
if (!CefCurrentlyOn(TID_UI)) {
CefPostTask(TID_UI,
base::Bind(CreateObserverOnUIThread, base::Unretained(state),
path, done_callback));
return;
}
new TestServerObserver(state, path, done_callback);
}
void SignalIfDone(CefRefPtr<CefWaitableEvent> event,
size_t* count,
size_t total) {
if (++(*count) == total) {
event->Signal();
}
}
} // namespace
TEST(TestServerTest, ObserverHelperSingle) {
CefRefPtr<CefWaitableEvent> event =
CefWaitableEvent::CreateWaitableEvent(true, false);
TestState state;
CreateObserverOnUIThread(&state, "/TestServerTest.ObserverHelperSingle",
base::Bind(&CefWaitableEvent::Signal, event));
event->TimedWait(2000);
EXPECT_TRUE(state.ExpectAll());
}
TEST(TestServerTest, ObserverHelperMultiple) {
CefRefPtr<CefWaitableEvent> event =
CefWaitableEvent::CreateWaitableEvent(true, false);
TestState states[3];
size_t count = 0;
const size_t size = arraysize(states);
const base::Closure& done_callback =
base::Bind(SignalIfDone, event, base::Unretained(&count), size);
for (size_t i = 0; i < size; ++i) {
std::stringstream ss;
ss << "/TestServerTest.ObserverHelperMultiple" << i;
CreateObserverOnUIThread(&states[i], ss.str(), done_callback);
}
event->TimedWait(2000);
EXPECT_EQ(size, count);
for (size_t i = 0; i < size; ++i) {
EXPECT_TRUE(states[i].ExpectAll()) << i;
}
}

View File

@ -17,6 +17,8 @@
#include "include/wrapper/cef_closure_task.h"
#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_suite.h"
#include "tests/ceftests/test_util.h"
#include "tests/gtest/include/gtest/gtest.h"
@ -45,9 +47,9 @@ const char kRequestSchemeCustom[] = "urcustom";
const char kRequestHostCustom[] = "test";
// Server backend.
const char kRequestAddressServer[] = "127.0.0.1";
const uint16 kRequestPortServer = 8099;
const char kRequestSchemeServer[] = "http";
const char* kRequestAddressServer = test_server::kServerAddress;
const uint16 kRequestPortServer = test_server::kServerPort;
const char* kRequestSchemeServer = test_server::kServerScheme;
const char kRequestSendCookieName[] = "urcookie_send";
const char kRequestSaveCookieName[] = "urcookie_save";
@ -1205,7 +1207,7 @@ class RequestSchemeHandlerFactory : public CefSchemeHandlerFactory {
// SERVER BACKEND
// HTTP server handler.
class RequestServerHandler : public CefServerHandler {
class RequestServerHandler : public test_server::ObserverHelper {
public:
RequestServerHandler()
: initialized_(false),
@ -1244,8 +1246,7 @@ class RequestServerHandler : public CefServerHandler {
EXPECT_TRUE(complete_callback_.is_null());
complete_callback_ = complete_callback;
CefServer::CreateServer(kRequestAddressServer, kRequestPortServer, 10,
this);
Initialize();
}
// Results in a call to VerifyResults() and eventual execution of the
@ -1256,73 +1257,59 @@ class RequestServerHandler : public CefServerHandler {
EXPECT_TRUE(complete_callback_.is_null());
complete_callback_ = complete_callback;
EXPECT_TRUE(server_);
if (server_)
server_->Shutdown();
Shutdown();
}
void OnServerCreated(CefRefPtr<CefServer> server) override {
EXPECT_TRUE(server);
EXPECT_TRUE(server->IsRunning());
EXPECT_FALSE(server->HasConnection());
void OnInitialized(const std::string& server_origin) override {
EXPECT_UI_THREAD();
EXPECT_STREQ(server_origin.c_str(), GetRequestOrigin(true).c_str());
EXPECT_FALSE(got_initialized_);
got_initialized_.yes();
EXPECT_FALSE(got_server_created_);
got_server_created_.yes();
EXPECT_FALSE(server_);
server_ = server;
EXPECT_FALSE(server_runner_);
server_runner_ = server_->GetTaskRunner();
EXPECT_TRUE(server_runner_);
EXPECT_TRUE(server_runner_->BelongsToCurrentThread());
CefPostTask(TID_UI, base::Bind(&RequestServerHandler::RunCompleteCallback,
this, true));
RunCompleteCallback(true);
}
void OnServerDestroyed(CefRefPtr<CefServer> server) override {
EXPECT_TRUE(VerifyServer(server));
EXPECT_FALSE(server->IsRunning());
EXPECT_FALSE(server->HasConnection());
EXPECT_FALSE(got_server_destroyed_);
got_server_destroyed_.yes();
void OnShutdown() override {
EXPECT_UI_THREAD();
EXPECT_FALSE(got_shutdown_);
got_shutdown_.yes();
data_map_.SetOwnerTaskRunner(nullptr);
server_ = nullptr;
VerifyResults();
delete this;
}
void OnClientConnected(CefRefPtr<CefServer> server,
bool OnClientConnected(CefRefPtr<CefServer> server,
int connection_id) override {
EXPECT_TRUE(VerifyServer(server));
EXPECT_TRUE(server->HasConnection());
EXPECT_TRUE(server->IsValidConnection(connection_id));
EXPECT_UI_THREAD();
EXPECT_TRUE(connection_id_set_.find(connection_id) ==
connection_id_set_.end());
connection_id_set_.insert(connection_id);
actual_connection_ct_++;
return true;
}
void OnClientDisconnected(CefRefPtr<CefServer> server,
bool OnClientDisconnected(CefRefPtr<CefServer> server,
int connection_id) override {
EXPECT_TRUE(VerifyServer(server));
EXPECT_FALSE(server->IsValidConnection(connection_id));
EXPECT_UI_THREAD();
ConnectionIdSet::iterator it = connection_id_set_.find(connection_id);
EXPECT_TRUE(it != connection_id_set_.end());
connection_id_set_.erase(it);
return true;
}
void OnHttpRequest(CefRefPtr<CefServer> server,
bool OnHttpRequest(CefRefPtr<CefServer> server,
int connection_id,
const CefString& client_address,
CefRefPtr<CefRequest> request) override {
EXPECT_TRUE(VerifyServer(server));
EXPECT_UI_THREAD();
EXPECT_TRUE(VerifyConnection(connection_id));
EXPECT_FALSE(client_address.empty());
@ -1333,52 +1320,18 @@ class RequestServerHandler : public CefServerHandler {
HandleRequest(server, connection_id, request);
actual_http_request_ct_++;
}
void OnWebSocketRequest(CefRefPtr<CefServer> server,
int connection_id,
const CefString& client_address,
CefRefPtr<CefRequest> request,
CefRefPtr<CefCallback> callback) override {
NOTREACHED();
}
void OnWebSocketConnected(CefRefPtr<CefServer> server,
int connection_id) override {
NOTREACHED();
}
void OnWebSocketMessage(CefRefPtr<CefServer> server,
int connection_id,
const void* data,
size_t data_size) override {
NOTREACHED();
return true;
}
private:
bool RunningOnServerThread() {
return server_runner_ && server_runner_->BelongsToCurrentThread();
}
bool VerifyServer(CefRefPtr<CefServer> server) {
V_DECLARE();
V_EXPECT_TRUE(RunningOnServerThread());
V_EXPECT_TRUE(server);
V_EXPECT_TRUE(server_);
V_EXPECT_TRUE(server->GetAddress().ToString() ==
server_->GetAddress().ToString());
V_RETURN();
}
bool VerifyConnection(int connection_id) {
return connection_id_set_.find(connection_id) != connection_id_set_.end();
}
void VerifyResults() {
EXPECT_TRUE(RunningOnServerThread());
EXPECT_TRUE(got_server_created_);
EXPECT_TRUE(got_server_destroyed_);
EXPECT_TRUE(got_initialized_);
EXPECT_TRUE(got_shutdown_);
EXPECT_TRUE(connection_id_set_.empty());
EXPECT_EQ(expected_connection_ct_, actual_connection_ct_) << request_log_;
EXPECT_EQ(expected_http_request_ct_, actual_http_request_ct_)
@ -1409,7 +1362,7 @@ class RequestServerHandler : public CefServerHandler {
}
}
void HandleAuthRequest(CefRefPtr<CefServer> server,
static void HandleAuthRequest(CefRefPtr<CefServer> server,
int connection_id,
CefRefPtr<CefRequest> request) {
CefRefPtr<CefResponse> response = CefResponse::Create();
@ -1417,7 +1370,7 @@ class RequestServerHandler : public CefServerHandler {
SendResponse(server, connection_id, response, std::string());
}
void HandleNormalRequest(CefRefPtr<CefServer> server,
static void HandleNormalRequest(CefRefPtr<CefServer> server,
int connection_id,
CefRefPtr<CefRequest> request,
RequestRunSettings* settings) {
@ -1437,7 +1390,7 @@ class RequestServerHandler : public CefServerHandler {
SendResponse(server, connection_id, response, response_data);
}
void HandleRedirectRequest(CefRefPtr<CefServer> server,
static void HandleRedirectRequest(CefRefPtr<CefServer> server,
int connection_id,
CefRefPtr<CefRequest> request,
CefRefPtr<CefRequest> redirect_request,
@ -1460,10 +1413,19 @@ class RequestServerHandler : public CefServerHandler {
SendResponse(server, connection_id, redirect_response, std::string());
}
void SendResponse(CefRefPtr<CefServer> server,
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::Bind(RequestServerHandler::SendResponse, server, connection_id,
response, response_data)));
return;
}
const int response_code = response->GetStatus();
if (response_code <= 0) {
// Intentionally not responding for incomplete request tests.
@ -1498,8 +1460,8 @@ class RequestServerHandler : public CefServerHandler {
EXPECT_UI_THREAD();
if (startup) {
// Transfer DataMap ownership to the server thread.
data_map_.SetOwnerTaskRunner(server_->GetTaskRunner());
// Transfer DataMap ownership to the UI thread.
data_map_.SetOwnerTaskRunner(CefTaskRunner::GetForCurrentThread());
}
EXPECT_FALSE(complete_callback_.is_null());
@ -1509,8 +1471,6 @@ class RequestServerHandler : public CefServerHandler {
RequestDataMap data_map_;
CefRefPtr<CefServer> server_;
CefRefPtr<CefTaskRunner> server_runner_;
bool initialized_;
// Only accessed on the UI thread.
@ -1519,8 +1479,8 @@ class RequestServerHandler : public CefServerHandler {
// After initialization the below members are only accessed on the server
// thread.
TrackCallback got_server_created_;
TrackCallback got_server_destroyed_;
TrackCallback got_initialized_;
TrackCallback got_shutdown_;
typedef std::set<int> ConnectionIdSet;
ConnectionIdSet connection_id_set_;
@ -1531,106 +1491,6 @@ class RequestServerHandler : public CefServerHandler {
int actual_http_request_ct_;
std::string request_log_;
IMPLEMENT_REFCOUNTING(RequestServerHandler);
DISALLOW_COPY_AND_ASSIGN(RequestServerHandler);
};
// URLREQUEST CLIENT
// Implementation of CefURLRequestClient that stores response information.
class RequestClient : public CefURLRequestClient {
public:
typedef base::Callback<void(CefRefPtr<RequestClient>)>
RequestCompleteCallback;
explicit RequestClient(const RequestCompleteCallback& complete_callback)
: complete_callback_(complete_callback) {
EXPECT_FALSE(complete_callback_.is_null());
}
void OnRequestComplete(CefRefPtr<CefURLRequest> request) override {
request_complete_ct_++;
request_ = request->GetRequest();
EXPECT_TRUE(request_->IsReadOnly());
status_ = request->GetRequestStatus();
error_code_ = request->GetRequestError();
response_was_cached_ = request->ResponseWasCached();
response_ = request->GetResponse();
if (response_) {
EXPECT_TRUE(response_->IsReadOnly());
}
complete_callback_.Run(this);
}
void OnUploadProgress(CefRefPtr<CefURLRequest> request,
int64 current,
int64 total) override {
upload_progress_ct_++;
upload_total_ = total;
}
void OnDownloadProgress(CefRefPtr<CefURLRequest> request,
int64 current,
int64 total) override {
response_ = request->GetResponse();
EXPECT_TRUE(response_.get());
EXPECT_TRUE(response_->IsReadOnly());
download_progress_ct_++;
download_total_ = total;
}
void OnDownloadData(CefRefPtr<CefURLRequest> request,
const void* data,
size_t data_length) override {
response_ = request->GetResponse();
EXPECT_TRUE(response_.get());
EXPECT_TRUE(response_->IsReadOnly());
download_data_ct_++;
download_data_ += std::string(static_cast<const char*>(data), data_length);
}
bool GetAuthCredentials(bool isProxy,
const CefString& host,
int port,
const CefString& realm,
const CefString& scheme,
CefRefPtr<CefAuthCallback> callback) override {
auth_credentials_ct_++;
if (has_authentication_) {
callback->Continue(username_, password_);
return true;
}
return false;
}
private:
const RequestCompleteCallback complete_callback_;
public:
bool has_authentication_ = false;
std::string username_;
std::string password_;
int request_complete_ct_ = 0;
int upload_progress_ct_ = 0;
int download_progress_ct_ = 0;
int download_data_ct_ = 0;
int auth_credentials_ct_ = 0;
int64 upload_total_ = 0;
int64 download_total_ = 0;
std::string download_data_;
CefRefPtr<CefRequest> request_;
CefURLRequest::Status status_ = UR_UNKNOWN;
CefURLRequest::ErrorCode error_code_ = ERR_NONE;
CefRefPtr<CefResponse> response_;
bool response_was_cached_ = false;
private:
IMPLEMENT_REFCOUNTING(RequestClient);
};
// SHARED TEST RUNNER
@ -2501,31 +2361,31 @@ class RequestTestRunner : public base::RefCountedThreadSafe<RequestTestRunner> {
}
// Send a request. |complete_callback| will be executed on request completion.
void SendRequest(
const RequestClient::RequestCompleteCallback& complete_callback) {
CefRefPtr<CefRequest> request;
if (settings_.redirect_request)
request = settings_.redirect_request;
else
request = settings_.request;
EXPECT_TRUE(request.get());
void SendRequest(const test_request::RequestDoneCallback& done_callback) {
test_request::SendConfig config;
CefRefPtr<RequestClient> client = new RequestClient(complete_callback);
if (settings_.redirect_request)
config.request_ = settings_.redirect_request;
else
config.request_ = settings_.request;
EXPECT_TRUE(config.request_.get());
// Not delegating to CefRequestHandler::GetAuthCredentials.
if (!use_frame_method_ && settings_.expect_authentication) {
client->has_authentication_ = true;
client->username_ = settings_.username;
client->password_ = settings_.password;
config.has_credentials_ = true;
config.username_ = settings_.username;
config.password_ = settings_.password;
}
if (use_frame_method_) {
EXPECT_TRUE(frame_);
frame_->CreateURLRequest(request, client.get());
config.frame_ = frame_;
} else {
CefURLRequest::Create(request, client.get(), request_context_);
config.request_context_ = request_context_;
}
test_request::Send(config, done_callback);
if (settings_.incomplete_type != RequestRunSettings::INCOMPLETE_NONE) {
incomplete_request_callback_.Run();
incomplete_request_callback_.Reset();
@ -2533,7 +2393,7 @@ class RequestTestRunner : public base::RefCountedThreadSafe<RequestTestRunner> {
}
// Verify a response.
void VerifyResponse(CefRefPtr<RequestClient> client) {
void VerifyResponse(const test_request::State* const client) {
CefRefPtr<CefRequest> expected_request;
CefRefPtr<CefResponse> expected_response;
@ -2607,8 +2467,8 @@ class RequestTestRunner : public base::RefCountedThreadSafe<RequestTestRunner> {
}
void SingleRunTestComplete(const base::Closure& complete_callback,
CefRefPtr<RequestClient> completed_client) {
VerifyResponse(completed_client);
const test_request::State& completed_client) {
VerifyResponse(&completed_client);
complete_callback.Run();
}
@ -2628,9 +2488,9 @@ class RequestTestRunner : public base::RefCountedThreadSafe<RequestTestRunner> {
void MultipleRunTestNext(const base::Closure& complete_callback,
int send_count,
CefRefPtr<RequestClient> completed_client) {
const test_request::State& completed_client) {
// Verify the completed request.
VerifyResponse(completed_client);
VerifyResponse(&completed_client);
if (send_count == settings_.expected_send_count) {
// All requests complete.
@ -2757,6 +2617,7 @@ class RequestTestRunner : public base::RefCountedThreadSafe<RequestTestRunner> {
void ShutdownServer(const base::Closure& complete_callback) {
EXPECT_TRUE(server_handler_);
// |server_handler_| will delete itself after shutdown.
server_handler_->ShutdownServer(complete_callback);
server_handler_ = nullptr;
}
@ -2797,7 +2658,7 @@ class RequestTestRunner : public base::RefCountedThreadSafe<RequestTestRunner> {
TestMap test_map_;
// Server backend.
CefRefPtr<RequestServerHandler> server_handler_;
RequestServerHandler* server_handler_ = nullptr;
// Scheme handler backend.
std::string scheme_name_;