1use slog::warn;
2use warp::Filter;
3
4use crate::dependency_injection::EpochServiceWrapper;
5use crate::http_server::routes::middlewares;
6use crate::http_server::routes::router::RouterState;
7
8const MITHRIL_SIGNER_VERSION_HEADER: &str = "signer-node-version";
9
10pub fn routes(
11 router_state: &RouterState,
12) -> impl Filter<Extract = (impl warp::Reply + use<>,), Error = warp::Rejection> + Clone + use<> {
13 register_signer(router_state)
14 .or(registered_signers(router_state))
15 .or(signers_tickers(router_state))
16}
17
18fn register_signer(
20 router_state: &RouterState,
21) -> impl Filter<Extract = (impl warp::Reply + use<>,), Error = warp::Rejection> + Clone + use<> {
22 warp::path!("register-signer")
23 .and(warp::post())
24 .and(middlewares::with_origin_tag(router_state))
25 .and(warp::header::optional::<String>(
26 MITHRIL_SIGNER_VERSION_HEADER,
27 ))
28 .and(warp::body::json())
29 .and(middlewares::with_logger(router_state))
30 .and(middlewares::with_signer_registerer(router_state))
31 .and(middlewares::with_event_transmitter(router_state))
32 .and(middlewares::with_epoch_service(router_state))
33 .and(middlewares::with_metrics_service(router_state))
34 .and_then(handlers::register_signer)
35}
36
37fn signers_tickers(
39 router_state: &RouterState,
40) -> impl Filter<Extract = (impl warp::Reply + use<>,), Error = warp::Rejection> + Clone + use<> {
41 warp::path!("signers" / "tickers")
42 .and(warp::get())
43 .and(middlewares::with_logger(router_state))
44 .and(middlewares::extract_config(router_state, |config| {
45 config.network.to_string()
46 }))
47 .and(middlewares::with_signer_getter(router_state))
48 .and_then(handlers::signers_tickers)
49}
50
51fn registered_signers(
53 router_state: &RouterState,
54) -> impl Filter<Extract = (impl warp::Reply + use<>,), Error = warp::Rejection> + Clone + use<> {
55 warp::path!("signers" / "registered" / String)
56 .and(warp::get())
57 .and(middlewares::with_logger(router_state))
58 .and(middlewares::with_epoch_service(router_state))
59 .and(middlewares::with_verification_key_store(router_state))
60 .and_then(handlers::registered_signers)
61}
62
63async fn fetch_epoch_header_value(
64 epoch_service: EpochServiceWrapper,
65 logger: &slog::Logger,
66) -> String {
67 match epoch_service.read().await.epoch_of_current_data() {
68 Ok(epoch) => format!("{epoch}"),
69 Err(e) => {
70 warn!(logger, "Could not fetch epoch header value from Epoch service"; "error" => ?e);
71 String::new()
72 }
73 }
74}
75
76mod handlers {
77 use mithril_common::messages::{RegisterSignerMessage, TryFromMessageAdapter};
78 use slog::{Logger, debug, warn};
79 use std::convert::Infallible;
80 use std::sync::Arc;
81 use warp::http::StatusCode;
82
83 use crate::{
84 FromRegisterSignerAdapter, MetricsService, SignerRegisterer, SignerRegistrationError,
85 VerificationKeyStorer,
86 database::repository::SignerGetter,
87 entities::{
88 SignerRegistrationsMessage, SignerTickerListItemMessage, SignersTickersMessage,
89 },
90 event_store::{EventMessage, TransmitterService},
91 http_server::{
92 parameters,
93 routes::{reply, signer_routes::fetch_epoch_header_value},
94 },
95 };
96
97 use super::*;
98
99 #[allow(clippy::too_many_arguments)]
101 pub async fn register_signer(
102 origin_tag: Option<String>,
103 signer_node_version: Option<String>,
104 register_signer_message: RegisterSignerMessage,
105 logger: Logger,
106 signer_registerer: Arc<dyn SignerRegisterer>,
107 event_transmitter: Arc<TransmitterService<EventMessage>>,
108 epoch_service: EpochServiceWrapper,
109 metrics_service: Arc<MetricsService>,
110 ) -> Result<impl warp::Reply, Infallible> {
111 debug!(logger, ">> register_signer"; "payload" => ?register_signer_message);
112
113 metrics_service
114 .get_signer_registration_total_received_since_startup()
115 .increment(&[origin_tag.as_deref().unwrap_or_default()]);
116
117 let payload = register_signer_message.clone();
118 let registration_epoch = register_signer_message.epoch;
119
120 let signer = match FromRegisterSignerAdapter::try_adapt(register_signer_message) {
121 Ok(signer) => signer,
122 Err(err) => {
123 warn!(logger,"register_signer::payload decoding error"; "full_payload" => #?payload, "error" => ?err);
124 return Ok(reply::bad_request(
125 "Could not decode signer payload".to_string(),
126 err.to_string(),
127 ));
128 }
129 };
130
131 let epoch_str = fetch_epoch_header_value(epoch_service, &logger).await;
132
133 match signer_registerer.register_signer(registration_epoch, &signer).await {
134 Ok(signer_with_stake) => {
135 event_transmitter.send(EventMessage::signer_registration(
136 "HTTP::signer_register",
137 &signer_with_stake,
138 signer_node_version,
139 epoch_str.as_str(),
140 ));
141
142 metrics_service
143 .get_signer_registration_total_successful_since_startup()
144 .increment(&[origin_tag.as_deref().unwrap_or_default()]);
145
146 Ok(reply::empty(StatusCode::CREATED))
147 }
148 Err(SignerRegistrationError::ExistingSigner(signer_with_stake)) => {
149 debug!(
150 logger, "register_signer::already_registered";
151 "registration_epoch" => ?registration_epoch, "party_id" => &signer.party_id,
152 );
153
154 event_transmitter.send(EventMessage::signer_registration(
155 "HTTP::signer_register",
156 &signer_with_stake,
157 signer_node_version,
158 &epoch_str,
159 ));
160
161 Ok(reply::empty(StatusCode::CREATED))
162 }
163 Err(SignerRegistrationError::InvalidSignerRegistration(
164 _party_id,
165 _registration_epoch,
166 err,
167 )) => {
168 warn!(logger,"register_signer::failed_signer_registration"; "full_payload" => #?payload, "error" => ?err);
169 Ok(reply::bad_request(
170 "failed_signer_registration".to_string(),
171 err.to_string(),
172 ))
173 }
174 Err(SignerRegistrationError::RegistrationRoundNotYetOpened) => {
175 warn!(
176 logger, "register_signer::registration_round_not_yed_opened";
177 "registration_epoch" => ?registration_epoch, "party_id" => &signer.party_id,
178 );
179 Ok(reply::server_error(
180 SignerRegistrationError::RegistrationRoundNotYetOpened,
181 ))
182 }
183 Err(err) => {
184 warn!(logger,"register_signer::error"; "full_payload" => #?payload, "error" => ?err);
185 Ok(reply::server_error(err))
186 }
187 }
188 }
189
190 pub async fn registered_signers(
192 registered_at: String,
193 logger: Logger,
194 epoch_service: EpochServiceWrapper,
195 verification_key_store: Arc<dyn VerificationKeyStorer>,
196 ) -> Result<impl warp::Reply, Infallible> {
197 let expanded_epoch = match parameters::expand_epoch(®istered_at, epoch_service).await {
198 Ok(epoch) => epoch,
199 Err(err) => {
200 warn!(logger,"registered_signers::invalid_epoch"; "error" => ?err);
201 return Ok(reply::bad_request(
202 "invalid_epoch".to_string(),
203 err.to_string(),
204 ));
205 }
206 };
207
208 match verification_key_store
211 .get_signers(expanded_epoch.offset_to_recording_epoch())
212 .await
213 {
214 Ok(Some(signers)) => {
215 let message = SignerRegistrationsMessage::new(*expanded_epoch, signers);
216 Ok(reply::json(&message, StatusCode::OK))
217 }
218 Ok(None) => {
219 warn!(logger, "registered_signers::not_found");
220 Ok(reply::empty(StatusCode::NOT_FOUND))
221 }
222 Err(err) => {
223 warn!(logger,"registered_signers::error"; "error" => ?err);
224 Ok(reply::server_error(err))
225 }
226 }
227 }
228
229 pub async fn signers_tickers(
230 logger: Logger,
231 network: String,
232 signer_getter: Arc<dyn SignerGetter>,
233 ) -> Result<impl warp::Reply, Infallible> {
234 match signer_getter.get_all().await {
235 Ok(signers) => {
236 let signers: Vec<_> = signers
237 .into_iter()
238 .map(|s| SignerTickerListItemMessage {
239 party_id: s.signer_id,
240 pool_ticker: s.pool_ticker,
241 has_registered: s.last_registered_at.is_some(),
242 })
243 .collect();
244 Ok(reply::json(
245 &SignersTickersMessage { network, signers },
246 StatusCode::OK,
247 ))
248 }
249 Err(err) => {
250 warn!(logger,"registered_signers::error"; "error" => ?err);
251 Ok(reply::server_error(err))
252 }
253 }
254 }
255}
256
257#[cfg(test)]
258mod tests {
259 use anyhow::anyhow;
260 use mockall::predicate::eq;
261 use serde_json::Value::Null;
262 use std::sync::Arc;
263 use tokio::sync::RwLock;
264 use warp::{
265 http::{Method, StatusCode},
266 test::request,
267 };
268
269 use mithril_api_spec::APISpec;
270 use mithril_common::{
271 MITHRIL_ORIGIN_TAG_HEADER,
272 crypto_helper::ProtocolRegistrationError,
273 entities::Epoch,
274 messages::RegisterSignerMessage,
275 test::{
276 builder::MithrilFixtureBuilder,
277 double::{Dummy, fake_data},
278 mock_extensions::MockBuilder,
279 },
280 };
281
282 use crate::{
283 SignerRegistrationError,
284 database::{record::SignerRecord, repository::MockSignerGetter},
285 http_server::routes::reply::MithrilStatusCode,
286 initialize_dependencies,
287 services::{FakeEpochService, MockSignerRegisterer},
288 store::MockVerificationKeyStorer,
289 test::TestLogger,
290 };
291
292 use super::*;
293
294 fn setup_router(
295 state: RouterState,
296 ) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone {
297 let cors = warp::cors()
298 .allow_any_origin()
299 .allow_headers(vec!["content-type"])
300 .allow_methods(vec![Method::GET, Method::POST, Method::OPTIONS]);
301
302 warp::any().and(routes(&state).with(cors))
303 }
304
305 #[tokio::test]
306 async fn test_register_signer_post_ok() {
307 let signer_with_stake = fake_data::signers_with_stakes(1).pop().unwrap();
308 let mut mock_signer_registerer = MockSignerRegisterer::new();
309 mock_signer_registerer
310 .expect_register_signer()
311 .return_once(|_, _| Ok(signer_with_stake));
312 let mut dependency_manager = initialize_dependencies!().await;
313 dependency_manager.signer_registerer = Arc::new(mock_signer_registerer);
314
315 let signer: RegisterSignerMessage = RegisterSignerMessage::dummy();
316
317 let method = Method::POST.as_str();
318 let path = "/register-signer";
319
320 let response = request()
321 .method(method)
322 .path(path)
323 .json(&signer)
324 .reply(&setup_router(RouterState::new_with_dummy_config(Arc::new(
325 dependency_manager,
326 ))))
327 .await;
328
329 APISpec::verify_conformity(
330 APISpec::get_default_spec_file_from(crate::http_server::API_SPEC_LOCATION),
331 method,
332 path,
333 "application/json",
334 &signer,
335 &response,
336 &StatusCode::CREATED,
337 )
338 .unwrap();
339 }
340
341 #[tokio::test]
342 async fn test_register_signer_increments_signer_registration_total_received_and_successful_since_startup_metric_if_successful()
343 {
344 let method = Method::POST.as_str();
345 let path = "/register-signer";
346 let dependency_manager = {
347 let mut deps = initialize_dependencies!().await;
348 deps.signer_registerer = MockBuilder::<MockSignerRegisterer>::configure(|mock| {
349 mock.expect_register_signer()
350 .returning(|_, _| Ok(fake_data::signers_with_stakes(1).pop().unwrap()));
351 });
352 Arc::new(deps)
353 };
354
355 let initial_received_counter_value = dependency_manager
356 .metrics_service
357 .get_signer_registration_total_received_since_startup()
358 .get(&["TEST"]);
359 let initial_successful_counter_value = dependency_manager
360 .metrics_service
361 .get_signer_registration_total_successful_since_startup()
362 .get(&["HTTP"]);
363
364 request()
365 .method(method)
366 .path(path)
367 .json(&RegisterSignerMessage::dummy())
368 .header(MITHRIL_ORIGIN_TAG_HEADER, "TEST")
369 .reply(&setup_router(RouterState::new_with_origin_tag_white_list(
370 dependency_manager.clone(),
371 &["TEST"],
372 )))
373 .await;
374
375 assert_eq!(
376 initial_received_counter_value + 1,
377 dependency_manager
378 .metrics_service
379 .get_signer_registration_total_received_since_startup()
380 .get(&["TEST"])
381 );
382 assert_eq!(
383 initial_successful_counter_value + 1,
384 dependency_manager
385 .metrics_service
386 .get_signer_registration_total_successful_since_startup()
387 .get(&["TEST"])
388 );
389 }
390
391 #[tokio::test]
392 async fn test_register_signer_only_increments_signer_registration_total_received_since_startup_metric_if_failure()
393 {
394 let method = Method::POST.as_str();
395 let path = "/register-signer";
396 let dependency_manager = {
397 let mut deps = initialize_dependencies!().await;
398 deps.signer_registerer = MockBuilder::<MockSignerRegisterer>::configure(|mock| {
399 mock.expect_register_signer()
400 .returning(|_, _| Err(SignerRegistrationError::RegistrationRoundNotYetOpened));
401 });
402 Arc::new(deps)
403 };
404
405 let initial_received_counter_value = dependency_manager
406 .metrics_service
407 .get_signer_registration_total_received_since_startup()
408 .get(&["TEST"]);
409 let initial_successful_counter_value = dependency_manager
410 .metrics_service
411 .get_signer_registration_total_successful_since_startup()
412 .get(&["HTTP"]);
413
414 request()
415 .method(method)
416 .path(path)
417 .json(&RegisterSignerMessage::dummy())
418 .header(MITHRIL_ORIGIN_TAG_HEADER, "TEST")
419 .reply(&setup_router(RouterState::new_with_origin_tag_white_list(
420 dependency_manager.clone(),
421 &["TEST"],
422 )))
423 .await;
424
425 assert_eq!(
426 initial_received_counter_value + 1,
427 dependency_manager
428 .metrics_service
429 .get_signer_registration_total_received_since_startup()
430 .get(&["TEST"])
431 );
432 assert_eq!(
433 initial_successful_counter_value,
434 dependency_manager
435 .metrics_service
436 .get_signer_registration_total_successful_since_startup()
437 .get(&["TEST"])
438 );
439 }
440
441 #[tokio::test]
442 async fn test_register_signer_post_ok_existing() {
443 let signer_with_stake = fake_data::signers_with_stakes(1).pop().unwrap();
444 let mut mock_signer_registerer = MockSignerRegisterer::new();
445 mock_signer_registerer.expect_register_signer().return_once(|_, _| {
446 Err(SignerRegistrationError::ExistingSigner(Box::new(
447 signer_with_stake,
448 )))
449 });
450 let mut dependency_manager = initialize_dependencies!().await;
451 dependency_manager.signer_registerer = Arc::new(mock_signer_registerer);
452
453 let signer: RegisterSignerMessage = RegisterSignerMessage::dummy();
454
455 let method = Method::POST.as_str();
456 let path = "/register-signer";
457
458 let response = request()
459 .method(method)
460 .path(path)
461 .json(&signer)
462 .reply(&setup_router(RouterState::new_with_dummy_config(Arc::new(
463 dependency_manager,
464 ))))
465 .await;
466
467 APISpec::verify_conformity(
468 APISpec::get_default_spec_file_from(crate::http_server::API_SPEC_LOCATION),
469 method,
470 path,
471 "application/json",
472 &signer,
473 &response,
474 &StatusCode::CREATED,
475 )
476 .unwrap();
477 }
478
479 #[tokio::test]
480 async fn test_register_signer_post_ko_400() {
481 let mut mock_signer_registerer = MockSignerRegisterer::new();
482 mock_signer_registerer.expect_register_signer().return_once(|_, _| {
483 Err(SignerRegistrationError::InvalidSignerRegistration(
484 "party_2".to_string(),
485 Epoch(4),
486 anyhow!(ProtocolRegistrationError::OpCertInvalid),
487 ))
488 });
489 let mut dependency_manager = initialize_dependencies!().await;
490 dependency_manager.signer_registerer = Arc::new(mock_signer_registerer);
491
492 let signer: RegisterSignerMessage = RegisterSignerMessage::dummy();
493
494 let method = Method::POST.as_str();
495 let path = "/register-signer";
496
497 let response = request()
498 .method(method)
499 .path(path)
500 .json(&signer)
501 .reply(&setup_router(RouterState::new_with_dummy_config(Arc::new(
502 dependency_manager,
503 ))))
504 .await;
505
506 APISpec::verify_conformity(
507 APISpec::get_default_spec_file_from(crate::http_server::API_SPEC_LOCATION),
508 method,
509 path,
510 "application/json",
511 &signer,
512 &response,
513 &StatusCode::BAD_REQUEST,
514 )
515 .unwrap();
516 }
517
518 #[tokio::test]
519 async fn test_register_signer_post_ko_500() {
520 let mut mock_signer_registerer = MockSignerRegisterer::new();
521 mock_signer_registerer.expect_register_signer().return_once(|_, _| {
522 Err(SignerRegistrationError::FailedSignerRecorder(
523 "party_1".to_string(),
524 Epoch(4),
525 anyhow!("an error occurred"),
526 ))
527 });
528 let mut dependency_manager = initialize_dependencies!().await;
529 dependency_manager.signer_registerer = Arc::new(mock_signer_registerer);
530
531 let signer: RegisterSignerMessage = RegisterSignerMessage::dummy();
532 let method = Method::POST.as_str();
533 let path = "/register-signer";
534
535 let response = request()
536 .method(method)
537 .path(path)
538 .json(&signer)
539 .reply(&setup_router(RouterState::new_with_dummy_config(Arc::new(
540 dependency_manager,
541 ))))
542 .await;
543
544 APISpec::verify_conformity(
545 APISpec::get_default_spec_file_from(crate::http_server::API_SPEC_LOCATION),
546 method,
547 path,
548 "application/json",
549 &signer,
550 &response,
551 &StatusCode::INTERNAL_SERVER_ERROR,
552 )
553 .unwrap();
554 }
555
556 #[tokio::test]
557 async fn test_register_signer_post_ko_550() {
558 let mut mock_signer_registerer = MockSignerRegisterer::new();
559 mock_signer_registerer
560 .expect_register_signer()
561 .return_once(|_, _| Err(SignerRegistrationError::RegistrationRoundNotYetOpened));
562 let mut dependency_manager = initialize_dependencies!().await;
563 dependency_manager.signer_registerer = Arc::new(mock_signer_registerer);
564
565 let signer: RegisterSignerMessage = RegisterSignerMessage::dummy();
566 let method = Method::POST.as_str();
567 let path = "/register-signer";
568
569 let response = request()
570 .method(method)
571 .path(path)
572 .json(&signer)
573 .reply(&setup_router(RouterState::new_with_dummy_config(Arc::new(
574 dependency_manager,
575 ))))
576 .await;
577
578 APISpec::verify_conformity(
579 APISpec::get_default_spec_file_from(crate::http_server::API_SPEC_LOCATION),
580 method,
581 path,
582 "application/json",
583 &signer,
584 &response,
585 &MithrilStatusCode::registration_round_not_yet_opened(),
586 )
587 .unwrap();
588 }
589
590 #[tokio::test]
591 async fn test_registered_signers_get_offset_given_epoch_to_registration_epoch() {
592 let asked_epoch = Epoch(1);
593 let expected_retrieval_epoch = asked_epoch.offset_to_recording_epoch();
594 let mut mock_verification_key_store = MockVerificationKeyStorer::new();
595 mock_verification_key_store
596 .expect_get_signers()
597 .with(eq(expected_retrieval_epoch))
598 .return_once(|_| Ok(Some(fake_data::signers_with_stakes(3))))
599 .once();
600 let mut dependency_manager = initialize_dependencies!().await;
601 dependency_manager.verification_key_store = Arc::new(mock_verification_key_store);
602
603 let method = Method::GET.as_str();
604 let base_path = "/signers/registered";
605
606 let response = request()
607 .method(method)
608 .path(&format!("{base_path}/{asked_epoch}"))
609 .reply(&setup_router(RouterState::new_with_dummy_config(Arc::new(
610 dependency_manager,
611 ))))
612 .await;
613
614 assert!(
615 response.status().is_success(),
616 "expected the response to succeed, was: {response:#?}"
617 );
618 }
619
620 #[tokio::test]
621 async fn test_registered_signers_get_ok() {
622 let mut mock_verification_key_store = MockVerificationKeyStorer::new();
623 mock_verification_key_store
624 .expect_get_signers()
625 .return_once(|_| Ok(Some(fake_data::signers_with_stakes(3))))
626 .once();
627 let mut dependency_manager = initialize_dependencies!().await;
628 dependency_manager.verification_key_store = Arc::new(mock_verification_key_store);
629
630 let base_path = "/signers/registered";
631 let method = Method::GET.as_str();
632
633 let response = request()
634 .method(method)
635 .path(&format!("{base_path}/1"))
636 .reply(&setup_router(RouterState::new_with_dummy_config(Arc::new(
637 dependency_manager,
638 ))))
639 .await;
640
641 APISpec::verify_conformity(
642 APISpec::get_default_spec_file_from(crate::http_server::API_SPEC_LOCATION),
643 method,
644 &format!("{base_path}/{{epoch}}"),
645 "application/json",
646 &Null,
647 &response,
648 &StatusCode::OK,
649 )
650 .unwrap();
651 }
652
653 #[tokio::test]
654 async fn test_registered_signers_returns_404_not_found_when_no_registration() {
655 let mut mock_verification_key_store = MockVerificationKeyStorer::new();
656 mock_verification_key_store
657 .expect_get_signers()
658 .return_once(|_| Ok(None))
659 .once();
660 let mut dependency_manager = initialize_dependencies!().await;
661 dependency_manager.verification_key_store = Arc::new(mock_verification_key_store);
662
663 let method = Method::GET.as_str();
664 let base_path = "/signers/registered";
665
666 let response = request()
667 .method(method)
668 .path(&format!("{base_path}/3"))
669 .reply(&setup_router(RouterState::new_with_dummy_config(Arc::new(
670 dependency_manager,
671 ))))
672 .await;
673
674 APISpec::verify_conformity(
675 APISpec::get_default_spec_file_from(crate::http_server::API_SPEC_LOCATION),
676 method,
677 &format!("{base_path}/{{epoch}}"),
678 "application/json",
679 &Null,
680 &response,
681 &StatusCode::NOT_FOUND,
682 )
683 .unwrap();
684 }
685
686 #[tokio::test]
687 async fn test_registered_signers_get_ko() {
688 let mut mock_verification_key_store = MockVerificationKeyStorer::new();
689 mock_verification_key_store
690 .expect_get_signers()
691 .return_once(|_| Err(anyhow!("invalid query")));
692 let mut dependency_manager = initialize_dependencies!().await;
693 dependency_manager.verification_key_store = Arc::new(mock_verification_key_store);
694
695 let method = Method::GET.as_str();
696 let base_path = "/signers/registered";
697
698 let response = request()
699 .method(method)
700 .path(&format!("{base_path}/1"))
701 .reply(&setup_router(RouterState::new_with_dummy_config(Arc::new(
702 dependency_manager,
703 ))))
704 .await;
705
706 APISpec::verify_conformity(
707 APISpec::get_default_spec_file_from(crate::http_server::API_SPEC_LOCATION),
708 method,
709 &format!("{base_path}/{{epoch}}"),
710 "application/json",
711 &Null,
712 &response,
713 &StatusCode::INTERNAL_SERVER_ERROR,
714 )
715 .unwrap();
716 }
717
718 #[tokio::test]
719 async fn test_signers_tickers_get_ok() {
720 let mut mock_signer_getter = MockSignerGetter::new();
721 mock_signer_getter
722 .expect_get_all()
723 .return_once(|| {
724 Ok(vec![
725 SignerRecord {
726 signer_id: "pool_without_ticker".to_string(),
727 pool_ticker: None,
728 created_at: Default::default(),
729 updated_at: Default::default(),
730 last_registered_at: None,
731 },
732 SignerRecord {
733 signer_id: "pool_with_ticker".to_string(),
734 pool_ticker: Some("pool_ticker".to_string()),
735 created_at: Default::default(),
736 updated_at: Default::default(),
737 last_registered_at: None,
738 },
739 ])
740 })
741 .once();
742 let mut dependency_manager = initialize_dependencies!().await;
743 dependency_manager.signer_getter = Arc::new(mock_signer_getter);
744
745 let method = Method::GET.as_str();
746 let path = "/signers/tickers";
747
748 let response = request()
749 .method(method)
750 .path(path)
751 .reply(&setup_router(RouterState::new_with_dummy_config(Arc::new(
752 dependency_manager,
753 ))))
754 .await;
755
756 APISpec::verify_conformity(
757 APISpec::get_default_spec_file_from(crate::http_server::API_SPEC_LOCATION),
758 method,
759 path,
760 "application/json",
761 &Null,
762 &response,
763 &StatusCode::OK,
764 )
765 .unwrap();
766 }
767
768 #[tokio::test]
769 async fn test_signers_tickers_get_ko() {
770 let mut mock_signer_getter = MockSignerGetter::new();
771 mock_signer_getter
772 .expect_get_all()
773 .return_once(|| Err(anyhow!("an error")))
774 .once();
775 let mut dependency_manager = initialize_dependencies!().await;
776 dependency_manager.signer_getter = Arc::new(mock_signer_getter);
777
778 let method = Method::GET.as_str();
779 let path = "/signers/tickers";
780
781 let response = request()
782 .method(method)
783 .path(path)
784 .reply(&setup_router(RouterState::new_with_dummy_config(Arc::new(
785 dependency_manager,
786 ))))
787 .await;
788
789 APISpec::verify_conformity(
790 APISpec::get_default_spec_file_from(crate::http_server::API_SPEC_LOCATION),
791 method,
792 path,
793 "application/json",
794 &Null,
795 &response,
796 &StatusCode::INTERNAL_SERVER_ERROR,
797 )
798 .unwrap();
799 }
800
801 #[tokio::test]
802 async fn test_fetch_epoch_header_value_when_epoch_service_return_epoch() {
803 let fixture = MithrilFixtureBuilder::default().build();
804 let epoch_service = Arc::new(RwLock::new(FakeEpochService::from_fixture(
805 Epoch(84),
806 &fixture,
807 )));
808
809 let epoch_str = fetch_epoch_header_value(epoch_service, &TestLogger::stdout()).await;
810
811 assert_eq!(epoch_str, "84".to_string());
812 }
813
814 #[tokio::test]
815 async fn test_fetch_epoch_header_value_when_epoch_service_error_return_empty_string() {
816 let epoch_service = Arc::new(RwLock::new(FakeEpochService::without_data()));
817
818 let epoch_str = fetch_epoch_header_value(epoch_service, &TestLogger::stdout()).await;
819
820 assert_eq!(epoch_str, "".to_string());
821 }
822}