From 429004c81764d163b99b6cb4a87b2c201ff9d404 Mon Sep 17 00:00:00 2001 From: DJO <790521+Alenar@users.noreply.github.com> Date: Fri, 27 Jun 2025 11:16:38 +0200 Subject: [PATCH 1/4] test(common): refactor `CertificateChainBuilder` so it returns a type Instead of a tuple, this allow to extend the returned value with usefull fstructeatures for test (i.e. immediate access to genesis certificate). Also update the builder so generated certificates have different, deterministic, signed entity type. --- .../query/certificate/get_certificate.rs | 20 +- .../src/certificate_client/verify.rs | 54 ++--- .../certificate_chain/certificate_verifier.rs | 6 +- .../src/crypto_helper/tests_setup.rs | 11 +- .../test_utils/certificate_chain_builder.rs | 196 +++++++++++++++--- mithril-common/src/test_utils/mod.rs | 3 +- 6 files changed, 225 insertions(+), 65 deletions(-) diff --git a/mithril-aggregator/src/database/query/certificate/get_certificate.rs b/mithril-aggregator/src/database/query/certificate/get_certificate.rs index fba873aac06..1dde57fbf5d 100644 --- a/mithril-aggregator/src/database/query/certificate/get_certificate.rs +++ b/mithril-aggregator/src/database/query/certificate/get_certificate.rs @@ -123,7 +123,7 @@ mod tests { #[test] fn test_get_all_genesis_certificate_records() { // Two chains with different protocol parameters so generated certificates are different. - let (first_certificates_chain, _) = CertificateChainBuilder::new() + let first_certificates_chain = CertificateChainBuilder::new() .with_total_certificates(2) .with_protocol_parameters(ProtocolParameters { m: 90, @@ -131,9 +131,11 @@ mod tests { phi_f: 0.65, }) .build(); - let first_chain_genesis: CertificateRecord = - first_certificates_chain.last().unwrap().clone().into(); - let (second_certificates_chain, _) = CertificateChainBuilder::new() + let first_chain_genesis: CertificateRecord = first_certificates_chain + .genesis_certificate() + .clone() + .into(); + let second_certificates_chain = CertificateChainBuilder::new() .with_total_certificates(2) .with_protocol_parameters(ProtocolParameters { m: 100, @@ -141,8 +143,10 @@ mod tests { phi_f: 0.65, }) .build(); - let second_chain_genesis: CertificateRecord = - second_certificates_chain.last().unwrap().clone().into(); + let second_chain_genesis: CertificateRecord = second_certificates_chain + .genesis_certificate() + .clone() + .into(); assert_ne!(first_chain_genesis, second_chain_genesis); let connection = main_db_connection().unwrap(); @@ -151,14 +155,14 @@ mod tests { .unwrap(); assert_eq!(Vec::::new(), certificate_records); - insert_certificate_records(&connection, first_certificates_chain); + insert_certificate_records(&connection, first_certificates_chain.certificates_chained); let certificate_records: Vec = connection .fetch_collect(GetCertificateRecordQuery::all_genesis()) .unwrap(); assert_eq!(vec![first_chain_genesis.to_owned()], certificate_records); - insert_certificate_records(&connection, second_certificates_chain); + insert_certificate_records(&connection, second_certificates_chain.certificates_chained); let certificate_records: Vec = connection .fetch_collect(GetCertificateRecordQuery::all_genesis()) diff --git a/mithril-client/src/certificate_client/verify.rs b/mithril-client/src/certificate_client/verify.rs index 9255dba7676..6a022fbfb15 100644 --- a/mithril-client/src/certificate_client/verify.rs +++ b/mithril-client/src/certificate_client/verify.rs @@ -262,7 +262,7 @@ mod tests { #[tokio::test] async fn validating_chain_send_feedbacks() { - let (chain, verifier) = CertificateChainBuilder::new() + let chain = CertificateChainBuilder::new() .with_total_certificates(3) .with_certificates_per_epoch(1) .build(); @@ -270,8 +270,10 @@ mod tests { let feedback_receiver = Arc::new(StackFeedbackReceiver::new()); let certificate_client = CertificateClientTestBuilder::default() - .config_aggregator_client_mock(|mock| mock.expect_certificate_chain(chain.clone())) - .with_genesis_verification_key(verifier.to_verification_key()) + .config_aggregator_client_mock(|mock| { + mock.expect_certificate_chain(chain.certificates_chained.clone()) + }) + .with_genesis_verification_key(chain.genesis_verifier.to_verification_key()) .add_feedback_receiver(feedback_receiver.clone()) .build(); @@ -287,14 +289,12 @@ mod tests { let mut vec = vec![MithrilEvent::CertificateChainValidationStarted { certificate_chain_validation_id: id.to_string(), }]; - vec.extend( - chain - .into_iter() - .map(|c| MithrilEvent::CertificateValidated { - certificate_chain_validation_id: id.to_string(), - certificate_hash: c.hash, - }), - ); + vec.extend(chain.certificates_chained.into_iter().map(|c| { + MithrilEvent::CertificateValidated { + certificate_chain_validation_id: id.to_string(), + certificate_hash: c.hash, + } + })); vec.push(MithrilEvent::CertificateChainValidated { certificate_chain_validation_id: id.to_string(), }); @@ -306,15 +306,17 @@ mod tests { #[tokio::test] async fn verify_chain_return_certificate_with_given_hash() { - let (chain, verifier) = CertificateChainBuilder::new() + let chain = CertificateChainBuilder::new() .with_total_certificates(3) .with_certificates_per_epoch(1) .build(); let last_certificate_hash = chain.first().unwrap().hash.clone(); let certificate_client = CertificateClientTestBuilder::default() - .config_aggregator_client_mock(|mock| mock.expect_certificate_chain(chain.clone())) - .with_genesis_verification_key(verifier.to_verification_key()) + .config_aggregator_client_mock(|mock| { + mock.expect_certificate_chain(chain.certificates_chained.clone()) + }) + .with_genesis_verification_key(chain.genesis_verifier.to_verification_key()) .build(); let certificate = certificate_client @@ -359,7 +361,7 @@ mod tests { #[tokio::test] async fn genesis_certificates_verification_result_is_not_cached() { - let (chain, verifier) = CertificateChainBuilder::new() + let chain = CertificateChainBuilder::new() .with_total_certificates(1) .with_certificates_per_epoch(1) .build(); @@ -369,7 +371,7 @@ mod tests { let cache = Arc::new(MemoryCertificateVerifierCache::new(TimeDelta::hours(1))); let verifier = build_verifier_with_cache( |_mock| {}, - verifier.to_verification_key(), + chain.genesis_verifier.to_verification_key(), cache.clone(), ); @@ -394,7 +396,7 @@ mod tests { #[tokio::test] async fn non_genesis_certificates_verification_result_is_cached() { - let (chain, verifier) = CertificateChainBuilder::new() + let chain = CertificateChainBuilder::new() .with_total_certificates(2) .with_certificates_per_epoch(1) .build(); @@ -405,7 +407,7 @@ mod tests { let cache = Arc::new(MemoryCertificateVerifierCache::new(TimeDelta::hours(1))); let verifier = build_verifier_with_cache( |mock| mock.expect_certificate_chain(vec![genesis_certificate.clone()]), - verifier.to_verification_key(), + chain.genesis_verifier.to_verification_key(), cache.clone(), ); @@ -428,7 +430,7 @@ mod tests { #[tokio::test] async fn verification_of_first_certificate_of_a_chain_should_always_fetch_it_from_network() { - let (chain, verifier) = CertificateChainBuilder::new() + let chain = CertificateChainBuilder::new() .with_total_certificates(2) .with_certificates_per_epoch(1) .build(); @@ -440,10 +442,10 @@ mod tests { ); let certificate_client = CertificateClientTestBuilder::default() .config_aggregator_client_mock(|mock| { - // Expect to first certificate to be fetched from the network - mock.expect_certificate_chain(chain.clone()); + // Expect to fetch the first certificate from the network + mock.expect_certificate_chain(chain.certificates_chained.clone()); }) - .with_genesis_verification_key(verifier.to_verification_key()) + .with_genesis_verification_key(chain.genesis_verifier.to_verification_key()) .with_verifier_cache(cache.clone()) .build(); @@ -466,7 +468,7 @@ mod tests { // | n°3 | 2 | n°2 | Yes | No | // | n°2 | 2 | n°1 | Yes | No | // | n°1 | 1 | None (genesis) | Yes | Yes | - let (chain, verifier) = CertificateChainBuilder::new() + let chain = CertificateChainBuilder::new() .with_total_certificates(6) .with_certificates_per_epoch(3) .with_certificate_chaining_method(CertificateChainingMethod::Sequential) @@ -503,7 +505,7 @@ mod tests { .config_aggregator_client_mock(|mock| { mock.expect_certificate_chain(certificates_that_must_be_fully_verified); }) - .with_genesis_verification_key(verifier.to_verification_key()) + .with_genesis_verification_key(chain.genesis_verifier.to_verification_key()) .with_verifier_cache(cache) .build(); @@ -515,7 +517,7 @@ mod tests { #[tokio::test] async fn verify_chain_return_certificate_with_cache() { - let (chain, verifier) = CertificateChainBuilder::new() + let chain = CertificateChainBuilder::new() .with_total_certificates(5) .with_certificates_per_epoch(1) .build(); @@ -531,7 +533,7 @@ mod tests { [chain[0..3].to_vec(), vec![chain.last().unwrap().clone()]].concat(), ) }) - .with_genesis_verification_key(verifier.to_verification_key()) + .with_genesis_verification_key(chain.genesis_verifier.to_verification_key()) .with_verifier_cache(Arc::new(cache)) .build(); diff --git a/mithril-common/src/certificate_chain/certificate_verifier.rs b/mithril-common/src/certificate_chain/certificate_verifier.rs index 584f44a3c6f..f26cc5877dd 100644 --- a/mithril-common/src/certificate_chain/certificate_verifier.rs +++ b/mithril-common/src/certificate_chain/certificate_verifier.rs @@ -813,7 +813,7 @@ mod tests { } let (total_certificates, certificates_per_epoch) = (5, 1); - let (fake_certificates, _) = CertificateChainBuilder::new() + let fake_certificates = CertificateChainBuilder::new() .with_total_certificates(total_certificates) .with_certificates_per_epoch(certificates_per_epoch) .with_standard_certificate_processor(&|certificate, context| { @@ -1125,7 +1125,7 @@ mod tests { } let (total_certificates, certificates_per_epoch) = (7, 2); - let (fake_certificates, genesis_verifier) = CertificateChainBuilder::new() + let fake_certificates = CertificateChainBuilder::new() .with_total_certificates(total_certificates) .with_certificates_per_epoch(certificates_per_epoch) .with_standard_certificate_processor(&|certificate, context| { @@ -1146,7 +1146,7 @@ mod tests { let error = verifier .verify_certificate( &certificate_to_verify, - &genesis_verifier.to_verification_key(), + &fake_certificates.genesis_verifier.to_verification_key(), ) .await .expect_err("verify_certificate_chain should fail"); diff --git a/mithril-common/src/crypto_helper/tests_setup.rs b/mithril-common/src/crypto_helper/tests_setup.rs index 1dfef479521..fd8b4b867e4 100644 --- a/mithril-common/src/crypto_helper/tests_setup.rs +++ b/mithril-common/src/crypto_helper/tests_setup.rs @@ -192,14 +192,19 @@ pub fn setup_signers_from_stake_distribution( } /// Instantiate a certificate chain, use this for tests only. +/// Todo: update to CertificateChainFixture pub fn setup_certificate_chain( total_certificates: u64, certificates_per_epoch: u64, ) -> (Vec, ProtocolGenesisVerifier) { - let certificate_chain_builder = CertificateChainBuilder::new() + let certificate_chain_fixture = CertificateChainBuilder::new() .with_total_certificates(total_certificates) .with_certificates_per_epoch(certificates_per_epoch) - .with_protocol_parameters(setup_protocol_parameters()); + .with_protocol_parameters(setup_protocol_parameters()) + .build(); - certificate_chain_builder.build() + ( + certificate_chain_fixture.certificates_chained, + certificate_chain_fixture.genesis_verifier, + ) } diff --git a/mithril-common/src/test_utils/certificate_chain_builder.rs b/mithril-common/src/test_utils/certificate_chain_builder.rs index 8f4a0ad4499..d72fc93bbe9 100644 --- a/mithril-common/src/test_utils/certificate_chain_builder.rs +++ b/mithril-common/src/test_utils/certificate_chain_builder.rs @@ -1,21 +1,22 @@ +use std::cmp::min; +use std::collections::{BTreeSet, HashMap}; +use std::iter::repeat_n; +use std::ops::{Deref, DerefMut}; +use std::sync::Arc; + use crate::{ certificate_chain::CertificateGenesisProducer, crypto_helper::{ ProtocolAggregateVerificationKey, ProtocolClerk, ProtocolGenesisSigner, ProtocolGenesisVerifier, ProtocolParameters, }, - entities::{Certificate, CertificateSignature, Epoch, ProtocolMessage, ProtocolMessagePartKey}, + entities::{ + CardanoDbBeacon, Certificate, CertificateMetadata, CertificateSignature, Epoch, + ProtocolMessage, ProtocolMessagePartKey, SignedEntityType, + }, test_utils::{fake_data, MithrilFixture, MithrilFixtureBuilder, SignerFixture}, }; -use crate::entities::CertificateMetadata; -use std::{ - cmp::min, - collections::{BTreeSet, HashMap}, - iter::repeat_n, - sync::Arc, -}; - /// Genesis certificate processor function type. For tests only. type GenesisCertificateProcessorFunc = dyn Fn(Certificate, &CertificateChainBuilderContext, &ProtocolGenesisSigner) -> Certificate; @@ -96,6 +97,71 @@ pub enum CertificateChainingMethod { Sequential, } +/// Fixture built from a [CertificateChainBuilder], certificates are ordered from latest to genesis +#[derive(Debug, Clone)] +pub struct CertificateChainFixture { + /// The full certificates list, ordered from latest to genesis + pub certificates_chained: Vec, + /// The genesis verifier associated with this chain genesis certificate + pub genesis_verifier: ProtocolGenesisVerifier, +} + +impl Deref for CertificateChainFixture { + type Target = [Certificate]; + + fn deref(&self) -> &Self::Target { + &self.certificates_chained + } +} + +impl DerefMut for CertificateChainFixture { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.certificates_chained + } +} + +impl> From for Vec { + fn from(fixture: CertificateChainFixture) -> Self { + fixture + .certificates_chained + .into_iter() + .map(C::from) + .collect() + } +} + +impl CertificateChainFixture { + /// Return the genesis certificate of this chain + pub fn genesis_certificate(&self) -> &Certificate { + &self.certificates_chained[self.certificates_chained.len() - 1] + } + + /// Return a copy of the chain but with reversed order (from genesis to last) + pub fn reversed_chain(&self) -> Vec { + self.certificates_chained.iter().rev().cloned().collect() + } + + /// Extract the chain starting from the certificate with the given hash and all its parents + /// until the genesis certificate. + pub fn certificate_path_to_genesis>( + &self, + certificate_hash: H, + ) -> Vec { + let mut subchain = Vec::new(); + let mut hash_to_search = certificate_hash.as_ref().to_string(); + + // takes advantage of the fact that chained certificates are ordered from last to genesis + for certificate in &self.certificates_chained { + if certificate.hash == hash_to_search { + subchain.push(certificate.clone()); + hash_to_search = certificate.previous_hash.clone(); + } + } + + subchain + } +} + /// A builder for creating a certificate chain. For tests only. /// /// # Simple example usage for building a fully valid certificate chain @@ -104,12 +170,12 @@ pub enum CertificateChainingMethod { /// use mithril_common::crypto_helper::ProtocolParameters; /// use mithril_common::test_utils::CertificateChainBuilder; /// -/// let (certificate_chain, _protocol_genesis_verifier) = CertificateChainBuilder::new() +/// let certificate_chain_fixture = CertificateChainBuilder::new() /// .with_total_certificates(5) /// .with_certificates_per_epoch(2) /// .build(); /// -/// assert_eq!(5, certificate_chain.len()); +/// assert_eq!(5, certificate_chain_fixture.len()); /// ``` /// /// # More complex example usage for building a fully valid certificate chain @@ -119,7 +185,7 @@ pub enum CertificateChainingMethod { /// use mithril_common::crypto_helper::ProtocolParameters; /// use mithril_common::test_utils::CertificateChainBuilder; /// -/// let (certificate_chain, _protocol_genesis_verifier) = CertificateChainBuilder::new() +/// let certificate_chain_fixture = CertificateChainBuilder::new() /// .with_total_certificates(5) /// .with_certificates_per_epoch(2) /// .with_protocol_parameters(ProtocolParameters { @@ -130,7 +196,7 @@ pub enum CertificateChainingMethod { /// .with_total_signers_per_epoch_processor(&|epoch| min(1 + *epoch as usize, 10)) /// .build(); /// -/// assert_eq!(5, certificate_chain.len()); +/// assert_eq!(5, certificate_chain_fixture.len()); /// ``` /// /// # Advanced example usage for building an adversarial certificate chain @@ -140,7 +206,7 @@ pub enum CertificateChainingMethod { /// use mithril_common::crypto_helper::ProtocolParameters; /// use mithril_common::test_utils::CertificateChainBuilder; /// -/// let (certificate_chain, _protocol_genesis_verifier) = CertificateChainBuilder::new() +/// let certificate_chain_fixture = CertificateChainBuilder::new() /// .with_total_certificates(5) /// .with_certificates_per_epoch(2) /// .with_standard_certificate_processor(&|certificate, context| { @@ -154,7 +220,7 @@ pub enum CertificateChainingMethod { /// }) /// .build(); /// -/// assert_eq!(5, certificate_chain.len()); +/// assert_eq!(5, certificate_chain_fixture.len()); /// ``` pub struct CertificateChainBuilder<'a> { total_certificates: u64, @@ -247,7 +313,7 @@ impl<'a> CertificateChainBuilder<'a> { } /// Build the certificate chain. - pub fn build(self) -> (Vec, ProtocolGenesisVerifier) { + pub fn build(self) -> CertificateChainFixture { let (genesis_signer, genesis_verifier) = CertificateChainBuilder::setup_genesis(); let genesis_certificate_processor = self.genesis_certificate_processor; let standard_certificate_processor = self.standard_certificate_processor; @@ -279,7 +345,10 @@ impl<'a> CertificateChainBuilder<'a> { .collect::>(); let certificates_chained = self.compute_chained_certificates(certificates); - (certificates_chained, genesis_verifier) + CertificateChainFixture { + certificates_chained, + genesis_verifier, + } } fn compute_clerk_for_signers(signers: &[SignerFixture]) -> ProtocolClerk { @@ -438,7 +507,10 @@ impl<'a> CertificateChainBuilder<'a> { .aggregate(&single_signatures, certificate.signed_message.as_bytes()) .unwrap(); certificate.signature = CertificateSignature::MultiSignature( - certificate.signed_entity_type(), + SignedEntityType::CardanoDatabase(CardanoDbBeacon::new( + *context.epoch, + context.index_certificate as u64, + )), multi_signature.into(), ); @@ -565,12 +637,12 @@ mod test { total_certificates: u64, certificates_per_epoch: u64, ) -> Vec { - let (certificate_chain, _) = CertificateChainBuilder::default() + let certificate_chain_fixture = CertificateChainBuilder::default() .with_total_certificates(total_certificates) .with_certificates_per_epoch(certificates_per_epoch) .build(); - certificate_chain + certificate_chain_fixture.certificates_chained } #[test] @@ -750,6 +822,10 @@ mod test { .build_genesis_certificate(&context, &protocol_genesis_signer); assert!(genesis_certificate.is_genesis()); + assert_eq!( + SignedEntityType::genesis(Epoch(1)), + genesis_certificate.signed_entity_type() + ); assert_eq!(Epoch(1), genesis_certificate.epoch); assert_eq!( expected_protocol_parameters, @@ -798,6 +874,10 @@ mod test { .build_standard_certificate(&context); assert!(!standard_certificate.is_genesis()); + assert_eq!( + SignedEntityType::CardanoDatabase(CardanoDbBeacon::new(1, 2)), + standard_certificate.signed_entity_type() + ); assert_eq!(Epoch(1), standard_certificate.epoch); assert_eq!( expected_protocol_parameters, @@ -937,7 +1017,7 @@ mod test { #[test] fn builds_certificate_chain_with_alteration_on_genesis_certificate() { - let (certificates, _) = CertificateChainBuilder::new() + let certificate_chain_fixture = CertificateChainBuilder::new() .with_total_certificates(5) .with_genesis_certificate_processor(&|certificate, _, _| { let mut certificate = certificate; @@ -949,7 +1029,7 @@ mod test { assert_eq!( "altered_msg".to_string(), - certificates.last().unwrap().signed_message + certificate_chain_fixture.last().unwrap().signed_message ); } @@ -961,7 +1041,7 @@ mod test { .map(|i| format!("altered-msg-{i}")) .collect::>(); - let (certificates, _) = CertificateChainBuilder::new() + let certificate_chain_fixture = CertificateChainBuilder::new() .with_total_certificates(total_certificates) .with_standard_certificate_processor(&|certificate, context| { let mut certificate = certificate; @@ -971,11 +1051,79 @@ mod test { }) .build(); - let signed_message = certificates + let signed_message = certificate_chain_fixture + .certificates_chained .into_iter() .take(total_certificates as usize - 1) .map(|certificate| certificate.signed_message) .collect::>(); assert_eq!(expected_signed_messages, signed_message); } + + mod certificate_chain_fixture { + use super::*; + + #[test] + fn get_genesis_certificate() { + let chain_with_only_a_genesis = CertificateChainBuilder::new() + .with_total_certificates(1) + .build(); + assert!(chain_with_only_a_genesis.genesis_certificate().is_genesis()); + + let chain_with_multiple_certificates = CertificateChainBuilder::new() + .with_total_certificates(10) + .build(); + assert!(chain_with_multiple_certificates + .genesis_certificate() + .is_genesis()); + } + + #[test] + fn path_to_genesis_from_a_chain_with_one_certificate_per_epoch() { + let chain = CertificateChainBuilder::new() + .with_total_certificates(5) + .with_certificates_per_epoch(1) + .build(); + + assert_eq!( + chain.certificate_path_to_genesis(&chain[0].hash), + chain.certificates_chained + ); + } + + #[test] + fn path_to_genesis_from_a_chain_with_multiple_certificates_per_epoch() { + let chain = CertificateChainBuilder::new() + .with_total_certificates(9) + .with_certificates_per_epoch(3) + .build(); + + let expected_subchain = vec![ + chain[1].clone(), + chain[4].clone(), + chain[7].clone(), + chain[8].clone(), + ]; + assert_eq!( + chain.certificate_path_to_genesis(&chain[1].hash), + expected_subchain + ); + } + + #[test] + fn reversed_chain() { + let chain = CertificateChainBuilder::new() + .with_total_certificates(5) + .with_certificates_per_epoch(2) + .build(); + + let expected: Vec = chain + .certificates_chained + .clone() + .into_iter() + .rev() + .collect(); + assert_eq!(chain.reversed_chain(), expected); + } + } } diff --git a/mithril-common/src/test_utils/mod.rs b/mithril-common/src/test_utils/mod.rs index 08d29a6182c..abd251787d4 100644 --- a/mithril-common/src/test_utils/mod.rs +++ b/mithril-common/src/test_utils/mod.rs @@ -20,7 +20,8 @@ mod temp_dir; pub use cardano_transactions_builder::CardanoTransactionsBuilder; pub use certificate_chain_builder::{ - CertificateChainBuilder, CertificateChainBuilderContext, CertificateChainingMethod, + CertificateChainBuilder, CertificateChainBuilderContext, CertificateChainFixture, + CertificateChainingMethod, }; pub use dir_eq::*; pub use fixture_builder::{MithrilFixtureBuilder, StakeDistributionGenerationMethod}; From 51f79743b644470031c8a9d39c1b8a47fdb6e4d2 Mon Sep 17 00:00:00 2001 From: DJO <790521+Alenar@users.noreply.github.com> Date: Fri, 27 Jun 2025 15:31:31 +0200 Subject: [PATCH 2/4] test(common): make `test_setup::setup_certificate_chain` return a `CertificateChainFixture` --- .../query/certificate/get_certificate.rs | 22 ++-- .../query/certificate/insert_certificate.rs | 9 +- .../src/database/record/certificate.rs | 6 +- .../repository/certificate_repository.rs | 23 ++-- .../certificate_chain/certificate_verifier.rs | 100 ++++++++---------- .../src/crypto_helper/tests_setup.rs | 18 ++-- 6 files changed, 77 insertions(+), 101 deletions(-) diff --git a/mithril-aggregator/src/database/query/certificate/get_certificate.rs b/mithril-aggregator/src/database/query/certificate/get_certificate.rs index 1dde57fbf5d..ed613adeaec 100644 --- a/mithril-aggregator/src/database/query/certificate/get_certificate.rs +++ b/mithril-aggregator/src/database/query/certificate/get_certificate.rs @@ -71,18 +71,18 @@ mod tests { #[test] fn test_get_certificate_records_by_epoch() { - let (certificates, _) = setup_certificate_chain(20, 7); + let certificates = setup_certificate_chain(20, 7); let connection = main_db_connection().unwrap(); - insert_certificate_records(&connection, certificates.clone()); + insert_certificate_records(&connection, certificates.certificates_chained.clone()); let certificate_records: Vec = connection .fetch_collect(GetCertificateRecordQuery::by_epoch(Epoch(1)).unwrap()) .unwrap(); let expected_certificate_records: Vec = certificates - .iter() + .reversed_chain() + .into_iter() .filter_map(|c| (c.epoch == Epoch(1)).then_some(c.to_owned().into())) - .rev() .collect(); assert_eq!(expected_certificate_records, certificate_records); @@ -90,9 +90,9 @@ mod tests { .fetch_collect(GetCertificateRecordQuery::by_epoch(Epoch(3)).unwrap()) .unwrap(); let expected_certificate_records: Vec = certificates - .iter() + .reversed_chain() + .into_iter() .filter_map(|c| (c.epoch == Epoch(3)).then_some(c.to_owned().into())) - .rev() .collect(); assert_eq!(expected_certificate_records, certificate_records); @@ -104,15 +104,15 @@ mod tests { #[test] fn test_get_all_certificate_records() { - let (certificates, _) = setup_certificate_chain(5, 2); + let certificates = setup_certificate_chain(5, 2); let expected_certificate_records: Vec = certificates - .iter() - .map(|c| c.to_owned().into()) - .rev() + .reversed_chain() + .into_iter() + .map(Into::into) .collect(); let connection = main_db_connection().unwrap(); - insert_certificate_records(&connection, certificates.clone()); + insert_certificate_records(&connection, certificates.certificates_chained.clone()); let certificate_records: Vec = connection .fetch_collect(GetCertificateRecordQuery::all()) diff --git a/mithril-aggregator/src/database/query/certificate/insert_certificate.rs b/mithril-aggregator/src/database/query/certificate/insert_certificate.rs index 64014580fb2..ea7494e02ed 100644 --- a/mithril-aggregator/src/database/query/certificate/insert_certificate.rs +++ b/mithril-aggregator/src/database/query/certificate/insert_certificate.rs @@ -111,11 +111,11 @@ mod tests { #[test] fn test_insert_certificate_record() { - let (certificates, _) = setup_certificate_chain(5, 2); + let certificates = setup_certificate_chain(5, 2); let connection = main_db_connection().unwrap(); - for certificate in certificates { + for certificate in certificates.certificates_chained { let certificate_record: CertificateRecord = certificate.into(); let certificate_record_saved = connection .fetch_first(InsertCertificateRecordQuery::one( @@ -128,9 +128,8 @@ mod tests { #[test] fn test_insert_many_certificates_records() { - let (certificates, _) = setup_certificate_chain(5, 2); - let certificates_records: Vec = - certificates.into_iter().map(|cert| cert.into()).collect(); + let certificates = setup_certificate_chain(5, 2); + let certificates_records: Vec = certificates.into(); let connection = main_db_connection().unwrap(); diff --git a/mithril-aggregator/src/database/record/certificate.rs b/mithril-aggregator/src/database/record/certificate.rs index 660a82b728e..493c91b747e 100644 --- a/mithril-aggregator/src/database/record/certificate.rs +++ b/mithril-aggregator/src/database/record/certificate.rs @@ -390,16 +390,16 @@ mod tests { #[test] fn test_convert_certificates() { - let (certificates, _) = setup_certificate_chain(20, 3); + let certificates = setup_certificate_chain(20, 3); let mut certificate_records: Vec = Vec::new(); - for certificate in certificates.clone() { + for certificate in certificates.certificates_chained.clone() { certificate_records.push(certificate.into()); } let mut certificates_new: Vec = Vec::new(); for certificate_record in certificate_records { certificates_new.push(certificate_record.into()); } - assert_eq!(certificates, certificates_new); + assert_eq!(certificates.certificates_chained, certificates_new); } #[test] diff --git a/mithril-aggregator/src/database/repository/certificate_repository.rs b/mithril-aggregator/src/database/repository/certificate_repository.rs index bd31fdb792a..e91945c3e18 100644 --- a/mithril-aggregator/src/database/repository/certificate_repository.rs +++ b/mithril-aggregator/src/database/repository/certificate_repository.rs @@ -245,10 +245,10 @@ mod tests { #[tokio::test] async fn repository_get_certificate() { - let (certificates, _) = setup_certificate_chain(5, 2); + let certificates = setup_certificate_chain(5, 2); let expected_hash = certificates[0].hash.clone(); let connection = Arc::new(main_db_connection().unwrap()); - insert_certificate_records(&connection, certificates.clone()); + insert_certificate_records(&connection, certificates.certificates_chained.clone()); let repository: CertificateRepository = CertificateRepository::new(connection); let certificate = repository @@ -268,29 +268,28 @@ mod tests { #[tokio::test] async fn repository_get_latest_certificates() { - let (certificates, _) = setup_certificate_chain(5, 2); + let certificates = setup_certificate_chain(5, 2); let connection = Arc::new(main_db_connection().unwrap()); - insert_certificate_records(&connection, certificates.clone()); + insert_certificate_records(&connection, certificates.certificates_chained.clone()); let repository = CertificateRepository::new(connection); let latest_certificates = repository .get_latest_certificates(certificates.len()) .await .unwrap(); - let expected: Vec = certificates.into_iter().rev().collect(); - assert_eq!(expected, latest_certificates); + assert_eq!(certificates.reversed_chain(), latest_certificates); } #[tokio::test] async fn repository_get_latest_genesis_certificate() { - let (certificates, _) = setup_certificate_chain(5, 2); + let certificates = setup_certificate_chain(5, 2); let connection = Arc::new(main_db_connection().unwrap()); - insert_certificate_records(&connection, certificates.clone()); + insert_certificate_records(&connection, certificates.certificates_chained.clone()); let repository = CertificateRepository::new(connection); let latest_certificates = repository.get_latest_genesis_certificate().await.unwrap(); - let expected = Some(certificates.last().unwrap().clone()); + let expected = Some(certificates.genesis_certificate().clone()); assert_eq!(expected, latest_certificates); } @@ -509,11 +508,11 @@ mod tests { #[tokio::test] async fn get_master_certificate_for_epoch() { - let (certificates, _) = setup_certificate_chain(3, 1); + let certificates = setup_certificate_chain(3, 1); let expected_certificate_id = &certificates[2].hash; let epoch = &certificates[2].epoch; let connection = Arc::new(main_db_connection().unwrap()); - insert_certificate_records(&connection, certificates.clone()); + insert_certificate_records(&connection, certificates.certificates_chained.clone()); let repository: CertificateRepository = CertificateRepository::new(connection); let certificate = repository @@ -527,7 +526,7 @@ mod tests { #[tokio::test] async fn save_certificate() { - let (certificates, _) = setup_certificate_chain(5, 3); + let certificates = setup_certificate_chain(5, 3); let connection = Arc::new(main_db_connection().unwrap()); let repository: CertificateRepository = CertificateRepository::new(connection.clone()); let certificate = repository diff --git a/mithril-common/src/certificate_chain/certificate_verifier.rs b/mithril-common/src/certificate_chain/certificate_verifier.rs index f26cc5877dd..6042454b44b 100644 --- a/mithril-common/src/certificate_chain/certificate_verifier.rs +++ b/mithril-common/src/certificate_chain/certificate_verifier.rs @@ -531,15 +531,14 @@ mod tests { #[tokio::test] async fn verify_genesis_certificate_success() { let (total_certificates, certificates_per_epoch) = (5, 1); - let (fake_certificates, genesis_verifier) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let verifier = MockDependencyInjector::new().build_certificate_verifier(); - let genesis_certificate = fake_certificates.last().unwrap().clone(); + let genesis_certificate = fake_certificates.genesis_certificate(); let verify = verifier .verify_genesis_certificate( - &genesis_certificate, - &genesis_verifier.to_verification_key(), + genesis_certificate, + &fake_certificates.genesis_verifier.to_verification_key(), ) .await; @@ -549,18 +548,17 @@ mod tests { #[tokio::test] async fn verify_genesis_certificate_fails_if_is_not_genesis() { let (total_certificates, certificates_per_epoch) = (5, 1); - let (fake_certificates, genesis_verifier) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let verifier = MockDependencyInjector::new().build_certificate_verifier(); let standard_certificate = fake_certificates[0].clone(); - let mut genesis_certificate = fake_certificates.last().unwrap().clone(); + let mut genesis_certificate = fake_certificates.genesis_certificate().clone(); genesis_certificate.signature = standard_certificate.signature.clone(); genesis_certificate.hash = genesis_certificate.compute_hash(); let error = verifier .verify_genesis_certificate( &genesis_certificate, - &genesis_verifier.to_verification_key(), + &fake_certificates.genesis_verifier.to_verification_key(), ) .await .expect_err("verify_genesis_certificate should fail"); @@ -574,16 +572,15 @@ mod tests { #[tokio::test] async fn verify_genesis_certificate_fails_if_hash_unmatch() { let (total_certificates, certificates_per_epoch) = (5, 1); - let (fake_certificates, genesis_verifier) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let verifier = MockDependencyInjector::new().build_certificate_verifier(); - let mut genesis_certificate = fake_certificates.last().unwrap().clone(); + let mut genesis_certificate = fake_certificates.genesis_certificate().clone(); genesis_certificate.hash = "another-hash".to_string(); let error = verifier .verify_genesis_certificate( &genesis_certificate, - &genesis_verifier.to_verification_key(), + &fake_certificates.genesis_verifier.to_verification_key(), ) .await .expect_err("verify_genesis_certificate should fail"); @@ -594,10 +591,9 @@ mod tests { #[tokio::test] async fn verify_genesis_certificate_fails_if_protocol_message_unmatch() { let (total_certificates, certificates_per_epoch) = (5, 1); - let (fake_certificates, genesis_verifier) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let verifier = MockDependencyInjector::new().build_certificate_verifier(); - let mut genesis_certificate = fake_certificates.last().unwrap().clone(); + let mut genesis_certificate = fake_certificates.genesis_certificate().clone(); genesis_certificate.protocol_message.set_message_part( ProtocolMessagePartKey::CurrentEpoch, "another-value".to_string(), @@ -607,7 +603,7 @@ mod tests { let error = verifier .verify_genesis_certificate( &genesis_certificate, - &genesis_verifier.to_verification_key(), + &fake_certificates.genesis_verifier.to_verification_key(), ) .await .expect_err("verify_genesis_certificate should fail"); @@ -621,17 +617,16 @@ mod tests { #[tokio::test] async fn verify_genesis_certificate_fails_if_epoch_unmatch() { let (total_certificates, certificates_per_epoch) = (5, 1); - let (fake_certificates, genesis_verifier) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let verifier = MockDependencyInjector::new().build_certificate_verifier(); - let mut genesis_certificate = fake_certificates.last().unwrap().clone(); + let mut genesis_certificate = fake_certificates.genesis_certificate().clone(); genesis_certificate.epoch -= 1; genesis_certificate.hash = genesis_certificate.compute_hash(); let error = verifier .verify_genesis_certificate( &genesis_certificate, - &genesis_verifier.to_verification_key(), + &fake_certificates.genesis_verifier.to_verification_key(), ) .await .expect_err("verify_genesis_certificate should fail"); @@ -642,8 +637,7 @@ mod tests { #[tokio::test] async fn verify_standard_certificate_success_with_different_epochs_as_previous() { let (total_certificates, certificates_per_epoch) = (5, 1); - let (fake_certificates, _) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let verifier = MockDependencyInjector::new().build_certificate_verifier(); let certificate = fake_certificates[0].clone(); let previous_certificate = fake_certificates[1].clone(); @@ -658,8 +652,7 @@ mod tests { #[tokio::test] async fn verify_standard_certificate_success_with_same_epoch_as_previous() { let (total_certificates, certificates_per_epoch) = (5, 2); - let (fake_certificates, _) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let verifier = MockDependencyInjector::new().build_certificate_verifier(); let certificate = fake_certificates[0].clone(); let previous_certificate = fake_certificates[1].clone(); @@ -674,10 +667,9 @@ mod tests { #[tokio::test] async fn verify_standard_certificate_fails_if_is_not_genesis() { let (total_certificates, certificates_per_epoch) = (5, 1); - let (fake_certificates, _) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let verifier = MockDependencyInjector::new().build_certificate_verifier(); - let genesis_certificate = fake_certificates.last().unwrap().clone(); + let genesis_certificate = fake_certificates.genesis_certificate(); let mut standard_certificate = fake_certificates[0].clone(); standard_certificate.signature = genesis_certificate.signature.clone(); standard_certificate.hash = standard_certificate.compute_hash(); @@ -697,8 +689,7 @@ mod tests { #[tokio::test] async fn verify_standard_certificate_fails_if_infinite_loop() { let (total_certificates, certificates_per_epoch) = (5, 1); - let (fake_certificates, _) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let verifier = MockDependencyInjector::new().build_certificate_verifier(); let mut certificate = fake_certificates[0].clone(); certificate.previous_hash = certificate.hash.clone(); @@ -718,8 +709,7 @@ mod tests { #[tokio::test] async fn verify_standard_certificate_fails_if_hash_unmatch() { let (total_certificates, certificates_per_epoch) = (5, 1); - let (fake_certificates, _) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let verifier = MockDependencyInjector::new().build_certificate_verifier(); let mut certificate = fake_certificates[0].clone(); certificate.hash = "another-hash".to_string(); @@ -736,8 +726,7 @@ mod tests { #[tokio::test] async fn verify_standard_certificate_fails_if_protocol_message_unmatch() { let (total_certificates, certificates_per_epoch) = (5, 1); - let (fake_certificates, _) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let verifier = MockDependencyInjector::new().build_certificate_verifier(); let mut certificate = fake_certificates[0].clone(); certificate.protocol_message.set_message_part( @@ -761,8 +750,7 @@ mod tests { #[tokio::test] async fn verify_standard_certificate_fails_if_epoch_unmatch() { let (total_certificates, certificates_per_epoch) = (5, 1); - let (fake_certificates, _) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let verifier = MockDependencyInjector::new().build_certificate_verifier(); let mut certificate = fake_certificates[0].clone(); certificate.epoch -= 1; @@ -842,8 +830,7 @@ mod tests { #[tokio::test] async fn verify_standard_certificate_fails_if_certificate_previous_hash_unmatch() { let (total_certificates, certificates_per_epoch) = (5, 1); - let (fake_certificates, _) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let verifier = MockDependencyInjector::new().build_certificate_verifier(); let certificate = fake_certificates[0].clone(); let mut previous_certificate = fake_certificates[1].clone(); @@ -864,8 +851,7 @@ mod tests { #[tokio::test] async fn verify_standard_certificate_fails_if_certificate_chain_avk_unmatch() { let (total_certificates, certificates_per_epoch) = (5, 1); - let (fake_certificates, _) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let verifier = MockDependencyInjector::new().build_certificate_verifier(); let mut certificate = fake_certificates[0].clone(); let mut previous_certificate = fake_certificates[1].clone(); @@ -890,8 +876,7 @@ mod tests { #[tokio::test] async fn verify_standard_certificate_fails_if_certificate_chain_protocol_parameters_unmatch() { let (total_certificates, certificates_per_epoch) = (5, 1); - let (fake_certificates, _) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let verifier = MockDependencyInjector::new().build_certificate_verifier(); let mut certificate = fake_certificates[0].clone(); let mut previous_certificate = fake_certificates[1].clone(); @@ -919,16 +904,15 @@ mod tests { #[tokio::test] async fn verify_certificate_success_when_certificate_is_genesis_and_valid() { let (total_certificates, certificates_per_epoch) = (5, 1); - let (fake_certificates, genesis_verifier) = - setup_certificate_chain(total_certificates, certificates_per_epoch); - let genesis_certificate = fake_certificates.last().unwrap().clone(); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); + let genesis_certificate = fake_certificates.genesis_certificate(); let mock_container = MockDependencyInjector::new(); let verifier = mock_container.build_certificate_verifier(); let verify = verifier .verify_certificate( - &genesis_certificate, - &genesis_verifier.to_verification_key(), + genesis_certificate, + &fake_certificates.genesis_verifier.to_verification_key(), ) .await; @@ -938,8 +922,7 @@ mod tests { #[tokio::test] async fn verify_certificate_success_when_certificate_is_standard_and_valid() { let (total_certificates, certificates_per_epoch) = (5, 1); - let (fake_certificates, genesis_verifier) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let certificate = fake_certificates[0].clone(); let previous_certificate = fake_certificates[1].clone(); let mut mock_container = MockDependencyInjector::new(); @@ -951,7 +934,10 @@ mod tests { let verifier = mock_container.build_certificate_verifier(); let verify = verifier - .verify_certificate(&certificate, &genesis_verifier.to_verification_key()) + .verify_certificate( + &certificate, + &fake_certificates.genesis_verifier.to_verification_key(), + ) .await; verify.expect("verify_certificate should not fail"); @@ -1013,8 +999,7 @@ mod tests { } let (total_certificates, certificates_per_epoch) = (10, 1); - let (fake_certificates, genesis_verifier) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let fake_certificate_to_verify = fake_certificates[0].clone(); let verifier = CertificateVerifierTest::from_certificates(&fake_certificates); assert!(verifier.has_unverified_certificates().await); @@ -1022,7 +1007,7 @@ mod tests { let verify = verifier .verify_certificate_chain( fake_certificate_to_verify, - &genesis_verifier.to_verification_key(), + &fake_certificates.genesis_verifier.to_verification_key(), ) .await; @@ -1033,8 +1018,7 @@ mod tests { #[tokio::test] async fn verify_certificate_chain_success_when_chain_is_valid() { let (total_certificates, certificates_per_epoch) = (7, 2); - let (fake_certificates, genesis_verifier) = - setup_certificate_chain(total_certificates, certificates_per_epoch); + let fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let certificate_retriever = FakeCertificaterRetriever::from_certificates(&fake_certificates); let verifier = @@ -1044,7 +1028,7 @@ mod tests { let verify = verifier .verify_certificate_chain( certificate_to_verify, - &genesis_verifier.to_verification_key(), + &fake_certificates.genesis_verifier.to_verification_key(), ) .await; verify.expect("verify_certificate_chain should not fail"); @@ -1053,7 +1037,7 @@ mod tests { #[tokio::test] async fn verify_certificate_chain_fails_when_chain_is_tampered() { let (total_certificates, certificates_per_epoch) = (7, 2); - let (mut fake_certificates, genesis_verifier) = + let mut fake_certificates = setup_certificate_chain(total_certificates, certificates_per_epoch); let index_certificate_fail = (total_certificates / 2) as usize; fake_certificates[index_certificate_fail].signed_message = "tampered-message".to_string(); @@ -1066,7 +1050,7 @@ mod tests { let error = verifier .verify_certificate_chain( certificate_to_verify, - &genesis_verifier.to_verification_key(), + &fake_certificates.genesis_verifier.to_verification_key(), ) .await .expect_err("verify_certificate_chain should fail"); diff --git a/mithril-common/src/crypto_helper/tests_setup.rs b/mithril-common/src/crypto_helper/tests_setup.rs index fd8b4b867e4..1f8071dc740 100644 --- a/mithril-common/src/crypto_helper/tests_setup.rs +++ b/mithril-common/src/crypto_helper/tests_setup.rs @@ -6,11 +6,11 @@ use rand_core::SeedableRng; use crate::{ crypto_helper::{cardano::KesSignerStandard, KesSigner}, - entities::{Certificate, ProtocolMessage, ProtocolMessagePartKey, SignerWithStake, Stake}, - test_utils::{CertificateChainBuilder, SignerFixture, TempDir}, + entities::{ProtocolMessage, ProtocolMessagePartKey, SignerWithStake, Stake}, + test_utils::{CertificateChainBuilder, CertificateChainFixture, SignerFixture, TempDir}, }; -use super::{ed25519_alias::genesis::*, types::*, OpCert, SerDeShelleyFileFormat}; +use super::{types::*, OpCert, SerDeShelleyFileFormat}; /// Create or retrieve a temporary directory for storing cryptographic material for a signer, use this for tests only. pub fn setup_temp_directory_for_signer( @@ -192,19 +192,13 @@ pub fn setup_signers_from_stake_distribution( } /// Instantiate a certificate chain, use this for tests only. -/// Todo: update to CertificateChainFixture pub fn setup_certificate_chain( total_certificates: u64, certificates_per_epoch: u64, -) -> (Vec, ProtocolGenesisVerifier) { - let certificate_chain_fixture = CertificateChainBuilder::new() +) -> CertificateChainFixture { + CertificateChainBuilder::new() .with_total_certificates(total_certificates) .with_certificates_per_epoch(certificates_per_epoch) .with_protocol_parameters(setup_protocol_parameters()) - .build(); - - ( - certificate_chain_fixture.certificates_chained, - certificate_chain_fixture.genesis_verifier, - ) + .build() } From 89a6781f17e70362a7a6816a92e1ce0a4632d636 Mon Sep 17 00:00:00 2001 From: DJO <790521+Alenar@users.noreply.github.com> Date: Thu, 26 Jun 2025 17:43:52 +0200 Subject: [PATCH 3/4] test(common): introduce mock util and `MockInitializer` trait --- .../src/test_utils/mock_extensions.rs | 61 +++++++++++++++++++ mithril-common/src/test_utils/mod.rs | 1 + 2 files changed, 62 insertions(+) create mode 100644 mithril-common/src/test_utils/mock_extensions.rs diff --git a/mithril-common/src/test_utils/mock_extensions.rs b/mithril-common/src/test_utils/mock_extensions.rs new file mode 100644 index 00000000000..d4644230ded --- /dev/null +++ b/mithril-common/src/test_utils/mock_extensions.rs @@ -0,0 +1,61 @@ +//! A set of tools for working with `automock` +//! +//! IMPORTANT: To avoid polluting production code, those tools do not expose or reexpose any +//! `automock`types, users need to add them themselves to their crates. +use std::sync::Arc; + +/// Helper to create configured Mockall mock. +/// +/// This allows creation of the mock in a dedicated block isolated from the remaining test method +/// code. +pub struct MockBuilder { + phantom: std::marker::PhantomData, +} + +impl MockBuilder { + /// Create a new instance of the mock with the given configuration + /// + /// The type must be specified either: + /// ``` + /// use mithril_common::test_utils::mock_extensions::MockBuilder; + /// # #[derive(Default)] struct MockType {}; + /// + /// // from the builder generic + /// let mock = MockBuilder::::configure(|mock| {}); + /// + /// // or from the closure parameter + /// let mock = MockBuilder::configure(|mock: &mut MockType| {}); + /// ``` + pub fn configure(mock_config: impl FnOnce(&mut M)) -> Arc { + let mut mock = M::default(); + mock_config(&mut mock); + Arc::new(mock) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[mockall::automock] + trait TestTrait { + fn test_method(&self) -> String; + } + + #[test] + fn using_mock_builder() { + // specify the type on the closure parameter + let mock = MockBuilder::configure(|mock: &mut MockTestTrait| { + mock.expect_test_method() + .returning(|| "test explicit type".to_string()); + }); + assert_eq!("test explicit type".to_string(), mock.test_method()); + + // specify the type on the builder generic + let mock = MockBuilder::::configure(|mock| { + mock.expect_test_method() + .returning(|| "test turbofish".to_string()); + }); + assert_eq!("test turbofish".to_string(), mock.test_method()); + } +} diff --git a/mithril-common/src/test_utils/mod.rs b/mithril-common/src/test_utils/mod.rs index abd251787d4..535e27de0f0 100644 --- a/mithril-common/src/test_utils/mod.rs +++ b/mithril-common/src/test_utils/mod.rs @@ -8,6 +8,7 @@ pub mod fake_data; pub mod fake_keys; +pub mod mock_extensions; mod cardano_transactions_builder; mod certificate_chain_builder; From 4ec743e218ff91499abba9c5d64d432f9329dc08 Mon Sep 17 00:00:00 2001 From: DJO <790521+Alenar@users.noreply.github.com> Date: Mon, 30 Jun 2025 18:00:39 +0200 Subject: [PATCH 4/4] chore: upgrade crate versions * mithril-aggregator from `0.7.68` to `0.7.69` * mithril-client from `0.12.17` to `0.12.18` * mithril-common from `0.6.2` to `0.6.3` --- Cargo.lock | 6 +++--- mithril-aggregator/Cargo.toml | 2 +- mithril-client/Cargo.toml | 2 +- mithril-common/Cargo.toml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ff60cb29480..09f2d150883 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3889,7 +3889,7 @@ dependencies = [ [[package]] name = "mithril-aggregator" -version = "0.7.68" +version = "0.7.69" dependencies = [ "anyhow", "async-trait", @@ -4048,7 +4048,7 @@ dependencies = [ [[package]] name = "mithril-client" -version = "0.12.17" +version = "0.12.18" dependencies = [ "anyhow", "async-recursion", @@ -4138,7 +4138,7 @@ dependencies = [ [[package]] name = "mithril-common" -version = "0.6.2" +version = "0.6.3" dependencies = [ "anyhow", "async-trait", diff --git a/mithril-aggregator/Cargo.toml b/mithril-aggregator/Cargo.toml index 7eff387b46b..ddf7d805559 100644 --- a/mithril-aggregator/Cargo.toml +++ b/mithril-aggregator/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mithril-aggregator" -version = "0.7.68" +version = "0.7.69" description = "A Mithril Aggregator server" authors = { workspace = true } edition = { workspace = true } diff --git a/mithril-client/Cargo.toml b/mithril-client/Cargo.toml index 7af459f8f1b..f0409c2e2c0 100644 --- a/mithril-client/Cargo.toml +++ b/mithril-client/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mithril-client" -version = "0.12.17" +version = "0.12.18" description = "Mithril client library" authors = { workspace = true } edition = { workspace = true } diff --git a/mithril-common/Cargo.toml b/mithril-common/Cargo.toml index 84102d43c08..509dfeefaab 100644 --- a/mithril-common/Cargo.toml +++ b/mithril-common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mithril-common" -version = "0.6.2" +version = "0.6.3" description = "Common types, interfaces, and utilities for Mithril nodes." authors = { workspace = true } edition = { workspace = true }