saddle-framework 0.3.36

The single business-facing facade for Saddle applications
use super::*;
use saddle_boundary::ingress::{CodecError, ManagedIngressError};

#[test]
fn cross_crate_codec_classification_preserves_other_branches() {
    let codec = |status, code| ManagedIngressError::Codec(CodecError { http_status: status, code });
    assert!(envelope_rejection_facts(&codec(400, "INVALID_JSON_ENVELOPE")).is_some());
    for error in [codec(503, "INVALID_JSON_ENVELOPE"), codec(400, "OTHER"),
        ManagedIngressError::Storage(saddle_admission::AdmissionError::AllocationFailed)] {
        assert!(envelope_rejection_facts(&error).is_none());
    }
}

#[test]
fn codec_borrowed_written_original_is_single_and_missing_writer_unconfirmed() {
    use saddle_core::{ContextFact, ContextLabel, RequestLocalFacts, RequestRootPublisher, RequestViewPhase};
    use saddle_observability::{EmergencyDiagnostics, FileLoggingConfig, Rotation, RootDiagnosticScope};
    let directory = std::env::temp_dir().join(format!("codec-classification-{}-{}", std::process::id(),
        std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_nanos()));
    std::fs::create_dir(&directory).unwrap();
    let mut writer = EmergencyDiagnostics::start(&FileLoggingConfig::new(&directory, Rotation::Daily)).unwrap();
    let handle = writer.handle();
    let root = RequestRootPublisher::create(ContextLabel::checked("codec-control").unwrap(), ContextFact::NotEstablished).unwrap();
    let view = root.reference().view(RequestLocalFacts::new(RequestViewPhase::Reading));
    let error = ManagedIngressError::Codec(CodecError { http_status: 400, code: "INVALID_JSON_ENVELOPE" });
    let before = format!("{error:?}");
    let (facts, code) = envelope_rejection_facts(&error).unwrap();
    let recorded = RootDiagnosticScope::new(&view, Some(&handle)).source_borrowed_error_with_facts_written(
        &error, facts, code, RootRequestEvent::Ingress, Default::default());
    assert!(recorded.is_ok());
    assert_eq!(confirmed_ingress_status(&error, &recorded), 400);
    let raw = std::fs::read_to_string(writer.target()).unwrap();
    let rows: Vec<serde_json::Value> = raw.lines().map(|line| serde_json::from_str(line).unwrap()).collect();
    let original: Vec<_> = rows.iter().filter(|row| row["event"] == "request_error_original").collect();
    assert!(!original.is_empty());
    let id = &original[0]["occurrence"]["diagnostic_id"];
    assert!(original.iter().all(|row| &row["occurrence"]["diagnostic_id"] == id));
    let contexts: Vec<_> = original.iter().filter(|row| row["channel"] == "context").collect();
    assert_eq!(contexts.len(), 1);
    assert_eq!(original.iter().filter(|row| row["channel"] == "terminal").count(), 1);
    assert!(raw.contains("framework.ingress.invalid_json_envelope"));
    assert!(raw.contains("INVALID_JSON_ENVELOPE"));
    assert_eq!(format!("{error:?}"), before);
    let (facts, code) = envelope_rejection_facts(&error).unwrap();
    let missing = RootDiagnosticScope::new(&view, None).source_borrowed_error_with_facts_written(
        &error, facts, code, RootRequestEvent::Ingress, Default::default());
    assert!(missing.is_err());
    assert_eq!(confirmed_ingress_status(&error, &missing), 503);
    let deadline = std::time::Instant::now() + std::time::Duration::from_secs(5);
    while writer.shutdown() == saddle_observability::DiagnosticShutdown::Pending && std::time::Instant::now() < deadline {
        std::thread::yield_now();
    }
    assert_eq!(writer.shutdown(), saddle_observability::DiagnosticShutdown::Finished);
    // Keep actual native originals for the component evidence export.
    println!("codec original={}", writer.target().display());
}