//! 出站帧保留 JSON 原文,并在写出长度前验证合并后的预算。 use super::*; use crate::wire::json::Json; use std::{hint::black_box, process::Stdio, time::Instant}; #[derive(serde::Serialize)] struct Call<'input> { kind: &'static str, id: u64, operation: &'input str, } #[test] fn outgoing_payload_preserves_spelling_and_combined_limits() { let header = Call { kind: "call", id: 1, operation: "雪\"\\", }; for source in ["null", " \n{\"雪\":[1e9999,-0,\"\\u96ea\"]}\t "] { let value = Json::parse(source).unwrap(); let head = payload_header( serde_json::to_string(&header).unwrap(), 4, ",\"payload\":", value.shape().unwrap(), ) .unwrap(); let frame = format!("{head}{}}}", source.trim_ascii()); #[derive(serde::Serialize)] struct Reference<'input> { #[serde(flatten)] header: &'input Call<'input>, payload: &'input RawValue, } assert_eq!( frame, serde_json::to_string(&Reference { header: &header, payload: serde_json::from_str(source).unwrap(), }) .unwrap() ); crate::wire::raw::validate(&frame).unwrap(); } for count in [document::MAX_VALUES - 5, document::MAX_VALUES - 4] { let value = Json::encode(&vec![0; count]).unwrap(); let encoded = payload_header( serde_json::to_string(&header).unwrap(), 4, ",\"payload\":", value.shape().unwrap(), ); assert_eq!(encoded.is_ok(), count == document::MAX_VALUES - 5); } for depth in [document::MAX_DEPTH - 1, document::MAX_DEPTH] { let value = Json::parse(&("[".repeat(depth) + &"]".repeat(depth))).unwrap(); assert_eq!( payload_header( serde_json::to_string(&header).unwrap(), 4, ",\"payload\":", value.shape().unwrap() ) .is_ok(), depth < document::MAX_DEPTH ); } } #[test] fn oversized_frame_does_not_write_a_partial_prefix() { let runtime = tokio::runtime::Builder::new_current_thread() .enable_all() .build() .unwrap(); runtime.block_on(async { let mut child = tokio::process::Command::new("cat") .stdin(Stdio::piped()) .stdout(Stdio::piped()) .spawn() .unwrap(); let mut channel = Channel::new(child.stdin.take().unwrap(), child.stdout.take().unwrap()); let payload = Json::string(&"a".repeat(LIMIT - 2)).unwrap(); let header = Call { kind: "call", id: 1, operation: "measure", }; assert!( channel .send_payload( serde_json::to_string(&header).unwrap(), 4, ",\"payload\":", payload.as_str(), payload.shape().unwrap() ) .await .is_err() ); let control = serde_json::json!({"kind":"health","id":0}); channel.send(&control).await.unwrap(); assert_eq!(channel.read().await.unwrap().as_str(), control.to_string()); drop(channel); assert!(child.wait().await.unwrap().success()); }); } fn reference_header(header: &Call<'_>, values: usize, depth: usize) -> Result { if values + 4 > document::MAX_VALUES || depth + 1 > document::MAX_DEPTH { return Err("JSON budget".into()); } let mut text = serde_json::to_string(header).map_err(|error| error.to_string())?; // 与正式通道一样,整帧字节预算在写出长度前检查,不属于帧头编码计时。 text.pop(); text.push_str(",\"payload\":"); Ok(text) } #[test] #[ignore = "explicit release performance probe; header only, not complete IPC"] fn outgoing_header_cost() { let header = Call { kind: "call", id: 42, operation: "measure", }; let shape = document::Shape::new(2, 1); let expected = reference_header(&header, 2, 1).unwrap(); assert_eq!( payload_header( serde_json::to_string(&header).unwrap(), 4, ",\"payload\":", shape ) .unwrap(), expected ); for sample in 0..15 { for native in if sample % 2 == 0 { [false, true] } else { [true, false] } { let started = Instant::now(); let mut checksum = 0; for _ in 0..100_000 { let text = if native { reference_header(black_box(&header), black_box(2), black_box(1)) } else { payload_header( serde_json::to_string(black_box(&header)).unwrap(), 4, ",\"payload\":", black_box(shape), ) } .unwrap(); checksum += black_box(text).len(); } assert_eq!(checksum, 100_000 * expected.len()); println!( "worker_header,{sample},{},{},{checksum}", if native { "rust" } else { "dever" }, started.elapsed().as_nanos() ); } } }