feat: Cache state endpoint (#2642)

This commit is contained in:
Alex Kremer
2025-09-18 16:20:17 +01:00
committed by GitHub
parent 586a2116a4
commit 245a808e4b
9 changed files with 221 additions and 25 deletions

View File

@@ -189,6 +189,7 @@ ClioApplication::run(bool const useNgWebServer)
httpServer->onGet("/metrics", MetricsHandler{adminVerifier});
httpServer->onGet("/health", HealthCheckHandler{});
httpServer->onGet("/cache_state", CacheStateHandler{cache});
auto requestHandler = RequestHandler{adminVerifier, handler};
httpServer->onPost("/", requestHandler);
httpServer->onWs(std::move(requestHandler));
@@ -214,7 +215,7 @@ ClioApplication::run(bool const useNgWebServer)
// Init the web server
auto handler = std::make_shared<web::RPCServerHandler<RPCEngineType>>(config_, backend, rpcEngine, etl, dosGuard);
auto const httpServer = web::makeHttpServer(config_, ioc, dosGuard, handler);
auto const httpServer = web::makeHttpServer(config_, ioc, dosGuard, handler, cache);
// Blocks until stopped.
// When stopped, shared_ptrs fall out of scope

View File

@@ -120,4 +120,34 @@ HealthCheckHandler::operator()(
return web::ng::Response{boost::beast::http::status::ok, kHEALTH_CHECK_HTML, request};
}
web::ng::Response
CacheStateHandler::operator()(
web::ng::Request const& request,
web::ng::ConnectionMetadata&,
web::SubscriptionContextPtr,
boost::asio::yield_context
)
{
static constexpr auto kCACHE_CHECK_LOADED_HTML = R"html(
<!DOCTYPE html>
<html>
<head><title>Cache state</title></head>
<body><h1>Cache state</h1><p>Cache is fully loaded</p></body>
</html>
)html";
static constexpr auto kCACHE_CHECK_NOT_LOADED_HTML = R"html(
<!DOCTYPE html>
<html>
<head><title>Cache state</title></head>
<body><h1>Cache state</h1><p>Cache is not yet loaded</p></body>
</html>
)html";
if (cache_.get().isFull())
return web::ng::Response{boost::beast::http::status::ok, kCACHE_CHECK_LOADED_HTML, request};
return web::ng::Response{boost::beast::http::status::service_unavailable, kCACHE_CHECK_NOT_LOADED_HTML, request};
}
} // namespace app

View File

@@ -19,6 +19,7 @@
#pragma once
#include "data/LedgerCacheInterface.hpp"
#include "rpc/Errors.hpp"
#include "util/log/Logger.hpp"
#include "web/AdminVerificationStrategy.hpp"
@@ -163,6 +164,37 @@ public:
);
};
/**
* @brief A function object that handles the cache state check endpoint.
*/
class CacheStateHandler {
std::reference_wrapper<data::LedgerCacheInterface const> cache_;
public:
/**
* @brief Construct a new CacheStateHandler object.
*
* @param cache The ledger cache to use.
*/
CacheStateHandler(data::LedgerCacheInterface const& cache) : cache_{cache}
{
}
/**
* @brief The call of the function object.
*
* @param request The request to handle.
* @return The response to the request
*/
web::ng::Response
operator()(
web::ng::Request const& request,
web::ng::ConnectionMetadata&,
web::SubscriptionContextPtr,
boost::asio::yield_context
);
};
/**
* @brief A function object that handles the websocket endpoint.
*

View File

@@ -19,6 +19,7 @@
#pragma once
#include "data/LedgerCacheInterface.hpp"
#include "util/Taggable.hpp"
#include "web/AdminVerificationStrategy.hpp"
#include "web/PlainWsSession.hpp"
@@ -69,6 +70,7 @@ public:
* @param tagFactory A factory that is used to generate tags to track requests and sessions
* @param dosGuard The denial of service guard to use
* @param handler The server handler to use
* @param cache The ledger cache to use
* @param buffer Buffer with initial data received from the peer
* @param maxWsSendingQueueSize The maximum size of the sending queue for websocket
*/
@@ -80,6 +82,7 @@ public:
std::reference_wrapper<util::TagDecoratorFactory const> tagFactory,
std::reference_wrapper<dosguard::DOSGuardInterface> dosGuard,
std::shared_ptr<HandlerType> const& handler,
std::reference_wrapper<data::LedgerCacheInterface const> cache,
boost::beast::flat_buffer buffer,
std::uint32_t maxWsSendingQueueSize
)
@@ -90,6 +93,7 @@ public:
std::move(proxyIpResolver),
dosGuard,
handler,
cache,
std::move(buffer)
)
, stream_(std::move(socket))

View File

@@ -19,6 +19,7 @@
#pragma once
#include "data/LedgerCacheInterface.hpp"
#include "util/Taggable.hpp"
#include "util/log/Logger.hpp"
#include "web/AdminVerificationStrategy.hpp"
@@ -85,6 +86,7 @@ class Detector : public std::enable_shared_from_this<Detector<PlainSessionType,
std::reference_wrapper<util::TagDecoratorFactory const> tagFactory_;
std::reference_wrapper<dosguard::DOSGuardInterface> const dosGuard_;
std::shared_ptr<HandlerType> const handler_;
std::reference_wrapper<data::LedgerCacheInterface const> cache_;
boost::beast::flat_buffer buffer_;
std::shared_ptr<AdminVerificationStrategy> const adminVerification_;
std::uint32_t maxWsSendingQueueSize_;
@@ -99,6 +101,7 @@ public:
* @param tagFactory A factory that is used to generate tags to track requests and sessions
* @param dosGuard The denial of service guard to use
* @param handler The server handler to use
* @param cache The ledger cache to use
* @param adminVerification The admin verification strategy to use
* @param maxWsSendingQueueSize The maximum size of the sending queue for websocket
* @param proxyIpResolver The client ip resolver if a request was forwarded by a proxy
@@ -109,6 +112,7 @@ public:
std::reference_wrapper<util::TagDecoratorFactory const> tagFactory,
std::reference_wrapper<dosguard::DOSGuardInterface> dosGuard,
std::shared_ptr<HandlerType> handler,
std::reference_wrapper<data::LedgerCacheInterface const> cache,
std::shared_ptr<AdminVerificationStrategy> adminVerification,
std::uint32_t maxWsSendingQueueSize,
std::shared_ptr<ProxyIpResolver> proxyIpResolver
@@ -118,6 +122,7 @@ public:
, tagFactory_(std::cref(tagFactory))
, dosGuard_(dosGuard)
, handler_(std::move(handler))
, cache_(cache)
, adminVerification_(std::move(adminVerification))
, maxWsSendingQueueSize_(maxWsSendingQueueSize)
, proxyIpResolver_(std::move(proxyIpResolver))
@@ -179,6 +184,7 @@ public:
tagFactory_,
dosGuard_,
handler_,
cache_,
std::move(buffer_),
maxWsSendingQueueSize_
)
@@ -194,6 +200,7 @@ public:
tagFactory_,
dosGuard_,
handler_,
cache_,
std::move(buffer_),
maxWsSendingQueueSize_
)
@@ -223,6 +230,7 @@ class Server : public std::enable_shared_from_this<Server<PlainSessionType, SslS
util::TagDecoratorFactory tagFactory_;
std::reference_wrapper<dosguard::DOSGuardInterface> dosGuard_;
std::shared_ptr<HandlerType> handler_;
std::reference_wrapper<data::LedgerCacheInterface const> cache_;
tcp::acceptor acceptor_;
std::shared_ptr<AdminVerificationStrategy> adminVerification_;
std::uint32_t maxWsSendingQueueSize_;
@@ -238,6 +246,7 @@ public:
* @param tagFactory A factory that is used to generate tags to track requests and sessions
* @param dosGuard The denial of service guard to use
* @param handler The server handler to use
* @param cache The ledger cache to use
* @param adminVerification The admin verification strategy to use
* @param maxWsSendingQueueSize The maximum size of the sending queue for websocket
* @param proxyIpResolver The client ip resolver if a request was forwarded by a proxy
@@ -249,6 +258,7 @@ public:
util::TagDecoratorFactory tagFactory,
dosguard::DOSGuardInterface& dosGuard,
std::shared_ptr<HandlerType> handler,
std::reference_wrapper<data::LedgerCacheInterface const> cache,
std::shared_ptr<AdminVerificationStrategy> adminVerification,
std::uint32_t maxWsSendingQueueSize,
ProxyIpResolver proxyIpResolver
@@ -258,6 +268,7 @@ public:
, tagFactory_(tagFactory)
, dosGuard_(std::ref(dosGuard))
, handler_(std::move(handler))
, cache_(cache)
, acceptor_(boost::asio::make_strand(ioc))
, adminVerification_(std::move(adminVerification))
, maxWsSendingQueueSize_(maxWsSendingQueueSize)
@@ -320,6 +331,7 @@ private:
std::cref(tagFactory_),
dosGuard_,
handler_,
cache_,
adminVerification_,
maxWsSendingQueueSize_,
proxyIpResolver_
@@ -343,6 +355,7 @@ using HttpServer = Server<HttpSession, SslHttpSession, HandlerType>;
* @param ioc The server will run under this io_context
* @param dosGuard The dos guard to protect the server
* @param handler The handler to process the request
* @param cache The ledger cache to use
* @return The server instance
*/
template <typename HandlerType>
@@ -351,7 +364,8 @@ makeHttpServer(
util::config::ClioConfigDefinition const& config,
boost::asio::io_context& ioc,
dosguard::DOSGuardInterface& dosGuard,
std::shared_ptr<HandlerType> const& handler
std::shared_ptr<HandlerType> const& handler,
std::reference_wrapper<data::LedgerCacheInterface const> cache
)
{
static util::Logger const log{"WebServer"}; // NOLINT(readability-identifier-naming)
@@ -385,6 +399,7 @@ makeHttpServer(
util::TagDecoratorFactory(config),
dosGuard,
handler,
cache,
std::move(expectedAdminVerification).value(),
maxWsSendingQueueSize,
std::move(proxyIpResolver)

View File

@@ -19,6 +19,7 @@
#pragma once
#include "data/LedgerCacheInterface.hpp"
#include "util/Taggable.hpp"
#include "web/AdminVerificationStrategy.hpp"
#include "web/ProxyIpResolver.hpp"
@@ -76,6 +77,7 @@ public:
* @param tagFactory A factory that is used to generate tags to track requests and sessions
* @param dosGuard The denial of service guard to use
* @param handler The server handler to use
* @param cache The ledger cache to use
* @param buffer Buffer with initial data received from the peer
* @param maxWsSendingQueueSize The maximum size of the sending queue for websocket
*/
@@ -88,6 +90,7 @@ public:
std::reference_wrapper<util::TagDecoratorFactory const> tagFactory,
std::reference_wrapper<dosguard::DOSGuardInterface> dosGuard,
std::shared_ptr<HandlerType> const& handler,
std::reference_wrapper<data::LedgerCacheInterface const> cache,
boost::beast::flat_buffer buffer,
std::uint32_t maxWsSendingQueueSize
)
@@ -98,6 +101,7 @@ public:
std::move(proxyIpResolver),
dosGuard,
handler,
cache,
std::move(buffer)
)
, stream_(std::move(socket), ctx)

View File

@@ -19,6 +19,7 @@
#pragma once
#include "data/LedgerCacheInterface.hpp"
#include "rpc/Errors.hpp"
#include "util/Assert.hpp"
#include "util/Taggable.hpp"
@@ -71,6 +72,22 @@ static constexpr auto kHEALTH_CHECK_HTML = R"html(
</html>
)html";
static constexpr auto kCACHE_CHECK_LOADED_HTML = R"html(
<!DOCTYPE html>
<html>
<head><title>Cache state</title></head>
<body><h1>Cache state</h1><p>Cache is fully loaded</p></body>
</html>
)html";
static constexpr auto kCACHE_CHECK_NOT_LOADED_HTML = R"html(
<!DOCTYPE html>
<html>
<head><title>Cache state</title></head>
<body><h1>Cache state</h1><p>Cache is not yet loaded</p></body>
</html>
)html";
using tcp = boost::asio::ip::tcp;
/**
@@ -128,6 +145,7 @@ protected:
http::request<http::string_body> req_;
std::reference_wrapper<dosguard::DOSGuardInterface> dosGuard_;
std::shared_ptr<HandlerType> const handler_;
std::reference_wrapper<data::LedgerCacheInterface const> cache_;
util::Logger log_{"WebServer"};
util::Logger perfLog_{"Performance"};
@@ -169,6 +187,7 @@ public:
std::shared_ptr<ProxyIpResolver> proxyIpResolver,
std::reference_wrapper<dosguard::DOSGuardInterface> dosGuard,
std::shared_ptr<HandlerType> handler,
std::reference_wrapper<data::LedgerCacheInterface const> cache,
boost::beast::flat_buffer buffer
)
: ConnectionBase(tagFactory, ip)
@@ -178,6 +197,7 @@ public:
, buffer_(std::move(buffer))
, dosGuard_(dosGuard)
, handler_(std::move(handler))
, cache_(cache)
{
LOG(perfLog_.debug()) << tag() << "http session created";
dosGuard_.get().increment(ip);
@@ -222,6 +242,13 @@ public:
if (req_.method() == http::verb::get and req_.target() == "/health")
return sender_(httpResponse(http::status::ok, "text/html", kHEALTH_CHECK_HTML));
if (req_.method() == http::verb::get and req_.target() == "/cache_state") {
if (cache_.get().isFull())
return sender_(httpResponse(http::status::ok, "text/html", kCACHE_CHECK_LOADED_HTML));
return sender_(httpResponse(http::status::service_unavailable, "text/html", kCACHE_CHECK_NOT_LOADED_HTML));
}
if (auto resolvedIp = proxyIpResolver_->resolveClientIp(clientIp_, req_); resolvedIp != clientIp_) {
LOG(log_.info()) << tag() << "Detected a forwarded request from proxy. Proxy ip: " << clientIp_
<< ". Resolved client ip: " << resolvedIp;

View File

@@ -20,6 +20,7 @@
#include "app/WebHandlers.hpp"
#include "rpc/Errors.hpp"
#include "util/AsioContextTestFixture.hpp"
#include "util/MockLedgerCache.hpp"
#include "util/MockPrometheus.hpp"
#include "util/Taggable.hpp"
#include "util/config/ConfigDefinition.hpp"
@@ -149,6 +150,32 @@ TEST_F(HealthCheckHandlerTests, Call)
});
}
struct CacheStateHandlerTests : SyncAsioContextTest, WebHandlersTest {
web::ng::Request request{http::request<http::string_body>{http::verb::get, "/", 11}};
MockLedgerCache cache;
CacheStateHandler cacheStateHandler{cache};
};
TEST_F(CacheStateHandlerTests, CallWithCacheLoaded)
{
EXPECT_CALL(cache, isFull()).WillRepeatedly(testing::Return(true));
runSpawn([&](boost::asio::yield_context yield) {
auto response = cacheStateHandler(request, connectionMock, nullptr, yield);
auto const httpResponse = std::move(response).intoHttpResponse();
EXPECT_EQ(httpResponse.result(), boost::beast::http::status::ok);
});
}
TEST_F(CacheStateHandlerTests, CallWithoutCacheLoaded)
{
EXPECT_CALL(cache, isFull()).WillRepeatedly(testing::Return(false));
runSpawn([&](boost::asio::yield_context yield) {
auto response = cacheStateHandler(request, connectionMock, nullptr, yield);
auto const httpResponse = std::move(response).intoHttpResponse();
EXPECT_EQ(httpResponse.result(), boost::beast::http::status::service_unavailable);
});
}
struct RequestHandlerTest : SyncAsioContextTest, WebHandlersTest {
AdminVerificationStrategyStrictMockPtr adminVerifier{
std::make_shared<testing::StrictMock<AdminVerificationStrategyMock>>()

View File

@@ -17,7 +17,9 @@
*/
//==============================================================================
#include "data/LedgerCacheInterface.hpp"
#include "util/AssignRandomPort.hpp"
#include "util/MockLedgerCache.hpp"
#include "util/MockPrometheus.hpp"
#include "util/TestHttpClient.hpp"
#include "util/TestWebSocketClient.hpp"
@@ -48,11 +50,13 @@
#include <boost/json/value.hpp>
#include <boost/system/system_error.hpp>
#include <fmt/format.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <test_data/SslCert.hpp>
#include <condition_variable>
#include <cstdint>
#include <functional>
#include <memory>
#include <mutex>
#include <optional>
@@ -223,15 +227,18 @@ makeServerSync(
util::config::ClioConfigDefinition const& config,
boost::asio::io_context& ioc,
web::dosguard::DOSGuardInterface& dosGuard,
std::shared_ptr<Executor> const& handler
std::shared_ptr<Executor> const& handler,
std::reference_wrapper<data::LedgerCacheInterface const> cache
)
{
auto server = std::shared_ptr<web::HttpServer<Executor>>();
std::mutex m;
std::condition_variable cv;
bool ready = false;
boost::asio::dispatch(ioc.get_executor(), [&]() mutable {
server = web::makeHttpServer(config, ioc, dosGuard, handler);
server = web::makeHttpServer(config, ioc, dosGuard, handler, cache);
{
std::lock_guard const lk(m);
ready = true;
@@ -249,8 +256,9 @@ makeServerSync(
TEST_F(WebServerTest, Http)
{
auto cache = MockLedgerCache();
auto const e = std::make_shared<EchoExecutor>();
auto const server = makeServerSync(cfg, ctx, dosGuard, e);
auto const server = makeServerSync(cfg, ctx, dosGuard, e, cache);
auto const [status, res] = HttpSyncClient::post("localhost", port, R"JSON({"Hello":1})JSON");
EXPECT_EQ(res, R"JSON({"Hello":1})JSON");
EXPECT_EQ(status, boost::beast::http::status::ok);
@@ -258,8 +266,9 @@ TEST_F(WebServerTest, Http)
TEST_F(WebServerTest, Ws)
{
auto cache = MockLedgerCache();
auto e = std::make_shared<EchoExecutor>();
auto const server = makeServerSync(cfg, ctx, dosGuard, e);
auto const server = makeServerSync(cfg, ctx, dosGuard, e, cache);
WebSocketSyncClient wsClient;
wsClient.connect("localhost", port);
auto const res = wsClient.syncPost(R"JSON({"Hello":1})JSON");
@@ -269,8 +278,9 @@ TEST_F(WebServerTest, Ws)
TEST_F(WebServerTest, HttpInternalError)
{
auto cache = MockLedgerCache();
auto const e = std::make_shared<ExceptionExecutor>();
auto const server = makeServerSync(cfg, ctx, dosGuard, e);
auto const server = makeServerSync(cfg, ctx, dosGuard, e, cache);
auto const [status, res] = HttpSyncClient::post("localhost", port, R"JSON({})JSON");
EXPECT_EQ(
res,
@@ -281,8 +291,9 @@ TEST_F(WebServerTest, HttpInternalError)
TEST_F(WebServerTest, WsInternalError)
{
auto cache = MockLedgerCache();
auto e = std::make_shared<ExceptionExecutor>();
auto const server = makeServerSync(cfg, ctx, dosGuard, e);
auto const server = makeServerSync(cfg, ctx, dosGuard, e, cache);
WebSocketSyncClient wsClient;
wsClient.connect("localhost", port);
auto const res = wsClient.syncPost(R"JSON({"id":"id1"})JSON");
@@ -295,8 +306,9 @@ TEST_F(WebServerTest, WsInternalError)
TEST_F(WebServerTest, WsInternalErrorNotJson)
{
auto cache = MockLedgerCache();
auto e = std::make_shared<ExceptionExecutor>();
auto const server = makeServerSync(cfg, ctx, dosGuard, e);
auto const server = makeServerSync(cfg, ctx, dosGuard, e, cache);
WebSocketSyncClient wsClient;
wsClient.connect("localhost", port);
auto const res = wsClient.syncPost("not json");
@@ -314,7 +326,8 @@ TEST_F(WebServerTest, IncompleteSslConfig)
auto jsonConfig = generateJSONWithDynamicPort(port);
jsonConfig.as_object()["ssl_key_file"] = sslKeyFile.path;
auto const server = makeServerSync(getParseServerConfig(jsonConfig), ctx, dosGuard, e);
auto cache = MockLedgerCache();
auto const server = makeServerSync(getParseServerConfig(jsonConfig), ctx, dosGuard, e, cache);
EXPECT_EQ(server, nullptr);
}
@@ -326,24 +339,27 @@ TEST_F(WebServerTest, WrongSslConfig)
jsonConfig.as_object()["ssl_key_file"] = sslKeyFile.path;
jsonConfig.as_object()["ssl_cert_file"] = "wrong_path";
auto const server = makeServerSync(getParseServerConfig(jsonConfig), ctx, dosGuard, e);
auto cache = MockLedgerCache();
auto const server = makeServerSync(getParseServerConfig(jsonConfig), ctx, dosGuard, e, cache);
EXPECT_EQ(server, nullptr);
}
TEST_F(WebServerTest, Https)
{
auto cache = MockLedgerCache();
auto const e = std::make_shared<EchoExecutor>();
cfg = getParseServerConfig(addSslConfig(generateJSONWithDynamicPort(port)));
auto const server = makeServerSync(cfg, ctx, dosGuard, e);
auto const server = makeServerSync(cfg, ctx, dosGuard, e, cache);
auto const res = HttpsSyncClient::syncPost("localhost", port, R"JSON({"Hello":1})JSON");
EXPECT_EQ(res, R"JSON({"Hello":1})JSON");
}
TEST_F(WebServerTest, Wss)
{
auto cache = MockLedgerCache();
auto e = std::make_shared<EchoExecutor>();
cfg = getParseServerConfig(addSslConfig(generateJSONWithDynamicPort(port)));
auto server = makeServerSync(cfg, ctx, dosGuard, e);
auto server = makeServerSync(cfg, ctx, dosGuard, e, cache);
WebServerSslSyncClient wsClient;
wsClient.connect("localhost", port);
auto const res = wsClient.syncPost(R"JSON({"Hello":1})JSON");
@@ -354,8 +370,9 @@ TEST_F(WebServerTest, Wss)
TEST_F(WebServerTest, HttpPayloadOverload)
{
std::string const s100(100, 'a');
auto cache = MockLedgerCache();
auto const e = std::make_shared<EchoExecutor>();
auto server = makeServerSync(cfg, ctx, dosGuardOverload, e);
auto server = makeServerSync(cfg, ctx, dosGuardOverload, e, cache);
auto const [status, res] =
HttpSyncClient::post("localhost", port, fmt::format(R"JSON({{"payload":"{}"}})JSON", s100));
EXPECT_EQ(
@@ -368,8 +385,9 @@ TEST_F(WebServerTest, HttpPayloadOverload)
TEST_F(WebServerTest, WsPayloadOverload)
{
std::string const s100(100, 'a');
auto cache = MockLedgerCache();
auto const e = std::make_shared<EchoExecutor>();
auto server = makeServerSync(cfg, ctx, dosGuardOverload, e);
auto server = makeServerSync(cfg, ctx, dosGuardOverload, e, cache);
WebSocketSyncClient wsClient;
wsClient.connect("localhost", port);
auto const res = wsClient.syncPost(fmt::format(R"JSON({{"payload":"{}"}})JSON", s100));
@@ -382,8 +400,9 @@ TEST_F(WebServerTest, WsPayloadOverload)
TEST_F(WebServerTest, WsTooManyConnection)
{
auto cache = MockLedgerCache();
auto const e = std::make_shared<EchoExecutor>();
auto server = makeServerSync(cfg, ctx, dosGuardOverload, e);
auto server = makeServerSync(cfg, ctx, dosGuardOverload, e, cache);
// max connection is 2, exception should happen when the third connection is made
WebSocketSyncClient wsClient1;
wsClient1.connect("localhost", port);
@@ -404,18 +423,46 @@ TEST_F(WebServerTest, WsTooManyConnection)
TEST_F(WebServerTest, HealthCheck)
{
auto cache = MockLedgerCache();
auto e = std::make_shared<ExceptionExecutor>(); // request handled before we get to executor
auto const server = makeServerSync(cfg, ctx, dosGuard, e);
auto const server = makeServerSync(cfg, ctx, dosGuard, e, cache);
auto const [status, res] = HttpSyncClient::get("localhost", port, "", "/health");
EXPECT_FALSE(res.empty());
EXPECT_EQ(status, boost::beast::http::status::ok);
}
TEST_F(WebServerTest, CacheStateCheckWithLoadedCache)
{
auto cache = MockLedgerCache();
EXPECT_CALL(cache, isFull()).WillRepeatedly(testing::Return(true));
auto e = std::make_shared<ExceptionExecutor>(); // request handled before we get to executor
auto const server = makeServerSync(cfg, ctx, dosGuard, e, cache);
auto const [status, res] = HttpSyncClient::get("localhost", port, "", "/cache_state");
EXPECT_FALSE(res.empty());
EXPECT_EQ(status, boost::beast::http::status::ok);
}
TEST_F(WebServerTest, CacheStateCheckWithoutLoadedCache)
{
auto cache = MockLedgerCache();
EXPECT_CALL(cache, isFull()).WillRepeatedly(testing::Return(false));
auto e = std::make_shared<ExceptionExecutor>(); // request handled before we get to executor
auto const server = makeServerSync(cfg, ctx, dosGuard, e, cache);
auto const [status, res] = HttpSyncClient::get("localhost", port, "", "/cache_state");
EXPECT_FALSE(res.empty());
EXPECT_EQ(status, boost::beast::http::status::service_unavailable);
}
TEST_F(WebServerTest, GetOtherThanHealthCheck)
{
auto cache = MockLedgerCache();
auto e = std::make_shared<ExceptionExecutor>(); // request handled before we get to executor
auto const server = makeServerSync(cfg, ctx, dosGuard, e);
auto const server = makeServerSync(cfg, ctx, dosGuard, e, cache);
auto const [status, res] = HttpSyncClient::get("localhost", port, "", "/");
EXPECT_FALSE(res.empty());
@@ -539,9 +586,10 @@ class WebServerAdminTest : public WebServerTest, public ::testing::WithParamInte
TEST_P(WebServerAdminTest, WsAdminCheck)
{
auto cache = MockLedgerCache();
auto e = std::make_shared<AdminCheckExecutor>();
ClioConfigDefinition const serverConfig{getParseAdminServerConfig(boost::json::parse(GetParam().config))};
auto server = makeServerSync(serverConfig, ctx, dosGuardOverload, e);
auto server = makeServerSync(serverConfig, ctx, dosGuardOverload, e, cache);
WebSocketSyncClient wsClient;
uint32_t const webServerPort = serverConfig.get<uint32_t>("server.port");
wsClient.connect("localhost", std::to_string(webServerPort), GetParam().headers);
@@ -553,9 +601,10 @@ TEST_P(WebServerAdminTest, WsAdminCheck)
TEST_P(WebServerAdminTest, HttpAdminCheck)
{
auto cache = MockLedgerCache();
auto const e = std::make_shared<AdminCheckExecutor>();
ClioConfigDefinition const serverConfig{getParseAdminServerConfig(boost::json::parse(GetParam().config))};
auto server = makeServerSync(serverConfig, ctx, dosGuardOverload, e);
auto server = makeServerSync(serverConfig, ctx, dosGuardOverload, e, cache);
std::string const request = "Why hello";
uint32_t const webServerPort = serverConfig.get<uint32_t>("server.port");
auto const [status, res] =
@@ -651,7 +700,9 @@ TEST_F(WebServerTest, AdminErrorCfgTestBothAdminPasswordAndLocalAdminSet)
ClioConfigDefinition const serverConfig{
getParseAdminServerConfig(boost::json::parse(jsonServerConfigWithBothAdminPasswordAndLocalAdmin))
};
EXPECT_THROW(web::makeHttpServer(serverConfig, ctx, dosGuardOverload, e), std::logic_error);
MockLedgerCache cache;
EXPECT_THROW(web::makeHttpServer(serverConfig, ctx, dosGuardOverload, e, cache), std::logic_error);
}
TEST_F(WebServerTest, AdminErrorCfgTestBothAdminPasswordAndLocalAdminFalse)
@@ -672,19 +723,22 @@ TEST_F(WebServerTest, AdminErrorCfgTestBothAdminPasswordAndLocalAdminFalse)
ClioConfigDefinition const serverConfig{
getParseAdminServerConfig(boost::json::parse(jsonServerConfigWithNoAdminPasswordAndLocalAdminFalse))
};
EXPECT_THROW(web::makeHttpServer(serverConfig, ctx, dosGuardOverload, e), std::logic_error);
MockLedgerCache cache;
EXPECT_THROW(web::makeHttpServer(serverConfig, ctx, dosGuardOverload, e, cache), std::logic_error);
}
struct WebServerPrometheusTest : util::prometheus::WithPrometheus, WebServerTest {};
TEST_F(WebServerPrometheusTest, rejectedWithoutAdminPassword)
{
auto cache = MockLedgerCache();
auto const e = std::make_shared<EchoExecutor>();
uint32_t const webServerPort = tests::util::generateFreePort();
ClioConfigDefinition const serverConfig{
getParseAdminServerConfig(boost::json::parse(jsonServerConfigWithAdminPassword(webServerPort)))
};
auto server = makeServerSync(serverConfig, ctx, dosGuard, e);
auto server = makeServerSync(serverConfig, ctx, dosGuard, e, cache);
auto const [status, res] = HttpSyncClient::get("localhost", std::to_string(webServerPort), "", "/metrics");
EXPECT_EQ(res, "Only admin is allowed to collect metrics");
@@ -708,11 +762,12 @@ TEST_F(WebServerPrometheusDisabledTest, rejectedIfPrometheusIsDisabled)
webServerPort
);
auto cache = MockLedgerCache();
auto const e = std::make_shared<EchoExecutor>();
ClioConfigDefinition const serverConfig{
getParseAdminServerConfig(boost::json::parse(jsonServerConfigWithDisabledPrometheus))
};
auto server = makeServerSync(serverConfig, ctx, dosGuard, e);
auto server = makeServerSync(serverConfig, ctx, dosGuard, e, cache);
auto const [status, res] = HttpSyncClient::get(
"localhost",
std::to_string(webServerPort),
@@ -729,6 +784,7 @@ TEST_F(WebServerPrometheusDisabledTest, rejectedIfPrometheusIsDisabled)
TEST_F(WebServerPrometheusTest, validResponse)
{
auto cache = MockLedgerCache();
uint32_t const webServerPort = tests::util::generateFreePort();
auto& testCounter = PrometheusService::counterInt("test_counter", util::prometheus::Labels());
++testCounter;
@@ -736,7 +792,7 @@ TEST_F(WebServerPrometheusTest, validResponse)
ClioConfigDefinition const serverConfig{
getParseAdminServerConfig(boost::json::parse(jsonServerConfigWithAdminPassword(webServerPort)))
};
auto server = makeServerSync(serverConfig, ctx, dosGuard, e);
auto server = makeServerSync(serverConfig, ctx, dosGuard, e, cache);
auto const [status, res] = HttpSyncClient::get(
"localhost",
std::to_string(webServerPort),