diff options
Diffstat (limited to 'tests')
105 files changed, 2898 insertions, 517 deletions
diff --git a/tests/add.sh b/tests/add.sh index e26e05843..5c3eed793 100644 --- a/tests/add.sh +++ b/tests/add.sh @@ -9,7 +9,7 @@ echo $path2 if test "$path1" != "$path2"; then echo "nix-store --add and --add-fixed mismatch" exit 1 -fi +fi path3=$(nix-store --add-fixed sha256 ./dummy) echo $path3 diff --git a/tests/binary-cache-build-remote.sh b/tests/binary-cache-build-remote.sh new file mode 100644 index 000000000..81cd21a4a --- /dev/null +++ b/tests/binary-cache-build-remote.sh @@ -0,0 +1,16 @@ +source common.sh + +clearStore +clearCacheCache + +# Fails without remote builders +(! nix-build --store "file://$cacheDir" dependencies.nix) + +# Succeeds with default store as build remote. +outPath=$(nix-build --store "file://$cacheDir" --builders 'auto - - 1 1' -j0 dependencies.nix) + +# Test that the path exactly exists in the destination store. +nix path-info --store "file://$cacheDir" $outPath + +# Succeeds without any build capability because no-op +nix-build --store "file://$cacheDir" -j0 dependencies.nix diff --git a/tests/binary-cache.sh b/tests/binary-cache.sh index 17b63d978..d7bc1507b 100644 --- a/tests/binary-cache.sh +++ b/tests/binary-cache.sh @@ -1,15 +1,22 @@ source common.sh +needLocalStore "“--no-require-sigs” can’t be used with the daemon" + +# We can produce drvs directly into the binary cache clearStore -clearCache +clearCacheCache +nix-instantiate --store "file://$cacheDir" dependencies.nix # Create the binary cache. +clearStore +clearCache outPath=$(nix-build dependencies.nix --no-out-link) nix copy --to file://$cacheDir $outPath -basicTests() { +basicDownloadTests() { + # No uploading tests bcause upload with force HTTP doesn't work. # By default, a binary cache doesn't support "nix-env -qas", but does # support installation. @@ -44,12 +51,12 @@ basicTests() { # Test LocalBinaryCacheStore. -basicTests +basicDownloadTests # Test HttpBinaryCacheStore. export _NIX_FORCE_HTTP=1 -basicTests +basicDownloadTests # Test whether Nix notices if the NAR doesn't match the hash in the NAR info. @@ -125,20 +132,18 @@ grep -q "copying path.*input-0" $TEST_ROOT/log grep -q "copying path.*top" $TEST_ROOT/log -if [ -n "$HAVE_SODIUM" ]; then - # Create a signed binary cache. clearCache clearCacheCache -declare -a res=($(nix-store --generate-binary-cache-key test.nixos.org-1 $TEST_ROOT/sk1 $TEST_ROOT/pk1 )) -publicKey="$(cat $TEST_ROOT/pk1)" +nix key generate-secret --key-name test.nixos.org-1 > $TEST_ROOT/sk1 +publicKey=$(nix key convert-secret-to-public < $TEST_ROOT/sk1) -res=($(nix-store --generate-binary-cache-key test.nixos.org-1 $TEST_ROOT/sk2 $TEST_ROOT/pk2)) -badKey="$(cat $TEST_ROOT/pk2)" +nix key generate-secret --key-name test.nixos.org-1 > $TEST_ROOT/sk2 +badKey=$(nix key convert-secret-to-public < $TEST_ROOT/sk2) -res=($(nix-store --generate-binary-cache-key foo.nixos.org-1 $TEST_ROOT/sk3 $TEST_ROOT/pk3)) -otherKey="$(cat $TEST_ROOT/pk3)" +nix key generate-secret --key-name foo.nixos.org-1 > $TEST_ROOT/sk3 +otherKey=$(nix key convert-secret-to-public < $TEST_ROOT/sk3) _NIX_FORCE_HTTP= nix copy --to file://$cacheDir?secret-key=$TEST_ROOT/sk1 $outPath @@ -181,4 +186,90 @@ clearCacheCache nix-store -r $outPath --substituters "file://$cacheDir2 file://$cacheDir" --trusted-public-keys "$publicKey" -fi # HAVE_LIBSODIUM + +unset _NIX_FORCE_HTTP + + +# Test 'nix verify --all' on a binary cache. +nix store verify -vvvvv --all --store file://$cacheDir --no-trust + + +# Test local NAR caching. +narCache=$TEST_ROOT/nar-cache +rm -rf $narCache +mkdir $narCache + +[[ $(nix store cat --store "file://$cacheDir?local-nar-cache=$narCache" $outPath/foobar) = FOOBAR ]] + +rm -rfv "$cacheDir/nar" + +[[ $(nix store cat --store "file://$cacheDir?local-nar-cache=$narCache" $outPath/foobar) = FOOBAR ]] + +(! nix store cat --store file://$cacheDir $outPath/foobar) + + +# Test NAR listing generation. +clearCache + +outPath=$(nix-build --no-out-link -E ' + with import ./config.nix; + mkDerivation { + name = "nar-listing"; + buildCommand = "mkdir $out; echo foo > $out/bar; ln -s xyzzy $out/link"; + } +') + +nix copy --to file://$cacheDir?write-nar-listing=1 $outPath + +diff -u \ + <(jq -S < $cacheDir/$(basename $outPath | cut -c1-32).ls) \ + <(echo '{"version":1,"root":{"type":"directory","entries":{"bar":{"type":"regular","size":4,"narOffset":232},"link":{"type":"symlink","target":"xyzzy"}}}}' | jq -S) + + +# Test debug info index generation. +clearCache + +outPath=$(nix-build --no-out-link -E ' + with import ./config.nix; + mkDerivation { + name = "debug-info"; + buildCommand = "mkdir -p $out/lib/debug/.build-id/02; echo foo > $out/lib/debug/.build-id/02/623eda209c26a59b1a8638ff7752f6b945c26b.debug"; + } +') + +nix copy --to "file://$cacheDir?index-debug-info=1&compression=none" $outPath + +diff -u \ + <(cat $cacheDir/debuginfo/02623eda209c26a59b1a8638ff7752f6b945c26b.debug | jq -S) \ + <(echo '{"archive":"../nar/100vxs724qr46phz8m24iswmg9p3785hsyagz0kchf6q6gf06sw6.nar","member":"lib/debug/.build-id/02/623eda209c26a59b1a8638ff7752f6b945c26b.debug"}' | jq -S) + +# Test against issue https://github.com/NixOS/nix/issues/3964 +# +expr=' + with import ./config.nix; + mkDerivation { + name = "multi-output"; + buildCommand = "mkdir -p $out; echo foo > $doc; echo $doc > $out/docref"; + outputs = ["out" "doc"]; + } +' +outPath=$(nix-build --no-out-link -E "$expr") +docPath=$(nix-store -q --references $outPath) + +# $ nix-store -q --tree $outPath +# ...-multi-output +# +---...-multi-output-doc + +nix copy --to "file://$cacheDir" $outPath + +hashpart() { + basename "$1" | cut -c1-32 +} + +# break the closure of out by removing doc +rm $cacheDir/$(hashpart $docPath).narinfo + +nix-store --delete $outPath $docPath +# -vvv is the level that logs during the loop +timeout 60 nix-build --no-out-link -E "$expr" --option substituters "file://$cacheDir" \ + --option trusted-binary-caches "file://$cacheDir" --no-require-sigs diff --git a/tests/brotli.sh b/tests/brotli.sh index a3c6e55a8..dc9bbdb66 100644 --- a/tests/brotli.sh +++ b/tests/brotli.sh @@ -9,13 +9,13 @@ outPath=$(nix-build dependencies.nix --no-out-link) nix copy --to $cacheURI $outPath -HASH=$(nix hash-path $outPath) +HASH=$(nix hash path $outPath) clearStore clearCacheCache nix copy --from $cacheURI $outPath --no-check-sigs -HASH2=$(nix hash-path $outPath) +HASH2=$(nix hash path $outPath) [[ $HASH = $HASH2 ]] diff --git a/tests/build-hook-ca-fixed.nix b/tests/build-hook-ca-fixed.nix new file mode 100644 index 000000000..ec7171ac9 --- /dev/null +++ b/tests/build-hook-ca-fixed.nix @@ -0,0 +1,56 @@ +{ busybox }: + +with import ./config.nix; + +let + + mkDerivation = args: + derivation ({ + inherit system; + builder = busybox; + args = ["sh" "-e" args.builder or (builtins.toFile "builder-${args.name}.sh" "if [ -e .attrs.sh ]; then source .attrs.sh; fi; eval \"$buildCommand\"")]; + outputHashMode = "recursive"; + outputHashAlgo = "sha256"; + } // removeAttrs args ["builder" "meta"]) + // { meta = args.meta or {}; }; + + input1 = mkDerivation { + shell = busybox; + name = "build-remote-input-1"; + buildCommand = "echo FOO > $out"; + requiredSystemFeatures = ["foo"]; + outputHash = "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="; + }; + + input2 = mkDerivation { + shell = busybox; + name = "build-remote-input-2"; + buildCommand = "echo BAR > $out"; + requiredSystemFeatures = ["bar"]; + outputHash = "sha256-XArauVH91AVwP9hBBQNlkX9ccuPpSYx9o0zeIHb6e+Q="; + }; + + input3 = mkDerivation { + shell = busybox; + name = "build-remote-input-3"; + buildCommand = '' + read x < ${input2} + echo $x BAZ > $out + ''; + requiredSystemFeatures = ["baz"]; + outputHash = "sha256-daKAcPp/+BYMQsVi/YYMlCKoNAxCNDsaivwSHgQqD2s="; + }; + +in + + mkDerivation { + shell = busybox; + name = "build-remote"; + buildCommand = + '' + read x < ${input1} + read y < ${input3} + echo "$x $y" > $out + ''; + outputHash = "sha256-5SxbkUw6xe2l9TE1uwCvTtTDysD1vhRor38OtDF0LqQ="; + } diff --git a/tests/build-hook-ca-floating.nix b/tests/build-hook-ca-floating.nix new file mode 100644 index 000000000..67295985f --- /dev/null +++ b/tests/build-hook-ca-floating.nix @@ -0,0 +1,53 @@ +{ busybox }: + +with import ./config.nix; + +let + + mkDerivation = args: + derivation ({ + inherit system; + builder = busybox; + args = ["sh" "-e" args.builder or (builtins.toFile "builder-${args.name}.sh" "if [ -e .attrs.sh ]; then source .attrs.sh; fi; eval \"$buildCommand\"")]; + outputHashMode = "recursive"; + outputHashAlgo = "sha256"; + __contentAddressed = true; + } // removeAttrs args ["builder" "meta"]) + // { meta = args.meta or {}; }; + + input1 = mkDerivation { + shell = busybox; + name = "build-remote-input-1"; + buildCommand = "echo FOO > $out"; + requiredSystemFeatures = ["foo"]; + }; + + input2 = mkDerivation { + shell = busybox; + name = "build-remote-input-2"; + buildCommand = "echo BAR > $out"; + requiredSystemFeatures = ["bar"]; + }; + + input3 = mkDerivation { + shell = busybox; + name = "build-remote-input-3"; + buildCommand = '' + read x < ${input2} + echo $x BAZ > $out + ''; + requiredSystemFeatures = ["baz"]; + }; + +in + + mkDerivation { + shell = busybox; + name = "build-remote"; + buildCommand = + '' + read x < ${input1} + read y < ${input3} + echo "$x $y" > $out + ''; + } diff --git a/tests/build-hook.nix b/tests/build-hook.nix index a19c10dde..eb16676f0 100644 --- a/tests/build-hook.nix +++ b/tests/build-hook.nix @@ -23,6 +23,17 @@ let shell = busybox; name = "build-remote-input-2"; buildCommand = "echo BAR > $out"; + requiredSystemFeatures = ["bar"]; + }; + + input3 = mkDerivation { + shell = busybox; + name = "build-remote-input-3"; + buildCommand = '' + read x < ${input2} + echo $x BAZ > $out + ''; + requiredSystemFeatures = ["baz"]; }; in @@ -33,7 +44,7 @@ in buildCommand = '' read x < ${input1} - read y < ${input2} - echo $x$y > $out + read y < ${input3} + echo "$x $y" > $out ''; } diff --git a/tests/build-remote-content-addressed-fixed.sh b/tests/build-remote-content-addressed-fixed.sh new file mode 100644 index 000000000..ae7441591 --- /dev/null +++ b/tests/build-remote-content-addressed-fixed.sh @@ -0,0 +1,5 @@ +source common.sh + +file=build-hook-ca-fixed.nix + +source build-remote.sh diff --git a/tests/build-remote-content-addressed-floating.sh b/tests/build-remote-content-addressed-floating.sh new file mode 100644 index 000000000..13ef47d2d --- /dev/null +++ b/tests/build-remote-content-addressed-floating.sh @@ -0,0 +1,9 @@ +source common.sh + +file=build-hook-ca-floating.nix + +sed -i 's/experimental-features .*/& ca-derivations/' "$NIX_CONF_DIR"/nix.conf + +CONTENT_ADDRESSED=true + +source build-remote.sh diff --git a/tests/build-remote-input-addressed.sh b/tests/build-remote-input-addressed.sh new file mode 100644 index 000000000..49d15c389 --- /dev/null +++ b/tests/build-remote-input-addressed.sh @@ -0,0 +1,33 @@ +source common.sh + +file=build-hook.nix + +source build-remote.sh + +# Add a `post-build-hook` option to the nix conf. +# This hook will be executed both for the local machine and the remote builders +# (because they share the same config). +registerBuildHook () { + # Dummy post-build-hook just to ensure that it's executed correctly. + # (we can't reuse the one from `$PWD/push-to-store.sh` because of + # https://github.com/NixOS/nix/issues/4341) + cat <<EOF > $TEST_ROOT/post-build-hook.sh +#!/bin/sh + +echo "Post hook ran successfully" +# Add an empty line to a counter file, just to check that this hook ran properly +echo "" >> $TEST_ROOT/post-hook-counter +EOF + chmod +x $TEST_ROOT/post-build-hook.sh + rm -f $TEST_ROOT/post-hook-counter + + echo "post-build-hook = $TEST_ROOT/post-build-hook.sh" >> $NIX_CONF_DIR/nix.conf +} + +registerBuildHook +source build-remote.sh + +# `build-hook.nix` has four derivations to build, and the hook runs twice for +# each derivation (once on the builder and once on the host), so the counter +# should contain eight lines now +[[ $(cat $TEST_ROOT/post-hook-counter | wc -l) -eq 8 ]] diff --git a/tests/build-remote.sh b/tests/build-remote.sh index 4dfb753e1..27d85a83d 100644 --- a/tests/build-remote.sh +++ b/tests/build-remote.sh @@ -1,31 +1,55 @@ -source common.sh +if ! canUseSandbox; then exit 99; fi +if ! [[ $busybox =~ busybox ]]; then exit 99; fi -clearStore +unset NIX_STORE_DIR +unset NIX_STATE_DIR -if ! canUseSandbox; then exit; fi -if ! [[ $busybox =~ busybox ]]; then exit; fi +function join_by { local d=$1; shift; echo -n "$1"; shift; printf "%s" "${@/#/$d}"; } -chmod -R u+w $TEST_ROOT/machine0 || true -chmod -R u+w $TEST_ROOT/machine1 || true -chmod -R u+w $TEST_ROOT/machine2 || true -rm -rf $TEST_ROOT/machine0 $TEST_ROOT/machine1 $TEST_ROOT/machine2 -rm -f $TEST_ROOT/result +EXTRA_SYSTEM_FEATURES=() +if [[ -n "$CONTENT_ADDRESSED" ]]; then + EXTRA_SYSTEM_FEATURES=("ca-derivations") +fi -unset NIX_STORE_DIR -unset NIX_STATE_DIR +builders=( + # system-features will automatically be added to the outer URL, but not inner + # remote-store URL. + "ssh://localhost?remote-store=$TEST_ROOT/machine1?system-features=$(join_by "%20" foo ${EXTRA_SYSTEM_FEATURES[@]}) - - 1 1 $(join_by "," foo ${EXTRA_SYSTEM_FEATURES[@]})" + "$TEST_ROOT/machine2 - - 1 1 $(join_by "," bar ${EXTRA_SYSTEM_FEATURES[@]})" + "ssh-ng://localhost?remote-store=$TEST_ROOT/machine3?system-features=$(join_by "%20" baz ${EXTRA_SYSTEM_FEATURES[@]}) - - 1 1 $(join_by "," baz ${EXTRA_SYSTEM_FEATURES[@]})" +) + +chmod -R +w $TEST_ROOT/machine* || true +rm -rf $TEST_ROOT/machine* || true # Note: ssh://localhost bypasses ssh, directly invoking nix-store as a # child process. This allows us to test LegacySSHStore::buildDerivation(). -nix build -L -v -f build-hook.nix -o $TEST_ROOT/result --max-jobs 0 \ +# ssh-ng://... likewise allows us to test RemoteStore::buildDerivation(). +nix build -L -v -f $file -o $TEST_ROOT/result --max-jobs 0 \ --arg busybox $busybox \ --store $TEST_ROOT/machine0 \ - --builders "ssh://localhost?remote-store=$TEST_ROOT/machine1; $TEST_ROOT/machine2 - - 1 1 foo" \ - --system-features foo + --builders "$(join_by '; ' "${builders[@]}")" outPath=$(readlink -f $TEST_ROOT/result) -cat $TEST_ROOT/machine0/$outPath | grep FOOBAR +grep 'FOO BAR BAZ' $TEST_ROOT/machine0/$outPath + +set -o pipefail + +# Ensure that input1 was built on store1 due to the required feature. +nix path-info --store $TEST_ROOT/machine1 --all \ + | grep builder-build-remote-input-1.sh \ + | grep -v builder-build-remote-input-2.sh \ + | grep -v builder-build-remote-input-3.sh + +# Ensure that input2 was built on store2 due to the required feature. +nix path-info --store $TEST_ROOT/machine2 --all \ + | grep -v builder-build-remote-input-1.sh \ + | grep builder-build-remote-input-2.sh \ + | grep -v builder-build-remote-input-3.sh -# Ensure that input1 was built on store2 due to the required feature. -(! nix path-info --store $TEST_ROOT/machine1 --all | grep builder-build-remote-input-1.sh) -nix path-info --store $TEST_ROOT/machine2 --all | grep builder-build-remote-input-1.sh +# Ensure that input3 was built on store3 due to the required feature. +nix path-info --store $TEST_ROOT/machine3 --all \ + | grep -v builder-build-remote-input-1.sh \ + | grep -v builder-build-remote-input-2.sh \ + | grep builder-build-remote-input-3.sh diff --git a/tests/build.sh b/tests/build.sh new file mode 100644 index 000000000..c77f620f7 --- /dev/null +++ b/tests/build.sh @@ -0,0 +1,19 @@ +source common.sh + +expectedJSONRegex='\[\{"drvPath":".*multiple-outputs-a.drv","outputs":\{"first":".*multiple-outputs-a-first","second":".*multiple-outputs-a-second"}},\{"drvPath":".*multiple-outputs-b.drv","outputs":\{"out":".*multiple-outputs-b"}}]' +nix build -f multiple-outputs.nix --json a.all b.all --no-link | jq --exit-status ' + (.[0] | + (.drvPath | match(".*multiple-outputs-a.drv")) and + (.outputs.first | match(".*multiple-outputs-a-first")) and + (.outputs.second | match(".*multiple-outputs-a-second"))) + and (.[1] | + (.drvPath | match(".*multiple-outputs-b.drv")) and + (.outputs.out | match(".*multiple-outputs-b"))) +' +testNormalization () { + clearStore + outPath=$(nix-build ./simple.nix --no-out-link) + test "$(stat -c %Y $outPath)" -eq 1 +} + +testNormalization diff --git a/tests/ca/build-with-garbage-path.sh b/tests/ca/build-with-garbage-path.sh new file mode 100755 index 000000000..9aa08a899 --- /dev/null +++ b/tests/ca/build-with-garbage-path.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +# Regression test for https://github.com/NixOS/nix/issues/4858 + +source common.sh + +requireDaemonNewerThan "2.4pre20210621" + +# Get the output path of `rootCA`, and put some garbage instead +outPath="$(nix-build ./content-addressed.nix -A rootCA --no-out-link)" +nix-store --delete "$outPath" +touch "$outPath" + +# The build should correctly remove the garbage and put the expected path instead +nix-build ./content-addressed.nix -A rootCA --no-out-link + +# Rebuild it. This shouldn’t overwrite the existing path +oldInode=$(stat -c '%i' "$outPath") +nix-build ./content-addressed.nix -A rootCA --no-out-link --arg seed 2 +newInode=$(stat -c '%i' "$outPath") +[[ "$oldInode" == "$newInode" ]] diff --git a/tests/ca/build.sh b/tests/ca/build.sh new file mode 100644 index 000000000..c8877f87f --- /dev/null +++ b/tests/ca/build.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash + +source common.sh + +drv=$(nix-instantiate --experimental-features ca-derivations ./content-addressed.nix -A rootCA --arg seed 1) +nix --experimental-features 'nix-command ca-derivations' show-derivation --derivation "$drv" --arg seed 1 + +buildAttr () { + local derivationPath=$1 + local seedValue=$2 + shift; shift + local args=("--experimental-features" "ca-derivations" "./content-addressed.nix" "-A" "$derivationPath" --arg seed "$seedValue" "--no-out-link") + args+=("$@") + nix-build "${args[@]}" +} + +testRemoteCache () { + clearCache + local outPath=$(buildAttr dependentNonCA 1) + nix copy --to file://$cacheDir $outPath + clearStore + buildAttr dependentNonCA 1 --option substituters file://$cacheDir --no-require-sigs |& (! grep "building dependent-non-ca") +} + +testDeterministicCA () { + [[ $(buildAttr rootCA 1) = $(buildAttr rootCA 2) ]] +} + +testCutoffFor () { + local out1 out2 + out1=$(buildAttr $1 1) + # The seed only changes the root derivation, and not it's output, so the + # dependent derivations should only need to be built once. + buildAttr rootCA 2 + out2=$(buildAttr $1 2 -j0) + test "$out1" == "$out2" +} + +testCutoff () { + # Don't directly build depenentCA, that way we'll make sure we dodn't rely on + # dependent derivations always being already built. + #testDerivation dependentCA + testCutoffFor transitivelyDependentCA + testCutoffFor dependentNonCA + testCutoffFor dependentFixedOutput +} + +testGC () { + nix-instantiate --experimental-features ca-derivations ./content-addressed.nix -A rootCA --arg seed 5 + nix-collect-garbage --experimental-features ca-derivations --option keep-derivations true + clearStore + buildAttr rootCA 1 --out-link $TEST_ROOT/rootCA + nix-collect-garbage --experimental-features ca-derivations + buildAttr rootCA 1 -j0 +} + +testNixCommand () { + clearStore + nix build --experimental-features 'nix-command ca-derivations' --file ./content-addressed.nix --no-link +} + +# Regression test for https://github.com/NixOS/nix/issues/4775 +testNormalization () { + clearStore + outPath=$(buildAttr rootCA 1) + test "$(stat -c %Y $outPath)" -eq 1 +} + +# Disabled until we have it properly working +# testRemoteCache +clearStore +testNormalization +testDeterministicCA +clearStore +testCutoff +testGC +testNixCommand diff --git a/tests/ca/common.sh b/tests/ca/common.sh new file mode 100644 index 000000000..c5aa34334 --- /dev/null +++ b/tests/ca/common.sh @@ -0,0 +1,5 @@ +source ../common.sh + +sed -i 's/experimental-features .*/& ca-derivations ca-references/' "$NIX_CONF_DIR"/nix.conf + +restartDaemon diff --git a/tests/ca/concurrent-builds.sh b/tests/ca/concurrent-builds.sh new file mode 100755 index 000000000..b442619e2 --- /dev/null +++ b/tests/ca/concurrent-builds.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +# Ensure that we can’t build twice the same derivation concurrently. +# Regression test for https://github.com/NixOS/nix/issues/5029 + +source common.sh + +buggyNeedLocalStore "For some reason, this deadlocks with the daemon" + +export NIX_TESTS_CA_BY_DEFAULT=1 + +clearStore + +for i in {0..5}; do + nix build --no-link --file ./racy.nix & +done + +wait diff --git a/tests/ca/config.nix.in b/tests/ca/config.nix.in new file mode 120000 index 000000000..af24ddb30 --- /dev/null +++ b/tests/ca/config.nix.in @@ -0,0 +1 @@ +../config.nix.in
\ No newline at end of file diff --git a/tests/ca/content-addressed.nix b/tests/ca/content-addressed.nix new file mode 100644 index 000000000..d328fc92c --- /dev/null +++ b/tests/ca/content-addressed.nix @@ -0,0 +1,83 @@ +with import ./config.nix; + +let mkCADerivation = args: mkDerivation ({ + __contentAddressed = true; + outputHashMode = "recursive"; + outputHashAlgo = "sha256"; +} // args); +in + +{ seed ? 0 }: +# A simple content-addressed derivation. +# The derivation can be arbitrarily modified by passing a different `seed`, +# but the output will always be the same +rec { + rootLegacy = mkDerivation { + name = "simple-input-addressed"; + buildCommand = '' + set -x + echo "Building a legacy derivation" + mkdir -p $out + echo "Hello World" > $out/hello + ''; + }; + rootCA = mkCADerivation { + name = "rootCA"; + outputs = [ "out" "dev" "foo"]; + buildCommand = '' + echo "building a CA derivation" + echo "The seed is ${toString seed}" + mkdir -p $out + echo ${rootLegacy}/hello > $out/dep + ln -s $out $out/self + # test symlinks at root + ln -s $out $dev + ln -s $out $foo + ''; + }; + dependentCA = mkCADerivation { + name = "dependent"; + buildCommand = '' + echo "building a dependent derivation" + mkdir -p $out + cat ${rootCA}/self/dep + echo ${rootCA}/self/dep > $out/dep + ''; + }; + transitivelyDependentCA = mkCADerivation { + name = "transitively-dependent"; + buildCommand = '' + echo "building transitively-dependent" + cat ${dependentCA}/dep + echo ${dependentCA} > $out + ''; + }; + dependentNonCA = mkDerivation { + name = "dependent-non-ca"; + buildCommand = '' + echo "Didn't cut-off" + echo "building dependent-non-ca" + mkdir -p $out + echo ${rootCA}/non-ca-hello > $out/dep + ''; + }; + dependentFixedOutput = mkDerivation { + name = "dependent-fixed-output"; + outputHashMode = "recursive"; + outputHashAlgo = "sha256"; + outputHash = "sha256-QvtAMbUl/uvi+LCObmqOhvNOapHdA2raiI4xG5zI5pA="; + buildCommand = '' + cat ${dependentCA}/dep + echo foo > $out + ''; + }; + runnable = mkCADerivation rec { + name = "runnable-thing"; + buildCommand = '' + mkdir -p $out/bin + echo ${rootCA} # Just to make it depend on it + echo "" > $out/bin/${name} + chmod +x $out/bin/${name} + ''; + }; +} diff --git a/tests/ca/duplicate-realisation-in-closure.sh b/tests/ca/duplicate-realisation-in-closure.sh new file mode 100644 index 000000000..74c5d25fd --- /dev/null +++ b/tests/ca/duplicate-realisation-in-closure.sh @@ -0,0 +1,28 @@ +source ./common.sh + +requireDaemonNewerThan "2.4pre20210625" + +sed -i 's/experimental-features .*/& ca-derivations ca-references/' "$NIX_CONF_DIR"/nix.conf + +export REMOTE_STORE_DIR="$TEST_ROOT/remote_store" +export REMOTE_STORE="file://$REMOTE_STORE_DIR" + +rm -rf $REMOTE_STORE_DIR +clearStore + +# Build dep1 and push that to the binary cache. +# This entails building (and pushing) current-time. +nix copy --to "$REMOTE_STORE" -f nondeterministic.nix dep1 +clearStore +sleep 2 # To make sure that `$(date)` will be different +# Build dep2. +# As we’ve cleared the cache, we’ll have to rebuild current-time. And because +# the current time isn’t the same as before, this will yield a new (different) +# realisation +nix build -f nondeterministic.nix dep2 --no-link + +# Build something that depends both on dep1 and dep2. +# If everything goes right, we should rebuild dep2 rather than fetch it from +# the cache (because that would mean duplicating `current-time` in the closure), +# and have `dep1 == dep2`. +nix build --substituters "$REMOTE_STORE" -f nondeterministic.nix toplevel --no-require-sigs --no-link diff --git a/tests/ca/flake.nix b/tests/ca/flake.nix new file mode 100644 index 000000000..332c92a67 --- /dev/null +++ b/tests/ca/flake.nix @@ -0,0 +1,3 @@ +{ + outputs = { self }: import ./content-addressed.nix {}; +} diff --git a/tests/ca/gc.sh b/tests/ca/gc.sh new file mode 100755 index 000000000..e9b6c5ab5 --- /dev/null +++ b/tests/ca/gc.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +# Ensure that garbage collection works properly with ca derivations + +source common.sh + +export NIX_TESTS_CA_BY_DEFAULT=1 + +cd .. +source gc.sh diff --git a/tests/ca/nix-copy.sh b/tests/ca/nix-copy.sh new file mode 100755 index 000000000..2e0dea2d2 --- /dev/null +++ b/tests/ca/nix-copy.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash + +source common.sh + +# Globally enable the ca derivations experimental flag +sed -i 's/experimental-features = .*/& ca-derivations ca-references/' "$NIX_CONF_DIR/nix.conf" + +export REMOTE_STORE_DIR="$TEST_ROOT/remote_store" +export REMOTE_STORE="file://$REMOTE_STORE_DIR" + +ensureCorrectlyCopied () { + attrPath="$1" + nix build --store "$REMOTE_STORE" --file ./content-addressed.nix "$attrPath" +} + +testOneCopy () { + clearStore + rm -rf "$REMOTE_STORE_DIR" + + attrPath="$1" + nix copy --to $REMOTE_STORE "$attrPath" --file ./content-addressed.nix + + ensureCorrectlyCopied "$attrPath" + + # Ensure that we can copy back what we put in the store + clearStore + nix copy --from $REMOTE_STORE \ + --file ./content-addressed.nix "$attrPath" \ + --no-check-sigs +} + +for attrPath in rootCA dependentCA transitivelyDependentCA dependentNonCA dependentFixedOutput; do + testOneCopy "$attrPath" +done diff --git a/tests/ca/nix-run.sh b/tests/ca/nix-run.sh new file mode 100755 index 000000000..81402af10 --- /dev/null +++ b/tests/ca/nix-run.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +source common.sh + +sed -i 's/experimental-features .*/& ca-derivations ca-references nix-command flakes/' "$NIX_CONF_DIR"/nix.conf + +FLAKE_PATH=path:$PWD + +nix run --no-write-lock-file $FLAKE_PATH#runnable diff --git a/tests/ca/nix-shell.sh b/tests/ca/nix-shell.sh new file mode 100755 index 000000000..7f1a3a73e --- /dev/null +++ b/tests/ca/nix-shell.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +source common.sh + +sed -i 's/experimental-features .*/& ca-derivations ca-references nix-command flakes/' "$NIX_CONF_DIR"/nix.conf + +CONTENT_ADDRESSED=true +cd .. +source ./nix-shell.sh + diff --git a/tests/ca/nondeterministic.nix b/tests/ca/nondeterministic.nix new file mode 100644 index 000000000..d6d099a3e --- /dev/null +++ b/tests/ca/nondeterministic.nix @@ -0,0 +1,35 @@ +with import ./config.nix; + +let mkCADerivation = args: mkDerivation ({ + __contentAddressed = true; + outputHashMode = "recursive"; + outputHashAlgo = "sha256"; +} // args); +in + +rec { + currentTime = mkCADerivation { + name = "current-time"; + buildCommand = '' + mkdir $out + echo $(date) > $out/current-time + ''; + }; + dep = seed: mkCADerivation { + name = "dep"; + inherit seed; + buildCommand = '' + echo ${currentTime} > $out + ''; + }; + dep1 = dep 1; + dep2 = dep 2; + toplevel = mkCADerivation { + name = "toplevel"; + buildCommand = '' + test ${dep1} == ${dep2} + touch $out + ''; + }; +} + diff --git a/tests/ca/post-hook.sh b/tests/ca/post-hook.sh new file mode 100755 index 000000000..1c9d4f700 --- /dev/null +++ b/tests/ca/post-hook.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +source common.sh + +requireDaemonNewerThan "2.4pre20210626" + +sed -i 's/experimental-features .*/& ca-derivations ca-references nix-command flakes/' "$NIX_CONF_DIR"/nix.conf + +export NIX_TESTS_CA_BY_DEFAULT=1 +cd .. +source ./post-hook.sh + + diff --git a/tests/ca/racy.nix b/tests/ca/racy.nix new file mode 100644 index 000000000..555a15484 --- /dev/null +++ b/tests/ca/racy.nix @@ -0,0 +1,15 @@ +# A derivation that would certainly fail if several builders tried to +# build it at once. + + +with import ./config.nix; + +mkDerivation { + name = "simple"; + buildCommand = '' + mkdir $out + echo bar >> $out/foo + sleep 3 + [[ "$(cat $out/foo)" == bar ]] + ''; +} diff --git a/tests/ca/recursive.sh b/tests/ca/recursive.sh new file mode 100755 index 000000000..648bf0a91 --- /dev/null +++ b/tests/ca/recursive.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +source common.sh + +requireDaemonNewerThan "2.4pre20210623" + +sed -i 's/experimental-features .*/& ca-derivations ca-references nix-command flakes/' "$NIX_CONF_DIR"/nix.conf + +export NIX_TESTS_CA_BY_DEFAULT=1 +cd .. +source ./recursive.sh + + diff --git a/tests/ca/signatures.sh b/tests/ca/signatures.sh new file mode 100644 index 000000000..4b4e468f7 --- /dev/null +++ b/tests/ca/signatures.sh @@ -0,0 +1,39 @@ +source common.sh + +# Globally enable the ca derivations experimental flag +sed -i 's/experimental-features = .*/& ca-derivations ca-references/' "$NIX_CONF_DIR/nix.conf" + +clearStore +clearCache + +nix-store --generate-binary-cache-key cache1.example.org $TEST_ROOT/sk1 $TEST_ROOT/pk1 +pk1=$(cat $TEST_ROOT/pk1) + +export REMOTE_STORE_DIR="$TEST_ROOT/remote_store" +export REMOTE_STORE="file://$REMOTE_STORE_DIR" + +ensureCorrectlyCopied () { + attrPath="$1" + nix build --store "$REMOTE_STORE" --file ./content-addressed.nix "$attrPath" +} + +testOneCopy () { + clearStore + rm -rf "$REMOTE_STORE_DIR" + + attrPath="$1" + nix copy --to $REMOTE_STORE "$attrPath" --file ./content-addressed.nix \ + --secret-key-files "$TEST_ROOT/sk1" + + ensureCorrectlyCopied "$attrPath" + + # Ensure that we can copy back what we put in the store + clearStore + nix copy --from $REMOTE_STORE \ + --file ./content-addressed.nix "$attrPath" \ + --trusted-public-keys $pk1 +} + +for attrPath in rootCA dependentCA transitivelyDependentCA dependentNonCA dependentFixedOutput; do + testOneCopy "$attrPath" +done diff --git a/tests/ca/substitute.sh b/tests/ca/substitute.sh new file mode 100644 index 000000000..3d9001bb8 --- /dev/null +++ b/tests/ca/substitute.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash + +# Ensure that binary substitution works properly with ca derivations + +source common.sh + +needLocalStore "“--no-require-sigs” can’t be used with the daemon" + +rm -rf $TEST_ROOT/binary_cache + +export REMOTE_STORE_DIR=$TEST_ROOT/binary_cache +export REMOTE_STORE=file://$REMOTE_STORE_DIR + +buildDrvs () { + nix build --file ./content-addressed.nix -L --no-link "$@" +} + +# Populate the remote cache +clearStore +nix copy --to $REMOTE_STORE --file ./content-addressed.nix + +# Restart the build on an empty store, ensuring that we don't build +clearStore +buildDrvs --substitute --substituters $REMOTE_STORE --no-require-sigs -j0 transitivelyDependentCA +# Check that the thing we’ve just substituted has its realisation stored +nix realisation info --file ./content-addressed.nix transitivelyDependentCA +# Check that its dependencies have it too +nix realisation info --file ./content-addressed.nix dependentCA rootCA + +# Same thing, but +# 1. With non-ca derivations +# 2. Erasing the realisations on the remote store +# +# Even in that case, realising the derivations should still produce the right +# realisations on the local store +# +# Regression test for #4725 +clearStore +nix build --file ../simple.nix -L --no-link --post-build-hook ../push-to-store.sh +clearStore +rm -r "$REMOTE_STORE_DIR/realisations" +nix build --file ../simple.nix -L --no-link --substitute --substituters "$REMOTE_STORE" --no-require-sigs -j0 +# There's no easy way to check whether a realisation is present on the local +# store − short of manually querying the db, but the build environment doesn't +# have the sqlite binary − so we instead push things again, and check that the +# realisations have correctly been pushed to the remote store +nix copy --to "$REMOTE_STORE" --file ../simple.nix +if [[ -z "$(ls "$REMOTE_STORE_DIR/realisations")" ]]; then + echo "Realisations not rebuilt" + exit 1 +fi + +# Test the local realisation disk cache +buildDrvs --post-build-hook ../push-to-store.sh +clearStore +# Add the realisations of rootCA to the cachecache +clearCacheCache +export _NIX_FORCE_HTTP=1 +buildDrvs --substitute --substituters $REMOTE_STORE --no-require-sigs -j0 +# Try rebuilding, but remove the realisations from the remote cache to force +# using the cachecache +clearStore +rm $REMOTE_STORE_DIR/realisations/* +buildDrvs --substitute --substituters $REMOTE_STORE --no-require-sigs -j0 diff --git a/tests/check.nix b/tests/check.nix index bca04fdaf..ec455ae2d 100644 --- a/tests/check.nix +++ b/tests/check.nix @@ -44,7 +44,7 @@ with import ./config.nix; }; hashmismatch = import <nix/fetchurl.nix> { - url = "file://" + toString ./dummy; + url = "file://" + builtins.getEnv "TMPDIR" + "/dummy"; sha256 = "0mdqa9w1p6cmli6976v4wi0sw9r4p5prkj7lzfd1877wk11c9c73"; }; diff --git a/tests/check.sh b/tests/check.sh index 5f25d04cb..ab48ff865 100644 --- a/tests/check.sh +++ b/tests/check.sh @@ -1,5 +1,8 @@ source common.sh +# XXX: This shouldn’t be, but #4813 cause this test to fail +buggyNeedLocalStore "see #4813" + checkBuildTempDirRemoved () { buildDir=$(sed -n 's/CHECK_TMPDIR=//p' $1 | head -1) @@ -61,30 +64,31 @@ nix-build check.nix -A nondeterministic --no-out-link --repeat 1 2> $TEST_ROOT/l [ "$status" = "1" ] grep 'differs from previous round' $TEST_ROOT/log -path=$(nix-build check.nix -A fetchurl --no-out-link --hashed-mirrors '') +path=$(nix-build check.nix -A fetchurl --no-out-link) chmod +w $path echo foo > $path chmod -w $path -nix-build check.nix -A fetchurl --no-out-link --check --hashed-mirrors '' +nix-build check.nix -A fetchurl --no-out-link --check # Note: "check" doesn't repair anything, it just compares to the hash stored in the database. [[ $(cat $path) = foo ]] -nix-build check.nix -A fetchurl --no-out-link --repair --hashed-mirrors '' +nix-build check.nix -A fetchurl --no-out-link --repair [[ $(cat $path) != foo ]] -nix-build check.nix -A hashmismatch --no-out-link --hashed-mirrors '' || status=$? +echo 'Hello World' > $TMPDIR/dummy +nix-build check.nix -A hashmismatch --no-out-link || status=$? [ "$status" = "102" ] -echo -n > ./dummy -nix-build check.nix -A hashmismatch --no-out-link --hashed-mirrors '' -echo 'Hello World' > ./dummy +echo -n > $TMPDIR/dummy +nix-build check.nix -A hashmismatch --no-out-link +echo 'Hello World' > $TMPDIR/dummy -nix-build check.nix -A hashmismatch --no-out-link --check --hashed-mirrors '' || status=$? +nix-build check.nix -A hashmismatch --no-out-link --check || status=$? [ "$status" = "102" ] # Multiple failures with --keep-going nix-build check.nix -A nondeterministic --no-out-link -nix-build check.nix -A nondeterministic -A hashmismatch --no-out-link --check --keep-going --hashed-mirrors '' || status=$? +nix-build check.nix -A nondeterministic -A hashmismatch --no-out-link --check --keep-going || status=$? [ "$status" = "110" ] diff --git a/tests/common.sh.in b/tests/common.sh.in index 308126094..7daab2460 100644 --- a/tests/common.sh.in +++ b/tests/common.sh.in @@ -1,5 +1,9 @@ set -e +if [[ -z "$COMMON_SH_SOURCED" ]]; then + +COMMON_SH_SOURCED=1 + export TEST_ROOT=$(realpath ${TMPDIR:-/tmp}/nix-test)/${TEST_NAME:-default} export NIX_STORE_DIR if ! NIX_STORE_DIR=$(readlink -f $TEST_ROOT/store 2> /dev/null); then @@ -11,7 +15,7 @@ export NIX_LOCALSTATE_DIR=$TEST_ROOT/var export NIX_LOG_DIR=$TEST_ROOT/var/log/nix export NIX_STATE_DIR=$TEST_ROOT/var/nix export NIX_CONF_DIR=$TEST_ROOT/etc -export NIX_DAEMON_SOCKET_PATH=$TEST_ROOT/daemon-socket +export NIX_DAEMON_SOCKET_PATH=$TEST_ROOT/dSocket unset NIX_USER_CONF_FILES export _NIX_TEST_SHARED=$TEST_ROOT/shared if [[ -n $NIX_STORE ]]; then @@ -29,18 +33,25 @@ unset XDG_CACHE_HOME mkdir -p $TEST_HOME export PATH=@bindir@:$PATH +if [[ -n "${NIX_CLIENT_PACKAGE:-}" ]]; then + export PATH="$NIX_CLIENT_PACKAGE/bin":$PATH +fi +if [[ -n "${NIX_DAEMON_PACKAGE:-}" ]]; then + export NIX_DAEMON_COMMAND="$NIX_DAEMON_PACKAGE/bin/nix-daemon" +fi coreutils=@coreutils@ export dot=@dot@ -export xmllint="@xmllint@" export SHELL="@bash@" export PAGER=cat -export HAVE_SODIUM="@HAVE_SODIUM@" export busybox="@sandbox_shell@" export version=@PACKAGE_VERSION@ export system=@system@ +export IMPURE_VAR1=foo +export IMPURE_VAR2=bar + cacheDir=$TEST_ROOT/binary-cache readLink() { @@ -59,7 +70,6 @@ clearStore() { mkdir "$NIX_STORE_DIR" rm -rf "$NIX_STATE_DIR" mkdir "$NIX_STATE_DIR" - nix-store --init clearProfiles } @@ -72,29 +82,57 @@ clearCacheCache() { } startDaemon() { + # Don’t start the daemon twice, as this would just make it loop indefinitely + if [[ "$NIX_REMOTE" == daemon ]]; then + return + fi # Start the daemon, wait for the socket to appear. !!! # ‘nix-daemon’ should have an option to fork into the background. - rm -f $NIX_STATE_DIR/daemon-socket/socket - nix-daemon & + rm -f $NIX_DAEMON_SOCKET_PATH + ${NIX_DAEMON_COMMAND:-nix daemon} & for ((i = 0; i < 30; i++)); do - if [ -e $NIX_DAEMON_SOCKET_PATH ]; then break; fi + if [[ -S $NIX_DAEMON_SOCKET_PATH ]]; then break; fi sleep 1 done pidDaemon=$! - trap "kill -9 $pidDaemon" EXIT + trap "killDaemon" EXIT export NIX_REMOTE=daemon } killDaemon() { - kill -9 $pidDaemon + kill $pidDaemon + for i in {0.10}; do + kill -0 $pidDaemon || break + sleep 1 + done + kill -9 $pidDaemon || true wait $pidDaemon || true trap "" EXIT } +restartDaemon() { + [[ -z "${pidDaemon:-}" ]] && return 0 + + killDaemon + unset NIX_REMOTE + startDaemon +} + if [[ $(uname) == Linux ]] && [[ -L /proc/self/ns/user ]] && unshare --user true; then _canUseSandbox=1 fi +isDaemonNewer () { + [[ -n "${NIX_DAEMON_PACKAGE:-}" ]] || return 0 + local requiredVersion="$1" + local daemonVersion=$($NIX_DAEMON_PACKAGE/bin/nix-daemon --version | cut -d' ' -f3) + return [[ $(nix eval --expr "builtins.compareVersions ''$daemonVersion'' ''2.4''") -ge 0 ]] +} + +requireDaemonNewerThan () { + isDaemonNewer "$1" || exit 99 +} + canUseSandbox() { if [[ ! $_canUseSandbox ]]; then echo "Sandboxing not supported, skipping this test..." @@ -120,4 +158,22 @@ expect() { [[ $res -eq $expected ]] } +needLocalStore() { + if [[ "$NIX_REMOTE" == "daemon" ]]; then + echo "Can’t run through the daemon ($1), skipping this test..." + return 99 + fi +} + +# Just to make it easy to find which tests should be fixed +buggyNeedLocalStore () { + needLocalStore +} + set -x + +if [[ -n "${NIX_DAEMON_PACKAGE:-}" ]]; then + startDaemon +fi + +fi # COMMON_SH_SOURCED diff --git a/tests/compute-levels.sh b/tests/compute-levels.sh new file mode 100644 index 000000000..e4322dfa1 --- /dev/null +++ b/tests/compute-levels.sh @@ -0,0 +1,7 @@ +source common.sh + +if [[ $(uname -ms) = "Linux x86_64" ]]; then + # x86_64 CPUs must always support the baseline + # microarchitecture level. + nix -vv --version | grep -q "x86_64-v1-linux" +fi diff --git a/tests/config.nix.in b/tests/config.nix.in index a57a8c596..7facbdcbc 100644 --- a/tests/config.nix.in +++ b/tests/config.nix.in @@ -1,3 +1,12 @@ +let + contentAddressedByDefault = builtins.getEnv "NIX_TESTS_CA_BY_DEFAULT" == "1"; + caArgs = if contentAddressedByDefault then { + __contentAddressed = true; + outputHashMode = "recursive"; + outputHashAlgo = "sha256"; + } else {}; +in + rec { shell = "@bash@"; @@ -13,6 +22,6 @@ rec { builder = shell; args = ["-e" args.builder or (builtins.toFile "builder-${args.name}.sh" "if [ -e .attrs.sh ]; then source .attrs.sh; fi; eval \"$buildCommand\"")]; PATH = path; - } // removeAttrs args ["builder" "meta"]) + } // caArgs // removeAttrs args ["builder" "meta"]) // { meta = args.meta or {}; }; } diff --git a/tests/config.sh b/tests/config.sh index 8fa349f11..01c78f2c3 100644 --- a/tests/config.sh +++ b/tests/config.sh @@ -1,18 +1,53 @@ source common.sh +# Isolate the home for this test. +# Other tests (e.g. flake registry tests) could be writing to $HOME in parallel. +export HOME=$TEST_ROOT/userhome + +# Test that using XDG_CONFIG_HOME works +# Assert the config folder didn't exist initially. +[ ! -e "$HOME/.config" ] +# Without XDG_CONFIG_HOME, creates $HOME/.config +unset XDG_CONFIG_HOME +# Run against the nix registry to create the config dir +# (Tip: this relies on removing non-existent entries being a no-op!) +nix registry remove userhome-without-xdg +# Verifies it created it +[ -e "$HOME/.config" ] +# Remove the directory it created +rm -rf "$HOME/.config" +# Run the same test, but with XDG_CONFIG_HOME +export XDG_CONFIG_HOME=$TEST_ROOT/confighome +# Assert the XDG_CONFIG_HOME/nix path does not exist yet. +[ ! -e "$TEST_ROOT/confighome/nix" ] +nix registry remove userhome-with-xdg +# Verifies the confighome path has been created +[ -e "$TEST_ROOT/confighome/nix" ] +# Assert the .config folder hasn't been created. +[ ! -e "$HOME/.config" ] + # Test that files are loaded from XDG by default -export XDG_CONFIG_HOME=/tmp/home -export XDG_CONFIG_DIRS=/tmp/dir1:/tmp/dir2 +export XDG_CONFIG_HOME=$TEST_ROOT/confighome +export XDG_CONFIG_DIRS=$TEST_ROOT/dir1:$TEST_ROOT/dir2 files=$(nix-build --verbose --version | grep "User config" | cut -d ':' -f2- | xargs) -[[ $files == "/tmp/home/nix/nix.conf:/tmp/dir1/nix/nix.conf:/tmp/dir2/nix/nix.conf" ]] +[[ $files == "$TEST_ROOT/confighome/nix/nix.conf:$TEST_ROOT/dir1/nix/nix.conf:$TEST_ROOT/dir2/nix/nix.conf" ]] # Test that setting NIX_USER_CONF_FILES overrides all the default user config files -export NIX_USER_CONF_FILES=/tmp/file1.conf:/tmp/file2.conf +export NIX_USER_CONF_FILES=$TEST_ROOT/file1.conf:$TEST_ROOT/file2.conf files=$(nix-build --verbose --version | grep "User config" | cut -d ':' -f2- | xargs) -[[ $files == "/tmp/file1.conf:/tmp/file2.conf" ]] +[[ $files == "$TEST_ROOT/file1.conf:$TEST_ROOT/file2.conf" ]] # Test that it's possible to load the config from a custom location here=$(readlink -f "$(dirname "${BASH_SOURCE[0]}")") export NIX_USER_CONF_FILES=$here/config/nix-with-substituters.conf var=$(nix show-config | grep '^substituters =' | cut -d '=' -f 2 | xargs) [[ $var == https://example.com ]] + +# Test that it's possible to load config from the environment +prev=$(nix show-config | grep '^cores' | cut -d '=' -f 2 | xargs) +export NIX_CONFIG="cores = 4242"$'\n'"experimental-features = nix-command flakes" +exp_cores=$(nix show-config | grep '^cores' | cut -d '=' -f 2 | xargs) +exp_features=$(nix show-config | grep '^experimental-features' | cut -d '=' -f 2 | xargs) +[[ $prev != $exp_cores ]] +[[ $exp_cores == "4242" ]] +[[ $exp_features == "nix-command flakes" ]] diff --git a/tests/db-migration.sh b/tests/db-migration.sh new file mode 100644 index 000000000..3f9dc8972 --- /dev/null +++ b/tests/db-migration.sh @@ -0,0 +1,29 @@ +# Test that we can successfully migrate from an older db schema + +# Only run this if we have an older Nix available +# XXX: This assumes that the `daemon` package is older than the `client` one +if [[ -z "$NIX_DAEMON_PACKAGE" ]]; then + exit 99 +fi + +source common.sh + +killDaemon +unset NIX_REMOTE + +# Fill the db using the older Nix +PATH_WITH_NEW_NIX="$PATH" +export PATH="$NIX_DAEMON_PACKAGE/bin:$PATH" +clearStore +nix-build simple.nix --no-out-link +nix-store --generate-binary-cache-key cache1.example.org $TEST_ROOT/sk1 $TEST_ROOT/pk1 +dependenciesOutPath=$(nix-build dependencies.nix --no-out-link --secret-key-files "$TEST_ROOT/sk1") +fixedOutPath=$(IMPURE_VAR1=foo IMPURE_VAR2=bar nix-build fixed.nix -A good.0 --no-out-link) + +# Migrate to the new schema and ensure that everything's there +export PATH="$PATH_WITH_NEW_NIX" +info=$(nix path-info --json $dependenciesOutPath) +[[ $info =~ '"ultimate":true' ]] +[[ $info =~ 'cache1.example.org' ]] +nix verify -r "$fixedOutPath" +nix verify -r "$dependenciesOutPath" --sigs-needed 1 --trusted-public-keys $(cat $TEST_ROOT/pk1) diff --git a/tests/describe-stores.sh b/tests/describe-stores.sh new file mode 100644 index 000000000..3fea61483 --- /dev/null +++ b/tests/describe-stores.sh @@ -0,0 +1,8 @@ +source common.sh + +# Query an arbitrary value in `nix describe-stores --json`'s output just to +# check that it has the right structure +[[ $(nix --experimental-features 'nix-command flakes' describe-stores --json | jq '.["SSH Store"]["compress"]["defaultValue"]') == false ]] + +# Ensure that the output of `nix describe-stores` isn't empty +[[ -n $(nix --experimental-features 'nix-command flakes' describe-stores) ]] diff --git a/tests/dummy b/tests/dummy new file mode 100644 index 000000000..557db03de --- /dev/null +++ b/tests/dummy @@ -0,0 +1 @@ +Hello World diff --git a/tests/dump-db.sh b/tests/dump-db.sh index d6eea42aa..48647f403 100644 --- a/tests/dump-db.sh +++ b/tests/dump-db.sh @@ -1,5 +1,7 @@ source common.sh +needLocalStore "--dump-db requires a local store" + clearStore path=$(nix-build dependencies.nix -o $TEST_ROOT/result) diff --git a/tests/eval-store.sh b/tests/eval-store.sh new file mode 100644 index 000000000..9ab7a87be --- /dev/null +++ b/tests/eval-store.sh @@ -0,0 +1,28 @@ +source common.sh + +requireDaemonNewerThan "2.4pre20210727" + +eval_store=$TEST_ROOT/eval-store + +clearStore +rm -rf "$eval_store" + +nix build -f dependencies.nix --eval-store "$eval_store" -o "$TEST_ROOT/result" +[[ -e $TEST_ROOT/result/foobar ]] +(! ls $NIX_STORE_DIR/*.drv) +ls $eval_store/nix/store/*.drv + +clearStore +rm -rf "$eval_store" + +nix-instantiate dependencies.nix --eval-store "$eval_store" +(! ls $NIX_STORE_DIR/*.drv) +ls $eval_store/nix/store/*.drv + +clearStore +rm -rf "$eval_store" + +nix-build dependencies.nix --eval-store "$eval_store" -o "$TEST_ROOT/result" +[[ -e $TEST_ROOT/result/foobar ]] +(! ls $NIX_STORE_DIR/*.drv) +ls $eval_store/nix/store/*.drv diff --git a/tests/fetchGit.sh b/tests/fetchGit.sh index d9c9874f5..89294d8d2 100644 --- a/tests/fetchGit.sh +++ b/tests/fetchGit.sh @@ -31,44 +31,60 @@ rev2=$(git -C $repo rev-parse HEAD) # Fetch a worktree unset _NIX_FORCE_HTTP -path0=$(nix eval --raw "(builtins.fetchGit file://$TEST_ROOT/worktree).outPath") +path0=$(nix eval --impure --raw --expr "(builtins.fetchGit file://$TEST_ROOT/worktree).outPath") +path0_=$(nix eval --impure --raw --expr "(builtins.fetchTree { type = \"git\"; url = file://$TEST_ROOT/worktree; }).outPath") +[[ $path0 = $path0_ ]] export _NIX_FORCE_HTTP=1 [[ $(tail -n 1 $path0/hello) = "hello" ]] # Fetch the default branch. -path=$(nix eval --raw "(builtins.fetchGit file://$repo).outPath") +path=$(nix eval --impure --raw --expr "(builtins.fetchGit file://$repo).outPath") [[ $(cat $path/hello) = world ]] +# Fetch a rev from another branch +git -C $repo checkout -b devtest +echo "different file" >> $TEST_ROOT/git/differentbranch +git -C $repo add differentbranch +git -C $repo commit -m 'Test2' +git -C $repo checkout master +devrev=$(git -C $repo rev-parse devtest) +out=$(nix eval --impure --raw --expr "builtins.fetchGit { url = file://$repo; rev = \"$devrev\"; }" 2>&1) || status=$? +[[ $status == 1 ]] +[[ $out =~ 'Cannot find Git revision' ]] + +[[ $(nix eval --raw --expr "builtins.readFile (builtins.fetchGit { url = file://$repo; rev = \"$devrev\"; allRefs = true; } + \"/differentbranch\")") = 'different file' ]] + # In pure eval mode, fetchGit without a revision should fail. -[[ $(nix eval --raw "(builtins.readFile (fetchGit file://$repo + \"/hello\"))") = world ]] -(! nix eval --pure-eval --raw "(builtins.readFile (fetchGit file://$repo + \"/hello\"))") +[[ $(nix eval --impure --raw --expr "builtins.readFile (fetchGit file://$repo + \"/hello\")") = world ]] +(! nix eval --raw --expr "builtins.readFile (fetchGit file://$repo + \"/hello\")") # Fetch using an explicit revision hash. -path2=$(nix eval --raw "(builtins.fetchGit { url = file://$repo; rev = \"$rev2\"; }).outPath") +path2=$(nix eval --raw --expr "(builtins.fetchGit { url = file://$repo; rev = \"$rev2\"; }).outPath") [[ $path = $path2 ]] # In pure eval mode, fetchGit with a revision should succeed. -[[ $(nix eval --pure-eval --raw "(builtins.readFile (fetchGit { url = file://$repo; rev = \"$rev2\"; } + \"/hello\"))") = world ]] +[[ $(nix eval --raw --expr "builtins.readFile (fetchGit { url = file://$repo; rev = \"$rev2\"; } + \"/hello\")") = world ]] # Fetch again. This should be cached. mv $repo ${repo}-tmp -path2=$(nix eval --raw "(builtins.fetchGit file://$repo).outPath") +path2=$(nix eval --impure --raw --expr "(builtins.fetchGit file://$repo).outPath") [[ $path = $path2 ]] -[[ $(nix eval "(builtins.fetchGit file://$repo).revCount") = 2 ]] -[[ $(nix eval --raw "(builtins.fetchGit file://$repo).rev") = $rev2 ]] +[[ $(nix eval --impure --expr "(builtins.fetchGit file://$repo).revCount") = 2 ]] +[[ $(nix eval --impure --raw --expr "(builtins.fetchGit file://$repo).rev") = $rev2 ]] +[[ $(nix eval --impure --raw --expr "(builtins.fetchGit file://$repo).shortRev") = ${rev2:0:7} ]] # Fetching with a explicit hash should succeed. -path2=$(nix eval --tarball-ttl 0 --raw "(builtins.fetchGit { url = file://$repo; rev = \"$rev2\"; }).outPath") +path2=$(nix eval --refresh --raw --expr "(builtins.fetchGit { url = file://$repo; rev = \"$rev2\"; }).outPath") [[ $path = $path2 ]] -path2=$(nix eval --tarball-ttl 0 --raw "(builtins.fetchGit { url = file://$repo; rev = \"$rev1\"; }).outPath") +path2=$(nix eval --refresh --raw --expr "(builtins.fetchGit { url = file://$repo; rev = \"$rev1\"; }).outPath") [[ $(cat $path2/hello) = utrecht ]] mv ${repo}-tmp $repo # Using a clean working tree should produce the same result. -path2=$(nix eval --raw "(builtins.fetchGit $repo).outPath") +path2=$(nix eval --impure --raw --expr "(builtins.fetchGit $repo).outPath") [[ $path = $path2 ]] # Using an unclean tree should yield the tracked but uncommitted changes. @@ -80,59 +96,66 @@ git -C $repo add dir1/foo git -C $repo rm hello unset _NIX_FORCE_HTTP -path2=$(nix eval --raw "(builtins.fetchGit $repo).outPath") +path2=$(nix eval --impure --raw --expr "(builtins.fetchGit $repo).outPath") [ ! -e $path2/hello ] [ ! -e $path2/bar ] [ ! -e $path2/dir2/bar ] [ ! -e $path2/.git ] [[ $(cat $path2/dir1/foo) = foo ]] -[[ $(nix eval --raw "(builtins.fetchGit $repo).rev") = 0000000000000000000000000000000000000000 ]] +[[ $(nix eval --impure --raw --expr "(builtins.fetchGit $repo).rev") = 0000000000000000000000000000000000000000 ]] # ... unless we're using an explicit ref or rev. -path3=$(nix eval --raw "(builtins.fetchGit { url = $repo; ref = \"master\"; }).outPath") +path3=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = $repo; ref = \"master\"; }).outPath") [[ $path = $path3 ]] -path3=$(nix eval --raw "(builtins.fetchGit { url = $repo; rev = \"$rev2\"; }).outPath") +path3=$(nix eval --raw --expr "(builtins.fetchGit { url = $repo; rev = \"$rev2\"; }).outPath") [[ $path = $path3 ]] # Committing should not affect the store path. git -C $repo commit -m 'Bla3' -a -path4=$(nix eval --tarball-ttl 0 --raw "(builtins.fetchGit file://$repo).outPath") +path4=$(nix eval --impure --refresh --raw --expr "(builtins.fetchGit file://$repo).outPath") [[ $path2 = $path4 ]] +nix eval --impure --raw --expr "(builtins.fetchGit { url = $repo; rev = \"$rev2\"; narHash = \"sha256-B5yIPHhEm0eysJKEsO7nqxprh9vcblFxpJG11gXJus1=\"; }).outPath" || status=$? +[[ "$status" = "102" ]] + +path5=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = $repo; rev = \"$rev2\"; narHash = \"sha256-Hr8g6AqANb3xqX28eu1XnjK/3ab8Gv6TJSnkb1LezG9=\"; }).outPath") +[[ $path = $path5 ]] + # tarball-ttl should be ignored if we specify a rev echo delft > $repo/hello git -C $repo add hello git -C $repo commit -m 'Bla4' rev3=$(git -C $repo rev-parse HEAD) -nix eval --tarball-ttl 3600 "(builtins.fetchGit { url = $repo; rev = \"$rev3\"; })" >/dev/null +nix eval --tarball-ttl 3600 --expr "builtins.fetchGit { url = $repo; rev = \"$rev3\"; }" >/dev/null # Update 'path' to reflect latest master -path=$(nix eval --raw "(builtins.fetchGit file://$repo).outPath") +path=$(nix eval --impure --raw --expr "(builtins.fetchGit file://$repo).outPath") # Check behavior when non-master branch is used git -C $repo checkout $rev2 -b dev echo dev > $repo/hello # File URI uses dirty tree unless specified otherwise -path2=$(nix eval --raw "(builtins.fetchGit file://$repo).outPath") +path2=$(nix eval --impure --raw --expr "(builtins.fetchGit file://$repo).outPath") [ $(cat $path2/hello) = dev ] # Using local path with branch other than 'master' should work when clean or dirty -path3=$(nix eval --raw "(builtins.fetchGit $repo).outPath") +path3=$(nix eval --impure --raw --expr "(builtins.fetchGit $repo).outPath") # (check dirty-tree handling was used) -[[ $(nix eval --raw "(builtins.fetchGit $repo).rev") = 0000000000000000000000000000000000000000 ]] +[[ $(nix eval --impure --raw --expr "(builtins.fetchGit $repo).rev") = 0000000000000000000000000000000000000000 ]] +[[ $(nix eval --impure --raw --expr "(builtins.fetchGit $repo).shortRev") = 0000000 ]] # Committing shouldn't change store path, or switch to using 'master' git -C $repo commit -m 'Bla5' -a -path4=$(nix eval --raw "(builtins.fetchGit $repo).outPath") +path4=$(nix eval --impure --raw --expr "(builtins.fetchGit $repo).outPath") [[ $(cat $path4/hello) = dev ]] [[ $path3 = $path4 ]] # Confirm same as 'dev' branch -path5=$(nix eval --raw "(builtins.fetchGit { url = $repo; ref = \"dev\"; }).outPath") +path5=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = $repo; ref = \"dev\"; }).outPath") [[ $path3 = $path5 ]] @@ -141,19 +164,32 @@ rm -rf $TEST_HOME/.cache/nix # Try again, but without 'git' on PATH. This should fail. NIX=$(command -v nix) -# This should fail -(! PATH= $NIX eval --raw "(builtins.fetchGit { url = $repo; ref = \"dev\"; }).outPath" ) +(! PATH= $NIX eval --impure --raw --expr "(builtins.fetchGit { url = $repo; ref = \"dev\"; }).outPath" ) # Try again, with 'git' available. This should work. -path5=$(nix eval --raw "(builtins.fetchGit { url = $repo; ref = \"dev\"; }).outPath") +path5=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = $repo; ref = \"dev\"; }).outPath") [[ $path3 = $path5 ]] # Fetching a shallow repo shouldn't work by default, because we can't # return a revCount. git clone --depth 1 file://$repo $TEST_ROOT/shallow -(! nix eval --raw "(builtins.fetchGit { url = $TEST_ROOT/shallow; ref = \"dev\"; }).outPath") +(! nix eval --impure --raw --expr "(builtins.fetchGit { url = $TEST_ROOT/shallow; ref = \"dev\"; }).outPath") # But you can request a shallow clone, which won't return a revCount. -path6=$(nix eval --raw "(builtins.fetchTree { type = \"git\"; url = \"file://$TEST_ROOT/shallow\"; ref = \"dev\"; shallow = true; }).outPath") +path6=$(nix eval --impure --raw --expr "(builtins.fetchTree { type = \"git\"; url = \"file://$TEST_ROOT/shallow\"; ref = \"dev\"; shallow = true; }).outPath") [[ $path3 = $path6 ]] -[[ $(nix eval "(builtins.fetchTree { type = \"git\"; url = \"file://$TEST_ROOT/shallow\"; ref = \"dev\"; shallow = true; }).revCount or 123") == 123 ]] +[[ $(nix eval --impure --expr "(builtins.fetchTree { type = \"git\"; url = \"file://$TEST_ROOT/shallow\"; ref = \"dev\"; shallow = true; }).revCount or 123") == 123 ]] + +# Explicit ref = "HEAD" should work, and produce the same outPath as without ref +path7=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = \"file://$repo\"; ref = \"HEAD\"; }).outPath") +path8=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = \"file://$repo\"; }).outPath") +[[ $path7 = $path8 ]] + +# ref = "HEAD" should fetch the HEAD revision +rev4=$(git -C $repo rev-parse HEAD) +rev4_nix=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = \"file://$repo\"; ref = \"HEAD\"; }).rev") +[[ $rev4 = $rev4_nix ]] + +# The name argument should be handled +path9=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = \"file://$repo\"; ref = \"HEAD\"; name = \"foo\"; }).outPath") +[[ $path9 =~ -foo$ ]] diff --git a/tests/fetchGitRefs.sh b/tests/fetchGitRefs.sh index 23934698e..52926040b 100644 --- a/tests/fetchGitRefs.sh +++ b/tests/fetchGitRefs.sh @@ -19,7 +19,7 @@ echo utrecht > "$repo"/hello git -C "$repo" add hello git -C "$repo" commit -m 'Bla1' -path=$(nix eval --raw "(builtins.fetchGit { url = $repo; ref = \"master\"; }).outPath") +path=$(nix eval --raw --impure --expr "(builtins.fetchGit { url = $repo; ref = \"master\"; }).outPath") # Test various combinations of ref names # (taken from the git project) @@ -42,7 +42,7 @@ valid_ref() { { set +x; printf >&2 '\n>>>>>>>>>> valid_ref %s\b <<<<<<<<<<\n' $(printf %s "$1" | sed -n -e l); set -x; } git check-ref-format --branch "$1" >/dev/null git -C "$repo" branch "$1" master >/dev/null - path1=$(nix eval --raw "(builtins.fetchGit { url = $repo; ref = ''$1''; }).outPath") + path1=$(nix eval --raw --impure --expr "(builtins.fetchGit { url = $repo; ref = ''$1''; }).outPath") [[ $path1 = $path ]] git -C "$repo" branch -D "$1" >/dev/null } @@ -56,7 +56,7 @@ invalid_ref() { else (! git check-ref-format --branch "$1" >/dev/null 2>&1) fi - nix --debug eval --raw "(builtins.fetchGit { url = $repo; ref = ''$1''; }).outPath" 2>&1 | grep 'invalid Git branch/tag name' >/dev/null + nix --debug eval --raw --impure --expr "(builtins.fetchGit { url = $repo; ref = ''$1''; }).outPath" 2>&1 | grep 'invalid Git branch/tag name' >/dev/null } diff --git a/tests/fetchGitSubmodules.sh b/tests/fetchGitSubmodules.sh index 4c2c13f1a..03d46088e 100644 --- a/tests/fetchGitSubmodules.sh +++ b/tests/fetchGitSubmodules.sh @@ -38,38 +38,38 @@ git -C $rootRepo commit -m "Add submodule" rev=$(git -C $rootRepo rev-parse HEAD) -r1=$(nix eval --raw "(builtins.fetchGit { url = file://$rootRepo; rev = \"$rev\"; }).outPath") -r2=$(nix eval --raw "(builtins.fetchGit { url = file://$rootRepo; rev = \"$rev\"; submodules = false; }).outPath") -r3=$(nix eval --raw "(builtins.fetchGit { url = file://$rootRepo; rev = \"$rev\"; submodules = true; }).outPath") +r1=$(nix eval --raw --expr "(builtins.fetchGit { url = file://$rootRepo; rev = \"$rev\"; }).outPath") +r2=$(nix eval --raw --expr "(builtins.fetchGit { url = file://$rootRepo; rev = \"$rev\"; submodules = false; }).outPath") +r3=$(nix eval --raw --expr "(builtins.fetchGit { url = file://$rootRepo; rev = \"$rev\"; submodules = true; }).outPath") -[[ $r1 == $r2 ]] -[[ $r2 != $r3 ]] +[[ $r1 == $r3 ]] +[[ $r2 != $r1 ]] -r4=$(nix eval --raw "(builtins.fetchGit { url = file://$rootRepo; ref = \"master\"; rev = \"$rev\"; }).outPath") -r5=$(nix eval --raw "(builtins.fetchGit { url = file://$rootRepo; ref = \"master\"; rev = \"$rev\"; submodules = false; }).outPath") -r6=$(nix eval --raw "(builtins.fetchGit { url = file://$rootRepo; ref = \"master\"; rev = \"$rev\"; submodules = true; }).outPath") -r7=$(nix eval --raw "(builtins.fetchGit { url = $rootRepo; ref = \"master\"; rev = \"$rev\"; submodules = true; }).outPath") -r8=$(nix eval --raw "(builtins.fetchGit { url = $rootRepo; rev = \"$rev\"; submodules = true; }).outPath") +r4=$(nix eval --raw --expr "(builtins.fetchGit { url = file://$rootRepo; ref = \"master\"; rev = \"$rev\"; }).outPath") +r5=$(nix eval --raw --expr "(builtins.fetchGit { url = file://$rootRepo; ref = \"master\"; rev = \"$rev\"; submodules = false; }).outPath") +r6=$(nix eval --raw --expr "(builtins.fetchGit { url = file://$rootRepo; ref = \"master\"; rev = \"$rev\"; submodules = true; }).outPath") +r7=$(nix eval --raw --expr "(builtins.fetchGit { url = $rootRepo; ref = \"master\"; rev = \"$rev\"; submodules = true; }).outPath") +r8=$(nix eval --raw --expr "(builtins.fetchGit { url = $rootRepo; rev = \"$rev\"; submodules = true; }).outPath") [[ $r1 == $r4 ]] -[[ $r4 == $r5 ]] +[[ $r4 == $r6 ]] [[ $r3 == $r6 ]] [[ $r6 == $r7 ]] [[ $r7 == $r8 ]] -have_submodules=$(nix eval "(builtins.fetchGit { url = $rootRepo; rev = \"$rev\"; }).submodules") -[[ $have_submodules == false ]] +have_submodules=$(nix eval --expr "(builtins.fetchGit { url = $rootRepo; rev = \"$rev\"; }).submodules") +[[ $have_submodules == true ]] -have_submodules=$(nix eval "(builtins.fetchGit { url = $rootRepo; rev = \"$rev\"; submodules = false; }).submodules") +have_submodules=$(nix eval --expr "(builtins.fetchGit { url = $rootRepo; rev = \"$rev\"; submodules = false; }).submodules") [[ $have_submodules == false ]] -have_submodules=$(nix eval "(builtins.fetchGit { url = $rootRepo; rev = \"$rev\"; submodules = true; }).submodules") +have_submodules=$(nix eval --expr "(builtins.fetchGit { url = $rootRepo; rev = \"$rev\"; submodules = true; }).submodules") [[ $have_submodules == true ]] -pathWithoutSubmodules=$(nix eval --raw "(builtins.fetchGit { url = file://$rootRepo; rev = \"$rev\"; }).outPath") -pathWithSubmodules=$(nix eval --raw "(builtins.fetchGit { url = file://$rootRepo; rev = \"$rev\"; submodules = true; }).outPath") -pathWithSubmodulesAgain=$(nix eval --raw "(builtins.fetchGit { url = file://$rootRepo; rev = \"$rev\"; submodules = true; }).outPath") -pathWithSubmodulesAgainWithRef=$(nix eval --raw "(builtins.fetchGit { url = file://$rootRepo; ref = \"master\"; rev = \"$rev\"; submodules = true; }).outPath") +pathWithoutSubmodules=$(nix eval --raw --expr "(builtins.fetchGit { url = file://$rootRepo; rev = \"$rev\"; submodules = false; }).outPath") +pathWithSubmodules=$(nix eval --raw --expr "(builtins.fetchGit { url = file://$rootRepo; rev = \"$rev\"; }).outPath") +pathWithSubmodulesAgain=$(nix eval --raw --expr "(builtins.fetchGit { url = file://$rootRepo; rev = \"$rev\"; submodules = true; }).outPath") +pathWithSubmodulesAgainWithRef=$(nix eval --raw --expr "(builtins.fetchGit { url = file://$rootRepo; ref = \"master\"; rev = \"$rev\"; submodules = true; }).outPath") # The resulting store path cannot be the same. [[ $pathWithoutSubmodules != $pathWithSubmodules ]] @@ -91,7 +91,7 @@ test "$(find "$pathWithSubmodules" -name .git)" = "" # Git repos without submodules can be fetched with submodules = true. subRev=$(git -C $subRepo rev-parse HEAD) -noSubmoduleRepoBaseline=$(nix eval --raw "(builtins.fetchGit { url = file://$subRepo; rev = \"$subRev\"; }).outPath") -noSubmoduleRepo=$(nix eval --raw "(builtins.fetchGit { url = file://$subRepo; rev = \"$subRev\"; submodules = true; }).outPath") +noSubmoduleRepoBaseline=$(nix eval --raw --expr "(builtins.fetchGit { url = file://$subRepo; rev = \"$subRev\"; }).outPath") +noSubmoduleRepo=$(nix eval --raw --expr "(builtins.fetchGit { url = file://$subRepo; rev = \"$subRev\"; submodules = true; }).outPath") [[ $noSubmoduleRepoBaseline == $noSubmoduleRepo ]] diff --git a/tests/fetchMercurial.sh b/tests/fetchMercurial.sh index 4088dbd39..726840664 100644 --- a/tests/fetchMercurial.sh +++ b/tests/fetchMercurial.sh @@ -9,12 +9,15 @@ clearStore repo=$TEST_ROOT/hg -rm -rf $repo ${repo}-tmp $TEST_HOME/.cache/nix/hg +rm -rf $repo ${repo}-tmp $TEST_HOME/.cache/nix hg init $repo echo '[ui]' >> $repo/.hg/hgrc echo 'username = Foobar <foobar@example.org>' >> $repo/.hg/hgrc +# Set ui.tweakdefaults to ensure HGPLAIN is being set. +echo 'tweakdefaults = True' >> $repo/.hg/hgrc + echo utrecht > $repo/hello touch $repo/.hgignore hg add --cwd $repo hello .hgignore @@ -26,43 +29,43 @@ hg commit --cwd $repo -m 'Bla2' rev2=$(hg log --cwd $repo -r tip --template '{node}') # Fetch the default branch. -path=$(nix eval --raw "(builtins.fetchMercurial file://$repo).outPath") +path=$(nix eval --impure --raw --expr "(builtins.fetchMercurial file://$repo).outPath") [[ $(cat $path/hello) = world ]] # In pure eval mode, fetchGit without a revision should fail. -[[ $(nix eval --raw "(builtins.readFile (fetchMercurial file://$repo + \"/hello\"))") = world ]] -(! nix eval --pure-eval --raw "(builtins.readFile (fetchMercurial file://$repo + \"/hello\"))") +[[ $(nix eval --impure --raw --expr "(builtins.readFile (fetchMercurial file://$repo + \"/hello\"))") = world ]] +(! nix eval --raw --expr "builtins.readFile (fetchMercurial file://$repo + \"/hello\")") # Fetch using an explicit revision hash. -path2=$(nix eval --raw "(builtins.fetchMercurial { url = file://$repo; rev = \"$rev2\"; }).outPath") +path2=$(nix eval --impure --raw --expr "(builtins.fetchMercurial { url = file://$repo; rev = \"$rev2\"; }).outPath") [[ $path = $path2 ]] # In pure eval mode, fetchGit with a revision should succeed. -[[ $(nix eval --pure-eval --raw "(builtins.readFile (fetchMercurial { url = file://$repo; rev = \"$rev2\"; } + \"/hello\"))") = world ]] +[[ $(nix eval --raw --expr "builtins.readFile (fetchMercurial { url = file://$repo; rev = \"$rev2\"; } + \"/hello\")") = world ]] # Fetch again. This should be cached. mv $repo ${repo}-tmp -path2=$(nix eval --raw "(builtins.fetchMercurial file://$repo).outPath") +path2=$(nix eval --impure --raw --expr "(builtins.fetchMercurial file://$repo).outPath") [[ $path = $path2 ]] -[[ $(nix eval --raw "(builtins.fetchMercurial file://$repo).branch") = default ]] -[[ $(nix eval "(builtins.fetchMercurial file://$repo).revCount") = 1 ]] -[[ $(nix eval --raw "(builtins.fetchMercurial file://$repo).rev") = $rev2 ]] +[[ $(nix eval --impure --raw --expr "(builtins.fetchMercurial file://$repo).branch") = default ]] +[[ $(nix eval --impure --expr "(builtins.fetchMercurial file://$repo).revCount") = 1 ]] +[[ $(nix eval --impure --raw --expr "(builtins.fetchMercurial file://$repo).rev") = $rev2 ]] # But with TTL 0, it should fail. -(! nix eval --tarball-ttl 0 "(builtins.fetchMercurial file://$repo)") +(! nix eval --impure --refresh --expr "builtins.fetchMercurial file://$repo") # Fetching with a explicit hash should succeed. -path2=$(nix eval --tarball-ttl 0 --raw "(builtins.fetchMercurial { url = file://$repo; rev = \"$rev2\"; }).outPath") +path2=$(nix eval --refresh --raw --expr "(builtins.fetchMercurial { url = file://$repo; rev = \"$rev2\"; }).outPath") [[ $path = $path2 ]] -path2=$(nix eval --tarball-ttl 0 --raw "(builtins.fetchMercurial { url = file://$repo; rev = \"$rev1\"; }).outPath") +path2=$(nix eval --refresh --raw --expr "(builtins.fetchMercurial { url = file://$repo; rev = \"$rev1\"; }).outPath") [[ $(cat $path2/hello) = utrecht ]] mv ${repo}-tmp $repo # Using a clean working tree should produce the same result. -path2=$(nix eval --raw "(builtins.fetchMercurial $repo).outPath") +path2=$(nix eval --impure --raw --expr "(builtins.fetchMercurial $repo).outPath") [[ $path = $path2 ]] # Using an unclean tree should yield the tracked but uncommitted changes. @@ -73,21 +76,26 @@ echo bar > $repo/dir2/bar hg add --cwd $repo dir1/foo hg rm --cwd $repo hello -path2=$(nix eval --raw "(builtins.fetchMercurial $repo).outPath") +path2=$(nix eval --impure --raw --expr "(builtins.fetchMercurial $repo).outPath") [ ! -e $path2/hello ] [ ! -e $path2/bar ] [ ! -e $path2/dir2/bar ] [ ! -e $path2/.hg ] [[ $(cat $path2/dir1/foo) = foo ]] -[[ $(nix eval --raw "(builtins.fetchMercurial $repo).rev") = 0000000000000000000000000000000000000000 ]] +[[ $(nix eval --impure --raw --expr "(builtins.fetchMercurial $repo).rev") = 0000000000000000000000000000000000000000 ]] -# ... unless we're using an explicit rev. -path3=$(nix eval --raw "(builtins.fetchMercurial { url = $repo; rev = \"default\"; }).outPath") +# ... unless we're using an explicit ref. +path3=$(nix eval --impure --raw --expr "(builtins.fetchMercurial { url = $repo; rev = \"default\"; }).outPath") [[ $path = $path3 ]] # Committing should not affect the store path. hg commit --cwd $repo -m 'Bla3' -path4=$(nix eval --tarball-ttl 0 --raw "(builtins.fetchMercurial file://$repo).outPath") +path4=$(nix eval --impure --refresh --raw --expr "(builtins.fetchMercurial file://$repo).outPath") [[ $path2 = $path4 ]] + +echo paris > $repo/hello +# Passing a `name` argument should be reflected in the output path +path5=$(nix eval -vvvvv --impure --refresh --raw --expr "(builtins.fetchMercurial { url = \"file://$repo\"; name = \"foo\"; } ).outPath") +[[ $path5 =~ -foo$ ]] diff --git a/tests/fetchurl.sh b/tests/fetchurl.sh index 2535651b0..3d1685f43 100644 --- a/tests/fetchurl.sh +++ b/tests/fetchurl.sh @@ -5,46 +5,44 @@ clearStore # Test fetching a flat file. hash=$(nix-hash --flat --type sha256 ./fetchurl.sh) -outPath=$(nix-build '<nix/fetchurl.nix>' --argstr url file://$(pwd)/fetchurl.sh --argstr sha256 $hash --no-out-link --hashed-mirrors '') +outPath=$(nix-build -vvvvv --expr 'import <nix/fetchurl.nix>' --argstr url file://$(pwd)/fetchurl.sh --argstr sha256 $hash --no-out-link) cmp $outPath fetchurl.sh # Now using a base-64 hash. clearStore -hash=$(nix hash-file --type sha512 --base64 ./fetchurl.sh) +hash=$(nix hash file --type sha512 --base64 ./fetchurl.sh) -outPath=$(nix-build '<nix/fetchurl.nix>' --argstr url file://$(pwd)/fetchurl.sh --argstr sha512 $hash --no-out-link --hashed-mirrors '') +outPath=$(nix-build -vvvvv --expr 'import <nix/fetchurl.nix>' --argstr url file://$(pwd)/fetchurl.sh --argstr sha512 $hash --no-out-link) cmp $outPath fetchurl.sh # Now using an SRI hash. clearStore -hash=$(nix hash-file ./fetchurl.sh) +hash=$(nix hash file ./fetchurl.sh) [[ $hash =~ ^sha256- ]] -outPath=$(nix-build '<nix/fetchurl.nix>' --argstr url file://$(pwd)/fetchurl.sh --argstr hash $hash --no-out-link --hashed-mirrors '') +outPath=$(nix-build -vvvvv --expr 'import <nix/fetchurl.nix>' --argstr url file://$(pwd)/fetchurl.sh --argstr hash $hash --no-out-link) cmp $outPath fetchurl.sh -# Test the hashed mirror feature. +# Test that we can substitute from a different store dir. clearStore -hash=$(nix hash-file --type sha512 --base64 ./fetchurl.sh) -hash32=$(nix hash-file --type sha512 --base16 ./fetchurl.sh) +other_store=file://$TEST_ROOT/other_store?store=/fnord/store -mirror=$TEST_ROOT/hashed-mirror -rm -rf $mirror -mkdir -p $mirror/sha512 -ln -s $(pwd)/fetchurl.sh $mirror/sha512/$hash32 +hash=$(nix hash file --type sha256 --base16 ./fetchurl.sh) -outPath=$(nix-build '<nix/fetchurl.nix>' --argstr url file:///no-such-dir/fetchurl.sh --argstr sha512 $hash --no-out-link --hashed-mirrors "file://$mirror") +storePath=$(nix --store $other_store store add-file ./fetchurl.sh) + +outPath=$(nix-build -vvvvv --expr 'import <nix/fetchurl.nix>' --argstr url file:///no-such-dir/fetchurl.sh --argstr sha256 $hash --no-out-link --substituters $other_store) # Test hashed mirrors with an SRI hash. -nix-build '<nix/fetchurl.nix>' --argstr url file:///no-such-dir/fetchurl.sh --argstr hash $(nix to-sri --type sha512 $hash) \ - --argstr name bla --no-out-link --hashed-mirrors "file://$mirror" +nix-build -vvvvv --expr 'import <nix/fetchurl.nix>' --argstr url file:///no-such-dir/fetchurl.sh --argstr hash $(nix hash to-sri --type sha256 $hash) \ + --no-out-link --substituters $other_store # Test unpacking a NAR. rm -rf $TEST_ROOT/archive @@ -57,7 +55,7 @@ nix-store --dump $TEST_ROOT/archive > $nar hash=$(nix-hash --flat --type sha256 $nar) -outPath=$(nix-build '<nix/fetchurl.nix>' --argstr url file://$nar --argstr sha256 $hash \ +outPath=$(nix-build -vvvvv --expr 'import <nix/fetchurl.nix>' --argstr url file://$nar --argstr sha256 $hash \ --arg unpack true --argstr name xyzzy --no-out-link) echo $outPath | grep -q 'xyzzy' @@ -71,7 +69,7 @@ nix-store --delete $outPath narxz=$TEST_ROOT/archive.nar.xz rm -f $narxz xz --keep $nar -outPath=$(nix-build '<nix/fetchurl.nix>' --argstr url file://$narxz --argstr sha256 $hash \ +outPath=$(nix-build -vvvvv --expr 'import <nix/fetchurl.nix>' --argstr url file://$narxz --argstr sha256 $hash \ --arg unpack true --argstr name xyzzy --no-out-link) test -x $outPath/fetchurl.sh diff --git a/tests/filter-source.sh b/tests/filter-source.sh index 1f8dceee5..ba34d2eac 100644 --- a/tests/filter-source.sh +++ b/tests/filter-source.sh @@ -10,10 +10,16 @@ touch $TEST_ROOT/filterin/bak touch $TEST_ROOT/filterin/bla.c.bak ln -s xyzzy $TEST_ROOT/filterin/link -nix-build ./filter-source.nix -o $TEST_ROOT/filterout +checkFilter() { + test ! -e $1/foo/bar + test -e $1/xyzzy + test -e $1/bak + test ! -e $1/bla.c.bak + test ! -L $1/link +} -test ! -e $TEST_ROOT/filterout/foo/bar -test -e $TEST_ROOT/filterout/xyzzy -test -e $TEST_ROOT/filterout/bak -test ! -e $TEST_ROOT/filterout/bla.c.bak -test ! -L $TEST_ROOT/filterout/link +nix-build ./filter-source.nix -o $TEST_ROOT/filterout1 +checkFilter $TEST_ROOT/filterout1 + +nix-build ./path.nix -o $TEST_ROOT/filterout2 +checkFilter $TEST_ROOT/filterout2 diff --git a/tests/fixed.sh b/tests/fixed.sh index 8f51403a7..90c4c8c32 100644 --- a/tests/fixed.sh +++ b/tests/fixed.sh @@ -2,9 +2,6 @@ source common.sh clearStore -export IMPURE_VAR1=foo -export IMPURE_VAR2=bar - path=$(nix-store -q $(nix-instantiate fixed.nix -A good.0)) echo 'testing bad...' diff --git a/tests/flakes.sh b/tests/flakes.sh new file mode 100644 index 000000000..2ede7f72c --- /dev/null +++ b/tests/flakes.sh @@ -0,0 +1,786 @@ +source common.sh + +if [[ -z $(type -p git) ]]; then + echo "Git not installed; skipping flake tests" + exit 99 +fi + +if [[ -z $(type -p hg) ]]; then + echo "Mercurial not installed; skipping flake tests" + exit 99 +fi + +clearStore +rm -rf $TEST_HOME/.cache $TEST_HOME/.config + +registry=$TEST_ROOT/registry.json + +flake1Dir=$TEST_ROOT/flake1 +flake2Dir=$TEST_ROOT/flake2 +flake3Dir=$TEST_ROOT/flake3 +flake5Dir=$TEST_ROOT/flake5 +flake6Dir=$TEST_ROOT/flake6 +flake7Dir=$TEST_ROOT/flake7 +templatesDir=$TEST_ROOT/templates +nonFlakeDir=$TEST_ROOT/nonFlake +badFlakeDir=$TEST_ROOT/badFlake +flakeA=$TEST_ROOT/flakeA +flakeB=$TEST_ROOT/flakeB +flakeGitBare=$TEST_ROOT/flakeGitBare +flakeFollowsA=$TEST_ROOT/follows/flakeA +flakeFollowsB=$TEST_ROOT/follows/flakeA/flakeB +flakeFollowsC=$TEST_ROOT/follows/flakeA/flakeB/flakeC +flakeFollowsD=$TEST_ROOT/follows/flakeA/flakeD +flakeFollowsE=$TEST_ROOT/follows/flakeA/flakeE + +for repo in $flake1Dir $flake2Dir $flake3Dir $flake7Dir $templatesDir $nonFlakeDir $flakeA $flakeB $flakeFollowsA; do + rm -rf $repo $repo.tmp + mkdir -p $repo + git -C $repo init + git -C $repo config user.email "foobar@example.com" + git -C $repo config user.name "Foobar" +done + +cat > $flake1Dir/flake.nix <<EOF +{ + description = "Bla bla"; + + outputs = inputs: rec { + packages.$system.foo = import ./simple.nix; + defaultPackage.$system = packages.$system.foo; + + # To test "nix flake init". + legacyPackages.x86_64-linux.hello = import ./simple.nix; + }; +} +EOF + +cp ./simple.nix ./simple.builder.sh ./config.nix $flake1Dir/ +git -C $flake1Dir add flake.nix simple.nix simple.builder.sh config.nix +git -C $flake1Dir commit -m 'Initial' + +cat > $flake2Dir/flake.nix <<EOF +{ + description = "Fnord"; + + outputs = { self, flake1 }: rec { + packages.$system.bar = flake1.packages.$system.foo; + }; +} +EOF + +git -C $flake2Dir add flake.nix +git -C $flake2Dir commit -m 'Initial' + +cat > $flake3Dir/flake.nix <<EOF +{ + description = "Fnord"; + + outputs = { self, flake2 }: rec { + packages.$system.xyzzy = flake2.packages.$system.bar; + + checks = { + xyzzy = packages.$system.xyzzy; + }; + }; +} +EOF + +git -C $flake3Dir add flake.nix +git -C $flake3Dir commit -m 'Initial' + +cat > $nonFlakeDir/README.md <<EOF +FNORD +EOF + +git -C $nonFlakeDir add README.md +git -C $nonFlakeDir commit -m 'Initial' + +# Construct a custom registry, additionally test the --registry flag +nix registry add --registry $registry flake1 git+file://$flake1Dir +nix registry add --registry $registry flake2 git+file://$flake2Dir +nix registry add --registry $registry flake3 git+file://$flake3Dir +nix registry add --registry $registry flake4 flake3 +nix registry add --registry $registry flake5 hg+file://$flake5Dir +nix registry add --registry $registry nixpkgs flake1 +nix registry add --registry $registry templates git+file://$templatesDir + +# Test 'nix flake list'. +[[ $(nix registry list | wc -l) == 7 ]] + +# Test 'nix flake metadata'. +nix flake metadata flake1 +nix flake metadata flake1 | grep -q 'Locked URL:.*flake1.*' + +# Test 'nix flake metadata' on a local flake. +(cd $flake1Dir && nix flake metadata) | grep -q 'URL:.*flake1.*' +(cd $flake1Dir && nix flake metadata .) | grep -q 'URL:.*flake1.*' +nix flake metadata $flake1Dir | grep -q 'URL:.*flake1.*' + +# Test 'nix flake metadata --json'. +json=$(nix flake metadata flake1 --json | jq .) +[[ $(echo "$json" | jq -r .description) = 'Bla bla' ]] +[[ -d $(echo "$json" | jq -r .path) ]] +[[ $(echo "$json" | jq -r .lastModified) = $(git -C $flake1Dir log -n1 --format=%ct) ]] +hash1=$(echo "$json" | jq -r .revision) + +echo -n '# foo' >> $flake1Dir/flake.nix +git -C $flake1Dir commit -a -m 'Foo' +hash2=$(nix flake metadata flake1 --json --refresh | jq -r .revision) +[[ $hash1 != $hash2 ]] + +# Test 'nix build' on a flake. +nix build -o $TEST_ROOT/result flake1#foo +[[ -e $TEST_ROOT/result/hello ]] + +# Test defaultPackage. +nix build -o $TEST_ROOT/result flake1 +[[ -e $TEST_ROOT/result/hello ]] + +nix build -o $TEST_ROOT/result $flake1Dir +nix build -o $TEST_ROOT/result git+file://$flake1Dir + +# Check that store symlinks inside a flake are not interpreted as flakes. +nix build -o $flake1Dir/result git+file://$flake1Dir +nix path-info $flake1Dir/result + +# 'getFlake' on a mutable flakeref should fail in pure mode, but succeed in impure mode. +(! nix build -o $TEST_ROOT/result --expr "(builtins.getFlake \"$flake1Dir\").defaultPackage.$system") +nix build -o $TEST_ROOT/result --expr "(builtins.getFlake \"$flake1Dir\").defaultPackage.$system" --impure + +# 'getFlake' on an immutable flakeref should succeed even in pure mode. +nix build -o $TEST_ROOT/result --expr "(builtins.getFlake \"git+file://$flake1Dir?rev=$hash2\").defaultPackage.$system" + +# Building a flake with an unlocked dependency should fail in pure mode. +(! nix build -o $TEST_ROOT/result flake2#bar --no-registries) +(! nix build -o $TEST_ROOT/result flake2#bar --no-use-registries) +(! nix eval --expr "builtins.getFlake \"$flake2Dir\"") + +# But should succeed in impure mode. +(! nix build -o $TEST_ROOT/result flake2#bar --impure) +nix build -o $TEST_ROOT/result flake2#bar --impure --no-write-lock-file + +# Building a local flake with an unlocked dependency should fail with --no-update-lock-file. +nix build -o $TEST_ROOT/result $flake2Dir#bar --no-update-lock-file 2>&1 | grep 'requires lock file changes' + +# But it should succeed without that flag. +nix build -o $TEST_ROOT/result $flake2Dir#bar --no-write-lock-file +nix build -o $TEST_ROOT/result $flake2Dir#bar --no-update-lock-file 2>&1 | grep 'requires lock file changes' +nix build -o $TEST_ROOT/result $flake2Dir#bar --commit-lock-file +[[ -e $flake2Dir/flake.lock ]] +[[ -z $(git -C $flake2Dir diff master) ]] + +# Rerunning the build should not change the lockfile. +nix build -o $TEST_ROOT/result $flake2Dir#bar +[[ -z $(git -C $flake2Dir diff master) ]] + +# Building with a lockfile should not require a fetch of the registry. +nix build -o $TEST_ROOT/result --flake-registry file:///no-registry.json $flake2Dir#bar --refresh +nix build -o $TEST_ROOT/result --no-registries $flake2Dir#bar --refresh +nix build -o $TEST_ROOT/result --no-use-registries $flake2Dir#bar --refresh + +# Updating the flake should not change the lockfile. +nix flake lock $flake2Dir +[[ -z $(git -C $flake2Dir diff master) ]] + +# Now we should be able to build the flake in pure mode. +nix build -o $TEST_ROOT/result flake2#bar + +# Or without a registry. +nix build -o $TEST_ROOT/result --no-registries git+file://$flake2Dir#bar --refresh +nix build -o $TEST_ROOT/result --no-use-registries git+file://$flake2Dir#bar --refresh + +# Test whether indirect dependencies work. +nix build -o $TEST_ROOT/result $flake3Dir#xyzzy +git -C $flake3Dir add flake.lock + +# Add dependency to flake3. +rm $flake3Dir/flake.nix + +cat > $flake3Dir/flake.nix <<EOF +{ + description = "Fnord"; + + outputs = { self, flake1, flake2 }: rec { + packages.$system.xyzzy = flake2.packages.$system.bar; + packages.$system."sth sth" = flake1.packages.$system.foo; + }; +} +EOF + +git -C $flake3Dir add flake.nix +git -C $flake3Dir commit -m 'Update flake.nix' + +# Check whether `nix build` works with an incomplete lockfile +nix build -o $TEST_ROOT/result $flake3Dir#"sth sth" +nix build -o $TEST_ROOT/result $flake3Dir#"sth%20sth" + +# Check whether it saved the lockfile +(! [[ -z $(git -C $flake3Dir diff master) ]]) + +git -C $flake3Dir add flake.lock + +git -C $flake3Dir commit -m 'Add lockfile' + +# Test whether registry caching works. +nix registry list --flake-registry file://$registry | grep -q flake3 +mv $registry $registry.tmp +nix store gc +nix registry list --flake-registry file://$registry --refresh | grep -q flake3 +mv $registry.tmp $registry + +# Test whether flakes are registered as GC roots for offline use. +# FIXME: use tarballs rather than git. +rm -rf $TEST_HOME/.cache +nix store gc # get rid of copies in the store to ensure they get fetched to our git cache +_NIX_FORCE_HTTP=1 nix build -o $TEST_ROOT/result git+file://$flake2Dir#bar +mv $flake1Dir $flake1Dir.tmp +mv $flake2Dir $flake2Dir.tmp +nix store gc +_NIX_FORCE_HTTP=1 nix build -o $TEST_ROOT/result git+file://$flake2Dir#bar +_NIX_FORCE_HTTP=1 nix build -o $TEST_ROOT/result git+file://$flake2Dir#bar --refresh +mv $flake1Dir.tmp $flake1Dir +mv $flake2Dir.tmp $flake2Dir + +# Add nonFlakeInputs to flake3. +rm $flake3Dir/flake.nix + +cat > $flake3Dir/flake.nix <<EOF +{ + inputs = { + flake1 = {}; + flake2 = {}; + nonFlake = { + url = git+file://$nonFlakeDir; + flake = false; + }; + }; + + description = "Fnord"; + + outputs = inputs: rec { + packages.$system.xyzzy = inputs.flake2.packages.$system.bar; + packages.$system.sth = inputs.flake1.packages.$system.foo; + packages.$system.fnord = + with import ./config.nix; + mkDerivation { + inherit system; + name = "fnord"; + buildCommand = '' + cat \${inputs.nonFlake}/README.md > \$out + ''; + }; + }; +} +EOF + +cp ./config.nix $flake3Dir + +git -C $flake3Dir add flake.nix config.nix +git -C $flake3Dir commit -m 'Add nonFlakeInputs' + +# Check whether `nix build` works with a lockfile which is missing a +# nonFlakeInputs. +nix build -o $TEST_ROOT/result $flake3Dir#sth --commit-lock-file + +nix build -o $TEST_ROOT/result flake3#fnord +[[ $(cat $TEST_ROOT/result) = FNORD ]] + +# Check whether flake input fetching is lazy: flake3#sth does not +# depend on flake2, so this shouldn't fail. +rm -rf $TEST_HOME/.cache +clearStore +mv $flake2Dir $flake2Dir.tmp +mv $nonFlakeDir $nonFlakeDir.tmp +nix build -o $TEST_ROOT/result flake3#sth +(! nix build -o $TEST_ROOT/result flake3#xyzzy) +(! nix build -o $TEST_ROOT/result flake3#fnord) +mv $flake2Dir.tmp $flake2Dir +mv $nonFlakeDir.tmp $nonFlakeDir +nix build -o $TEST_ROOT/result flake3#xyzzy flake3#fnord + +# Test doing multiple `lookupFlake`s +nix build -o $TEST_ROOT/result flake4#xyzzy + +# Test 'nix flake update' and --override-flake. +nix flake lock $flake3Dir +[[ -z $(git -C $flake3Dir diff master) ]] + +nix flake update $flake3Dir --override-flake flake2 nixpkgs +[[ ! -z $(git -C $flake3Dir diff master) ]] + +# Make branch "removeXyzzy" where flake3 doesn't have xyzzy anymore +git -C $flake3Dir checkout -b removeXyzzy +rm $flake3Dir/flake.nix + +cat > $flake3Dir/flake.nix <<EOF +{ + inputs = { + nonFlake = { + url = "$nonFlakeDir"; + flake = false; + }; + }; + + description = "Fnord"; + + outputs = { self, flake1, flake2, nonFlake }: rec { + packages.$system.sth = flake1.packages.$system.foo; + packages.$system.fnord = + with import ./config.nix; + mkDerivation { + inherit system; + name = "fnord"; + buildCommand = '' + cat \${nonFlake}/README.md > \$out + ''; + }; + }; +} +EOF +nix flake lock $flake3Dir +git -C $flake3Dir add flake.nix flake.lock +git -C $flake3Dir commit -m 'Remove packages.xyzzy' +git -C $flake3Dir checkout master + +# Test whether fuzzy-matching works for registry entries. +(! nix build -o $TEST_ROOT/result flake4/removeXyzzy#xyzzy) +nix build -o $TEST_ROOT/result flake4/removeXyzzy#sth + +# Testing the nix CLI +nix registry add flake1 flake3 +[[ $(nix registry list | wc -l) == 8 ]] +nix registry pin flake1 +[[ $(nix registry list | wc -l) == 8 ]] +nix registry pin flake1 flake3 +[[ $(nix registry list | wc -l) == 8 ]] +nix registry remove flake1 +[[ $(nix registry list | wc -l) == 7 ]] + +# Test 'nix flake init'. +cat > $templatesDir/flake.nix <<EOF +{ + description = "Some templates"; + + outputs = { self }: { + templates = { + trivial = { + path = ./trivial; + description = "A trivial flake"; + }; + }; + defaultTemplate = self.templates.trivial; + }; +} +EOF + +mkdir $templatesDir/trivial + +cat > $templatesDir/trivial/flake.nix <<EOF +{ + description = "A flake for building Hello World"; + + outputs = { self, nixpkgs }: { + packages.x86_64-linux.hello = nixpkgs.legacyPackages.x86_64-linux.hello; + defaultPackage.x86_64-linux = self.packages.x86_64-linux.hello; + }; +} +EOF + +git -C $templatesDir add flake.nix trivial/flake.nix +git -C $templatesDir commit -m 'Initial' + +nix flake check templates +nix flake show templates +nix flake show templates --json | jq + +(cd $flake7Dir && nix flake init) +(cd $flake7Dir && nix flake init) # check idempotence +git -C $flake7Dir add flake.nix +nix flake check $flake7Dir +nix flake show $flake7Dir +nix flake show $flake7Dir --json | jq +git -C $flake7Dir commit -a -m 'Initial' + +# Test 'nix flake new'. +rm -rf $flake6Dir +nix flake new -t templates#trivial $flake6Dir +nix flake new -t templates#trivial $flake6Dir # check idempotence +nix flake check $flake6Dir + +# Test 'nix flake clone'. +rm -rf $TEST_ROOT/flake1-v2 +nix flake clone flake1 --dest $TEST_ROOT/flake1-v2 +[ -e $TEST_ROOT/flake1-v2/flake.nix ] + +# More 'nix flake check' tests. +cat > $flake3Dir/flake.nix <<EOF +{ + outputs = { flake1, self }: { + overlay = final: prev: { + }; + }; +} +EOF + +nix flake check $flake3Dir + +cat > $flake3Dir/flake.nix <<EOF +{ + outputs = { flake1, self }: { + overlay = finalll: prev: { + }; + }; +} +EOF + +(! nix flake check $flake3Dir) + +cat > $flake3Dir/flake.nix <<EOF +{ + outputs = { flake1, self }: { + nixosModules.foo = { + a.b.c = 123; + foo = true; + }; + }; +} +EOF + +nix flake check $flake3Dir + +cat > $flake3Dir/flake.nix <<EOF +{ + outputs = { flake1, self }: { + nixosModules.foo = { + a.b.c = 123; + foo = assert false; true; + }; + }; +} +EOF + +(! nix flake check $flake3Dir) + +cat > $flake3Dir/flake.nix <<EOF +{ + outputs = { flake1, self }: { + nixosModule = { config, pkgs, ... }: { + a.b.c = 123; + }; + }; +} +EOF + +nix flake check $flake3Dir + +cat > $flake3Dir/flake.nix <<EOF +{ + outputs = { flake1, self }: { + nixosModule = { config, pkgs }: { + a.b.c = 123; + }; + }; +} +EOF + +(! nix flake check $flake3Dir) + +cat > $flake3Dir/flake.nix <<EOF +{ + outputs = { flake1, self }: { + defaultPackage = { + system-1 = "foo"; + system-2 = "bar"; + }; + }; +} +EOF + +checkRes=$(nix flake check --keep-going $flake3Dir 2>&1 && fail "nix flake check should have failed" || true) +echo "$checkRes" | grep -q "defaultPackage.system-1" +echo "$checkRes" | grep -q "defaultPackage.system-2" + +# Test 'follows' inputs. +cat > $flake3Dir/flake.nix <<EOF +{ + inputs.foo = { + type = "indirect"; + id = "flake1"; + }; + inputs.bar.follows = "foo"; + + outputs = { self, foo, bar }: { + }; +} +EOF + +nix flake lock $flake3Dir +[[ $(jq -c .nodes.root.inputs.bar $flake3Dir/flake.lock) = '["foo"]' ]] + +cat > $flake3Dir/flake.nix <<EOF +{ + inputs.bar.follows = "flake2/flake1"; + + outputs = { self, flake2, bar }: { + }; +} +EOF + +nix flake lock $flake3Dir +[[ $(jq -c .nodes.root.inputs.bar $flake3Dir/flake.lock) = '["flake2","flake1"]' ]] + +cat > $flake3Dir/flake.nix <<EOF +{ + inputs.bar.follows = "flake2"; + + outputs = { self, flake2, bar }: { + }; +} +EOF + +nix flake lock $flake3Dir +[[ $(jq -c .nodes.root.inputs.bar $flake3Dir/flake.lock) = '["flake2"]' ]] + +# Test overriding inputs of inputs. +cat > $flake3Dir/flake.nix <<EOF +{ + inputs.flake2.inputs.flake1 = { + type = "git"; + url = file://$flake7Dir; + }; + + outputs = { self, flake2 }: { + }; +} +EOF + +nix flake lock $flake3Dir +[[ $(jq .nodes.flake1.locked.url $flake3Dir/flake.lock) =~ flake7 ]] + +cat > $flake3Dir/flake.nix <<EOF +{ + inputs.flake2.inputs.flake1.follows = "foo"; + inputs.foo.url = git+file://$flake7Dir; + + outputs = { self, flake2 }: { + }; +} +EOF + +nix flake update $flake3Dir +[[ $(jq -c .nodes.flake2.inputs.flake1 $flake3Dir/flake.lock) =~ '["foo"]' ]] +[[ $(jq .nodes.foo.locked.url $flake3Dir/flake.lock) =~ flake7 ]] + +# Test git+file with bare repo. +rm -rf $flakeGitBare +git clone --bare $flake1Dir $flakeGitBare +nix build -o $TEST_ROOT/result git+file://$flakeGitBare + +# Test Mercurial flakes. +rm -rf $flake5Dir +hg init $flake5Dir + +cat > $flake5Dir/flake.nix <<EOF +{ + outputs = { self, flake1 }: { + defaultPackage.$system = flake1.defaultPackage.$system; + + expr = assert builtins.pathExists ./flake.lock; 123; + }; +} +EOF + +hg add $flake5Dir/flake.nix +hg commit --config ui.username=foobar@example.org $flake5Dir -m 'Initial commit' + +nix build -o $TEST_ROOT/result hg+file://$flake5Dir +[[ -e $TEST_ROOT/result/hello ]] + +(! nix flake metadata --json hg+file://$flake5Dir | jq -e -r .revision) + +nix eval hg+file://$flake5Dir#expr + +nix eval hg+file://$flake5Dir#expr + +(! nix eval hg+file://$flake5Dir#expr --no-allow-dirty) + +(! nix flake metadata --json hg+file://$flake5Dir | jq -e -r .revision) + +hg commit --config ui.username=foobar@example.org $flake5Dir -m 'Add lock file' + +nix flake metadata --json hg+file://$flake5Dir --refresh | jq -e -r .revision +nix flake metadata --json hg+file://$flake5Dir +[[ $(nix flake metadata --json hg+file://$flake5Dir | jq -e -r .revCount) = 1 ]] + +nix build -o $TEST_ROOT/result hg+file://$flake5Dir --no-registries --no-allow-dirty +nix build -o $TEST_ROOT/result hg+file://$flake5Dir --no-use-registries --no-allow-dirty + +# Test tarball flakes +tar cfz $TEST_ROOT/flake.tar.gz -C $TEST_ROOT --exclude .hg flake5 + +nix build -o $TEST_ROOT/result file://$TEST_ROOT/flake.tar.gz + +# Building with a tarball URL containing a SRI hash should also work. +url=$(nix flake metadata --json file://$TEST_ROOT/flake.tar.gz | jq -r .url) +[[ $url =~ sha256- ]] + +nix build -o $TEST_ROOT/result $url + +# Building with an incorrect SRI hash should fail. +nix build -o $TEST_ROOT/result "file://$TEST_ROOT/flake.tar.gz?narHash=sha256-qQ2Zz4DNHViCUrp6gTS7EE4+RMqFQtUfWF2UNUtJKS0=" 2>&1 | grep 'NAR hash mismatch' + +# Test --override-input. +git -C $flake3Dir reset --hard +nix flake lock $flake3Dir --override-input flake2/flake1 flake5 -vvvvv +[[ $(jq .nodes.flake1_2.locked.url $flake3Dir/flake.lock) =~ flake5 ]] + +nix flake lock $flake3Dir --override-input flake2/flake1 flake1 +[[ $(jq -r .nodes.flake1_2.locked.rev $flake3Dir/flake.lock) =~ $hash2 ]] + +nix flake lock $flake3Dir --override-input flake2/flake1 flake1/master/$hash1 +[[ $(jq -r .nodes.flake1_2.locked.rev $flake3Dir/flake.lock) =~ $hash1 ]] + +# Test --update-input. +nix flake lock $flake3Dir +[[ $(jq -r .nodes.flake1_2.locked.rev $flake3Dir/flake.lock) = $hash1 ]] + +nix flake lock $flake3Dir --update-input flake2/flake1 +[[ $(jq -r .nodes.flake1_2.locked.rev $flake3Dir/flake.lock) =~ $hash2 ]] + +# Test 'nix flake metadata --json'. +nix flake metadata $flake3Dir --json | jq . + +# Test circular flake dependencies. +cat > $flakeA/flake.nix <<EOF +{ + inputs.b.url = git+file://$flakeB; + inputs.b.inputs.a.follows = "/"; + + outputs = { self, nixpkgs, b }: { + foo = 123 + b.bar; + xyzzy = 1000; + }; +} +EOF + +git -C $flakeA add flake.nix + +cat > $flakeB/flake.nix <<EOF +{ + inputs.a.url = git+file://$flakeA; + + outputs = { self, nixpkgs, a }: { + bar = 456 + a.xyzzy; + }; +} +EOF + +git -C $flakeB add flake.nix +git -C $flakeB commit -a -m 'Foo' + +[[ $(nix eval $flakeA#foo) = 1579 ]] +[[ $(nix eval $flakeA#foo) = 1579 ]] + +sed -i $flakeB/flake.nix -e 's/456/789/' +git -C $flakeB commit -a -m 'Foo' + +[[ $(nix eval --update-input b $flakeA#foo) = 1912 ]] + +# Test list-inputs with circular dependencies +nix flake metadata $flakeA + +# Test flake follow paths +mkdir -p $flakeFollowsB +mkdir -p $flakeFollowsC +mkdir -p $flakeFollowsD +mkdir -p $flakeFollowsE + +cat > $flakeFollowsA/flake.nix <<EOF +{ + description = "Flake A"; + inputs = { + B = { + url = "path:./flakeB"; + inputs.foobar.follows = "D"; + }; + + D.url = "path:./flakeD"; + foobar.url = "path:./flakeE"; + }; + outputs = { ... }: {}; +} +EOF + +cat > $flakeFollowsB/flake.nix <<EOF +{ + description = "Flake B"; + inputs = { + foobar.url = "path:./../flakeE"; + C = { + url = "path:./flakeC"; + inputs.foobar.follows = "foobar"; + }; + }; + outputs = { ... }: {}; +} +EOF + +cat > $flakeFollowsC/flake.nix <<EOF +{ + description = "Flake C"; + inputs = { + foobar.url = "path:./../../flakeE"; + }; + outputs = { ... }: {}; +} +EOF + +cat > $flakeFollowsD/flake.nix <<EOF +{ + description = "Flake D"; + inputs = {}; + outputs = { ... }: {}; +} +EOF + +cat > $flakeFollowsE/flake.nix <<EOF +{ + description = "Flake D"; + inputs = {}; + outputs = { ... }: {}; +} +EOF + +git -C $flakeFollowsA add flake.nix flakeB/flake.nix \ + flakeB/flakeC/flake.nix flakeD/flake.nix flakeE/flake.nix + +nix flake lock $flakeFollowsA + +[[ $(jq -c .nodes.B.inputs.C $flakeFollowsA/flake.lock) = '"C"' ]] +[[ $(jq -c .nodes.B.inputs.foobar $flakeFollowsA/flake.lock) = '["D"]' ]] +[[ $(jq -c .nodes.C.inputs.foobar $flakeFollowsA/flake.lock) = '["B","foobar"]' ]] + +# Ensure a relative path is not allowed to go outside the store path +cat > $flakeFollowsA/flake.nix <<EOF +{ + description = "Flake A"; + inputs = { + B.url = "path:./../../flakeB"; + }; + outputs = { ... }: {}; +} +EOF + +git -C $flakeFollowsA add flake.nix + +nix flake lock $flakeFollowsA 2>&1 | grep 'this is a security violation' + +# Test flake in store does not evaluate +rm -rf $badFlakeDir +mkdir $badFlakeDir +echo INVALID > $badFlakeDir/flake.nix +nix store delete $(nix store add-path $badFlakeDir) + +[[ $(nix path-info $(nix store add-path $flake1Dir)) =~ flake1 ]] +[[ $(nix path-info path:$(nix store add-path $flake1Dir)) =~ simple ]] diff --git a/tests/function-trace.sh b/tests/function-trace.sh index 182a4d5c2..3b7f364e3 100755 --- a/tests/function-trace.sh +++ b/tests/function-trace.sh @@ -32,8 +32,6 @@ expect_trace() { # failure inside a tryEval expect_trace 'builtins.tryEval (throw "example")' " -function-trace entered undefined position at -function-trace exited undefined position at function-trace entered (string):1:1 at function-trace entered (string):1:19 at function-trace exited (string):1:19 at @@ -42,32 +40,24 @@ function-trace exited (string):1:1 at # Missing argument to a formal function expect_trace '({ x }: x) { }' " -function-trace entered undefined position at -function-trace exited undefined position at function-trace entered (string):1:1 at function-trace exited (string):1:1 at " # Too many arguments to a formal function expect_trace '({ x }: x) { x = "x"; y = "y"; }' " -function-trace entered undefined position at -function-trace exited undefined position at function-trace entered (string):1:1 at function-trace exited (string):1:1 at " # Not enough arguments to a lambda expect_trace '(x: y: x + y) 1' " -function-trace entered undefined position at -function-trace exited undefined position at function-trace entered (string):1:1 at function-trace exited (string):1:1 at " # Too many arguments to a lambda expect_trace '(x: x) 1 2' " -function-trace entered undefined position at -function-trace exited undefined position at function-trace entered (string):1:1 at function-trace exited (string):1:1 at function-trace entered (string):1:1 at @@ -76,8 +66,6 @@ function-trace exited (string):1:1 at # Not a function expect_trace '1 2' " -function-trace entered undefined position at -function-trace exited undefined position at function-trace entered (string):1:1 at function-trace exited (string):1:1 at " diff --git a/tests/gc-auto.sh b/tests/gc-auto.sh index b282644ca..521d9e539 100644 --- a/tests/gc-auto.sh +++ b/tests/gc-auto.sh @@ -1,10 +1,12 @@ source common.sh +needLocalStore "“min-free” and “max-free” are daemon options" + clearStore -garbage1=$(nix add-to-store --name garbage1 ./nar-access.sh) -garbage2=$(nix add-to-store --name garbage2 ./nar-access.sh) -garbage3=$(nix add-to-store --name garbage3 ./nar-access.sh) +garbage1=$(nix store add-path --name garbage1 ./nar-access.sh) +garbage2=$(nix store add-path --name garbage2 ./nar-access.sh) +garbage3=$(nix store add-path --name garbage3 ./nar-access.sh) ls -l $garbage3 POSIXLY_CORRECT=1 du $garbage3 @@ -59,11 +61,11 @@ with import ./config.nix; mkDerivation { EOF ) -nix build -v -o $TEST_ROOT/result-A -L "($expr)" \ +nix build --impure -v -o $TEST_ROOT/result-A -L --expr "$expr" \ --min-free 1000 --max-free 2000 --min-free-check-interval 1 & pid1=$! -nix build -v -o $TEST_ROOT/result-B -L "($expr2)" \ +nix build --impure -v -o $TEST_ROOT/result-B -L --expr "$expr2" \ --min-free 1000 --max-free 2000 --min-free-check-interval 1 & pid2=$! diff --git a/tests/gc-runtime.sh b/tests/gc-runtime.sh index 4c5028005..6094959cb 100644 --- a/tests/gc-runtime.sh +++ b/tests/gc-runtime.sh @@ -4,7 +4,7 @@ case $system in *linux*) ;; *) - exit 0; + exit 99; esac set -m # enable job control, needed for kill diff --git a/tests/gc.sh b/tests/gc.sh index 8b4f8d282..cf0e2c32d 100644 --- a/tests/gc.sh +++ b/tests/gc.sh @@ -12,7 +12,7 @@ ln -sf $outPath "$NIX_STATE_DIR"/gcroots/foo nix-store --gc --print-roots | grep $outPath nix-store --gc --print-live | grep $outPath nix-store --gc --print-dead | grep $drvPath -if nix-store --gc --print-dead | grep $outPath; then false; fi +if nix-store --gc --print-dead | grep -E $outPath$; then false; fi nix-store --gc --print-dead diff --git a/tests/github-flakes.nix b/tests/github-flakes.nix new file mode 100644 index 000000000..7ac397d81 --- /dev/null +++ b/tests/github-flakes.nix @@ -0,0 +1,150 @@ +{ nixpkgs, system, overlay }: + +with import (nixpkgs + "/nixos/lib/testing-python.nix") { + inherit system; + extraConfigurations = [ { nixpkgs.overlays = [ overlay ]; } ]; +}; + +let + + # Generate a fake root CA and a fake github.com certificate. + cert = pkgs.runCommand "cert" { buildInputs = [ pkgs.openssl ]; } + '' + mkdir -p $out + + openssl genrsa -out ca.key 2048 + openssl req -new -x509 -days 36500 -key ca.key \ + -subj "/C=NL/ST=Denial/L=Springfield/O=Dis/CN=Root CA" -out $out/ca.crt + + openssl req -newkey rsa:2048 -nodes -keyout $out/server.key \ + -subj "/C=CN/ST=Denial/L=Springfield/O=Dis/CN=github.com" -out server.csr + openssl x509 -req -extfile <(printf "subjectAltName=DNS:api.github.com,DNS:github.com,DNS:raw.githubusercontent.com") \ + -days 36500 -in server.csr -CA $out/ca.crt -CAkey ca.key -CAcreateserial -out $out/server.crt + ''; + + registry = pkgs.writeTextFile { + name = "registry"; + text = '' + { + "flakes": [ + { + "from": { + "type": "indirect", + "id": "nixpkgs" + }, + "to": { + "type": "github", + "owner": "NixOS", + "repo": "nixpkgs" + } + } + ], + "version": 2 + } + ''; + destination = "/flake-registry.json"; + }; + + api = pkgs.runCommand "nixpkgs-flake" {} + '' + mkdir -p $out/tarball + + dir=NixOS-nixpkgs-${nixpkgs.shortRev} + cp -prd ${nixpkgs} $dir + # Set the correct timestamp in the tarball. + find $dir -print0 | xargs -0 touch -t ${builtins.substring 0 12 nixpkgs.lastModifiedDate}.${builtins.substring 12 2 nixpkgs.lastModifiedDate} -- + tar cfz $out/tarball/${nixpkgs.rev} $dir --hard-dereference + + mkdir -p $out/commits + echo '{"sha": "${nixpkgs.rev}"}' > $out/commits/HEAD + ''; + +in + +makeTest ( + +{ + name = "github-flakes"; + + nodes = + { # Impersonate github.com and api.github.com. + github = + { config, pkgs, ... }: + { networking.firewall.allowedTCPPorts = [ 80 443 ]; + + services.httpd.enable = true; + services.httpd.adminAddr = "foo@example.org"; + services.httpd.extraConfig = '' + ErrorLog syslog:local6 + ''; + services.httpd.virtualHosts."github.com" = + { forceSSL = true; + sslServerKey = "${cert}/server.key"; + sslServerCert = "${cert}/server.crt"; + servedDirs = + [ { urlPath = "/NixOS/flake-registry/raw/master"; + dir = registry; + } + ]; + }; + services.httpd.virtualHosts."api.github.com" = + { forceSSL = true; + sslServerKey = "${cert}/server.key"; + sslServerCert = "${cert}/server.crt"; + servedDirs = + [ { urlPath = "/repos/NixOS/nixpkgs"; + dir = api; + } + ]; + }; + }; + + client = + { config, lib, pkgs, nodes, ... }: + { virtualisation.writableStore = true; + virtualisation.diskSize = 2048; + virtualisation.pathsInNixDB = [ pkgs.hello pkgs.fuse ]; + virtualisation.memorySize = 4096; + nix.binaryCaches = lib.mkForce [ ]; + nix.extraOptions = "experimental-features = nix-command flakes"; + environment.systemPackages = [ pkgs.jq ]; + networking.hosts.${(builtins.head nodes.github.config.networking.interfaces.eth1.ipv4.addresses).address} = + [ "github.com" "api.github.com" "raw.githubusercontent.com" ]; + security.pki.certificateFiles = [ "${cert}/ca.crt" ]; + }; + }; + + testScript = { nodes }: '' + # fmt: off + import json + import time + + start_all() + + github.wait_for_unit("httpd.service") + + client.succeed("curl -v https://github.com/ >&2") + client.succeed("nix registry list | grep nixpkgs") + + rev = client.succeed("nix flake info nixpkgs --json | jq -r .revision") + assert rev.strip() == "${nixpkgs.rev}", "revision mismatch" + + client.succeed("nix registry pin nixpkgs") + + client.succeed("nix flake info nixpkgs --tarball-ttl 0 >&2") + + # Shut down the web server. The flake should be cached on the client. + github.succeed("systemctl stop httpd.service") + + info = json.loads(client.succeed("nix flake info nixpkgs --json")) + date = time.strftime("%Y%m%d%H%M%S", time.gmtime(info['lastModified'])) + assert date == "${nixpkgs.lastModifiedDate}", "time mismatch" + + client.succeed("nix build nixpkgs#hello") + + # The build shouldn't fail even with --tarball-ttl 0 (the server + # being down should not be a fatal error). + client.succeed("nix build nixpkgs#fuse --tarball-ttl 0") + ''; + +}) diff --git a/tests/hash.sh b/tests/hash.sh index 4cfc97901..e5f75e2cf 100644 --- a/tests/hash.sh +++ b/tests/hash.sh @@ -2,7 +2,7 @@ source common.sh try () { printf "%s" "$2" > $TEST_ROOT/vector - hash=$(nix hash-file --base16 $EXTRA --type "$1" $TEST_ROOT/vector) + hash=$(nix hash file --base16 $EXTRA --type "$1" $TEST_ROOT/vector) if test "$hash" != "$3"; then echo "hash $1, expected $3, got $hash" exit 1 @@ -69,17 +69,17 @@ try2 md5 "f78b733a68f5edbdf9413899339eaa4a" # Conversion. try3() { - h64=$(nix to-base64 --type "$1" "$2") + h64=$(nix hash to-base64 --type "$1" "$2") [ "$h64" = "$4" ] - sri=$(nix to-sri --type "$1" "$2") + sri=$(nix hash to-sri --type "$1" "$2") [ "$sri" = "$1-$4" ] h32=$(nix-hash --type "$1" --to-base32 "$2") [ "$h32" = "$3" ] h16=$(nix-hash --type "$1" --to-base16 "$h32") [ "$h16" = "$2" ] - h16=$(nix to-base16 --type "$1" "$h64") + h16=$(nix hash to-base16 --type "$1" "$h64") [ "$h16" = "$2" ] - h16=$(nix to-base16 "$sri") + h16=$(nix hash to-base16 "$sri") [ "$h16" = "$2" ] } try3 sha1 "800d59cfcd3c05e900cb4e214be48f6b886a08df" "vw46m23bizj4n8afrc0fj19wrp7mj3c0" "gA1Zz808BekAy04hS+SPa4hqCN8=" diff --git a/tests/init.sh b/tests/init.sh index 0c2c0e170..3c6d5917d 100644 --- a/tests/init.sh +++ b/tests/init.sh @@ -19,7 +19,11 @@ keep-derivations = false sandbox = false experimental-features = nix-command flakes gc-reserved-space = 0 +substituters = +flake-registry = $TEST_ROOT/registry.json +show-trace = true include nix.conf.extra +trusted-users = $(whoami) EOF cat > "$NIX_CONF_DIR"/nix.conf.extra <<EOF @@ -32,5 +36,3 @@ nix-store --init # Did anything happen? test -e "$NIX_STATE_DIR"/db/db.sqlite - -echo 'Hello World' > ./dummy diff --git a/tests/install-darwin.sh b/tests/install-darwin.sh index 9933eba94..7e44e54c4 100755 --- a/tests/install-darwin.sh +++ b/tests/install-darwin.sh @@ -53,7 +53,7 @@ trap finish EXIT # First setup Nix cleanup -curl -o install https://nixos.org/nix/install +curl -L -o install https://nixos.org/nix/install yes | bash ./install verify diff --git a/tests/lang.sh b/tests/lang.sh index c797a2a74..61bb444ba 100644 --- a/tests/lang.sh +++ b/tests/lang.sh @@ -1,6 +1,7 @@ source common.sh export TEST_VAR=foo # for eval-okay-getenv.nix +export NIX_REMOTE=dummy:// nix-instantiate --eval -E 'builtins.trace "Hello" 123' 2>&1 | grep -q Hello (! nix-instantiate --show-trace --eval -E 'builtins.addErrorContext "Hello" 123' 2>&1 | grep -q Hello) diff --git a/tests/lang/eval-fail-antiquoted-path.nix b/tests/lang/eval-fail-nonexist-path.nix index f2f08107b..f2f08107b 100644 --- a/tests/lang/eval-fail-antiquoted-path.nix +++ b/tests/lang/eval-fail-nonexist-path.nix diff --git a/tests/lang/eval-okay-floor-ceil.exp b/tests/lang/eval-okay-floor-ceil.exp new file mode 100644 index 000000000..81f80420b --- /dev/null +++ b/tests/lang/eval-okay-floor-ceil.exp @@ -0,0 +1 @@ +"23;24;23;23" diff --git a/tests/lang/eval-okay-floor-ceil.nix b/tests/lang/eval-okay-floor-ceil.nix new file mode 100644 index 000000000..d76a0d86e --- /dev/null +++ b/tests/lang/eval-okay-floor-ceil.nix @@ -0,0 +1,9 @@ +with import ./lib.nix; + +let + n1 = builtins.floor 23.5; + n2 = builtins.ceil 23.5; + n3 = builtins.floor 23; + n4 = builtins.ceil 23; +in + builtins.concatStringsSep ";" (map toString [ n1 n2 n3 n4 ]) diff --git a/tests/lang/eval-okay-ind-string.exp b/tests/lang/eval-okay-ind-string.exp index 9cf4bd2ee..7862331fa 100644 --- a/tests/lang/eval-okay-ind-string.exp +++ b/tests/lang/eval-okay-ind-string.exp @@ -1 +1 @@ -"This is an indented multi-line string\nliteral. An amount of whitespace at\nthe start of each line matching the minimum\nindentation of all lines in the string\nliteral together will be removed. Thus,\nin this case four spaces will be\nstripped from each line, even though\n THIS LINE is indented six spaces.\n\nAlso, empty lines don't count in the\ndetermination of the indentation level (the\nprevious empty line has indentation 0, but\nit doesn't matter).\nIf the string starts with whitespace\n followed by a newline, it's stripped, but\n that's not the case here. Two spaces are\n stripped because of the \" \" at the start. \nThis line is indented\na bit further.\nAnti-quotations, like so, are\nalso allowed.\n The \\ is not special here.\n' can be followed by any character except another ', e.g. 'x'.\nLikewise for $, e.g. $$ or $varName.\nBut ' followed by ' is special, as is $ followed by {.\nIf you want them, use anti-quotations: '', ${.\n Tabs are not interpreted as whitespace (since we can't guess\n what tab settings are intended), so don't use them.\n\tThis line starts with a space and a tab, so only one\n space will be stripped from each line.\nAlso note that if the last line (just before the closing ' ')\nconsists only of whitespace, it's ignored. But here there is\nsome non-whitespace stuff, so the line isn't removed. \nThis shows a hacky way to preserve an empty line after the start.\nBut there's no reason to do so: you could just repeat the empty\nline.\n Similarly you can force an indentation level,\n in this case to 2 spaces. This works because the anti-quote\n is significant (not whitespace).\nstart on network-interfaces\n\nstart script\n\n rm -f /var/run/opengl-driver\n ln -sf 123 /var/run/opengl-driver\n\n rm -f /var/log/slim.log\n \nend script\n\nenv SLIM_CFGFILE=abc\nenv SLIM_THEMESDIR=def\nenv FONTCONFIG_FILE=/etc/fonts/fonts.conf \t\t\t\t# !!! cleanup\nenv XKB_BINDIR=foo/bin \t\t\t\t# Needed for the Xkb extension.\nenv LD_LIBRARY_PATH=libX11/lib:libXext/lib:/usr/lib/ # related to xorg-sys-opengl - needed to load libglx for (AI)GLX support (for compiz)\n\nenv XORG_DRI_DRIVER_PATH=nvidiaDrivers/X11R6/lib/modules/drivers/ \n\nexec slim/bin/slim\nEscaping of ' followed by ': ''\nEscaping of $ followed by {: ${\nAnd finally to interpret \\n etc. as in a string: \n, \r, \t.\nfoo\n'bla'\nbar\ncut -d $'\\t' -f 1\nending dollar $$\n" +"This is an indented multi-line string\nliteral. An amount of whitespace at\nthe start of each line matching the minimum\nindentation of all lines in the string\nliteral together will be removed. Thus,\nin this case four spaces will be\nstripped from each line, even though\n THIS LINE is indented six spaces.\n\nAlso, empty lines don't count in the\ndetermination of the indentation level (the\nprevious empty line has indentation 0, but\nit doesn't matter).\nIf the string starts with whitespace\n followed by a newline, it's stripped, but\n that's not the case here. Two spaces are\n stripped because of the \" \" at the start. \nThis line is indented\na bit further.\nAnti-quotations, like so, are\nalso allowed.\n The \\ is not special here.\n' can be followed by any character except another ', e.g. 'x'.\nLikewise for $, e.g. $$ or $varName.\nBut ' followed by ' is special, as is $ followed by {.\nIf you want them, use anti-quotations: '', \${.\n Tabs are not interpreted as whitespace (since we can't guess\n what tab settings are intended), so don't use them.\n\tThis line starts with a space and a tab, so only one\n space will be stripped from each line.\nAlso note that if the last line (just before the closing ' ')\nconsists only of whitespace, it's ignored. But here there is\nsome non-whitespace stuff, so the line isn't removed. \nThis shows a hacky way to preserve an empty line after the start.\nBut there's no reason to do so: you could just repeat the empty\nline.\n Similarly you can force an indentation level,\n in this case to 2 spaces. This works because the anti-quote\n is significant (not whitespace).\nstart on network-interfaces\n\nstart script\n\n rm -f /var/run/opengl-driver\n ln -sf 123 /var/run/opengl-driver\n\n rm -f /var/log/slim.log\n \nend script\n\nenv SLIM_CFGFILE=abc\nenv SLIM_THEMESDIR=def\nenv FONTCONFIG_FILE=/etc/fonts/fonts.conf \t\t\t\t# !!! cleanup\nenv XKB_BINDIR=foo/bin \t\t\t\t# Needed for the Xkb extension.\nenv LD_LIBRARY_PATH=libX11/lib:libXext/lib:/usr/lib/ # related to xorg-sys-opengl - needed to load libglx for (AI)GLX support (for compiz)\n\nenv XORG_DRI_DRIVER_PATH=nvidiaDrivers/X11R6/lib/modules/drivers/ \n\nexec slim/bin/slim\nEscaping of ' followed by ': ''\nEscaping of $ followed by {: \${\nAnd finally to interpret \\n etc. as in a string: \n, \r, \t.\nfoo\n'bla'\nbar\ncut -d $'\\t' -f 1\nending dollar $$\n" diff --git a/tests/lang/eval-okay-path-antiquotation.nix b/tests/lang/eval-okay-path-antiquotation.nix new file mode 100644 index 000000000..497d7c1c7 --- /dev/null +++ b/tests/lang/eval-okay-path-antiquotation.nix @@ -0,0 +1,12 @@ +let + foo = "foo"; +in +{ + simple = ./${foo}; + surrounded = ./a-${foo}-b; + absolute = /${foo}; + expr = ./${foo + "/bar"}; + home = ~/${foo}; + notfirst = ./bar/${foo}; + slashes = /${foo}/${"bar"}; +} diff --git a/tests/lang/eval-okay-search-path.nix b/tests/lang/eval-okay-search-path.nix index c5a123d04..6fe33decc 100644 --- a/tests/lang/eval-okay-search-path.nix +++ b/tests/lang/eval-okay-search-path.nix @@ -1,10 +1,9 @@ with import ./lib.nix; with builtins; -assert pathExists <nix/fetchurl.nix>; +assert isFunction (import <nix/fetchurl.nix>); -assert length __nixPath == 6; -assert length (filter (x: x.prefix == "nix") __nixPath) == 1; +assert length __nixPath == 5; assert length (filter (x: baseNameOf x.path == "dir4") __nixPath) == 1; import <a.nix> + import <b.nix> + import <c.nix> + import <dir5/c.nix> diff --git a/tests/lang/parse-okay-url.nix b/tests/lang/parse-okay-url.nix index fce3b13ee..08de27d0a 100644 --- a/tests/lang/parse-okay-url.nix +++ b/tests/lang/parse-okay-url.nix @@ -3,5 +3,6 @@ http://www2.mplayerhq.hu/MPlayer/releases/fonts/font-arial-iso-8859-1.tar.bz2 http://losser.st-lab.cs.uu.nl/~armijn/.nix/gcc-3.3.4-static-nix.tar.gz http://fpdownload.macromedia.com/get/shockwave/flash/english/linux/7.0r25/install_flash_player_7_linux.tar.gz + https://ftp5.gwdg.de/pub/linux/archlinux/extra/os/x86_64/unzip-6.0-14-x86_64.pkg.tar.zst ftp://ftp.gtk.org/pub/gtk/v1.2/gtk+-1.2.10.tar.gz ] diff --git a/tests/linux-sandbox.sh b/tests/linux-sandbox.sh index 16abd974c..3f304ac2f 100644 --- a/tests/linux-sandbox.sh +++ b/tests/linux-sandbox.sh @@ -1,14 +1,16 @@ source common.sh +needLocalStore "the sandbox only runs on the builder side, so it makes no sense to test it with the daemon" + clearStore -if ! canUseSandbox; then exit; fi +if ! canUseSandbox; then exit 99; fi # Note: we need to bind-mount $SHELL into the chroot. Currently we # only support the case where $SHELL is in the Nix store, because # otherwise things get complicated (e.g. if it's in /bin, do we need # /lib as well?). -if [[ ! $SHELL =~ /nix/store ]]; then exit; fi +if [[ ! $SHELL =~ /nix/store ]]; then exit 99; fi chmod -R u+w $TEST_ROOT/store0 || true rm -rf $TEST_ROOT/store0 @@ -22,9 +24,9 @@ outPath=$(nix-build dependencies.nix --no-out-link --sandbox-paths /nix/store) nix path-info -r $outPath | grep input-2 -nix ls-store -R -l $outPath | grep foobar +nix store ls -R -l $outPath | grep foobar -nix cat-store $outPath/foobar | grep FOOBAR +nix store cat $outPath/foobar | grep FOOBAR # Test --check without hash rewriting. nix-build dependencies.nix --no-out-link --check --sandbox-paths /nix/store diff --git a/tests/local-store.sh b/tests/local-store.sh new file mode 100644 index 000000000..4ec3d64b0 --- /dev/null +++ b/tests/local-store.sh @@ -0,0 +1,20 @@ +source common.sh + +cd $TEST_ROOT + +echo example > example.txt +mkdir -p ./x + +NIX_STORE_DIR=$TEST_ROOT/x + +CORRECT_PATH=$(nix-store --store ./x --add example.txt) + +PATH1=$(nix path-info --store ./x $CORRECT_PATH) +[ $CORRECT_PATH == $PATH1 ] + +PATH2=$(nix path-info --store "$PWD/x" $CORRECT_PATH) +[ $CORRECT_PATH == $PATH2 ] + +# FIXME we could also test the query parameter version: +# PATH3=$(nix path-info --store "local?store=$PWD/x" $CORRECT_PATH) +# [ $CORRECT_PATH == $PATH3 ] diff --git a/tests/local.mk b/tests/local.mk index f3ac330d8..b100e7f15 100644 --- a/tests/local.mk +++ b/tests/local.mk @@ -1,20 +1,28 @@ nix_tests = \ - init.sh hash.sh lang.sh add.sh simple.sh dependencies.sh \ + hash.sh lang.sh add.sh simple.sh dependencies.sh \ config.sh \ gc.sh \ + ca/gc.sh \ gc-concurrent.sh \ gc-auto.sh \ referrers.sh user-envs.sh logging.sh nix-build.sh misc.sh fixed.sh \ gc-runtime.sh check-refs.sh filter-source.sh \ - remote-store.sh export.sh export-graph.sh \ + local-store.sh remote-store.sh export.sh export-graph.sh \ + db-migration.sh \ timeout.sh secure-drv-outputs.sh nix-channel.sh \ multiple-outputs.sh import-derivation.sh fetchurl.sh optimise-store.sh \ - binary-cache.sh nix-profile.sh repair.sh dump-db.sh case-hack.sh \ + binary-cache.sh \ + substitute-with-invalid-ca.sh \ + binary-cache-build-remote.sh \ + nix-profile.sh repair.sh dump-db.sh case-hack.sh \ check-reqs.sh pass-as-file.sh tarball.sh restricted.sh \ placeholders.sh nix-shell.sh \ linux-sandbox.sh \ build-dry.sh \ - build-remote.sh \ + build-remote-input-addressed.sh \ + build-remote-content-addressed-fixed.sh \ + build-remote-content-addressed-floating.sh \ + ssh-relay.sh \ nar-access.sh \ structured-attrs.sh \ fetchGit.sh \ @@ -24,20 +32,38 @@ nix_tests = \ signing.sh \ shell.sh \ brotli.sh \ + zstd.sh \ pure-eval.sh \ check.sh \ plugins.sh \ search.sh \ nix-copy-ssh.sh \ post-hook.sh \ + ca/post-hook.sh \ function-trace.sh \ - recursive.sh + recursive.sh \ + describe-stores.sh \ + flakes.sh \ + build.sh \ + compute-levels.sh \ + repl.sh \ + ca/build.sh \ + ca/build-with-garbage-path.sh \ + ca/duplicate-realisation-in-closure.sh \ + ca/substitute.sh \ + ca/signatures.sh \ + ca/nix-shell.sh \ + ca/nix-run.sh \ + ca/recursive.sh \ + ca/concurrent-builds.sh \ + ca/nix-copy.sh \ + eval-store.sh # parallel.sh install-tests += $(foreach x, $(nix_tests), tests/$(x)) tests-environment = NIX_REMOTE= $(bash) -e -clean-files += $(d)/common.sh +clean-files += $(d)/common.sh $(d)/config.nix $(d)/ca/config.nix -test-deps += tests/common.sh tests/config.nix tests/plugins/libplugintest.$(SO_EXT) +test-deps += tests/common.sh tests/config.nix tests/ca/config.nix tests/plugins/libplugintest.$(SO_EXT) diff --git a/tests/misc.sh b/tests/misc.sh index a81c9dbb1..2830856ae 100644 --- a/tests/misc.sh +++ b/tests/misc.sh @@ -17,10 +17,10 @@ nix-env -q --foo 2>&1 | grep "unknown flag" # Eval Errors. eval_arg_res=$(nix-instantiate --eval -E 'let a = {} // a; in a.foo' 2>&1 || true) -echo $eval_arg_res | grep "at: (1:15) from string" +echo $eval_arg_res | grep "at «string»:1:15:" echo $eval_arg_res | grep "infinite recursion encountered" eval_stdin_res=$(echo 'let a = {} // a; in a.foo' | nix-instantiate --eval -E - 2>&1 || true) -echo $eval_stdin_res | grep "at: (1:15) from stdin" +echo $eval_stdin_res | grep "at «stdin»:1:15:" echo $eval_stdin_res | grep "infinite recursion encountered" diff --git a/tests/multiple-outputs.nix b/tests/multiple-outputs.nix index 4a9010d18..b915493f7 100644 --- a/tests/multiple-outputs.nix +++ b/tests/multiple-outputs.nix @@ -2,6 +2,21 @@ with import ./config.nix; rec { + # Want to ensure that "out" doesn't get a suffix on it's path. + nameCheck = mkDerivation { + name = "multiple-outputs-a"; + outputs = [ "out" "dev" ]; + builder = builtins.toFile "builder.sh" + '' + mkdir $first $second + test -z $all + echo "first" > $first/file + echo "second" > $second/file + ln -s $first $second/link + ''; + helloString = "Hello, world!"; + }; + a = mkDerivation { name = "multiple-outputs-a"; outputs = [ "first" "second" ]; diff --git a/tests/multiple-outputs.sh b/tests/multiple-outputs.sh index bedbc39a4..0bca12b42 100644 --- a/tests/multiple-outputs.sh +++ b/tests/multiple-outputs.sh @@ -4,6 +4,12 @@ clearStore rm -f $TEST_ROOT/result* +# Test whether the output names match our expectations +outPath=$(nix-instantiate multiple-outputs.nix --eval -A nameCheck.out.outPath) +[ "$(echo "$outPath" | sed -E 's_^".*/[^-/]*-([^/]*)"$_\1_')" = "multiple-outputs-a" ] +outPath=$(nix-instantiate multiple-outputs.nix --eval -A nameCheck.dev.outPath) +[ "$(echo "$outPath" | sed -E 's_^".*/[^-/]*-([^/]*)"$_\1_')" = "multiple-outputs-a-dev" ] + # Test whether read-only evaluation works when referring to the # ‘drvPath’ attribute. echo "evaluating c..." @@ -52,7 +58,7 @@ outPath2=$(nix-build $(nix-instantiate multiple-outputs.nix -A a.second) --no-ou # Delete one of the outputs and rebuild it. This will cause a hash # rewrite. -nix-store --delete $TEST_ROOT/result-second --ignore-liveness +env -u NIX_REMOTE nix store delete $TEST_ROOT/result-second --ignore-liveness nix-build multiple-outputs.nix -A a.all -o $TEST_ROOT/result [ "$(cat $TEST_ROOT/result-second/file)" = "second" ] [ "$(cat $TEST_ROOT/result-second/link/file)" = "first" ] diff --git a/tests/nar-access.sh b/tests/nar-access.sh index 553d6ca89..dcc2e8a36 100644 --- a/tests/nar-access.sh +++ b/tests/nar-access.sh @@ -9,33 +9,45 @@ cd "$TEST_ROOT" narFile="$TEST_ROOT/path.nar" nix-store --dump $storePath > $narFile -# Check that find and ls-nar match. +# Check that find and nar ls match. ( cd $storePath; find . | sort ) > files.find -nix ls-nar -R -d $narFile "" | sort > files.ls-nar +nix nar ls -R -d $narFile "" | sort > files.ls-nar diff -u files.find files.ls-nar # Check that file contents of data match. -nix cat-nar $narFile /foo/data > data.cat-nar +nix nar cat $narFile /foo/data > data.cat-nar diff -u data.cat-nar $storePath/foo/data # Check that file contents of baz match. -nix cat-nar $narFile /foo/baz > baz.cat-nar +nix nar cat $narFile /foo/baz > baz.cat-nar diff -u baz.cat-nar $storePath/foo/baz -nix cat-store $storePath/foo/baz > baz.cat-nar +nix store cat $storePath/foo/baz > baz.cat-nar diff -u baz.cat-nar $storePath/foo/baz # Test --json. -[[ $(nix ls-nar --json $narFile /) = '{"type":"directory","entries":{"foo":{},"foo-x":{},"qux":{},"zyx":{}}}' ]] -[[ $(nix ls-nar --json -R $narFile /foo) = '{"type":"directory","entries":{"bar":{"type":"regular","size":0,"narOffset":368},"baz":{"type":"regular","size":0,"narOffset":552},"data":{"type":"regular","size":58,"narOffset":736}}}' ]] -[[ $(nix ls-nar --json -R $narFile /foo/bar) = '{"type":"regular","size":0,"narOffset":368}' ]] -[[ $(nix ls-store --json $storePath) = '{"type":"directory","entries":{"foo":{},"foo-x":{},"qux":{},"zyx":{}}}' ]] -[[ $(nix ls-store --json -R $storePath/foo) = '{"type":"directory","entries":{"bar":{"type":"regular","size":0},"baz":{"type":"regular","size":0},"data":{"type":"regular","size":58}}}' ]] -[[ $(nix ls-store --json -R $storePath/foo/bar) = '{"type":"regular","size":0}' ]] +diff -u \ + <(nix nar ls --json $narFile / | jq -S) \ + <(echo '{"type":"directory","entries":{"foo":{},"foo-x":{},"qux":{},"zyx":{}}}' | jq -S) +diff -u \ + <(nix nar ls --json -R $narFile /foo | jq -S) \ + <(echo '{"type":"directory","entries":{"bar":{"type":"regular","size":0,"narOffset":368},"baz":{"type":"regular","size":0,"narOffset":552},"data":{"type":"regular","size":58,"narOffset":736}}}' | jq -S) +diff -u \ + <(nix nar ls --json -R $narFile /foo/bar | jq -S) \ + <(echo '{"type":"regular","size":0,"narOffset":368}' | jq -S) +diff -u \ + <(nix store ls --json $storePath | jq -S) \ + <(echo '{"type":"directory","entries":{"foo":{},"foo-x":{},"qux":{},"zyx":{}}}' | jq -S) +diff -u \ + <(nix store ls --json -R $storePath/foo | jq -S) \ + <(echo '{"type":"directory","entries":{"bar":{"type":"regular","size":0},"baz":{"type":"regular","size":0},"data":{"type":"regular","size":58}}}' | jq -S) +diff -u \ + <(nix store ls --json -R $storePath/foo/bar| jq -S) \ + <(echo '{"type":"regular","size":0}' | jq -S) # Test missing files. -nix ls-store --json -R $storePath/xyzzy 2>&1 | grep 'does not exist in NAR' -nix ls-store $storePath/xyzzy 2>&1 | grep 'does not exist' +nix store ls --json -R $storePath/xyzzy 2>&1 | grep 'does not exist in NAR' +nix store ls $storePath/xyzzy 2>&1 | grep 'does not exist' # Test failure to dump. if nix-store --dump $storePath >/dev/full ; then diff --git a/tests/nix-build-examples.nix b/tests/nix-build-examples.nix new file mode 100644 index 000000000..e54dbbf62 --- /dev/null +++ b/tests/nix-build-examples.nix @@ -0,0 +1,33 @@ +with import ./config.nix; + +rec { + + input0 = mkDerivation { + name = "dependencies-input-0"; + buildCommand = "mkdir $out; echo foo > $out/bar"; + }; + + input1 = mkDerivation { + name = "dependencies-input-1"; + buildCommand = "mkdir $out; echo FOO > $out/foo"; + }; + + input2 = mkDerivation { + name = "dependencies-input-2"; + buildCommand = '' + mkdir $out + echo BAR > $out/bar + echo ${input0} > $out/input0 + ''; + }; + + body = mkDerivation { + name = "dependencies-top"; + builder = ./dependencies.builder0.sh + "/FOOBAR/../."; + input1 = input1 + "/."; + input2 = "${input2}/."; + input1_drv = input1; + meta.description = "Random test package"; + }; + +} diff --git a/tests/nix-build.sh b/tests/nix-build.sh index 0eb599608..44a5a14cd 100644 --- a/tests/nix-build.sh +++ b/tests/nix-build.sh @@ -24,5 +24,20 @@ outPath2=$(nix-build $(nix-instantiate dependencies.nix) --no-out-link) outPath2=$(nix-build $(nix-instantiate dependencies.nix)!out --no-out-link) [[ $outPath = $outPath2 ]] -outPath2=$(nix-store -r $(nix-instantiate --indirect --add-root $TEST_ROOT/indirect dependencies.nix)!out) +outPath2=$(nix-store -r $(nix-instantiate --add-root $TEST_ROOT/indirect dependencies.nix)!out) [[ $outPath = $outPath2 ]] + +# The order of the paths on stdout must correspond to the -A options +# https://github.com/NixOS/nix/issues/4197 + +input0="$(nix-build nix-build-examples.nix -A input0 --no-out-link)" +input1="$(nix-build nix-build-examples.nix -A input1 --no-out-link)" +input2="$(nix-build nix-build-examples.nix -A input2 --no-out-link)" +body="$(nix-build nix-build-examples.nix -A body --no-out-link)" + +outPathsA="$(echo $(nix-build nix-build-examples.nix -A input0 -A input1 -A input2 -A body --no-out-link))" +[[ "$outPathsA" = "$input0 $input1 $input2 $body" ]] + +# test a different ordering to make sure it fails, not just in 23 out of 24 permutations +outPathsB="$(echo $(nix-build nix-build-examples.nix -A body -A input1 -A input2 -A input0 --no-out-link))" +[[ "$outPathsB" = "$body $input1 $input2 $input0" ]] diff --git a/tests/nix-channel.sh b/tests/nix-channel.sh index 49c68981a..63c0f97ba 100644 --- a/tests/nix-channel.sh +++ b/tests/nix-channel.sh @@ -28,9 +28,6 @@ nix-channel --update # Do a query. nix-env -qa \* --meta --xml --out-path > $TEST_ROOT/meta.xml -if [ "$xmllint" != false ]; then - $xmllint --noout $TEST_ROOT/meta.xml || fail "malformed XML" -fi grep -q 'meta.*description.*Random test package' $TEST_ROOT/meta.xml grep -q 'item.*attrPath="foo".*name="dependencies-top"' $TEST_ROOT/meta.xml @@ -47,9 +44,6 @@ nix-channel --update # Do a query. nix-env -qa \* --meta --xml --out-path > $TEST_ROOT/meta.xml -if [ "$xmllint" != false ]; then - $xmllint --noout $TEST_ROOT/meta.xml || fail "malformed XML" -fi grep -q 'meta.*description.*Random test package' $TEST_ROOT/meta.xml grep -q 'item.*attrPath="foo".*name="dependencies-top"' $TEST_ROOT/meta.xml diff --git a/tests/nix-copy-closure.nix b/tests/nix-copy-closure.nix index bb5db7410..1b63a3fca 100644 --- a/tests/nix-copy-closure.nix +++ b/tests/nix-copy-closure.nix @@ -1,17 +1,20 @@ # Test ‘nix-copy-closure’. -{ nixpkgs, system, nix }: +{ nixpkgs, system, overlay }: -with import (nixpkgs + "/nixos/lib/testing.nix") { inherit system; }; +with import (nixpkgs + "/nixos/lib/testing-python.nix") { + inherit system; + extraConfigurations = [ { nixpkgs.overlays = [ overlay ]; } ]; +}; -makeTest (let pkgA = pkgs.cowsay; pkgB = pkgs.wget; pkgC = pkgs.hello; in { +makeTest (let pkgA = pkgs.cowsay; pkgB = pkgs.wget; pkgC = pkgs.hello; pkgD = pkgs.tmux; in { + name = "nix-copy-closure"; nodes = { client = { config, lib, pkgs, ... }: { virtualisation.writableStore = true; - virtualisation.pathsInNixDB = [ pkgA ]; - nix.package = nix; + virtualisation.pathsInNixDB = [ pkgA pkgD.drvPath ]; nix.binaryCaches = lib.mkForce [ ]; }; @@ -20,45 +23,55 @@ makeTest (let pkgA = pkgs.cowsay; pkgB = pkgs.wget; pkgC = pkgs.hello; in { { services.openssh.enable = true; virtualisation.writableStore = true; virtualisation.pathsInNixDB = [ pkgB pkgC ]; - nix.package = nix; }; }; - testScript = { nodes }: - '' - startAll; + testScript = { nodes }: '' + # fmt: off + import subprocess - # Create an SSH key on the client. - my $key = `${pkgs.openssh}/bin/ssh-keygen -t ed25519 -f key -N ""`; - $client->succeed("mkdir -m 700 /root/.ssh"); - $client->copyFileFromHost("key", "/root/.ssh/id_ed25519"); - $client->succeed("chmod 600 /root/.ssh/id_ed25519"); + start_all() - # Install the SSH key on the server. - $server->succeed("mkdir -m 700 /root/.ssh"); - $server->copyFileFromHost("key.pub", "/root/.ssh/authorized_keys"); - $server->waitForUnit("sshd"); - $client->waitForUnit("network.target"); - $client->succeed("ssh -o StrictHostKeyChecking=no " . $server->name() . " 'echo hello world'"); + # Create an SSH key on the client. + subprocess.run([ + "${pkgs.openssh}/bin/ssh-keygen", "-t", "ed25519", "-f", "key", "-N", "" + ], capture_output=True, check=True) - # Copy the closure of package A from the client to the server. - $server->fail("nix-store --check-validity ${pkgA}"); - $client->succeed("nix-copy-closure --to server --gzip ${pkgA} >&2"); - $server->succeed("nix-store --check-validity ${pkgA}"); + client.succeed("mkdir -m 700 /root/.ssh") + client.copy_from_host("key", "/root/.ssh/id_ed25519") + client.succeed("chmod 600 /root/.ssh/id_ed25519") - # Copy the closure of package B from the server to the client. - $client->fail("nix-store --check-validity ${pkgB}"); - $client->succeed("nix-copy-closure --from server --gzip ${pkgB} >&2"); - $client->succeed("nix-store --check-validity ${pkgB}"); + # Install the SSH key on the server. + server.succeed("mkdir -m 700 /root/.ssh") + server.copy_from_host("key.pub", "/root/.ssh/authorized_keys") + server.wait_for_unit("sshd") + client.wait_for_unit("network.target") + client.succeed(f"ssh -o StrictHostKeyChecking=no {server.name} 'echo hello world'") - # Copy the closure of package C via the SSH substituter. - $client->fail("nix-store -r ${pkgC}"); - # FIXME - #$client->succeed( - # "nix-store --option use-ssh-substituter true" - # . " --option ssh-substituter-hosts root\@server" - # . " -r ${pkgC} >&2"); - #$client->succeed("nix-store --check-validity ${pkgC}"); - ''; + # Copy the closure of package A from the client to the server. + server.fail("nix-store --check-validity ${pkgA}") + client.succeed("nix-copy-closure --to server --gzip ${pkgA} >&2") + server.succeed("nix-store --check-validity ${pkgA}") + # Copy the closure of package B from the server to the client. + client.fail("nix-store --check-validity ${pkgB}") + client.succeed("nix-copy-closure --from server --gzip ${pkgB} >&2") + client.succeed("nix-store --check-validity ${pkgB}") + + # Copy the closure of package C via the SSH substituter. + client.fail("nix-store -r ${pkgC}") + + # Copy the derivation of package D's derivation from the client to the server. + server.fail("nix-store --check-validity ${pkgD.drvPath}") + client.succeed("nix-copy-closure --to server --gzip ${pkgD.drvPath} >&2") + server.succeed("nix-store --check-validity ${pkgD.drvPath}") + + # FIXME + # client.succeed( + # "nix-store --option use-ssh-substituter true" + # " --option ssh-substituter-hosts root\@server" + # " -r ${pkgC} >&2" + # ) + # client.succeed("nix-store --check-validity ${pkgC}") + ''; }) diff --git a/tests/nix-shell.sh b/tests/nix-shell.sh index 650904057..a31d35887 100644 --- a/tests/nix-shell.sh +++ b/tests/nix-shell.sh @@ -2,6 +2,20 @@ source common.sh clearStore +if [[ -n ${CONTENT_ADDRESSED:-} ]]; then + nix-shell () { + command nix-shell --arg contentAddressed true "$@" + } + + nix_develop() { + nix develop --arg contentAddressed true "$@" + } +else + nix_develop() { + nix develop "$@" + } +fi + # Test nix-shell -A export IMPURE_VAR=foo export SELECTED_IMPURE_VAR=baz @@ -27,12 +41,12 @@ output=$(nix-shell --pure --keep SELECTED_IMPURE_VAR shell.nix -A shellDrv --run # Test nix-shell on a .drv symlink # Legacy: absolute path and .drv extension required -nix-instantiate shell.nix -A shellDrv --indirect --add-root $TEST_ROOT/shell.drv +nix-instantiate shell.nix -A shellDrv --add-root $TEST_ROOT/shell.drv [[ $(nix-shell --pure $TEST_ROOT/shell.drv --run \ 'echo "$IMPURE_VAR - $VAR_FROM_STDENV_SETUP - $VAR_FROM_NIX"') = " - foo - bar" ]] # New behaviour: just needs to resolve to a derivation in the store -nix-instantiate shell.nix -A shellDrv --indirect --add-root $TEST_ROOT/shell +nix-instantiate shell.nix -A shellDrv --add-root $TEST_ROOT/shell [[ $(nix-shell --pure $TEST_ROOT/shell --run \ 'echo "$IMPURE_VAR - $VAR_FROM_STDENV_SETUP - $VAR_FROM_NIX"') = " - foo - bar" ]] @@ -40,25 +54,57 @@ nix-instantiate shell.nix -A shellDrv --indirect --add-root $TEST_ROOT/shell output=$(NIX_PATH=nixpkgs=shell.nix nix-shell --pure -p foo bar --run 'echo "$(foo) $(bar)"') [ "$output" = "foo bar" ] +# Test nix-shell -p --arg x y +output=$(NIX_PATH=nixpkgs=shell.nix nix-shell --pure -p foo --argstr fooContents baz --run 'echo "$(foo)"') +[ "$output" = "baz" ] + # Test nix-shell shebang mode -sed -e "s|@ENV_PROG@|$(type -p env)|" shell.shebang.sh > $TEST_ROOT/shell.shebang.sh +sed -e "s|@ENV_PROG@|$(type -P env)|" shell.shebang.sh > $TEST_ROOT/shell.shebang.sh chmod a+rx $TEST_ROOT/shell.shebang.sh output=$($TEST_ROOT/shell.shebang.sh abc def) [ "$output" = "foo bar abc def" ] +# Test nix-shell shebang mode again with metacharacters in the filename. +# First word of filename is chosen to not match any file in the test root. +sed -e "s|@ENV_PROG@|$(type -P env)|" shell.shebang.sh > $TEST_ROOT/spaced\ \\\'\"shell.shebang.sh +chmod a+rx $TEST_ROOT/spaced\ \\\'\"shell.shebang.sh + +output=$($TEST_ROOT/spaced\ \\\'\"shell.shebang.sh abc def) +[ "$output" = "foo bar abc def" ] + # Test nix-shell shebang mode for ruby # This uses a fake interpreter that returns the arguments passed # This, in turn, verifies the `rc` script is valid and the `load()` script (given using `-e`) is as expected. -sed -e "s|@SHELL_PROG@|$(type -p nix-shell)|" shell.shebang.rb > $TEST_ROOT/shell.shebang.rb +sed -e "s|@SHELL_PROG@|$(type -P nix-shell)|" shell.shebang.rb > $TEST_ROOT/shell.shebang.rb chmod a+rx $TEST_ROOT/shell.shebang.rb output=$($TEST_ROOT/shell.shebang.rb abc ruby) -[ "$output" = '-e load("'"$TEST_ROOT"'/shell.shebang.rb") -- abc ruby' ] +[ "$output" = '-e load(ARGV.shift) -- '"$TEST_ROOT"'/shell.shebang.rb abc ruby' ] + +# Test nix-shell shebang mode for ruby again with metacharacters in the filename. +# Note: fake interpreter only space-separates args without adding escapes to its output. +sed -e "s|@SHELL_PROG@|$(type -P nix-shell)|" shell.shebang.rb > $TEST_ROOT/spaced\ \\\'\"shell.shebang.rb +chmod a+rx $TEST_ROOT/spaced\ \\\'\"shell.shebang.rb + +output=$($TEST_ROOT/spaced\ \\\'\"shell.shebang.rb abc ruby) +[ "$output" = '-e load(ARGV.shift) -- '"$TEST_ROOT"'/spaced \'\''"shell.shebang.rb abc ruby' ] # Test 'nix develop'. -nix develop -f shell.nix shellDrv -c bash -c '[[ -n $stdenv ]]' +nix_develop -f shell.nix shellDrv -c bash -c '[[ -n $stdenv ]]' + +# Ensure `nix develop -c` preserves stdin +echo foo | nix develop -f shell.nix shellDrv -c cat | grep -q foo + +# Ensure `nix develop -c` actually executes the command if stdout isn't a terminal +nix_develop -f shell.nix shellDrv -c echo foo |& grep -q foo # Test 'nix print-dev-env'. +[[ $(nix print-dev-env -f shell.nix shellDrv --json | jq -r .variables.arr1.value[2]) = '3 4' ]] + source <(nix print-dev-env -f shell.nix shellDrv) [[ -n $stdenv ]] +[[ ${arr1[2]} = "3 4" ]] +[[ ${arr2[1]} = $'\n' ]] +[[ ${arr2[2]} = $'x\ny' ]] +[[ $(fun) = blabla ]] diff --git a/tests/optimise-store.sh b/tests/optimise-store.sh index 61e3df2f9..8c2d05cd5 100644 --- a/tests/optimise-store.sh +++ b/tests/optimise-store.sh @@ -26,7 +26,8 @@ if [ "$inode1" = "$inode3" ]; then exit 1 fi -nix-store --optimise +# XXX: This should work through the daemon too +NIX_REMOTE="" nix-store --optimise inode1="$(stat --format=%i $outPath1/foo)" inode3="$(stat --format=%i $outPath3/foo)" diff --git a/tests/path.nix b/tests/path.nix new file mode 100644 index 000000000..883c3c41b --- /dev/null +++ b/tests/path.nix @@ -0,0 +1,14 @@ +with import ./config.nix; + +mkDerivation { + name = "filter"; + builder = builtins.toFile "builder" "ln -s $input $out"; + input = + builtins.path { + path = ((builtins.getEnv "TEST_ROOT") + "/filterin"); + filter = path: type: + type != "symlink" + && baseNameOf path != "foo" + && !((import ./lang/lib.nix).hasSuffix ".bak" (baseNameOf path)); + }; +} diff --git a/tests/plugins.sh b/tests/plugins.sh index 4b1baeddc..e22bf4408 100644 --- a/tests/plugins.sh +++ b/tests/plugins.sh @@ -2,6 +2,6 @@ source common.sh set -o pipefail -res=$(nix eval '(builtins.anotherNull)' --option setting-set true --option plugin-files $PWD/plugins/libplugintest*) +res=$(nix --option setting-set true --option plugin-files $PWD/plugins/libplugintest* eval --expr builtins.anotherNull) [ "$res"x = "nullx" ] diff --git a/tests/post-hook.sh b/tests/post-hook.sh index aa3e6a574..049e40749 100644 --- a/tests/post-hook.sh +++ b/tests/post-hook.sh @@ -4,7 +4,10 @@ clearStore rm -f $TEST_ROOT/result -export REMOTE_STORE=$TEST_ROOT/remote_store +export REMOTE_STORE=file:$TEST_ROOT/remote_store +echo 'require-sigs = false' >> $NIX_CONF_DIR/nix.conf + +restartDaemon # Build the dependencies and push them to the remote store nix-build -o $TEST_ROOT/result dependencies.nix --post-build-hook $PWD/push-to-store.sh diff --git a/tests/pure-eval.sh b/tests/pure-eval.sh index 49c856448..c994fbb98 100644 --- a/tests/pure-eval.sh +++ b/tests/pure-eval.sh @@ -2,17 +2,25 @@ source common.sh clearStore -nix eval --pure-eval '(assert 1 + 2 == 3; true)' +nix eval --expr 'assert 1 + 2 == 3; true' -[[ $(nix eval '(builtins.readFile ./pure-eval.sh)') =~ clearStore ]] +[[ $(nix eval --impure --expr 'builtins.readFile ./pure-eval.sh') =~ clearStore ]] -(! nix eval --pure-eval '(builtins.readFile ./pure-eval.sh)') +(! nix eval --expr 'builtins.readFile ./pure-eval.sh') -(! nix eval --pure-eval '(builtins.currentTime)') -(! nix eval --pure-eval '(builtins.currentSystem)') +(! nix eval --expr builtins.currentTime) +(! nix eval --expr builtins.currentSystem) (! nix-instantiate --pure-eval ./simple.nix) -[[ $(nix eval "((import (builtins.fetchurl { url = file://$(pwd)/pure-eval.nix; })).x)") == 123 ]] -(! nix eval --pure-eval "((import (builtins.fetchurl { url = file://$(pwd)/pure-eval.nix; })).x)") -nix eval --pure-eval "((import (builtins.fetchurl { url = file://$(pwd)/pure-eval.nix; sha256 = \"$(nix hash-file pure-eval.nix --type sha256)\"; })).x)" +[[ $(nix eval --impure --expr "(import (builtins.fetchurl { url = file://$(pwd)/pure-eval.nix; })).x") == 123 ]] +(! nix eval --expr "(import (builtins.fetchurl { url = file://$(pwd)/pure-eval.nix; })).x") +nix eval --expr "(import (builtins.fetchurl { url = file://$(pwd)/pure-eval.nix; sha256 = \"$(nix hash file pure-eval.nix --type sha256)\"; })).x" + +rm -rf $TEST_ROOT/eval-out +nix eval --store dummy:// --write-to $TEST_ROOT/eval-out --expr '{ x = "foo" + "bar"; y = { z = "bla"; }; }' +[[ $(cat $TEST_ROOT/eval-out/x) = foobar ]] +[[ $(cat $TEST_ROOT/eval-out/y/z) = bla ]] + +rm -rf $TEST_ROOT/eval-out +(! nix eval --store dummy:// --write-to $TEST_ROOT/eval-out --expr '{ "." = "bla"; }') diff --git a/tests/push-to-store.sh b/tests/push-to-store.sh index 6aadb916b..25352c751 100755 --- a/tests/push-to-store.sh +++ b/tests/push-to-store.sh @@ -1,4 +1,6 @@ #!/bin/sh -echo Pushing "$@" to "$REMOTE_STORE" -printf "%s" "$OUT_PATHS" | xargs -d: nix copy --to "$REMOTE_STORE" --no-require-sigs +set -x + +echo Pushing "$OUT_PATHS" to "$REMOTE_STORE" +printf "%s" "$DRV_PATH" | xargs nix copy --to "$REMOTE_STORE" --no-require-sigs diff --git a/tests/recursive.sh b/tests/recursive.sh index 2d4f83895..91518d67d 100644 --- a/tests/recursive.sh +++ b/tests/recursive.sh @@ -1,18 +1,20 @@ source common.sh +sed -i 's/experimental-features .*/& recursive-nix/' "$NIX_CONF_DIR"/nix.conf +restartDaemon + # FIXME -if [[ $(uname) != Linux ]]; then exit; fi +if [[ $(uname) != Linux ]]; then exit 99; fi clearStore rm -f $TEST_ROOT/result -export unreachable=$(nix add-to-store ./recursive.sh) +export unreachable=$(nix store add-path ./recursive.sh) -nix --experimental-features 'nix-command recursive-nix' build -o $TEST_ROOT/result -L '( +NIX_BIN_DIR=$(dirname $(type -p nix)) nix --extra-experimental-features 'nix-command recursive-nix' build -o $TEST_ROOT/result -L --impure --expr ' with import ./config.nix; - with import <nix/config.nix>; - mkDerivation { + mkDerivation rec { name = "recursive"; dummy = builtins.toFile "dummy" "bla bla"; SHELL = shell; @@ -20,12 +22,15 @@ nix --experimental-features 'nix-command recursive-nix' build -o $TEST_ROOT/resu # Note: this is a string without context. unreachable = builtins.getEnv "unreachable"; + NIX_TESTS_CA_BY_DEFAULT = builtins.getEnv "NIX_TESTS_CA_BY_DEFAULT"; + requiredSystemFeatures = [ "recursive-nix" ]; buildCommand = '\'\'' mkdir $out - PATH=${nixBinDir}:$PATH - opts="--experimental-features nix-command" + opts="--experimental-features nix-command ${if (NIX_TESTS_CA_BY_DEFAULT == "1") then "--extra-experimental-features ca-derivations" else ""}" + + PATH=${builtins.getEnv "NIX_BIN_DIR"}:$PATH # Check that we can query/build paths in our input closure. nix $opts path-info $dummy @@ -38,7 +43,7 @@ nix --experimental-features 'nix-command recursive-nix' build -o $TEST_ROOT/resu # Add something to the store. echo foobar > foobar - foobar=$(nix $opts add-to-store ./foobar) + foobar=$(nix $opts store add-path ./foobar) nix $opts path-info $foobar nix $opts build $foobar @@ -46,24 +51,23 @@ nix --experimental-features 'nix-command recursive-nix' build -o $TEST_ROOT/resu # Add it to our closure. ln -s $foobar $out/foobar - [[ $(nix $opts path-info --all | wc -l) -eq 3 ]] + [[ $(nix $opts path-info --all | wc -l) -eq 4 ]] # Build a derivation. - nix $opts build -L '\''( - derivation { + nix $opts build -L --impure --expr '\'' + with import ${./config.nix}; + mkDerivation { name = "inner1"; - builder = builtins.getEnv "SHELL"; - system = builtins.getEnv "system"; + buildCommand = "echo $fnord blaat > $out"; fnord = builtins.toFile "fnord" "fnord"; - args = [ "-c" "echo $fnord blaat > $out" ]; } - )'\'' + '\'' [[ $(nix $opts path-info --json ./result) =~ fnord ]] ln -s $(nix $opts path-info ./result) $out/inner1 '\'\''; - }) + } ' [[ $(cat $TEST_ROOT/result/inner1) =~ blaat ]] diff --git a/tests/referrers.sh b/tests/referrers.sh index 614dd8f5b..81323c280 100644 --- a/tests/referrers.sh +++ b/tests/referrers.sh @@ -1,5 +1,7 @@ source common.sh +needLocalStore "uses some low-level store manipulations that aren’t available through the daemon" + clearStore max=500 diff --git a/tests/remote-builds.nix b/tests/remote-builds.nix index 18d490830..b9e7352c0 100644 --- a/tests/remote-builds.nix +++ b/tests/remote-builds.nix @@ -1,8 +1,11 @@ # Test Nix's remote build feature. -{ nixpkgs, system, nix }: +{ nixpkgs, system, overlay }: -with import (nixpkgs + "/nixos/lib/testing.nix") { inherit system; }; +with import (nixpkgs + "/nixos/lib/testing-python.nix") { + inherit system; + extraConfigurations = [ { nixpkgs.overlays = [ overlay ]; } ]; +}; makeTest ( @@ -13,7 +16,6 @@ let { config, pkgs, ... }: { services.openssh.enable = true; virtualisation.writableStore = true; - nix.package = nix; nix.useSandbox = true; }; @@ -34,6 +36,7 @@ let in { + name = "remote-builds"; nodes = { builder1 = builder; @@ -59,50 +62,51 @@ in ]; virtualisation.writableStore = true; virtualisation.pathsInNixDB = [ config.system.build.extraUtils ]; - nix.package = nix; nix.binaryCaches = lib.mkForce [ ]; programs.ssh.extraConfig = "ConnectTimeout 30"; }; }; - testScript = { nodes }: - '' - startAll; - - # Create an SSH key on the client. - my $key = `${pkgs.openssh}/bin/ssh-keygen -t ed25519 -f key -N ""`; - $client->succeed("mkdir -p -m 700 /root/.ssh"); - $client->copyFileFromHost("key", "/root/.ssh/id_ed25519"); - $client->succeed("chmod 600 /root/.ssh/id_ed25519"); - - # Install the SSH key on the builders. - $client->waitForUnit("network.target"); - foreach my $builder ($builder1, $builder2) { - $builder->succeed("mkdir -p -m 700 /root/.ssh"); - $builder->copyFileFromHost("key.pub", "/root/.ssh/authorized_keys"); - $builder->waitForUnit("sshd"); - $client->succeed("ssh -o StrictHostKeyChecking=no " . $builder->name() . " 'echo hello world'"); - } - - # Perform a build and check that it was performed on the builder. - my $out = $client->succeed( - "nix-build ${expr nodes.client.config 1} 2> build-output", - "grep -q Hello build-output" - ); - $builder1->succeed("test -e $out"); - - # And a parallel build. - my ($out1, $out2) = split /\s/, - $client->succeed('nix-store -r $(nix-instantiate ${expr nodes.client.config 2})\!out $(nix-instantiate ${expr nodes.client.config 3})\!out'); - $builder1->succeed("test -e $out1 -o -e $out2"); - $builder2->succeed("test -e $out1 -o -e $out2"); - - # And a failing build. - $client->fail("nix-build ${expr nodes.client.config 5}"); - - # Test whether the build hook automatically skips unavailable builders. - $builder1->block; - $client->succeed("nix-build ${expr nodes.client.config 4}"); - ''; - + testScript = { nodes }: '' + # fmt: off + import subprocess + + start_all() + + # Create an SSH key on the client. + subprocess.run([ + "${pkgs.openssh}/bin/ssh-keygen", "-t", "ed25519", "-f", "key", "-N", "" + ], capture_output=True, check=True) + client.succeed("mkdir -p -m 700 /root/.ssh") + client.copy_from_host("key", "/root/.ssh/id_ed25519") + client.succeed("chmod 600 /root/.ssh/id_ed25519") + + # Install the SSH key on the builders. + client.wait_for_unit("network.target") + for builder in [builder1, builder2]: + builder.succeed("mkdir -p -m 700 /root/.ssh") + builder.copy_from_host("key.pub", "/root/.ssh/authorized_keys") + builder.wait_for_unit("sshd") + client.succeed(f"ssh -o StrictHostKeyChecking=no {builder.name} 'echo hello world'") + + # Perform a build and check that it was performed on the builder. + out = client.succeed( + "nix-build ${expr nodes.client.config 1} 2> build-output", + "grep -q Hello build-output" + ) + builder1.succeed(f"test -e {out}") + + # And a parallel build. + paths = client.succeed(r'nix-store -r $(nix-instantiate ${expr nodes.client.config 2})\!out $(nix-instantiate ${expr nodes.client.config 3})\!out') + out1, out2 = paths.split() + builder1.succeed(f"test -e {out1} -o -e {out2}") + builder2.succeed(f"test -e {out1} -o -e {out2}") + + # And a failing build. + client.fail("nix-build ${expr nodes.client.config 5}") + + # Test whether the build hook automatically skips unavailable builders. + builder1.block() + client.succeed("nix-build ${expr nodes.client.config 4}") + ''; }) diff --git a/tests/remote-store.sh b/tests/remote-store.sh index 4cc73465a..31210ab47 100644 --- a/tests/remote-store.sh +++ b/tests/remote-store.sh @@ -2,16 +2,33 @@ source common.sh clearStore +# Ensure "fake ssh" remote store works just as legacy fake ssh would. +nix --store ssh-ng://localhost?remote-store=$TEST_ROOT/other-store doctor + startDaemon +# Test import-from-derivation through the daemon. +[[ $(nix eval --impure --raw --expr ' + with import ./config.nix; + import ( + mkDerivation { + name = "foo"; + bla = import ./dependencies.nix; + buildCommand = " + echo \\\"hi\\\" > $out + "; + } + ) +') = hi ]] + storeCleared=1 NIX_REMOTE_=$NIX_REMOTE $SHELL ./user-envs.sh +nix-store --gc --max-freed 1K + nix-store --dump-db > $TEST_ROOT/d1 NIX_REMOTE= nix-store --dump-db > $TEST_ROOT/d2 cmp $TEST_ROOT/d1 $TEST_ROOT/d2 -nix-store --gc --max-freed 1K - killDaemon user=$(whoami) diff --git a/tests/repair.sh b/tests/repair.sh index ec7ad5dca..12dcde8ea 100644 --- a/tests/repair.sh +++ b/tests/repair.sh @@ -1,5 +1,7 @@ source common.sh +needLocalStore "--repair needs a local store" + clearStore path=$(nix-build dependencies.nix -o $TEST_ROOT/result) @@ -13,14 +15,14 @@ hash=$(nix-hash $path2) chmod u+w $path2 touch $path2/bad -if nix-store --verify --check-contents -v; then - echo "nix-store --verify succeeded unexpectedly" >&2 - exit 1 -fi +(! nix-store --verify --check-contents -v) # The path can be repaired by rebuilding the derivation. nix-store --verify --check-contents --repair +(! [ -e $path2/bad ]) +(! [ -w $path2 ]) + nix-store --verify-path $path2 # Re-corrupt and delete the deriver. Now --verify --repair should @@ -30,10 +32,7 @@ touch $path2/bad nix-store --delete $(nix-store -qd $path2) -if nix-store --verify --check-contents --repair; then - echo "nix-store --verify --repair succeeded unexpectedly" >&2 - exit 1 -fi +(! nix-store --verify --check-contents --repair) nix-build dependencies.nix -o $TEST_ROOT/result --repair diff --git a/tests/repl.sh b/tests/repl.sh new file mode 100644 index 000000000..4e3059517 --- /dev/null +++ b/tests/repl.sh @@ -0,0 +1,18 @@ +source common.sh + +replCmds=" +simple = import ./simple.nix +:b simple +" + +testRepl () { + local nixArgs=("$@") + local outPath=$(nix repl "${nixArgs[@]}" <<< "$replCmds" |& + grep -o -E "$NIX_STORE_DIR/\w*-simple") + nix path-info "${nixArgs[@]}" "$outPath" +} + +# Simple test, try building a drv +testRepl +# Same thing (kind-of), but with a remote store. +testRepl --store "$TEST_ROOT/store?real=$NIX_STORE_DIR" diff --git a/tests/restricted.sh b/tests/restricted.sh index e02becc60..242b901dd 100644 --- a/tests/restricted.sh +++ b/tests/restricted.sh @@ -17,18 +17,18 @@ nix-instantiate --restrict-eval --eval -E 'builtins.readDir ../src/nix-channel' (! nix-instantiate --restrict-eval --eval -E 'let __nixPath = [ { prefix = "foo"; path = ./.; } ]; in <foo>') nix-instantiate --restrict-eval --eval -E 'let __nixPath = [ { prefix = "foo"; path = ./.; } ]; in <foo>' -I src=. -p=$(nix eval --raw "(builtins.fetchurl file://$(pwd)/restricted.sh)" --restrict-eval --allowed-uris "file://$(pwd)") +p=$(nix eval --raw --expr "builtins.fetchurl file://$(pwd)/restricted.sh" --impure --restrict-eval --allowed-uris "file://$(pwd)") cmp $p restricted.sh -(! nix eval --raw "(builtins.fetchurl file://$(pwd)/restricted.sh)" --restrict-eval) +(! nix eval --raw --expr "builtins.fetchurl file://$(pwd)/restricted.sh" --impure --restrict-eval) -(! nix eval --raw "(builtins.fetchurl file://$(pwd)/restricted.sh)" --restrict-eval --allowed-uris "file://$(pwd)/restricted.sh/") +(! nix eval --raw --expr "builtins.fetchurl file://$(pwd)/restricted.sh" --impure --restrict-eval --allowed-uris "file://$(pwd)/restricted.sh/") -nix eval --raw "(builtins.fetchurl file://$(pwd)/restricted.sh)" --restrict-eval --allowed-uris "file://$(pwd)/restricted.sh" +nix eval --raw --expr "builtins.fetchurl file://$(pwd)/restricted.sh" --impure --restrict-eval --allowed-uris "file://$(pwd)/restricted.sh" -(! nix eval --raw "(builtins.fetchurl https://github.com/NixOS/patchelf/archive/master.tar.gz)" --restrict-eval) -(! nix eval --raw "(builtins.fetchTarball https://github.com/NixOS/patchelf/archive/master.tar.gz)" --restrict-eval) -(! nix eval --raw "(fetchGit git://github.com/NixOS/patchelf.git)" --restrict-eval) +(! nix eval --raw --expr "builtins.fetchurl https://github.com/NixOS/patchelf/archive/master.tar.gz" --impure --restrict-eval) +(! nix eval --raw --expr "builtins.fetchTarball https://github.com/NixOS/patchelf/archive/master.tar.gz" --impure --restrict-eval) +(! nix eval --raw --expr "fetchGit git://github.com/NixOS/patchelf.git" --impure --restrict-eval) ln -sfn $(pwd)/restricted.nix $TEST_ROOT/restricted.nix [[ $(nix-instantiate --eval $TEST_ROOT/restricted.nix) == 3 ]] @@ -37,7 +37,7 @@ ln -sfn $(pwd)/restricted.nix $TEST_ROOT/restricted.nix (! nix-instantiate --eval --restrict-eval $TEST_ROOT/restricted.nix -I .) nix-instantiate --eval --restrict-eval $TEST_ROOT/restricted.nix -I $TEST_ROOT -I . -[[ $(nix eval --raw --restrict-eval -I . '(builtins.readFile "${import ./simple.nix}/hello")') == 'Hello World!' ]] +[[ $(nix eval --raw --impure --restrict-eval -I . --expr 'builtins.readFile "${import ./simple.nix}/hello"') == 'Hello World!' ]] # Check whether we can leak symlink information through directory traversal. traverseDir="$(pwd)/restricted-traverse-me" @@ -45,7 +45,7 @@ ln -sfn "$(pwd)/restricted-secret" "$(pwd)/restricted-innocent" mkdir -p "$traverseDir" goUp="..$(echo "$traverseDir" | sed -e 's,[^/]\+,..,g')" output="$(nix eval --raw --restrict-eval -I "$traverseDir" \ - "(builtins.readFile \"$traverseDir/$goUp$(pwd)/restricted-innocent\")" \ + --expr "builtins.readFile \"$traverseDir/$goUp$(pwd)/restricted-innocent\"" \ 2>&1 || :)" echo "$output" | grep "is forbidden" ! echo "$output" | grep -F restricted-secret diff --git a/tests/search.sh b/tests/search.sh index 14da3127b..ee3261687 100644 --- a/tests/search.sh +++ b/tests/search.sh @@ -3,41 +3,23 @@ source common.sh clearStore clearCache -# No packages -(( $(NIX_PATH= nix search -u|wc -l) == 0 )) - -# Haven't updated cache, still nothing -(( $(nix search -f search.nix hello|wc -l) == 0 )) -(( $(nix search -f search.nix |wc -l) == 0 )) - -# Update cache, search should work -(( $(nix search -f search.nix -u hello|wc -l) > 0 )) - -# Use cache -(( $(nix search -f search.nix foo|wc -l) > 0 )) -(( $(nix search foo|wc -l) > 0 )) - -# Test --no-cache works -# No results from cache -(( $(nix search --no-cache foo |wc -l) == 0 )) -# Does find results from file pointed at -(( $(nix search -f search.nix --no-cache foo |wc -l) > 0 )) +(( $(nix search -f search.nix '' hello | wc -l) > 0 )) # Check descriptions are searched -(( $(nix search broken | wc -l) > 0 )) +(( $(nix search -f search.nix '' broken | wc -l) > 0 )) # Check search that matches nothing -(( $(nix search nosuchpackageexists | wc -l) == 0 )) +(( $(nix search -f search.nix '' nosuchpackageexists | wc -l) == 0 )) # Search for multiple arguments -(( $(nix search hello empty | wc -l) == 3 )) +(( $(nix search -f search.nix '' hello empty | wc -l) == 2 )) # Multiple arguments will not exist -(( $(nix search hello broken | wc -l) == 0 )) +(( $(nix search -f search.nix '' hello broken | wc -l) == 0 )) ## Search expressions # Check that empty search string matches all -nix search|grep -q foo -nix search|grep -q bar -nix search|grep -q hello +nix search -f search.nix '' |grep -q foo +nix search -f search.nix '' |grep -q bar +nix search -f search.nix '' |grep -q hello diff --git a/tests/setuid.nix b/tests/setuid.nix index 63d3c05cb..35eb304ed 100644 --- a/tests/setuid.nix +++ b/tests/setuid.nix @@ -1,108 +1,126 @@ # Verify that Linux builds cannot create setuid or setgid binaries. -{ nixpkgs, system, nix }: +{ nixpkgs, system, overlay }: -with import (nixpkgs + "/nixos/lib/testing.nix") { inherit system; }; +with import (nixpkgs + "/nixos/lib/testing-python.nix") { + inherit system; + extraConfigurations = [ { nixpkgs.overlays = [ overlay ]; } ]; +}; makeTest { + name = "setuid"; machine = { config, lib, pkgs, ... }: { virtualisation.writableStore = true; - nix.package = nix; nix.binaryCaches = lib.mkForce [ ]; nix.nixPath = [ "nixpkgs=${lib.cleanSource pkgs.path}" ]; virtualisation.pathsInNixDB = [ pkgs.stdenv pkgs.pkgsi686Linux.stdenv ]; }; - testScript = { nodes }: - '' - startAll; - - # Copying to /tmp should succeed. - $machine->succeed('nix-build --no-sandbox -E \'(with import <nixpkgs> {}; runCommand "foo" {} " - mkdir -p $out - cp ${pkgs.coreutils}/bin/id /tmp/id - ")\' '); - - $machine->succeed('[[ $(stat -c %a /tmp/id) = 555 ]]'); - - $machine->succeed("rm /tmp/id"); - - # Creating a setuid binary should fail. - $machine->fail('nix-build --no-sandbox -E \'(with import <nixpkgs> {}; runCommand "foo" {} " - mkdir -p $out - cp ${pkgs.coreutils}/bin/id /tmp/id - chmod 4755 /tmp/id - ")\' '); - - $machine->succeed('[[ $(stat -c %a /tmp/id) = 555 ]]'); - - $machine->succeed("rm /tmp/id"); - - # Creating a setgid binary should fail. - $machine->fail('nix-build --no-sandbox -E \'(with import <nixpkgs> {}; runCommand "foo" {} " - mkdir -p $out - cp ${pkgs.coreutils}/bin/id /tmp/id - chmod 2755 /tmp/id - ")\' '); - - $machine->succeed('[[ $(stat -c %a /tmp/id) = 555 ]]'); - - $machine->succeed("rm /tmp/id"); - - # The checks should also work on 32-bit binaries. - $machine->fail('nix-build --no-sandbox -E \'(with import <nixpkgs> { system = "i686-linux"; }; runCommand "foo" {} " - mkdir -p $out - cp ${pkgs.coreutils}/bin/id /tmp/id - chmod 2755 /tmp/id - ")\' '); - - $machine->succeed('[[ $(stat -c %a /tmp/id) = 555 ]]'); - - $machine->succeed("rm /tmp/id"); - - # The tests above use fchmodat(). Test chmod() as well. - $machine->succeed('nix-build --no-sandbox -E \'(with import <nixpkgs> {}; runCommand "foo" { buildInputs = [ perl ]; } " - mkdir -p $out - cp ${pkgs.coreutils}/bin/id /tmp/id - perl -e \"chmod 0666, qw(/tmp/id) or die\" - ")\' '); - - $machine->succeed('[[ $(stat -c %a /tmp/id) = 666 ]]'); - - $machine->succeed("rm /tmp/id"); - - $machine->fail('nix-build --no-sandbox -E \'(with import <nixpkgs> {}; runCommand "foo" { buildInputs = [ perl ]; } " - mkdir -p $out - cp ${pkgs.coreutils}/bin/id /tmp/id - perl -e \"chmod 04755, qw(/tmp/id) or die\" - ")\' '); - - $machine->succeed('[[ $(stat -c %a /tmp/id) = 555 ]]'); - - $machine->succeed("rm /tmp/id"); - - # And test fchmod(). - $machine->succeed('nix-build --no-sandbox -E \'(with import <nixpkgs> {}; runCommand "foo" { buildInputs = [ perl ]; } " - mkdir -p $out - cp ${pkgs.coreutils}/bin/id /tmp/id - perl -e \"my \\\$x; open \\\$x, qw(/tmp/id); chmod 01750, \\\$x or die\" - ")\' '); - - $machine->succeed('[[ $(stat -c %a /tmp/id) = 1750 ]]'); - - $machine->succeed("rm /tmp/id"); - - $machine->fail('nix-build --no-sandbox -E \'(with import <nixpkgs> {}; runCommand "foo" { buildInputs = [ perl ]; } " - mkdir -p $out - cp ${pkgs.coreutils}/bin/id /tmp/id - perl -e \"my \\\$x; open \\\$x, qw(/tmp/id); chmod 04777, \\\$x or die\" - ")\' '); - - $machine->succeed('[[ $(stat -c %a /tmp/id) = 555 ]]'); - - $machine->succeed("rm /tmp/id"); - ''; - + testScript = { nodes }: '' + # fmt: off + start_all() + + # Copying to /tmp should succeed. + machine.succeed(r""" + nix-build --no-sandbox -E '(with import <nixpkgs> {}; runCommand "foo" {} " + mkdir -p $out + cp ${pkgs.coreutils}/bin/id /tmp/id + ")' + """.strip()) + + machine.succeed('[[ $(stat -c %a /tmp/id) = 555 ]]') + + machine.succeed("rm /tmp/id") + + # Creating a setuid binary should fail. + machine.fail(r""" + nix-build --no-sandbox -E '(with import <nixpkgs> {}; runCommand "foo" {} " + mkdir -p $out + cp ${pkgs.coreutils}/bin/id /tmp/id + chmod 4755 /tmp/id + ")' + """.strip()) + + machine.succeed('[[ $(stat -c %a /tmp/id) = 555 ]]') + + machine.succeed("rm /tmp/id") + + # Creating a setgid binary should fail. + machine.fail(r""" + nix-build --no-sandbox -E '(with import <nixpkgs> {}; runCommand "foo" {} " + mkdir -p $out + cp ${pkgs.coreutils}/bin/id /tmp/id + chmod 2755 /tmp/id + ")' + """.strip()) + + machine.succeed('[[ $(stat -c %a /tmp/id) = 555 ]]') + + machine.succeed("rm /tmp/id") + + # The checks should also work on 32-bit binaries. + machine.fail(r""" + nix-build --no-sandbox -E '(with import <nixpkgs> { system = "i686-linux"; }; runCommand "foo" {} " + mkdir -p $out + cp ${pkgs.coreutils}/bin/id /tmp/id + chmod 2755 /tmp/id + ")' + """.strip()) + + machine.succeed('[[ $(stat -c %a /tmp/id) = 555 ]]') + + machine.succeed("rm /tmp/id") + + # The tests above use fchmodat(). Test chmod() as well. + machine.succeed(r""" + nix-build --no-sandbox -E '(with import <nixpkgs> {}; runCommand "foo" { buildInputs = [ perl ]; } " + mkdir -p $out + cp ${pkgs.coreutils}/bin/id /tmp/id + perl -e \"chmod 0666, qw(/tmp/id) or die\" + ")' + """.strip()) + + machine.succeed('[[ $(stat -c %a /tmp/id) = 666 ]]') + + machine.succeed("rm /tmp/id") + + machine.fail(r""" + nix-build --no-sandbox -E '(with import <nixpkgs> {}; runCommand "foo" { buildInputs = [ perl ]; } " + mkdir -p $out + cp ${pkgs.coreutils}/bin/id /tmp/id + perl -e \"chmod 04755, qw(/tmp/id) or die\" + ")' + """.strip()) + + machine.succeed('[[ $(stat -c %a /tmp/id) = 555 ]]') + + machine.succeed("rm /tmp/id") + + # And test fchmod(). + machine.succeed(r""" + nix-build --no-sandbox -E '(with import <nixpkgs> {}; runCommand "foo" { buildInputs = [ perl ]; } " + mkdir -p $out + cp ${pkgs.coreutils}/bin/id /tmp/id + perl -e \"my \\\$x; open \\\$x, qw(/tmp/id); chmod 01750, \\\$x or die\" + ")' + """.strip()) + + machine.succeed('[[ $(stat -c %a /tmp/id) = 1750 ]]') + + machine.succeed("rm /tmp/id") + + machine.fail(r""" + nix-build --no-sandbox -E '(with import <nixpkgs> {}; runCommand "foo" { buildInputs = [ perl ]; } " + mkdir -p $out + cp ${pkgs.coreutils}/bin/id /tmp/id + perl -e \"my \\\$x; open \\\$x, qw(/tmp/id); chmod 04777, \\\$x or die\" + ")' + """.strip()) + + machine.succeed('[[ $(stat -c %a /tmp/id) = 555 ]]') + + machine.succeed("rm /tmp/id") + ''; } diff --git a/tests/shell.nix b/tests/shell.nix index 6cb4f082b..4912d295a 100644 --- a/tests/shell.nix +++ b/tests/shell.nix @@ -1,6 +1,18 @@ -{ inNixShell ? false }: +{ inNixShell ? false, contentAddressed ? false, fooContents ? "foo" }: -with import ./config.nix; +let cfg = import ./config.nix; in +with cfg; + +let + mkDerivation = + if contentAddressed then + args: cfg.mkDerivation ({ + __contentAddressed = true; + outputHashMode = "recursive"; + outputHashAlgo = "sha256"; + } // args) + else cfg.mkDerivation; +in let pkgs = rec { setupSh = builtins.toFile "setup" '' @@ -8,6 +20,20 @@ let pkgs = rec { for pkg in $buildInputs; do export PATH=$PATH:$pkg/bin done + + # mimic behavior of stdenv for `$out` etc. for structured attrs. + if [ -n "''${NIX_ATTRS_SH_FILE}" ]; then + for o in "''${!outputs[@]}"; do + eval "''${o}=''${outputs[$o]}" + export "''${o}" + done + fi + + declare -a arr1=(1 2 "3 4" 5) + declare -a arr2=(x $'\n' $'x\ny') + fun() { + echo blabla + } ''; stdenv = mkDerivation { @@ -22,8 +48,11 @@ let pkgs = rec { name = "shellDrv"; builder = "/does/not/exist"; VAR_FROM_NIX = "bar"; + ASCII_PERCENT = "%"; + ASCII_AT = "@"; TEST_inNixShell = if inNixShell then "true" else "false"; inherit stdenv; + outputs = ["dev" "out"]; }; # Used by nix-shell -p @@ -33,7 +62,7 @@ let pkgs = rec { foo = runCommand "foo" {} '' mkdir -p $out/bin - echo 'echo foo' > $out/bin/foo + echo 'echo ${fooContents}' > $out/bin/foo chmod a+rx $out/bin/foo ln -s ${shell} $out/bin/bash ''; @@ -49,7 +78,7 @@ let pkgs = rec { # ruby "interpreter" that outputs "$@" ruby = runCommand "ruby" {} '' mkdir -p $out/bin - echo 'printf -- "$*"' > $out/bin/ruby + echo 'printf %s "$*"' > $out/bin/ruby chmod a+rx $out/bin/ruby ''; diff --git a/tests/shell.sh b/tests/shell.sh index 7a9ee8ab0..2b85bb337 100644 --- a/tests/shell.sh +++ b/tests/shell.sh @@ -6,7 +6,7 @@ clearCache nix shell -f shell-hello.nix hello -c hello | grep 'Hello World' nix shell -f shell-hello.nix hello -c hello NixOS | grep 'Hello NixOS' -if ! canUseSandbox; then exit; fi +if ! canUseSandbox; then exit 99; fi chmod -R u+w $TEST_ROOT/store0 || true rm -rf $TEST_ROOT/store0 diff --git a/tests/signing.sh b/tests/signing.sh index 9e29e3fbf..6aafbeb91 100644 --- a/tests/signing.sh +++ b/tests/signing.sh @@ -17,40 +17,40 @@ info=$(nix path-info --json $outPath) [[ $info =~ 'cache1.example.org' ]] [[ $info =~ 'cache2.example.org' ]] -# Test "nix verify". -nix verify -r $outPath +# Test "nix store verify". +nix store verify -r $outPath -expect 2 nix verify -r $outPath --sigs-needed 1 +expect 2 nix store verify -r $outPath --sigs-needed 1 -nix verify -r $outPath --sigs-needed 1 --trusted-public-keys $pk1 +nix store verify -r $outPath --sigs-needed 1 --trusted-public-keys $pk1 -expect 2 nix verify -r $outPath --sigs-needed 2 --trusted-public-keys $pk1 +expect 2 nix store verify -r $outPath --sigs-needed 2 --trusted-public-keys $pk1 -nix verify -r $outPath --sigs-needed 2 --trusted-public-keys "$pk1 $pk2" +nix store verify -r $outPath --sigs-needed 2 --trusted-public-keys "$pk1 $pk2" -nix verify --all --sigs-needed 2 --trusted-public-keys "$pk1 $pk2" +nix store verify --all --sigs-needed 2 --trusted-public-keys "$pk1 $pk2" # Build something unsigned. outPath2=$(nix-build simple.nix --no-out-link) -nix verify -r $outPath +nix store verify -r $outPath # Verify that the path did not get signed but does have the ultimate bit. info=$(nix path-info --json $outPath2) [[ $info =~ '"ultimate":true' ]] (! [[ $info =~ 'signatures' ]]) -# Test "nix verify". -nix verify -r $outPath2 +# Test "nix store verify". +nix store verify -r $outPath2 -expect 2 nix verify -r $outPath2 --sigs-needed 1 +expect 2 nix store verify -r $outPath2 --sigs-needed 1 -expect 2 nix verify -r $outPath2 --sigs-needed 1 --trusted-public-keys $pk1 +expect 2 nix store verify -r $outPath2 --sigs-needed 1 --trusted-public-keys $pk1 -# Test "nix sign-paths". -nix sign-paths --key-file $TEST_ROOT/sk1 $outPath2 +# Test "nix store sign". +nix store sign --key-file $TEST_ROOT/sk1 $outPath2 -nix verify -r $outPath2 --sigs-needed 1 --trusted-public-keys $pk1 +nix store verify -r $outPath2 --sigs-needed 1 --trusted-public-keys $pk1 # Build something content-addressed. outPathCA=$(IMPURE_VAR1=foo IMPURE_VAR2=bar nix-build ./fixed.nix -A good.0 --no-out-link) @@ -59,12 +59,12 @@ outPathCA=$(IMPURE_VAR1=foo IMPURE_VAR2=bar nix-build ./fixed.nix -A good.0 --no # Content-addressed paths don't need signatures, so they verify # regardless of --sigs-needed. -nix verify $outPathCA -nix verify $outPathCA --sigs-needed 1000 +nix store verify $outPathCA +nix store verify $outPathCA --sigs-needed 1000 # Check that signing a content-addressed path doesn't overflow validSigs -nix sign-paths --key-file $TEST_ROOT/sk1 $outPathCA -nix verify -r $outPathCA --sigs-needed 1000 --trusted-public-keys $pk1 +nix store sign --key-file $TEST_ROOT/sk1 $outPathCA +nix store verify -r $outPathCA --sigs-needed 1000 --trusted-public-keys $pk1 # Copy to a binary cache. nix copy --to file://$cacheDir $outPath2 @@ -76,7 +76,7 @@ info=$(nix path-info --store file://$cacheDir --json $outPath2) (! [[ $info =~ 'cache2.example.org' ]]) # Verify that adding a signature to a path in a binary cache works. -nix sign-paths --store file://$cacheDir --key-file $TEST_ROOT/sk2 $outPath2 +nix store sign --store file://$cacheDir --key-file $TEST_ROOT/sk2 $outPath2 info=$(nix path-info --store file://$cacheDir --json $outPath2) [[ $info =~ 'cache1.example.org' ]] [[ $info =~ 'cache2.example.org' ]] @@ -89,17 +89,17 @@ rm -rf $TEST_ROOT/store0 # But succeed if we supply the public keys. nix copy --to $TEST_ROOT/store0 $outPath --trusted-public-keys $pk1 -expect 2 nix verify --store $TEST_ROOT/store0 -r $outPath +expect 2 nix store verify --store $TEST_ROOT/store0 -r $outPath -nix verify --store $TEST_ROOT/store0 -r $outPath --trusted-public-keys $pk1 -nix verify --store $TEST_ROOT/store0 -r $outPath --sigs-needed 2 --trusted-public-keys "$pk1 $pk2" +nix store verify --store $TEST_ROOT/store0 -r $outPath --trusted-public-keys $pk1 +nix store verify --store $TEST_ROOT/store0 -r $outPath --sigs-needed 2 --trusted-public-keys "$pk1 $pk2" # It should also succeed if we disable signature checking. (! nix copy --to $TEST_ROOT/store0 $outPath2) nix copy --to $TEST_ROOT/store0?require-sigs=false $outPath2 # But signatures should still get copied. -nix verify --store $TEST_ROOT/store0 -r $outPath2 --trusted-public-keys $pk1 +nix store verify --store $TEST_ROOT/store0 -r $outPath2 --trusted-public-keys $pk1 # Content-addressed stuff can be copied without signatures. nix copy --to $TEST_ROOT/store0 $outPathCA diff --git a/tests/simple.sh b/tests/simple.sh index 37631b648..15bd2bd16 100644 --- a/tests/simple.sh +++ b/tests/simple.sh @@ -10,13 +10,15 @@ outPath=$(nix-store -rvv "$drvPath") echo "output path is $outPath" +(! [ -w $outPath ]) + text=$(cat "$outPath"/hello) if test "$text" != "Hello World!"; then exit 1; fi # Directed delete: $outPath is not reachable from a root, so it should # be deleteable. nix-store --delete $outPath -if test -e $outPath/hello; then false; fi +(! [ -e $outPath/hello ]) outPath="$(NIX_REMOTE=local?store=/foo\&real=$TEST_ROOT/real-store nix-instantiate --readonly-mode hash-check.nix)" if test "$outPath" != "/foo/lfy1s6ca46rm5r6w4gg9hc0axiakjcnm-dependencies.drv"; then diff --git a/tests/ssh-relay.sh b/tests/ssh-relay.sh new file mode 100644 index 000000000..053b2f00d --- /dev/null +++ b/tests/ssh-relay.sh @@ -0,0 +1,16 @@ +source common.sh + +echo foo > $TEST_ROOT/hello.sh + +ssh_localhost=ssh://localhost +remote_store=?remote-store=$ssh_localhost + +store=$ssh_localhost + +store+=$remote_store +store+=$remote_store +store+=$remote_store + +out=$(nix store add-path --store "$store" $TEST_ROOT/hello.sh) + +[ foo = $(< $out) ] diff --git a/tests/structured-attrs-shell.nix b/tests/structured-attrs-shell.nix new file mode 100644 index 000000000..57c1e6bd2 --- /dev/null +++ b/tests/structured-attrs-shell.nix @@ -0,0 +1,21 @@ +with import ./config.nix; +let + dep = mkDerivation { + name = "dep"; + buildCommand = '' + mkdir $out; echo bla > $out/bla + ''; + }; + inherit (import ./shell.nix { inNixShell = true; }) stdenv; +in +mkDerivation { + name = "structured2"; + __structuredAttrs = true; + inherit stdenv; + outputs = [ "out" "dev" ]; + my.list = [ "a" "b" "c" ]; + exportReferencesGraph.refs = [ dep ]; + buildCommand = '' + touch ''${outputs[out]}; touch ''${outputs[dev]} + ''; +} diff --git a/tests/structured-attrs.nix b/tests/structured-attrs.nix index c39c3a346..e93139a44 100644 --- a/tests/structured-attrs.nix +++ b/tests/structured-attrs.nix @@ -36,7 +36,7 @@ mkDerivation { echo bar > $dest echo foo > $dest2 - json=$(cat .attrs.json) + json=$(cat $NIX_ATTRS_JSON_FILE) [[ $json =~ '"narHash":"sha256:1r7yc43zqnzl5b0als5vnyp649gk17i37s7mj00xr8kc47rjcybk"' ]] [[ $json =~ '"narSize":288' ]] [[ $json =~ '"closureSize":288' ]] diff --git a/tests/structured-attrs.sh b/tests/structured-attrs.sh index dcfe6d580..e585ce37f 100644 --- a/tests/structured-attrs.sh +++ b/tests/structured-attrs.sh @@ -1,5 +1,9 @@ source common.sh +# 27ce722638 required some incompatible changes to the nix file, so skip this +# tests for the older versions +requireDaemonNewerThan "2.4pre20210622" + clearStore rm -f $TEST_ROOT/result @@ -8,3 +12,12 @@ nix-build structured-attrs.nix -A all -o $TEST_ROOT/result [[ $(cat $TEST_ROOT/result/foo) = bar ]] [[ $(cat $TEST_ROOT/result-dev/foo) = foo ]] + +export NIX_BUILD_SHELL=$SHELL +env NIX_PATH=nixpkgs=shell.nix nix-shell structured-attrs-shell.nix \ + --run 'test -e .attrs.json; test "3" = "$(jq ".my.list|length" < $NIX_ATTRS_JSON_FILE)"' + +# `nix develop` is a slightly special way of dealing with environment vars, it parses +# these from a shell-file exported from a derivation. This is to test especially `outputs` +# (which is an associative array in thsi case) being fine. +nix develop -f structured-attrs-shell.nix -c bash -c 'test -n "$out"' diff --git a/tests/substitute-with-invalid-ca.sh b/tests/substitute-with-invalid-ca.sh new file mode 100644 index 000000000..4d0b01e0f --- /dev/null +++ b/tests/substitute-with-invalid-ca.sh @@ -0,0 +1,38 @@ +source common.sh + +BINARY_CACHE=file://$cacheDir + +getHash() { + basename "$1" | cut -d '-' -f 1 +} +getRemoteNarInfo () { + echo "$cacheDir/$(getHash "$1").narinfo" +} + +cat <<EOF > $TEST_HOME/good.txt +I’m a good path +EOF + +cat <<EOF > $TEST_HOME/bad.txt +I’m a bad path +EOF + +good=$(nix-store --add $TEST_HOME/good.txt) +bad=$(nix-store --add $TEST_HOME/bad.txt) +nix copy --to "$BINARY_CACHE" "$good" +nix copy --to "$BINARY_CACHE" "$bad" +nix-collect-garbage >/dev/null 2>&1 + +# Falsifying the narinfo file for '$good' +goodPathNarInfo=$(getRemoteNarInfo "$good") +badPathNarInfo=$(getRemoteNarInfo "$bad") +for fieldName in URL FileHash FileSize NarHash NarSize; do + sed -i "/^$fieldName/d" "$goodPathNarInfo" + grep -E "^$fieldName" "$badPathNarInfo" >> "$goodPathNarInfo" +done + +# Copying back '$good' from the binary cache. This should fail as it is +# corrupted +if nix copy --from "$BINARY_CACHE" "$good"; then + fail "Importing a path with a wrong CA field should fail" +fi diff --git a/tests/tarball.sh b/tests/tarball.sh index b3ec16d40..1301922a5 100644 --- a/tests/tarball.sh +++ b/tests/tarball.sh @@ -10,14 +10,14 @@ mkdir -p $tarroot cp dependencies.nix $tarroot/default.nix cp config.nix dependencies.builder*.sh $tarroot/ -hash=$(nix hash-path $tarroot) +hash=$(nix hash path $tarroot) test_tarball() { local ext="$1" local compressor="$2" tarball=$TEST_ROOT/tarball.tar$ext - (cd $TEST_ROOT && tar c tarball) | $compressor > $tarball + (cd $TEST_ROOT && tar cf - tarball) | $compressor > $tarball nix-env -f file://$tarball -qa --out-path | grep -q dependencies @@ -27,16 +27,24 @@ test_tarball() { nix-build -o $TEST_ROOT/result -E "import (fetchTarball file://$tarball)" - nix-build --experimental-features flakes -o $TEST_ROOT/result -E "import (fetchTree file://$tarball)" - nix-build --experimental-features flakes -o $TEST_ROOT/result -E "import (fetchTree { type = \"tarball\"; url = file://$tarball; })" - nix-build --experimental-features flakes -o $TEST_ROOT/result -E "import (fetchTree { type = \"tarball\"; url = file://$tarball; narHash = \"$hash\"; })" - nix-build --experimental-features flakes -o $TEST_ROOT/result -E "import (fetchTree { type = \"tarball\"; url = file://$tarball; narHash = \"sha256-xdKv2pq/IiwLSnBBJXW8hNowI4MrdZfW+SYqDQs7Tzc=\"; })" 2>&1 | grep 'NAR hash mismatch in input' + nix-build -o $TEST_ROOT/result -E "import (fetchTree file://$tarball)" + nix-build -o $TEST_ROOT/result -E "import (fetchTree { type = \"tarball\"; url = file://$tarball; })" + nix-build -o $TEST_ROOT/result -E "import (fetchTree { type = \"tarball\"; url = file://$tarball; narHash = \"$hash\"; })" + nix-build -o $TEST_ROOT/result -E "import (fetchTree { type = \"tarball\"; url = file://$tarball; narHash = \"sha256-xdKv2pq/IiwLSnBBJXW8hNowI4MrdZfW+SYqDQs7Tzc=\"; })" 2>&1 | grep 'NAR hash mismatch in input' + + nix-instantiate --strict --eval -E "!((import (fetchTree { type = \"tarball\"; url = file://$tarball; narHash = \"$hash\"; })) ? submodules)" >&2 + nix-instantiate --strict --eval -E "!((import (fetchTree { type = \"tarball\"; url = file://$tarball; narHash = \"$hash\"; })) ? submodules)" 2>&1 | grep 'true' nix-instantiate --eval -E '1 + 2' -I fnord=file://no-such-tarball.tar$ext nix-instantiate --eval -E 'with <fnord/xyzzy>; 1 + 2' -I fnord=file://no-such-tarball$ext (! nix-instantiate --eval -E '<fnord/xyzzy> 1' -I fnord=file://no-such-tarball$ext) nix-instantiate --eval -E '<fnord/config.nix>' -I fnord=file://no-such-tarball$ext -I fnord=. + + # Ensure that the `name` attribute isn’t accepted as that would mess + # with the content-addressing + (! nix-instantiate --eval -E "fetchTree { type = \"tarball\"; url = file://$tarball; narHash = \"$hash\"; name = \"foo\"; }") + } test_tarball '' cat diff --git a/tests/timeout.sh b/tests/timeout.sh index eea9b5731..e3fb3ebcc 100644 --- a/tests/timeout.sh +++ b/tests/timeout.sh @@ -2,6 +2,8 @@ source common.sh +# XXX: This shouldn’t be, but #4813 cause this test to fail +needLocalStore "see #4813" set +e messages=$(nix-build -Q timeout.nix -A infiniteLoop --timeout 2 2>&1) diff --git a/tests/user-envs.nix b/tests/user-envs.nix index 1aa410cc9..43eff1a68 100644 --- a/tests/user-envs.nix +++ b/tests/user-envs.nix @@ -13,7 +13,7 @@ let builder = ./user-envs.builder.sh; } // { meta = { - description = "A silly test package"; + description = "A silly test package with some \${escaped anti-quotation} in it"; }; }); diff --git a/tests/zstd.sh b/tests/zstd.sh new file mode 100644 index 000000000..ba7c20501 --- /dev/null +++ b/tests/zstd.sh @@ -0,0 +1,28 @@ +source common.sh + +clearStore +clearCache + +cacheURI="file://$cacheDir?compression=zstd" + +outPath=$(nix-build dependencies.nix --no-out-link) + +nix copy --to $cacheURI $outPath + +HASH=$(nix hash path $outPath) + +clearStore +clearCacheCache + +nix copy --from $cacheURI $outPath --no-check-sigs + +if ls $cacheDir/nar/*.zst &> /dev/null; then + echo "files do exist" +else + echo "nars do not exist" + exit 1 +fi + +HASH2=$(nix hash path $outPath) + +[[ $HASH = $HASH2 ]] |