Skip to content

Commit

Permalink
phd: gate OS-specific tests, make others more OS-agnostic
Browse files Browse the repository at this point in the history
some smoketests instigated a graceful reboot by sending `reboot\n` to
the serial console, but Windows guests are rewarded (via Cygwin) with

```
bash: reboot: command not found
```

as of #785 there is now a TestVm helper `graceful_reboot` that does this
in whatever way the guest adapter desires, so use that instead.

unfortunately `graceful_reboot` is only mostly right for Windows guests,
so fix that here too: `shutdown` immediately terminates the cmd.exe
session, at which point the SAC redraws the previous screen, which
happens to have all the sigils we look for to detect that Windows has
freshly booted. we then log back into the imminently-shutdown Windows,
shutdown takes effect, and PHD becomes fully desynchronized from the
guest state.

so, look for "BdsDxe: loading " as an outside-the-guest-OS sigil that
tells us we're watching a fresh boot. this comes from OVMF, so a booted
guest will have clobbered the message and not know to redraw it even if
it seeks to recreate a previous display.

other tests depend on Linux-specific features like `efivarfs` or
`mount -o ro`, so skip them on non-Linux guests.
  • Loading branch information
iximeow committed Oct 19, 2024
1 parent ea01303 commit 5e32408
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 8 deletions.
24 changes: 24 additions & 0 deletions phd-tests/framework/src/guest_os/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,30 @@ pub enum GuestOsKind {
WindowsServer2022,
}

impl GuestOsKind {
pub fn is_linux(&self) -> bool {
match self {
GuestOsKind::Alpine
| GuestOsKind::Debian11NoCloud
| GuestOsKind::Ubuntu2204 => true,
GuestOsKind::WindowsServer2016
| GuestOsKind::WindowsServer2019
| GuestOsKind::WindowsServer2022 => false,
}
}

pub fn is_windows(&self) -> bool {
match self {
GuestOsKind::WindowsServer2016
| GuestOsKind::WindowsServer2019
| GuestOsKind::WindowsServer2022 => true,
GuestOsKind::Alpine
| GuestOsKind::Debian11NoCloud
| GuestOsKind::Ubuntu2204 => false,
}
}
}

impl FromStr for GuestOsKind {
type Err = std::io::Error;

Expand Down
16 changes: 16 additions & 0 deletions phd-tests/framework/src/guest_os/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,22 @@ pub(super) fn get_login_sequence_for<'a>(
));

let mut commands = vec![
// Look for `BdsDxe:` as a sign that we're actually seeing a fresh boot.
// This is not terribly important in the case of a first boot, but in a
// case such as logging out and waiting for reboot, exiting a cmd.exe
// session causes Windows to redraw its previous screen - everything
// past `Computer is booting, ...` below.
//
// A test that tries to boot and wait for a new login sequence would
// then incorrectly identify the already-booted VM as the freshly-booted
// OS it was waiting for, log in again, and at some point later finally
// actually reboot.
//
// At least on Windows Server 2022, there is an XML prelude that is
// printed to COM1 that we could look for here, but check for `BdsDxe: `
// instead as that comes from OVMF and will be consistent regardless of
// guest OS version.
CommandSequenceEntry::wait_for("BdsDxe: loading "),
CommandSequenceEntry::wait_for(
"Computer is booting, SAC started and initialized.",
),
Expand Down
12 changes: 12 additions & 0 deletions phd-tests/tests/src/boot_order.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ async fn configurable_boot_order(ctx: &Framework) {
// We haven't specified a boot order. So, we'll expect that we boot to the
// lower-numbered PCI device (4) and end up in Alpine 3.20.
let mut vm = ctx.spawn_vm(&cfg, None).await?;
if !vm.guest_os_kind().is_linux() {
phd_skip!("boot order tests require efivarfs to manipulate UEFI vars");
}
vm.launch().await?;
vm.wait_to_boot().await?;

Expand Down Expand Up @@ -162,6 +165,9 @@ async fn unbootable_disk_skipped(ctx: &Framework) {
cfg.boot_order(vec!["unbootable", "boot-disk"]);

let mut vm = ctx.spawn_vm(&cfg, None).await?;
if !vm.guest_os_kind().is_linux() {
phd_skip!("boot order tests require efivarfs to manipulate UEFI vars");
}
vm.launch().await?;
vm.wait_to_boot().await?;

Expand Down Expand Up @@ -279,6 +285,9 @@ async fn guest_can_adjust_boot_order(ctx: &Framework) {
cfg.boot_order(vec!["boot-disk", "unbootable"]);

let mut vm = ctx.spawn_vm(&cfg, None).await?;
if !vm.guest_os_kind().is_linux() {
phd_skip!("boot order tests require efivarfs to manipulate UEFI vars");
}
vm.launch().await?;
vm.wait_to_boot().await?;

Expand Down Expand Up @@ -446,6 +455,9 @@ async fn boot_order_source_priority(ctx: &Framework) {
cfg.clear_boot_order();

let mut vm_no_bootorder = ctx.spawn_vm(&cfg, None).await?;
if !vm_no_bootorder.guest_os_kind().is_linux() {
phd_skip!("boot order tests require efivarfs to manipulate UEFI vars");
}
vm_no_bootorder.launch().await?;
vm_no_bootorder.wait_to_boot().await?;

Expand Down
5 changes: 1 addition & 4 deletions phd-tests/tests/src/crucible/smoke.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,7 @@ async fn guest_reboot_test(ctx: &Framework) {
vm.launch().await?;
vm.wait_to_boot().await?;

// Don't use `run_shell_command` because the guest won't echo another prompt
// after this.
vm.send_serial_str("reboot\n").await?;
vm.wait_to_boot().await?;
vm.graceful_reboot().await?;
}

#[phd_testcase]
Expand Down
3 changes: 3 additions & 0 deletions phd-tests/tests/src/disk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ async fn in_memory_backend_smoke_test(ctx: &Framework) {
);

let mut vm = ctx.spawn_vm(&cfg, None).await?;
if vm.guest_os_kind().is_windows() {
phd_skip!("this test uses mount options not supported by Cygwin");
}
vm.launch().await?;
vm.wait_to_boot().await?;

Expand Down
5 changes: 1 addition & 4 deletions phd-tests/tests/src/smoke.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,7 @@ async fn guest_reboot_test(ctx: &Framework) {
vm.launch().await?;
vm.wait_to_boot().await?;

// Don't use `run_shell_command` because the guest won't echo another prompt
// after this.
vm.send_serial_str("reboot\n").await?;
vm.wait_to_boot().await?;
vm.graceful_reboot().await?;
}

#[phd_testcase]
Expand Down

0 comments on commit 5e32408

Please sign in to comment.