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 fn is_persistent_storage(&self) -> bool {
167 false
168 }
169}
170
171#[async_trait]
172impl Repository<RelayerRepoModel, String> for InMemoryRelayerRepository {
173 async fn create(&self, relayer: RelayerRepoModel) -> Result<RelayerRepoModel, RepositoryError> {
174 let mut store = Self::acquire_lock(&self.store).await?;
175 if store.contains_key(&relayer.id) {
176 return Err(RepositoryError::ConstraintViolation(format!(
177 "Relayer with ID {} already exists",
178 relayer.id
179 )));
180 }
181 store.insert(relayer.id.clone(), relayer.clone());
182 Ok(relayer)
183 }
184
185 async fn get_by_id(&self, id: String) -> Result<RelayerRepoModel, RepositoryError> {
186 let store = Self::acquire_lock(&self.store).await?;
187 match store.get(&id) {
188 Some(relayer) => Ok(relayer.clone()),
189 None => Err(RepositoryError::NotFound(format!(
190 "Relayer with ID {id} not found"
191 ))),
192 }
193 }
194 #[allow(clippy::map_entry)]
195 async fn update(
196 &self,
197 id: String,
198 relayer: RelayerRepoModel,
199 ) -> Result<RelayerRepoModel, RepositoryError> {
200 let mut store = Self::acquire_lock(&self.store).await?;
201 if store.contains_key(&id) {
202 let mut updated_relayer = relayer;
204 updated_relayer.id = id.clone(); store.insert(id, updated_relayer.clone());
206 Ok(updated_relayer)
207 } else {
208 Err(RepositoryError::NotFound(format!(
209 "Relayer with ID {id} not found"
210 )))
211 }
212 }
213
214 async fn delete_by_id(&self, id: String) -> Result<(), RepositoryError> {
215 let mut store = Self::acquire_lock(&self.store).await?;
216 if store.remove(&id).is_some() {
217 Ok(())
218 } else {
219 Err(RepositoryError::NotFound(format!(
220 "Relayer with ID {id} not found"
221 )))
222 }
223 }
224
225 async fn list_all(&self) -> Result<Vec<RelayerRepoModel>, RepositoryError> {
226 let store = Self::acquire_lock(&self.store).await?;
227 Ok(store.values().cloned().collect())
228 }
229
230 async fn list_paginated(
231 &self,
232 query: PaginationQuery,
233 ) -> Result<PaginatedResult<RelayerRepoModel>, RepositoryError> {
234 let total = self.count().await?;
235 let start = ((query.page - 1) * query.per_page) as usize;
236 let items = self
237 .store
238 .lock()
239 .await
240 .values()
241 .skip(start)
242 .take(query.per_page as usize)
243 .cloned()
244 .collect();
245 Ok(PaginatedResult {
246 items,
247 total: total as u64,
248 page: query.page,
249 per_page: query.per_page,
250 })
251 }
252
253 async fn count(&self) -> Result<usize, RepositoryError> {
254 Ok(self.store.lock().await.len())
255 }
256
257 async fn has_entries(&self) -> Result<bool, RepositoryError> {
258 let store = Self::acquire_lock(&self.store).await?;
259 Ok(!store.is_empty())
260 }
261
262 async fn drop_all_entries(&self) -> Result<(), RepositoryError> {
263 let mut store = Self::acquire_lock(&self.store).await?;
264 store.clear();
265 Ok(())
266 }
267}
268
269#[cfg(test)]
270mod tests {
271 use crate::models::{NetworkType, RelayerEvmPolicy};
272
273 use super::*;
274
275 fn create_test_relayer(id: String) -> RelayerRepoModel {
276 RelayerRepoModel {
277 id: id.clone(),
278 name: format!("Relayer {}", id.clone()),
279 network: "TestNet".to_string(),
280 paused: false,
281 network_type: NetworkType::Evm,
282 policies: RelayerNetworkPolicy::Evm(RelayerEvmPolicy {
283 gas_price_cap: None,
284 whitelist_receivers: None,
285 eip1559_pricing: Some(false),
286 private_transactions: Some(false),
287 min_balance: Some(0),
288 gas_limit_estimation: Some(true),
289 }),
290 signer_id: "test".to_string(),
291 address: "0x".to_string(),
292 notification_id: None,
293 system_disabled: false,
294 custom_rpc_urls: None,
295 ..Default::default()
296 }
297 }
298
299 #[actix_web::test]
300 async fn test_new_repository_is_empty() {
301 let repo = InMemoryRelayerRepository::new();
302 assert_eq!(repo.count().await.unwrap(), 0);
303 }
304
305 #[actix_web::test]
306 async fn test_add_relayer() {
307 let repo = InMemoryRelayerRepository::new();
308 let relayer = create_test_relayer("test".to_string());
309
310 repo.create(relayer.clone()).await.unwrap();
311 assert_eq!(repo.count().await.unwrap(), 1);
312
313 let stored = repo.get_by_id("test".to_string()).await.unwrap();
314 assert_eq!(stored.id, relayer.id);
315 assert_eq!(stored.name, relayer.name);
316 }
317
318 #[actix_web::test]
319 async fn test_update_relayer() {
320 let repo = InMemoryRelayerRepository::new();
321 let mut relayer = create_test_relayer("test".to_string());
322
323 repo.create(relayer.clone()).await.unwrap();
324
325 relayer.name = "Updated Name".to_string();
326 repo.update("test".to_string(), relayer.clone())
327 .await
328 .unwrap();
329
330 let updated = repo.get_by_id("test".to_string()).await.unwrap();
331 assert_eq!(updated.name, "Updated Name");
332 }
333
334 #[actix_web::test]
335 async fn test_list_relayers() {
336 let repo = InMemoryRelayerRepository::new();
337 let relayer1 = create_test_relayer("test".to_string());
338 let relayer2 = create_test_relayer("test2".to_string());
339
340 repo.create(relayer1.clone()).await.unwrap();
341 repo.create(relayer2).await.unwrap();
342
343 let relayers = repo.list_all().await.unwrap();
344 assert_eq!(relayers.len(), 2);
345 }
346
347 #[actix_web::test]
348 async fn test_list_active_relayers() {
349 let repo = InMemoryRelayerRepository::new();
350 let relayer1 = create_test_relayer("test".to_string());
351 let mut relayer2 = create_test_relayer("test2".to_string());
352
353 relayer2.paused = true;
354
355 repo.create(relayer1.clone()).await.unwrap();
356 repo.create(relayer2).await.unwrap();
357
358 let active_relayers = repo.list_active().await.unwrap();
359 assert_eq!(active_relayers.len(), 1);
360 assert_eq!(active_relayers[0].id, "test".to_string());
361 }
362
363 #[actix_web::test]
364 async fn test_update_nonexistent_relayer() {
365 let repo = InMemoryRelayerRepository::new();
366 let relayer = create_test_relayer("test".to_string());
367
368 let result = repo.update("test".to_string(), relayer).await;
369 assert!(matches!(result, Err(RepositoryError::NotFound(_))));
370 }
371
372 #[actix_web::test]
373 async fn test_get_nonexistent_relayer() {
374 let repo = InMemoryRelayerRepository::new();
375
376 let result = repo.get_by_id("test".to_string()).await;
377 assert!(matches!(result, Err(RepositoryError::NotFound(_))));
378 }
379
380 #[actix_web::test]
381 async fn test_partial_update_relayer() {
382 let repo = InMemoryRelayerRepository::new();
383
384 let relayer_id = "test_relayer".to_string();
386 let initial_relayer = create_test_relayer(relayer_id.clone());
387
388 repo.create(initial_relayer.clone()).await.unwrap();
389
390 let update_req = UpdateRelayerRequest {
392 name: None,
393 paused: Some(true),
394 policies: None,
395 notification_id: None,
396 custom_rpc_urls: None,
397 };
398
399 let updated_relayer = repo
400 .partial_update(relayer_id.clone(), update_req)
401 .await
402 .unwrap();
403
404 assert_eq!(updated_relayer.id, initial_relayer.id);
405 assert!(updated_relayer.paused);
406 }
407
408 #[actix_web::test]
409 async fn test_disable_relayer() {
410 let repo = InMemoryRelayerRepository::new();
411
412 let relayer_id = "test_relayer".to_string();
414 let initial_relayer = create_test_relayer(relayer_id.clone());
415
416 repo.create(initial_relayer.clone()).await.unwrap();
417
418 let disabled_relayer = repo
420 .disable_relayer(
421 relayer_id.clone(),
422 DisabledReason::BalanceCheckFailed("test reason".to_string()),
423 )
424 .await
425 .unwrap();
426
427 assert_eq!(disabled_relayer.id, initial_relayer.id);
428 assert!(disabled_relayer.system_disabled);
429 assert_eq!(
430 disabled_relayer.disabled_reason,
431 Some(DisabledReason::BalanceCheckFailed(
432 "test reason".to_string()
433 ))
434 );
435 }
436
437 #[actix_web::test]
438 async fn test_enable_relayer() {
439 let repo = InMemoryRelayerRepository::new();
440
441 let relayer_id = "test_relayer".to_string();
443 let mut initial_relayer = create_test_relayer(relayer_id.clone());
444
445 initial_relayer.system_disabled = true;
446
447 repo.create(initial_relayer.clone()).await.unwrap();
448
449 let enabled_relayer = repo.enable_relayer(relayer_id.clone()).await.unwrap();
451
452 assert_eq!(enabled_relayer.id, initial_relayer.id);
453 assert!(!enabled_relayer.system_disabled);
454 }
455
456 #[actix_web::test]
457 async fn test_update_policy() {
458 let repo = InMemoryRelayerRepository::new();
459 let relayer = create_test_relayer("test".to_string());
460
461 repo.create(relayer.clone()).await.unwrap();
462
463 let new_policy = RelayerNetworkPolicy::Evm(RelayerEvmPolicy {
465 gas_price_cap: Some(50000000000),
466 whitelist_receivers: Some(vec!["0x1234".to_string()]),
467 eip1559_pricing: Some(true),
468 private_transactions: Some(true),
469 min_balance: Some(1000000),
470 gas_limit_estimation: Some(true),
471 });
472
473 let updated_relayer = repo
475 .update_policy("test".to_string(), new_policy.clone())
476 .await
477 .unwrap();
478
479 match updated_relayer.policies {
481 RelayerNetworkPolicy::Evm(policy) => {
482 assert_eq!(policy.gas_price_cap, Some(50000000000));
483 assert_eq!(policy.whitelist_receivers, Some(vec!["0x1234".to_string()]));
484 assert_eq!(policy.eip1559_pricing, Some(true));
485 assert!(policy.private_transactions.unwrap_or(false));
486 assert_eq!(policy.min_balance, Some(1000000));
487 }
488 _ => panic!("Unexpected policy type"),
489 }
490 }
491
492 #[actix_web::test]
494 async fn test_has_entries() {
495 let repo = InMemoryRelayerRepository::new();
496 assert!(!repo.has_entries().await.unwrap());
497
498 let relayer = create_test_relayer("test".to_string());
499
500 repo.create(relayer.clone()).await.unwrap();
501 assert!(repo.has_entries().await.unwrap());
502 }
503
504 #[actix_web::test]
505 async fn test_drop_all_entries() {
506 let repo = InMemoryRelayerRepository::new();
507 let relayer = create_test_relayer("test".to_string());
508
509 repo.create(relayer.clone()).await.unwrap();
510
511 assert!(repo.has_entries().await.unwrap());
512
513 repo.drop_all_entries().await.unwrap();
514 assert!(!repo.has_entries().await.unwrap());
515 }
516
517 #[actix_web::test]
518 async fn test_list_by_signer_id() {
519 let repo = InMemoryRelayerRepository::new();
520
521 let relayer1 = RelayerRepoModel {
523 id: "relayer-1".to_string(),
524 name: "Relayer 1".to_string(),
525 network: "ethereum".to_string(),
526 paused: false,
527 network_type: NetworkType::Evm,
528 signer_id: "signer-alpha".to_string(),
529 policies: RelayerNetworkPolicy::Evm(RelayerEvmPolicy::default()),
530 address: "0x1111".to_string(),
531 notification_id: None,
532 system_disabled: false,
533 custom_rpc_urls: None,
534 ..Default::default()
535 };
536
537 let relayer2 = RelayerRepoModel {
538 id: "relayer-2".to_string(),
539 name: "Relayer 2".to_string(),
540 network: "polygon".to_string(),
541 paused: true,
542 network_type: NetworkType::Evm,
543 signer_id: "signer-alpha".to_string(), policies: RelayerNetworkPolicy::Evm(RelayerEvmPolicy::default()),
545 address: "0x2222".to_string(),
546 notification_id: None,
547 system_disabled: false,
548 custom_rpc_urls: None,
549 ..Default::default()
550 };
551
552 let relayer3 = RelayerRepoModel {
553 id: "relayer-3".to_string(),
554 name: "Relayer 3".to_string(),
555 network: "solana".to_string(),
556 paused: false,
557 network_type: NetworkType::Solana,
558 signer_id: "signer-beta".to_string(), policies: RelayerNetworkPolicy::Solana(crate::models::RelayerSolanaPolicy::default()),
560 address: "solana-addr".to_string(),
561 notification_id: None,
562 system_disabled: false,
563 custom_rpc_urls: None,
564 ..Default::default()
565 };
566
567 let relayer4 = RelayerRepoModel {
568 id: "relayer-4".to_string(),
569 name: "Relayer 4".to_string(),
570 network: "stellar".to_string(),
571 paused: false,
572 network_type: NetworkType::Stellar,
573 signer_id: "signer-alpha".to_string(), policies: RelayerNetworkPolicy::Stellar(crate::models::RelayerStellarPolicy::default()),
575 address: "stellar-addr".to_string(),
576 notification_id: Some("notification-1".to_string()),
577 system_disabled: true,
578 custom_rpc_urls: None,
579 ..Default::default()
580 };
581
582 repo.create(relayer1).await.unwrap();
584 repo.create(relayer2).await.unwrap();
585 repo.create(relayer3).await.unwrap();
586 repo.create(relayer4).await.unwrap();
587
588 let relayers_with_alpha = repo.list_by_signer_id("signer-alpha").await.unwrap();
590 assert_eq!(relayers_with_alpha.len(), 3);
591
592 let alpha_ids: Vec<String> = relayers_with_alpha.iter().map(|r| r.id.clone()).collect();
593 assert!(alpha_ids.contains(&"relayer-1".to_string()));
594 assert!(alpha_ids.contains(&"relayer-2".to_string()));
595 assert!(alpha_ids.contains(&"relayer-4".to_string()));
596 assert!(!alpha_ids.contains(&"relayer-3".to_string()));
597
598 let relayer2_found = relayers_with_alpha
600 .iter()
601 .find(|r| r.id == "relayer-2")
602 .unwrap();
603 let relayer4_found = relayers_with_alpha
604 .iter()
605 .find(|r| r.id == "relayer-4")
606 .unwrap();
607 assert!(relayer2_found.paused); assert!(relayer4_found.system_disabled); let relayers_with_beta = repo.list_by_signer_id("signer-beta").await.unwrap();
612 assert_eq!(relayers_with_beta.len(), 1);
613 assert_eq!(relayers_with_beta[0].id, "relayer-3");
614 assert_eq!(relayers_with_beta[0].network_type, NetworkType::Solana);
615
616 let relayers_with_gamma = repo.list_by_signer_id("signer-gamma").await.unwrap();
618 assert_eq!(relayers_with_gamma.len(), 0);
619
620 let relayers_with_empty = repo.list_by_signer_id("").await.unwrap();
622 assert_eq!(relayers_with_empty.len(), 0);
623
624 assert_eq!(repo.count().await.unwrap(), 4);
626
627 repo.delete_by_id("relayer-2".to_string()).await.unwrap();
629
630 let relayers_with_alpha_after_delete =
631 repo.list_by_signer_id("signer-alpha").await.unwrap();
632 assert_eq!(relayers_with_alpha_after_delete.len(), 2); let alpha_ids_after: Vec<String> = relayers_with_alpha_after_delete
635 .iter()
636 .map(|r| r.id.clone())
637 .collect();
638 assert!(alpha_ids_after.contains(&"relayer-1".to_string()));
639 assert!(!alpha_ids_after.contains(&"relayer-2".to_string())); assert!(alpha_ids_after.contains(&"relayer-4".to_string()));
641 }
642
643 #[actix_web::test]
644 async fn test_list_by_notification_id() {
645 let repo = InMemoryRelayerRepository::new();
646
647 let relayer1 = RelayerRepoModel {
649 id: "relayer-1".to_string(),
650 name: "Relayer 1".to_string(),
651 network: "ethereum".to_string(),
652 paused: false,
653 network_type: NetworkType::Evm,
654 signer_id: "test-signer".to_string(),
655 policies: RelayerNetworkPolicy::Evm(RelayerEvmPolicy::default()),
656 address: "0x1111".to_string(),
657 notification_id: Some("notification-alpha".to_string()),
658 system_disabled: false,
659 custom_rpc_urls: None,
660 ..Default::default()
661 };
662
663 let relayer2 = RelayerRepoModel {
664 id: "relayer-2".to_string(),
665 name: "Relayer 2".to_string(),
666 network: "polygon".to_string(),
667 paused: true,
668 network_type: NetworkType::Evm,
669 signer_id: "test-signer".to_string(),
670 policies: RelayerNetworkPolicy::Evm(RelayerEvmPolicy::default()),
671 address: "0x2222".to_string(),
672 notification_id: Some("notification-alpha".to_string()), system_disabled: false,
674 custom_rpc_urls: None,
675 ..Default::default()
676 };
677
678 let relayer3 = RelayerRepoModel {
679 id: "relayer-3".to_string(),
680 name: "Relayer 3".to_string(),
681 network: "solana".to_string(),
682 paused: false,
683 network_type: NetworkType::Solana,
684 signer_id: "test-signer".to_string(),
685 policies: RelayerNetworkPolicy::Solana(crate::models::RelayerSolanaPolicy::default()),
686 address: "solana-addr".to_string(),
687 notification_id: Some("notification-beta".to_string()), system_disabled: false,
689 custom_rpc_urls: None,
690 ..Default::default()
691 };
692
693 let relayer4 = RelayerRepoModel {
694 id: "relayer-4".to_string(),
695 name: "Relayer 4".to_string(),
696 network: "stellar".to_string(),
697 paused: false,
698 network_type: NetworkType::Stellar,
699 signer_id: "test-signer".to_string(),
700 policies: RelayerNetworkPolicy::Stellar(crate::models::RelayerStellarPolicy::default()),
701 address: "stellar-addr".to_string(),
702 notification_id: None, system_disabled: true,
704 custom_rpc_urls: None,
705 ..Default::default()
706 };
707
708 let relayer5 = RelayerRepoModel {
709 id: "relayer-5".to_string(),
710 name: "Relayer 5".to_string(),
711 network: "bsc".to_string(),
712 paused: false,
713 network_type: NetworkType::Evm,
714 signer_id: "test-signer".to_string(),
715 policies: RelayerNetworkPolicy::Evm(RelayerEvmPolicy::default()),
716 address: "0x5555".to_string(),
717 notification_id: Some("notification-alpha".to_string()), system_disabled: false,
719 custom_rpc_urls: None,
720 ..Default::default()
721 };
722
723 repo.create(relayer1).await.unwrap();
725 repo.create(relayer2).await.unwrap();
726 repo.create(relayer3).await.unwrap();
727 repo.create(relayer4).await.unwrap();
728 repo.create(relayer5).await.unwrap();
729
730 let relayers_with_alpha = repo
732 .list_by_notification_id("notification-alpha")
733 .await
734 .unwrap();
735 assert_eq!(relayers_with_alpha.len(), 3);
736
737 let alpha_ids: Vec<String> = relayers_with_alpha.iter().map(|r| r.id.clone()).collect();
738 assert!(alpha_ids.contains(&"relayer-1".to_string()));
739 assert!(alpha_ids.contains(&"relayer-2".to_string()));
740 assert!(alpha_ids.contains(&"relayer-5".to_string()));
741 assert!(!alpha_ids.contains(&"relayer-3".to_string()));
742 assert!(!alpha_ids.contains(&"relayer-4".to_string()));
743
744 let relayer2_found = relayers_with_alpha
746 .iter()
747 .find(|r| r.id == "relayer-2")
748 .unwrap();
749 let relayer5_found = relayers_with_alpha
750 .iter()
751 .find(|r| r.id == "relayer-5")
752 .unwrap();
753 assert!(relayer2_found.paused); assert_eq!(relayer5_found.network, "bsc"); let relayers_with_beta = repo
758 .list_by_notification_id("notification-beta")
759 .await
760 .unwrap();
761 assert_eq!(relayers_with_beta.len(), 1);
762 assert_eq!(relayers_with_beta[0].id, "relayer-3");
763 assert_eq!(relayers_with_beta[0].network_type, NetworkType::Solana);
764
765 let relayers_with_gamma = repo
767 .list_by_notification_id("notification-gamma")
768 .await
769 .unwrap();
770 assert_eq!(relayers_with_gamma.len(), 0);
771
772 let relayers_with_empty = repo.list_by_notification_id("").await.unwrap();
774 assert_eq!(relayers_with_empty.len(), 0);
775
776 assert_eq!(repo.count().await.unwrap(), 5);
778
779 repo.delete_by_id("relayer-2".to_string()).await.unwrap();
781
782 let relayers_with_alpha_after_delete = repo
783 .list_by_notification_id("notification-alpha")
784 .await
785 .unwrap();
786 assert_eq!(relayers_with_alpha_after_delete.len(), 2); let alpha_ids_after: Vec<String> = relayers_with_alpha_after_delete
789 .iter()
790 .map(|r| r.id.clone())
791 .collect();
792 assert!(alpha_ids_after.contains(&"relayer-1".to_string()));
793 assert!(!alpha_ids_after.contains(&"relayer-2".to_string())); assert!(alpha_ids_after.contains(&"relayer-5".to_string()));
795
796 let mut updated_relayer = repo.get_by_id("relayer-5".to_string()).await.unwrap();
798 updated_relayer.notification_id = Some("notification-beta".to_string());
799 repo.update("relayer-5".to_string(), updated_relayer)
800 .await
801 .unwrap();
802
803 let relayers_with_alpha_final = repo
805 .list_by_notification_id("notification-alpha")
806 .await
807 .unwrap();
808 assert_eq!(relayers_with_alpha_final.len(), 1);
809 assert_eq!(relayers_with_alpha_final[0].id, "relayer-1");
810
811 let relayers_with_beta_final = repo
813 .list_by_notification_id("notification-beta")
814 .await
815 .unwrap();
816 assert_eq!(relayers_with_beta_final.len(), 2);
817 let beta_ids_final: Vec<String> = relayers_with_beta_final
818 .iter()
819 .map(|r| r.id.clone())
820 .collect();
821 assert!(beta_ids_final.contains(&"relayer-3".to_string()));
822 assert!(beta_ids_final.contains(&"relayer-5".to_string()));
823 }
824}