@@ -1238,4 +1238,68 @@ mod tests {
12381238 observe ( & mut d, now, & [ 11 ] ) ;
12391239 assert ! ( d. get_handover_readiness( ) . is_ready( ) ) ;
12401240 }
1241+
1242+ #[ test]
1243+ fn observe_out_of_order_and_fill_gap_moves_cumulative_tsn_ack ( ) {
1244+ let now = Instant :: now ( ) ;
1245+ let mut d = DataTracker :: new ( INITIAL_TSN , & Options :: default ( ) ) ;
1246+
1247+ // Receive 12, 14, 15. Then 11 (which advances cum_ack), then 13 (which fills the gap).
1248+ observe ( & mut d, now, & [ 12 , 14 , 15 , 11 , 13 ] ) ;
1249+
1250+ let sack = d. create_selective_ack ( A_RWND ) ;
1251+ assert_eq ! ( sack. cumulative_tsn_ack, Tsn ( 15 ) ) ;
1252+ assert ! ( sack. gap_ack_blocks. is_empty( ) ) ;
1253+ assert ! ( sack. duplicate_tsns. is_empty( ) ) ;
1254+ }
1255+
1256+ #[ test]
1257+ fn observe_out_of_order_and_fill_gap_moves_cumulative_tsn_ack_multiple_blocks ( ) {
1258+ let now = Instant :: now ( ) ;
1259+ let mut d = DataTracker :: new ( INITIAL_TSN , & Options :: default ( ) ) ;
1260+
1261+ // Create two separate blocks: 12-13 and 15-16
1262+ observe ( & mut d, now, & [ 12 , 13 , 15 , 16 ] ) ;
1263+ // Now fill the gap between them with 14. This should merge the blocks.
1264+ // The current implementation of `add_additional_tsn` is buggy and will
1265+ // result in `[12..14, 14..17]`.
1266+ observe ( & mut d, now, & [ 14 ] ) ;
1267+ // Now receive 11, which should advance the cumulative ack over all blocks.
1268+ observe ( & mut d, now, & [ 11 ] ) ;
1269+
1270+ let sack = d. create_selective_ack ( A_RWND ) ;
1271+ assert_eq ! ( sack. cumulative_tsn_ack, Tsn ( 16 ) ) ;
1272+ assert ! ( sack. gap_ack_blocks. is_empty( ) ) ;
1273+ assert ! ( sack. duplicate_tsns. is_empty( ) ) ;
1274+ }
1275+
1276+ #[ test]
1277+ fn observe_fill_gap_of_three_blocks_advances_cumulative_tsn ( ) {
1278+ let now = Instant :: now ( ) ;
1279+ let mut d = DataTracker :: new ( INITIAL_TSN , & Options :: default ( ) ) ;
1280+
1281+ // Create two separate blocks: 13 and 15.
1282+ // State: additional_tsn_blocks = [13..14, 15..16]
1283+ observe ( & mut d, now, & [ 13 , 15 ] ) ;
1284+
1285+ // Fill the gap between them with 14.
1286+ // This hits a bug in `add_additional_tsn` where expanding a block to the left
1287+ // doesn't check if it can merge with the block before it, resulting in adjacent blocks.
1288+ // State: additional_tsn_blocks = [13..14, 14..16]
1289+ observe ( & mut d, now, & [ 14 ] ) ;
1290+
1291+ // Add 12, which expands the first block to the left.
1292+ // State: additional_tsn_blocks = [12..14, 14..16]
1293+ observe ( & mut d, now, & [ 12 ] ) ;
1294+
1295+ // Now receive 11, which should advance the cumulative ack over all blocks.
1296+ // But `observe` only processes one block, leaving last_cumulative_acked_tsn
1297+ // at 13 instead of 15.
1298+ observe ( & mut d, now, & [ 11 ] ) ;
1299+
1300+ let sack = d. create_selective_ack ( A_RWND ) ;
1301+ assert_eq ! ( sack. cumulative_tsn_ack, Tsn ( 15 ) ) ;
1302+ assert ! ( sack. gap_ack_blocks. is_empty( ) ) ;
1303+ assert ! ( sack. duplicate_tsns. is_empty( ) ) ;
1304+ }
12411305}
0 commit comments