rusmes_loadtest/
generators.rs1use crate::config::MessageContent;
4use rand::RngExt;
5
6#[derive(Clone)]
8pub struct MessageGenerator {
9 min_size: usize,
10 max_size: usize,
11 #[allow(dead_code)]
12 content_type: MessageContent,
13}
14
15impl MessageGenerator {
16 pub fn new(min_size: usize, max_size: usize) -> Self {
18 Self {
19 min_size,
20 max_size,
21 content_type: MessageContent::Random,
22 }
23 }
24
25 pub fn with_content_type(
27 min_size: usize,
28 max_size: usize,
29 content_type: MessageContent,
30 ) -> Self {
31 Self {
32 min_size,
33 max_size,
34 content_type,
35 }
36 }
37
38 pub fn generate(&self) -> String {
40 let mut rng = rand::rng();
41 let target_size = rng.random_range(self.min_size..=self.max_size);
42
43 let from = format!("loadtest{}@example.com", rng.random::<u32>());
44 let to = format!("user{}@example.com", rng.random::<u32>());
45 let subject = format!("Load Test Message {}", rng.random::<u32>());
46
47 let headers = format!(
49 "From: {}\r\n\
50 To: {}\r\n\
51 Subject: {}\r\n\
52 \r\n",
53 from, to, subject
54 );
55
56 let body_size = target_size.saturating_sub(headers.len()).max(1);
58 let body = self.generate_body(body_size);
59
60 format!("{}{}", headers, body)
61 }
62
63 fn generate_body(&self, size: usize) -> String {
65 let mut rng = rand::rng();
66 let words = vec![
67 "Lorem",
68 "ipsum",
69 "dolor",
70 "sit",
71 "amet",
72 "consectetur",
73 "adipiscing",
74 "elit",
75 "sed",
76 "do",
77 "eiusmod",
78 "tempor",
79 "incididunt",
80 "ut",
81 "labore",
82 "et",
83 "dolore",
84 "magna",
85 "aliqua",
86 "enim",
87 "ad",
88 "minim",
89 "veniam",
90 "quis",
91 ];
92
93 let mut body = String::with_capacity(size);
94 while body.len() < size {
95 let word = words[rng.random_range(0..words.len())];
96 body.push_str(word);
97 body.push(' ');
98 }
99
100 body.truncate(size);
101 body
102 }
103
104 pub fn generate_with_attachment(&self, attachment_size: usize) -> String {
106 let mut rng = rand::rng();
107
108 let from = format!("loadtest{}@example.com", rng.random::<u32>());
109 let to = format!("user{}@example.com", rng.random::<u32>());
110 let subject = format!("Load Test Message with Attachment {}", rng.random::<u32>());
111
112 let boundary = "----=_NextPart_000_0001_01D0A1B2.C3D4E5F6";
113 let attachment_data = "A".repeat(attachment_size);
114
115 format!(
116 "From: {}\r\n\
117 To: {}\r\n\
118 Subject: {}\r\n\
119 MIME-Version: 1.0\r\n\
120 Content-Type: multipart/mixed; boundary=\"{}\"\r\n\
121 \r\n\
122 --{}\r\n\
123 Content-Type: text/plain; charset=\"utf-8\"\r\n\
124 \r\n\
125 This is a load test message with attachment.\r\n\
126 \r\n\
127 --{}\r\n\
128 Content-Type: application/octet-stream\r\n\
129 Content-Transfer-Encoding: base64\r\n\
130 Content-Disposition: attachment; filename=\"test.dat\"\r\n\
131 \r\n\
132 {}\r\n\
133 --{}--\r\n",
134 from, to, subject, boundary, boundary, boundary, attachment_data, boundary
135 )
136 }
137}
138
139#[cfg(test)]
140mod tests {
141 use super::*;
142
143 #[test]
144 fn test_message_generation() {
145 let generator = MessageGenerator::new(1024, 2048);
146 let message = generator.generate();
147
148 assert!(message.len() >= 1024);
149 assert!(message.len() <= 2048);
150 assert!(message.contains("From:"));
151 assert!(message.contains("To:"));
152 assert!(message.contains("Subject:"));
153 }
154
155 #[test]
156 fn test_message_with_attachment() {
157 let generator = MessageGenerator::new(1024, 2048);
158 let message = generator.generate_with_attachment(100);
159
160 assert!(message.contains("MIME-Version: 1.0"));
161 assert!(message.contains("Content-Type: multipart/mixed"));
162 assert!(message.contains("attachment"));
163 }
164
165 #[test]
166 fn test_body_generation() {
167 let generator = MessageGenerator::new(100, 200);
168 let body = generator.generate_body(150);
169
170 assert_eq!(body.len(), 150);
171 }
172}