2021-07-02 20:24:02 +08:00
|
|
|
# Running Tests interactively {#sec-running-nixos-tests-interactively}
|
|
|
|
|
|
|
|
The test itself can be run interactively. This is particularly useful
|
|
|
|
when developing or debugging a test:
|
|
|
|
|
|
|
|
```ShellSession
|
2022-01-02 23:48:56 +01:00
|
|
|
$ nix-build . -A nixosTests.login.driverInteractive
|
2022-01-25 13:45:49 +01:00
|
|
|
$ ./result/bin/nixos-test-driver
|
2022-01-02 23:48:56 +01:00
|
|
|
[...]
|
|
|
|
>>>
|
2021-07-02 20:24:02 +08:00
|
|
|
```
|
|
|
|
|
2024-08-31 14:18:42 +00:00
|
|
|
::: {.note}
|
|
|
|
By executing the test driver in this way,
|
|
|
|
the VMs executed may gain network & Internet access via their backdoor control interface,
|
|
|
|
typically recognized as `eth0`.
|
|
|
|
:::
|
|
|
|
|
2021-07-02 20:24:02 +08:00
|
|
|
You can then take any Python statement, e.g.
|
|
|
|
|
|
|
|
```py
|
2022-01-02 23:48:56 +01:00
|
|
|
>>> start_all()
|
|
|
|
>>> test_script()
|
|
|
|
>>> machine.succeed("touch /tmp/foo")
|
|
|
|
>>> print(machine.succeed("pwd")) # Show stdout of command
|
2021-07-02 20:24:02 +08:00
|
|
|
```
|
|
|
|
|
|
|
|
The function `test_script` executes the entire test script and drops you
|
|
|
|
back into the test driver command line upon its completion. This allows
|
|
|
|
you to inspect the state of the VMs after the test (e.g. to debug the
|
|
|
|
test script).
|
|
|
|
|
2022-06-20 14:48:38 +02:00
|
|
|
## Shell access in interactive mode {#sec-nixos-test-shell-access}
|
|
|
|
|
|
|
|
The function `<yourmachine>.shell_interact()` grants access to a shell running
|
|
|
|
inside a virtual machine. To use it, replace `<yourmachine>` with the name of a
|
|
|
|
virtual machine defined in the test, for example: `machine.shell_interact()`.
|
|
|
|
Keep in mind that this shell may not display everything correctly as it is
|
|
|
|
running within an interactive Python REPL, and logging output from the virtual
|
|
|
|
machine may overwrite input and output from the guest shell:
|
|
|
|
|
|
|
|
```py
|
|
|
|
>>> machine.shell_interact()
|
|
|
|
machine: Terminal is ready (there is no initial prompt):
|
|
|
|
$ hostname
|
|
|
|
machine
|
|
|
|
```
|
|
|
|
|
|
|
|
As an alternative, you can proxy the guest shell to a local TCP server by first
|
|
|
|
starting a TCP server in a terminal using the command:
|
|
|
|
|
|
|
|
```ShellSession
|
2024-06-07 14:04:00 -03:00
|
|
|
$ socat 'READLINE,PROMPT=$ ' tcp-listen:4444,reuseaddr
|
2022-06-20 14:48:38 +02:00
|
|
|
```
|
|
|
|
|
|
|
|
In the terminal where the test driver is running, connect to this server by
|
|
|
|
using:
|
|
|
|
|
|
|
|
```py
|
|
|
|
>>> machine.shell_interact("tcp:127.0.0.1:4444")
|
|
|
|
```
|
|
|
|
|
|
|
|
Once the connection is established, you can enter commands in the socat terminal
|
|
|
|
where socat is running.
|
|
|
|
|
2025-03-21 17:14:23 +00:00
|
|
|
## SSH Access for test machines {#sec-nixos-test-ssh-access}
|
|
|
|
|
|
|
|
An SSH-based backdoor to log into machines can be enabled with
|
|
|
|
|
|
|
|
```nix
|
|
|
|
{
|
|
|
|
name = "…";
|
|
|
|
nodes.machines = { /* … */ };
|
2025-05-12 15:27:24 +02:00
|
|
|
interactive.sshBackdoor.enable = true;
|
2025-03-21 17:14:23 +00:00
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2025-05-12 15:27:24 +02:00
|
|
|
::: {.warning}
|
|
|
|
Make sure to only enable the backdoor for interactive tests
|
|
|
|
(i.e. by using `interactive.sshBackdoor.enable`)! This is the only
|
|
|
|
supported configuration.
|
|
|
|
|
|
|
|
Running a test in a sandbox with this will fail because `/dev/vhost-vsock` isn't available
|
|
|
|
in the sandbox.
|
|
|
|
:::
|
|
|
|
|
2025-03-21 17:14:23 +00:00
|
|
|
This creates a [vsock socket](https://man7.org/linux/man-pages/man7/vsock.7.html)
|
|
|
|
for each VM to log in with SSH. This configures root login with an empty password.
|
|
|
|
|
|
|
|
When the VMs get started interactively with the test-driver, it's possible to
|
|
|
|
connect to `machine` with
|
|
|
|
|
|
|
|
```
|
|
|
|
$ ssh vsock/3 -o User=root
|
|
|
|
```
|
|
|
|
|
|
|
|
The socket numbers correspond to the node number of the test VM, but start
|
|
|
|
at three instead of one because that's the lowest possible
|
2025-05-09 10:07:15 +02:00
|
|
|
vsock number. The exact SSH commands are also printed out when starting
|
|
|
|
`nixos-test-driver`.
|
2025-03-21 17:14:23 +00:00
|
|
|
|
|
|
|
On non-NixOS systems you'll probably need to enable
|
|
|
|
the SSH config from {manpage}`systemd-ssh-proxy(1)` yourself.
|
|
|
|
|
2025-05-09 10:07:15 +02:00
|
|
|
If starting VM fails with an error like
|
|
|
|
|
|
|
|
```
|
|
|
|
qemu-system-x86_64: -device vhost-vsock-pci,guest-cid=3: vhost-vsock: unable to set guest cid: Address already in use
|
|
|
|
```
|
|
|
|
|
|
|
|
it means that the vsock numbers for the VMs are already in use. This can happen
|
|
|
|
if another interactive test with SSH backdoor enabled is running on the machine.
|
|
|
|
|
|
|
|
In that case, you need to assign another range of vsock numbers. You can pick another
|
|
|
|
offset with
|
|
|
|
|
|
|
|
```nix
|
|
|
|
{
|
|
|
|
sshBackdoor = {
|
|
|
|
enable = true;
|
|
|
|
vsockOffset = 23542;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2023-11-10 18:46:54 +01:00
|
|
|
## Port forwarding to NixOS test VMs {#sec-nixos-test-port-forwarding}
|
|
|
|
|
|
|
|
If your test has only a single VM, you may use e.g.
|
|
|
|
|
|
|
|
```ShellSession
|
2023-11-11 01:22:13 +01:00
|
|
|
$ QEMU_NET_OPTS="hostfwd=tcp:127.0.0.1:2222-:22" ./result/bin/nixos-test-driver
|
2023-11-10 18:46:54 +01:00
|
|
|
```
|
|
|
|
|
|
|
|
to port-forward a port in the VM (here `22`) to the host machine (here port `2222`).
|
|
|
|
|
|
|
|
This naturally does not work when multiple machines are involved,
|
|
|
|
since a single port on the host cannot forward to multiple VMs.
|
|
|
|
|
|
|
|
If the test defines multiple machines, you may opt to _temporarily_ set
|
|
|
|
`virtualisation.forwardPorts` in the test definition for debugging.
|
|
|
|
|
2023-11-11 01:22:13 +01:00
|
|
|
Such port forwardings connect via the VM's virtual network interface.
|
|
|
|
Thus they cannot connect to ports that are only bound to the VM's
|
|
|
|
loopback interface (`127.0.0.1`), and the VM's NixOS firewall
|
|
|
|
must be configured to allow these connections.
|
|
|
|
|
2022-06-15 18:04:41 +02:00
|
|
|
## Reuse VM state {#sec-nixos-test-reuse-vm-state}
|
|
|
|
|
2021-07-02 20:24:02 +08:00
|
|
|
You can re-use the VM states coming from a previous run by setting the
|
|
|
|
`--keep-vm-state` flag.
|
|
|
|
|
|
|
|
```ShellSession
|
2022-01-25 13:45:49 +01:00
|
|
|
$ ./result/bin/nixos-test-driver --keep-vm-state
|
2021-07-02 20:24:02 +08:00
|
|
|
```
|
|
|
|
|
|
|
|
The machine state is stored in the `$TMPDIR/vm-state-machinename`
|
|
|
|
directory.
|
2022-06-15 18:04:41 +02:00
|
|
|
|
|
|
|
## Interactive-only test configuration {#sec-nixos-test-interactive-configuration}
|
|
|
|
|
2022-08-19 12:09:58 +02:00
|
|
|
The `.driverInteractive` attribute combines the regular test configuration with
|
2022-09-29 12:41:59 +02:00
|
|
|
definitions from the [`interactive` submodule](#test-opt-interactive). This gives you
|
2022-08-19 12:09:58 +02:00
|
|
|
a more usable, graphical, but slightly different configuration.
|
|
|
|
|
|
|
|
You can add your own interactive-only test configuration by adding extra
|
2022-09-29 12:41:59 +02:00
|
|
|
configuration to the [`interactive` submodule](#test-opt-interactive).
|
2022-08-19 12:09:58 +02:00
|
|
|
|
|
|
|
To interactively run only the regular configuration, build the `<test>.driver` attribute
|
|
|
|
instead, and call it with the flag `result/bin/nixos-test-driver --interactive`.
|