mirror of
https://github.com/XRPLF/clio.git
synced 2025-12-06 17:27:58 +00:00
@@ -167,6 +167,7 @@ if (tests)
|
||||
unittests/etl/TransformerTests.cpp
|
||||
unittests/etl/CacheLoaderTests.cpp
|
||||
unittests/etl/AmendmentBlockHandlerTests.cpp
|
||||
unittests/etl/LedgerPublisherTests.cpp
|
||||
# RPC
|
||||
unittests/rpc/ErrorTests.cpp
|
||||
unittests/rpc/BaseTests.cpp
|
||||
|
||||
@@ -279,7 +279,7 @@ ETLService::ETLService(
|
||||
, cacheLoader_(config, ioc, backend, backend->cache())
|
||||
, ledgerFetcher_(backend, balancer)
|
||||
, ledgerLoader_(backend, balancer, ledgerFetcher_, state_)
|
||||
, ledgerPublisher_(ioc, backend, subscriptions, state_)
|
||||
, ledgerPublisher_(ioc, backend, backend->cache(), subscriptions, state_)
|
||||
, amendmentBlockHandler_(ioc, state_)
|
||||
{
|
||||
startSequence_ = config.maybeValue<uint32_t>("start_sequence");
|
||||
|
||||
@@ -73,11 +73,12 @@ class ETLService
|
||||
using LoadBalancerType = LoadBalancer;
|
||||
using NetworkValidatedLedgersType = NetworkValidatedLedgers;
|
||||
using DataPipeType = etl::detail::ExtractionDataPipe<org::xrpl::rpc::v1::GetLedgerResponse>;
|
||||
using CacheLoaderType = etl::detail::CacheLoader<data::LedgerCache>;
|
||||
using CacheType = data::LedgerCache;
|
||||
using CacheLoaderType = etl::detail::CacheLoader<CacheType>;
|
||||
using LedgerFetcherType = etl::detail::LedgerFetcher<LoadBalancerType>;
|
||||
using ExtractorType = etl::detail::Extractor<DataPipeType, NetworkValidatedLedgersType, LedgerFetcherType>;
|
||||
using LedgerLoaderType = etl::detail::LedgerLoader<LoadBalancerType, LedgerFetcherType>;
|
||||
using LedgerPublisherType = etl::detail::LedgerPublisher<SubscriptionManagerType>;
|
||||
using LedgerPublisherType = etl::detail::LedgerPublisher<SubscriptionManagerType, CacheType>;
|
||||
using AmendmentBlockHandlerType = etl::detail::AmendmentBlockHandler<>;
|
||||
using TransformerType =
|
||||
etl::detail::Transformer<DataPipeType, LedgerLoaderType, LedgerPublisherType, AmendmentBlockHandlerType>;
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include <etl/SystemState.h>
|
||||
#include <feed/SubscriptionManager.h>
|
||||
#include <util/LedgerUtils.h>
|
||||
#include <util/Profiler.h>
|
||||
#include <util/log/Logger.h>
|
||||
|
||||
#include <ripple/protocol/LedgerHeader.h>
|
||||
@@ -44,7 +43,7 @@ namespace etl::detail {
|
||||
* includes reading all of the transactions from the database) is done from the application wide asio io_service, and a
|
||||
* strand is used to ensure ledgers are published in order.
|
||||
*/
|
||||
template <typename SubscriptionManagerType>
|
||||
template <typename SubscriptionManagerType, typename CacheType>
|
||||
class LedgerPublisher
|
||||
{
|
||||
util::Logger log_{"ETL"};
|
||||
@@ -52,6 +51,7 @@ class LedgerPublisher
|
||||
boost::asio::strand<boost::asio::io_context::executor_type> publishStrand_;
|
||||
|
||||
std::shared_ptr<BackendInterface> backend_;
|
||||
std::reference_wrapper<CacheType> cache_;
|
||||
std::shared_ptr<SubscriptionManagerType> subscriptions_;
|
||||
std::reference_wrapper<SystemState const> state_; // shared state for ETL
|
||||
|
||||
@@ -71,10 +71,12 @@ public:
|
||||
LedgerPublisher(
|
||||
boost::asio::io_context& ioc,
|
||||
std::shared_ptr<BackendInterface> backend,
|
||||
std::shared_ptr<feed::SubscriptionManager> subscriptions,
|
||||
CacheType& cache,
|
||||
std::shared_ptr<SubscriptionManagerType> subscriptions,
|
||||
SystemState const& state)
|
||||
: publishStrand_{boost::asio::make_strand(ioc)}
|
||||
, backend_{std::move(backend)}
|
||||
, cache_{cache}
|
||||
, subscriptions_{std::move(subscriptions)}
|
||||
, state_{std::cref(state)}
|
||||
{
|
||||
@@ -99,6 +101,7 @@ public:
|
||||
|
||||
if (!range || range->maxSequence < ledgerSequence)
|
||||
{
|
||||
++numAttempts;
|
||||
LOG(log_.debug()) << "Trying to publish. Could not find "
|
||||
"ledger with sequence = "
|
||||
<< ledgerSequence;
|
||||
@@ -110,7 +113,6 @@ public:
|
||||
return false;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
++numAttempts;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -126,7 +128,7 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Publish the passed in ledger
|
||||
* @brief Publish the passed ledger asynchronously.
|
||||
*
|
||||
* All ledgers are published thru publishStrand_ which ensures that all publishes are performed in a serial fashion.
|
||||
*
|
||||
@@ -145,34 +147,34 @@ public:
|
||||
std::vector<data::LedgerObject> const diff = data::synchronousAndRetryOnTimeout(
|
||||
[&](auto yield) { return backend_->fetchLedgerDiff(lgrInfo.seq, yield); });
|
||||
|
||||
backend_->cache().update(diff, lgrInfo.seq); // todo: inject cache to update, don't use backend cache
|
||||
cache_.get().update(diff, lgrInfo.seq);
|
||||
backend_->updateRange(lgrInfo.seq);
|
||||
}
|
||||
|
||||
setLastClose(lgrInfo.closeTime);
|
||||
auto age = lastCloseAgeSeconds();
|
||||
|
||||
// if the ledger closed over 10 minutes ago, assume we are still catching up and don't publish
|
||||
// if the ledger closed over MAX_LEDGER_AGE_SECONDS ago, assume we are still catching up and don't publish
|
||||
// TODO: this probably should be a strategy
|
||||
static constexpr std::uint32_t MAX_LEDGER_AGE_SECONDS = 600;
|
||||
if (age < MAX_LEDGER_AGE_SECONDS)
|
||||
{
|
||||
std::optional<ripple::Fees> fees = data::synchronousAndRetryOnTimeout(
|
||||
[&](auto yield) { return backend_->fetchFees(lgrInfo.seq, yield); });
|
||||
assert(fees);
|
||||
|
||||
std::vector<data::TransactionAndMetadata> const transactions = data::synchronousAndRetryOnTimeout(
|
||||
[&](auto yield) { return backend_->fetchAllTransactionsInLedger(lgrInfo.seq, yield); });
|
||||
|
||||
auto ledgerRange = backend_->fetchLedgerRange();
|
||||
auto const ledgerRange = backend_->fetchLedgerRange();
|
||||
assert(ledgerRange);
|
||||
assert(fees);
|
||||
|
||||
std::string const range =
|
||||
std::to_string(ledgerRange->minSequence) + "-" + std::to_string(ledgerRange->maxSequence);
|
||||
|
||||
subscriptions_->pubLedger(lgrInfo, *fees, range, transactions.size());
|
||||
|
||||
for (auto& txAndMeta : transactions)
|
||||
for (auto const& txAndMeta : transactions)
|
||||
subscriptions_->pubTransaction(txAndMeta, lgrInfo);
|
||||
|
||||
subscriptions_->pubBookChanges(lgrInfo, transactions);
|
||||
@@ -223,6 +225,10 @@ public:
|
||||
return now - (rippleEpochStart + closeTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the sequence of the last schueduled ledger to publish, Be aware that the ledger may not have been
|
||||
* published to network
|
||||
*/
|
||||
std::optional<uint32_t>
|
||||
getLastPublishedSequence() const
|
||||
{
|
||||
|
||||
@@ -126,7 +126,7 @@ TEST_F(CacheLoaderTest, FromCache)
|
||||
.WillByDefault(Return(std::vector<Blob>{keysSize - 1, Blob{'s'}}));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(loops);
|
||||
|
||||
EXPECT_CALL(cache, update).Times(loops);
|
||||
EXPECT_CALL(cache, updateImp).Times(loops);
|
||||
EXPECT_CALL(cache, isFull).Times(1);
|
||||
|
||||
std::mutex m;
|
||||
|
||||
249
unittests/etl/LedgerPublisherTests.cpp
Normal file
249
unittests/etl/LedgerPublisherTests.cpp
Normal file
@@ -0,0 +1,249 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of clio: https://github.com/XRPLF/clio
|
||||
Copyright (c) 2023, 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 <etl/impl/LedgerPublisher.h>
|
||||
#include <util/Fixtures.h>
|
||||
#include <util/MockCache.h>
|
||||
#include <util/TestObject.h>
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
using namespace testing;
|
||||
using namespace etl;
|
||||
namespace json = boost::json;
|
||||
using namespace std::chrono;
|
||||
|
||||
static auto constexpr ACCOUNT = "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn";
|
||||
static auto constexpr ACCOUNT2 = "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun";
|
||||
static auto constexpr LEDGERHASH = "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652";
|
||||
static auto constexpr SEQ = 30;
|
||||
static auto constexpr AGE = 800;
|
||||
|
||||
class ETLLedgerPublisherTest : public MockBackendTest, public SyncAsioContextTest, public MockSubscriptionManagerTest
|
||||
{
|
||||
void
|
||||
SetUp() override
|
||||
{
|
||||
MockBackendTest::SetUp();
|
||||
SyncAsioContextTest::SetUp();
|
||||
MockSubscriptionManagerTest::SetUp();
|
||||
}
|
||||
|
||||
void
|
||||
TearDown() override
|
||||
{
|
||||
MockSubscriptionManagerTest::TearDown();
|
||||
SyncAsioContextTest::TearDown();
|
||||
MockBackendTest::TearDown();
|
||||
}
|
||||
|
||||
protected:
|
||||
util::Config cfg{json::parse("{}")};
|
||||
MockCache mockCache;
|
||||
};
|
||||
|
||||
TEST_F(ETLLedgerPublisherTest, PublishLedgerInfoIsWritingFalse)
|
||||
{
|
||||
SystemState dummyState;
|
||||
dummyState.isWriting = false;
|
||||
auto const dummyLedgerInfo = CreateLedgerInfo(LEDGERHASH, SEQ, AGE);
|
||||
detail::LedgerPublisher publisher(ctx, mockBackendPtr, mockCache, mockSubscriptionManagerPtr, dummyState);
|
||||
publisher.publish(dummyLedgerInfo);
|
||||
|
||||
MockBackend* rawBackendPtr = dynamic_cast<MockBackend*>(mockBackendPtr.get());
|
||||
ASSERT_NE(rawBackendPtr, nullptr);
|
||||
|
||||
ON_CALL(*rawBackendPtr, fetchLedgerDiff(SEQ, _)).WillByDefault(Return(std::vector<LedgerObject>{}));
|
||||
EXPECT_CALL(*rawBackendPtr, fetchLedgerDiff(SEQ, _)).Times(1);
|
||||
|
||||
// setLastPublishedSequence not in strand, should verify before run
|
||||
EXPECT_TRUE(publisher.getLastPublishedSequence());
|
||||
EXPECT_EQ(publisher.getLastPublishedSequence().value(), SEQ);
|
||||
|
||||
EXPECT_CALL(mockCache, updateImp).Times(1);
|
||||
|
||||
ctx.run();
|
||||
EXPECT_TRUE(rawBackendPtr->fetchLedgerRange());
|
||||
EXPECT_EQ(rawBackendPtr->fetchLedgerRange().value().minSequence, SEQ);
|
||||
EXPECT_EQ(rawBackendPtr->fetchLedgerRange().value().maxSequence, SEQ);
|
||||
}
|
||||
|
||||
TEST_F(ETLLedgerPublisherTest, PublishLedgerInfoIsWritingTrue)
|
||||
{
|
||||
SystemState dummyState;
|
||||
dummyState.isWriting = true;
|
||||
auto const dummyLedgerInfo = CreateLedgerInfo(LEDGERHASH, SEQ, AGE);
|
||||
detail::LedgerPublisher publisher(ctx, mockBackendPtr, mockCache, mockSubscriptionManagerPtr, dummyState);
|
||||
publisher.publish(dummyLedgerInfo);
|
||||
|
||||
MockBackend* rawBackendPtr = dynamic_cast<MockBackend*>(mockBackendPtr.get());
|
||||
EXPECT_CALL(*rawBackendPtr, fetchLedgerDiff(_, _)).Times(0);
|
||||
|
||||
// setLastPublishedSequence not in strand, should verify before run
|
||||
EXPECT_TRUE(publisher.getLastPublishedSequence());
|
||||
EXPECT_EQ(publisher.getLastPublishedSequence().value(), SEQ);
|
||||
|
||||
ctx.run();
|
||||
EXPECT_FALSE(rawBackendPtr->fetchLedgerRange());
|
||||
}
|
||||
|
||||
TEST_F(ETLLedgerPublisherTest, PublishLedgerInfoInRange)
|
||||
{
|
||||
SystemState dummyState;
|
||||
dummyState.isWriting = true;
|
||||
|
||||
auto const dummyLedgerInfo = CreateLedgerInfo(LEDGERHASH, SEQ, 0); // age is 0
|
||||
detail::LedgerPublisher publisher(ctx, mockBackendPtr, mockCache, mockSubscriptionManagerPtr, dummyState);
|
||||
mockBackendPtr->updateRange(SEQ - 1);
|
||||
mockBackendPtr->updateRange(SEQ);
|
||||
|
||||
publisher.publish(dummyLedgerInfo);
|
||||
|
||||
MockBackend* rawBackendPtr = dynamic_cast<MockBackend*>(mockBackendPtr.get());
|
||||
EXPECT_CALL(*rawBackendPtr, fetchLedgerDiff(_, _)).Times(0);
|
||||
|
||||
// mock fetch fee
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1);
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::fees().key, SEQ, _))
|
||||
.WillByDefault(Return(CreateFeeSettingBlob(1, 2, 3, 4, 0)));
|
||||
|
||||
// mock fetch transactions
|
||||
EXPECT_CALL(*rawBackendPtr, fetchAllTransactionsInLedger).Times(1);
|
||||
TransactionAndMetadata t1;
|
||||
t1.transaction = CreatePaymentTransactionObject(ACCOUNT, ACCOUNT2, 100, 3, SEQ).getSerializer().peekData();
|
||||
t1.metadata = CreatePaymentTransactionMetaObject(ACCOUNT, ACCOUNT2, 110, 30).getSerializer().peekData();
|
||||
t1.ledgerSequence = SEQ;
|
||||
ON_CALL(*rawBackendPtr, fetchAllTransactionsInLedger(SEQ, _))
|
||||
.WillByDefault(Return(std::vector<TransactionAndMetadata>{t1}));
|
||||
|
||||
// setLastPublishedSequence not in strand, should verify before run
|
||||
EXPECT_TRUE(publisher.getLastPublishedSequence());
|
||||
EXPECT_EQ(publisher.getLastPublishedSequence().value(), SEQ);
|
||||
|
||||
MockSubscriptionManager* rawSubscriptionManagerPtr =
|
||||
dynamic_cast<MockSubscriptionManager*>(mockSubscriptionManagerPtr.get());
|
||||
|
||||
EXPECT_CALL(*rawSubscriptionManagerPtr, pubLedger(_, _, fmt::format("{}-{}", SEQ - 1, SEQ), 1)).Times(1);
|
||||
EXPECT_CALL(*rawSubscriptionManagerPtr, pubBookChanges).Times(1);
|
||||
// mock 1 transaction
|
||||
EXPECT_CALL(*rawSubscriptionManagerPtr, pubTransaction).Times(1);
|
||||
|
||||
ctx.run();
|
||||
// last publish time should be set
|
||||
EXPECT_TRUE(publisher.lastPublishAgeSeconds() <= 1);
|
||||
}
|
||||
|
||||
TEST_F(ETLLedgerPublisherTest, PublishLedgerInfoCloseTimeGreaterThanNow)
|
||||
{
|
||||
SystemState dummyState;
|
||||
dummyState.isWriting = true;
|
||||
|
||||
ripple::LedgerInfo dummyLedgerInfo = CreateLedgerInfo(LEDGERHASH, SEQ, 0);
|
||||
auto const nowPlus10 = system_clock::now() + seconds(10);
|
||||
auto const closeTime = duration_cast<seconds>(nowPlus10.time_since_epoch()).count() - rippleEpochStart;
|
||||
dummyLedgerInfo.closeTime = ripple::NetClock::time_point{seconds{closeTime}};
|
||||
|
||||
mockBackendPtr->updateRange(SEQ - 1);
|
||||
mockBackendPtr->updateRange(SEQ);
|
||||
|
||||
detail::LedgerPublisher publisher(ctx, mockBackendPtr, mockCache, mockSubscriptionManagerPtr, dummyState);
|
||||
publisher.publish(dummyLedgerInfo);
|
||||
|
||||
MockBackend* rawBackendPtr = dynamic_cast<MockBackend*>(mockBackendPtr.get());
|
||||
EXPECT_CALL(*rawBackendPtr, fetchLedgerDiff(_, _)).Times(0);
|
||||
|
||||
// mock fetch fee
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1);
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::fees().key, SEQ, _))
|
||||
.WillByDefault(Return(CreateFeeSettingBlob(1, 2, 3, 4, 0)));
|
||||
|
||||
// mock fetch transactions
|
||||
EXPECT_CALL(*rawBackendPtr, fetchAllTransactionsInLedger).Times(1);
|
||||
TransactionAndMetadata t1;
|
||||
t1.transaction = CreatePaymentTransactionObject(ACCOUNT, ACCOUNT2, 100, 3, SEQ).getSerializer().peekData();
|
||||
t1.metadata = CreatePaymentTransactionMetaObject(ACCOUNT, ACCOUNT2, 110, 30).getSerializer().peekData();
|
||||
t1.ledgerSequence = SEQ;
|
||||
ON_CALL(*rawBackendPtr, fetchAllTransactionsInLedger(SEQ, _))
|
||||
.WillByDefault(Return(std::vector<TransactionAndMetadata>{t1}));
|
||||
|
||||
// setLastPublishedSequence not in strand, should verify before run
|
||||
EXPECT_TRUE(publisher.getLastPublishedSequence());
|
||||
EXPECT_EQ(publisher.getLastPublishedSequence().value(), SEQ);
|
||||
|
||||
MockSubscriptionManager* rawSubscriptionManagerPtr =
|
||||
dynamic_cast<MockSubscriptionManager*>(mockSubscriptionManagerPtr.get());
|
||||
|
||||
EXPECT_CALL(*rawSubscriptionManagerPtr, pubLedger(_, _, fmt::format("{}-{}", SEQ - 1, SEQ), 1)).Times(1);
|
||||
EXPECT_CALL(*rawSubscriptionManagerPtr, pubBookChanges).Times(1);
|
||||
// mock 1 transaction
|
||||
EXPECT_CALL(*rawSubscriptionManagerPtr, pubTransaction).Times(1);
|
||||
|
||||
ctx.run();
|
||||
// last publish time should be set
|
||||
EXPECT_TRUE(publisher.lastPublishAgeSeconds() <= 1);
|
||||
}
|
||||
|
||||
TEST_F(ETLLedgerPublisherTest, PublishLedgerSeqStopIsTrue)
|
||||
{
|
||||
SystemState dummyState;
|
||||
dummyState.isStopping = true;
|
||||
detail::LedgerPublisher publisher(ctx, mockBackendPtr, mockCache, mockSubscriptionManagerPtr, dummyState);
|
||||
EXPECT_FALSE(publisher.publish(SEQ, {}));
|
||||
}
|
||||
|
||||
TEST_F(ETLLedgerPublisherTest, PublishLedgerSeqMaxAttampt)
|
||||
{
|
||||
SystemState dummyState;
|
||||
dummyState.isStopping = false;
|
||||
detail::LedgerPublisher publisher(ctx, mockBackendPtr, mockCache, mockSubscriptionManagerPtr, dummyState);
|
||||
|
||||
static auto constexpr MAX_ATTEMPT = 2;
|
||||
MockBackend* rawBackendPtr = dynamic_cast<MockBackend*>(mockBackendPtr.get());
|
||||
EXPECT_CALL(*rawBackendPtr, hardFetchLedgerRange).Times(MAX_ATTEMPT);
|
||||
|
||||
LedgerRange const range{.minSequence = SEQ - 1, .maxSequence = SEQ - 1};
|
||||
ON_CALL(*rawBackendPtr, hardFetchLedgerRange(_)).WillByDefault(Return(range));
|
||||
EXPECT_FALSE(publisher.publish(SEQ, MAX_ATTEMPT));
|
||||
}
|
||||
|
||||
TEST_F(ETLLedgerPublisherTest, PublishLedgerSeqStopIsFalse)
|
||||
{
|
||||
SystemState dummyState;
|
||||
dummyState.isStopping = false;
|
||||
detail::LedgerPublisher publisher(ctx, mockBackendPtr, mockCache, mockSubscriptionManagerPtr, dummyState);
|
||||
|
||||
MockBackend* rawBackendPtr = dynamic_cast<MockBackend*>(mockBackendPtr.get());
|
||||
LedgerRange const range{.minSequence = SEQ, .maxSequence = SEQ};
|
||||
ON_CALL(*rawBackendPtr, hardFetchLedgerRange(_)).WillByDefault(Return(range));
|
||||
EXPECT_CALL(*rawBackendPtr, hardFetchLedgerRange).Times(1);
|
||||
|
||||
auto const dummyLedgerInfo = CreateLedgerInfo(LEDGERHASH, SEQ, AGE);
|
||||
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(SEQ, _)).WillByDefault(Return(dummyLedgerInfo));
|
||||
EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1);
|
||||
|
||||
ON_CALL(*rawBackendPtr, fetchLedgerDiff(SEQ, _)).WillByDefault(Return(std::vector<LedgerObject>{}));
|
||||
EXPECT_CALL(*rawBackendPtr, fetchLedgerDiff(SEQ, _)).Times(1);
|
||||
EXPECT_CALL(mockCache, updateImp).Times(1);
|
||||
|
||||
EXPECT_TRUE(publisher.publish(SEQ, {}));
|
||||
ctx.run();
|
||||
}
|
||||
@@ -25,7 +25,15 @@
|
||||
|
||||
struct MockCache
|
||||
{
|
||||
MOCK_METHOD(void, update, (std::vector<data::LedgerObject> const& a, uint32_t b, bool c), ());
|
||||
virtual ~MockCache() = default;
|
||||
|
||||
MOCK_METHOD(void, updateImp, (std::vector<data::LedgerObject> const& a, uint32_t b, bool c), ());
|
||||
|
||||
virtual void
|
||||
update(std::vector<data::LedgerObject> const& a, uint32_t b, bool c = false)
|
||||
{
|
||||
updateImp(a, b, c);
|
||||
}
|
||||
|
||||
MOCK_METHOD(std::optional<data::Blob>, get, (ripple::uint256 const& a, uint32_t b), (const));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user