From a3d97faec83a24d9c79ebdb19611b2c06e18a341 Mon Sep 17 00:00:00 2001 From: japabu Date: Wed, 28 Oct 2026 23:50:41 +0100 Subject: [PATCH] tests: the stick test waits for any load line past 1500, not one exact line the_log_lands_on_the_boot_stick waited on the console for the exact line `stick_load: line 1500 `. Under the load the console falls behind, and logkeeper then sheds the oldest program lines it holds for the console. A shed line 1500 made the test stall with "it never stopped talking and never got there" while the guest was tens of thousands of lines further on. The nightly's kvm suite went red that way on 10-22, 10-24, 10-26 and 10-28. A census of the old wait on a Linux KVM suite saw 565 whole lines missing in one block and no partial line, which is logkeeper's shedding rather than QEMU losing bytes. The wait now accepts any `stick_load: line N` with N >= 1500, so it ends once the load has written past that point, which is what the test needs before it presses the power button. The stick's contents remain the test's assertion. The same Linux KVM suite also went red on two amdvi boots that wrote nothing at all for 63 s, independent of this change. They are recorded in issues/two-amdvi-boots-in-a-kvm-suite-wrote-not-one-byte.md. Co-Authored-By: Claude Opus 5.5 --- ...boots-in-a-kvm-suite-wrote-not-one-byte.md | 30 +++++++++++++++++++ tests/toyos.rs | 13 +++++++- 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 issues/two-amdvi-boots-in-a-kvm-suite-wrote-not-one-byte.md diff --git a/issues/two-amdvi-boots-in-a-kvm-suite-wrote-not-one-byte.md b/issues/two-amdvi-boots-in-a-kvm-suite-wrote-not-one-byte.md new file mode 100644 index 0000000000..7a7acaf43f --- /dev/null +++ b/issues/two-amdvi-boots-in-a-kvm-suite-wrote-not-one-byte.md @@ -0,0 +1,30 @@ +--- +status: open +kind: defect +opened: 2026-10-28 +--- + +# Two amdvi boots in a KVM suite wrote not one byte + +A full `cargo test --test toyos-build` at `0eb2c09d0` on a Linux x86_64 KVM +host went red on `amdvi_selftest` and `amdvi_firmware_left`, and on nothing +else. Both boots used `tests/images/testcases.toml`, finished building in the +same second and timed out together after 63 s. Both reported `the console +carried: nothing at all` and `uart: nothing at all`. So the 16550 file was +empty, without even the firmware's screen-clearing escapes that the netcase +boots in +`issues/a-netcase-boot-under-host-load-said-nothing-past-the-firmwares-screen-clears.md` +wrote. Both tests passed in that host's suites at `e4bdb0a5d` and `7745af98d`. +`7745af98d` differs from `0eb2c09d0` only in a host-side wait inside +`the_log_lands_on_the_boot_stick`. That suite ran alone on the host, and its +load during these boots was not recorded. Log: +https://github.com/ToyOSOrg/evidence/tree/d06821d0cb6e754f1fec16a5921bc4378d9ba600/pr-1107/r2 + +Not reduced: whether QEMU or the firmware ever ran in those boots. A QMP read +of a silent guest's registers would say. No `red-run-serial` file was empty, +so the empty 16550 files were not kept. + +**Exit**: a silent boot's registers read, naming where it stopped, and the fix +at that cause. If it is the netcase boots' cause, fold this record into that one. + +**Owner**: the orchestrator. diff --git a/tests/toyos.rs b/tests/toyos.rs index 9ff6c2ccbe..117b7aac09 100644 --- a/tests/toyos.rs +++ b/tests/toyos.rs @@ -2954,7 +2954,12 @@ fn the_log_lands_on_the_boot_stick(test_config: &Path) -> Result<(), String> { // power button is pressed, as the metal row's deadline finds it. writeln!(qemu.stdin_mut(), "run {}", metal::STICK_LOAD_JOB).map_err(|e| e.to_string())?; qemu.flush_stdin(); - qemu::await_marker(&mut qemu, &mut console, "stick_load: line 1500 ", "the load to write the stick")?; + // Any line past the first 1500, not one exact line: logkeeper sheds its + // oldest console lines when the console falls behind the load. + let from = console.len(); + qemu::await_guest(&mut qemu, &mut console, "the load to write the stick", |log| { + log[from..].lines().any(|l| stick_load_line(l).is_some_and(|n| n >= 1500)) + })?; qemu::QmpShutdown::open(qemu.qmp_socket(), qemu.budget(qemu::GUEST_QUIET)).power_button(); let by = qemu.budget(Duration::from_secs(60)); console.push_str(&qemu.await_exit(by)?); @@ -2981,6 +2986,12 @@ fn the_log_lands_on_the_boot_stick(test_config: &Path) -> Result<(), String> { usb_stopped_before_the_reset(&log, &console) } +fn stick_load_line(line: &str) -> Option { + let (_, rest) = line.split_once("stick_load: line ")?; + let digits = rest.find(|c: char| !c.is_ascii_digit()).unwrap_or(rest.len()); + rest[..digits].parse().ok() +} + /// usbd ended for the stop with every connected port's reset finished and its /// controller halted and reset (its exit code, which the kernel records, /// because its own line may reach no log), and it ended before the kernel's