From 9bfb7778a5231d2e00057875900d6b8f1d80b115 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Cabrera?= Date: Wed, 23 Apr 2025 20:01:42 -0400 Subject: [PATCH 1/3] Fix codec handling This patch fixes how the encoding codec is handled across the entire codebase. Prior to this commit, support for codecs other than JSON was incomplete, mainly since the code assumed that all function output must be valid . Proper handling of codecs involves: * Validating JSON as the canonical input to function runner. * Encoding from JSON to a given codec if needed * Encoding to JSON from the function's output if needed and ensuring to keep save any encoding errors when needed. In order to achieve proper codec handling, I opted to encapsulate the details related to input and output bytes in a container (`BytesContainer`), which can either hold input or output bytes, and simiarly perform all the byte-level operations needed for reporting, such as calculating the length, presenting a human-readable representation, etc. This commit also adds the proper tests for each codec. --- Cargo.lock | 117 ++++++++++----- Cargo.toml | 2 + src/container.rs | 137 ++++++++++++++++++ src/engine.rs | 127 ++++++++-------- src/function_run_result.rs | 119 +++++++-------- src/lib.rs | 16 ++ src/main.rs | 38 +---- tests/fixtures/build/echo.wasm | Bin 0 -> 49850 bytes tests/fixtures/build/messagepack-invalid.wasm | Bin 0 -> 49558 bytes tests/fixtures/build/messagepack-valid.wasm | Bin 0 -> 49866 bytes tests/fixtures/echo/Cargo.toml | 6 + tests/fixtures/echo/src/main.rs | 7 + tests/fixtures/messagepack-invalid/Cargo.toml | 7 + .../fixtures/messagepack-invalid/src/main.rs | 10 ++ tests/fixtures/messagepack-valid/Cargo.toml | 7 + tests/fixtures/messagepack-valid/src/main.rs | 7 + tests/integration_tests.rs | 124 ++++++++++++---- 17 files changed, 502 insertions(+), 222 deletions(-) create mode 100644 src/container.rs create mode 100644 tests/fixtures/build/echo.wasm create mode 100644 tests/fixtures/build/messagepack-invalid.wasm create mode 100644 tests/fixtures/build/messagepack-valid.wasm create mode 100644 tests/fixtures/echo/Cargo.toml create mode 100644 tests/fixtures/echo/src/main.rs create mode 100644 tests/fixtures/messagepack-invalid/Cargo.toml create mode 100644 tests/fixtures/messagepack-invalid/src/main.rs create mode 100644 tests/fixtures/messagepack-valid/Cargo.toml create mode 100644 tests/fixtures/messagepack-valid/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 6a9b6855..788826ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -319,7 +319,7 @@ checksum = "4ac68674a6042af2bcee1adad9f6abd432642cf03444ce3a5b36c3f39f23baf8" dependencies = [ "cap-primitives", "cap-std", - "rustix", + "rustix 0.38.42", "smallvec", ] @@ -335,7 +335,7 @@ dependencies = [ "io-lifetimes", "ipnet", "maybe-owned", - "rustix", + "rustix 0.38.42", "windows-sys 0.59.0", "winx", ] @@ -359,7 +359,7 @@ dependencies = [ "cap-primitives", "io-extras", "io-lifetimes", - "rustix", + "rustix 0.38.42", ] [[package]] @@ -372,7 +372,7 @@ dependencies = [ "cap-primitives", "iana-time-zone", "once_cell", - "rustix", + "rustix 0.38.42", "winx", ] @@ -751,11 +751,15 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" +[[package]] +name = "echo" +version = "0.1.0" + [[package]] name = "either" -version = "1.13.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "embedded-io" @@ -792,18 +796,18 @@ dependencies = [ [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -831,12 +835,12 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fd-lock" -version = "4.0.2" +version = "4.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e5768da2206272c81ef0b5e951a41862938a6070da63bcea197899942d3b947" +checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78" dependencies = [ "cfg-if", - "rustix", + "rustix 1.0.5", "windows-sys 0.52.0", ] @@ -857,9 +861,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foldhash" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "form_urlencoded" @@ -872,13 +876,13 @@ dependencies = [ [[package]] name = "fs-set-times" -version = "0.20.2" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e2e6123af26f0f2c51cc66869137080199406754903cc926a7690401ce09cb4" +checksum = "94e7099f6313ecacbe1256e8ff9d617b75d1bcb16a6fddef94866d225a01a14a" dependencies = [ "io-lifetimes", - "rustix", - "windows-sys 0.59.0", + "rustix 1.0.5", + "windows-sys 0.52.0", ] [[package]] @@ -1412,6 +1416,12 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +[[package]] +name = "linux-raw-sys" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" + [[package]] name = "litemap" version = "0.7.4" @@ -1492,7 +1502,21 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64" dependencies = [ - "rustix", + "rustix 0.38.42", +] + +[[package]] +name = "messagepack-invalid" +version = "0.1.0" +dependencies = [ + "rmpv", +] + +[[package]] +name = "messagepack-valid" +version = "0.1.0" +dependencies = [ + "rmpv", ] [[package]] @@ -1847,6 +1871,16 @@ dependencies = [ "serde", ] +[[package]] +name = "rmpv" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58450723cd9ee93273ce44a20b6ec4efe17f8ed2e3631474387bfdecf18bb2a9" +dependencies = [ + "num-traits", + "rmp", +] + [[package]] name = "rust-embed" version = "8.6.0" @@ -1903,11 +1937,24 @@ dependencies = [ "errno", "itoa", "libc", - "linux-raw-sys", + "linux-raw-sys 0.4.14", "once_cell", "windows-sys 0.59.0", ] +[[package]] +name = "rustix" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys 0.9.4", + "windows-sys 0.52.0", +] + [[package]] name = "rustversion" version = "1.0.18" @@ -2112,7 +2159,7 @@ dependencies = [ "cap-std", "fd-lock", "io-lifetimes", - "rustix", + "rustix 0.38.42", "windows-sys 0.59.0", "winx", ] @@ -2138,7 +2185,7 @@ dependencies = [ "cfg-if", "fastrand", "once_cell", - "rustix", + "rustix 0.38.42", "windows-sys 0.59.0", ] @@ -2380,7 +2427,7 @@ dependencies = [ "io-extras", "io-lifetimes", "log", - "rustix", + "rustix 0.38.42", "system-interface", "thiserror", "tracing", @@ -2455,9 +2502,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.221.2" +version = "0.221.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9845c470a2e10b61dd42c385839cdd6496363ed63b5c9e420b5488b77bd22083" +checksum = "d06bfa36ab3ac2be0dee563380147a5b81ba10dd8885d7fbbc9eb574be67d185" dependencies = [ "bitflags 2.6.0", "hashbrown 0.15.2", @@ -2522,7 +2569,7 @@ dependencies = [ "psm", "pulley-interpreter 28.0.1", "rayon", - "rustix", + "rustix 0.38.42", "semver", "serde", "serde_derive", @@ -2570,7 +2617,7 @@ dependencies = [ "postcard", "psm", "pulley-interpreter 29.0.1", - "rustix", + "rustix 0.38.42", "serde", "serde_derive", "smallvec", @@ -2614,7 +2661,7 @@ dependencies = [ "directories-next", "log", "postcard", - "rustix", + "rustix 0.38.42", "serde", "serde_derive", "sha2", @@ -2727,7 +2774,7 @@ dependencies = [ "anyhow", "cc", "cfg-if", - "rustix", + "rustix 0.38.42", "wasmtime-asm-macros 28.0.1", "wasmtime-versioned-export-macros 28.0.1", "windows-sys 0.59.0", @@ -2740,7 +2787,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cec0a8e5620ae71bfcaaec78e3076be5b6ebf869f4e6191925d73242224a915" dependencies = [ "object", - "rustix", + "rustix 0.38.42", "wasmtime-versioned-export-macros 28.0.1", ] @@ -2818,7 +2865,7 @@ dependencies = [ "futures", "io-extras", "io-lifetimes", - "rustix", + "rustix 0.38.42", "system-interface", "thiserror", "tokio", @@ -3133,9 +3180,9 @@ dependencies = [ [[package]] name = "wit-parser" -version = "0.221.2" +version = "0.221.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbe1538eea6ea5ddbe5defd0dc82539ad7ba751e1631e9185d24a931f0a5adc8" +checksum = "896112579ed56b4a538b07a3d16e562d101ff6265c46b515ce0c701eef16b2ac" dependencies = [ "anyhow", "id-arena", diff --git a/Cargo.toml b/Cargo.toml index 498858c3..a47ea45e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,8 @@ members = [ "tests/fixtures/log_truncation_function", "tests/fixtures/exports", "tests/fixtures/noop", + "tests/fixtures/messagepack-valid", + "tests/fixtures/messagepack-invalid", "tests/fixtures/echo", ] [package] diff --git a/src/container.rs b/src/container.rs new file mode 100644 index 00000000..3f79e6d0 --- /dev/null +++ b/src/container.rs @@ -0,0 +1,137 @@ +use crate::Codec; +use anyhow::{anyhow, Result}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Default)] +pub enum BytesContainerType { + /// Input bytes. + #[default] + Input, + /// Output bytes. + Output, +} + +/// A container of bytes to hold either the input or output bytes. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BytesContainer { + /// The raw bytes. + #[serde(skip)] + pub raw: Vec, + /// Bytes encoding. + #[serde(skip)] + pub codec: Codec, + /// The JSON represantation of the bytes. + #[serde(skip)] + pub json_value: Option, + /// The human readable representation of the bytes. + pub humanized: String, + /// Context for encoding errors. + #[serde(skip)] + pub encoding_error: Option, +} + +impl Default for BytesContainer { + fn default() -> Self { + Self { + codec: Codec::Raw, + humanized: "".into(), + json_value: None, + raw: Default::default(), + encoding_error: None, + } + } +} + +impl BytesContainer { + pub fn new(ty: BytesContainerType, codec: Codec, raw: Vec) -> Result { + match codec { + Codec::Raw => { + let humanized = raw + .iter() + .map(|b| format!("{:02x}", b)) + .collect::>() + .join(" "); + + Ok(Self { + raw, + codec, + humanized, + ..Default::default() + }) + } + Codec::Json => match ty { + BytesContainerType::Input => { + let json = serde_json::from_slice::(&raw) + .map_err(|e| anyhow!("Invalid input JSON: {}", e))?; + let minified_buffer = serde_json::to_vec(&json) + .map_err(|e| anyhow!("Couldn't serialize JSON: {}", e))?; + + Ok(Self { + codec, + raw: minified_buffer, + json_value: Some(json.clone()), + humanized: serde_json::to_string_pretty(&json)?, + encoding_error: None, + }) + } + BytesContainerType::Output => { + let mut this = Self { + codec, + ..Default::default() + }; + + match serde_json::from_slice::(&raw) { + Ok(json) => { + this.json_value = Some(json.clone()); + this.humanized = serde_json::to_string_pretty(&json)?; + this.raw = serde_json::to_vec(&json)?; + } + Err(e) => { + this.humanized = String::from_utf8_lossy(&raw).into(); + this.encoding_error = Some(e.to_string()); + } + }; + + Ok(this) + } + }, + Codec::Messagepack => match ty { + BytesContainerType::Input => { + let json: serde_json::Value = serde_json::from_slice(&raw) + .map_err(|e| anyhow!("Invalid input JSON: {}", e))?; + let bytes = rmp_serde::to_vec(&json) + .map_err(|e| anyhow!("Couldn't convert JSON to MessagePack: {}", e))?; + + Ok(Self { + raw: bytes, + codec, + json_value: Some(json.clone()), + humanized: serde_json::to_string_pretty(&json)?, + encoding_error: None, + }) + } + BytesContainerType::Output => { + let mut this = Self { + codec, + ..Default::default() + }; + + let value: Result = rmp_serde::decode::from_slice(&raw); + match value { + Ok(json) => { + this.json_value = Some(json.clone()); + this.humanized = serde_json::to_string_pretty(&json)?; + this.raw = raw; + } + Err(e) => { + this.humanized = String::from_utf8_lossy(&raw).into(); + this.encoding_error = Some(e.to_string()); + } + }; + + Ok(this) + } + }, + } + } +} diff --git a/src/engine.rs b/src/engine.rs index 61dd8bdd..45e777e3 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -7,10 +7,8 @@ use wasmtime_wasi::pipe::{MemoryInputPipe, MemoryOutputPipe}; use wasmtime_wasi::preview1::WasiP1Ctx; use wasmtime_wasi::{I32Exit, WasiCtxBuilder}; -use crate::function_run_result::{ - FunctionOutput::{self, InvalidJsonOutput, JsonOutput}, - FunctionRunResult, InvalidOutput, -}; +use crate::function_run_result::FunctionRunResult; +use crate::{BytesContainer, BytesContainerType}; #[derive(Clone)] pub struct ProfileOpts { @@ -50,7 +48,7 @@ fn import_modules( #[derive(Default)] pub struct FunctionRunParams<'a> { pub function_path: PathBuf, - pub input: Vec, + pub input: BytesContainer, pub export: &'a str, pub profile_opts: Option<&'a ProfileOpts>, pub scale_factor: f64, @@ -128,7 +126,7 @@ pub fn run(params: FunctionRunParams) -> Result { let module = Module::from_file(&engine, &function_path) .map_err(|e| anyhow!("Couldn't load the Function {:?}: {}", &function_path, e))?; - let input_stream = MemoryInputPipe::new(input.clone()); + let input_stream = MemoryInputPipe::new(input.raw.clone()); let output_stream = MemoryOutputPipe::new(usize::MAX); let error_stream = MemoryOutputPipe::new(usize::MAX); @@ -207,32 +205,18 @@ pub fn run(params: FunctionRunParams) -> Result { .try_into_inner() .expect("Output stream reference still exists"); - let output: FunctionOutput = match serde_json::from_slice(&raw_output) { - Ok(json_output) => JsonOutput(json_output), - Err(error) => InvalidJsonOutput(InvalidOutput { - stdout: std::str::from_utf8(&raw_output) - .map_err(|e| anyhow!("Couldn't print Function Output: {}", e)) - .unwrap() - .to_owned(), - error: error.to_string(), - }), - }; + let output = BytesContainer::new(BytesContainerType::Output, input.codec, raw_output.to_vec())?; let name = function_path.file_name().unwrap().to_str().unwrap(); let size = function_path.metadata()?.len() / 1024; - let parsed_input = - String::from_utf8(input).map_err(|e| anyhow!("Couldn't parse input: {}", e))?; - - let function_run_input = serde_json::from_str(&parsed_input)?; - let function_run_result = FunctionRunResult { name: name.to_string(), size, memory_usage, instructions, logs: String::from_utf8_lossy(&logs).into(), - input: function_run_input, + input, output, profile: profile_data, scale_factor, @@ -248,117 +232,133 @@ mod tests { use serde_json::json; use super::*; + use crate::Codec; + use anyhow::Result; use std::path::Path; const DEFAULT_EXPORT: &str = "_start"; + fn json_input(raw: &[u8]) -> Result { + BytesContainer::new(BytesContainerType::Input, Codec::Json, raw.to_vec()) + } + #[test] - fn test_js_function() { - let input = include_bytes!("../tests/fixtures/input/js_function_input.json").to_vec(); + fn test_js_function() -> Result<()> { + let input = json_input(include_bytes!( + "../tests/fixtures/input/js_function_input.json" + ))?; + let function_run_result = run(FunctionRunParams { function_path: Path::new("tests/fixtures/build/js_function.wasm").to_path_buf(), input, export: DEFAULT_EXPORT, ..Default::default() - }); + })?; - assert!(function_run_result.is_ok()); - assert_eq!(function_run_result.unwrap().memory_usage, 1280); + assert_eq!(function_run_result.memory_usage, 1280); + + Ok(()) } #[test] - fn test_js_v2_function() { - let input = include_bytes!("../tests/fixtures/input/js_function_input.json").to_vec(); + fn test_js_v2_function() -> Result<()> { + let input = json_input(include_bytes!( + "../tests/fixtures/input/js_function_input.json" + ))?; let function_run_result = run(FunctionRunParams { function_path: Path::new("tests/fixtures/build/js_function_v2.wasm").to_path_buf(), input, export: DEFAULT_EXPORT, ..Default::default() - }); + })?; - assert!(function_run_result.is_ok()); - assert_eq!(function_run_result.unwrap().memory_usage, 1344); + assert_eq!(function_run_result.memory_usage, 1344); + Ok(()) } #[test] - fn test_js_v3_function() { - let input = include_bytes!("../tests/fixtures/input/js_function_input.json").to_vec(); + fn test_js_v3_function() -> Result<()> { + let input = json_input(include_bytes!( + "../tests/fixtures/input/js_function_input.json" + ))?; + let function_run_result = run(FunctionRunParams { function_path: Path::new("tests/fixtures/build/js_function_v3.wasm").to_path_buf(), input, export: DEFAULT_EXPORT, ..Default::default() - }); + })?; - assert!(function_run_result.is_ok()); - assert_eq!(function_run_result.unwrap().memory_usage, 1344); + assert_eq!(function_run_result.memory_usage, 1344); + Ok(()) } #[test] - fn test_js_functions_javy_v1() { - let input = include_bytes!("../tests/fixtures/input/js_function_input.json").to_vec(); + fn test_js_functions_javy_v1() -> Result<()> { + let input = json_input(include_bytes!( + "../tests/fixtures/input/js_function_input.json" + ))?; + let function_run_result = run(FunctionRunParams { function_path: Path::new("tests/fixtures/build/js_functions_javy_v1.wasm") .to_path_buf(), input, export: DEFAULT_EXPORT, ..Default::default() - }); + })?; - assert!(function_run_result.is_ok()); - assert_eq!(function_run_result.unwrap().memory_usage, 1344); + assert_eq!(function_run_result.memory_usage, 1344); + Ok(()) } #[test] - fn test_exit_code_zero() { + fn test_exit_code_zero() -> Result<()> { let function_run_result = run(FunctionRunParams { function_path: Path::new("tests/fixtures/build/exit_code.wasm").to_path_buf(), - input: json!({ "code": 0 }).to_string().into(), + input: json_input(&serde_json::to_vec(&json!({ "code": 0 }))?)?, export: DEFAULT_EXPORT, ..Default::default() - }) - .unwrap(); + })?; assert_eq!(function_run_result.logs, ""); + Ok(()) } #[test] - fn test_exit_code_one() { + fn test_exit_code_one() -> Result<()> { let function_run_result = run(FunctionRunParams { function_path: Path::new("tests/fixtures/build/exit_code.wasm").to_path_buf(), - input: json!({ "code": 1 }).to_string().into(), + input: json_input(&serde_json::to_vec(&json!({ "code": 1 }))?)?, export: DEFAULT_EXPORT, ..Default::default() - }) - .unwrap(); + })?; assert_eq!(function_run_result.logs, "module exited with code: 1"); + Ok(()) } #[test] - fn test_linear_memory_usage_in_kb() { + fn test_linear_memory_usage_in_kb() -> Result<()> { let function_run_result = run(FunctionRunParams { function_path: Path::new("tests/fixtures/build/linear_memory.wasm").to_path_buf(), - input: "{}".as_bytes().to_vec(), + input: json_input(&serde_json::to_vec(&json!({}))?)?, export: DEFAULT_EXPORT, ..Default::default() - }) - .unwrap(); + })?; assert_eq!(function_run_result.memory_usage, 12800); // 200 * 64KiB pages + Ok(()) } #[test] - fn test_logs_truncation() { - let input = "{}".as_bytes().to_vec(); + fn test_logs_truncation() -> Result<()> { let function_run_result = run(FunctionRunParams { + input: json_input("{}".as_bytes())?, function_path: Path::new("tests/fixtures/build/log_truncation_function.wasm") .to_path_buf(), - input, export: DEFAULT_EXPORT, ..Default::default() - }) - .unwrap(); + })?; assert!( function_run_result.to_string().contains( @@ -368,23 +368,24 @@ mod tests { ), "Expected logs to be truncated, but were: {function_run_result}" ); + Ok(()) } #[test] - fn test_file_size_in_kb() { + fn test_file_size_in_kb() -> Result<()> { let file_path = Path::new("tests/fixtures/build/exit_code.wasm"); let function_run_result = run(FunctionRunParams { function_path: file_path.to_path_buf(), - input: json!({ "code": 0 }).to_string().into(), + input: json_input(&serde_json::to_vec(&json!({ "code": 0 }))?)?, export: DEFAULT_EXPORT, ..Default::default() - }) - .unwrap(); + })?; assert_eq!( function_run_result.size, file_path.metadata().unwrap().len() / 1024 ); + Ok(()) } } diff --git a/src/function_run_result.rs b/src/function_run_result.rs index 89e9db83..52d2cd2a 100644 --- a/src/function_run_result.rs +++ b/src/function_run_result.rs @@ -1,3 +1,4 @@ +use crate::BytesContainer; use colored::Colorize; use serde::{Deserialize, Serialize}; use std::fmt; @@ -10,13 +11,6 @@ pub struct InvalidOutput { pub stdout: String, } -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(untagged)] -pub enum FunctionOutput { - JsonOutput(serde_json::Value), - InvalidJsonOutput(InvalidOutput), -} - #[derive(Serialize, Deserialize, Clone, Debug)] pub struct FunctionRunResult { pub name: String, @@ -24,8 +18,8 @@ pub struct FunctionRunResult { pub memory_usage: u64, pub instructions: u64, pub logs: String, - pub input: serde_json::Value, - pub output: FunctionOutput, + pub input: BytesContainer, + pub output: BytesContainer, #[serde(skip)] pub profile: Option, #[serde(skip)] @@ -37,24 +31,17 @@ const DEFAULT_INSTRUCTIONS_LIMIT: u64 = 11_000_000; const DEFAULT_INPUT_SIZE_LIMIT: u64 = 128_000; const DEFAULT_OUTPUT_SIZE_LIMIT: u64 = 20_000; -pub fn get_json_size_as_bytes(value: &serde_json::Value) -> usize { - serde_json::to_vec(value).map(|v| v.len()).unwrap_or(0) -} - impl FunctionRunResult { pub fn to_json(&self) -> String { serde_json::to_string_pretty(&self).unwrap_or_else(|error| error.to_string()) } pub fn input_size(&self) -> usize { - get_json_size_as_bytes(&self.input) + self.input.raw.len() } pub fn output_size(&self) -> usize { - match &self.output { - FunctionOutput::JsonOutput(value) => get_json_size_as_bytes(value), - FunctionOutput::InvalidJsonOutput(_value) => 0, - } + self.output.raw.len() } } @@ -98,8 +85,7 @@ impl fmt::Display for FunctionRunResult { formatter, "{}\n\n{}", " Input ".black().on_bright_yellow(), - serde_json::to_string_pretty(&self.input) - .expect("Input should be serializable to a string") + self.input.humanized, )?; writeln!( @@ -120,31 +106,27 @@ impl fmt::Display for FunctionRunResult { )?; } - match &self.output { - FunctionOutput::JsonOutput(json_output) => { - writeln!( - formatter, - "{}\n\n{}", - " Output ".black().on_bright_green(), - serde_json::to_string_pretty(&json_output) - .expect("Output should be serializable to a string") - )?; - } - FunctionOutput::InvalidJsonOutput(invalid_output) => { - writeln!( - formatter, - "{}\n\n{}", - " Invalid Output ".black().on_bright_red(), - invalid_output.stdout - )?; - - writeln!( - formatter, - "{}\n\n{}", - " JSON Error ".black().on_bright_red(), - invalid_output.error - )?; - } + if let Some(e) = &self.output.encoding_error { + writeln!( + formatter, + "{}\n\n{}", + " Invalid Output ".black().on_bright_red(), + self.output.humanized, + )?; + + writeln!( + formatter, + "{}\n\n{}", + " JSON Error ".black().on_bright_red(), + e + )?; + } else { + writeln!( + formatter, + "{}\n\n{}", + " Output ".black().on_bright_green(), + self.output.humanized, + )?; } let input_size_limit = self.scale_factor * DEFAULT_INPUT_SIZE_LIMIT as f64; @@ -234,13 +216,22 @@ mod tests { use anyhow::Result; use predicates::prelude::*; + use crate::*; + use super::*; + fn json_output(raw: &[u8]) -> Result { + BytesContainer::new(BytesContainerType::Output, Codec::Json, raw.to_vec()) + } + + fn mock_json_input() -> Result { + let bytes = "{\"input_test\": \"input_value\"}".as_bytes(); + BytesContainer::new(BytesContainerType::Input, Codec::Json, bytes.to_vec()) + } + #[test] fn test_js_output() -> Result<()> { - let mock_input_string = "{\"input_test\": \"input_value\"}".to_string(); - let mock_function_input = serde_json::from_str(&mock_input_string)?; - let expected_input_display = serde_json::to_string_pretty(&mock_function_input)?; + let input = mock_json_input()?; let function_run_result = FunctionRunResult { name: "test".to_string(), @@ -248,10 +239,10 @@ mod tests { memory_usage: 1000, instructions: 1001, logs: "test".to_string(), - input: mock_function_input, - output: FunctionOutput::JsonOutput(serde_json::json!({ + input: input.clone(), + output: json_output(&serde_json::to_vec(&serde_json::json!({ "test": "test" - })), + }))?)?, profile: None, scale_factor: 1.0, success: true, @@ -259,7 +250,7 @@ mod tests { let predicate = predicates::str::contains("Instructions: 1.001K") .and(predicates::str::contains("Linear Memory Usage: 1000KB")) - .and(predicates::str::contains(expected_input_display)) + .and(predicates::str::contains(input.humanized)) .and(predicates::str::contains("Input Size: 28B")) .and(predicates::str::contains("Output Size: 15B")); assert!(predicate.eval(&function_run_result.to_string())); @@ -270,9 +261,7 @@ mod tests { #[test] fn test_js_output_1000() -> Result<()> { - let mock_input_string = "{\"input_test\": \"input_value\"}".to_string(); - let mock_function_input = serde_json::from_str(&mock_input_string)?; - let expected_input_display = serde_json::to_string_pretty(&mock_function_input)?; + let input = mock_json_input()?; let function_run_result = FunctionRunResult { name: "test".to_string(), @@ -280,10 +269,10 @@ mod tests { memory_usage: 1000, instructions: 1000, logs: "test".to_string(), - input: mock_function_input, - output: FunctionOutput::JsonOutput(serde_json::json!({ + input: input.clone(), + output: json_output(&serde_json::to_vec(&serde_json::json!({ "test": "test" - })), + }))?)?, profile: None, scale_factor: 1.0, success: true, @@ -291,16 +280,14 @@ mod tests { let predicate = predicates::str::contains("Instructions: 1") .and(predicates::str::contains("Linear Memory Usage: 1000KB")) - .and(predicates::str::contains(expected_input_display)); + .and(predicates::str::contains(input.humanized)); assert!(predicate.eval(&function_run_result.to_string())); Ok(()) } #[test] fn test_instructions_less_than_1000() -> Result<()> { - let mock_input_string = "{\"input_test\": \"input_value\"}".to_string(); - let mock_function_input = serde_json::from_str(&mock_input_string)?; - let expected_input_display = serde_json::to_string_pretty(&mock_function_input)?; + let input = mock_json_input()?; let function_run_result = FunctionRunResult { name: "test".to_string(), @@ -308,10 +295,10 @@ mod tests { memory_usage: 1000, instructions: 999, logs: "test".to_string(), - input: mock_function_input, - output: FunctionOutput::JsonOutput(serde_json::json!({ + input: input.clone(), + output: json_output(&serde_json::to_vec(&serde_json::json!({ "test": "test" - })), + }))?)?, profile: None, scale_factor: 1.0, success: true, @@ -319,7 +306,7 @@ mod tests { let predicate = predicates::str::contains("Instructions: 999") .and(predicates::str::contains("Linear Memory Usage: 1000KB")) - .and(predicates::str::contains(expected_input_display)); + .and(predicates::str::contains(input.humanized)); assert!(predicate.eval(&function_run_result.to_string())); Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index a7f46265..afff8259 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,20 @@ pub mod bluejay_schema_analyzer; +pub mod container; pub mod engine; pub mod function_run_result; pub mod scale_limits_analyzer; +use clap::ValueEnum; + +pub use container::*; + +/// Supported input encoding. +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Default)] +pub enum Codec { + /// JSON input. + Json, + /// Raw input, no validation, passed as-is. + #[default] + Raw, + /// JSON input encoded as Messagepack. + Messagepack, +} diff --git a/src/main.rs b/src/main.rs index 383b2284..b176dec5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +use function_runner::{BytesContainer, BytesContainerType, Codec}; + use std::{ fs::File, io::{stdin, BufReader, Read}, @@ -5,7 +7,7 @@ use std::{ }; use anyhow::{anyhow, Result}; -use clap::{Parser, ValueEnum}; +use clap::Parser; use function_runner::{ bluejay_schema_analyzer::BluejaySchemaAnalyzer, engine::{run, FunctionRunParams, ProfileOpts}, @@ -16,17 +18,6 @@ use is_terminal::IsTerminal; const PROFILE_DEFAULT_INTERVAL: u32 = 500_000; // every 5us const DEFAULT_SCALE_FACTOR: f64 = 1.0; -/// Supported input flavors -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] -enum Codec { - /// JSON input, must be valid JSON - Json, - /// Raw input, no validation, passed as-is - Raw, - /// JSON input, will be converted to MessagePack, must be valid JSON - JsonToMessagepack, -} - /// Simple Function runner which takes JSON as a convenience. #[derive(Parser, Debug)] #[clap(version)] @@ -144,26 +135,9 @@ fn main() -> Result<()> { let query_string = opts.read_query_to_string().transpose()?; - let (json_value, buffer) = match opts.codec { - Codec::Json => { - let json = serde_json::from_slice::(&buffer) - .map_err(|e| anyhow!("Invalid input JSON: {}", e))?; - let minified_buffer = - serde_json::to_vec(&json).map_err(|e| anyhow!("Couldn't serialize JSON: {}", e))?; - (Some(json), minified_buffer) - } - Codec::Raw => (None, buffer), - Codec::JsonToMessagepack => { - let json: serde_json::Value = serde_json::from_slice(&buffer) - .map_err(|e| anyhow!("Invalid input JSON: {}", e))?; - let bytes = rmp_serde::to_vec(&json) - .map_err(|e| anyhow!("Couldn't convert JSON to MessagePack: {}", e))?; - (Some(json), bytes) - } - }; - + let input = BytesContainer::new(BytesContainerType::Input, opts.codec, buffer)?; let scale_factor = if let (Some(schema_string), Some(query_string), Some(json_value)) = - (schema_string, query_string, json_value) + (schema_string, query_string, input.json_value.clone()) { BluejaySchemaAnalyzer::analyze_schema_definition( &schema_string, @@ -180,7 +154,7 @@ fn main() -> Result<()> { let function_run_result = run(FunctionRunParams { function_path: opts.function, - input: buffer, + input, export: opts.export.as_ref(), profile_opts: profile_opts.as_ref(), scale_factor, diff --git a/tests/fixtures/build/echo.wasm b/tests/fixtures/build/echo.wasm new file mode 100644 index 0000000000000000000000000000000000000000..d2f92ba7ba5b79df00d921e5d448522c6f822cbd GIT binary patch literal 49850 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 WL5wGX4&(v#SS;iO7=UM${09ILONpHT literal 0 HcmV?d00001 diff --git a/tests/fixtures/build/messagepack-valid.wasm b/tests/fixtures/build/messagepack-valid.wasm new file mode 100644 index 0000000000000000000000000000000000000000..1e3a1fa53cdeb193ff1a6638dda18790b4d4fa02 GIT binary patch literal 49866 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

qXOelvJ^7W=uD%$Jn%rAnSb|My(mP1yIb1>1= znOl#v{Aa!%k5!JW;-M)Unl03kY^ci@L^qmmh$cn#;Op5l4Nl0#&V;U1((7~q=0ez2p5&X+(q<*YxFdI!qrgzVSm>v{6^Or2{V zt46gXjLlo@XP6QDQ3ozF^cefu3$dTQaHN7*SaFf`g`7M2aWm6#?DBDnB%3;z{!ch} z*71yV-3dB|t0XPPxzbZ&GUwben^ZF~0XcW_n`b+BGni>6d8VB^oL+I4bz{hBaaZQt ziM!gIJGd)z?gF$@pj6gN<}P#YvQ(EO%jSp3qsAI(lGxCZQ&c{?_iw4A#zLFt%tXXi_;94#cB zh7OVS!0cJx4sMap%|#hjWWORncrxb>cc$gs`8aoOt3=?OJJgkP?m#ND(K>+VoV&1P z4QfFqc6B+NY{ao0FK)y%kJ5^^Em)$f6c~Yq^!xaE%*WORLg(j!Iiy^kkJv;xfAjSC zj4ngS(}UgQ>A{(BbGxS(m_Bmhq$jn)->K7+X02fvkKS0Qa)mBo0vULxnl#ApQ!W>1 zQjNUw6CtPAlB4W<7f>v2JD)D9?$*XV`=*yPHLz&&AGm_CT1(?*Jh0$aSu3jc<`KqY zQ1{3AXviY>1U5xVZK=nuk<_xMJ|B5rk(6F|S?6mE5Yl}M39$wT0z*nyo@QukXyU!u zb@2sNS5DP0t;<lCo#jIVJ?S+MnksX$c-DPGkI z8O`OSF(R}ivuM<{j=~dv&r9b&U`W)Mecep+r;VR}4AUmgZbf=^FJKi-$MzUNo$`9m z2zUv0ZW4Y_cw;-@yiHol=ec@dz{3pddvR@qJY;p%#B;3C@XB8-kSxI>DD4v@vHU${ zIyOKbx8BY|sC|sc0|s6}DDs|quUH{RC4K%^d-Dxo)*4g`5@ogU2ij{vdpRORBMdWL z3)i^47U(ft>O%;IVA=F&M7a;fii4k*K%bcgRRA>}ThRc^yd7pj{H<**ImdQ9u|k=C zl@xQ4u94au9~aUek+9s4xdn`?KSNJ-`NZ@9sZZEO{jhNyuTXdM`Vqezg!=V(DMb6lrrwthmGVu8+QZ&|DO^KL+m89@!@@7SmCQzec*)XTg-yUV;bwO!B&V z0PQTrbrKw(blJB!x<(fHh&xX#U-3da#neG=WU)sF6uJ)Pse__AkOG{e4mz!a&XGl) zI_S0z=7`2DAEyK~Ns{KEmvmO@&-42noQu6&zh`4C^Exl!yYyDCTSwfDrUF*3AfAKv z9@rlc(L}3El#I`eDHj~XTAZ>e7X|S=L9FEA$%44sAnr~f?lg!`mZwP@{gqnC1|itn z&(xt1Bsa0vg*j*i7#i@N8TZ+HNXw&X5WP1FQ;<>^>bUn@ti96~RB*VED)@sAC%>X) zO+1f$*zz+sNMSUZ2oB7kZBb|mk8sL^RJQ(nL169FT;IS##l?_Bq(o9pDQ86pAc`A# z%V1FFqpIK140IqhfflE-bH`iiLHuTwGX-IlHNBaYO-rD-UFA$qSY;IZtjeY=q#mRq z4VM7L$7ZCbnHbv``B&P((w_ReP=*qc+gb#I9d+DP`q=6)Na)lCPPVIx3VW$l(PJ;Q zDqo+Fu7pY%HGx_>N5G@a0(N_Hq?=>eHg6_Gl3DZ0%cT&%X|qkLENsH&Qvd)S1ei}M z>I`0Y4Y_0u(ar4hS8Il`KWis_BSl0j`*U{gnYAz}p>zn$X=^akr|f#sKxW7T)A#k9 zftoRd8&R1Vths&a)LA{=<9VC?a6M?=CI_R4gUvBwj%tGu!&ERa+!XFoLba?+>p8Ve z*>j6KNisQv7=JnZGAG5T4!;F#20+UT3nt+i8&`XLgo2ct=tR6FPPfH&iNyktJEJbV zhoV&O$?jO{)G{+=6?tTKS9O2liOx@3*?^qG9A*8Wp51& zA4=g{Olr%Y(jlKECC8)bI%!)Bx`0FF=XX@S;@+^`9zL^SjmV=?<6Ub3#|+a)01c& zBv}g!G*oEzA$`q$n^wis)2_|qRz>zV=%UjITu5#qbh^_-=Ch!XhWUFP@0pAHL@;6MWDP z?%7xL7g2!^p6R1c_8jXO0*N7{PuVid5#;h?n+qO0n2&hnZxv4RJg>+v;&(E?$;QOw z#Ijw(2PgM88xza+G$tknZ))rv+&Q}Rz~JuTp=A@zoy+zN4v(GRoTz$L{)~p_<@o8E zJ?FVUhu_XY+6_{>tG zY>wY@#r{b?;yd0P+}&&p4&55>u+qlRy4d?Y+6vyCgS&S(hT`p8_f8IvkF8s`f9#g# z;NC@xx5wjS@nF3D%JH$r_84&YH-^WC8VBR?{gd(dF1p%3HZ-v=p1ipc?{196!xM45 zgI9WX6)BqS4e~@%G(~U6XO#9KPx1$?fs3!C@dN#dNo8a$Q_< z<$&s)?F$=tS6olydIi@Gt}|PzN!pfoS)09S+o`lo)>i%c)YE?t@Gfw-UWKdZH<#Zj z{7&T;>%U)%m+((%N$J<)UthGS)O)bEw|9B(ir$sIt9n=W_VxDnuIXL7ym$HXg9dQ`ShHg7%HEaBSFTvOa^|eQN<=R!ftCp`?v1;Y2RjXF7>RZ*nYR#&(t9w^3U%g`W%GIk@uU_4^x_|YW)oc5D z`)4yiTnzd^IaV^8IrR%jcTT9XI;T_Gv=B>+ijyD^|k-PRxF55Fc1XJ!B+&$5l zZ0>J(-e-cU*8?s-S^~FRv*$nNc|Om_^)j)0cxMBi-?Q`PCSCoU_A&L|!tYFe+4G0E z7cGx(KiN#7@c$40=Ow?#->oUH3|{oVaMpi(^&{fjjrx-}Hw}-) z7hV)M#)jfWx>+3Gax=msTn&%i6mQ?|-56E9F7PqJReU(cRlNUZuHx4nw@zjPCYc)> zpF~P`-aOcJ5(yzMh=(WjYItm7c&HJ_i_~O-p^)0`-aYhFrk{^<6&=6MRXXc$xk}e$ zo|Ju9~<5|KGayYw>dmEIk;nY1E!$fCi;0f zSMdx9LgHMK^3LXx=7JNPUM&)lhz8QQg_&fjU+%v%sqUVAi#Ydy(gP%q}^DF0EaPgH} z-~GW4{=u)k=U2-)74L(^c%nV zt`A0?U2{%aynNNV4I4MV^2)74jkmw^&Ub(2&;I<8NB{DhH-6@`JqrrOQhDxaeQVd< z|Iw%Zwxj>9_uOA7U2yTP;dlSmobhd6`q7VHyW=N6KX&bP@B97pmz}fd`VZXmp+CI$ zzWX2i!o!c`%av2kSa->Wt3Ptz<9~He;q>|SmtTCz4}SRLV_$wWieL8fvlp#gvu@KX zFTd*A>tFTi*WUPs?K>O0Mkfyb`k}Yq`>{_xbmYlTd~$63JAeP%Z>axTE{v9jyF!22 z`BS%@5iaju5H0LDGk0F@(x~g)sgLCsMhl}w#Z~1i!&Q~T{T-*4it{emur}OT?C3o; zR||V`{=k}OOKw?IDs&VE;&Y-(M_;%uH@^^73Ri9JU)i~`aDK6rKRZ057)(8RO*QOa zQatz6`DZVfds@ep40UPe>4j2$Q}LXR{pIx+pPRoRSIS?V_jA=SSAI<~IAh0|n~J5W zkG!G2pu+-;Y=@AK>4`si(I z3+F~R=Fcu|EG^2NeE6YtQ;)u`u_antm@^>G`Q7J>cYJek>BB!byt3OrBi|Jj55My_ zqtRSv*iopyd;8Q+^M^lu`DGoG7f$`p(nN9ZDI4E7w=%bKL&xb;zj64o@Ga}RPr2i& zv-0_=zd0{=an0YmG@Ks=hX>A@vo7Z!e)8O@Z=M(Vho7GMUyCn~N>On8oJ%jiXzKsI zFz-j#=XzEJhr5E$CtrT_tAFwL&;H{v zFERn>Uw6Spn_v0*JKn|1Pk-T09{r0azV_@tdM)v|K=Sd1p~fBW`TY-k^@*=_&RM+f zf(@H*c-@U}*f!L-^F1G>$(O(S-Dm&tXy=>_n}-@xcl`0gU;NVFeCz1H-2Rq#-20I) ze(B3!`P$$8_f2>I>0dqi#Md@ox%GzEykXmKzU$qe`pjp)^k`#x{rckk|f_gPPT?XSP_#IY;4zV>y6BA<9!_M;z< zjrU)4$@&deMWfBhcURU$XS{q{yeArY`P5^%+a3z%=WqM>@HK@~JLYwW?M4uh`T5rr&dY5q zEs0=`aCv!2G(TSsryk(dvgK1hDP9j%UBj>9+3o%&pH>N}@g5SH?5iW`fS z{ABse@U_uvI;L))x1e-t$K}z~+w&j4w{lvv{6o>pX#Qa$`{1wTGF&)Ykr zsV{~-VRz>XD*ROOZyOq%9CSK=ZMo`^Ec345r)&278t&z9H3!FTYQz(hgG~&XIh~m) za&LBxH_c==WRq|{Z<@S0zJosH&;AbAdaDl^TGzv4l*^80@6A0)-`PkL@gTmaTv!^} zgZCV51kW$Hc5?MX&$~T}z4zp{d#^wF9`B^n;vFZF&A_kHl#_P&4jpXu{Uwf=>j&-8!1YjEwddC#ovUGU5+|HqlnTsg4nL)V-+ z_{_COM+UFkI{wUcA9#51dhct4uWEe#L$C7wu6Bd>^oL&kiSN~3`@?6SdEJxG4c-`g zKf3X#f9UnzUa#OS#VZQ<-``a3J*Db5V6GtWqnG(-_PnmVuA{@B7x^8S&fIz71s&(k z^W%ORL`9gWPzuiQ`Ff%sL`ABUg863jZv%XuNQj24BF|3{3GPmw z=-2$d?#0Zs6fURVf`3uCFy|L9CM~+E1Dr*Hzm2~s4O;vU_+jxB!>yx3S0T*3f)D75 zNPZYGxvt>)q9%EoFzw3WmH!8b^IUuMmdYcBqlW&C{G8X}2mj`mqR79C@gtwjF?pjM zf1KcaNZ=JflYh;rfJPs0%+ozofd4d*??L}nxmDe} zG%pwCi^ZUDX7pY@Y!j_0`d$91Ilr5p=UA_~A^#rQToifHFBor6!Q0NCJk2!A#H5Ru z_YUGpj^Zz)O_nwHPfYGy*1LMw+BK{CcCA^va!2pl!R0#|%XjTuv%0Uhv2x|Eohx^) zS-yJbuEx$C%d);&!OrmbvMegzwqyS;x}1(rT|~Mr-ZgA7GXDBRWB0D}Rc&}|c+&f1 zch$QVwQvSLZwF`a?!ndnXqUWp{S>MGXTc*VAKz)gnCU4~n^(a?ucXfp^E>^&r0)X_ z(hnBsJwV@=)8|FF-3$Lq`kt7?&liQf;+(3tg+A}hc@{zb>Nsf*-m(qY>3oR31^2mx z@5+Q+Ke=m-WjrjuvTgs~ZIj~-Wk9xJCX~v!c6?8RRHPy){r8Ww*L`-K$9;vL=qDU2 zDpAzCfL~UA2KS0!&*Il!Kjyi{Pu3@6vy5e%lSV>s(@9m!D!i3CvM96bP2Q|TO)L6V zLL{CXk8f&>HJXD2e%R7|`x_)#R4v|o>AHBw@ZdB09y$_iY? zbt%_V>5%2OxAM>^u$n_c-z9QF~=*w6MP`PI01mr zY-|=J9KlXvtc`4O!d!Y5Owj&W3a1 z)`?}{ZFqc}>6T@;3{DJ-JHL^RrMYR0*(AT^=JDMb(JQAoT#MHF4-|QeD9hk{npA@H z$Y6}Gwr6m1QrV5k=AbeYd-m>b>}ik#upD5sL2`5qCK?=zjUp~1BK{)5*l6y)RZY<* zjln(f5FA3r1HNFaSJ8hq-e|#P>zrv&Zud} zp8b=JgP!*U{lxThA{C*NlKO6YMS50HwAL=gwH$a;5{BnAZ*pyhRGNO zz7I0i+4OrByeHYgyQT9T{6kke8|zBoq_HlRCX9y~lVn}-c0tMbp5aN<$C9|Ye=NRb z7@vCkOm%V5uKl}rlc&Y|9*lu<$M^*Nko9|hiCo`!6BNsKIpX4;$1eNin5lHpX-@xL z!?lYq6@LPY`SsHQ)Hqcf^KyQIURv-cL0jzsdqnc$a2kwE1OSiGPm4}b&2;j$9J+UAsMqb z=f_#+=a;-A%uQA=>+9R}EqGGY?8M$6YGdPLOIbBQxt_Qe=y&MUla`RZXUaSqM;jJBnM#mwtg-hzh!KFb9}ThcGd9SM&g!AHXIyg?dFE@ z{kwfLcn?!Bz-wV>O zADh^}cdz09`mx5ry&$VGv|)S~@NeC9g(-*4V^=lDZ(=cQVk;WHdHooQqH)uBbNG#o zAsCDQGFe&8{qg#4V%gro-Da_tjY}7M-d#N|-cP9C$4{2R9KNP4D6#P7d5=&>xq+Jv3xp{B`aR3M7`zNpzJJ7wcQ{#f|D1Att@gbK^LKWH#PY$z+_eQ7c z_Mm0PFg81oDHiCkdWc4waC&uE~vU&D%LtNP}jxHTSSIf|IkVbR*n(kRPu&s zC*2^tNH@sK?M{E1lb$7`vP62X+&(JK=9gXdUiDO8I_p$^DpOtctG2q=Pk7Ng{ZwD? z)ke=6S5~jRuI@Dsj)}G1j;!Cz?;yY51{C@@Y}&}H@|)S>VC0fVdvt-ix(_jOn`gl;<<|}i+dspUN(2};_j0c$BP%&N{e%g zF+dcay?F7wg@vx_;>8OW^X!+oE}nC`xA@crXR)#C+WkAFM!n4hiZ?-DTcw$3;H$$~ z-lgO6y`6jGIcM8=rP+YrCgchs!yfXCotm7y)tlCj7-%U-Z!0|I_)I*;gR|ANi6{2& zyjc+{2E2*AOI1|sO{(BMi7+vOw3_!St>$7l#^c>m62@@y;p53$_X>{KMHIF=%QEed z=>-olR=&+yc}>GK3sJzttzMfJh@H}l6=-8|Fbtwo#`hZWrN5^up}pfh zX!&@2FKSNgW7A9#%$$s)h8hz)o5OptIl$VY*?L0HS+6zMoj4RjnM2{JQicfQy%xK9 zt+7So2{o1CYagM-Ttlgaif@r6j>mW6$$MB(B2Wne%r1A?#OJD1b;p?Vh9qHz*boZr zY!FR*8~2Zyr(x||u?Q~!BaIWq<;)yWA{vuKuug%x{{Pyza*&3CAUb$gLlhM+80bD)CJpQQ({oY z=}{e1r-+L>dloS|Q^c~o!E$PdZ{rkuKupM2b;Q4AkBX^FKCZg>8cp*N(GYKRBR1qc zorrbS$IGlFdgZB1(GNSPEiq5;C~fb_IoVIMY?$p*T^+I{A7ft%4>8`sz;?Z3NyIw{ IZ = vec![]; + std::io::stdin().read_to_end(&mut buf).unwrap(); + std::io::stdout().write_all(&buf).unwrap(); +} diff --git a/tests/fixtures/messagepack-invalid/Cargo.toml b/tests/fixtures/messagepack-invalid/Cargo.toml new file mode 100644 index 00000000..81dc9124 --- /dev/null +++ b/tests/fixtures/messagepack-invalid/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "messagepack-invalid" +version = "0.1.0" +edition = "2021" + +[dependencies] +rmpv = "1.3.0" diff --git a/tests/fixtures/messagepack-invalid/src/main.rs b/tests/fixtures/messagepack-invalid/src/main.rs new file mode 100644 index 00000000..515c86c2 --- /dev/null +++ b/tests/fixtures/messagepack-invalid/src/main.rs @@ -0,0 +1,10 @@ +use std::io::{Read, Write}; + +fn main() { + let mut buf: Vec = vec![]; + std::io::stdin().read_to_end(&mut buf).unwrap(); + std::io::stdout() + // Invalid messagepack. + .write_all(&[192, 193, 194, 195, 196, 197, 198, 199, 200, 201]) + .unwrap(); +} diff --git a/tests/fixtures/messagepack-valid/Cargo.toml b/tests/fixtures/messagepack-valid/Cargo.toml new file mode 100644 index 00000000..0dbd8fcc --- /dev/null +++ b/tests/fixtures/messagepack-valid/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "messagepack-valid" +version = "0.1.0" +edition = "2021" + +[dependencies] +rmpv = "1.3.0" diff --git a/tests/fixtures/messagepack-valid/src/main.rs b/tests/fixtures/messagepack-valid/src/main.rs new file mode 100644 index 00000000..ee274407 --- /dev/null +++ b/tests/fixtures/messagepack-valid/src/main.rs @@ -0,0 +1,7 @@ +use std::io::{Read, Write}; + +fn main() { + let mut buf: Vec = vec![]; + std::io::stdin().read_to_end(&mut buf).unwrap(); + std::io::stdout().write_all(&buf).unwrap(); +} diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 5b47f54f..b1ccec0a 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -1,19 +1,21 @@ #[cfg(test)] mod tests { + use anyhow::Result; use assert_cmd::prelude::*; use assert_fs::prelude::*; use function_runner::function_run_result::FunctionRunResult; use predicates::prelude::*; use predicates::{prelude::predicate, str::contains}; use serde_json::json; + use std::io::Write; use std::{ fs::File, process::{Command, Stdio}, }; #[test] - fn run() -> Result<(), Box> { + fn run() -> Result<()> { let mut cmd = Command::cargo_bin("function-runner")?; let input_file = temp_input(json!({"count": 0}))?; @@ -26,7 +28,7 @@ mod tests { } #[test] - fn invalid_json_input() -> Result<(), Box> { + fn invalid_json_input() -> Result<()> { let mut cmd = Command::cargo_bin("function-runner")?; cmd.args(["--function", "tests/fixtures/build/exit_code.wasm"]) @@ -40,7 +42,7 @@ mod tests { } #[test] - fn run_stdin() -> Result<(), Box> { + fn run_stdin() -> Result<()> { let mut cmd = Command::cargo_bin("function-runner")?; let input_file = temp_input(json!({"exit_code": 0}))?; @@ -63,7 +65,7 @@ mod tests { } #[test] - fn run_no_opts() -> Result<(), Box> { + fn run_no_opts() -> Result<()> { let mut cmd = Command::cargo_bin("function-runner")?; let output = cmd .stdout(Stdio::piped()) @@ -86,7 +88,7 @@ mod tests { #[test] #[ignore = "This test hangs on CI but runs locally, is_terminal is likely returning false in CI"] - fn run_function_no_input() -> Result<(), Box> { + fn run_function_no_input() -> Result<()> { let mut cmd = Command::cargo_bin("function-runner")?; cmd.args(["--function", "tests/fixtures/build/exit_code.wasm"]); @@ -98,7 +100,7 @@ mod tests { } #[test] - fn run_json() -> Result<(), Box> { + fn run_json() -> Result<()> { let mut cmd = Command::cargo_bin("function-runner")?; let input_file = temp_input(json!({"count": 0}))?; @@ -115,7 +117,7 @@ mod tests { } #[test] - fn wasm_file_doesnt_exist() -> Result<(), Box> { + fn wasm_file_doesnt_exist() -> Result<()> { let mut cmd = Command::cargo_bin("function-runner")?; let input_file = temp_input(json!({"exit_code": 0}))?; @@ -130,7 +132,7 @@ mod tests { } #[test] - fn input_file_doesnt_exist() -> Result<(), Box> { + fn input_file_doesnt_exist() -> Result<()> { let mut cmd = Command::cargo_bin("function-runner")?; cmd.args(["--function", "tests/fixtures/build/exit_code.wasm"]) @@ -143,7 +145,7 @@ mod tests { } #[test] - fn profile_writes_file() -> Result<(), Box> { + fn profile_writes_file() -> Result<()> { let (mut cmd, temp) = profile_base_cmd_in_temp_dir()?; cmd.arg("--profile").assert().success(); temp.child("noop.perf").assert(predicate::path::exists()); @@ -152,7 +154,7 @@ mod tests { } #[test] - fn profile_writes_specified_file_name() -> Result<(), Box> { + fn profile_writes_specified_file_name() -> Result<()> { let (mut cmd, temp) = profile_base_cmd_in_temp_dir()?; cmd.args(["--profile-out", "foo.perf"]).assert().success(); temp.child("foo.perf").assert(predicate::path::exists()); @@ -161,7 +163,7 @@ mod tests { } #[test] - fn profile_frequency_triggers_profiling() -> Result<(), Box> { + fn profile_frequency_triggers_profiling() -> Result<()> { let (mut cmd, temp) = profile_base_cmd_in_temp_dir()?; cmd.args(["--profile-frequency", "80000"]) .assert() @@ -172,7 +174,7 @@ mod tests { } #[test] - fn incorrect_input() -> Result<(), Box> { + fn incorrect_input() -> Result<()> { let mut cmd = Command::cargo_bin("function-runner")?; let input_file = temp_input(json!({}))?; @@ -194,7 +196,7 @@ mod tests { } #[test] - fn exports() -> Result<(), Box> { + fn exports() -> Result<()> { let mut cmd = Command::cargo_bin("function-runner")?; let input_file = temp_input(json!({}))?; cmd.args(["--function", "tests/fixtures/build/exports.wasm"]) @@ -208,7 +210,7 @@ mod tests { } #[test] - fn missing_export() -> Result<(), Box> { + fn missing_export() -> Result<()> { let mut cmd = Command::cargo_bin("function-runner")?; let input_file = temp_input(json!({}))?; cmd.args(["--function", "tests/fixtures/build/exports.wasm"]) @@ -223,8 +225,7 @@ mod tests { } #[test] - fn failing_function_returns_non_zero_exit_code_for_module_errors( - ) -> Result<(), Box> { + fn failing_function_returns_non_zero_exit_code_for_module_errors() -> Result<()> { let mut cmd = Command::cargo_bin("function-runner")?; let input_file = temp_input(json!({}))?; cmd.args([ @@ -241,8 +242,7 @@ mod tests { Ok(()) } - fn profile_base_cmd_in_temp_dir( - ) -> Result<(Command, assert_fs::TempDir), Box> { + fn profile_base_cmd_in_temp_dir() -> Result<(Command, assert_fs::TempDir)> { let mut cmd = Command::cargo_bin("function-runner")?; let cwd = std::env::current_dir()?; let temp = assert_fs::TempDir::new()?; @@ -258,9 +258,7 @@ mod tests { Ok((cmd, temp)) } - fn temp_input( - json: serde_json::Value, - ) -> Result> { + fn temp_input(json: serde_json::Value) -> Result { let file = assert_fs::NamedTempFile::new("input.json")?; file.write_str(json.to_string().as_str())?; @@ -268,8 +266,7 @@ mod tests { } #[test] - fn test_scale_limits_analyzer_use_defaults_when_query_and_schema_not_provided( - ) -> Result<(), Box> { + fn test_scale_limits_analyzer_use_defaults_when_query_and_schema_not_provided() -> Result<()> { let mut cmd = Command::cargo_bin("function-runner")?; let input_file = temp_input(json!({"cart": { "lines": [ @@ -292,8 +289,7 @@ mod tests { } #[test] - fn test_scale_limits_analyzer_use_defaults_when_query_or_schema_not_provided( - ) -> Result<(), Box> { + fn test_scale_limits_analyzer_use_defaults_when_query_or_schema_not_provided() -> Result<()> { let mut cmd = Command::cargo_bin("function-runner")?; let input_file = temp_input(json!({"cart": { "lines": [ @@ -318,7 +314,7 @@ mod tests { } #[test] - fn test_scale_limits_analyzer_with_scaled_limits() -> Result<(), Box> { + fn test_scale_limits_analyzer_with_scaled_limits() -> Result<()> { let mut cmd = Command::cargo_bin("function-runner")?; let input_data = vec![json!({"quantity": 2}); 400]; @@ -351,4 +347,80 @@ mod tests { Ok(()) } + + #[test] + fn messagepack_roundtrip() -> Result<()> { + let mut cmd = Command::cargo_bin("function-runner")?; + let input = temp_input(json!({"hello": "world"}))?; + + cmd.args(["--function", "tests/fixtures/build/messagepack-valid.wasm"]) + .arg("--codec") + .arg("messagepack") + .arg("--json") + .arg("--input") + .arg(input.as_os_str()) + .stdout(Stdio::piped()) + .spawn() + .expect("Failed to spawn child process") + .wait_with_output() + .expect("Failed waiting for output"); + + cmd.assert().success(); + cmd.assert().stdout(contains("hello")); + cmd.assert().stdout(contains("world")); + + Ok(()) + } + + #[test] + fn messagepack_failure() -> Result<()> { + let mut cmd = Command::cargo_bin("function-runner")?; + let input = temp_input(json!({}))?; + + cmd.args([ + "--function", + "tests/fixtures/build/messagepack-invalid.wasm", + ]) + .arg("--codec") + .arg("messagepack") + .arg("--json") + .arg("--input") + .arg(input.as_os_str()) + .stdout(Stdio::piped()) + .spawn() + .expect("Failed to spawn child process") + .wait_with_output() + .expect("Failed waiting for output"); + + cmd.assert().success(); + cmd.assert().stdout(contains("null")); + + Ok(()) + } + + #[test] + fn raw_roundtrip() -> Result<()> { + let mut cmd = Command::cargo_bin("function-runner")?; + let input = temp_input(json!({}))?; + + let mut child = cmd + .args(["--function", "tests/fixtures/build/echo.wasm"]) + .arg("--codec") + .arg("raw") + .arg("--json") + .arg("--input") + .arg(input.as_os_str()) + .stdout(Stdio::piped()) + .stdin(Stdio::piped()) + .spawn()?; + if let Some(mut stdin) = child.stdin.take() { + stdin.write_all(&[1, 2])?; + } + + child.wait_with_output()?; + cmd.assert().success(); + cmd.assert().stdout(contains("7b 7d")); + + Ok(()) + } } From 1d78999726e707be59ccde5048299b2b58ec02d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Cabrera?= Date: Thu, 24 Apr 2025 15:53:36 -0400 Subject: [PATCH 2/3] Fix messagepack test and make `Json` default codec --- src/lib.rs | 2 +- tests/fixtures/build/messagepack-valid.wasm | Bin 49866 -> 61736 bytes tests/fixtures/messagepack-valid/src/main.rs | 2 ++ 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index afff8259..ecde0ba7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,10 +10,10 @@ pub use container::*; /// Supported input encoding. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Default)] pub enum Codec { + #[default] /// JSON input. Json, /// Raw input, no validation, passed as-is. - #[default] Raw, /// JSON input encoded as Messagepack. Messagepack, diff --git a/tests/fixtures/build/messagepack-valid.wasm b/tests/fixtures/build/messagepack-valid.wasm index 1e3a1fa53cdeb193ff1a6638dda18790b4d4fa02..79cfd9666523ff70e82879668385787e43382fe7 100644 GIT binary patch delta 29915 zcmb`Q3!GNvedo{Rz0JJu3`ZDXV7Q$31!X`kBO)N)=8SR^@UAf=HV!Z-GstB?#6&%# zpdrR6dfa^M)+EH*XcCDRG||MQ)VQtPx?LN|mS#;$Q`?VC-CeV_+icd>{r;ZkoOfnm zFl~34&w0-|&-MTOpa1RoKmX_OAMf^`{F(o8r+dduuH!iFUGC`Xy*PH`>;2f=+}Kfq zW8R(XbENX(s)Tvw?l{-ym8>-Tpwf3xtPnrAa&Dul-r;!Paq|!UVEls*UFJHv|7wiu zB+c&hc)xqUTgsJv&vTrHN-kf@<@{VOm-jrck>@7gDSDpoxK1(0kK^*&+yJb(Q8~}a zH3;lN(8zB-pZ8Dk{k)&|d_U(j=6r`{@&!MicRVvX$MGG9Zp=U5_dUn=C;DU+Jm2;B zb#s0ppLcV4cbmI%W%4`j{5Wj5!gV6IyrQz`yoIOCU%Y%p|BjtE&-`T1)?2nUlpC+z zK4RWoK@bM)n3M)gRl~xA~?!!Q~$Jh8s71>iX_=>o=?&aJTHf_0ylZ z?e;t3Yj#!KQsWoz_3w92ciq_QjE=r}*lG8ir8)Z;xeGlf2y0H08;>eG<H=@%XNlcyH~2Z6}L>4 z_TJFtwU#G0%txhOKnRMV-|lr(3)JFaL0rpqg<&Zyb%kr&o~RYWTv%M$R?9{1a$57L z6c)l6uWIL;EMR1WiD?qIDURNJ=+!cy39Rg)XKdbnK)Kw^GMHMcL!UE1U@ zuAr}$XIz3M^eCH)VmESw<}fcf-RRDNfq~uX*i}j;I`HISCm02S@=?%BMLW8(?zzzI zweT6}LMO~EB+<0myU;6zPLx~X2y>l%)16VmhqKUI%njtv=Jv>*!z9G*q2HBTj}1@Gv0lkV~3$9-HB68g5X zEgZdUvL=w#LS0ZDxoZH3LH7oY}&Sm z4zOyf3w}3x6{w?ALQf-bgQki%m|Y?J$I2c>cEx7X5u`RLdRytE^&GZ)ape@KnnIep za@oQey1}*OZ+I5H&^h!Fxz(Zv>@-j-F!jJe{TfKG)Lfcqa+EvAX^C>%VWF@P{q;V& zf!LJkg+AEHo#NB9UWW69dX2F5P z7c)i!RGCq|e>YItQB{kgc~NdyEdQ0~o%3?nH zBJk0-{a{Sr%mk7la(BYoepp=9R)Z)b%0=$7wt8B_!8>Y=UE#hbnw+o^DGXd)e^JqO+aBpl*Z{qkKB3KQOm_e z44~Ncp}VImcSV!IwSVw7mC2vwmCBN=Im=Mro8mRczF<4%^wk`IbGkHd!6L~Pq+RT_ zc%9KNEm9*Nx$1RVB63AU_OG7rAqIT-)g(k70M_Rt8bE~Yb!*B%6^ZQ(Lu9gxuOQ5Dj`M!T?O` zkTf;ayX4-x_FnT4)w#|tx7yq_@VZkS1^q$sQ2Uy;S|M^)G$9tG0xsePqwB4+FBmOZ z(GD{xThFs=kZ-^M3G07x*{uSbmX&s7kVqW(PFUB z>x|rdg4}l;V?)6oTa9%D@SM@i+`e6}7@#Cy$s}?Jcj9d#5>{5c_y5LZ*W>9bWUScA2 zV$n(~eP|vRdZ8H`KdrsdKq(ln0rQudFCHU9NJO8PveLvk(PGUrgo-2;2Re~a;ZSUr zfUfpCYt4(WeQjIjH_C_2PcWSy#vgw8VX>E?dr{-1ZOsj=Ian`vEH?~NU{;LhNH%M$ zSjfzuXV3*1O8D+xR&(1-DbVD$r9~wdm}--rCRr?ZR9z)5kmw5CsuyeKf(dlr+KWCz ze<0Q1&$Paa?rx=P=+#JyTz>$I*IO<{9YJe3dh&>oswb8BS$1aUj!g+K+jcGQcN6nKo!F~0#eOa2}TePlG2_@;;N>ds7 zXEZHVpas=JbeQ7OiUDhz=r#LNZ3aorUGe2jzDeTQy{#5x*|kw&b2#d9ra=@is@g2M zhd5JHVL%!J#_Kcy({dPGLCb<~j)PVSBPPLuJ46ww1sCw5eMge0Vdj`OzHQBX=)lO; z=)g0{?G1C|N52D)uzE0!+rFrhqKrO;G*lL%(mY17j1`PVOeDWIx@~({=&Kd`qT+UV zG#?f(Z9}O66Bfg&rX17`yU83w2K5<{STppI1M;X5o{A^RJV8{}a?6^i7I}S85PGqc zl~4h=PkFxb5HBO;<&>8jIWMog{D^sRR8S^^7^%^s@`{l2ATXFr7MR`rkOKr?X~YmT z7{OAl`ph$0uI6c}1?hu}XyC5B5;Ynl2_O?=_1=e{e8bt%7skbYo1X)CW##Hwx&H0Z zz@2yP-JRa(7M?PQ&5Pyez!R^jWdq-GCcKP=VyRe-K?B8!fFT|*jRP@N($d9=krP)v z+H#lz*&^L39@c)j zQYc67KMNhVN#uo+logiysU&^f$yP&-Ry`My8-1|nu$GDleQcM<@8V_uUg}SB%E4sX zKvhPMe4d0UynylONxfiTsK=EUl!IczDMRh~=wXZD(Cw35m0D~0U@AsRhJ7vm3t`?^ zWvZ`UdJQ`no4Q??LjFb%e>3fi*+t>QNTx;1z{_YD?nRNNt9E*lBLEGq>3N5hyja=m z%y0z(Xr_<^GW9|~ootl8lrc?pb}_@uapc-2bVDP%wVWzKGwtRn+W)+fX%<8rBSwQp zkB}NnNxs#zByKmR7=%MNWcF!xJWY)&a0amx`gX~WwTB@ZObwA?ol$NX;zc-Neyce{ zGDhiXB9BL)HEUA@vYy1UaFD?{>+er3>z@+GP-t?QKQC!FIlsgOa@V5ZY8)9;=s-z zaY<*AHb@aH2Bl(InK7sgs~O^Ig+bbbj-Wm4l$7(SM@!h(@TpKID_F*;!+hg%YA;*i zo(g;Djx3`F%n!4I)DRjW8fk(-%~{uyu-hD`-OQxurlOy~+70w^%t3A9(4xPYe)}Rn z?u>r_X>fKrc~I{2;=ltb2M)EZ!ckoV|Lp7ub3*yvuz4?5`H3~(g`35@a0AP^)!ej- z*3wR_^4bg1d{8r#ZMq9uoET2l!m5=U!;*XG`Bzc}DUJ$Az>9Pkr74cuD3>To%sK?P zm1@55kXasTg~h*U9$cX_TyQ;2_#a+Eo&m#m$$?;89Dohx!Hf1Cq?`S2`A6PRj~5w7 zF<=E9weTje4t_6NHAioyS=cr}DqjO@Uz5iAfHaw+ED0lceG<0=pH)k(ph4ah!`#WA zpHk{LV$!b#W&R>>12yGLI%uqaLk7*e@ zZhY&6iEWc6PnjB4YtyEmDpR*h7Cw~jRL&_|A2FuF+2Vi_9`H1uM@Nb281m7m?Rb$c z269%&IKO7G?nO*OZ%uw>p~}T(uxY_nBNtpyzR-0Xr&_3-RgU&p=vfsOD+|yOMka}dHfnko=ikI-|?OMT%@b5GvQ{H&>9jhQJb`OBJS0ZC30ih);x zONPRAM!mwNst}iKjrNn*=&0AYOsJEOO*B!YF_-iz7-7$u8Mt4F4oHG>MUh7hac z#91t6mN#kG1kE*Y#n5_SFkuie2-pa4*&2p9=DCe0!Zl6Z{wv{%PXugE9bqTnyAIw* z;JaR3s_uBy)s6=-{x{)n_D~Q-3$AD(w6wr9oiL@R*DG9MC((+Npc)sWyDdjmX2DIO zTG1Fy_`z^GBHOZcM(L(c$ztk^)aT54g>-&R1=h+#E3nucM16x2&3d8t<^)8f=e8;6Ugde5dw-mJe6a z?_&fm8#laV)zU9oFj`t$MLk+;JA=(k8LXNf0zH>z*k$GoG~o z{s)cHrA^|7lQc25-h?F1su3Z;19P(KE%oXt1h$2ExLLfk3GsZgCJ?)BGaE3c<_g$VyvSy8%QmtsjpN^b-TIJOd|)=%4fQbaa!XHr(tL*d{P!K(caWL zXiz<^Jy>mk{1ywh{KNOACGb!Uq2((_M39z?!|)pqYX8CdDTYRF0wNpU#9#|-M5Pc2 z1I*G$E#P&GKAVD^le7C|t>MtXqHZ;~iuR>7sQfwmsI>>{ofGEE_~r$O+0VYVz5-_F z8f)7)o}DVD0V`VO3P+DBNJaRYO>(K1ma$1Z9EezAxPi=Ow(hRtNT_LIIo?osjLebj zj|~+0o0xbuP=@WGxcbKiN?tAnh3)WDvc8PCY`hrR#!2Mu?5(L4!^zxjDU}&s&!&{L z{s&02b>dZBzY`cIK&9-QAlT((sqdUHPP=oWs>mg~YtoqlW4BGt1X~8Unu~#|E~^f0 zI<#rFV|DB31x@%T@ZaELDkt}kY4x7GCwX#AN6fnW(-z-0s0GK8afW~x6E0#mjFB=X zJjA*Z^3hW!hJ?tGE^m=HojMA1%KQT?{}o-LXepZ%lEOlplny)+A$J9q$Q5vQ^46Hi z@uN@6F`)&qal6Qs5Is)XFlWK@)>%;gNzN+`4Q;SfnK{C04Ru$T-xqp>Z{hmHOXF1i zA+E4$2@K`5XUWFJ!sM2gbG-vck{4RSne|X9zWwzbSHk{dZtGf}wg6#ak4TAda+nUr3X%X!hArZQB9Cj(UHzB4q zIBm9#jF0^B_*gSxay*C+ud}|T);MHKEpn^r_Md>l10*;N+C)a$9Fy2!?_gOIbc?gJ z3f9b?nV=kT$IOfjG&U8ZF%GS#zU~^kV?|Jtd@y07ch^11hKaMTeLLI8Fb+yNB0)3@ zqZHAOb~cXBdjI#tL=KS!(KB*co}2DtI9j%{JC%cOlfRz0v>sh2t%sLz4J;yOVMcHn zCk+y_B&bO>E<)SZLZNar>Fom=hGaKyJ4fWk7A-UN=8I?RBJ<6$qU77(+?XX zY@gV;GM_HhwI6j}3fA5@$}Dw=$~8YxK>C>8Xxnz~<&|ytP!V`+rHVfqqTSo8t|WBW z5cwtuGB-XN@K(|zo1OhD`vHQ-zUc7LB>ZekjFr~QRFFhZCI{6VtVBw()T0e|dw=Bh z3$Hi_6z_n4gjf8u3ejV-&5L$9?r}p$`$oUCtQzLEz4UJS0%_328af}|ERjztpEj-` zszwTjdR2$E57YSjLmPi*uyNuH*&$@qJZP6D&}fEtm32~Yu)u&~NEC9>q~KA?MR#mx zY(hQ3$&5WLWTRJMhM+J;3lFo!TnHW;=OAEgQv%c=2bYky9cK5K6wr*vK|4+%x4vqV ziCeD5f*I$!iODrFkH90u9iut(BlG4Ciuk*30X9WJfE@@O1J~FM0+x!c)e0@Kxv6!E z4W2aFBwvDF7wiGrvltcbJo z%i2)rni+*uXv`ID95I5R<{3&g_7NbGY%tIw4x_lnOTbZ@(G-o+-e)?UquFgSE)Bluy7SRHRTC0nGkCTzOlxJ2Y$w(`;`8iMzL}S0*m> zSBm|^apHb7S;&rdp^O+Y(d&ieJCmnQd~2^Y(u_Q|dt(R-Y`CYA_a={@^x}(Iw!4S{ zLz`^1S@Z8$GHuE<$|lIn&F@I$>)FNEwfQN$QHm_@SXC*f*s=Cgh&n;?k-LsP~FTT%p zlhe=g_uL?n<`aFlpWCW;hCTG-DfT9MZ3^t-Hu6 z|A#cXJPmg51Vsa`B!_3jIV&L&j4094!$?S@F#P^%F8Ta5XPUi7iF{89e|$|X23w|t zOM+-HD(s35yZuX?O5~LZE0#%d0ih*IlF$JkAD%Tf`K>9ZUb+9XmI{5XOIjF_pOT>V zG28V{BSVrxlN17&)EN5R6GaOadWu|NIWrkE^{TOd$9gB*t|_A4V2z*eOKzK5J1)oT zgG$IbH1%WN-|b5(;RKJj8R4vHLs}56p+;cPLd2fD-y1cCeqXR4*%?0Fau(7SLI@};D0_QX#<@+I&j)RlLJUTSf9{l@S@3Xha)tTbOT`q$+q56&K=e!ez)x^Az} zzRf%E<>cZy=ePbNL}q6PWhOe=#U^U>k9Q{r=CsTm%xpH9l{7P}(qvMDtjf>ktoEqc zG56xJ$9@aiJp<8DjQ&SHde6Qkcb?vo{Px_rt@rJR*Jnp>>-Gkg`9s|Q#t)Vxe>-D)B-3yjTcjROckJIfOx5aecvI}4{c*YMKLYCTQQcK6dZUX0` z<3}_hO#W_Oqek(M^U}dgPS$n&?U)Z9U_j?EAWV_Syo^nL~g5) zR2wP{M1)si%3)azthz=_#)SsA_Re;k=y&6bn+hhl+a^?VW{COd7`~TSE`)s4glMdI zdCW3qA{Sl1olpZpZOloht|g!0s|nIzp56 zZaYgme2>L^-gO*D&WQq>&C!R+=YC^$%ydK^1I7$7Lsj(r5a5M_28t-CO70Wbsh+#K zDQ~fROg3eTXrbIzQLCzga2rx3D|px`YffSufk73=D2r)?^WLywulD#HEpQbaq-7hf z8o6oh6T<^!7O5!>2+KsTyGqsc_{;6Q>wOiEYFQ>GH=0z-vJA_2`SvVQ63(9=|5u%3 zI?4~i+TC6&wM7`TVW~~_TxbR{ zlgniP?z6fO-rqZGewMC9BRb(%XHA-nIHxJc9Q~4hO^vSTPo3Z)H<`b1(X79+BO2sq zLsznCex@8WVFrAXESyV6uPi*Rd;wYoQ#Nc2E=c}<;o@`CMx3muQ#C7i-s{Z_%`1nj z9sU-BjI%`Y69cg{@Dd+YvW?Rn?T7;w?r*J^DSO;5G*K|Kb`;DCI@VtxU)55AC`fBt!wn{u|D%uAV8h4%<8 zjh@eBWlo+HwMH_8ZCj%ug7eKOI)&=v%S>KB|7`cnq;SF2 z1y{}=Im@glgrt8!3qV(OTtfiKU!FfMsdP5x&m?xpO9ncpCl_?iI9VUJbzX9^tYe*v zPd5~WGoaVnH+Oo$*(&5mN)1}os_6?WJ8i)3mUD<;DebS9>o>X4>#6)yThSD zcQpu+Ei?TUIIo~O3_Yx$v>vhb^q@s-2eh1Zaf~i-M;zb$wYK?E*1Wwnoq!o??ax6Ci*&cE%!^S*tRoEcjCyoFksb zN_K;0bG|9ZGTx%y96~V>njyVO-+?wWJ((^*C{ze^Fms*OffP+C032FMg_tc{D5E^D zlXaM=&+O_*#GG(0hB;WE*<5V*YXp*#YV^Tj87doPWe>)vnCN}T!5EbtT3s5MQdLv^ zT(i4_R}s?6vlF8o5Bypp_jGs1RL5JHor@{6w=>wJ-P&QJ3wp2_73Bt$*HIbL2V5j) z`Bk6I5Oc(~6YXmm&kXz5GMzY$xOX_MA>xE7j3!u>1`9MAE(>Ehi9{k6w=hYA;W5Zq zQQ>taFg&)H`6sy&77!$stn-kyIWup_x@d?BWNXan(fQ&aRdarV+R^J7RpSGSr5rTu zD)Jot3Degpw^*mwR?({=&~gfAF|1euEr>ul5XnkV6M%H%$lt$=K$%WXb&2N;g=Vxz zXUEfCSVxZ_MdcvZjD5>$YeLpBkg$DYx;98kXI?X@)6(Vt<$8R)V(`GO=r|DcTD&8vaf)%vRZ&cg9iv6dd_OqfR9BL05dR>g=a~&Kn2geRC?W=iG?5)8 zhZ*y9zFf>US$qz$>mas?xn|6kMf2u}t_&*`Q21m$U-&ZUY8OMBCXuK#d7L#Sj4FIg zBbO>E_YN62{(Ce`J%&sX>RAw3$WE|lbX6MJYr@Fhh$1TzI~HlHkB*6E#+)q6 zwPDp(`5#=fS&9M#f2KhXJku=uznI#X%$_UIAQX)vW>EGq(ow^DAh)d)H5vCB>-8Z4 z-kf9q>Jw~7InE-w<&a4IC90@6o-7wMHx08;c^h(Q*_6X;=Y@P^qMeUc(9C;ZlV3x| zxRIu~?1cC(ALH3LqTQ$|dV?}%GozwYX>`XgUO`-@z`!p@?ddArvsW3VeKPY%;JH=Llv8>;&s67W@xHx#_f|c#gGA7a zZ-OGU|0{+CT(IGBLIgj66%v2eknMu&^g~W+!8q2v&Y^$x8TSwr%tquIp;zZmq#M;B zNqJA(*d6D(qb#Th7#|Fqt}^{;WbNLywGxzQbUlR6H!MuMz|-zsBo`3%^bsKIn1*%^VwbCi z`OuG#anH5N?4lOKrYCB?4tiLujodcdF=^w{1AbVRN7Hz{Puh4H?}-U4F@|x-b5q#N zcZG=HTgtiLm=osM=a?lC`pH1c%f)RZ;-FowFFv?CS^snVoTQjk_HD8E!{V|wcET7z zAMPo~e0wQuHY(dFU2V$4Govh(?L8lNJkv$B=$SoGjZQ7%CSK@Ghy2YHI?$$<8Z$-; zr9vk&W>h^FM{vWrpy+XoGA(vi=THh178i!^ft(wuQ(yu zLD;NSw+@B`g4MNJV6vE&$qII?BBF|wnf3Cvtaizu=2NY@eg2z9-5UEt(rCE8#S$2z zVpGYh8IX;z*eKs8pFiwG{{rX&NC0>8$!#_FpSAX!uKYBSv@st}VVO?AZ`OlVYD8w@* z`@JMkG4wAqQ9O$BA+imU@JwGCAc|yC^tg7fhI$_s(7h*fOj`%sbb^@)Ln=zWd`-pm zjQb~=scn8a51eG;C#S`){s-%4m2F9#CC;em8(DE&k>%h5CQhZRE)4|4&*|X){Vrh# z?-5==MoqyOIo$5NMo0MpOmoM`Z_#;XfR0{w*03Vm89nnOx|`=Z(L=w_L(PqY2ROb; zlk%Oa;D<%nmS5NoOCWkRwNOP~Zm&2RJ4tRufQt4b+(0T#1m_FJ{pL$OJUmhYObTI4 zw|ftls_0^?WLyQ^)QvzVqJPL-A1x6vfB1W(A!z_qeou_C88@odjFO5 zaj;Fu-ngqZ|Jm232AeX+;+8o3&BV|2Ch1UQ+HBSqSQzX>lPU~yLQVS9%&dZMayT|Q z_MCn|N-yXVb(wuSs@^3YL;3Esrb*Fo!k(%+(KL>wFM@^A&Go?amQq<9N;ZhhqHhU{ zMcymH1;Ir$FDI7ipaw~4ANvO?QOM}iR*YU%A`=a5V&^ZVp8SGhv;!bR-s*>Se}>6h z2!({6qLdy{666!bFKSZRNsM0n1`jZI2&q91gxEmvA$3$%%%o=YP8)s(tZk&(0-TZ{ z3f@qi31_9_lGerqKaKVpt>OCy=YjLYKfOpOgU@gBwWwp}TfAV+66T;M8(?=-Px^r< zpnmby^GA{oqjBE5uO#EUW~^Kr@}(!@HF0nRpU}98H(%(j=Jx3KG~5+7?DHz)g`Jc- zW)I8pYQsJ=U+sIzlnbj(rZv1E=;+`R$@5+3dhdKM`JY{JcPIRf{*t z!BFGX5)8qNxx#uZdElbOSKDP7*kofDWGPTd-ty2zAVG_8vMgx@!Tr7yeBL#aSqSVI zRH+T+QCJ23z!r#(ym@Hs()F&O`1Gt!^o|oNtvP{bY|f2N%znm26Ox*f4}^G@BQy4dseKd zJZq7O%6#@n@~11Nd#}Bi{L_k=XDcvNhW@C_B-IYvH@-+B7qD@6OXLRE$*#4p&x3Z> zbk`-HTG_tjH$*g0M!UBfq5(crhTqrO_H%>b*QsRQN&Ip0haqlfS+pZ3|89%$yx ztgTihyH-V}nkFat{;E0N;e*M$tJ>$Ay@hshI&$ftR!0LSDI`hX%#k|)u@-djW}5n9 zvTSvA{A(`(j?0(hB)zrxj0SQLWpexK`Q8UFCC{#Ihl_r)I;!j=Hj*Nb5F*}@%vf`+ z0m2gycduFM=952KvutoU<1blK)7WfiJh-i3tAXLFE4f%g@cI$0Z@=WBsTm5eC8PIp zh#W;G07P^I$bzv+c17BffD147L)>4T$~2N`lcVZ8#Z%dM9ina5E{eR}4mOG9tK zOCGqi)m?k&$xBDOQ`6vRnNny7^v0#Imm0M3(ZBs?m$}~l=ac_>`EN~p=Q)WY9M=VCS=+PSI-jB{PERS zom$TZ0}W6a@{>W8wC~J-A4caxGs$(={@M9AWF1KpM25YzZ+a?kjF}GQ>~W+2bT8oN zgLcCfKhldLW%eYW{MhPW7wO-cy!Ek5>cZks$F&7_T;H%>jWAL))HNSp-f<>fsB7kN z<>2Fm<%fOyNz!!Z&6KI)$z$JeeDc$e&mBD&c!aN*_K8QDymq#tlUA*r>@G+)t-Z1} z-IhcxBCE}grNfS8#ZCIwPEUThcJ_ji3y8byK18~95p^>snyB)c9?Bo-zT_*#* zgTcs9HLDVARYKx3Th$qEt0rsKO^IifCt2**EFPE_6A%Vnu{l}p8t#2Gxng;~e1uSs z8ltc2CdxV`ddj4L41(oG2TL=ouN~S1{s{F`%O*QE2I~u|33t~GR#Cgex(q3G_L41N znjRB0)d?2Z?O-*BLeh{n$`@oOYx{v9y3B(7GtUH$#R%{f5RkM7C+grn2r1~JwXWaJ}SruQ`K3{o!Whj5afCd=kdSdkdPxNPX8MgMJbLOWBtsS2kytd!+RWfdq8JVK zBrWcZ=W<%j0^NuP`K7gFYDF1XFQ!7>98Y?cm#$b6>190)4D3bh$z;KvC&6rW6Jj47 z{l<^Kk>8<@bUD%MWSEtI^l0`}jt=N?;Lk)6d?_ZDv6Q{-{V@%hngcwUkGMsTo8nKH z)Q5*W?;m_dNwJMV4SDux{%41q@b%qxB+P5i^AO#1S;d07DS4Hn6Za8>dtlj%kW zOrA-Eux#FwKTiInx4P&9LH-(0SW+^mi}o=t&TBC;h2=+wzh>aRkJRY*%yT)p^E!4% z$yWqB0qe=?zH_HqC|!~b__Qbq!pA_ET$OpEZ;kiPk>r2%%}$GopGPhlZNBz2(;U{b zg6+kk>^#W4z%A+T;&a6c`%$aEyLriM6|pEc@%S2|KF60vo7eCHyJ7i88=#(?deeK} z+eeb|TUL1c|1{~|@?G5~Z@pTu?cDnLQR(@DT3$nY|47ojt-EHLHFIscO7V+ZOkaUR z&Axjid2rj*iU=<>#YlL0+w3b-;-jI%7ROS%zn%yYmvti4Gz=xdUB8GBNrhFh<9}4t3&F7R498F%_J~z16t$8|M#fAv0nU{|y z|FC^gbG=1Cr@IfiNU!yK{=&TvFH|Ez$4RZNSM^&jaeS-4{={V_QGP=jV=OgWLbM(>VJ|LMix znZfI?&hdOE6V^<=xT8IO&yr2e0UCttnl{mk5)F3%Bcvs^)Hx)_@UzK?2ANijoQV&W zd5Y3T5RAa8f{|_pS#>qk0d|cd5#Co zO}sh0;-ku?qsQdOMTaw3hh7X)gj!FZa~;HxozuMVdEd=*J#H`GeEWtGTUU&WJ<%i8 z80x!L(UV{+bqQPanwOGEr-VFL&WIE6)Y0TiyMAMO%Kj*99f|?I8p#$Gwyg~HueSR3C9gAoYH%r|5X|3eC`zI$| z_gyyvqK)Lq_~85Z{hJVN+Ay=i)PMiJ3CX-KbkqUe_yvRH^X?x+@^$y0h-5LXSr*#U zbUJO7A{m3BE<3O%5ywKZSrLoD!Uy^rEs{N9^3ew-ie+AW;Cu0&oXdZ-qOE2QzzH!P zYXeEjNm6n6E&0jWGnJ9IOZ%vxT~YL2)JfdE#AwGTHd?(-PPXCtRx_N2&F(pwF@1({ zSyrpv(0=|pIaMI}*etYX*#5nXqODg!WRy2ncG07=|q692X?rLjT8$Wo;`Z!3}hC_^}8hfIA zby#j&t;uCbf(qNR+Gv6$4C9kg5m)Wy8*mYNOSLUe=G9;-9G(inG(DK4kW&6)^s40SQc|mRZ9-dl7TBdxtdekjFL}Ul(p&ME&$i~r~iT&WCJ;s0hwD$L>Pk*C`g(j6_z0miIzV0xIS zZi49uwIH?SWx>30^w1yeKj=;#EW-cvgBS>Qj>1V=QosA$Lk~anaAV~K*RII;RAVlA zB{(g{z7KWGS}slf?*;hhS1{oKEzbixllryc6~K%99&)(agcK;|#vHDecb@+@0m|h` zF?HNHfX95AfLFa$U0#hLVsHcPdQq4pUy5d>zE)C(Ia)>C_Mn&PO9#D@8DF|Qu7_mX z|AORBCI#OIu3_uhC?B}8#2SjlSoxdzc~|e~>EAJLNB7N}d)9Za>+k9Bo;SDuX8z-) zZS!_+-MV@Gjoq8JkiWBg-R7P--QE4`Z(O)wPWQHLylv?2zh%>wd7C$_o2MGO@91AY zFV>4v`@8#ZrRD~cx@qgYo3?J4+rMLD_omG~8^WDi!;PCZZw_y{aqH%uaNW%tH}>>z zcLJx)ahy}RJg)nA|JMU}+OLJs0GMofc5+MyJL%|Mu2EbqTotYy*I2G`T&47VJolAb zc6D#wv|&wme_v1k6+PV>(u9k;cXsRbqMmI#Z(P0UrcFDS?q1*1v!Q3hmYZ){*V7+v z-5Bv|ZwgnIOdFw6Y ztndPkAv#VrYu%eSZ(VQZt-t%0Pwnbi&%|w@%p}UpVroV%yJKhnrY$#6lr4_CA+N6# zUCOJ@kalOK4R5?@CnaB|(N+rFOQX%)_wz0i_yS{WOYZ#gB5$mpeD}*68$aReBdd<{ z89$lzl_jGe<2B&*IqsU7KlGDbU#YFklHX0UKj1E0{$YAw5;~4x(!cgxV5m&b*`#x> z#F@f1_0V4e{OI|43(eOX9p^NX=jW4O9hf_MH_0KdcXO%q?tHT3tKTgAyDu>2Gm~F@ zwe_LL3Q5Cb*t==)SdE#!K&c<74X{#kzX3r&I3&ifiJ-Ct-*mVLczmeU+Kqj??8U9{QXz2%0UuxHDL zaMP9zJ-fq;NEh&Qx>$m&yh)lb_yZ?r*^ZI*k*aV#*7!Vbv zvAOH}yWxtto3_q5xQ0r zFyYNTA~R>y=)k#wj?d#7!?kqxwx0DnW8{lvwb_>K?8`n1ix?i{-o*XO+=be#k?A}u zJ$sh~(EEs^`6wBA+OHRqs-AQ|Jtn#STaEEs0MbuKk8w@l3b`_htRDBS*-+Z`V*+Oy zcLA-5)wAek=dIg%!kaejxT$;R`Wydcke~6d67MPGlSLk12MEc}R3s$p4*urU)h&T@ zC25nPz6K{c#@Cz6f88vK*EJ)V_w-T?+IzPp+5D}wD_4vSoYiEU2a9PeBEq3#ANrn+ z{c-Bdq}(hnja|>DtKrI^1Ufc0nf~-z@7!_8z|-f)-ydhWA-m6}M%K$5p67DS(!-4?q9!&m23+ z4ssTE4%NQ#A~XFb69COf7!7qX*V$Y|C^_eFott#OaOJpdl)pr8H*eX}eN)ed^Lg%Q zN&e#tr^RoRB^Lc}rb)+n9Owk_|KVK?51k+Jy#AHAL|SS_|FZWBc<$tixVpG5pZS2xjx0! z%hk{I8LoS{9_0Em*EhJn&Gj1B8&iWB&Y$z}bFTl*RRQ4fTs5wFTuZnv;#wIV`u6v_ c3*K`-N+!JWmC*`w;Hwp2BA6C9I*#;z0pkU*6aWAK delta 18060 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 diff --git a/tests/fixtures/messagepack-valid/src/main.rs b/tests/fixtures/messagepack-valid/src/main.rs index ee274407..5e3dd736 100644 --- a/tests/fixtures/messagepack-valid/src/main.rs +++ b/tests/fixtures/messagepack-valid/src/main.rs @@ -3,5 +3,7 @@ use std::io::{Read, Write}; fn main() { let mut buf: Vec = vec![]; std::io::stdin().read_to_end(&mut buf).unwrap(); + let mut cursor = std::io::Cursor::new(&buf); + rmpv::decode::read_value(&mut cursor).expect("Valid messagepack"); std::io::stdout().write_all(&buf).unwrap(); } From 6b34fce810877ee1f059eb59318661b516585d6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Cabrera?= Date: Fri, 25 Apr 2025 09:01:08 -0400 Subject: [PATCH 3/3] Update Cargo.toml Co-authored-by: Alex Bradley --- Cargo.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index a47ea45e..6d14ce6c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,8 @@ members = [ "tests/fixtures/exports", "tests/fixtures/noop", "tests/fixtures/messagepack-valid", - "tests/fixtures/messagepack-invalid", "tests/fixtures/echo", + "tests/fixtures/messagepack-invalid", + "tests/fixtures/echo", ] [package]