cratestack-client-rust 0.4.4

Rust-native schema-first framework for typed HTTP APIs, generated clients, and backend services.
Documentation
use std::path::PathBuf;

use super::{
    ClientStateStore, JsonFileStateStore, PersistedClientState, RequestJournalEntry,
    RuntimeCodecConfig, RuntimeConfigWire, RuntimeEnvelopeConfig, RuntimeErrorCode, RuntimeHandle,
    RuntimeRequestWire, RuntimeStateStoreConfig, RuntimeTransportConfig,
};

#[test]
fn json_file_store_round_trips_state_under_project_tmp() {
    let path = project_tmp_path("state-store-unit.json");
    if path.exists() {
        std::fs::remove_file(&path).expect("existing tmp file should be removable");
    }

    let store = JsonFileStateStore::new(&path);
    store
        .append_request_journal(&RequestJournalEntry {
            method: "GET".to_owned(),
            path: "/posts".to_owned(),
            status_code: 200,
            content_type: Some("application/cbor".to_owned()),
            recorded_at: chrono::Utc::now(),
        })
        .expect("journal entry should append");

    let loaded = store.load().expect("state should load");
    assert_eq!(loaded.schema_version, 1);
    assert_eq!(loaded.state_version, 1);
    assert_eq!(loaded.request_journal.len(), 1);

    std::fs::remove_file(&path).expect("tmp file should be removable");
}

#[test]
fn runtime_handle_rejects_invalid_method_without_running_http() {
    let handle = RuntimeHandle::new(RuntimeConfigWire {
        base_url: "http://127.0.0.1:1/".to_owned(),
        state_store: RuntimeStateStoreConfig::InMemory,
        transport: RuntimeTransportConfig::default(),
    })
    .expect("runtime handle should build");

    let error = handle
        .execute(RuntimeRequestWire {
            method: "BAD METHOD".to_owned(),
            path: "/posts".to_owned(),
            canonical_query: None,
            headers: Vec::new(),
            body: Vec::new(),
        })
        .expect_err("invalid method should fail before transport");

    assert_eq!(error.code as u32, super::RuntimeErrorCode::BadInput as u32);
}

#[test]
fn persisted_state_defaults_missing_state_version() {
    let state: PersistedClientState =
        serde_json::from_str(r#"{"schema_version":1,"request_journal":[]}"#)
            .expect("legacy state should decode");

    assert_eq!(state.state_version, 0);
}

#[test]
fn runtime_handle_rejects_unsupported_envelope_config() {
    let result = RuntimeHandle::new(RuntimeConfigWire {
        base_url: "http://127.0.0.1:1/".to_owned(),
        state_store: RuntimeStateStoreConfig::InMemory,
        transport: RuntimeTransportConfig {
            codec: RuntimeCodecConfig::Cbor,
            envelope: RuntimeEnvelopeConfig::CoseSign1,
        },
    });

    let error = match result {
        Ok(_) => panic!("unsupported envelope should fail"),
        Err(error) => error,
    };

    assert_eq!(error.code, RuntimeErrorCode::BadInput);
}

fn project_tmp_path(file_name: &str) -> PathBuf {
    PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("../../tmp/client-rust-tests")
        .join(file_name)
}