use super::{Frame, WorkerRefusal, WorkerRefusalCode, decode, encode, encoded_len};
use serde_json::Value;
type TestResult = Result<(), Box<dyn std::error::Error>>;
fn bytes(frame: &Frame) -> Result<Vec<u8>, super::ProtocolError> {
let mut bytes = vec![0; encoded_len(frame)?];
let written = encode(frame, &mut bytes)?;
assert_eq!(written, bytes.len());
Ok(bytes)
}
fn hex(bytes: &[u8]) -> String {
const DIGITS: &[u8; 16] = b"0123456789abcdef";
let mut output = String::with_capacity(bytes.len() * 2);
for &byte in bytes {
output.push(char::from(DIGITS[usize::from(byte >> 4)]));
output.push(char::from(DIGITS[usize::from(byte & 0x0f)]));
}
output
}
#[test]
fn worker_refusal_fixture_pins_every_code_and_maximal_words() -> TestResult {
let fixture: Value =
serde_json::from_str(include_str!("../../../../docs/wire/worker-refusal.json"))?;
let cases = fixture["cases"].as_array().ok_or("missing cases")?;
assert_eq!(cases.len(), 5);
for case in cases {
let code = case["code"].as_str().ok_or("missing code")?;
let words = case["words"].as_str().ok_or("missing words")?;
let refusal = WorkerRefusal::new(code, words)?;
assert_eq!(hex(&refusal.canonical_bytes()?), case["payload_hex"]);
assert_eq!(WorkerRefusal::decode(&refusal.canonical_bytes()?)?, refusal);
assert_eq!(
refusal.code().reason_code(),
case["conversation_reason_code"]
);
assert_eq!(refusal.code().caller_name(), case["conversation_code"]);
let frame = Frame::new_push_refusal(1, 7, &refusal)?;
let encoded = bytes(&frame)?;
assert_eq!(hex(&encoded), case["frame_hex"]);
let (decoded, consumed) = decode(&encoded)?;
assert_eq!(consumed, encoded.len());
assert_eq!(decoded, frame);
let caller_frame = Frame::ConversationError {
flags: 0,
stream_id: 1,
conversation_id: 9,
reason_code: refusal.code().reason_code(),
message: Some(words.to_owned()),
};
assert_eq!(hex(&bytes(&caller_frame)?), case["conversation_frame_hex"]);
}
for code in WorkerRefusalCode::ALL {
assert!(cases.iter().any(|case| case["code"] == code.name()));
assert_eq!(
WorkerRefusalCode::from_reason_code(code.reason_code()),
Some(code)
);
}
assert_eq!(
cases[4]["words"]
.as_str()
.ok_or("missing maximal words")?
.len(),
1024
);
let control = &fixture["opaque_control"];
let opaque = Frame::new_push_reply(1, 7, vec![0, 1, 2, 255])?;
assert_eq!(hex(&bytes(&opaque)?), control["frame_hex"]);
assert_eq!(decode(&bytes(&opaque)?)?.0, opaque);
Ok(())
}
#[test]
fn worker_refusal_preserves_every_captured_golden_trace_frame() -> TestResult {
for capture in [
include_bytes!("../../../../docs/wire/golden-trace/admitter.c2s.bin").as_slice(),
include_bytes!("../../../../docs/wire/golden-trace/admitter.s2c.bin").as_slice(),
include_bytes!("../../../../docs/wire/golden-trace/observer.c2s.bin").as_slice(),
include_bytes!("../../../../docs/wire/golden-trace/observer.s2c.bin").as_slice(),
] {
let mut remaining = capture;
while !remaining.is_empty() {
let (frame, consumed) = decode(remaining)?;
assert!(consumed > 0);
let original = remaining.get(..consumed).ok_or("invalid decoded length")?;
assert_eq!(bytes(&frame)?, original);
remaining = remaining.get(consumed..).ok_or("invalid decoded length")?;
}
}
Ok(())
}
#[test]
fn worker_refusal_requires_exact_canonical_record_and_closed_code() -> TestResult {
for malformed in [
br#"{"code":"busy","words":"secret","extra":true}"#.as_slice(),
br#"{"code":"busy","words":"first","words":"second"}"#,
br#"{"words":"secret","code":"busy"}"#,
br#"{"code": "busy", "words": "secret"}"#,
br#"{"code":"unknown","words":"secret"}"#,
br#"{"code":"busy"}"#,
br#"{"code":"busy","words":4}"#,
br#"{"code":"busy","words":"secret"}null"#,
b"\xff",
b"[]",
b"null",
] {
let error = WorkerRefusal::decode(malformed)
.err()
.ok_or("accepted malformed refusal")?;
assert!(!format!("{error:?}").contains("secret"));
}
assert!(WorkerRefusal::new("Busy", "secret").is_err());
assert!(WorkerRefusal::new("worker_busy", "secret").is_err());
Ok(())
}
#[test]
fn worker_refusal_bound_counts_utf8_bytes_and_escaped_control_bytes() -> TestResult {
for words in ["é".repeat(512), "\0".repeat(1024), String::new()] {
let refusal = WorkerRefusal::new("unavailable", words)?;
assert_eq!(WorkerRefusal::decode(&refusal.canonical_bytes()?)?, refusal);
}
for words in ["x".repeat(1025), "é".repeat(513)] {
let error = WorkerRefusal::new("busy", words)
.err()
.ok_or("accepted oversized words")?;
assert!(error.message().ok_or("missing bound")?.contains("1024"));
}
assert!(WorkerRefusal::decode(&vec![b' '; 7000]).is_err());
Ok(())
}
#[test]
fn worker_refusal_reserved_flags_are_named_before_encoding() -> TestResult {
for reserved in [2, 4, 8, 16, 32, 64, 128, 255] {
let frame = Frame::PushReply {
flags: reserved,
stream_id: 1,
correlation_id: 7,
payload: vec![],
};
let error = encoded_len(&frame).err().ok_or("accepted reserved flags")?;
assert!(
error
.message()
.ok_or("missing fault name")?
.contains("push_reply_reserved_flags")
);
}
assert!(Frame::new_push_refusal(0, 7, &WorkerRefusal::new("busy", "")?).is_err());
Ok(())
}
#[test]
fn worker_refusal_debug_never_exposes_words_or_payload_bytes() -> TestResult {
let refusal = WorkerRefusal::new("busy", "worker-private-words")?;
let frame = Frame::new_push_refusal(1, 7, &refusal)?;
for rendered in [format!("{refusal:?}"), format!("{frame:?}")] {
assert!(!rendered.contains("worker-private-words"));
assert!(!rendered.contains("123, 34, 99"));
}
Ok(())
}