Skip to content

Latest commit

 

History

History
363 lines (255 loc) · 13.2 KB

File metadata and controls

363 lines (255 loc) · 13.2 KB

Mina Tests

This document describes the different kinds of tests that exist in the Mina codebase and how to run them.

Table of Contents


Overview

The Mina codebase has several categories of tests that range from fast in-process unit tests to full end-to-end integration tests that spin up a real network of nodes. The table below gives a high-level view:

Category Scope Can run locally? Tool
Inline unit tests Single library dune runtest
Standalone test executables One or more libraries dune runtest
Profile-dependent tests One or more libraries dune runtest
PPX tests ppx_mina extension make test-ppx
ZkApps examples unit tests zkapps_examples app ✅ (nightly in CI) dune runtest
Archive node unit tests archive app ✅ (needs PostgreSQL) dune runtest
Command-line / single-node tests Daemon CLI ✅ (needs app built) mina-command-line-tests
Integration tests (Lucy) Full multi-node network ✅ (needs Docker) mina-test-executive
Rosetta tests Rosetta API + daemon ⚠️ (CI recommended) custom scripts
Replayer test Archive replayer ⚠️ (needs PostgreSQL) mina-replayer
Fuzzy ZkApp tests ZkApp logic dune exec
Coverage tests Unit tests with coverage make test-coverage

Unit Tests

Inline Tests

The most common form of testing. Many OCaml library modules include inline tests written with ppx_inline_test. These are declared with let%test, let%test_unit, or let%test_module inside the source files, and are compiled and run by dune when the (inline_tests ...) stanza is present in the library's dune file.

Run all unit tests under src/lib:

dune runtest src/lib --profile=dev

Run unit tests for a specific library:

dune runtest src/lib/<library-name> --profile=dev

Run a single inline test case (using the helper script):

./scripts/testone.sh src/lib/<library-name>/<file>.ml [<test-name>]

Tips:

  • The default build profile is dev. Use --profile=devnet or --profile=mainnet when you need a profile that matches a deployed network.
  • Set DUNE_PROFILE in the environment to avoid repeating --profile=... on every command.
  • Dune caches test results; use --force to re-run all tests even if sources have not changed.
  • Running tests modifies resource limits: the scripts typically call ulimit -s 65532 and ulimit -n 10240.
  • On retry after failure, dune will only re-run the failing tests, which saves time.

Standalone Test Executables

Some tests are compiled as standalone executables (using the dune (tests ...) or (executable ...) stanza) and are also invoked via dune runtest. This includes tests in src/test/archive/ and src/lib/ subdirectories that have their own tests/ folder.

These are run the same way as inline tests:

dune runtest src/test/archive --profile=dev

To run tests for a whole subtree:

dune runtest src/ --profile=dev

Profile-dependent Tests

Some tests have expected values that vary depending on the build profile (e.g. dev, devnet, lightnet, mainnet). These tests must be run once per profile that you want to validate.

Run profile-dependent tests:

export DUNE_PROFILE=dev   # or devnet, lightnet, mainnet
dune build --force src/lib/node_config   # rebuild node_config for the chosen profile
dune runtest \
    src/lib/blockchain_snark/tests \
    src/lib/transaction_snark/test/constraint_count \
    src/lib/transaction_snark/test/print_transaction_snark_vk

In CI these are run for each profile separately by buildkite/scripts/profile-dependent-tests.sh.

PPX Tests

The ppx_mina preprocessor extension has its own test suite that verifies that the PPX behaves correctly (e.g. that [@@deriving version] attributes compile or fail in expected ways).

make test-ppx

This runs make inside src/lib/ppx_mina/tests/.

ZkApps Examples Unit Tests

The src/app/zkapps_examples application contains runnable ZkApp examples that double as integration-style unit tests. In CI these only run during nightly builds (NIGHTLY=true), but they can be run locally at any time:

dune build --profile=dev src/app/zkapps_examples
dune runtest --profile=dev src/app/zkapps_examples

Archive Node Unit Tests

The archive application (src/app/archive) has its own unit test suite that requires a running PostgreSQL instance.

Prerequisites: PostgreSQL must be installed and a test database must be created. The helper script buildkite/scripts/setup-database-for-archive-node.sh will configure it:

source ./buildkite/scripts/setup-database-for-archive-node.sh <user> <password> <db>

This sets the MINA_TEST_POSTGRES environment variable. After setup:

dune runtest src/app/archive --profile=dev

In CI this is handled by buildkite/scripts/tests/archive-node-unit-tests.sh.


Command-line / Single-node Tests

The mina-command-line-tests binary (src/test/command_line_tests/) tests the Mina daemon CLI in a single-node configuration. The test runner uses mina_automation, which automatically locates the Mina daemon binary — first in _build/default/ (local build), then in system paths such as /usr/local/bin.

Build and run locally:

# Build the daemon and the test runner
dune build src/app/cli/src/mina.exe src/test/command_line_tests/command_line_tests.exe --profile=dev

# Run all tests
export MINA_LIBP2P_PASS="naughty blue worm"
export MINA_PRIVKEY_PASS="naughty blue worm"
./_build/default/src/test/command_line_tests/command_line_tests.exe test -v

In CI this is handled by buildkite/scripts/single-node-tests.sh, which installs the mina-test-suite and mina-testnet-generic-lightnet debian packages and then runs mina-command-line-tests test -v.


Integration Tests (Lucy)

"Lucy" is Mina's end-to-end integration testing framework. It spins up a complete multi-node Mina testnet using Docker Swarm and runs test logic against the live network.

Lucy tests are found in src/app/test_executive/ and use a custom OCaml DSL defined in src/lib/integration_test_lib/. See src/app/test_executive/README.md for the full guide.

Prerequisites:

  • Docker with Swarm mode enabled (docker swarm init --advertise-addr 127.0.0.1)
  • A mina-daemon Docker image URL
  • A mina-archive Docker image URL

Compile from source and run locally (recommended for development):

make build
dune build src/app/test_executive/test_executive.exe src/app/logproc/logproc.exe

The compiled binaries will be at:

  • ./_build/default/src/app/test_executive/test_executive.exe
  • ./_build/default/src/app/logproc/logproc.exe

You can add optional shell aliases for convenience (in ~/.bashrc or ~/.bash_aliases):

alias test_executive=./_build/default/src/app/test_executive/test_executive.exe
alias logproc=./_build/default/src/app/logproc/logproc.exe

Then run a test the same way as with the installed binary:

export TEST_NAME=<test>
export MINA_IMAGE=<url-to-mina-daemon-image>
export ARCHIVE_IMAGE=<url-to-mina-archive-image>

test_executive local "$TEST_NAME" \
  --mina-image "$MINA_IMAGE" \
  --archive-image "$ARCHIVE_IMAGE" \
  --debug \
  | tee "$TEST_NAME.local.test.log" \
  | logproc -i inline -f '!(.level in ["Spam", "Debug"])'

Alternatively, install the mina-test-executive debian package:

echo "deb [trusted=yes] http://packages.o1test.net $(lsb_release -cs) stable" \
  > /etc/apt/sources.list.d/o1.list
apt-get update && apt-get install -y mina-test-executive

Then invoke the installed binary directly:

mina-test-executive local "$TEST_NAME" \
  --mina-image "$MINA_IMAGE" \
  --archive-image "$ARCHIVE_IMAGE" \
  --debug \
  | tee "$TEST_NAME.local.test.log" \
  | mina-logproc -i inline -f '!(.level in ["Spam", "Debug"])'

Available tests (as of this writing):

Test name Branch
peers-reliability all
chain-reliability all
payments all
delegation all
archive-node compatible
gossip-consis all
medium-bootstrap all
block-prod-prio all
zkapps develop
zkapps-timing develop
snarkyjs develop

In CI the integration tests are driven by buildkite/scripts/run-test-executive-local.sh. The --debug flag keeps the testnet alive after the test completes, which is useful for post-mortem inspection of node logs via docker logs.


End-to-end Tests

Rosetta Tests

The Rosetta API has multiple test suites:

  1. Indexer test — Validates that the Rosetta indexer produces correct output. Requires a running PostgreSQL instance with archive data ($PG_CONN):

    mina-rosetta-indexer-test --archive_uri "$PG_CONN"

    In CI this is handled by buildkite/scripts/rosetta-indexer-test.sh.

  2. Block race test — Races the Mina daemon, archive, and Rosetta to check for block consistency under load. Requires the daemon, archive, and Rosetta binaries and a PostgreSQL connection:

    ./scripts/rosetta/test-block-race.sh \
      --mina-exe /usr/local/bin/mina \
      --archive-exe /usr/local/bin/mina-archive \
      --rosetta-exe /usr/local/bin/mina-rosetta \
      --postgres-uri "$PG_CONN" \
      --ledger <path-to-ledger>

    In CI this is handled by buildkite/scripts/tests/rosetta-block-race-test.sh.

  3. Rosetta integration tests — Spins up a daemon with archive and Rosetta and runs end-to-end API validation. Requires all Mina service binaries and a PostgreSQL instance. In CI this is handled by buildkite/scripts/tests/rosetta-integration-tests.sh.

Replayer Test

The archive replayer (mina-replayer) replays historical blockchain transactions against an archive database and verifies that the resulting ledger state matches expectations.

Prerequisites: A PostgreSQL instance with archive data and $PG_CONN set to the connection URI.

./scripts/replayer-test.sh \
  -i src/test/archive/sample_db/replayer_input_file.json \
  -p "$PG_CONN" \
  -a mina-replayer

In CI this is handled by buildkite/scripts/replayer-test.sh.

Fuzzy ZkApp Tests

Property-based / fuzzy tests for ZkApp transaction logic. These run a ZkApp transaction generator with a random seed and validate the results.

dune exec <path-to-fuzzy-test-exe> --profile=<profile> \
  -- --timeout <seconds> \
     --individual-test-timeout <seconds> \
     --seed $RANDOM

The exact path and profile are configured per CI step; see buildkite/scripts/fuzzy-zkapp-test.sh for the invocation used in CI.


Coverage Testing

To measure code coverage of the unit test suite, use the bisect_ppx-instrumented test run:

Run all unit tests with coverage instrumentation:

make test-coverage

This calls scripts/create_coverage_profiles.sh, which runs:

dune runtest --instrument-with bisect_ppx --force src/lib --profile=dev

Run coverage for a specific library only:

scripts/create_coverage_profiles.sh <library-name>

Generate reports after running tests with coverage:

# HTML report
make coverage-html
# open _coverage/index.html in a browser

# Text summary
make coverage-summary

Running Tests in CI

The CI system (Buildkite) runs tests automatically on each pull request. The following environment variables influence test behaviour:

Variable Description
DUNE_PROFILE Dune build profile (dev, devnet, lightnet, mainnet). Defaults to dev.
NPROC Number of parallel jobs for dune runtest. Defaults to the number of logical CPU cores.
ERROR_ON_PROOF Set to true in CI to fail if proof cache needs updating.
NIGHTLY Set to true to enable nightly-only tests (e.g. ZkApps examples).
MINA_LIBP2P_PASS Passphrase for libp2p keys used during tests.
MINA_PRIVKEY_PASS Passphrase for private keys used during tests.
PG_CONN PostgreSQL connection URI for tests that require an archive database.

Some tests are designed to run exclusively in CI because they require large amounts of resources, cloud credentials, or specific infrastructure (e.g. Docker Swarm, pre-built Debian packages). These include the Rosetta integration tests, the archive upgrade test, and the Debian upgrade test.

Tests that can be run locally are primarily unit tests (via dune runtest) and integration tests via Lucy (provided Docker is installed and a suitable daemon image is available).