alkblobs 0.2.2

Content-addressed blob storage: multi-hash put/get/verify store with pluggable backends, transport- and protocol-agnostic
Documentation
//! 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();
}