1use crate::models::PaginationQuery;
11use crate::{
12 models::UpdateRelayerRequest,
13 models::{DisabledReason, RelayerNetworkPolicy, RelayerRepoModel, RepositoryError},
14};
15use async_trait::async_trait;
16use eyre::Result;
17use std::collections::HashMap;
18use tokio::sync::{Mutex, MutexGuard};
19
20use crate::repositories::{PaginatedResult, RelayerRepository, Repository};
21
22#[derive(Debug)]
23pub struct InMemoryRelayerRepository {
24 store: Mutex<HashMap<String, RelayerRepoModel>>,
25}
26
27impl InMemoryRelayerRepository {
28 pub fn new() -> Self {
29 Self {
30 store: Mutex::new(HashMap::new()),
31 }
32 }
33 async fn acquire_lock<T>(lock: &Mutex<T>) -> Result<MutexGuard<T>, RepositoryError> {
34 Ok(lock.lock().await)
35 }
36}
37
38impl Default for InMemoryRelayerRepository {
39 fn default() -> Self {
40 Self::new()
41 }
42}
43
44impl Clone for InMemoryRelayerRepository {
45 fn clone(&self) -> Self {
46 let data = self
48 .store
49 .try_lock()
50 .map(|guard| guard.clone())
51 .unwrap_or_else(|_| HashMap::new());
52
53 Self {
54 store: Mutex::new(data),
55 }
56 }
57}
58
59#[async_trait]
60impl RelayerRepository for InMemoryRelayerRepository {
61 async fn list_active(&self) -> Result<Vec<RelayerRepoModel>, RepositoryError> {
62 let store = Self::acquire_lock(&self.store).await?;
63 let active_relayers: Vec<RelayerRepoModel> = store
64 .values()
65 .filter(|&relayer| !relayer.paused)
66 .cloned()
67 .collect();
68 Ok(active_relayers)
69 }
70
71 async fn list_by_signer_id(
72 &self,
73 signer_id: &str,
74 ) -> Result<Vec<RelayerRepoModel>, RepositoryError> {
75 let store = Self::acquire_lock(&self.store).await?;
76 let relayers_with_signer: Vec<RelayerRepoModel> = store
77 .values()
78 .filter(|&relayer| relayer.signer_id == signer_id)
79 .cloned()
80 .collect();
81 Ok(relayers_with_signer)
82 }
83
84 async fn list_by_notification_id(
85 &self,
86 notification_id: &str,
87 ) -> Result<Vec<RelayerRepoModel>, RepositoryError> {
88 let store = Self::acquire_lock(&self.store).await?;
89 let relayers_with_notification: Vec<RelayerRepoModel> = store
90 .values()
91 .filter(|&relayer| {
92 relayer
93 .notification_id
94 .as_ref()
95 .is_some_and(|id| id == notification_id)
96 })
97 .cloned()
98 .collect();
99 Ok(relayers_with_notification)
100 }
101
102 async fn partial_update(
103 &self,
104 id: String,
105 update: UpdateRelayerRequest,
106 ) -> Result<RelayerRepoModel, RepositoryError> {
107 let mut store = Self::acquire_lock(&self.store).await?;
108 if let Some(relayer) = store.get_mut(&id) {
109 if let Some(paused) = update.paused {
110 relayer.paused = paused;
111 }
112 Ok(relayer.clone())
113 } else {
114 Err(RepositoryError::NotFound(format!(
115 "Relayer with ID {id} not found"
116 )))
117 }
118 }
119
120 async fn update_policy(
121 &self,
122 id: String,
123 policy: RelayerNetworkPolicy,
124 ) -> Result<RelayerRepoModel, RepositoryError> {
125 let mut store = Self::acquire_lock(&self.store).await?;
126 let relayer = store
127 .get_mut(&id)
128 .ok_or_else(|| RepositoryError::NotFound(format!("Relayer with ID {id} not found")))?;
129 relayer.policies = policy;
130 Ok(relayer.clone())
131 }
132
133 async fn disable_relayer(
134 &self,
135 relayer_id: String,
136 reason: DisabledReason,
137 ) -> Result<RelayerRepoModel, RepositoryError> {
138 let mut store = self.store.lock().await;
139 if let Some(relayer) = store.get_mut(&relayer_id) {
140 relayer.system_disabled = true;
141 relayer.disabled_reason = Some(reason);
142 Ok(relayer.clone())
143 } else {
144 Err(RepositoryError::NotFound(format!(
145 "Relayer with ID {relayer_id} not found"
146 )))
147 }
148 }
149
150 async fn enable_relayer(
151 &self,
152 relayer_id: String,
153 ) -> Result<RelayerRepoModel, RepositoryError> {
154 let mut store = self.store.lock().await;
155 if let Some(relayer) = store.get_mut(&relayer_id) {
156 relayer.system_disabled = false;
157 relayer.disabled_reason = None;
158 Ok(relayer.clone())
159 } else {
160 Err(RepositoryError::NotFound(format!(
161 "Relayer with ID {relayer_id} not found"
162 )))
163 }
164 }
165}
166
167#[async_trait]
168impl Repository<RelayerRepoModel, String> for InMemoryRelayerRepository {
169 async fn create(&self, relayer: RelayerRepoModel) -> Result<RelayerRepoModel, RepositoryError> {
170 let mut store = Self::acquire_lock(&self.store).await?;
171 if store.contains_key(&relayer.id) {
172 return Err(RepositoryError::ConstraintViolation(format!(
173 "Relayer with ID {} already exists",
174 relayer.id
175 )));
176 }
177 store.insert(relayer.id.clone(), relayer.clone());
178 Ok(relayer)
179 }
180
181 async fn get_by_id(&self, id: String) -> Result<RelayerRepoModel, RepositoryError> {
182 let store = Self::acquire_lock(&self.store).await?;
183 match store.get(&id) {
184 Some(relayer) => Ok(relayer.clone()),
185 None => Err(RepositoryError::NotFound(format!(
186 "Relayer with ID {id} not found"
187 ))),
188 }
189 }
190 #[allow(clippy::map_entry)]
191 async fn update(
192 &self,
193 id: String,
194 relayer: RelayerRepoModel,
195 ) -> Result<RelayerRepoModel, RepositoryError> {
196 let mut store = Self::acquire_lock(&self.store).await?;
197 if store.contains_key(&id) {
198 let mut updated_relayer = relayer;
200 updated_relayer.id = id.clone(); store.insert(id, updated_relayer.clone());
202 Ok(updated_relayer)
203 } else {
204 Err(RepositoryError::NotFound(format!(
205 "Relayer with ID {id} not found"
206 )))
207 }
208 }
209
210 async fn delete_by_id(&self, id: String) -> Result<(), RepositoryError> {
211 let mut store = Self::acquire_lock(&self.store).await?;
212 if store.remove(&id).is_some() {
213 Ok(())
214 } else {
215 Err(RepositoryError::NotFound(format!(
216 "Relayer with ID {id} not found"
217 )))
218 }
219 }
220
221 async fn list_all(&self) -> Result<Vec<RelayerRepoModel>, RepositoryError> {
222 let store = Self::acquire_lock(&self.store).await?;
223 Ok(store.values().cloned().collect())
224 }
225
226 async fn list_paginated(
227 &self,
228 query: PaginationQuery,
229 ) -> Result<PaginatedResult<RelayerRepoModel>, RepositoryError> {
230 let total = self.count().await?;
231 let start = ((query.page - 1) * query.per_page) as usize;
232 let items = self
233 .store
234 .lock()
235 .await
236 .values()
237 .skip(start)
238 .take(query.per_page as usize)
239 .cloned()
240 .collect();
241 Ok(PaginatedResult {
242 items,
243 total: total as u64,
244 page: query.page,
245 per_page: query.per_page,
246 })
247 }
248
249 async fn count(&self) -> Result<usize, RepositoryError> {
250 Ok(self.store.lock().await.len())
251 }
252
253 async fn has_entries(&self) -> Result<bool, RepositoryError> {
254 let store = Self::acquire_lock(&self.store).await?;
255 Ok(!store.is_empty())
256 }
257
258 async fn drop_all_entries(&self) -> Result<(), RepositoryError> {
259 let mut store = Self::acquire_lock(&self.store).await?;
260 store.clear();
261 Ok(())
262 }
263}
264
265#[cfg(test)]
266mod tests {
267 use crate::models::{NetworkType, RelayerEvmPolicy};
268
269 use super::*;
270
271 fn create_test_relayer(id: String) -> RelayerRepoModel {
272 RelayerRepoModel {
273 id: id.clone(),
274 name: format!("Relayer {}", id.clone()),
275 network: "TestNet".to_string(),
276 paused: false,
277 network_type: NetworkType::Evm,
278 policies: RelayerNetworkPolicy::Evm(RelayerEvmPolicy {
279 gas_price_cap: None,
280 whitelist_receivers: None,
281 eip1559_pricing: Some(false),
282 private_transactions: Some(false),
283 min_balance: Some(0),
284 gas_limit_estimation: Some(true),
285 }),
286 signer_id: "test".to_string(),
287 address: "0x".to_string(),
288 notification_id: None,
289 system_disabled: false,
290 custom_rpc_urls: None,
291 ..Default::default()
292 }
293 }
294
295 #[actix_web::test]
296 async fn test_new_repository_is_empty() {
297 let repo = InMemoryRelayerRepository::new();
298 assert_eq!(repo.count().await.unwrap(), 0);
299 }
300
301 #[actix_web::test]
302 async fn test_add_relayer() {
303 let repo = InMemoryRelayerRepository::new();
304 let relayer = create_test_relayer("test".to_string());
305
306 repo.create(relayer.clone()).await.unwrap();
307 assert_eq!(repo.count().await.unwrap(), 1);
308
309 let stored = repo.get_by_id("test".to_string()).await.unwrap();
310 assert_eq!(stored.id, relayer.id);
311 assert_eq!(stored.name, relayer.name);
312 }
313
314 #[actix_web::test]
315 async fn test_update_relayer() {
316 let repo = InMemoryRelayerRepository::new();
317 let mut relayer = create_test_relayer("test".to_string());
318
319 repo.create(relayer.clone()).await.unwrap();
320
321 relayer.name = "Updated Name".to_string();
322 repo.update("test".to_string(), relayer.clone())
323 .await
324 .unwrap();
325
326 let updated = repo.get_by_id("test".to_string()).await.unwrap();
327 assert_eq!(updated.name, "Updated Name");
328 }
329
330 #[actix_web::test]
331 async fn test_list_relayers() {
332 let repo = InMemoryRelayerRepository::new();
333 let relayer1 = create_test_relayer("test".to_string());
334 let relayer2 = create_test_relayer("test2".to_string());
335
336 repo.create(relayer1.clone()).await.unwrap();
337 repo.create(relayer2).await.unwrap();
338
339 let relayers = repo.list_all().await.unwrap();
340 assert_eq!(relayers.len(), 2);
341 }
342
343 #[actix_web::test]
344 async fn test_list_active_relayers() {
345 let repo = InMemoryRelayerRepository::new();
346 let relayer1 = create_test_relayer("test".to_string());
347 let mut relayer2 = create_test_relayer("test2".to_string());
348
349 relayer2.paused = true;
350
351 repo.create(relayer1.clone()).await.unwrap();
352 repo.create(relayer2).await.unwrap();
353
354 let active_relayers = repo.list_active().await.unwrap();
355 assert_eq!(active_relayers.len(), 1);
356 assert_eq!(active_relayers[0].id, "test".to_string());
357 }
358
359 #[actix_web::test]
360 async fn test_update_nonexistent_relayer() {
361 let repo = InMemoryRelayerRepository::new();
362 let relayer = create_test_relayer("test".to_string());
363
364 let result = repo.update("test".to_string(), relayer).await;
365 assert!(matches!(result, Err(RepositoryError::NotFound(_))));
366 }
367
368 #[actix_web::test]
369 async fn test_get_nonexistent_relayer() {
370 let repo = InMemoryRelayerRepository::new();
371
372 let result = repo.get_by_id("test".to_string()).await;
373 assert!(matches!(result, Err(RepositoryError::NotFound(_))));
374 }
375
376 #[actix_web::test]
377 async fn test_partial_update_relayer() {
378 let repo = InMemoryRelayerRepository::new();
379
380 let relayer_id = "test_relayer".to_string();
382 let initial_relayer = create_test_relayer(relayer_id.clone());
383
384 repo.create(initial_relayer.clone()).await.unwrap();
385
386 let update_req = UpdateRelayerRequest {
388 name: None,
389 paused: Some(true),
390 policies: None,
391 notification_id: None,
392 custom_rpc_urls: None,
393 };
394
395 let updated_relayer = repo
396 .partial_update(relayer_id.clone(), update_req)
397 .await
398 .unwrap();
399
400 assert_eq!(updated_relayer.id, initial_relayer.id);
401 assert!(updated_relayer.paused);
402 }
403
404 #[actix_web::test]
405 async fn test_disable_relayer() {
406 let repo = InMemoryRelayerRepository::new();
407
408 let relayer_id = "test_relayer".to_string();
410 let initial_relayer = create_test_relayer(relayer_id.clone());
411
412 repo.create(initial_relayer.clone()).await.unwrap();
413
414 let disabled_relayer = repo
416 .disable_relayer(
417 relayer_id.clone(),
418 DisabledReason::BalanceCheckFailed("test reason".to_string()),
419 )
420 .await
421 .unwrap();
422
423 assert_eq!(disabled_relayer.id, initial_relayer.id);
424 assert!(disabled_relayer.system_disabled);
425 assert_eq!(
426 disabled_relayer.disabled_reason,
427 Some(DisabledReason::BalanceCheckFailed(
428 "test reason".to_string()
429 ))
430 );
431 }
432
433 #[actix_web::test]
434 async fn test_enable_relayer() {
435 let repo = InMemoryRelayerRepository::new();
436
437 let relayer_id = "test_relayer".to_string();
439 let mut initial_relayer = create_test_relayer(relayer_id.clone());
440
441 initial_relayer.system_disabled = true;
442
443 repo.create(initial_relayer.clone()).await.unwrap();
444
445 let enabled_relayer = repo.enable_relayer(relayer_id.clone()).await.unwrap();
447
448 assert_eq!(enabled_relayer.id, initial_relayer.id);
449 assert!(!enabled_relayer.system_disabled);
450 }
451
452 #[actix_web::test]
453 async fn test_update_policy() {
454 let repo = InMemoryRelayerRepository::new();
455 let relayer = create_test_relayer("test".to_string());
456
457 repo.create(relayer.clone()).await.unwrap();
458
459 let new_policy = RelayerNetworkPolicy::Evm(RelayerEvmPolicy {
461 gas_price_cap: Some(50000000000),
462 whitelist_receivers: Some(vec!["0x1234".to_string()]),
463 eip1559_pricing: Some(true),
464 private_transactions: Some(true),
465 min_balance: Some(1000000),
466 gas_limit_estimation: Some(true),
467 });
468
469 let updated_relayer = repo
471 .update_policy("test".to_string(), new_policy.clone())
472 .await
473 .unwrap();
474
475 match updated_relayer.policies {
477 RelayerNetworkPolicy::Evm(policy) => {
478 assert_eq!(policy.gas_price_cap, Some(50000000000));
479 assert_eq!(policy.whitelist_receivers, Some(vec!["0x1234".to_string()]));
480 assert_eq!(policy.eip1559_pricing, Some(true));
481 assert!(policy.private_transactions.unwrap_or(false));
482 assert_eq!(policy.min_balance, Some(1000000));
483 }
484 _ => panic!("Unexpected policy type"),
485 }
486 }
487
488 #[actix_web::test]
490 async fn test_has_entries() {
491 let repo = InMemoryRelayerRepository::new();
492 assert!(!repo.has_entries().await.unwrap());
493
494 let relayer = create_test_relayer("test".to_string());
495
496 repo.create(relayer.clone()).await.unwrap();
497 assert!(repo.has_entries().await.unwrap());
498 }
499
500 #[actix_web::test]
501 async fn test_drop_all_entries() {
502 let repo = InMemoryRelayerRepository::new();
503 let relayer = create_test_relayer("test".to_string());
504
505 repo.create(relayer.clone()).await.unwrap();
506
507 assert!(repo.has_entries().await.unwrap());
508
509 repo.drop_all_entries().await.unwrap();
510 assert!(!repo.has_entries().await.unwrap());
511 }
512
513 #[actix_web::test]
514 async fn test_list_by_signer_id() {
515 let repo = InMemoryRelayerRepository::new();
516
517 let relayer1 = RelayerRepoModel {
519 id: "relayer-1".to_string(),
520 name: "Relayer 1".to_string(),
521 network: "ethereum".to_string(),
522 paused: false,
523 network_type: NetworkType::Evm,
524 signer_id: "signer-alpha".to_string(),
525 policies: RelayerNetworkPolicy::Evm(RelayerEvmPolicy::default()),
526 address: "0x1111".to_string(),
527 notification_id: None,
528 system_disabled: false,
529 custom_rpc_urls: None,
530 ..Default::default()
531 };
532
533 let relayer2 = RelayerRepoModel {
534 id: "relayer-2".to_string(),
535 name: "Relayer 2".to_string(),
536 network: "polygon".to_string(),
537 paused: true,
538 network_type: NetworkType::Evm,
539 signer_id: "signer-alpha".to_string(), policies: RelayerNetworkPolicy::Evm(RelayerEvmPolicy::default()),
541 address: "0x2222".to_string(),
542 notification_id: None,
543 system_disabled: false,
544 custom_rpc_urls: None,
545 ..Default::default()
546 };
547
548 let relayer3 = RelayerRepoModel {
549 id: "relayer-3".to_string(),
550 name: "Relayer 3".to_string(),
551 network: "solana".to_string(),
552 paused: false,
553 network_type: NetworkType::Solana,
554 signer_id: "signer-beta".to_string(), policies: RelayerNetworkPolicy::Solana(crate::models::RelayerSolanaPolicy::default()),
556 address: "solana-addr".to_string(),
557 notification_id: None,
558 system_disabled: false,
559 custom_rpc_urls: None,
560 ..Default::default()
561 };
562
563 let relayer4 = RelayerRepoModel {
564 id: "relayer-4".to_string(),
565 name: "Relayer 4".to_string(),
566 network: "stellar".to_string(),
567 paused: false,
568 network_type: NetworkType::Stellar,
569 signer_id: "signer-alpha".to_string(), policies: RelayerNetworkPolicy::Stellar(crate::models::RelayerStellarPolicy::default()),
571 address: "stellar-addr".to_string(),
572 notification_id: Some("notification-1".to_string()),
573 system_disabled: true,
574 custom_rpc_urls: None,
575 ..Default::default()
576 };
577
578 repo.create(relayer1).await.unwrap();
580 repo.create(relayer2).await.unwrap();
581 repo.create(relayer3).await.unwrap();
582 repo.create(relayer4).await.unwrap();
583
584 let relayers_with_alpha = repo.list_by_signer_id("signer-alpha").await.unwrap();
586 assert_eq!(relayers_with_alpha.len(), 3);
587
588 let alpha_ids: Vec<String> = relayers_with_alpha.iter().map(|r| r.id.clone()).collect();
589 assert!(alpha_ids.contains(&"relayer-1".to_string()));
590 assert!(alpha_ids.contains(&"relayer-2".to_string()));
591 assert!(alpha_ids.contains(&"relayer-4".to_string()));
592 assert!(!alpha_ids.contains(&"relayer-3".to_string()));
593
594 let relayer2_found = relayers_with_alpha
596 .iter()
597 .find(|r| r.id == "relayer-2")
598 .unwrap();
599 let relayer4_found = relayers_with_alpha
600 .iter()
601 .find(|r| r.id == "relayer-4")
602 .unwrap();
603 assert!(relayer2_found.paused); assert!(relayer4_found.system_disabled); let relayers_with_beta = repo.list_by_signer_id("signer-beta").await.unwrap();
608 assert_eq!(relayers_with_beta.len(), 1);
609 assert_eq!(relayers_with_beta[0].id, "relayer-3");
610 assert_eq!(relayers_with_beta[0].network_type, NetworkType::Solana);
611
612 let relayers_with_gamma = repo.list_by_signer_id("signer-gamma").await.unwrap();
614 assert_eq!(relayers_with_gamma.len(), 0);
615
616 let relayers_with_empty = repo.list_by_signer_id("").await.unwrap();
618 assert_eq!(relayers_with_empty.len(), 0);
619
620 assert_eq!(repo.count().await.unwrap(), 4);
622
623 repo.delete_by_id("relayer-2".to_string()).await.unwrap();
625
626 let relayers_with_alpha_after_delete =
627 repo.list_by_signer_id("signer-alpha").await.unwrap();
628 assert_eq!(relayers_with_alpha_after_delete.len(), 2); let alpha_ids_after: Vec<String> = relayers_with_alpha_after_delete
631 .iter()
632 .map(|r| r.id.clone())
633 .collect();
634 assert!(alpha_ids_after.contains(&"relayer-1".to_string()));
635 assert!(!alpha_ids_after.contains(&"relayer-2".to_string())); assert!(alpha_ids_after.contains(&"relayer-4".to_string()));
637 }
638
639 #[actix_web::test]
640 async fn test_list_by_notification_id() {
641 let repo = InMemoryRelayerRepository::new();
642
643 let relayer1 = RelayerRepoModel {
645 id: "relayer-1".to_string(),
646 name: "Relayer 1".to_string(),
647 network: "ethereum".to_string(),
648 paused: false,
649 network_type: NetworkType::Evm,
650 signer_id: "test-signer".to_string(),
651 policies: RelayerNetworkPolicy::Evm(RelayerEvmPolicy::default()),
652 address: "0x1111".to_string(),
653 notification_id: Some("notification-alpha".to_string()),
654 system_disabled: false,
655 custom_rpc_urls: None,
656 ..Default::default()
657 };
658
659 let relayer2 = RelayerRepoModel {
660 id: "relayer-2".to_string(),
661 name: "Relayer 2".to_string(),
662 network: "polygon".to_string(),
663 paused: true,
664 network_type: NetworkType::Evm,
665 signer_id: "test-signer".to_string(),
666 policies: RelayerNetworkPolicy::Evm(RelayerEvmPolicy::default()),
667 address: "0x2222".to_string(),
668 notification_id: Some("notification-alpha".to_string()), system_disabled: false,
670 custom_rpc_urls: None,
671 ..Default::default()
672 };
673
674 let relayer3 = RelayerRepoModel {
675 id: "relayer-3".to_string(),
676 name: "Relayer 3".to_string(),
677 network: "solana".to_string(),
678 paused: false,
679 network_type: NetworkType::Solana,
680 signer_id: "test-signer".to_string(),
681 policies: RelayerNetworkPolicy::Solana(crate::models::RelayerSolanaPolicy::default()),
682 address: "solana-addr".to_string(),
683 notification_id: Some("notification-beta".to_string()), system_disabled: false,
685 custom_rpc_urls: None,
686 ..Default::default()
687 };
688
689 let relayer4 = RelayerRepoModel {
690 id: "relayer-4".to_string(),
691 name: "Relayer 4".to_string(),
692 network: "stellar".to_string(),
693 paused: false,
694 network_type: NetworkType::Stellar,
695 signer_id: "test-signer".to_string(),
696 policies: RelayerNetworkPolicy::Stellar(crate::models::RelayerStellarPolicy::default()),
697 address: "stellar-addr".to_string(),
698 notification_id: None, system_disabled: true,
700 custom_rpc_urls: None,
701 ..Default::default()
702 };
703
704 let relayer5 = RelayerRepoModel {
705 id: "relayer-5".to_string(),
706 name: "Relayer 5".to_string(),
707 network: "bsc".to_string(),
708 paused: false,
709 network_type: NetworkType::Evm,
710 signer_id: "test-signer".to_string(),
711 policies: RelayerNetworkPolicy::Evm(RelayerEvmPolicy::default()),
712 address: "0x5555".to_string(),
713 notification_id: Some("notification-alpha".to_string()), system_disabled: false,
715 custom_rpc_urls: None,
716 ..Default::default()
717 };
718
719 repo.create(relayer1).await.unwrap();
721 repo.create(relayer2).await.unwrap();
722 repo.create(relayer3).await.unwrap();
723 repo.create(relayer4).await.unwrap();
724 repo.create(relayer5).await.unwrap();
725
726 let relayers_with_alpha = repo
728 .list_by_notification_id("notification-alpha")
729 .await
730 .unwrap();
731 assert_eq!(relayers_with_alpha.len(), 3);
732
733 let alpha_ids: Vec<String> = relayers_with_alpha.iter().map(|r| r.id.clone()).collect();
734 assert!(alpha_ids.contains(&"relayer-1".to_string()));
735 assert!(alpha_ids.contains(&"relayer-2".to_string()));
736 assert!(alpha_ids.contains(&"relayer-5".to_string()));
737 assert!(!alpha_ids.contains(&"relayer-3".to_string()));
738 assert!(!alpha_ids.contains(&"relayer-4".to_string()));
739
740 let relayer2_found = relayers_with_alpha
742 .iter()
743 .find(|r| r.id == "relayer-2")
744 .unwrap();
745 let relayer5_found = relayers_with_alpha
746 .iter()
747 .find(|r| r.id == "relayer-5")
748 .unwrap();
749 assert!(relayer2_found.paused); assert_eq!(relayer5_found.network, "bsc"); let relayers_with_beta = repo
754 .list_by_notification_id("notification-beta")
755 .await
756 .unwrap();
757 assert_eq!(relayers_with_beta.len(), 1);
758 assert_eq!(relayers_with_beta[0].id, "relayer-3");
759 assert_eq!(relayers_with_beta[0].network_type, NetworkType::Solana);
760
761 let relayers_with_gamma = repo
763 .list_by_notification_id("notification-gamma")
764 .await
765 .unwrap();
766 assert_eq!(relayers_with_gamma.len(), 0);
767
768 let relayers_with_empty = repo.list_by_notification_id("").await.unwrap();
770 assert_eq!(relayers_with_empty.len(), 0);
771
772 assert_eq!(repo.count().await.unwrap(), 5);
774
775 repo.delete_by_id("relayer-2".to_string()).await.unwrap();
777
778 let relayers_with_alpha_after_delete = repo
779 .list_by_notification_id("notification-alpha")
780 .await
781 .unwrap();
782 assert_eq!(relayers_with_alpha_after_delete.len(), 2); let alpha_ids_after: Vec<String> = relayers_with_alpha_after_delete
785 .iter()
786 .map(|r| r.id.clone())
787 .collect();
788 assert!(alpha_ids_after.contains(&"relayer-1".to_string()));
789 assert!(!alpha_ids_after.contains(&"relayer-2".to_string())); assert!(alpha_ids_after.contains(&"relayer-5".to_string()));
791
792 let mut updated_relayer = repo.get_by_id("relayer-5".to_string()).await.unwrap();
794 updated_relayer.notification_id = Some("notification-beta".to_string());
795 repo.update("relayer-5".to_string(), updated_relayer)
796 .await
797 .unwrap();
798
799 let relayers_with_alpha_final = repo
801 .list_by_notification_id("notification-alpha")
802 .await
803 .unwrap();
804 assert_eq!(relayers_with_alpha_final.len(), 1);
805 assert_eq!(relayers_with_alpha_final[0].id, "relayer-1");
806
807 let relayers_with_beta_final = repo
809 .list_by_notification_id("notification-beta")
810 .await
811 .unwrap();
812 assert_eq!(relayers_with_beta_final.len(), 2);
813 let beta_ids_final: Vec<String> = relayers_with_beta_final
814 .iter()
815 .map(|r| r.id.clone())
816 .collect();
817 assert!(beta_ids_final.contains(&"relayer-3".to_string()));
818 assert!(beta_ids_final.contains(&"relayer-5".to_string()));
819 }
820}