use crate::logging::is_log_file;
#[test]
fn resilient_writer_creates_recognized_dated_file_with_content() {
use crate::logging::ResilientFileWriter;
use std::io::Write;
use tracing_subscriber::fmt::writer::MakeWriter;
let dir = std::env::temp_dir().join(format!("opencrabs-log-test-{}", std::process::id()));
let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(&dir).unwrap();
let writer = ResilientFileWriter::new(dir.clone(), "opencrabs".to_string());
{
let mut w = writer.make_writer();
w.write_all(b"hello from the resilient writer\n").unwrap();
w.flush().unwrap();
}
let log_name = std::fs::read_dir(&dir)
.unwrap()
.filter_map(|e| e.ok())
.map(|e| e.file_name().to_string_lossy().into_owned())
.find(|n| is_log_file(n))
.expect("writer must create a log file the readers can recognize");
let content = std::fs::read_to_string(dir.join(&log_name)).unwrap();
assert!(
content.contains("hello from the resilient writer"),
"the event must be written to the file; got: {content:?}"
);
let _ = std::fs::remove_dir_all(&dir);
}
#[test]
fn matches_rolling_daily_log_files() {
assert!(is_log_file("opencrabs.2026-06-10"));
assert!(is_log_file("opencrabs.2026-06-11"));
}
#[test]
fn rejects_unrelated_files() {
assert!(!is_log_file(".gitignore"));
assert!(
!is_log_file("opencrabs"),
"a bare prefix with no date suffix is not a rolling log file"
);
assert!(
!is_log_file("other.2026-06-10"),
"a different prefix must not match"
);
assert!(!is_log_file("nginx.log"));
}
#[test]
fn old_extension_check_would_have_missed_the_real_files() {
let real = "opencrabs.2026-06-10";
assert_ne!(
std::path::Path::new(real)
.extension()
.and_then(|e| e.to_str()),
Some("log"),
"the rolling file's extension is the date, not \"log\" — that's why the old check matched nothing"
);
assert!(
is_log_file(real),
"the new matcher catches what the old missed"
);
}
#[test]
fn make_writer_waits_for_the_lock_instead_of_discarding_the_event() {
use crate::logging::ResilientFileWriter;
use std::io::Write;
use std::sync::Arc;
use std::time::Duration;
use tracing_subscriber::fmt::writer::MakeWriter;
let dir = std::env::temp_dir().join(format!(
"opencrabs-log-contention-test-{}",
std::process::id()
));
let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(&dir).unwrap();
let writer = Arc::new(ResilientFileWriter::new(
dir.clone(),
"opencrabs".to_string(),
));
let writer2 = Arc::clone(&writer);
let handle = std::thread::spawn(move || {
let _guard = writer2.appender_lock_for_test().expect("must acquire lock");
std::thread::sleep(Duration::from_millis(200));
});
std::thread::sleep(Duration::from_millis(50));
let start = std::time::Instant::now();
let mut w = writer.make_writer();
let elapsed = start.elapsed();
assert!(
elapsed >= Duration::from_millis(100),
"make_writer must wait for the lock rather than skip the event, returned after {elapsed:?}"
);
w.write_all(b"this must be kept\n")
.expect("a contended write still succeeds");
handle.join().unwrap();
let wrote_something = std::fs::read_dir(&dir)
.expect("read dir")
.filter_map(Result::ok)
.any(|e| e.metadata().map(|m| m.len() > 0).unwrap_or(false));
assert!(wrote_something, "the contended event must land on disk");
let _ = std::fs::remove_dir_all(&dir);
}