# armdb — Стратегия тестирования
---
## Текущее покрытие (~186 тестов)
Покрыто: CRUD, итераторы (22 теста), recovery (8 тестов вкл. truncated entries),
конкурентность (7 тестов), компакция (6 тестов вкл. concurrent + double),
все кодеки (rapira, bytemuck, zerocopy), WriteHook (8 тестов), migrate (5 тестов),
typed/zero деревья, shard prefix routing, стресс-тесты (12 тестов `#[ignore]`),
loom permutation testing для SkipList (7 тестов, `--features loom`),
Miri UB detection для SkipList (9 тестов, `cargo +nightly miri`).
Паттерн — `tempdir()` + малый датасет (100-1000 записей) для unit tests,
zipfian + 10K-1M записей для stress tests.
**Готово:**
- Фаззинг: 5 fuzz targets (entry, recovery, byte_view, hint) + 2 proptest model tests (BTreeMap comparison)
- Стресс: concurrent ConstTree (6 threads + compaction + flush), crash recovery (fork + SIGKILL × 50), large dataset (1M entries)
- Compaction: concurrent reads/writes (4 теста), double compaction, aggressive pressure
**Главные пробелы:**
- Нет бенчмарков KV-операций (criterion установлен, бенчей нет)
- Concurrent VarTree compaction — transient read corruption, см. `docs/bugs/concurrent-compaction-var-read.md`
- ~~Нет loom тестов для SkipList~~ — **готово** (7 тестов, `cargo test -p armdb --features loom --test loom_skiplist`)
- ~~Нет Miri тестов для SkipList~~ — **готово** (9 тестов, `cargo +nightly miri test -p armdb --test miri_skiplist`)
- Нет encryption + recovery + compaction комбинированных тестов
- Нет larger-than-RAM профиля
---
## 1. Фаззинг
### a) `cargo-fuzz` (libFuzzer) — 5 targets (готово)
| `fuzz_entry_header` | EntryHeader десериализация, CRC валидация |
| `fuzz_entry_roundtrip` | Entry encode/decode + CRC + bit-flip corruption |
| `fuzz_recovery` | Recovery из malformed `.data` файлов (не должен паниковать) |
| `fuzz_byte_view` | ByteView inline/heap boundary (20 байт), refcounting |
| `fuzz_hint_parse` | Hint file parsing для разных key sizes |
### b) Loom — permutation testing для lock-free SkipList (готово)
7 тестов в `armdb/tests/loom_skiplist.rs`. Запуск: `cargo test -p armdb --features loom --test loom_skiplist`.
| `concurrent_get_insert` | get ‖ insert | Reader не видит partial node |
| `concurrent_get_remove` | get ‖ remove | Reader корректно пропускает marked nodes |
| `insert_remove_same_key` | insert ‖ remove (один ключ) | Оба ordering через write_lock корректны |
| `concurrent_iter_insert` | iter ‖ insert | Iterator не паникует; weakly-consistent |
| `concurrent_iter_remove` | iter ‖ remove | Iterator пропускает marked nodes |
| `concurrent_swap_load_data` | swap_data ‖ load_data | RCU: reader видит old или new, не torn |
| `concurrent_swap_load_disk` | swap_disk ‖ load_disk | RCU: reader видит old или new, не torn |
Реализация: conditional `loom::sync::atomic` вместо `std::sync::atomic` (feature `loom`),
`loom::sync::Mutex` вместо `parking_lot::Mutex`, `seize::retire` отключён под loom (leak допустим).
### c) Miri — UB detection для SkipList (готово)
9 тестов в `armdb/tests/miri_skiplist.rs`. Запуск: `cargo +nightly miri test -p armdb --test miri_skiplist`.
**Что ловит (дополняет loom):**
- Stacked/Tree Borrows violations в 54 unsafe блоках
- Use-after-free через реальный `seize::retire` (loom его отключает!)
- Double-free, invalid pointer dereference
- Data races в concurrent тестах
| `single_insert_get_remove` | single | Полный lifecycle: alloc → insert → get → remove → retire → Drop |
| `single_overwrite_rcu_const` | single | ConstNode RCU: swap_data/load_data, Stacked Borrows |
| `single_overwrite_rcu_var` | single | VarNode RCU: swap_disk/load_disk |
| `single_drop_populated` | single | Drop 3 нод: нет double-free |
| `single_iter_full` | single | Iterator pointer validity |
| `single_insert_exists` | single | Rejected node freed correctly |
| `concurrent_get_insert` | multi | Reader vs writer: data race detection |
| `concurrent_get_remove` | multi | Reader vs remover с реальным retire |
| `concurrent_iter_modify` | multi | Iterator vs concurrent insert+remove |
Concurrent тесты: `MIRIFLAGS="-Zmiri-preemption-rate=0.1"` для exploration разных schedulings.
Несколько seeds: `MIRIFLAGS="-Zmiri-seed=N -Zmiri-preemption-rate=0.1"`.
**Ключевое**: seize v0.5.1 Miri-совместим (`#[cfg(not(miri))]` на platform barriers).
Retire **активен** под Miri — в отличие от loom, Miri тестирует реальный путь рекламации.
### d) `proptest` — модельный фаззинг (готово, можно расширять)
Два теста в `proptest_model.rs`: `const_tree_model_test` и `var_tree_model_test`.
Сравнение с BTreeMap, до 200 операций за sequence (Put, Get, Delete, Insert, CAS, Compact, CloseReopen, Iter, PrefixIter).
**Можно улучшить:** увеличить keyspace (сейчас 4 группы × 16 ID), увеличить max ops, добавить concurrent model test.
---
## 2. Бенчмарки (criterion) — пробел
`criterion = "0.8"` уже в dev-dependencies, но бенчей для armdb нет.
### Профили workload
| **seq-write** | 1M sequential puts | Пропускная способность записи |
| **rand-write** | 1M random puts | Запись + shard contention |
| **seq-read** | Чтение всех ключей по порядку | Read throughput, cache locality |
| **rand-read-hot** | Чтение из working set < cache | Block cache hit rate |
| **rand-read-cold** | Чтение из working set > cache | Disk I/O, cache miss penalty |
| **read-write-mix** | 80% read / 20% write | Реалистичная нагрузка |
| **scan** | `prefix_iter().take(100)` × 10K | Iterator performance |
| **overwrite** | Put на существующие ключи | Compaction pressure, dead bytes |
**Метрики:** throughput (ops/sec), latency p50/p99/p99.9, memory usage.
---
## 3. Стресс / нагрузочное тестирование
### a) In-process stress tests (готово)
Все тесты в `armdb/tests/stress_tests.rs`, `#[ignore]`, запуск: `cargo test -- --ignored --nocapture`.
| `stress_concurrent` | ConstTree: 6 threads × 100K ops + compaction + flush, zipfian 10K keyspace |
| `stress_concurrent_var` | VarTree: 6 threads × 100K ops, 16MB cache. **Compaction отключён** — transient corruption |
| `stress_compaction_pressure` | ConstTree: 100K inserts, double overwrite, double compact, close/reopen verify |
| `stress_large_dataset` | VarTree: 1M entries × 512B, zipfian/uniform/mixed reads, 4MB cache |
| `stress_var_full_lifecycle` | VarTree: 6 threads + compaction + flush + 32KB files + reopen verify |
| `stress_var_single_thread` | VarTree: 100K single-thread puts, isolates concurrency |
| `stress_var_bisect/minimal/no_rotation/rotation_no_cache` | Isolation тесты для block cache бага |
Инфраструктура: Zipfian distribution, `make_key`/`make_value`/`verify_value` helpers, `Config::test()`.
### b) Crash testing (готово)
| `stress_crash_recovery` | ConstTree: 50 итераций fork + SIGKILL + recovery verify |
| `stress_crash_recovery_var` | VarTree: 50 итераций fork + SIGKILL + recovery verify, block cache 4MB |
### c) Larger-than-RAM тест — пробел
Рекомендация: 10GB данных (values по 1KB), 64MB cache → cache miss rate ~90%+, мерить p99 latency.
---
## 4. Недостающие correctness тесты
| Concurrent VarTree compaction + reads | **Открытый баг** — transient corruption, см. `docs/bugs/concurrent-compaction-var-read.md` |
| Recovery после truncated entry | Готово (4 теста в `recovery_truncated_tests.rs`) |
| Compaction + concurrent reads/writes (ConstTree) | Готово (4 теста в `compaction_concurrent_tests.rs` + `stress_concurrent`) |
| Encryption + recovery + compaction | Пробел |
| `WriteHook` + compaction | Пробел (hook тесты есть, но без concurrent compaction) |
| `migrate()` на большом дереве | Готово (5 тестов в `migrate_large_tests.rs`) |
| loom для SkipList | **Готово** — 7 тестов (get‖insert, get‖remove, insert‖remove, iter‖insert, iter‖remove, swap_data‖load_data, swap_disk‖load_disk) |
### Deterministic simulation testing (TigerBeetle / FoundationDB подход)
- Заменить I/O на детерминированный мок
- Инжектить ошибки: `pread` returns EIO, `write` partial, disk full
- Воспроизводимые сценарии из seed
---
## 5. Приоритеты
1. **Исправить concurrent VarTree compaction** — открытый баг, блокирует полноценное стресс-тестирование VarTree
2. **criterion бенчмарки** — без них невозможно оценить эффект оптимизаций
3. ~~loom для SkipList~~ — **готово**
4. **encryption комбинированные тесты** — encryption + recovery + compaction
5. **larger-than-RAM профиль** — отдельная категория поведения