Skip to content

Commit e4f25d9

Browse files
committed
Allow to run all VerificationKeyStorer tests using a macro
1 parent a6972a0 commit e4f25d9

File tree

3 files changed

+162
-51
lines changed

3 files changed

+162
-51
lines changed

mithril-aggregator/src/store/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,8 @@ pub use certificate_store::CertificateStore;
77
pub use pending_certificate_store::CertificatePendingStore;
88
pub use protocol_parameters_store::{ProtocolParametersStore, ProtocolParametersStorer};
99
pub use verification_key_store::{VerificationKeyStore, VerificationKeyStorer};
10+
11+
#[cfg(test)]
12+
pub use verification_key_store::test_suite as verification_key_store_test_suite;
13+
#[cfg(test)]
14+
pub(crate) use verification_key_store::test_verification_key_storer;

mithril-aggregator/src/store/verification_key_store.rs

Lines changed: 137 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ use mithril_common::store::{adapter::StoreAdapter, StoreError};
88

99
type Adapter = Box<dyn StoreAdapter<Key = Epoch, Record = HashMap<PartyId, SignerWithStake>>>;
1010

11-
/// Mocking trait for `VerificationKeyStore`.
11+
/// Store and get signers verification keys for given epoch.
1212
#[async_trait]
1313
pub trait VerificationKeyStorer: Sync + Send {
14-
/// Save the verification key, for the given [Signer] for the given [Epoch].
14+
/// Save the verification key, for the given [Signer] for the given [Epoch], returns the
15+
/// previous values if one already existed.
1516
async fn save_verification_key(
1617
&self,
1718
epoch: Epoch,
@@ -88,24 +89,74 @@ impl VerificationKeyStorer for VerificationKeyStore {
8889
}
8990
}
9091

92+
/// Macro that generate tests that a [VerificationKeyStorer] must pass
9193
#[cfg(test)]
92-
mod tests {
93-
use super::*;
94+
macro_rules! test_verification_key_storer {
95+
($suit_name:ident => $store_builder:expr) => {
96+
#[cfg(test)]
97+
mod $suit_name {
98+
use crate::store::verification_key_store_test_suite as test_suite;
99+
100+
#[tokio::test]
101+
async fn save_key_in_empty_store() {
102+
test_suite::save_key_in_empty_store(&$store_builder).await;
103+
}
94104

95-
use mithril_common::store::adapter::MemoryAdapter;
105+
#[tokio::test]
106+
async fn update_signer_in_store() {
107+
test_suite::update_signer_in_store(&$store_builder).await;
108+
}
96109

97-
fn init_store(
110+
#[tokio::test]
111+
async fn get_verification_keys_for_empty_epoch() {
112+
test_suite::get_verification_keys_for_empty_epoch(&$store_builder).await;
113+
}
114+
115+
#[tokio::test]
116+
async fn get_verification_keys_for_existing_epoch() {
117+
test_suite::get_verification_keys_for_existing_epoch(&$store_builder).await;
118+
}
119+
120+
#[tokio::test]
121+
async fn check_retention_limit() {
122+
test_suite::check_retention_limit(&$store_builder).await;
123+
}
124+
}
125+
};
126+
}
127+
128+
#[cfg(test)]
129+
pub(crate) use test_verification_key_storer;
130+
131+
#[macro_use]
132+
#[cfg(test)]
133+
pub mod test_suite {
134+
use mithril_common::entities::{Epoch, PartyId, Signer, SignerWithStake};
135+
use std::collections::{BTreeMap, HashMap};
136+
use std::sync::Arc;
137+
138+
use crate::VerificationKeyStorer;
139+
140+
/// A builder of [VerificationKeyStorer], the arguments are:
141+
/// * initial_data
142+
/// * optional retention limit
143+
type StoreBuilder = dyn Fn(
144+
Vec<(Epoch, HashMap<PartyId, SignerWithStake>)>,
145+
Option<usize>,
146+
) -> Arc<dyn VerificationKeyStorer>;
147+
148+
fn build_signers(
98149
nb_epoch: u64,
99-
signers_per_epoch: u64,
100-
retention_limit: Option<usize>,
101-
) -> VerificationKeyStore {
102-
let mut values: Vec<(Epoch, HashMap<PartyId, SignerWithStake>)> = Vec::new();
150+
signers_per_epoch: usize,
151+
) -> Vec<(Epoch, HashMap<PartyId, SignerWithStake>)> {
152+
let mut values = vec![];
103153

104154
for epoch in 1..=nb_epoch {
105-
let mut signers: HashMap<PartyId, SignerWithStake> = HashMap::new();
155+
let mut signers: HashMap<PartyId, SignerWithStake> =
156+
HashMap::with_capacity(signers_per_epoch);
106157

107158
for party_idx in 1..=signers_per_epoch {
108-
let party_id = format!("{party_idx}");
159+
let party_id = format!("party_id:e{epoch}:{party_idx}");
109160
signers.insert(
110161
party_id.clone(),
111162
SignerWithStake {
@@ -121,19 +172,12 @@ mod tests {
121172
values.push((Epoch(epoch), signers));
122173
}
123174

124-
let values = if !values.is_empty() {
125-
Some(values)
126-
} else {
127-
None
128-
};
129-
let adapter: MemoryAdapter<Epoch, HashMap<PartyId, SignerWithStake>> =
130-
MemoryAdapter::new(values).unwrap();
131-
VerificationKeyStore::new(Box::new(adapter), retention_limit)
175+
values
132176
}
133177

134-
#[tokio::test]
135-
async fn save_key_in_empty_store() {
136-
let store = init_store(0, 0, None);
178+
pub async fn save_key_in_empty_store(store_builder: &StoreBuilder) {
179+
let signers = build_signers(0, 0);
180+
let store = store_builder(signers, None);
137181
let res = store
138182
.save_verification_key(
139183
Epoch(0),
@@ -152,15 +196,15 @@ mod tests {
152196
assert!(res.is_none());
153197
}
154198

155-
#[tokio::test]
156-
async fn update_signer_in_store() {
157-
let store = init_store(1, 1, None);
199+
pub async fn update_signer_in_store(store_builder: &StoreBuilder) {
200+
let signers = build_signers(1, 1);
201+
let store = store_builder(signers, None);
158202
let res = store
159203
.save_verification_key(
160204
Epoch(1),
161205
SignerWithStake {
162-
party_id: "1".to_string(),
163-
verification_key: "test".to_string(),
206+
party_id: "party_id:e1:1".to_string(),
207+
verification_key: "new_vkey".to_string(),
164208
verification_key_signature: None,
165209
operational_certificate: None,
166210
kes_period: None,
@@ -170,40 +214,50 @@ mod tests {
170214
.await
171215
.unwrap();
172216

173-
assert!(res.is_some());
174217
assert_eq!(
175-
SignerWithStake {
176-
party_id: "1".to_string(),
177-
verification_key: "vkey 1".to_string(),
218+
Some(SignerWithStake {
219+
party_id: "party_id:e1:1".to_string(),
220+
verification_key: "vkey party_id:e1:1".to_string(),
178221
verification_key_signature: None,
179222
operational_certificate: None,
180223
kes_period: None,
181224
stake: 10,
182-
},
183-
res.unwrap(),
225+
}),
226+
res,
184227
);
185228
}
186229

187-
#[tokio::test]
188-
async fn get_verification_keys_for_empty_epoch() {
189-
let store = init_store(2, 1, None);
230+
pub async fn get_verification_keys_for_empty_epoch(store_builder: &StoreBuilder) {
231+
let signers = build_signers(2, 1);
232+
let store = store_builder(signers, None);
190233
let res = store.get_verification_keys(Epoch(0)).await.unwrap();
191234

192235
assert!(res.is_none());
193236
}
194237

195-
#[tokio::test]
196-
async fn get_verification_keys_for_existing_epoch() {
197-
let store = init_store(2, 2, None);
198-
let res = store.get_verification_keys(Epoch(1)).await.unwrap();
238+
pub async fn get_verification_keys_for_existing_epoch(store_builder: &StoreBuilder) {
239+
let signers = build_signers(2, 2);
240+
let expected_signers: Option<BTreeMap<PartyId, Signer>> = signers
241+
.iter()
242+
.filter(|(e, _)| e == 1)
243+
.cloned()
244+
.map(|(_, signers)| {
245+
BTreeMap::from_iter(signers.into_iter().map(|(p, s)| (p, s.into())))
246+
})
247+
.next();
248+
let store = store_builder(signers, None);
249+
let res = store
250+
.get_verification_keys(Epoch(1))
251+
.await
252+
.unwrap()
253+
.map(|x| BTreeMap::from_iter(x.into_iter()));
199254

200-
assert!(res.is_some());
201-
assert_eq!(2, res.unwrap().len());
255+
assert_eq!(expected_signers, res);
202256
}
203257

204-
#[tokio::test]
205-
async fn check_retention_limit() {
206-
let store = init_store(2, 2, Some(2));
258+
pub async fn check_retention_limit(store_builder: &StoreBuilder) {
259+
let signers = build_signers(2, 2);
260+
let store = store_builder(signers, Some(2));
207261
assert!(store
208262
.get_verification_keys(Epoch(1))
209263
.await
@@ -223,10 +277,42 @@ mod tests {
223277
)
224278
.await
225279
.unwrap();
226-
assert!(store
227-
.get_verification_keys(Epoch(1))
228-
.await
229-
.unwrap()
230-
.is_none());
280+
let first_epoch_keys = store.get_verification_keys(Epoch(1)).await.unwrap();
281+
assert_eq!(None, first_epoch_keys);
282+
}
283+
}
284+
285+
#[cfg(test)]
286+
mod tests {
287+
use mithril_common::{
288+
entities::{Epoch, PartyId, SignerWithStake},
289+
store::adapter::MemoryAdapter,
290+
};
291+
use std::{collections::HashMap, sync::Arc};
292+
293+
use crate::{VerificationKeyStore, VerificationKeyStorer};
294+
295+
pub fn init_store(
296+
initial_data: Vec<(Epoch, HashMap<PartyId, SignerWithStake>)>,
297+
retention_limit: Option<usize>,
298+
) -> Arc<dyn VerificationKeyStorer> {
299+
let values = if initial_data.is_empty() {
300+
None
301+
} else {
302+
Some(initial_data)
303+
};
304+
305+
let adapter: MemoryAdapter<Epoch, HashMap<PartyId, SignerWithStake>> =
306+
MemoryAdapter::new(values).unwrap();
307+
308+
Arc::new(VerificationKeyStore::new(
309+
Box::new(adapter),
310+
retention_limit,
311+
))
231312
}
313+
314+
test_verification_key_storer!(
315+
test_verification_key_store =>
316+
crate::store::verification_key_store::tests::init_store
317+
);
232318
}

mithril-common/src/entities/epoch.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,18 @@ impl PartialEq<Epoch> for u64 {
137137
}
138138
}
139139

140+
impl PartialEq<u64> for &Epoch {
141+
fn eq(&self, other: &u64) -> bool {
142+
self.0.eq(other)
143+
}
144+
}
145+
146+
impl PartialEq<&Epoch> for u64 {
147+
fn eq(&self, other: &&Epoch) -> bool {
148+
other.0.eq(self)
149+
}
150+
}
151+
140152
impl Display for Epoch {
141153
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
142154
write!(f, "{}", self.0)
@@ -201,4 +213,12 @@ mod tests {
201213
fn test_next() {
202214
assert_eq!(Epoch(4), Epoch(3).next());
203215
}
216+
217+
#[test]
218+
fn test_eq() {
219+
assert_eq!(Epoch(3), 3);
220+
assert_eq!(&Epoch(4), 4);
221+
assert_eq!(5, Epoch(5));
222+
assert_eq!(6, &Epoch(6));
223+
}
204224
}

0 commit comments

Comments
 (0)