pdc-core 0.1.2

A network load testing library
Documentation
pub mod composite;
pub mod custom;
pub mod exponential;
use serde::{Deserialize, Serialize};

use std::time::Duration;

/// Structs that impl the Scenario trait feed generators all the
/// inform information to run a traffic simulation.
pub trait Scenario: Send + Sync + ScenarioClone {
    /// Returns the rate (in #/sec) at which a generator should create traffic
    fn rate(&self, time_elasped: Duration) -> f32;
    /// Return the total duration of a scenario in miliseconds;
    fn duration(&self) -> u128;
    /// Returns the maximum rate in achieved in a scenario
    fn max_rate(&self) -> f32;
}

pub trait ScenarioClone {
    fn clone_box(&self) -> Box<dyn Scenario>;
}

impl<T> ScenarioClone for T
where
    T: 'static + Scenario + Clone,
{
    fn clone_box(&self) -> Box<dyn Scenario> {
        Box::new(self.clone())
    }
}

impl Clone for Box<dyn Scenario> {
    fn clone(&self) -> Box<dyn Scenario> {
        self.clone_box()
    }
}

/// A scenario that produces a constant amount of traffic.
#[derive(Serialize, Deserialize, Clone)]
pub struct ConstantScenario {
    pub rate: f32,
    pub duration: u128,
}

impl Scenario for ConstantScenario {
    fn rate(&self, _time_elasped: Duration) -> f32 {
        self.rate
    }

    fn duration(&self) -> u128 {
        self.duration
    }

    fn max_rate(&self) -> f32 {
        self.rate
    }
}

#[derive(Serialize, Deserialize, Clone)]
pub struct LinearScenario {
    pub starting_rate: f32,
    // slope of the rate in Req/s^2
    pub slope: f32,
    pub duration: u128,
}

impl Scenario for LinearScenario {
    fn rate(&self, time_elasped: Duration) -> f32 {
        self.starting_rate + self.slope * time_elasped.as_millis() as f32 / 1000.
    }

    fn duration(&self) -> u128 {
        self.duration
    }

    fn max_rate(&self) -> f32 {
        self.starting_rate + self.slope * (self.duration as f32 / 1000.)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::time::Duration;

    #[test]
    fn constant_scenario() {
        let scene = ConstantScenario {
            rate: 500.,
            duration: 1000,
        };
        assert_eq!(scene.duration(), 1000);
        assert_eq!(scene.rate(Duration::from_millis(0)), 500.);
        assert_eq!(scene.rate(Duration::from_millis(500)), 500.);
        assert_eq!(scene.rate(Duration::from_millis(1000)), 500.);
        assert_eq!(scene.max_rate(), 500.);
    }

    #[test]
    fn linear_scenario() {
        let scene = LinearScenario {
            starting_rate: 0.,
            slope: 100.,
            duration: 20000,
        };
        assert_eq!(scene.duration(), 20000);
        assert_eq!(scene.rate(Duration::from_millis(0)), 0.);
        assert_eq!(scene.rate(Duration::from_millis(500)), 50.);
        assert_eq!(scene.rate(Duration::from_millis(20000)), 2000.);
        assert_eq!(scene.max_rate(), 2000.);
    }
}