- put_as(algorithm, len: Option<u64>, stream) is the facade's sole public write surface; put, put_git_object, put_known, and the matches! family restriction are deleted outright (no shim, 0.x) - put_in_batch takes the algorithm parameter (batch, algorithm, len, stream); the one seam routes every member - Digest::derive, Key::derive, Digest::from_git_oid_hex deleted; explicit construction is Algorithm::derive / Key::from_bytes over the physical encoding - the put_unknown fleet arm honors its threaded algorithm parameter (the put.rs:360 re-hardcode), pinned by a live pg-lo fleet test - the unknown-length arm retained per §Decision 3; its identity-family form pinned (buffer + staged routes land the known-length key) - the seam-guard test transforms: blob algorithms are legal at the seam; put_as lands the canonical blob derivation (git vectors) - caller sweep: ~250 sites across src/, tests/, and the conformance columns; the ops put handler's store arm rides the seam's blob arm canonically until the put-handler task (§Decision 4) - fuzz key_encoding target: the from_git_oid_hex arm dies with the constructor; seed regeneration a no-op diff; corpus-replay gate green Verified: cargo test (default), cargo test --all-features server-less and against the live pglo-poc harness, both clippy variants (-D warnings), cargo fmt --check, cargo doc --no-deps, the fuzz corpus-replay gate.
138 lines
4.4 KiB
Rust
138 lines
4.4 KiB
Rust
//! The README quick start's verification: each fence's call shape
|
|
//! compiles and runs against the real API as an async test (the
|
|
//! filesystem arguments are minted per-run instead of the README's
|
|
//! literal `./` paths, so the suite never writes the repo root). Each
|
|
//! fence is feature-gated to the constructor it exercises (mem, the
|
|
//! sqlite default, the postgres kv-only form) — the same gate the
|
|
//! constructor carries — so the file compiles on every matrix build;
|
|
//! the pg row additionally needs its live harness (`ALKBLOBS_PG_*`
|
|
//! env — unset means a clean skip, the conformance columns'
|
|
//! harness convention), like the conformance pg columns.
|
|
|
|
#[cfg(feature = "mem")]
|
|
#[tokio::test]
|
|
async fn readme_quick_start_mem() {
|
|
use alkblobs::{Algorithm, Store};
|
|
let store = Store::mem_only();
|
|
|
|
let content: &[u8] = b"hello, blobs";
|
|
let (key, pin) = store
|
|
.put_as(
|
|
Algorithm::GitBlobSha256,
|
|
Some(content.len() as u64),
|
|
std::io::Cursor::new(content),
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
let (len, blob) = store.get(&key.as_bytes()).await.unwrap().unwrap();
|
|
assert_eq!(blob.read_at(0, len).await.unwrap(), content);
|
|
|
|
drop(pin);
|
|
let report = store.sweep().await.unwrap();
|
|
assert!(report.aborted.is_some());
|
|
assert_eq!(report.deleted, 0);
|
|
}
|
|
|
|
#[cfg(feature = "sqlite")]
|
|
#[tokio::test]
|
|
async fn readme_quick_start_sqlite_local() {
|
|
use alkblobs::{Algorithm, Store, DEFAULT_DISPATCH_THRESHOLD};
|
|
use std::time::Duration;
|
|
|
|
let dir = std::env::temp_dir().join(format!("alkblobs-readme-sqlite-{}", std::process::id()));
|
|
std::fs::create_dir_all(&dir).unwrap();
|
|
let store = Store::dual_tier_sqlite_local(
|
|
dir.join("./blobs.db"),
|
|
dir.join("./blobs-root"),
|
|
DEFAULT_DISPATCH_THRESHOLD,
|
|
Duration::from_secs(300),
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
let content: &[u8] = b"durable path";
|
|
let (key, _pin) = store
|
|
.put_as(
|
|
Algorithm::GitBlobSha256,
|
|
Some(content.len() as u64),
|
|
std::io::Cursor::new(content),
|
|
)
|
|
.await
|
|
.unwrap();
|
|
assert!(store.has(&key.as_bytes()).await.unwrap());
|
|
|
|
std::fs::remove_dir_all(&dir).unwrap();
|
|
}
|
|
|
|
#[cfg(feature = "postgres")]
|
|
#[tokio::test]
|
|
async fn readme_quick_start_postgres_kv_only() {
|
|
use alkblobs::{Algorithm, PgOpts, Store, DEFAULT_DISPATCH_THRESHOLD};
|
|
use std::sync::atomic::{AtomicU64, Ordering};
|
|
use std::time::Duration;
|
|
|
|
let host = match std::env::var("ALKBLOBS_PG_HOST") {
|
|
Ok(v) if !v.is_empty() => v,
|
|
_ => {
|
|
eprintln!(
|
|
"skipping (no postgres harness server): set ALKBLOBS_PG_HOST/PORT/USER/PASSWORD/DB"
|
|
);
|
|
return;
|
|
}
|
|
};
|
|
let port = std::env::var("ALKBLOBS_PG_PORT")
|
|
.ok()
|
|
.filter(|v| !v.is_empty())
|
|
.unwrap_or_else(|| "15432".to_string());
|
|
let user = std::env::var("ALKBLOBS_PG_USER")
|
|
.ok()
|
|
.filter(|v| !v.is_empty())
|
|
.unwrap_or_else(|| "postgres".to_string());
|
|
let password = std::env::var("ALKBLOBS_PG_PASSWORD")
|
|
.ok()
|
|
.filter(|v| !v.is_empty())
|
|
.unwrap_or_else(|| "poc".to_string());
|
|
let db = std::env::var("ALKBLOBS_PG_DB")
|
|
.ok()
|
|
.filter(|v| !v.is_empty())
|
|
.unwrap_or_else(|| "blobs".to_string());
|
|
let dsn = format!("host={host} port={port} user={user} password={password} dbname={db}");
|
|
static SEQ: AtomicU64 = AtomicU64::new(0);
|
|
let schema = format!(
|
|
"alkblobs_readme_pg_kv_{}_{}",
|
|
std::process::id(),
|
|
SEQ.fetch_add(1, Ordering::Relaxed)
|
|
);
|
|
|
|
let store = Store::kv_only_postgres(
|
|
&dsn,
|
|
PgOpts {
|
|
schema: schema.clone(),
|
|
..PgOpts::default()
|
|
},
|
|
DEFAULT_DISPATCH_THRESHOLD,
|
|
Duration::from_secs(300),
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
let content: &[u8] = b"pool-backed path";
|
|
let (key, _pin) = store
|
|
.put_as(
|
|
Algorithm::GitBlobSha256,
|
|
Some(content.len() as u64),
|
|
std::io::Cursor::new(content),
|
|
)
|
|
.await
|
|
.unwrap();
|
|
assert!(store.has(&key.as_bytes()).await.unwrap());
|
|
|
|
let (client, conn) = tokio_postgres::connect(&dsn, tokio_postgres::NoTls)
|
|
.await
|
|
.unwrap();
|
|
tokio::spawn(conn);
|
|
let drop_schema = format!("DROP SCHEMA {schema} CASCADE");
|
|
client.batch_execute(&drop_schema).await.unwrap();
|
|
}
|