Skip to content

Commit

Permalink
Backported test server updates from 1.10.x
Browse files Browse the repository at this point in the history
  • Loading branch information
COM8 committed Oct 14, 2023
1 parent 743ca57 commit 21e3815
Show file tree
Hide file tree
Showing 13 changed files with 536 additions and 479 deletions.
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -301,8 +301,8 @@ if(CPR_BUILD_TESTS)
clear_variable(DESTINATION CMAKE_CXX_CLANG_TIDY BACKUP CMAKE_CXX_CLANG_TIDY_BKP)

FetchContent_Declare(mongoose
URL https://github.com/cesanta/mongoose/archive/6.18.tar.gz
URL_HASH SHA256=f5c10346abc9c72f7cac7885d853ca064fb09aad57580433941a8fd7a3543769 # the hash for 6.18.tar.gz
URL https://github.com/cesanta/mongoose/archive/7.7.tar.gz
URL_HASH SHA256=4e5733dae31c3a81156af63ca9aa3a6b9b736547f21f23c3ab2f8e3f1ecc16c0 # the hash for 7.7.tar.gz
USES_TERMINAL_DOWNLOAD TRUE) # <---- This is needed only for Ninja to show download progress
# We can not use FetchContent_MakeAvailable, since we need to patch mongoose to use CMake
if (NOT mongoose_POPULATED)
Expand Down
2 changes: 1 addition & 1 deletion cmake/mongoose.CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ target_include_directories(mongoose PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

if(ENABLE_SSL_TESTS)
# Enable mongoose SSL
target_compile_definitions(mongoose PUBLIC MG_ENABLE_SSL)
target_compile_definitions(mongoose PUBLIC MG_ENABLE_OPENSSL)
target_link_libraries(mongoose PRIVATE OpenSSL::SSL)
endif()
52 changes: 41 additions & 11 deletions test/abstractServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ void AbstractServer::Stop() {
server_stop_cv.wait(server_lock);
}

static void EventHandler(mg_connection* conn, int event, void* event_data) {
static void EventHandler(mg_connection* conn, int event, void* event_data, void* context) {
switch (event) {
case MG_EV_RECV:
case MG_EV_SEND:
case MG_EV_READ:
case MG_EV_WRITE:
/** Do nothing. Just for housekeeping. **/
break;
case MG_EV_POLL:
Expand All @@ -36,22 +36,20 @@ static void EventHandler(mg_connection* conn, int event, void* event_data) {
/** Do nothing. Just for housekeeping. **/
break;
case MG_EV_ACCEPT:
/** Do nothing. Just for housekeeping. **/
/* Initialize HTTPS connection if Server is an HTTPS Server */
static_cast<AbstractServer*>(context)->acceptConnection(conn);
break;
case MG_EV_CONNECT:
/** Do nothing. Just for housekeeping. **/
break;
case MG_EV_TIMER:
/** Do nothing. Just for housekeeping. **/
break;

case MG_EV_HTTP_CHUNK: {
/** Do nothing. Just for housekeeping. **/
} break;

case MG_EV_HTTP_REQUEST: {
AbstractServer* server = static_cast<AbstractServer*>(conn->mgr->user_data);
server->OnRequest(conn, static_cast<http_message*>(event_data));
case MG_EV_HTTP_MSG: {
AbstractServer* server = static_cast<AbstractServer*>(context);
server->OnRequest(conn, static_cast<mg_http_message*>(event_data));
} break;

default:
Expand All @@ -69,10 +67,12 @@ void AbstractServer::Run() {

// Main server loop:
while (should_run) {
mg_mgr_poll(&mgr, 1000);
// NOLINTNEXTLINE (cppcoreguidelines-avoid-magic-numbers)
mg_mgr_poll(&mgr, 100);
}

// Shutdown and cleanup:
timer_args.clear();
mg_mgr_free(&mgr);

// Notify the main thread that we have shut down everything:
Expand Down Expand Up @@ -110,4 +110,34 @@ std::string AbstractServer::Base64Decode(const std::string& in) {
return out;
}

// Sends error similar like in mongoose 6 method mg_http_send_error
// https://github.com/cesanta/mongoose/blob/6.18/mongoose.c#L7081-L7089
void AbstractServer::SendError(mg_connection* conn, int code, std::string& reason) {
std::string headers{"Content-Type: text/plain\r\nConnection: close\r\n"};
mg_http_reply(conn, code, headers.c_str(), reason.c_str());
}

// Checks whether a pointer to a connection is still managed by a mg_mgr.
// This check tells whether it is still possible to send a message via the given connection
// Note that it is still possible that the pointer of an old connection object may be reused by mongoose.
// In this case, the active connection might refer to a different connection than the one the caller refers to
bool AbstractServer::IsConnectionActive(mg_mgr* mgr, mg_connection* conn) {
mg_connection* c{mgr->conns};
while (c) {
if (c == conn) {
return true;
}
c = c->next;
}
return false;
}

uint16_t AbstractServer::GetRemotePort(const mg_connection* conn) {
return (conn->rem.port >> 8) | (conn->rem.port << 8);
}

uint16_t AbstractServer::GetLocalPort(const mg_connection* conn) {
return (conn->loc.port >> 8) | (conn->loc.port << 8);
}

} // namespace cpr
29 changes: 26 additions & 3 deletions test/abstractServer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,22 @@
#include "mongoose.h"

namespace cpr {

// Helper struct for functions using timers to simulate slow connections
struct TimerArg {
mg_mgr* mgr;
mg_connection* connection;
unsigned long connection_id;
mg_timer timer;
unsigned counter;

explicit TimerArg(mg_mgr* m, mg_connection* c, mg_timer&& t) : mgr{m}, connection{c}, connection_id{0}, timer{t}, counter{0} {}

~TimerArg() {
mg_timer_free(&mgr->timers, &timer);
}
};

class AbstractServer : public testing::Environment {
public:
~AbstractServer() override = default;
Expand All @@ -25,22 +41,29 @@ class AbstractServer : public testing::Environment {
virtual std::string GetBaseUrl() = 0;
virtual uint16_t GetPort() = 0;

virtual void OnRequest(mg_connection* conn, http_message* msg) = 0;
virtual void acceptConnection(mg_connection* conn) = 0;
virtual void OnRequest(mg_connection* conn, mg_http_message* msg) = 0;

private:
std::shared_ptr<std::thread> serverThread{nullptr};
std::mutex server_mutex;
std::condition_variable server_start_cv;
std::condition_variable server_stop_cv;
std::atomic<bool> should_run{false};
mg_mgr mgr{};

void Run();

protected:
virtual mg_connection* initServer(mg_mgr* mgr, MG_CB(mg_event_handler_t event_handler, void* user_data)) = 0;
mg_mgr mgr{};
std::vector<std::unique_ptr<TimerArg>> timer_args{};
virtual mg_connection* initServer(mg_mgr* mgr, mg_event_handler_t event_handler) = 0;

static std::string Base64Decode(const std::string& in);
static void SendError(mg_connection* conn, int code, std::string& reason);
static bool IsConnectionActive(mg_mgr* mgr, mg_connection* conn);

static uint16_t GetRemotePort(const mg_connection* conn);
static uint16_t GetLocalPort(const mg_connection* conn);
};
} // namespace cpr

Expand Down
2 changes: 1 addition & 1 deletion test/callback_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -863,7 +863,7 @@ TEST(CallbackDataTests, CallbackHeaderFunctionCancelTest) {

TEST(CallbackDataTests, CallbackHeaderFunctionTextTest) {
Url url{server->GetBaseUrl() + "/url_post.html"};
std::vector<std::string> expected_headers{"HTTP/1.1 201 OK\r\n", "Content-Type: application/json\r\n", "\r\n"};
std::vector<std::string> expected_headers{"HTTP/1.1 201 Created\r\n", "Content-Type: application/json\r\n", "\r\n"};
std::set<std::string> response_headers;
Post(url, HeaderCallback{[&response_headers](const std::string& header, intptr_t /*userdata*/) -> bool {
response_headers.insert(header);
Expand Down
4 changes: 2 additions & 2 deletions test/error_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,14 @@ TEST(ErrorTests, ChronoConnectTimeoutFailure) {
TEST(ErrorTests, LowSpeedTimeFailure) {
Url url{server->GetBaseUrl() + "/low_speed.html"};
Response response = cpr::Get(url, cpr::LowSpeed{1000, 1});
EXPECT_EQ(0, response.status_code);
// Do not check for the HTTP status code, since libcurl always provides the status code of the header if it was received
EXPECT_EQ(ErrorCode::OPERATION_TIMEDOUT, response.error.code);
}

TEST(ErrorTests, LowSpeedBytesFailure) {
Url url{server->GetBaseUrl() + "/low_speed_bytes.html"};
Response response = cpr::Get(url, cpr::LowSpeed{1000, 1});
EXPECT_EQ(0, response.status_code);
// Do not check for the HTTP status code, since libcurl always provides the status code of the header if it was received
EXPECT_EQ(ErrorCode::OPERATION_TIMEDOUT, response.error.code);
}

Expand Down
Loading

0 comments on commit 21e3815

Please sign in to comment.