# STR-005: Test Infrastructure

| Link | Path |
|------|------|
| **Normative** | [NORMATIVE.md](../NORMATIVE.md) |
| **Verification** | [VERIFICATION.md](../VERIFICATION.md) |
| **Tracking** | [TRACKING.yaml](../TRACKING.yaml) |
| **Spec** | [SPEC.md](../../../../resources/SPEC.md) Section 17 |

---

## Summary

Test infrastructure MUST provide reusable helpers for creating temporary RocksDB stores, test blocks with deterministic hashes, small-cache test configs, and linked block chains.

---

## Specification

### Temporary RocksDB Directory Helper

```rust
/// Creates a temporary directory for a RocksDB store that is
/// automatically cleaned up when the returned guard is dropped.
pub fn temp_blockstore_dir() -> (TempDir, PathBuf) {
    let dir = tempfile::tempdir().unwrap();
    let path = dir.path().to_path_buf();
    (dir, path)
}
```

### Test Block Helper

```rust
/// Creates a test L2Block with deterministic content derived from
/// the given height and parent hash.
pub fn test_block(height: u64, parent_hash: Bytes32) -> L2Block {
    // Build L2BlockHeader with:
    //   - height set to `height`
    //   - parent_hash set to `parent_hash`
    //   - timestamp set to `height * 10`
    //   - other fields set to deterministic defaults
    // Build L2Block wrapping the header with empty transactions
    // Hash MUST be deterministic: same inputs always produce same hash
}

/// Creates a test L2BlockHeader with deterministic fields.
pub fn test_header(height: u64, parent_hash: Bytes32) -> L2BlockHeader {
    // Same deterministic logic as test_block but returns just the header
}
```

### Test Config

```rust
/// Returns a BlockStoreConfig suitable for unit tests with small caches.
pub fn test_config(path: PathBuf) -> BlockStoreConfig {
    BlockStoreConfig {
        path,
        block_cache_capacity: 10,
        header_cache_capacity: 20,
        cache_shards: 2,
        warm_cache_on_open: false,
        write_buffer_size: 4 * 1024 * 1024,  // 4 MB
        block_cache_size: 8 * 1024 * 1024,    // 8 MB
        max_open_files: 100,
        enable_blob_db: false,
        compress_blocks: false,
        compression_level: 1,
        use_compression_dict: false,
        write_pipeline_batch_size: 4,
        write_pipeline_flush_ms: 10,
        sync_writes: false,
        enable_compaction_pruning: false,
        min_retained_height: None,
    }
}
```

### Chain Builder

```rust
/// Builds a chain of `n` linked blocks starting from genesis.
/// Returns the blocks in order [genesis, block_1, ..., block_{n-1}].
/// Each block's parent_hash points to the previous block's hash.
pub fn build_chain(n: usize) -> Vec<L2Block> {
    let genesis_hash = Bytes32::default(); // or zero hash
    let mut blocks = Vec::with_capacity(n);
    let mut parent = genesis_hash;
    for height in 0..n {
        let block = test_block(height as u64, parent);
        parent = block.hash();  // computed deterministically
        blocks.push(block);
    }
    blocks
}
```

---

## Acceptance Criteria

- [x] `temp_blockstore_dir()` creates a directory that exists on disk
- [x] `temp_blockstore_dir()` directory is cleaned up when guard is dropped
- [x] `test_block()` returns a valid L2Block at the specified height
- [x] `test_block()` uses the provided parent_hash
- [x] `test_block()` is deterministic (same inputs produce identical blocks)
- [x] `test_header()` returns a valid L2BlockHeader matching `test_block()` output
- [x] `test_config()` returns a config with small cache capacities
- [x] `test_config()` disables blob DB and compression for test simplicity
- [x] `build_chain(n)` returns exactly `n` blocks
- [x] `build_chain(n)` has correct parent-child hash linking
- [x] `build_chain(1)` returns just a genesis block with default parent hash

---

## Implementation Notes

- Place helpers in a `tests/common/mod.rs` or `src/test_helpers.rs` (cfg(test)) module.
- Deterministic hashing requires that all fields fed into the hash are fixed given height and parent_hash. Use simple patterns like zeroed fields or height-derived values.
- The `tempfile` crate handles automatic cleanup via `TempDir`'s `Drop` impl.
- These helpers will be used extensively by every other domain's test suite.

---

## Test Plan

| Test Name | Type | Description |
|-----------|------|-------------|
| `test_temp_dir_created` | unit | Call `temp_blockstore_dir()`, verify path exists |
| `test_temp_dir_cleanup` | unit | Drop the guard, verify path no longer exists |
| `test_block_deterministic` | unit | Call `test_block()` twice with same args, assert equality |
| `test_block_height_correct` | unit | Call `test_block(42, ...)`, verify header height is 42 |
| `test_block_parent_hash_correct` | unit | Call `test_block(1, hash)`, verify parent_hash matches |
| `test_header_matches_block` | unit | Compare `test_header()` output to `test_block().header` |
| `test_config_small_caches` | unit | Verify test config has block_cache_capacity=10, header_cache_capacity=20 |
| `test_build_chain_length` | unit | `build_chain(5)` returns exactly 5 blocks |
| `test_build_chain_linking` | unit | For each block in chain, verify parent_hash equals previous block's hash |
| `test_build_chain_heights` | unit | Verify heights are 0, 1, 2, ..., n-1 |

---

## Expected Test Files

- `tests/str_005_tests.rs`
