little-durable-objects 0.1.5

Standalone regional durable-object control plane, host, and durability runtime
Documentation
use std::env;

use anyhow::Result;
use little_durable_objects::{
    actor_state::ActorStorageKey,
    host::HostId,
    host_leases::{HostLeaseRegistry, HostLeaseRequest, HostLeaseStore, PostgresHostLeaseStore},
    placement::{ObjectPlacementStore, PlacementClaim, PostgresObjectPlacementStore},
};

#[tokio::test]
async fn postgres_placement_keeps_home_region_and_increments_owner_epoch() -> Result<()> {
    let Some(url) = postgres_url() else {
        return Ok(());
    };
    let placements = PostgresObjectPlacementStore::connect(&url).await?;
    let object = ActorStorageKey::new(format!("object.v1.test.Counter.{}", uuid::Uuid::new_v4()));
    let first = match placements
        .claim(&object, None, &HostId::new("host-a"), "us-east")
        .await?
    {
        PlacementClaim::Acquired(placement) => placement,
        claim => anyhow::bail!("unexpected initial placement: {claim:?}"),
    };
    let second = match placements
        .claim(&object, Some(&first), &HostId::new("host-b"), "us-east")
        .await?
    {
        PlacementClaim::Acquired(placement) => placement,
        claim => anyhow::bail!("unexpected takeover: {claim:?}"),
    };
    assert_eq!(second.owner_epoch, 2);
    assert_eq!(second.home_region, "us-east");
    assert!(
        placements
            .claim(&object, Some(&second), &HostId::new("host-c"), "eu-west")
            .await
            .is_err()
    );
    Ok(())
}

#[tokio::test]
async fn postgres_host_lease_store_round_trips_and_fences_sessions() -> Result<()> {
    let Some(url) = postgres_url() else {
        return Ok(());
    };
    let leases = PostgresHostLeaseStore::connect(&url).await?;
    let host_id = HostId::new(format!("host-{}", uuid::Uuid::new_v4()));
    let first = HostLeaseRequest {
        id: host_id.clone(),
        session_id: uuid::Uuid::new_v4().to_string(),
        route: "http://127.0.0.1:7000".into(),
        duration_ms: 30_000,
    };
    let mut successor = first.clone();
    successor.session_id = uuid::Uuid::new_v4().to_string();
    assert!(leases.register(&first).await.is_ok());
    assert!(leases.register(&successor).await.is_err());
    leases.unregister(&host_id, &first.session_id).await?;
    let successor = leases.register(&successor).await?;
    assert_eq!(
        leases.lease_status(&host_id).await?.lease,
        Some(successor.clone())
    );
    leases.unregister(&host_id, &successor.session_id).await?;
    Ok(())
}

fn postgres_url() -> Option<String> {
    env::var("DURABLE_OBJECT_TEST_POSTGRES_URL").ok()
}