Merge staging-next into staging
This commit is contained in:
commit
fd4afd6d9b
26 changed files with 2402 additions and 1342 deletions
|
@ -17,9 +17,9 @@ trap "rm ${tmpfile}" 0
|
||||||
|
|
||||||
echo "Remember that you need to manually run 'maintainers/scripts/haskell/hydra-report.hs get-report' sometime before running this script."
|
echo "Remember that you need to manually run 'maintainers/scripts/haskell/hydra-report.hs get-report' sometime before running this script."
|
||||||
echo "Generating a list of broken builds and displaying for manual confirmation ..."
|
echo "Generating a list of broken builds and displaying for manual confirmation ..."
|
||||||
maintainers/scripts/haskell/hydra-report.hs mark-broken-list | sort -i > $tmpfile
|
maintainers/scripts/haskell/hydra-report.hs mark-broken-list | sort -i > "$tmpfile"
|
||||||
|
|
||||||
$EDITOR $tmpfile
|
$EDITOR "$tmpfile"
|
||||||
|
|
||||||
tail -n +3 "$broken_config" >> "$tmpfile"
|
tail -n +3 "$broken_config" >> "$tmpfile"
|
||||||
|
|
||||||
|
@ -28,10 +28,11 @@ broken-packages:
|
||||||
# These packages don't compile.
|
# These packages don't compile.
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
# clear environment here to avoid things like allowing broken builds in
|
||||||
sort -iu "$tmpfile" >> "$broken_config"
|
sort -iu "$tmpfile" >> "$broken_config"
|
||||||
maintainers/scripts/haskell/regenerate-hackage-packages.sh
|
env -i maintainers/scripts/haskell/regenerate-hackage-packages.sh
|
||||||
maintainers/scripts/haskell/regenerate-transitive-broken-packages.sh
|
env -i maintainers/scripts/haskell/regenerate-transitive-broken-packages.sh
|
||||||
maintainers/scripts/haskell/regenerate-hackage-packages.sh
|
env -i maintainers/scripts/haskell/regenerate-hackage-packages.sh
|
||||||
|
|
||||||
if [[ "${1:-}" == "--do-commit" ]]; then
|
if [[ "${1:-}" == "--do-commit" ]]; then
|
||||||
git add $broken_config
|
git add $broken_config
|
||||||
|
|
|
@ -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
|
one or more virtual machines containing the NixOS system(s) required for the
|
||||||
test.
|
test.
|
||||||
</para>
|
</para>
|
||||||
<xi:include href="writing-nixos-tests.xml" />
|
<xi:include href="../from_md/development/writing-nixos-tests.section.xml" />
|
||||||
<xi:include href="running-nixos-tests.xml" />
|
<xi:include href="../from_md/development/running-nixos-tests.section.xml" />
|
||||||
<xi:include href="running-nixos-tests-interactively.xml" />
|
<xi:include href="../from_md/development/running-nixos-tests-interactively.section.xml" />
|
||||||
</chapter>
|
</chapter>
|
||||||
|
|
|
@ -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.
|
|
@ -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>></prompt>
|
|
||||||
</screen>
|
|
||||||
You can then take any Python statement, e.g.
|
|
||||||
<screen>
|
|
||||||
<prompt>></prompt> start_all()
|
|
||||||
<prompt>></prompt> test_script()
|
|
||||||
<prompt>></prompt> machine.succeed("touch /tmp/foo")
|
|
||||||
<prompt>></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>
|
|
31
nixos/doc/manual/development/running-nixos-tests.section.md
Normal file
31
nixos/doc/manual/development/running-nixos-tests.section.md
Normal file
|
@ -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
|
||||||
|
```
|
|
@ -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 '<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>
|
|
301
nixos/doc/manual/development/writing-nixos-tests.section.md
Normal file
301
nixos/doc/manual/development/writing-nixos-tests.section.md
Normal file
|
@ -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
|
||||||
|
'';
|
||||||
|
```
|
|
@ -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>
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" 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:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
$ nix-build nixos/tests/login.nix -A driverInteractive
|
||||||
|
$ ./result/bin/nixos-test-driver
|
||||||
|
starting VDE switch for network 1
|
||||||
|
>
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
You can then take any Python statement, e.g.
|
||||||
|
</para>
|
||||||
|
<programlisting language="python">
|
||||||
|
> start_all()
|
||||||
|
> test_script()
|
||||||
|
> machine.succeed("touch /tmp/foo")
|
||||||
|
> print(machine.succeed("pwd")) # Show stdout of command
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
The function <literal>test_script</literal> 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:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
$ nix-build nixos/tests/login.nix -A driverInteractive
|
||||||
|
$ ./result/bin/nixos-run-vms
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
The script <literal>nixos-run-vms</literal> starts the virtual
|
||||||
|
machines defined by test.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
You can re-use the VM states coming from a previous run by setting
|
||||||
|
the <literal>--keep-vm-state</literal> flag.
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
$ ./result/bin/nixos-run-vms --keep-vm-state
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
The machine state is stored in the
|
||||||
|
<literal>$TMPDIR/vm-state-machinename</literal> directory.
|
||||||
|
</para>
|
||||||
|
</section>
|
|
@ -0,0 +1,34 @@
|
||||||
|
<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-running-nixos-tests">
|
||||||
|
<title>Running Tests</title>
|
||||||
|
<para>
|
||||||
|
You can run tests using <literal>nix-build</literal>. For example,
|
||||||
|
to run the test
|
||||||
|
<link xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/login.nix"><literal>login.nix</literal></link>,
|
||||||
|
you just do:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
$ nix-build '<nixpkgs/nixos/tests/login.nix>'
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
or, if you don’t want to rely on <literal>NIX_PATH</literal>:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
$ 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
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
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:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
$ firefox result/log.html
|
||||||
|
</programlisting>
|
||||||
|
</section>
|
|
@ -0,0 +1,526 @@
|
||||||
|
<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-writing-nixos-tests">
|
||||||
|
<title>Writing Tests</title>
|
||||||
|
<para>
|
||||||
|
A NixOS test is a Nix expression that has the following structure:
|
||||||
|
</para>
|
||||||
|
<programlisting language="bash">
|
||||||
|
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…
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
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,
|
||||||
|
<link xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/login.nix"><literal>login.nix</literal></link>
|
||||||
|
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,
|
||||||
|
<link xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/nfs/simple.nix"><literal>nfs/simple.nix</literal></link>,
|
||||||
|
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:
|
||||||
|
</para>
|
||||||
|
<variablelist>
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<literal>virtualisation.memorySize</literal>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The memory of the VM in megabytes.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<literal>virtualisation.vlans</literal>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The virtual networks to which the VM is connected. See
|
||||||
|
<link xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/nat.nix"><literal>nat.nix</literal></link>
|
||||||
|
for an example.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<literal>virtualisation.writableStore</literal>
|
||||||
|
</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>
|
||||||
|
<para>
|
||||||
|
For more options, see the module
|
||||||
|
<link xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/virtualisation/qemu-vm.nix"><literal>qemu-vm.nix</literal></link>.
|
||||||
|
</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>name</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:
|
||||||
|
</para>
|
||||||
|
<programlisting language="python">
|
||||||
|
machine.start()
|
||||||
|
machine.wait_for_unit("default.target")
|
||||||
|
if not "Linux" in machine.succeed("uname"):
|
||||||
|
raise Exception("Wrong OS")
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
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:
|
||||||
|
</para>
|
||||||
|
<programlisting language="python">
|
||||||
|
start_all()
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
The following methods are available on machine objects:
|
||||||
|
</para>
|
||||||
|
<variablelist>
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<literal>start</literal>
|
||||||
|
</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>
|
||||||
|
<literal>shutdown</literal>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Shut down the machine, waiting for the VM to exit.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<literal>crash</literal>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Simulate a sudden power failure, by telling the VM to exit
|
||||||
|
immediately.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<literal>block</literal>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Simulate unplugging the Ethernet cable that connects the
|
||||||
|
machine to the other machines.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<literal>unblock</literal>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Undo the effect of <literal>block</literal>.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<literal>screenshot</literal>
|
||||||
|
</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>
|
||||||
|
<literal>get_screen_text_variants</literal>
|
||||||
|
</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 <literal>enableOCR</literal> to the
|
||||||
|
test attribute set.
|
||||||
|
</para>
|
||||||
|
</note>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<literal>get_screen_text</literal>
|
||||||
|
</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 <literal>enableOCR</literal> to the
|
||||||
|
test attribute set.
|
||||||
|
</para>
|
||||||
|
</note>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<literal>send_monitor_command</literal>
|
||||||
|
</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>
|
||||||
|
<literal>send_key</literal>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Simulate pressing keys on the virtual keyboard, e.g.,
|
||||||
|
<literal>send_key("ctrl-alt-delete")</literal>.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<literal>send_chars</literal>
|
||||||
|
</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>
|
||||||
|
<literal>execute</literal>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Execute a shell command, returning a list
|
||||||
|
<literal>(status, stdout)</literal>.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<literal>succeed</literal>
|
||||||
|
</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:
|
||||||
|
</para>
|
||||||
|
<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>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<literal>fail</literal>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Like <literal>succeed</literal>, but raising an exception if
|
||||||
|
the command returns a zero status.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<literal>wait_until_succeeds</literal>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Repeat a shell command with 1-second intervals until it
|
||||||
|
succeeds.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<literal>wait_until_fails</literal>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Repeat a shell command with 1-second intervals until it fails.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<literal>wait_for_unit</literal>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Wait until the specified systemd unit has reached the
|
||||||
|
<quote>active</quote> state.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<literal>wait_for_file</literal>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Wait until the specified file exists.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<literal>wait_for_open_port</literal>
|
||||||
|
</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>
|
||||||
|
<literal>wait_for_closed_port</literal>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Wait until nobody is listening on the given TCP port.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<literal>wait_for_x</literal>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Wait until the X11 server is accepting connections.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<literal>wait_for_text</literal>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Wait until the supplied regular expressions matches the
|
||||||
|
textual contents of the screen by using optical character
|
||||||
|
recognition (see <literal>get_screen_text</literal> and
|
||||||
|
<literal>get_screen_text_variants</literal>).
|
||||||
|
</para>
|
||||||
|
<note>
|
||||||
|
<para>
|
||||||
|
This requires passing <literal>enableOCR</literal> to the
|
||||||
|
test attribute set.
|
||||||
|
</para>
|
||||||
|
</note>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<literal>wait_for_console_text</literal>
|
||||||
|
</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>
|
||||||
|
<literal>wait_for_window</literal>
|
||||||
|
</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>
|
||||||
|
<literal>copy_from_host</literal>
|
||||||
|
</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>
|
||||||
|
<literal>systemctl</literal>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Runs <literal>systemctl</literal> commands with optional
|
||||||
|
support for <literal>systemctl --user</literal>
|
||||||
|
</para>
|
||||||
|
<programlisting language="python">
|
||||||
|
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>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<literal>shell_interact</literal>
|
||||||
|
</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>
|
||||||
|
To test user units declared by
|
||||||
|
<literal>systemd.user.services</literal> the optional
|
||||||
|
<literal>user</literal> argument can be used:
|
||||||
|
</para>
|
||||||
|
<programlisting language="python">
|
||||||
|
machine.start()
|
||||||
|
machine.wait_for_x()
|
||||||
|
machine.wait_for_unit("xautolock.service", "x-session-user")
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
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):
|
||||||
|
</para>
|
||||||
|
<programlisting language="bash">
|
||||||
|
import ./make-test-python.nix {
|
||||||
|
skipLint = true;
|
||||||
|
machine =
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
{ configuration…
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript =
|
||||||
|
''
|
||||||
|
Python code…
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
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):
|
||||||
|
</para>
|
||||||
|
<programlisting language="bash">
|
||||||
|
testScript =
|
||||||
|
''
|
||||||
|
# fmt: off
|
||||||
|
Python code…
|
||||||
|
# fmt: on
|
||||||
|
'';
|
||||||
|
</programlisting>
|
||||||
|
</section>
|
|
@ -126,6 +126,14 @@ in
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
environment.localBinInPath = mkOption {
|
||||||
|
description = ''
|
||||||
|
Add ~/.local/bin/ to $PATH
|
||||||
|
'';
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
};
|
||||||
|
|
||||||
environment.binsh = mkOption {
|
environment.binsh = mkOption {
|
||||||
default = "${config.system.build.binsh}/bin/sh";
|
default = "${config.system.build.binsh}/bin/sh";
|
||||||
defaultText = "\${config.system.build.binsh}/bin/sh";
|
defaultText = "\${config.system.build.binsh}/bin/sh";
|
||||||
|
@ -198,6 +206,10 @@ in
|
||||||
# ~/bin if it exists overrides other bin directories.
|
# ~/bin if it exists overrides other bin directories.
|
||||||
export PATH="$HOME/bin:$PATH"
|
export PATH="$HOME/bin:$PATH"
|
||||||
''}
|
''}
|
||||||
|
|
||||||
|
${optionalString cfg.localBinInPath ''
|
||||||
|
export PATH="$HOME/.local/bin:$PATH"
|
||||||
|
''}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
system.activationScripts.binsh = stringAfter [ "stdio" ]
|
system.activationScripts.binsh = stringAfter [ "stdio" ]
|
||||||
|
|
|
@ -99,9 +99,22 @@ in
|
||||||
LockFile = "/run/geoipupdate/.lock";
|
LockFile = "/run/geoipupdate/.lock";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
systemd.services.geoipupdate-create-db-dir = {
|
||||||
|
serviceConfig.Type = "oneshot";
|
||||||
|
script = ''
|
||||||
|
mkdir -p ${cfg.settings.DatabaseDirectory}
|
||||||
|
chmod 0755 ${cfg.settings.DatabaseDirectory}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
systemd.services.geoipupdate = {
|
systemd.services.geoipupdate = {
|
||||||
description = "GeoIP Updater";
|
description = "GeoIP Updater";
|
||||||
after = [ "network-online.target" "nss-lookup.target" ];
|
requires = [ "geoipupdate-create-db-dir.service" ];
|
||||||
|
after = [
|
||||||
|
"geoipupdate-create-db-dir.service"
|
||||||
|
"network-online.target"
|
||||||
|
"nss-lookup.target"
|
||||||
|
];
|
||||||
wants = [ "network-online.target" ];
|
wants = [ "network-online.target" ];
|
||||||
startAt = cfg.interval;
|
startAt = cfg.interval;
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
|
@ -119,11 +132,9 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
geoipupdateConf = pkgs.writeText "discourse.conf" (geoipupdateKeyValue cfg.settings);
|
geoipupdateConf = pkgs.writeText "geoipupdate.conf" (geoipupdateKeyValue cfg.settings);
|
||||||
|
|
||||||
script = ''
|
script = ''
|
||||||
mkdir -p "${cfg.settings.DatabaseDirectory}"
|
|
||||||
chmod 755 "${cfg.settings.DatabaseDirectory}"
|
|
||||||
chown geoip "${cfg.settings.DatabaseDirectory}"
|
chown geoip "${cfg.settings.DatabaseDirectory}"
|
||||||
|
|
||||||
cp ${geoipupdateConf} /run/geoipupdate/GeoIP.conf
|
cp ${geoipupdateConf} /run/geoipupdate/GeoIP.conf
|
||||||
|
@ -139,7 +150,38 @@ in
|
||||||
ReadWritePaths = cfg.settings.DatabaseDirectory;
|
ReadWritePaths = cfg.settings.DatabaseDirectory;
|
||||||
RuntimeDirectory = "geoipupdate";
|
RuntimeDirectory = "geoipupdate";
|
||||||
RuntimeDirectoryMode = 0700;
|
RuntimeDirectoryMode = 0700;
|
||||||
|
CapabilityBoundingSet = "";
|
||||||
|
PrivateDevices = true;
|
||||||
|
PrivateMounts = true;
|
||||||
|
PrivateUsers = true;
|
||||||
|
ProtectClock = true;
|
||||||
|
ProtectControlGroups = true;
|
||||||
|
ProtectHome = true;
|
||||||
|
ProtectHostname = true;
|
||||||
|
ProtectKernelLogs = true;
|
||||||
|
ProtectKernelModules = true;
|
||||||
|
ProtectKernelTunables = true;
|
||||||
|
ProtectProc = "invisible";
|
||||||
|
ProcSubset = "pid";
|
||||||
|
SystemCallFilter = [ "@system-service" "~@privileged" "~@resources" ];
|
||||||
|
RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
|
||||||
|
RestrictRealtime = true;
|
||||||
|
RestrictNamespaces = true;
|
||||||
|
MemoryDenyWriteExecute = true;
|
||||||
|
LockPersonality = true;
|
||||||
|
SystemCallArchitectures = "native";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.timers.geoipupdate-initial-run = {
|
||||||
|
wantedBy = [ "timers.target" ];
|
||||||
|
unitConfig.ConditionPathExists = "!${cfg.settings.DatabaseDirectory}";
|
||||||
|
timerConfig = {
|
||||||
|
Unit = "geoipupdate.service";
|
||||||
|
OnActiveSec = 0;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
meta.maintainers = [ lib.maintainers.talyz ];
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,8 @@ stdenv.mkDerivation rec {
|
||||||
|
|
||||||
outputs = [ "bin" "out" "dev" "man" ];
|
outputs = [ "bin" "out" "dev" "man" ];
|
||||||
|
|
||||||
|
depsBuildBuild = [ pkg-config ];
|
||||||
|
|
||||||
nativeBuildInputs = [ meson ninja pkg-config scdoc ];
|
nativeBuildInputs = [ meson ninja pkg-config scdoc ];
|
||||||
|
|
||||||
buildInputs = [ systemd ];
|
buildInputs = [ systemd ];
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
pname = "lean";
|
pname = "lean";
|
||||||
version = "3.30.0";
|
version = "3.31.0";
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "leanprover-community";
|
owner = "leanprover-community";
|
||||||
|
@ -11,8 +11,8 @@ stdenv.mkDerivation rec {
|
||||||
# from. this is then used to check whether an olean file should be
|
# from. this is then used to check whether an olean file should be
|
||||||
# rebuilt. don't use a tag as rev because this will get replaced into
|
# rebuilt. don't use a tag as rev because this will get replaced into
|
||||||
# src/githash.h.in in preConfigure.
|
# src/githash.h.in in preConfigure.
|
||||||
rev = "a5822ea47ebc52eec6323d8f1b60f6ec025daf99";
|
rev = "333783350cd3fe38f25fed1da7d6a433d8f85b77";
|
||||||
sha256 = "sha256-gJhbkl19iilNyfCt2TfPmghYA3yCjg6kS+yk/x/k14Y=";
|
sha256 = "sha256-N8Ju7pSGssvt84/0e1o6G/p7fWM1c0Mzw+ftL1/++J4=";
|
||||||
};
|
};
|
||||||
|
|
||||||
nativeBuildInputs = [ cmake ];
|
nativeBuildInputs = [ cmake ];
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
}:
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
version = "1.8.0";
|
version = "1.8.1";
|
||||||
|
|
||||||
# build stimuli file for PGO build and the script to generate it
|
# build stimuli file for PGO build and the script to generate it
|
||||||
# independently of the foot's build, so we can cache the result
|
# independently of the foot's build, so we can cache the result
|
||||||
|
@ -94,7 +94,7 @@ stdenv.mkDerivation rec {
|
||||||
|
|
||||||
src = fetchzip {
|
src = fetchzip {
|
||||||
url = "https://codeberg.org/dnkl/${pname}/archive/${version}.tar.gz";
|
url = "https://codeberg.org/dnkl/${pname}/archive/${version}.tar.gz";
|
||||||
sha256 = "07irlhkvziv51cp5zn1yz8ljfnrnfjcykv5pgfwmpslw3nl5szxv";
|
sha256 = "0yrz7n0wls8g8w7ja934icwxmng3sxh70x87qmzc9c9cb1wyd989";
|
||||||
};
|
};
|
||||||
|
|
||||||
nativeBuildInputs = [
|
nativeBuildInputs = [
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"commit": "8005ce7c7ba90fa92db65f86c544623353a96cf8",
|
"commit": "1567e96c400fcd62dfc0d9412881591d6e1e9f22",
|
||||||
"url": "https://github.com/commercialhaskell/all-cabal-hashes/archive/8005ce7c7ba90fa92db65f86c544623353a96cf8.tar.gz",
|
"url": "https://github.com/commercialhaskell/all-cabal-hashes/archive/1567e96c400fcd62dfc0d9412881591d6e1e9f22.tar.gz",
|
||||||
"sha256": "1kzhh7h0csb0vh9avbjsm6hziaa3lbpmzp4pkij4s3bbl4l664aa",
|
"sha256": "04z26ypfp3nip2x6gwrv5k1lmckmmi03ry3z97syc72qqj59n9hq",
|
||||||
"msg": "Update from Hackage at 2021-06-22T07:13:30Z"
|
"msg": "Update from Hackage at 2021-06-26T12:56:56Z"
|
||||||
}
|
}
|
||||||
|
|
|
@ -706,10 +706,6 @@ self: super: {
|
||||||
uuid-types = doJailbreak super.uuid-types;
|
uuid-types = doJailbreak super.uuid-types;
|
||||||
uuid = doJailbreak super.uuid;
|
uuid = doJailbreak super.uuid;
|
||||||
|
|
||||||
# Bypass version check for random < 1.2 (1.2 works fine).
|
|
||||||
# https://github.com/yeyan/xmonad-wallpaper/issues/2
|
|
||||||
xmonad-wallpaper = doJailbreak super.xmonad-wallpaper;
|
|
||||||
|
|
||||||
# The tests spuriously fail
|
# The tests spuriously fail
|
||||||
libmpd = dontCheck super.libmpd;
|
libmpd = dontCheck super.libmpd;
|
||||||
|
|
||||||
|
@ -1936,4 +1932,12 @@ EOT
|
||||||
# https://github.com/dagit/zenc/issues/5
|
# https://github.com/dagit/zenc/issues/5
|
||||||
zenc = doJailbreak super.zenc;
|
zenc = doJailbreak super.zenc;
|
||||||
|
|
||||||
|
# Indeterministic tests
|
||||||
|
# Fixed on upstream: https://github.com/softwarefactory-project/matrix-client-haskell/commit/4ca4963cfd06379d9bdce49742af854aed6a0d37
|
||||||
|
matrix-client = dontCheck super.matrix-client;
|
||||||
|
|
||||||
|
# Flakey tests
|
||||||
|
# upstream https://github.com/circuithub/rel8/issues/86
|
||||||
|
rel8 = dontCheck super.rel8;
|
||||||
|
|
||||||
} // import ./configuration-tensorflow.nix {inherit pkgs haskellLib;} self super
|
} // import ./configuration-tensorflow.nix {inherit pkgs haskellLib;} self super
|
||||||
|
|
|
@ -173,6 +173,7 @@ self: super: {
|
||||||
hls-brittany-plugin = dontCheck super.hls-brittany-plugin;
|
hls-brittany-plugin = dontCheck super.hls-brittany-plugin;
|
||||||
hls-fourmolu-plugin = dontCheck super.hls-fourmolu-plugin;
|
hls-fourmolu-plugin = dontCheck super.hls-fourmolu-plugin;
|
||||||
hls-module-name-plugin = dontCheck super.hls-module-name-plugin;
|
hls-module-name-plugin = dontCheck super.hls-module-name-plugin;
|
||||||
|
hls-splice-plugin = dontCheck super.hls-splice-plugin;
|
||||||
|
|
||||||
# We are lacking pure pgrep at the moment for tests to work
|
# We are lacking pure pgrep at the moment for tests to work
|
||||||
tmp-postgres = dontCheck super.tmp-postgres;
|
tmp-postgres = dontCheck super.tmp-postgres;
|
||||||
|
|
|
@ -617,6 +617,7 @@ broken-packages:
|
||||||
- chunky
|
- chunky
|
||||||
- church
|
- church
|
||||||
- church-maybe
|
- church-maybe
|
||||||
|
- churros
|
||||||
- cielo
|
- cielo
|
||||||
- cil
|
- cil
|
||||||
- cinvoke
|
- cinvoke
|
||||||
|
@ -1640,7 +1641,6 @@ broken-packages:
|
||||||
- gitter
|
- gitter
|
||||||
- git-vogue
|
- git-vogue
|
||||||
- gi-vips
|
- gi-vips
|
||||||
- gi-wnck
|
|
||||||
- glade
|
- glade
|
||||||
- glapp
|
- glapp
|
||||||
- Gleam
|
- Gleam
|
||||||
|
@ -2289,6 +2289,7 @@ broken-packages:
|
||||||
- hs-rs-notify
|
- hs-rs-notify
|
||||||
- hs-scrape
|
- hs-scrape
|
||||||
- hsseccomp
|
- hsseccomp
|
||||||
|
- hssh
|
||||||
- hs-snowtify
|
- hs-snowtify
|
||||||
- hs-speedscope
|
- hs-speedscope
|
||||||
- hsSqlite3
|
- hsSqlite3
|
||||||
|
@ -2453,6 +2454,7 @@ broken-packages:
|
||||||
- initialize
|
- initialize
|
||||||
- inject-function
|
- inject-function
|
||||||
- inline-asm
|
- inline-asm
|
||||||
|
- inline-r
|
||||||
- inserts
|
- inserts
|
||||||
- instana-haskell-trace-sdk
|
- instana-haskell-trace-sdk
|
||||||
- instance-map
|
- instance-map
|
||||||
|
@ -2963,6 +2965,7 @@ broken-packages:
|
||||||
- mi
|
- mi
|
||||||
- miconix-test
|
- miconix-test
|
||||||
- microbase
|
- microbase
|
||||||
|
- microformats2-parser
|
||||||
- microgroove
|
- microgroove
|
||||||
- microlens-each
|
- microlens-each
|
||||||
- micrologger
|
- micrologger
|
||||||
|
@ -3597,6 +3600,7 @@ broken-packages:
|
||||||
- plat
|
- plat
|
||||||
- platinum-parsing
|
- platinum-parsing
|
||||||
- PlayingCards
|
- PlayingCards
|
||||||
|
- plex
|
||||||
- plist
|
- plist
|
||||||
- plist-buddy
|
- plist-buddy
|
||||||
- plot-gtk
|
- plot-gtk
|
||||||
|
@ -3979,6 +3983,7 @@ broken-packages:
|
||||||
- reversi
|
- reversi
|
||||||
- ReviewBoard
|
- ReviewBoard
|
||||||
- rewrite-inspector
|
- rewrite-inspector
|
||||||
|
- rfc
|
||||||
- rfc-prelude
|
- rfc-prelude
|
||||||
- rhbzquery
|
- rhbzquery
|
||||||
- ribbit
|
- ribbit
|
||||||
|
@ -4869,6 +4874,7 @@ broken-packages:
|
||||||
- turing-music
|
- turing-music
|
||||||
- turtle-options
|
- turtle-options
|
||||||
- tweak
|
- tweak
|
||||||
|
- twee
|
||||||
- twentefp-websockets
|
- twentefp-websockets
|
||||||
- twfy-api-client
|
- twfy-api-client
|
||||||
- twhs
|
- twhs
|
||||||
|
|
|
@ -218,6 +218,7 @@ package-maintainers:
|
||||||
- hlint
|
- hlint
|
||||||
- hmatrix
|
- hmatrix
|
||||||
- iCalendar
|
- iCalendar
|
||||||
|
- matrix-client
|
||||||
- neuron
|
- neuron
|
||||||
- optics
|
- optics
|
||||||
- reflex-dom
|
- reflex-dom
|
||||||
|
@ -356,6 +357,7 @@ unsupported-platforms:
|
||||||
gi-ibus: [ x86_64-darwin ]
|
gi-ibus: [ x86_64-darwin ]
|
||||||
gi-ostree: [ x86_64-darwin ]
|
gi-ostree: [ x86_64-darwin ]
|
||||||
gi-vte: [ x86_64-darwin ]
|
gi-vte: [ x86_64-darwin ]
|
||||||
|
gi-wnck: [ x86_64-darwin ]
|
||||||
gnome-keyring: [ x86_64-darwin ]
|
gnome-keyring: [ x86_64-darwin ]
|
||||||
gtk-mac-integration: [ i686-linux, x86_64-linux, aarch64-linux, armv7l-linux ]
|
gtk-mac-integration: [ i686-linux, x86_64-linux, aarch64-linux, armv7l-linux ]
|
||||||
gtk-sni-tray: [ x86_64-darwin ]
|
gtk-sni-tray: [ x86_64-darwin ]
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -44,6 +44,7 @@ in
|
||||||
, libraryFrameworkDepends ? [], executableFrameworkDepends ? []
|
, libraryFrameworkDepends ? [], executableFrameworkDepends ? []
|
||||||
, homepage ? "https://hackage.haskell.org/package/${pname}"
|
, homepage ? "https://hackage.haskell.org/package/${pname}"
|
||||||
, platforms ? with lib.platforms; all # GHC can cross-compile
|
, platforms ? with lib.platforms; all # GHC can cross-compile
|
||||||
|
, badPlatforms ? lib.platforms.none
|
||||||
, hydraPlatforms ? null
|
, hydraPlatforms ? null
|
||||||
, hyperlinkSource ? true
|
, hyperlinkSource ? true
|
||||||
, isExecutable ? false, isLibrary ? !isExecutable
|
, isExecutable ? false, isLibrary ? !isExecutable
|
||||||
|
@ -289,7 +290,7 @@ in lib.fix (drv:
|
||||||
assert allPkgconfigDepends != [] -> pkg-config != null;
|
assert allPkgconfigDepends != [] -> pkg-config != null;
|
||||||
|
|
||||||
stdenv.mkDerivation ({
|
stdenv.mkDerivation ({
|
||||||
name = "${pname}-${version}";
|
inherit pname version;
|
||||||
|
|
||||||
outputs = [ "out" ]
|
outputs = [ "out" ]
|
||||||
++ (optional enableSeparateDataOutput "data")
|
++ (optional enableSeparateDataOutput "data")
|
||||||
|
@ -663,6 +664,7 @@ stdenv.mkDerivation ({
|
||||||
// optionalAttrs (args ? description) { inherit description; }
|
// optionalAttrs (args ? description) { inherit description; }
|
||||||
// optionalAttrs (args ? maintainers) { inherit maintainers; }
|
// optionalAttrs (args ? maintainers) { inherit maintainers; }
|
||||||
// optionalAttrs (args ? hydraPlatforms) { inherit hydraPlatforms; }
|
// optionalAttrs (args ? hydraPlatforms) { inherit hydraPlatforms; }
|
||||||
|
// optionalAttrs (args ? badPlatforms) { inherit badPlatforms; }
|
||||||
// optionalAttrs (args ? changelog) { inherit changelog; }
|
// optionalAttrs (args ? changelog) { inherit changelog; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
880
pkgs/development/haskell-modules/hackage-packages.nix
generated
880
pkgs/development/haskell-modules/hackage-packages.nix
generated
File diff suppressed because it is too large
Load diff
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
buildGoModule rec {
|
buildGoModule rec {
|
||||||
pname = "grafana";
|
pname = "grafana";
|
||||||
version = "8.0.3";
|
version = "8.0.4";
|
||||||
|
|
||||||
excludedPackages = [ "release_publisher" ];
|
excludedPackages = [ "release_publisher" ];
|
||||||
|
|
||||||
|
@ -10,12 +10,12 @@ buildGoModule rec {
|
||||||
rev = "v${version}";
|
rev = "v${version}";
|
||||||
owner = "grafana";
|
owner = "grafana";
|
||||||
repo = "grafana";
|
repo = "grafana";
|
||||||
sha256 = "sha256-GGtmsz3c7Q6mEGCJ6cdz2CjOW0ovZZW8j6LMfFgrMZ4=";
|
sha256 = "sha256-I4TUPni2WDdpsV19nltsaF1PugB5SOtQ9Jb0YzWUwFg=";
|
||||||
};
|
};
|
||||||
|
|
||||||
srcStatic = fetchurl {
|
srcStatic = fetchurl {
|
||||||
url = "https://dl.grafana.com/oss/release/grafana-${version}.linux-amd64.tar.gz";
|
url = "https://dl.grafana.com/oss/release/grafana-${version}.linux-amd64.tar.gz";
|
||||||
sha256 = "sha256-2x0FhKinrXAFenJcUDh4Q3RJNBrqixKBNZT7BZNNOj8=";
|
sha256 = "sha256-GUVnw2kKxVfztvfsNMwRLxPTqRYzbxXzoH2GkmZB2JE=";
|
||||||
};
|
};
|
||||||
|
|
||||||
vendorSha256 = "sha256-x7sSVIim/TOhMTbnRK/fpgxiSRSO8KwGILTE2i1gU3U=";
|
vendorSha256 = "sha256-x7sSVIim/TOhMTbnRK/fpgxiSRSO8KwGILTE2i1gU3U=";
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
buildGoModule rec {
|
buildGoModule rec {
|
||||||
pname = "gopass";
|
pname = "gopass";
|
||||||
version = "1.12.6";
|
version = "1.12.7";
|
||||||
|
|
||||||
nativeBuildInputs = [ installShellFiles makeWrapper ];
|
nativeBuildInputs = [ installShellFiles makeWrapper ];
|
||||||
|
|
||||||
|
@ -21,10 +21,10 @@ buildGoModule rec {
|
||||||
owner = "gopasspw";
|
owner = "gopasspw";
|
||||||
repo = pname;
|
repo = pname;
|
||||||
rev = "v${version}";
|
rev = "v${version}";
|
||||||
sha256 = "17y9indpgqqx261bqvckfqq1q2zciahssaalaa5c5hb6bnw5ls52";
|
sha256 = "08mzm03vhc8pqyl17y8dkrcpgy3ckmb84x84b6ap3cja3y8gmj5x";
|
||||||
};
|
};
|
||||||
|
|
||||||
vendorSha256 = "106rn0bkvzf2fw21f6wpiya88ysj8sfc2zkkm47iqr23d2202i4b";
|
vendorSha256 = "0ym6f1h51bj3qlzxs936fz3p47l63nad4xckl16m13iy0k7z5flg";
|
||||||
|
|
||||||
subPackages = [ "." ];
|
subPackages = [ "." ];
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue