diff --git a/.config/nextest.toml b/.config/nextest.toml new file mode 100644 index 000000000..9fabc4519 --- /dev/null +++ b/.config/nextest.toml @@ -0,0 +1,14 @@ +[test-groups] +dashd-integration = { max-threads = 1 } + +[profile.ci] +fail-fast = false + +[profile.ci.junit] +path = "junit.xml" + +# dashd integration tests each start their own dashd process; +# running them concurrently causes resource contention and crashes. +[[profile.ci.overrides]] +filter = 'binary(dashd_sync)' +test-group = 'dashd-integration' diff --git a/.github/scripts/ci_config.py b/.github/scripts/ci_config.py index 7c56715c8..66e0606ed 100755 --- a/.github/scripts/ci_config.py +++ b/.github/scripts/ci_config.py @@ -11,6 +11,7 @@ import argparse import json import os +import shutil import subprocess import sys from pathlib import Path @@ -118,6 +119,9 @@ def run_group_tests(args): if coverage and args.group not in no_coverage: github_output("crate_flags", args.group) + junit_dir = Path("target/test-results") + junit_dir.mkdir(parents=True, exist_ok=True) + for crate in crates: # Skip dash-fuzz on Windows if args.os == "windows-latest" and crate == "dash-fuzz": @@ -127,17 +131,39 @@ def run_group_tests(args): github_group_start(f"Testing {crate}") if coverage and args.group not in no_coverage: - cmd = ["cargo", "llvm-cov", "--no-report", "-p", crate, "--all-features"] + cmd = [ + "cargo", "llvm-cov", "nextest", + "--no-report", "-p", crate, "--all-features", + "--profile", "ci", + "--no-tests=pass", + ] else: - cmd = ["cargo", "test", "-p", crate, "--all-features"] + cmd = [ + "cargo", "nextest", "run", + "-p", crate, "--all-features", + "--profile", "ci", + "--no-tests=pass", + ] result = subprocess.run(cmd) + # Collect JUnit XML per crate for Codecov test analytics + src = Path("target/nextest/ci/junit.xml") + if src.exists(): + shutil.copy(src, junit_dir / f"junit-{crate}.xml") + github_group_end() if result.returncode != 0: failed.append(crate) github_error(f"Test failed for {crate} on {args.os}") + junit_files = sorted(junit_dir.glob("junit-*.xml")) + if junit_files: + github_output( + "junit_files", + ",".join(str(f).replace("\\", "/") for f in junit_files), + ) + if failed: print("\n" + "=" * 40) print(f"FAILED TESTS ({args.group} on {args.os}):") diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 65ee36f76..32cd4708b 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -42,6 +42,9 @@ jobs: with: shared-key: "test-${{ inputs.os }}-${{ matrix.group }}" + - name: Install cargo-nextest + uses: taiki-e/install-action@nextest + - name: Install cargo-llvm-cov if: inputs.coverage uses: taiki-e/install-action@cargo-llvm-cov @@ -85,6 +88,14 @@ jobs: token: ${{ secrets.CODECOV_TOKEN }} fail_ci_if_error: true + - name: Upload test results to Codecov + if: ${{ !cancelled() && steps.tests.outputs.junit_files }} + uses: codecov/test-results-action@v1 + with: + files: ${{ steps.tests.outputs.junit_files }} + flags: ${{ matrix.group }} + token: ${{ secrets.CODECOV_TOKEN }} + - name: Upload failed dashd test logs if: failure() && (matrix.group == 'spv' || matrix.group == 'ffi') uses: actions/upload-artifact@v4