//! Tests for TestCluster.

#[cfg(test)]
mod test_cluster_tests {
    use super::super::access::TestClusterAccessExt;
    use super::super::convergence::TestClusterConvergenceExt;
    use super::super::creation::TestClusterCreationExt;
    use super::super::lifecycle::TestClusterLifecycleExt;
    use super::super::sync::TestClusterSyncExt;
    use super::super::types::TestCluster;

    #[tokio::test]
    async fn test_spawn_cluster() {
        let cluster = TestCluster::spawn(3).await.expect("spawn cluster");

        assert_eq!(cluster.node_count(), 3);
        assert_eq!(cluster.alive_node_indices().len(), 3);
        assert!(cluster.is_converged()); // Empty clusters are converged
    }

    #[tokio::test]
    async fn test_write_and_converge() {
        let mut cluster = TestCluster::spawn(3).await.expect("spawn cluster");

        // Write to node 0
        cluster.get_node_mut(0).write_assertion("test", "pred", 1000).await.expect("write");

        // Not converged yet
        assert!(!cluster.is_converged());

        // Sync all
        cluster.sync_all().await.expect("sync");

        // Should be converged
        cluster.assert_converged();
    }

    #[tokio::test]
    async fn test_partition_and_heal() {
        let mut cluster = TestCluster::spawn(4).await.expect("spawn cluster");

        // Write to node 0
        cluster.get_node_mut(0).write_assertion("test", "pred", 1000).await.expect("write");

        // Partition [0,1] from [2,3]
        cluster.network().partition(&[0, 1], &[2, 3]);

        // Sync all (partition will block cross-group)
        cluster.sync_all().await.expect("sync");

        // Nodes 0,1 should have data, 2,3 should not
        assert_eq!(cluster.get_node(0).assertion_count(), 1);
        assert_eq!(cluster.get_node(1).assertion_count(), 1);
        assert_eq!(cluster.get_node(2).assertion_count(), 0);
        assert_eq!(cluster.get_node(3).assertion_count(), 0);

        // Heal
        cluster.network().heal();

        // Sync again
        cluster.sync_all().await.expect("sync");

        // All should have data now
        cluster.assert_converged();
        assert_eq!(cluster.get_node(2).assertion_count(), 1);
    }

    #[tokio::test]
    async fn test_node_failure() {
        let mut cluster = TestCluster::spawn(3).await.expect("spawn cluster");

        // Write to node 0
        cluster.get_node_mut(0).write_assertion("test", "pred", 1000).await.expect("write");

        // Kill node 1
        cluster.kill_node(1);

        // Sync
        cluster.sync_all().await.expect("sync");

        // Node 2 should have data (from node 0)
        // Node 1 is dead, won't participate
        assert_eq!(cluster.get_node(0).assertion_count(), 1);
        assert_eq!(cluster.get_node(2).assertion_count(), 1);

        // Converged among alive nodes
        cluster.assert_converged();
    }

    #[tokio::test]
    async fn test_restart_node() {
        let mut cluster = TestCluster::spawn(2).await.expect("spawn cluster");

        // Write to node 0
        cluster.get_node_mut(0).write_assertion("test", "pred", 1000).await.expect("write");

        // Sync to node 1
        cluster.sync_all().await.expect("sync");
        assert_eq!(cluster.get_node(1).assertion_count(), 1);

        // Restart node 1 (loses all data)
        cluster.restart_node(1).expect("restart");
        assert_eq!(cluster.get_node(1).assertion_count(), 0);

        // Sync again to recover
        cluster.sync_all().await.expect("sync");
        assert_eq!(cluster.get_node(1).assertion_count(), 1);
    }

    #[tokio::test]
    async fn test_summary() {
        use super::super::convergence::TestClusterSummaryExt;

        let mut cluster = TestCluster::spawn(3).await.expect("spawn cluster");

        cluster.get_node_mut(0).write_assertion("test", "pred", 1000).await.expect("write");
        cluster.kill_node(2);

        let summary = cluster.summary();

        assert_eq!(summary.node_count, 3);
        assert_eq!(summary.alive_count, 2);
        assert!(!summary.converged); // Not synced yet
    }
}
