High-performance cache policies and supporting data structures.
CacheKit employs a multi-layered testing approach combining unit tests, property tests, and fuzz tests to ensure correctness and robustness.
Following the workspace rules, we:
Location: #[cfg(test)] mod tests in each module
Purpose: Verify specific behaviors and edge cases
Example:
#[test]
fn clock_ring_eviction_prefers_unreferenced() {
let mut ring = ClockRing::new(2);
ring.insert("a", 1);
ring.insert("b", 2);
ring.touch(&"a");
let evicted = ring.insert("c", 3);
assert_eq!(evicted, Some(("b", 2)));
assert!(ring.contains(&"a"));
}
Run:
cargo test
Location: #[cfg(test)] mod property_tests in each module
Purpose: Verify invariants hold across arbitrary inputs
Dependencies: proptest = "1.5"
Key Properties for ClockRing:
Example:
proptest! {
#[test]
fn prop_len_within_capacity(
capacity in 1usize..100,
ops in prop::collection::vec((0u32..1000, 0u32..100), 0..200)
) {
let mut ring = ClockRing::new(capacity);
for (key, value) in ops {
ring.insert(key, value);
prop_assert!(ring.len() <= ring.capacity());
}
}
}
Run:
cargo test prop_
Run with more cases:
PROPTEST_CASES=10000 cargo test prop_len_within_capacity
Location: fuzz/fuzz_targets/
Purpose: Find crashes and invariant violations through mutation-based testing
Dependencies: cargo-fuzz, libfuzzer-sys
Targets:
clock_ring_arbitrary_ops - Random operation sequencesclock_ring_insert_stress - Heavy insert loadclock_ring_eviction_patterns - Reference bit patternsRun:
cd fuzz
cargo fuzz run clock_ring_arbitrary_ops -- -max_total_time=60
See fuzz/README.md for detailed fuzzing instructions.
We expose complex private methods for testing using #[cfg(test)] pub(crate):
impl<K, V> ClockRing<K, V> {
#[cfg(any(test, debug_assertions))]
pub fn debug_validate_invariants(&self) {
// Check all invariants
assert_eq!(self.len, self.slots.iter().filter(|s| s.is_some()).count());
assert_eq!(self.len, self.index.len());
// ...
}
#[cfg(any(test, debug_assertions))]
pub fn debug_snapshot_slots(&self) -> Vec<Option<(&K, bool)>> {
// Expose internal state for assertions
}
}
This allows thorough testing without polluting the public API.
# Unit tests
cargo test
# Property tests with more cases
PROPTEST_CASES=10000 cargo test
# Fuzz tests (short run)
cd fuzz
cargo fuzz run clock_ring_arbitrary_ops -- -max_total_time=60
# With features enabled
cargo test --all-features
# Concurrency tests
cargo test --features concurrency
Our CI runs:
See Fuzzing in CI/CD for detailed fuzzing setup.
Example CI configuration:
# Quick fuzz on PRs
- name: Run fuzz tests (quick)
run: |
cargo install cargo-fuzz
cd fuzz
cargo fuzz run clock_ring_arbitrary_ops -- -max_total_time=60 -seed=1
cargo fuzz run clock_ring_insert_stress -- -max_total_time=60 -seed=2
cargo fuzz run clock_ring_eviction_patterns -- -max_total_time=60 -seed=3
# Property tests with more cases
- name: Run property tests
run: PROPTEST_CASES=1000 cargo test prop_
# Unit tests
- name: Run unit tests
run: cargo test --all-features
When a property test fails, proptest generates a minimal failing case:
Test failed: prop_len_within_capacity
minimal failing input: capacity = 1, ops = [(5, 10)]
Replay the failure:
#[test]
fn reproduce_prop_failure() {
let mut ring = ClockRing::new(1);
ring.insert(5, 10);
ring.debug_validate_invariants();
}
Crashes are saved to fuzz/artifacts/<target>/crash-<hash>:
Reproduce:
cargo fuzz run clock_ring_arbitrary_ops fuzz/artifacts/clock_ring_arbitrary_ops/crash-abc123
Debug in GDB:
rust-gdb --args target/x86_64-unknown-linux-gnu/release/clock_ring_arbitrary_ops fuzz/artifacts/clock_ring_arbitrary_ops/crash-abc123
Performance-critical paths have separate benchmarks (see benchmarks/):
cargo bench
Don’t use #[test] for performance testing; use criterion benchmarks instead.
tests, property_tests, fuzz_testsprop_len_within_capacity, not test1debug_validate_invariants(), debug_snapshot_slots()// 1. Add unit test
#[test]
fn new_feature_basic_behavior() {
// Test happy path
}
// 2. Add property test
proptest! {
#[test]
fn prop_new_feature_maintains_invariants(
input in arbitrary_input_strategy()
) {
// Verify invariants
}
}
// 3. Add fuzz target (if public API)
// fuzz/fuzz_targets/new_feature.rs
fuzz_target!(|data: &[u8]| {
// Decode and test
});