nido-svc-common 0.1.0-alpha.1

Shared health, error, OpenAPI, SSE, and middleware primitives for nido-*-svc crates
Documentation
// SPDX-License-Identifier: Apache-2.0 OR MIT

use axum::{body::to_bytes, response::IntoResponse};
use nido_svc_common::error::{NidoSvcError, ProblemJson};
use serde_json::Value;

// ── ProblemJson serde round-trip ─────────────────────────────────────────────

#[test]
fn problem_json_serde_round_trip() {
    let p = ProblemJson {
        type_url: "https://nido.local/errors/not-found".to_owned(),
        title: "Not Found".to_owned(),
        status: 404,
        detail: Some("item 42 missing".to_owned()),
        instance: None,
    };
    let json_str = serde_json::to_string(&p).expect("serialize");
    let v: Value = serde_json::from_str(&json_str).expect("deserialize");
    assert_eq!(v["type"], "https://nido.local/errors/not-found");
    assert_eq!(v["title"], "Not Found");
    assert_eq!(v["status"], 404);
    assert_eq!(v["detail"], "item 42 missing");
    assert!(v.get("instance").is_none(), "None fields must be omitted");
}

#[test]
fn problem_json_omits_none_fields() {
    let p = ProblemJson {
        type_url: "https://nido.local/errors/unauthorized".to_owned(),
        title: "Unauthorized".to_owned(),
        status: 401,
        detail: None,
        instance: None,
    };
    let v: Value = serde_json::from_str(&serde_json::to_string(&p).unwrap()).unwrap();
    assert!(v.get("detail").is_none());
    assert!(v.get("instance").is_none());
}

// ── NidoSvcError → IntoResponse status codes ─────────────────────────────────

#[tokio::test]
async fn not_found_maps_to_404() {
    let err = NidoSvcError::NotFound("thing".to_owned());
    let resp = err.into_response();
    assert_eq!(resp.status(), 404);
    let body = to_bytes(resp.into_body(), 4096).await.unwrap();
    let v: Value = serde_json::from_slice(&body).unwrap();
    assert_eq!(v["status"], 404);
}

#[tokio::test]
async fn invalid_argument_maps_to_400() {
    let err = NidoSvcError::InvalidArgument("bad param".to_owned());
    let resp = err.into_response();
    assert_eq!(resp.status(), 400);
    let body = to_bytes(resp.into_body(), 4096).await.unwrap();
    let v: Value = serde_json::from_slice(&body).unwrap();
    assert_eq!(v["status"], 400);
}

#[tokio::test]
async fn unauthorized_maps_to_401() {
    let err = NidoSvcError::Unauthorized;
    let resp = err.into_response();
    assert_eq!(resp.status(), 401);
}

#[tokio::test]
async fn internal_maps_to_500() {
    let err = NidoSvcError::Internal(anyhow::anyhow!("db exploded"));
    let resp = err.into_response();
    assert_eq!(resp.status(), 500);
    let body = to_bytes(resp.into_body(), 4096).await.unwrap();
    let v: Value = serde_json::from_slice(&body).unwrap();
    assert_eq!(v["status"], 500);
    assert!(v["detail"].as_str().unwrap().contains("db exploded"));
}