use saddle_core::{
BoundedDiagnostic, BoundedDiagnosticCause, CaptureSite, ContextFact, ContextLabel,
Diagnostic, DiagnosticCategory, DiagnosticCause, DiagnosticCode, DiagnosticStage,
RequestLocalFacts, RequestRootPublisher, RequestViewPhase,
};
use saddle_observability::{
EmergencyDiagnostics, FileLoggingConfig, RootDiagnosticScope, RootOutcomeFacts,
RootRequestEvent, RootSupervisionReturn, Rotation,
};
#[test]
fn written_receipt_follows_actual_terminal_record() {
use std::os::unix::fs::PermissionsExt;
let directory =
std::env::temp_dir().join(format!("saddle-written-source-{}", std::process::id()));
std::fs::create_dir_all(&directory).unwrap();
let existing = directory.join(saddle_observability::EMERGENCY_FILE_NAME);
std::fs::write(&existing, b"").unwrap();
std::fs::set_permissions(&existing, std::fs::Permissions::from_mode(0o600)).unwrap();
let mut writer =
EmergencyDiagnostics::start(&FileLoggingConfig::new(&directory, Rotation::Daily)).unwrap();
let handle = writer.handle();
let root = RequestRootPublisher::create(
ContextLabel::checked("dispatch-test").unwrap(),
ContextFact::NotEstablished,
)
.unwrap();
let view = root
.reference()
.view(RequestLocalFacts::new(RequestViewPhase::Handler));
let source = RootDiagnosticScope::new(&view, Some(&handle));
let error = std::io::Error::new(std::io::ErrorKind::InvalidData, "dispatch original cause");
let written = source
.source_error_written(
&error,
DiagnosticStage::RequestHandler,
RootRequestEvent::Handler,
RootOutcomeFacts::default(),
)
.ok()
.expect("writer must acknowledge complete source");
let long_error = std::io::Error::other("long original ".repeat(1500));
let long_written = source.source_error_written(
&long_error,
DiagnosticStage::RequestHandler,
RootRequestEvent::Handler,
RootOutcomeFacts::default(),
).ok().expect("every continuation and terminal must be acknowledged");
let code = DiagnosticCode::new("test.original_description").unwrap();
let description = "independent panic payload with private detail";
let bounded = BoundedDiagnostic::capture(
DiagnosticCategory::UnexpectedError,
CaptureSite::FirstObserved,
BoundedDiagnosticCause::new(DiagnosticStage::RequestHandler, code),
);
let bounded_id = bounded.occurrence();
let description_written = source
.source_description_written(
&description,
bounded,
code,
RootRequestEvent::Handler,
RootOutcomeFacts::default(),
)
.ok()
.expect("description source must be confirmed");
assert_eq!(
serde_json::to_value(description_written.occurrence()).unwrap(),
serde_json::to_value(bounded_id).unwrap()
);
let existing = Diagnostic::capture(
DiagnosticCategory::UnexpectedError,
CaptureSite::FirstObserved,
DiagnosticCause::new(DiagnosticStage::RequestHandler, code),
);
let existing_id = existing.occurrence();
let existing_written = source
.source_existing_error_written(
&error,
existing,
code,
RootRequestEvent::Handler,
RootOutcomeFacts::default(),
)
.ok()
.expect("existing source must be confirmed");
assert_eq!(
serde_json::to_value(existing_written.occurrence()).unwrap(),
serde_json::to_value(existing_id).unwrap()
);
let rows = std::fs::read_to_string(writer.target()).unwrap();
assert_eq!(std::fs::metadata(writer.target()).unwrap().permissions().mode() & 0o777, 0o644);
assert!(rows.contains("dispatch original cause"));
assert!(rows.contains(description));
assert!(
rows.lines()
.any(|row| row.contains("exposed_chain_complete"))
);
let supervised = RootSupervisionReturn::<()>::failed(written).consume().unwrap_err();
assert_eq!(
supervised.original_capture(),
saddle_observability::root_diagnostic::OriginalCaptureState::CompleteWritten
);
assert_eq!(long_written.into_source().original_capture(), saddle_observability::root_diagnostic::OriginalCaptureState::CompleteWritten);
assert_eq!(description_written.into_source().original_capture(), saddle_observability::root_diagnostic::OriginalCaptureState::CompleteWritten);
assert_eq!(existing_written.into_source().original_capture(), saddle_observability::root_diagnostic::OriginalCaptureState::CompleteWritten);
let continuations = rows.lines().filter_map(|line| serde_json::from_str::<serde_json::Value>(line).ok())
.filter(|row| row["state"] == "continuation").count();
assert!(continuations >= 2, "long original must reuse the confirmation slot across segments");
drop(handle);
while writer.shutdown() == saddle_observability::DiagnosticShutdown::Pending {
std::thread::yield_now();
}
drop(writer);
let fresh = directory.join("fresh");
let mut new_writer = EmergencyDiagnostics::start(&FileLoggingConfig::new(&fresh, Rotation::Daily)).unwrap();
let new_handle = new_writer.handle();
let new_root = RequestRootPublisher::create(ContextLabel::checked("fresh").unwrap(), ContextFact::NotEstablished).unwrap();
let new_view = new_root.reference().view(RequestLocalFacts::new(RequestViewPhase::Handler));
let new_error = std::io::Error::other("new file mode");
let new_written = RootDiagnosticScope::new(&new_view, Some(&new_handle)).source_error_written(
&new_error, DiagnosticStage::RequestHandler, RootRequestEvent::Handler,
RootOutcomeFacts::default(),
).ok().expect("new file writer confirms source");
assert_eq!(new_written.into_source().original_capture(), saddle_observability::root_diagnostic::OriginalCaptureState::CompleteWritten);
assert_eq!(std::fs::metadata(new_writer.target()).unwrap().permissions().mode() & 0o777, 0o644);
drop(new_handle);
while new_writer.shutdown() == saddle_observability::DiagnosticShutdown::Pending {
std::thread::yield_now();
}
std::fs::remove_dir_all(directory).unwrap();
}
#[test]
fn missing_output_cannot_issue_written_receipt() {
let root = RequestRootPublisher::create(
ContextLabel::checked("dispatch-test").unwrap(),
ContextFact::NotEstablished,
)
.unwrap();
let view = root
.reference()
.view(RequestLocalFacts::new(RequestViewPhase::Handler));
let scope = RootDiagnosticScope::new(&view, None);
let error = std::io::Error::other("unavailable output");
assert!(
scope
.source_error_written(
&error,
DiagnosticStage::RequestHandler,
RootRequestEvent::Handler,
RootOutcomeFacts::default()
)
.is_err()
);
let code = DiagnosticCode::new("test.original_description").unwrap();
let bounded = BoundedDiagnostic::capture(
DiagnosticCategory::UnexpectedError,
CaptureSite::FirstObserved,
BoundedDiagnosticCause::new(DiagnosticStage::RequestHandler, code),
);
assert!(
scope
.source_description_written(
&"unavailable original",
bounded,
code,
RootRequestEvent::Handler,
RootOutcomeFacts::default(),
)
.is_err()
);
}