Home Explore Blog Models CI



nixpkgs

1st chunk of `nixos/doc/manual/development/writing-nixos-tests.section.md`
cfa5653607554d8ff3504d626f312ec1a5c6d3bf15c6377d0000000100000fe5
# Writing Tests {#sec-writing-nixos-tests}

A NixOS test is a module that has the following structure:

```nix
{

  # One or more machines:
  nodes = {
    machine =
      { config, pkgs, ... }:
      {
        # ...
      };
    machine2 =
      { config, pkgs, ... }:
      {
        # ...
      };
    # …
  };

  testScript = ''
    Python code…
  '';
}
```

We refer to the whole test above as a test module, whereas the values
in [`nodes.<name>`](#test-opt-nodes) are NixOS modules themselves.

The option [`testScript`](#test-opt-testScript) is a piece 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 option [`nodes`](#test-opt-nodes).

An example of a single-node test is
[`login.nix`](https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/login.nix).
It 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. An interesting multi-node test is
[`nfs/simple.nix`](https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/nfs/simple.nix).
It uses two client nodes to test correct locking across server crashes.

## Calling a test {#sec-calling-nixos-tests}

Tests are invoked differently depending on whether the test is part of NixOS or lives in a different project.

### Testing within NixOS {#sec-call-nixos-test-in-nixos}

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).

```nix
{ hostname = runTest ./hostname.nix; }
```

Overrides can be added by defining an anonymous module in `all-tests.nix`.

```nix
{
  hostname = runTest {
    imports = [ ./hostname.nix ];
    defaults.networking.firewall.enable = false;
  };
}
```

You can run a test with attribute name `hostname` in `nixos/tests/all-tests.nix` by invoking:

```shell
cd /my/git/clone/of/nixpkgs
nix-build -A nixosTests.hostname
```

### Testing outside the NixOS project {#sec-call-nixos-test-outside-nixos}

Outside the `nixpkgs` repository, you can use the `runNixOSTest` function from
`pkgs.testers`:

```nix
let
  pkgs = import <nixpkgs> { };

in
pkgs.testers.runNixOSTest {
  imports = [ ./test.nix ];
  defaults.services.foo.package = mypkg;
}
```

`runNixOSTest` returns a derivation that runs the test.

## Configuring the nodes {#sec-nixos-test-nodes}

There are a few special NixOS options for test VMs:

`virtualisation.memorySize`

:   The memory of the VM in MiB (1024×1024 bytes).

`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 specified a node `nodes.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")
t.assertIn("Linux", machine.succeed("uname"), "Wrong OS")
```

The first line is technically 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

Title: Writing and Running NixOS Tests
Summary
This document outlines how to write and execute NixOS tests. A NixOS test is structured as a Nix module containing `nodes` (configurations for one or more virtual machines) and a `testScript` (Python code that orchestrates the test, interacting with the VMs). Examples like `login.nix` and `nfs/simple.nix` demonstrate single and multi-node setups. The document also explains how to invoke tests: either by adding them to `nixos/tests/all-tests.nix` for tests within NixOS, or by using `pkgs.testers.runNixOSTest` for external projects. Special NixOS options for test VMs like `virtualisation.memorySize` and `virtualisation.writableStore` are mentioned. Finally, it details how the Python `testScript` interacts with VM objects to start machines, wait for services, and execute commands, with an example using `machine.start()`, `machine.wait_for_unit()`, and `machine.succeed()`.