git.iko.soy/typeable/nixpkgs
on master help sign in
Merge pull request #128987 from bobby285271/pr9

nixos/doc: convert "Chapter 62. NixOS Tests" to CommonMark

commit74f12354e687eac7510cee0f2c9e29559465e064 authorRyan Mulligan <ryan@ryantm.com> dateFri 2 Jul 2021, 06:55 (5 years ago) parenta4acf6d47fe2c7
10 files changed+989−605
nixos/doc/manual/development/nixos-tests.xml+3−3 nixos/doc/manual/development/running-nixos-tests-interactively.section.md+44 nixos/doc/manual/development/running-nixos-tests-interactively.xml−49 nixos/doc/manual/development/running-nixos-tests.section.md+31 nixos/doc/manual/development/running-nixos-tests.xml−36 nixos/doc/manual/development/writing-nixos-tests.section.md+301 nixos/doc/manual/development/writing-nixos-tests.xml−517 nixos/doc/manual/from_md/development/running-nixos-tests-interactively.section.xml+50 nixos/doc/manual/from_md/development/running-nixos-tests.section.xml+34 nixos/doc/manual/from_md/development/writing-nixos-tests.section.xml+526
nixos/doc/manual/development/nixos-tests.xml+3−3
@@ -13,7 +13,7 @@ xlink:href="https://github.com/NixOS/nixpkgs/tree/master/nixos/tests">nixos/test
1313 one or more virtual machines containing the NixOS system(s) required for the
1414 test.
1515 </para>
16− <xi:include href="writing-nixos-tests.xml" />
17− <xi:include href="running-nixos-tests.xml" />
18− <xi:include href="running-nixos-tests-interactively.xml" />
16+ <xi:include href="../from_md/development/writing-nixos-tests.section.xml" />
17+ <xi:include href="../from_md/development/running-nixos-tests.section.xml" />
18+ <xi:include href="../from_md/development/running-nixos-tests-interactively.section.xml" />
1919</chapter>
nixos/doc/manual/development/running-nixos-tests-interactively.section.mdnew file+44
@@ -0,0 +1,44 @@
1+# Running Tests interactively {#sec-running-nixos-tests-interactively}
2+
3+The test itself can be run interactively. This is particularly useful
4+when developing or debugging a test:
5+
6+```ShellSession
7+$ nix-build nixos/tests/login.nix -A driverInteractive
8+$ ./result/bin/nixos-test-driver
9+starting VDE switch for network 1
10+>
11+```
12+
13+You can then take any Python statement, e.g.
14+
15+```py
16+> start_all()
17+> test_script()
18+> machine.succeed("touch /tmp/foo")
19+> print(machine.succeed("pwd")) # Show stdout of command
20+```
21+
22+The function `test_script` executes the entire test script and drops you
23+back into the test driver command line upon its completion. This allows
24+you to inspect the state of the VMs after the test (e.g. to debug the
25+test script).
26+
27+To just start and experiment with the VMs, run:
28+
29+```ShellSession
30+$ nix-build nixos/tests/login.nix -A driverInteractive
31+$ ./result/bin/nixos-run-vms
32+```
33+
34+The script `nixos-run-vms` starts the virtual machines defined by test.
35+
36+You can re-use the VM states coming from a previous run by setting the
37+`--keep-vm-state` flag.
38+
39+```ShellSession
40+$ ./result/bin/nixos-run-vms --keep-vm-state
41+```
42+
43+The machine state is stored in the `$TMPDIR/vm-state-machinename`
44+directory.
nixos/doc/manual/development/running-nixos-tests-interactively.xmldeleted−49
@@ -1,49 +0,0 @@
1−<section xmlns="http://docbook.org/ns/docbook"
2− xmlns:xlink="http://www.w3.org/1999/xlink"
3− xmlns:xi="http://www.w3.org/2001/XInclude"
4− version="5.0"
5− xml:id="sec-running-nixos-tests-interactively">
6− <title>Running Tests interactively</title>
7−
8− <para>
9− The test itself can be run interactively. This is particularly useful when
10− developing or debugging a test:
11−<screen>
12−<prompt>$ </prompt>nix-build nixos/tests/login.nix -A driverInteractive
13−<prompt>$ </prompt>./result/bin/nixos-test-driver
14−starting VDE switch for network 1
15−<prompt>&gt;</prompt>
16−</screen>
17− You can then take any Python statement, e.g.
18−<screen>
19−<prompt>&gt;</prompt> start_all()
20−<prompt>&gt;</prompt> test_script()
21−<prompt>&gt;</prompt> machine.succeed("touch /tmp/foo")
22−<prompt>&gt;</prompt> print(machine.succeed("pwd")) # Show stdout of command
23−</screen>
24− The function <command>test_script</command> executes the entire test script
25− and drops you back into the test driver command line upon its completion.
26− This allows you to inspect the state of the VMs after the test (e.g. to debug
27− the test script).
28− </para>
29−
30− <para>
31− To just start and experiment with the VMs, run:
32−<screen>
33−<prompt>$ </prompt>nix-build nixos/tests/login.nix -A driverInteractive
34−<prompt>$ </prompt>./result/bin/nixos-run-vms
35−</screen>
36− The script <command>nixos-run-vms</command> starts the virtual machines
37− defined by test.
38− </para>
39−
40− <para>
41− You can re-use the VM states coming from a previous run
42− by setting the <command>--keep-vm-state</command> flag.
43−<screen>
44−<prompt>$ </prompt>./result/bin/nixos-run-vms --keep-vm-state
45−</screen>
46− The machine state is stored in the
47− <filename>$TMPDIR/vm-state-</filename><varname>machinename</varname> directory.
48− </para>
49−</section>
nixos/doc/manual/development/running-nixos-tests.section.mdnew file+31
@@ -0,0 +1,31 @@
1+# Running Tests {#sec-running-nixos-tests}
2+
3+You can run tests using `nix-build`. For example, to run the test
4+[`login.nix`](https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/login.nix),
5+you just do:
6+
7+```ShellSession
8+$ nix-build '<nixpkgs/nixos/tests/login.nix>'
9+```
10+
11+or, if you don't want to rely on `NIX_PATH`:
12+
13+```ShellSession
14+$ cd /my/nixpkgs/nixos/tests
15+$ nix-build login.nix
16+…
17+running the VM test script
18+machine: QEMU running (pid 8841)
19+…
20+6 out of 6 tests succeeded
21+```
22+
23+After building/downloading all required dependencies, this will perform
24+a build that starts a QEMU/KVM virtual machine containing a NixOS
25+system. The virtual machine mounts the Nix store of the host; this makes
26+VM creation very fast, as no disk image needs to be created. Afterwards,
27+you can view a pretty-printed log of the test:
28+
29+```ShellSession
30+$ firefox result/log.html
31+```
nixos/doc/manual/development/running-nixos-tests.xmldeleted−36
@@ -1,36 +0,0 @@
1−<section xmlns="http://docbook.org/ns/docbook"
2− xmlns:xlink="http://www.w3.org/1999/xlink"
3− xmlns:xi="http://www.w3.org/2001/XInclude"
4− version="5.0"
5− xml:id="sec-running-nixos-tests">
6− <title>Running Tests</title>
7−
8− <para>
9− You can run tests using <command>nix-build</command>. For example, to run the
10− test
11− <filename
12−xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/login.nix">login.nix</filename>,
13− you just do:
14−<screen>
15−<prompt>$ </prompt>nix-build '&lt;nixpkgs/nixos/tests/login.nix>'
16−</screen>
17− or, if you don’t want to rely on <envar>NIX_PATH</envar>:
18−<screen>
19−<prompt>$ </prompt>cd /my/nixpkgs/nixos/tests
20−<prompt>$ </prompt>nix-build login.nix
21−…
22−running the VM test script
23−machine: QEMU running (pid 8841)
24−…
25−6 out of 6 tests succeeded
26−</screen>
27− After building/downloading all required dependencies, this will perform a
28− build that starts a QEMU/KVM virtual machine containing a NixOS system. The
29− virtual machine mounts the Nix store of the host; this makes VM creation very
30− fast, as no disk image needs to be created. Afterwards, you can view a
31− pretty-printed log of the test:
32−<screen>
33−<prompt>$ </prompt>firefox result/log.html
34−</screen>
35− </para>
36−</section>
nixos/doc/manual/development/writing-nixos-tests.section.mdnew file+301
@@ -0,0 +1,301 @@
1+# Writing Tests {#sec-writing-nixos-tests}
2+
3+A NixOS test is a Nix expression that has the following structure:
4+
5+```nix
6+import ./make-test-python.nix {
7+
8+ # Either the configuration of a single machine:
9+ machine =
10+ { config, pkgs, ... }:
11+ { configuration…
12+ };
13+
14+ # Or a set of machines:
15+ nodes =
16+ { machine1 =
17+ { config, pkgs, ... }: { … };
18+ machine2 =
19+ { config, pkgs, ... }: { … };
20+ …
21+ };
22+
23+ testScript =
24+ ''
25+ Python code…
26+ '';
27+}
28+```
29+
30+The attribute `testScript` is a bit of Python code that executes the
31+test (described below). During the test, it will start one or more
32+virtual machines, the configuration of which is described by the
33+attribute `machine` (if you need only one machine in your test) or by
34+the attribute `nodes` (if you need multiple machines). For instance,
35+[`login.nix`](https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/login.nix)
36+only needs a single machine to test whether users can log in
37+on the virtual console, whether device ownership is correctly maintained
38+when switching between consoles, and so on. On the other hand,
39+[`nfs/simple.nix`](https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/nfs/simple.nix),
40+which tests NFS client and server functionality in the
41+Linux kernel (including whether locks are maintained across server
42+crashes), requires three machines: a server and two clients.
43+
44+There are a few special NixOS configuration options for test VMs:
45+
46+`virtualisation.memorySize`
47+
48+: The memory of the VM in megabytes.
49+
50+`virtualisation.vlans`
51+
52+: The virtual networks to which the VM is connected. See
53+ [`nat.nix`](https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/nat.nix)
54+ for an example.
55+
56+`virtualisation.writableStore`
57+
58+: By default, the Nix store in the VM is not writable. If you enable
59+ this option, a writable union file system is mounted on top of the
60+ Nix store to make it appear writable. This is necessary for tests
61+ that run Nix operations that modify the store.
62+
63+For more options, see the module
64+[`qemu-vm.nix`](https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/virtualisation/qemu-vm.nix).
65+
66+The test script is a sequence of Python statements that perform various
67+actions, such as starting VMs, executing commands in the VMs, and so on.
68+Each virtual machine is represented as an object stored in the variable
69+`name` if this is also the identifier of the machine in the declarative
70+config. If you didn\'t specify multiple machines using the `nodes`
71+attribute, it is just `machine`. The following example starts the
72+machine, waits until it has finished booting, then executes a command
73+and checks that the output is more-or-less correct:
74+
75+```py
76+machine.start()
77+machine.wait_for_unit("default.target")
78+if not "Linux" in machine.succeed("uname"):
79+ raise Exception("Wrong OS")
80+```
81+
82+The first line is actually unnecessary; machines are implicitly started
83+when you first execute an action on them (such as `wait_for_unit` or
84+`succeed`). If you have multiple machines, you can speed up the test by
85+starting them in parallel:
86+
87+```py
88+start_all()
89+```
90+
91+The following methods are available on machine objects:
92+
93+`start`
94+
95+: Start the virtual machine. This method is asynchronous --- it does
96+ not wait for the machine to finish booting.
97+
98+`shutdown`
99+
100+: Shut down the machine, waiting for the VM to exit.
101+
102+`crash`
103+
104+: Simulate a sudden power failure, by telling the VM to exit
105+ immediately.
106+
107+`block`
108+
109+: Simulate unplugging the Ethernet cable that connects the machine to
110+ the other machines.
111+
112+`unblock`
113+
114+: Undo the effect of `block`.
115+
116+`screenshot`
117+
118+: Take a picture of the display of the virtual machine, in PNG format.
119+ The screenshot is linked from the HTML log.
120+
121+`get_screen_text_variants`
122+
123+: Return a list of different interpretations of what is currently
124+ visible on the machine\'s screen using optical character
125+ recognition. The number and order of the interpretations is not
126+ specified and is subject to change, but if no exception is raised at
127+ least one will be returned.
128+
129+ ::: {.note}
130+ This requires passing `enableOCR` to the test attribute set.
131+ :::
132+
133+`get_screen_text`
134+
135+: Return a textual representation of what is currently visible on the
136+ machine\'s screen using optical character recognition.
137+
138+ ::: {.note}
139+ This requires passing `enableOCR` to the test attribute set.
140+ :::
141+
142+`send_monitor_command`
143+
144+: Send a command to the QEMU monitor. This is rarely used, but allows
145+ doing stuff such as attaching virtual USB disks to a running
146+ machine.
147+
148+`send_key`
149+
150+: Simulate pressing keys on the virtual keyboard, e.g.,
151+ `send_key("ctrl-alt-delete")`.
152+
153+`send_chars`
154+
155+: Simulate typing a sequence of characters on the virtual keyboard,
156+ e.g., `send_chars("foobar\n")` will type the string `foobar`
157+ followed by the Enter key.
158+
159+`execute`
160+
161+: Execute a shell command, returning a list `(status, stdout)`.
162+
163+`succeed`
164+
165+: Execute a shell command, raising an exception if the exit status is
166+ not zero, otherwise returning the standard output. Commands are run
167+ with `set -euo pipefail` set:
168+
169+ - If several commands are separated by `;` and one fails, the
170+ command as a whole will fail.
171+
172+ - For pipelines, the last non-zero exit status will be returned
173+ (if there is one, zero will be returned otherwise).
174+
175+ - Dereferencing unset variables fail the command.
176+
177+`fail`
178+
179+: Like `succeed`, but raising an exception if the command returns a zero
180+ status.
181+
182+`wait_until_succeeds`
183+
184+: Repeat a shell command with 1-second intervals until it succeeds.
185+
186+`wait_until_fails`
187+
188+: Repeat a shell command with 1-second intervals until it fails.
189+
190+`wait_for_unit`
191+
192+: Wait until the specified systemd unit has reached the "active"
193+ state.
194+
195+`wait_for_file`
196+
197+: Wait until the specified file exists.
198+
199+`wait_for_open_port`
200+
201+: Wait until a process is listening on the given TCP port (on
202+ `localhost`, at least).
203+
204+`wait_for_closed_port`
205+
206+: Wait until nobody is listening on the given TCP port.
207+
208+`wait_for_x`
209+
210+: Wait until the X11 server is accepting connections.
211+
212+`wait_for_text`
213+
214+: Wait until the supplied regular expressions matches the textual
215+ contents of the screen by using optical character recognition (see
216+ `get_screen_text` and `get_screen_text_variants`).
217+
218+ ::: {.note}
219+ This requires passing `enableOCR` to the test attribute set.
220+ :::
221+
222+`wait_for_console_text`
223+
224+: Wait until the supplied regular expressions match a line of the
225+ serial console output. This method is useful when OCR is not
226+ possibile or accurate enough.
227+
228+`wait_for_window`
229+
230+: Wait until an X11 window has appeared whose name matches the given
231+ regular expression, e.g., `wait_for_window("Terminal")`.
232+
233+`copy_from_host`
234+
235+: Copies a file from host to machine, e.g.,
236+ `copy_from_host("myfile", "/etc/my/important/file")`.
237+
238+ The first argument is the file on the host. The file needs to be
239+ accessible while building the nix derivation. The second argument is
240+ the location of the file on the machine.
241+
242+`systemctl`
243+
244+: Runs `systemctl` commands with optional support for
245+ `systemctl --user`
246+
247+ ```py
248+ machine.systemctl("list-jobs --no-pager") # runs `systemctl list-jobs --no-pager`
249+ machine.systemctl("list-jobs --no-pager", "any-user") # spawns a shell for `any-user` and runs `systemctl --user list-jobs --no-pager`
250+ ```
251+
252+`shell_interact`
253+
254+: Allows you to directly interact with the guest shell. This should
255+ only be used during test development, not in production tests.
256+ Killing the interactive session with `Ctrl-d` or `Ctrl-c` also ends
257+ the guest session.
258+
259+To test user units declared by `systemd.user.services` the optional
260+`user` argument can be used:
261+
262+```py
263+machine.start()
264+machine.wait_for_x()
265+machine.wait_for_unit("xautolock.service", "x-session-user")
266+```
267+
268+This applies to `systemctl`, `get_unit_info`, `wait_for_unit`,
269+`start_job` and `stop_job`.
270+
271+For faster dev cycles it\'s also possible to disable the code-linters
272+(this shouldn\'t be commited though):
273+
274+```nix
275+import ./make-test-python.nix {
276+ skipLint = true;
277+ machine =
278+ { config, pkgs, ... }:
279+ { configuration…
280+ };
281+
282+ testScript =
283+ ''
284+ Python code…
285+ '';
286+}
287+```
288+
289+This will produce a Nix warning at evaluation time. To fully disable the
290+linter, wrap the test script in comment directives to disable the Black
291+linter directly (again, don\'t commit this within the Nixpkgs
292+repository):
293+
294+```nix
295+ testScript =
296+ ''
297+ # fmt: off
298+ Python code…
299+ # fmt: on
300+ '';
301+```
nixos/doc/manual/development/writing-nixos-tests.xmldeleted−517
@@ -1,517 +0,0 @@
1−<section xmlns="http://docbook.org/ns/docbook"
2− xmlns:xlink="http://www.w3.org/1999/xlink"
3− xmlns:xi="http://www.w3.org/2001/XInclude"
4− version="5.0"
5− xml:id="sec-writing-nixos-tests">
6− <title>Writing Tests</title>
7−
8− <para>
9− A NixOS test is a Nix expression that has the following structure:
10−<programlisting>
11−import ./make-test-python.nix {
12−
13− # Either the configuration of a single machine:
14− machine =
15− { config, pkgs, ... }:
16− { <replaceable>configuration…</replaceable>
17− };
18−
19− # Or a set of machines:
20− nodes =
21− { <replaceable>machine1</replaceable> =
22− { config, pkgs, ... }: { <replaceable>…</replaceable> };
23− <replaceable>machine2</replaceable> =
24− { config, pkgs, ... }: { <replaceable>…</replaceable> };
25− …
26− };
27−
28− testScript =
29− ''
30− <replaceable>Python code…</replaceable>
31− '';
32−}
33−</programlisting>
34− The attribute <literal>testScript</literal> is a bit of Python code that
35− executes the test (described below). During the test, it will start one or
36− more virtual machines, the configuration of which is described by the
37− attribute <literal>machine</literal> (if you need only one machine in your
38− test) or by the attribute <literal>nodes</literal> (if you need multiple
39− machines). For instance,
40− <filename
41−xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/login.nix">login.nix</filename>
42− only needs a single machine to test whether users can log in on the virtual
43− console, whether device ownership is correctly maintained when switching
44− between consoles, and so on. On the other hand,
45− <filename
46−xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/nfs/simple.nix">nfs/simple.nix</filename>,
47− which tests NFS client and server functionality in the Linux kernel
48− (including whether locks are maintained across server crashes), requires
49− three machines: a server and two clients.
50− </para>
51−
52− <para>
53− There are a few special NixOS configuration options for test VMs:
54−<!-- FIXME: would be nice to generate this automatically. -->
55− <variablelist>
56− <varlistentry>
57− <term>
58− <option>virtualisation.memorySize</option>
59− </term>
60− <listitem>
61− <para>
62− The memory of the VM in megabytes.
63− </para>
64− </listitem>
65− </varlistentry>
66− <varlistentry>
67− <term>
68− <option>virtualisation.vlans</option>
69− </term>
70− <listitem>
71− <para>
72− The virtual networks to which the VM is connected. See
73− <filename
74− xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/nat.nix">nat.nix</filename>
75− for an example.
76− </para>
77− </listitem>
78− </varlistentry>
79− <varlistentry>
80− <term>
81− <option>virtualisation.writableStore</option>
82− </term>
83− <listitem>
84− <para>
85− By default, the Nix store in the VM is not writable. If you enable this
86− option, a writable union file system is mounted on top of the Nix store
87− to make it appear writable. This is necessary for tests that run Nix
88− operations that modify the store.
89− </para>
90− </listitem>
91− </varlistentry>
92− </variablelist>
93− For more options, see the module
94− <filename
95−xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/virtualisation/qemu-vm.nix">qemu-vm.nix</filename>.
96− </para>
97−
98− <para>
99− The test script is a sequence of Python statements that perform various
100− actions, such as starting VMs, executing commands in the VMs, and so on. Each
101− virtual machine is represented as an object stored in the variable
102− <literal><replaceable>name</replaceable></literal> if this is also the
103− identifier of the machine in the declarative config.
104− If you didn't specify multiple machines using the <literal>nodes</literal>
105− attribute, it is just <literal>machine</literal>.
106− The following example starts the machine, waits until it has finished booting,
107− then executes a command and checks that the output is more-or-less correct:
108−<programlisting>
109−machine.start()
110−machine.wait_for_unit("default.target")
111−if not "Linux" in machine.succeed("uname"):
112− raise Exception("Wrong OS")
113−</programlisting>
114− The first line is actually unnecessary; machines are implicitly started when
115− you first execute an action on them (such as <literal>wait_for_unit</literal>
116− or <literal>succeed</literal>). If you have multiple machines, you can speed
117− up the test by starting them in parallel:
118−<programlisting>
119−start_all()
120−</programlisting>
121− </para>
122−
123− <para>
124− The following methods are available on machine objects:
125− <variablelist>
126− <varlistentry>
127− <term>
128− <methodname>start</methodname>
129− </term>
130− <listitem>
131− <para>
132− Start the virtual machine. This method is asynchronous — it does not
133− wait for the machine to finish booting.
134− </para>
135− </listitem>
136− </varlistentry>
137− <varlistentry>
138− <term>
139− <methodname>shutdown</methodname>
140− </term>
141− <listitem>
142− <para>
143− Shut down the machine, waiting for the VM to exit.
144− </para>
145− </listitem>
146− </varlistentry>
147− <varlistentry>
148− <term>
149− <methodname>crash</methodname>
150− </term>
151− <listitem>
152− <para>
153− Simulate a sudden power failure, by telling the VM to exit immediately.
154− </para>
155− </listitem>
156− </varlistentry>
157− <varlistentry>
158− <term>
159− <methodname>block</methodname>
160− </term>
161− <listitem>
162− <para>
163− Simulate unplugging the Ethernet cable that connects the machine to the
164− other machines.
165− </para>
166− </listitem>
167− </varlistentry>
168− <varlistentry>
169− <term>
170− <methodname>unblock</methodname>
171− </term>
172− <listitem>
173− <para>
174− Undo the effect of <methodname>block</methodname>.
175− </para>
176− </listitem>
177− </varlistentry>
178− <varlistentry>
179− <term>
180− <methodname>screenshot</methodname>
181− </term>
182− <listitem>
183− <para>
184− Take a picture of the display of the virtual machine, in PNG format. The
185− screenshot is linked from the HTML log.
186− </para>
187− </listitem>
188− </varlistentry>
189− <varlistentry>
190− <term>
191− <methodname>get_screen_text_variants</methodname>
192− </term>
193− <listitem>
194− <para>
195− Return a list of different interpretations of what is currently visible
196− on the machine's screen using optical character recognition. The number
197− and order of the interpretations is not specified and is subject to
198− change, but if no exception is raised at least one will be returned.
199− </para>
200− <note>
201− <para>
202− This requires passing <option>enableOCR</option> to the test attribute
203− set.
204− </para>
205− </note>
206− </listitem>
207− </varlistentry>
208− <varlistentry>
209− <term>
210− <methodname>get_screen_text</methodname>
211− </term>
212− <listitem>
213− <para>
214− Return a textual representation of what is currently visible on the
215− machine's screen using optical character recognition.
216− </para>
217− <note>
218− <para>
219− This requires passing <option>enableOCR</option> to the test attribute
220− set.
221− </para>
222− </note>
223− </listitem>
224− </varlistentry>
225− <varlistentry>
226− <term>
227− <methodname>send_monitor_command</methodname>
228− </term>
229− <listitem>
230− <para>
231− Send a command to the QEMU monitor. This is rarely used, but allows doing
232− stuff such as attaching virtual USB disks to a running machine.
233− </para>
234− </listitem>
235− </varlistentry>
236− <varlistentry>
237− <term>
238− <methodname>send_key</methodname>
239− </term>
240− <listitem>
241− <para>
242− Simulate pressing keys on the virtual keyboard, e.g.,
243− <literal>send_key("ctrl-alt-delete")</literal>.
244− </para>
245− </listitem>
246− </varlistentry>
247− <varlistentry>
248− <term>
249− <methodname>send_chars</methodname>
250− </term>
251− <listitem>
252− <para>
253− Simulate typing a sequence of characters on the virtual keyboard, e.g.,
254− <literal>send_chars("foobar\n")</literal> will type the string
255− <literal>foobar</literal> followed by the Enter key.
256− </para>
257− </listitem>
258− </varlistentry>
259− <varlistentry>
260− <term>
261− <methodname>execute</methodname>
262− </term>
263− <listitem>
264− <para>
265− Execute a shell command, returning a list
266− <literal>(<replaceable>status</replaceable>,
267− <replaceable>stdout</replaceable>)</literal>.
268− </para>
269− </listitem>
270− </varlistentry>
271− <varlistentry>
272− <term>
273− <methodname>succeed</methodname>
274− </term>
275− <listitem>
276− <para>
277− Execute a shell command, raising an exception if the exit status
278− is not zero, otherwise returning the standard output. Commands
279− are run with <literal>set -euo pipefail</literal> set:
280− <itemizedlist>
281− <listitem>
282− <para>
283− If several commands are separated by <literal>;</literal>
284− and one fails, the command as a whole will fail.
285− </para>
286− </listitem>
287− <listitem>
288− <para>
289− For pipelines, the last non-zero exit status will be
290− returned (if there is one, zero will be returned
291− otherwise).
292− </para>
293− </listitem>
294− <listitem>
295− <para>
296− Dereferencing unset variables fail the command.
297− </para>
298− </listitem>
299− </itemizedlist>
300− </para>
301− </listitem>
302− </varlistentry>
303− <varlistentry>
304− <term>
305− <methodname>fail</methodname>
306− </term>
307− <listitem>
308− <para>
309− Like <methodname>succeed</methodname>, but raising an exception if the
310− command returns a zero status.
311− </para>
312− </listitem>
313− </varlistentry>
314− <varlistentry>
315− <term>
316− <methodname>wait_until_succeeds</methodname>
317− </term>
318− <listitem>
319− <para>
320− Repeat a shell command with 1-second intervals until it succeeds.
321− </para>
322− </listitem>
323− </varlistentry>
324− <varlistentry>
325− <term>
326− <methodname>wait_until_fails</methodname>
327− </term>
328− <listitem>
329− <para>
330− Repeat a shell command with 1-second intervals until it fails.
331− </para>
332− </listitem>
333− </varlistentry>
334− <varlistentry>
335− <term>
336− <methodname>wait_for_unit</methodname>
337− </term>
338− <listitem>
339− <para>
340− Wait until the specified systemd unit has reached the “active” state.
341− </para>
342− </listitem>
343− </varlistentry>
344− <varlistentry>
345− <term>
346− <methodname>wait_for_file</methodname>
347− </term>
348− <listitem>
349− <para>
350− Wait until the specified file exists.
351− </para>
352− </listitem>
353− </varlistentry>
354− <varlistentry>
355− <term>
356− <methodname>wait_for_open_port</methodname>
357− </term>
358− <listitem>
359− <para>
360− Wait until a process is listening on the given TCP port (on
361− <literal>localhost</literal>, at least).
362− </para>
363− </listitem>
364− </varlistentry>
365− <varlistentry>
366− <term>
367− <methodname>wait_for_closed_port</methodname>
368− </term>
369− <listitem>
370− <para>
371− Wait until nobody is listening on the given TCP port.
372− </para>
373− </listitem>
374− </varlistentry>
375− <varlistentry>
376− <term>
377− <methodname>wait_for_x</methodname>
378− </term>
379− <listitem>
380− <para>
381− Wait until the X11 server is accepting connections.
382− </para>
383− </listitem>
384− </varlistentry>
385− <varlistentry>
386− <term>
387− <methodname>wait_for_text</methodname>
388− </term>
389− <listitem>
390− <para>
391− Wait until the supplied regular expressions matches the textual contents
392− of the screen by using optical character recognition (see
393− <methodname>get_screen_text</methodname> and
394− <methodname>get_screen_text_variants</methodname>).
395− </para>
396− <note>
397− <para>
398− This requires passing <option>enableOCR</option> to the test attribute
399− set.
400− </para>
401− </note>
402− </listitem>
403− </varlistentry>
404− <varlistentry>
405− <term>
406− <methodname>wait_for_console_text</methodname>
407− </term>
408− <listitem>
409− <para>
410− Wait until the supplied regular expressions match a line of the serial
411− console output. This method is useful when OCR is not possibile or
412− accurate enough.
413− </para>
414− </listitem>
415− </varlistentry>
416− <varlistentry>
417− <term>
418− <methodname>wait_for_window</methodname>
419− </term>
420− <listitem>
421− <para>
422− Wait until an X11 window has appeared whose name matches the given
423− regular expression, e.g., <literal>wait_for_window("Terminal")</literal>.
424− </para>
425− </listitem>
426− </varlistentry>
427− <varlistentry>
428− <term>
429− <methodname>copy_from_host</methodname>
430− </term>
431− <listitem>
432− <para>
433− Copies a file from host to machine, e.g.,
434− <literal>copy_from_host("myfile", "/etc/my/important/file")</literal>.
435− </para>
436− <para>
437− The first argument is the file on the host. The file needs to be
438− accessible while building the nix derivation. The second argument is the
439− location of the file on the machine.
440− </para>
441− </listitem>
442− </varlistentry>
443− <varlistentry>
444− <term>
445− <methodname>systemctl</methodname>
446− </term>
447− <listitem>
448− <para>
449− Runs <literal>systemctl</literal> commands with optional support for
450− <literal>systemctl --user</literal>
451− </para>
452− <para>
453−<programlisting>
454−machine.systemctl("list-jobs --no-pager") # runs `systemctl list-jobs --no-pager`
455−machine.systemctl("list-jobs --no-pager", "any-user") # spawns a shell for `any-user` and runs `systemctl --user list-jobs --no-pager`
456−</programlisting>
457− </para>
458− </listitem>
459− </varlistentry>
460− <varlistentry>
461− <term>
462− <methodname>shell_interact</methodname>
463− </term>
464− <listitem>
465− <para>
466− Allows you to directly interact with the guest shell.
467− This should only be used during test development, not in production tests.
468− Killing the interactive session with <literal>Ctrl-d</literal> or <literal>Ctrl-c</literal> also ends the guest session.
469− </para>
470− </listitem>
471− </varlistentry>
472− </variablelist>
473− </para>
474−
475− <para>
476− To test user units declared by <literal>systemd.user.services</literal> the
477− optional <literal>user</literal> argument can be used:
478−<programlisting>
479−machine.start()
480−machine.wait_for_x()
481−machine.wait_for_unit("xautolock.service", "x-session-user")
482−</programlisting>
483− This applies to <literal>systemctl</literal>, <literal>get_unit_info</literal>,
484− <literal>wait_for_unit</literal>, <literal>start_job</literal> and
485− <literal>stop_job</literal>.
486− </para>
487−
488− <para>
489− For faster dev cycles it's also possible to disable the code-linters (this shouldn't
490− be commited though):
491−<programlisting>
492−import ./make-test-python.nix {
493− skipLint = true;
494− machine =
495− { config, pkgs, ... }:
496− { <replaceable>configuration…</replaceable>
497− };
498−
499− testScript =
500− ''
501− <replaceable>Python code…</replaceable>
502− '';
503−}
504−</programlisting>
505− This will produce a Nix warning at evaluation time. To fully disable the
506− linter, wrap the test script in comment directives to disable the Black linter
507− directly (again, don't commit this within the Nixpkgs repository):
508−<programlisting>
509− testScript =
510− ''
511− # fmt: off
512− <replaceable>Python code…</replaceable>
513− # fmt: on
514− '';
515−</programlisting>
516− </para>
517−</section>
nixos/doc/manual/from_md/development/running-nixos-tests-interactively.section.xmlnew file+50
@@ -0,0 +1,50 @@
1+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-running-nixos-tests-interactively">
2+ <title>Running Tests interactively</title>
3+ <para>
4+ The test itself can be run interactively. This is particularly
5+ useful when developing or debugging a test:
6+ </para>
7+ <programlisting>
8+$ nix-build nixos/tests/login.nix -A driverInteractive
9+$ ./result/bin/nixos-test-driver
10+starting VDE switch for network 1
11+&gt;
12+</programlisting>
13+ <para>
14+ You can then take any Python statement, e.g.
15+ </para>
16+ <programlisting language="python">
17+&gt; start_all()
18+&gt; test_script()
19+&gt; machine.succeed(&quot;touch /tmp/foo&quot;)
20+&gt; print(machine.succeed(&quot;pwd&quot;)) # Show stdout of command
21+</programlisting>
22+ <para>
23+ The function <literal>test_script</literal> executes the entire test
24+ script and drops you back into the test driver command line upon its
25+ completion. This allows you to inspect the state of the VMs after
26+ the test (e.g. to debug the test script).
27+ </para>
28+ <para>
29+ To just start and experiment with the VMs, run:
30+ </para>
31+ <programlisting>
32+$ nix-build nixos/tests/login.nix -A driverInteractive
33+$ ./result/bin/nixos-run-vms
34+</programlisting>
35+ <para>
36+ The script <literal>nixos-run-vms</literal> starts the virtual
37+ machines defined by test.
38+ </para>
39+ <para>
40+ You can re-use the VM states coming from a previous run by setting
41+ the <literal>--keep-vm-state</literal> flag.
42+ </para>
43+ <programlisting>
44+$ ./result/bin/nixos-run-vms --keep-vm-state
45+</programlisting>
46+ <para>
47+ The machine state is stored in the
48+ <literal>$TMPDIR/vm-state-machinename</literal> directory.
49+ </para>
50+</section>
nixos/doc/manual/from_md/development/running-nixos-tests.section.xmlnew file+34
@@ -0,0 +1,34 @@
1+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-running-nixos-tests">
2+ <title>Running Tests</title>
3+ <para>
4+ You can run tests using <literal>nix-build</literal>. For example,
5+ to run the test
6+ <link xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/login.nix"><literal>login.nix</literal></link>,
7+ you just do:
8+ </para>
9+ <programlisting>
10+$ nix-build '&lt;nixpkgs/nixos/tests/login.nix&gt;'
11+</programlisting>
12+ <para>
13+ or, if you don’t want to rely on <literal>NIX_PATH</literal>:
14+ </para>
15+ <programlisting>
16+$ cd /my/nixpkgs/nixos/tests
17+$ nix-build login.nix
18+…
19+running the VM test script
20+machine: QEMU running (pid 8841)
21+…
22+6 out of 6 tests succeeded
23+</programlisting>
24+ <para>
25+ After building/downloading all required dependencies, this will
26+ perform a build that starts a QEMU/KVM virtual machine containing a
27+ NixOS system. The virtual machine mounts the Nix store of the host;
28+ this makes VM creation very fast, as no disk image needs to be
29+ created. Afterwards, you can view a pretty-printed log of the test:
30+ </para>
31+ <programlisting>
32+$ firefox result/log.html
33+</programlisting>
34+</section>
nixos/doc/manual/from_md/development/writing-nixos-tests.section.xmlnew file+526
@@ -0,0 +1,526 @@
1+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-writing-nixos-tests">
2+ <title>Writing Tests</title>
3+ <para>
4+ A NixOS test is a Nix expression that has the following structure:
5+ </para>
6+ <programlisting language="bash">
7+import ./make-test-python.nix {
8+
9+ # Either the configuration of a single machine:
10+ machine =
11+ { config, pkgs, ... }:
12+ { configuration…
13+ };
14+
15+ # Or a set of machines:
16+ nodes =
17+ { machine1 =
18+ { config, pkgs, ... }: { … };
19+ machine2 =
20+ { config, pkgs, ... }: { … };
21+ …
22+ };
23+
24+ testScript =
25+ ''
26+ Python code…
27+ '';
28+}
29+</programlisting>
30+ <para>
31+ The attribute <literal>testScript</literal> is a bit of Python code
32+ that executes the test (described below). During the test, it will
33+ start one or more virtual machines, the configuration of which is
34+ described by the attribute <literal>machine</literal> (if you need
35+ only one machine in your test) or by the attribute
36+ <literal>nodes</literal> (if you need multiple machines). For
37+ instance,
38+ <link xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/login.nix"><literal>login.nix</literal></link>
39+ only needs a single machine to test whether users can log in on the
40+ virtual console, whether device ownership is correctly maintained
41+ when switching between consoles, and so on. On the other hand,
42+ <link xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/nfs/simple.nix"><literal>nfs/simple.nix</literal></link>,
43+ which tests NFS client and server functionality in the Linux kernel
44+ (including whether locks are maintained across server crashes),
45+ requires three machines: a server and two clients.
46+ </para>
47+ <para>
48+ There are a few special NixOS configuration options for test VMs:
49+ </para>
50+ <variablelist>
51+ <varlistentry>
52+ <term>
53+ <literal>virtualisation.memorySize</literal>
54+ </term>
55+ <listitem>
56+ <para>
57+ The memory of the VM in megabytes.
58+ </para>
59+ </listitem>
60+ </varlistentry>
61+ <varlistentry>
62+ <term>
63+ <literal>virtualisation.vlans</literal>
64+ </term>
65+ <listitem>
66+ <para>
67+ The virtual networks to which the VM is connected. See
68+ <link xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/nat.nix"><literal>nat.nix</literal></link>
69+ for an example.
70+ </para>
71+ </listitem>
72+ </varlistentry>
73+ <varlistentry>
74+ <term>
75+ <literal>virtualisation.writableStore</literal>
76+ </term>
77+ <listitem>
78+ <para>
79+ By default, the Nix store in the VM is not writable. If you
80+ enable this option, a writable union file system is mounted on
81+ top of the Nix store to make it appear writable. This is
82+ necessary for tests that run Nix operations that modify the
83+ store.
84+ </para>
85+ </listitem>
86+ </varlistentry>
87+ </variablelist>
88+ <para>
89+ For more options, see the module
90+ <link xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/virtualisation/qemu-vm.nix"><literal>qemu-vm.nix</literal></link>.
91+ </para>
92+ <para>
93+ The test script is a sequence of Python statements that perform
94+ various actions, such as starting VMs, executing commands in the
95+ VMs, and so on. Each virtual machine is represented as an object
96+ stored in the variable <literal>name</literal> if this is also the
97+ identifier of the machine in the declarative config. If you didn't
98+ specify multiple machines using the <literal>nodes</literal>
99+ attribute, it is just <literal>machine</literal>. The following
100+ example starts the machine, waits until it has finished booting,
101+ then executes a command and checks that the output is more-or-less
102+ correct:
103+ </para>
104+ <programlisting language="python">
105+machine.start()
106+machine.wait_for_unit(&quot;default.target&quot;)
107+if not &quot;Linux&quot; in machine.succeed(&quot;uname&quot;):
108+ raise Exception(&quot;Wrong OS&quot;)
109+</programlisting>
110+ <para>
111+ The first line is actually unnecessary; machines are implicitly
112+ started when you first execute an action on them (such as
113+ <literal>wait_for_unit</literal> or <literal>succeed</literal>). If
114+ you have multiple machines, you can speed up the test by starting
115+ them in parallel:
116+ </para>
117+ <programlisting language="python">
118+start_all()
119+</programlisting>
120+ <para>
121+ The following methods are available on machine objects:
122+ </para>
123+ <variablelist>
124+ <varlistentry>
125+ <term>
126+ <literal>start</literal>
127+ </term>
128+ <listitem>
129+ <para>
130+ Start the virtual machine. This method is asynchronous — it
131+ does not wait for the machine to finish booting.
132+ </para>
133+ </listitem>
134+ </varlistentry>
135+ <varlistentry>
136+ <term>
137+ <literal>shutdown</literal>
138+ </term>
139+ <listitem>
140+ <para>
141+ Shut down the machine, waiting for the VM to exit.
142+ </para>
143+ </listitem>
144+ </varlistentry>
145+ <varlistentry>
146+ <term>
147+ <literal>crash</literal>
148+ </term>
149+ <listitem>
150+ <para>
151+ Simulate a sudden power failure, by telling the VM to exit
152+ immediately.
153+ </para>
154+ </listitem>
155+ </varlistentry>
156+ <varlistentry>
157+ <term>
158+ <literal>block</literal>
159+ </term>
160+ <listitem>
161+ <para>
162+ Simulate unplugging the Ethernet cable that connects the
163+ machine to the other machines.
164+ </para>
165+ </listitem>
166+ </varlistentry>
167+ <varlistentry>
168+ <term>
169+ <literal>unblock</literal>
170+ </term>
171+ <listitem>
172+ <para>
173+ Undo the effect of <literal>block</literal>.
174+ </para>
175+ </listitem>
176+ </varlistentry>
177+ <varlistentry>
178+ <term>
179+ <literal>screenshot</literal>
180+ </term>
181+ <listitem>
182+ <para>
183+ Take a picture of the display of the virtual machine, in PNG
184+ format. The screenshot is linked from the HTML log.
185+ </para>
186+ </listitem>
187+ </varlistentry>
188+ <varlistentry>
189+ <term>
190+ <literal>get_screen_text_variants</literal>
191+ </term>
192+ <listitem>
193+ <para>
194+ Return a list of different interpretations of what is
195+ currently visible on the machine's screen using optical
196+ character recognition. The number and order of the
197+ interpretations is not specified and is subject to change, but
198+ if no exception is raised at least one will be returned.
199+ </para>
200+ <note>
201+ <para>
202+ This requires passing <literal>enableOCR</literal> to the
203+ test attribute set.
204+ </para>
205+ </note>
206+ </listitem>
207+ </varlistentry>
208+ <varlistentry>
209+ <term>
210+ <literal>get_screen_text</literal>
211+ </term>
212+ <listitem>
213+ <para>
214+ Return a textual representation of what is currently visible
215+ on the machine's screen using optical character recognition.
216+ </para>
217+ <note>
218+ <para>
219+ This requires passing <literal>enableOCR</literal> to the
220+ test attribute set.
221+ </para>
222+ </note>
223+ </listitem>
224+ </varlistentry>
225+ <varlistentry>
226+ <term>
227+ <literal>send_monitor_command</literal>
228+ </term>
229+ <listitem>
230+ <para>
231+ Send a command to the QEMU monitor. This is rarely used, but
232+ allows doing stuff such as attaching virtual USB disks to a
233+ running machine.
234+ </para>
235+ </listitem>
236+ </varlistentry>
237+ <varlistentry>
238+ <term>
239+ <literal>send_key</literal>
240+ </term>
241+ <listitem>
242+ <para>
243+ Simulate pressing keys on the virtual keyboard, e.g.,
244+ <literal>send_key(&quot;ctrl-alt-delete&quot;)</literal>.
245+ </para>
246+ </listitem>
247+ </varlistentry>
248+ <varlistentry>
249+ <term>
250+ <literal>send_chars</literal>
251+ </term>
252+ <listitem>
253+ <para>
254+ Simulate typing a sequence of characters on the virtual
255+ keyboard, e.g.,
256+ <literal>send_chars(&quot;foobar\n&quot;)</literal> will type
257+ the string <literal>foobar</literal> followed by the Enter
258+ key.
259+ </para>
260+ </listitem>
261+ </varlistentry>
262+ <varlistentry>
263+ <term>
264+ <literal>execute</literal>
265+ </term>
266+ <listitem>
267+ <para>
268+ Execute a shell command, returning a list
269+ <literal>(status, stdout)</literal>.
270+ </para>
271+ </listitem>
272+ </varlistentry>
273+ <varlistentry>
274+ <term>
275+ <literal>succeed</literal>
276+ </term>
277+ <listitem>
278+ <para>
279+ Execute a shell command, raising an exception if the exit
280+ status is not zero, otherwise returning the standard output.
281+ Commands are run with <literal>set -euo pipefail</literal>
282+ set:
283+ </para>
284+ <itemizedlist>
285+ <listitem>
286+ <para>
287+ If several commands are separated by <literal>;</literal>
288+ and one fails, the command as a whole will fail.
289+ </para>
290+ </listitem>
291+ <listitem>
292+ <para>
293+ For pipelines, the last non-zero exit status will be
294+ returned (if there is one, zero will be returned
295+ otherwise).
296+ </para>
297+ </listitem>
298+ <listitem>
299+ <para>
300+ Dereferencing unset variables fail the command.
301+ </para>
302+ </listitem>
303+ </itemizedlist>
304+ </listitem>
305+ </varlistentry>
306+ <varlistentry>
307+ <term>
308+ <literal>fail</literal>
309+ </term>
310+ <listitem>
311+ <para>
312+ Like <literal>succeed</literal>, but raising an exception if
313+ the command returns a zero status.
314+ </para>
315+ </listitem>
316+ </varlistentry>
317+ <varlistentry>
318+ <term>
319+ <literal>wait_until_succeeds</literal>
320+ </term>
321+ <listitem>
322+ <para>
323+ Repeat a shell command with 1-second intervals until it
324+ succeeds.
325+ </para>
326+ </listitem>
327+ </varlistentry>
328+ <varlistentry>
329+ <term>
330+ <literal>wait_until_fails</literal>
331+ </term>
332+ <listitem>
333+ <para>
334+ Repeat a shell command with 1-second intervals until it fails.
335+ </para>
336+ </listitem>
337+ </varlistentry>
338+ <varlistentry>
339+ <term>
340+ <literal>wait_for_unit</literal>
341+ </term>
342+ <listitem>
343+ <para>
344+ Wait until the specified systemd unit has reached the
345+ <quote>active</quote> state.
346+ </para>
347+ </listitem>
348+ </varlistentry>
349+ <varlistentry>
350+ <term>
351+ <literal>wait_for_file</literal>
352+ </term>
353+ <listitem>
354+ <para>
355+ Wait until the specified file exists.
356+ </para>
357+ </listitem>
358+ </varlistentry>
359+ <varlistentry>
360+ <term>
361+ <literal>wait_for_open_port</literal>
362+ </term>
363+ <listitem>
364+ <para>
365+ Wait until a process is listening on the given TCP port (on
366+ <literal>localhost</literal>, at least).
367+ </para>
368+ </listitem>
369+ </varlistentry>
370+ <varlistentry>
371+ <term>
372+ <literal>wait_for_closed_port</literal>
373+ </term>
374+ <listitem>
375+ <para>
376+ Wait until nobody is listening on the given TCP port.
377+ </para>
378+ </listitem>
379+ </varlistentry>
380+ <varlistentry>
381+ <term>
382+ <literal>wait_for_x</literal>
383+ </term>
384+ <listitem>
385+ <para>
386+ Wait until the X11 server is accepting connections.
387+ </para>
388+ </listitem>
389+ </varlistentry>
390+ <varlistentry>
391+ <term>
392+ <literal>wait_for_text</literal>
393+ </term>
394+ <listitem>
395+ <para>
396+ Wait until the supplied regular expressions matches the
397+ textual contents of the screen by using optical character
398+ recognition (see <literal>get_screen_text</literal> and
399+ <literal>get_screen_text_variants</literal>).
400+ </para>
401+ <note>
402+ <para>
403+ This requires passing <literal>enableOCR</literal> to the
404+ test attribute set.
405+ </para>
406+ </note>
407+ </listitem>
408+ </varlistentry>
409+ <varlistentry>
410+ <term>
411+ <literal>wait_for_console_text</literal>
412+ </term>
413+ <listitem>
414+ <para>
415+ Wait until the supplied regular expressions match a line of
416+ the serial console output. This method is useful when OCR is
417+ not possibile or accurate enough.
418+ </para>
419+ </listitem>
420+ </varlistentry>
421+ <varlistentry>
422+ <term>
423+ <literal>wait_for_window</literal>
424+ </term>
425+ <listitem>
426+ <para>
427+ Wait until an X11 window has appeared whose name matches the
428+ given regular expression, e.g.,
429+ <literal>wait_for_window(&quot;Terminal&quot;)</literal>.
430+ </para>
431+ </listitem>
432+ </varlistentry>
433+ <varlistentry>
434+ <term>
435+ <literal>copy_from_host</literal>
436+ </term>
437+ <listitem>
438+ <para>
439+ Copies a file from host to machine, e.g.,
440+ <literal>copy_from_host(&quot;myfile&quot;, &quot;/etc/my/important/file&quot;)</literal>.
441+ </para>
442+ <para>
443+ The first argument is the file on the host. The file needs to
444+ be accessible while building the nix derivation. The second
445+ argument is the location of the file on the machine.
446+ </para>
447+ </listitem>
448+ </varlistentry>
449+ <varlistentry>
450+ <term>
451+ <literal>systemctl</literal>
452+ </term>
453+ <listitem>
454+ <para>
455+ Runs <literal>systemctl</literal> commands with optional
456+ support for <literal>systemctl --user</literal>
457+ </para>
458+ <programlisting language="python">
459+machine.systemctl(&quot;list-jobs --no-pager&quot;) # runs `systemctl list-jobs --no-pager`
460+machine.systemctl(&quot;list-jobs --no-pager&quot;, &quot;any-user&quot;) # spawns a shell for `any-user` and runs `systemctl --user list-jobs --no-pager`
461+</programlisting>
462+ </listitem>
463+ </varlistentry>
464+ <varlistentry>
465+ <term>
466+ <literal>shell_interact</literal>
467+ </term>
468+ <listitem>
469+ <para>
470+ Allows you to directly interact with the guest shell. This
471+ should only be used during test development, not in production
472+ tests. Killing the interactive session with
473+ <literal>Ctrl-d</literal> or <literal>Ctrl-c</literal> also
474+ ends the guest session.
475+ </para>
476+ </listitem>
477+ </varlistentry>
478+ </variablelist>
479+ <para>
480+ To test user units declared by
481+ <literal>systemd.user.services</literal> the optional
482+ <literal>user</literal> argument can be used:
483+ </para>
484+ <programlisting language="python">
485+machine.start()
486+machine.wait_for_x()
487+machine.wait_for_unit(&quot;xautolock.service&quot;, &quot;x-session-user&quot;)
488+</programlisting>
489+ <para>
490+ This applies to <literal>systemctl</literal>,
491+ <literal>get_unit_info</literal>, <literal>wait_for_unit</literal>,
492+ <literal>start_job</literal> and <literal>stop_job</literal>.
493+ </para>
494+ <para>
495+ For faster dev cycles it's also possible to disable the code-linters
496+ (this shouldn't be commited though):
497+ </para>
498+ <programlisting language="bash">
499+import ./make-test-python.nix {
500+ skipLint = true;
501+ machine =
502+ { config, pkgs, ... }:
503+ { configuration…
504+ };
505+
506+ testScript =
507+ ''
508+ Python code…
509+ '';
510+}
511+</programlisting>
512+ <para>
513+ This will produce a Nix warning at evaluation time. To fully disable
514+ the linter, wrap the test script in comment directives to disable
515+ the Black linter directly (again, don't commit this within the
516+ Nixpkgs repository):
517+ </para>
518+ <programlisting language="bash">
519+ testScript =
520+ ''
521+ # fmt: off
522+ Python code…
523+ # fmt: on
524+ '';
525+</programlisting>
526+</section>