diff --git a/phd-tests/framework/src/test_vm/mod.rs b/phd-tests/framework/src/test_vm/mod.rs index c251d7f8d..d21d14a32 100644 --- a/phd-tests/framework/src/test_vm/mod.rs +++ b/phd-tests/framework/src/test_vm/mod.rs @@ -148,10 +148,12 @@ pub struct ShellOutput { output: String, } -pub struct ShellOutputExecutor { - fut: Pin>>> +pub struct ShellOutputExecutor<'ctx> { + vm: &'ctx TestVm, + cmd: &'ctx str, } +/* impl ShellOutputExecutor { fn require_ok(self) -> ShellOutputOkExecutor { ShellOutputOkExecutor { @@ -159,6 +161,56 @@ impl ShellOutputExecutor { } } } +*/ + +impl<'a> std::future::IntoFuture for ShellOutputExecutor<'a> { + type Output = Result; + type IntoFuture = Pin>>; + + fn into_future(self) -> Self::IntoFuture { + Box::pin(async move { + // Allow the guest OS to transform the input command into a + // guest-specific command sequence. This accounts for the guest's shell + // type (which affects e.g. affects how it displays multi-line commands) + // and serial console buffering discipline. + let command_sequence = self.vm.guest_os.shell_command_sequence(self.cmd); + self.vm.run_command_sequence(command_sequence).await?; + + // `shell_command_sequence` promises that the generated command sequence + // clears buffer of everything up to and including the input command + // before actually issuing the final '\n' that issues the command. + // This ensures that the buffer contents returned by this call contain + // only the command's output. + let output = self + .vm + .wait_for_serial_output( + self.vm.guest_os.get_shell_prompt(), + Duration::from_secs(300), + ) + .await?; + + let status_command_sequence = + self.vm.guest_os.shell_command_sequence("echo $?"); + self.vm.run_command_sequence(status_command_sequence).await?; + + let status = self + .vm + .wait_for_serial_output( + self.vm.guest_os.get_shell_prompt(), + Duration::from_secs(300), + ) + .await?; + + // Trim any leading newlines inserted when the command was issued and + // any trailing whitespace that isn't actually part of the command + // output. Any other embedded whitespace is the caller's problem. + let output = output.trim().to_string(); + let status = status.trim().parse::()?; + + Ok(ShellOutput { status, output }) + }) + } +} pub struct ShellOutputOkExecutor { fut: Pin>>> @@ -167,13 +219,15 @@ pub struct ShellOutputOkExecutor { use std::pin::Pin; use std::task::Poll; -impl std::future::Future for ShellOutputExecutor { +/* +impl<' std::future::Future for ShellOutputExecutor { type Output = Result; fn poll(mut self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll { self.fut.as_mut().poll(cx) } } +*/ impl std::future::Future for ShellOutputOkExecutor { type Output = Result; @@ -964,49 +1018,10 @@ impl TestVm { // unfortunately I don't know how to plumb the futures for that, since we'd // have to close over `&self`, so doing any Boxing to hold an // `async move {}` immediately causes issues. - pub fn run_shell_command<'a>(&'a self, cmd: &'a str) -> impl std::future::Future> + 'a { - let fut = Box::pin(async move { - // Allow the guest OS to transform the input command into a - // guest-specific command sequence. This accounts for the guest's shell - // type (which affects e.g. affects how it displays multi-line commands) - // and serial console buffering discipline. - let command_sequence = self.guest_os.shell_command_sequence(cmd); - self.run_command_sequence(command_sequence).await?; - - // `shell_command_sequence` promises that the generated command sequence - // clears buffer of everything up to and including the input command - // before actually issuing the final '\n' that issues the command. - // This ensures that the buffer contents returned by this call contain - // only the command's output. - let output = self - .wait_for_serial_output( - self.guest_os.get_shell_prompt(), - Duration::from_secs(300), - ) - .await?; - - let status_command_sequence = - self.guest_os.shell_command_sequence("echo $?"); - self.run_command_sequence(status_command_sequence).await?; - - let status = self - .wait_for_serial_output( - self.guest_os.get_shell_prompt(), - Duration::from_secs(300), - ) - .await?; - - // Trim any leading newlines inserted when the command was issued and - // any trailing whitespace that isn't actually part of the command - // output. Any other embedded whitespace is the caller's problem. - let output = output.trim().to_string(); - let status = status.trim().parse::()?; - - Ok(ShellOutput { status, output }) - }); - + pub fn run_shell_command<'a>(&'a self, cmd: &'a str) -> ShellOutputExecutor<'a> { ShellOutputExecutor { - fut, + vm: self, + cmd, } }