about summary refs log tree commit diff
path: root/nixpkgs/pkgs/build-support/testers
diff options
context:
space:
mode:
authorAlyssa Ross <hi@alyssa.is>2023-06-16 06:56:35 +0000
committerAlyssa Ross <hi@alyssa.is>2023-06-16 06:56:35 +0000
commit99fcaeccb89621dd492203ce1f2d551c06f228ed (patch)
tree41cb730ae07383004789779b0f6e11cb3f4642a3 /nixpkgs/pkgs/build-support/testers
parent59c5f5ac8682acc13bb22bc29c7cf02f7d75f01f (diff)
parent75a5ebf473cd60148ba9aec0d219f72e5cf52519 (diff)
downloadnixlib-99fcaeccb89621dd492203ce1f2d551c06f228ed.tar
nixlib-99fcaeccb89621dd492203ce1f2d551c06f228ed.tar.gz
nixlib-99fcaeccb89621dd492203ce1f2d551c06f228ed.tar.bz2
nixlib-99fcaeccb89621dd492203ce1f2d551c06f228ed.tar.lz
nixlib-99fcaeccb89621dd492203ce1f2d551c06f228ed.tar.xz
nixlib-99fcaeccb89621dd492203ce1f2d551c06f228ed.tar.zst
nixlib-99fcaeccb89621dd492203ce1f2d551c06f228ed.zip
Merge branch 'nixos-unstable' of https://github.com/NixOS/nixpkgs
Conflicts:
	nixpkgs/nixos/modules/config/console.nix
	nixpkgs/nixos/modules/services/mail/mailman.nix
	nixpkgs/nixos/modules/services/mail/public-inbox.nix
	nixpkgs/nixos/modules/services/mail/rss2email.nix
	nixpkgs/nixos/modules/services/networking/ssh/sshd.nix
	nixpkgs/pkgs/applications/networking/instant-messengers/dino/default.nix
	nixpkgs/pkgs/applications/networking/irc/weechat/default.nix
	nixpkgs/pkgs/applications/window-managers/sway/default.nix
	nixpkgs/pkgs/build-support/go/module.nix
	nixpkgs/pkgs/build-support/rust/build-rust-package/default.nix
	nixpkgs/pkgs/development/interpreters/python/default.nix
	nixpkgs/pkgs/development/node-packages/overrides.nix
	nixpkgs/pkgs/development/tools/b4/default.nix
	nixpkgs/pkgs/servers/dict/dictd-db.nix
	nixpkgs/pkgs/servers/mail/public-inbox/default.nix
	nixpkgs/pkgs/tools/security/pinentry/default.nix
	nixpkgs/pkgs/tools/text/unoconv/default.nix
	nixpkgs/pkgs/top-level/all-packages.nix
Diffstat (limited to 'nixpkgs/pkgs/build-support/testers')
-rw-r--r--nixpkgs/pkgs/build-support/testers/default.nix73
-rw-r--r--nixpkgs/pkgs/build-support/testers/expect-failure.sh71
-rw-r--r--nixpkgs/pkgs/build-support/testers/hasPkgConfigModule/tester.nix47
-rw-r--r--nixpkgs/pkgs/build-support/testers/hasPkgConfigModule/tests.nix36
-rw-r--r--nixpkgs/pkgs/build-support/testers/test/default.nix188
-rw-r--r--nixpkgs/pkgs/build-support/testers/testMetaPkgConfig/tester.nix14
6 files changed, 426 insertions, 3 deletions
diff --git a/nixpkgs/pkgs/build-support/testers/default.nix b/nixpkgs/pkgs/build-support/testers/default.nix
index 020352836c89..190ce72d0e63 100644
--- a/nixpkgs/pkgs/build-support/testers/default.nix
+++ b/nixpkgs/pkgs/build-support/testers/default.nix
@@ -1,8 +1,60 @@
-{ pkgs, lib, callPackage, runCommand, stdenv }:
+{ pkgs, buildPackages, lib, callPackage, runCommand, stdenv, substituteAll, }:
 # Documentation is in doc/builders/testers.chapter.md
 {
+  # See https://nixos.org/manual/nixpkgs/unstable/#tester-testBuildFailure
+  # or doc/builders/testers.chapter.md
+  testBuildFailure = drv: drv.overrideAttrs (orig: {
+    builder = buildPackages.bash;
+    args = [
+      (substituteAll { coreutils = buildPackages.coreutils; src = ./expect-failure.sh; })
+      orig.realBuilder or stdenv.shell
+    ] ++ orig.args or ["-e" (orig.builder or ../../stdenv/generic/default-builder.sh)];
+  });
+
+  # See https://nixos.org/manual/nixpkgs/unstable/#tester-testEqualDerivation
+  # or doc/builders/testers.chapter.md
   testEqualDerivation = callPackage ./test-equal-derivation.nix { };
 
+  # See https://nixos.org/manual/nixpkgs/unstable/#tester-testEqualContents
+  # or doc/builders/testers.chapter.md
+  testEqualContents = {
+    assertion,
+    actual,
+    expected,
+  }: runCommand "equal-contents-${lib.strings.toLower assertion}" {
+    inherit assertion actual expected;
+  } ''
+    echo "Checking:"
+    echo "$assertion"
+    if ! diff -U5 -r "$actual" "$expected" --color=always
+    then
+      echo
+      echo 'Contents must be equal, but were not!'
+      echo
+      echo "+: expected,   at $expected"
+      echo "-: unexpected, at $actual"
+      exit 1
+    else
+      find "$expected" -type f -executable > expected-executables | sort
+      find "$actual" -type f -executable > actual-executables | sort
+      if ! diff -U0 actual-executables expected-executables --color=always
+      then
+        echo
+        echo "Contents must be equal, but some files' executable bits don't match"
+        echo
+        echo "+: make this file executable in the actual contents"
+        echo "-: make this file non-executable in the actual contents"
+        exit 1
+      else
+        echo "expected $expected and actual $actual match."
+        echo 'OK'
+        touch $out
+      fi
+    fi
+  '';
+
+  # See https://nixos.org/manual/nixpkgs/unstable/#tester-testVersion
+  # or doc/builders/testers.chapter.md
   testVersion =
     { package,
       command ? "${package.meta.mainProgram or package.pname or package.name} --version",
@@ -43,6 +95,20 @@
     in checked;
 
   # See doc/builders/testers.chapter.md or
+  # https://nixos.org/manual/nixpkgs/unstable/#tester-runNixOSTest
+  runNixOSTest =
+    let nixos = import ../../../nixos/lib {};
+    in testModule:
+        nixos.runTest {
+          _file = "pkgs.runNixOSTest implementation";
+          imports = [
+            (lib.setDefaultModuleLocation "the argument that was passed to pkgs.runNixOSTest" testModule)
+          ];
+          hostPkgs = pkgs;
+          node.pkgs = pkgs;
+        };
+
+  # See doc/builders/testers.chapter.md or
   # https://nixos.org/manual/nixpkgs/unstable/#tester-invalidateFetcherByDrvHash
   nixosTest =
     let
@@ -67,6 +133,9 @@
             else test;
           calledTest = lib.toFunction loadedTest pkgs;
         in
-          nixosTesting.makeTest calledTest;
+          nixosTesting.simpleTest calledTest;
+
+  hasPkgConfigModule = callPackage ./hasPkgConfigModule/tester.nix { };
 
+  testMetaPkgConfig = callPackage ./testMetaPkgConfig/tester.nix { };
 }
diff --git a/nixpkgs/pkgs/build-support/testers/expect-failure.sh b/nixpkgs/pkgs/build-support/testers/expect-failure.sh
new file mode 100644
index 000000000000..9c725d48bf34
--- /dev/null
+++ b/nixpkgs/pkgs/build-support/testers/expect-failure.sh
@@ -0,0 +1,71 @@
+# Run a builder, flip exit code, save log and fix outputs
+#
+# Sub-goals:
+# - Delegate to another original builder passed via args
+# - Save the build log to output for further checks
+# - Make the derivation succeed if the original builder fails
+# - Make the derivation fail if the original builder returns exit code 0
+#
+# Requirements:
+# This runs before, without and after stdenv. Do not modify the environment;
+# especially not before invoking the original builder. For example, use
+# "@" substitutions instead of PATH.
+# Do not export any variables.
+
+# Stricter bash
+set -eu
+
+# ------------------------
+# Run the original builder
+
+echo "testBuildFailure: Expecting non-zero exit from builder and args: ${*@Q}"
+
+("$@" 2>&1) | @coreutils@/bin/tee $TMPDIR/testBuildFailure.log \
+  | while IFS= read -r ln; do
+    echo "original builder: $ln"
+  done
+
+r=${PIPESTATUS[0]}
+if [[ $r = 0 ]]; then
+  echo "testBuildFailure: The builder did not fail, but a failure was expected!"
+  exit 1
+fi
+echo "testBuildFailure: Original builder produced exit code: $r"
+
+# -----------------------------------------
+# Write the build log to the default output
+#
+# # from stdenv setup.sh
+getAllOutputNames() {
+    if [ -n "$__structuredAttrs" ]; then
+        echo "${!outputs[*]}"
+    else
+        echo "$outputs"
+    fi
+}
+
+outs=( $(getAllOutputNames) )
+defOut=${outs[0]}
+defOutPath=${!defOut}
+
+if [[ ! -d $defOutPath ]]; then
+  if [[ -e $defOutPath ]]; then
+    @coreutils@/bin/mv $defOutPath $TMPDIR/out-node
+    @coreutils@/bin/mkdir $defOutPath
+    @coreutils@/bin/mv $TMPDIR/out-node $defOutPath/result
+  fi
+fi
+
+@coreutils@/bin/mkdir -p $defOutPath
+@coreutils@/bin/mv $TMPDIR/testBuildFailure.log $defOutPath/testBuildFailure.log
+echo $r >$defOutPath/testBuildFailure.exit
+
+# ------------------------------------------------------
+# Put empty directories in place for any missing outputs
+
+for outputName in ${outputs:-out}; do
+  outputPath="${!outputName}"
+  if [[ ! -e "${outputPath}" ]]; then
+    @coreutils@/bin/mkdir "${outputPath}";
+  fi
+done
diff --git a/nixpkgs/pkgs/build-support/testers/hasPkgConfigModule/tester.nix b/nixpkgs/pkgs/build-support/testers/hasPkgConfigModule/tester.nix
new file mode 100644
index 000000000000..c8342cdd5c3b
--- /dev/null
+++ b/nixpkgs/pkgs/build-support/testers/hasPkgConfigModule/tester.nix
@@ -0,0 +1,47 @@
+# Static arguments
+{ runCommand, pkg-config }:
+
+# Tester arguments
+{ package,
+  moduleName,
+  testName ? "check-pkg-config-${moduleName}",
+}:
+
+runCommand testName {
+    nativeBuildInputs = [ pkg-config ];
+    buildInputs = [ package ];
+    inherit moduleName;
+    meta = {
+      description = "Test whether ${package.name} exposes pkg-config module ${moduleName}";
+    }
+    # Make sure licensing info etc is preserved, as this is a concern for e.g. cache.nixos.org,
+    # as hydra can't check this meta info in dependencies.
+    # The test itself is just Nixpkgs, with MIT license.
+    // builtins.intersectAttrs
+        {
+          available = throw "unused";
+          broken = throw "unused";
+          insecure = throw "unused";
+          license = throw "unused";
+          maintainers = throw "unused";
+          platforms = throw "unused";
+          unfree = throw "unused";
+          unsupported = throw "unused";
+        }
+        package.meta;
+  } ''
+    echo "checking pkg-config module $moduleName in $buildInputs"
+    set +e
+    version="$(pkg-config --modversion $moduleName)"
+    r=$?
+    set -e
+    if [[ $r = 0 ]]; then
+      echo "✅ pkg-config module $moduleName exists and has version $version"
+      echo "$version" > $out
+    else
+      echo "These modules were available in the input propagation closure:"
+      pkg-config --list-all
+      echo "❌ pkg-config module $moduleName was not found"
+      false
+    fi
+  ''
diff --git a/nixpkgs/pkgs/build-support/testers/hasPkgConfigModule/tests.nix b/nixpkgs/pkgs/build-support/testers/hasPkgConfigModule/tests.nix
new file mode 100644
index 000000000000..8005c3f93709
--- /dev/null
+++ b/nixpkgs/pkgs/build-support/testers/hasPkgConfigModule/tests.nix
@@ -0,0 +1,36 @@
+# cd nixpkgs
+# nix-build -A tests.testers.hasPkgConfigModule
+{ lib, testers, zlib, runCommand }:
+
+lib.recurseIntoAttrs {
+
+  zlib-has-zlib = testers.hasPkgConfigModule {
+    package = zlib;
+    moduleName = "zlib";
+  };
+
+  zlib-does-not-have-ylib = runCommand "zlib-does-not-have-ylib" {
+    failed = testers.testBuildFailure (
+      testers.hasPkgConfigModule {
+      package = zlib;
+      moduleName = "ylib";
+      }
+    );
+  } ''
+    echo 'it logs a relevant error message'
+    {
+      grep -F "pkg-config module ylib was not found" $failed/testBuildFailure.log
+    }
+
+    echo 'it logs which pkg-config modules are available, to be helpful'
+    {
+      # grep -v: the string zlib does also occur in a store path in an earlier message, which isn't particularly helpful
+      grep -v "checking pkg-config module" < $failed/testBuildFailure.log \
+        | grep -F "zlib"
+    }
+
+    # done
+    touch $out
+  '';
+
+}
diff --git a/nixpkgs/pkgs/build-support/testers/test/default.nix b/nixpkgs/pkgs/build-support/testers/test/default.nix
index 30e778cf652e..fc4df4964f39 100644
--- a/nixpkgs/pkgs/build-support/testers/test/default.nix
+++ b/nixpkgs/pkgs/build-support/testers/test/default.nix
@@ -1,4 +1,4 @@
-{ testers, lib, pkgs, ... }:
+{ testers, lib, pkgs, hello, runCommand, ... }:
 let
   pkgs-with-overlay = pkgs.extend(final: prev: {
     proof-of-overlay-hello = prev.hello;
@@ -12,6 +12,19 @@ let
 
 in
 lib.recurseIntoAttrs {
+  hasPkgConfigModule = pkgs.callPackage ../hasPkgConfigModule/tests.nix { };
+
+  runNixOSTest-example = pkgs-with-overlay.testers.runNixOSTest ({ lib, ... }: {
+    name = "runNixOSTest-test";
+    nodes.machine = { pkgs, ... }: {
+      system.nixos = dummyVersioning;
+      environment.systemPackages = [ pkgs.proof-of-overlay-hello pkgs.figlet ];
+    };
+    testScript = ''
+      machine.succeed("hello | figlet >/dev/console")
+    '';
+  });
+
   # Check that the wiring of nixosTest is correct.
   # Correct operation of the NixOS test driver should be asserted elsewhere.
   nixosTest-example = pkgs-with-overlay.testers.nixosTest ({ lib, pkgs, figlet, ... }: {
@@ -24,4 +37,177 @@ lib.recurseIntoAttrs {
       machine.succeed("hello | figlet >/dev/console")
     '';
   });
+
+  testBuildFailure = lib.recurseIntoAttrs {
+    happy = runCommand "testBuildFailure-happy" {
+      failed = testers.testBuildFailure (runCommand "fail" {} ''
+        echo ok-ish >$out
+
+        echo failing though
+        echo also stderr 1>&2
+        echo 'line\nwith-\bbackslashes'
+        printf "incomplete line - no newline"
+
+        exit 3
+      '');
+    } ''
+      grep -F 'ok-ish' $failed/result
+
+      grep -F 'failing though' $failed/testBuildFailure.log
+      grep -F 'also stderr' $failed/testBuildFailure.log
+      grep -F 'line\nwith-\bbackslashes' $failed/testBuildFailure.log
+      grep -F 'incomplete line - no newline' $failed/testBuildFailure.log
+
+      [[ 3 = $(cat $failed/testBuildFailure.exit) ]]
+
+      touch $out
+    '';
+
+    helloDoesNotFail = runCommand "testBuildFailure-helloDoesNotFail" {
+      failed = testers.testBuildFailure (testers.testBuildFailure hello);
+
+      # Add hello itself as a prerequisite, so we don't try to run this test if
+      # there's an actual failure in hello.
+      inherit hello;
+    } ''
+      echo "Checking $failed/testBuildFailure.log"
+      grep -F 'testBuildFailure: The builder did not fail, but a failure was expected' $failed/testBuildFailure.log >/dev/null
+      [[ 1 = $(cat $failed/testBuildFailure.exit) ]]
+      touch $out
+      echo 'All good.'
+    '';
+
+    multiOutput = runCommand "testBuildFailure-multiOutput" {
+      failed = testers.testBuildFailure (runCommand "fail" {
+        # dev will be the default output
+        outputs = ["dev" "doc" "out"];
+      } ''
+        echo i am failing
+        exit 1
+      '');
+    } ''
+      grep -F 'i am failing' $failed/testBuildFailure.log >/dev/null
+      [[ 1 = $(cat $failed/testBuildFailure.exit) ]]
+
+      # Checking our note that dev is the default output
+      echo $failed/_ | grep -- '-dev/_' >/dev/null
+      echo 'All good.'
+      touch $out
+    '';
+  };
+
+  testEqualContents = lib.recurseIntoAttrs {
+    happy = testers.testEqualContents {
+      assertion = "The same directory contents at different paths are recognized as equal";
+      expected = runCommand "expected" {} ''
+        mkdir -p $out/c
+        echo a >$out/a
+        echo b >$out/b
+        echo d >$out/c/d
+      '';
+      actual = runCommand "actual" {} ''
+        mkdir -p $out/c
+        echo a >$out/a
+        echo b >$out/b
+        echo d >$out/c/d
+      '';
+    };
+
+    unequalExe =
+      runCommand "testEqualContents-unequalExe" {
+        log = testers.testBuildFailure (testers.testEqualContents {
+          assertion = "The same directory contents at different paths are recognized as equal";
+          expected = runCommand "expected" {} ''
+            mkdir -p $out/c
+            echo a >$out/a
+            chmod a+x $out/a
+            echo b >$out/b
+            echo d >$out/c/d
+          '';
+          actual = runCommand "actual" {} ''
+            mkdir -p $out/c
+            echo a >$out/a
+            echo b >$out/b
+            chmod a+x $out/b
+            echo d >$out/c/d
+          '';
+        });
+      } ''
+        (
+          set -x
+          grep -F -- "executable bits don't match" $log/testBuildFailure.log
+          grep -E -- '+.*-actual/a' $log/testBuildFailure.log
+          grep -E -- '-.*-actual/b' $log/testBuildFailure.log
+          grep -F -- "--- actual-executables" $log/testBuildFailure.log
+          grep -F -- "+++ expected-executables" $log/testBuildFailure.log
+        ) || {
+          echo "Test failed: could not find pattern in build log $log"
+          exit 1
+        }
+        echo 'All good.'
+        touch $out
+      '';
+
+    fileDiff =
+      runCommand "testEqualContents-fileDiff" {
+        log = testers.testBuildFailure (testers.testEqualContents {
+          assertion = "The same directory contents at different paths are recognized as equal";
+          expected = runCommand "expected" {} ''
+            mkdir -p $out/c
+            echo a >$out/a
+            echo b >$out/b
+            echo d >$out/c/d
+          '';
+          actual = runCommand "actual" {} ''
+            mkdir -p $out/c
+            echo a >$out/a
+            echo B >$out/b
+            echo d >$out/c/d
+          '';
+        });
+      } ''
+        (
+          set -x
+          grep -F -- "Contents must be equal but were not" $log/testBuildFailure.log
+          grep -E -- '+++ .*-actual/b' $log/testBuildFailure.log
+          grep -E -- '--- .*-actual/b' $log/testBuildFailure.log
+          grep -F -- "-B" $log/testBuildFailure.log
+          grep -F -- "+b" $log/testBuildFailure.log
+        ) || {
+          echo "Test failed: could not find pattern in build log $log"
+          exit 1
+        }
+        echo 'All good.'
+        touch $out
+      '';
+
+    fileMissing =
+      runCommand "testEqualContents-fileMissing" {
+        log = testers.testBuildFailure (testers.testEqualContents {
+          assertion = "The same directory contents at different paths are recognized as equal";
+          expected = runCommand "expected" {} ''
+            mkdir -p $out/c
+            echo a >$out/a
+            echo b >$out/b
+            echo d >$out/c/d
+          '';
+          actual = runCommand "actual" {} ''
+            mkdir -p $out/c
+            echo a >$out/a
+            echo d >$out/c/d
+          '';
+        });
+      } ''
+        (
+          set -x
+          grep -F -- "Contents must be equal but were not" $log/testBuildFailure.log
+          grep -E -- 'Only in .*-expected: b' $log/testBuildFailure.log
+        ) || {
+          echo "Test failed: could not find pattern in build log $log"
+          exit 1
+        }
+        echo 'All good.'
+        touch $out
+      '';
+  };
 }
diff --git a/nixpkgs/pkgs/build-support/testers/testMetaPkgConfig/tester.nix b/nixpkgs/pkgs/build-support/testers/testMetaPkgConfig/tester.nix
new file mode 100644
index 000000000000..bee97ace1409
--- /dev/null
+++ b/nixpkgs/pkgs/build-support/testers/testMetaPkgConfig/tester.nix
@@ -0,0 +1,14 @@
+{ lib, runCommand, testers }:
+
+package:
+
+runCommand "check-meta-pkg-config-modules-for-${package.name}" {
+  meta = {
+    description = "Test whether ${package.name} exposes all pkg-config modules ${toString package.meta.pkgConfigModules}";
+  };
+  dependsOn = map
+    (moduleName: testers.hasPkgConfigModule { inherit package moduleName; })
+    package.meta.pkgConfigModules;
+} ''
+  echo "found all of ${toString package.meta.pkgConfigModules}" > "$out"
+''