mirror of
https://github.com/XRPLF/clio.git
synced 2025-12-06 17:27:58 +00:00
@@ -121,6 +121,7 @@ target_sources(
|
||||
util/requests/WsConnectionTests.cpp
|
||||
util/RandomTests.cpp
|
||||
util/RetryTests.cpp
|
||||
util/RepeatTests.cpp
|
||||
util/SignalsHandlerTests.cpp
|
||||
util/TimeUtilsTests.cpp
|
||||
util/TxUtilTests.cpp
|
||||
@@ -129,7 +130,7 @@ target_sources(
|
||||
web/impl/ServerSslContextTests.cpp
|
||||
web/RPCServerHandlerTests.cpp
|
||||
web/ServerTests.cpp
|
||||
web/SweepHandlerTests.cpp
|
||||
web/IntervalSweepHandlerTests.cpp
|
||||
web/WhitelistHandlerTests.cpp
|
||||
# New Config
|
||||
util/newconfig/ArrayViewTests.cpp
|
||||
|
||||
@@ -38,7 +38,6 @@ constexpr auto JSONData = R"JSON(
|
||||
{
|
||||
"dos_guard": {
|
||||
"max_fetches": 100,
|
||||
"sweep_interval": 1,
|
||||
"max_connections": 2,
|
||||
"max_requests": 3,
|
||||
"whitelist": [
|
||||
@@ -55,33 +54,13 @@ struct MockWhitelistHandler {
|
||||
};
|
||||
|
||||
using MockWhitelistHandlerType = NiceMock<MockWhitelistHandler>;
|
||||
|
||||
class FakeSweepHandler {
|
||||
private:
|
||||
using guardType = BasicDOSGuard<MockWhitelistHandlerType, FakeSweepHandler>;
|
||||
guardType* dosGuard_;
|
||||
|
||||
public:
|
||||
void
|
||||
setup(guardType* guard)
|
||||
{
|
||||
dosGuard_ = guard;
|
||||
}
|
||||
|
||||
void
|
||||
sweep()
|
||||
{
|
||||
dosGuard_->clear();
|
||||
}
|
||||
};
|
||||
}; // namespace
|
||||
|
||||
class DOSGuardTest : public NoLoggerFixture {
|
||||
protected:
|
||||
Config cfg{json::parse(JSONData)};
|
||||
FakeSweepHandler sweepHandler{};
|
||||
MockWhitelistHandlerType whitelistHandler;
|
||||
BasicDOSGuard<MockWhitelistHandlerType, FakeSweepHandler> guard{cfg, whitelistHandler, sweepHandler};
|
||||
BasicDOSGuard<MockWhitelistHandlerType> guard{cfg, whitelistHandler};
|
||||
};
|
||||
|
||||
TEST_F(DOSGuardTest, Whitelisting)
|
||||
@@ -124,7 +103,7 @@ TEST_F(DOSGuardTest, ClearFetchCountOnTimer)
|
||||
EXPECT_FALSE(guard.add(IP, 1)); // can't add even 1 anymore
|
||||
EXPECT_FALSE(guard.isOk(IP));
|
||||
|
||||
sweepHandler.sweep(); // pretend sweep called from timer
|
||||
guard.clear(); // pretend sweep called from timer
|
||||
EXPECT_TRUE(guard.isOk(IP)); // can fetch again
|
||||
}
|
||||
|
||||
@@ -148,6 +127,6 @@ TEST_F(DOSGuardTest, RequestLimitOnTimer)
|
||||
EXPECT_TRUE(guard.isOk(IP));
|
||||
EXPECT_FALSE(guard.request(IP));
|
||||
EXPECT_FALSE(guard.isOk(IP));
|
||||
sweepHandler.sweep();
|
||||
guard.clear();
|
||||
EXPECT_TRUE(guard.isOk(IP)); // can request again
|
||||
}
|
||||
|
||||
@@ -18,37 +18,42 @@
|
||||
//==============================================================================
|
||||
|
||||
#include "etl/SystemState.hpp"
|
||||
#include "etl/impl/AmendmentBlock.hpp"
|
||||
#include "util/FakeAmendmentBlockAction.hpp"
|
||||
#include "etl/impl/AmendmentBlockHandler.hpp"
|
||||
#include "util/AsioContextTestFixture.hpp"
|
||||
#include "util/LoggerFixtures.hpp"
|
||||
#include "util/MockPrometheus.hpp"
|
||||
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
|
||||
using namespace testing;
|
||||
using namespace etl;
|
||||
using namespace etl::impl;
|
||||
|
||||
struct AmendmentBlockHandlerTest : util::prometheus::WithPrometheus, NoLoggerFixture {
|
||||
using AmendmentBlockHandlerType = impl::AmendmentBlockHandler<FakeAmendmentBlockAction>;
|
||||
|
||||
boost::asio::io_context ioc_;
|
||||
struct AmendmentBlockHandlerTest : util::prometheus::WithPrometheus, SyncAsioContextTest {
|
||||
testing::StrictMock<testing::MockFunction<void()>> actionMock;
|
||||
etl::SystemState state;
|
||||
};
|
||||
|
||||
TEST_F(AmendmentBlockHandlerTest, CallToOnAmendmentBlockSetsStateAndRepeatedlyCallsAction)
|
||||
{
|
||||
std::size_t callCount = 0;
|
||||
SystemState state;
|
||||
AmendmentBlockHandlerType handler{ioc_, state, std::chrono::nanoseconds{1}, {std::ref(callCount)}};
|
||||
AmendmentBlockHandler handler{ctx, state, std::chrono::nanoseconds{1}, actionMock.AsStdFunction()};
|
||||
|
||||
EXPECT_FALSE(state.isAmendmentBlocked);
|
||||
EXPECT_CALL(actionMock, Call()).Times(testing::AtLeast(10));
|
||||
handler.onAmendmentBlock();
|
||||
EXPECT_TRUE(state.isAmendmentBlocked);
|
||||
|
||||
ioc_.run_for(std::chrono::milliseconds{1});
|
||||
EXPECT_TRUE(callCount >= 10);
|
||||
runContextFor(std::chrono::milliseconds{1});
|
||||
}
|
||||
|
||||
struct DefaultAmendmentBlockActionTest : LoggerFixture {};
|
||||
|
||||
TEST_F(DefaultAmendmentBlockActionTest, Call)
|
||||
{
|
||||
AmendmentBlockHandler::defaultAmendmentBlockAction();
|
||||
auto const loggerString = getLoggerString();
|
||||
EXPECT_TRUE(loggerString.starts_with("ETL:FTL Can't process new ledgers")) << "LoggerString " << loggerString;
|
||||
}
|
||||
|
||||
82
tests/unit/util/RepeatTests.cpp
Normal file
82
tests/unit/util/RepeatTests.cpp
Normal file
@@ -0,0 +1,82 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of clio: https://github.com/XRPLF/clio
|
||||
Copyright (c) 2024, the clio developers.
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include "util/AsioContextTestFixture.hpp"
|
||||
#include "util/Repeat.hpp"
|
||||
#include "util/WithTimeout.hpp"
|
||||
|
||||
#include <boost/asio/error.hpp>
|
||||
#include <boost/asio/executor_work_guard.hpp>
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <ranges>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
using namespace util;
|
||||
using testing::AtLeast;
|
||||
|
||||
struct RepeatTests : SyncAsioContextTest {
|
||||
Repeat repeat{ctx};
|
||||
testing::StrictMock<testing::MockFunction<void()>> handlerMock;
|
||||
|
||||
void
|
||||
withRunningContext(std::function<void()> func)
|
||||
{
|
||||
tests::common::util::withTimeout(std::chrono::seconds{1000}, [this, func = std::move(func)]() {
|
||||
auto workGuard = boost::asio::make_work_guard(ctx);
|
||||
std::thread thread{[this]() { ctx.run(); }};
|
||||
func();
|
||||
workGuard.reset();
|
||||
thread.join();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(RepeatTests, CallsHandler)
|
||||
{
|
||||
repeat.start(std::chrono::milliseconds{1}, handlerMock.AsStdFunction());
|
||||
EXPECT_CALL(handlerMock, Call).Times(AtLeast(10));
|
||||
runContextFor(std::chrono::milliseconds{20});
|
||||
}
|
||||
|
||||
TEST_F(RepeatTests, StopsOnStop)
|
||||
{
|
||||
withRunningContext([this]() {
|
||||
repeat.start(std::chrono::milliseconds{1}, handlerMock.AsStdFunction());
|
||||
EXPECT_CALL(handlerMock, Call).Times(AtLeast(1));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds{10});
|
||||
repeat.stop();
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(RepeatTests, RunsAfterStop)
|
||||
{
|
||||
withRunningContext([this]() {
|
||||
for ([[maybe_unused]] auto _ : std::ranges::iota_view(0, 2)) {
|
||||
repeat.start(std::chrono::milliseconds{1}, handlerMock.AsStdFunction());
|
||||
EXPECT_CALL(handlerMock, Call).Times(AtLeast(1));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds{10});
|
||||
repeat.stop();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -17,9 +17,9 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include "rpc/FakesAndMocks.hpp"
|
||||
#include "util/AsioContextTestFixture.hpp"
|
||||
#include "util/config/Config.hpp"
|
||||
#include "web/DOSGuard.hpp"
|
||||
#include "web/IntervalSweepHandler.hpp"
|
||||
|
||||
#include <boost/json/parse.hpp>
|
||||
@@ -28,30 +28,29 @@
|
||||
|
||||
#include <chrono>
|
||||
|
||||
using namespace util;
|
||||
using namespace web;
|
||||
using namespace testing;
|
||||
|
||||
constexpr static auto JSONData = R"JSON(
|
||||
struct IntervalSweepHandlerTest : SyncAsioContextTest {
|
||||
protected:
|
||||
constexpr static auto JSONData = R"JSON(
|
||||
{
|
||||
"dos_guard": {
|
||||
"max_fetches": 100,
|
||||
"sweep_interval": 0.1,
|
||||
"max_connections": 2,
|
||||
"whitelist": ["127.0.0.1"]
|
||||
"sweep_interval": 0
|
||||
}
|
||||
}
|
||||
)JSON";
|
||||
|
||||
class DOSGuardIntervalSweepHandlerTest : public SyncAsioContextTest {
|
||||
protected:
|
||||
Config cfg{boost::json::parse(JSONData)};
|
||||
IntervalSweepHandler sweepHandler{cfg, ctx};
|
||||
tests::common::BasicDOSGuardMock<IntervalSweepHandler> guard{sweepHandler};
|
||||
struct DosGuardMock : BaseDOSGuard {
|
||||
MOCK_METHOD(void, clear, (), (noexcept, override));
|
||||
};
|
||||
testing::StrictMock<DosGuardMock> guardMock;
|
||||
|
||||
util::Config cfg{boost::json::parse(JSONData)};
|
||||
IntervalSweepHandler sweepHandler{cfg, ctx, guardMock};
|
||||
};
|
||||
|
||||
TEST_F(DOSGuardIntervalSweepHandlerTest, SweepAfterInterval)
|
||||
TEST_F(IntervalSweepHandlerTest, SweepAfterInterval)
|
||||
{
|
||||
EXPECT_CALL(guard, clear()).Times(AtLeast(2));
|
||||
ctx.run_for(std::chrono::milliseconds(400));
|
||||
EXPECT_CALL(guardMock, clear()).Times(testing::AtLeast(10));
|
||||
runContextFor(std::chrono::milliseconds{20});
|
||||
}
|
||||
@@ -127,14 +127,14 @@ struct WebServerTest : NoLoggerFixture {
|
||||
boost::asio::io_context ctxSync;
|
||||
std::string const port = std::to_string(tests::util::generateFreePort());
|
||||
Config cfg{generateJSONWithDynamicPort(port)};
|
||||
IntervalSweepHandler sweepHandler = web::IntervalSweepHandler{cfg, ctxSync};
|
||||
WhitelistHandler whitelistHandler = web::WhitelistHandler{cfg};
|
||||
DOSGuard dosGuard = web::DOSGuard{cfg, whitelistHandler, sweepHandler};
|
||||
WhitelistHandler whitelistHandler{cfg};
|
||||
DOSGuard dosGuard{cfg, whitelistHandler};
|
||||
IntervalSweepHandler sweepHandler{cfg, ctxSync, dosGuard};
|
||||
|
||||
Config cfgOverload{generateJSONDataOverload(port)};
|
||||
IntervalSweepHandler sweepHandlerOverload = web::IntervalSweepHandler{cfgOverload, ctxSync};
|
||||
WhitelistHandler whitelistHandlerOverload = web::WhitelistHandler{cfgOverload};
|
||||
DOSGuard dosGuardOverload = web::DOSGuard{cfgOverload, whitelistHandlerOverload, sweepHandlerOverload};
|
||||
WhitelistHandler whitelistHandlerOverload{cfgOverload};
|
||||
DOSGuard dosGuardOverload{cfgOverload, whitelistHandlerOverload};
|
||||
IntervalSweepHandler sweepHandlerOverload{cfgOverload, ctxSync, dosGuardOverload};
|
||||
// this ctx is for http server
|
||||
boost::asio::io_context ctx;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user