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}