diff --git a/.github/scripts/strategy-matrix/generate.py b/.github/scripts/strategy-matrix/generate.py index 4784142b7b..6b249103a4 100755 --- a/.github/scripts/strategy-matrix/generate.py +++ b/.github/scripts/strategy-matrix/generate.py @@ -40,6 +40,7 @@ def generate_strategy_matrix(all: bool, config: Config) -> list: # The default CMake target is 'all' for Linux and MacOS and 'install' # for Windows, but it can get overridden for certain configurations. cmake_target = "install" if os["distro_name"] == "windows" else "all" + unittest_args = "" # We build and test all configurations by default, except for Windows in # Debug, because it is too slow, as well as when code coverage is @@ -67,7 +68,7 @@ def generate_strategy_matrix(all: bool, config: Config) -> list: and build_type == "Release" and architecture["platform"] == "linux/amd64" ): - cmake_args = f"-DUNIT_TEST_REFERENCE_FEE=500 {cmake_args}" + unittest_args = f"{unittest_args} --unittest-fee=500" skip = False if ( f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-15" @@ -87,7 +88,7 @@ def generate_strategy_matrix(all: bool, config: Config) -> list: and build_type == "Release" and architecture["platform"] == "linux/amd64" ): - cmake_args = f"-DUNIT_TEST_REFERENCE_FEE=1000 {cmake_args}" + unittest_args = f"{unittest_args} --unittest-fee=1000" skip = False if ( f"{os['compiler_name']}-{os['compiler_version']}" == "clang-20" @@ -245,6 +246,7 @@ def generate_strategy_matrix(all: bool, config: Config) -> list: { "config_name": config_name + "-asan-ubsan", "cmake_args": cmake_args, + "unittest_args": unittest_args, "cmake_target": cmake_target, "build_only": build_only, "build_type": build_type, @@ -260,6 +262,7 @@ def generate_strategy_matrix(all: bool, config: Config) -> list: { "config_name": config_name + "-tsan-ubsan", "cmake_args": cmake_args, + "unittest_args": unittest_args, "cmake_target": cmake_target, "build_only": build_only, "build_type": build_type, @@ -273,6 +276,7 @@ def generate_strategy_matrix(all: bool, config: Config) -> list: { "config_name": config_name, "cmake_args": cmake_args, + "unittest_args": unittest_args, "cmake_target": cmake_target, "build_only": build_only, "build_type": build_type, diff --git a/.github/workflows/reusable-build-test-config.yml b/.github/workflows/reusable-build-test-config.yml index 57112ed96a..cd3b834807 100644 --- a/.github/workflows/reusable-build-test-config.yml +++ b/.github/workflows/reusable-build-test-config.yml @@ -25,6 +25,12 @@ on: type: string default: "" + unittest_args: + description: "Additional arguments to pass to rippled when running tests" + required: false + type: string + default: "" + cmake_target: description: "The CMake target to build." required: true @@ -257,11 +263,12 @@ jobs: working-directory: ${{ runner.os == 'Windows' && format('{0}/{1}', env.BUILD_DIR, inputs.build_type) || env.BUILD_DIR }} env: BUILD_NPROC: ${{ steps.nproc.outputs.nproc }} + UNITTEST_ARGS: ${{ inputs.unittest_args }} run: | set -o pipefail # Coverage builds are slower due to instrumentation; use fewer parallel jobs to avoid flakiness [ "$COVERAGE_ENABLED" = "true" ] && BUILD_NPROC=$(( BUILD_NPROC - 2 )) - ./xrpld --unittest --unittest-jobs "${BUILD_NPROC}" 2>&1 | tee unittest.log + ./xrpld --unittest --unittest-jobs "${BUILD_NPROC}" ${UNITTEST_ARGS} 2>&1 | tee unittest.log - name: Show test failure summary if: ${{ failure() && !inputs.build_only }} diff --git a/.github/workflows/reusable-build-test.yml b/.github/workflows/reusable-build-test.yml index 0086cbbfb5..4498e41fce 100644 --- a/.github/workflows/reusable-build-test.yml +++ b/.github/workflows/reusable-build-test.yml @@ -53,6 +53,7 @@ jobs: build_type: ${{ matrix.build_type }} ccache_enabled: ${{ inputs.ccache_enabled }} cmake_args: ${{ matrix.cmake_args }} + unittest_args: ${{ matrix.unittest_args }} cmake_target: ${{ matrix.cmake_target }} runs_on: ${{ toJSON(matrix.architecture.runner) }} image: ${{ contains(matrix.architecture.platform, 'linux') && format('ghcr.io/xrplf/ci/{0}-{1}:{2}-{3}-sha-{4}', matrix.os.distro_name, matrix.os.distro_version, matrix.os.compiler_name, matrix.os.compiler_version, matrix.os.image_sha) || '' }} diff --git a/cmake/XrplCore.cmake b/cmake/XrplCore.cmake index a50e30f660..c1dc82d78e 100644 --- a/cmake/XrplCore.cmake +++ b/cmake/XrplCore.cmake @@ -251,10 +251,6 @@ if(xrpld) add_executable(xrpld) if(tests) target_compile_definitions(xrpld PUBLIC ENABLE_TESTS) - target_compile_definitions( - xrpld - PRIVATE UNIT_TEST_REFERENCE_FEE=${UNIT_TEST_REFERENCE_FEE} - ) endif() target_include_directories( xrpld diff --git a/cmake/XrplSettings.cmake b/cmake/XrplSettings.cmake index 44a727a994..5b7e3c115b 100644 --- a/cmake/XrplSettings.cmake +++ b/cmake/XrplSettings.cmake @@ -23,12 +23,6 @@ option(assert "Enables asserts, even in release builds" OFF) option(xrpld "Build xrpld" ON) option(tests "Build tests" ON) -if(tests) - # This setting allows making a separate workflow to test fees other than default 10 - if(NOT UNIT_TEST_REFERENCE_FEE) - set(UNIT_TEST_REFERENCE_FEE "10" CACHE STRING "") - endif() -endif() option(unity "Creates a build using UNITY support in cmake." OFF) if(unity) diff --git a/include/xrpl/beast/unit_test/runner.h b/include/xrpl/beast/unit_test/runner.h index c8a6956732..22d13ec95f 100644 --- a/include/xrpl/beast/unit_test/runner.h +++ b/include/xrpl/beast/unit_test/runner.h @@ -9,6 +9,7 @@ #include #include +#include #include namespace beast { @@ -22,6 +23,7 @@ namespace unit_test { class runner { std::string arg_; + std::optional referenceFee_; bool default_ = false; bool failed_ = false; bool cond_ = false; @@ -54,6 +56,24 @@ public: return arg_; } + /** Set the reference fee (in drops) for tests. + + If provided, this value is used in every suite that + does not override it. + */ + void + referenceFee(std::int64_t fee) + { + referenceFee_ = fee; + } + + /** Returns the reference fee, if any. */ + std::optional const& + referenceFee() const + { + return referenceFee_; + } + /** Run the specified suite. @return `true` if any conditions failed. */ diff --git a/include/xrpl/beast/unit_test/suite.h b/include/xrpl/beast/unit_test/suite.h index fa5157e126..e6bd0c0886 100644 --- a/include/xrpl/beast/unit_test/suite.h +++ b/include/xrpl/beast/unit_test/suite.h @@ -281,6 +281,16 @@ public: return runner_->arg(); } + /** Return the reference fee associated with the runner. */ + std::optional + referenceFee() const + { + assert(runner_); + if (!runner_) + return {}; + return runner_->referenceFee(); + } + // DEPRECATED // @return `true` if the test condition indicates success(a false value) template diff --git a/include/xrpl/ledger/helpers/NFTokenHelpers.h b/include/xrpl/ledger/helpers/NFTokenHelpers.h index 3af81eff16..d8dac4caaf 100644 --- a/include/xrpl/ledger/helpers/NFTokenHelpers.h +++ b/include/xrpl/ledger/helpers/NFTokenHelpers.h @@ -20,6 +20,10 @@ removeTokenOffersWithLimit( Keylet const& directory, std::size_t maxDeletableOffers); +/** Returns tesSUCCESS if NFToken has few enough offers that it can be burned */ +TER +notTooManyOffers(ReadView const& view, uint256 const& nftokenID); + /** Finds the specified token in the owner's token directory. */ std::optional findToken(ReadView const& view, AccountID const& owner, uint256 const& nftokenID); diff --git a/src/libxrpl/ledger/helpers/NFTokenHelpers.cpp b/src/libxrpl/ledger/helpers/NFTokenHelpers.cpp index 7e7335232f..4652bccca8 100644 --- a/src/libxrpl/ledger/helpers/NFTokenHelpers.cpp +++ b/src/libxrpl/ledger/helpers/NFTokenHelpers.cpp @@ -607,6 +607,33 @@ removeTokenOffersWithLimit(ApplyView& view, Keylet const& directory, std::size_t return deletedOffersCount; } +TER +notTooManyOffers(ReadView const& view, uint256 const& nftokenID) +{ + std::size_t totalOffers = 0; + + { + Dir const buys(view, keylet::nft_buys(nftokenID)); + for (auto iter = buys.begin(); iter != buys.end(); iter.next_page()) + { + totalOffers += iter.page_size(); + if (totalOffers > maxDeletableTokenOfferEntries) + return tefTOO_BIG; + } + } + + { + Dir const sells(view, keylet::nft_sells(nftokenID)); + for (auto iter = sells.begin(); iter != sells.end(); iter.next_page()) + { + totalOffers += iter.page_size(); + if (totalOffers > maxDeletableTokenOfferEntries) + return tefTOO_BIG; + } + } + return tesSUCCESS; +} + bool deleteTokenOffer(ApplyView& view, std::shared_ptr const& offer) { diff --git a/src/test/app/AMM_test.cpp b/src/test/app/AMM_test.cpp index a434eb96c7..30e0b66165 100644 --- a/src/test/app/AMM_test.cpp +++ b/src/test/app/AMM_test.cpp @@ -5043,13 +5043,7 @@ private: FeatureBitset const all{testable_amendments()}; { - Env env( - *this, - envconfig([](std::unique_ptr cfg) { - cfg->FEES.reference_fee = XRPAmount(1); - return cfg; - }), - all); + Env env(*this, all, XRPAmount(1)); fund(env, gw, {alice}, XRP(20'000), {USD(10'000)}); AMM amm(env, gw, XRP(10'000), USD(10'000)); for (auto i = 0; i < maxDeletableAMMTrustLines + 10; ++i) @@ -5101,13 +5095,7 @@ private: } { - Env env( - *this, - envconfig([](std::unique_ptr cfg) { - cfg->FEES.reference_fee = XRPAmount(1); - return cfg; - }), - all); + Env env(*this, all, XRPAmount(1)); fund(env, gw, {alice}, XRP(20'000), {USD(10'000)}); AMM amm(env, gw, XRP(10'000), USD(10'000)); for (auto i = 0; i < (maxDeletableAMMTrustLines * 2) + 10; ++i) diff --git a/src/test/app/FeeVote_test.cpp b/src/test/app/FeeVote_test.cpp index 62f1058de5..4daf0938cc 100644 --- a/src/test/app/FeeVote_test.cpp +++ b/src/test/app/FeeVote_test.cpp @@ -635,7 +635,7 @@ class FeeVote_test : public beast::unit_test::suite Env env(*this, testable_amendments() | featureXRPFees); // establish what the current fees are - BEAST_EXPECT(env.current()->fees().base == XRPAmount{UNIT_TEST_REFERENCE_FEE}); + BEAST_EXPECT(env.current()->fees().base == env.app().config().FEES.reference_fee); BEAST_EXPECT(env.current()->fees().reserve == XRPAmount{200'000'000}); BEAST_EXPECT(env.current()->fees().increment == XRPAmount{50'000'000}); diff --git a/src/test/app/LedgerMaster_test.cpp b/src/test/app/LedgerMaster_test.cpp index 7a8904dbd7..8a41682ff3 100644 --- a/src/test/app/LedgerMaster_test.cpp +++ b/src/test/app/LedgerMaster_test.cpp @@ -14,8 +14,6 @@ class LedgerMaster_test : public beast::unit_test::suite using namespace jtx; return envconfig([&](std::unique_ptr cfg) { cfg->NETWORK_ID = networkID; - // This test relies on ledger hash so must lock it to fee 10. - cfg->FEES.reference_fee = 10; return cfg; }); } @@ -28,7 +26,8 @@ class LedgerMaster_test : public beast::unit_test::suite using namespace test::jtx; using namespace std::literals; - test::jtx::Env env{*this, makeNetworkConfig(11111)}; + // This test relies on ledger hash so must lock it to fee 10. + test::jtx::Env env{*this, makeNetworkConfig(11111), XRPAmount(10)}; auto const alice = Account("alice"); env.fund(XRP(1000), alice); diff --git a/src/test/app/MPToken_test.cpp b/src/test/app/MPToken_test.cpp index 69dd397210..e66c8329a2 100644 --- a/src/test/app/MPToken_test.cpp +++ b/src/test/app/MPToken_test.cpp @@ -2060,9 +2060,7 @@ class MPToken_test : public beast::unit_test::suite Account const alice{"alice"}; - auto cfg = envconfig(); - cfg->FEES.reference_fee = 10; - Env env{*this, std::move(cfg), features}; + Env env{*this, features, XRPAmount(10)}; MPTTester mptAlice(env, alice); mptAlice.create(); diff --git a/src/test/app/Regression_test.cpp b/src/test/app/Regression_test.cpp index 59ab0e427d..69036548c8 100644 --- a/src/test/app/Regression_test.cpp +++ b/src/test/app/Regression_test.cpp @@ -152,11 +152,13 @@ struct Regression_test : public beast::unit_test::suite { testcase("Autofilled fee should use the escalated fee"); using namespace jtx; - Env env(*this, envconfig([](std::unique_ptr cfg) { - cfg->section("transaction_queue").set("minimum_txn_in_ledger_standalone", "3"); - cfg->FEES.reference_fee = 10; - return cfg; - })); + Env env( + *this, + envconfig([](std::unique_ptr cfg) { + cfg->section("transaction_queue").set("minimum_txn_in_ledger_standalone", "3"); + return cfg; + }), + XRPAmount(10)); Env_ss envs(env); auto const alice = Account("alice"); diff --git a/src/test/app/TxQ_test.cpp b/src/test/app/TxQ_test.cpp index 6f13f9d419..5369187e62 100644 --- a/src/test/app/TxQ_test.cpp +++ b/src/test/app/TxQ_test.cpp @@ -1229,8 +1229,7 @@ public: testcase("tie breaking"); auto cfg = makeConfig({{"minimum_txn_in_ledger_standalone", "4"}}); - cfg->FEES.reference_fee = 10; - Env env(*this, std::move(cfg)); + Env env(*this, std::move(cfg), XRPAmount(10)); auto alice = Account("alice"); auto bob = Account("bob"); @@ -2621,8 +2620,7 @@ public: {{"minimum_txn_in_ledger_standalone", "1"}, {"ledgers_in_queue", "10"}, {"maximum_txn_per_account", "11"}}); - cfg->FEES.reference_fee = 10; - Env env(*this, std::move(cfg)); + Env env(*this, std::move(cfg), XRPAmount(10)); auto const baseFee = env.current()->fees().base.drops(); diff --git a/src/test/basics/PerfLog_test.cpp b/src/test/basics/PerfLog_test.cpp index 470a52d220..7990688a96 100644 --- a/src/test/basics/PerfLog_test.cpp +++ b/src/test/basics/PerfLog_test.cpp @@ -28,8 +28,8 @@ class PerfLog_test : public beast::unit_test::suite // We're only using Env for its Journal. That Journal gives better // coverage in unit tests. - test::jtx::Env env_{*this, test::jtx::envconfig(), nullptr, beast::severities::kDisabled}; - beast::Journal j_{env_.app().getJournal("PerfLog_test")}; + std::optional env_; + std::optional j_; struct Fixture { @@ -175,7 +175,7 @@ public: { // Verify a PerfLog creates its file when constructed. - Fixture fixture{env_.app(), j_}; + Fixture fixture{env_->app(), *j_}; BEAST_EXPECT(!exists(fixture.logFile())); auto perfLog{fixture.perfLog(WithFile::yes)}; @@ -187,7 +187,7 @@ public: // Create a file where PerfLog wants to put its directory. // Make sure that PerfLog tries to shutdown the server since it // can't open its file. - Fixture fixture{env_.app(), j_}; + Fixture fixture{env_->app(), *j_}; if (!BEAST_EXPECT(!exists(fixture.logDir()))) return; @@ -220,7 +220,7 @@ public: // Put a write protected file where PerfLog wants to write its // file. Make sure that PerfLog tries to shutdown the server // since it can't open its file. - Fixture fixture{env_.app(), j_}; + Fixture fixture{env_->app(), *j_}; if (!BEAST_EXPECT(!exists(fixture.logDir()))) return; @@ -276,7 +276,7 @@ public: { // Exercise the rpc interfaces of PerfLog. // Start up the PerfLog that we'll use for testing. - Fixture fixture{env_.app(), j_}; + Fixture fixture{env_->app(), *j_}; auto perfLog{fixture.perfLog(withFile)}; perfLog->start(); @@ -472,7 +472,7 @@ public: // Exercise the jobs interfaces of PerfLog. // Start up the PerfLog that we'll use for testing. - Fixture fixture{env_.app(), j_}; + Fixture fixture{env_->app(), *j_}; auto perfLog{fixture.perfLog(withFile)}; perfLog->start(); @@ -795,7 +795,7 @@ public: // the PerLog behaves as well as possible if an invalid ID is passed. // Start up the PerfLog that we'll use for testing. - Fixture fixture{env_.app(), j_}; + Fixture fixture{env_->app(), *j_}; auto perfLog{fixture.perfLog(withFile)}; perfLog->start(); @@ -934,7 +934,7 @@ public: // the interface and see that it doesn't crash. using namespace boost::filesystem; - Fixture fixture{env_.app(), j_}; + Fixture fixture{env_->app(), *j_}; BEAST_EXPECT(!exists(fixture.logDir())); auto perfLog{fixture.perfLog(withFile)}; @@ -985,6 +985,9 @@ public: void run() override { + env_.emplace(*this, test::jtx::envconfig(), nullptr, beast::severities::kDisabled); + j_.emplace(env_->app().getJournal("PerfLog_test")); + testFileCreation(); testRPC(WithFile::no); testRPC(WithFile::yes); diff --git a/src/test/core/ClosureCounter_test.cpp b/src/test/core/ClosureCounter_test.cpp index 088b7b9ff9..3ffab55fd7 100644 --- a/src/test/core/ClosureCounter_test.cpp +++ b/src/test/core/ClosureCounter_test.cpp @@ -16,8 +16,8 @@ class ClosureCounter_test : public beast::unit_test::suite { // We're only using Env for its Journal. That Journal gives better // coverage in unit tests. - test::jtx::Env env_{*this, jtx::envconfig(), nullptr, beast::severities::kDisabled}; - beast::Journal j{env_.app().getJournal("ClosureCounter_test")}; + std::optional env_; + std::optional j; void testConstruction() @@ -257,7 +257,7 @@ class ClosureCounter_test : public beast::unit_test::suite // Join with 0 count should not stall. using namespace std::chrono_literals; - voidCounter.join("testWrap", 1ms, j); + voidCounter.join("testWrap", 1ms, *j); // Wrapping a closure after join() should return std::nullopt. BEAST_EXPECT(voidCounter.wrap([]() {}) == std::nullopt); @@ -278,7 +278,7 @@ class ClosureCounter_test : public beast::unit_test::suite std::thread localThread([&voidCounter, &threadExited, this]() { // Should stall after calling join. using namespace std::chrono_literals; - voidCounter.join("testWaitOnJoin", 1ms, j); + voidCounter.join("testWaitOnJoin", 1ms, *j); threadExited.store(true); }); @@ -308,6 +308,9 @@ public: void run() override { + env_.emplace(*this, jtx::envconfig(), nullptr, beast::severities::kDisabled); + j.emplace(env_->app().getJournal("ClosureCounter_test")); + testConstruction(); testArgs(); testWrap(); diff --git a/src/test/jtx/Env.h b/src/test/jtx/Env.h index d638d520ba..256c212c70 100644 --- a/src/test/jtx/Env.h +++ b/src/test/jtx/Env.h @@ -153,7 +153,8 @@ private: beast::unit_test::suite& suite, std::unique_ptr config, std::unique_ptr logs, - beast::severities::Severity thresh); + beast::severities::Severity thresh, + std::optional referenceFee); ~AppBundle(); }; @@ -186,9 +187,15 @@ public: std::unique_ptr config, FeatureBitset features, std::unique_ptr logs = nullptr, - beast::severities::Severity thresh = beast::severities::kError) + std::optional thresh = std::nullopt, + std::optional referenceFee = std::nullopt) : test(suite_) - , bundle_(suite_, std::move(config), std::move(logs), thresh) + , bundle_( + suite_, + std::move(config), + std::move(logs), + thresh.value_or(beast::severities::kError), + referenceFee) , journal{bundle_.app->getJournal("Env")} { memoize(Account::master); @@ -199,8 +206,8 @@ public: } /** - * @brief Create Env with default config and specified - * features. + * @brief Create Env with default config, specified + * features, log handler, and reference fee. * * This constructor will create an Env with the standard Env configuration * (from envconfig()) and features explicitly specified. Use @@ -208,13 +215,36 @@ public: * collection of features appropriate for passing here. * * @param suite_ the current unit_test::suite - * @param args collection of features + * @param features collection of features + * @param logs log handler + * @param referenceFee non-default reference fee * */ Env(beast::unit_test::suite& suite_, FeatureBitset features, - std::unique_ptr logs = nullptr) - : Env(suite_, envconfig(), features, std::move(logs)) + std::unique_ptr logs, + std::optional referenceFee = std::nullopt) + : Env(suite_, envconfig(), features, std::move(logs), std::nullopt, referenceFee) + { + } + /** + * @brief Create Env with default config, specified + * features, and reference fee. + * + * This constructor will create an Env with the standard Env configuration + * (from envconfig()) and features explicitly specified. Use + * with_only_features(...) or supported_features_except(...) to create a + * collection of features appropriate for passing here. + * + * @param suite_ the current unit_test::suite + * @param features collection of features + * @param referenceFee non-default reference fee + * + */ + Env(beast::unit_test::suite& suite_, + FeatureBitset features, + std::optional referenceFee = std::nullopt) + : Env(suite_, envconfig(), features, nullptr, std::nullopt, referenceFee) { } @@ -233,8 +263,48 @@ public: Env(beast::unit_test::suite& suite_, std::unique_ptr config, std::unique_ptr logs = nullptr, - beast::severities::Severity thresh = beast::severities::kError) - : Env(suite_, std::move(config), testable_amendments(), std::move(logs), thresh) + std::optional thresh = std::nullopt, + std::optional referenceFee = std::nullopt) + : Env(suite_, + std::move(config), + testable_amendments(), + std::move(logs), + thresh, + referenceFee) + { + } + + /** + * @brief Create Env using suite, Config pointer, and reference fee. + * + * This constructor will create an Env with the specified configuration + * and takes ownership the passed Config pointer. All supported amendments + * are enabled by this version of the constructor. + * + * @param suite_ the current unit_test::suite + * @param config The desired Config - ownership will be taken by moving + * the pointer. See envconfig and related functions for common config + * tweaks. + * @param referenceFee Optional reference fee to use in fee settings. + */ + Env(beast::unit_test::suite& suite_, + std::unique_ptr config, + std::optional referenceFee) + : Env(suite_, std::move(config), testable_amendments(), nullptr, std::nullopt, referenceFee) + { + } + + /** + * @brief Create Env with the current test suite and a referenceFee + * + * This constructor will create an Env with the standard + * test Env configuration (from envconfig()) and all supported + * amendments enabled. + * + * @param suite_ the current unit_test::suite + */ + Env(beast::unit_test::suite& suite_, std::optional referenceFee) + : Env(suite_, envconfig(), referenceFee) { } @@ -248,8 +318,9 @@ public: * @param suite_ the current unit_test::suite */ Env(beast::unit_test::suite& suite_, - beast::severities::Severity thresh = beast::severities::kError) - : Env(suite_, envconfig(), nullptr, thresh) + beast::severities::Severity thresh = beast::severities::kError, + std::optional referenceFee = std::nullopt) + : Env(suite_, envconfig(), nullptr, thresh, referenceFee) { } diff --git a/src/test/jtx/impl/Env.cpp b/src/test/jtx/impl/Env.cpp index bba10439ed..05ea66e94a 100644 --- a/src/test/jtx/impl/Env.cpp +++ b/src/test/jtx/impl/Env.cpp @@ -40,7 +40,8 @@ Env::AppBundle::AppBundle( beast::unit_test::suite& suite, std::unique_ptr config, std::unique_ptr logs, - beast::severities::Severity thresh) + beast::severities::Severity thresh, + std::optional referenceFee) : AppBundle() { using namespace beast::severities; @@ -56,6 +57,14 @@ Env::AppBundle::AppBundle( } auto timeKeeper_ = std::make_unique(); timeKeeper = timeKeeper_.get(); + if (referenceFee) + { + config->FEES.reference_fee = *referenceFee; + } + else if (auto const fee = suite.referenceFee()) + { + config->FEES.reference_fee = *fee; + } // Hack so we don't have to call Config::setup HTTPClient::initializeSSLContext( config->SSL_VERIFY_DIR, config->SSL_VERIFY_FILE, config->SSL_VERIFY, debugLog()); diff --git a/src/test/jtx/impl/envconfig.cpp b/src/test/jtx/impl/envconfig.cpp index e31e687c3d..4058c45ba7 100644 --- a/src/test/jtx/impl/envconfig.cpp +++ b/src/test/jtx/impl/envconfig.cpp @@ -14,7 +14,7 @@ setupConfigForUnitTests(Config& cfg) using namespace jtx; // Default fees to old values, so tests don't have to worry about changes in // Config.h - cfg.FEES.reference_fee = UNIT_TEST_REFERENCE_FEE; + cfg.FEES.reference_fee = XRPAmount(10); cfg.FEES.account_reserve = XRP(200).value().xrp().drops(); cfg.FEES.owner_reserve = XRP(50).value().xrp().drops(); diff --git a/src/test/overlay/reduce_relay_test.cpp b/src/test/overlay/reduce_relay_test.cpp index bac70d35a6..7c3e0ec426 100644 --- a/src/test/overlay/reduce_relay_test.cpp +++ b/src/test/overlay/reduce_relay_test.cpp @@ -870,9 +870,9 @@ protected: void printPeers(std::string const& msg, std::uint16_t validator = 0) { - auto peers = network_.overlay().getPeers(network_.validator(validator)); - std::cout << msg << " " - << "num peers " << (int)network_.overlay().getNumPeers() << std::endl; + auto peers = network_->overlay().getPeers(network_->validator(validator)); + std::cout << msg << " " << "num peers " << (int)network_->overlay().getNumPeers() + << std::endl; for (auto& [k, v] : peers) std::cout << k << ":" << (int)std::get(v) << " "; std::cout << std::endl; @@ -925,8 +925,8 @@ protected: std::unordered_map events{{LinkDown, {}}, {PeerDisconnected, {}}}; time_point lastCheck = ManualClock::now(); - network_.reset(); - network_.propagate([&](Link& link, MessageSPtr m) { + network_->reset(); + network_->propagate([&](Link& link, MessageSPtr m) { auto& validator = link.validator(); auto now = ManualClock::now(); @@ -943,7 +943,7 @@ protected: if (squelched) { - auto selected = network_.overlay().getSelected(validator); + auto selected = network_->overlay().getSelected(validator); str << " selected: "; for (auto s : selected) str << s << " "; @@ -953,11 +953,11 @@ protected: << " random, squelched, validator: " << validator.id() << " peers: " << str.str() << std::endl; } - auto countingState = network_.overlay().isCountingState(validator); + auto countingState = network_->overlay().isCountingState(validator); BEAST_EXPECT( countingState == false && selected.size() == - env_.app().config().VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS); + env_->app().config().VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS); } // Trigger Link Down or Peer Disconnect event @@ -973,13 +973,13 @@ protected: events[event].time_ = now; if (event == EventType::LinkDown) { - network_.enableLink(validator.id(), link.peerId(), false); + network_->enableLink(validator.id(), link.peerId(), false); events[event].isSelected_ = - network_.overlay().isSelected(validator, link.peerId()); + network_->overlay().isSelected(validator, link.peerId()); } else { - events[event].isSelected_ = network_.isSelected(link.peerId()); + events[event].isSelected_ = network_->isSelected(link.peerId()); } }; auto r = rand_int(0, 1000); @@ -992,8 +992,8 @@ protected: if (events[EventType::PeerDisconnected].state_ == State::On) { auto& event = events[EventType::PeerDisconnected]; - bool const allCounting = network_.allCounting(event.peer_); - network_.overlay().deletePeer( + bool const allCounting = network_->allCounting(event.peer_); + network_->overlay().deletePeer( event.peer_, [&](PublicKey const& v, PeerWPtr const& peerPtr) { if (event.isSelected_) sendSquelch(v, peerPtr, {}); @@ -1011,7 +1011,7 @@ protected: event.isSelected_ = false; event.handledCnt_ += handled; event.handled_ = false; - network_.onDisconnectPeer(event.peer_); + network_->onDisconnectPeer(event.peer_); } auto& event = events[EventType::LinkDown]; @@ -1029,17 +1029,17 @@ protected: bool mustHandle = false; if (event.state_ == State::On && BEAST_EXPECT(event.key_)) { - event.isSelected_ = network_.overlay().isSelected(*event.key_, event.peer_); - auto peers = network_.overlay().getPeers(*event.key_); + event.isSelected_ = network_->overlay().isSelected(*event.key_, event.peer_); + auto peers = network_->overlay().getPeers(*event.key_); auto d = reduce_relay::epoch(now).count() - std::get<3>(peers[event.peer_]); mustHandle = event.isSelected_ && d > milliseconds(reduce_relay::IDLED).count() && - network_.overlay().inState( + network_->overlay().inState( *event.key_, reduce_relay::PeerState::Squelched) > 0 && peers.contains(event.peer_); } - network_.overlay().deleteIdlePeers([&](PublicKey const& v, PeerWPtr const& ptr) { + network_->overlay().deleteIdlePeers([&](PublicKey const& v, PeerWPtr const& ptr) { event.handled_ = true; if (mustHandle && v == event.key_) { @@ -1061,7 +1061,7 @@ protected: event.isSelected_ = false; event.handledCnt_ += handled; event.handled_ = false; - network_.enableLink(event.validator_, event.peer_, true); + network_->enableLink(event.validator_, event.peer_, true); } }); @@ -1082,7 +1082,7 @@ protected: bool checkCounting(PublicKey const& validator, bool isCountingState) { - auto countingState = network_.overlay().isCountingState(validator); + auto countingState = network_->overlay().isCountingState(validator); BEAST_EXPECT(countingState == isCountingState); return countingState == isCountingState; } @@ -1133,7 +1133,7 @@ protected: propagateAndSquelch(bool log, bool purge = true, bool resetClock = true) { int n = 0; - network_.propagate( + network_->propagate( [&](Link& link, MessageSPtr message) { std::uint16_t squelched = 0; link.send( @@ -1146,7 +1146,8 @@ protected: { BEAST_EXPECT( squelched == - MAX_PEERS - env_.app().config().VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS); + MAX_PEERS - + env_->app().config().VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS); n++; } }, @@ -1154,11 +1155,11 @@ protected: reduce_relay::MAX_MESSAGE_THRESHOLD + 2, purge, resetClock); - auto selected = network_.overlay().getSelected(network_.validator(0)); + auto selected = network_->overlay().getSelected(network_->validator(0)); BEAST_EXPECT( - selected.size() == env_.app().config().VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS); + selected.size() == env_->app().config().VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS); BEAST_EXPECT(n == 1); // only one selection round - auto res = checkCounting(network_.validator(0), false); + auto res = checkCounting(network_->validator(0), false); BEAST_EXPECT(res); return n == 1 && res; } @@ -1173,7 +1174,7 @@ protected: bool resetClock = true) { bool squelched = false; - network_.propagate( + network_->propagate( [&](Link& link, MessageSPtr message) { link.send( message, @@ -1186,7 +1187,7 @@ protected: nMessages, purge, resetClock); - auto res = checkCounting(network_.validator(0), countingState); + auto res = checkCounting(network_->validator(0), countingState); return !squelched && res; } @@ -1198,7 +1199,7 @@ protected: { doTest("New Peer", log, [this](bool log) { BEAST_EXPECT(propagateAndSquelch(log, true, false)); - network_.addPeer(); + network_->addPeer(); BEAST_EXPECT(propagateNoSquelch(log, 1, true, false, false)); }); } @@ -1211,14 +1212,14 @@ protected: doTest("Selected Peer Disconnects", log, [this](bool log) { ManualClock::advance(seconds(601)); BEAST_EXPECT(propagateAndSquelch(log, true, false)); - auto id = network_.overlay().getSelectedPeer(network_.validator(0)); + auto id = network_->overlay().getSelectedPeer(network_->validator(0)); std::uint16_t unsquelched = 0; - network_.overlay().deletePeer( + network_->overlay().deletePeer( id, [&](PublicKey const& key, PeerWPtr const& peer) { unsquelched++; }); BEAST_EXPECT( unsquelched == - MAX_PEERS - env_.app().config().VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS); - BEAST_EXPECT(checkCounting(network_.validator(0), true)); + MAX_PEERS - env_->app().config().VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS); + BEAST_EXPECT(checkCounting(network_->validator(0), true)); }); } @@ -1232,13 +1233,13 @@ protected: BEAST_EXPECT(propagateAndSquelch(log, true, false)); ManualClock::advance(reduce_relay::IDLED + seconds(1)); std::uint16_t unsquelched = 0; - network_.overlay().deleteIdlePeers( + network_->overlay().deleteIdlePeers( [&](PublicKey const& key, PeerWPtr const& peer) { unsquelched++; }); - auto peers = network_.overlay().getPeers(network_.validator(0)); + auto peers = network_->overlay().getPeers(network_->validator(0)); BEAST_EXPECT( unsquelched == - MAX_PEERS - env_.app().config().VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS); - BEAST_EXPECT(checkCounting(network_.validator(0), true)); + MAX_PEERS - env_->app().config().VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS); + BEAST_EXPECT(checkCounting(network_->validator(0), true)); }); } @@ -1250,17 +1251,17 @@ protected: doTest("Squelched Peer Disconnects", log, [this](bool log) { ManualClock::advance(seconds(601)); BEAST_EXPECT(propagateAndSquelch(log, true, false)); - auto peers = network_.overlay().getPeers(network_.validator(0)); + auto peers = network_->overlay().getPeers(network_->validator(0)); auto it = std::find_if(peers.begin(), peers.end(), [&](auto it) { return std::get(it.second) == reduce_relay::PeerState::Squelched; }); assert(it != peers.end()); std::uint16_t unsquelched = 0; - network_.overlay().deletePeer( + network_->overlay().deletePeer( it->first, [&](PublicKey const& key, PeerWPtr const& peer) { unsquelched++; }); BEAST_EXPECT(unsquelched == 0); - BEAST_EXPECT(checkCounting(network_.validator(0), false)); + BEAST_EXPECT(checkCounting(network_->validator(0), false)); }); } @@ -1404,9 +1405,9 @@ vp_base_squelch_max_selected_peers=2 doTest("BaseSquelchReady", log, [&](bool log) { ManualClock::reset(); auto createSlots = [&](bool baseSquelchEnabled) -> reduce_relay::Slots { - env_.app().config().VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE = baseSquelchEnabled; + env_->app().config().VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE = baseSquelchEnabled; return reduce_relay::Slots( - env_.app(), network_.overlay(), env_.app().config()); + env_->app().logs(), network_->overlay(), env_->app().config()); }; // base squelching must not be ready if squelching is disabled BEAST_EXPECT(!createSlots(false).baseSquelchReady()); @@ -1430,32 +1431,32 @@ vp_base_squelch_max_selected_peers=2 testInternalHashRouter(bool log) { doTest("Duplicate Message", log, [&](bool log) { - network_.reset(); + network_->reset(); // update message count for the same peer/validator std::int16_t const nMessages = 5; for (int i = 0; i < nMessages; i++) { uint256 const key(i); - network_.overlay().updateSlotAndSquelch( - key, network_.validator(0), 0, [&](PublicKey const&, PeerWPtr, std::uint32_t) { + network_->overlay().updateSlotAndSquelch( + key, network_->validator(0), 0, [&](PublicKey const&, PeerWPtr, std::uint32_t) { }); } - auto peers = network_.overlay().getPeers(network_.validator(0)); + auto peers = network_->overlay().getPeers(network_->validator(0)); // first message changes Slot state to Counting and is not counted, // hence '-1'. BEAST_EXPECT(std::get<1>(peers[0]) == (nMessages - 1)); // add duplicate uint256 const key(nMessages - 1); - network_.overlay().updateSlotAndSquelch( - key, network_.validator(0), 0, [&](PublicKey const&, PeerWPtr, std::uint32_t) {}); + network_->overlay().updateSlotAndSquelch( + key, network_->validator(0), 0, [&](PublicKey const&, PeerWPtr, std::uint32_t) {}); // confirm the same number of messages - peers = network_.overlay().getPeers(network_.validator(0)); + peers = network_->overlay().getPeers(network_->validator(0)); BEAST_EXPECT(std::get<1>(peers[0]) == (nMessages - 1)); // advance the clock ManualClock::advance(reduce_relay::IDLED + seconds(1)); - network_.overlay().updateSlotAndSquelch( - key, network_.validator(0), 0, [&](PublicKey const&, PeerWPtr, std::uint32_t) {}); - peers = network_.overlay().getPeers(network_.validator(0)); + network_->overlay().updateSlotAndSquelch( + key, network_->validator(0), 0, [&](PublicKey const&, PeerWPtr, std::uint32_t) {}); + peers = network_->overlay().getPeers(network_->validator(0)); // confirm message number increased BEAST_EXPECT(std::get<1>(peers[0]) == nMessages); }); @@ -1487,7 +1488,8 @@ vp_base_squelch_max_selected_peers=2 auto run = [&](int npeers) { handler.maxDuration_ = 0; - reduce_relay::Slots slots(env_.app(), handler, env_.app().config()); + reduce_relay::Slots slots( + env_->app().logs(), handler, env_->app().config()); // 1st message from a new peer switches the slot // to counting state and resets the counts of all peers + // MAX_MESSAGE_THRESHOLD + 1 messages to reach the threshold @@ -1562,10 +1564,10 @@ vp_base_squelch_max_selected_peers=2 << "[compression]\n" << "1\n"; c.loadFromString(str.str()); - env_.app().config().VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE = + env_->app().config().VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE = c.VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE; - env_.app().config().COMPRESSION = c.COMPRESSION; + env_->app().config().COMPRESSION = c.COMPRESSION; }; auto handshake = [&](int outboundEnable, int inboundEnable) { beast::IP::Address const addr = boost::asio::ip::make_address("172.1.1.100"); @@ -1573,10 +1575,10 @@ vp_base_squelch_max_selected_peers=2 setEnv(outboundEnable); auto request = xrpl::makeRequest( true, - env_.app().config().COMPRESSION, + env_->app().config().COMPRESSION, false, - env_.app().config().TX_REDUCE_RELAY_ENABLE, - env_.app().config().VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE); + env_->app().config().TX_REDUCE_RELAY_ENABLE, + env_->app().config().VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE); http_request_type http_request; http_request.version(request.version()); http_request.base() = request.base(); @@ -1591,7 +1593,7 @@ vp_base_squelch_max_selected_peers=2 setEnv(inboundEnable); auto http_resp = xrpl::makeResponse( - true, http_request, addr, addr, uint256{1}, 1, {1, 0}, env_.app()); + true, http_request, addr, addr, uint256{1}, 1, {1, 0}, env_->app()); // outbound is enabled if the response's header has the feature // enabled and the peer's configuration is enabled auto const outboundEnabled = @@ -1605,23 +1607,21 @@ vp_base_squelch_max_selected_peers=2 }); } - jtx::Env env_; - Network network_; + std::optional env_; + std::optional network_; public: - reduce_relay_test() - : env_(*this, jtx::envconfig([](std::unique_ptr cfg) { - cfg->VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE = true; - cfg->VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS = 6; - return cfg; - })) - , network_(env_.app()) - { - } - void run() override { + env_.emplace(*this); + env_.emplace(*this, jtx::envconfig([](std::unique_ptr cfg) { + cfg->VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE = true; + cfg->VP_REDUCE_RELAY_SQUELCH_MAX_SELECTED_PEERS = 6; + return cfg; + })); + network_.emplace(env_->app()); + bool const log = false; testConfig(log); testInitialRound(log); diff --git a/src/test/rpc/AccountTx_test.cpp b/src/test/rpc/AccountTx_test.cpp index 2470ec3c4c..b3c9262ef6 100644 --- a/src/test/rpc/AccountTx_test.cpp +++ b/src/test/rpc/AccountTx_test.cpp @@ -93,10 +93,7 @@ class AccountTx_test : public beast::unit_test::suite testcase("Parameters APIv" + std::to_string(apiVersion)); using namespace test::jtx; - Env env(*this, envconfig([](std::unique_ptr cfg) { - cfg->FEES.reference_fee = 10; - return cfg; - })); + Env env(*this, XRPAmount(10)); Account const A1{"A1"}; env.fund(XRP(10000), A1); env.close(); diff --git a/src/test/rpc/DeliveredAmount_test.cpp b/src/test/rpc/DeliveredAmount_test.cpp index 167027006a..bf93a06b4f 100644 --- a/src/test/rpc/DeliveredAmount_test.cpp +++ b/src/test/rpc/DeliveredAmount_test.cpp @@ -187,9 +187,7 @@ class DeliveredAmount_test : public beast::unit_test::suite for (bool const afterSwitchTime : {true, false}) { - auto cfg = envconfig(); - cfg->FEES.reference_fee = 10; - Env env(*this, std::move(cfg)); + Env env(*this, XRPAmount(10)); env.fund(XRP(10000), alice, bob, carol, gw); env.trust(USD(1000), alice, bob, carol); if (afterSwitchTime) @@ -278,9 +276,7 @@ class DeliveredAmount_test : public beast::unit_test::suite for (bool const afterSwitchTime : {true, false}) { - auto cfg = envconfig(); - cfg->FEES.reference_fee = 10; - Env env(*this, std::move(cfg)); + Env env(*this, XRPAmount(10)); env.fund(XRP(10000), alice, bob, carol, gw); env.trust(USD(1000), alice, bob, carol); if (afterSwitchTime) diff --git a/src/test/rpc/JSONRPC_test.cpp b/src/test/rpc/JSONRPC_test.cpp index b9d4ee4a98..fd6bab4690 100644 --- a/src/test/rpc/JSONRPC_test.cpp +++ b/src/test/rpc/JSONRPC_test.cpp @@ -2719,10 +2719,7 @@ public: // "b" (not in the ledger) is rDg53Haik2475DJx8bjMDSDPj4VX7htaMd. // "c" (phantom signer) is rPcNzota6B8YBokhYtcTNqQVCngtbnWfux. - Env env(*this, envconfig([](std::unique_ptr cfg) { - cfg->FEES.reference_fee = 10; - return cfg; - })); + Env env(*this, XRPAmount(10)); env.fund(XRP(100000), a, ed, g); env.close(); diff --git a/src/test/rpc/LedgerClosed_test.cpp b/src/test/rpc/LedgerClosed_test.cpp index 2bc5c2b0c9..1f5aebfc4c 100644 --- a/src/test/rpc/LedgerClosed_test.cpp +++ b/src/test/rpc/LedgerClosed_test.cpp @@ -14,9 +14,7 @@ public: using namespace test::jtx; // This test relies on ledger hash so must lock it to fee 10. - auto p = envconfig(); - p->FEES.reference_fee = 10; - Env env{*this, std::move(p), FeatureBitset{}}; + Env env{*this, FeatureBitset{}, XRPAmount{10}}; Account const alice{"alice"}; env.fund(XRP(10000), alice); diff --git a/src/test/rpc/LedgerEntry_test.cpp b/src/test/rpc/LedgerEntry_test.cpp index 7688c09fa7..a81e1f560b 100644 --- a/src/test/rpc/LedgerEntry_test.cpp +++ b/src/test/rpc/LedgerEntry_test.cpp @@ -514,9 +514,7 @@ class LedgerEntry_test : public beast::unit_test::suite testcase("AccountRoot"); using namespace test::jtx; - auto cfg = envconfig(); - cfg->FEES.reference_fee = 10; - Env env{*this, std::move(cfg)}; + Env env{*this, XRPAmount(10)}; Account const alice{"alice"}; env.fund(XRP(10000), alice); diff --git a/src/test/rpc/LedgerRPC_test.cpp b/src/test/rpc/LedgerRPC_test.cpp index 8f965aa2cf..8f156db826 100644 --- a/src/test/rpc/LedgerRPC_test.cpp +++ b/src/test/rpc/LedgerRPC_test.cpp @@ -238,10 +238,8 @@ class LedgerRPC_test : public beast::unit_test::suite testcase("Lookup ledger"); using namespace test::jtx; - auto cfg = envconfig(); - cfg->FEES.reference_fee = 10; - Env env{*this, std::move(cfg), FeatureBitset{}}; // hashes requested below - // assume no amendments + Env env{*this, FeatureBitset{}, XRPAmount(10)}; // hashes requested below + // assume no amendments env.fund(XRP(10000), "alice"); env.close(); env.fund(XRP(10000), "bob"); @@ -408,8 +406,7 @@ class LedgerRPC_test : public beast::unit_test::suite return cfg; }); - cfg->FEES.reference_fee = 10; - Env env(*this, std::move(cfg)); + Env env(*this, std::move(cfg), XRPAmount(10)); Json::Value jv; jv[jss::ledger_index] = "current"; diff --git a/src/test/rpc/LedgerRequest_test.cpp b/src/test/rpc/LedgerRequest_test.cpp index 4462c1f039..789bbc427c 100644 --- a/src/test/rpc/LedgerRequest_test.cpp +++ b/src/test/rpc/LedgerRequest_test.cpp @@ -142,10 +142,8 @@ public: { using namespace test::jtx; - auto cfg = envconfig(); - cfg->FEES.reference_fee = 10; - Env env{*this, std::move(cfg), FeatureBitset{}}; // the hashes being checked below - // assume no amendments + Env env{*this, FeatureBitset{}, XRPAmount(10)}; // the hashes being checked below + // assume no amendments Account const gw{"gateway"}; auto const USD = gw["USD"]; env.fund(XRP(100000), gw); @@ -294,11 +292,13 @@ public: { using namespace test::jtx; using namespace std::chrono_literals; - Env env{*this, envconfig([](std::unique_ptr cfg) { - cfg->FEES.reference_fee = 10; - cfg->NODE_SIZE = 0; - return cfg; - })}; + Env env{ + *this, + envconfig([](std::unique_ptr cfg) { + cfg->NODE_SIZE = 0; + return cfg; + }), + XRPAmount(10)}; Account const gw{"gateway"}; auto const USD = gw["USD"]; env.fund(XRP(100000), gw); diff --git a/src/test/rpc/Subscribe_test.cpp b/src/test/rpc/Subscribe_test.cpp index 080c9232de..df8f5e0900 100644 --- a/src/test/rpc/Subscribe_test.cpp +++ b/src/test/rpc/Subscribe_test.cpp @@ -286,11 +286,7 @@ public: using namespace std::chrono_literals; using namespace jtx; - Env env(*this, envconfig([](std::unique_ptr cfg) { - cfg->FEES.reference_fee = 10; - cfg = single_thread_io(std::move(cfg)); - return cfg; - })); + Env env(*this, envconfig(single_thread_io), nullptr, std::nullopt, XRPAmount(10)); auto wsc = makeWSClient(env.app().config()); Json::Value stream{Json::objectValue}; diff --git a/src/test/rpc/TransactionEntry_test.cpp b/src/test/rpc/TransactionEntry_test.cpp index 6421587478..48b3ee4a84 100644 --- a/src/test/rpc/TransactionEntry_test.cpp +++ b/src/test/rpc/TransactionEntry_test.cpp @@ -16,10 +16,7 @@ class TransactionEntry_test : public beast::unit_test::suite { testcase("Invalid request params"); using namespace test::jtx; - Env env{*this, envconfig([](std::unique_ptr cfg) { - cfg->FEES.reference_fee = 10; - return cfg; - })}; + Env env{*this, XRPAmount(10)}; { // no params @@ -123,10 +120,7 @@ class TransactionEntry_test : public beast::unit_test::suite { testcase("Basic request API version " + std::to_string(apiVersion)); using namespace test::jtx; - Env env{*this, envconfig([](std::unique_ptr cfg) { - cfg->FEES.reference_fee = 10; - return cfg; - })}; + Env env{*this, XRPAmount(10)}; auto check_tx = [this, &env, apiVersion]( int index, diff --git a/src/test/rpc/Transaction_test.cpp b/src/test/rpc/Transaction_test.cpp index 9f06607729..a5d956adb6 100644 --- a/src/test/rpc/Transaction_test.cpp +++ b/src/test/rpc/Transaction_test.cpp @@ -725,10 +725,7 @@ class Transaction_test : public beast::unit_test::suite using namespace test::jtx; using std::to_string; - Env env{*this, envconfig([](std::unique_ptr cfg) { - cfg->FEES.reference_fee = 10; - return cfg; - })}; + Env env{*this, XRPAmount(10)}; Account const alice{"alice"}; Account const alie{"alie"}; Account const gw{"gw"}; @@ -803,10 +800,7 @@ class Transaction_test : public beast::unit_test::suite using namespace test::jtx; using std::to_string; - Env env{*this, envconfig([](std::unique_ptr cfg) { - cfg->FEES.reference_fee = 10; - return cfg; - })}; + Env env{*this, XRPAmount(10)}; Account const alice{"alice"}; Account const gw{"gw"}; auto const USD{gw["USD"]}; diff --git a/src/xrpld/app/main/Main.cpp b/src/xrpld/app/main/Main.cpp index ebd5920492..7872f5cd9d 100644 --- a/src/xrpld/app/main/Main.cpp +++ b/src/xrpld/app/main/Main.cpp @@ -242,6 +242,7 @@ static int runUnitTests( std::string const& pattern, std::string const& argument, + std::optional referenceFee, bool quiet, bool log, bool child, @@ -261,6 +262,8 @@ runUnitTests( multi_runner_child child_runner{num_jobs, quiet, log}; child_runner.arg(argument); + if (referenceFee) + child_runner.referenceFee(*referenceFee); multi_selector const pred(pattern); auto const any_failed = child_runner.run_multi(pred) || anyMissing(child_runner, pred); @@ -318,6 +321,8 @@ runUnitTests( // child multi_runner_child runner{num_jobs, quiet, log}; runner.arg(argument); + if (referenceFee) + runner.referenceFee(*referenceFee); auto const anyFailed = runner.run_multi(multi_selector(pattern)); if (anyFailed) @@ -408,6 +413,10 @@ run(int argc, char** argv) "argument is handled individually by any suite that accesses it -- " "as such, it typically only make sense to provide this when running " "a single suite.")( + "unittest-fee", + po::value(), + "Supplies a reference fee (in drops) to unit tests. If provided, this " + "value is used in every suite that does not override it.")( "unittest-ipv6", "Use IPv6 localhost when running unittests (default is IPv4).")( "unittest-log", "Force unit test log message output. Only useful in combination with " @@ -503,9 +512,12 @@ run(int argc, char** argv) if (vm.contains("unittest")) { std::string argument; + std::optional referenceFee; if (vm.contains("unittest-arg")) argument = vm["unittest-arg"].as(); + if (vm.count("unittest-fee")) + referenceFee = vm["unittest-fee"].as(); std::size_t numJobs = 1; bool unittestChild = false; @@ -516,6 +528,7 @@ run(int argc, char** argv) return runUnitTests( vm["unittest"].as(), argument, + referenceFee, vm.contains("quiet"), vm.contains("unittest-log"), unittestChild, @@ -526,13 +539,12 @@ run(int argc, char** argv) } // LCOV_EXCL_START - if (vm.contains("unittest-jobs")) + if (vm.count("unittest-jobs") || vm.count("unittest-arg") || vm.count("unittest-fee") || + vm.count("unittest-log") || vm.count("unittest-ipv6")) { // unittest jobs only makes sense with `unittest` - std::cerr << "xrpld: '--unittest-jobs' specified without " - "'--unittest'.\n"; - std::cerr << "To run the unit tests the '--unittest' option must " - "be present.\n"; + std::cerr << "xrpld: unittest-related parameter specified without '--unittest'.\n"; + std::cerr << "To run the unit tests the '--unittest' option must be present.\n"; return 1; }