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