openzeppelin_monitor/utils/tests/builders/
network.rs

1//! Test helper utilities for Network configuration
2//!
3//! - `NetworkBuilder`: Builder for creating test Network instances
4
5use crate::models::{BlockChainType, Network, RpcUrl, SecretString, SecretValue};
6
7/// Builder for creating test Network instances
8pub struct NetworkBuilder {
9	name: String,
10	slug: String,
11	network_type: BlockChainType,
12	chain_id: Option<u64>,
13	network_passphrase: Option<String>,
14	store_blocks: Option<bool>,
15	rpc_urls: Vec<RpcUrl>,
16	block_time_ms: u64,
17	confirmation_blocks: u64,
18	cron_schedule: String,
19	max_past_blocks: Option<u64>,
20}
21
22impl Default for NetworkBuilder {
23	fn default() -> Self {
24		Self {
25			name: "Test Network".to_string(),
26			slug: "test_network".to_string(),
27			network_type: BlockChainType::EVM,
28			chain_id: Some(1),
29			network_passphrase: None,
30			store_blocks: Some(true),
31			rpc_urls: vec![],
32			block_time_ms: 1000,
33			confirmation_blocks: 1,
34			cron_schedule: "0 */5 * * * *".to_string(),
35			max_past_blocks: Some(10),
36		}
37	}
38}
39
40impl NetworkBuilder {
41	pub fn new() -> Self {
42		Self::default()
43	}
44
45	pub fn name(mut self, name: &str) -> Self {
46		self.name = name.to_string();
47		self
48	}
49
50	pub fn slug(mut self, slug: &str) -> Self {
51		self.slug = slug.to_string();
52		self
53	}
54
55	pub fn network_type(mut self, network_type: BlockChainType) -> Self {
56		self.network_type = network_type;
57		self
58	}
59
60	pub fn chain_id(mut self, chain_id: u64) -> Self {
61		self.chain_id = Some(chain_id);
62		self
63	}
64
65	pub fn network_passphrase(mut self, passphrase: &str) -> Self {
66		self.network_passphrase = Some(passphrase.to_string());
67		self
68	}
69
70	pub fn store_blocks(mut self, store: bool) -> Self {
71		self.store_blocks = Some(store);
72		self
73	}
74
75	pub fn rpc_url(mut self, url: &str) -> Self {
76		self.rpc_urls = vec![RpcUrl {
77			type_: "rpc".to_string(),
78			url: SecretValue::Plain(SecretString::new(url.to_string())),
79			weight: 100,
80		}];
81		self
82	}
83
84	pub fn rpc_urls(mut self, urls: Vec<&str>) -> Self {
85		self.rpc_urls = urls
86			.into_iter()
87			.map(|url| RpcUrl {
88				type_: "rpc".to_string(),
89				url: SecretValue::Plain(SecretString::new(url.to_string())),
90				weight: 100,
91			})
92			.collect();
93		self
94	}
95
96	pub fn websocket_rpc_urls(mut self, urls: Vec<&str>) -> Self {
97		self.rpc_urls = urls
98			.into_iter()
99			.map(|url| RpcUrl {
100				type_: "ws_rpc".to_string(),
101				url: SecretValue::Plain(SecretString::new(url.to_string())),
102				weight: 100,
103			})
104			.collect();
105		self
106	}
107
108	pub fn add_rpc_url(mut self, url: &str, type_: &str, weight: u32) -> Self {
109		self.rpc_urls.push(RpcUrl {
110			type_: type_.to_string(),
111			url: SecretValue::Plain(SecretString::new(url.to_string())),
112			weight,
113		});
114		self
115	}
116
117	pub fn add_secret_rpc_url(mut self, url: SecretValue, type_: &str, weight: u32) -> Self {
118		self.rpc_urls.push(RpcUrl {
119			type_: type_.to_string(),
120			url,
121			weight,
122		});
123		self
124	}
125
126	pub fn clear_rpc_urls(mut self) -> Self {
127		self.rpc_urls.clear();
128		self
129	}
130
131	pub fn block_time_ms(mut self, block_time: u64) -> Self {
132		self.block_time_ms = block_time;
133		self
134	}
135
136	pub fn confirmation_blocks(mut self, blocks: u64) -> Self {
137		self.confirmation_blocks = blocks;
138		self
139	}
140
141	pub fn cron_schedule(mut self, schedule: &str) -> Self {
142		self.cron_schedule = schedule.to_string();
143		self
144	}
145
146	pub fn max_past_blocks(mut self, blocks: u64) -> Self {
147		self.max_past_blocks = Some(blocks);
148		self
149	}
150
151	pub fn build(self) -> Network {
152		Network {
153			name: self.name,
154			slug: self.slug,
155			network_type: self.network_type,
156			chain_id: self.chain_id,
157			network_passphrase: self.network_passphrase,
158			store_blocks: self.store_blocks,
159			rpc_urls: self.rpc_urls,
160			block_time_ms: self.block_time_ms,
161			confirmation_blocks: self.confirmation_blocks,
162			cron_schedule: self.cron_schedule,
163			max_past_blocks: self.max_past_blocks,
164		}
165	}
166}
167
168#[cfg(test)]
169mod tests {
170	use super::*;
171
172	#[test]
173	fn test_default_network() {
174		let network = NetworkBuilder::new().build();
175
176		assert_eq!(network.name, "Test Network");
177		assert_eq!(network.slug, "test_network");
178		assert_eq!(network.network_type, BlockChainType::EVM);
179		assert_eq!(network.chain_id, Some(1));
180		assert_eq!(network.network_passphrase, None);
181		assert_eq!(network.store_blocks, Some(true));
182		assert_eq!(network.block_time_ms, 1000);
183		assert_eq!(network.confirmation_blocks, 1);
184		assert_eq!(network.cron_schedule, "0 */5 * * * *");
185		assert_eq!(network.max_past_blocks, Some(10));
186		assert_eq!(network.rpc_urls.len(), 0);
187	}
188
189	#[test]
190	fn test_basic_builder_methods() {
191		let network = NetworkBuilder::new()
192			.name("Ethereum")
193			.slug("eth")
194			.network_type(BlockChainType::EVM)
195			.chain_id(1)
196			.store_blocks(true)
197			.block_time_ms(15000)
198			.confirmation_blocks(12)
199			.build();
200
201		assert_eq!(network.name, "Ethereum");
202		assert_eq!(network.slug, "eth");
203		assert_eq!(network.network_type, BlockChainType::EVM);
204		assert_eq!(network.chain_id, Some(1));
205		assert_eq!(network.store_blocks, Some(true));
206		assert_eq!(network.block_time_ms, 15000);
207		assert_eq!(network.confirmation_blocks, 12);
208	}
209
210	#[test]
211	fn test_rpc_url_methods() {
212		let network = NetworkBuilder::new()
213			.clear_rpc_urls()
214			.add_rpc_url("https://rpc1.example.com", "http", 50)
215			.add_rpc_url("https://rpc2.example.com", "ws", 50)
216			.build();
217
218		assert_eq!(network.rpc_urls.len(), 2);
219		assert_eq!(
220			network.rpc_urls[0].url.as_ref().to_string(),
221			"https://rpc1.example.com".to_string()
222		);
223		assert_eq!(network.rpc_urls[0].type_, "http");
224		assert_eq!(network.rpc_urls[0].weight, 50);
225		assert_eq!(
226			network.rpc_urls[1].url.as_ref().to_string(),
227			"https://rpc2.example.com".to_string()
228		);
229		assert_eq!(network.rpc_urls[1].type_, "ws");
230		assert_eq!(network.rpc_urls[1].weight, 50);
231	}
232
233	#[test]
234	fn test_secret_rpc_url() {
235		let network = NetworkBuilder::new()
236			.add_secret_rpc_url(
237				SecretValue::Plain(SecretString::new("https://rpc1.example.com".to_string())),
238				"rpc",
239				50,
240			)
241			.build();
242
243		assert_eq!(network.rpc_urls.len(), 1);
244		assert_eq!(
245			network.rpc_urls[0].url.as_ref().to_string(),
246			"https://rpc1.example.com".to_string()
247		);
248		assert_eq!(network.rpc_urls[0].type_, "rpc");
249	}
250
251	#[test]
252	fn test_rpc_urls_bulk_set() {
253		let network = NetworkBuilder::new()
254			.rpc_urls(vec!["https://rpc1.com", "https://rpc2.com"])
255			.build();
256
257		assert_eq!(network.rpc_urls.len(), 2);
258		assert_eq!(
259			network.rpc_urls[0].url.as_ref().to_string(),
260			"https://rpc1.com".to_string()
261		);
262		assert_eq!(
263			network.rpc_urls[1].url.as_ref().to_string(),
264			"https://rpc2.com".to_string()
265		);
266		// Check defaults are applied
267		assert!(network.rpc_urls.iter().all(|url| url.type_ == "rpc"));
268		assert!(network.rpc_urls.iter().all(|url| url.weight == 100));
269	}
270
271	#[test]
272	fn test_websocket_rpc_urls() {
273		let network = NetworkBuilder::new()
274			.websocket_rpc_urls(vec!["wss://ws1.example.com", "wss://ws2.example.com"])
275			.build();
276
277		assert_eq!(network.rpc_urls.len(), 2);
278		assert_eq!(
279			network.rpc_urls[0].url.as_ref().to_string(),
280			"wss://ws1.example.com".to_string()
281		);
282		assert_eq!(network.rpc_urls[0].type_, "ws_rpc");
283		assert_eq!(network.rpc_urls[1].type_, "ws_rpc");
284	}
285
286	#[test]
287	fn test_stellar_network() {
288		let network = NetworkBuilder::new()
289			.name("Stellar")
290			.slug("xlm")
291			.network_type(BlockChainType::Stellar)
292			.network_passphrase("Test SDF Network")
293			.build();
294
295		assert_eq!(network.network_type, BlockChainType::Stellar);
296		assert_eq!(
297			network.network_passphrase,
298			Some("Test SDF Network".to_string())
299		);
300		assert_eq!(network.chain_id, Some(1)); // From default
301	}
302}