use super::{Frame, ProtocolError, decode, encode, encoded_len};
const OLDER_ACK: [u8; 18] = [
0x0A, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x07,
];
const FLAGS_BYTE: usize = 1;
fn encode_frame(frame: &Frame) -> Result<Vec<u8>, ProtocolError> {
let mut bytes = vec![0_u8; encoded_len(frame)?];
let written = encode(frame, &mut bytes)?;
bytes.truncate(written);
Ok(bytes)
}
fn ack(durable_position: Option<u64>) -> Frame {
Frame::PublishAck {
flags: 0x01,
stream_id: 1,
message_id: 7,
durable_position,
}
}
#[test]
fn publish_ack_without_position_keeps_the_older_layout() -> Result<(), ProtocolError> {
assert_eq!(encode_frame(&ack(None))?, OLDER_ACK.to_vec());
Ok(())
}
#[test]
fn publish_ack_with_position_appends_it() -> Result<(), ProtocolError> {
let bytes = encode_frame(&ack(Some(7717)))?;
assert_eq!(bytes.len(), OLDER_ACK.len() + 8);
let Some(tail) = bytes.get(bytes.len() - 8..) else {
return Err(ProtocolError::codec(
"encoded ack shorter than its position",
));
};
assert_eq!(tail, 7717_u64.to_be_bytes().as_slice());
assert_eq!(bytes.get(FLAGS_BYTE), Some(&0x03));
Ok(())
}
#[test]
fn older_publish_ack_decodes_without_position() -> Result<(), ProtocolError> {
let (frame, consumed) = decode(&OLDER_ACK)?;
assert_eq!(consumed, OLDER_ACK.len());
assert_eq!(frame, ack(None));
Ok(())
}
#[test]
fn newer_publish_ack_decodes_with_position() -> Result<(), ProtocolError> {
let bytes = encode_frame(&ack(Some(7717)))?;
let (frame, consumed) = decode(&bytes)?;
assert_eq!(consumed, bytes.len());
assert!(matches!(
frame,
Frame::PublishAck {
stream_id: 1,
message_id: 7,
durable_position: Some(7717),
..
}
));
Ok(())
}
#[test]
fn publish_ack_flag_without_position_is_refused() {
let mut bytes = OLDER_ACK;
bytes[FLAGS_BYTE] = 0x03;
assert!(matches!(
decode(&bytes),
Err(ProtocolError::CodecError { .. })
));
}