use platform_core::util::elastic_queue::{base_dir, ElasticQueue, MEMORY_BUFFER};
use platform_core::{overrides, resources};
use std::sync::Once;
fn setup() {
static INIT: Once = Once::new();
INIT.call_once(|| {
resources::prepend_resource_root("tests/resources");
let holding = std::env::temp_dir().join(format!("mercury-eq-test-{}", std::process::id()));
overrides::set("transient.data.store", &holding.display().to_string());
overrides::set("elastic.queue.segment.size.bytes", "512");
});
}
fn payload(n: u64) -> Vec<u8> {
format!("event-{n}-{}", "x".repeat(100)).into_bytes()
}
fn segment_files_for(id_fragment: &str) -> Vec<String> {
std::fs::read_dir(base_dir())
.map(|entries| {
entries
.flatten()
.map(|e| e.file_name().to_string_lossy().to_string())
.filter(|name| {
name.starts_with("eq-") && name.contains(id_fragment) && name.ends_with(".dat")
})
.collect()
})
.unwrap_or_default()
}
#[test]
fn fifo_order_across_memory_and_disk_tiers() {
setup();
let total = MEMORY_BUFFER + 30; let mut queue = ElasticQueue::new("fifo.order.test");
for n in 0..total {
queue.write(&payload(n)).unwrap();
}
assert_eq!(queue.write_counter(), total);
assert!(
!segment_files_for("fifo.order.test").is_empty(),
"expected overflow segments on disk"
);
for n in 0..total {
assert_eq!(queue.read().unwrap(), payload(n), "FIFO order broke at {n}");
}
assert!(queue.read().unwrap().is_empty());
assert!(queue.is_closed());
assert!(
segment_files_for("fifo.order.test").is_empty(),
"all segments should be reclaimed after drain"
);
}
#[test]
fn peek_holds_the_next_event_without_consuming() {
setup();
let mut queue = ElasticQueue::new("peek.test");
queue.write(&payload(1)).unwrap();
queue.write(&payload(2)).unwrap();
assert_eq!(queue.peek().unwrap(), payload(1));
assert_eq!(queue.peek().unwrap(), payload(1)); assert_eq!(queue.read().unwrap(), payload(1)); assert_eq!(queue.read().unwrap(), payload(2));
}
#[test]
fn queue_is_reusable_after_drain_with_a_new_generation() {
setup();
let mut queue = ElasticQueue::new("reuse.test");
for n in 0..(MEMORY_BUFFER + 5) {
queue.write(&payload(n)).unwrap();
}
while !queue.read().unwrap().is_empty() {}
assert!(queue.is_closed());
for n in 100..(100 + MEMORY_BUFFER + 5) {
queue.write(&payload(n)).unwrap();
}
for n in 100..(100 + MEMORY_BUFFER + 5) {
assert_eq!(queue.read().unwrap(), payload(n));
}
}
#[test]
fn sealed_consumed_segments_are_reclaimed_immediately() {
setup();
let mut queue = ElasticQueue::new("reclaim.test");
let total = MEMORY_BUFFER + 40; for n in 0..total {
queue.write(&payload(n)).unwrap();
}
let during_burst = segment_files_for("reclaim.test").len();
assert!(
during_burst >= 2,
"expected multiple sealed segments, saw {during_burst}"
);
for _ in 0..(total - 5) {
assert!(!queue.read().unwrap().is_empty());
}
let near_end = segment_files_for("reclaim.test").len();
assert!(
near_end < during_burst,
"consumed segments should be deleted incrementally ({near_end} vs {during_burst})"
);
while !queue.read().unwrap().is_empty() {}
assert!(segment_files_for("reclaim.test").is_empty());
}
#[test]
fn destroy_purges_stray_segment_files() {
setup();
let mut queue = ElasticQueue::new("destroy.test");
for n in 0..(MEMORY_BUFFER + 20) {
queue.write(&payload(n)).unwrap();
}
assert!(!segment_files_for("destroy.test").is_empty());
queue.destroy();
assert!(queue.is_closed());
assert!(segment_files_for("destroy.test").is_empty());
}
#[test]
fn empty_writes_are_ignored() {
setup();
let mut queue = ElasticQueue::new("empty.write.test");
queue.write(&[]).unwrap();
assert!(queue.is_closed());
assert!(queue.read().unwrap().is_empty());
}