restructure and test, pure python and rust transport both _work_

This commit is contained in:
2026-04-10 16:25:54 -03:00
parent 9d3ff2c6ba
commit e906b0a963
11 changed files with 1146 additions and 67 deletions

View File

@@ -10,3 +10,6 @@ serde_json = { workspace = true }
tracing = { workspace = true }
tracing-subscriber = { workspace = true }
anyhow = { workspace = true }
[dev-dependencies]
tokio = { workspace = true, features = ["macros", "rt"] }

View File

@@ -256,6 +256,117 @@ mod tests {
}
}
// -- P1: Audio packet round-trip --
#[test]
fn audio_packet_round_trip() {
let header = PacketHeader {
packet_type: PacketType::Audio,
flags: 0,
length: 256,
timestamp_ns: 500_000_000,
};
let bytes = header.to_bytes();
let decoded = PacketHeader::from_bytes(&bytes).unwrap();
assert_eq!(decoded.packet_type, PacketType::Audio);
assert!(!decoded.is_keyframe());
assert_eq!(decoded.length, 256);
assert_eq!(decoded.timestamp_ns, 500_000_000);
}
// -- P1: Partial / truncated reads --
#[test]
fn header_rejects_unknown_packet_type() {
let mut bytes = [0u8; HEADER_SIZE];
bytes[0] = 99; // not 0, 1, or 2
assert!(PacketHeader::from_bytes(&bytes).is_err());
}
#[test]
fn header_at_max_payload_size_is_accepted() {
let mut bytes = [0u8; HEADER_SIZE];
bytes[4..8].copy_from_slice(&MAX_PAYLOAD_SIZE.to_le_bytes());
assert!(PacketHeader::from_bytes(&bytes).is_ok());
}
#[tokio::test]
async fn read_packet_truncated_header_returns_error() {
// Feed only 8 bytes (half a header) — read_exact should fail.
let short_buf: &[u8] = &[0u8; 8];
let mut reader = tokio::io::BufReader::new(short_buf);
let result = read_packet(&mut reader).await;
assert!(result.is_err(), "expected error on truncated header");
}
#[tokio::test]
async fn read_packet_truncated_payload_returns_error() {
// Write a valid header claiming 100 bytes of payload, but only provide 50.
let header = PacketHeader {
packet_type: PacketType::Video,
flags: FLAG_KEYFRAME,
length: 100,
timestamp_ns: 0,
};
let mut buf = Vec::new();
buf.extend_from_slice(&header.to_bytes());
buf.extend_from_slice(&[0u8; 50]); // only 50 of the promised 100
let mut reader = tokio::io::BufReader::new(buf.as_slice());
let result = read_packet(&mut reader).await;
assert!(result.is_err(), "expected error on truncated payload");
}
#[tokio::test]
async fn write_then_read_round_trip() {
let payload: Vec<u8> = (0u8..128).collect();
let packet = WirePacket {
header: PacketHeader {
packet_type: PacketType::Audio,
flags: 0,
length: payload.len() as u32,
timestamp_ns: 999_999_999,
},
payload: payload.clone(),
};
let mut buf = Vec::new();
write_packet(&mut buf, &packet).await.unwrap();
let mut reader = tokio::io::BufReader::new(buf.as_slice());
let decoded = read_packet(&mut reader).await.unwrap();
assert_eq!(decoded.header.packet_type, PacketType::Audio);
assert_eq!(decoded.header.timestamp_ns, 999_999_999);
assert_eq!(decoded.payload, payload);
}
// -- P1: Timestamp monotonicity helpers --
#[test]
fn zero_timestamp_is_valid() {
let header = PacketHeader {
packet_type: PacketType::Video,
flags: FLAG_KEYFRAME,
length: 0,
timestamp_ns: 0,
};
let decoded = PacketHeader::from_bytes(&header.to_bytes()).unwrap();
assert_eq!(decoded.timestamp_ns, 0);
}
#[test]
fn max_timestamp_round_trips() {
let header = PacketHeader {
packet_type: PacketType::Video,
flags: 0,
length: 0,
timestamp_ns: u64::MAX,
};
let decoded = PacketHeader::from_bytes(&header.to_bytes()).unwrap();
assert_eq!(decoded.timestamp_ns, u64::MAX);
}
#[test]
fn all_control_variants_serialize() {
let messages = vec![