about summary refs log tree commit diff
path: root/nixpkgs/nixos/doc/manual/development
diff options
context:
space:
mode:
authorAlyssa Ross <hi@alyssa.is>2021-07-09 12:30:28 +0000
committerAlyssa Ross <hi@alyssa.is>2021-07-23 09:11:31 +0000
commit55cc63c079f49e81d695a25bc2f5b3902f2bd290 (patch)
treee705335d97f50b927c76ccb4a3fbde9fab8372b9 /nixpkgs/nixos/doc/manual/development
parentc26eb6f74d9393127a21eee7a9620a920769f613 (diff)
parent87807e64a5ef5206b745a40af118c7be8db73681 (diff)
downloadnixlib-55cc63c079f49e81d695a25bc2f5b3902f2bd290.tar
nixlib-55cc63c079f49e81d695a25bc2f5b3902f2bd290.tar.gz
nixlib-55cc63c079f49e81d695a25bc2f5b3902f2bd290.tar.bz2
nixlib-55cc63c079f49e81d695a25bc2f5b3902f2bd290.tar.lz
nixlib-55cc63c079f49e81d695a25bc2f5b3902f2bd290.tar.xz
nixlib-55cc63c079f49e81d695a25bc2f5b3902f2bd290.tar.zst
nixlib-55cc63c079f49e81d695a25bc2f5b3902f2bd290.zip
Merge commit '87807e64a5ef5206b745a40af118c7be8db73681'
Diffstat (limited to 'nixpkgs/nixos/doc/manual/development')
-rw-r--r--nixpkgs/nixos/doc/manual/development/nixos-tests.xml6
-rw-r--r--nixpkgs/nixos/doc/manual/development/running-nixos-tests-interactively.section.md44
-rw-r--r--nixpkgs/nixos/doc/manual/development/running-nixos-tests-interactively.xml49
-rw-r--r--nixpkgs/nixos/doc/manual/development/running-nixos-tests.section.md31
-rw-r--r--nixpkgs/nixos/doc/manual/development/running-nixos-tests.xml36
-rw-r--r--nixpkgs/nixos/doc/manual/development/writing-nixos-tests.section.md301
-rw-r--r--nixpkgs/nixos/doc/manual/development/writing-nixos-tests.xml517
7 files changed, 379 insertions, 605 deletions
diff --git a/nixpkgs/nixos/doc/manual/development/nixos-tests.xml b/nixpkgs/nixos/doc/manual/development/nixos-tests.xml
index 2695082e3867..702fc03f6686 100644
--- a/nixpkgs/nixos/doc/manual/development/nixos-tests.xml
+++ b/nixpkgs/nixos/doc/manual/development/nixos-tests.xml
@@ -13,7 +13,7 @@ xlink:href="https://github.com/NixOS/nixpkgs/tree/master/nixos/tests">nixos/test
   one or more virtual machines containing the NixOS system(s) required for the
   test.
  </para>
- <xi:include href="writing-nixos-tests.xml" />
- <xi:include href="running-nixos-tests.xml" />
- <xi:include href="running-nixos-tests-interactively.xml" />
+ <xi:include href="../from_md/development/writing-nixos-tests.section.xml" />
+ <xi:include href="../from_md/development/running-nixos-tests.section.xml" />
+ <xi:include href="../from_md/development/running-nixos-tests-interactively.section.xml" />
 </chapter>
diff --git a/nixpkgs/nixos/doc/manual/development/running-nixos-tests-interactively.section.md b/nixpkgs/nixos/doc/manual/development/running-nixos-tests-interactively.section.md
new file mode 100644
index 000000000000..3ba4e16e77f4
--- /dev/null
+++ b/nixpkgs/nixos/doc/manual/development/running-nixos-tests-interactively.section.md
@@ -0,0 +1,44 @@
+# 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
+$ nix-build nixos/tests/login.nix -A driverInteractive
+$ ./result/bin/nixos-test-driver
+starting VDE switch for network 1
+>
+```
+
+You can then take any Python statement, e.g.
+
+```py
+> start_all()
+> test_script()
+> machine.succeed("touch /tmp/foo")
+> print(machine.succeed("pwd")) # Show stdout of command
+```
+
+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).
+
+To just start and experiment with the VMs, run:
+
+```ShellSession
+$ nix-build nixos/tests/login.nix -A driverInteractive
+$ ./result/bin/nixos-run-vms
+```
+
+The script `nixos-run-vms` starts the virtual machines defined by test.
+
+You can re-use the VM states coming from a previous run by setting the
+`--keep-vm-state` flag.
+
+```ShellSession
+$ ./result/bin/nixos-run-vms --keep-vm-state
+```
+
+The machine state is stored in the `$TMPDIR/vm-state-machinename`
+directory.
diff --git a/nixpkgs/nixos/doc/manual/development/running-nixos-tests-interactively.xml b/nixpkgs/nixos/doc/manual/development/running-nixos-tests-interactively.xml
deleted file mode 100644
index a6044d5f89e8..000000000000
--- a/nixpkgs/nixos/doc/manual/development/running-nixos-tests-interactively.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<section xmlns="http://docbook.org/ns/docbook"
-        xmlns:xlink="http://www.w3.org/1999/xlink"
-        xmlns:xi="http://www.w3.org/2001/XInclude"
-        version="5.0"
-        xml:id="sec-running-nixos-tests-interactively">
- <title>Running Tests interactively</title>
-
- <para>
-  The test itself can be run interactively. This is particularly useful when
-  developing or debugging a test:
-<screen>
-<prompt>$ </prompt>nix-build nixos/tests/login.nix -A driverInteractive
-<prompt>$ </prompt>./result/bin/nixos-test-driver
-starting VDE switch for network 1
-<prompt>&gt;</prompt>
-</screen>
-  You can then take any Python statement, e.g.
-<screen>
-<prompt>&gt;</prompt> start_all()
-<prompt>&gt;</prompt> test_script()
-<prompt>&gt;</prompt> machine.succeed("touch /tmp/foo")
-<prompt>&gt;</prompt> print(machine.succeed("pwd")) # Show stdout of command
-</screen>
-  The function <command>test_script</command> 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).
- </para>
-
- <para>
-  To just start and experiment with the VMs, run:
-<screen>
-<prompt>$ </prompt>nix-build nixos/tests/login.nix -A driverInteractive
-<prompt>$ </prompt>./result/bin/nixos-run-vms
-</screen>
-  The script <command>nixos-run-vms</command> starts the virtual machines
-  defined by test.
- </para>
-
- <para>
-   You can re-use the VM states coming from a previous run
-   by setting the <command>--keep-vm-state</command> flag.
-<screen>
-<prompt>$ </prompt>./result/bin/nixos-run-vms --keep-vm-state
-</screen>
-  The machine state is stored in the
-  <filename>$TMPDIR/vm-state-</filename><varname>machinename</varname> directory.
- </para>
-</section>
diff --git a/nixpkgs/nixos/doc/manual/development/running-nixos-tests.section.md b/nixpkgs/nixos/doc/manual/development/running-nixos-tests.section.md
new file mode 100644
index 000000000000..d6a456f01883
--- /dev/null
+++ b/nixpkgs/nixos/doc/manual/development/running-nixos-tests.section.md
@@ -0,0 +1,31 @@
+# Running Tests {#sec-running-nixos-tests}
+
+You can run tests using `nix-build`. For example, to run the test
+[`login.nix`](https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/login.nix),
+you just do:
+
+```ShellSession
+$ nix-build '<nixpkgs/nixos/tests/login.nix>'
+```
+
+or, if you don't want to rely on `NIX_PATH`:
+
+```ShellSession
+$ cd /my/nixpkgs/nixos/tests
+$ nix-build login.nix
+…
+running the VM test script
+machine: QEMU running (pid 8841)
+…
+6 out of 6 tests succeeded
+```
+
+After building/downloading all required dependencies, this will perform
+a build that starts a QEMU/KVM virtual machine containing a NixOS
+system. The virtual machine mounts the Nix store of the host; this makes
+VM creation very fast, as no disk image needs to be created. Afterwards,
+you can view a pretty-printed log of the test:
+
+```ShellSession
+$ firefox result/log.html
+```
diff --git a/nixpkgs/nixos/doc/manual/development/running-nixos-tests.xml b/nixpkgs/nixos/doc/manual/development/running-nixos-tests.xml
deleted file mode 100644
index e9257c907daf..000000000000
--- a/nixpkgs/nixos/doc/manual/development/running-nixos-tests.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<section xmlns="http://docbook.org/ns/docbook"
-        xmlns:xlink="http://www.w3.org/1999/xlink"
-        xmlns:xi="http://www.w3.org/2001/XInclude"
-        version="5.0"
-        xml:id="sec-running-nixos-tests">
- <title>Running Tests</title>
-
- <para>
-  You can run tests using <command>nix-build</command>. For example, to run the
-  test
-  <filename
-xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/login.nix">login.nix</filename>,
-  you just do:
-<screen>
-<prompt>$ </prompt>nix-build '&lt;nixpkgs/nixos/tests/login.nix>'
-</screen>
-  or, if you don’t want to rely on <envar>NIX_PATH</envar>:
-<screen>
-<prompt>$ </prompt>cd /my/nixpkgs/nixos/tests
-<prompt>$ </prompt>nix-build login.nix
-…
-running the VM test script
-machine: QEMU running (pid 8841)
-…
-6 out of 6 tests succeeded
-</screen>
-  After building/downloading all required dependencies, this will perform a
-  build that starts a QEMU/KVM virtual machine containing a NixOS system. The
-  virtual machine mounts the Nix store of the host; this makes VM creation very
-  fast, as no disk image needs to be created. Afterwards, you can view a
-  pretty-printed log of the test:
-<screen>
-<prompt>$ </prompt>firefox result/log.html
-</screen>
- </para>
-</section>
diff --git a/nixpkgs/nixos/doc/manual/development/writing-nixos-tests.section.md b/nixpkgs/nixos/doc/manual/development/writing-nixos-tests.section.md
new file mode 100644
index 000000000000..8471e7608af9
--- /dev/null
+++ b/nixpkgs/nixos/doc/manual/development/writing-nixos-tests.section.md
@@ -0,0 +1,301 @@
+# Writing Tests {#sec-writing-nixos-tests}
+
+A NixOS test is a Nix expression that has the following structure:
+
+```nix
+import ./make-test-python.nix {
+
+  # Either the configuration of a single machine:
+  machine =
+    { config, pkgs, ... }:
+    { configuration…
+    };
+
+  # Or a set of machines:
+  nodes =
+    { machine1 =
+        { config, pkgs, ... }: { … };
+      machine2 =
+        { config, pkgs, ... }: { … };
+      …
+    };
+
+  testScript =
+    ''
+      Python code…
+    '';
+}
+```
+
+The attribute `testScript` is a bit of Python code that executes the
+test (described below). During the test, it will start one or more
+virtual machines, the configuration of which is described by the
+attribute `machine` (if you need only one machine in your test) or by
+the attribute `nodes` (if you need multiple machines). For instance,
+[`login.nix`](https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/login.nix)
+only needs a single machine to test whether users can log in
+on the virtual console, whether device ownership is correctly maintained
+when switching between consoles, and so on. On the other hand,
+[`nfs/simple.nix`](https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/nfs/simple.nix),
+which tests NFS client and server functionality in the
+Linux kernel (including whether locks are maintained across server
+crashes), requires three machines: a server and two clients.
+
+There are a few special NixOS configuration options for test VMs:
+
+`virtualisation.memorySize`
+
+:   The memory of the VM in megabytes.
+
+`virtualisation.vlans`
+
+:   The virtual networks to which the VM is connected. See
+    [`nat.nix`](https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/nat.nix)
+    for an example.
+
+`virtualisation.writableStore`
+
+:   By default, the Nix store in the VM is not writable. If you enable
+    this option, a writable union file system is mounted on top of the
+    Nix store to make it appear writable. This is necessary for tests
+    that run Nix operations that modify the store.
+
+For more options, see the module
+[`qemu-vm.nix`](https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/virtualisation/qemu-vm.nix).
+
+The test script is a sequence of Python statements that perform various
+actions, such as starting VMs, executing commands in the VMs, and so on.
+Each virtual machine is represented as an object stored in the variable
+`name` if this is also the identifier of the machine in the declarative
+config. If you didn\'t specify multiple machines using the `nodes`
+attribute, it is just `machine`. The following example starts the
+machine, waits until it has finished booting, then executes a command
+and checks that the output is more-or-less correct:
+
+```py
+machine.start()
+machine.wait_for_unit("default.target")
+if not "Linux" in machine.succeed("uname"):
+  raise Exception("Wrong OS")
+```
+
+The first line is actually unnecessary; machines are implicitly started
+when you first execute an action on them (such as `wait_for_unit` or
+`succeed`). If you have multiple machines, you can speed up the test by
+starting them in parallel:
+
+```py
+start_all()
+```
+
+The following methods are available on machine objects:
+
+`start`
+
+:   Start the virtual machine. This method is asynchronous --- it does
+    not wait for the machine to finish booting.
+
+`shutdown`
+
+:   Shut down the machine, waiting for the VM to exit.
+
+`crash`
+
+:   Simulate a sudden power failure, by telling the VM to exit
+    immediately.
+
+`block`
+
+:   Simulate unplugging the Ethernet cable that connects the machine to
+    the other machines.
+
+`unblock`
+
+:   Undo the effect of `block`.
+
+`screenshot`
+
+:   Take a picture of the display of the virtual machine, in PNG format.
+    The screenshot is linked from the HTML log.
+
+`get_screen_text_variants`
+
+:   Return a list of different interpretations of what is currently
+    visible on the machine\'s screen using optical character
+    recognition. The number and order of the interpretations is not
+    specified and is subject to change, but if no exception is raised at
+    least one will be returned.
+
+    ::: {.note}
+    This requires passing `enableOCR` to the test attribute set.
+    :::
+
+`get_screen_text`
+
+:   Return a textual representation of what is currently visible on the
+    machine\'s screen using optical character recognition.
+
+    ::: {.note}
+    This requires passing `enableOCR` to the test attribute set.
+    :::
+
+`send_monitor_command`
+
+:   Send a command to the QEMU monitor. This is rarely used, but allows
+    doing stuff such as attaching virtual USB disks to a running
+    machine.
+
+`send_key`
+
+:   Simulate pressing keys on the virtual keyboard, e.g.,
+    `send_key("ctrl-alt-delete")`.
+
+`send_chars`
+
+:   Simulate typing a sequence of characters on the virtual keyboard,
+    e.g., `send_chars("foobar\n")` will type the string `foobar`
+    followed by the Enter key.
+
+`execute`
+
+:   Execute a shell command, returning a list `(status, stdout)`.
+
+`succeed`
+
+:   Execute a shell command, raising an exception if the exit status is
+    not zero, otherwise returning the standard output. Commands are run
+    with `set -euo pipefail` set:
+
+    -   If several commands are separated by `;` and one fails, the
+        command as a whole will fail.
+
+    -   For pipelines, the last non-zero exit status will be returned
+        (if there is one, zero will be returned otherwise).
+
+    -   Dereferencing unset variables fail the command.
+
+`fail`
+
+:   Like `succeed`, but raising an exception if the command returns a zero
+    status.
+
+`wait_until_succeeds`
+
+:   Repeat a shell command with 1-second intervals until it succeeds.
+
+`wait_until_fails`
+
+:   Repeat a shell command with 1-second intervals until it fails.
+
+`wait_for_unit`
+
+:   Wait until the specified systemd unit has reached the "active"
+    state.
+
+`wait_for_file`
+
+:   Wait until the specified file exists.
+
+`wait_for_open_port`
+
+:   Wait until a process is listening on the given TCP port (on
+    `localhost`, at least).
+
+`wait_for_closed_port`
+
+:   Wait until nobody is listening on the given TCP port.
+
+`wait_for_x`
+
+:   Wait until the X11 server is accepting connections.
+
+`wait_for_text`
+
+:   Wait until the supplied regular expressions matches the textual
+    contents of the screen by using optical character recognition (see
+    `get_screen_text` and `get_screen_text_variants`).
+
+    ::: {.note}
+    This requires passing `enableOCR` to the test attribute set.
+    :::
+
+`wait_for_console_text`
+
+:   Wait until the supplied regular expressions match a line of the
+    serial console output. This method is useful when OCR is not
+    possibile or accurate enough.
+
+`wait_for_window`
+
+:   Wait until an X11 window has appeared whose name matches the given
+    regular expression, e.g., `wait_for_window("Terminal")`.
+
+`copy_from_host`
+
+:   Copies a file from host to machine, e.g.,
+    `copy_from_host("myfile", "/etc/my/important/file")`.
+
+    The first argument is the file on the host. The file needs to be
+    accessible while building the nix derivation. The second argument is
+    the location of the file on the machine.
+
+`systemctl`
+
+:   Runs `systemctl` commands with optional support for
+    `systemctl --user`
+
+    ```py
+    machine.systemctl("list-jobs --no-pager") # runs `systemctl list-jobs --no-pager`
+    machine.systemctl("list-jobs --no-pager", "any-user") # spawns a shell for `any-user` and runs `systemctl --user list-jobs --no-pager`
+    ```
+
+`shell_interact`
+
+:   Allows you to directly interact with the guest shell. This should
+    only be used during test development, not in production tests.
+    Killing the interactive session with `Ctrl-d` or `Ctrl-c` also ends
+    the guest session.
+
+To test user units declared by `systemd.user.services` the optional
+`user` argument can be used:
+
+```py
+machine.start()
+machine.wait_for_x()
+machine.wait_for_unit("xautolock.service", "x-session-user")
+```
+
+This applies to `systemctl`, `get_unit_info`, `wait_for_unit`,
+`start_job` and `stop_job`.
+
+For faster dev cycles it\'s also possible to disable the code-linters
+(this shouldn\'t be commited though):
+
+```nix
+import ./make-test-python.nix {
+  skipLint = true;
+  machine =
+    { config, pkgs, ... }:
+    { configuration…
+    };
+
+  testScript =
+    ''
+      Python code…
+    '';
+}
+```
+
+This will produce a Nix warning at evaluation time. To fully disable the
+linter, wrap the test script in comment directives to disable the Black
+linter directly (again, don\'t commit this within the Nixpkgs
+repository):
+
+```nix
+  testScript =
+    ''
+      # fmt: off
+      Python code…
+      # fmt: on
+    '';
+```
diff --git a/nixpkgs/nixos/doc/manual/development/writing-nixos-tests.xml b/nixpkgs/nixos/doc/manual/development/writing-nixos-tests.xml
deleted file mode 100644
index e372c66410de..000000000000
--- a/nixpkgs/nixos/doc/manual/development/writing-nixos-tests.xml
+++ /dev/null
@@ -1,517 +0,0 @@
-<section xmlns="http://docbook.org/ns/docbook"
-        xmlns:xlink="http://www.w3.org/1999/xlink"
-        xmlns:xi="http://www.w3.org/2001/XInclude"
-        version="5.0"
-        xml:id="sec-writing-nixos-tests">
- <title>Writing Tests</title>
-
- <para>
-  A NixOS test is a Nix expression that has the following structure:
-<programlisting>
-import ./make-test-python.nix {
-
-  # Either the configuration of a single machine:
-  machine =
-    { config, pkgs, ... }:
-    { <replaceable>configuration…</replaceable>
-    };
-
-  # Or a set of machines:
-  nodes =
-    { <replaceable>machine1</replaceable> =
-        { config, pkgs, ... }: { <replaceable>…</replaceable> };
-      <replaceable>machine2</replaceable> =
-        { config, pkgs, ... }: { <replaceable>…</replaceable> };
-      …
-    };
-
-  testScript =
-    ''
-      <replaceable>Python code…</replaceable>
-    '';
-}
-</programlisting>
-  The attribute <literal>testScript</literal> is a bit of Python code that
-  executes the test (described below). During the test, it will start one or
-  more virtual machines, the configuration of which is described by the
-  attribute <literal>machine</literal> (if you need only one machine in your
-  test) or by the attribute <literal>nodes</literal> (if you need multiple
-  machines). For instance,
-  <filename
-xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/login.nix">login.nix</filename>
-  only needs a single machine to test whether users can log in on the virtual
-  console, whether device ownership is correctly maintained when switching
-  between consoles, and so on. On the other hand,
-  <filename
-xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/nfs/simple.nix">nfs/simple.nix</filename>,
-  which tests NFS client and server functionality in the Linux kernel
-  (including whether locks are maintained across server crashes), requires
-  three machines: a server and two clients.
- </para>
-
- <para>
-  There are a few special NixOS configuration options for test VMs:
-<!-- FIXME: would be nice to generate this automatically. -->
-  <variablelist>
-   <varlistentry>
-    <term>
-     <option>virtualisation.memorySize</option>
-    </term>
-    <listitem>
-     <para>
-      The memory of the VM in megabytes.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <option>virtualisation.vlans</option>
-    </term>
-    <listitem>
-     <para>
-      The virtual networks to which the VM is connected. See
-      <filename
-    xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/nat.nix">nat.nix</filename>
-      for an example.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <option>virtualisation.writableStore</option>
-    </term>
-    <listitem>
-     <para>
-      By default, the Nix store in the VM is not writable. If you enable this
-      option, a writable union file system is mounted on top of the Nix store
-      to make it appear writable. This is necessary for tests that run Nix
-      operations that modify the store.
-     </para>
-    </listitem>
-   </varlistentry>
-  </variablelist>
-  For more options, see the module
-  <filename
-xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/virtualisation/qemu-vm.nix">qemu-vm.nix</filename>.
- </para>
-
- <para>
-  The test script is a sequence of Python statements that perform various
-  actions, such as starting VMs, executing commands in the VMs, and so on. Each
-  virtual machine is represented as an object stored in the variable
-  <literal><replaceable>name</replaceable></literal> if this is also the
-  identifier of the machine in the declarative config.
-  If you didn't specify multiple machines using the <literal>nodes</literal>
-  attribute, it is just <literal>machine</literal>.
-  The following example starts the machine, waits until it has finished booting,
-  then executes a command and checks that the output is more-or-less correct:
-<programlisting>
-machine.start()
-machine.wait_for_unit("default.target")
-if not "Linux" in machine.succeed("uname"):
-  raise Exception("Wrong OS")
-</programlisting>
-  The first line is actually unnecessary; machines are implicitly started when
-  you first execute an action on them (such as <literal>wait_for_unit</literal>
-  or <literal>succeed</literal>). If you have multiple machines, you can speed
-  up the test by starting them in parallel:
-<programlisting>
-start_all()
-</programlisting>
- </para>
-
- <para>
-  The following methods are available on machine objects:
-  <variablelist>
-   <varlistentry>
-    <term>
-     <methodname>start</methodname>
-    </term>
-    <listitem>
-     <para>
-      Start the virtual machine. This method is asynchronous — it does not
-      wait for the machine to finish booting.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>shutdown</methodname>
-    </term>
-    <listitem>
-     <para>
-      Shut down the machine, waiting for the VM to exit.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>crash</methodname>
-    </term>
-    <listitem>
-     <para>
-      Simulate a sudden power failure, by telling the VM to exit immediately.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>block</methodname>
-    </term>
-    <listitem>
-     <para>
-      Simulate unplugging the Ethernet cable that connects the machine to the
-      other machines.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>unblock</methodname>
-    </term>
-    <listitem>
-     <para>
-      Undo the effect of <methodname>block</methodname>.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>screenshot</methodname>
-    </term>
-    <listitem>
-     <para>
-      Take a picture of the display of the virtual machine, in PNG format. The
-      screenshot is linked from the HTML log.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>get_screen_text_variants</methodname>
-    </term>
-    <listitem>
-     <para>
-      Return a list of different interpretations of what is currently visible
-      on the machine's screen using optical character recognition. The number
-      and order of the interpretations is not specified and is subject to
-      change, but if no exception is raised at least one will be returned.
-     </para>
-     <note>
-      <para>
-       This requires passing <option>enableOCR</option> to the test attribute
-       set.
-      </para>
-     </note>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>get_screen_text</methodname>
-    </term>
-    <listitem>
-     <para>
-      Return a textual representation of what is currently visible on the
-      machine's screen using optical character recognition.
-     </para>
-     <note>
-      <para>
-       This requires passing <option>enableOCR</option> to the test attribute
-       set.
-      </para>
-     </note>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>send_monitor_command</methodname>
-    </term>
-    <listitem>
-     <para>
-      Send a command to the QEMU monitor. This is rarely used, but allows doing
-      stuff such as attaching virtual USB disks to a running machine.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>send_key</methodname>
-    </term>
-    <listitem>
-     <para>
-      Simulate pressing keys on the virtual keyboard, e.g.,
-      <literal>send_key("ctrl-alt-delete")</literal>.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>send_chars</methodname>
-    </term>
-    <listitem>
-     <para>
-      Simulate typing a sequence of characters on the virtual keyboard, e.g.,
-      <literal>send_chars("foobar\n")</literal> will type the string
-      <literal>foobar</literal> followed by the Enter key.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>execute</methodname>
-    </term>
-    <listitem>
-     <para>
-      Execute a shell command, returning a list
-      <literal>(<replaceable>status</replaceable>,
-      <replaceable>stdout</replaceable>)</literal>.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>succeed</methodname>
-    </term>
-    <listitem>
-     <para>
-      Execute a shell command, raising an exception if the exit status
-      is not zero, otherwise returning the standard output. Commands
-      are run with <literal>set -euo pipefail</literal> set:
-      <itemizedlist>
-        <listitem>
-          <para>
-            If several commands are separated by <literal>;</literal>
-            and one fails, the command as a whole will fail.
-          </para>
-        </listitem>
-        <listitem>
-          <para>
-            For pipelines, the last non-zero exit status will be
-            returned (if there is one, zero will be returned
-            otherwise).
-          </para>
-        </listitem>
-        <listitem>
-          <para>
-            Dereferencing unset variables fail the command.
-          </para>
-        </listitem>
-      </itemizedlist>
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>fail</methodname>
-    </term>
-    <listitem>
-     <para>
-      Like <methodname>succeed</methodname>, but raising an exception if the
-      command returns a zero status.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>wait_until_succeeds</methodname>
-    </term>
-    <listitem>
-     <para>
-      Repeat a shell command with 1-second intervals until it succeeds.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>wait_until_fails</methodname>
-    </term>
-    <listitem>
-     <para>
-      Repeat a shell command with 1-second intervals until it fails.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>wait_for_unit</methodname>
-    </term>
-    <listitem>
-     <para>
-      Wait until the specified systemd unit has reached the “active” state.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>wait_for_file</methodname>
-    </term>
-    <listitem>
-     <para>
-      Wait until the specified file exists.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>wait_for_open_port</methodname>
-    </term>
-    <listitem>
-     <para>
-      Wait until a process is listening on the given TCP port (on
-      <literal>localhost</literal>, at least).
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>wait_for_closed_port</methodname>
-    </term>
-    <listitem>
-     <para>
-      Wait until nobody is listening on the given TCP port.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>wait_for_x</methodname>
-    </term>
-    <listitem>
-     <para>
-      Wait until the X11 server is accepting connections.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>wait_for_text</methodname>
-    </term>
-    <listitem>
-     <para>
-      Wait until the supplied regular expressions matches the textual contents
-      of the screen by using optical character recognition (see
-     <methodname>get_screen_text</methodname> and
-     <methodname>get_screen_text_variants</methodname>).
-     </para>
-     <note>
-      <para>
-       This requires passing <option>enableOCR</option> to the test attribute
-       set.
-      </para>
-     </note>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>wait_for_console_text</methodname>
-    </term>
-    <listitem>
-     <para>
-      Wait until the supplied regular expressions match a line of the serial
-      console output. This method is useful when OCR is not possibile or
-      accurate enough.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>wait_for_window</methodname>
-    </term>
-    <listitem>
-     <para>
-      Wait until an X11 window has appeared whose name matches the given
-      regular expression, e.g., <literal>wait_for_window("Terminal")</literal>.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>copy_from_host</methodname>
-    </term>
-    <listitem>
-     <para>
-      Copies a file from host to machine, e.g.,
-      <literal>copy_from_host("myfile", "/etc/my/important/file")</literal>.
-     </para>
-     <para>
-      The first argument is the file on the host. The file needs to be
-      accessible while building the nix derivation. The second argument is the
-      location of the file on the machine.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>systemctl</methodname>
-    </term>
-    <listitem>
-     <para>
-      Runs <literal>systemctl</literal> commands with optional support for
-      <literal>systemctl --user</literal>
-     </para>
-     <para>
-<programlisting>
-machine.systemctl("list-jobs --no-pager") # runs `systemctl list-jobs --no-pager`
-machine.systemctl("list-jobs --no-pager", "any-user") # spawns a shell for `any-user` and runs `systemctl --user list-jobs --no-pager`
-</programlisting>
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>shell_interact</methodname>
-    </term>
-    <listitem>
-     <para>
-      Allows you to directly interact with the guest shell.
-      This should only be used during test development, not in production tests.
-      Killing the interactive session with <literal>Ctrl-d</literal> or <literal>Ctrl-c</literal> also ends the guest session.
-     </para>
-    </listitem>
-   </varlistentry>
-  </variablelist>
- </para>
-
- <para>
-  To test user units declared by <literal>systemd.user.services</literal> the
-  optional <literal>user</literal> argument can be used:
-<programlisting>
-machine.start()
-machine.wait_for_x()
-machine.wait_for_unit("xautolock.service", "x-session-user")
-</programlisting>
-  This applies to <literal>systemctl</literal>, <literal>get_unit_info</literal>,
-  <literal>wait_for_unit</literal>, <literal>start_job</literal> and
-  <literal>stop_job</literal>.
- </para>
-
- <para>
-  For faster dev cycles it's also possible to disable the code-linters (this shouldn't
-  be commited though):
-<programlisting>
-import ./make-test-python.nix {
-  skipLint = true;
-  machine =
-    { config, pkgs, ... }:
-    { <replaceable>configuration…</replaceable>
-    };
-
-  testScript =
-    ''
-      <replaceable>Python code…</replaceable>
-    '';
-}
-</programlisting>
-  This will produce a Nix warning at evaluation time. To fully disable the
-  linter, wrap the test script in comment directives to disable the Black linter
-  directly (again, don't commit this within the Nixpkgs repository):
-<programlisting>
-  testScript =
-    ''
-      # fmt: off
-      <replaceable>Python code…</replaceable>
-      # fmt: on
-    '';
-</programlisting>
- </para>
-</section>