openzeppelin_monitor/utils/tests/builders/midnight/
monitor.rs1use crate::models::{
6 AddressWithSpec, ChainConfiguration, EventCondition, FunctionCondition, MatchConditions,
7 MidnightMonitorConfig, Monitor, ScriptLanguage, TransactionCondition, TransactionStatus,
8 TriggerConditions,
9};
10
11pub struct MonitorBuilder {
13 name: String,
14 networks: Vec<String>,
15 paused: bool,
16 addresses: Vec<AddressWithSpec>,
17 match_conditions: MatchConditions,
18 trigger_conditions: Vec<TriggerConditions>,
19 triggers: Vec<String>,
20 chain_configurations: Vec<ChainConfiguration>,
21}
22
23impl Default for MonitorBuilder {
24 fn default() -> Self {
26 Self {
27 name: "TestMonitor".to_string(),
28 networks: vec!["midnight_testnet".to_string()],
29 paused: false,
30 addresses: vec![AddressWithSpec {
31 address: "0202000000000000000000000000000000000000000000000000000000000000000000"
32 .to_string(),
33 contract_spec: None,
34 }],
35 match_conditions: MatchConditions {
36 functions: vec![],
37 events: vec![],
38 transactions: vec![],
39 },
40 trigger_conditions: vec![],
41 triggers: vec![],
42 chain_configurations: vec![ChainConfiguration {
43 midnight: Some(MidnightMonitorConfig::default()),
44 ..Default::default()
45 }],
46 }
47 }
48}
49
50impl MonitorBuilder {
51 pub fn new() -> Self {
53 Self::default()
54 }
55
56 pub fn name(mut self, name: &str) -> Self {
58 self.name = name.to_string();
59 self
60 }
61
62 pub fn networks(mut self, networks: Vec<String>) -> Self {
64 self.networks = networks;
65 self
66 }
67
68 pub fn paused(mut self, paused: bool) -> Self {
70 self.paused = paused;
71 self
72 }
73
74 pub fn address(mut self, address: &str) -> Self {
76 self.addresses = vec![AddressWithSpec {
77 address: address.to_string(),
78 contract_spec: None,
79 }];
80 self
81 }
82
83 pub fn addresses(mut self, addresses: Vec<String>) -> Self {
85 self.addresses = addresses
86 .into_iter()
87 .map(|addr| AddressWithSpec {
88 address: addr,
89 contract_spec: None,
90 })
91 .collect();
92 self
93 }
94
95 pub fn add_address(mut self, address: &str) -> Self {
97 self.addresses.push(AddressWithSpec {
98 address: address.to_string(),
99 contract_spec: None,
100 });
101 self
102 }
103
104 pub fn function(mut self, signature: &str, expression: Option<String>) -> Self {
106 self.match_conditions.functions.push(FunctionCondition {
107 signature: signature.to_string(),
108 expression,
109 });
110 self
111 }
112
113 pub fn event(mut self, signature: &str, expression: Option<String>) -> Self {
115 self.match_conditions.events.push(EventCondition {
116 signature: signature.to_string(),
117 expression,
118 });
119 self
120 }
121
122 pub fn transaction(mut self, status: TransactionStatus, expression: Option<String>) -> Self {
124 self.match_conditions
125 .transactions
126 .push(TransactionCondition { status, expression });
127 self
128 }
129
130 pub fn trigger_condition(
132 mut self,
133 script_path: &str,
134 timeout_ms: u32,
135 language: ScriptLanguage,
136 arguments: Option<Vec<String>>,
137 ) -> Self {
138 self.trigger_conditions.push(TriggerConditions {
139 script_path: script_path.to_string(),
140 timeout_ms,
141 arguments,
142 language,
143 });
144 self
145 }
146
147 pub fn triggers(mut self, triggers: Vec<String>) -> Self {
149 self.triggers = triggers;
150 self
151 }
152
153 pub fn match_conditions(mut self, match_conditions: MatchConditions) -> Self {
155 self.match_conditions = match_conditions;
156 self
157 }
158
159 pub fn build(self) -> Monitor {
161 Monitor {
162 name: self.name,
163 networks: self.networks,
164 paused: self.paused,
165 addresses: self.addresses,
166 match_conditions: self.match_conditions,
167 trigger_conditions: self.trigger_conditions,
168 triggers: self.triggers,
169 chain_configurations: self.chain_configurations,
170 }
171 }
172}
173
174#[cfg(test)]
175mod tests {
176 use super::*;
177
178 #[test]
179 fn test_default_monitor() {
180 let monitor = MonitorBuilder::new().build();
181
182 assert_eq!(monitor.name, "TestMonitor");
183 assert_eq!(monitor.networks, vec!["midnight_testnet"]);
184 assert!(!monitor.paused);
185 assert_eq!(monitor.addresses.len(), 1);
186 assert_eq!(
187 monitor.addresses[0].address,
188 "0202000000000000000000000000000000000000000000000000000000000000000000"
189 );
190 assert!(monitor.addresses[0].contract_spec.is_none());
191 assert!(monitor.match_conditions.functions.is_empty());
192 assert!(monitor.match_conditions.events.is_empty());
193 assert!(monitor.match_conditions.transactions.is_empty());
194 assert!(monitor.trigger_conditions.is_empty());
195 assert!(monitor.triggers.is_empty());
196 }
197
198 #[test]
199 fn test_basic_builder_methods() {
200 let monitor = MonitorBuilder::new()
201 .name("MyMonitor")
202 .networks(vec!["midnight_testnet".to_string()])
203 .paused(true)
204 .address("0202000000000000000000000000000000000000000000000000000000000000000000")
205 .build();
206
207 assert_eq!(monitor.name, "MyMonitor");
208 assert_eq!(monitor.networks, vec!["midnight_testnet"]);
209 assert!(monitor.paused);
210 assert_eq!(monitor.addresses.len(), 1);
211 assert_eq!(
212 monitor.addresses[0].address,
213 "0202000000000000000000000000000000000000000000000000000000000000000000"
214 );
215 }
216
217 #[test]
218 fn test_address_methods() {
219 let monitor = MonitorBuilder::new()
220 .addresses(vec!["0x123".to_string(), "0x456".to_string()])
221 .add_address("0x789")
222 .build();
223
224 assert_eq!(monitor.addresses.len(), 3);
225 assert_eq!(monitor.addresses[0].address, "0x123");
226 assert_eq!(monitor.addresses[1].address, "0x456");
227 assert_eq!(monitor.addresses[2].address, "0x789");
228 }
229
230 #[test]
231 fn test_match_conditions() {
232 let monitor = MonitorBuilder::new()
233 .function("transfer(address,uint256)", Some("value >= 0".to_string()))
234 .event("Transfer(address,address,uint256)", None)
235 .transaction(TransactionStatus::Success, None)
236 .build();
237
238 assert_eq!(monitor.match_conditions.functions.len(), 1);
239 assert_eq!(
240 monitor.match_conditions.functions[0].signature,
241 "transfer(address,uint256)".to_string()
242 );
243 assert_eq!(
244 monitor.match_conditions.functions[0].expression,
245 Some("value >= 0".to_string())
246 );
247 assert_eq!(monitor.match_conditions.events.len(), 1);
248 assert_eq!(
249 monitor.match_conditions.events[0].signature,
250 "Transfer(address,address,uint256)".to_string()
251 );
252 assert_eq!(monitor.match_conditions.transactions.len(), 1);
253 assert_eq!(
254 monitor.match_conditions.transactions[0].status,
255 TransactionStatus::Success
256 );
257 }
258
259 #[test]
260 fn test_match_condition() {
261 let monitor = MonitorBuilder::new()
262 .match_conditions(MatchConditions {
263 functions: vec![FunctionCondition {
264 signature: "transfer(address,uint256)".to_string(),
265 expression: None,
266 }],
267 events: vec![],
268 transactions: vec![],
269 })
270 .build();
271 assert_eq!(monitor.match_conditions.functions.len(), 1);
272 assert_eq!(
273 monitor.match_conditions.functions[0].signature,
274 "transfer(address,uint256)"
275 );
276 assert!(monitor.match_conditions.events.is_empty());
277 assert!(monitor.match_conditions.transactions.is_empty());
278 }
279
280 #[test]
281 fn test_trigger_conditions() {
282 let monitor = MonitorBuilder::new()
283 .trigger_condition("script.py", 1000, ScriptLanguage::Python, None)
284 .trigger_condition(
285 "script.js",
286 2000,
287 ScriptLanguage::JavaScript,
288 Some(vec!["-verbose".to_string()]),
289 )
290 .build();
291
292 assert_eq!(monitor.trigger_conditions.len(), 2);
293 assert_eq!(monitor.trigger_conditions[0].script_path, "script.py");
294 assert_eq!(monitor.trigger_conditions[0].timeout_ms, 1000);
295 assert_eq!(
296 monitor.trigger_conditions[0].language,
297 ScriptLanguage::Python
298 );
299 assert_eq!(monitor.trigger_conditions[1].script_path, "script.js");
300 assert_eq!(monitor.trigger_conditions[1].timeout_ms, 2000);
301 assert_eq!(
302 monitor.trigger_conditions[1].language,
303 ScriptLanguage::JavaScript
304 );
305 assert_eq!(
306 monitor.trigger_conditions[1].arguments,
307 Some(vec!["-verbose".to_string()])
308 );
309 }
310
311 #[test]
312 fn test_triggers() {
313 let monitor = MonitorBuilder::new()
314 .triggers(vec!["trigger1".to_string(), "trigger2".to_string()])
315 .build();
316
317 assert_eq!(monitor.triggers.len(), 2);
318 assert_eq!(monitor.triggers[0], "trigger1");
319 assert_eq!(monitor.triggers[1], "trigger2");
320 }
321
322 #[test]
323 fn test_complex_monitor_build() {
324 let monitor = MonitorBuilder::new()
325 .name("ComplexMonitor")
326 .networks(vec!["ethereum".to_string(), "midnight_testnet".to_string()])
327 .paused(true)
328 .addresses(vec![
329 "0x123".to_string(),
330 "0202000000000000000000000000000000000000000000000000000000000000000000"
331 .to_string(),
332 ])
333 .add_address("0x789")
334 .function("transfer(address,uint256)", Some("value >= 0".to_string()))
335 .event("Transfer(address,address,uint256)", None)
336 .transaction(TransactionStatus::Success, None)
337 .trigger_condition("script.py", 1000, ScriptLanguage::Python, None)
338 .triggers(vec!["trigger1".to_string(), "trigger2".to_string()])
339 .build();
340
341 assert_eq!(monitor.name, "ComplexMonitor");
343 assert_eq!(monitor.networks, vec!["ethereum", "midnight_testnet"]);
344 assert!(monitor.paused);
345 assert_eq!(monitor.addresses.len(), 3);
346 assert_eq!(monitor.addresses[0].address, "0x123");
347 assert_eq!(
348 monitor.addresses[1].address,
349 "0202000000000000000000000000000000000000000000000000000000000000000000"
350 );
351 assert_eq!(monitor.addresses[2].address, "0x789");
352 assert_eq!(monitor.match_conditions.functions.len(), 1);
353 assert_eq!(
354 monitor.match_conditions.functions[0].expression,
355 Some("value >= 0".to_string())
356 );
357 assert_eq!(monitor.match_conditions.events.len(), 1);
358 assert_eq!(monitor.match_conditions.transactions.len(), 1);
359 assert_eq!(monitor.trigger_conditions.len(), 1);
360 assert_eq!(monitor.triggers.len(), 2);
361 }
362}