shadow_load_testing/
report.rs1use serde::{Serialize, Deserialize};
4use std::time::Duration;
5
6#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct LoadTestReport {
9 pub peer_count: usize,
10 pub results: Vec<LoadTestResult>,
11 pub timestamp: String,
12}
13
14#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct LoadTestResult {
17 pub name: String,
18 pub duration_ms: u64,
19 pub passed: bool,
20}
21
22impl LoadTestReport {
23 pub fn new(peer_count: usize) -> Self {
24 LoadTestReport {
25 peer_count,
26 results: Vec::new(),
27 timestamp: chrono::Utc::now().to_rfc3339(),
28 }
29 }
30
31 pub fn record(&mut self, name: &str, duration: Duration, passed: bool) {
32 self.results.push(LoadTestResult {
33 name: name.to_string(),
34 duration_ms: duration.as_millis() as u64,
35 passed,
36 });
37 }
38
39 pub fn all_passed(&self) -> bool {
40 self.results.iter().all(|r| r.passed)
41 }
42
43 pub fn total_duration_ms(&self) -> u64 {
44 self.results.iter().map(|r| r.duration_ms).sum()
45 }
46
47 pub fn passed_count(&self) -> usize {
48 self.results.iter().filter(|r| r.passed).count()
49 }
50
51 pub fn failed_count(&self) -> usize {
52 self.results.iter().filter(|r| !r.passed).count()
53 }
54
55 pub fn summary(&self) -> String {
56 format!(
57 "Load Test Report ({})\n\
58 Peers: {}\n\
59 Tests: {} passed, {} failed, {} total\n\
60 Total Duration: {}ms\n\
61 Results:\n{}",
62 self.timestamp,
63 self.peer_count,
64 self.passed_count(),
65 self.failed_count(),
66 self.results.len(),
67 self.total_duration_ms(),
68 self.results
69 .iter()
70 .map(|r| {
71 format!(
72 " {} - {} ({}ms)",
73 if r.passed { "pass" } else { "FAIL" },
74 r.name,
75 r.duration_ms
76 )
77 })
78 .collect::<Vec<_>>()
79 .join("\n")
80 )
81 }
82
83 pub fn to_json(&self) -> String {
84 serde_json::to_string_pretty(self).unwrap_or_default()
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91
92 #[test]
93 fn test_report_creation() {
94 let mut report = LoadTestReport::new(10_000);
95 report.record("test_1", Duration::from_millis(100), true);
96 report.record("test_2", Duration::from_millis(200), true);
97 report.record("test_3", Duration::from_millis(50), false);
98
99 assert_eq!(report.peer_count, 10_000);
100 assert_eq!(report.passed_count(), 2);
101 assert_eq!(report.failed_count(), 1);
102 assert_eq!(report.total_duration_ms(), 350);
103 assert!(!report.all_passed());
104 }
105
106 #[test]
107 fn test_report_all_passed() {
108 let mut report = LoadTestReport::new(100);
109 report.record("a", Duration::from_millis(10), true);
110 report.record("b", Duration::from_millis(20), true);
111 assert!(report.all_passed());
112 }
113
114 #[test]
115 fn test_report_summary() {
116 let mut report = LoadTestReport::new(5000);
117 report.record("dht_stress", Duration::from_millis(500), true);
118 let summary = report.summary();
119 assert!(summary.contains("5000"));
120 assert!(summary.contains("dht_stress"));
121 }
122
123 #[test]
124 fn test_report_json() {
125 let mut report = LoadTestReport::new(1000);
126 report.record("test", Duration::from_millis(100), true);
127 let json = report.to_json();
128 assert!(json.contains("peer_count"));
129 assert!(json.contains("1000"));
130 }
131}