Remove fixture races exposed by concurrent file IO
Read only atomically published journal batches, not in-progress spool tempfiles. Wait for a guest-ready notification before closing stdin in the EOF test, rather than treating process admission as handler readiness. Card: SAU-359
This commit is contained in:
+11
-8
@@ -208,7 +208,11 @@ async fn journal_recovers_after_sqlite_write_failure() {
|
|||||||
call(&h, "core.log", json!({})).await;
|
call(&h, "core.log", json!({})).await;
|
||||||
let batches: Vec<Value> = std::fs::read_dir(w.0.join("logs/core/failed-batches"))
|
let batches: Vec<Value> = std::fs::read_dir(w.0.join("logs/core/failed-batches"))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.map(|file| serde_json::from_slice(&std::fs::read(file.unwrap().path()).unwrap()).unwrap())
|
.map(Result::unwrap)
|
||||||
|
// The writer atomically publishes .json files; its temporary files can
|
||||||
|
// still be incomplete while later process-exit entries are spooling.
|
||||||
|
.filter(|file| file.path().extension().is_some_and(|ext| ext == "json"))
|
||||||
|
.map(|file| serde_json::from_slice(&std::fs::read(file.path()).unwrap()).unwrap())
|
||||||
.collect();
|
.collect();
|
||||||
assert!(
|
assert!(
|
||||||
batches
|
batches
|
||||||
@@ -1104,17 +1108,16 @@ async fn stop_closes_stdin_and_waits_for_exit() {
|
|||||||
let w = TestWorld::new();
|
let w = TestWorld::new();
|
||||||
let h = w.start().await;
|
let h = w.start().await;
|
||||||
let hc = h.clone();
|
let hc = h.clone();
|
||||||
|
let mut events = h.subscribe();
|
||||||
let pending = tokio::spawn(async move { hc.call("probe.wait_eof", json!({})).await });
|
let pending = tokio::spawn(async move { hc.call("probe.wait_eof", json!({})).await });
|
||||||
|
// Admission is not readiness: stop may otherwise close stdin before the
|
||||||
|
// request reaches the guest, so wait for the handler to enter its EOF loop.
|
||||||
let pid = tokio::time::timeout(std::time::Duration::from_secs(20), async {
|
let pid = tokio::time::timeout(std::time::Duration::from_secs(20), async {
|
||||||
loop {
|
loop {
|
||||||
if let Some((pid, _)) = h
|
let event = events.recv().await.unwrap();
|
||||||
.processes()
|
if event["params"]["name"] == "waiting-eof" {
|
||||||
.into_iter()
|
break event["params"]["params"]["pid"].clone();
|
||||||
.find(|(_, p)| p.method == "wait_eof")
|
|
||||||
{
|
|
||||||
break pid;
|
|
||||||
}
|
}
|
||||||
tokio::task::yield_now().await;
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
|
|||||||
@@ -83,6 +83,9 @@ fn unknown_id() {
|
|||||||
}
|
}
|
||||||
fn wait_eof(lines: &mut Lines) {
|
fn wait_eof(lines: &mut Lines) {
|
||||||
std::fs::write("/state/waiting", "yes").unwrap();
|
std::fs::write("/state/waiting", "yes").unwrap();
|
||||||
|
send(json!({"jsonrpc":"2.0","method":"core.notify","params":{
|
||||||
|
"name":"waiting-eof", "params":{"pid":std::env::var("SAUSAGE_PID").unwrap()}
|
||||||
|
}}));
|
||||||
for _ in lines {}
|
for _ in lines {}
|
||||||
std::fs::write("/state/stopped", "yes").unwrap();
|
std::fs::write("/state/stopped", "yes").unwrap();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user