Files
core/test/rust/runtime/worker/protocol.rs
T
2026-11-03 03:32:07 +00:00

172 lines
5.4 KiB
Rust

//! 出站帧保留 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<String, String> {
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()
);
}
}
}