use std::io;
use std::net::IpAddr;
use std::time::Duration;
use ping_async::{IcmpEchoRequestor, IcmpEchoStatus};
#[tokio::test]
async fn test_multiple_requestors_same_target() {
let req1 = IcmpEchoRequestor::new("127.0.0.1".parse().unwrap(), None, None, None).unwrap();
let req2 = IcmpEchoRequestor::new("127.0.0.1".parse().unwrap(), None, None, None).unwrap();
let (result1, result2) = tokio::join!(req1.send(), req2.send());
assert!(result1.is_ok(), "First requestor should succeed");
assert!(result2.is_ok(), "Second requestor should succeed");
let reply1 = result1.unwrap();
let reply2 = result2.unwrap();
assert_eq!(reply1.destination(), "127.0.0.1".parse::<IpAddr>().unwrap());
assert_eq!(reply2.destination(), "127.0.0.1".parse::<IpAddr>().unwrap());
}
#[tokio::test]
async fn test_high_concurrency() {
let req = IcmpEchoRequestor::new("127.0.0.1".parse().unwrap(), None, None, None).unwrap();
let futures: Vec<_> = (0..50).map(|_| req.send()).collect();
let results = futures::future::join_all(futures).await;
assert_eq!(results.len(), 50);
let success_count = results.iter().filter(|r| r.is_ok()).count();
assert!(
success_count > 40,
"Most loopback pings should succeed, got {success_count}/50"
);
}
#[tokio::test]
async fn test_rapid_firing() {
let req = IcmpEchoRequestor::new("127.0.0.1".parse().unwrap(), None, None, None).unwrap();
for i in 0..20 {
let result = req.send().await;
assert!(result.is_ok(), "Request {i} should succeed");
}
}
#[tokio::test]
async fn test_error_mapping() {
let invalid_req = IcmpEchoRequestor::new(
"8.8.8.8".parse().unwrap(), Some("::1".parse().unwrap()), None,
None,
);
match invalid_req {
Err(error) => {
assert_eq!(error.kind(), io::ErrorKind::InvalidInput);
assert!(error.to_string().contains("does not match"));
}
Ok(_) => panic!("IPv4 target with IPv6 source should fail"),
}
}
#[tokio::test]
async fn test_timeout_behavior() {
let req = IcmpEchoRequestor::new(
"192.0.2.1".parse().unwrap(), None,
None,
Some(Duration::from_millis(1000)), )
.unwrap();
let start = std::time::Instant::now();
let result = req.send().await.unwrap();
let elapsed = start.elapsed();
assert_eq!(result.status(), IcmpEchoStatus::TimedOut);
assert!(
elapsed >= Duration::from_millis(500),
"Should wait at least 500ms"
);
assert!(
elapsed < Duration::from_millis(1500),
"Should timeout within 1s"
);
}
#[tokio::test]
async fn test_icmp_creation() {
let ipv4_req = IcmpEchoRequestor::new("8.8.8.8".parse().unwrap(), None, None, None);
let ipv6_req =
IcmpEchoRequestor::new("2001:4860:4860::8888".parse().unwrap(), None, None, None);
match (ipv4_req, ipv6_req) {
(Ok(_), Ok(_)) => {
println!("Both IPv4 and IPv6 ICMP creation successful");
}
(Err(e), _) | (_, Err(e)) => {
println!("ICMP creation failed (may need elevation): {e}");
}
}
}