From 95c8770fa23b136472b8051ea12358b9e0c9da55 Mon Sep 17 00:00:00 2001 From: Connor Baker Date: Thu, 20 Feb 2025 23:16:16 +0000 Subject: [PATCH] testers.testBuildFailure': move to separate directory and use buildCommandPath --- pkgs/build-support/testers/default.nix | 67 +--------- pkgs/build-support/testers/test/default.nix | 111 +--------------- .../testBuildFailurePrime/build-command.sh | 40 ++++++ .../testers/testBuildFailurePrime/tester.nix | 47 +++++++ .../testers/testBuildFailurePrime/tests.nix | 119 ++++++++++++++++++ 5 files changed, 211 insertions(+), 173 deletions(-) create mode 100644 pkgs/build-support/testers/testBuildFailurePrime/build-command.sh create mode 100644 pkgs/build-support/testers/testBuildFailurePrime/tester.nix create mode 100644 pkgs/build-support/testers/testBuildFailurePrime/tests.nix diff --git a/pkgs/build-support/testers/default.nix b/pkgs/build-support/testers/default.nix index 83c85c3a9f7d..0fcbeff9f0d0 100644 --- a/pkgs/build-support/testers/default.nix +++ b/pkgs/build-support/testers/default.nix @@ -36,71 +36,8 @@ # See https://nixos.org/manual/nixpkgs/unstable/#tester-testBuildFailurePrime # or doc/build-helpers/testers.chapter.md - testBuildFailure' = - let - mkBuildCommand = - script: - '' - set -euo pipefail - - if [[ -n ''${expectedBuilderExitCode:-} ]]; then - nixLog "checking original builder exit code" - builderExitCode=$(<"$failed/testBuildFailure.exit") - if ((expectedBuilderExitCode == builderExitCode)); then - nixLog "original builder exit code matches expected value of $expectedBuilderExitCode" - else - nixErrorLog "original builder produced exit code $builderExitCode but was expected to produce $expectedBuilderExitCode" - exit 1 - fi - unset builderExitCode - fi - - if ((''${#expectedBuilderLogEntries[@]})); then - nixLog "checking original builder log" - builderLogEntries="$(<"$failed/testBuildFailure.log")" - shouldExit=0 - for expectedBuilderLogEntry in "''${expectedBuilderLogEntries[@]}"; do - if [[ ''${builderLogEntries} == *"$expectedBuilderLogEntry"* ]]; then - nixLog "original builder log contains ''${expectedBuilderLogEntry@Q}" - else - nixErrorLog "original builder log does not contain ''${expectedBuilderLogEntry@Q}" - shouldExit=1 - fi - done - unset builderLogEntries - ((shouldExit)) && exit 1 - unset shouldExit - fi - '' - + lib.optionalString (script != "") '' - nixLog "running additional checks from user-provided script" - ${script} - '' - + '' - touch "$out" - ''; - final = - { - drv, - name ? null, - expectedBuilderExitCode ? 1, # NOTE: Should be an integer. - expectedBuilderLogEntries ? [ ], # NOTE: Should be an array of string-coercible values. TODO: Only checks for inclusion, not order! - script ? "", # Succeed by default if checks pass. - }: - (runCommand name { - __structuredAttrs = true; - strictDeps = true; - failed = testers.testBuildFailure drv; - inherit expectedBuilderExitCode expectedBuilderLogEntries; - } (mkBuildCommand script)).overrideAttrs - ( - finalAttrs: _: { - # Fix name so the default value uses whatever failed ends up as. - name = if name != null then name else "testBuildFailure-${finalAttrs.failed.name}"; - } - ); - in - lib.makeOverridable final; + # NOTE: Must be `import`-ed rather than `callPackage`-d to preserve the `override` attribute. + testBuildFailure' = import ./testBuildFailurePrime/tester.nix { inherit lib stdenvNoCC testers; }; # See https://nixos.org/manual/nixpkgs/unstable/#tester-testEqualDerivation # or doc/build-helpers/testers.chapter.md diff --git a/pkgs/build-support/testers/test/default.nix b/pkgs/build-support/testers/test/default.nix index a7187a7dbfbf..7e4df128391d 100644 --- a/pkgs/build-support/testers/test/default.nix +++ b/pkgs/build-support/testers/test/default.nix @@ -220,114 +220,9 @@ lib.recurseIntoAttrs { sideEffectStructuredAttrs = overrideStructuredAttrs true sideEffects; }; - testBuildFailure' = lib.recurseIntoAttrs rec { - # NOTE: This example is used in the docs. - # See https://nixos.org/manual/nixpkgs/unstable/#tester-testBuildFailurePrime - # or doc/build-helpers/testers.chapter.md - doc-example = testers.testBuildFailure' { - drv = runCommand "doc-example" { } '' - echo ok-ish >"$out" - echo failing though - exit 3 - ''; - expectedBuilderExitCode = 3; - expectedBuilderLogEntries = [ "failing though" ]; - script = '' - grep --silent -F 'ok-ish' "$failed/result" - ''; - }; - - happy = testers.testBuildFailure' { - drv = runCommand "happy" { } '' - echo ok-ish >$out - - echo failing though - echo also stderr 1>&2 - echo 'line\nwith-\bbackslashes' - printf "incomplete line - no newline" - - exit 3 - ''; - expectedBuilderExitCode = 3; - expectedBuilderLogEntries = [ - "failing though" - "also stderr" - ''line\nwith-\bbackslashes'' - "incomplete line - no newline" - ]; - script = '' - grep --silent -F 'ok-ish' "$failed/result" - ''; - }; - - happyStructuredAttrs = overrideStructuredAttrs true happy; - - helloDoesNotFail = testers.testBuildFailure' { - drv = testers.testBuildFailure hello; - expectedBuilderLogEntries = [ - "testBuildFailure: The builder did not fail, but a failure was expected" - ]; - }; - - multiOutput = testers.testBuildFailure' { - drv = - runCommand "multiOutput" - { - # dev will be the default output - outputs = [ - "dev" - "doc" - "out" - ]; - } - '' - echo i am failing - exit 1 - ''; - expectedBuilderLogEntries = [ - "i am failing" - ]; - script = '' - # Checking our note that dev is the default output - echo $failed/_ | grep -- '-dev/_' >/dev/null - echo 'All good.' - ''; - }; - - multiOutputStructuredAttrs = overrideStructuredAttrs true multiOutput; - - sideEffects = testers.testBuildFailure' { - drv = stdenvNoCC.mkDerivation { - name = "fail-with-side-effects"; - src = emptyDirectory; - - postHook = '' - echo touching side-effect... - # Assert that the side-effect doesn't exist yet... - # We're checking that this hook isn't run by expect-failure.sh - if [[ -e side-effect ]]; then - echo "side-effect already exists" - exit 1 - fi - touch side-effect - ''; - - buildPhase = '' - echo i am failing - exit 1 - ''; - }; - expectedBuilderLogEntries = [ - "touching side-effect..." - "i am failing" - ]; - script = '' - [[ ! -e side-effect ]] - ''; - }; - - sideEffectStructuredAttrs = overrideStructuredAttrs true sideEffects; - }; + testBuildFailure' = lib.recurseIntoAttrs ( + pkgs.callPackages ../testBuildFailurePrime/tests.nix { inherit overrideStructuredAttrs; } + ); testEqualContents = lib.recurseIntoAttrs { equalDir = testers.testEqualContents { diff --git a/pkgs/build-support/testers/testBuildFailurePrime/build-command.sh b/pkgs/build-support/testers/testBuildFailurePrime/build-command.sh new file mode 100644 index 000000000000..f3f292a5f724 --- /dev/null +++ b/pkgs/build-support/testers/testBuildFailurePrime/build-command.sh @@ -0,0 +1,40 @@ +# shellcheck shell=bash + +set -eu + +scriptPhase() { + runHook preScript + + nixLog "checking original builder exit code" + local -ir builderExitCode=$(<"${failed:?}/testBuildFailure.exit") + # shellcheck disable=SC2154 + if ((expectedBuilderExitCode == builderExitCode)); then + nixLog "original builder exit code matches expected value of $expectedBuilderExitCode" + else + nixErrorLog "original builder produced exit code $builderExitCode but was expected to produce $expectedBuilderExitCode" + exit 1 + fi + + # shellcheck disable=SC2154 + if ((${#expectedBuilderLogEntries[@]})); then + nixLog "checking original builder log" + local -r builderLogEntries="$(<"${failed:?}/testBuildFailure.log")" + local -i shouldExit=0 + for expectedBuilderLogEntry in "${expectedBuilderLogEntries[@]}"; do + if [[ ${builderLogEntries} == *"$expectedBuilderLogEntry"* ]]; then + nixLog "original builder log contains ${expectedBuilderLogEntry@Q}" + else + nixErrorLog "original builder log does not contain ${expectedBuilderLogEntry@Q}" + shouldExit=1 + fi + done + ((shouldExit)) && exit 1 + fi + + runHook script + + runHook postScript +} + +runHook scriptPhase +touch "${out:?}" diff --git a/pkgs/build-support/testers/testBuildFailurePrime/tester.nix b/pkgs/build-support/testers/testBuildFailurePrime/tester.nix new file mode 100644 index 000000000000..8b28e19dd1d7 --- /dev/null +++ b/pkgs/build-support/testers/testBuildFailurePrime/tester.nix @@ -0,0 +1,47 @@ +# NOTE: Must be `import`-ed rather than `callPackage`-d to preserve the `override` attribute. +{ + lib, + stdenvNoCC, + testers, +}: +let + inherit (lib) maintainers; + inherit (lib.customisation) makeOverridable; + inherit (testers) testBuildFailure; + + # See https://nixos.org/manual/nixpkgs/unstable/#tester-testBuildFailurePrime + # or doc/build-helpers/testers.chapter.md + testBuildFailure' = + { + drv, + name ? "testBuildFailure-${drv.name}", + expectedBuilderExitCode ? 1, + expectedBuilderLogEntries ? [ ], + script ? "", + }: + let + failed = testBuildFailure drv; + in + stdenvNoCC.mkDerivation { + __structuredAttrs = true; + strictDeps = true; + + inherit name; + + nativeBuildInputs = [ failed ]; + + inherit failed; + + inherit expectedBuilderExitCode expectedBuilderLogEntries; + + inherit script; + + buildCommandPath = ./build-command.sh; + + meta = { + description = "A wrapper around testers.testBuildFailure to simplify common use cases"; + maintainers = [ maintainers.connorbaker ]; + }; + }; +in +makeOverridable testBuildFailure' diff --git a/pkgs/build-support/testers/testBuildFailurePrime/tests.nix b/pkgs/build-support/testers/testBuildFailurePrime/tests.nix new file mode 100644 index 000000000000..9ba65387ae8b --- /dev/null +++ b/pkgs/build-support/testers/testBuildFailurePrime/tests.nix @@ -0,0 +1,119 @@ +{ + emptyDirectory, + hello, + overrideStructuredAttrs, + runCommand, + stdenvNoCC, + testers, +}: +let + final = { + # NOTE: This example is used in the docs. + # See https://nixos.org/manual/nixpkgs/unstable/#tester-testBuildFailurePrime + # or doc/build-helpers/testers.chapter.md + doc-example = testers.testBuildFailure' { + drv = runCommand "doc-example" { } '' + echo ok-ish >"$out" + echo failing though + exit 3 + ''; + expectedBuilderExitCode = 3; + expectedBuilderLogEntries = [ "failing though" ]; + script = '' + grep --silent -F 'ok-ish' "$failed/result" + ''; + }; + + happy = testers.testBuildFailure' { + drv = runCommand "happy" { } '' + echo ok-ish >$out + + echo failing though + echo also stderr 1>&2 + echo 'line\nwith-\bbackslashes' + printf "incomplete line - no newline" + + exit 3 + ''; + expectedBuilderExitCode = 3; + expectedBuilderLogEntries = [ + "failing though" + "also stderr" + ''line\nwith-\bbackslashes'' + "incomplete line - no newline" + ]; + script = '' + grep --silent -F 'ok-ish' "$failed/result" + ''; + }; + + happyStructuredAttrs = overrideStructuredAttrs true final.happy; + + helloDoesNotFail = testers.testBuildFailure' { + drv = testers.testBuildFailure hello; + expectedBuilderLogEntries = [ + "testBuildFailure: The builder did not fail, but a failure was expected" + ]; + }; + + multiOutput = testers.testBuildFailure' { + drv = + runCommand "multiOutput" + { + # dev will be the default output + outputs = [ + "dev" + "doc" + "out" + ]; + } + '' + echo i am failing + exit 1 + ''; + expectedBuilderLogEntries = [ + "i am failing" + ]; + script = '' + # Checking our note that dev is the default output + echo $failed/_ | grep -- '-dev/_' >/dev/null + echo 'All good.' + ''; + }; + + multiOutputStructuredAttrs = overrideStructuredAttrs true final.multiOutput; + + sideEffects = testers.testBuildFailure' { + drv = stdenvNoCC.mkDerivation { + name = "fail-with-side-effects"; + src = emptyDirectory; + + postHook = '' + echo touching side-effect... + # Assert that the side-effect doesn't exist yet... + # We're checking that this hook isn't run by expect-failure.sh + if [[ -e side-effect ]]; then + echo "side-effect already exists" + exit 1 + fi + touch side-effect + ''; + + buildPhase = '' + echo i am failing + exit 1 + ''; + }; + expectedBuilderLogEntries = [ + "touching side-effect..." + "i am failing" + ]; + script = '' + [[ ! -e side-effect ]] + ''; + }; + + sideEffectsStructuredAttrs = overrideStructuredAttrs true final.sideEffects; + }; +in +final