Testing Guide
On this page
- Quick Start
- Test Categories
- Unit Tests
- Integration Tests
- Property-Based Tests
- Fuzzing
- Setup
- Available Fuzz Targets
- Running Fuzzing
- Analyzing Crashes
- VOPR Simulation Testing
- Running VOPR
- Available Scenarios
- Extended VOPR Runs
- Understanding VOPR Output
- Invariant Checkers
- Core Invariants
- Query Invariants
- Test Coverage
- Continuous Integration
- Debugging Test Failures
- Property Test Failures
- VOPR Failures
- Integration Test Failures
- Performance Benchmarking
- Best Practices
- Writing Tests
- Property Testing
- Fuzzing
- VOPR
- Troubleshooting
- Property Tests Flaking
- Fuzz Target Crashes Immediately
- VOPR Reports Timeout
- Resources
- See Also
This guide covers how to run tests, property-based tests, fuzzing, and VOPR simulation testing for Kimberlite.
Quick Start
# Run all tests
# Run with nextest (faster)
# Run specific package tests
# Run single test
Test Categories
Unit Tests
Unit tests live in src/tests.rs within each crate or inline with #[cfg(test)] modules.
# All unit tests
# Specific crate
Integration Tests
Integration tests are in tests/ directories.
# All integration tests
# Specific integration test file
Property-Based Tests
Property tests use proptest to verify invariants across random inputs.
# Run with more test cases
PROPTEST_CASES=10000
# Specific property test
Key property tests:
kimberlite-types: StreamId ↔ TenantId roundtripkimberlite-query: Key encoding/decoding, type coercion, aggregates
Fuzzing
Kimberlite uses cargo-fuzz for automated fuzzing of critical parsers.
Setup
# Install cargo-fuzz
Available Fuzz Targets
# List all fuzz targets
# Or:
Current targets:
parse_sql- SQL parser fuzzing
Running Fuzzing
# Quick smoke test (1 minute)
# Run specific target for 1 hour
# Or:
# Run until crash is found
Analyzing Crashes
# Fuzz crashes are saved to:
# Reproduce a crash
VOPR Simulation Testing
VOPR (Viewstamped Operation Replication) provides deterministic simulation testing with fault injection.
Running VOPR
# Default scenario
# Specific scenario
# List available scenarios
# Or:
Available Scenarios
- baseline - Normal operation without faults
- swizzle - Swizzle-clogging (intermittent network congestion)
- gray - Gray failures (partial node failures, slow responses)
- multi-tenant - Multiple tenants with fault injection
- time-compression - 10x accelerated time
- combined - All fault types enabled
Extended VOPR Runs
# Overnight run (10M iterations)
# With verbose output
Understanding VOPR Output
Running VOPR scenario: multi-tenant
Seed: 12345
Iterations: 100000
✓ Simulation completed successfully
Events: 98542
Simulated time: 15.23s
Storage hash: 0x1a2b3c...
Success indicators:
- All invariants hold (no violations)
- Storage hash is deterministic (same seed → same hash)
- No crashes or panics
Failure output:
✗ Invariant violation: tenant_isolation
Message: row belongs to tenant 2 but was returned to tenant 1
At event: 45231
Seed: 12345 (use this to reproduce)
Invariant Checkers
VOPR includes several invariant checkers:
Core Invariants
- HashChainChecker - Verifies hash chain integrity
- LinearizabilityChecker - Ensures operations appear atomic
- ConsistencyChecker - Verifies replica consistency
Query Invariants
- QueryDeterminismChecker - Same query+params → same result
- ReadYourWritesChecker - Writes are visible to subsequent reads
- TypeSafetyChecker - Column types match schema
- OrderByLimitChecker - LIMIT applied after ORDER BY
- AggregateCorrectnessChecker - COUNT/SUM are correct
- TenantIsolationChecker - No cross-tenant data leakage
Test Coverage
# Generate coverage report (requires tarpaulin)
# View coverage
Continuous Integration
The CI pipeline runs:
# Format check
# Clippy with strict lints
# All tests
# Documentation check
# Smoke fuzz (limited time)
Debugging Test Failures
Property Test Failures
# Property tests print failing cases
PROPTEST_CASES=1000
# Output includes:
# proptest: Shrinking failed
# minimal failing case: (tenant_id: 4294967295, local_id: 2147483647)
VOPR Failures
# Reproduce with the same seed
# Enable verbose output for more detail
Integration Test Failures
# Run with verbose output
# Run specific failing test
Performance Benchmarking
# Run benchmarks (requires nightly)
# Specific benchmark
Best Practices
Writing Tests
- Use descriptive names:
test_stream_id_roundtrip_with_max_values - Test edge cases: Zero, max values, boundaries
- Use property tests for invariants that must hold for all inputs
- Keep tests fast: Unit tests < 1ms, integration tests < 100ms
Property Testing
use *;
proptest!
Fuzzing
- Start with short runs: Validate the target works before long runs
- Use corpus: Save interesting inputs to
fuzz/corpus/ - Minimize crashes:
cargo fuzz cminto minimize corpus - Triage crashes: Check if crash is exploitable or just input validation
VOPR
- Start with Baseline: Ensure correctness without faults
- Add faults incrementally: SwizzleClogging → GrayFailures → Combined
- Use appropriate operation counts:
- Quick check: 10K operations
- CI: 100K operations
- Overnight: 10M+ operations
- Save seeds: Failing seeds can reproduce bugs deterministically
Troubleshooting
Property Tests Flaking
# Run with fixed seed
PROPTEST_SEED=12345
Fuzz Target Crashes Immediately
# Check it compiles
# Run with timeout
VOPR Reports Timeout
# Increase timeout or reduce operations
Resources
See Also
- TESTING.md - Testing philosophy and strategy
- VOPR_DEPLOYMENT.md - Deploying VOPR in production
- CLAUDE.md - Quick commands for Claude Code