use ftr::{Ftr, TracerouteConfigBuilder};
use std::sync::Arc;
use tokio::task::JoinSet;
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
async fn test_parallel_ftr_instances() {
let mut tasks = JoinSet::new();
for i in 0..10 {
tasks.spawn(async move {
let ftr = Ftr::new();
let config = TracerouteConfigBuilder::new()
.target("127.0.0.1")
.max_hops(3)
.enable_asn_lookup(true)
.enable_rdns(true)
.build()
.unwrap();
let result = ftr.trace_with_config(config).await;
(i, result.is_ok())
});
}
let mut results = Vec::new();
while let Some(result) = tasks.join_next().await {
match result {
Ok((id, success)) => {
results.push((id, success));
}
Err(e) => {
eprintln!("Task failed: {}", e);
}
}
}
assert_eq!(results.len(), 10);
println!("Successfully ran {} parallel Ftr instances", results.len());
}
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
async fn test_cache_isolation_between_instances() {
let ftr1 = Arc::new(Ftr::new());
let ftr2 = Arc::new(Ftr::new());
let target = "8.8.8.8";
let ftr1_clone = ftr1.clone();
let ftr2_clone = ftr2.clone();
let (result1, result2) = tokio::join!(
async move {
let config = TracerouteConfigBuilder::new()
.target(target)
.max_hops(5)
.enable_asn_lookup(true)
.enable_rdns(true)
.build()
.unwrap();
ftr1_clone.trace_with_config(config).await
},
async move {
let config = TracerouteConfigBuilder::new()
.target(target)
.max_hops(5)
.enable_asn_lookup(true)
.enable_rdns(true)
.build()
.unwrap();
ftr2_clone.trace_with_config(config).await
}
);
match (&result1, &result2) {
(Ok(_), Ok(_)) => {
println!("Both instances completed successfully");
}
_ => {
eprintln!("Some traces failed (acceptable in test environment)");
}
}
assert_eq!(result1.is_ok(), result2.is_ok());
}
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
async fn test_high_concurrency_no_interference() {
let ftr = Arc::new(Ftr::new());
let mut tasks = JoinSet::new();
for i in 0..50 {
let ftr_clone = ftr.clone();
let target = if i % 2 == 0 { "127.0.0.1" } else { "::1" };
tasks.spawn(async move {
let config = TracerouteConfigBuilder::new()
.target(target)
.max_hops(2)
.enable_asn_lookup(false) .enable_rdns(false) .build()
.unwrap();
let result = ftr_clone.trace_with_config(config).await;
result.is_ok()
});
}
let mut success_count = 0;
let mut failure_count = 0;
while let Some(result) = tasks.join_next().await {
match result {
Ok(true) => success_count += 1,
Ok(false) => failure_count += 1,
Err(e) => eprintln!("Task panicked: {}", e),
}
}
println!(
"High concurrency test: {} succeeded, {} failed out of 50",
success_count, failure_count
);
assert!(success_count > 0 || failure_count == 50); }
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
async fn test_separate_instances_separate_caches() {
let ftr1 = Ftr::new();
let ftr2 = Ftr::new();
let config1 = TracerouteConfigBuilder::new()
.target("192.168.1.1") .max_hops(1)
.enable_asn_lookup(true)
.build()
.unwrap();
let config2 = TracerouteConfigBuilder::new()
.target("10.0.0.1") .max_hops(1)
.enable_asn_lookup(true)
.build()
.unwrap();
let result1 = ftr1.trace_with_config(config1.clone()).await;
let result2 = ftr2.trace_with_config(config2.clone()).await;
println!(
"Instance 1: {}, Instance 2: {}",
if result1.is_ok() { "OK" } else { "Failed" },
if result2.is_ok() { "OK" } else { "Failed" }
);
let result1_second = ftr1.trace_with_config(config1).await;
let result2_second = ftr2.trace_with_config(config2).await;
assert_eq!(result1.is_ok(), result1_second.is_ok());
assert_eq!(result2.is_ok(), result2_second.is_ok());
}
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
async fn test_stress_test_cache_isolation() {
let mut instances = Vec::new();
for _ in 0..20 {
instances.push(Arc::new(Ftr::new()));
}
let mut tasks = JoinSet::new();
for (idx, ftr) in instances.into_iter().enumerate() {
for j in 0..5 {
let ftr_clone = ftr.clone();
tasks.spawn(async move {
let target = match (idx + j) % 3 {
0 => "127.0.0.1",
1 => "192.168.1.1",
_ => "10.0.0.1",
};
let config = TracerouteConfigBuilder::new()
.target(target)
.max_hops(1)
.build()
.unwrap();
ftr_clone.trace_with_config(config).await.is_ok()
});
}
}
let mut completed = 0;
while let Some(result) = tasks.join_next().await {
if result.is_ok() {
completed += 1;
}
}
println!("Stress test: {} operations completed", completed);
assert_eq!(completed, 100); }