use anyhow::Result;
use std::time::Duration;
use tokio::time::timeout;
use p2p_foundation::{P2PNode, NodeConfig, Multiaddr};
use crate::common::{TestNetwork, TestAssertions, PerformanceTest};
#[tokio::test]
async fn test_node_creation_default() -> Result<()> {
let config = NodeConfig::default();
let node = P2PNode::new(config).await?;
assert!(!node.peer_id().to_string().is_empty());
let addrs = node.listen_addrs().await?;
assert!(!addrs.is_empty(), "Node should be listening on at least one address");
node.stop().await?;
Ok(())
}
#[tokio::test]
async fn test_node_creation_custom() -> Result<()> {
let config = NodeConfig::builder()
.port(9001)
.enable_ipv6(true)
.enable_metrics(true)
.enable_mcp(true)
.build();
let node = P2PNode::new(config).await?;
let addrs = node.listen_addrs().await?;
assert!(addrs.iter().any(|addr| addr.to_string().contains("9001")));
assert!(addrs.iter().any(|addr| addr.to_string().contains("ip6")));
let metrics = node.get_metrics().await?;
assert!(metrics.is_some());
let mcp_services = node.mcp_list_services().await?;
assert!(!mcp_services.is_empty());
node.stop().await?;
Ok(())
}
#[tokio::test]
async fn test_peer_connection() -> Result<()> {
let network = TestNetwork::simple(2).await?;
let node1_peers = network.node(0)?.peer_count().await;
let node2_peers = network.node(1)?.peer_count().await;
assert!(node1_peers >= 1, "Node 1 should have at least 1 peer");
assert!(node2_peers >= 1, "Node 2 should have at least 1 peer");
let node1_id = network.node(1)?.peer_id();
let node2_id = network.node(0)?.peer_id();
assert!(network.node(0)?.is_connected(&node1_id).await?);
assert!(network.node(1)?.is_connected(&node2_id).await?);
network.stop().await?;
Ok(())
}
#[tokio::test]
async fn test_multiple_peer_connections() -> Result<()> {
let network = TestNetwork::simple(5).await?;
network.wait_for_discovery().await?;
for i in 0..5 {
let peer_count = network.node(i)?.peer_count().await;
assert!(
peer_count >= 4,
"Node {} should have at least 4 peers, got {}",
i, peer_count
);
}
TestAssertions::assert_full_connectivity(&network).await?;
network.stop().await?;
Ok(())
}
#[tokio::test]
async fn test_connection_timeout() -> Result<()> {
let node = P2PNode::new(NodeConfig::default()).await?;
let invalid_addr: Multiaddr = "/ip4/192.0.2.1/tcp/1234".parse()?;
let start = std::time::Instant::now();
let result = timeout(
Duration::from_secs(5),
node.connect_peer(&invalid_addr.to_string())
).await;
assert!(result.is_err() || result.unwrap().is_err());
assert!(start.elapsed() >= Duration::from_secs(1));
node.stop().await?;
Ok(())
}
#[tokio::test]
async fn test_peer_disconnection_reconnection() -> Result<()> {
let mut network = TestNetwork::simple(2).await?;
let node1_id = network.node(1)?.peer_id();
assert!(network.node(0)?.is_connected(&node1_id).await?);
network.node_mut(0)?.disconnect(&node1_id).await?;
tokio::time::sleep(Duration::from_secs(1)).await;
assert!(!network.node(0)?.is_connected(&node1_id).await?);
let node1_addr = network.addrs[1].clone();
network.node_mut(0)?.connect_peer(&node1_addr.to_string()).await?;
tokio::time::sleep(Duration::from_secs(1)).await;
assert!(network.node(0)?.is_connected(&node1_id).await?);
network.stop().await?;
Ok(())
}
#[tokio::test]
async fn test_network_resilience() -> Result<()> {
let mut network = TestNetwork::simple(4).await?;
network.wait_for_discovery().await?;
let failed_node = network.nodes.remove(2);
failed_node.stop().await?;
tokio::time::sleep(Duration::from_secs(5)).await;
for i in 0..network.nodes.len() {
for j in (i + 1)..network.nodes.len() {
let peer_id = network.nodes[j].peer_id();
assert!(
network.nodes[i].can_reach_peer(peer_id).await?,
"Node {} cannot reach node {} after failure",
i, j
);
}
}
network.stop().await?;
Ok(())
}
#[tokio::test]
async fn test_connection_limits() -> Result<()> {
let config = NodeConfig::builder()
.port(9010)
.build();
let mut node_config = config;
node_config.max_peers = 2;
let node = P2PNode::new(node_config).await?;
let mut other_nodes = Vec::new();
for i in 0..3 {
let other_config = NodeConfig::builder()
.port(9011 + i as u16)
.build();
other_nodes.push(P2PNode::new(other_config).await?);
}
let node_addr = node.listen_addrs().await?[0].clone();
for other_node in &other_nodes {
let _ = other_node.connect_peer(&node_addr.to_string()).await;
}
tokio::time::sleep(Duration::from_secs(2)).await;
let peer_count = node.peer_count().await;
assert!(
peer_count <= 2,
"Node should respect max_peers limit, got {} peers",
peer_count
);
node.stop().await?;
for other_node in other_nodes {
other_node.stop().await?;
}
Ok(())
}
#[tokio::test]
async fn test_topology_discovery() -> Result<()> {
let network = TestNetwork::simple(6).await?;
network.wait_for_discovery().await?;
for (i, node) in network.nodes.iter().enumerate() {
let topology = node.get_network_topology().await?;
assert!(
topology.nodes.len() >= 5,
"Node {} should know about at least 5 other nodes, got {}",
i, topology.nodes.len()
);
assert!(
!topology.routes.is_empty(),
"Node {} should have routing information",
i
);
}
network.stop().await?;
Ok(())
}
#[tokio::test]
async fn test_connection_performance() -> Result<()> {
let mut perf = PerformanceTest::new();
let connection_time = perf.measure_async("single_connection", async {
let network = TestNetwork::simple(2).await?;
network.stop().await?;
Ok::<(), anyhow::Error>(())
}).await?;
let multi_connection_time = perf.measure_async("multi_connection", async {
let network = TestNetwork::simple(10).await?;
network.wait_for_discovery().await?;
network.stop().await?;
Ok::<(), anyhow::Error>(())
}).await?;
perf.print_results();
assert!(
perf.get_measurement("single_connection").unwrap() < Duration::from_secs(5),
"Single connection should take less than 5 seconds"
);
assert!(
perf.get_measurement("multi_connection").unwrap() < Duration::from_secs(30),
"Multi-node network setup should take less than 30 seconds"
);
Ok(())
}
#[tokio::test]
async fn test_mixed_ipv4_ipv6_network() -> Result<()> {
let ipv4_config = NodeConfig::builder()
.port(9020)
.enable_ipv6(false)
.build();
let ipv4_node = P2PNode::new(ipv4_config).await?;
let ipv6_config = NodeConfig::builder()
.port(9021)
.enable_ipv6(true)
.build();
let ipv6_node = P2PNode::new(ipv6_config).await?;
let ipv4_addrs = ipv4_node.listen_addrs().await?;
let ipv6_addrs = ipv6_node.listen_addrs().await?;
if let Some(ipv4_addr) = ipv4_addrs.iter().find(|addr| addr.to_string().contains("ip4")) {
let result = timeout(
Duration::from_secs(10),
ipv6_node.connect_peer(&ipv4_addr.to_string())
).await;
match result {
Ok(Ok(_)) => {
let ipv4_peer_id = ipv4_node.peer_id();
assert!(ipv6_node.is_connected(&ipv4_peer_id).await?);
},
Ok(Err(_)) | Err(_) => {
println!("Mixed IPv4/IPv6 connection failed - expected without tunneling");
}
}
}
ipv4_node.stop().await?;
ipv6_node.stop().await?;
Ok(())
}
#[tokio::test]
async fn test_keep_alive() -> Result<()> {
let config = TestNetworkConfig {
node_count: 2,
bootstrap_wait: Duration::from_secs(2),
..Default::default()
};
let network = TestNetwork::new(config).await?;
let node1_id = network.node(1)?.peer_id();
assert!(network.node(0)?.is_connected(&node1_id).await?);
tokio::time::sleep(Duration::from_secs(35)).await;
assert!(
network.node(0)?.is_connected(&node1_id).await?,
"Connection should be maintained by keep-alive"
);
let test_data = b"keep-alive test";
network.node(0)?.send_message(&node1_id, test_data.to_vec()).await?;
network.stop().await?;
Ok(())
}
#[tokio::test]
async fn test_connection_stress() -> Result<()> {
let node1 = P2PNode::new(NodeConfig::builder().port(9030).build()).await?;
let node2 = P2PNode::new(NodeConfig::builder().port(9031).build()).await?;
let node1_addr = node1.listen_addrs().await?[0].clone();
let node2_id = node2.peer_id();
for i in 0..10 {
println!("Stress test iteration {}", i);
node2.connect_peer(&node1_addr.to_string()).await?;
assert!(node1.is_connected(&node2_id).await?);
node1.disconnect(&node2_id).await?;
tokio::time::sleep(Duration::from_millis(100)).await;
assert!(!node1.is_connected(&node2_id).await?);
}
node1.stop().await?;
node2.stop().await?;
Ok(())
}