mirror of
https://github.com/XRPLF/clio.git
synced 2025-12-06 17:27:58 +00:00
@@ -34,7 +34,7 @@
|
||||
|
||||
// Base class for feed tests, providing easy way to access the received feed
|
||||
template <typename TestedFeed>
|
||||
class FeedBaseTest : public util::prometheus::WithPrometheus, public SyncAsioContextTest, public MockBackendTest {
|
||||
struct FeedBaseTest : util::prometheus::WithPrometheus, SyncAsioContextTest, MockBackendTest {
|
||||
protected:
|
||||
std::shared_ptr<web::ConnectionBase> sessionPtr;
|
||||
std::shared_ptr<TestedFeed> testFeedPtr;
|
||||
@@ -44,7 +44,6 @@ protected:
|
||||
SetUp() override
|
||||
{
|
||||
SyncAsioContextTest::SetUp();
|
||||
MockBackendTest::SetUp();
|
||||
testFeedPtr = std::make_shared<TestedFeed>(ctx);
|
||||
sessionPtr = std::make_shared<MockSession>();
|
||||
sessionPtr->apiSubVersion = 1;
|
||||
@@ -56,7 +55,6 @@ protected:
|
||||
{
|
||||
sessionPtr.reset();
|
||||
testFeedPtr.reset();
|
||||
MockBackendTest::TearDown();
|
||||
SyncAsioContextTest::TearDown();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -195,23 +195,8 @@ protected:
|
||||
|
||||
template <template <typename> typename MockType = ::testing::NiceMock>
|
||||
struct MockBackendTestBase : virtual public NoLoggerFixture {
|
||||
void
|
||||
SetUp() override
|
||||
{
|
||||
backend.reset();
|
||||
}
|
||||
|
||||
class BackendProxy {
|
||||
std::shared_ptr<BackendInterface> backend;
|
||||
|
||||
private:
|
||||
void
|
||||
reset()
|
||||
{
|
||||
backend = std::make_shared<MockType<MockBackend>>(util::Config{});
|
||||
}
|
||||
|
||||
friend MockBackendTestBase;
|
||||
std::shared_ptr<MockType<MockBackend>> backend = std::make_shared<MockType<MockBackend>>(util::Config{});
|
||||
|
||||
public:
|
||||
auto
|
||||
@@ -230,11 +215,10 @@ struct MockBackendTestBase : virtual public NoLoggerFixture {
|
||||
return backend;
|
||||
}
|
||||
|
||||
operator MockBackend*()
|
||||
MockType<MockBackend>&
|
||||
operator*()
|
||||
{
|
||||
MockBackend* ret = dynamic_cast<MockBackend*>(backend.get());
|
||||
[&] { ASSERT_NE(ret, nullptr); }();
|
||||
return ret;
|
||||
return *backend;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -266,14 +250,6 @@ using MockBackendTestNaggy = MockBackendTestBase<::testing::NaggyMock>;
|
||||
*/
|
||||
using MockBackendTestStrict = MockBackendTestBase<::testing::StrictMock>;
|
||||
|
||||
/**
|
||||
* @brief Fixture with a mock subscription manager
|
||||
*/
|
||||
struct MockSubscriptionManagerTest : virtual public NoLoggerFixture {
|
||||
protected:
|
||||
std::shared_ptr<MockSubscriptionManager> mockSubscriptionManagerPtr = std::make_shared<MockSubscriptionManager>();
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Fixture with a mock etl balancer
|
||||
*/
|
||||
@@ -283,7 +259,7 @@ protected:
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Fixture with a mock subscription manager
|
||||
* @brief Fixture with a mock etl service
|
||||
*/
|
||||
template <template <typename> typename MockType = ::testing::NiceMock>
|
||||
struct MockETLServiceTestBase : virtual public NoLoggerFixture {
|
||||
@@ -328,15 +304,14 @@ protected:
|
||||
* HandlerBaseTestStrict.
|
||||
*/
|
||||
template <template <typename> typename MockType = ::testing::NiceMock>
|
||||
struct HandlerBaseTestBase : public MockBackendTestBase<MockType>,
|
||||
public util::prometheus::WithPrometheus,
|
||||
public SyncAsioContextTest,
|
||||
public MockETLServiceTestBase<MockType> {
|
||||
struct HandlerBaseTestBase : util::prometheus::WithPrometheus,
|
||||
MockBackendTestBase<MockType>,
|
||||
SyncAsioContextTest,
|
||||
MockETLServiceTestBase<MockType> {
|
||||
protected:
|
||||
void
|
||||
SetUp() override
|
||||
{
|
||||
MockBackendTestBase<MockType>::SetUp();
|
||||
SyncAsioContextTest::SetUp();
|
||||
MockETLServiceTestBase<MockType>::SetUp();
|
||||
}
|
||||
@@ -346,7 +321,6 @@ protected:
|
||||
{
|
||||
MockETLServiceTestBase<MockType>::TearDown();
|
||||
SyncAsioContextTest::TearDown();
|
||||
MockBackendTestBase<MockType>::TearDown();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -19,13 +19,36 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "etl/ETLHelpers.hpp"
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
struct MockNetworkValidatedLedgers {
|
||||
MOCK_METHOD(void, push, (uint32_t), ());
|
||||
MOCK_METHOD(std::optional<uint32_t>, getMostRecent, (), ());
|
||||
MOCK_METHOD(bool, waitUntilValidatedByNetwork, (uint32_t), ());
|
||||
struct MockNetworkValidatedLedgers : public etl::NetworkValidatedLedgersInterface {
|
||||
MOCK_METHOD(void, push, (uint32_t), (override));
|
||||
MOCK_METHOD(std::optional<uint32_t>, getMostRecent, (), (override));
|
||||
MOCK_METHOD(bool, waitUntilValidatedByNetwork, (uint32_t, std::optional<uint32_t>), (override));
|
||||
};
|
||||
|
||||
template <template <typename> typename MockType>
|
||||
struct MockNetworkValidatedLedgersPtrImpl {
|
||||
std::shared_ptr<MockType<MockNetworkValidatedLedgers>> ptr =
|
||||
std::make_shared<MockType<MockNetworkValidatedLedgers>>();
|
||||
|
||||
operator std::shared_ptr<etl::NetworkValidatedLedgersInterface>() const
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
|
||||
MockType<MockNetworkValidatedLedgers>&
|
||||
operator*()
|
||||
{
|
||||
return *ptr;
|
||||
}
|
||||
};
|
||||
|
||||
using MockNetworkValidatedLedgersPtr = MockNetworkValidatedLedgersPtrImpl<testing::NiceMock>;
|
||||
using StrictMockNetworkValidatedLedgersPtr = MockNetworkValidatedLedgersPtrImpl<testing::StrictMock>;
|
||||
|
||||
@@ -18,41 +18,180 @@
|
||||
//==============================================================================
|
||||
#pragma once
|
||||
|
||||
#include "data/BackendInterface.hpp"
|
||||
#include "etl/ETLHelpers.hpp"
|
||||
#include "etl/Source.hpp"
|
||||
#include "feed/SubscriptionManagerInterface.hpp"
|
||||
#include "util/config/Config.hpp"
|
||||
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/spawn.hpp>
|
||||
#include <boost/json/object.hpp>
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <gmock/gmock.h>
|
||||
#include <grpcpp/support/status.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <org/xrpl/rpc/v1/get_ledger.pb.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
class MockSource {
|
||||
public:
|
||||
MOCK_METHOD(bool, isConnected, (), (const));
|
||||
MOCK_METHOD(boost::json::object, toJson, (), (const));
|
||||
MOCK_METHOD(void, run, ());
|
||||
MOCK_METHOD(void, pause, ());
|
||||
MOCK_METHOD(void, resume, ());
|
||||
MOCK_METHOD(std::string, toString, (), (const));
|
||||
MOCK_METHOD(bool, hasLedger, (uint32_t), (const));
|
||||
MOCK_METHOD((std::pair<grpc::Status, org::xrpl::rpc::v1::GetLedgerResponse>), fetchLedger, (uint32_t, bool, bool));
|
||||
MOCK_METHOD((std::pair<std::vector<std::string>, bool>), loadInitialLedger, (uint32_t, uint32_t, bool));
|
||||
struct MockSource : etl::SourceBase {
|
||||
MOCK_METHOD(void, run, (), (override));
|
||||
MOCK_METHOD(bool, isConnected, (), (const, override));
|
||||
MOCK_METHOD(void, setForwarding, (bool), (override));
|
||||
MOCK_METHOD(boost::json::object, toJson, (), (const, override));
|
||||
MOCK_METHOD(std::string, toString, (), (const, override));
|
||||
MOCK_METHOD(bool, hasLedger, (uint32_t), (const, override));
|
||||
MOCK_METHOD(
|
||||
(std::pair<grpc::Status, org::xrpl::rpc::v1::GetLedgerResponse>),
|
||||
fetchLedger,
|
||||
(uint32_t, bool, bool),
|
||||
(override)
|
||||
);
|
||||
MOCK_METHOD((std::pair<std::vector<std::string>, bool>), loadInitialLedger, (uint32_t, uint32_t, bool), (override));
|
||||
MOCK_METHOD(
|
||||
std::optional<boost::json::object>,
|
||||
forwardToRippled,
|
||||
(boost::json::object const&, std::optional<std::string> const&, boost::asio::yield_context),
|
||||
(const)
|
||||
(const, override)
|
||||
);
|
||||
MOCK_METHOD(
|
||||
std::optional<boost::json::object>,
|
||||
requestFromRippled,
|
||||
(boost::json::object const&, std::optional<std::string> const&, boost::asio::yield_context),
|
||||
(const)
|
||||
);
|
||||
MOCK_METHOD(boost::uuids::uuid, token, (), (const));
|
||||
};
|
||||
|
||||
template <template <typename> typename MockType>
|
||||
using MockSourcePtr = std::shared_ptr<MockType<MockSource>>;
|
||||
|
||||
template <template <typename> typename MockType>
|
||||
class MockSourceWrapper : public etl::SourceBase {
|
||||
MockSourcePtr<MockType> mock_;
|
||||
|
||||
public:
|
||||
MockSourceWrapper(MockSourcePtr<MockType> mockData) : mock_(std::move(mockData))
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
mock_->run();
|
||||
}
|
||||
|
||||
bool
|
||||
isConnected() const override
|
||||
{
|
||||
return mock_->isConnected();
|
||||
}
|
||||
|
||||
void
|
||||
setForwarding(bool isForwarding) override
|
||||
{
|
||||
mock_->setForwarding(isForwarding);
|
||||
}
|
||||
|
||||
boost::json::object
|
||||
toJson() const override
|
||||
{
|
||||
return mock_->toJson();
|
||||
}
|
||||
|
||||
std::string
|
||||
toString() const override
|
||||
{
|
||||
return mock_->toString();
|
||||
}
|
||||
|
||||
bool
|
||||
hasLedger(uint32_t sequence) const override
|
||||
{
|
||||
return mock_->hasLedger(sequence);
|
||||
}
|
||||
|
||||
std::pair<grpc::Status, org::xrpl::rpc::v1::GetLedgerResponse>
|
||||
fetchLedger(uint32_t sequence, bool getObjects, bool getObjectNeighbors) override
|
||||
{
|
||||
return mock_->fetchLedger(sequence, getObjects, getObjectNeighbors);
|
||||
}
|
||||
|
||||
std::pair<std::vector<std::string>, bool>
|
||||
loadInitialLedger(uint32_t sequence, uint32_t maxLedger, bool getObjects) override
|
||||
{
|
||||
return mock_->loadInitialLedger(sequence, maxLedger, getObjects);
|
||||
}
|
||||
|
||||
std::optional<boost::json::object>
|
||||
forwardToRippled(
|
||||
boost::json::object const& request,
|
||||
std::optional<std::string> const& forwardToRippledClientIp,
|
||||
boost::asio::yield_context yield
|
||||
) const override
|
||||
{
|
||||
return mock_->forwardToRippled(request, forwardToRippledClientIp, yield);
|
||||
}
|
||||
};
|
||||
|
||||
struct MockSourceCallbacks {
|
||||
etl::SourceBase::OnDisconnectHook onDisconnect;
|
||||
etl::SourceBase::OnConnectHook onConnect;
|
||||
etl::SourceBase::OnLedgerClosedHook onLedgerClosed;
|
||||
};
|
||||
|
||||
template <template <typename> typename MockType>
|
||||
struct MockSourceData {
|
||||
MockSourcePtr<MockType> source = std::make_shared<MockType<MockSource>>();
|
||||
std::optional<MockSourceCallbacks> callbacks;
|
||||
};
|
||||
|
||||
template <template <typename> typename MockType = testing::NiceMock>
|
||||
class MockSourceFactoryImpl {
|
||||
std::vector<MockSourceData<MockType>> mockData_;
|
||||
|
||||
public:
|
||||
MockSourceFactoryImpl(size_t numSources)
|
||||
{
|
||||
mockData_.reserve(numSources);
|
||||
std::ranges::generate_n(std::back_inserter(mockData_), numSources, [] { return MockSourceData<MockType>{}; });
|
||||
}
|
||||
|
||||
etl::SourcePtr
|
||||
makeSourceMock(
|
||||
util::Config const&,
|
||||
boost::asio::io_context&,
|
||||
std::shared_ptr<BackendInterface>,
|
||||
std::shared_ptr<feed::SubscriptionManagerInterface>,
|
||||
std::shared_ptr<etl::NetworkValidatedLedgersInterface>,
|
||||
etl::SourceBase::OnConnectHook onConnect,
|
||||
etl::SourceBase::OnDisconnectHook onDisconnect,
|
||||
etl::SourceBase::OnLedgerClosedHook onLedgerClosed
|
||||
)
|
||||
{
|
||||
auto it = std::ranges::find_if(mockData_, [](auto const& d) { return not d.callbacks.has_value(); });
|
||||
[&]() { ASSERT_NE(it, mockData_.end()) << "Make source called more than expected"; }();
|
||||
it->callbacks = MockSourceCallbacks{std::move(onDisconnect), std::move(onConnect), std::move(onLedgerClosed)};
|
||||
|
||||
return std::make_unique<MockSourceWrapper<MockType>>(it->source);
|
||||
}
|
||||
|
||||
MockType<MockSource>&
|
||||
sourceAt(size_t index)
|
||||
{
|
||||
return *mockData_.at(index).source;
|
||||
}
|
||||
|
||||
MockSourceCallbacks&
|
||||
callbacksAt(size_t index)
|
||||
{
|
||||
auto& callbacks = mockData_.at(index).callbacks;
|
||||
[&]() { ASSERT_TRUE(callbacks.has_value()) << "Callbacks not set"; }();
|
||||
return *callbacks;
|
||||
}
|
||||
};
|
||||
|
||||
using MockSourceFactory = MockSourceFactoryImpl<>;
|
||||
using StrictMockSourceFactory = MockSourceFactoryImpl<testing::StrictMock>;
|
||||
|
||||
@@ -20,7 +20,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "data/Types.hpp"
|
||||
#include "web/interface/ConnectionBase.hpp"
|
||||
#include "feed/SubscriptionManagerInterface.hpp"
|
||||
#include "feed/Types.hpp"
|
||||
|
||||
#include <boost/asio/spawn.hpp>
|
||||
#include <boost/json.hpp>
|
||||
@@ -36,70 +37,89 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct MockSubscriptionManager {
|
||||
public:
|
||||
using session_ptr = std::shared_ptr<web::ConnectionBase>;
|
||||
MockSubscriptionManager() = default;
|
||||
|
||||
MOCK_METHOD(boost::json::object, subLedger, (boost::asio::yield_context, session_ptr), ());
|
||||
struct MockSubscriptionManager : feed::SubscriptionManagerInterface {
|
||||
MOCK_METHOD(
|
||||
boost::json::object,
|
||||
subLedger,
|
||||
(boost::asio::yield_context, feed::SubscriberSharedPtr const&),
|
||||
(override)
|
||||
);
|
||||
|
||||
MOCK_METHOD(
|
||||
void,
|
||||
pubLedger,
|
||||
(ripple::LedgerInfo const&, ripple::Fees const&, std::string const&, std::uint32_t),
|
||||
()
|
||||
(ripple::LedgerHeader const&, ripple::Fees const&, std::string const&, std::uint32_t),
|
||||
(const, override)
|
||||
);
|
||||
|
||||
MOCK_METHOD(
|
||||
void,
|
||||
pubBookChanges,
|
||||
(ripple::LedgerInfo const&, std::vector<data::TransactionAndMetadata> const&),
|
||||
()
|
||||
(const, override)
|
||||
);
|
||||
|
||||
MOCK_METHOD(void, unsubLedger, (session_ptr), ());
|
||||
MOCK_METHOD(void, unsubLedger, (feed::SubscriberSharedPtr const&), (override));
|
||||
|
||||
MOCK_METHOD(void, subTransactions, (session_ptr), ());
|
||||
MOCK_METHOD(void, subTransactions, (feed::SubscriberSharedPtr const&), (override));
|
||||
|
||||
MOCK_METHOD(void, unsubTransactions, (session_ptr), ());
|
||||
MOCK_METHOD(void, unsubTransactions, (feed::SubscriberSharedPtr const&), (override));
|
||||
|
||||
MOCK_METHOD(void, pubTransaction, (data::TransactionAndMetadata const&, ripple::LedgerInfo const&), ());
|
||||
MOCK_METHOD(void, pubTransaction, (data::TransactionAndMetadata const&, ripple::LedgerInfo const&), (override));
|
||||
|
||||
MOCK_METHOD(void, subAccount, (ripple::AccountID const&, session_ptr&), ());
|
||||
MOCK_METHOD(void, subAccount, (ripple::AccountID const&, feed::SubscriberSharedPtr const&), (override));
|
||||
|
||||
MOCK_METHOD(void, unsubAccount, (ripple::AccountID const&, session_ptr const&), ());
|
||||
MOCK_METHOD(void, unsubAccount, (ripple::AccountID const&, feed::SubscriberSharedPtr const&), (override));
|
||||
|
||||
MOCK_METHOD(void, subBook, (ripple::Book const&, session_ptr), ());
|
||||
MOCK_METHOD(void, subBook, (ripple::Book const&, feed::SubscriberSharedPtr const&), (override));
|
||||
|
||||
MOCK_METHOD(void, unsubBook, (ripple::Book const&, session_ptr), ());
|
||||
MOCK_METHOD(void, unsubBook, (ripple::Book const&, feed::SubscriberSharedPtr const&), (override));
|
||||
|
||||
MOCK_METHOD(void, subBookChanges, (session_ptr), ());
|
||||
MOCK_METHOD(void, subBookChanges, (feed::SubscriberSharedPtr const&), (override));
|
||||
|
||||
MOCK_METHOD(void, unsubBookChanges, (session_ptr), ());
|
||||
MOCK_METHOD(void, unsubBookChanges, (feed::SubscriberSharedPtr const&), (override));
|
||||
|
||||
MOCK_METHOD(void, subManifest, (session_ptr), ());
|
||||
MOCK_METHOD(void, subManifest, (feed::SubscriberSharedPtr const&), (override));
|
||||
|
||||
MOCK_METHOD(void, unsubManifest, (session_ptr), ());
|
||||
MOCK_METHOD(void, unsubManifest, (feed::SubscriberSharedPtr const&), (override));
|
||||
|
||||
MOCK_METHOD(void, subValidation, (session_ptr), ());
|
||||
MOCK_METHOD(void, subValidation, (feed::SubscriberSharedPtr const&), (override));
|
||||
|
||||
MOCK_METHOD(void, unsubValidation, (session_ptr), ());
|
||||
MOCK_METHOD(void, unsubValidation, (feed::SubscriberSharedPtr const&), (override));
|
||||
|
||||
MOCK_METHOD(void, forwardProposedTransaction, (boost::json::object const&), ());
|
||||
MOCK_METHOD(void, forwardProposedTransaction, (boost::json::object const&), (override));
|
||||
|
||||
MOCK_METHOD(void, forwardManifest, (boost::json::object const&), ());
|
||||
MOCK_METHOD(void, forwardManifest, (boost::json::object const&), (const, override));
|
||||
|
||||
MOCK_METHOD(void, forwardValidation, (boost::json::object const&), ());
|
||||
MOCK_METHOD(void, forwardValidation, (boost::json::object const&), (const, override));
|
||||
|
||||
MOCK_METHOD(void, subProposedAccount, (ripple::AccountID const&, session_ptr), ());
|
||||
MOCK_METHOD(void, subProposedAccount, (ripple::AccountID const&, feed::SubscriberSharedPtr const&), (override));
|
||||
|
||||
MOCK_METHOD(void, unsubProposedAccount, (ripple::AccountID const&, session_ptr), ());
|
||||
MOCK_METHOD(void, unsubProposedAccount, (ripple::AccountID const&, feed::SubscriberSharedPtr const&), (override));
|
||||
|
||||
MOCK_METHOD(void, subProposedTransactions, (session_ptr), ());
|
||||
MOCK_METHOD(void, subProposedTransactions, (feed::SubscriberSharedPtr const&), (override));
|
||||
|
||||
MOCK_METHOD(void, unsubProposedTransactions, (session_ptr), ());
|
||||
MOCK_METHOD(void, unsubProposedTransactions, (feed::SubscriberSharedPtr const&), (override));
|
||||
|
||||
MOCK_METHOD(void, cleanup, (session_ptr), ());
|
||||
|
||||
MOCK_METHOD(boost::json::object, report, (), (const));
|
||||
MOCK_METHOD(boost::json::object, report, (), (const, override));
|
||||
};
|
||||
|
||||
template <template <typename> typename MockType = ::testing::NiceMock>
|
||||
struct MockSubscriptionManagerSharedPtrImpl {
|
||||
std::shared_ptr<MockType<MockSubscriptionManager>> subscriptionManagerMock =
|
||||
std::make_shared<MockType<MockSubscriptionManager>>();
|
||||
|
||||
operator std::shared_ptr<feed::SubscriptionManagerInterface>()
|
||||
{
|
||||
return subscriptionManagerMock;
|
||||
}
|
||||
|
||||
MockType<MockSubscriptionManager>&
|
||||
operator*()
|
||||
{
|
||||
return *subscriptionManagerMock;
|
||||
}
|
||||
};
|
||||
|
||||
using MockSubscriptionManagerSharedPtr = MockSubscriptionManagerSharedPtrImpl<>;
|
||||
using StrictMockSubscriptionManagerSharedPtr = MockSubscriptionManagerSharedPtrImpl<testing::StrictMock>;
|
||||
|
||||
@@ -26,8 +26,8 @@ target_sources(
|
||||
etl/ForwardingSourceTests.cpp
|
||||
etl/GrpcSourceTests.cpp
|
||||
etl/LedgerPublisherTests.cpp
|
||||
etl/SourceTests.cpp
|
||||
etl/SubscriptionSourceDependenciesTests.cpp
|
||||
etl/LoadBalancerTests.cpp
|
||||
etl/SourceImplTests.cpp
|
||||
etl/SubscriptionSourceTests.cpp
|
||||
etl/TransformerTests.cpp
|
||||
# Feed
|
||||
@@ -114,6 +114,7 @@ target_sources(
|
||||
util/requests/RequestBuilderTests.cpp
|
||||
util/requests/SslContextTests.cpp
|
||||
util/requests/WsConnectionTests.cpp
|
||||
util/RandomTests.cpp
|
||||
util/RetryTests.cpp
|
||||
util/SignalsHandlerTests.cpp
|
||||
util/TxUtilTests.cpp
|
||||
|
||||
@@ -40,7 +40,7 @@ using namespace testing;
|
||||
constexpr static auto MAXSEQ = 30;
|
||||
constexpr static auto MINSEQ = 10;
|
||||
|
||||
struct BackendInterfaceTest : MockBackendTestNaggy, SyncAsioContextTest, WithPrometheus {};
|
||||
struct BackendInterfaceTest : WithPrometheus, MockBackendTestNaggy, SyncAsioContextTest {};
|
||||
|
||||
TEST_F(BackendInterfaceTest, FetchFeesSuccessPath)
|
||||
{
|
||||
|
||||
@@ -45,19 +45,6 @@ namespace {
|
||||
constexpr auto SEQ = 30;
|
||||
|
||||
struct CacheLoaderTest : util::prometheus::WithPrometheus, MockBackendTest {
|
||||
void
|
||||
SetUp() override
|
||||
{
|
||||
MockBackendTest::SetUp();
|
||||
}
|
||||
|
||||
void
|
||||
TearDown() override
|
||||
{
|
||||
MockBackendTest::TearDown();
|
||||
}
|
||||
|
||||
protected:
|
||||
DiffProvider diffProvider;
|
||||
MockCache cache;
|
||||
};
|
||||
|
||||
@@ -76,3 +76,15 @@ TEST_F(ETLStateTest, NetworkIdInvalid)
|
||||
ASSERT_TRUE(state.has_value());
|
||||
EXPECT_FALSE(state->networkID.has_value());
|
||||
}
|
||||
|
||||
TEST_F(ETLStateTest, ResponseHasError)
|
||||
{
|
||||
auto const json = json::parse(
|
||||
R"JSON({
|
||||
"error": "error"
|
||||
})JSON"
|
||||
);
|
||||
EXPECT_CALL(source, forwardToRippled).WillOnce(Return(json.as_object()));
|
||||
auto const state = etl::ETLState::fetchETLStateFromSource(source);
|
||||
EXPECT_FALSE(state.has_value());
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
using namespace testing;
|
||||
@@ -38,127 +37,96 @@ using namespace etl;
|
||||
struct ETLExtractorTest : util::prometheus::WithPrometheus, NoLoggerFixture {
|
||||
using ExtractionDataPipeType = MockExtractionDataPipe;
|
||||
using LedgerFetcherType = MockLedgerFetcher;
|
||||
using ExtractorType = etl::impl::Extractor<ExtractionDataPipeType, MockNetworkValidatedLedgers, LedgerFetcherType>;
|
||||
using ExtractorType = etl::impl::Extractor<ExtractionDataPipeType, LedgerFetcherType>;
|
||||
|
||||
ExtractionDataPipeType dataPipe_;
|
||||
std::shared_ptr<MockNetworkValidatedLedgers> networkValidatedLedgers_ =
|
||||
std::make_shared<MockNetworkValidatedLedgers>();
|
||||
MockNetworkValidatedLedgersPtr networkValidatedLedgers_;
|
||||
LedgerFetcherType ledgerFetcher_;
|
||||
SystemState state_;
|
||||
|
||||
std::unique_ptr<ExtractorType> extractor_;
|
||||
|
||||
void
|
||||
SetUp() override
|
||||
ETLExtractorTest()
|
||||
{
|
||||
state_.isStopping = false;
|
||||
state_.writeConflict = false;
|
||||
state_.isReadOnly = false;
|
||||
state_.isWriting = false;
|
||||
}
|
||||
|
||||
void
|
||||
TearDown() override
|
||||
{
|
||||
extractor_.reset();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(ETLExtractorTest, StopsWhenCurrentSequenceExceedsFinishSequence)
|
||||
{
|
||||
auto const rawNetworkValidatedLedgersPtr = networkValidatedLedgers_.get();
|
||||
|
||||
ON_CALL(*rawNetworkValidatedLedgersPtr, waitUntilValidatedByNetwork).WillByDefault(Return(true));
|
||||
EXPECT_CALL(*rawNetworkValidatedLedgersPtr, waitUntilValidatedByNetwork).Times(3);
|
||||
ON_CALL(dataPipe_, getStride).WillByDefault(Return(4));
|
||||
EXPECT_CALL(dataPipe_, getStride).Times(3);
|
||||
EXPECT_CALL(*networkValidatedLedgers_, waitUntilValidatedByNetwork).Times(3).WillRepeatedly(Return(true));
|
||||
EXPECT_CALL(dataPipe_, getStride).Times(3).WillRepeatedly(Return(4));
|
||||
|
||||
auto response = FakeFetchResponse{};
|
||||
ON_CALL(ledgerFetcher_, fetchDataAndDiff(_)).WillByDefault(Return(response));
|
||||
EXPECT_CALL(ledgerFetcher_, fetchDataAndDiff).Times(3);
|
||||
EXPECT_CALL(ledgerFetcher_, fetchDataAndDiff).Times(3).WillRepeatedly(Return(response));
|
||||
EXPECT_CALL(dataPipe_, push).Times(3);
|
||||
EXPECT_CALL(dataPipe_, finish(0)).Times(1);
|
||||
|
||||
// expected to invoke for seq 0, 4, 8 and finally stop as seq will be greater than finishing seq
|
||||
extractor_ = std::make_unique<ExtractorType>(dataPipe_, networkValidatedLedgers_, ledgerFetcher_, 0, 11, state_);
|
||||
ExtractorType{dataPipe_, networkValidatedLedgers_, ledgerFetcher_, 0, 11, state_};
|
||||
}
|
||||
|
||||
TEST_F(ETLExtractorTest, StopsOnWriteConflict)
|
||||
{
|
||||
EXPECT_CALL(dataPipe_, finish(0)).Times(1);
|
||||
EXPECT_CALL(dataPipe_, finish(0));
|
||||
state_.writeConflict = true;
|
||||
|
||||
// despite finish sequence being far ahead, we set writeConflict and so exit the loop immediately
|
||||
extractor_ = std::make_unique<ExtractorType>(dataPipe_, networkValidatedLedgers_, ledgerFetcher_, 0, 64, state_);
|
||||
ExtractorType{dataPipe_, networkValidatedLedgers_, ledgerFetcher_, 0, 64, state_};
|
||||
}
|
||||
|
||||
TEST_F(ETLExtractorTest, StopsOnServerShutdown)
|
||||
{
|
||||
EXPECT_CALL(dataPipe_, finish(0)).Times(1);
|
||||
EXPECT_CALL(dataPipe_, finish(0));
|
||||
state_.isStopping = true;
|
||||
|
||||
// despite finish sequence being far ahead, we set isStopping and so exit the loop immediately
|
||||
extractor_ = std::make_unique<ExtractorType>(dataPipe_, networkValidatedLedgers_, ledgerFetcher_, 0, 64, state_);
|
||||
ExtractorType{dataPipe_, networkValidatedLedgers_, ledgerFetcher_, 0, 64, state_};
|
||||
}
|
||||
|
||||
// stop extractor thread if fetcheResponse is empty
|
||||
TEST_F(ETLExtractorTest, StopsIfFetchIsUnsuccessful)
|
||||
{
|
||||
auto const rawNetworkValidatedLedgersPtr = networkValidatedLedgers_.get();
|
||||
EXPECT_CALL(*networkValidatedLedgers_, waitUntilValidatedByNetwork).WillOnce(Return(true));
|
||||
|
||||
ON_CALL(*rawNetworkValidatedLedgersPtr, waitUntilValidatedByNetwork).WillByDefault(Return(true));
|
||||
EXPECT_CALL(*rawNetworkValidatedLedgersPtr, waitUntilValidatedByNetwork).Times(1);
|
||||
|
||||
ON_CALL(ledgerFetcher_, fetchDataAndDiff(_)).WillByDefault(Return(std::nullopt));
|
||||
EXPECT_CALL(ledgerFetcher_, fetchDataAndDiff).Times(1);
|
||||
EXPECT_CALL(dataPipe_, finish(0)).Times(1);
|
||||
EXPECT_CALL(ledgerFetcher_, fetchDataAndDiff).WillOnce(Return(std::nullopt));
|
||||
EXPECT_CALL(dataPipe_, finish(0));
|
||||
|
||||
// we break immediately because fetchDataAndDiff returns nullopt
|
||||
extractor_ = std::make_unique<ExtractorType>(dataPipe_, networkValidatedLedgers_, ledgerFetcher_, 0, 64, state_);
|
||||
ExtractorType{dataPipe_, networkValidatedLedgers_, ledgerFetcher_, 0, 64, state_};
|
||||
}
|
||||
|
||||
TEST_F(ETLExtractorTest, StopsIfWaitingUntilValidatedByNetworkTimesOut)
|
||||
{
|
||||
auto const rawNetworkValidatedLedgersPtr = networkValidatedLedgers_.get();
|
||||
|
||||
// note that in actual clio code we don't return false unless a timeout is specified and exceeded
|
||||
ON_CALL(*rawNetworkValidatedLedgersPtr, waitUntilValidatedByNetwork).WillByDefault(Return(false));
|
||||
EXPECT_CALL(*rawNetworkValidatedLedgersPtr, waitUntilValidatedByNetwork).Times(1);
|
||||
EXPECT_CALL(*networkValidatedLedgers_, waitUntilValidatedByNetwork).WillOnce(Return(false));
|
||||
EXPECT_CALL(dataPipe_, finish(0)).Times(1);
|
||||
|
||||
// we emulate waitUntilValidatedByNetwork timing out which would lead to shutdown of the extractor thread
|
||||
extractor_ = std::make_unique<ExtractorType>(dataPipe_, networkValidatedLedgers_, ledgerFetcher_, 0, 64, state_);
|
||||
ExtractorType{dataPipe_, networkValidatedLedgers_, ledgerFetcher_, 0, 64, state_};
|
||||
}
|
||||
|
||||
TEST_F(ETLExtractorTest, SendsCorrectResponseToDataPipe)
|
||||
{
|
||||
auto const rawNetworkValidatedLedgersPtr = networkValidatedLedgers_.get();
|
||||
|
||||
ON_CALL(*rawNetworkValidatedLedgersPtr, waitUntilValidatedByNetwork).WillByDefault(Return(true));
|
||||
EXPECT_CALL(*rawNetworkValidatedLedgersPtr, waitUntilValidatedByNetwork).Times(1);
|
||||
ON_CALL(dataPipe_, getStride).WillByDefault(Return(4));
|
||||
EXPECT_CALL(dataPipe_, getStride).Times(1);
|
||||
EXPECT_CALL(*networkValidatedLedgers_, waitUntilValidatedByNetwork).WillOnce(Return(true));
|
||||
EXPECT_CALL(dataPipe_, getStride).WillOnce(Return(4));
|
||||
|
||||
auto response = FakeFetchResponse{1234};
|
||||
auto optionalResponse = std::optional<FakeFetchResponse>{};
|
||||
|
||||
ON_CALL(ledgerFetcher_, fetchDataAndDiff(_)).WillByDefault(Return(response));
|
||||
EXPECT_CALL(ledgerFetcher_, fetchDataAndDiff).Times(1);
|
||||
EXPECT_CALL(dataPipe_, push).Times(1).WillOnce(SaveArg<1>(&optionalResponse));
|
||||
EXPECT_CALL(dataPipe_, finish(0)).Times(1);
|
||||
EXPECT_CALL(ledgerFetcher_, fetchDataAndDiff).WillOnce(Return(response));
|
||||
EXPECT_CALL(dataPipe_, push(_, std::optional{response}));
|
||||
EXPECT_CALL(dataPipe_, finish(0));
|
||||
|
||||
// expect to finish after just one response due to finishSequence set to 1
|
||||
extractor_ = std::make_unique<ExtractorType>(dataPipe_, networkValidatedLedgers_, ledgerFetcher_, 0, 1, state_);
|
||||
extractor_->waitTillFinished(); // this is what clio does too. waiting for the thread to join
|
||||
|
||||
EXPECT_TRUE(optionalResponse.has_value());
|
||||
EXPECT_EQ(optionalResponse.value(), response);
|
||||
ExtractorType extractor{dataPipe_, networkValidatedLedgers_, ledgerFetcher_, 0, 1, state_};
|
||||
extractor.waitTillFinished(); // this is what clio does too. waiting for the thread to join
|
||||
}
|
||||
|
||||
TEST_F(ETLExtractorTest, CallsPipeFinishWithInitialSequenceAtExit)
|
||||
{
|
||||
EXPECT_CALL(dataPipe_, finish(123)).Times(1);
|
||||
EXPECT_CALL(dataPipe_, finish(123));
|
||||
state_.isStopping = true;
|
||||
|
||||
extractor_ = std::make_unique<ExtractorType>(dataPipe_, networkValidatedLedgers_, ledgerFetcher_, 123, 234, state_);
|
||||
ExtractorType{dataPipe_, networkValidatedLedgers_, ledgerFetcher_, 123, 234, state_};
|
||||
}
|
||||
|
||||
@@ -50,29 +50,22 @@ static auto constexpr LEDGERHASH = "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A
|
||||
static auto constexpr SEQ = 30;
|
||||
static auto constexpr AGE = 800;
|
||||
|
||||
struct ETLLedgerPublisherTest : util::prometheus::WithPrometheus,
|
||||
MockBackendTest,
|
||||
SyncAsioContextTest,
|
||||
MockSubscriptionManagerTest {
|
||||
struct ETLLedgerPublisherTest : util::prometheus::WithPrometheus, MockBackendTestStrict, SyncAsioContextTest {
|
||||
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;
|
||||
StrictMockSubscriptionManagerSharedPtr mockSubscriptionManagerPtr;
|
||||
};
|
||||
|
||||
TEST_F(ETLLedgerPublisherTest, PublishLedgerInfoIsWritingFalse)
|
||||
@@ -83,14 +76,13 @@ TEST_F(ETLLedgerPublisherTest, PublishLedgerInfoIsWritingFalse)
|
||||
impl::LedgerPublisher publisher(ctx, backend, mockCache, mockSubscriptionManagerPtr, dummyState);
|
||||
publisher.publish(dummyLedgerInfo);
|
||||
|
||||
ON_CALL(*backend, fetchLedgerDiff(SEQ, _)).WillByDefault(Return(std::vector<LedgerObject>{}));
|
||||
EXPECT_CALL(*backend, fetchLedgerDiff(SEQ, _)).Times(1);
|
||||
EXPECT_CALL(*backend, fetchLedgerDiff(SEQ, _)).WillOnce(Return(std::vector<LedgerObject>{}));
|
||||
|
||||
// setLastPublishedSequence not in strand, should verify before run
|
||||
EXPECT_TRUE(publisher.getLastPublishedSequence());
|
||||
EXPECT_EQ(publisher.getLastPublishedSequence().value(), SEQ);
|
||||
|
||||
EXPECT_CALL(mockCache, updateImp).Times(1);
|
||||
EXPECT_CALL(mockCache, updateImp);
|
||||
|
||||
ctx.run();
|
||||
EXPECT_TRUE(backend->fetchLedgerRange());
|
||||
@@ -106,8 +98,6 @@ TEST_F(ETLLedgerPublisherTest, PublishLedgerInfoIsWritingTrue)
|
||||
impl::LedgerPublisher publisher(ctx, backend, mockCache, mockSubscriptionManagerPtr, dummyState);
|
||||
publisher.publish(dummyLedgerInfo);
|
||||
|
||||
EXPECT_CALL(*backend, fetchLedgerDiff(_, _)).Times(0);
|
||||
|
||||
// setLastPublishedSequence not in strand, should verify before run
|
||||
EXPECT_TRUE(publisher.getLastPublishedSequence());
|
||||
EXPECT_EQ(publisher.getLastPublishedSequence().value(), SEQ);
|
||||
@@ -127,33 +117,26 @@ TEST_F(ETLLedgerPublisherTest, PublishLedgerInfoInRange)
|
||||
|
||||
publisher.publish(dummyLedgerInfo);
|
||||
|
||||
EXPECT_CALL(*backend, fetchLedgerDiff(_, _)).Times(0);
|
||||
|
||||
// mock fetch fee
|
||||
EXPECT_CALL(*backend, doFetchLedgerObject).Times(1);
|
||||
ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::fees().key, SEQ, _))
|
||||
.WillByDefault(Return(CreateLegacyFeeSettingBlob(1, 2, 3, 4, 0)));
|
||||
EXPECT_CALL(*backend, doFetchLedgerObject(ripple::keylet::fees().key, SEQ, _))
|
||||
.WillOnce(Return(CreateLegacyFeeSettingBlob(1, 2, 3, 4, 0)));
|
||||
|
||||
// mock fetch transactions
|
||||
EXPECT_CALL(*backend, 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(*backend, fetchAllTransactionsInLedger(SEQ, _))
|
||||
.WillByDefault(Return(std::vector<TransactionAndMetadata>{t1}));
|
||||
|
||||
// mock fetch transactions
|
||||
EXPECT_CALL(*backend, fetchAllTransactionsInLedger).WillOnce(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);
|
||||
EXPECT_CALL(*mockSubscriptionManagerPtr, pubLedger(_, _, fmt::format("{}-{}", SEQ - 1, SEQ), 1));
|
||||
EXPECT_CALL(*mockSubscriptionManagerPtr, pubBookChanges);
|
||||
// mock 1 transaction
|
||||
EXPECT_CALL(*rawSubscriptionManagerPtr, pubTransaction).Times(1);
|
||||
EXPECT_CALL(*mockSubscriptionManagerPtr, pubTransaction);
|
||||
|
||||
ctx.run();
|
||||
// last publish time should be set
|
||||
@@ -175,33 +158,27 @@ TEST_F(ETLLedgerPublisherTest, PublishLedgerInfoCloseTimeGreaterThanNow)
|
||||
impl::LedgerPublisher publisher(ctx, backend, mockCache, mockSubscriptionManagerPtr, dummyState);
|
||||
publisher.publish(dummyLedgerInfo);
|
||||
|
||||
EXPECT_CALL(*backend, fetchLedgerDiff(_, _)).Times(0);
|
||||
|
||||
// mock fetch fee
|
||||
EXPECT_CALL(*backend, doFetchLedgerObject).Times(1);
|
||||
ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::fees().key, SEQ, _))
|
||||
.WillByDefault(Return(CreateLegacyFeeSettingBlob(1, 2, 3, 4, 0)));
|
||||
EXPECT_CALL(*backend, doFetchLedgerObject(ripple::keylet::fees().key, SEQ, _))
|
||||
.WillOnce(Return(CreateLegacyFeeSettingBlob(1, 2, 3, 4, 0)));
|
||||
|
||||
// mock fetch transactions
|
||||
EXPECT_CALL(*backend, 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(*backend, fetchAllTransactionsInLedger(SEQ, _))
|
||||
.WillByDefault(Return(std::vector<TransactionAndMetadata>{t1}));
|
||||
|
||||
// mock fetch transactions
|
||||
EXPECT_CALL(*backend, fetchAllTransactionsInLedger(SEQ, _))
|
||||
.WillOnce(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);
|
||||
EXPECT_CALL(*mockSubscriptionManagerPtr, pubLedger(_, _, fmt::format("{}-{}", SEQ - 1, SEQ), 1));
|
||||
EXPECT_CALL(*mockSubscriptionManagerPtr, pubBookChanges);
|
||||
// mock 1 transaction
|
||||
EXPECT_CALL(*rawSubscriptionManagerPtr, pubTransaction).Times(1);
|
||||
EXPECT_CALL(*mockSubscriptionManagerPtr, pubTransaction);
|
||||
|
||||
ctx.run();
|
||||
// last publish time should be set
|
||||
@@ -224,11 +201,10 @@ TEST_F(ETLLedgerPublisherTest, PublishLedgerSeqMaxAttampt)
|
||||
|
||||
static auto constexpr MAX_ATTEMPT = 2;
|
||||
|
||||
EXPECT_CALL(*backend, hardFetchLedgerRange).Times(MAX_ATTEMPT);
|
||||
|
||||
LedgerRange const range{.minSequence = SEQ - 1, .maxSequence = SEQ - 1};
|
||||
ON_CALL(*backend, hardFetchLedgerRange(_)).WillByDefault(Return(range));
|
||||
EXPECT_FALSE(publisher.publish(SEQ, MAX_ATTEMPT));
|
||||
EXPECT_CALL(*backend, hardFetchLedgerRange).Times(MAX_ATTEMPT).WillRepeatedly(Return(range));
|
||||
|
||||
EXPECT_FALSE(publisher.publish(SEQ, MAX_ATTEMPT, std::chrono::milliseconds{1}));
|
||||
}
|
||||
|
||||
TEST_F(ETLLedgerPublisherTest, PublishLedgerSeqStopIsFalse)
|
||||
@@ -238,16 +214,13 @@ TEST_F(ETLLedgerPublisherTest, PublishLedgerSeqStopIsFalse)
|
||||
impl::LedgerPublisher publisher(ctx, backend, mockCache, mockSubscriptionManagerPtr, dummyState);
|
||||
|
||||
LedgerRange const range{.minSequence = SEQ, .maxSequence = SEQ};
|
||||
ON_CALL(*backend, hardFetchLedgerRange(_)).WillByDefault(Return(range));
|
||||
EXPECT_CALL(*backend, hardFetchLedgerRange).Times(1);
|
||||
EXPECT_CALL(*backend, hardFetchLedgerRange).WillOnce(Return(range));
|
||||
|
||||
auto const dummyLedgerInfo = CreateLedgerInfo(LEDGERHASH, SEQ, AGE);
|
||||
ON_CALL(*backend, fetchLedgerBySequence(SEQ, _)).WillByDefault(Return(dummyLedgerInfo));
|
||||
EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1);
|
||||
EXPECT_CALL(*backend, fetchLedgerBySequence(SEQ, _)).WillOnce(Return(dummyLedgerInfo));
|
||||
|
||||
ON_CALL(*backend, fetchLedgerDiff(SEQ, _)).WillByDefault(Return(std::vector<LedgerObject>{}));
|
||||
EXPECT_CALL(*backend, fetchLedgerDiff(SEQ, _)).Times(1);
|
||||
EXPECT_CALL(mockCache, updateImp).Times(1);
|
||||
EXPECT_CALL(*backend, fetchLedgerDiff(SEQ, _)).WillOnce(Return(std::vector<LedgerObject>{}));
|
||||
EXPECT_CALL(mockCache, updateImp);
|
||||
|
||||
EXPECT_TRUE(publisher.publish(SEQ, {}));
|
||||
ctx.run();
|
||||
@@ -264,15 +237,10 @@ TEST_F(ETLLedgerPublisherTest, PublishMultipleTxInOrder)
|
||||
|
||||
publisher.publish(dummyLedgerInfo);
|
||||
|
||||
EXPECT_CALL(*backend, fetchLedgerDiff(_, _)).Times(0);
|
||||
|
||||
// mock fetch fee
|
||||
EXPECT_CALL(*backend, doFetchLedgerObject).Times(1);
|
||||
ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::fees().key, SEQ, _))
|
||||
.WillByDefault(Return(CreateLegacyFeeSettingBlob(1, 2, 3, 4, 0)));
|
||||
EXPECT_CALL(*backend, doFetchLedgerObject(ripple::keylet::fees().key, SEQ, _))
|
||||
.WillOnce(Return(CreateLegacyFeeSettingBlob(1, 2, 3, 4, 0)));
|
||||
|
||||
// mock fetch transactions
|
||||
EXPECT_CALL(*backend, fetchAllTransactionsInLedger).Times(1);
|
||||
// t1 index > t2 index
|
||||
TransactionAndMetadata t1;
|
||||
t1.transaction = CreatePaymentTransactionObject(ACCOUNT, ACCOUNT2, 100, 3, SEQ).getSerializer().peekData();
|
||||
@@ -284,22 +252,21 @@ TEST_F(ETLLedgerPublisherTest, PublishMultipleTxInOrder)
|
||||
t2.metadata = CreatePaymentTransactionMetaObject(ACCOUNT, ACCOUNT2, 110, 30, 1).getSerializer().peekData();
|
||||
t2.ledgerSequence = SEQ;
|
||||
t2.date = 2;
|
||||
ON_CALL(*backend, fetchAllTransactionsInLedger(SEQ, _))
|
||||
.WillByDefault(Return(std::vector<TransactionAndMetadata>{t1, t2}));
|
||||
|
||||
// mock fetch transactions
|
||||
EXPECT_CALL(*backend, fetchAllTransactionsInLedger(SEQ, _))
|
||||
.WillOnce(Return(std::vector<TransactionAndMetadata>{t1, t2}));
|
||||
|
||||
// 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), 2)).Times(1);
|
||||
EXPECT_CALL(*rawSubscriptionManagerPtr, pubBookChanges).Times(1);
|
||||
EXPECT_CALL(*mockSubscriptionManagerPtr, pubLedger(_, _, fmt::format("{}-{}", SEQ - 1, SEQ), 2));
|
||||
EXPECT_CALL(*mockSubscriptionManagerPtr, pubBookChanges);
|
||||
// should call pubTransaction t2 first (greater tx index)
|
||||
Sequence const s;
|
||||
EXPECT_CALL(*rawSubscriptionManagerPtr, pubTransaction(t2, _)).InSequence(s);
|
||||
EXPECT_CALL(*rawSubscriptionManagerPtr, pubTransaction(t1, _)).InSequence(s);
|
||||
EXPECT_CALL(*mockSubscriptionManagerPtr, pubTransaction(t2, _)).InSequence(s);
|
||||
EXPECT_CALL(*mockSubscriptionManagerPtr, pubTransaction(t1, _)).InSequence(s);
|
||||
|
||||
ctx.run();
|
||||
// last publish time should be set
|
||||
|
||||
568
tests/unit/etl/LoadBalancerTests.cpp
Normal file
568
tests/unit/etl/LoadBalancerTests.cpp
Normal file
@@ -0,0 +1,568 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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 "etl/LoadBalancer.hpp"
|
||||
#include "etl/Source.hpp"
|
||||
#include "util/Fixtures.hpp"
|
||||
#include "util/MockNetworkValidatedLedgers.hpp"
|
||||
#include "util/MockPrometheus.hpp"
|
||||
#include "util/MockSource.hpp"
|
||||
#include "util/MockSubscriptionManager.hpp"
|
||||
#include "util/Random.hpp"
|
||||
#include "util/config/Config.hpp"
|
||||
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/spawn.hpp>
|
||||
#include <boost/json/array.hpp>
|
||||
#include <boost/json/object.hpp>
|
||||
#include <boost/json/parse.hpp>
|
||||
#include <boost/json/value.hpp>
|
||||
#include <gmock/gmock.h>
|
||||
#include <grpcpp/support/status.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <org/xrpl/rpc/v1/get_ledger.pb.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
using namespace etl;
|
||||
using testing::Return;
|
||||
|
||||
struct LoadBalancerConstructorTests : util::prometheus::WithPrometheus, MockBackendTestStrict {
|
||||
StrictMockSubscriptionManagerSharedPtr subscriptionManager_;
|
||||
StrictMockNetworkValidatedLedgersPtr networkManager_;
|
||||
StrictMockSourceFactory sourceFactory_{2};
|
||||
boost::asio::io_context ioContext_;
|
||||
boost::json::value configJson_{{"etl_sources", {"source1", "source2"}}};
|
||||
|
||||
std::unique_ptr<LoadBalancer>
|
||||
makeLoadBalancer()
|
||||
{
|
||||
return std::make_unique<LoadBalancer>(
|
||||
util::Config{configJson_},
|
||||
ioContext_,
|
||||
backend,
|
||||
subscriptionManager_,
|
||||
networkManager_,
|
||||
[this](auto&&... args) -> SourcePtr {
|
||||
return sourceFactory_.makeSourceMock(std::forward<decltype(args)>(args)...);
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(LoadBalancerConstructorTests, construct)
|
||||
{
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), forwardToRippled).WillOnce(Return(boost::json::object{}));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), run);
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), forwardToRippled).WillOnce(Return(boost::json::object{}));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), run);
|
||||
makeLoadBalancer();
|
||||
}
|
||||
|
||||
TEST_F(LoadBalancerConstructorTests, fetchETLState_Source0Fails)
|
||||
{
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), forwardToRippled).WillOnce(Return(std::nullopt));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), toString);
|
||||
EXPECT_THROW({ makeLoadBalancer(); }, std::logic_error);
|
||||
}
|
||||
|
||||
TEST_F(LoadBalancerConstructorTests, fetchETLState_Source0ReturnsError)
|
||||
{
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), forwardToRippled)
|
||||
.WillOnce(Return(boost::json::object{{"error", "some error"}}));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), toString);
|
||||
EXPECT_THROW({ makeLoadBalancer(); }, std::logic_error);
|
||||
}
|
||||
|
||||
TEST_F(LoadBalancerConstructorTests, fetchETLState_Source1Fails)
|
||||
{
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), forwardToRippled).WillOnce(Return(boost::json::object{}));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), forwardToRippled).WillOnce(Return(std::nullopt));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), toString);
|
||||
EXPECT_THROW({ makeLoadBalancer(); }, std::logic_error);
|
||||
}
|
||||
|
||||
TEST_F(LoadBalancerConstructorTests, fetchETLState_DifferentNetworkID)
|
||||
{
|
||||
auto const source1Json = boost::json::parse(R"({"result": {"info": {"network_id": 0}}})");
|
||||
auto const source2Json = boost::json::parse(R"({"result": {"info": {"network_id": 1}}})");
|
||||
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), forwardToRippled).WillOnce(Return(source1Json.as_object()));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), forwardToRippled).WillOnce(Return(source2Json.as_object()));
|
||||
EXPECT_THROW({ makeLoadBalancer(); }, std::logic_error);
|
||||
}
|
||||
|
||||
TEST_F(LoadBalancerConstructorTests, fetchETLState_Source1FailsButAllowNoEtlIsTrue)
|
||||
{
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), forwardToRippled).WillOnce(Return(boost::json::object{}));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), run);
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), forwardToRippled).WillOnce(Return(std::nullopt));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), toString);
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), run);
|
||||
|
||||
configJson_.as_object()["allow_no_etl"] = true;
|
||||
makeLoadBalancer();
|
||||
}
|
||||
|
||||
TEST_F(LoadBalancerConstructorTests, fetchETLState_DifferentNetworkIDButAllowNoEtlIsTrue)
|
||||
{
|
||||
auto const source1Json = boost::json::parse(R"({"result": {"info": {"network_id": 0}}})");
|
||||
auto const source2Json = boost::json::parse(R"({"result": {"info": {"network_id": 1}}})");
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), forwardToRippled).WillOnce(Return(source1Json.as_object()));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), run);
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), forwardToRippled).WillOnce(Return(source2Json.as_object()));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), run);
|
||||
|
||||
configJson_.as_object()["allow_no_etl"] = true;
|
||||
makeLoadBalancer();
|
||||
}
|
||||
|
||||
struct LoadBalancerConstructorDeathTest : LoadBalancerConstructorTests {};
|
||||
|
||||
TEST_F(LoadBalancerConstructorDeathTest, numMarkersSpecifiedInConfigIsInvalid)
|
||||
{
|
||||
uint32_t const numMarkers = 257;
|
||||
configJson_.as_object()["num_markers"] = numMarkers;
|
||||
EXPECT_DEATH({ makeLoadBalancer(); }, ".*");
|
||||
}
|
||||
|
||||
struct LoadBalancerOnConnectHookTests : LoadBalancerConstructorTests {
|
||||
LoadBalancerOnConnectHookTests()
|
||||
{
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), forwardToRippled).WillOnce(Return(boost::json::object{}));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), run);
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), forwardToRippled).WillOnce(Return(boost::json::object{}));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), run);
|
||||
loadBalancer_ = makeLoadBalancer();
|
||||
}
|
||||
std::unique_ptr<LoadBalancer> loadBalancer_;
|
||||
};
|
||||
|
||||
TEST_F(LoadBalancerOnConnectHookTests, sourcesConnect)
|
||||
{
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), isConnected()).WillOnce(Return(true));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), setForwarding(true));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), setForwarding(false));
|
||||
sourceFactory_.callbacksAt(0).onConnect();
|
||||
sourceFactory_.callbacksAt(1).onConnect();
|
||||
}
|
||||
|
||||
TEST_F(LoadBalancerOnConnectHookTests, sourcesConnect_Source0IsNotConnected)
|
||||
{
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), isConnected()).WillOnce(Return(false));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), setForwarding(false));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), isConnected()).WillOnce(Return(false));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), setForwarding(false));
|
||||
sourceFactory_.callbacksAt(0).onConnect(); // assuming it connects and disconnects immediately
|
||||
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), isConnected()).WillOnce(Return(false));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), setForwarding(false));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), isConnected()).WillOnce(Return(true));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), setForwarding(true));
|
||||
sourceFactory_.callbacksAt(1).onConnect();
|
||||
|
||||
// Nothing is called on another connect
|
||||
sourceFactory_.callbacksAt(0).onConnect();
|
||||
}
|
||||
|
||||
TEST_F(LoadBalancerOnConnectHookTests, sourcesConnect_BothSourcesAreNotConnected)
|
||||
{
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), isConnected()).WillOnce(Return(false));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), setForwarding(false));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), isConnected()).WillOnce(Return(false));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), setForwarding(false));
|
||||
sourceFactory_.callbacksAt(0).onConnect();
|
||||
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), isConnected()).WillOnce(Return(false));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), setForwarding(false));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), isConnected()).WillOnce(Return(false));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), setForwarding(false));
|
||||
sourceFactory_.callbacksAt(1).onConnect();
|
||||
|
||||
// Then source 0 got connected
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), isConnected()).WillOnce(Return(true));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), setForwarding(true));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), setForwarding(false));
|
||||
sourceFactory_.callbacksAt(0).onConnect();
|
||||
}
|
||||
|
||||
struct LoadBalancerOnDisconnectHookTests : LoadBalancerOnConnectHookTests {
|
||||
LoadBalancerOnDisconnectHookTests()
|
||||
{
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), isConnected()).WillOnce(Return(true));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), setForwarding(true));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), setForwarding(false));
|
||||
sourceFactory_.callbacksAt(0).onConnect();
|
||||
|
||||
// nothing happens on source 1 connect
|
||||
sourceFactory_.callbacksAt(1).onConnect();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(LoadBalancerOnDisconnectHookTests, source0Disconnects)
|
||||
{
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), isConnected()).WillOnce(Return(false));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), setForwarding(false));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), isConnected()).WillOnce(Return(true));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), setForwarding(true));
|
||||
sourceFactory_.callbacksAt(0).onDisconnect();
|
||||
}
|
||||
|
||||
TEST_F(LoadBalancerOnDisconnectHookTests, source1Disconnects)
|
||||
{
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), isConnected()).WillOnce(Return(true));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), setForwarding(true));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), setForwarding(false));
|
||||
sourceFactory_.callbacksAt(1).onDisconnect();
|
||||
}
|
||||
|
||||
TEST_F(LoadBalancerOnDisconnectHookTests, source0DisconnectsAndConnectsBack)
|
||||
{
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), isConnected()).WillOnce(Return(false));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), setForwarding(false));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), isConnected()).WillOnce(Return(true));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), setForwarding(true));
|
||||
sourceFactory_.callbacksAt(0).onDisconnect();
|
||||
|
||||
sourceFactory_.callbacksAt(0).onConnect();
|
||||
}
|
||||
|
||||
TEST_F(LoadBalancerOnDisconnectHookTests, source1DisconnectsAndConnectsBack)
|
||||
{
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), isConnected()).WillOnce(Return(true));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), setForwarding(true));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), setForwarding(false));
|
||||
sourceFactory_.callbacksAt(1).onDisconnect();
|
||||
|
||||
sourceFactory_.callbacksAt(1).onConnect();
|
||||
}
|
||||
|
||||
TEST_F(LoadBalancerOnConnectHookTests, bothSourcesDisconnectAndConnectBack)
|
||||
{
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), isConnected()).Times(2).WillRepeatedly(Return(false));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), setForwarding(false)).Times(2);
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), isConnected()).Times(2).WillRepeatedly(Return(false));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), setForwarding(false)).Times(2);
|
||||
sourceFactory_.callbacksAt(0).onDisconnect();
|
||||
sourceFactory_.callbacksAt(1).onDisconnect();
|
||||
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), isConnected()).WillOnce(Return(true));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), setForwarding(true));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), setForwarding(false));
|
||||
sourceFactory_.callbacksAt(0).onConnect();
|
||||
|
||||
sourceFactory_.callbacksAt(1).onConnect();
|
||||
}
|
||||
|
||||
struct LoadBalancer3SourcesTests : LoadBalancerConstructorTests {
|
||||
LoadBalancer3SourcesTests()
|
||||
{
|
||||
sourceFactory_ = StrictMockSourceFactory{3};
|
||||
configJson_.as_object()["etl_sources"] = {"source1", "source2", "source3"};
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), forwardToRippled).WillOnce(Return(boost::json::object{}));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), run);
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), forwardToRippled).WillOnce(Return(boost::json::object{}));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), run);
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(2), forwardToRippled).WillOnce(Return(boost::json::object{}));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(2), run);
|
||||
loadBalancer_ = makeLoadBalancer();
|
||||
}
|
||||
std::unique_ptr<LoadBalancer> loadBalancer_;
|
||||
};
|
||||
|
||||
TEST_F(LoadBalancer3SourcesTests, forwardingUpdate)
|
||||
{
|
||||
// Source 2 is connected first
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), isConnected()).WillOnce(Return(false));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), setForwarding(false));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), isConnected()).WillOnce(Return(false));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), setForwarding(false));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(2), isConnected()).WillOnce(Return(true));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(2), setForwarding(true));
|
||||
sourceFactory_.callbacksAt(2).onConnect();
|
||||
|
||||
// Then source 0 and 1 are getting connected, but nothing should happen
|
||||
sourceFactory_.callbacksAt(0).onConnect();
|
||||
sourceFactory_.callbacksAt(1).onConnect();
|
||||
|
||||
// Source 0 got disconnected
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), isConnected()).WillOnce(Return(false));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), setForwarding(false));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), isConnected()).WillOnce(Return(true));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), setForwarding(true));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(2), setForwarding(false)); // only source 1 must be forwarding
|
||||
sourceFactory_.callbacksAt(0).onDisconnect();
|
||||
}
|
||||
|
||||
struct LoadBalancerLoadInitialLedgerTests : LoadBalancerOnConnectHookTests {
|
||||
LoadBalancerLoadInitialLedgerTests()
|
||||
{
|
||||
util::Random::setSeed(0);
|
||||
}
|
||||
|
||||
uint32_t const sequence_ = 123;
|
||||
uint32_t const numMarkers_ = 16;
|
||||
bool const cacheOnly_ = true;
|
||||
std::pair<std::vector<std::string>, bool> const response_ = {{"1", "2", "3"}, true};
|
||||
};
|
||||
|
||||
TEST_F(LoadBalancerLoadInitialLedgerTests, load)
|
||||
{
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), hasLedger(sequence_)).WillOnce(Return(true));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), loadInitialLedger(sequence_, numMarkers_, cacheOnly_))
|
||||
.WillOnce(Return(response_));
|
||||
|
||||
EXPECT_EQ(loadBalancer_->loadInitialLedger(sequence_, cacheOnly_), response_.first);
|
||||
}
|
||||
|
||||
TEST_F(LoadBalancerLoadInitialLedgerTests, load_source0DoesntHaveLedger)
|
||||
{
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), hasLedger(sequence_)).WillOnce(Return(false));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), hasLedger(sequence_)).WillOnce(Return(true));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), loadInitialLedger(sequence_, numMarkers_, cacheOnly_))
|
||||
.WillOnce(Return(response_));
|
||||
|
||||
EXPECT_EQ(loadBalancer_->loadInitialLedger(sequence_, cacheOnly_), response_.first);
|
||||
}
|
||||
|
||||
TEST_F(LoadBalancerLoadInitialLedgerTests, load_bothSourcesDontHaveLedger)
|
||||
{
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), hasLedger(sequence_)).Times(2).WillRepeatedly(Return(false));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), hasLedger(sequence_)).WillOnce(Return(false)).WillOnce(Return(true));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), loadInitialLedger(sequence_, numMarkers_, cacheOnly_))
|
||||
.WillOnce(Return(response_));
|
||||
|
||||
EXPECT_EQ(loadBalancer_->loadInitialLedger(sequence_, cacheOnly_, std::chrono::milliseconds{1}), response_.first);
|
||||
}
|
||||
|
||||
TEST_F(LoadBalancerLoadInitialLedgerTests, load_source0ReturnsStatusFalse)
|
||||
{
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), hasLedger(sequence_)).WillOnce(Return(true));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), loadInitialLedger(sequence_, numMarkers_, cacheOnly_))
|
||||
.WillOnce(Return(std::make_pair(std::vector<std::string>{}, false)));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), hasLedger(sequence_)).WillOnce(Return(true));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), loadInitialLedger(sequence_, numMarkers_, cacheOnly_))
|
||||
.WillOnce(Return(response_));
|
||||
|
||||
EXPECT_EQ(loadBalancer_->loadInitialLedger(sequence_, cacheOnly_), response_.first);
|
||||
}
|
||||
|
||||
struct LoadBalancerLoadInitialLedgerCustomNumMarkersTests : LoadBalancerConstructorTests {
|
||||
uint32_t const numMarkers_ = 16;
|
||||
uint32_t const sequence_ = 123;
|
||||
bool const cacheOnly_ = true;
|
||||
std::pair<std::vector<std::string>, bool> const response_ = {{"1", "2", "3"}, true};
|
||||
};
|
||||
|
||||
TEST_F(LoadBalancerLoadInitialLedgerCustomNumMarkersTests, loadInitialLedger)
|
||||
{
|
||||
configJson_.as_object()["num_markers"] = numMarkers_;
|
||||
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), forwardToRippled).WillOnce(Return(boost::json::object{}));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), run);
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), forwardToRippled).WillOnce(Return(boost::json::object{}));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), run);
|
||||
auto loadBalancer = makeLoadBalancer();
|
||||
|
||||
util::Random::setSeed(0);
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), hasLedger(sequence_)).WillOnce(Return(true));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), loadInitialLedger(sequence_, numMarkers_, cacheOnly_))
|
||||
.WillOnce(Return(response_));
|
||||
|
||||
EXPECT_EQ(loadBalancer->loadInitialLedger(sequence_, cacheOnly_), response_.first);
|
||||
}
|
||||
|
||||
struct LoadBalancerFetchLegerTests : LoadBalancerOnConnectHookTests {
|
||||
LoadBalancerFetchLegerTests()
|
||||
{
|
||||
util::Random::setSeed(0);
|
||||
response_.second.set_validated(true);
|
||||
}
|
||||
uint32_t const sequence_ = 123;
|
||||
bool const getObjects_ = true;
|
||||
bool const getObjectNeighbors_ = false;
|
||||
std::pair<grpc::Status, org::xrpl::rpc::v1::GetLedgerResponse> response_ =
|
||||
std::make_pair(grpc::Status::OK, org::xrpl::rpc::v1::GetLedgerResponse{});
|
||||
};
|
||||
|
||||
TEST_F(LoadBalancerFetchLegerTests, fetch)
|
||||
{
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), hasLedger(sequence_)).WillOnce(Return(true));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), fetchLedger(sequence_, getObjects_, getObjectNeighbors_))
|
||||
.WillOnce(Return(response_));
|
||||
|
||||
EXPECT_TRUE(loadBalancer_->fetchLedger(sequence_, getObjects_, getObjectNeighbors_).has_value());
|
||||
}
|
||||
|
||||
TEST_F(LoadBalancerFetchLegerTests, fetch_Source0ReturnsBadStatus)
|
||||
{
|
||||
auto source0Response = response_;
|
||||
source0Response.first = grpc::Status::CANCELLED;
|
||||
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), hasLedger(sequence_)).WillOnce(Return(true));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), fetchLedger(sequence_, getObjects_, getObjectNeighbors_))
|
||||
.WillOnce(Return(source0Response));
|
||||
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), hasLedger(sequence_)).WillOnce(Return(true));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), fetchLedger(sequence_, getObjects_, getObjectNeighbors_))
|
||||
.WillOnce(Return(response_));
|
||||
|
||||
EXPECT_TRUE(loadBalancer_->fetchLedger(sequence_, getObjects_, getObjectNeighbors_).has_value());
|
||||
}
|
||||
|
||||
TEST_F(LoadBalancerFetchLegerTests, fetch_Source0ReturnsNotValidated)
|
||||
{
|
||||
auto source0Response = response_;
|
||||
source0Response.second.set_validated(false);
|
||||
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), hasLedger(sequence_)).WillOnce(Return(true));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), fetchLedger(sequence_, getObjects_, getObjectNeighbors_))
|
||||
.WillOnce(Return(source0Response));
|
||||
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), hasLedger(sequence_)).WillOnce(Return(true));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), fetchLedger(sequence_, getObjects_, getObjectNeighbors_))
|
||||
.WillOnce(Return(response_));
|
||||
|
||||
EXPECT_TRUE(loadBalancer_->fetchLedger(sequence_, getObjects_, getObjectNeighbors_).has_value());
|
||||
}
|
||||
|
||||
TEST_F(LoadBalancerFetchLegerTests, fetch_bothSourcesFail)
|
||||
{
|
||||
auto badResponse = response_;
|
||||
badResponse.second.set_validated(false);
|
||||
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), hasLedger(sequence_)).Times(2).WillRepeatedly(Return(true));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), fetchLedger(sequence_, getObjects_, getObjectNeighbors_))
|
||||
.WillOnce(Return(badResponse))
|
||||
.WillOnce(Return(response_));
|
||||
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), hasLedger(sequence_)).WillOnce(Return(true));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), fetchLedger(sequence_, getObjects_, getObjectNeighbors_))
|
||||
.WillOnce(Return(badResponse));
|
||||
|
||||
EXPECT_TRUE(loadBalancer_->fetchLedger(sequence_, getObjects_, getObjectNeighbors_, std::chrono::milliseconds{1})
|
||||
.has_value());
|
||||
}
|
||||
|
||||
struct LoadBalancerForwardToRippledTests : LoadBalancerConstructorTests, SyncAsioContextTest {
|
||||
LoadBalancerForwardToRippledTests()
|
||||
{
|
||||
util::Random::setSeed(0);
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), forwardToRippled).WillOnce(Return(boost::json::object{}));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), run);
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), forwardToRippled).WillOnce(Return(boost::json::object{}));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), run);
|
||||
}
|
||||
|
||||
boost::json::object const request_{{"request", "value"}};
|
||||
std::optional<std::string> const clientIP_ = "some_ip";
|
||||
boost::json::object const response_{{"response", "other_value"}};
|
||||
};
|
||||
|
||||
TEST_F(LoadBalancerForwardToRippledTests, forward)
|
||||
{
|
||||
auto loadBalancer = makeLoadBalancer();
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), forwardToRippled(request_, clientIP_, testing::_))
|
||||
.WillOnce(Return(response_));
|
||||
|
||||
runSpawn([&](boost::asio::yield_context yield) {
|
||||
EXPECT_EQ(loadBalancer->forwardToRippled(request_, clientIP_, yield), response_);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(LoadBalancerForwardToRippledTests, source0Fails)
|
||||
{
|
||||
auto loadBalancer = makeLoadBalancer();
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), forwardToRippled(request_, clientIP_, testing::_))
|
||||
.WillOnce(Return(std::nullopt));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), forwardToRippled(request_, clientIP_, testing::_))
|
||||
.WillOnce(Return(response_));
|
||||
|
||||
runSpawn([&](boost::asio::yield_context yield) {
|
||||
EXPECT_EQ(loadBalancer->forwardToRippled(request_, clientIP_, yield), response_);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(LoadBalancerForwardToRippledTests, bothSourcesFail)
|
||||
{
|
||||
auto loadBalancer = makeLoadBalancer();
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), forwardToRippled(request_, clientIP_, testing::_))
|
||||
.WillOnce(Return(std::nullopt));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), forwardToRippled(request_, clientIP_, testing::_))
|
||||
.WillOnce(Return(std::nullopt));
|
||||
|
||||
runSpawn([&](boost::asio::yield_context yield) {
|
||||
EXPECT_EQ(loadBalancer->forwardToRippled(request_, clientIP_, yield), std::nullopt);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(LoadBalancerForwardToRippledTests, forwardingCacheEnabled)
|
||||
{
|
||||
configJson_.as_object()["forwarding_cache_timeout"] = 10.;
|
||||
auto loadBalancer = makeLoadBalancer();
|
||||
|
||||
auto const request = boost::json::object{{"command", "server_info"}};
|
||||
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), forwardToRippled(request, clientIP_, testing::_))
|
||||
.WillOnce(Return(response_));
|
||||
|
||||
runSpawn([&](boost::asio::yield_context yield) {
|
||||
EXPECT_EQ(loadBalancer->forwardToRippled(request, clientIP_, yield), response_);
|
||||
EXPECT_EQ(loadBalancer->forwardToRippled(request, clientIP_, yield), response_);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(LoadBalancerForwardToRippledTests, onLedgerClosedHookInvalidatesCache)
|
||||
{
|
||||
configJson_.as_object()["forwarding_cache_timeout"] = 10.;
|
||||
auto loadBalancer = makeLoadBalancer();
|
||||
|
||||
auto const request = boost::json::object{{"command", "server_info"}};
|
||||
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), forwardToRippled(request, clientIP_, testing::_))
|
||||
.WillOnce(Return(response_));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), forwardToRippled(request, clientIP_, testing::_))
|
||||
.WillOnce(Return(boost::json::object{}));
|
||||
|
||||
runSpawn([&](boost::asio::yield_context yield) {
|
||||
EXPECT_EQ(loadBalancer->forwardToRippled(request, clientIP_, yield), response_);
|
||||
EXPECT_EQ(loadBalancer->forwardToRippled(request, clientIP_, yield), response_);
|
||||
sourceFactory_.callbacksAt(0).onLedgerClosed();
|
||||
EXPECT_EQ(loadBalancer->forwardToRippled(request, clientIP_, yield), boost::json::object{});
|
||||
});
|
||||
}
|
||||
|
||||
struct LoadBalancerToJsonTests : LoadBalancerOnConnectHookTests {};
|
||||
|
||||
TEST_F(LoadBalancerToJsonTests, toJson)
|
||||
{
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), toJson).WillOnce(Return(boost::json::object{{"source1", "value1"}}));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(1), toJson).WillOnce(Return(boost::json::object{{"source2", "value2"}}));
|
||||
|
||||
auto const expectedJson =
|
||||
boost::json::array({boost::json::object{{"source1", "value1"}}, boost::json::object{{"source2", "value2"}}});
|
||||
EXPECT_EQ(loadBalancer_->toJson(), expectedJson);
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include "etl/Source.hpp"
|
||||
#include "etl/impl/SourceImpl.hpp"
|
||||
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/spawn.hpp>
|
||||
@@ -36,7 +36,7 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
using namespace etl;
|
||||
using namespace etl::impl;
|
||||
|
||||
using testing::Return;
|
||||
using testing::StrictMock;
|
||||
@@ -72,7 +72,7 @@ struct ForwardingSourceMock {
|
||||
);
|
||||
};
|
||||
|
||||
struct SourceTest : public ::testing::Test {
|
||||
struct SourceImplTest : public ::testing::Test {
|
||||
boost::asio::io_context ioc_;
|
||||
|
||||
StrictMock<GrpcSourceMock> grpcSourceMock_;
|
||||
@@ -94,25 +94,25 @@ struct SourceTest : public ::testing::Test {
|
||||
};
|
||||
};
|
||||
|
||||
TEST_F(SourceTest, run)
|
||||
TEST_F(SourceImplTest, run)
|
||||
{
|
||||
EXPECT_CALL(*subscriptionSourceMock_, run());
|
||||
source_.run();
|
||||
}
|
||||
|
||||
TEST_F(SourceTest, isConnected)
|
||||
TEST_F(SourceImplTest, isConnected)
|
||||
{
|
||||
EXPECT_CALL(*subscriptionSourceMock_, isConnected()).WillOnce(testing::Return(true));
|
||||
EXPECT_TRUE(source_.isConnected());
|
||||
}
|
||||
|
||||
TEST_F(SourceTest, setForwarding)
|
||||
TEST_F(SourceImplTest, setForwarding)
|
||||
{
|
||||
EXPECT_CALL(*subscriptionSourceMock_, setForwarding(true));
|
||||
source_.setForwarding(true);
|
||||
}
|
||||
|
||||
TEST_F(SourceTest, toJson)
|
||||
TEST_F(SourceImplTest, toJson)
|
||||
{
|
||||
EXPECT_CALL(*subscriptionSourceMock_, validatedRange()).WillOnce(Return(std::string("some_validated_range")));
|
||||
EXPECT_CALL(*subscriptionSourceMock_, isConnected()).WillOnce(Return(true));
|
||||
@@ -130,7 +130,7 @@ TEST_F(SourceTest, toJson)
|
||||
EXPECT_GE(std::stoi(lastMessageAgeStr), 0);
|
||||
}
|
||||
|
||||
TEST_F(SourceTest, toString)
|
||||
TEST_F(SourceImplTest, toString)
|
||||
{
|
||||
EXPECT_CALL(*subscriptionSourceMock_, validatedRange()).WillOnce(Return(std::string("some_validated_range")));
|
||||
|
||||
@@ -141,14 +141,14 @@ TEST_F(SourceTest, toString)
|
||||
);
|
||||
}
|
||||
|
||||
TEST_F(SourceTest, hasLedger)
|
||||
TEST_F(SourceImplTest, hasLedger)
|
||||
{
|
||||
uint32_t const ledgerSeq = 123;
|
||||
EXPECT_CALL(*subscriptionSourceMock_, hasLedger(ledgerSeq)).WillOnce(Return(true));
|
||||
EXPECT_TRUE(source_.hasLedger(ledgerSeq));
|
||||
}
|
||||
|
||||
TEST_F(SourceTest, fetchLedger)
|
||||
TEST_F(SourceImplTest, fetchLedger)
|
||||
{
|
||||
uint32_t const ledgerSeq = 123;
|
||||
|
||||
@@ -158,7 +158,7 @@ TEST_F(SourceTest, fetchLedger)
|
||||
EXPECT_EQ(actualStatus.error_code(), grpc::StatusCode::OK);
|
||||
}
|
||||
|
||||
TEST_F(SourceTest, loadInitialLedger)
|
||||
TEST_F(SourceImplTest, loadInitialLedger)
|
||||
{
|
||||
uint32_t const ledgerSeq = 123;
|
||||
uint32_t const numMarkers = 3;
|
||||
@@ -171,7 +171,7 @@ TEST_F(SourceTest, loadInitialLedger)
|
||||
EXPECT_TRUE(actualSuccess);
|
||||
}
|
||||
|
||||
TEST_F(SourceTest, forwardToRippled)
|
||||
TEST_F(SourceImplTest, forwardToRippled)
|
||||
{
|
||||
boost::json::object const request = {{"some_key", "some_value"}};
|
||||
std::optional<std::string> const clientIp = "some_client_ip";
|
||||
@@ -1,70 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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 "etl/impl/SubscriptionSourceDependencies.hpp"
|
||||
#include "util/MockNetworkValidatedLedgers.hpp"
|
||||
#include "util/MockSubscriptionManager.hpp"
|
||||
|
||||
#include <boost/json/object.hpp>
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
using namespace etl::impl;
|
||||
using testing::StrictMock;
|
||||
|
||||
struct SubscriptionSourceDependenciesTest : testing::Test {
|
||||
std::shared_ptr<StrictMock<MockNetworkValidatedLedgers>> networkValidatedLedgers_ =
|
||||
std::make_shared<StrictMock<MockNetworkValidatedLedgers>>();
|
||||
|
||||
std::shared_ptr<StrictMock<MockSubscriptionManager>> subscriptionManager_ =
|
||||
std::make_shared<StrictMock<MockSubscriptionManager>>();
|
||||
|
||||
SubscriptionSourceDependencies dependencies_{networkValidatedLedgers_, subscriptionManager_};
|
||||
};
|
||||
|
||||
TEST_F(SubscriptionSourceDependenciesTest, ForwardProposedTransaction)
|
||||
{
|
||||
boost::json::object const txJson = {{"tx", "json"}};
|
||||
EXPECT_CALL(*subscriptionManager_, forwardProposedTransaction(txJson));
|
||||
dependencies_.forwardProposedTransaction(txJson);
|
||||
}
|
||||
|
||||
TEST_F(SubscriptionSourceDependenciesTest, ForwardValidation)
|
||||
{
|
||||
boost::json::object const validationJson = {{"validation", "json"}};
|
||||
EXPECT_CALL(*subscriptionManager_, forwardValidation(validationJson));
|
||||
dependencies_.forwardValidation(validationJson);
|
||||
}
|
||||
|
||||
TEST_F(SubscriptionSourceDependenciesTest, ForwardManifest)
|
||||
{
|
||||
boost::json::object const manifestJson = {{"manifest", "json"}};
|
||||
EXPECT_CALL(*subscriptionManager_, forwardManifest(manifestJson));
|
||||
dependencies_.forwardManifest(manifestJson);
|
||||
}
|
||||
|
||||
TEST_F(SubscriptionSourceDependenciesTest, PushValidatedLedger)
|
||||
{
|
||||
uint32_t const idx = 42;
|
||||
EXPECT_CALL(*networkValidatedLedgers_, push(idx));
|
||||
dependencies_.pushValidatedLedger(idx);
|
||||
}
|
||||
@@ -43,26 +43,21 @@ using testing::StrictMock;
|
||||
struct SubscriptionSourceConnectionTests : public NoLoggerFixture {
|
||||
SubscriptionSourceConnectionTests()
|
||||
{
|
||||
subscriptionSource_->run();
|
||||
subscriptionSource_.run();
|
||||
}
|
||||
|
||||
boost::asio::io_context ioContext_;
|
||||
|
||||
TestWsServer wsServer_{ioContext_, "0.0.0.0", 11113};
|
||||
|
||||
template <typename T>
|
||||
using StrictMockPtr = std::shared_ptr<StrictMock<T>>;
|
||||
|
||||
StrictMockPtr<MockNetworkValidatedLedgers> networkValidatedLedgers_ =
|
||||
std::make_shared<StrictMock<MockNetworkValidatedLedgers>>();
|
||||
StrictMockPtr<MockSubscriptionManager> subscriptionManager_ =
|
||||
std::make_shared<StrictMock<MockSubscriptionManager>>();
|
||||
StrictMockNetworkValidatedLedgersPtr networkValidatedLedgers_;
|
||||
StrictMockSubscriptionManagerSharedPtr subscriptionManager_;
|
||||
|
||||
StrictMock<MockFunction<void()>> onConnectHook_;
|
||||
StrictMock<MockFunction<void()>> onDisconnectHook_;
|
||||
StrictMock<MockFunction<void()>> onLedgerClosedHook_;
|
||||
|
||||
std::unique_ptr<SubscriptionSource> subscriptionSource_ = std::make_unique<SubscriptionSource>(
|
||||
SubscriptionSource subscriptionSource_{
|
||||
ioContext_,
|
||||
"127.0.0.1",
|
||||
"11113",
|
||||
@@ -73,7 +68,7 @@ struct SubscriptionSourceConnectionTests : public NoLoggerFixture {
|
||||
onLedgerClosedHook_.AsStdFunction(),
|
||||
std::chrono::milliseconds(1),
|
||||
std::chrono::milliseconds(1)
|
||||
);
|
||||
};
|
||||
|
||||
[[maybe_unused]] TestWsConnection
|
||||
serverConnection(boost::asio::yield_context yield)
|
||||
@@ -99,13 +94,13 @@ struct SubscriptionSourceConnectionTests : public NoLoggerFixture {
|
||||
|
||||
TEST_F(SubscriptionSourceConnectionTests, ConnectionFailed)
|
||||
{
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_->stop(); });
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_.stop(); });
|
||||
ioContext_.run();
|
||||
}
|
||||
|
||||
TEST_F(SubscriptionSourceConnectionTests, ConnectionFailed_Retry_ConnectionFailed)
|
||||
{
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([]() {}).WillOnce([this]() { subscriptionSource_->stop(); });
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([]() {}).WillOnce([this]() { subscriptionSource_.stop(); });
|
||||
ioContext_.run();
|
||||
}
|
||||
|
||||
@@ -117,7 +112,7 @@ TEST_F(SubscriptionSourceConnectionTests, ReadError)
|
||||
});
|
||||
|
||||
EXPECT_CALL(onConnectHook_, Call());
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_->stop(); });
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_.stop(); });
|
||||
ioContext_.run();
|
||||
}
|
||||
|
||||
@@ -131,21 +126,23 @@ TEST_F(SubscriptionSourceConnectionTests, ReadError_Reconnect)
|
||||
});
|
||||
|
||||
EXPECT_CALL(onConnectHook_, Call()).Times(2);
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([]() {}).WillOnce([this]() { subscriptionSource_->stop(); });
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([]() {}).WillOnce([this]() { subscriptionSource_.stop(); });
|
||||
ioContext_.run();
|
||||
}
|
||||
|
||||
TEST_F(SubscriptionSourceConnectionTests, IsConnected)
|
||||
{
|
||||
EXPECT_FALSE(subscriptionSource_->isConnected());
|
||||
EXPECT_FALSE(subscriptionSource_.isConnected());
|
||||
boost::asio::spawn(ioContext_, [this](boost::asio::yield_context yield) {
|
||||
auto connection = serverConnection(yield);
|
||||
EXPECT_TRUE(subscriptionSource_->isConnected());
|
||||
connection.close(yield);
|
||||
});
|
||||
|
||||
EXPECT_CALL(onConnectHook_, Call());
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_->stop(); });
|
||||
EXPECT_CALL(onConnectHook_, Call()).WillOnce([this]() { EXPECT_TRUE(subscriptionSource_.isConnected()); });
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() {
|
||||
EXPECT_FALSE(subscriptionSource_.isConnected());
|
||||
subscriptionSource_.stop();
|
||||
});
|
||||
ioContext_.run();
|
||||
}
|
||||
|
||||
@@ -170,7 +167,7 @@ TEST_F(SubscriptionSourceReadTests, GotWrongMessage_Reconnect)
|
||||
});
|
||||
|
||||
EXPECT_CALL(onConnectHook_, Call()).Times(2);
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([]() {}).WillOnce([this]() { subscriptionSource_->stop(); });
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([]() {}).WillOnce([this]() { subscriptionSource_.stop(); });
|
||||
ioContext_.run();
|
||||
}
|
||||
|
||||
@@ -182,7 +179,7 @@ TEST_F(SubscriptionSourceReadTests, GotResult)
|
||||
});
|
||||
|
||||
EXPECT_CALL(onConnectHook_, Call());
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_->stop(); });
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_.stop(); });
|
||||
ioContext_.run();
|
||||
}
|
||||
|
||||
@@ -194,7 +191,7 @@ TEST_F(SubscriptionSourceReadTests, GotResultWithLedgerIndex)
|
||||
});
|
||||
|
||||
EXPECT_CALL(onConnectHook_, Call());
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_->stop(); });
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_.stop(); });
|
||||
EXPECT_CALL(*networkValidatedLedgers_, push(123));
|
||||
ioContext_.run();
|
||||
}
|
||||
@@ -209,7 +206,7 @@ TEST_F(SubscriptionSourceReadTests, GotResultWithLedgerIndexAsString_Reconnect)
|
||||
});
|
||||
|
||||
EXPECT_CALL(onConnectHook_, Call()).Times(2);
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([]() {}).WillOnce([this]() { subscriptionSource_->stop(); });
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([]() {}).WillOnce([this]() { subscriptionSource_.stop(); });
|
||||
ioContext_.run();
|
||||
}
|
||||
|
||||
@@ -223,21 +220,21 @@ TEST_F(SubscriptionSourceReadTests, GotResultWithValidatedLedgersAsNumber_Reconn
|
||||
});
|
||||
|
||||
EXPECT_CALL(onConnectHook_, Call()).Times(2);
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([]() {}).WillOnce([this]() { subscriptionSource_->stop(); });
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([]() {}).WillOnce([this]() { subscriptionSource_.stop(); });
|
||||
ioContext_.run();
|
||||
}
|
||||
|
||||
TEST_F(SubscriptionSourceReadTests, GotResultWithValidatedLedgers)
|
||||
{
|
||||
EXPECT_FALSE(subscriptionSource_->hasLedger(123));
|
||||
EXPECT_FALSE(subscriptionSource_->hasLedger(124));
|
||||
EXPECT_FALSE(subscriptionSource_->hasLedger(455));
|
||||
EXPECT_FALSE(subscriptionSource_->hasLedger(456));
|
||||
EXPECT_FALSE(subscriptionSource_->hasLedger(457));
|
||||
EXPECT_FALSE(subscriptionSource_->hasLedger(32));
|
||||
EXPECT_FALSE(subscriptionSource_->hasLedger(31));
|
||||
EXPECT_FALSE(subscriptionSource_->hasLedger(789));
|
||||
EXPECT_FALSE(subscriptionSource_->hasLedger(790));
|
||||
EXPECT_FALSE(subscriptionSource_.hasLedger(123));
|
||||
EXPECT_FALSE(subscriptionSource_.hasLedger(124));
|
||||
EXPECT_FALSE(subscriptionSource_.hasLedger(455));
|
||||
EXPECT_FALSE(subscriptionSource_.hasLedger(456));
|
||||
EXPECT_FALSE(subscriptionSource_.hasLedger(457));
|
||||
EXPECT_FALSE(subscriptionSource_.hasLedger(32));
|
||||
EXPECT_FALSE(subscriptionSource_.hasLedger(31));
|
||||
EXPECT_FALSE(subscriptionSource_.hasLedger(789));
|
||||
EXPECT_FALSE(subscriptionSource_.hasLedger(790));
|
||||
|
||||
boost::asio::spawn(ioContext_, [this](boost::asio::yield_context yield) {
|
||||
auto connection = connectAndSendMessage(R"({"result":{"validated_ledgers":"123-456,789,32"}})", yield);
|
||||
@@ -245,20 +242,20 @@ TEST_F(SubscriptionSourceReadTests, GotResultWithValidatedLedgers)
|
||||
});
|
||||
|
||||
EXPECT_CALL(onConnectHook_, Call());
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_->stop(); });
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_.stop(); });
|
||||
ioContext_.run();
|
||||
|
||||
EXPECT_TRUE(subscriptionSource_->hasLedger(123));
|
||||
EXPECT_TRUE(subscriptionSource_->hasLedger(124));
|
||||
EXPECT_TRUE(subscriptionSource_->hasLedger(455));
|
||||
EXPECT_TRUE(subscriptionSource_->hasLedger(456));
|
||||
EXPECT_FALSE(subscriptionSource_->hasLedger(457));
|
||||
EXPECT_TRUE(subscriptionSource_->hasLedger(32));
|
||||
EXPECT_FALSE(subscriptionSource_->hasLedger(31));
|
||||
EXPECT_TRUE(subscriptionSource_->hasLedger(789));
|
||||
EXPECT_FALSE(subscriptionSource_->hasLedger(790));
|
||||
EXPECT_TRUE(subscriptionSource_.hasLedger(123));
|
||||
EXPECT_TRUE(subscriptionSource_.hasLedger(124));
|
||||
EXPECT_TRUE(subscriptionSource_.hasLedger(455));
|
||||
EXPECT_TRUE(subscriptionSource_.hasLedger(456));
|
||||
EXPECT_FALSE(subscriptionSource_.hasLedger(457));
|
||||
EXPECT_TRUE(subscriptionSource_.hasLedger(32));
|
||||
EXPECT_FALSE(subscriptionSource_.hasLedger(31));
|
||||
EXPECT_TRUE(subscriptionSource_.hasLedger(789));
|
||||
EXPECT_FALSE(subscriptionSource_.hasLedger(790));
|
||||
|
||||
EXPECT_EQ(subscriptionSource_->validatedRange(), "123-456,789,32");
|
||||
EXPECT_EQ(subscriptionSource_.validatedRange(), "123-456,789,32");
|
||||
}
|
||||
|
||||
TEST_F(SubscriptionSourceReadTests, GotResultWithValidatedLedgersWrongValue_Reconnect)
|
||||
@@ -271,17 +268,17 @@ TEST_F(SubscriptionSourceReadTests, GotResultWithValidatedLedgersWrongValue_Reco
|
||||
});
|
||||
|
||||
EXPECT_CALL(onConnectHook_, Call()).Times(2);
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([]() {}).WillOnce([this]() { subscriptionSource_->stop(); });
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([]() {}).WillOnce([this]() { subscriptionSource_.stop(); });
|
||||
ioContext_.run();
|
||||
}
|
||||
|
||||
TEST_F(SubscriptionSourceReadTests, GotResultWithLedgerIndexAndValidatedLedgers)
|
||||
{
|
||||
EXPECT_FALSE(subscriptionSource_->hasLedger(1));
|
||||
EXPECT_FALSE(subscriptionSource_->hasLedger(1));
|
||||
EXPECT_FALSE(subscriptionSource_->hasLedger(2));
|
||||
EXPECT_FALSE(subscriptionSource_->hasLedger(3));
|
||||
EXPECT_FALSE(subscriptionSource_->hasLedger(4));
|
||||
EXPECT_FALSE(subscriptionSource_.hasLedger(1));
|
||||
EXPECT_FALSE(subscriptionSource_.hasLedger(1));
|
||||
EXPECT_FALSE(subscriptionSource_.hasLedger(2));
|
||||
EXPECT_FALSE(subscriptionSource_.hasLedger(3));
|
||||
EXPECT_FALSE(subscriptionSource_.hasLedger(4));
|
||||
|
||||
boost::asio::spawn(ioContext_, [this](boost::asio::yield_context yield) {
|
||||
auto connection = connectAndSendMessage(R"({"result":{"ledger_index":123,"validated_ledgers":"1-3"}})", yield);
|
||||
@@ -289,16 +286,16 @@ TEST_F(SubscriptionSourceReadTests, GotResultWithLedgerIndexAndValidatedLedgers)
|
||||
});
|
||||
|
||||
EXPECT_CALL(onConnectHook_, Call());
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_->stop(); });
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_.stop(); });
|
||||
EXPECT_CALL(*networkValidatedLedgers_, push(123));
|
||||
ioContext_.run();
|
||||
|
||||
EXPECT_EQ(subscriptionSource_->validatedRange(), "1-3");
|
||||
EXPECT_FALSE(subscriptionSource_->hasLedger(0));
|
||||
EXPECT_TRUE(subscriptionSource_->hasLedger(1));
|
||||
EXPECT_TRUE(subscriptionSource_->hasLedger(2));
|
||||
EXPECT_TRUE(subscriptionSource_->hasLedger(3));
|
||||
EXPECT_FALSE(subscriptionSource_->hasLedger(4));
|
||||
EXPECT_EQ(subscriptionSource_.validatedRange(), "1-3");
|
||||
EXPECT_FALSE(subscriptionSource_.hasLedger(0));
|
||||
EXPECT_TRUE(subscriptionSource_.hasLedger(1));
|
||||
EXPECT_TRUE(subscriptionSource_.hasLedger(2));
|
||||
EXPECT_TRUE(subscriptionSource_.hasLedger(3));
|
||||
EXPECT_FALSE(subscriptionSource_.hasLedger(4));
|
||||
}
|
||||
|
||||
TEST_F(SubscriptionSourceReadTests, GotLedgerClosed)
|
||||
@@ -309,13 +306,13 @@ TEST_F(SubscriptionSourceReadTests, GotLedgerClosed)
|
||||
});
|
||||
|
||||
EXPECT_CALL(onConnectHook_, Call());
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_->stop(); });
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_.stop(); });
|
||||
ioContext_.run();
|
||||
}
|
||||
|
||||
TEST_F(SubscriptionSourceReadTests, GotLedgerClosedForwardingIsSet)
|
||||
{
|
||||
subscriptionSource_->setForwarding(true);
|
||||
subscriptionSource_.setForwarding(true);
|
||||
|
||||
boost::asio::spawn(ioContext_, [this](boost::asio::yield_context yield) {
|
||||
auto connection = connectAndSendMessage(R"({"type": "ledgerClosed"})", yield);
|
||||
@@ -324,7 +321,10 @@ TEST_F(SubscriptionSourceReadTests, GotLedgerClosedForwardingIsSet)
|
||||
|
||||
EXPECT_CALL(onConnectHook_, Call());
|
||||
EXPECT_CALL(onLedgerClosedHook_, Call());
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_->stop(); });
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() {
|
||||
EXPECT_FALSE(subscriptionSource_.isForwarding());
|
||||
subscriptionSource_.stop();
|
||||
});
|
||||
ioContext_.run();
|
||||
}
|
||||
|
||||
@@ -336,7 +336,7 @@ TEST_F(SubscriptionSourceReadTests, GotLedgerClosedWithLedgerIndex)
|
||||
});
|
||||
|
||||
EXPECT_CALL(onConnectHook_, Call());
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_->stop(); });
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_.stop(); });
|
||||
EXPECT_CALL(*networkValidatedLedgers_, push(123));
|
||||
ioContext_.run();
|
||||
}
|
||||
@@ -351,7 +351,7 @@ TEST_F(SubscriptionSourceReadTests, GotLedgerClosedWithLedgerIndexAsString_Recon
|
||||
});
|
||||
|
||||
EXPECT_CALL(onConnectHook_, Call()).Times(2);
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([]() {}).WillOnce([this]() { subscriptionSource_->stop(); });
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([]() {}).WillOnce([this]() { subscriptionSource_.stop(); });
|
||||
ioContext_.run();
|
||||
}
|
||||
|
||||
@@ -365,16 +365,16 @@ TEST_F(SubscriptionSourceReadTests, GorLedgerClosedWithValidatedLedgersAsNumber_
|
||||
});
|
||||
|
||||
EXPECT_CALL(onConnectHook_, Call()).Times(2);
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([]() {}).WillOnce([this]() { subscriptionSource_->stop(); });
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([]() {}).WillOnce([this]() { subscriptionSource_.stop(); });
|
||||
ioContext_.run();
|
||||
}
|
||||
|
||||
TEST_F(SubscriptionSourceReadTests, GotLedgerClosedWithValidatedLedgers)
|
||||
{
|
||||
EXPECT_FALSE(subscriptionSource_->hasLedger(0));
|
||||
EXPECT_FALSE(subscriptionSource_->hasLedger(1));
|
||||
EXPECT_FALSE(subscriptionSource_->hasLedger(2));
|
||||
EXPECT_FALSE(subscriptionSource_->hasLedger(3));
|
||||
EXPECT_FALSE(subscriptionSource_.hasLedger(0));
|
||||
EXPECT_FALSE(subscriptionSource_.hasLedger(1));
|
||||
EXPECT_FALSE(subscriptionSource_.hasLedger(2));
|
||||
EXPECT_FALSE(subscriptionSource_.hasLedger(3));
|
||||
|
||||
boost::asio::spawn(ioContext_, [this](boost::asio::yield_context yield) {
|
||||
auto connection = connectAndSendMessage(R"({"type":"ledgerClosed","validated_ledgers":"1-2"})", yield);
|
||||
@@ -382,22 +382,22 @@ TEST_F(SubscriptionSourceReadTests, GotLedgerClosedWithValidatedLedgers)
|
||||
});
|
||||
|
||||
EXPECT_CALL(onConnectHook_, Call());
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_->stop(); });
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_.stop(); });
|
||||
ioContext_.run();
|
||||
|
||||
EXPECT_FALSE(subscriptionSource_->hasLedger(0));
|
||||
EXPECT_TRUE(subscriptionSource_->hasLedger(1));
|
||||
EXPECT_TRUE(subscriptionSource_->hasLedger(2));
|
||||
EXPECT_FALSE(subscriptionSource_->hasLedger(3));
|
||||
EXPECT_EQ(subscriptionSource_->validatedRange(), "1-2");
|
||||
EXPECT_FALSE(subscriptionSource_.hasLedger(0));
|
||||
EXPECT_TRUE(subscriptionSource_.hasLedger(1));
|
||||
EXPECT_TRUE(subscriptionSource_.hasLedger(2));
|
||||
EXPECT_FALSE(subscriptionSource_.hasLedger(3));
|
||||
EXPECT_EQ(subscriptionSource_.validatedRange(), "1-2");
|
||||
}
|
||||
|
||||
TEST_F(SubscriptionSourceReadTests, GotLedgerClosedWithLedgerIndexAndValidatedLedgers)
|
||||
{
|
||||
EXPECT_FALSE(subscriptionSource_->hasLedger(0));
|
||||
EXPECT_FALSE(subscriptionSource_->hasLedger(1));
|
||||
EXPECT_FALSE(subscriptionSource_->hasLedger(2));
|
||||
EXPECT_FALSE(subscriptionSource_->hasLedger(3));
|
||||
EXPECT_FALSE(subscriptionSource_.hasLedger(0));
|
||||
EXPECT_FALSE(subscriptionSource_.hasLedger(1));
|
||||
EXPECT_FALSE(subscriptionSource_.hasLedger(2));
|
||||
EXPECT_FALSE(subscriptionSource_.hasLedger(3));
|
||||
|
||||
boost::asio::spawn(ioContext_, [this](boost::asio::yield_context yield) {
|
||||
auto connection =
|
||||
@@ -406,15 +406,15 @@ TEST_F(SubscriptionSourceReadTests, GotLedgerClosedWithLedgerIndexAndValidatedLe
|
||||
});
|
||||
|
||||
EXPECT_CALL(onConnectHook_, Call());
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_->stop(); });
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_.stop(); });
|
||||
EXPECT_CALL(*networkValidatedLedgers_, push(123));
|
||||
ioContext_.run();
|
||||
|
||||
EXPECT_FALSE(subscriptionSource_->hasLedger(0));
|
||||
EXPECT_TRUE(subscriptionSource_->hasLedger(1));
|
||||
EXPECT_TRUE(subscriptionSource_->hasLedger(2));
|
||||
EXPECT_FALSE(subscriptionSource_->hasLedger(3));
|
||||
EXPECT_EQ(subscriptionSource_->validatedRange(), "1-2");
|
||||
EXPECT_FALSE(subscriptionSource_.hasLedger(0));
|
||||
EXPECT_TRUE(subscriptionSource_.hasLedger(1));
|
||||
EXPECT_TRUE(subscriptionSource_.hasLedger(2));
|
||||
EXPECT_FALSE(subscriptionSource_.hasLedger(3));
|
||||
EXPECT_EQ(subscriptionSource_.validatedRange(), "1-2");
|
||||
}
|
||||
|
||||
TEST_F(SubscriptionSourceReadTests, GotTransactionIsForwardingFalse)
|
||||
@@ -425,13 +425,13 @@ TEST_F(SubscriptionSourceReadTests, GotTransactionIsForwardingFalse)
|
||||
});
|
||||
|
||||
EXPECT_CALL(onConnectHook_, Call());
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_->stop(); });
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_.stop(); });
|
||||
ioContext_.run();
|
||||
}
|
||||
|
||||
TEST_F(SubscriptionSourceReadTests, GotTransactionIsForwardingTrue)
|
||||
{
|
||||
subscriptionSource_->setForwarding(true);
|
||||
subscriptionSource_.setForwarding(true);
|
||||
boost::json::object const message = {{"transaction", "some_transaction_data"}};
|
||||
|
||||
boost::asio::spawn(ioContext_, [&message, this](boost::asio::yield_context yield) {
|
||||
@@ -440,7 +440,7 @@ TEST_F(SubscriptionSourceReadTests, GotTransactionIsForwardingTrue)
|
||||
});
|
||||
|
||||
EXPECT_CALL(onConnectHook_, Call());
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_->stop(); });
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_.stop(); });
|
||||
EXPECT_CALL(*subscriptionManager_, forwardProposedTransaction(message));
|
||||
ioContext_.run();
|
||||
}
|
||||
@@ -453,13 +453,13 @@ TEST_F(SubscriptionSourceReadTests, GotValidationReceivedIsForwardingFalse)
|
||||
});
|
||||
|
||||
EXPECT_CALL(onConnectHook_, Call());
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_->stop(); });
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_.stop(); });
|
||||
ioContext_.run();
|
||||
}
|
||||
|
||||
TEST_F(SubscriptionSourceReadTests, GotValidationReceivedIsForwardingTrue)
|
||||
{
|
||||
subscriptionSource_->setForwarding(true);
|
||||
subscriptionSource_.setForwarding(true);
|
||||
boost::json::object const message = {{"type", "validationReceived"}};
|
||||
|
||||
boost::asio::spawn(ioContext_, [&message, this](boost::asio::yield_context yield) {
|
||||
@@ -468,7 +468,7 @@ TEST_F(SubscriptionSourceReadTests, GotValidationReceivedIsForwardingTrue)
|
||||
});
|
||||
|
||||
EXPECT_CALL(onConnectHook_, Call());
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_->stop(); });
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_.stop(); });
|
||||
EXPECT_CALL(*subscriptionManager_, forwardValidation(message));
|
||||
ioContext_.run();
|
||||
}
|
||||
@@ -481,13 +481,13 @@ TEST_F(SubscriptionSourceReadTests, GotManiefstReceivedIsForwardingFalse)
|
||||
});
|
||||
|
||||
EXPECT_CALL(onConnectHook_, Call());
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_->stop(); });
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_.stop(); });
|
||||
ioContext_.run();
|
||||
}
|
||||
|
||||
TEST_F(SubscriptionSourceReadTests, GotManifestReceivedIsForwardingTrue)
|
||||
{
|
||||
subscriptionSource_->setForwarding(true);
|
||||
subscriptionSource_.setForwarding(true);
|
||||
boost::json::object const message = {{"type", "manifestReceived"}};
|
||||
|
||||
boost::asio::spawn(ioContext_, [&message, this](boost::asio::yield_context yield) {
|
||||
@@ -496,7 +496,7 @@ TEST_F(SubscriptionSourceReadTests, GotManifestReceivedIsForwardingTrue)
|
||||
});
|
||||
|
||||
EXPECT_CALL(onConnectHook_, Call());
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_->stop(); });
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_.stop(); });
|
||||
EXPECT_CALL(*subscriptionManager_, forwardManifest(message));
|
||||
ioContext_.run();
|
||||
}
|
||||
@@ -509,10 +509,10 @@ TEST_F(SubscriptionSourceReadTests, LastMessageTime)
|
||||
});
|
||||
|
||||
EXPECT_CALL(onConnectHook_, Call());
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_->stop(); });
|
||||
EXPECT_CALL(onDisconnectHook_, Call()).WillOnce([this]() { subscriptionSource_.stop(); });
|
||||
ioContext_.run();
|
||||
|
||||
auto const actualLastTimeMessage = subscriptionSource_->lastMessageTime();
|
||||
auto const actualLastTimeMessage = subscriptionSource_.lastMessageTime();
|
||||
auto const now = std::chrono::steady_clock::now();
|
||||
auto const diff = std::chrono::duration_cast<std::chrono::milliseconds>(now - actualLastTimeMessage);
|
||||
EXPECT_LT(diff, std::chrono::milliseconds(100));
|
||||
|
||||
@@ -67,7 +67,6 @@ struct ETLTransformerTest : util::prometheus::WithPrometheus, MockBackendTest {
|
||||
void
|
||||
SetUp() override
|
||||
{
|
||||
MockBackendTest::SetUp();
|
||||
state_.isStopping = false;
|
||||
state_.writeConflict = false;
|
||||
state_.isReadOnly = false;
|
||||
@@ -78,7 +77,6 @@ struct ETLTransformerTest : util::prometheus::WithPrometheus, MockBackendTest {
|
||||
TearDown() override
|
||||
{
|
||||
transformer_.reset();
|
||||
MockBackendTest::TearDown();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -64,7 +64,6 @@ protected:
|
||||
void
|
||||
SetUp() override
|
||||
{
|
||||
MockBackendTest::SetUp();
|
||||
SyncAsioContextTest::SetUp();
|
||||
SubscriptionManagerPtr = std::make_shared<SubscriptionManager>(ctx, backend);
|
||||
session = std::make_shared<MockSession>();
|
||||
@@ -78,7 +77,6 @@ protected:
|
||||
session.reset();
|
||||
SubscriptionManagerPtr.reset();
|
||||
SyncAsioContextTest::TearDown();
|
||||
MockBackendTest::TearDown();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -62,13 +62,11 @@ class RPCHelpersTest : public util::prometheus::WithPrometheus, public MockBacke
|
||||
void
|
||||
SetUp() override
|
||||
{
|
||||
MockBackendTest::SetUp();
|
||||
SyncAsioContextTest::SetUp();
|
||||
}
|
||||
void
|
||||
TearDown() override
|
||||
{
|
||||
MockBackendTest::TearDown();
|
||||
SyncAsioContextTest::TearDown();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -43,23 +43,19 @@ using namespace rpc;
|
||||
namespace json = boost::json;
|
||||
using namespace testing;
|
||||
|
||||
using TestServerInfoHandler =
|
||||
BaseServerInfoHandler<MockSubscriptionManager, MockLoadBalancer, MockETLService, MockCounters>;
|
||||
using TestServerInfoHandler = BaseServerInfoHandler<MockLoadBalancer, MockETLService, MockCounters>;
|
||||
|
||||
constexpr static auto LEDGERHASH = "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652";
|
||||
constexpr static auto CLIENTIP = "1.1.1.1";
|
||||
|
||||
class RPCServerInfoHandlerTest : public HandlerBaseTest,
|
||||
public MockLoadBalancerTest,
|
||||
public MockSubscriptionManagerTest,
|
||||
public MockCountersTest {
|
||||
protected:
|
||||
struct RPCServerInfoHandlerTest : HandlerBaseTest, MockLoadBalancerTest, MockCountersTest {
|
||||
StrictMockSubscriptionManagerSharedPtr mockSubscriptionManagerPtr;
|
||||
|
||||
void
|
||||
SetUp() override
|
||||
{
|
||||
HandlerBaseTest::SetUp();
|
||||
MockLoadBalancerTest::SetUp();
|
||||
MockSubscriptionManagerTest::SetUp();
|
||||
MockCountersTest::SetUp();
|
||||
|
||||
backend->setRange(10, 30);
|
||||
@@ -69,7 +65,6 @@ protected:
|
||||
TearDown() override
|
||||
{
|
||||
MockCountersTest::TearDown();
|
||||
MockSubscriptionManagerTest::TearDown();
|
||||
MockLoadBalancerTest::TearDown();
|
||||
HandlerBaseTest::TearDown();
|
||||
}
|
||||
@@ -341,7 +336,6 @@ TEST_F(RPCServerInfoHandlerTest, AdminSectionPresentWhenAdminFlagIsSet)
|
||||
{
|
||||
MockLoadBalancer* rawBalancerPtr = mockLoadBalancerPtr.get();
|
||||
MockCounters* rawCountersPtr = mockCountersPtr.get();
|
||||
MockSubscriptionManager* rawSubscriptionManagerPtr = mockSubscriptionManagerPtr.get();
|
||||
MockETLService* rawETLServicePtr = mockETLServicePtr.get();
|
||||
|
||||
auto const empty = json::object{};
|
||||
@@ -360,7 +354,7 @@ TEST_F(RPCServerInfoHandlerTest, AdminSectionPresentWhenAdminFlagIsSet)
|
||||
// admin calls
|
||||
EXPECT_CALL(*rawCountersPtr, report).WillOnce(Return(empty));
|
||||
|
||||
EXPECT_CALL(*rawSubscriptionManagerPtr, report).WillOnce(Return(empty));
|
||||
EXPECT_CALL(*mockSubscriptionManagerPtr, report).WillOnce(Return(empty));
|
||||
|
||||
EXPECT_CALL(*rawETLServicePtr, getInfo).WillOnce(Return(empty));
|
||||
|
||||
@@ -381,7 +375,6 @@ TEST_F(RPCServerInfoHandlerTest, BackendCountersPresentWhenRequestWithParam)
|
||||
{
|
||||
MockLoadBalancer* rawBalancerPtr = mockLoadBalancerPtr.get();
|
||||
MockCounters* rawCountersPtr = mockCountersPtr.get();
|
||||
MockSubscriptionManager* rawSubscriptionManagerPtr = mockSubscriptionManagerPtr.get();
|
||||
MockETLService* rawETLServicePtr = mockETLServicePtr.get();
|
||||
|
||||
auto const empty = json::object{};
|
||||
@@ -400,7 +393,7 @@ TEST_F(RPCServerInfoHandlerTest, BackendCountersPresentWhenRequestWithParam)
|
||||
// admin calls
|
||||
EXPECT_CALL(*rawCountersPtr, report).WillOnce(Return(empty));
|
||||
|
||||
EXPECT_CALL(*rawSubscriptionManagerPtr, report).WillOnce(Return(empty));
|
||||
EXPECT_CALL(*mockSubscriptionManagerPtr, report).WillOnce(Return(empty));
|
||||
|
||||
EXPECT_CALL(*rawETLServicePtr, getInfo).WillOnce(Return(empty));
|
||||
|
||||
@@ -427,7 +420,6 @@ TEST_F(RPCServerInfoHandlerTest, RippledForwardedValuesPresent)
|
||||
{
|
||||
MockLoadBalancer* rawBalancerPtr = mockLoadBalancerPtr.get();
|
||||
MockCounters* rawCountersPtr = mockCountersPtr.get();
|
||||
MockSubscriptionManager* rawSubscriptionManagerPtr = mockSubscriptionManagerPtr.get();
|
||||
MockETLService* rawETLServicePtr = mockETLServicePtr.get();
|
||||
|
||||
auto const empty = json::object{};
|
||||
@@ -456,7 +448,7 @@ TEST_F(RPCServerInfoHandlerTest, RippledForwardedValuesPresent)
|
||||
// admin calls
|
||||
EXPECT_CALL(*rawCountersPtr, report).WillOnce(Return(empty));
|
||||
|
||||
EXPECT_CALL(*rawSubscriptionManagerPtr, report).WillOnce(Return(empty));
|
||||
EXPECT_CALL(*mockSubscriptionManagerPtr, report).WillOnce(Return(empty));
|
||||
|
||||
EXPECT_CALL(*rawETLServicePtr, getInfo).WillOnce(Return(empty));
|
||||
|
||||
@@ -478,7 +470,6 @@ TEST_F(RPCServerInfoHandlerTest, RippledForwardedValuesMissingNoExceptionThrown)
|
||||
{
|
||||
MockLoadBalancer* rawBalancerPtr = mockLoadBalancerPtr.get();
|
||||
MockCounters* rawCountersPtr = mockCountersPtr.get();
|
||||
MockSubscriptionManager* rawSubscriptionManagerPtr = mockSubscriptionManagerPtr.get();
|
||||
MockETLService* rawETLServicePtr = mockETLServicePtr.get();
|
||||
|
||||
auto const empty = json::object{};
|
||||
@@ -502,7 +493,7 @@ TEST_F(RPCServerInfoHandlerTest, RippledForwardedValuesMissingNoExceptionThrown)
|
||||
// admin calls
|
||||
EXPECT_CALL(*rawCountersPtr, report).WillOnce(Return(empty));
|
||||
|
||||
EXPECT_CALL(*rawSubscriptionManagerPtr, report).WillOnce(Return(empty));
|
||||
EXPECT_CALL(*mockSubscriptionManagerPtr, report).WillOnce(Return(empty));
|
||||
|
||||
EXPECT_CALL(*rawETLServicePtr, getInfo).WillOnce(Return(empty));
|
||||
|
||||
|
||||
@@ -44,29 +44,25 @@ namespace json = boost::json;
|
||||
using namespace testing;
|
||||
using namespace feed;
|
||||
|
||||
using TestUnsubscribeHandler = BaseUnsubscribeHandler<MockSubscriptionManager>;
|
||||
|
||||
constexpr static auto ACCOUNT = "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn";
|
||||
constexpr static auto ACCOUNT2 = "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun";
|
||||
|
||||
class RPCUnsubscribeTest : public HandlerBaseTest, public MockSubscriptionManagerTest {
|
||||
protected:
|
||||
struct RPCUnsubscribeTest : HandlerBaseTest {
|
||||
void
|
||||
SetUp() override
|
||||
{
|
||||
HandlerBaseTest::SetUp();
|
||||
MockSubscriptionManagerTest::SetUp();
|
||||
session_ = std::make_shared<MockSession>();
|
||||
}
|
||||
void
|
||||
TearDown() override
|
||||
{
|
||||
MockSubscriptionManagerTest::TearDown();
|
||||
HandlerBaseTest::TearDown();
|
||||
}
|
||||
|
||||
std::shared_ptr<feed::SubscriptionManager> subManager_;
|
||||
std::shared_ptr<web::ConnectionBase> session_;
|
||||
StrictMockSubscriptionManagerSharedPtr mockSubscriptionManagerPtr;
|
||||
};
|
||||
|
||||
struct UnsubscribeParamTestCaseBundle {
|
||||
@@ -530,7 +526,7 @@ TEST_P(UnsubscribeParameterTest, InvalidParams)
|
||||
{
|
||||
auto const testBundle = GetParam();
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{TestUnsubscribeHandler{backend, mockSubscriptionManagerPtr}};
|
||||
auto const handler = AnyHandler{UnsubscribeHandler{backend, mockSubscriptionManagerPtr}};
|
||||
auto const req = json::parse(testBundle.testJson);
|
||||
auto const output = handler.process(req, Context{yield});
|
||||
ASSERT_FALSE(output);
|
||||
@@ -543,7 +539,7 @@ TEST_P(UnsubscribeParameterTest, InvalidParams)
|
||||
TEST_F(RPCUnsubscribeTest, EmptyResponse)
|
||||
{
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{TestUnsubscribeHandler{backend, mockSubscriptionManagerPtr}};
|
||||
auto const handler = AnyHandler{UnsubscribeHandler{backend, mockSubscriptionManagerPtr}};
|
||||
auto const output = handler.process(json::parse(R"({})"), Context{yield, session_});
|
||||
ASSERT_TRUE(output);
|
||||
EXPECT_TRUE(output.result->as_object().empty());
|
||||
@@ -558,16 +554,15 @@ TEST_F(RPCUnsubscribeTest, Streams)
|
||||
})"
|
||||
);
|
||||
|
||||
MockSubscriptionManager* rawSubscriptionManagerPtr = mockSubscriptionManagerPtr.get();
|
||||
EXPECT_CALL(*rawSubscriptionManagerPtr, unsubLedger).Times(1);
|
||||
EXPECT_CALL(*rawSubscriptionManagerPtr, unsubTransactions).Times(1);
|
||||
EXPECT_CALL(*rawSubscriptionManagerPtr, unsubValidation).Times(1);
|
||||
EXPECT_CALL(*rawSubscriptionManagerPtr, unsubManifest).Times(1);
|
||||
EXPECT_CALL(*rawSubscriptionManagerPtr, unsubBookChanges).Times(1);
|
||||
EXPECT_CALL(*rawSubscriptionManagerPtr, unsubProposedTransactions).Times(1);
|
||||
EXPECT_CALL(*mockSubscriptionManagerPtr, unsubLedger).Times(1);
|
||||
EXPECT_CALL(*mockSubscriptionManagerPtr, unsubTransactions).Times(1);
|
||||
EXPECT_CALL(*mockSubscriptionManagerPtr, unsubValidation).Times(1);
|
||||
EXPECT_CALL(*mockSubscriptionManagerPtr, unsubManifest).Times(1);
|
||||
EXPECT_CALL(*mockSubscriptionManagerPtr, unsubBookChanges).Times(1);
|
||||
EXPECT_CALL(*mockSubscriptionManagerPtr, unsubProposedTransactions).Times(1);
|
||||
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{TestUnsubscribeHandler{backend, mockSubscriptionManagerPtr}};
|
||||
auto const handler = AnyHandler{UnsubscribeHandler{backend, mockSubscriptionManagerPtr}};
|
||||
auto const output = handler.process(input, Context{yield, session_});
|
||||
ASSERT_TRUE(output);
|
||||
EXPECT_TRUE(output.result->as_object().empty());
|
||||
@@ -584,12 +579,11 @@ TEST_F(RPCUnsubscribeTest, Accounts)
|
||||
ACCOUNT2
|
||||
));
|
||||
|
||||
MockSubscriptionManager* rawSubscriptionManagerPtr = mockSubscriptionManagerPtr.get();
|
||||
EXPECT_CALL(*rawSubscriptionManagerPtr, unsubAccount(rpc::accountFromStringStrict(ACCOUNT).value(), _)).Times(1);
|
||||
EXPECT_CALL(*rawSubscriptionManagerPtr, unsubAccount(rpc::accountFromStringStrict(ACCOUNT2).value(), _)).Times(1);
|
||||
EXPECT_CALL(*mockSubscriptionManagerPtr, unsubAccount(rpc::accountFromStringStrict(ACCOUNT).value(), _)).Times(1);
|
||||
EXPECT_CALL(*mockSubscriptionManagerPtr, unsubAccount(rpc::accountFromStringStrict(ACCOUNT2).value(), _)).Times(1);
|
||||
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{TestUnsubscribeHandler{backend, mockSubscriptionManagerPtr}};
|
||||
auto const handler = AnyHandler{UnsubscribeHandler{backend, mockSubscriptionManagerPtr}};
|
||||
auto const output = handler.process(input, Context{yield, session_});
|
||||
ASSERT_TRUE(output);
|
||||
EXPECT_TRUE(output.result->as_object().empty());
|
||||
@@ -606,14 +600,13 @@ TEST_F(RPCUnsubscribeTest, AccountsProposed)
|
||||
ACCOUNT2
|
||||
));
|
||||
|
||||
MockSubscriptionManager* rawSubscriptionManagerPtr = mockSubscriptionManagerPtr.get();
|
||||
EXPECT_CALL(*rawSubscriptionManagerPtr, unsubProposedAccount(rpc::accountFromStringStrict(ACCOUNT).value(), _))
|
||||
EXPECT_CALL(*mockSubscriptionManagerPtr, unsubProposedAccount(rpc::accountFromStringStrict(ACCOUNT).value(), _))
|
||||
.Times(1);
|
||||
EXPECT_CALL(*rawSubscriptionManagerPtr, unsubProposedAccount(rpc::accountFromStringStrict(ACCOUNT2).value(), _))
|
||||
EXPECT_CALL(*mockSubscriptionManagerPtr, unsubProposedAccount(rpc::accountFromStringStrict(ACCOUNT2).value(), _))
|
||||
.Times(1);
|
||||
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{TestUnsubscribeHandler{backend, mockSubscriptionManagerPtr}};
|
||||
auto const handler = AnyHandler{UnsubscribeHandler{backend, mockSubscriptionManagerPtr}};
|
||||
auto const output = handler.process(input, Context{yield, session_});
|
||||
ASSERT_TRUE(output);
|
||||
EXPECT_TRUE(output.result->as_object().empty());
|
||||
@@ -643,12 +636,11 @@ TEST_F(RPCUnsubscribeTest, Books)
|
||||
auto const parsedBookMaybe = rpc::parseBook(input.as_object().at("books").as_array()[0].as_object());
|
||||
auto const book = std::get<ripple::Book>(parsedBookMaybe);
|
||||
|
||||
MockSubscriptionManager* rawSubscriptionManagerPtr = mockSubscriptionManagerPtr.get();
|
||||
EXPECT_CALL(*rawSubscriptionManagerPtr, unsubBook(book, _)).Times(1);
|
||||
EXPECT_CALL(*rawSubscriptionManagerPtr, unsubBook(ripple::reversed(book), _)).Times(1);
|
||||
EXPECT_CALL(*mockSubscriptionManagerPtr, unsubBook(book, _)).Times(1);
|
||||
EXPECT_CALL(*mockSubscriptionManagerPtr, unsubBook(ripple::reversed(book), _)).Times(1);
|
||||
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{TestUnsubscribeHandler{backend, mockSubscriptionManagerPtr}};
|
||||
auto const handler = AnyHandler{UnsubscribeHandler{backend, mockSubscriptionManagerPtr}};
|
||||
auto const output = handler.process(input, Context{yield, session_});
|
||||
ASSERT_TRUE(output);
|
||||
EXPECT_TRUE(output.result->as_object().empty());
|
||||
@@ -677,11 +669,10 @@ TEST_F(RPCUnsubscribeTest, SingleBooks)
|
||||
auto const parsedBookMaybe = rpc::parseBook(input.as_object().at("books").as_array()[0].as_object());
|
||||
auto const book = std::get<ripple::Book>(parsedBookMaybe);
|
||||
|
||||
MockSubscriptionManager* rawSubscriptionManagerPtr = mockSubscriptionManagerPtr.get();
|
||||
EXPECT_CALL(*rawSubscriptionManagerPtr, unsubBook(book, _)).Times(1);
|
||||
EXPECT_CALL(*mockSubscriptionManagerPtr, unsubBook(book, _)).Times(1);
|
||||
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{TestUnsubscribeHandler{backend, mockSubscriptionManagerPtr}};
|
||||
auto const handler = AnyHandler{UnsubscribeHandler{backend, mockSubscriptionManagerPtr}};
|
||||
auto const output = handler.process(input, Context{yield, session_});
|
||||
ASSERT_TRUE(output);
|
||||
EXPECT_TRUE(output.result->as_object().empty());
|
||||
|
||||
62
tests/unit/util/RandomTests.cpp
Normal file
62
tests/unit/util/RandomTests.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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/Random.hpp"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
|
||||
using namespace util;
|
||||
|
||||
struct RandomTests : public ::testing::Test {
|
||||
static std::vector<int>
|
||||
generateRandoms(size_t const numRandoms = 1000)
|
||||
{
|
||||
std::vector<int> v;
|
||||
v.reserve(numRandoms);
|
||||
std::ranges::generate_n(std::back_inserter(v), numRandoms, []() { return Random::uniform(0, 1000); });
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(RandomTests, Uniform)
|
||||
{
|
||||
std::ranges::for_each(generateRandoms(), [](int const& e) {
|
||||
EXPECT_GE(e, 0);
|
||||
EXPECT_LE(e, 1000);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(RandomTests, FixedSeed)
|
||||
{
|
||||
Random::setSeed(42);
|
||||
std::vector<int> const v1 = generateRandoms();
|
||||
|
||||
Random::setSeed(42);
|
||||
std::vector<int> const v2 = generateRandoms();
|
||||
|
||||
ASSERT_EQ(v1.size(), v2.size());
|
||||
for (size_t i = 0; i < v1.size(); ++i) {
|
||||
EXPECT_EQ(v1[i], v2[i]);
|
||||
};
|
||||
}
|
||||
@@ -66,15 +66,10 @@ struct MockWsBase : public web::ConnectionBase {
|
||||
}
|
||||
};
|
||||
|
||||
class WebRPCServerHandlerTest : public util::prometheus::WithPrometheus,
|
||||
public MockBackendTest,
|
||||
public SyncAsioContextTest {
|
||||
protected:
|
||||
struct WebRPCServerHandlerTest : util::prometheus::WithPrometheus, MockBackendTest, SyncAsioContextTest {
|
||||
void
|
||||
SetUp() override
|
||||
{
|
||||
MockBackendTest::SetUp();
|
||||
|
||||
etl = std::make_shared<MockETLService>();
|
||||
rpcEngine = std::make_shared<MockAsyncRPCEngine>();
|
||||
tagFactory = std::make_shared<util::TagDecoratorFactory>(cfg);
|
||||
@@ -82,12 +77,6 @@ protected:
|
||||
handler = std::make_shared<RPCServerHandler<MockAsyncRPCEngine, MockETLService>>(cfg, backend, rpcEngine, etl);
|
||||
}
|
||||
|
||||
void
|
||||
TearDown() override
|
||||
{
|
||||
MockBackendTest::TearDown();
|
||||
}
|
||||
|
||||
std::shared_ptr<MockAsyncRPCEngine> rpcEngine;
|
||||
std::shared_ptr<MockETLService> etl;
|
||||
std::shared_ptr<util::TagDecoratorFactory> tagFactory;
|
||||
|
||||
Reference in New Issue
Block a user