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