Files
galaxy/crates/galaxy_logging/src/rotation_tests.rs
T

139 lines
5.3 KiB
Rust

use std::io::Read;
use super::*;
fn read(path: &Path) -> String {
let mut s = String::new();
File::open(path).unwrap().read_to_string(&mut s).unwrap();
s
}
#[test]
fn writes_below_threshold_do_not_rotate() {
let tmp = tempfile::tempdir().unwrap();
let mut w = RotatingFileWriter::open(tmp.path(), "warp.log", 1024, 3).unwrap();
w.write_all(b"hello world\n").unwrap();
w.flush().unwrap();
assert_eq!(read(&tmp.path().join("warp.log")), "hello world\n");
assert!(!tmp.path().join("warp.log.in_session.0").exists());
}
#[test]
fn crossing_threshold_rotates_to_in_session_zero() {
let tmp = tempfile::tempdir().unwrap();
let mut w = RotatingFileWriter::open(tmp.path(), "warp.log", 16, 3).unwrap();
w.write_all(b"first batch ").unwrap(); // 12 bytes
w.write_all(b"more content").unwrap(); // crosses 16 → rotate before write
w.flush().unwrap();
assert_eq!(
read(&tmp.path().join("warp.log.in_session.0")),
"first batch "
);
assert_eq!(read(&tmp.path().join("warp.log")), "more content");
}
#[test]
fn repeated_rotations_shift_slots_up() {
let tmp = tempfile::tempdir().unwrap();
let mut w = RotatingFileWriter::open(tmp.path(), "warp.log", 8, 3).unwrap();
// Each write of ~10 bytes crosses the 8-byte threshold and triggers
// a rotation before the write lands. So the *previous* batch becomes
// .in_session.0 each time, shifting older slots up.
w.write_all(b"aaaaaaaaa\n").unwrap(); // first write — no prior content, becomes active
w.write_all(b"bbbbbbbbb\n").unwrap(); // rotates "aaa..." -> .0
w.write_all(b"ccccccccc\n").unwrap(); // rotates "bbb..." -> .0, "aaa..." -> .1
w.write_all(b"ddddddddd\n").unwrap(); // rotates "ccc..." -> .0, "bbb..." -> .1, "aaa..." -> .2
w.flush().unwrap();
assert_eq!(read(&tmp.path().join("warp.log")), "ddddddddd\n");
assert_eq!(
read(&tmp.path().join("warp.log.in_session.0")),
"ccccccccc\n"
);
assert_eq!(
read(&tmp.path().join("warp.log.in_session.1")),
"bbbbbbbbb\n"
);
assert_eq!(
read(&tmp.path().join("warp.log.in_session.2")),
"aaaaaaaaa\n"
);
}
#[test]
fn overflow_drops_the_oldest_slot() {
let tmp = tempfile::tempdir().unwrap();
let mut w = RotatingFileWriter::open(tmp.path(), "warp.log", 8, 2).unwrap();
w.write_all(b"aaaaaaaaa\n").unwrap();
w.write_all(b"bbbbbbbbb\n").unwrap(); // rotates -> .0 = aaa
w.write_all(b"ccccccccc\n").unwrap(); // rotates -> .0 = bbb, .1 = aaa
w.write_all(b"ddddddddd\n").unwrap(); // rotates -> .0 = ccc, .1 = bbb, aaa dropped
w.flush().unwrap();
assert_eq!(read(&tmp.path().join("warp.log")), "ddddddddd\n");
assert_eq!(
read(&tmp.path().join("warp.log.in_session.0")),
"ccccccccc\n"
);
assert_eq!(
read(&tmp.path().join("warp.log.in_session.1")),
"bbbbbbbbb\n"
);
assert!(!tmp.path().join("warp.log.in_session.2").exists());
}
#[test]
fn oversized_first_write_does_not_promote_empty_file_to_in_session_zero() {
// Regression for the Oz nit on #11000: when the very first write
// exceeds `max_bytes`, the rotator must NOT rename an empty active
// file into `.in_session.0` — that would burn a retention slot
// before any useful data exists. The oversized payload stays in the
// active file and is promoted on the next real rotation.
let tmp = tempfile::tempdir().unwrap();
let mut w = RotatingFileWriter::open(tmp.path(), "warp.log", 8, 3).unwrap();
w.write_all(b"oversized first payload\n").unwrap(); // 24 bytes, > 8
w.flush().unwrap();
assert!(!tmp.path().join("warp.log.in_session.0").exists());
assert_eq!(
read(&tmp.path().join("warp.log")),
"oversized first payload\n"
);
// On the next write the (now-populated) active file rotates
// normally and the oversized payload becomes `.in_session.0`.
w.write_all(b"next\n").unwrap();
w.flush().unwrap();
assert_eq!(
read(&tmp.path().join("warp.log.in_session.0")),
"oversized first payload\n"
);
assert_eq!(read(&tmp.path().join("warp.log")), "next\n");
}
#[test]
fn zero_max_rotation_truncates_in_place_without_sidecar() {
let tmp = tempfile::tempdir().unwrap();
let mut w = RotatingFileWriter::open(tmp.path(), "warp.log", 8, 0).unwrap();
// First write skips rotation since the active file is still empty;
// both batches land sequentially, and the second crosses the
// threshold so the truncate-in-place branch fires.
w.write_all(b"first batch\n").unwrap();
w.write_all(b"second batch\n").unwrap();
w.flush().unwrap();
// With max_rotation=0, no .in_session.N file should ever exist.
assert!(!tmp.path().join("warp.log.in_session.0").exists());
// The active file holds only the most recent batch (older content
// truncated since slot 0 is not retained).
assert_eq!(read(&tmp.path().join("warp.log")), "second batch\n");
}
#[test]
fn zero_max_bytes_disables_rotation_entirely() {
let tmp = tempfile::tempdir().unwrap();
let mut w = RotatingFileWriter::open(tmp.path(), "warp.log", 0, 3).unwrap();
for _ in 0..100 {
w.write_all(b"line\n").unwrap();
}
w.flush().unwrap();
assert!(!tmp.path().join("warp.log.in_session.0").exists());
assert_eq!(read(&tmp.path().join("warp.log")).len(), 500);
}