1/*
2 Create tests that run in the nix sandbox with additional access to selected host paths
3
4 This is for example useful for testing hardware where a tests needs access to
5 /sys and optionally more.
6
7 The following example shows a test that accesses the GPU:
8
9 Example:
10 makeImpureTest {
11 name = "opencl";
12 testedPackage = "mypackage"; # Or testPath = "mypackage.impureTests.opencl.testDerivation"
13
14 sandboxPaths = [ "/sys" "/dev/dri" ]; # Defaults to ["/sys"]
15 prepareRunCommands = ""; # (Optional) Setup for the runScript
16 nixFlags = []; # (Optional) nix-build options for the runScript
17
18 testScript = "...";
19 }
20
21 Save as `test.nix` next to a package and reference it from the package:
22 passthru.impureTests = { opencl = callPackage ./test.nix {}; };
23
24 `makeImpureTest` will return here a script that contains the actual nix-build command including all necessary sandbox flags.
25
26 It can be executed like this:
27 $(nix-build -A mypackage.impureTests)
28
29 Rerun an already cached test:
30 $(nix-build -A mypackage.impureTests) --check
31*/
32{
33 lib,
34 stdenv,
35 writeShellScript,
36
37 name,
38 testedPackage ? null,
39 testPath ? "${testedPackage}.impureTests.${name}.testDerivation",
40 sandboxPaths ? [ "/sys" ],
41 prepareRunCommands ? "",
42 nixFlags ? [ ],
43 testScript,
44 ...
45}@args:
46
47let
48 sandboxPathsTests = builtins.map (path: "[[ ! -e '${path}' ]]") sandboxPaths;
49 sandboxPathsTest = lib.concatStringsSep " || " sandboxPathsTests;
50 sandboxPathsList = lib.concatStringsSep " " sandboxPaths;
51
52 testDerivation = stdenv.mkDerivation (
53 lib.recursiveUpdate
54 {
55 name = "test-run-${name}";
56
57 requiredSystemFeatures = [ "nixos-test" ];
58
59 buildCommand = ''
60 mkdir -p $out
61
62 if ${sandboxPathsTest}; then
63 echo 'Run this test as *root* with `--option extra-sandbox-paths '"'${sandboxPathsList}'"'`'
64 exit 1
65 fi
66
67 # Run test
68 ${testScript}
69 '';
70
71 passthru.runScript = runScript;
72 }
73 (
74 builtins.removeAttrs args [
75 "lib"
76 "stdenv"
77 "writeShellScript"
78
79 "name"
80 "testedPackage"
81 "testPath"
82 "sandboxPaths"
83 "prepareRunCommands"
84 "nixFlags"
85 "testScript"
86 ]
87 )
88 );
89
90 runScript = writeShellScript "run-script-${name}" ''
91 set -euo pipefail
92
93 ${prepareRunCommands}
94
95 sudo nix-build --option extra-sandbox-paths '${sandboxPathsList}' ${lib.escapeShellArgs nixFlags} -A ${testPath} "$@"
96 '';
97in
98# The main output is the run script, inject the derivation for the actual test
99runScript.overrideAttrs (old: {
100 passthru = { inherit testDerivation; };
101})