@@ -4,6 +4,7 @@ use std::{collections::HashMap, thread::sleep, time::Duration};
44#[ cfg( feature = "serde" ) ]
55use std:: { sync:: mpsc, time:: Instant } ;
66
7+ use itertools:: Itertools ;
78use netem_trace:: {
89 model:: { BwTraceConfig , RepeatedBwPatternConfig , StaticBwConfig } ,
910 Bandwidth , BwTrace ,
@@ -543,7 +544,7 @@ fn test_drophead_queue() {
543544#[ cfg( feature = "serde" ) ]
544545#[ instrument]
545546#[ test_log:: test]
546- #[ serial_test:: serial ]
547+ #[ serial_test:: parallel ]
547548fn test_codel_queue ( ) {
548549 let mut config = RattanConfig :: < StdPacket > {
549550 env : StdNetEnvConfig {
@@ -898,3 +899,68 @@ fn test_replay() {
898899 assert ! ( back_5s_bitrate < back_5s_target_rate * 1.03 ) ;
899900 }
900901}
902+
903+ #[ instrument]
904+ #[ test_log:: test]
905+ #[ serial_test:: parallel]
906+ fn test_low_rate ( ) {
907+ // cargo run -- link --uplink-bandwidth 4096bps --ping -c 10 10.2.1.1 -s 100 -i 0.3
908+ let mut config = RattanConfig :: < StdPacket > {
909+ env : StdNetEnvConfig {
910+ mode : StdNetEnvMode :: Isolated ,
911+ client_cores : vec ! [ 1 ] ,
912+ server_cores : vec ! [ 3 ] ,
913+ ..Default :: default ( )
914+ } ,
915+ ..Default :: default ( )
916+ } ;
917+
918+ config. cells . insert (
919+ "up_bw" . to_string ( ) ,
920+ CellBuildConfig :: Bw ( BwCellBuildConfig :: Infinite ( BwCellConfig :: new (
921+ Bandwidth :: from_bps ( 4096 ) ,
922+ InfiniteQueueConfig :: new ( ) ,
923+ None ,
924+ ) ) ) ,
925+ ) ;
926+
927+ config. links = HashMap :: from ( [
928+ ( "left" . to_string ( ) , "up_bw" . to_string ( ) ) ,
929+ ( "up_bw" . to_string ( ) , "right" . to_string ( ) ) ,
930+ ( "right" . to_string ( ) , "left" . to_string ( ) ) ,
931+ ] ) ;
932+ let mut radix = RattanRadix :: < AfPacketDriver > :: new ( config) . unwrap ( ) ;
933+ radix. spawn_rattan ( ) . unwrap ( ) ;
934+ radix. start_rattan ( ) . unwrap ( ) ;
935+
936+ // Wait for AfPacketDriver to be ready
937+ std:: thread:: sleep ( std:: time:: Duration :: from_millis ( 100 ) ) ;
938+
939+ let _span = span ! ( Level :: INFO , "bandwidth_low_rate" ) . entered ( ) ;
940+ info ! ( "try to ping 128B packets in a 4096bps link" ) ;
941+ let right_ip = radix. right_ip ( 1 ) . to_string ( ) ;
942+ let left_handle = radix
943+ . left_spawn ( None , move || {
944+ let handle = std:: process:: Command :: new ( "ping" )
945+ . args ( [ & right_ip, "-c" , "10" , "-i" , "0.3" , "-s" , "100" ] )
946+ . stdout ( std:: process:: Stdio :: piped ( ) )
947+ . spawn ( )
948+ . unwrap ( ) ;
949+ Ok ( handle. wait_with_output ( ) )
950+ } )
951+ . unwrap ( ) ;
952+ let output = left_handle. join ( ) . unwrap ( ) . unwrap ( ) . unwrap ( ) ;
953+ let stdout = String :: from_utf8 ( output. stdout ) . unwrap ( ) ;
954+
955+ let re = Regex :: new ( r"time=(\d+)" ) . unwrap ( ) ;
956+ let latency = re
957+ . captures_iter ( & stdout)
958+ . flat_map ( |cap| cap[ 1 ] . parse :: < f64 > ( ) )
959+ . collect :: < Vec < _ > > ( ) ;
960+ info ! ( ?latency) ;
961+
962+ // Should all be 250ms.
963+ let ( & min, & max) = latency. iter ( ) . minmax ( ) . into_option ( ) . unwrap ( ) ;
964+ assert ! ( min >= 248.0 ) ;
965+ assert ! ( max <= 250.0 ) ;
966+ }
0 commit comments