diff --git a/.github/workflows/reusable-build-test-config.yml b/.github/workflows/reusable-build-test-config.yml index d4135207fe..69fa7a7bef 100644 --- a/.github/workflows/reusable-build-test-config.yml +++ b/.github/workflows/reusable-build-test-config.yml @@ -223,11 +223,13 @@ jobs: BUILD_TYPE: ${{ inputs.build_type }} CMAKE_TARGET: ${{ inputs.cmake_target }} run: | + set -o pipefail cmake \ --build . \ --config "${BUILD_TYPE}" \ --parallel "${BUILD_NPROC}" \ - --target "${CMAKE_TARGET}" + --target "${CMAKE_TARGET}" \ + 2>&1 | tee "${GITHUB_WORKSPACE}/build.log" - name: Show ccache statistics if: ${{ inputs.ccache_enabled }} @@ -322,7 +324,7 @@ jobs: PRELOAD="" fi - LD_PRELOAD="$PRELOAD" ./xrpld --unittest --unittest-jobs "${BUILD_NPROC}" 2>&1 | tee unittest.log + LD_PRELOAD="$PRELOAD" ./xrpld --unittest --unittest-jobs "${BUILD_NPROC}" 2>&1 | tee "${GITHUB_WORKSPACE}/unittest.log" # Smoke-run every benchmark module with a single repetition to confirm the # benchmarks still build and execute. This is a correctness check, not a @@ -341,25 +343,27 @@ jobs: done < <(find src/benchmarks -type f -perm -u+x -name 'xrpl.bench.*') exit "${rc}" - - name: Show test failure summary - if: ${{ failure() && !inputs.build_only }} - env: - WORKING_DIR: ${{ runner.os == 'Windows' && format('{0}\{1}', env.BUILD_DIR, inputs.build_type) || env.BUILD_DIR }} + - name: Show build/test failure summary + if: ${{ failure() }} run: | - if [ ! -d "${WORKING_DIR}" ]; then - echo "Working directory '${WORKING_DIR}' does not exist." - exit 0 - fi + cd "${GITHUB_WORKSPACE}" - cd "${WORKING_DIR}" - - if [ ! -f unittest.log ]; then - echo "unittest.log not found; embedded tests may not have run." - exit 0 - fi - - if ! grep -E "failed" unittest.log; then - echo "Log present but no failure lines found in unittest.log." + if [ -f unittest.log ]; then + if ! grep -E "failed" unittest.log | grep -vE "^I[0-9]|^[0-9]+> (ERR:|FTL:)"; then + echo "unittest.log present but no failure lines found." + fi + elif [ -f build.log ]; then + # GCC/Clang emit "error:" (covers "fatal error:"); MSVC emits + # "error C####:", "error LNK####:", and "fatal error LNK####:". + # -A6 prints the lines that follow each match (source line, caret, + # notes, and the "N errors generated" tally) to capture the whole + # diagnostic block. + if ! grep -E -A6 "error:|error C[0-9]{4}|error LNK[0-9]{4}|fatal error" build.log; then + echo "build.log present but no compile errors found." + fi + else + echo "unittest.log/build.log not found; something went wrong." + exit 1 fi - name: Debug failure (Linux) if: ${{ failure() && runner.os == 'Linux' && !inputs.build_only }} diff --git a/src/test/app/Invariants_test.cpp b/src/test/app/Invariants_test.cpp index 076e39a42b..eaf1f2704c 100644 --- a/src/test/app/Invariants_test.cpp +++ b/src/test/app/Invariants_test.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -101,6 +102,12 @@ class Invariants_test : public beast::unit_test::Suite return xrpl::test::jtx::testableAmendments() | fixCleanup3_1_3 | fixCleanup3_2_0; } + test::jtx::Env + makeEnv(FeatureBitset features) + { + return {*this, test::jtx::envconfig(), features, nullptr, beast::Severity::Disabled}; + } + /** * Run a specific test case to put the ledger into a state that will be * detected by an invariant. Simulates the actions of a transaction that @@ -130,7 +137,7 @@ class Invariants_test : public beast::unit_test::Suite TxAccount setTxAccount = TxAccount::None) { doInvariantCheck( - test::jtx::Env(*this, defaultAmendments()), + makeEnv(defaultAmendments()), expectLogs, precheck, fee, @@ -1494,7 +1501,7 @@ class Invariants_test : public beast::unit_test::Suite testcase << "PermissionedDomain" + std::string(fixEnabled ? " fix" : ""); doInvariantCheck( - Env(*this, features), + makeEnv(features), {{"permissioned domain with no rules."}}, [](Account const& a1, Account const& a2, ApplyContext& ac) { return createPermissionedDomain(ac, a1, a2, 0).get(); @@ -1507,7 +1514,7 @@ class Invariants_test : public beast::unit_test::Suite static constexpr auto kTooBig = kMaxPermissionedDomainCredentialsArraySize + 1; doInvariantCheck( - Env(*this, features), + makeEnv(features), {{"permissioned domain bad credentials size " + std::to_string(kTooBig)}}, [](Account const& a1, Account const& a2, ApplyContext& ac) { return !!createPermissionedDomain(ac, a1, a2, kTooBig); @@ -1518,7 +1525,7 @@ class Invariants_test : public beast::unit_test::Suite testcase << "PermissionedDomain 3"; doInvariantCheck( - Env(*this, features), + makeEnv(features), {{"permissioned domain credentials aren't sorted"}}, [](Account const& a1, Account const& a2, ApplyContext& ac) { auto slePd = createPermissionedDomain(ac, a1, a2, 0); @@ -1542,7 +1549,7 @@ class Invariants_test : public beast::unit_test::Suite testcase << "PermissionedDomain 4"; doInvariantCheck( - Env(*this, features), + makeEnv(features), {{"permissioned domain credentials aren't unique"}}, [](Account const& a1, Account const& a2, ApplyContext& ac) { auto slePd = createPermissionedDomain(ac, a1, a2, 0); @@ -1565,7 +1572,7 @@ class Invariants_test : public beast::unit_test::Suite testcase << "PermissionedDomain Set 1"; doInvariantCheck( - Env(*this, features), + makeEnv(features), {{"permissioned domain with no rules."}}, [&](Account const& a1, Account const& a2, ApplyContext& ac) { // create PD @@ -1586,7 +1593,7 @@ class Invariants_test : public beast::unit_test::Suite testcase << "PermissionedDomain Set 2"; doInvariantCheck( - Env(*this, features), + makeEnv(features), {{"permissioned domain bad credentials size " + std::to_string(kTooBig)}}, [&](Account const& a1, Account const& a2, ApplyContext& ac) { // create PD @@ -1617,7 +1624,7 @@ class Invariants_test : public beast::unit_test::Suite testcase << "PermissionedDomain Set 3"; doInvariantCheck( - Env(*this, features), + makeEnv(features), {{"permissioned domain credentials aren't sorted"}}, [&](Account const& a1, Account const& a2, ApplyContext& ac) { // create PD @@ -1647,7 +1654,7 @@ class Invariants_test : public beast::unit_test::Suite testcase << "PermissionedDomain Set 4"; doInvariantCheck( - Env(*this, features), + makeEnv(features), {{"permissioned domain credentials aren't unique"}}, [&](Account const& a1, Account const& a2, ApplyContext& ac) { // create PD @@ -1688,7 +1695,7 @@ class Invariants_test : public beast::unit_test::Suite { testcase << "PermissionedDomain set 2 domains "; doInvariantCheck( - Env(*this, features), + makeEnv(features), fixEnabled ? badMoreThan1 : emptyV, [](Account const& a1, Account const& a2, ApplyContext& ac) { createPermissionedDomain(ac, a1, a2); @@ -1734,7 +1741,7 @@ class Invariants_test : public beast::unit_test::Suite { testcase << "PermissionedDomain set 0 domains "; doInvariantCheck( - Env(*this, features), + makeEnv(features), fixEnabled ? badNoDomains : emptyV, [](Account const&, Account const&, ApplyContext&) { return true; }, XRPAmount{}, @@ -1757,7 +1764,7 @@ class Invariants_test : public beast::unit_test::Suite env1.close(); doInvariantCheck( - Env(*this, features), + makeEnv(features), a1, a2, fixEnabled ? badNoDomains : emptyV, @@ -1798,7 +1805,7 @@ class Invariants_test : public beast::unit_test::Suite { testcase << "PermissionedDomain del, create domain "; doInvariantCheck( - Env(*this, features), + makeEnv(features), fixEnabled ? badNotDeleted : emptyV, [](Account const& a1, Account const& a2, ApplyContext& ac) { createPermissionedDomain(ac, a1, a2); @@ -1995,7 +2002,7 @@ class Invariants_test : public beast::unit_test::Suite testcase << "PermissionedDEX" + std::string(fixEnabled ? " fix" : ""); doInvariantCheck( - Env(*this, features), + makeEnv(features), {{"domain doesn't exist"}}, [](Account const& a1, Account const&, ApplyContext& ac) { Keylet const offerKey = keylet::offer(a1.id(), 10); @@ -2022,7 +2029,7 @@ class Invariants_test : public beast::unit_test::Suite // missing domain ID in offer object doInvariantCheck( - Env(*this, features), + makeEnv(features), {{"hybrid offer is malformed"}}, [&](Account const& a1, Account const& a2, ApplyContext& ac) { Keylet const offerKey = keylet::offer(a2.id(), 10); @@ -4342,7 +4349,7 @@ class Invariants_test : public beast::unit_test::Suite }; doInvariantCheck( - Env{*this, defaultAmendments() - fixCleanup3_2_0}, + makeEnv(defaultAmendments() - fixCleanup3_2_0), {}, [](Account const&, Account const&, ApplyContext&) { return true; }, XRPAmount{}, @@ -5468,7 +5475,7 @@ class Invariants_test : public beast::unit_test::Suite // sfHighLimit issue, not the keylet currency). testcase << "overwrite: NoXRPTrustLines" + std::string(fixEnabled ? " fix" : ""); doInvariantCheck( - Env(*this, features), + makeEnv(features), fixEnabled ? std::vector{{"an XRP trust line was created"}} : std::vector{}, [&insertOrderedTrustLinePair](Account const& a1, Account const& a2, ApplyContext& ac) { @@ -5496,7 +5503,7 @@ class Invariants_test : public beast::unit_test::Suite // Regression: bad deep-freeze trust line followed by a valid one. testcase << "overwrite: NoDeepFreeze" + std::string(fixEnabled ? " fix" : ""); doInvariantCheck( - Env(*this, features), + makeEnv(features), fixEnabled ? std::vector{{"a trust line with deep freeze flag without " "normal freeze was created"}} : std::vector{}, @@ -5530,7 +5537,7 @@ class Invariants_test : public beast::unit_test::Suite // still fires ("a MPT issuance was created"). testcase << "overwrite: NoZeroEscrow MPT" + std::string(fixEnabled ? " fix" : ""); doInvariantCheck( - Env(*this, features), + makeEnv(features), fixEnabled ? std::vector{{"escrow specifies invalid amount"}} : std::vector{{"a MPT issuance was created"}}, [](Account const& a1, Account const&, ApplyContext& ac) {