feat: More verbose forwarding errors (#1523)

Fixes #1516.
This commit is contained in:
Sergey Kuznetsov
2024-07-09 15:22:01 +01:00
committed by GitHub
parent 094ed8f299
commit 46bd67a9ec
19 changed files with 176 additions and 53 deletions

View File

@@ -19,12 +19,14 @@
#include "etl/LoadBalancer.hpp"
#include "etl/Source.hpp"
#include "rpc/Errors.hpp"
#include "util/AsioContextTestFixture.hpp"
#include "util/MockBackendTestFixture.hpp"
#include "util/MockNetworkValidatedLedgers.hpp"
#include "util/MockPrometheus.hpp"
#include "util/MockSource.hpp"
#include "util/MockSubscriptionManager.hpp"
#include "util/NameGenerator.hpp"
#include "util/Random.hpp"
#include "util/config/Config.hpp"
@@ -41,10 +43,12 @@
#include <chrono>
#include <cstdint>
#include <expected>
#include <memory>
#include <optional>
#include <stdexcept>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
@@ -111,8 +115,10 @@ TEST_F(LoadBalancerConstructorTests, forwardingTimeoutPassedToSourceFactory)
TEST_F(LoadBalancerConstructorTests, fetchETLState_AllSourcesFail)
{
EXPECT_CALL(sourceFactory_, makeSource).Times(2);
EXPECT_CALL(sourceFactory_.sourceAt(0), forwardToRippled).WillOnce(Return(std::nullopt));
EXPECT_CALL(sourceFactory_.sourceAt(1), forwardToRippled).WillOnce(Return(std::nullopt));
EXPECT_CALL(sourceFactory_.sourceAt(0), forwardToRippled)
.WillOnce(Return(std::unexpected{rpc::ClioError::etlCONNECTION_ERROR}));
EXPECT_CALL(sourceFactory_.sourceAt(1), forwardToRippled)
.WillOnce(Return(std::unexpected{rpc::ClioError::etlCONNECTION_ERROR}));
EXPECT_THROW({ makeLoadBalancer(); }, std::logic_error);
}
@@ -130,7 +136,8 @@ TEST_F(LoadBalancerConstructorTests, fetchETLState_Source1Fails0OK)
{
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), forwardToRippled)
.WillOnce(Return(std::unexpected{rpc::ClioError::etlCONNECTION_ERROR}));
EXPECT_CALL(sourceFactory_.sourceAt(0), run);
EXPECT_CALL(sourceFactory_.sourceAt(1), run);
makeLoadBalancer();
@@ -139,7 +146,8 @@ TEST_F(LoadBalancerConstructorTests, fetchETLState_Source1Fails0OK)
TEST_F(LoadBalancerConstructorTests, fetchETLState_Source0Fails1OK)
{
EXPECT_CALL(sourceFactory_, makeSource).Times(2);
EXPECT_CALL(sourceFactory_.sourceAt(0), forwardToRippled).WillOnce(Return(std::nullopt));
EXPECT_CALL(sourceFactory_.sourceAt(0), forwardToRippled)
.WillOnce(Return(std::unexpected{rpc::ClioError::etlCONNECTION_ERROR}));
EXPECT_CALL(sourceFactory_.sourceAt(1), forwardToRippled).WillOnce(Return(boost::json::object{}));
EXPECT_CALL(sourceFactory_.sourceAt(0), run);
EXPECT_CALL(sourceFactory_.sourceAt(1), run);
@@ -162,7 +170,8 @@ TEST_F(LoadBalancerConstructorTests, fetchETLState_AllSourcesFailButAllowNoEtlIs
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));
EXPECT_CALL(sourceFactory_.sourceAt(1), forwardToRippled)
.WillOnce(Return(std::unexpected{rpc::ClioError::etlCONNECTION_ERROR}));
EXPECT_CALL(sourceFactory_.sourceAt(1), run);
configJson_.as_object()["allow_no_etl"] = true;
@@ -566,7 +575,7 @@ TEST_F(LoadBalancerForwardToRippledTests, source0Fails)
sourceFactory_.sourceAt(0),
forwardToRippled(request_, clientIP_, LoadBalancer::USER_FORWARDING_X_USER_VALUE, testing::_)
)
.WillOnce(Return(std::nullopt));
.WillOnce(Return(std::unexpected{rpc::ClioError::etlCONNECTION_ERROR}));
EXPECT_CALL(
sourceFactory_.sourceAt(1),
forwardToRippled(request_, clientIP_, LoadBalancer::USER_FORWARDING_X_USER_VALUE, testing::_)
@@ -578,7 +587,56 @@ TEST_F(LoadBalancerForwardToRippledTests, source0Fails)
});
}
TEST_F(LoadBalancerForwardToRippledTests, bothSourcesFail)
struct LoadBalancerForwardToRippledErrorTestBundle {
std::string testName;
rpc::ClioError firstSourceError;
rpc::ClioError secondSourceError;
rpc::ClioError responseExpectedError;
};
struct LoadBalancerForwardToRippledErrorTests
: LoadBalancerForwardToRippledTests,
testing::WithParamInterface<LoadBalancerForwardToRippledErrorTestBundle> {};
INSTANTIATE_TEST_SUITE_P(
LoadBalancerForwardToRippledErrorTests,
LoadBalancerForwardToRippledErrorTests,
testing::Values(
LoadBalancerForwardToRippledErrorTestBundle{
"ConnectionError_RequestError",
rpc::ClioError::etlCONNECTION_ERROR,
rpc::ClioError::etlREQUEST_ERROR,
rpc::ClioError::etlREQUEST_ERROR
},
LoadBalancerForwardToRippledErrorTestBundle{
"RequestError_RequestTimeout",
rpc::ClioError::etlREQUEST_ERROR,
rpc::ClioError::etlREQUEST_TIMEOUT,
rpc::ClioError::etlREQUEST_TIMEOUT
},
LoadBalancerForwardToRippledErrorTestBundle{
"RequestTimeout_InvalidResponse",
rpc::ClioError::etlREQUEST_TIMEOUT,
rpc::ClioError::etlINVALID_RESPONSE,
rpc::ClioError::etlINVALID_RESPONSE
},
LoadBalancerForwardToRippledErrorTestBundle{
"BothRequestTimeout",
rpc::ClioError::etlREQUEST_TIMEOUT,
rpc::ClioError::etlREQUEST_TIMEOUT,
rpc::ClioError::etlREQUEST_TIMEOUT
},
LoadBalancerForwardToRippledErrorTestBundle{
"InvalidResponse_RequestError",
rpc::ClioError::etlINVALID_RESPONSE,
rpc::ClioError::etlREQUEST_ERROR,
rpc::ClioError::etlINVALID_RESPONSE
}
),
tests::util::NameGenerator
);
TEST_P(LoadBalancerForwardToRippledErrorTests, bothSourcesFail)
{
EXPECT_CALL(sourceFactory_, makeSource).Times(2);
auto loadBalancer = makeLoadBalancer();
@@ -586,15 +644,17 @@ TEST_F(LoadBalancerForwardToRippledTests, bothSourcesFail)
sourceFactory_.sourceAt(0),
forwardToRippled(request_, clientIP_, LoadBalancer::USER_FORWARDING_X_USER_VALUE, testing::_)
)
.WillOnce(Return(std::nullopt));
.WillOnce(Return(std::unexpected{GetParam().firstSourceError}));
EXPECT_CALL(
sourceFactory_.sourceAt(1),
forwardToRippled(request_, clientIP_, LoadBalancer::USER_FORWARDING_X_USER_VALUE, testing::_)
)
.WillOnce(Return(std::nullopt));
.WillOnce(Return(std::unexpected{GetParam().secondSourceError}));
runSpawn([&](boost::asio::yield_context yield) {
EXPECT_EQ(loadBalancer->forwardToRippled(request_, clientIP_, false, yield), std::nullopt);
auto const response = loadBalancer->forwardToRippled(request_, clientIP_, false, yield);
ASSERT_FALSE(response);
EXPECT_EQ(response.error(), GetParam().responseExpectedError);
});
}