Skip to content

Latest commit

 

History

History
286 lines (211 loc) · 11.9 KB

README.md

File metadata and controls

286 lines (211 loc) · 11.9 KB

Miden Client Integration Tests

This directory contains integration tests for the Miden client library. These tests verify the functionality of the client against a running Miden node.

Features

  • Parallel Execution: Run tests in parallel to significantly reduce total execution time
  • Test Filtering: Filter tests by name patterns, categories, or exclude specific tests
  • Flexible Configuration: Configurable RPC endpoints, timeouts, and parallel job counts
  • Comprehensive Reporting: Detailed test results with timing statistics and progress tracking
  • cargo-nextest-like Experience: Similar filtering and execution patterns as cargo-nextest

Installation

To install the integration tests binary:

make install-tests

This will build and install the miden-client-integration-tests binary to your system.

Usage

Running the Binary

The integration tests binary can be run with various command-line options:

miden-client-integration-tests [OPTIONS]

Command-Line Options

  • -n, --network <NETWORK> - Network preset: devnet, testnet, localhost, or a custom RPC endpoint (default: localhost). Sets defaults for all components (RPC, prover, note transport)
  • -t, --timeout <MILLISECONDS> - Timeout for RPC requests in milliseconds (default: 10000)
  • --prover-url <URL> - Override prover endpoint. Accepts devnet, testnet, localhost, or a custom URL. If unset, defaults based on network
  • --note-transport-url <URL> - Override note transport endpoint. Accepts devnet, testnet, or a custom URL. If unset, defaults based on network
  • -j, --jobs <NUMBER> - Number of tests to run in parallel (default: auto-detected CPU cores, set to 1 for sequential execution)
  • -f, --filter <REGEX> - Filter tests by name using regex patterns
  • --contains <STRING> - Only run tests whose names contain this substring
  • --exclude <REGEX> - Exclude tests whose names match this regex pattern
  • --retry-count <NUMBER> - Number of times to retry failed tests (default: 3, set to 0 to disable retries)
  • --list - List all available tests without running them
  • -h, --help - Show help information
  • -V, --version - Show version information

Examples

Run all tests with default settings (auto-detected CPU cores):

miden-client-integration-tests

Run tests sequentially (no parallelism):

miden-client-integration-tests --jobs 1

Run tests with custom parallelism:

miden-client-integration-tests --jobs 8

List all available tests without running them:

miden-client-integration-tests --list

Run only client-related tests:

miden-client-integration-tests --filter "client"

Run tests containing "fpi" in their name:

miden-client-integration-tests --contains "fpi"

Exclude swap-related tests:

miden-client-integration-tests --exclude "swap"

Run tests against devnet:

miden-client-integration-tests --network devnet

Run tests against testnet:

miden-client-integration-tests --network testnet

Run tests against devnet (auto-configures remote prover):

miden-client-integration-tests --network devnet

Run tests against testnet with a local prover override:

miden-client-integration-tests --network testnet --prover-url localhost

Run tests against a custom RPC endpoint with timeout:

miden-client-integration-tests --network http://192.168.1.100:57291 --timeout 30000

Complex example: Run non-swap tests in parallel excluding swap tests:

miden-client-integration-tests --exclude "swap"

Show help:

miden-client-integration-tests --help

Environment Variables

The following environment variables configure both the standalone binary and the cargo test generated wrappers:

  • TEST_MIDEN_NETWORK - Network preset: devnet, testnet, localhost, or a custom RPC endpoint URL (default: localhost). Sets defaults for all components
  • TEST_MIDEN_RPC_URL - Overrides the RPC endpoint from the network preset
  • TEST_MIDEN_PROVER_URL - Overrides the prover: devnet, testnet, localhost, or a custom URL (default: derived from network)
  • TEST_MIDEN_NOTE_TRANSPORT_URL - Overrides note transport: devnet, testnet, or a custom URL (default: derived from network)
  • MIDEN_TEST_TIMEOUT - Test timeout in milliseconds (default: 10000)

Network Presets

Network RPC Prover Note Transport
testnet rpc.testnet.miden.io tx-prover.testnet.miden.io transport.miden.io
devnet rpc.devnet.miden.io tx-prover.devnet.miden.io transport.devnet.miden.io
localhost localhost:57291 localhost (none)

Any individual env var overrides the corresponding component from the preset. For example:

# Use testnet defaults but force local prover
TEST_MIDEN_NETWORK=testnet TEST_MIDEN_PROVER_URL=localhost cargo test

# Use devnet RPC with a custom note transport
TEST_MIDEN_NETWORK=devnet TEST_MIDEN_NOTE_TRANSPORT_URL=http://localhost:57292 cargo test

For the standalone binary, CLI flags (--network, --prover-url, --note-transport-url, --timeout) take precedence over environment variables.

Test Categories

The integration tests cover several categories:

  • Client: Basic client functionality, account management, and note handling
  • Custom Transaction: Custom transaction types and Merkle store operations
  • FPI: Foreign Procedure Interface tests
  • Network Transaction: Network-level transaction processing
  • Onchain: On-chain account and note operations
  • Swap Transaction: Asset swap functionality
  • AggLayer: AggLayer bridge integration (GER updates, bridge-in/out)

AggLayer Tests

AggLayer tests verify the bridge integration flow: GER updates, faucet registration, bridge-in (claiming), and bridge-out.

Pre-deployed accounts

The four AggLayer accounts are always supplied rather than created by the tests: they are network accounts, which no client transaction can deploy, and on a fee-charging chain they must be seeded with the fee asset because no note in their allowlist can carry it to them later.

scripts/start-test-node.sh writes them into ./data/:

  • bridge_admin.mac - Bridge admin wallet (includes secret key)
  • ger_manager.mac - GER manager wallet (includes secret key)
  • bridge.mac - AggLayer bridge account (no secret key, network account)
  • agglayer_faucet.mac - AggLayer faucet account (no secret key, network account)

The bridge is deployed unconfigured. The tests register the faucet against it with a CONFIG_AGG_BRIDGE note, using a deterministic test origin token address (0xAAAA...AA).

Environment variables

  • AGGLAYER_ACCOUNTS_DIR - Directory holding the AggLayer .mac account files. Required by the AggLayer tests. The Make targets point it at ./data, where the testing node writes them. On devnet, point it at wherever the devnet account files are stored.
make start-node-background
AGGLAYER_ACCOUNTS_DIR=./data miden-client-integration-tests --contains "agglayer"

Testing against devnet

The same tests work against devnet by setting AGGLAYER_ACCOUNTS_DIR to the directory containing devnet-specific .mac files and using the appropriate RPC endpoint:

AGGLAYER_ACCOUNTS_DIR=/path/to/devnet/accounts \
  miden-client-integration-tests --network devnet --contains "agglayer"

Fees

The testing node charges a fee for every transaction, as a real chain does: its genesis sets verification_base_fee = 500. To run it fee-free instead:

MIDEN_VERIFICATION_BASE_FEE=0 make start-node-background

The suite never mints. It draws the native asset from pre-funded basic wallets named by --funders (or MIDEN_FUNDER_ACCOUNTS_DIR), either one .mac file or a directory of them. A path naming no .mac file means no funders (useful for fee-free chains) so the Make targets can pass the same path either way.

# Local node: its genesis pre-funds the wallets and start-test-node.sh writes them here.
# The Makefile targets pass this for you.
MIDEN_FUNDER_ACCOUNTS_DIR=$PWD/data/funders cargo nextest run --workspace --release --test=integration

# Deployed network: supply wallets funded out of band, since nothing can be minted there.
miden-client-integration-tests --network testnet --funders ./testnet-funders

The insert_new_* helpers pay each account they create. The account is deployed by whichever transaction first consumes that note, as described below. An account a test builds itself can be funded and deployed on the spot with TestClient::deploy_account, whose deploy transaction consumes the funding note and thereby settles its own fee.

A funding transaction costs a fee and a proof, so accounts are funded in batches wherever a test creates more than one: the setup_* helpers create their accounts with the insert_new_*_unfunded variants and then pass the whole set to TestClient::fund_if_needed, which pays them all from one transaction. A test creating several accounts of its own should do the same rather than calling the funding insert_new_* helpers in a row.

Funding costs no transaction of its own beyond that payment. Each account's note is held until the account's next transaction and folded into it, so that one transaction deploys the account, funds it and does the test's work. TestClient::submit_new_transaction does the folding; a request going somewhere else needs TestClient::fund_request first, notably a batch, which borrows the client for as long as it lives. A test that needs the funding to land in a particular transaction — one asserting on what a sync reports, say — should call TestClient::take_funding and consume the note itself.

Funders must be public and carry their secret key: a public funder's state is read from the chain by whichever process claims it, which is what makes sharing one between test processes safe.

Environment variables

  • MIDEN_FUNDER_ACCOUNTS_DIR - funder .mac file or directory, same as --funders. Unset, empty or naming no .mac file leaves the run without funders
  • MIDEN_VERIFICATION_BASE_FEE - genesis verification_base_fee for the testing node (default 500; 0 runs the node fee-free and declares no funder wallets)
  • MIDEN_NUM_FUNDER_WALLETS - number of wallets a fee-charging genesis pre-funds (default 16)

Test Case Generation

The integration tests use an automatic code generation system to create both cargo nextest compatible tests and a standalone binary. Test functions that start with test_ are automatically discovered during build time and used to generate:

  1. Individual #[tokio::test] wrappers - These allow the tests to be run using standard cargo test or cargo nextest run commands
  2. Programmatic test access - A Vec<TestCase> that enables the standalone binary to enumerate and execute tests dynamically with custom parallelism and filtering

The discovery system:

  • Scans all .rs files in the src/ directory recursively
  • Identifies functions named test_* (supporting pub async fn test_*, async fn test_*, etc.)
  • Generates test registry and integration test wrappers automatically

This dual approach allows the same test code to work seamlessly with both nextest (for development) and the standalone binary (for CI/CD and production testing scenarios), ensuring consistent behavior across different execution environments.

Writing Tests

To add a new integration test:

  1. Create a public async function that starts with test_
  2. The function should take a ClientConfig parameter
  3. The function should return Result<()>
  4. Place the function in any .rs file under src/

Example:

pub async fn test_my_feature(client_config: ClientConfig) -> Result<()> {
    let (mut client, authenticator) = client_config.into_client().await?;
    // test logic here
}

The build system will automatically discover this function and include it in both the test registry and generate tokio test wrappers.

License

This project is MIT licensed.