Skip to content

Commit bd22d12

Browse files
authored
test(config): add comprehensive unit tests for ConsensusConfig type (#70)
1 parent 8368667 commit bd22d12

1 file changed

Lines changed: 170 additions & 0 deletions

File tree

crates/node/config/src/consensus.rs

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,173 @@ where
8383
.map(|s| hex::decode(s.strip_prefix("0x").unwrap_or(&s)).map_err(serde::de::Error::custom))
8484
.collect()
8585
}
86+
87+
#[cfg(test)]
88+
mod tests {
89+
use commonware_codec::Write as _;
90+
use commonware_cryptography::Signer as _;
91+
92+
use super::*;
93+
94+
fn create_valid_public_key_bytes() -> Vec<u8> {
95+
let private_key =
96+
ed25519::PrivateKey::from(ed25519_consensus::SigningKey::from([42u8; 32]));
97+
let public_key = private_key.public_key();
98+
let mut bytes = Vec::new();
99+
public_key.write(&mut bytes);
100+
bytes
101+
}
102+
103+
#[test]
104+
fn default_consensus_config() {
105+
let config = ConsensusConfig::default();
106+
assert!(config.validator_key.is_none());
107+
assert_eq!(config.threshold, DEFAULT_THRESHOLD);
108+
assert!(config.participants.is_empty());
109+
}
110+
111+
#[test]
112+
fn default_threshold_constant() {
113+
assert_eq!(DEFAULT_THRESHOLD, 2);
114+
assert_eq!(default_threshold(), DEFAULT_THRESHOLD);
115+
}
116+
117+
#[test]
118+
fn serde_json_roundtrip() {
119+
let pk_bytes = create_valid_public_key_bytes();
120+
let config = ConsensusConfig {
121+
validator_key: Some(PathBuf::from("/path/to/key")),
122+
threshold: 3,
123+
participants: vec![pk_bytes],
124+
};
125+
let serialized = serde_json::to_string(&config).expect("serialize");
126+
let deserialized: ConsensusConfig = serde_json::from_str(&serialized).expect("deserialize");
127+
assert_eq!(config, deserialized);
128+
}
129+
130+
#[test]
131+
fn serde_toml_roundtrip() {
132+
let config =
133+
ConsensusConfig { validator_key: Some("/path/to/key".into()), ..Default::default() };
134+
let serialized = toml::to_string(&config).expect("serialize toml");
135+
let deserialized: ConsensusConfig = toml::from_str(&serialized).expect("deserialize toml");
136+
assert_eq!(config, deserialized);
137+
}
138+
139+
#[test]
140+
fn serde_defaults_applied() {
141+
let config: ConsensusConfig = serde_json::from_str("{}").expect("deserialize");
142+
assert!(config.validator_key.is_none());
143+
assert_eq!(config.threshold, DEFAULT_THRESHOLD);
144+
assert!(config.participants.is_empty());
145+
}
146+
147+
#[test]
148+
fn serde_partial_threshold() {
149+
let config: ConsensusConfig =
150+
serde_json::from_str(r#"{"threshold": 7}"#).expect("deserialize");
151+
assert_eq!(config.threshold, 7);
152+
assert!(config.validator_key.is_none());
153+
assert!(config.participants.is_empty());
154+
}
155+
156+
#[test]
157+
fn serde_partial_validator_key() {
158+
let config: ConsensusConfig =
159+
serde_json::from_str(r#"{"validator_key": "/etc/key"}"#).expect("deserialize");
160+
assert_eq!(config.validator_key, Some(PathBuf::from("/etc/key")));
161+
assert_eq!(config.threshold, DEFAULT_THRESHOLD);
162+
}
163+
164+
#[test]
165+
fn deserialize_participants_with_0x_prefix() {
166+
let pk_bytes = create_valid_public_key_bytes();
167+
let hex_with_prefix = format!("0x{}", hex::encode(&pk_bytes));
168+
let json = format!(r#"{{"participants": ["{}"]}}"#, hex_with_prefix);
169+
170+
let config: ConsensusConfig = serde_json::from_str(&json).expect("deserialize");
171+
assert_eq!(config.participants.len(), 1);
172+
assert_eq!(config.participants[0], pk_bytes);
173+
}
174+
175+
#[test]
176+
fn deserialize_participants_without_prefix() {
177+
let pk_bytes = create_valid_public_key_bytes();
178+
let hex_without_prefix = hex::encode(&pk_bytes);
179+
let json = format!(r#"{{"participants": ["{}"]}}"#, hex_without_prefix);
180+
181+
let config: ConsensusConfig = serde_json::from_str(&json).expect("deserialize");
182+
assert_eq!(config.participants.len(), 1);
183+
assert_eq!(config.participants[0], pk_bytes);
184+
}
185+
186+
#[test]
187+
fn build_validator_set_empty() {
188+
let config = ConsensusConfig::default();
189+
let result = config.build_validator_set().expect("build empty set");
190+
assert!(result.is_empty());
191+
}
192+
193+
#[test]
194+
fn build_validator_set_single_key() {
195+
let pk_bytes = create_valid_public_key_bytes();
196+
let config = ConsensusConfig { participants: vec![pk_bytes], ..Default::default() };
197+
let result = config.build_validator_set().expect("build validator set");
198+
assert_eq!(result.len(), 1);
199+
}
200+
201+
#[test]
202+
fn build_validator_set_multiple_keys() {
203+
let keys: Vec<_> = (1..=3u8)
204+
.map(|i| {
205+
let pk = ed25519::PrivateKey::from(ed25519_consensus::SigningKey::from([i; 32]));
206+
let mut bytes = Vec::new();
207+
pk.public_key().write(&mut bytes);
208+
bytes
209+
})
210+
.collect();
211+
212+
let config = ConsensusConfig { participants: keys, threshold: 2, ..Default::default() };
213+
214+
let result = config.build_validator_set().expect("build validator set");
215+
assert_eq!(result.len(), 3);
216+
}
217+
218+
#[test]
219+
fn build_validator_set_invalid_length() {
220+
let config = ConsensusConfig { participants: vec![vec![0u8; 16]], ..Default::default() };
221+
let result = config.build_validator_set();
222+
assert!(result.is_err());
223+
assert!(matches!(result.unwrap_err(), ConfigError::InvalidParticipantKeyLength(16)));
224+
}
225+
226+
#[test]
227+
fn participants_hex_serialization() {
228+
let pk_bytes = create_valid_public_key_bytes();
229+
let expected_hex = hex::encode(&pk_bytes);
230+
let config = ConsensusConfig { participants: vec![pk_bytes], ..Default::default() };
231+
232+
let serialized = serde_json::to_string(&config).expect("serialize");
233+
assert!(serialized.contains(&expected_hex));
234+
}
235+
236+
#[test]
237+
fn consensus_config_clone_and_eq() {
238+
let pk_bytes = create_valid_public_key_bytes();
239+
let config = ConsensusConfig {
240+
validator_key: Some(PathBuf::from("/custom/path")),
241+
threshold: 10,
242+
participants: vec![pk_bytes],
243+
};
244+
assert_eq!(config, config.clone());
245+
assert_ne!(config, ConsensusConfig::default());
246+
}
247+
248+
#[test]
249+
fn consensus_config_debug() {
250+
let config = ConsensusConfig::default();
251+
let debug = format!("{:?}", config);
252+
assert!(debug.contains("ConsensusConfig"));
253+
assert!(debug.contains("threshold"));
254+
}
255+
}

0 commit comments

Comments
 (0)