mirror of
https://github.com/XRPLF/clio.git
synced 2025-12-06 17:27:58 +00:00
69
tests/unit/etlng/AmendmentBlockHandlerTests.cpp
Normal file
69
tests/unit/etlng/AmendmentBlockHandlerTests.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of clio: https://github.com/XRPLF/clio
|
||||
Copyright (c) 2025, 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/SystemState.hpp"
|
||||
#include "etlng/impl/AmendmentBlockHandler.hpp"
|
||||
#include "util/LoggerFixtures.hpp"
|
||||
#include "util/MockPrometheus.hpp"
|
||||
#include "util/async/context/BasicExecutionContext.hpp"
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <semaphore>
|
||||
|
||||
using namespace etlng::impl;
|
||||
|
||||
struct AmendmentBlockHandlerNgTests : util::prometheus::WithPrometheus {
|
||||
protected:
|
||||
testing::StrictMock<testing::MockFunction<void()>> actionMock_;
|
||||
etl::SystemState state_;
|
||||
|
||||
util::async::CoroExecutionContext ctx_;
|
||||
};
|
||||
|
||||
TEST_F(AmendmentBlockHandlerNgTests, CallTonotifyAmendmentBlockedSetsStateAndRepeatedlyCallsAction)
|
||||
{
|
||||
constexpr static auto kMAX_ITERATIONS = 10uz;
|
||||
etlng::impl::AmendmentBlockHandler handler{ctx_, state_, std::chrono::nanoseconds{1}, actionMock_.AsStdFunction()};
|
||||
auto counter = 0uz;
|
||||
std::binary_semaphore stop{0};
|
||||
|
||||
EXPECT_FALSE(state_.isAmendmentBlocked);
|
||||
EXPECT_CALL(actionMock_, Call()).Times(testing::AtLeast(10)).WillRepeatedly([&]() {
|
||||
if (++counter; counter > kMAX_ITERATIONS)
|
||||
stop.release();
|
||||
});
|
||||
|
||||
handler.notifyAmendmentBlocked();
|
||||
stop.acquire(); // wait for the counter to reach over kMAX_ITERATIONS
|
||||
|
||||
EXPECT_TRUE(state_.isAmendmentBlocked);
|
||||
}
|
||||
|
||||
struct DefaultAmendmentBlockActionNgTest : LoggerFixture {};
|
||||
|
||||
TEST_F(DefaultAmendmentBlockActionNgTest, Call)
|
||||
{
|
||||
AmendmentBlockHandler::kDEFAULT_AMENDMENT_BLOCK_ACTION();
|
||||
auto const loggerString = getLoggerString();
|
||||
EXPECT_TRUE(loggerString.starts_with("ETL:FTL Can't process new ledgers")) << "LoggerString " << loggerString;
|
||||
}
|
||||
@@ -24,10 +24,12 @@
|
||||
#include "etlng/impl/Extraction.hpp"
|
||||
#include "util/BinaryTestObject.hpp"
|
||||
#include "util/LoggerFixtures.hpp"
|
||||
#include "util/TestObject.hpp"
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <google/protobuf/repeated_ptr_field.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/basics/strHex.h>
|
||||
#include <xrpl/proto/org/xrpl/rpc/v1/get_ledger.pb.h>
|
||||
#include <xrpl/proto/org/xrpl/rpc/v1/ledger.pb.h>
|
||||
@@ -38,14 +40,146 @@
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
constinit auto const kLEDGER_HASH = "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652";
|
||||
constinit auto const kLEDGER_HASH2 = "1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515BC";
|
||||
constinit auto const kSEQ = 30;
|
||||
} // namespace
|
||||
|
||||
struct ExtractionTests : NoLoggerFixture {};
|
||||
struct ExtractionModelNgTests : NoLoggerFixture {};
|
||||
|
||||
TEST_F(ExtractionTests, ModType)
|
||||
TEST_F(ExtractionModelNgTests, LedgerDataCopyableAndEquatable)
|
||||
{
|
||||
auto const first = etlng::model::LedgerData{
|
||||
.transactions =
|
||||
{util::createTransaction(ripple::TxType::ttNFTOKEN_BURN),
|
||||
util::createTransaction(ripple::TxType::ttNFTOKEN_BURN),
|
||||
util::createTransaction(ripple::TxType::ttNFTOKEN_CREATE_OFFER)},
|
||||
.objects = {util::createObject(), util::createObject(), util::createObject()},
|
||||
.successors = std::vector<etlng::model::BookSuccessor>{{.firstBook = "first", .bookBase = "base"}},
|
||||
.edgeKeys = std::vector<std::string>{"key1", "key2"},
|
||||
.header = createLedgerHeader(kLEDGER_HASH, kSEQ, 1),
|
||||
.rawHeader = {1, 2, 3},
|
||||
.seq = kSEQ
|
||||
};
|
||||
|
||||
auto const second = first;
|
||||
EXPECT_EQ(first, second);
|
||||
|
||||
{
|
||||
auto third = second;
|
||||
third.transactions.clear();
|
||||
EXPECT_NE(first, third);
|
||||
}
|
||||
{
|
||||
auto third = second;
|
||||
third.objects = {util::createObject()};
|
||||
EXPECT_NE(first, third);
|
||||
}
|
||||
{
|
||||
auto third = second;
|
||||
third.successors = std::vector<etlng::model::BookSuccessor>{{.firstBook = "second", .bookBase = "base"}};
|
||||
EXPECT_NE(first, third);
|
||||
}
|
||||
{
|
||||
auto third = second;
|
||||
third.edgeKeys = std::vector<std::string>{"key1"};
|
||||
EXPECT_NE(first, third);
|
||||
}
|
||||
{
|
||||
auto third = second;
|
||||
third.header = createLedgerHeader(kLEDGER_HASH2, kSEQ, 2);
|
||||
EXPECT_NE(first, third);
|
||||
}
|
||||
{
|
||||
auto third = second;
|
||||
third.rawHeader = {2, 3, 4};
|
||||
EXPECT_NE(first, third);
|
||||
}
|
||||
{
|
||||
auto third = second;
|
||||
third.seq = kSEQ - 1;
|
||||
EXPECT_NE(first, third);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ExtractionModelNgTests, TransactionIsEquatable)
|
||||
{
|
||||
auto const tx = std::vector{util::createTransaction(ripple::TxType::ttNFTOKEN_BURN)};
|
||||
auto other = tx;
|
||||
EXPECT_EQ(tx, other);
|
||||
|
||||
other.push_back(util::createTransaction(ripple::TxType::ttNFTOKEN_ACCEPT_OFFER));
|
||||
EXPECT_NE(tx, other);
|
||||
}
|
||||
|
||||
TEST_F(ExtractionModelNgTests, ObjectCopyableAndEquatable)
|
||||
{
|
||||
auto const obj = util::createObject();
|
||||
auto const other = obj;
|
||||
EXPECT_EQ(obj, other);
|
||||
|
||||
{
|
||||
auto third = other;
|
||||
third.key = ripple::uint256{42};
|
||||
EXPECT_NE(obj, third);
|
||||
}
|
||||
{
|
||||
auto third = other;
|
||||
third.keyRaw = "key";
|
||||
EXPECT_NE(obj, third);
|
||||
}
|
||||
{
|
||||
auto third = other;
|
||||
third.data = {2, 3};
|
||||
EXPECT_NE(obj, third);
|
||||
}
|
||||
{
|
||||
auto third = other;
|
||||
third.dataRaw = "something";
|
||||
EXPECT_NE(obj, third);
|
||||
}
|
||||
{
|
||||
auto third = other;
|
||||
third.successor = "succ";
|
||||
EXPECT_NE(obj, third);
|
||||
}
|
||||
{
|
||||
auto third = other;
|
||||
third.predecessor = "pred";
|
||||
EXPECT_NE(obj, third);
|
||||
}
|
||||
{
|
||||
auto third = other;
|
||||
third.type = etlng::model::Object::ModType::Deleted;
|
||||
EXPECT_NE(obj, third);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ExtractionModelNgTests, BookSuccessorCopyableAndEquatable)
|
||||
{
|
||||
auto const succ = etlng::model::BookSuccessor{.firstBook = "first", .bookBase = "base"};
|
||||
auto const other = succ;
|
||||
EXPECT_EQ(succ, other);
|
||||
|
||||
{
|
||||
auto third = other;
|
||||
third.bookBase = "all your base are belong to us";
|
||||
EXPECT_NE(succ, third);
|
||||
}
|
||||
{
|
||||
auto third = other;
|
||||
third.firstBook = "not the first book";
|
||||
EXPECT_NE(succ, third);
|
||||
}
|
||||
}
|
||||
|
||||
struct ExtractionNgTests : NoLoggerFixture {};
|
||||
|
||||
TEST_F(ExtractionNgTests, ModType)
|
||||
{
|
||||
using namespace etlng::impl;
|
||||
using ModType = etlng::model::Object::ModType;
|
||||
@@ -56,7 +190,7 @@ TEST_F(ExtractionTests, ModType)
|
||||
EXPECT_EQ(extractModType(PBObjType::UNSPECIFIED), ModType::Unspecified);
|
||||
}
|
||||
|
||||
TEST_F(ExtractionTests, OneTransaction)
|
||||
TEST_F(ExtractionNgTests, OneTransaction)
|
||||
{
|
||||
using namespace etlng::impl;
|
||||
|
||||
@@ -74,7 +208,7 @@ TEST_F(ExtractionTests, OneTransaction)
|
||||
EXPECT_EQ(res.sttx.getTxnType(), expected.sttx.getTxnType());
|
||||
}
|
||||
|
||||
TEST_F(ExtractionTests, MultipleTransactions)
|
||||
TEST_F(ExtractionNgTests, MultipleTransactions)
|
||||
{
|
||||
using namespace etlng::impl;
|
||||
|
||||
@@ -102,7 +236,7 @@ TEST_F(ExtractionTests, MultipleTransactions)
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ExtractionTests, OneObject)
|
||||
TEST_F(ExtractionNgTests, OneObject)
|
||||
{
|
||||
using namespace etlng::impl;
|
||||
|
||||
@@ -110,6 +244,9 @@ TEST_F(ExtractionTests, OneObject)
|
||||
auto original = org::xrpl::rpc::v1::RawLedgerObject();
|
||||
original.set_data(expected.dataRaw);
|
||||
original.set_key(expected.keyRaw);
|
||||
original.set_mod_type(
|
||||
org::xrpl::rpc::v1::RawLedgerObject::ModificationType::RawLedgerObject_ModificationType_CREATED
|
||||
);
|
||||
|
||||
auto res = extractObj(original);
|
||||
EXPECT_EQ(ripple::strHex(res.key), ripple::strHex(expected.keyRaw));
|
||||
@@ -119,7 +256,7 @@ TEST_F(ExtractionTests, OneObject)
|
||||
EXPECT_EQ(res.type, expected.type);
|
||||
}
|
||||
|
||||
TEST_F(ExtractionTests, OneObjectWithSuccessorAndPredecessor)
|
||||
TEST_F(ExtractionNgTests, OneObjectWithSuccessorAndPredecessor)
|
||||
{
|
||||
using namespace etlng::impl;
|
||||
|
||||
@@ -129,6 +266,9 @@ TEST_F(ExtractionTests, OneObjectWithSuccessorAndPredecessor)
|
||||
original.set_key(expected.keyRaw);
|
||||
original.set_predecessor(expected.predecessor);
|
||||
original.set_successor(expected.successor);
|
||||
original.set_mod_type(
|
||||
org::xrpl::rpc::v1::RawLedgerObject::ModificationType::RawLedgerObject_ModificationType_CREATED
|
||||
);
|
||||
|
||||
auto res = extractObj(original);
|
||||
EXPECT_EQ(ripple::strHex(res.key), ripple::strHex(expected.keyRaw));
|
||||
@@ -138,7 +278,7 @@ TEST_F(ExtractionTests, OneObjectWithSuccessorAndPredecessor)
|
||||
EXPECT_EQ(res.type, expected.type);
|
||||
}
|
||||
|
||||
TEST_F(ExtractionTests, MultipleObjects)
|
||||
TEST_F(ExtractionNgTests, MultipleObjects)
|
||||
{
|
||||
using namespace etlng::impl;
|
||||
|
||||
@@ -146,6 +286,9 @@ TEST_F(ExtractionTests, MultipleObjects)
|
||||
auto original = org::xrpl::rpc::v1::RawLedgerObject();
|
||||
original.set_data(expected.dataRaw);
|
||||
original.set_key(expected.keyRaw);
|
||||
original.set_mod_type(
|
||||
org::xrpl::rpc::v1::RawLedgerObject::ModificationType::RawLedgerObject_ModificationType_CREATED
|
||||
);
|
||||
|
||||
auto list = org::xrpl::rpc::v1::RawLedgerObjects();
|
||||
for (auto i = 0; i < 10; ++i) {
|
||||
@@ -165,7 +308,7 @@ TEST_F(ExtractionTests, MultipleObjects)
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ExtractionTests, OneSuccessor)
|
||||
TEST_F(ExtractionNgTests, OneSuccessor)
|
||||
{
|
||||
using namespace etlng::impl;
|
||||
|
||||
@@ -179,7 +322,7 @@ TEST_F(ExtractionTests, OneSuccessor)
|
||||
EXPECT_EQ(ripple::strHex(res.bookBase), ripple::strHex(expected.bookBase));
|
||||
}
|
||||
|
||||
TEST_F(ExtractionTests, MultipleSuccessors)
|
||||
TEST_F(ExtractionNgTests, MultipleSuccessors)
|
||||
{
|
||||
using namespace etlng::impl;
|
||||
|
||||
@@ -205,7 +348,7 @@ TEST_F(ExtractionTests, MultipleSuccessors)
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ExtractionTests, SuccessorsWithNoNeighborsIncluded)
|
||||
TEST_F(ExtractionNgTests, SuccessorsWithNoNeighborsIncluded)
|
||||
{
|
||||
using namespace etlng::impl;
|
||||
|
||||
@@ -238,7 +381,7 @@ struct MockFetcher : etl::LedgerFetcherInterface {
|
||||
MOCK_METHOD(std::optional<GetLedgerResponseType>, fetchDataAndDiff, (uint32_t), (override));
|
||||
};
|
||||
|
||||
struct ExtractorTests : ExtractionTests {
|
||||
struct ExtractorTests : ExtractionNgTests {
|
||||
std::shared_ptr<MockFetcher> fetcher = std::make_shared<MockFetcher>();
|
||||
etlng::impl::Extractor extractor{fetcher};
|
||||
};
|
||||
|
||||
160
tests/unit/etlng/LoadingTests.cpp
Normal file
160
tests/unit/etlng/LoadingTests.cpp
Normal file
@@ -0,0 +1,160 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of clio: https://github.com/XRPLF/clio
|
||||
Copyright (c) 2025, 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 "data/Types.hpp"
|
||||
#include "etlng/InitialLoadObserverInterface.hpp"
|
||||
#include "etlng/Models.hpp"
|
||||
#include "etlng/RegistryInterface.hpp"
|
||||
#include "etlng/impl/Loading.hpp"
|
||||
#include "rpc/RPCHelpers.hpp"
|
||||
#include "util/BinaryTestObject.hpp"
|
||||
#include "util/MockBackendTestFixture.hpp"
|
||||
#include "util/MockETLServiceTestFixture.hpp"
|
||||
#include "util/MockPrometheus.hpp"
|
||||
#include "util/TestObject.hpp"
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace etlng::model;
|
||||
using namespace etlng::impl;
|
||||
|
||||
namespace {
|
||||
|
||||
constinit auto const kLEDGER_HASH = "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652";
|
||||
constinit auto const kSEQ = 30;
|
||||
|
||||
struct MockRegistry : etlng::RegistryInterface {
|
||||
MOCK_METHOD(void, dispatchInitialObjects, (uint32_t, std::vector<Object> const&, std::string), (override));
|
||||
MOCK_METHOD(void, dispatchInitialData, (LedgerData const&), (override));
|
||||
MOCK_METHOD(void, dispatch, (LedgerData const&), (override));
|
||||
};
|
||||
|
||||
struct MockLoadObserver : etlng::InitialLoadObserverInterface {
|
||||
MOCK_METHOD(
|
||||
void,
|
||||
onInitialLoadGotMoreObjects,
|
||||
(uint32_t, std::vector<Object> const&, std::optional<std::string>),
|
||||
(override)
|
||||
);
|
||||
};
|
||||
|
||||
struct LoadingTests : util::prometheus::WithPrometheus,
|
||||
MockBackendTest,
|
||||
MockLedgerFetcherTest,
|
||||
MockAmendmentBlockHandlerTest {
|
||||
protected:
|
||||
std::shared_ptr<MockRegistry> mockRegistryPtr_ = std::make_shared<MockRegistry>();
|
||||
Loader loader_{backend_, mockLedgerFetcherPtr_, mockRegistryPtr_, mockAmendmentBlockHandlerPtr_};
|
||||
};
|
||||
|
||||
struct LoadingDeathTest : LoadingTests {};
|
||||
|
||||
auto
|
||||
createTestData()
|
||||
{
|
||||
auto const header = createLedgerHeader(kLEDGER_HASH, kSEQ);
|
||||
return LedgerData{
|
||||
.transactions = {},
|
||||
.objects = {util::createObject(), util::createObject(), util::createObject()},
|
||||
.successors = {},
|
||||
.edgeKeys = {},
|
||||
.header = header,
|
||||
.rawHeader = {},
|
||||
.seq = kSEQ
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_F(LoadingTests, LoadInitialLedger)
|
||||
{
|
||||
auto const data = createTestData();
|
||||
|
||||
EXPECT_CALL(*backend_, hardFetchLedgerRange(testing::_)).WillOnce(testing::Return(std::nullopt));
|
||||
EXPECT_CALL(*backend_, doFinishWrites());
|
||||
EXPECT_CALL(*mockRegistryPtr_, dispatchInitialData(data));
|
||||
|
||||
auto const res = loader_.loadInitialLedger(data);
|
||||
EXPECT_TRUE(res.has_value());
|
||||
EXPECT_EQ(rpc::ledgerHeaderToBlob(res.value(), true), rpc::ledgerHeaderToBlob(data.header, true));
|
||||
}
|
||||
|
||||
TEST_F(LoadingTests, LoadSuccess)
|
||||
{
|
||||
auto const data = createTestData();
|
||||
|
||||
EXPECT_CALL(*backend_, doFinishWrites());
|
||||
EXPECT_CALL(*mockRegistryPtr_, dispatch(data));
|
||||
|
||||
loader_.load(data);
|
||||
}
|
||||
|
||||
TEST_F(LoadingTests, LoadFailure)
|
||||
{
|
||||
auto const data = createTestData();
|
||||
|
||||
EXPECT_CALL(*backend_, doFinishWrites()).Times(0);
|
||||
EXPECT_CALL(*mockRegistryPtr_, dispatch(data)).WillOnce([](auto const&) {
|
||||
throw std::runtime_error("some error");
|
||||
});
|
||||
EXPECT_CALL(*mockAmendmentBlockHandlerPtr_, notifyAmendmentBlocked());
|
||||
|
||||
loader_.load(data);
|
||||
}
|
||||
|
||||
TEST_F(LoadingTests, OnInitialLoadGotMoreObjectsWithKey)
|
||||
{
|
||||
auto const data = createTestData();
|
||||
auto const lastKey = std::make_optional<std::string>("something");
|
||||
|
||||
EXPECT_CALL(*mockRegistryPtr_, dispatchInitialObjects(kSEQ, data.objects, lastKey->data()));
|
||||
|
||||
loader_.onInitialLoadGotMoreObjects(kSEQ, data.objects, lastKey);
|
||||
}
|
||||
|
||||
TEST_F(LoadingTests, OnInitialLoadGotMoreObjectsWithoutKey)
|
||||
{
|
||||
auto const data = createTestData();
|
||||
auto const lastKey = std::optional<std::string>{};
|
||||
|
||||
EXPECT_CALL(*mockRegistryPtr_, dispatchInitialObjects(kSEQ, data.objects, std::string{}));
|
||||
|
||||
loader_.onInitialLoadGotMoreObjects(kSEQ, data.objects, lastKey);
|
||||
}
|
||||
|
||||
TEST_F(LoadingDeathTest, LoadInitialLedgerHasDataInDB)
|
||||
{
|
||||
auto const data = createTestData();
|
||||
auto const range = LedgerRange{.minSequence = kSEQ - 1, .maxSequence = kSEQ};
|
||||
|
||||
// backend_ leaks due to death test. would be nice to figure out a better solution but for now
|
||||
// we simply don't set expectations and allow the mock to leak
|
||||
testing::Mock::AllowLeak(&*backend_);
|
||||
ON_CALL(*backend_, hardFetchLedgerRange(testing::_)).WillByDefault(testing::Return(range));
|
||||
|
||||
EXPECT_DEATH({ [[maybe_unused]] auto unused = loader_.loadInitialLedger(data); }, ".*");
|
||||
}
|
||||
Reference in New Issue
Block a user