mirror of
https://github.com/XRPLF/clio.git
synced 2025-12-06 17:27:58 +00:00
@@ -195,6 +195,13 @@ TEST_F(ConfigTest, Array)
|
||||
ASSERT_TRUE(exp.empty());
|
||||
}
|
||||
|
||||
TEST_F(ConfigTest, toMilliseconds)
|
||||
{
|
||||
EXPECT_EQ(Config::toMilliseconds(0.0f).count(), 0);
|
||||
EXPECT_EQ(Config::toMilliseconds(0.123f).count(), 123);
|
||||
EXPECT_EQ(Config::toMilliseconds(3.45f).count(), 3450);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Simple custom data type with json parsing support
|
||||
*/
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
@@ -37,7 +38,7 @@ using namespace etl::impl;
|
||||
|
||||
struct ForwardingSourceTests : SyncAsioContextTest {
|
||||
TestWsServer server_{ctx, "0.0.0.0", 11114};
|
||||
ForwardingSource forwardingSource{"127.0.0.1", "11114", std::chrono::milliseconds{1}};
|
||||
ForwardingSource forwardingSource{"127.0.0.1", "11114", std::chrono::milliseconds{1}, std::chrono::milliseconds{1}};
|
||||
};
|
||||
|
||||
TEST_F(ForwardingSourceTests, ConnectionFailed)
|
||||
@@ -101,6 +102,19 @@ TEST_F(ForwardingSourceOperationsTests, ReadFailed)
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(ForwardingSourceOperationsTests, ReadTimeout)
|
||||
{
|
||||
TestWsConnectionPtr connection;
|
||||
boost::asio::spawn(ctx, [&](boost::asio::yield_context yield) {
|
||||
connection = std::make_unique<TestWsConnection>(serverConnection(yield));
|
||||
});
|
||||
|
||||
runSpawn([&](boost::asio::yield_context yield) {
|
||||
auto result = forwardingSource.forwardToRippled(boost::json::parse(message_).as_object(), {}, {}, yield);
|
||||
EXPECT_FALSE(result);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(ForwardingSourceOperationsTests, ParseFailed)
|
||||
{
|
||||
boost::asio::spawn(ctx, [&](boost::asio::yield_context yield) {
|
||||
|
||||
@@ -66,15 +66,40 @@ struct LoadBalancerConstructorTests : util::prometheus::WithPrometheus, MockBack
|
||||
backend,
|
||||
subscriptionManager_,
|
||||
networkManager_,
|
||||
[this](auto&&... args) -> SourcePtr {
|
||||
return sourceFactory_.makeSourceMock(std::forward<decltype(args)>(args)...);
|
||||
}
|
||||
[this](auto&&... args) -> SourcePtr { return sourceFactory_(std::forward<decltype(args)>(args)...); }
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(LoadBalancerConstructorTests, construct)
|
||||
{
|
||||
EXPECT_CALL(sourceFactory_, makeSource).Times(2);
|
||||
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, forwardingTimeoutPassedToSourceFactory)
|
||||
{
|
||||
auto const forwardingTimeout = 10;
|
||||
configJson_.as_object()["forwarding"] = boost::json::object{{"timeout", float{forwardingTimeout}}};
|
||||
EXPECT_CALL(
|
||||
sourceFactory_,
|
||||
makeSource(
|
||||
testing::_,
|
||||
testing::_,
|
||||
testing::_,
|
||||
testing::_,
|
||||
testing::_,
|
||||
std::chrono::steady_clock::duration{std::chrono::seconds{forwardingTimeout}},
|
||||
testing::_,
|
||||
testing::_,
|
||||
testing::_
|
||||
)
|
||||
)
|
||||
.Times(2);
|
||||
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{}));
|
||||
@@ -84,6 +109,7 @@ TEST_F(LoadBalancerConstructorTests, construct)
|
||||
|
||||
TEST_F(LoadBalancerConstructorTests, fetchETLState_Source0Fails)
|
||||
{
|
||||
EXPECT_CALL(sourceFactory_, makeSource).Times(1);
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), forwardToRippled).WillOnce(Return(std::nullopt));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), toString);
|
||||
EXPECT_THROW({ makeLoadBalancer(); }, std::logic_error);
|
||||
@@ -91,6 +117,7 @@ TEST_F(LoadBalancerConstructorTests, fetchETLState_Source0Fails)
|
||||
|
||||
TEST_F(LoadBalancerConstructorTests, fetchETLState_Source0ReturnsError)
|
||||
{
|
||||
EXPECT_CALL(sourceFactory_, makeSource).Times(1);
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), forwardToRippled)
|
||||
.WillOnce(Return(boost::json::object{{"error", "some error"}}));
|
||||
EXPECT_CALL(sourceFactory_.sourceAt(0), toString);
|
||||
@@ -99,6 +126,7 @@ TEST_F(LoadBalancerConstructorTests, fetchETLState_Source0ReturnsError)
|
||||
|
||||
TEST_F(LoadBalancerConstructorTests, fetchETLState_Source1Fails)
|
||||
{
|
||||
EXPECT_CALL(sourceFactory_, makeSource).Times(2);
|
||||
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);
|
||||
@@ -110,6 +138,7 @@ 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_, makeSource).Times(2);
|
||||
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);
|
||||
@@ -117,6 +146,7 @@ TEST_F(LoadBalancerConstructorTests, fetchETLState_DifferentNetworkID)
|
||||
|
||||
TEST_F(LoadBalancerConstructorTests, fetchETLState_Source1FailsButAllowNoEtlIsTrue)
|
||||
{
|
||||
EXPECT_CALL(sourceFactory_, makeSource).Times(2);
|
||||
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));
|
||||
@@ -131,6 +161,7 @@ TEST_F(LoadBalancerConstructorTests, fetchETLState_DifferentNetworkIDButAllowNoE
|
||||
{
|
||||
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_, makeSource).Times(2);
|
||||
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()));
|
||||
@@ -152,6 +183,7 @@ TEST_F(LoadBalancerConstructorDeathTest, numMarkersSpecifiedInConfigIsInvalid)
|
||||
struct LoadBalancerOnConnectHookTests : LoadBalancerConstructorTests {
|
||||
LoadBalancerOnConnectHookTests()
|
||||
{
|
||||
EXPECT_CALL(sourceFactory_, makeSource).Times(2);
|
||||
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{}));
|
||||
@@ -280,8 +312,9 @@ TEST_F(LoadBalancerOnConnectHookTests, bothSourcesDisconnectAndConnectBack)
|
||||
struct LoadBalancer3SourcesTests : LoadBalancerConstructorTests {
|
||||
LoadBalancer3SourcesTests()
|
||||
{
|
||||
sourceFactory_ = StrictMockSourceFactory{3};
|
||||
sourceFactory_.setSourcesNumber(3);
|
||||
configJson_.as_object()["etl_sources"] = {"source1", "source2", "source3"};
|
||||
EXPECT_CALL(sourceFactory_, makeSource).Times(3);
|
||||
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{}));
|
||||
@@ -381,6 +414,7 @@ TEST_F(LoadBalancerLoadInitialLedgerCustomNumMarkersTests, loadInitialLedger)
|
||||
{
|
||||
configJson_.as_object()["num_markers"] = numMarkers_;
|
||||
|
||||
EXPECT_CALL(sourceFactory_, makeSource).Times(2);
|
||||
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{}));
|
||||
@@ -484,6 +518,7 @@ struct LoadBalancerForwardToRippledTests : LoadBalancerConstructorTests, SyncAsi
|
||||
|
||||
TEST_F(LoadBalancerForwardToRippledTests, forward)
|
||||
{
|
||||
EXPECT_CALL(sourceFactory_, makeSource).Times(2);
|
||||
auto loadBalancer = makeLoadBalancer();
|
||||
EXPECT_CALL(
|
||||
sourceFactory_.sourceAt(0),
|
||||
@@ -498,6 +533,7 @@ TEST_F(LoadBalancerForwardToRippledTests, forward)
|
||||
|
||||
TEST_F(LoadBalancerForwardToRippledTests, forwardWithXUserHeader)
|
||||
{
|
||||
EXPECT_CALL(sourceFactory_, makeSource).Times(2);
|
||||
auto loadBalancer = makeLoadBalancer();
|
||||
EXPECT_CALL(
|
||||
sourceFactory_.sourceAt(0),
|
||||
@@ -512,6 +548,7 @@ TEST_F(LoadBalancerForwardToRippledTests, forwardWithXUserHeader)
|
||||
|
||||
TEST_F(LoadBalancerForwardToRippledTests, source0Fails)
|
||||
{
|
||||
EXPECT_CALL(sourceFactory_, makeSource).Times(2);
|
||||
auto loadBalancer = makeLoadBalancer();
|
||||
EXPECT_CALL(
|
||||
sourceFactory_.sourceAt(0),
|
||||
@@ -531,6 +568,7 @@ TEST_F(LoadBalancerForwardToRippledTests, source0Fails)
|
||||
|
||||
TEST_F(LoadBalancerForwardToRippledTests, bothSourcesFail)
|
||||
{
|
||||
EXPECT_CALL(sourceFactory_, makeSource).Times(2);
|
||||
auto loadBalancer = makeLoadBalancer();
|
||||
EXPECT_CALL(
|
||||
sourceFactory_.sourceAt(0),
|
||||
@@ -550,7 +588,8 @@ TEST_F(LoadBalancerForwardToRippledTests, bothSourcesFail)
|
||||
|
||||
TEST_F(LoadBalancerForwardToRippledTests, forwardingCacheEnabled)
|
||||
{
|
||||
configJson_.as_object()["forwarding_cache_timeout"] = 10.;
|
||||
configJson_.as_object()["forwarding"] = boost::json::object{{"cache_timeout", 10.}};
|
||||
EXPECT_CALL(sourceFactory_, makeSource).Times(2);
|
||||
auto loadBalancer = makeLoadBalancer();
|
||||
|
||||
auto const request = boost::json::object{{"command", "server_info"}};
|
||||
@@ -569,13 +608,15 @@ TEST_F(LoadBalancerForwardToRippledTests, forwardingCacheEnabled)
|
||||
|
||||
TEST_F(LoadBalancerForwardToRippledTests, forwardingCacheDisabledOnLedgerClosedHookCalled)
|
||||
{
|
||||
EXPECT_CALL(sourceFactory_, makeSource).Times(2);
|
||||
auto loadBalancer = makeLoadBalancer();
|
||||
EXPECT_NO_THROW(sourceFactory_.callbacksAt(0).onLedgerClosed());
|
||||
}
|
||||
|
||||
TEST_F(LoadBalancerForwardToRippledTests, onLedgerClosedHookInvalidatesCache)
|
||||
{
|
||||
configJson_.as_object()["forwarding_cache_timeout"] = 10.;
|
||||
configJson_.as_object()["forwarding"] = boost::json::object{{"cache_timeout", 10.}};
|
||||
EXPECT_CALL(sourceFactory_, makeSource).Times(2);
|
||||
auto loadBalancer = makeLoadBalancer();
|
||||
|
||||
auto const request = boost::json::object{{"command", "server_info"}};
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "util/requests/Types.hpp"
|
||||
#include "util/requests/WsConnection.hpp"
|
||||
|
||||
#include <boost/asio/error.hpp>
|
||||
#include <boost/asio/spawn.hpp>
|
||||
#include <boost/beast/http/field.hpp>
|
||||
#include <gtest/gtest.h>
|
||||
@@ -29,6 +30,7 @@
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <expected>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
@@ -119,6 +121,75 @@ TEST_P(WsConnectionTests, SendAndReceive)
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(WsConnectionTests, ReadTimeout)
|
||||
{
|
||||
TestWsConnectionPtr serverConnection;
|
||||
asio::spawn(ctx, [&](asio::yield_context yield) {
|
||||
serverConnection = std::make_unique<TestWsConnection>(unwrap(server.acceptConnection(yield)));
|
||||
});
|
||||
|
||||
runSpawn([&](asio::yield_context yield) {
|
||||
auto connection = unwrap(builder.plainConnect(yield));
|
||||
auto message = connection->read(yield, std::chrono::milliseconds{1});
|
||||
ASSERT_FALSE(message.has_value());
|
||||
ASSERT_TRUE(message.error().errorCode().has_value());
|
||||
EXPECT_EQ(message.error().errorCode().value().value(), asio::error::timed_out);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(WsConnectionTests, ReadWithTimeoutWorksFine)
|
||||
{
|
||||
asio::spawn(ctx, [&](asio::yield_context yield) {
|
||||
auto serverConnection = unwrap(server.acceptConnection(yield));
|
||||
auto maybeError = serverConnection.send("hello", yield);
|
||||
EXPECT_FALSE(maybeError.has_value()) << *maybeError;
|
||||
});
|
||||
|
||||
runSpawn([&](asio::yield_context yield) {
|
||||
auto connection = unwrap(builder.plainConnect(yield));
|
||||
auto message = connection->read(yield, std::chrono::seconds{1});
|
||||
ASSERT_TRUE(message.has_value()) << message.error().message();
|
||||
EXPECT_EQ(message.value(), "hello");
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(WsConnectionTests, WriteTimeout)
|
||||
{
|
||||
TestWsConnectionPtr serverConnection;
|
||||
asio::spawn(ctx, [&](asio::yield_context yield) {
|
||||
serverConnection = std::make_unique<TestWsConnection>(unwrap(server.acceptConnection(yield)));
|
||||
});
|
||||
|
||||
runSpawn([&](asio::yield_context yield) {
|
||||
auto connection = unwrap(builder.plainConnect(yield));
|
||||
std::optional<RequestError> error;
|
||||
|
||||
// Write is success even if the other side is not reading.
|
||||
// It seems we need to fill some socket buffer before the timeout occurs.
|
||||
while (not error.has_value()) {
|
||||
error = connection->write("hello", yield, std::chrono::milliseconds{1});
|
||||
}
|
||||
ASSERT_TRUE(error.has_value());
|
||||
EXPECT_EQ(error->errorCode().value().value(), asio::error::timed_out);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(WsConnectionTests, WriteWithTimeoutWorksFine)
|
||||
{
|
||||
asio::spawn(ctx, [&](asio::yield_context yield) {
|
||||
auto serverConnection = unwrap(server.acceptConnection(yield));
|
||||
auto message = serverConnection.receive(yield);
|
||||
ASSERT_TRUE(message.has_value());
|
||||
EXPECT_EQ(message, "hello");
|
||||
});
|
||||
|
||||
runSpawn([&](asio::yield_context yield) {
|
||||
auto connection = unwrap(builder.plainConnect(yield));
|
||||
auto error = connection->write("hello", yield, std::chrono::seconds{1});
|
||||
ASSERT_FALSE(error.has_value()) << error->message();
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(WsConnectionTests, TrySslUsePlain)
|
||||
{
|
||||
asio::spawn(ctx, [&](asio::yield_context yield) {
|
||||
@@ -148,7 +219,7 @@ TEST_F(WsConnectionTests, TrySslUsePlain)
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(WsConnectionTests, Timeout)
|
||||
TEST_F(WsConnectionTests, ConnectionTimeout)
|
||||
{
|
||||
builder.setConnectionTimeout(std::chrono::milliseconds{1});
|
||||
runSpawn([&](asio::yield_context yield) {
|
||||
@@ -213,9 +284,9 @@ TEST_F(WsConnectionTests, CloseConnection)
|
||||
|
||||
TEST_F(WsConnectionTests, CloseConnectionTimeout)
|
||||
{
|
||||
TestWsConnectionPtr serverConnection;
|
||||
asio::spawn(ctx, [&](asio::yield_context yield) {
|
||||
auto serverConnection = unwrap(server.acceptConnection(yield));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds{10});
|
||||
auto serverConnection = std::make_unique<TestWsConnection>(unwrap(server.acceptConnection(yield)));
|
||||
});
|
||||
|
||||
runSpawn([&](asio::yield_context yield) {
|
||||
|
||||
Reference in New Issue
Block a user