pdc-core 0.1.2

A network load testing library
Documentation
extern crate itertools;

use itertools::Itertools;

use super::Scenario;
use serde::Deserialize;
use std::path::PathBuf;

/// A custom scenario allows for a custom curve to be constructed out of a list of points (time ms, rate req/sec).
/// This scenario will LERP bettween the provided points when `rate()` is called.
#[derive(Clone)]
pub struct CustomScenario {
    points: Vec<Point>,
}

#[derive(Debug, Deserialize, Clone)]
pub struct Point {
    // In milliseconds
    time: usize,
    // In Requests or Packets per second.
    rate: f32,
}

impl Scenario for CustomScenario {
    fn rate(&self, time_elasped: std::time::Duration) -> f32 {
        let time = time_elasped.as_millis() as usize;
        for (p1, p2) in self.points.iter().tuple_windows() {
            if p1.time <= time && p2.time >= time {
                return CustomScenario::lerp(p1, p2, time);
            }
        }
        0.
    }

    fn duration(&self) -> u128 {
        match self.points.last() {
            Some(p) => p.time as u128,
            None => 0,
        }
    }

    fn max_rate(&self) -> f32 {
        let mut max = 0.;
        for p in self.points.iter() {
            if p.rate > max {
                max = p.rate;
            }
        }
        max
    }
}

impl CustomScenario {
    pub fn new(mut points: Vec<Point>) -> Self {
        points.sort_by(|a, b| a.time.partial_cmp(&b.time).unwrap());
        CustomScenario { points }
    }

    /// Import a custom Scenario from a CSV file.
    pub fn from_csv(filename: PathBuf) -> Self {
        let mut points = Vec::new();
        let mut rdr = csv::Reader::from_path(filename).unwrap();
        for result in rdr.deserialize() {
            let p: Point = result.unwrap();
            points.push(p);
        }
        points.sort_by(|a, b| a.time.partial_cmp(&b.time).unwrap());
        CustomScenario { points }
    }

    /// This function asumes p1 comes befor p2
    fn lerp(p1: &Point, p2: &Point, time: usize) -> f32 {
        // Have to multiply buy 1000 to get time in microseconds
        let dt = (p2.time - p1.time) * 1000;
        let tau = (time - p1.time) as f32 / dt as f32;
        p1.rate + (p2.rate * tau)
    }
}