···11+/* Create tests that run in the nix sandbox with additional access to selected host paths
22+33+ This is for example useful for testing hardware where a tests needs access to
44+ /sys and optionally more.
55+66+ The following example shows a test that accesses the GPU:
77+88+ Example:
99+ makeImpureTest {
1010+ name = "opencl";
1111+ testedPackage = "mypackage"; # Or testPath = "mypackage.impureTests.opencl.testDerivation"
1212+1313+ sandboxPaths = [ "/sys" "/dev/dri" ]; # Defaults to ["/sys"]
1414+ prepareRunCommands = ""; # (Optional) Setup for the runScript
1515+ nixFlags = []; # (Optional) nix-build options for the runScript
1616+1717+ testScript = "...";
1818+ }
1919+2020+ Save as `test.nix` next to a package and reference it from the package:
2121+ passthru.impureTests = { opencl = callPackage ./test.nix {}; };
2222+2323+ `makeImpureTest` will return here a script that contains the actual nix-build command including all necessary sandbox flags.
2424+2525+ It can be executed like this:
2626+ $(nix-build -A mypackage.impureTests)
2727+2828+ Rerun an already cached test:
2929+ $(nix-build -A mypackage.impureTests) --check
3030+*/
3131+{ lib
3232+, stdenv
3333+, writeShellScript
3434+3535+, name
3636+, testedPackage ? null
3737+, testPath ? "${testedPackage}.impureTests.${name}.testDerivation"
3838+, sandboxPaths ? [ "/sys" ]
3939+, prepareRunCommands ? ""
4040+, nixFlags ? [ ]
4141+, testScript
4242+, ...
4343+} @ args:
4444+4545+let
4646+ sandboxPathsTests = builtins.map (path: "[[ ! -e '${path}' ]]") sandboxPaths;
4747+ sandboxPathsTest = lib.concatStringsSep " || " sandboxPathsTests;
4848+ sandboxPathsList = lib.concatStringsSep " " sandboxPaths;
4949+5050+ testDerivation = stdenv.mkDerivation (lib.recursiveUpdate
5151+ {
5252+ name = "test-run-${name}";
5353+5454+ requiredSystemFeatures = [ "nixos-test" ];
5555+5656+ buildCommand = ''
5757+ mkdir -p $out
5858+5959+ if ${sandboxPathsTest}; then
6060+ echo 'Run this test as *root* with `--option extra-sandbox-paths '"'${sandboxPathsList}'"'`'
6161+ exit 1
6262+ fi
6363+6464+ # Run test
6565+ ${testScript}
6666+ '';
6767+6868+ passthru.runScript = runScript;
6969+ }
7070+ (builtins.removeAttrs args [
7171+ "lib"
7272+ "stdenv"
7373+ "writeShellScript"
7474+7575+ "name"
7676+ "testedPackage"
7777+ "testPath"
7878+ "sandboxPaths"
7979+ "prepareRunCommands"
8080+ "nixFlags"
8181+ "testScript"
8282+ ])
8383+ );
8484+8585+ runScript = writeShellScript "run-script-${name}" ''
8686+ set -euo pipefail
8787+8888+ ${prepareRunCommands}
8989+9090+ sudo nix-build --option extra-sandbox-paths '${sandboxPathsList}' ${lib.escapeShellArgs nixFlags} -A ${testPath} "$@"
9191+ '';
9292+in
9393+# The main output is the run script, inject the derivation for the actual test
9494+runScript.overrideAttrs (old: {
9595+ passthru = { inherit testDerivation; };
9696+})