greentic-flow 0.5.0

Generic YGTC flow schema/loader/IR for self-describing component nodes.
Documentation
use greentic_flow::cache::ArtifactKey;
use greentic_flow::cache::singleflight::Singleflight;
use tokio::sync::oneshot;

#[tokio::test]
async fn singleflight_serializes_same_key_and_releases_after_drop() {
    let singleflight = Singleflight::new();
    let key = ArtifactKey::new("profile".to_string(), "sha256:test".to_string());

    let guard = singleflight.acquire(key.clone()).await;
    let cloned = singleflight.clone();
    let (entered_tx, mut entered_rx) = oneshot::channel();

    let waiter = tokio::spawn(async move {
        let _guard = cloned.acquire(key).await;
        let _ = entered_tx.send(());
    });

    for _ in 0..10 {
        tokio::task::yield_now().await;
    }
    assert!(
        matches!(
            entered_rx.try_recv(),
            Err(tokio::sync::oneshot::error::TryRecvError::Empty)
        ),
        "second acquire should block while first guard is held"
    );

    drop(guard);

    waiter
        .await
        .expect("waiter should finish once the guard drops");
}