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
use super::ScenarioProgressBar;
use crate::mjolnir_lib::{bootstrap::ClientLoadConfig, MjolnirError};
use assert_fs::TempDir;
use indicatif::{MultiProgress, ProgressBar};
use jormungandr_automation::{
    jormungandr::LogLevel,
    testing::{benchmark_speed, SpeedBenchmarkFinish},
};
use jormungandr_lib::interfaces::NodeState;
use std::{thread, time};
pub struct IterationBasedClientLoad {
    config: ClientLoadConfig,
    sync_iteration: u32,
}

impl IterationBasedClientLoad {
    pub fn new(config: ClientLoadConfig, sync_iteration: u32) -> Self {
        Self {
            config,
            sync_iteration,
        }
    }

    fn get_storage_name(&self, id: u32, iteration: u32) -> String {
        format!("storage_{}_{}", id, iteration)
    }

    fn start_node(
        &self,
        temp_dir: &TempDir,
        id: u32,
        iteration: u32,
        multi_progress: &MultiProgress,
    ) -> Result<thread::JoinHandle<Result<SpeedBenchmarkFinish, MjolnirError>>, MjolnirError> {
        let storage_folder_name = self.get_storage_name(id, iteration);

        let progress_bar = ScenarioProgressBar::new(
            multi_progress.add(ProgressBar::new(1)),
            &format!("[Node: {}, iter: {}]", id, iteration),
        );

        let node = super::start_node(&self.config, &storage_folder_name, temp_dir)?;
        let benchmark = benchmark_speed(&storage_folder_name).no_target().start();

        Ok(thread::spawn(move || loop {
            thread::sleep(time::Duration::from_secs(2));

            if let Some(last_loaded_block) = node.logger.last_validated_block_date() {
                progress_bar.set_progress(&format!("block: {}", last_loaded_block))
            }
            node.check_no_errors_in_log()?;
            progress_bar.set_error_lines(
                node.logger
                    .get_log_lines_with_level(LogLevel::ERROR)
                    .map(|x| x.to_string())
                    .collect(),
            );

            let stats = node.rest().stats()?;
            if stats.state == NodeState::Running {
                progress_bar.set_finished();
                return Ok(benchmark.stop());
            }
        }))
    }

    pub fn run(&self) -> Result<(), MjolnirError> {
        let m = MultiProgress::new();
        let mut results = vec![];

        for iter in 1..=self.sync_iteration {
            println!("Iteration {}", iter);

            let mut handles = vec![];
            let mut temp_dirs = vec![];

            for client_id in 1..=self.config.count() {
                let temp_dir = TempDir::new().unwrap();
                handles.push(self.start_node(&temp_dir, client_id, iter, &m)?);
                temp_dirs.push(temp_dir);
            }
            m.join_and_clear().unwrap();

            for handle in handles {
                results.push(
                    handle
                        .join()
                        .map_err(|_| MjolnirError::InternalClientError)?,
                );
            }
        }

        if self.config.measure() {
            for overall_result in results {
                if let Ok(measurement) = &overall_result {
                    println!("{}", measurement);
                }
            }
        }
        Ok(())
    }
}