#[cfg(feature = "mahimahi")]
pub mod mahimahi;
#[cfg(feature = "mahimahi")]
pub use mahimahi::{load_mahimahi_trace, Mahimahi, MahimahiExt};
#[cfg(any(
feature = "bw-model",
feature = "delay-model",
feature = "loss-model",
feature = "duplicate-model",
feature = "model",
))]
pub mod model;
#[cfg(feature = "trace-ext")]
pub mod series;
pub use bandwidth::Bandwidth;
pub use std::time::Duration;
pub type Delay = std::time::Duration;
pub type LossPattern = Vec<f64>;
pub type DuplicatePattern = Vec<f64>;
pub trait BwTrace: Send {
fn next_bw(&mut self) -> Option<(Bandwidth, Duration)>;
}
pub trait DelayTrace: Send {
fn next_delay(&mut self) -> Option<(Delay, Duration)>;
}
pub trait DelayPerPacketTrace: Send {
fn next_delay(&mut self) -> Option<Delay>;
}
pub trait LossTrace: Send {
fn next_loss(&mut self) -> Option<(LossPattern, Duration)>;
}
pub trait DuplicateTrace: Send {
fn next_duplicate(&mut self) -> Option<(DuplicatePattern, Duration)>;
}
#[cfg(test)]
mod test {
use model::TraceBwConfig;
use self::model::bw::Forever;
use super::*;
#[cfg(feature = "serde")]
use crate::model::RepeatedBwPatternConfig;
use crate::model::{BwTraceConfig, NormalizedBwConfig, SawtoothBwConfig, StaticBwConfig};
#[test]
fn test_static_bw_model() {
let mut static_bw = StaticBwConfig::new()
.bw(Bandwidth::from_mbps(24))
.duration(Duration::from_secs(1))
.build();
assert_eq!(
static_bw.next_bw(),
Some((Bandwidth::from_mbps(24), Duration::from_secs(1)))
);
}
#[test]
fn test_normalized_bw_model() {
let mut normal_bw = NormalizedBwConfig::new()
.mean(Bandwidth::from_mbps(12))
.std_dev(Bandwidth::from_mbps(1))
.duration(Duration::from_secs(1))
.step(Duration::from_millis(100))
.seed(42)
.build();
assert_eq!(
normal_bw.next_bw(),
Some((Bandwidth::from_bps(12069427), Duration::from_millis(100)))
);
assert_eq!(
normal_bw.next_bw(),
Some((Bandwidth::from_bps(12132938), Duration::from_millis(100)))
);
let mut normal_bw = NormalizedBwConfig::new()
.mean(Bandwidth::from_mbps(12))
.std_dev(Bandwidth::from_mbps(1))
.duration(Duration::from_secs(1))
.step(Duration::from_millis(100))
.seed(42)
.upper_bound(Bandwidth::from_kbps(12100))
.lower_bound(Bandwidth::from_kbps(11900))
.build();
assert_eq!(
normal_bw.next_bw(),
Some((Bandwidth::from_bps(12069427), Duration::from_millis(100)))
);
assert_eq!(
normal_bw.next_bw(),
Some((Bandwidth::from_bps(12100000), Duration::from_millis(100)))
);
}
#[test]
fn test_sawtooth_bw_model() {
let mut sawtooth_bw = SawtoothBwConfig::new()
.bottom(Bandwidth::from_mbps(12))
.top(Bandwidth::from_mbps(16))
.duration(Duration::from_secs(1))
.step(Duration::from_millis(100))
.interval(Duration::from_millis(500))
.duty_ratio(0.8)
.build();
assert_eq!(
sawtooth_bw.next_bw(),
Some((Bandwidth::from_mbps(12), Duration::from_millis(100)))
);
assert_eq!(
sawtooth_bw.next_bw(),
Some((Bandwidth::from_mbps(13), Duration::from_millis(100)))
);
assert_eq!(
sawtooth_bw.next_bw(),
Some((Bandwidth::from_mbps(14), Duration::from_millis(100)))
);
assert_eq!(
sawtooth_bw.next_bw(),
Some((Bandwidth::from_mbps(15), Duration::from_millis(100)))
);
assert_eq!(
sawtooth_bw.next_bw(),
Some((Bandwidth::from_mbps(16), Duration::from_millis(100)))
);
assert_eq!(
sawtooth_bw.next_bw(),
Some((Bandwidth::from_mbps(12), Duration::from_millis(100)))
);
assert_eq!(
sawtooth_bw.next_bw(),
Some((Bandwidth::from_mbps(13), Duration::from_millis(100)))
);
assert_eq!(
sawtooth_bw.next_bw(),
Some((Bandwidth::from_mbps(14), Duration::from_millis(100)))
);
assert_eq!(
sawtooth_bw.next_bw(),
Some((Bandwidth::from_mbps(15), Duration::from_millis(100)))
);
let mut sawtooth_bw = SawtoothBwConfig::new()
.bottom(Bandwidth::from_mbps(12))
.top(Bandwidth::from_mbps(16))
.duration(Duration::from_secs(1))
.step(Duration::from_millis(100))
.interval(Duration::from_millis(500))
.duty_ratio(0.8)
.std_dev(Bandwidth::from_mbps(5))
.upper_noise_bound(Bandwidth::from_mbps(1))
.lower_noise_bound(Bandwidth::from_kbps(500))
.build();
assert_eq!(
sawtooth_bw.next_bw(),
Some((Bandwidth::from_bps(12347139), Duration::from_millis(100)))
);
assert_eq!(
sawtooth_bw.next_bw(),
Some((Bandwidth::from_bps(13664690), Duration::from_millis(100)))
);
assert_eq!(
sawtooth_bw.next_bw(),
Some((Bandwidth::from_mbps(15), Duration::from_millis(100)))
);
assert_eq!(
sawtooth_bw.next_bw(),
Some((Bandwidth::from_bps(14500000), Duration::from_millis(100)))
);
}
#[test]
fn test_trace_bw() {
let mut trace_bw = TraceBwConfig::new()
.pattern(vec![
(
Duration::from_millis(1),
vec![
Bandwidth::from_kbps(29123),
Bandwidth::from_kbps(41242),
Bandwidth::from_kbps(7395),
],
),
(
Duration::from_millis(2),
vec![Bandwidth::from_mbps(1), Bandwidth::from_kbps(8542)],
),
])
.build();
assert_eq!(
trace_bw.next_bw(),
Some((Bandwidth::from_bps(29123000), Duration::from_millis(1)))
);
assert_eq!(
trace_bw.next_bw(),
Some((Bandwidth::from_bps(41242000), Duration::from_millis(1)))
);
assert_eq!(
trace_bw.next_bw(),
Some((Bandwidth::from_bps(7395000), Duration::from_millis(1)))
);
assert_eq!(
trace_bw.next_bw(),
Some((Bandwidth::from_bps(1000000), Duration::from_millis(2)))
);
assert_eq!(
trace_bw.next_bw(),
Some((Bandwidth::from_bps(8542000), Duration::from_millis(2)))
);
assert_eq!(trace_bw.next_bw(), None);
}
#[test]
#[cfg(feature = "serde")]
fn test_model_serde() {
let a = vec![
Box::new(
StaticBwConfig::new()
.bw(Bandwidth::from_mbps(12))
.duration(Duration::from_secs(1)),
) as Box<dyn BwTraceConfig>,
Box::new(
StaticBwConfig::new()
.bw(Bandwidth::from_mbps(24))
.duration(Duration::from_secs(1)),
) as Box<dyn BwTraceConfig>,
];
let ser =
Box::new(RepeatedBwPatternConfig::new().pattern(a).count(2)) as Box<dyn BwTraceConfig>;
let ser_str = serde_json::to_string(&ser).unwrap();
#[cfg(not(feature = "human"))]
let des_str = "{\"RepeatedBwPatternConfig\":{\"pattern\":[{\"StaticBwConfig\":{\"bw\":{\"gbps\":0,\"bps\":12000000},\"duration\":{\"secs\":1,\"nanos\":0}}},{\"StaticBwConfig\":{\"bw\":{\"gbps\":0,\"bps\":24000000},\"duration\":{\"secs\":1,\"nanos\":0}}}],\"count\":2}}";
#[cfg(feature = "human")]
let des_str = "{\"RepeatedBwPatternConfig\":{\"pattern\":[{\"StaticBwConfig\":{\"bw\":\"12Mbps\",\"duration\":\"1s\"}},{\"StaticBwConfig\":{\"bw\":\"24Mbps\",\"duration\":\"1s\"}}],\"count\":2}}";
assert_eq!(ser_str, des_str);
let des: Box<dyn BwTraceConfig> = serde_json::from_str(des_str).unwrap();
let mut model = des.into_model();
assert_eq!(
model.next_bw(),
Some((Bandwidth::from_mbps(12), Duration::from_secs(1)))
);
}
#[test]
fn test_forever() {
let mut normal_bw = NormalizedBwConfig::new()
.mean(Bandwidth::from_mbps(12))
.std_dev(Bandwidth::from_mbps(1))
.duration(Duration::from_millis(200))
.step(Duration::from_millis(100))
.seed(42)
.build();
assert_eq!(
normal_bw.next_bw(),
Some((Bandwidth::from_bps(12069427), Duration::from_millis(100)))
);
assert_eq!(
normal_bw.next_bw(),
Some((Bandwidth::from_bps(12132938), Duration::from_millis(100)))
);
assert_eq!(normal_bw.next_bw(), None);
let normal_bw_config = NormalizedBwConfig::new()
.mean(Bandwidth::from_mbps(12))
.std_dev(Bandwidth::from_mbps(1))
.duration(Duration::from_millis(200))
.step(Duration::from_millis(100))
.seed(42);
let normal_bw_repeated = normal_bw_config.forever();
let mut model = Box::new(normal_bw_repeated).into_model();
assert_eq!(
model.next_bw(),
Some((Bandwidth::from_bps(12069427), Duration::from_millis(100)))
);
assert_eq!(
model.next_bw(),
Some((Bandwidth::from_bps(12132938), Duration::from_millis(100)))
);
assert_eq!(
model.next_bw(),
Some((Bandwidth::from_bps(12069427), Duration::from_millis(100)))
);
assert_eq!(
model.next_bw(),
Some((Bandwidth::from_bps(12132938), Duration::from_millis(100)))
);
}
#[test]
#[cfg(feature = "human")]
fn test_compatibility_with_figment() {
use figment::{
providers::{Format, Json},
Figment,
};
let config = r##"
{
"RepeatedBwPatternConfig":{
"pattern":[
{
"TraceBwConfig":{
"pattern":[
[
"25ms",
[
"10Mbps",
"20Mbps"
]
],
[
"2ms",
[
"11Mbps",
"23Mbps"
]
]
]
}
},
{
"SawtoothBwConfig":{
"bottom":"10Mbps",
"top":"20Mbps",
"step":"1ms",
"interval":"10ms",
"duty_ratio":0.5
}
}
],
"count":0
}
}"##;
let trace: Box<dyn BwTraceConfig> = Figment::new()
.merge(Json::string(config))
.extract()
.unwrap();
let mut model = trace.into_model();
assert_eq!(
model.next_bw(),
Some((Bandwidth::from_mbps(10), Duration::from_millis(25)))
);
assert_eq!(
model.next_bw(),
Some((Bandwidth::from_mbps(20), Duration::from_millis(25)))
);
assert_eq!(
model.next_bw(),
Some((Bandwidth::from_mbps(11), Duration::from_millis(2)))
);
assert_eq!(
model.next_bw(),
Some((Bandwidth::from_mbps(23), Duration::from_millis(2)))
);
assert_eq!(
model.next_bw(),
Some((Bandwidth::from_mbps(10), Duration::from_millis(1)))
);
assert_eq!(
model.next_bw(),
Some((Bandwidth::from_mbps(12), Duration::from_millis(1)))
);
assert_eq!(
model.next_bw(),
Some((Bandwidth::from_mbps(14), Duration::from_millis(1)))
);
assert_eq!(
model.next_bw(),
Some((Bandwidth::from_mbps(16), Duration::from_millis(1)))
);
assert_eq!(
model.next_bw(),
Some((Bandwidth::from_mbps(18), Duration::from_millis(1)))
);
}
}