Merge branch 'gemini/ticket-tests': ticket codec + gossip wire-type unit tests

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-02 05:37:26 -04:00
co-authored by Claude Opus 4.8
2 changed files with 110 additions and 0 deletions
+50
View File
@@ -285,3 +285,53 @@ impl RoomState for IrohGossipState {
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::network::PeerState;
use iroh::SecretKey;
fn sample_peer_state() -> PeerState {
let secret = SecretKey::generate();
let public = secret.public();
let addr = iroh::EndpointAddr::from(public);
PeerState {
name: "TestPeerGossip".to_string(),
is_muted: true,
addr,
}
}
#[test]
fn test_gossip_message_leave_round_trip() {
let original = GossipMessage::Leave;
let serialized = serde_json::to_string(&original).unwrap();
let deserialized: GossipMessage = serde_json::from_str(&serialized).unwrap();
assert!(matches!(deserialized, GossipMessage::Leave));
}
#[test]
fn test_gossip_payload_announce_round_trip() {
let peer_state = sample_peer_state();
let author = peer_state.addr.id;
let payload = GossipPayload {
author,
msg: GossipMessage::Announce(peer_state.clone()),
};
let serialized = serde_json::to_string(&payload).unwrap();
let deserialized: GossipPayload = serde_json::from_str(&serialized).unwrap();
assert_eq!(deserialized.author, author);
match deserialized.msg {
GossipMessage::Announce(state) => {
assert_eq!(state, peer_state);
}
GossipMessage::Leave => {
panic!("Expected GossipMessage::Announce, got Leave");
}
}
}
}
+60
View File
@@ -139,3 +139,63 @@ pub trait RoomState: Send + Sync {
pub mod iroh_impl;
pub mod gossip;
#[cfg(test)]
mod tests {
use super::*;
use iroh::{SecretKey, EndpointAddr};
fn sample_peer_state() -> PeerState {
let secret = SecretKey::generate();
let public = secret.public();
let addr = EndpointAddr::from(public);
PeerState {
name: "TestPeer".to_string(),
is_muted: false,
addr,
}
}
#[test]
fn test_ticket_round_trip() {
let state = sample_peer_state();
let topic_id = [7u8; 32];
let original_ticket = PeerSpeakTicket {
host_addr: state.addr.clone(),
topic_id,
};
let ticket_str = original_ticket.to_string();
let parsed_ticket = ticket_str.parse::<PeerSpeakTicket>().unwrap();
assert_eq!(parsed_ticket.host_addr.id, original_ticket.host_addr.id);
assert_eq!(parsed_ticket.topic_id, original_ticket.topic_id);
}
#[test]
fn test_malformed_rejection() {
// empty string
let res1 = "".parse::<PeerSpeakTicket>();
assert!(matches!(res1, Err(NetError::InvalidTicket(_))));
// non-base64 garbage
let res2 = "!!!not base64!!!".parse::<PeerSpeakTicket>();
assert!(matches!(res2, Err(NetError::InvalidTicket(_))));
// valid URL-safe-base64 that decodes to non-JSON bytes
let bad_json = b"hello world";
let encoded = base64::Engine::encode(
&base64::engine::general_purpose::URL_SAFE_NO_PAD,
bad_json,
);
let res3 = encoded.parse::<PeerSpeakTicket>();
assert!(matches!(res3, Err(NetError::InvalidTicket(_))));
}
#[test]
fn test_peer_state_serde_round_trip() {
let original = sample_peer_state();
let serialized = serde_json::to_string(&original).unwrap();
let deserialized: PeerState = serde_json::from_str(&serialized).unwrap();
assert_eq!(original, deserialized);
}
}