Priority: HIGH (post-release)
Risk: HIGH — ядро приложения, может сломать timing и e2e поведение
Blocked by: ничего
Блокирует: unit тесты pipeline без root, CI без привилегий
Контекст
Сейчас execute_worker_task напрямую вызывает:
start_nfqws2() — spawn процесса
nftables::add_worker_rule() / remove_worker_rules() — shell-out в nft
http_test() / http_test_data() — TCP connect с SO_MARK
interpret_http_result() — интерпретация
Всё это требует root + Linux + nftables + nfqws2 binary. Unit тесты невозможны.
Цель
Возможность тестировать pipeline логику (батчинг, error handling, retry, scoring) без root и без реального nfqws2/nftables.
Предлагаемый подход
1. Trait WorkerBackend
#[async_trait]
trait WorkerBackend {
async fn start_worker(&self, qnum: u16, args: &[String]) -> Result<WorkerHandle, Error>;
async fn stop_worker(&mut self, handle: WorkerHandle);
}
Реализации:
Nfqws2Backend — текущая логика (spawn nfqws2)
MockBackend — для тестов (no-op, configurable failures)
2. Trait FirewallBackend
#[async_trait]
trait FirewallBackend {
async fn prepare(&self) -> Result<(), Error>;
async fn add_rules(&self, slots: &[WorkerSlot], port: u16, ips: &[String]) -> Result<(), Error>;
async fn remove_rules(&self) -> Result<(), Error>;
async fn cleanup(&self);
}
Реализации:
NftablesBackend — текущая логика
MockFirewall — для тестов
- (будущее)
IptablesBackend
3. Рефакторинг execute_worker_task
Разбить на:
setup_worker() — start nfqws2 + wait_for_ready
run_http_test() — HTTP request + interpret
cleanup_worker() — kill nfqws2
Каждая — отдельная тестируемая функция.
Что НЕ менять
- Сигнатуры
run_parallel() / run_check() — публичный API
- Формат отчётов
- CLI интерфейс
- e2e тесты — они должны продолжать работать as-is
Риски
- Timing regression — nfqws2 spawn → sleep → nft rules → HTTP request — порядок критичен. Абстракция может скрыть timing-зависимость
- Performance — dynamic dispatch через trait objects добавляет vtable indirection. На 150 стр/сек может быть заметно. Замерить benchmark до/после
- Scope creep — соблазн переделать "ещё вот это". Строго ограничить scope: traits + mock + 5-10 unit тестов
Критерии готовности
Priority: HIGH (post-release)
Risk: HIGH — ядро приложения, может сломать timing и e2e поведение
Blocked by: ничего
Блокирует: unit тесты pipeline без root, CI без привилегий
Контекст
Сейчас
execute_worker_taskнапрямую вызывает:start_nfqws2()— spawn процессаnftables::add_worker_rule()/remove_worker_rules()— shell-out в nfthttp_test()/http_test_data()— TCP connect с SO_MARKinterpret_http_result()— интерпретацияВсё это требует root + Linux + nftables + nfqws2 binary. Unit тесты невозможны.
Цель
Возможность тестировать pipeline логику (батчинг, error handling, retry, scoring) без root и без реального nfqws2/nftables.
Предлагаемый подход
1. Trait
WorkerBackendРеализации:
Nfqws2Backend— текущая логика (spawn nfqws2)MockBackend— для тестов (no-op, configurable failures)2. Trait
FirewallBackendРеализации:
NftablesBackend— текущая логикаMockFirewall— для тестовIptablesBackend3. Рефакторинг
execute_worker_taskРазбить на:
setup_worker()— start nfqws2 + wait_for_readyrun_http_test()— HTTP request + interpretcleanup_worker()— kill nfqws2Каждая — отдельная тестируемая функция.
Что НЕ менять
run_parallel()/run_check()— публичный APIРиски
Критерии готовности
cargo testпроходит без root (unit тесты pipeline)benchmarkпоказывает ±5% от текущей производительностиexecute_worker_taskразбит на 3+ функции ≤30 строк каждая