Merge pull request #165752 from helsinki-systems/feat/test-runner-send-serial
nixos/test-runner: Allow writing to qemu stdin
This commit is contained in:
commit
5a650acbb1
3 changed files with 70 additions and 1 deletions
|
@ -158,6 +158,12 @@ The following methods are available on machine objects:
|
|||
e.g., `send_chars("foobar\n")` will type the string `foobar`
|
||||
followed by the Enter key.
|
||||
|
||||
`send_console`
|
||||
|
||||
: Send keys to the kernel console. This allows interaction with the systemd
|
||||
emergency mode, for example. Takes a string that is sent, e.g.,
|
||||
`send_console("\n\nsystemctl default\n")`.
|
||||
|
||||
`execute`
|
||||
|
||||
: Execute a shell command, returning a list `(status, stdout)`.
|
||||
|
@ -272,6 +278,13 @@ The following methods are available on machine objects:
|
|||
Killing the interactive session with `Ctrl-d` or `Ctrl-c` also ends
|
||||
the guest session.
|
||||
|
||||
`console_interact`
|
||||
|
||||
: Allows you to directly interact with QEMU's stdin. This should
|
||||
only be used during test development, not in production tests.
|
||||
Output from QEMU is only read line-wise. `Ctrl-c` kills QEMU and
|
||||
`Ctrl-d` closes console and returns to the test runner.
|
||||
|
||||
To test user units declared by `systemd.user.services` the optional
|
||||
`user` argument can be used:
|
||||
|
||||
|
|
|
@ -261,6 +261,19 @@ start_all()
|
|||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>send_console</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Send keys to the kernel console. This allows interaction
|
||||
with the systemd emergency mode, for example. Takes a string
|
||||
that is sent, e.g.,
|
||||
<literal>send_console("\n\nsystemctl default\n")</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>execute</literal>
|
||||
|
@ -502,6 +515,21 @@ machine.systemctl("list-jobs --no-pager", "any-user") # spaw
|
|||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<literal>console_interact</literal>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Allows you to directly interact with QEMU’s stdin. This
|
||||
should only be used during test development, not in
|
||||
production tests. Output from QEMU is only read line-wise.
|
||||
<literal>Ctrl-c</literal> kills QEMU and
|
||||
<literal>Ctrl-d</literal> closes console and returns to the
|
||||
test runner.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
<para>
|
||||
To test user units declared by
|
||||
|
|
|
@ -198,7 +198,7 @@ class StartCommand:
|
|||
) -> subprocess.Popen:
|
||||
return subprocess.Popen(
|
||||
self.cmd(monitor_socket_path, shell_socket_path),
|
||||
stdin=subprocess.DEVNULL,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
shell=True,
|
||||
|
@ -558,6 +558,28 @@ class Machine:
|
|||
pass_fds=[self.shell.fileno()],
|
||||
)
|
||||
|
||||
def console_interact(self) -> None:
|
||||
"""Allows you to interact with QEMU's stdin
|
||||
|
||||
The shell can be exited with Ctrl+D. Note that Ctrl+C is not allowed to be used.
|
||||
QEMU's stdout is read line-wise.
|
||||
|
||||
Should only be used during test development, not in the production test."""
|
||||
self.log("Terminal is ready (there is no prompt):")
|
||||
|
||||
assert self.process
|
||||
assert self.process.stdin
|
||||
|
||||
while True:
|
||||
try:
|
||||
char = sys.stdin.buffer.read(1)
|
||||
except KeyboardInterrupt:
|
||||
break
|
||||
if char == b"": # ctrl+d
|
||||
self.log("Closing connection to the console")
|
||||
break
|
||||
self.send_console(char.decode())
|
||||
|
||||
def succeed(self, *commands: str, timeout: Optional[int] = None) -> str:
|
||||
"""Execute each command and check that it succeeds."""
|
||||
output = ""
|
||||
|
@ -834,6 +856,12 @@ class Machine:
|
|||
self.send_monitor_command("sendkey {}".format(key))
|
||||
time.sleep(0.01)
|
||||
|
||||
def send_console(self, chars: str) -> None:
|
||||
assert self.process
|
||||
assert self.process.stdin
|
||||
self.process.stdin.write(chars.encode())
|
||||
self.process.stdin.flush()
|
||||
|
||||
def start(self) -> None:
|
||||
if self.booted:
|
||||
return
|
||||
|
|
Loading…
Reference in a new issue