zebra/.github/workflows/ci-unit-tests-os.yml

321 lines
13 KiB
YAML

# This workflow performs unit tests across different operating systems and Rust versions. It includes steps for:
# - Testing on Ubuntu and macOS with stable and beta Rust toolchains.
# - Installing Zebra from the lockfile without cache on Ubuntu.
# - Verifying that Cargo.lock is up-to-date with Cargo.toml changes.
# - Running cargo-deny checks for dependencies.
# - Checking for unused dependencies in the code.
name: Multi-OS Unit Tests
# Ensures that only one workflow task will run at a time. Previous builds, if
# already in process, will get cancelled. Only the latest commit will be allowed
# to run, cancelling any workflows in between
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
on:
workflow_dispatch:
pull_request:
paths:
# code and tests
- '**/*.rs'
# hard-coded checkpoints and proptest regressions
- '**/*.txt'
# test data snapshots
- '**/*.snap'
# dependencies
- '**/Cargo.toml'
- '**/Cargo.lock'
- '**/deny.toml'
# configuration files
- '.cargo/config.toml'
- '**/clippy.toml'
# workflow definitions
- '.github/workflows/ci-unit-tests-os.yml'
# we build Rust caches on main,
# so they can be shared by all branches:
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#restrictions-for-accessing-a-cache
push:
branches:
- main
paths:
# production code and test code
- '**/*.rs'
# hard-coded checkpoints
# TODO: skip proptest regressions?
- '**/*.txt'
# test data snapshots
- '**/*.snap'
# dependencies
- '**/Cargo.toml'
- '**/Cargo.lock'
- '**/deny.toml'
# configuration files
- '.cargo/config.toml'
- '**/clippy.toml'
# workflow definitions
- '.github/workflows/ci-unit-tests-os.yml'
env:
CARGO_INCREMENTAL: ${{ vars.CARGO_INCREMENTAL }}
RUST_LOG: ${{ vars.RUST_LOG }}
RUST_BACKTRACE: ${{ vars.RUST_BACKTRACE }}
RUST_LIB_BACKTRACE: ${{ vars.RUST_LIB_BACKTRACE }}
COLORBT_SHOW_HIDDEN: ${{ vars.COLORBT_SHOW_HIDDEN }}
jobs:
########################################
### Build and test Zebra on all OSes ###
########################################
test:
name: Test ${{ matrix.rust }} on ${{ matrix.os }}${{ matrix.features }}
# The large timeout is to accommodate:
# - macOS and Windows builds (typically 50-90 minutes), and
timeout-minutes: 120
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
# TODO: Windows was removed for now, see https://github.com/ZcashFoundation/zebra/issues/3801
os: [ubuntu-latest, macos-latest]
rust: [stable, beta]
# TODO: When vars.EXPERIMENTAL_FEATURES has features in it, add it here.
# Or work out a way to trim the space from the variable: GitHub doesn't allow empty variables.
# Or use `default` for the empty feature set and EXPERIMENTAL_FEATURES, and update the branch protection rules.
#features: ${{ fromJSON(format('["", "{0}"]', vars.EXPERIMENTAL_FEATURES)) }}
features: [""]
exclude:
# We're excluding macOS beta for the following reasons:
# - the concurrent macOS runner limit is much lower than the Linux limit
# - macOS is slower than Linux, and shouldn't have a build or test difference with Linux
# - macOS is a second-tier Zebra support platform
- os: macos-latest
rust: beta
steps:
- uses: actions/checkout@v4.1.2
with:
persist-credentials: false
- uses: r7kamura/rust-problem-matchers@v1.4.0
- name: Install last version of Protoc
uses: arduino/setup-protoc@v3.0.0
with:
# TODO: increase to latest version after https://github.com/arduino/setup-protoc/issues/33 is fixed
version: '23.x'
repo-token: ${{ secrets.GITHUB_TOKEN }}
# Setup Rust with ${{ matrix.rust }} toolchain and minimal profile
- name: Setup Rust
run: |
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain=${{ matrix.rust }} --profile=minimal
- uses: Swatinem/rust-cache@v2.7.3
# TODO: change Rust cache target directory on Windows,
# or remove this workaround once the build is more efficient (#3005).
#with:
# workspaces: ". -> C:\\zebra-target"
with:
# Split the experimental features cache from the regular cache, to avoid linker errors.
# (These might be "disk full" errors, or they might be dependency resolution issues.)
key: ${{ matrix.features }}
- name: Change target output directory on Windows
# Windows doesn't have enough space on the D: drive, so we redirect the build output to the
# larger C: drive.
# TODO: Remove this workaround once the build is more efficient (#3005).
if: matrix.os == 'windows-latest'
run: |
mkdir "C:\\zebra-target"
echo "CARGO_TARGET_DIR=C:\\zebra-target" | Out-File -FilePath "$env:GITHUB_ENV" -Encoding utf8 -Append
- name: cargo fetch
run: |
cargo fetch
- name: Install LLVM on Windows
if: matrix.os == 'windows-latest'
run: |
choco install llvm -y
echo "C:\Program Files\LLVM\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
echo "LIBCLANG_PATH=C:\Program Files\LLVM\bin" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
- name: Skip network tests on Ubuntu and Windows
# Ubuntu runners don't have reliable network or DNS during test steps.
# Windows runners have an unreliable network.
shell: bash
if: matrix.os != 'macos-latest'
run: echo "ZEBRA_SKIP_NETWORK_TESTS=1" >> $GITHUB_ENV
- name: Minimise proptest cases on macOS and Windows
# We set cases to 1, because some tests already run 1 case by default.
# We keep maximum shrink iterations at the default value, because it only happens on failure.
#
# Windows compilation and tests are slower than other platforms.
# macOS runners do extra network tests, so they take longer.
shell: bash
if: matrix.os != 'ubuntu-latest'
run: |
echo "PROPTEST_CASES=1" >> $GITHUB_ENV
echo "PROPTEST_MAX_SHRINK_ITERS=1024" >> $GITHUB_ENV
# Run unit and basic acceptance tests, only showing command output if the test fails.
#
# If some tests hang, add "-- --nocapture" for just that test, or for all the tests.
- name: Run tests${{ matrix.features }}
run: |
cargo test --features "${{ matrix.features }}" --release --verbose --workspace
# Explicitly run any tests that are usually #[ignored]
- name: Run zebrad large sync tests${{ matrix.features }}
# Skip the entire step on Ubuntu and Windows, because the test would be skipped anyway due to ZEBRA_SKIP_NETWORK_TESTS
if: matrix.os == 'macos-latest'
run: |
cargo test --features "${{ matrix.features }}" --release --verbose --package zebrad --test acceptance -- --nocapture --include-ignored sync_large_checkpoints_
# Install Zebra with lockfile dependencies, with no caching and default features
install-from-lockfile-no-cache:
name: Install zebrad from lockfile without cache on ubuntu-latest
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4.1.2
with:
persist-credentials: false
- uses: r7kamura/rust-problem-matchers@v1.4.0
# Setup Rust with stable toolchain and minimal profile
- name: Setup Rust
run: |
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain=stable --profile=minimal
- name: Install zebrad
run: |
cargo install --locked --path ./zebrad/ zebrad
# Check that Cargo.lock includes any Cargo.toml changes.
# This check makes sure the `cargo-deny` crate dependency checks are accurate.
check-cargo-lock:
name: Check Cargo.lock is up to date
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4.1.2
with:
persist-credentials: false
- uses: r7kamura/rust-problem-matchers@v1.4.0
- name: Install last version of Protoc
uses: arduino/setup-protoc@v3.0.0
with:
version: '23.x'
repo-token: ${{ secrets.GITHUB_TOKEN }}
# Setup Rust with stable toolchain and minimal profile
- name: Setup Rust
run: |
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain=stable --profile=minimal
- uses: Swatinem/rust-cache@v2.7.3
with:
shared-key: "clippy-cargo-lock"
- name: Check Cargo.lock is up to date
run: |
cargo check --locked --all-features --all-targets
cargo-deny:
name: Check deny.toml ${{ matrix.checks }} ${{ matrix.features }}
runs-on: ubuntu-latest
strategy:
matrix:
checks:
- bans
- sources
# We don't need to check `--no-default-features` here, because (except in very rare cases):
# - disabling features isn't going to add duplicate dependencies
# - disabling features isn't going to add more crate sources
features: ['', '--features default-release-binaries', '--all-features']
# Always run the --all-features job, to get accurate "skip tree root was not found" warnings
fail-fast: false
# Prevent sudden announcement of a new advisory from failing ci:
continue-on-error: ${{ matrix.checks == 'advisories' }}
steps:
- uses: actions/checkout@v4.1.2
with:
persist-credentials: false
- uses: r7kamura/rust-problem-matchers@v1.4.0
- name: Check ${{ matrix.checks }} with features ${{ matrix.features }}
uses: EmbarkStudios/cargo-deny-action@v1
with:
# --all-features spuriously activates openssl, but we want to ban that dependency in
# all of zebrad's production features for security reasons. But the --all-features job is
# the only job that gives accurate "skip tree root was not found" warnings.
# In other jobs, we expect some of these warnings, due to disabled features.
command: check ${{ matrix.checks }} ${{ matrix.features == '--all-features' && '--allow banned' || '--allow unmatched-skip-root' }}
arguments: --workspace ${{ matrix.features }}
unused-deps:
name: Check for unused dependencies
runs-on: ubuntu-latest
steps:
- name: Checkout git repository
uses: actions/checkout@v4.1.2
with:
persist-credentials: false
- uses: r7kamura/rust-problem-matchers@v1.4.0
# Setup Rust with stable toolchain and minimal profile
- name: Setup Rust
run: |
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain=stable --profile=minimal
- name: Install cargo-machete
uses: baptiste0928/cargo-install@v3.0.1
with:
crate: cargo-machete
- name: Check unused dependencies
# Exclude macro and transitive dependencies by filtering them out of the output,
# then if there are any more unused dependencies, fail the job.
run: |
echo "-- full cargo machete output, including ignored dependencies --"
cargo machete --skip-target-dir || true
echo "-- unused dependencies are below this line, full output is above --"
if cargo machete --skip-target-dir 2>/dev/null | \
grep --extended-regexp -e '^\\t' | \
grep -v -e gumdrop -e humantime-serde -e tinyvec -e zebra-utils; then
echo "New unused dependencies were found, please remove them!"
exit 1
else
echo "No unused dependencies found."
fi
failure-issue:
name: Open or update issues for OS integration failures
# When a new job is added to this workflow, add it to this list.
needs: [ test, install-from-lockfile-no-cache, check-cargo-lock, cargo-deny, unused-deps ]
# Only open tickets for failed or cancelled jobs that are not coming from PRs.
# (PR statuses are already reported in the PR jobs list, and checked by Mergify.)
if: (failure() && github.event.pull_request == null) || (cancelled() && github.event.pull_request == null)
runs-on: ubuntu-latest
steps:
- uses: jayqi/failed-build-issue-action@v1
with:
title-template: "{{refname}} branch CI failed: {{eventName}} in {{workflow}}"
# New failures open an issue with this label.
label-name: S-ci-fail-os-integration-auto-issue
# If there is already an open issue with this label, any failures become comments on that issue.
always-create-new-issue: false
github-token: ${{ secrets.GITHUB_TOKEN }}