Skip to content

Commit 6d42c92

Browse files
committed
feat(tests): Enhance routing and peer selection tests for improved coverage
- Refactored existing tests for better clarity and consistency, including renaming functions for better context. - Added new tests for routing table retrieval, error handling with empty bundles, and best route selection with multiple costs. - Implemented asynchronous tests for peer selection, ensuring only reachable peers are selected. - Improved assertions in tests to validate expected outcomes more effectively. These changes enhance the robustness of the testing framework, ensuring comprehensive coverage of routing and peer management functionalities.
1 parent 6ad2d43 commit 6d42c92

File tree

3 files changed

+410
-4
lines changed

3 files changed

+410
-4
lines changed

src/api/tests.rs

Lines changed: 205 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,8 @@ async fn test_find_best_route() -> anyhow::Result<()> {
285285

286286
let best_route = node.find_best_route(&dest)?;
287287
assert!(best_route.is_some());
288-
assert_eq!(best_route.unwrap().cost, 5); // Should be the cheaper route
288+
let best = best_route.unwrap();
289+
assert_eq!(best.cost, 5); // Should be the cheaper route
289290
Ok(())
290291
}
291292

@@ -301,7 +302,7 @@ async fn test_find_best_route_no_routes() -> anyhow::Result<()> {
301302
}
302303

303304
#[tokio::test]
304-
async fn test_select_peers_for_forwarding() -> anyhow::Result<()> {
305+
async fn api_test_select_peers_for_forwarding() -> anyhow::Result<()> {
305306
let temp_dir = TempDir::new()?;
306307
let node = DtnNode::with_store_path(temp_dir.path().to_str().unwrap())?;
307308

@@ -485,7 +486,208 @@ async fn test_complex_routing_scenario() -> anyhow::Result<()> {
485486
let dest = EndpointId::from("dtn://dest");
486487
let best_route = node.find_best_route(&dest)?;
487488
assert!(best_route.is_some());
488-
assert_eq!(best_route.unwrap().cost, 5); // Should be the cheapest
489+
let best = best_route.unwrap();
490+
assert_eq!(best.cost, 5); // Should be the cheapest
491+
492+
Ok(())
493+
}
494+
495+
#[tokio::test]
496+
async fn test_get_routing_table() -> anyhow::Result<()> {
497+
let temp_dir = TempDir::new()?;
498+
let node = DtnNode::with_store_path(temp_dir.path().to_str().unwrap())?;
499+
500+
// Test getting routing table reference
501+
let routing_table = node.get_routing_table();
502+
503+
// Add a route through the reference
504+
{
505+
let mut table = routing_table.lock().unwrap();
506+
table.add_route(RouteEntry {
507+
destination: EndpointId::from("dtn://test-dest"),
508+
next_hop: EndpointId::from("dtn://test-router"),
509+
cla_type: "tcp".to_string(),
510+
cost: 15,
511+
is_active: true,
512+
});
513+
}
514+
515+
// Verify through node's get_all_routes
516+
let routes = node.get_all_routes()?;
517+
assert_eq!(routes.len(), 1);
518+
assert_eq!(routes[0].destination.as_str(), "dtn://test-dest");
519+
assert_eq!(routes[0].cost, 15);
520+
521+
Ok(())
522+
}
523+
524+
#[tokio::test]
525+
async fn api_test_select_peers_for_forwarding_async() -> anyhow::Result<()> {
526+
let temp_dir = TempDir::new()?;
527+
let node = DtnNode::with_store_path(temp_dir.path().to_str().unwrap())?;
528+
529+
node.insert_bundle("Test async peer selection".to_string())
530+
.await?;
531+
532+
let bundles = node.list_bundles()?;
533+
let bundle_id = bundles.first().unwrap();
534+
let bundle = node.show_bundle(bundle_id)?;
535+
536+
let peers = node.select_peers_for_forwarding_async(&bundle).await?;
537+
assert_eq!(peers.len(), 0); // No reachable peers expected in this environment
538+
539+
Ok(())
540+
}
541+
542+
#[tokio::test]
543+
async fn test_error_handling_empty_bundle_list() -> anyhow::Result<()> {
544+
let temp_dir = TempDir::new()?;
545+
let node = DtnNode::with_store_path(temp_dir.path().to_str().unwrap())?;
546+
547+
// Test with empty bundle store
548+
let bundles = node.list_bundles()?;
549+
assert_eq!(bundles.len(), 0);
550+
551+
// Test status with no bundles
552+
let status = node.get_bundle_status(None)?;
553+
match status {
554+
BundleStatus::Summary {
555+
active,
556+
expired,
557+
total,
558+
} => {
559+
assert_eq!(active, 0);
560+
assert_eq!(expired, 0);
561+
assert_eq!(total, 0);
562+
}
563+
_ => panic!("Expected Summary status"),
564+
}
565+
566+
Ok(())
567+
}
568+
569+
#[tokio::test]
570+
async fn test_show_bundle_nonexistent() -> anyhow::Result<()> {
571+
let temp_dir = TempDir::new()?;
572+
let node = DtnNode::with_store_path(temp_dir.path().to_str().unwrap())?;
573+
574+
// Test showing non-existent bundle
575+
let result = node.show_bundle("nonexistent_bundle_id");
576+
assert!(result.is_err());
577+
578+
Ok(())
579+
}
580+
581+
#[tokio::test]
582+
async fn test_find_best_route_multiple_costs() -> anyhow::Result<()> {
583+
let temp_dir = TempDir::new()?;
584+
let node = DtnNode::with_store_path(temp_dir.path().to_str().unwrap())?;
585+
586+
let dest = EndpointId::from("dtn://multi-cost");
587+
588+
// Add routes with different costs
589+
node.add_route(RouteEntry {
590+
destination: dest.clone(),
591+
next_hop: EndpointId::from("dtn://expensive"),
592+
cla_type: "tcp".to_string(),
593+
cost: 100,
594+
is_active: true,
595+
})?;
596+
597+
node.add_route(RouteEntry {
598+
destination: dest.clone(),
599+
next_hop: EndpointId::from("dtn://medium"),
600+
cla_type: "ble".to_string(),
601+
cost: 50,
602+
is_active: true,
603+
})?;
604+
605+
node.add_route(RouteEntry {
606+
destination: dest.clone(),
607+
next_hop: EndpointId::from("dtn://cheap"),
608+
cla_type: "lora".to_string(),
609+
cost: 10,
610+
is_active: true,
611+
})?;
612+
613+
let best_route = node.find_best_route(&dest)?;
614+
assert!(best_route.is_some());
615+
let best = best_route.unwrap();
616+
assert_eq!(best.cost, 10); // Should be the cheapest
617+
assert_eq!(best.next_hop.as_str(), "dtn://cheap");
618+
619+
Ok(())
620+
}
621+
622+
#[tokio::test]
623+
async fn test_routing_config_varieties() -> anyhow::Result<()> {
624+
use crate::routing::algorithm::{RoutingAlgorithmType, RoutingConfig};
625+
let temp_dir = TempDir::new()?;
626+
627+
// Test with Epidemic routing
628+
let epidemic_config = RoutingConfig::new(RoutingAlgorithmType::Epidemic);
629+
let epidemic_node =
630+
DtnNode::with_routing_algorithm(temp_dir.path().to_str().unwrap(), epidemic_config)?;
631+
632+
epidemic_node
633+
.insert_bundle("Epidemic test".to_string())
634+
.await?;
635+
let bundles = epidemic_node.list_bundles()?;
636+
assert_eq!(bundles.len(), 1);
637+
638+
// Test with Prophet routing (should fall back to epidemic)
639+
let prophet_config = RoutingConfig::new(RoutingAlgorithmType::Prophet);
640+
let prophet_node =
641+
DtnNode::with_routing_algorithm(temp_dir.path().to_str().unwrap(), prophet_config)?;
642+
643+
prophet_node
644+
.insert_bundle("Prophet fallback test".to_string())
645+
.await?;
646+
let bundles = prophet_node.list_bundles()?;
647+
assert_eq!(bundles.len(), 2); // Same store as epidemic_node
648+
649+
Ok(())
650+
}
651+
652+
#[tokio::test]
653+
async fn test_bundle_status_with_partial_failures() -> anyhow::Result<()> {
654+
let temp_dir = TempDir::new()?;
655+
let node = DtnNode::with_store_path(temp_dir.path().to_str().unwrap())?;
656+
657+
// Insert valid bundles
658+
node.insert_bundle("Valid bundle 1".to_string()).await?;
659+
node.insert_bundle("Valid bundle 2".to_string()).await?;
660+
661+
let status = node.get_bundle_status(None)?;
662+
match status {
663+
BundleStatus::Summary {
664+
active,
665+
expired,
666+
total,
667+
} => {
668+
assert_eq!(active, 2);
669+
assert_eq!(expired, 0);
670+
assert_eq!(total, 2);
671+
}
672+
_ => panic!("Expected Summary status"),
673+
}
674+
675+
Ok(())
676+
}
677+
678+
#[tokio::test]
679+
async fn test_cleanup_expired_no_expired_bundles() -> anyhow::Result<()> {
680+
let temp_dir = TempDir::new()?;
681+
let node = DtnNode::with_store_path(temp_dir.path().to_str().unwrap())?;
682+
683+
// Insert fresh bundles (not expired)
684+
node.insert_bundle("Fresh bundle".to_string()).await?;
685+
686+
// Cleanup should succeed without removing anything
687+
node.cleanup_expired()?;
688+
689+
let bundles = node.list_bundles()?;
690+
assert_eq!(bundles.len(), 1); // Bundle should still be there
489691

490692
Ok(())
491693
}

src/cla/tests.rs

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ use crate::cla::manager::*;
7070
use crate::cla::tcp::client::*;
7171
use crate::cla::tcp::server::*;
7272
use crate::consts::tcp::*;
73+
use crate::routing::algorithm::ClaPeer;
7374
use async_trait::async_trait;
7475
use std::sync::atomic::{AtomicUsize, Ordering};
7576
use std::sync::Arc;
@@ -953,3 +954,156 @@ fn test_create_test_bundle_various_payloads() {
953954
assert_eq!(bundle.payload, payload);
954955
}
955956
}
957+
958+
// TcpPeer tests for better coverage
959+
#[test]
960+
fn test_tcp_peer_new() {
961+
let eid = crate::bpv7::EndpointId::from("dtn://test-peer");
962+
let peer = crate::cla::TcpPeer::new(eid.clone(), "192.168.1.100:8080".to_string());
963+
964+
assert_eq!(peer.peer_id, eid);
965+
assert_eq!(peer.address, "192.168.1.100:8080");
966+
}
967+
968+
#[test]
969+
fn test_tcp_peer_from_endpoint_id() {
970+
let eid = crate::bpv7::EndpointId::from("dtn://test-node");
971+
let peer = crate::cla::TcpPeer::from_endpoint_id(eid.clone());
972+
973+
assert_eq!(peer.peer_id, eid);
974+
assert_eq!(peer.address, "dtn://test-node");
975+
}
976+
977+
#[test]
978+
fn test_tcp_peer_for_test() {
979+
let eid = crate::bpv7::EndpointId::from("dtn://test-endpoint");
980+
let peer = crate::cla::TcpPeer::for_test(eid.clone());
981+
982+
assert_eq!(peer.peer_id, eid);
983+
assert_eq!(peer.address, "dtn://test-endpoint");
984+
}
985+
986+
#[test]
987+
fn test_tcp_peer_get_peer_endpoint_id() {
988+
let eid = crate::bpv7::EndpointId::from("dtn://my-peer");
989+
let peer = crate::cla::TcpPeer::new(eid.clone(), "10.0.0.1:9090".to_string());
990+
991+
assert_eq!(peer.get_peer_endpoint_id(), eid);
992+
}
993+
994+
#[test]
995+
fn test_tcp_peer_get_cla_type() {
996+
let eid = crate::bpv7::EndpointId::from("dtn://any-peer");
997+
let peer = crate::cla::TcpPeer::new(eid, "localhost:8080".to_string());
998+
999+
assert_eq!(peer.get_cla_type(), "tcp");
1000+
}
1001+
1002+
#[test]
1003+
fn test_tcp_peer_get_connection_address() {
1004+
let eid = crate::bpv7::EndpointId::from("dtn://addr-test");
1005+
let address = "example.com:1234".to_string();
1006+
let peer = crate::cla::TcpPeer::new(eid, address.clone());
1007+
1008+
assert_eq!(peer.get_connection_address(), address);
1009+
}
1010+
1011+
#[tokio::test]
1012+
async fn test_tcp_peer_is_reachable_unreachable() {
1013+
let eid = crate::bpv7::EndpointId::from("dtn://unreachable");
1014+
let peer = crate::cla::TcpPeer::new(eid, "127.0.0.1:19998".to_string()); // Non-existent port
1015+
1016+
let reachable = peer.is_reachable().await;
1017+
assert!(!reachable);
1018+
}
1019+
1020+
#[tokio::test]
1021+
async fn test_tcp_peer_is_reachable_timeout() {
1022+
let eid = crate::bpv7::EndpointId::from("dtn://timeout-test");
1023+
// Use a non-routable address that will cause timeout
1024+
let peer = crate::cla::TcpPeer::new(eid, "192.0.2.1:80".to_string()); // TEST-NET-1 (RFC 5737)
1025+
1026+
let reachable = peer.is_reachable().await;
1027+
assert!(!reachable);
1028+
}
1029+
1030+
#[tokio::test]
1031+
async fn test_tcp_peer_is_reachable_with_mock_server() -> anyhow::Result<()> {
1032+
// Create a mock server to test successful connection
1033+
let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await?;
1034+
let port = listener.local_addr()?.port();
1035+
1036+
// Start a server that accepts connections
1037+
tokio::spawn(async move {
1038+
if let Ok((stream, _)) = listener.accept().await {
1039+
drop(stream); // Just accept and close
1040+
}
1041+
});
1042+
1043+
let eid = crate::bpv7::EndpointId::from("dtn://reachable");
1044+
let peer = crate::cla::TcpPeer::new(eid, format!("127.0.0.1:{}", port));
1045+
1046+
// Give server time to start
1047+
tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;
1048+
1049+
let reachable = peer.is_reachable().await;
1050+
assert!(reachable);
1051+
1052+
Ok(())
1053+
}
1054+
1055+
// Additional TcpClaClient tests
1056+
#[test]
1057+
fn test_tcp_cla_client_new() {
1058+
let client = TcpClaClient {
1059+
target_addr: "test.example.com:8080".to_string(),
1060+
};
1061+
assert_eq!(client.target_addr, "test.example.com:8080");
1062+
}
1063+
1064+
#[tokio::test]
1065+
async fn test_tcp_cla_client_activate_connection_refused() {
1066+
let client = TcpClaClient {
1067+
target_addr: "127.0.0.1:19997".to_string(), // Non-existent server
1068+
};
1069+
1070+
let result = client.activate().await;
1071+
assert!(result.is_err());
1072+
}
1073+
1074+
#[tokio::test]
1075+
async fn test_tcp_cla_client_activate_invalid_address() {
1076+
let client = TcpClaClient {
1077+
target_addr: "invalid-hostname:8080".to_string(),
1078+
};
1079+
1080+
let result = client.activate().await;
1081+
assert!(result.is_err());
1082+
}
1083+
1084+
// Test create_bundle function variations
1085+
#[test]
1086+
fn test_create_bundle_empty_payload() {
1087+
let bundle = create_bundle("dtn://src", "dtn://dst", vec![]);
1088+
assert_eq!(bundle.payload, b"");
1089+
assert_eq!(bundle.primary.source, "dtn://src");
1090+
assert_eq!(bundle.primary.destination, "dtn://dst");
1091+
}
1092+
1093+
#[test]
1094+
fn test_create_bundle_large_payload() {
1095+
let large_payload = vec![0xFF; 1000];
1096+
let bundle = create_bundle("dtn://big-src", "dtn://big-dst", large_payload.clone());
1097+
assert_eq!(bundle.payload, large_payload);
1098+
}
1099+
1100+
#[test]
1101+
fn test_create_bundle_unicode_addresses() {
1102+
let bundle = create_bundle(
1103+
"dtn://テスト送信",
1104+
"dtn://テスト受信",
1105+
b"unicode test".to_vec(),
1106+
);
1107+
assert_eq!(bundle.primary.source, "dtn://テスト送信");
1108+
assert_eq!(bundle.primary.destination, "dtn://テスト受信");
1109+
}

0 commit comments

Comments
 (0)