Skip to main content

Integration testing framework

This document outlines a comprehensive external integration testing framework for the VisualSign parser that enables testing against real blockchain transactions from multiple chains.

Overview

The framework supports three testing modes:
  • Fixture mode - Recorded API responses (VCR-style)
  • Live API mode - Direct calls to blockchain explorers
  • Fork mode - Local blockchain forks (Surfpool/Anvil)

Problem statement

We need to:
  • Test parser implementations against real-world blockchain transactions
  • Support multiple chains (Solana, Ethereum, Sui, Tron)
  • Enable testing without API keys in CI/CD
  • Maintain reproducible test results
  • Test against both historical and current blockchain state

Architecture

external_integration/
├── src/
│   ├── api/           # API clients with recording capability
│   ├── forks/         # Local blockchain fork managers
│   ├── fetchers/      # Chain-specific transaction fetchers
│   ├── environments/  # Test environment orchestration
│   └── runner/        # Test execution framework
├── fixtures/          # Recorded API responses
└── tests/            # Integration tests

Testing modes

1. Fixture mode (default)

Uses recorded API responses (VCR-style):
  • Fast and deterministic
  • No API keys required
  • Ideal for CI/CD and regular test runs

2. Live API mode

Direct calls to blockchain explorers (Helius, Etherscan, etc.):
  • Validates against current blockchain state
  • Requires API keys
  • Used for recording new fixtures and validation

3. Fork mode

Local blockchain forks using Surfpool (Solana) or Anvil (Ethereum):
  • Full blockchain state testing
  • Enables transaction simulation
  • Consistent pattern across chains

Key components

VCR implementation

A minimal recording layer built on wiremock:
pub struct VcrProxy {
    mock_server: MockServer,
    cassette_path: PathBuf,
    mode: VcrMode,
    recorded_interactions: Vec<HttpInteraction>,
}

#[derive(Serialize, Deserialize)]
pub struct HttpInteraction {
    request: RequestPattern,
    response: ResponseData,
    recorded_at: String,
}
This approach:
  • Leverages wiremock’s reliability
  • Provides simple JSON cassettes (easy to inspect/edit)
  • Has minimal maintenance burden

Fork manager interface

#[async_trait]
pub trait LocalForkManager: Send + Sync {
    async fn start(&mut self) -> Result<()>;
    fn rpc_url(&self) -> &str;
    async fn wait_ready(&self) -> Result<()>;
    async fn fund_account(&self, address: &str, amount: u64) -> Result<()>;
}
Implementations:
  • SurfpoolManager - Solana mainnet fork
  • AnvilManager - Ethereum mainnet fork
  • Future: Sui, Tron equivalents

Test environment factory

pub enum TestMode {
    Fixture,  // Replay from cassettes
    Record,   // Record new cassettes
    Live,     // Direct API calls
    Fork,     // Local blockchain fork
    Mock,     // Wiremock for unit tests
}

pub struct TestEnvironment {
    pub chain: Chain,
    pub mode: TestMode,
    pub api_client: ChainApiClient,
    pub fork_manager: Option<Box<dyn LocalForkManager>>,
}

Testing workflow

Development workflow

# Record new fixtures from live API
cargo test --test external_integration record_jupiter_fixtures -- --ignored

# Test with fixtures (fast, no API needed)
cargo test --test external_integration test_jupiter

# Test with local fork
FORK_MODE=true cargo test --test external_integration test_jupiter -- --ignored

CI/CD workflow

# GitHub Actions - runs with fixtures by default
- name: Run external integration tests
  run: cargo test -p external_integration

# Nightly - validate against live API
- name: Nightly validation
  env:
    HELIUS_API_KEY: ${{ secrets.HELIUS_API_KEY }}
  run: cargo test -p external_integration --test nightly -- --ignored

Configuration

# external_integration/config/tests.toml

[general]
default_mode = "fixture"
fixtures_dir = "fixtures"

[solana]
enabled = true
api_provider = "helius"
fork_rpc = "https://api.mainnet-beta.solana.com"

[[solana.tests]]
name = "Jupiter SOL-USDC"
program_id = "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4"
cassette = "jupiter_sol_usdc.vcr.json"

[ethereum]
enabled = true
api_provider = "etherscan"
fork_rpc = "https://eth-mainnet.alchemyapi.io"

[[ethereum.tests]]
name = "Uniswap V3 USDC-WETH"
contract = "0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640"
cassette = "uniswap_usdc_weth.vcr.json"

Benefits

BenefitDescription
Multi-mode testingFixtures for fast CI/CD, live API for validation, forks for deep integration
Chain agnosticConsistent patterns across chains, easy to add new chains
Developer experienceSimple commands to record fixtures, fast local testing
MaintainabilityUses well-tested libraries, clear module boundaries
Cost effectiveMinimal API calls (only when recording), no API keys for most runs

Risks and mitigations

RiskMitigation
API rate limitsUse fixtures by default, limit live tests
Fixture stalenessNightly job to validate and update
Fork tool availabilityGraceful degradation, skip if unavailable
Large fixture filesCompress, store only essential data

Success metrics

  • All parser tests pass with fixtures
  • Less than 30 second test execution time with fixtures
  • Greater than 95% success rate against live API
  • Support for at least 2 chains (Solana, Ethereum)
  • No API keys required for PR checks