# Google Cloud unit tests that run when Rust code or dependencies are modified, # but only on PRs from the ZcashFoundation/zebra repository. (External PRs are tested by mergify.) # # This workflow is designed for running various unit tests within Docker containers. # Jobs: # 1. Builds a Docker image for tests, adaptable to the specified network (Mainnet or Testnet). # 2. 'test-all': Executes all Zebra tests, including normally ignored ones, in a Docker environment. # 3. 'test-fake-activation-heights': Runs state tests with fake activation heights, isolating its build products. # 4. 'test-empty-sync': Tests Zebra's ability to sync and checkpoint from an empty state. # 5. 'test-lightwalletd-integration': Validates integration with 'lightwalletd' starting from an empty state. # 6. 'test-configuration-file': Assesses the default Docker configuration for Zebra. # 7. 'test-configuration-file-testnet': Checks the Docker image reconfiguration for the Testnet. # 8. 'test-zebra-conf-path': Tests Zebra using a custom Docker configuration. name: Docker 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: inputs: network: default: 'Mainnet' description: 'Network to deploy: Mainnet or Testnet' required: true no_cache: description: 'Disable the Docker cache for this build' required: false type: boolean default: false pull_request: # Skip PRs where Rust code and dependencies aren't modified. 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 - 'docker/**' - '.github/workflows/ci-unit-tests-docker.yml' - '.github/workflows/sub-deploy-integration-tests-gcp.yml' - '.github/workflows/sub-build-docker-image.yml' - '.github/workflows/sub-find-cached-disks.yml' - '.github/workflows/sub-test-zebra-config.yml' push: branches: - main # Skip main branch updates where Rust code and dependencies aren't modified. 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 - 'docker/**' - '.dockerignore' - '.github/workflows/ci-unit-tests-docker.yml' - '.github/workflows/sub-deploy-integration-tests-gcp.yml' - '.github/workflows/sub-find-cached-disks.yml' - '.github/workflows/sub-build-docker-image.yml' env: # We need to combine the features manually because some tests don't use the Docker entrypoint TEST_FEATURES: ${{ format('{0} {1}', vars.RUST_PROD_FEATURES, vars.RUST_TEST_FEATURES) }} EXPERIMENTAL_FEATURES: ${{ format('{0} {1} {2}', vars.RUST_PROD_FEATURES, vars.RUST_TEST_FEATURES, vars.RUST_EXPERIMENTAL_FEATURES) }} RUST_LOG: ${{ vars.RUST_LOG }} RUST_BACKTRACE: ${{ vars.RUST_BACKTRACE }} RUST_LIB_BACKTRACE: ${{ vars.RUST_LIB_BACKTRACE }} COLORBT_SHOW_HIDDEN: ${{ vars.COLORBT_SHOW_HIDDEN }} CARGO_INCREMENTAL: ${{ vars.CARGO_INCREMENTAL }} # IMPORTANT # # The job names in `ci-unit-tests-docker.yml`, `ci-unit-tests-docker.patch.yml` and # `ci-unit-tests-docker.patch-external.yml` must be kept in sync. jobs: # Build the docker image used by the tests. # # The default network in the Zebra config in the image is mainnet, unless a manually triggered # workflow or repository variable is configured differently. Testnet jobs change that config to # testnet when running the image. build: name: Build CI Docker # Skip PRs from external repositories, let them pass, and then Mergify will check them if: ${{ !startsWith(github.event_name, 'pull') || !github.event.pull_request.head.repo.fork }} uses: ./.github/workflows/sub-build-docker-image.yml with: dockerfile_path: ./docker/Dockerfile dockerfile_target: tests image_name: ${{ vars.CI_IMAGE_NAME }} no_cache: ${{ inputs.no_cache || false }} rust_backtrace: full rust_lib_backtrace: full rust_log: info # Run all the zebra tests, including tests that are ignored by default. # # - We activate the gRPC feature to avoid recompiling `zebrad`, but we don't actually run any gRPC tests. test-all: name: Test all timeout-minutes: 180 runs-on: ubuntu-latest-xl needs: build steps: - uses: r7kamura/rust-problem-matchers@v1.4.0 - name: Inject slug/short variables uses: rlespinasse/github-slug-action@v4 with: short-length: 7 # Run unit, basic acceptance tests, and ignored tests, only showing command output if the test fails. # # If some tests hang, add "-- --nocapture" for just that test, or for all the tests. # # TODO: move this test command into entrypoint.sh - name: Run zebrad tests env: NETWORK: ${{ inputs.network || vars.ZCASH_NETWORK }} run: | docker pull ${{ vars.GAR_BASE }}/${{ vars.CI_IMAGE_NAME }}@${{ needs.build.outputs.image_digest }} docker run -e NETWORK --name zebrad-tests --tty ${{ vars.GAR_BASE }}/${{ vars.CI_IMAGE_NAME }}@${{ needs.build.outputs.image_digest }} cargo test --locked --release --features "${{ env.TEST_FEATURES }}" --workspace -- --include-ignored # Run unit, basic acceptance tests, and ignored tests with experimental features. # # TODO: move this test command into entrypoint.sh - name: Run zebrad tests with experimental features env: NETWORK: ${{ inputs.network || vars.ZCASH_NETWORK }} run: | # GitHub doesn't allow empty variables if [[ -n "${{ vars.RUST_EXPERIMENTAL_FEATURES }}" && "${{ vars.RUST_EXPERIMENTAL_FEATURES }}" != " " ]]; then docker run -e NETWORK --name zebrad-tests-experimental --tty ${{ vars.GAR_BASE }}/${{ vars.CI_IMAGE_NAME }}@${{ needs.build.outputs.image_digest }} cargo test --locked --release --features "${{ env.EXPERIMENTAL_FEATURES }} " --workspace -- --include-ignored else echo "Experimental builds are disabled, set RUST_EXPERIMENTAL_FEATURES in GitHub actions variables to enable them" fi # Run state tests with fake activation heights. # # This test changes zebra-chain's activation heights, # which can recompile all the Zebra crates, # so we want its build products to be cached separately. # # Also, we don't want to accidentally use the fake heights in other tests. # # (We activate the test features to avoid recompiling dependencies, but we don't actually run any gRPC tests.) test-fake-activation-heights: name: Test with fake activation heights timeout-minutes: 60 runs-on: ubuntu-latest needs: build steps: - uses: r7kamura/rust-problem-matchers@v1.4.0 - name: Inject slug/short variables uses: rlespinasse/github-slug-action@v4 with: short-length: 7 # TODO: move this test command into entrypoint.sh # make sure that at least one test runs, and that it doesn't skip itself due to the environmental variable - name: Run tests with fake activation heights run: | docker pull ${{ vars.GAR_BASE }}/${{ vars.CI_IMAGE_NAME }}@${{ needs.build.outputs.image_digest }} docker run -e NETWORK -e TEST_FAKE_ACTIVATION_HEIGHTS --name zebrad-tests -t ${{ vars.GAR_BASE }}/${{ vars.CI_IMAGE_NAME }}@${{ needs.build.outputs.image_digest }} cargo test --locked --release --features "zebra-test" --package zebra-state --lib -- --nocapture --include-ignored with_fake_activation_heights env: TEST_FAKE_ACTIVATION_HEIGHTS: '1' NETWORK: ${{ inputs.network || vars.ZCASH_NETWORK }} # Test that Zebra syncs and checkpoints a few thousand blocks from an empty state. test-empty-sync: name: Test checkpoint sync from empty state timeout-minutes: 60 runs-on: ubuntu-latest needs: build steps: - uses: r7kamura/rust-problem-matchers@v1.4.0 - name: Inject slug/short variables uses: rlespinasse/github-slug-action@v4 with: short-length: 7 # TODO: move this test command into entrypoint.sh - name: Run zebrad large sync tests run: | docker pull ${{ vars.GAR_BASE }}/${{ vars.CI_IMAGE_NAME }}@${{ needs.build.outputs.image_digest }} docker run -e NETWORK --name zebrad-tests -t ${{ vars.GAR_BASE }}/${{ vars.CI_IMAGE_NAME }}@${{ needs.build.outputs.image_digest }} cargo test --locked --release --features "${{ env.TEST_FEATURES }}" --package zebrad --test acceptance -- --nocapture --include-ignored sync_large_checkpoints_ env: NETWORK: ${{ inputs.network || vars.ZCASH_NETWORK }} # Test launching lightwalletd with an empty lightwalletd and Zebra state. test-lightwalletd-integration: name: Test integration with lightwalletd timeout-minutes: 60 runs-on: ubuntu-latest needs: build steps: - uses: r7kamura/rust-problem-matchers@v1.4.0 - name: Inject slug/short variables uses: rlespinasse/github-slug-action@v4 with: short-length: 7 # TODO: move this test command into entrypoint.sh - name: Run tests with empty lightwalletd launch run: | docker pull ${{ vars.GAR_BASE }}/${{ vars.CI_IMAGE_NAME }}@${{ needs.build.outputs.image_digest }} docker run -e NETWORK -e ZEBRA_TEST_LIGHTWALLETD --name lightwalletd-tests -t ${{ vars.GAR_BASE }}/${{ vars.CI_IMAGE_NAME }}@${{ needs.build.outputs.image_digest }} cargo test --locked --release --features "${{ env.TEST_FEATURES }}" --package zebrad --test acceptance -- --nocapture --include-ignored lightwalletd_integration env: ZEBRA_TEST_LIGHTWALLETD: '1' NETWORK: ${{ inputs.network || vars.ZCASH_NETWORK }} # Test that Zebra works using the default config with the latest Zebra version. test-configuration-file: name: Test CI default Docker config file needs: build uses: ./.github/workflows/sub-test-zebra-config.yml with: test_id: 'default-conf' docker_image: ${{ vars.GAR_BASE }}/${{ vars.CI_IMAGE_NAME }}@${{ needs.build.outputs.image_digest }} grep_patterns: '-e "net.*=.*Main.*estimated progress to chain tip.*BeforeOverwinter"' test_variables: '-e NETWORK' network: 'Mainnet' # Test reconfiguring the the docker image for tesnet. test-configuration-file-testnet: name: Test CI testnet Docker config file needs: build # Make sure Zebra can sync the genesis block on testnet uses: ./.github/workflows/sub-test-zebra-config.yml with: test_id: 'testnet-conf' docker_image: ${{ vars.GAR_BASE }}/${{ vars.CI_IMAGE_NAME }}@${{ needs.build.outputs.image_digest }} grep_patterns: '-e "net.*=.*Test.*estimated progress to chain tip.*Genesis" -e "net.*=.*Test.*estimated progress to chain tip.*BeforeOverwinter"' # TODO: improve the entrypoint to avoid using `ENTRYPOINT_FEATURES=""` test_variables: '-e NETWORK -e ZEBRA_CONF_PATH="/etc/zebrad/zebrad.toml" -e ENTRYPOINT_FEATURES=""' network: 'Testnet' # Test that Zebra works using $ZEBRA_CONF_PATH config test-zebra-conf-path: name: Test CI custom Docker config file needs: build uses: ./.github/workflows/sub-test-zebra-config.yml with: test_id: 'custom-conf' docker_image: ${{ vars.GAR_BASE }}/${{ vars.CI_IMAGE_NAME }}@${{ needs.build.outputs.image_digest }} grep_patterns: '-e "loaded zebrad config.*config_path.*=.*v1.0.0-rc.2.toml"' test_variables: '-e NETWORK -e ZEBRA_CONF_PATH="zebrad/tests/common/configs/v1.0.0-rc.2.toml"' network: ${{ inputs.network || vars.ZCASH_NETWORK }} failure-issue: name: Open or update issues for main branch failures # When a new test is added to this workflow, add it to this list. # # This list is for reliable tests that are run on the `main` branch. # Testnet jobs are not in this list, because we expect testnet to fail occasionally. needs: [ test-all, test-fake-activation-heights, test-empty-sync, test-lightwalletd-integration, test-configuration-file, test-zebra-conf-path ] # Only open tickets for failed scheduled jobs, manual workflow runs, or `main` branch merges. # (PR statuses are already reported in the PR jobs list, and checked by Mergify.) # TODO: if a job times out, we want to create a ticket. Does failure() do that? Or do we need cancelled()? if: failure() && 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. # TODO: do we want a different label for each workflow, or each kind of workflow? label-name: S-ci-fail-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 }}