mirror of
https://github.com/XRPLF/clio.git
synced 2025-12-06 17:27:58 +00:00
@@ -18,6 +18,7 @@
|
||||
//==============================================================================
|
||||
|
||||
#include <util/Fixtures.h>
|
||||
#include <util/MockPrometheus.h>
|
||||
|
||||
#include <rpc/Counters.h>
|
||||
#include <rpc/JS.h>
|
||||
@@ -27,8 +28,11 @@
|
||||
|
||||
using namespace rpc;
|
||||
|
||||
class RPCCountersTest : public NoLoggerFixture {
|
||||
protected:
|
||||
using util::prometheus::CounterInt;
|
||||
using util::prometheus::WithMockPrometheus;
|
||||
using util::prometheus::WithPrometheus;
|
||||
|
||||
struct RPCCountersTest : WithPrometheus, NoLoggerFixture {
|
||||
WorkQueue queue{4u, 1024u}; // todo: mock instead
|
||||
Counters counters{queue};
|
||||
};
|
||||
@@ -95,3 +99,87 @@ TEST_F(RPCCountersTest, CheckThatCountersAddUp)
|
||||
|
||||
EXPECT_EQ(report.at("work_queue"), queue.report()); // Counters report includes queue report
|
||||
}
|
||||
|
||||
struct RPCCountersMockPrometheusTests : WithMockPrometheus {
|
||||
WorkQueue queue{4u, 1024u}; // todo: mock instead
|
||||
Counters counters{queue};
|
||||
};
|
||||
|
||||
TEST_F(RPCCountersMockPrometheusTests, rpcFailed)
|
||||
{
|
||||
auto& startedMock = makeMock<CounterInt>("rpc_method_total_number", "{method=\"test\",status=\"started\"}");
|
||||
auto& failedMock = makeMock<CounterInt>("rpc_method_total_number", "{method=\"test\",status=\"failed\"}");
|
||||
EXPECT_CALL(startedMock, add(1));
|
||||
EXPECT_CALL(failedMock, add(1));
|
||||
counters.rpcFailed("test");
|
||||
}
|
||||
|
||||
TEST_F(RPCCountersMockPrometheusTests, rpcErrored)
|
||||
{
|
||||
auto& startedMock = makeMock<CounterInt>("rpc_method_total_number", "{method=\"test\",status=\"started\"}");
|
||||
auto& erroredMock = makeMock<CounterInt>("rpc_method_total_number", "{method=\"test\",status=\"errored\"}");
|
||||
EXPECT_CALL(startedMock, add(1));
|
||||
EXPECT_CALL(erroredMock, add(1));
|
||||
counters.rpcErrored("test");
|
||||
}
|
||||
|
||||
TEST_F(RPCCountersMockPrometheusTests, rpcComplete)
|
||||
{
|
||||
auto& startedMock = makeMock<CounterInt>("rpc_method_total_number", "{method=\"test\",status=\"started\"}");
|
||||
auto& finishedMock = makeMock<CounterInt>("rpc_method_total_number", "{method=\"test\",status=\"finished\"}");
|
||||
auto& durationMock = makeMock<CounterInt>("rpc_method_duration_us", "{method=\"test\"}");
|
||||
EXPECT_CALL(startedMock, add(1));
|
||||
EXPECT_CALL(finishedMock, add(1));
|
||||
EXPECT_CALL(durationMock, add(123));
|
||||
counters.rpcComplete("test", std::chrono::microseconds(123));
|
||||
}
|
||||
|
||||
TEST_F(RPCCountersMockPrometheusTests, rpcForwarded)
|
||||
{
|
||||
auto& forwardedMock = makeMock<CounterInt>("rpc_method_total_number", "{method=\"test\",status=\"forwarded\"}");
|
||||
EXPECT_CALL(forwardedMock, add(1));
|
||||
counters.rpcForwarded("test");
|
||||
}
|
||||
|
||||
TEST_F(RPCCountersMockPrometheusTests, rpcFailedToForwarded)
|
||||
{
|
||||
auto& failedForwadMock =
|
||||
makeMock<CounterInt>("rpc_method_total_number", "{method=\"test\",status=\"failed_forward\"}");
|
||||
EXPECT_CALL(failedForwadMock, add(1));
|
||||
counters.rpcFailedToForward("test");
|
||||
}
|
||||
|
||||
TEST_F(RPCCountersMockPrometheusTests, onTooBusy)
|
||||
{
|
||||
auto& tooBusyMock = makeMock<CounterInt>("rpc_error_total_number", "{error_type=\"too_busy\"}");
|
||||
EXPECT_CALL(tooBusyMock, add(1));
|
||||
counters.onTooBusy();
|
||||
}
|
||||
|
||||
TEST_F(RPCCountersMockPrometheusTests, onNotReady)
|
||||
{
|
||||
auto& notReadyMock = makeMock<CounterInt>("rpc_error_total_number", "{error_type=\"not_ready\"}");
|
||||
EXPECT_CALL(notReadyMock, add(1));
|
||||
counters.onNotReady();
|
||||
}
|
||||
|
||||
TEST_F(RPCCountersMockPrometheusTests, onBadSyntax)
|
||||
{
|
||||
auto& badSyntaxMock = makeMock<CounterInt>("rpc_error_total_number", "{error_type=\"bad_syntax\"}");
|
||||
EXPECT_CALL(badSyntaxMock, add(1));
|
||||
counters.onBadSyntax();
|
||||
}
|
||||
|
||||
TEST_F(RPCCountersMockPrometheusTests, onUnknownCommand)
|
||||
{
|
||||
auto& unknownCommandMock = makeMock<CounterInt>("rpc_error_total_number", "{error_type=\"unknown_command\"}");
|
||||
EXPECT_CALL(unknownCommandMock, add(1));
|
||||
counters.onUnknownCommand();
|
||||
}
|
||||
|
||||
TEST_F(RPCCountersMockPrometheusTests, onInternalError)
|
||||
{
|
||||
auto& internalErrorMock = makeMock<CounterInt>("rpc_error_total_number", "{error_type=\"internal_error\"}");
|
||||
EXPECT_CALL(internalErrorMock, add(1));
|
||||
counters.onInternalError();
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
//==============================================================================
|
||||
|
||||
#include <util/Fixtures.h>
|
||||
#include <util/MockPrometheus.h>
|
||||
|
||||
#include <rpc/WorkQueue.h>
|
||||
|
||||
@@ -28,6 +29,7 @@
|
||||
|
||||
using namespace util;
|
||||
using namespace rpc;
|
||||
using namespace util::prometheus;
|
||||
|
||||
namespace {
|
||||
constexpr auto JSONConfig = R"JSON({
|
||||
@@ -36,36 +38,31 @@ constexpr auto JSONConfig = R"JSON({
|
||||
})JSON";
|
||||
} // namespace
|
||||
|
||||
class RPCWorkQueueTest : public NoLoggerFixture {
|
||||
protected:
|
||||
struct RPCWorkQueueTestBase : NoLoggerFixture {
|
||||
Config cfg = Config{boost::json::parse(JSONConfig)};
|
||||
WorkQueue queue = WorkQueue::make_WorkQueue(cfg);
|
||||
};
|
||||
|
||||
struct RPCWorkQueueTest : WithPrometheus, RPCWorkQueueTestBase {};
|
||||
|
||||
TEST_F(RPCWorkQueueTest, WhitelistedExecutionCountAddsUp)
|
||||
{
|
||||
WorkQueue queue = WorkQueue::make_WorkQueue(cfg);
|
||||
|
||||
auto constexpr static TOTAL = 512u;
|
||||
uint32_t executeCount = 0u;
|
||||
|
||||
std::binary_semaphore sem{0};
|
||||
std::mutex mtx;
|
||||
|
||||
for (auto i = 0u; i < TOTAL; ++i) {
|
||||
queue.postCoro(
|
||||
[&executeCount, &sem, &mtx](auto /* yield */) {
|
||||
[&executeCount, &mtx](auto /* yield */) {
|
||||
std::lock_guard const lk(mtx);
|
||||
if (++executeCount; executeCount == TOTAL)
|
||||
sem.release(); // 1) note we are still in user function
|
||||
++executeCount;
|
||||
},
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
sem.acquire();
|
||||
|
||||
// 2) so we have to allow the size of queue to decrease by one asynchronously
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds{1});
|
||||
queue.join();
|
||||
|
||||
auto const report = queue.report();
|
||||
|
||||
@@ -77,13 +74,10 @@ TEST_F(RPCWorkQueueTest, WhitelistedExecutionCountAddsUp)
|
||||
|
||||
TEST_F(RPCWorkQueueTest, NonWhitelistedPreventSchedulingAtQueueLimitExceeded)
|
||||
{
|
||||
auto queue = WorkQueue::make_WorkQueue(cfg);
|
||||
|
||||
auto constexpr static TOTAL = 3u;
|
||||
auto expectedCount = 2u;
|
||||
auto unblocked = false;
|
||||
|
||||
std::binary_semaphore sem{0};
|
||||
std::mutex mtx;
|
||||
std::condition_variable cv;
|
||||
|
||||
@@ -93,8 +87,7 @@ TEST_F(RPCWorkQueueTest, NonWhitelistedPreventSchedulingAtQueueLimitExceeded)
|
||||
std::unique_lock lk{mtx};
|
||||
cv.wait(lk, [&] { return unblocked; });
|
||||
|
||||
if (--expectedCount; expectedCount == 0)
|
||||
sem.release();
|
||||
--expectedCount;
|
||||
},
|
||||
false
|
||||
);
|
||||
@@ -110,6 +103,40 @@ TEST_F(RPCWorkQueueTest, NonWhitelistedPreventSchedulingAtQueueLimitExceeded)
|
||||
}
|
||||
}
|
||||
|
||||
sem.acquire();
|
||||
queue.join();
|
||||
EXPECT_TRUE(unblocked);
|
||||
}
|
||||
|
||||
struct RPCWorkQueueMockPrometheusTest : WithMockPrometheus, RPCWorkQueueTestBase {};
|
||||
|
||||
TEST_F(RPCWorkQueueMockPrometheusTest, postCoroCouhters)
|
||||
{
|
||||
auto& queuedMock = makeMock<CounterInt>("work_queue_queued_total_number", "");
|
||||
auto& durationMock = makeMock<CounterInt>("work_queue_cumulitive_tasks_duration_us", "");
|
||||
auto& curSizeMock = makeMock<GaugeInt>("work_queue_current_size", "");
|
||||
|
||||
std::mutex mtx;
|
||||
bool canContinue = false;
|
||||
std::condition_variable cv;
|
||||
|
||||
EXPECT_CALL(curSizeMock, value()).WillOnce(::testing::Return(0));
|
||||
EXPECT_CALL(curSizeMock, add(1));
|
||||
EXPECT_CALL(queuedMock, add(1));
|
||||
EXPECT_CALL(durationMock, add(::testing::Gt(0))).WillOnce([&](auto) {
|
||||
EXPECT_CALL(curSizeMock, add(-1));
|
||||
std::unique_lock const lk{mtx};
|
||||
canContinue = true;
|
||||
cv.notify_all();
|
||||
});
|
||||
|
||||
auto const res = queue.postCoro(
|
||||
[&](auto /* yield */) {
|
||||
std::unique_lock lk{mtx};
|
||||
cv.wait(lk, [&]() { return canContinue; });
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
ASSERT_TRUE(res);
|
||||
queue.join();
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <rpc/common/AnyHandler.h>
|
||||
#include <rpc/handlers/Subscribe.h>
|
||||
#include <util/Fixtures.h>
|
||||
#include <util/MockPrometheus.h>
|
||||
#include <util/MockWsBase.h>
|
||||
#include <util/TestObject.h>
|
||||
|
||||
@@ -43,7 +44,7 @@ constexpr static auto PAYS20XRPGETS10USDBOOKDIR = "7B1767D41DBCE79D9585CF9D0262A
|
||||
constexpr static auto INDEX1 = "1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515BC";
|
||||
constexpr static auto INDEX2 = "E6DBAFC99223B42257915A63DFC6B0C032D4070F9A574B255AD97466726FC321";
|
||||
|
||||
class RPCSubscribeHandlerTest : public HandlerBaseTest {
|
||||
class RPCSubscribeHandlerTest : public util::prometheus::WithPrometheus, public HandlerBaseTest {
|
||||
protected:
|
||||
void
|
||||
SetUp() override
|
||||
|
||||
Reference in New Issue
Block a user