name: Coverage

# 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:
  push:
    branches:
      - main
    paths:
      # code and tests
      - '**/*.rs'
      # hard-coded checkpoints and proptest regressions
      - '**/*.txt'
      # test data snapshots
      - '**/*.snap'
      # dependencies
      - '**/Cargo.toml'
      - '**/Cargo.lock'
      # configuration files
      - '.cargo/config.toml'
      - '**/clippy.toml'
      # workflow definitions
      - 'codecov.yml'
      - '.github/workflows/coverage.yml'
  pull_request:
    paths:
      - '**/*.rs'
      - '**/*.txt'
      - '**/*.snap'
      - '**/Cargo.toml'
      - '**/Cargo.lock'
      - '.cargo/config.toml'
      - '**/clippy.toml'
      - 'codecov.yml'
      - '.github/workflows/coverage.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:
  coverage:
    name: Coverage on stable
    # The large timeout is to accommodate:
    # - stable builds (typically 30-50 minutes), and
    # - parameter downloads (an extra 90 minutes, but only when the cache expires)
    timeout-minutes: 140
    runs-on: ubuntu-latest-xl

    steps:
      - uses: actions/checkout@v4.1.0
        with:
          persist-credentials: false

      # 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 --component=llvm-tools-preview

      - name: Install cargo-llvm-cov cargo command
        run: cargo install cargo-llvm-cov

      - name: Skip network tests on Ubuntu
        # Ubuntu runners don't have reliable network or DNS during test steps.
        shell: bash
        run: echo "ZEBRA_SKIP_NETWORK_TESTS=1" >> $GITHUB_ENV

      - name: Minimise proptest cases in Coverage tests
        # We set cases to 1, because some tests already run 1 case by default.
        # We set maximum shrink iterations to 0, because we don't expect failures in these tests.
        #
        # Coverage tests are much slower than other tests, particularly in hot loops.
        shell: bash
        run: |
          echo "PROPTEST_CASES=1" >> $GITHUB_ENV
          echo "PROPTEST_MAX_SHRINK_ITERS=0" >> $GITHUB_ENV

      # Modified from:
      # https://github.com/zcash/librustzcash/blob/c48bb4def2e122289843ddb3cb2984c325c03ca0/.github/workflows/ci.yml#L20-L33
      - name: Fetch path to Zcash parameters
        working-directory: ./zebra-consensus
        shell: bash
        # cargo-llvm-cov doesn't have a silent mode, so we have to extract the path from stderr
        run: echo "ZCASH_PARAMS=$(cargo llvm-cov --lcov --no-report run --example get-params-path 2>&1 >/dev/null | tail -1)" >> $GITHUB_ENV
      - name: Cache Zcash parameters
        id: cache-params
        uses: actions/cache@v3
        with:
          path: ${{ env.ZCASH_PARAMS }}
          key: ${{ runner.os }}-sprout-and-sapling-params
      - name: Fetch Zcash parameters
        if: steps.cache-params.outputs.cache-hit != 'true'
        working-directory: ./zebra-consensus
        run: cargo llvm-cov --lcov --no-report run --example download-params

      - name: Run Zebra tests
        run: cargo llvm-cov --lcov --no-report

      - name: Generate coverage report
        run: cargo llvm-cov --lcov --no-run --output-path lcov.info

      - name: Upload coverage report to Codecov
        uses: codecov/codecov-action@v3.1.4
