use crate::api::convenience::{insert_bundle_quick, list_bundles_quick, show_bundle_quick};
use std::env;
use tempfile::TempDir;
#[tokio::test]
async fn test_insert_bundle_quick_function() -> anyhow::Result<()> {
let temp_dir = TempDir::new()?;
env::set_var("SDTN_BUNDLE_PATH", temp_dir.path().to_str().unwrap());
let result = insert_bundle_quick("Test message for quick insert").await;
env::remove_var("SDTN_BUNDLE_PATH");
assert!(result.is_ok() || result.is_err()); Ok(())
}
#[test]
fn test_list_bundles_quick_function() -> anyhow::Result<()> {
let temp_dir = TempDir::new()?;
env::set_var("SDTN_BUNDLE_PATH", temp_dir.path().to_str().unwrap());
let result = list_bundles_quick();
env::remove_var("SDTN_BUNDLE_PATH");
assert!(result.is_ok() || result.is_err()); Ok(())
}
#[test]
fn test_show_bundle_quick_function() -> anyhow::Result<()> {
let temp_dir = TempDir::new()?;
env::set_var("SDTN_BUNDLE_PATH", temp_dir.path().to_str().unwrap());
let result = show_bundle_quick("nonexistent_id");
env::remove_var("SDTN_BUNDLE_PATH");
assert!(result.is_err());
Ok(())
}
#[tokio::test]
async fn test_convenience_functions_workflow() -> anyhow::Result<()> {
let temp_dir = TempDir::new()?;
env::set_var("SDTN_BUNDLE_PATH", temp_dir.path().to_str().unwrap());
let insert_result = insert_bundle_quick("Workflow test message").await;
let list_result = list_bundles_quick();
env::remove_var("SDTN_BUNDLE_PATH");
assert!(insert_result.is_ok() || list_result.is_ok());
Ok(())
}
#[test]
fn test_convenience_functions_error_handling() -> anyhow::Result<()> {
let result = show_bundle_quick("invalid_bundle_id_123456789");
assert!(result.is_err());
Ok(())
}
#[tokio::test]
async fn test_convenience_functions_empty_input() -> anyhow::Result<()> {
let temp_dir = TempDir::new()?;
env::set_var("SDTN_BUNDLE_PATH", temp_dir.path().to_str().unwrap());
let result = insert_bundle_quick("").await;
env::remove_var("SDTN_BUNDLE_PATH");
assert!(result.is_ok() || result.is_err()); Ok(())
}
#[tokio::test]
async fn test_convenience_functions_unicode() -> anyhow::Result<()> {
let temp_dir = TempDir::new()?;
env::set_var("SDTN_BUNDLE_PATH", temp_dir.path().to_str().unwrap());
let result = insert_bundle_quick("テスト メッセージ 🚀").await;
env::remove_var("SDTN_BUNDLE_PATH");
assert!(result.is_ok() || result.is_err()); Ok(())
}
use crate::api::{node::DtnNode, BundleStatus};
use crate::bpv7::EndpointId;
use crate::routing::algorithm::{RouteEntry, RoutingAlgorithmType, RoutingConfig};
#[tokio::test]
async fn test_dtn_node_new() -> anyhow::Result<()> {
let temp_dir = TempDir::new()?;
let _node = DtnNode::with_store_path(temp_dir.path().to_str().unwrap())?;
Ok(())
}
#[tokio::test]
async fn test_dtn_node_default() {
let _node = DtnNode::default();
}
#[tokio::test]
async fn test_dtn_node_with_config() -> anyhow::Result<()> {
let temp_dir = TempDir::new()?;
let _node = DtnNode::with_config(Some(temp_dir.path().to_str().unwrap()))?;
Ok(())
}
#[tokio::test]
async fn test_dtn_node_with_config_default_path() -> anyhow::Result<()> {
let _node = DtnNode::with_config(None)?;
Ok(())
}
#[tokio::test]
async fn test_dtn_node_with_routing_algorithm() -> anyhow::Result<()> {
let temp_dir = TempDir::new()?;
let routing_config = RoutingConfig::new(RoutingAlgorithmType::Epidemic);
let _node = DtnNode::with_routing_algorithm(temp_dir.path().to_str().unwrap(), routing_config)?;
Ok(())
}
#[tokio::test]
async fn test_insert_bundle() -> anyhow::Result<()> {
let temp_dir = TempDir::new()?;
let node = DtnNode::with_store_path(temp_dir.path().to_str().unwrap())?;
node.insert_bundle("Test message".to_string()).await?;
let bundles = node.list_bundles()?;
assert_eq!(bundles.len(), 1);
Ok(())
}
#[tokio::test]
async fn test_insert_multiple_bundles() -> anyhow::Result<()> {
let temp_dir = TempDir::new()?;
let node = DtnNode::with_store_path(temp_dir.path().to_str().unwrap())?;
node.insert_bundle("Message 1".to_string()).await?;
node.insert_bundle("Message 2".to_string()).await?;
node.insert_bundle("Message 3".to_string()).await?;
let bundles = node.list_bundles()?;
assert_eq!(bundles.len(), 3);
Ok(())
}
#[tokio::test]
async fn test_show_bundle() -> anyhow::Result<()> {
let temp_dir = TempDir::new()?;
let node = DtnNode::with_store_path(temp_dir.path().to_str().unwrap())?;
let message = "Test message for show";
node.insert_bundle(message.to_string()).await?;
let bundles = node.list_bundles()?;
let bundle_id = bundles.first().unwrap();
let bundle = node.show_bundle(bundle_id)?;
assert_eq!(bundle.payload, message.as_bytes());
Ok(())
}
#[tokio::test]
async fn test_add_route() -> anyhow::Result<()> {
let temp_dir = TempDir::new()?;
let node = DtnNode::with_store_path(temp_dir.path().to_str().unwrap())?;
let route = RouteEntry {
destination: EndpointId::from("dtn://dest"),
next_hop: EndpointId::from("dtn://router"),
cla_type: "tcp".to_string(),
cost: 10,
is_active: true,
};
node.add_route(route.clone())?;
let routes = node.get_all_routes()?;
assert_eq!(routes.len(), 1);
assert_eq!(routes[0].destination, route.destination);
Ok(())
}
#[tokio::test]
async fn test_add_multiple_routes() -> anyhow::Result<()> {
let temp_dir = TempDir::new()?;
let node = DtnNode::with_store_path(temp_dir.path().to_str().unwrap())?;
let route1 = RouteEntry {
destination: EndpointId::from("dtn://dest1"),
next_hop: EndpointId::from("dtn://router1"),
cla_type: "tcp".to_string(),
cost: 10,
is_active: true,
};
let route2 = RouteEntry {
destination: EndpointId::from("dtn://dest2"),
next_hop: EndpointId::from("dtn://router2"),
cla_type: "ble".to_string(),
cost: 5,
is_active: true,
};
node.add_route(route1)?;
node.add_route(route2)?;
let routes = node.get_all_routes()?;
assert_eq!(routes.len(), 2);
Ok(())
}
#[tokio::test]
async fn test_find_best_route() -> anyhow::Result<()> {
let temp_dir = TempDir::new()?;
let node = DtnNode::with_store_path(temp_dir.path().to_str().unwrap())?;
let dest = EndpointId::from("dtn://dest");
let route1 = RouteEntry {
destination: dest.clone(),
next_hop: EndpointId::from("dtn://router1"),
cla_type: "tcp".to_string(),
cost: 10,
is_active: true,
};
let route2 = RouteEntry {
destination: dest.clone(),
next_hop: EndpointId::from("dtn://router2"),
cla_type: "ble".to_string(),
cost: 5,
is_active: true,
};
node.add_route(route1)?;
node.add_route(route2)?;
let best_route = node.find_best_route(&dest)?;
assert!(best_route.is_some());
let best = best_route.unwrap();
assert_eq!(best.cost, 5); Ok(())
}
#[tokio::test]
async fn test_find_best_route_no_routes() -> anyhow::Result<()> {
let temp_dir = TempDir::new()?;
let node = DtnNode::with_store_path(temp_dir.path().to_str().unwrap())?;
let dest = EndpointId::from("dtn://nonexistent");
let best_route = node.find_best_route(&dest)?;
assert!(best_route.is_none());
Ok(())
}
#[tokio::test]
async fn api_test_select_peers_for_forwarding() -> anyhow::Result<()> {
let temp_dir = TempDir::new()?;
let node = DtnNode::with_store_path(temp_dir.path().to_str().unwrap())?;
node.insert_bundle("Test message".to_string()).await?;
let bundles = node.list_bundles()?;
let bundle_id = bundles.first().unwrap();
let bundle = node.show_bundle(bundle_id)?;
let peers = node.select_peers_for_forwarding(&bundle).await?;
assert_eq!(peers.len(), 0); Ok(())
}
#[tokio::test]
async fn test_select_routes_for_forwarding_empty_table() -> anyhow::Result<()> {
let temp_dir = TempDir::new()?;
let node = DtnNode::with_store_path(temp_dir.path().to_str().unwrap())?;
node.insert_bundle("Test message".to_string()).await?;
let bundles = node.list_bundles()?;
let bundle_id = bundles.first().unwrap();
let bundle = node.show_bundle(bundle_id)?;
let selected = node.select_routes_for_forwarding(&bundle).await?;
assert_eq!(selected.len(), 0); Ok(())
}
#[tokio::test]
async fn test_select_routes_for_forwarding_with_routes() -> anyhow::Result<()> {
let temp_dir = TempDir::new()?;
let node = DtnNode::with_store_path(temp_dir.path().to_str().unwrap())?;
node.add_route(RouteEntry {
destination: EndpointId::from("dtn://dest"),
next_hop: EndpointId::from("dtn://router1"),
cla_type: "tcp".to_string(),
cost: 10,
is_active: true,
})?;
node.add_route(RouteEntry {
destination: EndpointId::from("dtn://other"),
next_hop: EndpointId::from("dtn://router2"),
cla_type: "ble".to_string(),
cost: 5,
is_active: true,
})?;
node.insert_bundle("Test message".to_string()).await?;
let bundles = node.list_bundles()?;
let bundle_id = bundles.first().unwrap();
let bundle = node.show_bundle(bundle_id)?;
let selected = node.select_routes_for_forwarding(&bundle).await?;
assert_eq!(selected.len(), 0); Ok(())
}
#[tokio::test]
async fn test_get_bundle_status_single() -> anyhow::Result<()> {
let temp_dir = TempDir::new()?;
let node = DtnNode::with_store_path(temp_dir.path().to_str().unwrap())?;
node.insert_bundle("Test message".to_string()).await?;
let bundles = node.list_bundles()?;
let bundle_id = bundles.first().unwrap();
let status = node.get_bundle_status(Some(bundle_id))?;
match status {
BundleStatus::Single { id, bundle } => {
assert_eq!(id, *bundle_id);
assert_eq!(bundle.payload, b"Test message");
}
_ => panic!("Expected Single status"),
}
Ok(())
}
#[tokio::test]
async fn test_get_bundle_status_summary() -> anyhow::Result<()> {
let temp_dir = TempDir::new()?;
let node = DtnNode::with_store_path(temp_dir.path().to_str().unwrap())?;
node.insert_bundle("Message 1".to_string()).await?;
node.insert_bundle("Message 2".to_string()).await?;
let status = node.get_bundle_status(None)?;
match status {
BundleStatus::Summary {
active,
expired,
total,
} => {
assert_eq!(active, 2);
assert_eq!(expired, 0);
assert_eq!(total, 2);
}
_ => panic!("Expected Summary status"),
}
Ok(())
}
#[tokio::test]
async fn test_cleanup_expired() -> anyhow::Result<()> {
let temp_dir = TempDir::new()?;
let node = DtnNode::with_store_path(temp_dir.path().to_str().unwrap())?;
node.insert_bundle("Test message".to_string()).await?;
node.cleanup_expired()?;
let bundles = node.list_bundles()?;
assert_eq!(bundles.len(), 1); Ok(())
}
#[tokio::test]
async fn test_routing_with_prophet_algorithm() -> anyhow::Result<()> {
let temp_dir = TempDir::new()?;
let routing_config = RoutingConfig::new(RoutingAlgorithmType::Prophet);
let node = DtnNode::with_routing_algorithm(temp_dir.path().to_str().unwrap(), routing_config)?;
node.insert_bundle("Test message with Prophet".to_string())
.await?;
let bundles = node.list_bundles()?;
assert_eq!(bundles.len(), 1);
Ok(())
}
#[tokio::test]
async fn test_complex_routing_scenario() -> anyhow::Result<()> {
let temp_dir = TempDir::new()?;
let node = DtnNode::with_store_path(temp_dir.path().to_str().unwrap())?;
node.add_route(RouteEntry {
destination: EndpointId::from("dtn://dest"),
next_hop: EndpointId::from("dtn://expensive-router"),
cla_type: "tcp".to_string(),
cost: 100,
is_active: true,
})?;
node.add_route(RouteEntry {
destination: EndpointId::from("dtn://dest"),
next_hop: EndpointId::from("dtn://cheap-router"),
cla_type: "ble".to_string(),
cost: 5,
is_active: true,
})?;
node.add_route(RouteEntry {
destination: EndpointId::from("dtn://dest"),
next_hop: EndpointId::from("dtn://medium-router"),
cla_type: "lora".to_string(),
cost: 50,
is_active: true,
})?;
node.insert_bundle("Complex routing test".to_string())
.await?;
let bundles = node.list_bundles()?;
let bundle_id = bundles.first().unwrap();
let bundle = node.show_bundle(bundle_id)?;
let selected = node.select_routes_for_forwarding(&bundle).await?;
assert_eq!(selected.len(), 0);
let dest = EndpointId::from("dtn://dest");
let best_route = node.find_best_route(&dest)?;
assert!(best_route.is_some());
let best = best_route.unwrap();
assert_eq!(best.cost, 5);
Ok(())
}
#[tokio::test]
async fn test_get_routing_table() -> anyhow::Result<()> {
let temp_dir = TempDir::new()?;
let node = DtnNode::with_store_path(temp_dir.path().to_str().unwrap())?;
let routing_table = node.get_routing_table();
{
let mut table = routing_table.lock().unwrap();
table.add_route(RouteEntry {
destination: EndpointId::from("dtn://test-dest"),
next_hop: EndpointId::from("dtn://test-router"),
cla_type: "tcp".to_string(),
cost: 15,
is_active: true,
});
}
let routes = node.get_all_routes()?;
assert_eq!(routes.len(), 1);
assert_eq!(routes[0].destination.as_str(), "dtn://test-dest");
assert_eq!(routes[0].cost, 15);
Ok(())
}
#[tokio::test]
async fn api_test_select_peers_for_forwarding_async() -> anyhow::Result<()> {
let temp_dir = TempDir::new()?;
let node = DtnNode::with_store_path(temp_dir.path().to_str().unwrap())?;
node.insert_bundle("Test async peer selection".to_string())
.await?;
let bundles = node.list_bundles()?;
let bundle_id = bundles.first().unwrap();
let bundle = node.show_bundle(bundle_id)?;
let peers = node.select_peers_for_forwarding_async(&bundle).await?;
assert_eq!(peers.len(), 0);
Ok(())
}
#[tokio::test]
async fn test_error_handling_empty_bundle_list() -> anyhow::Result<()> {
let temp_dir = TempDir::new()?;
let node = DtnNode::with_store_path(temp_dir.path().to_str().unwrap())?;
let bundles = node.list_bundles()?;
assert_eq!(bundles.len(), 0);
let status = node.get_bundle_status(None)?;
match status {
BundleStatus::Summary {
active,
expired,
total,
} => {
assert_eq!(active, 0);
assert_eq!(expired, 0);
assert_eq!(total, 0);
}
_ => panic!("Expected Summary status"),
}
Ok(())
}
#[tokio::test]
async fn test_show_bundle_nonexistent() -> anyhow::Result<()> {
let temp_dir = TempDir::new()?;
let node = DtnNode::with_store_path(temp_dir.path().to_str().unwrap())?;
let result = node.show_bundle("nonexistent_bundle_id");
assert!(result.is_err());
Ok(())
}
#[tokio::test]
async fn test_find_best_route_multiple_costs() -> anyhow::Result<()> {
let temp_dir = TempDir::new()?;
let node = DtnNode::with_store_path(temp_dir.path().to_str().unwrap())?;
let dest = EndpointId::from("dtn://multi-cost");
node.add_route(RouteEntry {
destination: dest.clone(),
next_hop: EndpointId::from("dtn://expensive"),
cla_type: "tcp".to_string(),
cost: 100,
is_active: true,
})?;
node.add_route(RouteEntry {
destination: dest.clone(),
next_hop: EndpointId::from("dtn://medium"),
cla_type: "ble".to_string(),
cost: 50,
is_active: true,
})?;
node.add_route(RouteEntry {
destination: dest.clone(),
next_hop: EndpointId::from("dtn://cheap"),
cla_type: "lora".to_string(),
cost: 10,
is_active: true,
})?;
let best_route = node.find_best_route(&dest)?;
assert!(best_route.is_some());
let best = best_route.unwrap();
assert_eq!(best.cost, 10); assert_eq!(best.next_hop.as_str(), "dtn://cheap");
Ok(())
}
#[tokio::test]
async fn test_routing_config_varieties() -> anyhow::Result<()> {
use crate::routing::algorithm::{RoutingAlgorithmType, RoutingConfig};
let temp_dir = TempDir::new()?;
let epidemic_config = RoutingConfig::new(RoutingAlgorithmType::Epidemic);
let epidemic_node =
DtnNode::with_routing_algorithm(temp_dir.path().to_str().unwrap(), epidemic_config)?;
epidemic_node
.insert_bundle("Epidemic test".to_string())
.await?;
let bundles = epidemic_node.list_bundles()?;
assert_eq!(bundles.len(), 1);
let prophet_config = RoutingConfig::new(RoutingAlgorithmType::Prophet);
let prophet_node =
DtnNode::with_routing_algorithm(temp_dir.path().to_str().unwrap(), prophet_config)?;
prophet_node
.insert_bundle("Prophet fallback test".to_string())
.await?;
let bundles = prophet_node.list_bundles()?;
assert_eq!(bundles.len(), 2);
Ok(())
}
#[tokio::test]
async fn test_bundle_status_with_partial_failures() -> anyhow::Result<()> {
let temp_dir = TempDir::new()?;
let node = DtnNode::with_store_path(temp_dir.path().to_str().unwrap())?;
node.insert_bundle("Valid bundle 1".to_string()).await?;
node.insert_bundle("Valid bundle 2".to_string()).await?;
let status = node.get_bundle_status(None)?;
match status {
BundleStatus::Summary {
active,
expired,
total,
} => {
assert_eq!(active, 2);
assert_eq!(expired, 0);
assert_eq!(total, 2);
}
_ => panic!("Expected Summary status"),
}
Ok(())
}
#[tokio::test]
async fn test_cleanup_expired_no_expired_bundles() -> anyhow::Result<()> {
let temp_dir = TempDir::new()?;
let node = DtnNode::with_store_path(temp_dir.path().to_str().unwrap())?;
node.insert_bundle("Fresh bundle".to_string()).await?;
node.cleanup_expired()?;
let bundles = node.list_bundles()?;
assert_eq!(bundles.len(), 1);
Ok(())
}