Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Testing

GasHammer has three test tiers: unit tests, integration tests, and end-to-end lifecycle tests.

Unit Tests

Unit tests live in mod tests blocks at the bottom of each source file.

# All unit tests
cargo test --workspace

# Single crate
cargo test -p gashammer-nitro

# Single test by name
cargo test --workspace -- test_feed_reconnects

Conventions

  • Test names describe behavior, not implementation: test_feed_reconnects_after_disconnect, not test_feed_1.
  • Async tests use #[tokio::test]. Never block_on.
  • Use proptest for property-based tests on serialization round-trips and workload generation.
  • Oracle invariant checks must have both passing and failing test cases.
  • Do not test private implementation details — test the public contract.

Current Test Counts

CrateTests
gashammer-common30+
gashammer-nitro48
gashammer-edge30+
gashammer-hive65
gashammer-workload40+
gashammer-telemetry20+
gashammer-oracle30+
gashammer-fault35+
gashammer-report30+
gashammer-scenario25+
gashammer-docgen15+
gashammer-testenv10+

Integration Tests

Integration tests require Docker and a running Nitro devnet. They are gated by the integration feature flag.

# Run integration tests (requires Docker)
cargo test --test integration -- --test-threads=1

Location: crates/gashammer-nitro/tests/integration.rs and crates/gashammer-testenv/tests/smoke.rs.

What They Test

  • Real JSON-RPC connectivity to a Nitro sequencer.
  • Transaction submission and receipt polling.
  • Contract deployment and interaction.
  • Feed relay connectivity.
  • L1 Geth health checks.

Devnet Profiles

ProfileContainersUse Case
MinimalL1 Geth, SequencerFast smoke tests
StandardL1 Geth, Sequencer, Feed RelayIntegration tests
FullAll + contract deploymentE2E lifecycle tests

E2E Lifecycle Tests

Full lifecycle tests boot a devnet, deploy contracts, fund accounts, run a scenario, and verify the report.

GASHAMMER_TEST_PROFILE=standard cargo test --test e2e -- --test-threads=1

LifecycleTest Builder

#![allow(unused)]
fn main() {
LifecycleTestBuilder::new()
    .scenario_yaml(include_str!("scenario.yaml"))
    .edge_count(2)
    .deploy_contracts(true)
    .expected_outcome(ExpectedOutcome::Pass)
    .timeout(Duration::from_secs(120))
    .build()
    .run()
    .await;
}

Test Contracts

GasHammer ships 7 compiled Solidity test contracts in contracts/test/build/:

ContractPurpose
CounterIncrement/decrement with storage writes
GasBurnerConfigurable gas consumption loop
StorageWriterBatch storage slot writes
EventEmitterEmit events for log testing
ReverterControlled reverts for failure testing
ContentionTargetConcurrent access patterns
GasHammerERC20ERC-20 token for transfer testing

Contracts are pre-compiled. Bytecode is embedded at build time via include_bytes!.

CI Pipeline

GitHub Actions runs the full test suite on every PR:

jobs:
  check:
    - cargo fmt --all -- --check
    - cargo clippy --workspace --all-targets -- -D warnings
    - cargo test --workspace
    - cargo deny check licenses
    - scripts/check-license-headers.sh

All checks must pass before merge. No exceptions.

Writing New Tests

  1. Add a #[test] or #[tokio::test] function in the mod tests block of the file containing the code under test.
  2. Name the test test_<behavior_description>.
  3. For integration tests that need Docker, add them to the tests/ directory and gate with #[cfg(feature = "integration")].
  4. Run cargo test -p <crate> to verify locally before pushing.