mirror of
				https://github.com/XRPLF/clio.git
				synced 2025-11-04 11:55:51 +00:00 
			
		
		
		
	Api v1 bool support (#877)
* Allow not bool for signer_lists * Allow transactions to be not bool for v1 * Add tests for JsonBool
This commit is contained in:
		@@ -175,6 +175,7 @@ if (tests)
 | 
			
		||||
    unittests/rpc/ForwardingProxyTests.cpp
 | 
			
		||||
    unittests/rpc/WorkQueueTests.cpp
 | 
			
		||||
    unittests/rpc/AmendmentsTests.cpp
 | 
			
		||||
    unittests/rpc/JsonBoolTests.cpp
 | 
			
		||||
    ## RPC handlers
 | 
			
		||||
    unittests/rpc/handlers/DefaultProcessorTests.cpp
 | 
			
		||||
    unittests/rpc/handlers/TestHandlerTests.cpp
 | 
			
		||||
 
 | 
			
		||||
@@ -176,7 +176,7 @@ tag_invoke(boost::json::value_to_tag<AccountInfoHandler::Input>, boost::json::va
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (jsonObject.contains(JS(signer_lists)))
 | 
			
		||||
        input.signerLists = jsonObject.at(JS(signer_lists)).as_bool();
 | 
			
		||||
        input.signerLists = boost::json::value_to<JsonBool>(jsonObject.at(JS(signer_lists)));
 | 
			
		||||
 | 
			
		||||
    return input;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -21,6 +21,7 @@
 | 
			
		||||
 | 
			
		||||
#include <data/BackendInterface.h>
 | 
			
		||||
#include <rpc/RPCHelpers.h>
 | 
			
		||||
#include <rpc/common/JsonBool.h>
 | 
			
		||||
#include <rpc/common/MetaProcessors.h>
 | 
			
		||||
#include <rpc/common/Types.h>
 | 
			
		||||
#include <rpc/common/Validators.h>
 | 
			
		||||
@@ -76,7 +77,7 @@ public:
 | 
			
		||||
        std::optional<std::string> ident;
 | 
			
		||||
        std::optional<std::string> ledgerHash;
 | 
			
		||||
        std::optional<uint32_t> ledgerIndex;
 | 
			
		||||
        bool signerLists = false;
 | 
			
		||||
        JsonBool signerLists{false};
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    using Result = HandlerReturnType<Output>;
 | 
			
		||||
@@ -88,14 +89,15 @@ public:
 | 
			
		||||
    RpcSpecConstRef
 | 
			
		||||
    spec([[maybe_unused]] uint32_t apiVersion) const
 | 
			
		||||
    {
 | 
			
		||||
        static auto const rpcSpec = RpcSpec{
 | 
			
		||||
        static auto const rpcSpecV1 = RpcSpec{
 | 
			
		||||
            {JS(account), validation::AccountValidator},
 | 
			
		||||
            {JS(ident), validation::AccountValidator},
 | 
			
		||||
            {JS(ledger_hash), validation::Uint256HexStringValidator},
 | 
			
		||||
            {JS(ledger_index), validation::LedgerIndexValidator},
 | 
			
		||||
            {JS(signer_lists), validation::Type<bool>{}}};
 | 
			
		||||
            {JS(ledger_index), validation::LedgerIndexValidator}};
 | 
			
		||||
 | 
			
		||||
        return rpcSpec;
 | 
			
		||||
        static auto const rpcSpec = RpcSpec{rpcSpecV1, {{JS(signer_lists), validation::Type<bool>{}}}};
 | 
			
		||||
 | 
			
		||||
        return apiVersion == 1 ? rpcSpecV1 : rpcSpec;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Result
 | 
			
		||||
 
 | 
			
		||||
@@ -167,7 +167,7 @@ tag_invoke(boost::json::value_to_tag<NoRippleCheckHandler::Input>, boost::json::
 | 
			
		||||
        input.limit = jsonObject.at(JS(limit)).as_int64();
 | 
			
		||||
 | 
			
		||||
    if (jsonObject.contains(JS(transactions)))
 | 
			
		||||
        input.transactions = jsonObject.at(JS(transactions)).as_bool();
 | 
			
		||||
        input.transactions = boost::json::value_to<JsonBool>(jsonObject.at(JS(transactions)));
 | 
			
		||||
 | 
			
		||||
    if (jsonObject.contains(JS(ledger_hash)))
 | 
			
		||||
        input.ledgerHash = jsonObject.at(JS(ledger_hash)).as_string().c_str();
 | 
			
		||||
 
 | 
			
		||||
@@ -21,6 +21,7 @@
 | 
			
		||||
 | 
			
		||||
#include <data/BackendInterface.h>
 | 
			
		||||
#include <rpc/RPCHelpers.h>
 | 
			
		||||
#include <rpc/common/JsonBool.h>
 | 
			
		||||
#include <rpc/common/MetaProcessors.h>
 | 
			
		||||
#include <rpc/common/Modifiers.h>
 | 
			
		||||
#include <rpc/common/Types.h>
 | 
			
		||||
@@ -62,7 +63,7 @@ public:
 | 
			
		||||
        std::optional<std::string> ledgerHash;
 | 
			
		||||
        std::optional<uint32_t> ledgerIndex;
 | 
			
		||||
        uint32_t limit = LIMIT_DEFAULT;
 | 
			
		||||
        bool transactions = false;
 | 
			
		||||
        JsonBool transactions{false};
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    using Result = HandlerReturnType<Output>;
 | 
			
		||||
@@ -75,7 +76,7 @@ public:
 | 
			
		||||
    RpcSpecConstRef
 | 
			
		||||
    spec([[maybe_unused]] uint32_t apiVersion) const
 | 
			
		||||
    {
 | 
			
		||||
        static auto const rpcSpec = RpcSpec{
 | 
			
		||||
        static auto const rpcSpecV1 = RpcSpec{
 | 
			
		||||
            {JS(account), validation::Required{}, validation::AccountValidator},
 | 
			
		||||
            {JS(role),
 | 
			
		||||
             validation::Required{},
 | 
			
		||||
@@ -87,11 +88,15 @@ public:
 | 
			
		||||
            {JS(limit),
 | 
			
		||||
             validation::Type<uint32_t>(),
 | 
			
		||||
             validation::Min(1u),
 | 
			
		||||
             modifiers::Clamp<int32_t>{LIMIT_MIN, LIMIT_MAX}},
 | 
			
		||||
            {JS(transactions), validation::Type<bool>()},
 | 
			
		||||
        };
 | 
			
		||||
             modifiers::Clamp<int32_t>{LIMIT_MIN, LIMIT_MAX}}};
 | 
			
		||||
 | 
			
		||||
        return rpcSpec;
 | 
			
		||||
        static auto const rpcSpec = RpcSpec{
 | 
			
		||||
            rpcSpecV1,
 | 
			
		||||
            {
 | 
			
		||||
                {JS(transactions), validation::Type<bool>()},
 | 
			
		||||
            }};
 | 
			
		||||
 | 
			
		||||
        return apiVersion == 1 ? rpcSpecV1 : rpcSpec;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Result
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										81
									
								
								unittests/rpc/JsonBoolTests.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								unittests/rpc/JsonBoolTests.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,81 @@
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
/*
 | 
			
		||||
    This file is part of clio: https://github.com/XRPLF/clio
 | 
			
		||||
    Copyright (c) 2023, 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 <rpc/common/JsonBool.h>
 | 
			
		||||
 | 
			
		||||
#include <boost/json/parse.hpp>
 | 
			
		||||
#include <gtest/gtest.h>
 | 
			
		||||
 | 
			
		||||
using namespace rpc;
 | 
			
		||||
namespace json = boost::json;
 | 
			
		||||
using namespace testing;
 | 
			
		||||
 | 
			
		||||
struct JsonBoolTestsCaseBundle
 | 
			
		||||
{
 | 
			
		||||
    std::string testName;
 | 
			
		||||
    std::string json;
 | 
			
		||||
    bool expectedBool;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class JsonBoolTests : public TestWithParam<JsonBoolTestsCaseBundle>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    struct NameGenerator
 | 
			
		||||
    {
 | 
			
		||||
        template <class ParamType>
 | 
			
		||||
        std::string
 | 
			
		||||
        operator()(const testing::TestParamInfo<ParamType>& info) const
 | 
			
		||||
        {
 | 
			
		||||
            auto bundle = static_cast<JsonBoolTestsCaseBundle>(info.param);
 | 
			
		||||
            return bundle.testName;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    static auto
 | 
			
		||||
    generateTestValuesForParametersTest()
 | 
			
		||||
    {
 | 
			
		||||
        return std::vector<JsonBoolTestsCaseBundle>{
 | 
			
		||||
            {"NullValue", R"({ "test_bool": null })", false},
 | 
			
		||||
            {"BoolTrueValue", R"({ "test_bool": true })", true},
 | 
			
		||||
            {"BoolFalseValue", R"({ "test_bool": false })", false},
 | 
			
		||||
            {"IntTrueValue", R"({ "test_bool": 1 })", true},
 | 
			
		||||
            {"IntFalseValue", R"({ "test_bool": 0 })", false},
 | 
			
		||||
            {"DoubleTrueValue", R"({ "test_bool": 0.1 })", true},
 | 
			
		||||
            {"DoubleFalseValue", R"({ "test_bool": 0.0 })", false},
 | 
			
		||||
            {"StringTrueValue", R"({ "test_bool": "true" })", true},
 | 
			
		||||
            {"StringFalseValue", R"({ "test_bool": "false" })", true},
 | 
			
		||||
            {"ArrayTrueValue", R"({ "test_bool": [0] })", true},
 | 
			
		||||
            {"ArrayFalseValue", R"({ "test_bool": [] })", false},
 | 
			
		||||
            {"ObjectTrueValue", R"({ "test_bool": { "key": null } })", true},
 | 
			
		||||
            {"ObjectFalseValue", R"({ "test_bool": {} })", false}};
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
INSTANTIATE_TEST_CASE_P(
 | 
			
		||||
    JsonBoolCheckGroup,
 | 
			
		||||
    JsonBoolTests,
 | 
			
		||||
    ValuesIn(JsonBoolTests::generateTestValuesForParametersTest()),
 | 
			
		||||
    JsonBoolTests::NameGenerator{});
 | 
			
		||||
 | 
			
		||||
TEST_P(JsonBoolTests, Parse)
 | 
			
		||||
{
 | 
			
		||||
    auto const testBundle = GetParam();
 | 
			
		||||
    const auto jv = json::parse(testBundle.json).as_object();
 | 
			
		||||
    ASSERT_TRUE(jv.contains("test_bool"));
 | 
			
		||||
    EXPECT_EQ(testBundle.expectedBool, value_to<JsonBool>(jv.at("test_bool")).value);
 | 
			
		||||
}
 | 
			
		||||
@@ -107,7 +107,7 @@ TEST_P(AccountInfoParameterTest, InvalidParams)
 | 
			
		||||
    runSpawn([&, this](auto yield) {
 | 
			
		||||
        auto const handler = AnyHandler{AccountInfoHandler{mockBackendPtr}};
 | 
			
		||||
        auto const req = json::parse(testBundle.testJson);
 | 
			
		||||
        auto const output = handler.process(req, Context{yield});
 | 
			
		||||
        auto const output = handler.process(req, Context{.yield = yield, .apiVersion = 2});
 | 
			
		||||
        ASSERT_FALSE(output);
 | 
			
		||||
 | 
			
		||||
        auto const err = rpc::makeError(output.error());
 | 
			
		||||
@@ -116,6 +116,25 @@ TEST_P(AccountInfoParameterTest, InvalidParams)
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_F(AccountInfoParameterTest, ApiV1SignerListIsNotBool)
 | 
			
		||||
{
 | 
			
		||||
    static constexpr auto reqJson = R"(
 | 
			
		||||
        {"ident":"rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun", "signer_lists":1}
 | 
			
		||||
    )";
 | 
			
		||||
    auto* rawBackendPtr = static_cast<MockBackend*>(mockBackendPtr.get());
 | 
			
		||||
    EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence);
 | 
			
		||||
    runSpawn([&, this](auto yield) {
 | 
			
		||||
        auto const handler = AnyHandler{AccountInfoHandler{mockBackendPtr}};
 | 
			
		||||
        auto const req = json::parse(reqJson);
 | 
			
		||||
        auto const output = handler.process(req, Context{.yield = yield, .apiVersion = 1});
 | 
			
		||||
        ASSERT_FALSE(output);
 | 
			
		||||
 | 
			
		||||
        auto const err = rpc::makeError(output.error());
 | 
			
		||||
        EXPECT_EQ(err.at("error").as_string(), "lgrNotFound");
 | 
			
		||||
        EXPECT_EQ(err.at("error_message").as_string(), "ledgerNotFound");
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_F(RPCAccountInfoHandlerTest, LedgerNonExistViaIntSequence)
 | 
			
		||||
{
 | 
			
		||||
    auto const rawBackendPtr = static_cast<MockBackend*>(mockBackendPtr.get());
 | 
			
		||||
 
 | 
			
		||||
@@ -156,7 +156,7 @@ TEST_P(NoRippleCheckParameterTest, InvalidParams)
 | 
			
		||||
    runSpawn([&, this](auto yield) {
 | 
			
		||||
        auto const handler = AnyHandler{NoRippleCheckHandler{mockBackendPtr}};
 | 
			
		||||
        auto const req = json::parse(testBundle.testJson);
 | 
			
		||||
        auto const output = handler.process(req, Context{yield});
 | 
			
		||||
        auto const output = handler.process(req, Context{.yield = yield, .apiVersion = 2});
 | 
			
		||||
        ASSERT_FALSE(output);
 | 
			
		||||
 | 
			
		||||
        auto const err = rpc::makeError(output.error());
 | 
			
		||||
@@ -165,6 +165,29 @@ TEST_P(NoRippleCheckParameterTest, InvalidParams)
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_F(NoRippleCheckParameterTest, V1ApiTransactionsIsNotBool)
 | 
			
		||||
{
 | 
			
		||||
    static constexpr auto reqJson = R"(
 | 
			
		||||
        {
 | 
			
		||||
            "account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
 | 
			
		||||
            "role": "gateway",
 | 
			
		||||
            "transactions": "gg"
 | 
			
		||||
         }
 | 
			
		||||
    )";
 | 
			
		||||
    auto rawBackendPtr = static_cast<MockBackend*>(mockBackendPtr.get());
 | 
			
		||||
    EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence);
 | 
			
		||||
    runSpawn([&, this](auto yield) {
 | 
			
		||||
        auto const handler = AnyHandler{NoRippleCheckHandler{mockBackendPtr}};
 | 
			
		||||
        auto const req = json::parse(reqJson);
 | 
			
		||||
        auto const output = handler.process(req, Context{.yield = yield, .apiVersion = 1});
 | 
			
		||||
        ASSERT_FALSE(output);
 | 
			
		||||
 | 
			
		||||
        auto const err = rpc::makeError(output.error());
 | 
			
		||||
        EXPECT_EQ(err.at("error").as_string(), "lgrNotFound");
 | 
			
		||||
        EXPECT_EQ(err.at("error_message").as_string(), "ledgerNotFound");
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_F(RPCNoRippleCheckTest, LedgerNotExistViaHash)
 | 
			
		||||
{
 | 
			
		||||
    auto const rawBackendPtr = static_cast<MockBackend*>(mockBackendPtr.get());
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user