biglybt: 3.5.0.0 -> 3.6.0.0
[NixPkgs.git] / nixos / doc / manual / development / writing-nixos-tests.section.md
blob3ce12f41c60fe4fef972f66b24e5aed0d90afa8a
1 # Writing Tests {#sec-writing-nixos-tests}
3 A NixOS test is a module that has the following structure:
5 ```nix
8   # One or more machines:
9   nodes =
10     { machine =
11         { config, pkgs, ... }: { /* ... */ };
12       machine2 =
13         { config, pkgs, ... }: { /* ... */ };
14       # …
15     };
17   testScript =
18     ''
19       Python code…
20     '';
22 ```
24 We refer to the whole test above as a test module, whereas the values
25 in [`nodes.<name>`](#test-opt-nodes) are NixOS modules themselves.
27 The option [`testScript`](#test-opt-testScript) is a piece of Python code that executes the
28 test (described below). During the test, it will start one or more
29 virtual machines, the configuration of which is described by
30 the option [`nodes`](#test-opt-nodes).
32 An example of a single-node test is
33 [`login.nix`](https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/login.nix).
34 It only needs a single machine to test whether users can log in
35 on the virtual console, whether device ownership is correctly maintained
36 when switching between consoles, and so on. An interesting multi-node test is
37 [`nfs/simple.nix`](https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/nfs/simple.nix).
38 It uses two client nodes to test correct locking across server crashes.
40 ## Calling a test {#sec-calling-nixos-tests}
42 Tests are invoked differently depending on whether the test is part of NixOS or lives in a different project.
44 ### Testing within NixOS {#sec-call-nixos-test-in-nixos}
46 Tests that are part of NixOS are added to [`nixos/tests/all-tests.nix`](https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/all-tests.nix).
48 ```nix
50   hostname = runTest ./hostname.nix;
52 ```
54 Overrides can be added by defining an anonymous module in `all-tests.nix`.
56 ```nix
58   hostname = runTest {
59     imports = [ ./hostname.nix ];
60     defaults.networking.firewall.enable = false;
61   };
63 ```
65 You can run a test with attribute name `hostname` in `nixos/tests/all-tests.nix` by invoking:
67 ```shell
68 cd /my/git/clone/of/nixpkgs
69 nix-build -A nixosTests.hostname
70 ```
72 ### Testing outside the NixOS project {#sec-call-nixos-test-outside-nixos}
74 Outside the `nixpkgs` repository, you can instantiate the test by first importing the NixOS library,
76 ```nix
77 let nixos-lib = import (nixpkgs + "/nixos/lib") { };
80 nixos-lib.runTest {
81   imports = [ ./test.nix ];
82   hostPkgs = pkgs;  # the Nixpkgs package set used outside the VMs
83   defaults.services.foo.package = mypkg;
85 ```
87 `runTest` returns a derivation that runs the test.
89 ## Configuring the nodes {#sec-nixos-test-nodes}
91 There are a few special NixOS options for test VMs:
93 `virtualisation.memorySize`
95 :   The memory of the VM in megabytes.
97 `virtualisation.vlans`
99 :   The virtual networks to which the VM is connected. See
100     [`nat.nix`](https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/nat.nix)
101     for an example.
103 `virtualisation.writableStore`
105 :   By default, the Nix store in the VM is not writable. If you enable
106     this option, a writable union file system is mounted on top of the
107     Nix store to make it appear writable. This is necessary for tests
108     that run Nix operations that modify the store.
110 For more options, see the module
111 [`qemu-vm.nix`](https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/virtualisation/qemu-vm.nix).
113 The test script is a sequence of Python statements that perform various
114 actions, such as starting VMs, executing commands in the VMs, and so on.
115 Each virtual machine is represented as an object stored in the variable
116 `name` if this is also the identifier of the machine in the declarative
117 config. If you specified a node `nodes.machine`, the following example starts the
118 machine, waits until it has finished booting, then executes a command
119 and checks that the output is more-or-less correct:
121 ```py
122 machine.start()
123 machine.wait_for_unit("default.target")
124 if not "Linux" in machine.succeed("uname"):
125   raise Exception("Wrong OS")
128 The first line is technically unnecessary; machines are implicitly started
129 when you first execute an action on them (such as `wait_for_unit` or
130 `succeed`). If you have multiple machines, you can speed up the test by
131 starting them in parallel:
133 ```py
134 start_all()
137 If the hostname of a node contains characters that can't be used in a
138 Python variable name, those characters will be replaced with
139 underscores in the variable name, so `nodes.machine-a` will be exposed
140 to Python as `machine_a`.
142 ## Machine objects {#ssec-machine-objects}
144 The following methods are available on machine objects:
146 @PYTHON_MACHINE_METHODS@
148 To test user units declared by `systemd.user.services` the optional
149 `user` argument can be used:
151 ```py
152 machine.start()
153 machine.wait_for_x()
154 machine.wait_for_unit("xautolock.service", "x-session-user")
157 This applies to `systemctl`, `get_unit_info`, `wait_for_unit`,
158 `start_job` and `stop_job`.
160 For faster dev cycles it's also possible to disable the code-linters
161 (this shouldn't be committed though):
163 ```nix
165   skipLint = true;
166   nodes.machine =
167     { config, pkgs, ... }:
168     { # configuration…
169     };
171   testScript =
172     ''
173       Python code…
174     '';
178 This will produce a Nix warning at evaluation time. To fully disable the
179 linter, wrap the test script in comment directives to disable the Black
180 linter directly (again, don't commit this within the Nixpkgs
181 repository):
183 ```nix
185   testScript =
186     ''
187       # fmt: off
188       Python code…
189       # fmt: on
190     '';
194 Similarly, the type checking of test scripts can be disabled in the following
195 way:
197 ```nix
199   skipTypeCheck = true;
200   nodes.machine =
201     { config, pkgs, ... }:
202     { # configuration…
203     };
207 ## Failing tests early {#ssec-failing-tests-early}
209 To fail tests early when certain invariants are no longer met (instead of waiting for the build to time out), the decorator `polling_condition` is provided. For example, if we are testing a program `foo` that should not quit after being started, we might write the following:
211 ```py
212 @polling_condition
213 def foo_running():
214     machine.succeed("pgrep -x foo")
217 machine.succeed("foo --start")
218 machine.wait_until_succeeds("pgrep -x foo")
220 with foo_running:
221     ...  # Put `foo` through its paces
224 `polling_condition` takes the following (optional) arguments:
226 `seconds_interval`
228 :   specifies how often the condition should be polled:
230 ```py
231 @polling_condition(seconds_interval=10)
232 def foo_running():
233     machine.succeed("pgrep -x foo")
236 `description`
238 :   is used in the log when the condition is checked. If this is not provided, the description is pulled from the docstring of the function. These two are therefore equivalent:
240 ```py
241 @polling_condition
242 def foo_running():
243     "check that foo is running"
244     machine.succeed("pgrep -x foo")
247 ```py
248 @polling_condition(description="check that foo is running")
249 def foo_running():
250     machine.succeed("pgrep -x foo")
253 ## Adding Python packages to the test script {#ssec-python-packages-in-test-script}
255 When additional Python libraries are required in the test script, they can be
256 added using the parameter `extraPythonPackages`. For example, you could add
257 `numpy` like this:
259 ```nix
261   extraPythonPackages = p: [ p.numpy ];
263   nodes = { };
265   # Type checking on extra packages doesn't work yet
266   skipTypeCheck = true;
268   testScript = ''
269     import numpy as np
270     assert str(np.zeros(4)) == "[0. 0. 0. 0.]"
271   '';
275 In that case, `numpy` is chosen from the generic `python3Packages`.
277 ## Test Options Reference {#sec-test-options-reference}
279 The following options can be used when writing tests.
281 ```{=include=} options
282 id-prefix: test-opt-
283 list-id: test-options-list
284 source: @NIXOS_TEST_OPTIONS_JSON@