klieo-workflow-api 3.2.0

Embeddable Axum run-service router fronting klieo-workflow (submit / poll declarative workflows).
Documentation
//! `GET /runs/{id}` behaviour.

mod common;

use std::time::Duration;

use axum::http::StatusCode;
use common::*;
use klieo_workflow::test_support::const_subflow;
use klieo_workflow::Registry;
use klieo_workflow_api::RunStatus;
use tower::ServiceExt;

const GENEROUS_TIMEOUT: Duration = Duration::from_secs(5);
const HIGH_CAP: usize = 8;

#[tokio::test]
async fn get_unknown_run_returns_404() {
    let router = build_router(Registry::new(), GENEROUS_TIMEOUT, HIGH_CAP).await;
    let response = router.oneshot(get_request("nonexistent")).await.unwrap();
    assert_eq!(response.status(), StatusCode::NOT_FOUND);
}

#[tokio::test]
async fn completed_run_polls_succeeded_with_result() {
    let registry = Registry::new().with_subflow("echo", const_subflow("DONE"));
    let router = build_router(registry, GENEROUS_TIMEOUT, HIGH_CAP).await;

    let submit = router
        .clone()
        .oneshot(submit_request(
            single_subflow_def("echo"),
            serde_json::json!({}),
        ))
        .await
        .unwrap();
    assert_eq!(submit.status(), StatusCode::ACCEPTED);
    let run_id = run_id_of(submit).await;

    let view = poll_until_terminal(router.clone(), &run_id).await;
    assert_eq!(view.status, RunStatus::Succeeded);
    assert_eq!(view.result, Some(serde_json::json!({ "tag": "DONE" })));

    // A direct GET after completion returns 200 with the same snapshot.
    let response = router.oneshot(get_request(&run_id)).await.unwrap();
    assert_eq!(response.status(), StatusCode::OK);
}

#[tokio::test]
async fn get_run_by_a_different_author_returns_404() {
    let registry = Registry::new().with_subflow("echo", const_subflow("OK"));
    let router = build_router_with_auth(
        distinct_author_authenticator(),
        registry,
        GENEROUS_TIMEOUT,
        HIGH_CAP,
    )
    .await;

    let submit = router
        .clone()
        .oneshot(submit_request(
            single_subflow_def("echo"),
            serde_json::json!({}),
        ))
        .await
        .unwrap();
    let run_id = run_id_of(submit).await;

    // OTHER_TOKEN has the same base read scope as the submitting TEST_TOKEN,
    // just a different identity — the run exists, but not for OTHER_TOKEN.
    let response = router
        .oneshot(get_request_as(&run_id, OTHER_TOKEN))
        .await
        .unwrap();
    assert_eq!(response.status(), StatusCode::NOT_FOUND);
}

#[tokio::test]
async fn get_run_with_read_all_scope_succeeds_for_any_author() {
    let registry = Registry::new().with_subflow("echo", const_subflow("OK"));
    let router = build_router_with_auth(
        distinct_author_authenticator(),
        registry,
        GENEROUS_TIMEOUT,
        HIGH_CAP,
    )
    .await;

    let submit = router
        .clone()
        .oneshot(submit_request(
            single_subflow_def("echo"),
            serde_json::json!({}),
        ))
        .await
        .unwrap();
    let run_id = run_id_of(submit).await;

    let response = router
        .oneshot(get_request_as(&run_id, READ_ALL_TOKEN))
        .await
        .unwrap();
    assert_eq!(response.status(), StatusCode::OK);
}