mirror of
https://github.com/XRPLF/clio.git
synced 2025-11-18 10:45:51 +00:00
@@ -69,6 +69,9 @@ public:
|
||||
if (specifiesCurrentOrClosedLedger(request))
|
||||
return true;
|
||||
|
||||
if (isForcedForward(ctx))
|
||||
return true;
|
||||
|
||||
auto const checkAccountInfoForward = [&]() {
|
||||
return ctx.method == "account_info" and request.contains("queue") and request.at("queue").is_bool() and
|
||||
request.at("queue").as_bool();
|
||||
@@ -138,6 +141,14 @@ private:
|
||||
{
|
||||
return handlerProvider_->contains(method) || isProxied(method);
|
||||
}
|
||||
|
||||
bool
|
||||
isForcedForward(web::Context const& ctx) const
|
||||
{
|
||||
static constexpr auto FORCE_FORWARD = "force_forward";
|
||||
return ctx.isAdmin and ctx.params.contains(FORCE_FORWARD) and ctx.params.at(FORCE_FORWARD).is_bool() and
|
||||
ctx.params.at(FORCE_FORWARD).as_bool();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace rpc::impl
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "util/MockCounters.hpp"
|
||||
#include "util/MockHandlerProvider.hpp"
|
||||
#include "util/MockLoadBalancer.hpp"
|
||||
#include "util/NameGenerator.hpp"
|
||||
#include "util/Taggable.hpp"
|
||||
#include "util/config/Config.hpp"
|
||||
#include "web/Context.hpp"
|
||||
@@ -32,10 +33,12 @@
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
using namespace rpc;
|
||||
using namespace testing;
|
||||
@@ -59,235 +62,159 @@ protected:
|
||||
};
|
||||
};
|
||||
|
||||
TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsFalseIfClioOnly)
|
||||
struct ShouldForwardParamTestCaseBundle {
|
||||
std::string testName;
|
||||
std::uint32_t apiVersion;
|
||||
std::string method;
|
||||
std::string testJson;
|
||||
bool mockedIsClioOnly;
|
||||
std::uint32_t called;
|
||||
bool isAdmin;
|
||||
bool expected;
|
||||
};
|
||||
|
||||
struct ShouldForwardParameterTest : public RPCForwardingProxyTest,
|
||||
WithParamInterface<ShouldForwardParamTestCaseBundle> {};
|
||||
|
||||
static auto
|
||||
generateTestValuesForParametersTest()
|
||||
{
|
||||
auto const isClioOnly = true;
|
||||
auto const isAdmin = true;
|
||||
auto const shouldForward = true;
|
||||
|
||||
return std::vector<ShouldForwardParamTestCaseBundle>{
|
||||
{"ShouldForwardReturnsFalseIfClioOnly", 2u, "test", "{}", isClioOnly, 1, !isAdmin, !shouldForward},
|
||||
{"ShouldForwardReturnsTrueIfProxied", 2u, "submit", "{}", !isClioOnly, 1, !isAdmin, shouldForward},
|
||||
{"ShouldForwardReturnsTrueIfCurrentLedgerSpecified",
|
||||
2u,
|
||||
"anymethod",
|
||||
R"({"ledger_index": "current"})",
|
||||
!isClioOnly,
|
||||
1,
|
||||
!isAdmin,
|
||||
shouldForward},
|
||||
{"ShouldForwardReturnsTrueIfClosedLedgerSpecified",
|
||||
2u,
|
||||
"anymethod",
|
||||
R"({"ledger_index": "closed"})",
|
||||
!isClioOnly,
|
||||
1,
|
||||
!isAdmin,
|
||||
shouldForward},
|
||||
{"ShouldForwardReturnsTrueIfAccountInfoWithQueueSpecified",
|
||||
2u,
|
||||
"account_info",
|
||||
R"({"queue": true})",
|
||||
!isClioOnly,
|
||||
1,
|
||||
!isAdmin,
|
||||
shouldForward},
|
||||
{"ShouldForwardReturnsFalseIfAccountInfoQueueIsFalse",
|
||||
2u,
|
||||
"account_info",
|
||||
R"({"queue": false})",
|
||||
!isClioOnly,
|
||||
1,
|
||||
!isAdmin,
|
||||
!shouldForward},
|
||||
{"ShouldForwardReturnsTrueIfLedgerWithQueueSpecified",
|
||||
2u,
|
||||
"ledger",
|
||||
R"({"queue": true})",
|
||||
!isClioOnly,
|
||||
1,
|
||||
!isAdmin,
|
||||
shouldForward},
|
||||
{"ShouldForwardReturnsFalseIfLedgerQueueIsFalse",
|
||||
2u,
|
||||
"ledger",
|
||||
R"({"queue": false})",
|
||||
!isClioOnly,
|
||||
1,
|
||||
!isAdmin,
|
||||
!shouldForward},
|
||||
{"ShouldNotForwardReturnsTrueIfAPIVersionIsV1",
|
||||
1u,
|
||||
"api_version_check",
|
||||
"{}",
|
||||
!isClioOnly,
|
||||
1,
|
||||
!isAdmin,
|
||||
!shouldForward},
|
||||
{"ShouldForwardReturnsFalseIfAPIVersionIsV2",
|
||||
2u,
|
||||
"api_version_check",
|
||||
"{}",
|
||||
!isClioOnly,
|
||||
1,
|
||||
!isAdmin,
|
||||
!shouldForward},
|
||||
{"ShouldNeverForwardSubscribe", 1u, "subscribe", "{}", !isClioOnly, 0, !isAdmin, !shouldForward},
|
||||
{"ShouldNeverForwardUnsubscribe", 1u, "unsubscribe", "{}", !isClioOnly, 0, !isAdmin, !shouldForward},
|
||||
{"ForceForwardTrue", 1u, "any_method", R"({"force_forward": true})", !isClioOnly, 1, isAdmin, shouldForward},
|
||||
{"ForceForwardFalse", 1u, "any_method", R"({"force_forward": false})", !isClioOnly, 1, isAdmin, !shouldForward},
|
||||
{"ForceForwardNotAdmin",
|
||||
1u,
|
||||
"any_method",
|
||||
R"({"force_forward": true})",
|
||||
!isClioOnly,
|
||||
1,
|
||||
!isAdmin,
|
||||
!shouldForward},
|
||||
{"ForceForwardSubscribe",
|
||||
1u,
|
||||
"subscribe",
|
||||
R"({"force_forward": true})",
|
||||
!isClioOnly,
|
||||
0,
|
||||
isAdmin,
|
||||
not shouldForward},
|
||||
{"ForceForwardUnsubscribe",
|
||||
1u,
|
||||
"unsubscribe",
|
||||
R"({"force_forward": true})",
|
||||
!isClioOnly,
|
||||
0,
|
||||
isAdmin,
|
||||
!shouldForward},
|
||||
{"ForceForwardClioOnly",
|
||||
1u,
|
||||
"clio_only_method",
|
||||
R"({"force_forward": true})",
|
||||
isClioOnly,
|
||||
1,
|
||||
isAdmin,
|
||||
!shouldForward},
|
||||
};
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
ShouldForwardTest,
|
||||
ShouldForwardParameterTest,
|
||||
ValuesIn(generateTestValuesForParametersTest()),
|
||||
tests::util::NameGenerator
|
||||
);
|
||||
|
||||
TEST_P(ShouldForwardParameterTest, Test)
|
||||
{
|
||||
auto const testBundle = GetParam();
|
||||
auto const rawHandlerProviderPtr = handlerProvider.get();
|
||||
auto const apiVersion = 2u;
|
||||
auto const method = "test";
|
||||
auto const params = json::parse("{}");
|
||||
auto const apiVersion = testBundle.apiVersion;
|
||||
auto const method = testBundle.method;
|
||||
auto const params = json::parse(testBundle.testJson);
|
||||
|
||||
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(true));
|
||||
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
|
||||
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(testBundle.mockedIsClioOnly));
|
||||
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(testBundle.called);
|
||||
|
||||
runSpawn([&](auto yield) {
|
||||
auto const range = backend->fetchLedgerRange();
|
||||
auto const ctx =
|
||||
web::Context(yield, method, apiVersion, params.as_object(), nullptr, tagFactory, *range, CLIENT_IP, true);
|
||||
auto const ctx = web::Context(
|
||||
yield, method, apiVersion, params.as_object(), nullptr, tagFactory, *range, CLIENT_IP, testBundle.isAdmin
|
||||
);
|
||||
|
||||
auto const res = proxy.shouldForward(ctx);
|
||||
ASSERT_FALSE(res);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsTrueIfProxied)
|
||||
{
|
||||
auto const rawHandlerProviderPtr = handlerProvider.get();
|
||||
auto const apiVersion = 2u;
|
||||
auto const method = "submit";
|
||||
auto const params = json::parse("{}");
|
||||
|
||||
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(false));
|
||||
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
|
||||
|
||||
runSpawn([&](auto yield) {
|
||||
auto const range = backend->fetchLedgerRange();
|
||||
auto const ctx =
|
||||
web::Context(yield, method, apiVersion, params.as_object(), nullptr, tagFactory, *range, CLIENT_IP, true);
|
||||
|
||||
auto const res = proxy.shouldForward(ctx);
|
||||
ASSERT_TRUE(res);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsTrueIfCurrentLedgerSpecified)
|
||||
{
|
||||
auto const rawHandlerProviderPtr = handlerProvider.get();
|
||||
auto const apiVersion = 2u;
|
||||
auto const method = "anymethod";
|
||||
auto const params = json::parse(R"({"ledger_index": "current"})");
|
||||
|
||||
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(false));
|
||||
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
|
||||
|
||||
runSpawn([&](auto yield) {
|
||||
auto const range = backend->fetchLedgerRange();
|
||||
auto const ctx =
|
||||
web::Context(yield, method, apiVersion, params.as_object(), nullptr, tagFactory, *range, CLIENT_IP, true);
|
||||
|
||||
auto const res = proxy.shouldForward(ctx);
|
||||
ASSERT_TRUE(res);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsTrueIfClosedLedgerSpecified)
|
||||
{
|
||||
auto const rawHandlerProviderPtr = handlerProvider.get();
|
||||
auto const apiVersion = 2u;
|
||||
auto const method = "anymethod";
|
||||
auto const params = json::parse(R"({"ledger_index": "closed"})");
|
||||
|
||||
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(false));
|
||||
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
|
||||
|
||||
runSpawn([&](auto yield) {
|
||||
auto const range = backend->fetchLedgerRange();
|
||||
auto const ctx =
|
||||
web::Context(yield, method, apiVersion, params.as_object(), nullptr, tagFactory, *range, CLIENT_IP, true);
|
||||
|
||||
auto const res = proxy.shouldForward(ctx);
|
||||
ASSERT_TRUE(res);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsTrueIfAccountInfoWithQueueSpecified)
|
||||
{
|
||||
auto const rawHandlerProviderPtr = handlerProvider.get();
|
||||
auto const apiVersion = 2u;
|
||||
auto const method = "account_info";
|
||||
auto const params = json::parse(R"({"queue": true})");
|
||||
|
||||
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(false));
|
||||
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
|
||||
|
||||
runSpawn([&](auto yield) {
|
||||
auto const range = backend->fetchLedgerRange();
|
||||
auto const ctx =
|
||||
web::Context(yield, method, apiVersion, params.as_object(), nullptr, tagFactory, *range, CLIENT_IP, true);
|
||||
|
||||
auto const res = proxy.shouldForward(ctx);
|
||||
ASSERT_TRUE(res);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsFalseIfAccountInfoQueueIsFalse)
|
||||
{
|
||||
auto const rawHandlerProviderPtr = handlerProvider.get();
|
||||
auto const apiVersion = 2u;
|
||||
auto const method = "account_info";
|
||||
auto const params = json::parse(R"({"queue": false})");
|
||||
|
||||
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(false));
|
||||
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
|
||||
|
||||
runSpawn([&](auto yield) {
|
||||
auto const range = backend->fetchLedgerRange();
|
||||
auto const ctx =
|
||||
web::Context(yield, method, apiVersion, params.as_object(), nullptr, tagFactory, *range, CLIENT_IP, true);
|
||||
|
||||
auto const res = proxy.shouldForward(ctx);
|
||||
ASSERT_FALSE(res);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsTrueIfLedgerWithQueueSpecified)
|
||||
{
|
||||
auto const rawHandlerProviderPtr = handlerProvider.get();
|
||||
auto const apiVersion = 2u;
|
||||
auto const method = "ledger";
|
||||
auto const params = json::parse(R"({"queue": true})");
|
||||
|
||||
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(false));
|
||||
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
|
||||
|
||||
runSpawn([&](auto yield) {
|
||||
auto const range = backend->fetchLedgerRange();
|
||||
auto const ctx =
|
||||
web::Context(yield, method, apiVersion, params.as_object(), nullptr, tagFactory, *range, CLIENT_IP, true);
|
||||
|
||||
auto const res = proxy.shouldForward(ctx);
|
||||
ASSERT_TRUE(res);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsFalseIfLedgerQueueIsFalse)
|
||||
{
|
||||
auto const rawHandlerProviderPtr = handlerProvider.get();
|
||||
auto const apiVersion = 2u;
|
||||
auto const method = "ledger";
|
||||
auto const params = json::parse(R"({"queue": false})");
|
||||
|
||||
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(false));
|
||||
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
|
||||
|
||||
runSpawn([&](auto yield) {
|
||||
auto const range = backend->fetchLedgerRange();
|
||||
auto const ctx =
|
||||
web::Context(yield, method, apiVersion, params.as_object(), nullptr, tagFactory, *range, CLIENT_IP, true);
|
||||
|
||||
auto const res = proxy.shouldForward(ctx);
|
||||
ASSERT_FALSE(res);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(RPCForwardingProxyTest, ShouldNotForwardReturnsTrueIfAPIVersionIsV1)
|
||||
{
|
||||
auto const apiVersion = 1u;
|
||||
auto const method = "api_version_check";
|
||||
auto const params = json::parse("{}");
|
||||
|
||||
auto const rawHandlerProviderPtr = handlerProvider.get();
|
||||
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(false));
|
||||
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
|
||||
|
||||
runSpawn([&](auto yield) {
|
||||
auto const range = backend->fetchLedgerRange();
|
||||
auto const ctx =
|
||||
web::Context(yield, method, apiVersion, params.as_object(), nullptr, tagFactory, *range, CLIENT_IP, true);
|
||||
|
||||
auto const res = proxy.shouldForward(ctx);
|
||||
ASSERT_FALSE(res);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsFalseIfAPIVersionIsV2)
|
||||
{
|
||||
auto const rawHandlerProviderPtr = handlerProvider.get();
|
||||
auto const apiVersion = 2u;
|
||||
auto const method = "api_version_check";
|
||||
auto const params = json::parse("{}");
|
||||
|
||||
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(false));
|
||||
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
|
||||
|
||||
runSpawn([&](auto yield) {
|
||||
auto const range = backend->fetchLedgerRange();
|
||||
auto const ctx =
|
||||
web::Context(yield, method, apiVersion, params.as_object(), nullptr, tagFactory, *range, CLIENT_IP, true);
|
||||
|
||||
auto const res = proxy.shouldForward(ctx);
|
||||
ASSERT_FALSE(res);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(RPCForwardingProxyTest, ShouldNeverForwardSubscribe)
|
||||
{
|
||||
auto const apiVersion = 1u;
|
||||
auto const method = "subscribe";
|
||||
auto const params = json::parse("{}");
|
||||
|
||||
runSpawn([&](auto yield) {
|
||||
auto const range = backend->fetchLedgerRange();
|
||||
auto const ctx =
|
||||
web::Context(yield, method, apiVersion, params.as_object(), nullptr, tagFactory, *range, CLIENT_IP, true);
|
||||
|
||||
auto const res = proxy.shouldForward(ctx);
|
||||
ASSERT_FALSE(res);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(RPCForwardingProxyTest, ShouldNeverForwardUnsubscribe)
|
||||
{
|
||||
auto const apiVersion = 1u;
|
||||
auto const method = "unsubscribe";
|
||||
auto const params = json::parse("{}");
|
||||
|
||||
runSpawn([&](auto yield) {
|
||||
auto const range = backend->fetchLedgerRange();
|
||||
auto const ctx =
|
||||
web::Context(yield, method, apiVersion, params.as_object(), nullptr, tagFactory, *range, CLIENT_IP, true);
|
||||
|
||||
auto const res = proxy.shouldForward(ctx);
|
||||
ASSERT_FALSE(res);
|
||||
ASSERT_EQ(res, testBundle.expected);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user