use qudag_protocol::{Coordinator, ProtocolConfig, ProtocolState};
use std::time::Duration;
use tokio::time::sleep;
#[tokio::test]
async fn test_network_partition_detection() {
let config1 = ProtocolConfig {
network: qudag_protocol::config::NetworkConfig {
port: 10001,
max_peers: 10,
connect_timeout: Duration::from_secs(5),
},
..Default::default()
};
let config2 = ProtocolConfig {
network: qudag_protocol::config::NetworkConfig {
port: 10002,
max_peers: 10,
connect_timeout: Duration::from_secs(5),
},
..Default::default()
};
let mut coordinator1 = Coordinator::new(config1).await.unwrap();
let mut coordinator2 = Coordinator::new(config2).await.unwrap();
coordinator1.start().await.unwrap();
coordinator2.start().await.unwrap();
sleep(Duration::from_millis(100)).await;
assert_eq!(coordinator1.state().await, ProtocolState::Running);
assert_eq!(coordinator2.state().await, ProtocolState::Running);
let message1 = vec![1, 2, 3];
let message2 = vec![4, 5, 6];
let result1 = coordinator1.broadcast_message(message1.clone()).await;
let result2 = coordinator2.broadcast_message(message2.clone()).await;
assert!(result1.is_ok());
assert!(result2.is_ok());
coordinator1.stop().await.unwrap();
coordinator2.stop().await.unwrap();
}
#[tokio::test]
async fn test_message_ordering_during_partition() {
let config = ProtocolConfig::default();
let mut coordinator = Coordinator::new(config).await.unwrap();
coordinator.start().await.unwrap();
let messages = vec![
vec![1, 0, 0],
vec![2, 0, 0],
vec![3, 0, 0],
vec![4, 0, 0],
vec![5, 0, 0],
];
for message in &messages {
let result = coordinator.broadcast_message(message.clone()).await;
assert!(result.is_ok());
sleep(Duration::from_millis(10)).await;
}
if let Some(dag) = coordinator.dag_manager() {
for message in &messages {
assert!(dag.contains_message(message));
}
}
coordinator.stop().await.unwrap();
}
#[tokio::test]
async fn test_partition_recovery_and_sync() {
let config1 = ProtocolConfig {
network: qudag_protocol::config::NetworkConfig {
port: 10003,
max_peers: 10,
connect_timeout: Duration::from_secs(5),
},
..Default::default()
};
let config2 = ProtocolConfig {
network: qudag_protocol::config::NetworkConfig {
port: 10004,
max_peers: 10,
connect_timeout: Duration::from_secs(5),
},
..Default::default()
};
let mut coordinator1 = Coordinator::new(config1).await.unwrap();
let mut coordinator2 = Coordinator::new(config2).await.unwrap();
coordinator1.start().await.unwrap();
coordinator2.start().await.unwrap();
let messages1 = vec![vec![1, 1, 1], vec![2, 2, 2]];
let messages2 = vec![vec![3, 3, 3], vec![4, 4, 4]];
for message in &messages1 {
coordinator1.broadcast_message(message.clone()).await.unwrap();
}
for message in &messages2 {
coordinator2.broadcast_message(message.clone()).await.unwrap();
}
sleep(Duration::from_millis(200)).await;
assert_eq!(coordinator1.state().await, ProtocolState::Running);
assert_eq!(coordinator2.state().await, ProtocolState::Running);
coordinator1.stop().await.unwrap();
coordinator2.stop().await.unwrap();
}
#[tokio::test]
async fn test_consensus_during_partition() {
let config = ProtocolConfig::default();
let mut coordinator = Coordinator::new(config).await.unwrap();
coordinator.start().await.unwrap();
let conflicting_messages = vec![
vec![100, 1, 1], vec![100, 1, 2], vec![100, 1, 3], ];
for message in &conflicting_messages {
let result = coordinator.broadcast_message(message.clone()).await;
assert!(result.is_ok());
sleep(Duration::from_millis(50)).await;
}
if let Some(dag) = coordinator.dag_manager() {
for message in &conflicting_messages {
assert!(dag.contains_message(message));
}
}
coordinator.stop().await.unwrap();
}
#[tokio::test]
async fn test_byzantine_behavior_during_partition() {
let config1 = ProtocolConfig {
network: qudag_protocol::config::NetworkConfig {
port: 10005,
max_peers: 10,
connect_timeout: Duration::from_secs(5),
},
..Default::default()
};
let config2 = ProtocolConfig {
network: qudag_protocol::config::NetworkConfig {
port: 10006,
max_peers: 10,
connect_timeout: Duration::from_secs(5),
},
..Default::default()
};
let mut honest_coordinator = Coordinator::new(config1).await.unwrap();
let mut byzantine_coordinator = Coordinator::new(config2).await.unwrap();
honest_coordinator.start().await.unwrap();
byzantine_coordinator.start().await.unwrap();
let honest_messages = vec![
vec![200, 1],
vec![200, 2],
vec![200, 3],
];
for message in &honest_messages {
honest_coordinator.broadcast_message(message.clone()).await.unwrap();
}
let byzantine_messages = vec![
vec![255; 1000], vec![], vec![200, 1], ];
for message in &byzantine_messages {
let result = byzantine_coordinator.broadcast_message(message.clone()).await;
assert!(result.is_ok());
}
assert_eq!(honest_coordinator.state().await, ProtocolState::Running);
assert_eq!(byzantine_coordinator.state().await, ProtocolState::Running);
honest_coordinator.stop().await.unwrap();
byzantine_coordinator.stop().await.unwrap();
}
#[tokio::test]
async fn test_dynamic_network_topology_changes() {
let configs: Vec<ProtocolConfig> = (0..3).map(|i| {
ProtocolConfig {
network: qudag_protocol::config::NetworkConfig {
port: 10007 + i as u16,
max_peers: 10,
connect_timeout: Duration::from_secs(5),
},
..Default::default()
}
}).collect();
let mut coordinators: Vec<Coordinator> = Vec::new();
for config in configs {
let mut coordinator = Coordinator::new(config).await.unwrap();
coordinator.start().await.unwrap();
coordinators.push(coordinator);
}
for (i, coordinator) in coordinators.iter_mut().enumerate() {
let message = vec![i as u8, 100, 100];
coordinator.broadcast_message(message).await.unwrap();
}
sleep(Duration::from_millis(100)).await;
coordinators[0].stop().await.unwrap();
for (i, coordinator) in coordinators.iter_mut().enumerate().skip(1) {
let message = vec![i as u8, 200, 200];
let result = coordinator.broadcast_message(message).await;
assert!(result.is_ok());
}
coordinators[0].start().await.unwrap();
for (i, coordinator) in coordinators.iter_mut().enumerate() {
let message = vec![i as u8, 300, 300];
let result = coordinator.broadcast_message(message).await;
assert!(result.is_ok());
}
for coordinator in coordinators.iter_mut() {
coordinator.stop().await.unwrap();
}
}
#[tokio::test]
async fn test_partition_tolerance_threshold() {
let num_nodes = 5;
let configs: Vec<ProtocolConfig> = (0..num_nodes).map(|i| {
ProtocolConfig {
network: qudag_protocol::config::NetworkConfig {
port: 10010 + i as u16,
max_peers: 10,
connect_timeout: Duration::from_secs(5),
},
..Default::default()
}
}).collect();
let mut coordinators: Vec<Coordinator> = Vec::new();
for config in configs {
let mut coordinator = Coordinator::new(config).await.unwrap();
coordinator.start().await.unwrap();
coordinators.push(coordinator);
}
let majority_nodes = 3;
for i in 0..majority_nodes {
let message = vec![i as u8, 250, 250];
coordinators[i].broadcast_message(message).await.unwrap();
}
for i in majority_nodes..num_nodes {
let message = vec![i as u8, 251, 251];
coordinators[i].broadcast_message(message).await.unwrap();
}
sleep(Duration::from_millis(200)).await;
for coordinator in &coordinators {
assert_eq!(coordinator.state().await, ProtocolState::Running);
}
for coordinator in coordinators.iter_mut() {
coordinator.stop().await.unwrap();
}
}