Skip to content

Commit

The runner's cancellation test no longer fails on a busy machine. It sent its log to an address that is not there (127.0.0.1:9), and once a step outlasted a batch of the log (1.5 s), each batch was tried three times with waits between, about 3 s, inside the loop that times the grace after SIGINT; two batches carried the step past the 8 s the test allows, and it read as SIGINT not ending the step. The tests now use an API with no address, which sends nothing, and the log keeps what it would have sent so the test still reads it all. Failing the same way on demand (cancelling at 1.6 s instead of 0.6 s) took 10.6 s before and passes in 1.8 s now.

Claude-Session:
https://claude.ai/code/session_01MQE64a4WNN14F8GELCiuc9
Claudeagent and Claudeagentcommitted Parent87b4b00Browse files
2 files+27−60/2 viewed
+4−2
300300 use std::process::Command;
301301 use std::time::{Duration, Instant};
302302
303− let api = Api { base: "http://127.0.0.1:9".into(), job: "job_1".into(), token: "t".into() };
304− let mut log = Log::new(api, Vec::new());
303+ // Offline: on a busy machine the step can outlast a batch of the log,
304+ // and sending it to an address that is not there held the loop for
305+ // seconds, past the grace this test measures.
306+ let mut log = Log::new(Api::offline(), Vec::new());
305307 let mut command = Command::new("sh");
306308 command.args(["-c", "trap 'echo cleaned up; exit 3' INT; echo started; while true; do sleep 0.1; done"]);
307309 let began = Instant::now();
+23−4
103103 }
104104 }
105105
106+ /// An API with no address, which sends nothing: what the tests use, so
107+ /// a step's run is not held up by reports that go nowhere (each one
108+ /// tried three times, with waits between, over a second and a half).
109+ #[cfg(test)]
110+ pub(crate) fn offline() -> Api {
111+ Api { base: String::new(), job: "job_1".into(), token: "t".into() }
112+ }
113+
106114 pub(crate) fn report(&self, report: Value) {
115+ // No address: nowhere to send it (Api::offline).
116+ if self.base.is_empty() {
117+ return;
118+ }
107119 // A report that cannot be sent is tried a few times, then dropped:
108120 // the job goes on, and g1t notices a silent job by itself.
109121 for attempt in 0..3 {
135147 last: Instant,
136148 /// When anything was last sent, for the ping.
137149 sent: Instant,
150+ /// Everything sent so far, so a test reads the whole log however its
151+ /// batches fell (`buffered`).
152+ #[cfg(test)]
153+ flushed: String,
138154 }
139155
140156 impl Log {
148164 buffer: String::new(),
149165 last: Instant::now(),
150166 sent: Instant::now(),
167+ #[cfg(test)]
168+ flushed: String::new(),
151169 }
152170 }
153171
154− /// What waits to be sent.
172+ /// The log so far: what was sent and what waits to be.
155173 #[cfg(all(test, unix))]
156174 pub(crate) fn buffered(&self) -> String {
157− self.buffer.clone()
175+ format!("{}{}", self.flushed, self.buffer)
158176 }
159177
160178 /// Starts writing to step `number` (0 for the job's setup).
210228 }
211229 self.sent = Instant::now();
212230 let text = std::mem::take(&mut self.buffer);
231+ #[cfg(test)]
232+ self.flushed.push_str(&text);
213233 self.api.report(json!({ "kind": "log", "step": self.step, "text": text }));
214234 }
215235
286306 use super::*;
287307
288308 fn log(secrets: &[&str]) -> Log {
289− let api = Api { base: "http://127.0.0.1:9".into(), job: "job_1".into(), token: "t".into() };
290− Log::new(api, mask::all_variants(secrets.iter().copied()))
309+ Log::new(Api::offline(), mask::all_variants(secrets.iter().copied()))
291310 }
292311
293312 #[test]