From 1001819e4c4c945406332b9db0b512a2b93eed88 Mon Sep 17 00:00:00 2001 From: Markus Scully Date: Sun, 10 Aug 2025 17:41:54 +0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=F0=9F=A7=AA=20cli,=20vanth:=20Fix?= =?UTF-8?q?=20SQLite=20store=20bug=20and=20add=20CLI=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Modified `Sqlite::get_all_of_ty` to return stored rows instead of empty results. - Added `Send` requirement to `Backend` trait. - Implemented `ContentHash::hex` method for hexadecimal representation. - Added integration test for CLI `write` and `get` commands with `run_vanth` helper. - Configured CLI tracing to log to stderr instead of stdout. - Added `serde` dependency to `cli` crate for test struct serialization. - Modified `handle_write` to print content hash after successful storage. --- Cargo.lock | 1 + crates/cli/Cargo.toml | 1 + crates/cli/src/cli.rs | 2 + crates/cli/src/main.rs | 1 + crates/cli/tests/integration/main.rs | 83 ++++++++++++++++++++++++++++ crates/vanth/src/lib.rs | 6 ++ crates/vanth/src/store.rs | 8 +-- 7 files changed, 97 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 65fd528..9e63199 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2107,6 +2107,7 @@ name = "vanth_cli" version = "0.1.0" dependencies = [ "clap", + "serde", "serde_json", "tempfile", "tracing", diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 8ebdf94..20e9d0b 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -5,6 +5,7 @@ edition.workspace = true [dependencies] clap.workspace = true +serde.workspace = true serde_json.workspace = true vanth = { path = "../vanth" } tracing.workspace = true diff --git a/crates/cli/src/cli.rs b/crates/cli/src/cli.rs index c8cce52..6c456f3 100644 --- a/crates/cli/src/cli.rs +++ b/crates/cli/src/cli.rs @@ -137,6 +137,8 @@ fn handle_write(args: &WriteArgs) { eprintln!("Error writing to store: {:?}", e); process::exit(1); }); + + println!("{}", content_hash.hex()); } fn handle_get(args: &GetArgs) { diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 241d5fb..b51ebc7 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -6,6 +6,7 @@ pub use cli::*; fn main() { tracing_subscriber::fmt() + .with_writer(std::io::stderr) .with_max_level(tracing::Level::TRACE) .init(); diff --git a/crates/cli/tests/integration/main.rs b/crates/cli/tests/integration/main.rs index e69de29..86b887a 100644 --- a/crates/cli/tests/integration/main.rs +++ b/crates/cli/tests/integration/main.rs @@ -0,0 +1,83 @@ +use std::io::Write; +use std::path::Path; +use std::process::Command; + +use serde::{Deserialize, Serialize}; +use serde_json::{Value, json}; +use tempfile::tempdir; +use vanth::{ContentHash, Vanth, hash as vanth_hash}; + +fn run_vanth(args: &[&str], input: Option<&str>) -> (String, String, i32) { + let mut cmd = Command::new(env!("CARGO_BIN_EXE_vanth_cli")); + cmd.args(args); + if let Some(inp) = input { + let mut child = cmd + .stdin(std::process::Stdio::piped()) + .stdout(std::process::Stdio::piped()) + .stderr(std::process::Stdio::piped()) + .spawn() + .unwrap(); + { + let stdin = child.stdin.as_mut().unwrap(); + stdin.write_all(inp.as_bytes()).unwrap(); + } + let output = child.wait_with_output().unwrap(); + ( + String::from_utf8(output.stdout).unwrap(), + String::from_utf8(output.stderr).unwrap(), + output.status.code().unwrap(), + ) + } else { + let output = cmd.output().unwrap(); + ( + String::from_utf8(output.stdout).unwrap(), + String::from_utf8(output.stderr).unwrap(), + output.status.code().unwrap(), + ) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, Vanth)] +struct Foo { + inner: i32, +} + +#[derive(Clone, Debug, Deserialize, Serialize, Vanth)] +struct Bar { + inner: f64, +} + +/// Create a value in the database with the `write` command, gets its hash from the CLI stdout output, and retrieve it +/// again with the `get` command. +#[test] +fn test_write_get() { + let tempdir = tempdir().unwrap(); + let db_path = tempdir.path().join("test.sqlite").to_str().unwrap().to_string(); + + let foo = Foo { inner: 6 }; + + let (stdout, stderr, exit) = run_vanth( + &[ + "write", + "--db", + &db_path, + "--ty", + &Foo::ty().to_string(), + "--value", + &serde_json::to_string(&foo).unwrap(), + ], + None, + ); + if exit != 0 { + panic!("{}", stderr); + } + let hash = stdout.trim(); + println!("x{}x", hash); + + let (stdout, stderr, exit) = run_vanth(&["get", "--db", &db_path, "--ty", &Foo::ty().to_string(), &hash], None); + if exit != 0 { + panic!("{}", stderr); + } + let recovered_foo = serde_json::from_str(&stdout).unwrap(); + assert_eq!(foo, recovered_foo); +} diff --git a/crates/vanth/src/lib.rs b/crates/vanth/src/lib.rs index ff35f1a..656f109 100644 --- a/crates/vanth/src/lib.rs +++ b/crates/vanth/src/lib.rs @@ -127,6 +127,12 @@ pub struct ContentHash { pub hash: [u8; 32], } +impl ContentHash { + pub fn hex(&self) -> String { + self.hash.iter().map(|b| format!("{:02x}", b)).collect::() + } +} + #[derive(Clone, Debug, Deserialize, Component, Serialize)] pub struct Reference { value: ReferenceValue, diff --git a/crates/vanth/src/store.rs b/crates/vanth/src/store.rs index b60b8b8..e1953b8 100644 --- a/crates/vanth/src/store.rs +++ b/crates/vanth/src/store.rs @@ -152,7 +152,7 @@ pub struct Cache { // backend: Backend, } -pub trait Backend: std::fmt::Debug { +pub trait Backend: std::fmt::Debug + Send { fn get_from_hash(&mut self, ty: Ty, content_hash: ContentHash) -> Result>>; fn get_all_of_ty(&mut self, ty: Ty) -> Result)>>; @@ -208,8 +208,6 @@ impl Backend for Sqlite { let table_name = Self::table_name(&ty); let query = format!("SELECT content_hash, content FROM \"{}\"", table_name); - trace!("Reading table {}", table_name); - let mut statement = match transaction.prepare(&query).map_err(Into::into) { Err(Error::SqliteTableDoesNotExist { .. }) => return Ok(Vec::new()), other => other?, @@ -229,9 +227,9 @@ impl Backend for Sqlite { } drop(statement); - transaction.commit()?; - Ok(Vec::new()) + + Ok(results) } fn write(&mut self, ty: Ty, content_hash: ContentHash, content: Vec) -> Result<()> {