Files
clio/tests/unit/feed/LedgerFeedTests.cpp
2026-03-24 15:25:32 +00:00

131 lines
4.6 KiB
C++

#include "feed/FeedTestUtil.hpp"
#include "feed/impl/LedgerFeed.hpp"
#include "util/Spawn.hpp"
#include "util/TestObject.hpp"
#include "web/SubscriptionContextInterface.hpp"
#include <boost/asio/io_context.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/json/parse.hpp>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <xrpl/protocol/Fees.h>
namespace {
constexpr auto kLEDGER_HASH = "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652";
} // namespace
using namespace feed::impl;
namespace json = boost::json;
using namespace testing;
using FeedLedgerTest = FeedBaseTest<LedgerFeed>;
TEST_F(FeedLedgerTest, SubPub)
{
backend_->setRange(10, 30);
auto const ledgerHeader = createLedgerHeader(kLEDGER_HASH, 30);
EXPECT_CALL(*backend_, fetchLedgerBySequence).WillOnce(testing::Return(ledgerHeader));
auto const feeBlob = createLegacyFeeSettingBlob(1, 2, 3, 4, 0);
EXPECT_CALL(*backend_, doFetchLedgerObject).WillOnce(testing::Return(feeBlob));
// check the function response
// Information about the ledgers on hand and current fee schedule. This
// includes the same fields as a ledger stream message, except that it omits
// the type and txn_count fields
static constexpr auto kLEDGER_RESPONSE =
R"JSON({
"validated_ledgers": "10-30",
"ledger_index": 30,
"ledger_hash": "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652",
"ledger_time": 0,
"fee_base": 1,
"reserve_base": 3,
"reserve_inc": 2,
"network_id": 123
})JSON";
boost::asio::io_context ioContext;
util::spawn(ioContext, [this](boost::asio::yield_context yield) {
EXPECT_CALL(*mockSessionPtr, onDisconnect);
auto res = testFeedPtr->sub(yield, backend_, sessionPtr, networkID);
// check the response
EXPECT_EQ(res, json::parse(kLEDGER_RESPONSE));
});
ioContext.run();
EXPECT_EQ(testFeedPtr->count(), 1);
static constexpr auto kLEDGER_PUB =
R"JSON({
"type": "ledgerClosed",
"ledger_index": 31,
"ledger_hash": "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652",
"ledger_time": 0,
"fee_base": 0,
"reserve_base": 10,
"reserve_inc": 0,
"validated_ledgers": "10-31",
"txn_count": 8,
"network_id": 123
})JSON";
// test publish
EXPECT_CALL(*mockSessionPtr, send(sharedStringJsonEq(kLEDGER_PUB))).Times(1);
auto const ledgerHeader2 = createLedgerHeader(kLEDGER_HASH, 31);
auto fee2 = ripple::Fees();
fee2.reserve = 10;
testFeedPtr->pub(ledgerHeader2, fee2, "10-31", 8, networkID);
// test unsub, after unsub the send should not be called
testFeedPtr->unsub(sessionPtr);
EXPECT_EQ(testFeedPtr->count(), 0);
EXPECT_CALL(*mockSessionPtr, send(_)).Times(0);
testFeedPtr->pub(ledgerHeader2, fee2, "10-31", 8, networkID);
}
TEST_F(FeedLedgerTest, AutoDisconnect)
{
backend_->setRange(10, 30);
auto const ledgerHeader = createLedgerHeader(kLEDGER_HASH, 30);
EXPECT_CALL(*backend_, fetchLedgerBySequence).WillOnce(testing::Return(ledgerHeader));
auto const feeBlob = createLegacyFeeSettingBlob(1, 2, 3, 4, 0);
EXPECT_CALL(*backend_, doFetchLedgerObject).WillOnce(testing::Return(feeBlob));
static constexpr auto kLEDGER_RESPONSE =
R"JSON({
"validated_ledgers": "10-30",
"ledger_index": 30,
"ledger_hash": "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652",
"ledger_time": 0,
"fee_base": 1,
"reserve_base": 3,
"reserve_inc": 2,
"network_id": 123
})JSON";
web::SubscriptionContextInterface::OnDisconnectSlot slot;
EXPECT_CALL(*mockSessionPtr, onDisconnect).WillOnce(testing::SaveArg<0>(&slot));
boost::asio::io_context ioContext;
util::spawn(ioContext, [this](boost::asio::yield_context yield) {
auto res = testFeedPtr->sub(yield, backend_, sessionPtr, networkID);
// check the response
EXPECT_EQ(res, json::parse(kLEDGER_RESPONSE));
});
ioContext.run();
EXPECT_EQ(testFeedPtr->count(), 1);
EXPECT_CALL(*mockSessionPtr, send(_)).Times(0);
ASSERT_TRUE(slot);
slot(sessionPtr.get());
sessionPtr.reset();
EXPECT_EQ(testFeedPtr->count(), 0);
auto const ledgerHeader2 = createLedgerHeader(kLEDGER_HASH, 31);
auto fee2 = ripple::Fees();
fee2.reserve = 10;
// no error
testFeedPtr->pub(ledgerHeader2, fee2, "10-31", 8, networkID);
}