use std::time::Duration;
use netem::{DataSize, NetemConfig};
use str0m::RtcError;
use str0m::bwe::Bitrate;
use crate::common::{BweTestContext, Step, connect_with_bwe, init_crypto_default, init_log};
#[test]
fn estimate_capped_by_max_bitrate() -> Result<(), RtcError> {
init_log();
init_crypto_default();
let plan = vec![
Step::Conditions {
description: "High capacity network (10 Mbps)",
config: NetemConfig::new()
.latency(Duration::from_millis(10))
.link(Bitrate::mbps(10), DataSize::kbytes(200))
.seed(42),
},
Step::Media {
description: "Send at 2 Mbps with 3 Mbps max",
desired_bitrate: Bitrate::mbps(3), media_send_rate: Bitrate::mbps(2),
},
Step::Run {
description: "Let probes discover high capacity",
duration: Duration::from_secs(10),
},
Step::Check {
description: "Estimate capped at max_bitrate",
at_least: Bitrate::mbps(2),
},
];
let (mut l, mut r) = connect_with_bwe(Bitrate::mbps(2), Bitrate::mbps(3));
let mut ctx = BweTestContext::new(&mut l, &mut r);
ctx.run_plan(&mut l, &mut r, &plan)?;
Ok(())
}
#[test]
fn estimate_recovers_after_capacity_restoration() -> Result<(), RtcError> {
init_log();
init_crypto_default();
let plan = vec![
Step::Conditions {
description: "Good network initially",
config: NetemConfig::new()
.latency(Duration::from_millis(20))
.link(Bitrate::mbps(5), DataSize::kbytes(100))
.seed(42),
},
Step::Media {
description: "Send at 2 Mbps",
desired_bitrate: Bitrate::mbps(5),
media_send_rate: Bitrate::mbps(2),
},
Step::Run {
description: "Establish baseline",
duration: Duration::from_secs(5),
},
Step::Check {
description: "Good estimate",
at_least: Bitrate::mbps(2),
},
Step::Conditions {
description: "Degrade to 1 Mbps",
config: NetemConfig::new()
.latency(Duration::from_millis(40))
.link(Bitrate::mbps(1), DataSize::kbytes(50))
.seed(42),
},
Step::Run {
description: "Estimate drops to lower capacity",
duration: Duration::from_secs(2),
},
Step::Check {
description: "Estimate reduced to ~1 Mbps",
at_least: Bitrate::kbps(400),
},
Step::Media {
description: "Reduce send rate to allow AIMD recovery",
desired_bitrate: Bitrate::mbps(5),
media_send_rate: Bitrate::kbps(500), },
Step::Conditions {
description: "Restore to 5 Mbps",
config: NetemConfig::new()
.latency(Duration::from_millis(20))
.link(Bitrate::mbps(5), DataSize::kbytes(100))
.seed(42),
},
Step::Run {
description: "Initial AIMD recovery period",
duration: Duration::from_secs(3),
},
Step::AssertNoProbes {
description: "No probes during initial AIMD recovery",
},
Step::Check {
description: "AIMD recovery is very slow after severe degradation",
at_least: Bitrate::kbps(350),
},
Step::Run {
description: "Continue recovery (slow due to low threshold)",
duration: Duration::from_secs(25),
},
Step::Check {
description: "Recovery remains slow (threshold adapted down)",
at_least: Bitrate::mbps(1),
},
];
let (mut l, mut r) = connect_with_bwe(Bitrate::mbps(2), Bitrate::mbps(5));
let mut ctx = BweTestContext::new(&mut l, &mut r);
ctx.run_plan(&mut l, &mut r, &plan)?;
Ok(())
}
#[test]
fn estimate_converges_to_actual_capacity() -> Result<(), RtcError> {
init_log();
init_crypto_default();
let plan = vec![
Step::Conditions {
description: "Network with 2 Mbps capacity",
config: NetemConfig::new()
.latency(Duration::from_millis(20))
.link(Bitrate::mbps(2), DataSize::kbytes(100))
.seed(42),
},
Step::Media {
description: "Send at 1.5 Mbps",
desired_bitrate: Bitrate::mbps(5),
media_send_rate: Bitrate::mbps(1),
},
Step::Run {
description: "Allow convergence over 15 seconds",
duration: Duration::from_secs(15),
},
Step::Check {
description: "Estimate converges near capacity",
at_least: Bitrate::mbps(1),
},
];
let (mut l, mut r) = connect_with_bwe(Bitrate::mbps(1), Bitrate::mbps(5));
let mut ctx = BweTestContext::new(&mut l, &mut r);
ctx.run_plan(&mut l, &mut r, &plan)?;
Ok(())
}