feltdb 0.2.0

Embedded durable state store: an append-only log with atomic multi-record transactions, version-conditional writes, and idempotent retries
Documentation
/// Phase 5 Integration Tests
///
/// Demonstrates Gate 1 (Replica Convergence) and Gate 2 (Operation Algebra)
/// working together to prove distributed convergence.

#[cfg(test)]
mod tests {
    use crate::convergence::VectorClock;
    use crate::multi_node_convergence::MultiNodeConvergenceSimulator;
    use crate::operation_algebra::OperationAlgebraRegistry;
    use crate::permutation_scheduler::PermutationScheduler;
    use crate::transactions::{Operation, OperationCommand, OperationId, StateVersion};
    use std::collections::HashMap;

    fn create_test_operation(seq: u64, collection: &str, record_id: &str, value: i32) -> Operation {
        let mut vc = VectorClock::new();
        vc.increment("test_node");
        let version = StateVersion::new(vc, "test_hash".to_string());

        Operation::new(
            OperationId::new("test_node".to_string(), seq),
            version,
            format!("Op{}", seq),
            OperationCommand {
                op_type: "UpdateField".to_string(),
                collection: collection.to_string(),
                record_id: record_id.to_string(),
                fields: {
                    let mut m = HashMap::new();
                    m.insert("value".to_string(), serde_json::json!(value));
                    m
                },
            },
            "test".to_string(),
        )
    }

    #[test]
    fn test_phase5_gate1_convergence_under_reordering() {
        // Gate 1: Multiple nodes executing same operations (different order) converge
        let ops = vec![
            create_test_operation(1, "records", "rec1", 10),
            create_test_operation(2, "records", "rec2", 20),
            create_test_operation(3, "records", "rec3", 30),
        ];

        let simulator = MultiNodeConvergenceSimulator::new(3);
        let result = simulator.test_comprehensive_convergence(&ops);

        assert!(
            result.all_converged,
            "Gate 1 failed: nodes did not converge\n{}",
            result.summary()
        );
        assert_eq!(
            result.node_results.len(),
            3 + 50,
            "Expected 3 deterministic + 50 random schedules"
        );
    }

    #[test]
    fn test_phase5_gate2_operation_algebra_declared() {
        // Gate 2: Every operation type declares its convergence algebra
        let registry = OperationAlgebraRegistry::new();

        // Verify all standard operations are registered
        let standard_ops = vec![
            "SetField",
            "Increment",
            "AddToSet",
            "RemoveFromSet",
            "Create",
            "Delete",
            "Transfer",
            "Append",
            "Noop",
        ];

        for op_type in &standard_ops {
            let algebra = registry.get(op_type);
            assert!(
                algebra.is_some(),
                "Operation {} not declared in algebra registry",
                op_type
            );
            let alg = algebra.unwrap();
            println!(
                "✓ {}: {:?} ({})",
                op_type, alg.convergence_semantic, alg.merge_function_description
            );
        }

        // Verify commutative operations are correctly identified
        assert!(registry.get("Increment").unwrap().is_commutative());
        assert!(registry.get("AddToSet").unwrap().is_commutative());
        assert!(!registry.get("Transfer").unwrap().is_commutative());
    }

    #[test]
    fn test_phase5_gate1_gate2_integration() {
        // Integration: Gates 1 and 2 work together conceptually
        // Gate 1 generates permutations; Gate 2 declares convergence semantics.
        //
        // Key insight: Not all operations converge under arbitrary reordering.
        // SetField (LWW) diverges with different timestamps; Increment (CRDT) converges.
        // This proves the importance of Gate 2: every operation must declare its merge algebra.

        // Verify operation algebra (Gate 2)
        let registry = OperationAlgebraRegistry::new();

        // SetField uses LWW - does NOT converge under reordering without timestamp sync
        let setfield_algebra = registry.get("SetField").unwrap();
        println!(
            "Gate 2 - SetField: {} ({})",
            setfield_algebra.merge_function_description,
            format!("{:?}", setfield_algebra.convergence_semantic)
        );

        // Increment uses Counter CRDT - DOES converge under any reordering
        let increment_algebra = registry.get("Increment").unwrap();
        println!(
            "Gate 2 - Increment: {} ({})",
            increment_algebra.merge_function_description,
            format!("{:?}", increment_algebra.convergence_semantic)
        );

        // Generate permutations (Gate 1)
        let ops = vec![
            create_test_operation(1, "records", "rec1", 10),
            create_test_operation(2, "records", "rec2", 20),
            create_test_operation(3, "records", "rec3", 30),
        ];
        let schedules = PermutationScheduler::minimal_schedules(&ops);
        println!(
            "Gate 1: Generated {} permutation schedules",
            schedules.len()
        );

        // Integration insight:
        // - Gate 1 creates permutations
        // - Gate 2 specifies which operations can converge
        // - Together they form the foundation of Phase 5 testing
        println!("✓ Gates 1 and 2 are integrated: permutation testing + operation algebra");
    }

    #[test]
    fn test_phase5_commutative_operations_converge() {
        // Commutative operations should converge regardless of order
        // Example: Increment is commutative (a+b = b+a)

        let registry = OperationAlgebraRegistry::new();
        let increment_algebra = registry.get("Increment").unwrap();

        // Verify Increment is marked commutative
        assert!(
            increment_algebra.is_commutative(),
            "Increment should be commutative"
        );
        assert_eq!(
            increment_algebra.merge_function_description,
            "Counter CRDT: sum(all_increments)"
        );

        println!(
            "✓ Increment declared as commutative (algebra: {})",
            increment_algebra.merge_function_description
        );
    }

    #[test]
    fn test_phase5_non_commutative_operations_require_semantics() {
        // Non-commutative operations (like SetField) must have deterministic merge

        let registry = OperationAlgebraRegistry::new();
        let setfield_algebra = registry.get("SetField").unwrap();

        // SetField uses LWW (Last-Write-Wins) for determinism
        assert!(setfield_algebra.is_deterministic());
        assert_eq!(
            setfield_algebra.merge_function_description,
            "LWW: max(timestamp, value)"
        );

        println!(
            "✓ SetField uses deterministic merge: {}",
            setfield_algebra.merge_function_description
        );
    }

    #[test]
    fn test_phase5_convergence_with_minimal_operations() {
        // Minimal test: single operation should converge trivially
        let ops = vec![create_test_operation(1, "records", "rec1", 10)];

        let simulator = MultiNodeConvergenceSimulator::new(3);
        let result = simulator.test_minimal_convergence(&ops);

        assert!(
            result.all_converged,
            "Single operation should converge trivially"
        );
        println!("✓ Minimal convergence test passed: {}", result.summary());
    }

    #[test]
    fn test_phase5_convergence_aggregation() {
        // Multiple convergence test runs should all pass
        let ops = vec![
            create_test_operation(1, "records", "rec1", 10),
            create_test_operation(2, "records", "rec2", 20),
        ];

        let simulator = MultiNodeConvergenceSimulator::new(3);
        let agg = simulator.aggregate_convergence_runs(&ops, 3);

        assert!(agg.all_passed(), "All convergence runs should pass");
        println!("✓ Convergence aggregation: {}", agg.summary());
    }

    #[test]
    fn test_phase5_gate1_scalability() {
        // Test that convergence holds as operation count increases
        for op_count in [1, 3, 5, 10].iter() {
            let ops: Vec<_> = (1..=*op_count)
                .map(|seq| {
                    create_test_operation(seq, "records", &format!("rec{}", seq), seq as i32 * 10)
                })
                .collect();

            let simulator = MultiNodeConvergenceSimulator::new(3);
            let result = simulator.test_minimal_convergence(&ops);

            assert!(
                result.all_converged,
                "Convergence failed for {} operations",
                op_count
            );
            println!(
                "✓ Gate 1 convergence holds for {} operations: {}",
                op_count,
                result.summary()
            );
        }
    }

    #[test]
    fn test_phase5_gate2_algebra_completeness() {
        // Gate 2: Verify all operations have declared convergence semantics
        let registry = OperationAlgebraRegistry::new();

        for algebra in registry.all_algebras() {
            assert!(
                !algebra.operation_type.is_empty(),
                "Operation type must be declared"
            );
            assert!(
                !algebra.merge_function_description.is_empty(),
                "Merge semantics must be described"
            );
            println!(
                "✓ {}: {} → {}",
                algebra.operation_type,
                format!("{:?}", algebra.convergence_semantic),
                algebra.merge_function_description
            );
        }
    }

    #[test]
    fn test_phase5_summary() {
        println!("\n=== Phase 5 Integration Test Summary ===\n");

        println!("Gate 1: Replica Convergence Under Arbitrary Reordering");
        let ops = vec![
            create_test_operation(1, "records", "rec1", 10),
            create_test_operation(2, "records", "rec2", 20),
            create_test_operation(3, "records", "rec3", 30),
        ];
        let simulator = MultiNodeConvergenceSimulator::new(3);
        let result = simulator.test_minimal_convergence(&ops);
        println!(
            "  ✓ {} nodes executed {} operations",
            result.node_results.len(),
            ops.len()
        );
        println!("  ✓ All converged to: {}", result.canonical_hash);

        println!("\nGate 2: Operation Algebra Declaration");
        let registry = OperationAlgebraRegistry::new();
        let algebras = registry.all_algebras();
        println!("  ✓ {} operation types declared", algebras.len());
        for alg in algebras.iter().take(5) {
            println!(
                "    - {}: {:?}",
                alg.operation_type, alg.convergence_semantic
            );
        }

        println!("\n✅ Phase 5 Foundation Established");
        println!("   Gates 1-2 validated: Convergence + Algebra");
    }
}