Skip to content

TEST-002: Adicionar property-based testing com proptest para WAL replay e compaction #372

@ElioNeto

Description

@ElioNeto

🟡 Médio | Qualidade | Testes

Problema

Testes unitários existentes são baseados em exemplos específicos. Não há property-based testing para verificar invariantes do sistema sob entradas aleatórias.

Impacto

  • Invariantes do LSM-tree (ex: "WAL replay produz mesmo estado") nunca são verificados exaustivamente
  • Edge cases raros podem corromper estado

Propriedades a testar

1. WAL Replay Property:

proptest! {
    #[test]
    fn wal_replay_produces_same_state(ops in prop::collection::vec(any::<Operation>(), 1..100)) {
        let dir = tempfile::tempdir().unwrap();
        let mut config = LsmConfig::default();
        config.core.dir_path = dir.path().to_path_buf();

        // Executar operações no engine
        let engine = Engine::new_from_config(&config, NoopCache).unwrap();
        for op in &ops {
            match op {
                Operation::Put(k, v) => engine.put(k, v).ok(),
                Operation::Delete(k) => engine.delete(k).ok(),
                _ => None,
            };
        }
        let state1 = engine.dump_all_keys();

        // Simular crash reiniciando engine
        drop(engine);
        let engine2 = Engine::new_from_config(&config, NoopCache).unwrap();
        let state2 = engine2.dump_all_keys();

        // PROPRIEDADE: Após replay do WAL, estado é idêntico
        prop_assert_eq!(state1, state2);
    }
}

2. Compaction Idempotency:

proptest! {
    #[test]
    fn compaction_is_idempotent(keys in prop::collection::vec("[a-z]{1,10}", 10..50)) {
        let dir = tempfile::tempdir().unwrap();
        let engine = setup_engine(&dir);

        for k in &keys { engine.put(k, "value").unwrap(); }

        // Compactar uma vez
        engine.compact().unwrap();
        let state1 = engine.dump_all();

        // Compactar de novo
        engine.compact().unwrap();
        let state2 = engine.dump_all();

        // PROPRIEDADE: Compactar duas vezes produz mesmo resultado
        prop_assert_eq!(state1, state2);
    }
}

3. Bloom Filter Never False Negative:

proptest! {
    #[test]
    fn bloom_filter_no_false_negative(key in "[a-z]{1,100}") {
        let mut filter = Bloom::new_for_fp_rate(100, 0.01);
        filter.insert(&key);
        // PROPRIEDADE: Bloom filter nunca diz "não presente" para chave inserida
        prop_assert!(filter.might_contain(&key));
    }
}

Setup:

# Cargo.toml
[dev-dependencies]
proptest = "1.5"

Esforço: Médio (12h)

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions