diff --git a/pkgs/build-support/make-impure-test.nix b/pkgs/build-support/make-impure-test.nix new file mode 100644 index 000000000000..84d0b30f426a --- /dev/null +++ b/pkgs/build-support/make-impure-test.nix @@ -0,0 +1,96 @@ +/* Create tests that run in the nix sandbox with additional access to selected host paths + + This is for example useful for testing hardware where a tests needs access to + /sys and optionally more. + + The following example shows a test that accesses the GPU: + + Example: + makeImpureTest { + name = "opencl"; + testedPackage = "mypackage"; # Or testPath = "mypackage.impureTests.opencl.testDerivation" + + sandboxPaths = [ "/sys" "/dev/dri" ]; # Defaults to ["/sys"] + prepareRunCommands = ""; # (Optional) Setup for the runScript + nixFlags = []; # (Optional) nix-build options for the runScript + + testScript = "..."; + } + + Save as `test.nix` next to a package and reference it from the package: + passthru.impureTests = { opencl = callPackage ./test.nix {}; }; + + `makeImpureTest` will return here a script that contains the actual nix-build command including all necessary sandbox flags. + + It can be executed like this: + $(nix-build -A mypackage.impureTests) + + Rerun an already cached test: + $(nix-build -A mypackage.impureTests) --check +*/ +{ lib +, stdenv +, writeShellScript + +, name +, testedPackage ? null +, testPath ? "${testedPackage}.impureTests.${name}.testDerivation" +, sandboxPaths ? [ "/sys" ] +, prepareRunCommands ? "" +, nixFlags ? [ ] +, testScript +, ... +} @ args: + +let + sandboxPathsTests = builtins.map (path: "[[ ! -e '${path}' ]]") sandboxPaths; + sandboxPathsTest = lib.concatStringsSep " || " sandboxPathsTests; + sandboxPathsList = lib.concatStringsSep " " sandboxPaths; + + testDerivation = stdenv.mkDerivation (lib.recursiveUpdate + { + name = "test-run-${name}"; + + requiredSystemFeatures = [ "nixos-test" ]; + + buildCommand = '' + mkdir -p $out + + if ${sandboxPathsTest}; then + echo 'Run this test as *root* with `--option extra-sandbox-paths '"'${sandboxPathsList}'"'`' + exit 1 + fi + + # Run test + ${testScript} + ''; + + passthru.runScript = runScript; + } + (builtins.removeAttrs args [ + "lib" + "stdenv" + "writeShellScript" + + "name" + "testedPackage" + "testPath" + "sandboxPaths" + "prepareRunCommands" + "nixFlags" + "testScript" + ]) + ); + + runScript = writeShellScript "run-script-${name}" '' + set -euo pipefail + + ${prepareRunCommands} + + sudo nix-build --option extra-sandbox-paths '${sandboxPathsList}' ${lib.escapeShellArgs nixFlags} -A ${testPath} "$@" + ''; +in +# The main output is the run script, inject the derivation for the actual test +runScript.overrideAttrs (old: { + passthru = { inherit testDerivation; }; +}) diff --git a/pkgs/development/libraries/amdvlk/default.nix b/pkgs/development/libraries/amdvlk/default.nix index 954628986e46..0895698378d0 100644 --- a/pkgs/development/libraries/amdvlk/default.nix +++ b/pkgs/development/libraries/amdvlk/default.nix @@ -1,4 +1,5 @@ { stdenv +, callPackage , lib , fetchRepoProject , writeScript @@ -102,6 +103,8 @@ in stdenv.mkDerivation rec { setHash "$hash" ''; + passthru.impureTests = { amdvlk = callPackage ./test.nix {}; }; + meta = with lib; { description = "AMD Open Source Driver For Vulkan"; homepage = "https://github.com/GPUOpen-Drivers/AMDVLK"; diff --git a/pkgs/development/libraries/amdvlk/test.nix b/pkgs/development/libraries/amdvlk/test.nix new file mode 100644 index 000000000000..e76e6dce9eaf --- /dev/null +++ b/pkgs/development/libraries/amdvlk/test.nix @@ -0,0 +1,49 @@ +{ lib, makeImpureTest, coreutils, amdvlk, vulkan-tools }: +makeImpureTest { + name = "amdvlk"; + testedPackage = "amdvlk"; + + sandboxPaths = [ "/sys" "/dev/dri" ]; + + nativeBuildInputs = [ vulkan-tools ]; + + VK_ICD_FILENAMES = "${amdvlk}/share/vulkan/icd.d/amd_icd64.json"; + XDG_RUNTIME_DIR = "/tmp"; + + # AMDVLK needs access to /dev/dri/card0 (or another card), but normally it is rw-rw---- + # Change the permissions to be rw for everyone + prepareRunCommands = '' + function reset_perms() + { + # Reset permissions to previous state + for card in /dev/dri/card*; do + sudo ${coreutils}/bin/chmod "0''${cardPerms[$card]}" $card + done + } + + # Save permissions on /dev/dri/card* + declare -A cardPerms + for card in /dev/dri/card*; do + cardPerms[$card]=$(stat -c "%a" $card) + done + + sudo ${coreutils}/bin/chmod o+rw /dev/dri/card* + trap reset_perms EXIT + ''; + + testScript = '' + # Check that there is at least one card with write-access + if ! ls -l /dev/dri/card* | cut -b8-9 | grep -q rw; then + echo 'AMDVLK needs rw access to /dev/dri/card0 or a fitting card, please run `sudo chmod o+rw /dev/dri/card*`' + exit 1 + fi + + vulkaninfo --summary + echo "Checking version" + vulkaninfo --summary | grep '= ${amdvlk.version}' + ''; + + meta = with lib.maintainers; { + maintainers = [ Flakebi ]; + }; +} diff --git a/pkgs/development/libraries/rocm-opencl-icd/default.nix b/pkgs/development/libraries/rocm-opencl-icd/default.nix index 9b0f7ab9f81f..fb78c4f04dd0 100644 --- a/pkgs/development/libraries/rocm-opencl-icd/default.nix +++ b/pkgs/development/libraries/rocm-opencl-icd/default.nix @@ -1,4 +1,4 @@ -{ lib, stdenv, rocm-opencl-runtime }: +{ lib, callPackage, stdenv, rocm-opencl-runtime }: stdenv.mkDerivation rec { pname = "rocm-opencl-icd"; @@ -11,6 +11,8 @@ stdenv.mkDerivation rec { echo "${rocm-opencl-runtime}/lib/libamdocl64.so" > $out/etc/OpenCL/vendors/amdocl64.icd ''; + passthru.impureTests = { rocm-opencl = callPackage ./test.nix {}; }; + meta = with lib; { description = "OpenCL ICD definition for AMD GPUs using the ROCm stack"; license = licenses.mit; diff --git a/pkgs/development/libraries/rocm-opencl-icd/test.nix b/pkgs/development/libraries/rocm-opencl-icd/test.nix new file mode 100644 index 000000000000..398a4818e7c3 --- /dev/null +++ b/pkgs/development/libraries/rocm-opencl-icd/test.nix @@ -0,0 +1,19 @@ +{ lib, makeImpureTest, clinfo, rocm-opencl-icd, rocm-smi }: +makeImpureTest { + name = "rocm-opencl"; + testedPackage = "rocm-opencl-icd"; + + nativeBuildInputs = [ clinfo rocm-smi ]; + + OCL_ICD_VENDORS = "${rocm-opencl-icd}/etc/OpenCL/vendors/"; + + testScript = '' + # Test fails if the number of platforms is 0 + clinfo | grep -E 'Number of platforms * [1-9]' + rocm-smi | grep -A1 GPU + ''; + + meta = with lib; { + maintainers = teams.rocm.members; + }; +} diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index a319f0c306de..343176a0d47e 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -950,6 +950,8 @@ with pkgs; makeAutostartItem = callPackage ../build-support/make-startupitem { }; + makeImpureTest = callPackage ../build-support/make-impure-test.nix; + makeInitrd = callPackage ../build-support/kernel/make-initrd.nix; # Args intentionally left out makeInitrdNG = callPackage ../build-support/kernel/make-initrd-ng.nix;