@@ -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}
0 commit comments