Compare commits

...

12 Commits

Author SHA1 Message Date
Alex Kremer
0eaaa1fb31 Add workaround for async_compose (#841)
Fixes #840
2023-09-18 18:52:32 +01:00
Alex Kremer
1846f629a5 AccountTx filtering by transaction type (#851)
Fixes #685
2023-09-18 18:52:00 +01:00
Alex Kremer
83af5af3c6 Remove deprecated cassandra options (#852)
Fixes #849
2023-09-18 13:40:38 +01:00
Alex Kremer
418a0ddbf2 Add libxrpl version to server_info output (#854)
Fixes #853
2023-09-18 13:39:01 +01:00
Alex Kremer
6cfbfda014 Repeatedly log on amendment block (#829)
Fixes #364
2023-09-13 13:34:02 +01:00
Alex Kremer
91648f98ad Fix malformed taker error to match rippled (#827)
Fixes #352
2023-09-11 19:39:10 +01:00
Sergey Kuznetsov
71e1637c5f Add options for better clangd support (#836)
Fixes #839
2023-09-11 17:53:30 +01:00
Sergey Kuznetsov
59cd2ce5aa Fix missing lock (#837) 2023-09-11 16:19:57 +01:00
Alex Kremer
d783edd57a Add working dir to git command executions (#828) 2023-09-11 13:40:22 +01:00
cyan317
1ce8a58167 Add number of requests to log (#838) 2023-09-11 12:58:45 +01:00
Peter Chen
92e5c4792b Change boost::json to json in unittests (#831) 2023-09-11 12:39:38 +01:00
Michael Legleux
d7f36733bc Link libstd++ and gcc lib statically (#830) 2023-08-24 12:41:08 +01:00
48 changed files with 942 additions and 462 deletions

1
.gitignore vendored
View File

@@ -1,6 +1,7 @@
*clio*.log
build*/
.build
.cache
.vscode
.python-version
CMakeUserPresets.json

View File

@@ -5,21 +5,27 @@
find_package (Git REQUIRED)
set (GIT_COMMAND rev-parse --short HEAD)
execute_process (COMMAND ${GIT_EXECUTABLE} ${GIT_COMMAND} OUTPUT_VARIABLE REV OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process (COMMAND ${GIT_EXECUTABLE} ${GIT_COMMAND}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE REV OUTPUT_STRIP_TRAILING_WHITESPACE)
set (GIT_COMMAND branch --show-current)
execute_process (COMMAND ${GIT_EXECUTABLE} ${GIT_COMMAND} OUTPUT_VARIABLE BRANCH OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process (COMMAND ${GIT_EXECUTABLE} ${GIT_COMMAND}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE BRANCH OUTPUT_STRIP_TRAILING_WHITESPACE)
if (BRANCH STREQUAL "")
set (BRANCH "dev")
endif ()
if (NOT (BRANCH MATCHES master OR BRANCH MATCHES release/*)) # for develop and any other branch name YYYYMMDDHMS-<branch>-<git-ref>
if (NOT (BRANCH MATCHES master OR BRANCH MATCHES release/*)) # for develop and any other branch name YYYYMMDDHMS-<branch>-<git-rev>
execute_process (COMMAND date +%Y%m%d%H%M%S OUTPUT_VARIABLE DATE OUTPUT_STRIP_TRAILING_WHITESPACE)
set (VERSION "${DATE}-${BRANCH}-${REV}")
else ()
set (GIT_COMMAND describe --tags)
execute_process (COMMAND ${GIT_EXECUTABLE} ${GIT_COMMAND} OUTPUT_VARIABLE TAG_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process (COMMAND ${GIT_EXECUTABLE} ${GIT_COMMAND}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE TAG_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE)
set (VERSION "${TAG_VERSION}-${REV}")
endif ()

View File

@@ -4,13 +4,14 @@ project(clio)
# ========================================================================== #
# Options #
# ========================================================================== #
option (verbose "Verbose build" FALSE)
option (verbose "Verbose build" FALSE)
option (tests "Build tests" FALSE)
option (docs "Generate doxygen docs" FALSE)
option (coverage "Build test coverage report" FALSE)
option (packaging "Create distribution packages" FALSE)
# ========================================================================== #
set (san "" CACHE STRING "Add sanitizer instrumentation")
set (CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
set_property (CACHE san PROPERTY STRINGS ";undefined;memory;address;thread")
# ========================================================================== #
@@ -135,7 +136,11 @@ target_sources (clio PRIVATE
# Clio server
add_executable (clio_server src/main/Main.cpp)
target_link_libraries (clio_server PUBLIC clio)
target_link_libraries (clio_server PRIVATE clio)
target_link_options(clio_server
PRIVATE
$<$<AND:$<NOT:$<BOOL:${APPLE}>>,$<NOT:$<BOOL:${san}>>>:-static-libstdc++ -static-libgcc>
)
# Unittesting
if (tests)
@@ -158,6 +163,7 @@ if (tests)
unittests/etl/ExtractorTests.cpp
unittests/etl/TransformerTests.cpp
unittests/etl/CacheLoaderTests.cpp
unittests/etl/AmendmentBlockHandlerTests.cpp
# RPC
unittests/rpc/ErrorTests.cpp
unittests/rpc/BaseTests.cpp
@@ -219,7 +225,7 @@ if (tests)
# See https://github.com/google/googletest/issues/3475
gtest_discover_tests (clio_tests DISCOVERY_TIMEOUT 10)
# Fix for dwarf5 bug on ci
# Fix for dwarf5 bug on ci
target_compile_options (clio PUBLIC -gdwarf-4)
target_compile_definitions (${TEST_TARGET} PUBLIC UNITTEST_BUILD)

View File

@@ -24,7 +24,7 @@ class Clio(ConanFile):
'fmt/10.0.0',
'grpc/1.50.1',
'openssl/1.1.1u',
'xrpl/1.12.0-b2',
'xrpl/1.12.0',
]
default_options = {

View File

@@ -16,21 +16,12 @@
//
// Advanced options. USE AT OWN RISK:
// ---
"max_connections_per_host": 1, // Defaults to 2
"core_connections_per_host": 1, // Defaults to 2
"max_concurrent_requests_threshold": 55000 // Defaults to ((max_read + max_write) / core_connections_per_host)
"core_connections_per_host": 1 // Defaults to 1
//
// Below options will use defaults from cassandra driver if left unspecified.
// See https://docs.datastax.com/en/developer/cpp-driver/2.0/api/struct.CassCluster/ for details.
// See https://docs.datastax.com/en/developer/cpp-driver/2.17/api/struct.CassCluster/ for details.
//
// "queue_size_event": 1,
// "queue_size_io": 2,
// "write_bytes_high_water_mark": 3,
// "write_bytes_low_water_mark": 4,
// "pending_requests_high_water_mark": 5,
// "pending_requests_low_water_mark": 6,
// "max_requests_per_flush": 7,
// "max_concurrent_creation": 8
// "queue_size_io": 2
//
// ---
}

View File

@@ -93,14 +93,15 @@ synchronous(FnType&& func)
if constexpr (!std::is_same<R, void>::value)
{
R res;
boost::asio::spawn(ctx, [&func, &res](auto yield) { res = func(yield); });
boost::asio::spawn(
ctx, [_ = boost::asio::make_work_guard(ctx), &func, &res](auto yield) { res = func(yield); });
ctx.run();
return res;
}
else
{
boost::asio::spawn(ctx, [&func](auto yield) { func(yield); });
boost::asio::spawn(ctx, [_ = boost::asio::make_work_guard(ctx), &func](auto yield) { func(yield); });
ctx.run();
}
}

View File

@@ -69,7 +69,7 @@ LedgerCache::getSuccessor(ripple::uint256 const& key, uint32_t seq) const
{
if (!full_)
return {};
std::shared_lock{mtx_};
std::shared_lock lck{mtx_};
successorReqCounter_++;
if (seq != latestSeq_)
return {};

View File

@@ -116,22 +116,10 @@ SettingsProvider::parseSettings() const
config_.valueOr<uint32_t>("max_write_requests_outstanding", settings.maxWriteRequestsOutstanding);
settings.maxReadRequestsOutstanding =
config_.valueOr<uint32_t>("max_read_requests_outstanding", settings.maxReadRequestsOutstanding);
settings.maxConnectionsPerHost =
config_.valueOr<uint32_t>("max_connections_per_host", settings.maxConnectionsPerHost);
settings.coreConnectionsPerHost =
config_.valueOr<uint32_t>("core_connections_per_host", settings.coreConnectionsPerHost);
settings.maxConcurrentRequestsThreshold = config_.valueOr<uint32_t>(
"max_concurrent_requests_threshold",
(settings.maxReadRequestsOutstanding + settings.maxWriteRequestsOutstanding) / settings.coreConnectionsPerHost);
settings.queueSizeIO = config_.maybeValue<uint32_t>("queue_size_io");
settings.queueSizeEvent = config_.maybeValue<uint32_t>("queue_size_event");
settings.writeBytesHighWatermark = config_.maybeValue<uint32_t>("write_bytes_high_water_mark");
settings.writeBytesLowWatermark = config_.maybeValue<uint32_t>("write_bytes_low_water_mark");
settings.pendingRequestsHighWatermark = config_.maybeValue<uint32_t>("pending_requests_high_water_mark");
settings.pendingRequestsLowWatermark = config_.maybeValue<uint32_t>("pending_requests_low_water_mark");
settings.maxRequestsPerFlush = config_.maybeValue<uint32_t>("max_requests_per_flush");
settings.maxConcurrentCreation = config_.maybeValue<uint32_t>("max_concurrent_creation");
auto const connectTimeoutSecond = config_.maybeValue<uint32_t>("connect_timeout");
if (connectTimeoutSecond)

View File

@@ -64,19 +64,6 @@ Cluster::Cluster(Settings const& settings) : ManagedObject{cass_cluster_new(), c
cass_cluster_set_connect_timeout(*this, settings.connectionTimeout.count());
cass_cluster_set_request_timeout(*this, settings.requestTimeout.count());
if (auto const rc =
cass_cluster_set_max_concurrent_requests_threshold(*this, settings.maxConcurrentRequestsThreshold);
rc != CASS_OK)
{
throw std::runtime_error(
fmt::format("Could not set max concurrent requests per host threshold: {}", cass_error_desc(rc)));
}
if (auto const rc = cass_cluster_set_max_connections_per_host(*this, settings.maxConnectionsPerHost); rc != CASS_OK)
{
throw std::runtime_error(fmt::format("Could not set max connections per host: {}", cass_error_desc(rc)));
}
if (auto const rc = cass_cluster_set_core_connections_per_host(*this, settings.coreConnectionsPerHost);
rc != CASS_OK)
{
@@ -90,71 +77,13 @@ Cluster::Cluster(Settings const& settings) : ManagedObject{cass_cluster_new(), c
throw std::runtime_error(fmt::format("Could not set queue size for IO per host: {}", cass_error_desc(rc)));
}
auto apply = []<typename ValueType, typename Fn>(
std::optional<ValueType> const& maybeValue, Fn&& fn) requires std::is_object_v<Fn>
{
if (maybeValue)
std::invoke(fn, maybeValue.value());
};
apply(settings.queueSizeEvent, [this](auto value) {
if (auto const rc = cass_cluster_set_queue_size_event(*this, value); rc != CASS_OK)
throw std::runtime_error(
fmt::format("Could not set queue size for events per host: {}", cass_error_desc(rc)));
});
apply(settings.writeBytesHighWatermark, [this](auto value) {
if (auto const rc = cass_cluster_set_write_bytes_high_water_mark(*this, value); rc != CASS_OK)
throw std::runtime_error(fmt::format("Could not set write bytes high water_mark: {}", cass_error_desc(rc)));
});
apply(settings.writeBytesLowWatermark, [this](auto value) {
if (auto const rc = cass_cluster_set_write_bytes_low_water_mark(*this, value); rc != CASS_OK)
throw std::runtime_error(fmt::format("Could not set write bytes low water mark: {}", cass_error_desc(rc)));
});
apply(settings.pendingRequestsHighWatermark, [this](auto value) {
if (auto const rc = cass_cluster_set_pending_requests_high_water_mark(*this, value); rc != CASS_OK)
throw std::runtime_error(
fmt::format("Could not set pending requests high water mark: {}", cass_error_desc(rc)));
});
apply(settings.pendingRequestsLowWatermark, [this](auto value) {
if (auto const rc = cass_cluster_set_pending_requests_low_water_mark(*this, value); rc != CASS_OK)
throw std::runtime_error(
fmt::format("Could not set pending requests low water mark: {}", cass_error_desc(rc)));
});
apply(settings.maxRequestsPerFlush, [this](auto value) {
if (auto const rc = cass_cluster_set_max_requests_per_flush(*this, value); rc != CASS_OK)
throw std::runtime_error(fmt::format("Could not set max requests per flush: {}", cass_error_desc(rc)));
});
apply(settings.maxConcurrentCreation, [this](auto value) {
if (auto const rc = cass_cluster_set_max_concurrent_creation(*this, value); rc != CASS_OK)
throw std::runtime_error(fmt::format("Could not set max concurrent creation: {}", cass_error_desc(rc)));
});
setupConnection(settings);
setupCertificate(settings);
setupCredentials(settings);
auto valueOrDefault = []<typename T>(std::optional<T> const& maybeValue) -> std::string {
return maybeValue ? to_string(*maybeValue) : "default";
};
LOG(log_.info()) << "Threads: " << settings.threads;
LOG(log_.info()) << "Max concurrent requests per host: " << settings.maxConcurrentRequestsThreshold;
LOG(log_.info()) << "Max connections per host: " << settings.maxConnectionsPerHost;
LOG(log_.info()) << "Core connections per host: " << settings.coreConnectionsPerHost;
LOG(log_.info()) << "IO queue size: " << queueSize;
LOG(log_.info()) << "Event queue size: " << valueOrDefault(settings.queueSizeEvent);
LOG(log_.info()) << "Write bytes high watermark: " << valueOrDefault(settings.writeBytesHighWatermark);
LOG(log_.info()) << "Write bytes low watermark: " << valueOrDefault(settings.writeBytesLowWatermark);
LOG(log_.info()) << "Pending requests high watermark: " << valueOrDefault(settings.pendingRequestsHighWatermark);
LOG(log_.info()) << "Pending requests low watermark: " << valueOrDefault(settings.pendingRequestsLowWatermark);
LOG(log_.info()) << "Max requests per flush: " << valueOrDefault(settings.maxRequestsPerFlush);
LOG(log_.info()) << "Max concurrent creation: " << valueOrDefault(settings.maxConcurrentCreation);
}
void

View File

@@ -73,45 +73,17 @@ struct Settings
uint32_t threads = std::thread::hardware_concurrency();
/** @brief The maximum number of outstanding write requests at any given moment */
uint32_t maxWriteRequestsOutstanding = 10'000;
uint32_t maxWriteRequestsOutstanding = 10'000u;
/** @brief The maximum number of outstanding read requests at any given moment */
uint32_t maxReadRequestsOutstanding = 100'000;
/** @brief The maximum number of connections per host */
uint32_t maxConnectionsPerHost = 2u;
uint32_t maxReadRequestsOutstanding = 100'000u;
/** @brief The number of connection per host to always have active */
uint32_t coreConnectionsPerHost = 2u;
/** @brief The maximum concurrent requests per connection; new connections will be created when reached */
uint32_t maxConcurrentRequestsThreshold =
(maxWriteRequestsOutstanding + maxReadRequestsOutstanding) / coreConnectionsPerHost;
/** @brief Size of the event queue */
std::optional<uint32_t> queueSizeEvent;
uint32_t coreConnectionsPerHost = 1u;
/** @brief Size of the IO queue */
std::optional<uint32_t> queueSizeIO;
/** @brief High watermark for bytes written */
std::optional<uint32_t> writeBytesHighWatermark;
/** @brief Low watermark for bytes written */
std::optional<uint32_t> writeBytesLowWatermark;
/** @brief High watermark for pending requests */
std::optional<uint32_t> pendingRequestsHighWatermark;
/** @brief Low watermark for pending requests */
std::optional<uint32_t> pendingRequestsLowWatermark;
/** @brief Maximum number of requests per flush */
std::optional<uint32_t> maxRequestsPerFlush;
/** @brief Maximum number of connections that will be created concurrently */
std::optional<uint32_t> maxConcurrentCreation;
/** @brief SSL certificate */
std::optional<std::string> certificate; // ssl context

View File

@@ -235,21 +235,15 @@ public:
while (true)
{
numReadRequestsOutstanding_ += numStatements;
// TODO: see if we can avoid using shared_ptr for self here
auto init = [this, &statements, &future]<typename Self>(Self& self) {
future.emplace(handle_.get().asyncExecute(
statements, [sself = std::make_shared<Self>(std::move(self))](auto&& res) mutable {
// Note: explicit work below needed on linux/gcc11
auto executor = boost::asio::get_associated_executor(*sself);
boost::asio::post(
executor,
[sself = std::move(sself),
res = std::move(res),
_ = boost::asio::make_work_guard(executor)]() mutable {
sself->complete(std::move(res));
sself.reset();
});
}));
auto sself = std::make_shared<Self>(std::move(self));
future.emplace(handle_.get().asyncExecute(statements, [sself](auto&& res) mutable {
boost::asio::post(
boost::asio::get_associated_executor(*sself),
[sself, res = std::move(res)]() mutable { sself->complete(std::move(res)); });
}));
};
auto res = boost::asio::async_compose<CompletionTokenType, void(ResultOrErrorType)>(
@@ -287,25 +281,21 @@ public:
while (true)
{
++numReadRequestsOutstanding_;
// TODO: see if we can avoid using shared_ptr for self here
auto init = [this, &statement, &future]<typename Self>(Self& self) {
future.emplace(handle_.get().asyncExecute(
statement, [sself = std::make_shared<Self>(std::move(self))](auto&&) mutable {
// Note: explicit work below needed on linux/gcc11
auto executor = boost::asio::get_associated_executor(*sself);
boost::asio::post(
executor, [sself = std::move(sself), _ = boost::asio::make_work_guard(executor)]() mutable {
sself->complete();
sself.reset();
});
}));
auto sself = std::make_shared<Self>(std::move(self));
future.emplace(handle_.get().asyncExecute(statement, [sself](auto&& res) mutable {
boost::asio::post(
boost::asio::get_associated_executor(*sself),
[sself, res = std::move(res)]() mutable { sself->complete(std::move(res)); });
}));
};
boost::asio::async_compose<CompletionTokenType, void()>(
auto res = boost::asio::async_compose<CompletionTokenType, void(ResultOrErrorType)>(
init, token, boost::asio::get_associated_executor(token));
--numReadRequestsOutstanding_;
if (auto res = future->get(); res)
if (res)
{
return res;
}
@@ -339,22 +329,15 @@ public:
futures.reserve(numOutstanding);
auto init = [this, &statements, &futures, &hadError, &numOutstanding]<typename Self>(Self& self) {
auto sself = std::make_shared<Self>(std::move(self)); // TODO: see if we can avoid this
auto executionHandler = [&hadError, &numOutstanding, sself = std::move(sself)](auto const& res) mutable {
auto sself = std::make_shared<Self>(std::move(self));
auto executionHandler = [&hadError, &numOutstanding, sself](auto const& res) mutable {
if (not res)
hadError = true;
// when all async operations complete unblock the result
if (--numOutstanding == 0)
{
// Note: explicit work below needed on linux/gcc11
auto executor = boost::asio::get_associated_executor(*sself);
boost::asio::post(
executor, [sself = std::move(sself), _ = boost::asio::make_work_guard(executor)]() mutable {
sself->complete();
sself.reset();
});
}
boost::asio::get_associated_executor(*sself), [sself]() mutable { sself->complete(); });
};
std::transform(

View File

@@ -73,7 +73,10 @@ void
invokeHelper(CassFuture* ptr, void* cbPtr)
{
// Note: can't use Future{ptr}.get() because double free will occur :/
// Note2: we are moving/copying it locally as a workaround for an issue we are seeing from asio recently.
// stackoverflow.com/questions/77004137/boost-asio-async-compose-gets-stuck-under-load
auto* cb = static_cast<FutureWithCallback::FnType*>(cbPtr);
auto local = std::make_unique<FutureWithCallback::FnType>(std::move(*cb));
if (auto const rc = cass_future_error_code(ptr); rc)
{
auto const errMsg = [&ptr](std::string const& label) {
@@ -82,11 +85,11 @@ invokeHelper(CassFuture* ptr, void* cbPtr)
cass_future_error_message(ptr, &message, &len);
return label + ": " + std::string{message, len};
}("invokeHelper");
(*cb)(Error{CassandraError{errMsg, rc}});
(*local)(Error{CassandraError{errMsg, rc}});
}
else
{
(*cb)(Result{cass_future_get_result(ptr)});
(*local)(Result{cass_future_get_result(ptr)});
}
}

View File

@@ -47,7 +47,8 @@ ETLService::runETLPipeline(uint32_t startSequence, uint32_t numExtractors)
extractors.push_back(std::make_unique<ExtractorType>(
pipe, networkValidatedLedgers_, ledgerFetcher_, startSequence + i, finishSequence_, state_));
auto transformer = TransformerType{pipe, backend_, ledgerLoader_, ledgerPublisher_, startSequence, state_};
auto transformer =
TransformerType{pipe, backend_, ledgerLoader_, ledgerPublisher_, amendmentBlockHandler_, startSequence, state_};
transformer.waitTillFinished(); // suspend current thread until exit condition is met
pipe.cleanup(); // TODO: this should probably happen automatically using destructor
@@ -110,12 +111,8 @@ ETLService::monitor()
}
catch (std::runtime_error const& e)
{
setAmendmentBlocked();
log_.fatal()
<< "Failed to load initial ledger, Exiting monitor loop: " << e.what()
<< " Possible cause: The ETL node is not compatible with the version of the rippled lib Clio is using.";
return;
LOG(log_.fatal()) << "Failed to load initial ledger: " << e.what();
return amendmentBlockHandler_.onAmendmentBlock();
}
if (ledger)
@@ -259,6 +256,7 @@ ETLService::ETLService(
, ledgerFetcher_(backend, balancer)
, ledgerLoader_(backend, balancer, ledgerFetcher_, state_)
, ledgerPublisher_(ioc, backend, subscriptions, state_)
, amendmentBlockHandler_(ioc, state_)
{
startSequence_ = config.maybeValue<uint32_t>("start_sequence");
finishSequence_ = config.maybeValue<uint32_t>("finish_sequence");

View File

@@ -24,6 +24,7 @@
#include <etl/LoadBalancer.h>
#include <etl/Source.h>
#include <etl/SystemState.h>
#include <etl/impl/AmendmentBlock.h>
#include <etl/impl/CacheLoader.h>
#include <etl/impl/ExtractionDataPipe.h>
#include <etl/impl/Extractor.h>
@@ -35,6 +36,7 @@
#include <util/log/Logger.h>
#include <ripple/proto/org/xrpl/rpc/v1/xrp_ledger.grpc.pb.h>
#include <boost/asio/steady_timer.hpp>
#include <grpcpp/grpcpp.h>
#include <memory>
@@ -76,7 +78,9 @@ class ETLService
using ExtractorType = etl::detail::Extractor<DataPipeType, NetworkValidatedLedgersType, LedgerFetcherType>;
using LedgerLoaderType = etl::detail::LedgerLoader<LoadBalancerType, LedgerFetcherType>;
using LedgerPublisherType = etl::detail::LedgerPublisher<SubscriptionManagerType>;
using TransformerType = etl::detail::Transformer<DataPipeType, LedgerLoaderType, LedgerPublisherType>;
using AmendmentBlockHandlerType = etl::detail::AmendmentBlockHandler<>;
using TransformerType =
etl::detail::Transformer<DataPipeType, LedgerLoaderType, LedgerPublisherType, AmendmentBlockHandlerType>;
util::Logger log_{"ETL"};
@@ -91,6 +95,7 @@ class ETLService
LedgerFetcherType ledgerFetcher_;
LedgerLoaderType ledgerLoader_;
LedgerPublisherType ledgerPublisher_;
AmendmentBlockHandlerType amendmentBlockHandler_;
SystemState state_;
@@ -267,14 +272,5 @@ private:
*/
void
doWork();
/**
* @brief Sets amendment blocked flag.
*/
void
setAmendmentBlocked()
{
state_.isAmendmentBlocked = true;
}
};
} // namespace etl

View File

@@ -36,10 +36,18 @@ struct SystemState
*/
bool isReadOnly = false;
std::atomic_bool isWriting = false; /**< @brief Whether the process is writing to the database. */
std::atomic_bool isStopping = false; /**< @brief Whether the software is stopping. */
std::atomic_bool writeConflict = false; /**< @brief Whether a write conflict was detected. */
std::atomic_bool isAmendmentBlocked = false; /**< @brief Whether we detected an amendment block. */
std::atomic_bool isWriting = false; /**< @brief Whether the process is writing to the database. */
std::atomic_bool isStopping = false; /**< @brief Whether the software is stopping. */
std::atomic_bool writeConflict = false; /**< @brief Whether a write conflict was detected. */
/**
* @brief Whether clio detected an amendment block.
*
* Being amendment blocked means that Clio was compiled with libxrpl that does not yet support some field that
* arrived from rippled and therefore can't extract the ledger diff. When this happens, Clio can't proceed with ETL
* and should log this error and only handle RPC requests.
*/
std::atomic_bool isAmendmentBlocked = false;
};
} // namespace etl

View File

@@ -0,0 +1,96 @@
//------------------------------------------------------------------------------
/*
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.
*/
//==============================================================================
#pragma once
#include <etl/SystemState.h>
#include <util/log/Logger.h>
#include <boost/asio/io_context.hpp>
#include <boost/asio/steady_timer.hpp>
#include <chrono>
#include <functional>
namespace etl::detail {
struct AmendmentBlockAction
{
void
operator()()
{
static util::Logger log{"ETL"};
LOG(log.fatal())
<< "Can't process new ledgers: The current ETL source is not compatible with the version of the "
"libxrpl Clio is currently using. Please upgrade Clio to a newer version.";
}
};
template <typename ActionCallableType = AmendmentBlockAction>
class AmendmentBlockHandler
{
std::reference_wrapper<boost::asio::io_context> ctx_;
std::reference_wrapper<SystemState> state_;
boost::asio::steady_timer timer_;
std::chrono::milliseconds interval_;
ActionCallableType action_;
public:
template <typename DurationType = std::chrono::seconds>
AmendmentBlockHandler(
boost::asio::io_context& ioc,
SystemState& state,
DurationType interval = DurationType{1},
ActionCallableType&& action = ActionCallableType())
: ctx_{std::ref(ioc)}
, state_{std::ref(state)}
, timer_{ioc}
, interval_{std::chrono::duration_cast<std::chrono::milliseconds>(interval)}
, action_{std::move(action)}
{
}
~AmendmentBlockHandler()
{
boost::asio::post(ctx_.get(), [this]() { timer_.cancel(); });
}
void
onAmendmentBlock()
{
state_.get().isAmendmentBlocked = true;
startReportingTimer();
}
private:
void
startReportingTimer()
{
action_();
timer_.expires_after(interval_);
timer_.async_wait([this](auto ec) {
if (!ec)
boost::asio::post(ctx_.get(), [this] { startReportingTimer(); });
});
}
};
} // namespace etl::detail

View File

@@ -68,6 +68,7 @@ class CacheLoader
std::vector<ClioPeer> clioPeers_;
std::thread thread_;
std::atomic_bool stopping_ = false;
public:
@@ -115,6 +116,8 @@ public:
~CacheLoader()
{
stop();
if (thread_.joinable())
thread_.join();
}
/**
@@ -367,7 +370,7 @@ private:
LOG(log_.info()) << "Loading cache. num cursors = " << cursors.size() - 1;
LOG(log_.trace()) << "cursors = " << cursorStr.str();
boost::asio::post(ioContext_.get(), [this, seq, cursors = std::move(cursors)]() {
thread_ = std::thread{[this, seq, cursors = std::move(cursors)]() {
auto startTime = std::chrono::system_clock::now();
auto markers = std::make_shared<std::atomic_int>(0);
auto numRemaining = std::make_shared<std::atomic_int>(cursors.size() - 1);
@@ -425,7 +428,7 @@ private:
}
});
}
});
}};
}
};

View File

@@ -21,6 +21,7 @@
#include <data/BackendInterface.h>
#include <etl/SystemState.h>
#include <etl/impl/AmendmentBlock.h>
#include <etl/impl/LedgerLoader.h>
#include <util/LedgerUtils.h>
#include <util/Profiler.h>
@@ -47,7 +48,11 @@ namespace etl::detail {
/**
* @brief Transformer thread that prepares new ledger out of raw data from GRPC.
*/
template <typename DataPipeType, typename LedgerLoaderType, typename LedgerPublisherType>
template <
typename DataPipeType,
typename LedgerLoaderType,
typename LedgerPublisherType,
typename AmendmentBlockHandlerType>
class Transformer
{
using GetLedgerResponseType = typename LedgerLoaderType::GetLedgerResponseType;
@@ -59,6 +64,8 @@ class Transformer
std::shared_ptr<BackendInterface> backend_;
std::reference_wrapper<LedgerLoaderType> loader_;
std::reference_wrapper<LedgerPublisherType> publisher_;
std::reference_wrapper<AmendmentBlockHandlerType> amendmentBlockHandler_;
uint32_t startSequence_;
std::reference_wrapper<SystemState> state_; // shared state for ETL
@@ -76,12 +83,14 @@ public:
std::shared_ptr<BackendInterface> backend,
LedgerLoaderType& loader,
LedgerPublisherType& publisher,
AmendmentBlockHandlerType& amendmentBlockHandler,
uint32_t startSequence,
SystemState& state)
: pipe_(std::ref(pipe))
: pipe_{std::ref(pipe)}
, backend_{backend}
, loader_(std::ref(loader))
, publisher_(std::ref(publisher))
, loader_{std::ref(loader)}
, publisher_{std::ref(publisher)}
, amendmentBlockHandler_{std::ref(amendmentBlockHandler)}
, startSequence_{startSequence}
, state_{std::ref(state)}
{
@@ -185,11 +194,9 @@ private:
}
catch (std::runtime_error const& e)
{
setAmendmentBlocked();
LOG(log_.fatal()) << "Failed to build next ledger: " << e.what();
log_.fatal()
<< "Failed to build next ledger: " << e.what()
<< " Possible cause: The ETL node is not compatible with the version of the rippled lib Clio is using.";
amendmentBlockHandler_.get().onAmendmentBlock();
return {ripple::LedgerHeader{}, false};
}
@@ -238,7 +245,7 @@ private:
LOG(log_.debug()) << "object neighbors not included. using cache";
if (!backend_->cache().isFull() || backend_->cache().latestLedgerSequence() != lgrInfo.seq - 1)
throw std::runtime_error("Cache is not full, but object neighbors were not included");
throw std::logic_error("Cache is not full, but object neighbors were not included");
auto const blob = obj.mutable_data();
auto checkBookBase = false;
@@ -288,7 +295,7 @@ private:
{
LOG(log_.debug()) << "object neighbors not included. using cache";
if (!backend_->cache().isFull() || backend_->cache().latestLedgerSequence() != lgrInfo.seq)
throw std::runtime_error("Cache is not full, but object neighbors were not included");
throw std::logic_error("Cache is not full, but object neighbors were not included");
for (auto const& obj : cacheUpdates)
{
@@ -423,19 +430,6 @@ private:
{
state_.get().writeConflict = conflict;
}
/**
* @brief Sets the amendment blocked flag.
*
* Being amendment blocked means that Clio was compiled with libxrpl that does not yet support some field that
* arrived from rippled and therefore can't extract the ledger diff. When this happens, Clio can't proceed with ETL
* and should log this error and only handle RPC requests.
*/
void
setAmendmentBlocked()
{
state_.get().isAmendmentBlocked = true;
}
};
} // namespace etl::detail

View File

@@ -19,10 +19,15 @@
#pragma once
#include <util/JsonUtils.h>
#include <ripple/protocol/jss.h>
/** @brief Helper macro for borrowing from ripple::jss static (J)son (S)trings. */
#define JS(x) ripple::jss::x.c_str()
/** @brief Access the lower case copy of a static (J)son (S)tring. */
#define JSL(x) util::toLower(JS(x))
/** @brief Provides access to (SF)ield name (S)trings. */
#define SFS(x) ripple::x.jsonName.c_str()

View File

@@ -141,6 +141,7 @@ accountFromStringStrict(std::string const& account)
else
return {};
}
std::pair<std::shared_ptr<ripple::STTx const>, std::shared_ptr<ripple::STObject const>>
deserializeTxPlusMeta(data::TransactionAndMetadata const& blobs)
{
@@ -654,8 +655,10 @@ traverseOwnedNodes(
}
auto end = std::chrono::system_clock::now();
LOG(gLog.debug()) << "Time loading owned directories: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << " milliseconds";
LOG(gLog.debug()) << fmt::format(
"Time loading owned directories: {} milliseconds, entries size: {}",
std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(),
keys.size());
auto [objects, timeDiff] = util::timed([&]() { return backend.fetchLedgerObjects(keys, sequence, yield); });

View File

@@ -22,6 +22,9 @@
#include <rpc/common/Concepts.h>
#include <rpc/common/Specs.h>
#include <rpc/common/Types.h>
#include <util/JsonUtils.h>
#include <string_view>
namespace rpc::modifiers {
@@ -68,4 +71,32 @@ public:
}
};
/**
* @brief Convert input string to lower case.
*
* Note: the conversion is only performed if the input value is a string.
*/
struct ToLower final
{
/**
* @brief Update the input string to lower case.
*
* @param value The JSON value representing the outer object
* @param key The key used to retrieve the modified value from the outer object
* @return Possibly an error
*/
[[nodiscard]] MaybeError
modify(boost::json::value& value, std::string_view key) const
{
if (not value.is_object() or not value.as_object().contains(key.data()))
return {}; // ignore. field does not exist, let 'required' fail instead
if (not value.as_object().at(key.data()).is_string())
return {}; // ignore for non-string types
value.as_object()[key.data()] = util::toLower(value.as_object().at(key.data()).as_string().c_str());
return {};
}
};
} // namespace rpc::modifiers

View File

@@ -21,6 +21,7 @@
namespace rpc {
// found here : https://xrpl.org/ledger_entry.html#:~:text=valid%20fields%20are%3A-,index,-account_root
std::unordered_map<std::string, ripple::LedgerEntryType> const AccountObjectsHandler::TYPESMAP{
{"state", ripple::ltRIPPLE_STATE},
{"ticket", ripple::ltTICKET},

View File

@@ -18,10 +18,50 @@
//==============================================================================
#include <rpc/handlers/AccountTx.h>
#include <util/JsonUtils.h>
#include <util/Profiler.h>
namespace rpc {
// found here : https://xrpl.org/transaction-types.html
// TODO [https://github.com/XRPLF/clio/issues/856]: add AMMBid, AMMCreate, AMMDelete, AMMDeposit, AMMVote, AMMWithdraw
std::unordered_map<std::string, ripple::TxType> const AccountTxHandler::TYPESMAP{
{JSL(AccountSet), ripple::ttACCOUNT_SET},
{JSL(AccountDelete), ripple::ttACCOUNT_DELETE},
{JSL(CheckCancel), ripple::ttCHECK_CANCEL},
{JSL(CheckCash), ripple::ttCHECK_CASH},
{JSL(CheckCreate), ripple::ttCHECK_CREATE},
{JSL(Clawback), ripple::ttCLAWBACK},
{JSL(DepositPreauth), ripple::ttDEPOSIT_PREAUTH},
{JSL(EscrowCancel), ripple::ttESCROW_CANCEL},
{JSL(EscrowCreate), ripple::ttESCROW_CREATE},
{JSL(EscrowFinish), ripple::ttESCROW_FINISH},
{JSL(NFTokenAcceptOffer), ripple::ttNFTOKEN_ACCEPT_OFFER},
{JSL(NFTokenBurn), ripple::ttNFTOKEN_BURN},
{JSL(NFTokenCancelOffer), ripple::ttNFTOKEN_CANCEL_OFFER},
{JSL(NFTokenCreateOffer), ripple::ttNFTOKEN_CREATE_OFFER},
{JSL(NFTokenMint), ripple::ttNFTOKEN_MINT},
{JSL(OfferCancel), ripple::ttOFFER_CANCEL},
{JSL(OfferCreate), ripple::ttOFFER_CREATE},
{JSL(Payment), ripple::ttPAYMENT},
{JSL(PaymentChannelClaim), ripple::ttPAYCHAN_CLAIM},
{JSL(PaymentChannelCreate), ripple::ttCHECK_CREATE},
{JSL(PaymentChannelFund), ripple::ttPAYCHAN_FUND},
{JSL(SetRegularKey), ripple::ttREGULAR_KEY_SET},
{JSL(SignerListSet), ripple::ttSIGNER_LIST_SET},
{JSL(TicketCreate), ripple::ttTICKET_CREATE},
{JSL(TrustSet), ripple::ttTRUST_SET},
};
// TODO: should be std::views::keys when clang supports it
std::unordered_set<std::string> const AccountTxHandler::TYPES_KEYS = [] {
std::unordered_set<std::string> keys;
std::transform(TYPESMAP.begin(), TYPESMAP.end(), std::inserter(keys, keys.begin()), [](auto const& pair) {
return pair.first;
});
return keys;
}();
// TODO: this is currently very similar to nft_history but its own copy for time
// being. we should aim to reuse common logic in some way in the future.
AccountTxHandler::Result
@@ -116,6 +156,18 @@ AccountTxHandler::process(AccountTxHandler::Input input, Context const& ctx) con
auto [txn, meta] = toExpandedJson(txnPlusMeta, NFTokenjson::ENABLE);
obj[JS(meta)] = std::move(meta);
obj[JS(tx)] = std::move(txn);
if (obj[JS(tx)].as_object().contains(JS(TransactionType)))
{
auto const objTransactionType = obj[JS(tx)].as_object()[JS(TransactionType)];
auto const strType = util::toLower(objTransactionType.as_string().c_str());
// if transactionType does not match
if (input.transactionType.has_value() && AccountTxHandler::TYPESMAP.contains(strType) &&
AccountTxHandler::TYPESMAP.at(strType) != input.transactionType.value())
continue;
}
obj[JS(tx)].as_object()[JS(ledger_index)] = txnPlusMeta.ledgerSequence;
obj[JS(tx)].as_object()[JS(date)] = txnPlusMeta.date;
}
@@ -208,6 +260,12 @@ tag_invoke(boost::json::value_to_tag<AccountTxHandler::Input>, boost::json::valu
jsonObject.at(JS(marker)).as_object().at(JS(ledger)).as_int64(),
jsonObject.at(JS(marker)).as_object().at(JS(seq)).as_int64()};
if (jsonObject.contains("tx_type"))
{
auto objTransactionType = jsonObject.at("tx_type");
input.transactionType = AccountTxHandler::TYPESMAP.at(objTransactionType.as_string().c_str());
}
return input;
}

View File

@@ -39,6 +39,9 @@ class AccountTxHandler
util::Logger log_{"RPC"};
std::shared_ptr<BackendInterface> sharedPtrBackend_;
static std::unordered_map<std::string, ripple::TxType> const TYPESMAP;
static const std::unordered_set<std::string> TYPES_KEYS;
public:
// no max limit
static auto constexpr LIMIT_MIN = 1;
@@ -77,6 +80,7 @@ public:
bool forward = false;
std::optional<uint32_t> limit;
std::optional<Marker> marker;
std::optional<ripple::TxType> transactionType;
};
using Result = HandlerReturnType<Output>;
@@ -109,6 +113,12 @@ public:
{JS(ledger), validation::Required{}, validation::Type<uint32_t>{}},
{JS(seq), validation::Required{}, validation::Type<uint32_t>{}},
}},
{
"tx_type",
validation::Type<std::string>{},
modifiers::ToLower{},
validation::OneOf<std::string>(TYPES_KEYS.cbegin(), TYPES_KEYS.cend()),
},
};
return rpcSpec;

View File

@@ -28,6 +28,7 @@
#include <rpc/common/Validators.h>
#include <ripple/basics/chrono.h>
#include <ripple/protocol/BuildInfo.h>
#include <chrono>
#include <fmt/core.h>
@@ -87,6 +88,7 @@ public:
std::chrono::time_point<std::chrono::system_clock> time = std::chrono::system_clock::now();
std::chrono::seconds uptime = {};
std::string clioVersion = Build::getClioVersionString();
std::string xrplVersion = ripple::BuildInfo::getVersionString();
std::optional<boost::json::object> rippledInfo = std::nullopt;
ValidatedLedgerSection validatedLedger = {};
CacheSection cache = {};
@@ -194,6 +196,7 @@ private:
{JS(time), to_string(std::chrono::floor<std::chrono::microseconds>(info.time))},
{JS(uptime), info.uptime.count()},
{"clio_version", info.clioVersion},
{"libxrpl_version", info.xrplVersion},
{JS(validated_ledger), value_from(info.validatedLedger)},
{"cache", value_from(info.cache)},
};

View File

@@ -21,6 +21,7 @@
#include <data/BackendInterface.h>
#include <rpc/RPCHelpers.h>
#include <rpc/common/MetaProcessors.h>
#include <rpc/common/Types.h>
#include <rpc/common/Validators.h>
@@ -95,7 +96,11 @@ public:
return Error{Status{RippledError::rpcINVALID_PARAMS, "snapshotNotBool"}};
if (book.as_object().contains("taker"))
if (auto const err = validation::AccountValidator.verify(book.as_object(), "taker"); !err)
if (auto const err = meta::WithCustomError(
validation::AccountValidator,
Status{RippledError::rpcBAD_ISSUER, "Issuer account malformed."})
.verify(book.as_object(), "taker");
!err)
return err;
auto const parsedBook = parseBook(book.as_object());

View File

@@ -21,6 +21,8 @@
#include <boost/json.hpp>
#include <algorithm>
#include <cctype>
#include <string>
/**
@@ -28,6 +30,13 @@
*/
namespace util {
inline std::string
toLower(std::string str)
{
std::transform(std::begin(str), std::end(str), std::begin(str), [](unsigned char c) { return std::tolower(c); });
return str;
}
/**
* @brief Removes any detected secret information from a response JSON object.
*

View File

@@ -66,12 +66,12 @@ public:
* @brief Send via shared_ptr of string, that enables SubscriptionManager to publish to clients.
*
* @param msg The message to send
* @throws Not supported unless implemented in child classes. Will always throw std::runtime_error.
* @throws Not supported unless implemented in child classes. Will always throw std::logic_error.
*/
virtual void
send(std::shared_ptr<std::string> msg)
{
throw std::runtime_error("web server can not send the shared payload");
throw std::logic_error("web server can not send the shared payload");
}
/**

View File

@@ -53,20 +53,11 @@ TEST_F(SettingsProviderTest, Defaults)
EXPECT_EQ(settings.requestTimeout, std::chrono::milliseconds{0});
EXPECT_EQ(settings.maxWriteRequestsOutstanding, 10'000);
EXPECT_EQ(settings.maxReadRequestsOutstanding, 100'000);
EXPECT_EQ(settings.maxConnectionsPerHost, 2);
EXPECT_EQ(settings.coreConnectionsPerHost, 2);
EXPECT_EQ(settings.maxConcurrentRequestsThreshold, (100'000 + 10'000) / 2);
EXPECT_EQ(settings.coreConnectionsPerHost, 1);
EXPECT_EQ(settings.certificate, std::nullopt);
EXPECT_EQ(settings.username, std::nullopt);
EXPECT_EQ(settings.password, std::nullopt);
EXPECT_EQ(settings.queueSizeIO, std::nullopt);
EXPECT_EQ(settings.queueSizeEvent, std::nullopt);
EXPECT_EQ(settings.writeBytesHighWatermark, std::nullopt);
EXPECT_EQ(settings.writeBytesLowWatermark, std::nullopt);
EXPECT_EQ(settings.pendingRequestsHighWatermark, std::nullopt);
EXPECT_EQ(settings.pendingRequestsLowWatermark, std::nullopt);
EXPECT_EQ(settings.maxRequestsPerFlush, std::nullopt);
EXPECT_EQ(settings.maxConcurrentCreation, std::nullopt);
auto const* cp = std::get_if<Settings::ContactPoints>(&settings.connectionInfo);
ASSERT_TRUE(cp != nullptr);
@@ -103,69 +94,16 @@ TEST_F(SettingsProviderTest, SimpleConfig)
EXPECT_EQ(provider.getTablePrefix(), "prefix");
}
TEST_F(SettingsProviderTest, DriverOptionCalculation)
{
Config cfg{json::parse(R"({
"contact_points": "123.123.123.123",
"max_write_requests_outstanding": 100,
"max_read_requests_outstanding": 200
})")};
SettingsProvider provider{cfg};
auto const settings = provider.getSettings();
EXPECT_EQ(settings.maxReadRequestsOutstanding, 200);
EXPECT_EQ(settings.maxWriteRequestsOutstanding, 100);
EXPECT_EQ(settings.maxConnectionsPerHost, 2);
EXPECT_EQ(settings.coreConnectionsPerHost, 2);
EXPECT_EQ(settings.maxConcurrentRequestsThreshold, 150); // calculated from above
}
TEST_F(SettingsProviderTest, DriverOptionSecifiedMaxConcurrentRequestsThreshold)
{
Config cfg{json::parse(R"({
"contact_points": "123.123.123.123",
"max_write_requests_outstanding": 100,
"max_read_requests_outstanding": 200,
"max_connections_per_host": 5,
"core_connections_per_host": 4,
"max_concurrent_requests_threshold": 1234
})")};
SettingsProvider provider{cfg};
auto const settings = provider.getSettings();
EXPECT_EQ(settings.maxReadRequestsOutstanding, 200);
EXPECT_EQ(settings.maxWriteRequestsOutstanding, 100);
EXPECT_EQ(settings.maxConnectionsPerHost, 5);
EXPECT_EQ(settings.coreConnectionsPerHost, 4);
EXPECT_EQ(settings.maxConcurrentRequestsThreshold, 1234);
}
TEST_F(SettingsProviderTest, DriverOptionalOptionsSpecified)
{
Config cfg{json::parse(R"({
"contact_points": "123.123.123.123",
"queue_size_event": 1,
"queue_size_io": 2,
"write_bytes_high_water_mark": 3,
"write_bytes_low_water_mark": 4,
"pending_requests_high_water_mark": 5,
"pending_requests_low_water_mark": 6,
"max_requests_per_flush": 7,
"max_concurrent_creation": 8
"queue_size_io": 2
})")};
SettingsProvider provider{cfg};
auto const settings = provider.getSettings();
EXPECT_EQ(settings.queueSizeEvent, 1);
EXPECT_EQ(settings.queueSizeIO, 2);
EXPECT_EQ(settings.writeBytesHighWatermark, 3);
EXPECT_EQ(settings.writeBytesLowWatermark, 4);
EXPECT_EQ(settings.pendingRequestsHighWatermark, 5);
EXPECT_EQ(settings.pendingRequestsLowWatermark, 6);
EXPECT_EQ(settings.maxRequestsPerFlush, 7);
EXPECT_EQ(settings.maxConcurrentCreation, 8);
}
TEST_F(SettingsProviderTest, SecureBundleConfig)

View File

@@ -0,0 +1,50 @@
//------------------------------------------------------------------------------
/*
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 <util/FakeAmendmentBlockAction.h>
#include <util/Fixtures.h>
#include <etl/impl/AmendmentBlock.h>
#include <gtest/gtest.h>
using namespace testing;
using namespace etl;
class AmendmentBlockHandlerTest : public NoLoggerFixture
{
protected:
using AmendmentBlockHandlerType = detail::AmendmentBlockHandler<FakeAmendmentBlockAction>;
boost::asio::io_context ioc_;
};
TEST_F(AmendmentBlockHandlerTest, CallToOnAmendmentBlockSetsStateAndRepeatedlyCallsAction)
{
std::size_t callCount = 0;
SystemState state;
AmendmentBlockHandlerType handler{ioc_, state, std::chrono::nanoseconds{1}, {std::ref(callCount)}};
EXPECT_FALSE(state.isAmendmentBlocked);
handler.onAmendmentBlock();
EXPECT_TRUE(state.isAmendmentBlocked);
ioc_.run_for(std::chrono::milliseconds{1});
EXPECT_TRUE(callCount >= 10);
}

View File

@@ -20,6 +20,7 @@
#include <etl/impl/Transformer.h>
#include <util/FakeFetchResponse.h>
#include <util/Fixtures.h>
#include <util/MockAmendmentBlockHandler.h>
#include <util/MockExtractionDataPipe.h>
#include <util/MockLedgerLoader.h>
#include <util/MockLedgerPublisher.h>
@@ -47,11 +48,14 @@ protected:
using ExtractionDataPipeType = MockExtractionDataPipe;
using LedgerLoaderType = MockLedgerLoader;
using LedgerPublisherType = MockLedgerPublisher;
using TransformerType = etl::detail::Transformer<ExtractionDataPipeType, LedgerLoaderType, LedgerPublisherType>;
using AmendmentBlockHandlerType = MockAmendmentBlockHandler;
using TransformerType = etl::detail::
Transformer<ExtractionDataPipeType, LedgerLoaderType, LedgerPublisherType, AmendmentBlockHandlerType>;
ExtractionDataPipeType dataPipe_;
LedgerLoaderType ledgerLoader_;
LedgerPublisherType ledgerPublisher_;
AmendmentBlockHandlerType amendmentBlockHandler_;
SystemState state_;
std::unique_ptr<TransformerType> transformer_;
@@ -82,8 +86,8 @@ TEST_F(ETLTransformerTest, StopsOnWriteConflict)
EXPECT_CALL(dataPipe_, popNext).Times(0);
EXPECT_CALL(ledgerPublisher_, publish(_)).Times(0);
transformer_ =
std::make_unique<TransformerType>(dataPipe_, mockBackendPtr, ledgerLoader_, ledgerPublisher_, 0, state_);
transformer_ = std::make_unique<TransformerType>(
dataPipe_, mockBackendPtr, ledgerLoader_, ledgerPublisher_, amendmentBlockHandler_, 0, state_);
transformer_->waitTillFinished(); // explicitly joins the thread
}
@@ -114,8 +118,8 @@ TEST_F(ETLTransformerTest, StopsOnEmptyFetchResponse)
EXPECT_CALL(*rawBackendPtr, doFinishWrites).Times(AtLeast(1));
EXPECT_CALL(ledgerPublisher_, publish(_)).Times(AtLeast(1));
transformer_ =
std::make_unique<TransformerType>(dataPipe_, mockBackendPtr, ledgerLoader_, ledgerPublisher_, 0, state_);
transformer_ = std::make_unique<TransformerType>(
dataPipe_, mockBackendPtr, ledgerLoader_, ledgerPublisher_, amendmentBlockHandler_, 0, state_);
// after 10ms we start spitting out empty responses which means the extractor is finishing up
// this is normally combined with stopping the entire thing by setting the isStopping flag.
@@ -147,6 +151,8 @@ TEST_F(ETLTransformerTest, DoesNotPublishIfCanNotBuildNextLedger)
// should not call publish
EXPECT_CALL(ledgerPublisher_, publish(_)).Times(0);
transformer_ =
std::make_unique<TransformerType>(dataPipe_, mockBackendPtr, ledgerLoader_, ledgerPublisher_, 0, state_);
transformer_ = std::make_unique<TransformerType>(
dataPipe_, mockBackendPtr, ledgerLoader_, ledgerPublisher_, amendmentBlockHandler_, 0, state_);
}
// TODO: implement tests for amendment block. requires more refactoring

View File

@@ -568,3 +568,25 @@ TEST_F(RPCBaseTest, ClampingModifier)
ASSERT_TRUE(spec.process(passingInput3));
ASSERT_EQ(passingInput3.at("amount").as_uint64(), 20u); // clamped
}
TEST_F(RPCBaseTest, ToLowerModifier)
{
auto spec = RpcSpec{
{"str", ToLower{}},
};
auto passingInput = json::parse(R"({ "str": "TesT" })");
ASSERT_TRUE(spec.process(passingInput));
ASSERT_EQ(passingInput.at("str").as_string(), "test");
auto passingInput2 = json::parse(R"({ "str2": "TesT" })");
ASSERT_TRUE(spec.process(passingInput2)); // no str no problem
auto passingInput3 = json::parse(R"({ "str": "already lower case" })");
ASSERT_TRUE(spec.process(passingInput3));
ASSERT_EQ(passingInput3.at("str").as_string(), "already lower case");
auto passingInput4 = json::parse(R"({ "str": "" })");
ASSERT_TRUE(spec.process(passingInput4)); // empty str no problem
ASSERT_EQ(passingInput4.at("str").as_string(), "");
}

View File

@@ -30,6 +30,7 @@
using namespace rpc;
using namespace testing;
namespace json = boost::json;
constexpr static auto CLIENT_IP = "127.0.0.1";
@@ -54,7 +55,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsFalseIfClioOnly)
auto const rawHandlerProviderPtr = static_cast<MockHandlerProvider*>(handlerProvider.get());
auto const apiVersion = 2u;
auto const method = "test";
auto const params = boost::json::parse("{}");
auto const params = json::parse("{}");
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(true));
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
@@ -74,7 +75,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsTrueIfProxied)
auto const rawHandlerProviderPtr = static_cast<MockHandlerProvider*>(handlerProvider.get());
auto const apiVersion = 2u;
auto const method = "submit";
auto const params = boost::json::parse("{}");
auto const params = json::parse("{}");
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(false));
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
@@ -94,7 +95,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsTrueIfCurrentLedgerSpecified)
auto const rawHandlerProviderPtr = static_cast<MockHandlerProvider*>(handlerProvider.get());
auto const apiVersion = 2u;
auto const method = "anymethod";
auto const params = boost::json::parse(R"({"ledger_index": "current"})");
auto const params = json::parse(R"({"ledger_index": "current"})");
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(false));
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
@@ -114,7 +115,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsTrueIfClosedLedgerSpecified)
auto const rawHandlerProviderPtr = static_cast<MockHandlerProvider*>(handlerProvider.get());
auto const apiVersion = 2u;
auto const method = "anymethod";
auto const params = boost::json::parse(R"({"ledger_index": "closed"})");
auto const params = json::parse(R"({"ledger_index": "closed"})");
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(false));
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
@@ -134,7 +135,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsTrueIfAccountInfoWithQueueSpe
auto const rawHandlerProviderPtr = static_cast<MockHandlerProvider*>(handlerProvider.get());
auto const apiVersion = 2u;
auto const method = "account_info";
auto const params = boost::json::parse(R"({"queue": true})");
auto const params = json::parse(R"({"queue": true})");
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(false));
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
@@ -154,7 +155,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsTrueIfLedgerWithQueueSpecifie
auto const rawHandlerProviderPtr = static_cast<MockHandlerProvider*>(handlerProvider.get());
auto const apiVersion = 2u;
auto const method = "ledger";
auto const params = boost::json::parse(R"({"queue": true})");
auto const params = json::parse(R"({"queue": true})");
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(false));
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
@@ -174,7 +175,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsTrueIfLedgerWithFullSpecified
auto const rawHandlerProviderPtr = static_cast<MockHandlerProvider*>(handlerProvider.get());
auto const apiVersion = 2u;
auto const method = "ledger";
auto const params = boost::json::parse(R"({"full": true})");
auto const params = json::parse(R"({"full": true})");
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(false));
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
@@ -194,7 +195,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsTrueIfLedgerWithAccountsSpeci
auto const rawHandlerProviderPtr = static_cast<MockHandlerProvider*>(handlerProvider.get());
auto const apiVersion = 2u;
auto const method = "ledger";
auto const params = boost::json::parse(R"({"accounts": true})");
auto const params = json::parse(R"({"accounts": true})");
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(false));
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
@@ -214,7 +215,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsFalseIfAccountInfoQueueIsFals
auto const rawHandlerProviderPtr = static_cast<MockHandlerProvider*>(handlerProvider.get());
auto const apiVersion = 2u;
auto const method = "account_info";
auto const params = boost::json::parse(R"({"queue": false})");
auto const params = json::parse(R"({"queue": false})");
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(false));
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
@@ -234,7 +235,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsFalseIfLedgerQueueIsFalse)
auto const rawHandlerProviderPtr = static_cast<MockHandlerProvider*>(handlerProvider.get());
auto const apiVersion = 2u;
auto const method = "ledger";
auto const params = boost::json::parse(R"({"queue": false})");
auto const params = json::parse(R"({"queue": false})");
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(false));
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
@@ -254,7 +255,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsFalseIfLedgerFullIsFalse)
auto const rawHandlerProviderPtr = static_cast<MockHandlerProvider*>(handlerProvider.get());
auto const apiVersion = 2u;
auto const method = "ledger";
auto const params = boost::json::parse(R"({"full": false})");
auto const params = json::parse(R"({"full": false})");
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(false));
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
@@ -274,7 +275,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsFalseIfLedgerAccountsIsFalse)
auto const rawHandlerProviderPtr = static_cast<MockHandlerProvider*>(handlerProvider.get());
auto const apiVersion = 2u;
auto const method = "ledger";
auto const params = boost::json::parse(R"({"accounts": false})");
auto const params = json::parse(R"({"accounts": false})");
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(false));
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
@@ -293,7 +294,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsTrueIfAPIVersionIsV1)
{
auto const apiVersion = 1u;
auto const method = "api_version_check";
auto const params = boost::json::parse("{}");
auto const params = json::parse("{}");
runSpawn([&](auto yield) {
auto const range = mockBackendPtr->fetchLedgerRange();
@@ -310,7 +311,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsFalseIfAPIVersionIsV2)
auto const rawHandlerProviderPtr = static_cast<MockHandlerProvider*>(handlerProvider.get());
auto const apiVersion = 2u;
auto const method = "api_version_check";
auto const params = boost::json::parse("{}");
auto const params = json::parse("{}");
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(false));
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
@@ -329,7 +330,7 @@ TEST_F(RPCForwardingProxyTest, ShouldNeverForwardSubscribe)
{
auto const apiVersion = 1u;
auto const method = "subscribe";
auto const params = boost::json::parse("{}");
auto const params = json::parse("{}");
runSpawn([&](auto yield) {
auto const range = mockBackendPtr->fetchLedgerRange();
@@ -345,7 +346,7 @@ TEST_F(RPCForwardingProxyTest, ShouldNeverForwardUnsubscribe)
{
auto const apiVersion = 1u;
auto const method = "unsubscribe";
auto const params = boost::json::parse("{}");
auto const params = json::parse("{}");
runSpawn([&](auto yield) {
auto const range = mockBackendPtr->fetchLedgerRange();
@@ -363,10 +364,10 @@ TEST_F(RPCForwardingProxyTest, ForwardCallsBalancerWithCorrectParams)
auto const rawBalancerPtr = static_cast<MockLoadBalancer*>(loadBalancer.get());
auto const apiVersion = 2u;
auto const method = "submit";
auto const params = boost::json::parse(R"({"test": true})");
auto const forwarded = boost::json::parse(R"({"test": true, "command": "submit"})");
auto const params = json::parse(R"({"test": true})");
auto const forwarded = json::parse(R"({"test": true, "command": "submit"})");
ON_CALL(*rawBalancerPtr, forwardToRippled).WillByDefault(Return(std::make_optional<boost::json::object>()));
ON_CALL(*rawBalancerPtr, forwardToRippled).WillByDefault(Return(std::make_optional<json::object>()));
EXPECT_CALL(*rawBalancerPtr, forwardToRippled(forwarded.as_object(), CLIENT_IP, _)).Times(1);
ON_CALL(*rawHandlerProviderPtr, contains).WillByDefault(Return(true));
@@ -382,7 +383,7 @@ TEST_F(RPCForwardingProxyTest, ForwardCallsBalancerWithCorrectParams)
auto const res = proxy.forward(ctx);
auto const data = std::get_if<boost::json::object>(&res);
auto const data = std::get_if<json::object>(&res);
EXPECT_TRUE(data != nullptr);
});
}
@@ -393,8 +394,8 @@ TEST_F(RPCForwardingProxyTest, ForwardingFailYieldsErrorStatus)
auto const rawBalancerPtr = static_cast<MockLoadBalancer*>(loadBalancer.get());
auto const apiVersion = 2u;
auto const method = "submit";
auto const params = boost::json::parse(R"({"test": true})");
auto const forwarded = boost::json::parse(R"({"test": true, "command": "submit"})");
auto const params = json::parse(R"({"test": true})");
auto const forwarded = json::parse(R"({"test": true, "command": "submit"})");
ON_CALL(*rawBalancerPtr, forwardToRippled).WillByDefault(Return(std::nullopt));
EXPECT_CALL(*rawBalancerPtr, forwardToRippled(forwarded.as_object(), CLIENT_IP, _)).Times(1);

View File

@@ -52,7 +52,7 @@ TEST_F(RPCAccountCurrenciesHandlerTest, AccountNotExist)
ON_CALL(*rawBackendPtr, doFetchLedgerObject).WillByDefault(Return(std::optional<Blob>{}));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}"
}})",
@@ -76,7 +76,7 @@ TEST_F(RPCAccountCurrenciesHandlerTest, LedgerNonExistViaIntSequence)
// return empty ledgerinfo
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(30, _)).WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}"
}})",
@@ -101,7 +101,7 @@ TEST_F(RPCAccountCurrenciesHandlerTest, LedgerNonExistViaStringSequence)
// return empty ledgerinfo
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(12, _)).WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"ledger_index":"{}"
@@ -128,7 +128,7 @@ TEST_F(RPCAccountCurrenciesHandlerTest, LedgerNonExistViaHash)
ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _))
.WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"ledger_hash":"{}"
@@ -197,7 +197,7 @@ TEST_F(RPCAccountCurrenciesHandlerTest, DefaultParameter)
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}"
}})",
@@ -235,7 +235,7 @@ TEST_F(RPCAccountCurrenciesHandlerTest, RequestViaLegderHash)
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"ledger_hash":"{}"
@@ -276,7 +276,7 @@ TEST_F(RPCAccountCurrenciesHandlerTest, RequestViaLegderSeq)
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"ledger_index":{}

View File

@@ -125,7 +125,7 @@ TEST_F(RPCAccountInfoHandlerTest, LedgerNonExistViaIntSequence)
// return empty ledgerinfo
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(30, _)).WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account": "{}",
"ledger_index": 30
@@ -150,7 +150,7 @@ TEST_F(RPCAccountInfoHandlerTest, LedgerNonExistViaStringSequence)
// return empty ledgerinfo
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(30, _)).WillByDefault(Return(std::nullopt));
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account": "{}",
"ledger_index": "30"
@@ -176,7 +176,7 @@ TEST_F(RPCAccountInfoHandlerTest, LedgerNonExistViaHash)
ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _))
.WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account": "{}",
"ledger_hash": "{}"
@@ -205,7 +205,7 @@ TEST_F(RPCAccountInfoHandlerTest, AccountNotExist)
ON_CALL(*rawBackendPtr, doFetchLedgerObject).WillByDefault(Return(std::optional<Blob>{}));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account": "{}"
}})",
@@ -233,7 +233,7 @@ TEST_F(RPCAccountInfoHandlerTest, AccountInvalid)
ON_CALL(*rawBackendPtr, doFetchLedgerObject).WillByDefault(Return(CreateFeeSettingBlob(1, 2, 3, 4, 0)));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account": "{}"
}})",
@@ -269,7 +269,7 @@ TEST_F(RPCAccountInfoHandlerTest, SignerListsInvalid)
.WillByDefault(Return(CreateAmendmentsObject({}).getSerializer().peekData()));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(4);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account": "{}",
"signer_lists": true
@@ -370,7 +370,7 @@ TEST_F(RPCAccountInfoHandlerTest, SignerListsTrue)
.WillByDefault(Return(CreateAmendmentsObject({}).getSerializer().peekData()));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(4);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account": "{}",
"signer_lists": true
@@ -443,7 +443,7 @@ TEST_F(RPCAccountInfoHandlerTest, Flags)
.WillByDefault(Return(CreateAmendmentsObject({}).getSerializer().peekData()));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(3);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account": "{}"
}})",
@@ -474,7 +474,7 @@ TEST_F(RPCAccountInfoHandlerTest, IdentAndSignerListsFalse)
.WillByDefault(Return(CreateAmendmentsObject({}).getSerializer().peekData()));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(3);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"ident": "{}"
}})",
@@ -551,7 +551,7 @@ TEST_F(RPCAccountInfoHandlerTest, DisallowIncoming)
.WillByDefault(Return(CreateAmendmentsObject({rpc::Amendments::DisallowIncoming}).getSerializer().peekData()));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(3);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account": "{}"
}})",
@@ -624,7 +624,7 @@ TEST_F(RPCAccountInfoHandlerTest, Clawback)
.WillByDefault(Return(CreateAmendmentsObject({rpc::Amendments::Clawback}).getSerializer().peekData()));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(3);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account": "{}"
}})",

View File

@@ -171,7 +171,7 @@ TEST_F(RPCAccountNFTsHandlerTest, LedgerNotFoundViaHash)
ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _))
.WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"ledger_hash":"{}"
@@ -198,7 +198,7 @@ TEST_F(RPCAccountNFTsHandlerTest, LedgerNotFoundViaStringIndex)
// return empty ledgerinfo
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(seq, _)).WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"ledger_index":"{}"
@@ -225,7 +225,7 @@ TEST_F(RPCAccountNFTsHandlerTest, LedgerNotFoundViaIntIndex)
// return empty ledgerinfo
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(seq, _)).WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"ledger_index":{}
@@ -254,7 +254,7 @@ TEST_F(RPCAccountNFTsHandlerTest, AccountNotFound)
ON_CALL(*rawBackendPtr, doFetchLedgerObject).WillByDefault(Return(std::optional<Blob>{}));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}"
}})",
@@ -316,7 +316,7 @@ TEST_F(RPCAccountNFTsHandlerTest, NormalPath)
.WillByDefault(Return(pageObject.getSerializer().peekData()));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}"
}})",
@@ -351,7 +351,7 @@ TEST_F(RPCAccountNFTsHandlerTest, Limit)
.WillByDefault(Return(pageObject.getSerializer().peekData()));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1 + limit);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"limit":{}
@@ -387,7 +387,7 @@ TEST_F(RPCAccountNFTsHandlerTest, Marker)
.WillByDefault(Return(pageObject.getSerializer().peekData()));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"marker":"{}"
@@ -450,7 +450,7 @@ TEST_F(RPCAccountNFTsHandlerTest, LimitLessThanMin)
.WillByDefault(Return(pageObject.getSerializer().peekData()));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"limit":{}
@@ -513,7 +513,7 @@ TEST_F(RPCAccountNFTsHandlerTest, LimitMoreThanMax)
.WillByDefault(Return(pageObject.getSerializer().peekData()));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"limit":{}

View File

@@ -176,7 +176,7 @@ TEST_F(RPCAccountObjectsHandlerTest, LedgerNonExistViaIntSequence)
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(MAXSEQ, _))
.WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"ledger_index":30
@@ -201,7 +201,7 @@ TEST_F(RPCAccountObjectsHandlerTest, LedgerNonExistViaStringSequence)
// return empty ledgerinfo
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(MAXSEQ, _)).WillByDefault(Return(std::nullopt));
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"ledger_index":"30"
@@ -227,7 +227,7 @@ TEST_F(RPCAccountObjectsHandlerTest, LedgerNonExistViaHash)
ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _))
.WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"ledger_hash":"{}"
@@ -256,7 +256,7 @@ TEST_F(RPCAccountObjectsHandlerTest, AccountNotExist)
ON_CALL(*rawBackendPtr, doFetchLedgerObject).WillByDefault(Return(std::optional<Blob>{}));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}"
}})",
@@ -334,7 +334,7 @@ TEST_F(RPCAccountObjectsHandlerTest, DefaultParameterNoNFTFound)
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}"
}})",
@@ -385,7 +385,7 @@ TEST_F(RPCAccountObjectsHandlerTest, Limit)
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"limit":{}
@@ -434,7 +434,7 @@ TEST_F(RPCAccountObjectsHandlerTest, Marker)
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"marker":"{},{}"
@@ -496,7 +496,7 @@ TEST_F(RPCAccountObjectsHandlerTest, MultipleDirNoNFT)
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"limit":{}
@@ -555,7 +555,7 @@ TEST_F(RPCAccountObjectsHandlerTest, TypeFilter)
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"type":"offer"
@@ -611,7 +611,7 @@ TEST_F(RPCAccountObjectsHandlerTest, TypeFilterReturnEmpty)
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"type": "check"
@@ -674,7 +674,7 @@ TEST_F(RPCAccountObjectsHandlerTest, DeletionBlockersOnlyFilter)
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account": "{}",
"deletion_blockers_only": true
@@ -725,7 +725,7 @@ TEST_F(RPCAccountObjectsHandlerTest, DeletionBlockersOnlyFilterWithTypeFilter)
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account": "{}",
"deletion_blockers_only": true,
@@ -793,7 +793,7 @@ TEST_F(RPCAccountObjectsHandlerTest, DeletionBlockersOnlyFilterEmptyResult)
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account": "{}",
"deletion_blockers_only": true
@@ -858,7 +858,7 @@ TEST_F(RPCAccountObjectsHandlerTest, DeletionBlockersOnlyFilterWithIncompatibleT
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account": "{}",
"deletion_blockers_only": true,
@@ -978,7 +978,7 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTMixOtherObjects)
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}"
}})",
@@ -1022,7 +1022,7 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTReachLimitReturnMarker)
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(11);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"limit":{}
@@ -1075,7 +1075,7 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTReachLimitNoMarker)
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(12);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"limit":{}
@@ -1157,7 +1157,7 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTMarker)
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(13);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"marker":"{},{}"
@@ -1218,7 +1218,7 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTMarkerNoMoreNFT)
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"marker":"{},{}"
@@ -1250,7 +1250,7 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTMarkerNotInRange)
ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillByDefault(Return(Blob{'f', 'a', 'k', 'e'}));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account": "{}",
"marker" : "{},{}"
@@ -1287,7 +1287,7 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTMarkerNotExist)
ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountNftMax, MAXSEQ, _)).WillByDefault(Return(std::nullopt));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account": "{}",
"marker" : "{},{}"
@@ -1367,7 +1367,7 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTLimitAdjust)
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(13);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"marker":"{},{}",
@@ -1469,7 +1469,7 @@ TEST_F(RPCAccountObjectsHandlerTest, FilterNFT)
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"type": "nft_page"
@@ -1517,7 +1517,7 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTZeroMarkerNotAffectOtherMarker)
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"limit":{},
@@ -1602,7 +1602,7 @@ TEST_F(RPCAccountObjectsHandlerTest, LimitLessThanMin)
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"limit": {}
@@ -1683,7 +1683,7 @@ TEST_F(RPCAccountObjectsHandlerTest, LimitMoreThanMax)
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"limit": {}

View File

@@ -164,7 +164,7 @@ TEST_F(RPCAccountOffersHandlerTest, LedgerNotFoundViaHash)
ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _))
.WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"ledger_hash":"{}"
@@ -191,7 +191,7 @@ TEST_F(RPCAccountOffersHandlerTest, LedgerNotFoundViaStringIndex)
// return empty ledgerinfo
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(seq, _)).WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"ledger_index":"{}"
@@ -218,7 +218,7 @@ TEST_F(RPCAccountOffersHandlerTest, LedgerNotFoundViaIntIndex)
// return empty ledgerinfo
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(seq, _)).WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"ledger_index":{}
@@ -247,7 +247,7 @@ TEST_F(RPCAccountOffersHandlerTest, AccountNotFound)
ON_CALL(*rawBackendPtr, doFetchLedgerObject).WillByDefault(Return(std::optional<Blob>{}));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}"
}})",
@@ -324,7 +324,7 @@ TEST_F(RPCAccountOffersHandlerTest, DefaultParams)
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}"
}})",
@@ -374,7 +374,7 @@ TEST_F(RPCAccountOffersHandlerTest, Limit)
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"limit":10
@@ -429,7 +429,7 @@ TEST_F(RPCAccountOffersHandlerTest, Marker)
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"marker":"{},{}"
@@ -467,7 +467,7 @@ TEST_F(RPCAccountOffersHandlerTest, MarkerNotExists)
ON_CALL(*rawBackendPtr, doFetchLedgerObject(hintIndex, ledgerSeq, _)).WillByDefault(Return(std::nullopt));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"marker":"{},{}"
@@ -524,7 +524,7 @@ TEST_F(RPCAccountOffersHandlerTest, LimitLessThanMin)
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"limit":{}
@@ -578,7 +578,7 @@ TEST_F(RPCAccountOffersHandlerTest, LimitMoreThanMax)
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"limit":{}

View File

@@ -309,9 +309,9 @@ TEST_F(RPCAccountTxHandlerTest, IndexSpecificForwardTrue)
runSpawn([&, this](auto yield) {
auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}};
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"account": "{}",
"ledger_index_min": {},
"ledger_index_max": {},
"forward": true
@@ -324,7 +324,7 @@ TEST_F(RPCAccountTxHandlerTest, IndexSpecificForwardTrue)
EXPECT_EQ(output->at("account").as_string(), ACCOUNT);
EXPECT_EQ(output->at("ledger_index_min").as_uint64(), MINSEQ + 1);
EXPECT_EQ(output->at("ledger_index_max").as_uint64(), MAXSEQ - 1);
EXPECT_EQ(output->at("marker").as_object(), json::parse(R"({"ledger":12,"seq":34})"));
EXPECT_EQ(output->at("marker").as_object(), json::parse(R"({"ledger": 12, "seq": 34})"));
EXPECT_EQ(output->at("transactions").as_array().size(), 2);
EXPECT_FALSE(output->as_object().contains("limit"));
});
@@ -350,9 +350,9 @@ TEST_F(RPCAccountTxHandlerTest, IndexSpecificForwardFalse)
runSpawn([&, this](auto yield) {
auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}};
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"account": "{}",
"ledger_index_min": {},
"ledger_index_max": {},
"forward": false
@@ -365,7 +365,7 @@ TEST_F(RPCAccountTxHandlerTest, IndexSpecificForwardFalse)
EXPECT_EQ(output->at("account").as_string(), ACCOUNT);
EXPECT_EQ(output->at("ledger_index_min").as_uint64(), MINSEQ + 1);
EXPECT_EQ(output->at("ledger_index_max").as_uint64(), MAXSEQ - 1);
EXPECT_EQ(output->at("marker").as_object(), json::parse(R"({"ledger":12,"seq":34})"));
EXPECT_EQ(output->at("marker").as_object(), json::parse(R"({"ledger": 12, "seq": 34})"));
EXPECT_EQ(output->at("transactions").as_array().size(), 2);
EXPECT_FALSE(output->as_object().contains("limit"));
});
@@ -391,9 +391,9 @@ TEST_F(RPCAccountTxHandlerTest, IndexNotSpecificForwardTrue)
runSpawn([&, this](auto yield) {
auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}};
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"account": "{}",
"ledger_index_min": {},
"ledger_index_max": {},
"forward": true
@@ -406,7 +406,7 @@ TEST_F(RPCAccountTxHandlerTest, IndexNotSpecificForwardTrue)
EXPECT_EQ(output->at("account").as_string(), ACCOUNT);
EXPECT_EQ(output->at("ledger_index_min").as_uint64(), MINSEQ);
EXPECT_EQ(output->at("ledger_index_max").as_uint64(), MAXSEQ);
EXPECT_EQ(output->at("marker").as_object(), json::parse(R"({"ledger":12,"seq":34})"));
EXPECT_EQ(output->at("marker").as_object(), json::parse(R"({"ledger": 12, "seq": 34})"));
EXPECT_EQ(output->at("transactions").as_array().size(), 2);
EXPECT_FALSE(output->as_object().contains("limit"));
});
@@ -432,9 +432,9 @@ TEST_F(RPCAccountTxHandlerTest, IndexNotSpecificForwardFalse)
runSpawn([&, this](auto yield) {
auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}};
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"account": "{}",
"ledger_index_min": {},
"ledger_index_max": {},
"forward": false
@@ -447,7 +447,7 @@ TEST_F(RPCAccountTxHandlerTest, IndexNotSpecificForwardFalse)
EXPECT_EQ(output->at("account").as_string(), ACCOUNT);
EXPECT_EQ(output->at("ledger_index_min").as_uint64(), MINSEQ);
EXPECT_EQ(output->at("ledger_index_max").as_uint64(), MAXSEQ);
EXPECT_EQ(output->at("marker").as_object(), json::parse(R"({"ledger":12,"seq":34})"));
EXPECT_EQ(output->at("marker").as_object(), json::parse(R"({"ledger": 12, "seq": 34})"));
EXPECT_EQ(output->at("transactions").as_array().size(), 2);
EXPECT_FALSE(output->as_object().contains("limit"));
});
@@ -473,9 +473,9 @@ TEST_F(RPCAccountTxHandlerTest, BinaryTrue)
runSpawn([&, this](auto yield) {
auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}};
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"account": "{}",
"ledger_index_min": {},
"ledger_index_max": {},
"binary": true
@@ -488,7 +488,7 @@ TEST_F(RPCAccountTxHandlerTest, BinaryTrue)
EXPECT_EQ(output->at("account").as_string(), ACCOUNT);
EXPECT_EQ(output->at("ledger_index_min").as_uint64(), MINSEQ);
EXPECT_EQ(output->at("ledger_index_max").as_uint64(), MAXSEQ);
EXPECT_EQ(output->at("marker").as_object(), json::parse(R"({"ledger":12,"seq":34})"));
EXPECT_EQ(output->at("marker").as_object(), json::parse(R"({"ledger": 12, "seq": 34})"));
EXPECT_EQ(output->at("transactions").as_array().size(), 2);
EXPECT_EQ(
output->at("transactions").as_array()[0].as_object().at("meta").as_string(),
@@ -522,9 +522,9 @@ TEST_F(RPCAccountTxHandlerTest, LimitAndMarker)
runSpawn([&, this](auto yield) {
auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}};
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"account": "{}",
"ledger_index_min": {},
"ledger_index_max": {},
"limit": 2,
@@ -540,7 +540,7 @@ TEST_F(RPCAccountTxHandlerTest, LimitAndMarker)
EXPECT_EQ(output->at("ledger_index_min").as_uint64(), MINSEQ);
EXPECT_EQ(output->at("ledger_index_max").as_uint64(), MAXSEQ);
EXPECT_EQ(output->at("limit").as_uint64(), 2);
EXPECT_EQ(output->at("marker").as_object(), json::parse(R"({"ledger":12,"seq":34})"));
EXPECT_EQ(output->at("marker").as_object(), json::parse(R"({"ledger": 12, "seq": 34})"));
EXPECT_EQ(output->at("transactions").as_array().size(), 2);
});
}
@@ -570,10 +570,10 @@ TEST_F(RPCAccountTxHandlerTest, SpecificLedgerIndex)
runSpawn([&, this](auto yield) {
auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}};
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"ledger_index":{}
"account": "{}",
"ledger_index": {}
}})",
ACCOUNT,
MAXSEQ - 1));
@@ -599,10 +599,10 @@ TEST_F(RPCAccountTxHandlerTest, SpecificNonexistLedgerIntIndex)
runSpawn([&, this](auto yield) {
auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}};
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"ledger_index":{}
"account": "{}",
"ledger_index": {}
}})",
ACCOUNT,
MAXSEQ - 1));
@@ -625,10 +625,10 @@ TEST_F(RPCAccountTxHandlerTest, SpecificNonexistLedgerStringIndex)
runSpawn([&, this](auto yield) {
auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}};
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"ledger_index":"{}"
"account": "{}",
"ledger_index": "{}"
}})",
ACCOUNT,
MAXSEQ - 1));
@@ -665,10 +665,10 @@ TEST_F(RPCAccountTxHandlerTest, SpecificLedgerHash)
runSpawn([&, this](auto yield) {
auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}};
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"ledger_hash":"{}"
"account": "{}",
"ledger_hash": "{}"
}})",
ACCOUNT,
LEDGERHASH));
@@ -708,10 +708,10 @@ TEST_F(RPCAccountTxHandlerTest, SpecificLedgerIndexValidated)
runSpawn([&, this](auto yield) {
auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}};
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"ledger_index":"validated"
"account": "{}",
"ledger_index": "validated"
}})",
ACCOUNT));
auto const output = handler.process(input, Context{yield});
@@ -745,9 +745,9 @@ TEST_F(RPCAccountTxHandlerTest, TxLessThanMinSeq)
runSpawn([&, this](auto yield) {
auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}};
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"account": "{}",
"ledger_index_min": {},
"ledger_index_max": {},
"forward": false
@@ -786,9 +786,9 @@ TEST_F(RPCAccountTxHandlerTest, TxLargerThanMaxSeq)
runSpawn([&, this](auto yield) {
auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}};
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account":"{}",
"account": "{}",
"ledger_index_min": {},
"ledger_index_max": {},
"forward": false
@@ -803,7 +803,7 @@ TEST_F(RPCAccountTxHandlerTest, TxLargerThanMaxSeq)
EXPECT_EQ(output->at("ledger_index_max").as_uint64(), MAXSEQ - 2);
EXPECT_EQ(output->at("transactions").as_array().size(), 1);
EXPECT_FALSE(output->as_object().contains("limit"));
EXPECT_EQ(output->at("marker").as_object(), json::parse(R"({"ledger":12,"seq":34})"));
EXPECT_EQ(output->at("marker").as_object(), json::parse(R"({"ledger": 12, "seq": 34})"));
});
}
@@ -909,8 +909,8 @@ TEST_F(RPCAccountTxHandlerTest, NFTTxs)
"date": 2
},
"validated": true
},
{
},
{
"meta":
{
"AffectedNodes":
@@ -1015,7 +1015,7 @@ TEST_F(RPCAccountTxHandlerTest, NFTTxs)
runSpawn([&, this](auto yield) {
auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}};
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account": "{}",
"ledger_index_min": {},
@@ -1028,6 +1028,312 @@ TEST_F(RPCAccountTxHandlerTest, NFTTxs)
-1));
auto const output = handler.process(input, Context{yield});
ASSERT_TRUE(output);
EXPECT_EQ(*output, boost::json::parse(OUT));
EXPECT_EQ(*output, json::parse(OUT));
});
}
struct AccountTxTransactionBundle
{
std::string testName;
std::string testJson;
std::string result;
};
// parameterized test cases for parameters check
struct AccountTxTransactionTypeTest : public RPCAccountTxHandlerTest,
public WithParamInterface<AccountTxTransactionBundle>
{
struct NameGenerator
{
template <class ParamType>
std::string
operator()(const testing::TestParamInfo<ParamType>& info) const
{
auto bundle = static_cast<AccountTxTransactionBundle>(info.param);
return bundle.testName;
}
};
};
static auto
generateTransactionTypeTestValues()
{
return std::vector<AccountTxTransactionBundle>{
AccountTxTransactionBundle{
"AccountSet",
R"({
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"ledger_index": "validated",
"tx_type": "AccountSet"
})",
"[]"},
AccountTxTransactionBundle{
"AccountDelete",
R"({
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"ledger_index": "validated",
"tx_type": "AccountDelete"
})",
"[]"},
AccountTxTransactionBundle{
"CheckCancel",
R"({
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"ledger_index": "validated",
"tx_type": "CheckCancel"
})",
"[]"},
AccountTxTransactionBundle{
"CheckCash",
R"({
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"ledger_index": "validated",
"tx_type": "CheckCash"
})",
"[]"},
AccountTxTransactionBundle{
"CheckCreate",
R"({
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"ledger_index": "validated",
"tx_type": "CheckCreate"
})",
"[]"},
AccountTxTransactionBundle{
"Clawback",
R"({
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"ledger_index": "validated",
"tx_type": "Clawback"
})",
"[]"},
AccountTxTransactionBundle{
"DepositPreauth",
R"({
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"ledger_index": "validated",
"tx_type": "DepositPreauth"
})",
"[]"},
AccountTxTransactionBundle{
"EscrowCancel",
R"({
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"ledger_index": "validated",
"tx_type": "EscrowCancel"
})",
"[]"},
AccountTxTransactionBundle{
"EscrowCreate",
R"({
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"ledger_index": "validated",
"tx_type": "EscrowCreate"
})",
"[]"},
AccountTxTransactionBundle{
"EscrowFinish",
R"({
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"ledger_index": "validated",
"tx_type": "EscrowFinish"
})",
"[]"},
AccountTxTransactionBundle{
"NFTokenAcceptOffer",
R"({
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"ledger_index": "validated",
"tx_type": "NFTokenAcceptOffer"
})",
"[]"},
AccountTxTransactionBundle{
"NFTokenBurn",
R"({
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"ledger_index": "validated",
"tx_type": "NFTokenBurn"
})",
"[]"},
AccountTxTransactionBundle{
"NFTokenCancelOffer",
R"({
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"ledger_index": "validated",
"tx_type": "NFTokenCancelOffer"
})",
"[]"},
AccountTxTransactionBundle{
"NFTokenCreateOffer",
R"({
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"ledger_index": "validated",
"tx_type": "NFTokenCreateOffer"
})",
"[]"},
AccountTxTransactionBundle{
"NFTokenMint",
R"({
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"ledger_index": "validated",
"tx_type": "NFTokenMint"
})",
"[]"},
AccountTxTransactionBundle{
"OfferCancel",
R"({
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"ledger_index": "validated",
"tx_type": "OfferCancel"
})",
"[]"},
AccountTxTransactionBundle{
"OfferCreate",
R"({
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"ledger_index": "validated",
"tx_type": "OfferCreate"
})",
"[]"},
AccountTxTransactionBundle{
"Payment",
R"({
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"ledger_index": "validated",
"tx_type": "Payment"
})",
R"([
{
"meta": {
"AffectedNodes": [
{
"ModifiedNode": {
"FinalFields": {
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"Balance": "22"
},
"LedgerEntryType": "AccountRoot"
}
},
{
"ModifiedNode": {
"FinalFields": {
"Account": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
"Balance": "23"
},
"LedgerEntryType": "AccountRoot"
}
}],
"TransactionIndex": 0,
"TransactionResult": "tesSUCCESS",
"delivered_amount": "unavailable"
},
"tx": {
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"Amount": "1",
"Destination": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
"Fee": "1",
"Sequence": 32,
"SigningPubKey": "74657374",
"TransactionType": "Payment",
"hash": "51D2AAA6B8E4E16EF22F6424854283D8391B56875858A711B8CE4D5B9A422CC2",
"ledger_index": 30,
"date": 1
},
"validated": true
}
])"},
AccountTxTransactionBundle{
"PaymentChannelClaim",
R"({
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"ledger_index": "validated",
"tx_type": "PaymentChannelClaim"
})",
"[]"},
AccountTxTransactionBundle{
"PaymentChannelCreate",
R"({
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"ledger_index": "validated",
"tx_type": "PaymentChannelCreate"
})",
"[]"},
AccountTxTransactionBundle{
"PaymentChannelFund",
R"({
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"ledger_index": "validated",
"tx_type": "PaymentChannelFund"
})",
"[]"},
AccountTxTransactionBundle{
"SetRegularKey",
R"({
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"ledger_index": "validated",
"tx_type": "SetRegularKey"
})",
"[]"},
AccountTxTransactionBundle{
"SignerListSet",
R"({
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"ledger_index": "validated",
"tx_type": "SignerListSet"
})",
"[]"},
AccountTxTransactionBundle{
"TicketCreate",
R"({
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"ledger_index": "validated",
"tx_type": "TicketCreate"
})",
"[]"},
AccountTxTransactionBundle{
"TrustSet",
R"({
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"ledger_index": "validated",
"tx_type": "TrustSet"
})",
"[]"},
};
}
INSTANTIATE_TEST_CASE_P(
RPCAccountTxTransactionTypeTest,
AccountTxTransactionTypeTest,
ValuesIn(generateTransactionTypeTestValues()),
AccountTxTransactionTypeTest::NameGenerator{});
TEST_P(AccountTxTransactionTypeTest, SpecificTransactionType)
{
mockBackendPtr->updateRange(MINSEQ); // min
mockBackendPtr->updateRange(MAXSEQ); // max
MockBackend* rawBackendPtr = static_cast<MockBackend*>(mockBackendPtr.get());
auto const transactions = genTransactions(MAXSEQ, MAXSEQ - 1);
auto const transCursor = TransactionsAndCursor{transactions, TransactionsCursor{12, 34}};
ON_CALL(*rawBackendPtr, fetchAccountTransactions).WillByDefault(Return(transCursor));
EXPECT_CALL(
*rawBackendPtr, fetchAccountTransactions(_, _, false, Optional(Eq(TransactionsCursor{MAXSEQ, INT32_MAX})), _))
.Times(1);
auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ);
EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1);
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(MAXSEQ, _)).WillByDefault(Return(ledgerinfo));
auto const testBundle = GetParam();
runSpawn([&, this](auto yield) {
auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}};
auto const req = json::parse(testBundle.testJson);
auto const output = handler.process(req, Context{yield});
EXPECT_TRUE(output);
auto const transactions = output->at("transactions").as_array();
auto const jsonObject = json::parse(testBundle.result);
EXPECT_EQ(jsonObject, transactions);
});
}

View File

@@ -107,7 +107,7 @@ TEST_F(RPCBookChangesHandlerTest, LedgerNonExistViaIntSequence)
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(MAXSEQ, _))
.WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
auto const static input = boost::json::parse(R"({"ledger_index":30})");
auto const static input = json::parse(R"({"ledger_index":30})");
auto const handler = AnyHandler{BookChangesHandler{mockBackendPtr}};
runSpawn([&](auto yield) {
auto const output = handler.process(input, Context{yield});
@@ -127,7 +127,7 @@ TEST_F(RPCBookChangesHandlerTest, LedgerNonExistViaStringSequence)
// return empty ledgerinfo
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(MAXSEQ, _)).WillByDefault(Return(std::nullopt));
auto const static input = boost::json::parse(R"({"ledger_index":"30"})");
auto const static input = json::parse(R"({"ledger_index":"30"})");
auto const handler = AnyHandler{BookChangesHandler{mockBackendPtr}};
runSpawn([&](auto yield) {
auto const output = handler.process(input, Context{yield});
@@ -148,7 +148,7 @@ TEST_F(RPCBookChangesHandlerTest, LedgerNonExistViaHash)
ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _))
.WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"ledger_hash":"{}"
}})",

View File

@@ -1107,7 +1107,7 @@ TEST_F(RPCBookOffersHandlerTest, LedgerNonExistViaIntSequence)
// return empty ledgerinfo
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(30, _)).WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"ledger_index": 30,
"taker_gets":
@@ -1140,7 +1140,7 @@ TEST_F(RPCBookOffersHandlerTest, LedgerNonExistViaSequence)
// return empty ledgerinfo
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(30, _)).WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"ledger_index": "30",
"taker_gets":
@@ -1174,7 +1174,7 @@ TEST_F(RPCBookOffersHandlerTest, LedgerNonExistViaHash)
ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _))
.WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"ledger_hash": "{}",
"taker_gets":
@@ -1248,7 +1248,7 @@ TEST_F(RPCBookOffersHandlerTest, Limit)
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"taker_gets":
{{
@@ -1319,7 +1319,7 @@ TEST_F(RPCBookOffersHandlerTest, LimitMoreThanMax)
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"taker_gets":
{{

View File

@@ -268,7 +268,7 @@ TEST_F(RPCNFTHistoryHandlerTest, IndexSpecificForwardTrue)
runSpawn([&, this](auto yield) {
auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}};
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"nft_id":"{}",
"ledger_index_min": {},
@@ -309,7 +309,7 @@ TEST_F(RPCNFTHistoryHandlerTest, IndexSpecificForwardFalse)
runSpawn([&, this](auto yield) {
auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}};
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"nft_id":"{}",
"ledger_index_min": {},
@@ -346,7 +346,7 @@ TEST_F(RPCNFTHistoryHandlerTest, IndexNotSpecificForwardTrue)
runSpawn([&, this](auto yield) {
auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}};
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"nft_id":"{}",
"ledger_index_min": {},
@@ -387,7 +387,7 @@ TEST_F(RPCNFTHistoryHandlerTest, IndexNotSpecificForwardFalse)
runSpawn([&, this](auto yield) {
auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}};
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"nft_id":"{}",
"ledger_index_min": {},
@@ -428,7 +428,7 @@ TEST_F(RPCNFTHistoryHandlerTest, BinaryTrue)
runSpawn([&, this](auto yield) {
auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}};
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"nft_id":"{}",
"ledger_index_min": {},
@@ -477,7 +477,7 @@ TEST_F(RPCNFTHistoryHandlerTest, LimitAndMarker)
runSpawn([&, this](auto yield) {
auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}};
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"nft_id":"{}",
"ledger_index_min": {},
@@ -525,7 +525,7 @@ TEST_F(RPCNFTHistoryHandlerTest, SpecificLedgerIndex)
runSpawn([&, this](auto yield) {
auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}};
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"nft_id":"{}",
"ledger_index":{}
@@ -554,7 +554,7 @@ TEST_F(RPCNFTHistoryHandlerTest, SpecificNonexistLedgerIntIndex)
runSpawn([&, this](auto yield) {
auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}};
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"nft_id":"{}",
"ledger_index":{}
@@ -580,7 +580,7 @@ TEST_F(RPCNFTHistoryHandlerTest, SpecificNonexistLedgerStringIndex)
runSpawn([&, this](auto yield) {
auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}};
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"nft_id":"{}",
"ledger_index":"{}"
@@ -620,7 +620,7 @@ TEST_F(RPCNFTHistoryHandlerTest, SpecificLedgerHash)
runSpawn([&, this](auto yield) {
auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}};
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"nft_id":"{}",
"ledger_hash":"{}"
@@ -658,7 +658,7 @@ TEST_F(RPCNFTHistoryHandlerTest, TxLessThanMinSeq)
runSpawn([&, this](auto yield) {
auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}};
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"nft_id":"{}",
"ledger_index_min": {},
@@ -699,7 +699,7 @@ TEST_F(RPCNFTHistoryHandlerTest, TxLargerThanMaxSeq)
runSpawn([&, this](auto yield) {
auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}};
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"nft_id":"{}",
"ledger_index_min": {},
@@ -740,7 +740,7 @@ TEST_F(RPCNFTHistoryHandlerTest, LimitMoreThanMax)
runSpawn([&, this](auto yield) {
auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}};
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"nft_id":"{}",
"ledger_index_min": {},

View File

@@ -174,7 +174,7 @@ TEST_F(RPCNoRippleCheckTest, LedgerNotExistViaHash)
// return empty ledgerinfo
ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(std::nullopt));
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account": "{}",
"role": "gateway",
@@ -202,7 +202,7 @@ TEST_F(RPCNoRippleCheckTest, LedgerNotExistViaIntIndex)
// return empty ledgerinfo
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(seq, _)).WillByDefault(Return(std::nullopt));
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account": "{}",
"role": "gateway",
@@ -230,7 +230,7 @@ TEST_F(RPCNoRippleCheckTest, LedgerNotExistViaStringIndex)
// return empty ledgerinfo
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(seq, _)).WillByDefault(Return(std::nullopt));
auto const static input = boost::json::parse(fmt::format(
auto const static input = json::parse(fmt::format(
R"({{
"account": "{}",
"role": "gateway",

View File

@@ -71,6 +71,7 @@ protected:
EXPECT_STREQ(info.at("complete_ledgers").as_string().c_str(), "10-30");
EXPECT_TRUE(info.contains("load_factor"));
EXPECT_TRUE(info.contains("clio_version"));
EXPECT_TRUE(info.contains("libxrpl_version"));
EXPECT_TRUE(info.contains("validated_ledger"));
EXPECT_TRUE(info.contains("time"));
EXPECT_TRUE(info.contains("uptime"));
@@ -284,7 +285,7 @@ TEST_F(RPCServerInfoHandlerTest, AdminSectionPresentWhenAdminFlagIsSet)
mockBackendPtr->updateRange(10); // min
mockBackendPtr->updateRange(30); // max
auto const empty = boost::json::object{};
auto const empty = json::object{};
auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30, 3); // 3 seconds old
ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo));
EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1);
@@ -336,7 +337,7 @@ TEST_F(RPCServerInfoHandlerTest, RippledForwardedValuesPresent)
mockBackendPtr->updateRange(10); // min
mockBackendPtr->updateRange(30); // max
auto const empty = boost::json::object{};
auto const empty = json::object{};
auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30, 3); // 3 seconds old
ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo));
EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1);
@@ -351,7 +352,7 @@ TEST_F(RPCServerInfoHandlerTest, RippledForwardedValuesPresent)
ON_CALL(*rawETLServicePtr, isAmendmentBlocked).WillByDefault(Return(false));
EXPECT_CALL(*rawETLServicePtr, isAmendmentBlocked).Times(1);
auto const rippledObj = boost::json::parse(R"({
auto const rippledObj = json::parse(R"({
"result": {
"info": {
"build_version": "1234",
@@ -399,7 +400,7 @@ TEST_F(RPCServerInfoHandlerTest, RippledForwardedValuesMissingNoExceptionThrown)
mockBackendPtr->updateRange(10); // min
mockBackendPtr->updateRange(30); // max
auto const empty = boost::json::object{};
auto const empty = json::object{};
auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30, 3); // 3 seconds old
ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo));
EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1);
@@ -414,7 +415,7 @@ TEST_F(RPCServerInfoHandlerTest, RippledForwardedValuesMissingNoExceptionThrown)
ON_CALL(*rawETLServicePtr, isAmendmentBlocked).WillByDefault(Return(false));
EXPECT_CALL(*rawETLServicePtr, isAmendmentBlocked).Times(1);
auto const rippledObj = boost::json::parse(R"({
auto const rippledObj = json::parse(R"({
"result": {
"info": {}
}

View File

@@ -504,8 +504,8 @@ generateTestValuesForParametersTest()
}
]
})",
"invalidParams",
"takerNotString"},
"badIssuer",
"Issuer account malformed."},
SubscribeParamTestCaseBundle{
"BooksItemInvalidTaker",
R"({
@@ -523,8 +523,8 @@ generateTestValuesForParametersTest()
}
]
})",
"actMalformed",
"takerMalformed"},
"badIssuer",
"Issuer account malformed."},
};
}

View File

@@ -0,0 +1,33 @@
//------------------------------------------------------------------------------
/*
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.
*/
//==============================================================================
#pragma once
#include <functional>
struct FakeAmendmentBlockAction
{
std::reference_wrapper<std::size_t> callCount;
void
operator()()
{
++(callCount.get());
}
};

View File

@@ -160,10 +160,6 @@ private:
*/
struct SyncAsioContextTest : virtual public NoLoggerFixture
{
SyncAsioContextTest()
{
}
template <typename F>
void
runSpawn(F&& f)

View File

@@ -0,0 +1,27 @@
//------------------------------------------------------------------------------
/*
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.
*/
//==============================================================================
#pragma once
#include <gmock/gmock.h>
struct MockAmendmentBlockHandler
{
MOCK_METHOD(void, onAmendmentBlock, (), ());
};