libfreemkv 0.31.4: prune 144 vacuous tests (keep spec-grounded subset)
This commit is contained in:
@@ -269,32 +269,6 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
/// Boundary: an op that finishes well within the deadline returns
|
||||
/// Ok even when a (live, never-cancelled) halt token is supplied.
|
||||
/// The halt-poll path must not spuriously convert a completed op
|
||||
/// into Halted/Timeout. Grounds the `Ok(v) => return Ok(v)` arm of
|
||||
/// the recv_timeout match (line 134) with a non-None halt.
|
||||
#[test]
|
||||
fn live_halt_token_does_not_interfere_with_fast_op() {
|
||||
let halt = Halt::new(); // never cancelled
|
||||
let r = bounded_syscall(Some(&halt), Duration::from_secs(5), || 123u64);
|
||||
assert!(matches!(r, Ok(123)));
|
||||
assert!(!halt.is_cancelled());
|
||||
}
|
||||
|
||||
/// The op's return value is propagated byte-for-byte, not just a
|
||||
/// success flag. A non-Copy heap type proves the worker's
|
||||
/// `tx.send(op())` moves the real value across the rendezvous
|
||||
/// channel (line 125) to the receiver (line 134).
|
||||
#[test]
|
||||
fn returns_owned_value_unchanged() {
|
||||
let r = bounded_syscall(None, Duration::from_secs(2), || vec![9u8, 8, 7, 6]);
|
||||
match r {
|
||||
Ok(v) => assert_eq!(v, vec![9u8, 8, 7, 6]),
|
||||
other => panic!("expected Ok(vec), got {other:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Timeout boundary: with a tiny deadline and an op that sleeps
|
||||
/// much longer, the helper must return Timeout and must do so
|
||||
/// roughly at the deadline — NOT wait for the op to finish (that
|
||||
@@ -318,31 +292,4 @@ mod tests {
|
||||
"timeout did not return near deadline: {elapsed:?} (op should be leaked, not awaited)"
|
||||
);
|
||||
}
|
||||
|
||||
/// A worker that returns a non-Copy value AND completes within the
|
||||
/// deadline must hand the value back; the rendezvous channel has
|
||||
/// capacity 0, so the worker's send blocks until the receiver is
|
||||
/// ready — exercising the happy-path handshake rather than the
|
||||
/// buffered-send path. Mutation: changing `sync_channel::<R>(0)` to
|
||||
/// a buffered channel would still pass; changing the recv arm to
|
||||
/// drop the value would fail here.
|
||||
#[test]
|
||||
fn zero_capacity_rendezvous_delivers_string() {
|
||||
let r = bounded_syscall(None, Duration::from_secs(2), || String::from("rendezvous"));
|
||||
assert!(matches!(r.as_deref(), Ok("rendezvous")));
|
||||
}
|
||||
|
||||
/// Halt that fires AFTER the op has already completed must still
|
||||
/// yield Ok — there is no race that turns a delivered result into
|
||||
/// Halted. The op completes instantly; we cancel the halt
|
||||
/// afterwards and confirm the earlier call returned Ok. This pins
|
||||
/// the precedence: a value already in the channel wins over a
|
||||
/// subsequent halt.
|
||||
#[test]
|
||||
fn op_completion_wins_over_later_halt() {
|
||||
let halt = Halt::new();
|
||||
let r = bounded_syscall(Some(&halt), Duration::from_secs(2), || 55u32);
|
||||
halt.cancel();
|
||||
assert!(matches!(r, Ok(55)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -423,25 +423,6 @@ mod tests {
|
||||
});
|
||||
}
|
||||
|
||||
/// Backpressure / recycle exhaustion does not deadlock: a source
|
||||
/// larger than the whole in-flight pool (FORWARD_DEPTH +
|
||||
/// RECYCLE_DEPTH chunks) must still drain fully when the consumer
|
||||
/// recycles. 10 chunks of 256 bytes = 2560 bytes; pool holds far
|
||||
/// fewer. Proves the producer parks on recycle_rx and resumes as
|
||||
/// the consumer returns buffers (lines 106-117). Mutation: dropping
|
||||
/// the recycle seed loop (lines 90-92) would deadlock on the first
|
||||
/// recv and within() times out.
|
||||
#[test]
|
||||
fn large_source_drains_with_recycling() {
|
||||
within(10, || {
|
||||
let src: Vec<u8> = (0..2560u32).map(|i| (i % 251) as u8).collect();
|
||||
let pf = BytePrefetcher::new(Cursor::new(src.clone()), 256, None).expect("spawn");
|
||||
let (got, err) = drain_to_vec(pf);
|
||||
assert!(err.is_none());
|
||||
assert_eq!(got, src);
|
||||
});
|
||||
}
|
||||
|
||||
/// Exact-multiple boundary: when the source length is an exact
|
||||
/// multiple of chunk_bytes, the final non-empty chunk is followed
|
||||
/// by an `Ok(0)` EOF read, NOT a spurious empty Ok batch. 12 bytes
|
||||
|
||||
@@ -416,20 +416,6 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
/// Reading entirely beyond EOF (seek lands past the end) must also
|
||||
/// error rather than silently return zeros. Grounding: read_exact
|
||||
/// over an empty remainder is UnexpectedEof.
|
||||
#[test]
|
||||
fn read_wholly_beyond_eof_errors() {
|
||||
let dir = tempdir().unwrap();
|
||||
let path = dir.path().join("beyond.iso");
|
||||
make_iso(&path, 4);
|
||||
let mut src = FileSectorSource::open(&path).unwrap();
|
||||
let mut buf = vec![0u8; SECTOR_SIZE];
|
||||
let r = src.read_sectors(10, 1, &mut buf, false);
|
||||
assert!(r.is_err(), "read starting past EOF must error");
|
||||
}
|
||||
|
||||
/// On a successful full read the returned count MUST equal
|
||||
/// `count * 2048` exactly — the declared byte count. Grounding:
|
||||
/// `Ok(bytes)` where `bytes = count * SECTOR_SIZE`.
|
||||
@@ -496,27 +482,6 @@ mod tests {
|
||||
assert_eq!(io.kind(), std::io::ErrorKind::NotFound);
|
||||
}
|
||||
|
||||
/// Repeated reads of the SAME sector must return identical bytes —
|
||||
/// the per-read seek makes each call independent of prior position,
|
||||
/// and the DONTNEED/prefetch hooks are advisory only (no data
|
||||
/// effect). Grounding: `seek(SeekFrom::Start(offset))` before every
|
||||
/// read.
|
||||
#[test]
|
||||
fn repeated_same_sector_is_stable() {
|
||||
let dir = tempdir().unwrap();
|
||||
let path = dir.path().join("stable.iso");
|
||||
make_iso(&path, 8);
|
||||
let mut src = FileSectorSource::open(&path).unwrap();
|
||||
let mut a = vec![0u8; SECTOR_SIZE];
|
||||
let mut b = vec![0u8; SECTOR_SIZE];
|
||||
src.read_sectors(5, 1, &mut a, false).unwrap();
|
||||
// Read a different sector in between to move the file cursor.
|
||||
src.read_sectors(0, 1, &mut b, false).unwrap();
|
||||
src.read_sectors(5, 1, &mut b, false).unwrap();
|
||||
assert_eq!(a, b, "same-LBA reads must be position-independent");
|
||||
assert!(a.iter().all(|x| *x == (5u8)));
|
||||
}
|
||||
|
||||
/// A DONTNEED drop crossing the chunk threshold must not corrupt or
|
||||
/// short subsequent reads — the eviction is a pure page-cache hint.
|
||||
/// We read past the DEFAULT 32 MiB drop chunk (16384 sectors) so the
|
||||
|
||||
@@ -926,22 +926,6 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// FIFO ordering: items must be delivered to `apply` in send order.
|
||||
/// crossbeam's `bounded` channel is FIFO; this pins that the
|
||||
/// pipeline does not reorder. Mutation: if the consumer loop reused
|
||||
/// a stale item or sorted, the equality fails.
|
||||
#[test]
|
||||
fn items_delivered_in_fifo_order() {
|
||||
let pipe =
|
||||
Pipeline::spawn(DEFAULT_PIPELINE_DEPTH, OrderSink { seen: Vec::new() }).expect("spawn");
|
||||
let input: Vec<u64> = (0..50).map(|i| i * 7 + 1).collect();
|
||||
for &i in &input {
|
||||
pipe.send(i).expect("send");
|
||||
}
|
||||
let seen = pipe.finish().expect("finish");
|
||||
assert_eq!(seen, input, "pipeline reordered or dropped items");
|
||||
}
|
||||
|
||||
/// Zero items sent: closing the pipeline immediately must still
|
||||
/// call `close()` exactly once and return its Output. The consumer
|
||||
/// loop's `while let Ok = rx.recv()` exits on the dropped tx with
|
||||
@@ -1117,23 +1101,6 @@ mod tests {
|
||||
assert!(!halt.is_cancelled(), "halt must not have been the cause");
|
||||
}
|
||||
|
||||
/// `send_with_halt` happy path: when there is room in the channel
|
||||
/// it must deliver the item (Ok) and the consumer must process it.
|
||||
/// Pins the `Ok(()) => return Ok(())` arm (line 390). Mutation:
|
||||
/// inverting that arm to Err would drop the item and the sum would
|
||||
/// be wrong.
|
||||
#[test]
|
||||
fn send_with_halt_delivers_when_room_available() {
|
||||
let pipe = Pipeline::spawn(DEFAULT_PIPELINE_DEPTH, SumSink { total: 0 }).expect("spawn");
|
||||
let halt = crate::halt::Halt::new();
|
||||
for i in 1..=5u64 {
|
||||
pipe.send_with_halt(i, &halt, Duration::from_secs(5))
|
||||
.expect("send_with_halt should deliver when room is available");
|
||||
}
|
||||
let total = pipe.finish().expect("finish");
|
||||
assert_eq!(total, 15, "1+2+3+4+5");
|
||||
}
|
||||
|
||||
/// `send_with_halt` with a pre-cancelled halt must return the item
|
||||
/// immediately without attempting to enqueue. Pins the pre-check at
|
||||
/// line 365 (`if halt.is_cancelled()`). Mutation: removing that
|
||||
@@ -1154,27 +1121,6 @@ mod tests {
|
||||
assert_eq!(total, 0, "item was enqueued despite pre-cancelled halt");
|
||||
}
|
||||
|
||||
/// `finish_with_halt` must propagate a consumer panic as
|
||||
/// `PipelineConsumerPanicked` — same as `finish`. The consumer
|
||||
/// panics on the first apply; finish_with_halt sees `is_finished()`
|
||||
/// true and joins, mapping the panic payload (lines 454-458).
|
||||
#[test]
|
||||
fn finish_with_halt_propagates_consumer_panic() {
|
||||
let prev = std::panic::take_hook();
|
||||
std::panic::set_hook(Box::new(|_| {}));
|
||||
let pipe = Pipeline::spawn(DEFAULT_PIPELINE_DEPTH, PanickingSink).expect("spawn");
|
||||
let _ = pipe.send(1);
|
||||
for i in 0..5u64 {
|
||||
let _ = pipe.send(i);
|
||||
}
|
||||
let res = pipe.finish_with_halt(None);
|
||||
std::panic::set_hook(prev);
|
||||
assert!(
|
||||
matches!(res, Err(Error::PipelineConsumerPanicked)),
|
||||
"expected PipelineConsumerPanicked, got {res:?}"
|
||||
);
|
||||
}
|
||||
|
||||
/// `finish_with_halt(None)` with a wedged consumer and NO halt
|
||||
/// token must NOT return early — it must keep polling until the
|
||||
/// JOIN_TIMEOUT_SECS deadline (it cannot observe a halt that was
|
||||
|
||||
@@ -230,17 +230,4 @@ mod tests {
|
||||
);
|
||||
assert_eq!(&bytes[10..14], b"TAIL");
|
||||
}
|
||||
|
||||
/// `write` (single call) returns the BufWriter's accepted count.
|
||||
/// For a buffer under the 4 MiB capacity this is the full length
|
||||
/// (lines 108-110). Mutation: a wrong count return would break
|
||||
/// callers relying on `Write::write`'s contract.
|
||||
#[test]
|
||||
fn write_returns_full_count_under_capacity() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let p = dir.path().join("count.bin");
|
||||
let mut s = LocalFileSink::create(&p).unwrap();
|
||||
let n = s.write(&[1u8; 1000]).unwrap();
|
||||
assert_eq!(n, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,24 +216,6 @@ mod tests {
|
||||
assert_eq!(bytes.load(Ordering::SeqCst), 3);
|
||||
}
|
||||
|
||||
/// Default `finish()` dispatched through a `dyn SequentialSink`
|
||||
/// trait object must still reach the default `flush` (vtable path).
|
||||
/// This guards that there is no accidental override that turns the
|
||||
/// default into a no-op via dyn dispatch.
|
||||
#[test]
|
||||
fn default_finish_flushes_through_dyn() {
|
||||
let flushed = Arc::new(AtomicBool::new(false));
|
||||
let bytes = Arc::new(AtomicUsize::new(0));
|
||||
let sink = FlushTracker {
|
||||
flushed: flushed.clone(),
|
||||
bytes: bytes.clone(),
|
||||
};
|
||||
let mut boxed: Box<dyn SequentialSink> = Box::new(sink);
|
||||
boxed.write_all(b"xy").unwrap();
|
||||
boxed.finish().unwrap();
|
||||
assert!(flushed.load(Ordering::SeqCst));
|
||||
}
|
||||
|
||||
/// `open_for_mkv` with `None` size hint must still produce a working
|
||||
/// random-access sink (the `match size_hint { None => ... }` arm,
|
||||
/// lines 103-106). Round-trip a seek-back patch through it to prove
|
||||
@@ -252,20 +234,4 @@ mod tests {
|
||||
drop(sink);
|
||||
assert_eq!(std::fs::read(&p).unwrap(), b"AAAACCCC");
|
||||
}
|
||||
|
||||
/// finish() through a `dyn RandomAccessSink` (the supertrait of
|
||||
/// SequentialSink) for a LocalFileSink must also flush+fsync. The
|
||||
/// existing regression test boxes as `dyn SequentialSink`; this
|
||||
/// pins the `dyn RandomAccessSink` vtable path too, since
|
||||
/// `open_for_mkv` returns exactly that boxed type.
|
||||
#[test]
|
||||
fn finish_through_random_access_dyn_persists() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let p = dir.path().join("ra-finish.bin");
|
||||
let mut sink: Box<dyn RandomAccessSink> = open_for_mkv(&p, None).unwrap();
|
||||
sink.write_all(b"durable").unwrap();
|
||||
sink.finish().unwrap();
|
||||
// Visible to a separate reader before drop.
|
||||
assert_eq!(&std::fs::read(&p).unwrap()[..], b"durable");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,27 +328,6 @@ mod tests {
|
||||
assert_eq!(received, b"unflushed-tail");
|
||||
}
|
||||
|
||||
/// `SocketSink::write` must report the exact byte count it accepted
|
||||
/// into the BufWriter (forwarded from `BufWriter::write`, lines
|
||||
/// 78-80). For a buffer smaller than the 1 MiB capacity this equals
|
||||
/// the full length. Mutation: returning a wrong/clamped count would
|
||||
/// break `Write::write_all`'s loop downstream; we pin the count
|
||||
/// here directly.
|
||||
#[test]
|
||||
fn write_reports_accepted_count() {
|
||||
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
|
||||
let addr = listener.local_addr().unwrap();
|
||||
let _accept = thread::spawn(move || {
|
||||
let _ = listener.accept();
|
||||
});
|
||||
let mut sink = SocketSink::connect(addr, None).unwrap();
|
||||
let n = sink.write(&[7u8; 100]).unwrap();
|
||||
assert_eq!(
|
||||
n, 100,
|
||||
"buffered write under capacity must accept all bytes"
|
||||
);
|
||||
}
|
||||
|
||||
/// UDP `write` must emit ONE datagram per call carrying exactly the
|
||||
/// bytes passed — no buffering, no coalescing (doc lines 100-108).
|
||||
/// Two writes of different lengths must arrive as two separate
|
||||
|
||||
@@ -522,30 +522,6 @@ mod tests {
|
||||
assert_eq!(&bytes, b"hello");
|
||||
}
|
||||
|
||||
/// `flush` must not be a durability barrier nor reorder bytes, but
|
||||
/// it also must not lose buffered data. We interleave write_all and
|
||||
/// flush and confirm exact byte order survives to disk. (Distinct
|
||||
/// from the existing `flush_is_observed_in_order` which uses 3
|
||||
/// words; this exercises many small flushes to stress the
|
||||
/// passthrough flush path at line 199-201.) Mutation: if `flush`
|
||||
/// dropped pending bytes the reassembly fails.
|
||||
#[test]
|
||||
fn many_interleaved_flushes_preserve_order() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let p = dir.path().join("many-flush.bin");
|
||||
let mut w = WritebackFile::create(&p).unwrap();
|
||||
let mut expected = Vec::new();
|
||||
for i in 0u8..32 {
|
||||
let chunk = [i; 4];
|
||||
w.write_all(&chunk).unwrap();
|
||||
expected.extend_from_slice(&chunk);
|
||||
w.flush().unwrap();
|
||||
}
|
||||
w.sync_all().unwrap();
|
||||
drop(w);
|
||||
assert_eq!(read_back(&p), expected);
|
||||
}
|
||||
|
||||
/// `sync_all` is idempotent: calling it twice (and then Drop, which
|
||||
/// also finalizes) must not corrupt data or panic. Doc lines
|
||||
/// 256-262: `finalize` is idempotent so explicit sync_all then drop
|
||||
|
||||
Reference in New Issue
Block a user