use crate::error::{Error, Result};
use crate::message::Message;
pub fn encode(message: &Message) -> Result<Vec<u8>> {
pack_io::encode(message).map_err(|e| Error::encoding("encode message", e))
}
pub fn decode(bytes: &[u8]) -> Result<Message> {
pack_io::decode(bytes).map_err(|e| Error::encoding("decode message", e))
}
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used, clippy::expect_used)]
use super::*;
use crate::message::{
AppendEntries, AppendEntriesReply, InstallSnapshot, InstallSnapshotReply, RequestVote,
RequestVoteReply, TimeoutNow,
};
use crate::types::{LogEntry, Snapshot};
fn round_trip(message: Message) {
let bytes = encode(&message).unwrap();
assert_eq!(decode(&bytes).unwrap(), message);
}
#[test]
fn test_every_message_variant_round_trips() {
round_trip(Message::RequestVote(RequestVote {
term: 4,
candidate: 2,
last_log_index: 9,
last_log_term: 3,
force: false,
}));
round_trip(Message::RequestVoteReply(RequestVoteReply {
term: 4,
vote_granted: true,
from: 3,
}));
round_trip(Message::AppendEntries(AppendEntries {
term: 5,
leader: 1,
prev_log_index: 2,
prev_log_term: 1,
entries: vec![
LogEntry::new(5, 3, b"cmd".to_vec()),
LogEntry::config(5, 4, &[1, 2, 3]),
],
leader_commit: 2,
}));
round_trip(Message::AppendEntriesReply(AppendEntriesReply {
term: 5,
success: false,
from: 2,
match_index: 0,
conflict_index: 3,
conflict_term: 2,
}));
round_trip(Message::InstallSnapshot(InstallSnapshot {
term: 6,
leader: 1,
snapshot: Snapshot::new(10, 3, b"serialized state".to_vec()),
}));
round_trip(Message::InstallSnapshotReply(InstallSnapshotReply {
term: 6,
from: 2,
last_index: 10,
}));
round_trip(Message::InstallSnapshot(InstallSnapshot {
term: 6,
leader: 1,
snapshot: Snapshot::with_config(10, 3, vec![1, 2, 3], b"state".to_vec()),
}));
round_trip(Message::TimeoutNow(TimeoutNow { term: 7, leader: 1 }));
}
#[test]
fn test_decode_rejects_garbage() {
assert!(decode(&[0xFF, 0xFF, 0xFF]).is_err());
}
proptest::proptest! {
#[test]
fn decode_never_panics_on_arbitrary_bytes(
bytes in proptest::collection::vec(proptest::prelude::any::<u8>(), 0..512)
) {
let _ = decode(&bytes);
}
#[test]
fn decoded_messages_re_encode_identically(
bytes in proptest::collection::vec(proptest::prelude::any::<u8>(), 0..512)
) {
if let Ok(message) = decode(&bytes) {
let re = encode(&message).unwrap();
proptest::prop_assert_eq!(decode(&re).unwrap(), message);
}
}
}
}