1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
mod burst;
mod constant;

use burst::BurstIapyxLoadCommand;
use clap::Parser;
use constant::ConstIapyxLoadCommand;
use iapyx::ArtificialUserLoad;
use iapyx::MultiControllerError;
use iapyx::NodeLoadError;
use iapyx::ServicingStationLoad;
pub use jortestkit::console::progress_bar::{parse_progress_bar_mode_from_str, ProgressBarMode};
use jortestkit::load::Monitor;
use std::path::PathBuf;
use thiserror::Error;

#[derive(Error, Debug)]
pub enum IapyxLoadCommandError {
    #[error("load runner error")]
    NodeLoadError(#[from] NodeLoadError),
    #[error("internal error")]
    MultiControllerError(#[from] MultiControllerError),
    #[error("serialize error")]
    SerializeError(#[from] serde_json::Error),
    #[error("servicing station error")]
    ServicingStationError(#[from] iapyx::ServicingStationLoadError),
    #[error("artificial users error")]
    ArtificialUserError(#[from] iapyx::ArtificialUserLoadError),
    #[error(transparent)]
    Io(#[from] std::io::Error),
}

#[derive(Parser, Debug)]
pub enum IapyxLoadCommand {
    /// Load which targets blockchain calls only
    #[clap(subcommand)]
    NodeOnly(NodeOnlyLoadCommand),
    /// Load which targets static data only
    StaticOnly(StaticOnlyLoadCommand),
    /// Load with simulate real user case (both blockchain and static data in some relation)
    Simulation(ArtificialLoadCommand),
}

impl IapyxLoadCommand {
    pub fn exec(&self) -> Result<(), IapyxLoadCommandError> {
        match self {
            Self::NodeOnly(node_only) => node_only.exec(),
            Self::StaticOnly(static_only) => static_only.exec(),
            Self::Simulation(simulation) => simulation.exec(),
        }
    }
}

#[derive(Parser, Debug)]
pub struct ArtificialLoadCommand {
    /// Path to configuration file
    #[clap(short = 'c', long = "config")]
    config: PathBuf,
}

impl ArtificialLoadCommand {
    pub fn exec(&self) -> Result<(), IapyxLoadCommandError> {
        let config = serde_json::from_str(&jortestkit::file::read_file(&self.config)?)?;
        let load = ArtificialUserLoad::new(config);
        load.start().map(|_| ()).map_err(Into::into)
    }
}

#[derive(Parser, Debug)]
pub struct StaticOnlyLoadCommand {
    /// Path to configuration file
    #[clap(short = 'c', long = "config")]
    config: PathBuf,
}

impl StaticOnlyLoadCommand {
    pub fn exec(&self) -> Result<(), IapyxLoadCommandError> {
        let config = serde_json::from_str(&jortestkit::file::read_file(&self.config)?)?;
        let load = ServicingStationLoad::new(config);
        load.start().map(|_| ()).map_err(Into::into)
    }
}

#[derive(Parser, Debug)]
pub enum NodeOnlyLoadCommand {
    /// Bursts mode. Sends votes in batches and then wait x seconds
    #[clap(subcommand)]
    Burst(BurstIapyxLoadCommand),
    /// Constant load. Sends votes with x votes per second speed.
    #[clap(subcommand)]
    Const(ConstIapyxLoadCommand),
}

impl NodeOnlyLoadCommand {
    pub fn exec(&self) -> Result<(), IapyxLoadCommandError> {
        match self {
            Self::Burst(burst) => burst.exec(),
            Self::Const(constant) => constant.exec(),
        }
    }
}

pub fn build_monitor(progress_bar_mode: &ProgressBarMode) -> Monitor {
    match progress_bar_mode {
        ProgressBarMode::Monitor => Monitor::Progress(100),
        ProgressBarMode::Standard => Monitor::Standard(100),
        ProgressBarMode::None => Monitor::Disabled(10),
    }
}