diff options
Diffstat (limited to 'third_party/nix/tests')
101 files changed, 4014 insertions, 0 deletions
diff --git a/third_party/nix/tests/add.sh b/third_party/nix/tests/add.sh new file mode 100644 index 000000000000..e26e05843d7f --- /dev/null +++ b/third_party/nix/tests/add.sh @@ -0,0 +1,28 @@ +source common.sh + +path1=$(nix-store --add ./dummy) +echo $path1 + +path2=$(nix-store --add-fixed sha256 --recursive ./dummy) +echo $path2 + +if test "$path1" != "$path2"; then + echo "nix-store --add and --add-fixed mismatch" + exit 1 +fi + +path3=$(nix-store --add-fixed sha256 ./dummy) +echo $path3 +test "$path1" != "$path3" || exit 1 + +path4=$(nix-store --add-fixed sha1 --recursive ./dummy) +echo $path4 +test "$path1" != "$path4" || exit 1 + +hash1=$(nix-store -q --hash $path1) +echo $hash1 + +hash2=$(nix-hash --type sha256 --base32 ./dummy) +echo $hash2 + +test "$hash1" = "sha256:$hash2" diff --git a/third_party/nix/tests/binary-cache.sh b/third_party/nix/tests/binary-cache.sh new file mode 100644 index 000000000000..eb58ae7c12a8 --- /dev/null +++ b/third_party/nix/tests/binary-cache.sh @@ -0,0 +1,170 @@ +source common.sh + +clearStore +clearCache + +# Create the binary cache. +outPath=$(nix-build dependencies.nix --no-out-link) + +nix copy --to file://$cacheDir $outPath + + +basicTests() { + + # By default, a binary cache doesn't support "nix-env -qas", but does + # support installation. + clearStore + clearCacheCache + + nix-env --substituters "file://$cacheDir" -f dependencies.nix -qas \* | grep -- "---" + + nix-store --substituters "file://$cacheDir" --no-require-sigs -r $outPath + + [ -x $outPath/program ] + + + # But with the right configuration, "nix-env -qas" should also work. + clearStore + clearCacheCache + echo "WantMassQuery: 1" >> $cacheDir/nix-cache-info + + nix-env --substituters "file://$cacheDir" -f dependencies.nix -qas \* | grep -- "--S" + nix-env --substituters "file://$cacheDir" -f dependencies.nix -qas \* | grep -- "--S" + + x=$(nix-env -f dependencies.nix -qas \* --prebuilt-only) + [ -z "$x" ] + + nix-store --substituters "file://$cacheDir" --no-require-sigs -r $outPath + + nix-store --check-validity $outPath + nix-store -qR $outPath | grep input-2 + + echo "WantMassQuery: 0" >> $cacheDir/nix-cache-info +} + + +# Test LocalBinaryCacheStore. +basicTests + + +# Test HttpBinaryCacheStore. +export _NIX_FORCE_HTTP_BINARY_CACHE_STORE=1 +basicTests + + +# Test whether Nix notices if the NAR doesn't match the hash in the NAR info. +clearStore + +nar=$(ls $cacheDir/nar/*.nar.xz | head -n1) +mv $nar $nar.good +mkdir -p $TEST_ROOT/empty +nix-store --dump $TEST_ROOT/empty | xz > $nar + +nix-build --substituters "file://$cacheDir" --no-require-sigs dependencies.nix -o $TEST_ROOT/result 2>&1 | tee $TEST_ROOT/log +grep -q "hash mismatch" $TEST_ROOT/log + +mv $nar.good $nar + + +# Test whether this unsigned cache is rejected if the user requires signed caches. +clearStore +clearCacheCache + +if nix-store --substituters "file://$cacheDir" -r $outPath; then + echo "unsigned binary cache incorrectly accepted" + exit 1 +fi + + +# Test whether fallback works if a NAR has disappeared. This does not require --fallback. +clearStore + +mv $cacheDir/nar $cacheDir/nar2 + +nix-build --substituters "file://$cacheDir" --no-require-sigs dependencies.nix -o $TEST_ROOT/result + +mv $cacheDir/nar2 $cacheDir/nar + + +# Test whether fallback works if a NAR is corrupted. This does require --fallback. +clearStore + +mv $cacheDir/nar $cacheDir/nar2 +mkdir $cacheDir/nar +for i in $(cd $cacheDir/nar2 && echo *); do touch $cacheDir/nar/$i; done + +(! nix-build --substituters "file://$cacheDir" --no-require-sigs dependencies.nix -o $TEST_ROOT/result) + +nix-build --substituters "file://$cacheDir" --no-require-sigs dependencies.nix -o $TEST_ROOT/result --fallback + +rm -rf $cacheDir/nar +mv $cacheDir/nar2 $cacheDir/nar + + +# Test whether building works if the binary cache contains an +# incomplete closure. +clearStore + +rm $(grep -l "StorePath:.*dependencies-input-2" $cacheDir/*.narinfo) + +nix-build --substituters "file://$cacheDir" --no-require-sigs dependencies.nix -o $TEST_ROOT/result 2>&1 | tee $TEST_ROOT/log +grep -q "copying path" $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)" + +res=($(nix-store --generate-binary-cache-key test.nixos.org-1 $TEST_ROOT/sk2 $TEST_ROOT/pk2)) +badKey="$(cat $TEST_ROOT/pk2)" + +res=($(nix-store --generate-binary-cache-key foo.nixos.org-1 $TEST_ROOT/sk3 $TEST_ROOT/pk3)) +otherKey="$(cat $TEST_ROOT/pk3)" + +_NIX_FORCE_HTTP_BINARY_CACHE_STORE= nix copy --to file://$cacheDir?secret-key=$TEST_ROOT/sk1 $outPath + + +# Downloading should fail if we don't provide a key. +clearStore +clearCacheCache + +(! nix-store -r $outPath --substituters "file://$cacheDir") + + +# And it should fail if we provide an incorrect key. +clearStore +clearCacheCache + +(! nix-store -r $outPath --substituters "file://$cacheDir" --trusted-public-keys "$badKey") + + +# It should succeed if we provide the correct key. +nix-store -r $outPath --substituters "file://$cacheDir" --trusted-public-keys "$otherKey $publicKey" + + +# It should fail if we corrupt the .narinfo. +clearStore + +cacheDir2=$TEST_ROOT/binary-cache-2 +rm -rf $cacheDir2 +cp -r $cacheDir $cacheDir2 + +for i in $cacheDir2/*.narinfo; do + grep -v References $i > $i.tmp + mv $i.tmp $i +done + +clearCacheCache + +(! nix-store -r $outPath --substituters "file://$cacheDir2" --trusted-public-keys "$publicKey") + +# If we provide a bad and a good binary cache, it should succeed. + +nix-store -r $outPath --substituters "file://$cacheDir2 file://$cacheDir" --trusted-public-keys "$publicKey" + +fi # HAVE_LIBSODIUM diff --git a/third_party/nix/tests/brotli.sh b/third_party/nix/tests/brotli.sh new file mode 100644 index 000000000000..a3c6e55a8fad --- /dev/null +++ b/third_party/nix/tests/brotli.sh @@ -0,0 +1,21 @@ +source common.sh + +clearStore +clearCache + +cacheURI="file://$cacheDir?compression=br" + +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 + +HASH2=$(nix hash-path $outPath) + +[[ $HASH = $HASH2 ]] diff --git a/third_party/nix/tests/build-dry.sh b/third_party/nix/tests/build-dry.sh new file mode 100644 index 000000000000..e72533e70614 --- /dev/null +++ b/third_party/nix/tests/build-dry.sh @@ -0,0 +1,52 @@ +source common.sh + +################################################### +# Check that --dry-run isn't confused with read-only mode +# https://github.com/NixOS/nix/issues/1795 + +clearStore +clearCache + +# Ensure this builds successfully first +nix build --no-link -f dependencies.nix + +clearStore +clearCache + +# Try --dry-run using old command first +nix-build --no-out-link dependencies.nix --dry-run 2>&1 | grep "will be built" +# Now new command: +nix build -f dependencies.nix --dry-run 2>&1 | grep "will be built" + +# TODO: XXX: FIXME: #1793 +# Disable this part of the test until the problem is resolved: +if [ -n "$ISSUE_1795_IS_FIXED" ]; then +clearStore +clearCache + +# Try --dry-run using new command first +nix build -f dependencies.nix --dry-run 2>&1 | grep "will be built" +# Now old command: +nix-build --no-out-link dependencies.nix --dry-run 2>&1 | grep "will be built" +fi + +################################################### +# Check --dry-run doesn't create links with --dry-run +# https://github.com/NixOS/nix/issues/1849 +clearStore +clearCache + +RESULT=$TEST_ROOT/result-link +rm -f $RESULT + +nix-build dependencies.nix -o $RESULT --dry-run + +[[ ! -h $RESULT ]] || fail "nix-build --dry-run created output link" + +nix build -f dependencies.nix -o $RESULT --dry-run + +[[ ! -h $RESULT ]] || fail "nix build --dry-run created output link" + +nix build -f dependencies.nix -o $RESULT + +[[ -h $RESULT ]] diff --git a/third_party/nix/tests/build-hook.nix b/third_party/nix/tests/build-hook.nix new file mode 100644 index 000000000000..8bff0fe79032 --- /dev/null +++ b/third_party/nix/tests/build-hook.nix @@ -0,0 +1,23 @@ +with import ./config.nix; + +let + + input1 = mkDerivation { + name = "build-hook-input-1"; + builder = ./dependencies.builder1.sh; + requiredSystemFeatures = ["foo"]; + }; + + input2 = mkDerivation { + name = "build-hook-input-2"; + builder = ./dependencies.builder2.sh; + }; + +in + + mkDerivation { + name = "build-hook"; + builder = ./dependencies.builder0.sh; + input1 = " " + input1 + "/."; + input2 = " ${input2}/."; + } diff --git a/third_party/nix/tests/build-remote.sh b/third_party/nix/tests/build-remote.sh new file mode 100644 index 000000000000..ddd68f327a15 --- /dev/null +++ b/third_party/nix/tests/build-remote.sh @@ -0,0 +1,24 @@ +source common.sh + +clearStore + +if ! canUseSandbox; then exit; fi +if [[ ! $SHELL =~ /nix/store ]]; then exit; fi + +chmod -R u+w $TEST_ROOT/store0 || true +chmod -R u+w $TEST_ROOT/store1 || true +rm -rf $TEST_ROOT/store0 $TEST_ROOT/store1 + +nix build -f build-hook.nix -o $TEST_ROOT/result --max-jobs 0 \ + --sandbox-paths /nix/store --sandbox-build-dir /build-tmp \ + --builders "$TEST_ROOT/store0; $TEST_ROOT/store1 - - 1 1 foo" \ + --system-features foo + +outPath=$TEST_ROOT/result + +cat $outPath/foobar | grep FOOBAR + +# Ensure that input1 was built on store1 due to the required feature. +p=$(readlink -f $outPath/input-2) +(! nix path-info --store $TEST_ROOT/store0 --all | grep dependencies.builder1.sh) +nix path-info --store $TEST_ROOT/store1 --all | grep dependencies.builder1.sh diff --git a/third_party/nix/tests/case-hack.sh b/third_party/nix/tests/case-hack.sh new file mode 100644 index 000000000000..61bf9b94bf5c --- /dev/null +++ b/third_party/nix/tests/case-hack.sh @@ -0,0 +1,19 @@ +source common.sh + +clearStore + +rm -rf $TEST_ROOT/case + +opts="--option use-case-hack true" + +# Check whether restoring and dumping a NAR that contains case +# collisions is round-tripping, even on a case-insensitive system. +nix-store $opts --restore $TEST_ROOT/case < case.nar +nix-store $opts --dump $TEST_ROOT/case > $TEST_ROOT/case.nar +cmp case.nar $TEST_ROOT/case.nar +[ "$(nix-hash $opts --type sha256 $TEST_ROOT/case)" = "$(nix-hash --flat --type sha256 case.nar)" ] + +# Check whether we detect true collisions (e.g. those remaining after +# removal of the suffix). +touch "$TEST_ROOT/case/xt_CONNMARK.h~nix~case~hack~3" +(! nix-store $opts --dump $TEST_ROOT/case > /dev/null) diff --git a/third_party/nix/tests/case.nar b/third_party/nix/tests/case.nar new file mode 100644 index 000000000000..22ff26db5afd --- /dev/null +++ b/third_party/nix/tests/case.nar Binary files differdiff --git a/third_party/nix/tests/check-refs.nix b/third_party/nix/tests/check-refs.nix new file mode 100644 index 000000000000..9d90b0920542 --- /dev/null +++ b/third_party/nix/tests/check-refs.nix @@ -0,0 +1,70 @@ +with import ./config.nix; + +rec { + + dep = import ./dependencies.nix; + + makeTest = nr: args: mkDerivation ({ + name = "check-refs-" + toString nr; + } // args); + + src = builtins.toFile "aux-ref" "bla bla"; + + test1 = makeTest 1 { + builder = builtins.toFile "builder.sh" "mkdir $out; ln -s $dep $out/link"; + inherit dep; + }; + + test2 = makeTest 2 { + builder = builtins.toFile "builder.sh" "mkdir $out; ln -s ${src} $out/link"; + inherit dep; + }; + + test3 = makeTest 3 { + builder = builtins.toFile "builder.sh" "mkdir $out; ln -s $dep $out/link"; + allowedReferences = []; + inherit dep; + }; + + test4 = makeTest 4 { + builder = builtins.toFile "builder.sh" "mkdir $out; ln -s $dep $out/link"; + allowedReferences = [dep]; + inherit dep; + }; + + test5 = makeTest 5 { + builder = builtins.toFile "builder.sh" "mkdir $out"; + allowedReferences = []; + inherit dep; + }; + + test6 = makeTest 6 { + builder = builtins.toFile "builder.sh" "mkdir $out; ln -s $out $out/link"; + allowedReferences = []; + inherit dep; + }; + + test7 = makeTest 7 { + builder = builtins.toFile "builder.sh" "mkdir $out; ln -s $out $out/link"; + allowedReferences = ["out"]; + inherit dep; + }; + + test8 = makeTest 8 { + builder = builtins.toFile "builder.sh" "mkdir $out; ln -s ${test1} $out/link"; + inherit dep; + }; + + test9 = makeTest 9 { + builder = builtins.toFile "builder.sh" "mkdir $out; ln -s $dep $out/link"; + inherit dep; + disallowedReferences = [dep]; + }; + + test10 = makeTest 10 { + builder = builtins.toFile "builder.sh" "mkdir $out; echo $test5; ln -s $dep $out/link"; + inherit dep test5; + disallowedReferences = [test5]; + }; + +} diff --git a/third_party/nix/tests/check-refs.sh b/third_party/nix/tests/check-refs.sh new file mode 100644 index 000000000000..16bbabc40985 --- /dev/null +++ b/third_party/nix/tests/check-refs.sh @@ -0,0 +1,42 @@ +source common.sh + +clearStore + +RESULT=$TEST_ROOT/result + +dep=$(nix-build -o $RESULT check-refs.nix -A dep) + +# test1 references dep, not itself. +test1=$(nix-build -o $RESULT check-refs.nix -A test1) +(! nix-store -q --references $test1 | grep -q $test1) +nix-store -q --references $test1 | grep -q $dep + +# test2 references src, not itself nor dep. +test2=$(nix-build -o $RESULT check-refs.nix -A test2) +(! nix-store -q --references $test2 | grep -q $test2) +(! nix-store -q --references $test2 | grep -q $dep) +nix-store -q --references $test2 | grep -q aux-ref + +# test3 should fail (unallowed ref). +(! nix-build -o $RESULT check-refs.nix -A test3) + +# test4 should succeed. +nix-build -o $RESULT check-refs.nix -A test4 + +# test5 should succeed. +nix-build -o $RESULT check-refs.nix -A test5 + +# test6 should fail (unallowed self-ref). +(! nix-build -o $RESULT check-refs.nix -A test6) + +# test7 should succeed (allowed self-ref). +nix-build -o $RESULT check-refs.nix -A test7 + +# test8 should fail (toFile depending on derivation output). +(! nix-build -o $RESULT check-refs.nix -A test8) + +# test9 should fail (disallowed reference). +(! nix-build -o $RESULT check-refs.nix -A test9) + +# test10 should succeed (no disallowed references). +nix-build -o $RESULT check-refs.nix -A test10 diff --git a/third_party/nix/tests/check-reqs.nix b/third_party/nix/tests/check-reqs.nix new file mode 100644 index 000000000000..41436cb48e08 --- /dev/null +++ b/third_party/nix/tests/check-reqs.nix @@ -0,0 +1,57 @@ +with import ./config.nix; + +rec { + dep1 = mkDerivation { + name = "check-reqs-dep1"; + builder = builtins.toFile "builder.sh" "mkdir $out; touch $out/file1"; + }; + + dep2 = mkDerivation { + name = "check-reqs-dep2"; + builder = builtins.toFile "builder.sh" "mkdir $out; touch $out/file2"; + }; + + deps = mkDerivation { + name = "check-reqs-deps"; + dep1 = dep1; + dep2 = dep2; + builder = builtins.toFile "builder.sh" '' + mkdir $out + ln -s $dep1/file1 $out/file1 + ln -s $dep2/file2 $out/file2 + ''; + }; + + makeTest = nr: allowreqs: mkDerivation { + name = "check-reqs-" + toString nr; + inherit deps; + builder = builtins.toFile "builder.sh" '' + mkdir $out + ln -s $deps $out/depdir1 + ''; + allowedRequisites = allowreqs; + }; + + # When specifying all the requisites, the build succeeds. + test1 = makeTest 1 [ dep1 dep2 deps ]; + + # But missing anything it fails. + test2 = makeTest 2 [ dep2 deps ]; + test3 = makeTest 3 [ dep1 deps ]; + test4 = makeTest 4 [ deps ]; + test5 = makeTest 5 []; + + test6 = mkDerivation { + name = "check-reqs"; + inherit deps; + builder = builtins.toFile "builder.sh" "mkdir $out; ln -s $deps $out/depdir1"; + disallowedRequisites = [dep1]; + }; + + test7 = mkDerivation { + name = "check-reqs"; + inherit deps; + builder = builtins.toFile "builder.sh" "mkdir $out; ln -s $deps $out/depdir1"; + disallowedRequisites = [test1]; + }; +} diff --git a/third_party/nix/tests/check-reqs.sh b/third_party/nix/tests/check-reqs.sh new file mode 100644 index 000000000000..e9f65fc2a6d3 --- /dev/null +++ b/third_party/nix/tests/check-reqs.sh @@ -0,0 +1,16 @@ +source common.sh + +clearStore + +RESULT=$TEST_ROOT/result + +nix-build -o $RESULT check-reqs.nix -A test1 + +(! nix-build -o $RESULT check-reqs.nix -A test2) +(! nix-build -o $RESULT check-reqs.nix -A test3) +(! nix-build -o $RESULT check-reqs.nix -A test4) 2>&1 | grep -q 'check-reqs-dep1' +(! nix-build -o $RESULT check-reqs.nix -A test4) 2>&1 | grep -q 'check-reqs-dep2' +(! nix-build -o $RESULT check-reqs.nix -A test5) +(! nix-build -o $RESULT check-reqs.nix -A test6) + +nix-build -o $RESULT check-reqs.nix -A test7 diff --git a/third_party/nix/tests/check.nix b/third_party/nix/tests/check.nix new file mode 100644 index 000000000000..56c82e565a8f --- /dev/null +++ b/third_party/nix/tests/check.nix @@ -0,0 +1,22 @@ +with import ./config.nix; + +{ + nondeterministic = mkDerivation { + name = "nondeterministic"; + buildCommand = + '' + mkdir $out + date +%s.%N > $out/date + ''; + }; + + hashmismatch = import <nix/fetchurl.nix> { + url = "file://" + toString ./dummy; + sha256 = "0mdqa9w1p6cmli6976v4wi0sw9r4p5prkj7lzfd1877wk11c9c73"; + }; + + fetchurl = import <nix/fetchurl.nix> { + url = "file://" + toString ./lang/eval-okay-xml.exp.xml; + sha256 = "0kg4sla7ihm8ijr8cb3117fhl99zrc2bwy1jrngsfmkh8bav4m0v"; + }; +} diff --git a/third_party/nix/tests/check.sh b/third_party/nix/tests/check.sh new file mode 100644 index 000000000000..bc23a6634ca0 --- /dev/null +++ b/third_party/nix/tests/check.sh @@ -0,0 +1,47 @@ +source common.sh + +clearStore + +nix-build dependencies.nix --no-out-link +nix-build dependencies.nix --no-out-link --check + +nix-build check.nix -A nondeterministic --no-out-link +nix-build check.nix -A nondeterministic --no-out-link --check 2> $TEST_ROOT/log || status=$? +grep 'may not be deterministic' $TEST_ROOT/log +[ "$status" = "104" ] + +clearStore + +nix-build dependencies.nix --no-out-link --repeat 3 + +nix-build check.nix -A nondeterministic --no-out-link --repeat 1 2> $TEST_ROOT/log || status=$? +[ "$status" = "1" ] +grep 'differs from previous round' $TEST_ROOT/log + +path=$(nix-build check.nix -A fetchurl --no-out-link --hashed-mirrors '') + +chmod +w $path +echo foo > $path +chmod -w $path + +nix-build check.nix -A fetchurl --no-out-link --check --hashed-mirrors '' +# 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 '' +[[ $(cat $path) != foo ]] + +nix-build check.nix -A hashmismatch --no-out-link --hashed-mirrors '' || status=$? +[ "$status" = "102" ] + +echo -n > ./dummy +nix-build check.nix -A hashmismatch --no-out-link --hashed-mirrors '' +echo 'Hello World' > ./dummy + +nix-build check.nix -A hashmismatch --no-out-link --check --hashed-mirrors '' || 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=$? +[ "$status" = "110" ] diff --git a/third_party/nix/tests/common.sh.in b/third_party/nix/tests/common.sh.in new file mode 100644 index 000000000000..15d7b1ef9119 --- /dev/null +++ b/third_party/nix/tests/common.sh.in @@ -0,0 +1,118 @@ +set -e + +export TEST_ROOT=$(realpath ${TMPDIR:-/tmp}/nix-test) +export NIX_STORE_DIR +if ! NIX_STORE_DIR=$(readlink -f $TEST_ROOT/store 2> /dev/null); then + # Maybe the build directory is symlinked. + export NIX_IGNORE_SYMLINK_STORE=1 + NIX_STORE_DIR=$TEST_ROOT/store +fi +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_TEST_SHARED=$TEST_ROOT/shared +if [[ -n $NIX_STORE ]]; then + export _NIX_TEST_NO_SANDBOX=1 +fi +export _NIX_IN_TEST=$TEST_ROOT/shared +export _NIX_TEST_NO_LSOF=1 +export NIX_REMOTE=$NIX_REMOTE_ +unset NIX_PATH +export TEST_HOME=$TEST_ROOT/test-home +export HOME=$TEST_HOME +unset XDG_CACHE_HOME +mkdir -p $TEST_HOME + +export PATH=@bindir@:$PATH +coreutils=@coreutils@ + +export dot=@dot@ +export xmllint="@xmllint@" +export SHELL="@bash@" +export PAGER=cat +export HAVE_SODIUM="@HAVE_SODIUM@" + +export version=@PACKAGE_VERSION@ +export system=@system@ + +cacheDir=$TEST_ROOT/binary-cache + +readLink() { + ls -l "$1" | sed 's/.*->\ //' +} + +clearProfiles() { + profiles="$NIX_STATE_DIR"/profiles + rm -rf $profiles +} + +clearStore() { + echo "clearing store..." + chmod -R +w "$NIX_STORE_DIR" + rm -rf "$NIX_STORE_DIR" + mkdir "$NIX_STORE_DIR" + rm -rf "$NIX_STATE_DIR" + mkdir "$NIX_STATE_DIR" + nix-store --init + clearProfiles +} + +clearCache() { + rm -rf "$cacheDir" +} + +clearCacheCache() { + rm -f $TEST_HOME/.cache/nix/binary-cache* +} + +startDaemon() { + # 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 & + for ((i = 0; i < 30; i++)); do + if [ -e $NIX_STATE_DIR/daemon-socket/socket ]; then break; fi + sleep 1 + done + pidDaemon=$! + trap "kill -9 $pidDaemon" EXIT + export NIX_REMOTE=daemon +} + +killDaemon() { + kill -9 $pidDaemon + wait $pidDaemon || true + trap "" EXIT +} + +if [[ $(uname) == Linux ]] && [[ -L /proc/self/ns/user ]] && unshare --user true; then + _canUseSandbox=1 +fi + +canUseSandbox() { + if [[ ! $_canUseSandbox ]]; then + echo "Sandboxing not supported, skipping this test..." + return 1 + fi + + return 0 +} + +fail() { + echo "$1" + exit 1 +} + +expect() { + local expected res + expected="$1" + shift + set +e + "$@" + res="$?" + set -e + [[ $res -eq $expected ]] +} + +set -x diff --git a/third_party/nix/tests/config.nix b/third_party/nix/tests/config.nix new file mode 100644 index 000000000000..6ba91065b83d --- /dev/null +++ b/third_party/nix/tests/config.nix @@ -0,0 +1,20 @@ +with import <nix/config.nix>; + +rec { + inherit shell; + + path = coreutils; + + system = builtins.currentSystem; + + shared = builtins.getEnv "_NIX_TEST_SHARED"; + + mkDerivation = args: + derivation ({ + inherit system; + builder = shell; + args = ["-e" args.builder or (builtins.toFile "builder.sh" "if [ -e .attrs.sh ]; then source .attrs.sh; fi; eval \"$buildCommand\"")]; + PATH = path; + } // removeAttrs args ["builder" "meta"]) + // { meta = args.meta or {}; }; +} diff --git a/third_party/nix/tests/dependencies.builder0.sh b/third_party/nix/tests/dependencies.builder0.sh new file mode 100644 index 000000000000..c37bf909a5f9 --- /dev/null +++ b/third_party/nix/tests/dependencies.builder0.sh @@ -0,0 +1,16 @@ +[ "${input1: -2}" = /. ] +[ "${input2: -2}" = /. ] + +mkdir $out +echo $(cat $input1/foo)$(cat $input2/bar) > $out/foobar + +ln -s $input2 $out/input-2 + +# Self-reference. +ln -s $out $out/self + +# Executable. +echo program > $out/program +chmod +x $out/program + +echo FOO diff --git a/third_party/nix/tests/dependencies.builder1.sh b/third_party/nix/tests/dependencies.builder1.sh new file mode 100644 index 000000000000..4b006a17d70f --- /dev/null +++ b/third_party/nix/tests/dependencies.builder1.sh @@ -0,0 +1,2 @@ +mkdir $out +echo FOO > $out/foo diff --git a/third_party/nix/tests/dependencies.builder2.sh b/third_party/nix/tests/dependencies.builder2.sh new file mode 100644 index 000000000000..4f886fdb3a1a --- /dev/null +++ b/third_party/nix/tests/dependencies.builder2.sh @@ -0,0 +1,2 @@ +mkdir $out +echo BAR > $out/bar diff --git a/third_party/nix/tests/dependencies.nix b/third_party/nix/tests/dependencies.nix new file mode 100644 index 000000000000..eca4b2964cfb --- /dev/null +++ b/third_party/nix/tests/dependencies.nix @@ -0,0 +1,24 @@ +with import ./config.nix; + +let { + + input1 = mkDerivation { + name = "dependencies-input-1"; + builder = ./dependencies.builder1.sh; + }; + + input2 = mkDerivation { + name = "dependencies-input-2"; + builder = "${./dependencies.builder2.sh}"; + }; + + body = mkDerivation { + name = "dependencies"; + builder = ./dependencies.builder0.sh + "/FOOBAR/../."; + input1 = input1 + "/."; + input2 = "${input2}/."; + input1_drv = input1; + meta.description = "Random test package"; + }; + +} diff --git a/third_party/nix/tests/dependencies.sh b/third_party/nix/tests/dependencies.sh new file mode 100644 index 000000000000..df204d185ddc --- /dev/null +++ b/third_party/nix/tests/dependencies.sh @@ -0,0 +1,52 @@ +source common.sh + +clearStore + +drvPath=$(nix-instantiate dependencies.nix) + +echo "derivation is $drvPath" + +nix-store -q --tree "$drvPath" | grep ' +---.*builder1.sh' + +# Test Graphviz graph generation. +nix-store -q --graph "$drvPath" > $TEST_ROOT/graph +if test -n "$dot"; then + # Does it parse? + $dot < $TEST_ROOT/graph +fi + +outPath=$(nix-store -rvv "$drvPath") || fail "build failed" + +# Test Graphviz graph generation. +nix-store -q --graph "$outPath" > $TEST_ROOT/graph +if test -n "$dot"; then + # Does it parse? + $dot < $TEST_ROOT/graph +fi + +nix-store -q --tree "$outPath" | grep '+---.*dependencies-input-2' + +echo "output path is $outPath" + +text=$(cat "$outPath"/foobar) +if test "$text" != "FOOBAR"; then exit 1; fi + +deps=$(nix-store -quR "$drvPath") + +echo "output closure contains $deps" + +# The output path should be in the closure. +echo "$deps" | grep -q "$outPath" + +# Input-1 is not retained. +if echo "$deps" | grep -q "dependencies-input-1"; then exit 1; fi + +# Input-2 is retained. +input2OutPath=$(echo "$deps" | grep "dependencies-input-2") + +# The referrers closure of input-2 should include outPath. +nix-store -q --referrers-closure "$input2OutPath" | grep "$outPath" + +# Check that the derivers are set properly. +test $(nix-store -q --deriver "$outPath") = "$drvPath" +nix-store -q --deriver "$input2OutPath" | grep -q -- "-input-2.drv" diff --git a/third_party/nix/tests/dump-db.sh b/third_party/nix/tests/dump-db.sh new file mode 100644 index 000000000000..d6eea42aa04e --- /dev/null +++ b/third_party/nix/tests/dump-db.sh @@ -0,0 +1,20 @@ +source common.sh + +clearStore + +path=$(nix-build dependencies.nix -o $TEST_ROOT/result) + +deps="$(nix-store -qR $TEST_ROOT/result)" + +nix-store --dump-db > $TEST_ROOT/dump + +rm -rf $NIX_STATE_DIR/db + +nix-store --load-db < $TEST_ROOT/dump + +deps2="$(nix-store -qR $TEST_ROOT/result)" + +[ "$deps" = "$deps2" ]; + +nix-store --dump-db > $TEST_ROOT/dump2 +cmp $TEST_ROOT/dump $TEST_ROOT/dump2 diff --git a/third_party/nix/tests/export-graph.nix b/third_party/nix/tests/export-graph.nix new file mode 100644 index 000000000000..fdac9583db2c --- /dev/null +++ b/third_party/nix/tests/export-graph.nix @@ -0,0 +1,29 @@ +with import ./config.nix; + +rec { + + printRefs = + '' + echo $exportReferencesGraph + while read path; do + read drv + read nrRefs + echo "$path has $nrRefs references" + echo "$path" >> $out + for ((n = 0; n < $nrRefs; n++)); do read ref; echo "ref $ref"; test -e "$ref"; done + done < refs + ''; + + foo."bar.runtimeGraph" = mkDerivation { + name = "dependencies"; + builder = builtins.toFile "build-graph-builder" "${printRefs}"; + exportReferencesGraph = ["refs" (import ./dependencies.nix)]; + }; + + foo."bar.buildGraph" = mkDerivation { + name = "dependencies"; + builder = builtins.toFile "build-graph-builder" "${printRefs}"; + exportReferencesGraph = ["refs" (import ./dependencies.nix).drvPath]; + }; + +} diff --git a/third_party/nix/tests/export-graph.sh b/third_party/nix/tests/export-graph.sh new file mode 100644 index 000000000000..a6fd69054425 --- /dev/null +++ b/third_party/nix/tests/export-graph.sh @@ -0,0 +1,30 @@ +source common.sh + +clearStore +clearProfiles + +checkRef() { + nix-store -q --references $TEST_ROOT/result | grep -q "$1" || fail "missing reference $1" +} + +# Test the export of the runtime dependency graph. + +outPath=$(nix-build ./export-graph.nix -A 'foo."bar.runtimeGraph"' -o $TEST_ROOT/result) + +test $(nix-store -q --references $TEST_ROOT/result | wc -l) = 2 || fail "bad nr of references" + +checkRef input-2 +for i in $(cat $outPath); do checkRef $i; done + +# Test the export of the build-time dependency graph. + +nix-store --gc # should force rebuild of input-1 + +outPath=$(nix-build ./export-graph.nix -A 'foo."bar.buildGraph"' -o $TEST_ROOT/result) + +checkRef input-1 +checkRef input-1.drv +checkRef input-2 +checkRef input-2.drv + +for i in $(cat $outPath); do checkRef $i; done diff --git a/third_party/nix/tests/export.sh b/third_party/nix/tests/export.sh new file mode 100644 index 000000000000..2238539bcca9 --- /dev/null +++ b/third_party/nix/tests/export.sh @@ -0,0 +1,36 @@ +source common.sh + +clearStore + +outPath=$(nix-build dependencies.nix --no-out-link) + +nix-store --export $outPath > $TEST_ROOT/exp + +nix-store --export $(nix-store -qR $outPath) > $TEST_ROOT/exp_all + +if nix-store --export $outPath >/dev/full ; then + echo "exporting to a bad file descriptor should fail" + exit 1 +fi + + +clearStore + +if nix-store --import < $TEST_ROOT/exp; then + echo "importing a non-closure should fail" + exit 1 +fi + + +clearStore + +nix-store --import < $TEST_ROOT/exp_all + +nix-store --export $(nix-store -qR $outPath) > $TEST_ROOT/exp_all2 + + +clearStore + +# Regression test: the derivers in exp_all2 are empty, which shouldn't +# cause a failure. +nix-store --import < $TEST_ROOT/exp_all2 diff --git a/third_party/nix/tests/fetchGit.sh b/third_party/nix/tests/fetchGit.sh new file mode 100644 index 000000000000..4c46bdf0465b --- /dev/null +++ b/third_party/nix/tests/fetchGit.sh @@ -0,0 +1,141 @@ +source common.sh + +if [[ -z $(type -p git) ]]; then + echo "Git not installed; skipping Git tests" + exit 99 +fi + +clearStore + +repo=$TEST_ROOT/git + +rm -rf $repo ${repo}-tmp $TEST_HOME/.cache/nix/gitv2 + +git init $repo +git -C $repo config user.email "foobar@example.com" +git -C $repo config user.name "Foobar" + +echo utrecht > $repo/hello +touch $repo/.gitignore +git -C $repo add hello .gitignore +git -C $repo commit -m 'Bla1' +rev1=$(git -C $repo rev-parse HEAD) + +echo world > $repo/hello +git -C $repo commit -m 'Bla2' -a +rev2=$(git -C $repo rev-parse HEAD) + +# Fetch the default branch. +path=$(nix eval --raw "(builtins.fetchGit file://$repo).outPath") +[[ $(cat $path/hello) = world ]] + +# 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\"))") + +# Fetch using an explicit revision hash. +path2=$(nix eval --raw "(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 ]] + +# Fetch again. This should be cached. +mv $repo ${repo}-tmp +path2=$(nix eval --raw "(builtins.fetchGit file://$repo).outPath") +[[ $path = $path2 ]] + +[[ $(nix eval "(builtins.fetchGit file://$repo).revCount") = 2 ]] +[[ $(nix eval --raw "(builtins.fetchGit file://$repo).rev") = $rev2 ]] + +# But with TTL 0, it should fail. +(! nix eval --tarball-ttl 0 "(builtins.fetchGit file://$repo)" -vvvvv) + +# Fetching with a explicit hash should succeed. +path2=$(nix eval --tarball-ttl 0 --raw "(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") +[[ $(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") +[[ $path = $path2 ]] + +# Using an unclean tree should yield the tracked but uncommitted changes. +mkdir $repo/dir1 $repo/dir2 +echo foo > $repo/dir1/foo +echo bar > $repo/bar +echo bar > $repo/dir2/bar +git -C $repo add dir1/foo +git -C $repo rm hello + +path2=$(nix eval --raw "(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 ]] + +# ... unless we're using an explicit ref or rev. +path3=$(nix eval --raw "(builtins.fetchGit { url = $repo; ref = \"master\"; }).outPath") +[[ $path = $path3 ]] + +path3=$(nix eval --raw "(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") +[[ $path2 = $path4 ]] + +# 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 + +# Update 'path' to reflect latest master +path=$(nix eval --raw "(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 'master' unless specified otherwise +path2=$(nix eval --raw "(builtins.fetchGit file://$repo).outPath") +[[ $path = $path2 ]] + +# Using local path with branch other than 'master' should work when clean or dirty +path3=$(nix eval --raw "(builtins.fetchGit $repo).outPath") +# (check dirty-tree handling was used) +[[ $(nix eval --raw "(builtins.fetchGit $repo).rev") = 0000000000000000000000000000000000000000 ]] + +# 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") +[[ $(cat $path4/hello) = dev ]] +[[ $path3 = $path4 ]] + +# Confirm same as 'dev' branch +path5=$(nix eval --raw "(builtins.fetchGit { url = $repo; ref = \"dev\"; }).outPath") +[[ $path3 = $path5 ]] + + +# Nuke the cache +rm -rf $TEST_HOME/.cache/nix/gitv2 + +# Try again, but without 'git' on PATH +NIX=$(command -v nix) +# This should fail +(! PATH= $NIX eval --raw "(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") +[[ $path3 = $path5 ]] diff --git a/third_party/nix/tests/fetchMercurial.sh b/third_party/nix/tests/fetchMercurial.sh new file mode 100644 index 000000000000..4088dbd39796 --- /dev/null +++ b/third_party/nix/tests/fetchMercurial.sh @@ -0,0 +1,93 @@ +source common.sh + +if [[ -z $(type -p hg) ]]; then + echo "Mercurial not installed; skipping Mercurial tests" + exit 99 +fi + +clearStore + +repo=$TEST_ROOT/hg + +rm -rf $repo ${repo}-tmp $TEST_HOME/.cache/nix/hg + +hg init $repo +echo '[ui]' >> $repo/.hg/hgrc +echo 'username = Foobar <foobar@example.org>' >> $repo/.hg/hgrc + +echo utrecht > $repo/hello +touch $repo/.hgignore +hg add --cwd $repo hello .hgignore +hg commit --cwd $repo -m 'Bla1' +rev1=$(hg log --cwd $repo -r tip --template '{node}') + +echo world > $repo/hello +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") +[[ $(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\"))") + +# Fetch using an explicit revision hash. +path2=$(nix eval --raw "(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 ]] + +# Fetch again. This should be cached. +mv $repo ${repo}-tmp +path2=$(nix eval --raw "(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 ]] + +# But with TTL 0, it should fail. +(! nix eval --tarball-ttl 0 "(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") +[[ $path = $path2 ]] + +path2=$(nix eval --tarball-ttl 0 --raw "(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") +[[ $path = $path2 ]] + +# Using an unclean tree should yield the tracked but uncommitted changes. +mkdir $repo/dir1 $repo/dir2 +echo foo > $repo/dir1/foo +echo bar > $repo/bar +echo bar > $repo/dir2/bar +hg add --cwd $repo dir1/foo +hg rm --cwd $repo hello + +path2=$(nix eval --raw "(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 ]] + +# ... unless we're using an explicit rev. +path3=$(nix eval --raw "(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") +[[ $path2 = $path4 ]] diff --git a/third_party/nix/tests/fetchurl.sh b/third_party/nix/tests/fetchurl.sh new file mode 100644 index 000000000000..7319ced2b599 --- /dev/null +++ b/third_party/nix/tests/fetchurl.sh @@ -0,0 +1,78 @@ +source common.sh + +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 '') + +cmp $outPath fetchurl.sh + +# Now using a base-64 hash. +clearStore + +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 '') + +cmp $outPath fetchurl.sh + +# Now using an SRI hash. +clearStore + +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 '') + +cmp $outPath fetchurl.sh + +# Test the hashed mirror feature. +clearStore + +hash=$(nix hash-file --type sha512 --base64 ./fetchurl.sh) +hash32=$(nix hash-file --type sha512 --base16 ./fetchurl.sh) + +mirror=$TMPDIR/hashed-mirror +rm -rf $mirror +mkdir -p $mirror/sha512 +ln -s $(pwd)/fetchurl.sh $mirror/sha512/$hash32 + +outPath=$(nix-build '<nix/fetchurl.nix>' --argstr url file:///no-such-dir/fetchurl.sh --argstr sha512 $hash --no-out-link --hashed-mirrors "file://$mirror") + +# 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" + +# Test unpacking a NAR. +rm -rf $TEST_ROOT/archive +mkdir -p $TEST_ROOT/archive +cp ./fetchurl.sh $TEST_ROOT/archive +chmod +x $TEST_ROOT/archive/fetchurl.sh +ln -s foo $TEST_ROOT/archive/symlink +nar=$TEST_ROOT/archive.nar +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 \ + --arg unpack true --argstr name xyzzy --no-out-link) + +echo $outPath | grep -q 'xyzzy' + +test -x $outPath/fetchurl.sh +test -L $outPath/symlink + +nix-store --delete $outPath + +# Test unpacking a compressed NAR. +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 \ + --arg unpack true --argstr name xyzzy --no-out-link) + +test -x $outPath/fetchurl.sh +test -L $outPath/symlink diff --git a/third_party/nix/tests/filter-source.nix b/third_party/nix/tests/filter-source.nix new file mode 100644 index 000000000000..9071636394af --- /dev/null +++ b/third_party/nix/tests/filter-source.nix @@ -0,0 +1,12 @@ +with import ./config.nix; + +mkDerivation { + name = "filter"; + builder = builtins.toFile "builder" "ln -s $input $out"; + input = + let filter = path: type: + type != "symlink" + && baseNameOf path != "foo" + && !((import ./lang/lib.nix).hasSuffix ".bak" (baseNameOf path)); + in builtins.filterSource filter ((builtins.getEnv "TEST_ROOT") + "/filterin"); +} diff --git a/third_party/nix/tests/filter-source.sh b/third_party/nix/tests/filter-source.sh new file mode 100644 index 000000000000..1f8dceee5786 --- /dev/null +++ b/third_party/nix/tests/filter-source.sh @@ -0,0 +1,19 @@ +source common.sh + +rm -rf $TEST_ROOT/filterin +mkdir $TEST_ROOT/filterin +mkdir $TEST_ROOT/filterin/foo +touch $TEST_ROOT/filterin/foo/bar +touch $TEST_ROOT/filterin/xyzzy +touch $TEST_ROOT/filterin/b +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 + +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 diff --git a/third_party/nix/tests/fixed.builder1.sh b/third_party/nix/tests/fixed.builder1.sh new file mode 100644 index 000000000000..c41bb2b9a611 --- /dev/null +++ b/third_party/nix/tests/fixed.builder1.sh @@ -0,0 +1,3 @@ +if test "$IMPURE_VAR1" != "foo"; then exit 1; fi +if test "$IMPURE_VAR2" != "bar"; then exit 1; fi +echo "Hello World!" > $out diff --git a/third_party/nix/tests/fixed.builder2.sh b/third_party/nix/tests/fixed.builder2.sh new file mode 100644 index 000000000000..31ea1579a514 --- /dev/null +++ b/third_party/nix/tests/fixed.builder2.sh @@ -0,0 +1,6 @@ +echo dummy: $dummy +if test -n "$dummy"; then sleep 2; fi +mkdir $out +mkdir $out/bla +echo "Hello World!" > $out/foo +ln -s foo $out/bar diff --git a/third_party/nix/tests/fixed.nix b/third_party/nix/tests/fixed.nix new file mode 100644 index 000000000000..76580ffa19e8 --- /dev/null +++ b/third_party/nix/tests/fixed.nix @@ -0,0 +1,50 @@ +with import ./config.nix; + +rec { + + f2 = dummy: builder: mode: algo: hash: mkDerivation { + name = "fixed"; + inherit builder; + outputHashMode = mode; + outputHashAlgo = algo; + outputHash = hash; + inherit dummy; + impureEnvVars = ["IMPURE_VAR1" "IMPURE_VAR2"]; + }; + + f = f2 ""; + + good = [ + (f ./fixed.builder1.sh "flat" "md5" "8ddd8be4b179a529afa5f2ffae4b9858") + (f ./fixed.builder1.sh "flat" "sha1" "a0b65939670bc2c010f4d5d6a0b3e4e4590fb92b") + (f ./fixed.builder2.sh "recursive" "md5" "3670af73070fa14077ad74e0f5ea4e42") + (f ./fixed.builder2.sh "recursive" "sha1" "vw46m23bizj4n8afrc0fj19wrp7mj3c0") + ]; + + good2 = [ + # Yes, this looks fscked up: builder2 doesn't have that result. + # But Nix sees that an output with the desired hash already + # exists, and will refrain from building it. + (f ./fixed.builder2.sh "flat" "md5" "8ddd8be4b179a529afa5f2ffae4b9858") + ]; + + sameAsAdd = + f ./fixed.builder2.sh "recursive" "sha256" "1ixr6yd3297ciyp9im522dfxpqbkhcw0pylkb2aab915278fqaik"; + + bad = [ + (f ./fixed.builder1.sh "flat" "md5" "0ddd8be4b179a529afa5f2ffae4b9858") + ]; + + reallyBad = [ + # Hash too short, and not base-32 either. + (f ./fixed.builder1.sh "flat" "md5" "ddd8be4b179a529afa5f2ffae4b9858") + ]; + + # Test for building two derivations in parallel that produce the + # same output path because they're fixed-output derivations. + parallelSame = [ + (f2 "foo" ./fixed.builder2.sh "recursive" "md5" "3670af73070fa14077ad74e0f5ea4e42") + (f2 "bar" ./fixed.builder2.sh "recursive" "md5" "3670af73070fa14077ad74e0f5ea4e42") + ]; + +} diff --git a/third_party/nix/tests/fixed.sh b/third_party/nix/tests/fixed.sh new file mode 100644 index 000000000000..8f51403a7071 --- /dev/null +++ b/third_party/nix/tests/fixed.sh @@ -0,0 +1,56 @@ +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...' +nix-build fixed.nix -A bad --no-out-link && fail "should fail" + +# Building with the bad hash should produce the "good" output path as +# a side-effect. +[[ -e $path ]] +nix path-info --json $path | grep fixed:md5:2qk15sxzzjlnpjk9brn7j8ppcd + +echo 'testing good...' +nix-build fixed.nix -A good --no-out-link + +echo 'testing good2...' +nix-build fixed.nix -A good2 --no-out-link + +echo 'testing reallyBad...' +nix-instantiate fixed.nix -A reallyBad && fail "should fail" + +# While we're at it, check attribute selection a bit more. +echo 'testing attribute selection...' +test $(nix-instantiate fixed.nix -A good.1 | wc -l) = 1 + +# Test parallel builds of derivations that produce the same output. +# Only one should run at the same time. +echo 'testing parallelSame...' +clearStore +nix-build fixed.nix -A parallelSame --no-out-link -j2 + +# Fixed-output derivations with a recursive SHA-256 hash should +# produce the same path as "nix-store --add". +echo 'testing sameAsAdd...' +out=$(nix-build fixed.nix -A sameAsAdd --no-out-link) + +# This is what fixed.builder2 produces... +rm -rf $TEST_ROOT/fixed +mkdir $TEST_ROOT/fixed +mkdir $TEST_ROOT/fixed/bla +echo "Hello World!" > $TEST_ROOT/fixed/foo +ln -s foo $TEST_ROOT/fixed/bar + +out2=$(nix-store --add $TEST_ROOT/fixed) +[ "$out" = "$out2" ] + +out3=$(nix-store --add-fixed --recursive sha256 $TEST_ROOT/fixed) +[ "$out" = "$out3" ] + +out4=$(nix-store --print-fixed-path --recursive sha256 "1ixr6yd3297ciyp9im522dfxpqbkhcw0pylkb2aab915278fqaik" fixed) +[ "$out" = "$out4" ] diff --git a/third_party/nix/tests/function-trace.sh b/third_party/nix/tests/function-trace.sh new file mode 100755 index 000000000000..182a4d5c287a --- /dev/null +++ b/third_party/nix/tests/function-trace.sh @@ -0,0 +1,85 @@ +source common.sh + +set +x + +expect_trace() { + expr="$1" + expect="$2" + actual=$( + nix-instantiate \ + --trace-function-calls \ + --expr "$expr" 2>&1 \ + | grep "function-trace" \ + | sed -e 's/ [0-9]*$//' + ); + + echo -n "Tracing expression '$expr'" + set +e + msg=$(diff -swB \ + <(echo "$expect") \ + <(echo "$actual") + ); + result=$? + set -e + if [ $result -eq 0 ]; then + echo " ok." + else + echo " failed. difference:" + echo "$msg" + return $result + fi +} + +# 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 +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 +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 +" + +set -e diff --git a/third_party/nix/tests/gc-auto.sh b/third_party/nix/tests/gc-auto.sh new file mode 100644 index 000000000000..de1e2cfe4059 --- /dev/null +++ b/third_party/nix/tests/gc-auto.sh @@ -0,0 +1,70 @@ +source common.sh + +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) + +ls -l $garbage3 +POSIXLY_CORRECT=1 du $garbage3 + +fake_free=$TEST_ROOT/fake-free +export _NIX_TEST_FREE_SPACE_FILE=$fake_free +echo 1100 > $fake_free + +expr=$(cat <<EOF +with import ./config.nix; mkDerivation { + name = "gc-A"; + buildCommand = '' + set -x + [[ \$(ls \$NIX_STORE/*-garbage? | wc -l) = 3 ]] + mkdir \$out + echo foo > \$out/bar + echo 1... + sleep 2 + echo 200 > ${fake_free}.tmp1 + mv ${fake_free}.tmp1 $fake_free + echo 2... + sleep 2 + echo 3... + sleep 2 + echo 4... + [[ \$(ls \$NIX_STORE/*-garbage? | wc -l) = 1 ]] + ''; +} +EOF +) + +expr2=$(cat <<EOF +with import ./config.nix; mkDerivation { + name = "gc-B"; + buildCommand = '' + set -x + mkdir \$out + echo foo > \$out/bar + echo 1... + sleep 2 + echo 200 > ${fake_free}.tmp2 + mv ${fake_free}.tmp2 $fake_free + echo 2... + sleep 2 + echo 3... + sleep 2 + echo 4... + ''; +} +EOF +) + +nix build -v -o $TEST_ROOT/result-A -L "($expr)" \ + --min-free 1000 --max-free 2000 --min-free-check-interval 1 & +pid=$! + +nix build -v -o $TEST_ROOT/result-B -L "($expr2)" \ + --min-free 1000 --max-free 2000 --min-free-check-interval 1 + +wait "$pid" + +[[ foo = $(cat $TEST_ROOT/result-A/bar) ]] +[[ foo = $(cat $TEST_ROOT/result-B/bar) ]] diff --git a/third_party/nix/tests/gc-concurrent.builder.sh b/third_party/nix/tests/gc-concurrent.builder.sh new file mode 100644 index 000000000000..0cd67df3aeda --- /dev/null +++ b/third_party/nix/tests/gc-concurrent.builder.sh @@ -0,0 +1,13 @@ +mkdir $out +echo $(cat $input1/foo)$(cat $input2/bar) > $out/foobar + +sleep 10 + +# $out should not have been GC'ed while we were sleeping, but just in +# case... +mkdir -p $out + +# Check that the GC hasn't deleted the lock on our output. +test -e "$out.lock" + +ln -s $input2 $out/input-2 diff --git a/third_party/nix/tests/gc-concurrent.nix b/third_party/nix/tests/gc-concurrent.nix new file mode 100644 index 000000000000..c0595cc471b9 --- /dev/null +++ b/third_party/nix/tests/gc-concurrent.nix @@ -0,0 +1,27 @@ +with import ./config.nix; + +rec { + + input1 = mkDerivation { + name = "dependencies-input-1"; + builder = ./dependencies.builder1.sh; + }; + + input2 = mkDerivation { + name = "dependencies-input-2"; + builder = ./dependencies.builder2.sh; + }; + + test1 = mkDerivation { + name = "gc-concurrent"; + builder = ./gc-concurrent.builder.sh; + inherit input1 input2; + }; + + test2 = mkDerivation { + name = "gc-concurrent2"; + builder = ./gc-concurrent2.builder.sh; + inherit input1 input2; + }; + +} diff --git a/third_party/nix/tests/gc-concurrent.sh b/third_party/nix/tests/gc-concurrent.sh new file mode 100644 index 000000000000..d395930ca0dc --- /dev/null +++ b/third_party/nix/tests/gc-concurrent.sh @@ -0,0 +1,58 @@ +source common.sh + +clearStore + +drvPath1=$(nix-instantiate gc-concurrent.nix -A test1) +outPath1=$(nix-store -q $drvPath1) + +drvPath2=$(nix-instantiate gc-concurrent.nix -A test2) +outPath2=$(nix-store -q $drvPath2) + +drvPath3=$(nix-instantiate simple.nix) +outPath3=$(nix-store -r $drvPath3) + +(! test -e $outPath3.lock) +touch $outPath3.lock + +rm -f "$NIX_STATE_DIR"/gcroots/foo* +ln -s $drvPath2 "$NIX_STATE_DIR"/gcroots/foo +ln -s $outPath3 "$NIX_STATE_DIR"/gcroots/foo2 + +# Start build #1 in the background. It starts immediately. +nix-store -rvv "$drvPath1" & +pid1=$! + +# Start build #2 in the background after 10 seconds. +(sleep 10 && nix-store -rvv "$drvPath2") & +pid2=$! + +# Run the garbage collector while the build is running. +sleep 6 +nix-collect-garbage + +# Wait for build #1/#2 to finish. +echo waiting for pid $pid1 to finish... +wait $pid1 +echo waiting for pid $pid2 to finish... +wait $pid2 + +# Check that the root of build #1 and its dependencies haven't been +# deleted. The should not be deleted by the GC because they were +# being built during the GC. +cat $outPath1/foobar +cat $outPath1/input-2/bar + +# Check that build #2 has succeeded. It should succeed because the +# derivation is a GC root. +cat $outPath2/foobar + +rm -f "$NIX_STATE_DIR"/gcroots/foo* + +# The collector should have deleted lock files for paths that have +# been built previously. +(! test -e $outPath3.lock) + +# If we run the collector now, it should delete outPath1/2. +nix-collect-garbage +(! test -e $outPath1) +(! test -e $outPath2) diff --git a/third_party/nix/tests/gc-concurrent2.builder.sh b/third_party/nix/tests/gc-concurrent2.builder.sh new file mode 100644 index 000000000000..4bfb33103e73 --- /dev/null +++ b/third_party/nix/tests/gc-concurrent2.builder.sh @@ -0,0 +1,7 @@ +mkdir $out +echo $(cat $input1/foo)$(cat $input2/bar)xyzzy > $out/foobar + +# Check that the GC hasn't deleted the lock on our output. +test -e "$out.lock" + +sleep 6 diff --git a/third_party/nix/tests/gc-runtime.nix b/third_party/nix/tests/gc-runtime.nix new file mode 100644 index 000000000000..ee5980bdff98 --- /dev/null +++ b/third_party/nix/tests/gc-runtime.nix @@ -0,0 +1,17 @@ +with import ./config.nix; + +mkDerivation { + name = "gc-runtime"; + builder = + # Test inline source file definitions. + builtins.toFile "builder.sh" '' + mkdir $out + + cat > $out/program <<EOF + #! ${shell} + sleep 10000 + EOF + + chmod +x $out/program + ''; +} diff --git a/third_party/nix/tests/gc-runtime.sh b/third_party/nix/tests/gc-runtime.sh new file mode 100644 index 000000000000..4c5028005c57 --- /dev/null +++ b/third_party/nix/tests/gc-runtime.sh @@ -0,0 +1,38 @@ +source common.sh + +case $system in + *linux*) + ;; + *) + exit 0; +esac + +set -m # enable job control, needed for kill + +profiles="$NIX_STATE_DIR"/profiles +rm -rf $profiles + +nix-env -p $profiles/test -f ./gc-runtime.nix -i gc-runtime + +outPath=$(nix-env -p $profiles/test -q --no-name --out-path gc-runtime) +echo $outPath + +echo "backgrounding program..." +$profiles/test/program & +sleep 2 # hack - wait for the program to get started +child=$! +echo PID=$child + +nix-env -p $profiles/test -e gc-runtime +nix-env -p $profiles/test --delete-generations old + +nix-store --gc + +kill -- -$child + +if ! test -e $outPath; then + echo "running program was garbage collected!" + exit 1 +fi + +exit 0 diff --git a/third_party/nix/tests/gc.sh b/third_party/nix/tests/gc.sh new file mode 100644 index 000000000000..8b4f8d282184 --- /dev/null +++ b/third_party/nix/tests/gc.sh @@ -0,0 +1,40 @@ +source common.sh + +drvPath=$(nix-instantiate dependencies.nix) +outPath=$(nix-store -rvv "$drvPath") + +# Set a GC root. +rm -f "$NIX_STATE_DIR"/gcroots/foo +ln -sf $outPath "$NIX_STATE_DIR"/gcroots/foo + +[ "$(nix-store -q --roots $outPath)" = "$NIX_STATE_DIR/gcroots/foo -> $outPath" ] + +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 + +nix-store --gc --print-dead + +inUse=$(readLink $outPath/input-2) +if nix-store --delete $inUse; then false; fi +test -e $inUse + +if nix-store --delete $outPath; then false; fi +test -e $outPath + +nix-collect-garbage + +# Check that the root and its dependencies haven't been deleted. +cat $outPath/foobar +cat $outPath/input-2/bar + +# Check that the derivation has been GC'd. +if test -e $drvPath; then false; fi + +rm "$NIX_STATE_DIR"/gcroots/foo + +nix-collect-garbage + +# Check that the output has been GC'd. +if test -e $outPath/foobar; then false; fi diff --git a/third_party/nix/tests/hash-check.nix b/third_party/nix/tests/hash-check.nix new file mode 100644 index 000000000000..4a8e9b8a8df9 --- /dev/null +++ b/third_party/nix/tests/hash-check.nix @@ -0,0 +1,29 @@ +let { + + input1 = derivation { + name = "dependencies-input-1"; + system = "i086-msdos"; + builder = "/bar/sh"; + args = ["-e" "-x" ./dummy]; + }; + + input2 = derivation { + name = "dependencies-input-2"; + system = "i086-msdos"; + builder = "/bar/sh"; + args = ["-e" "-x" ./dummy]; + outputHashMode = "recursive"; + outputHashAlgo = "md5"; + outputHash = "ffffffffffffffffffffffffffffffff"; + }; + + body = derivation { + name = "dependencies"; + system = "i086-msdos"; + builder = "/bar/sh"; + args = ["-e" "-x" (./dummy + "/FOOBAR/../.")]; + input1 = input1 + "/."; + inherit input2; + }; + +} \ No newline at end of file diff --git a/third_party/nix/tests/hash.sh b/third_party/nix/tests/hash.sh new file mode 100644 index 000000000000..4cfc97901012 --- /dev/null +++ b/third_party/nix/tests/hash.sh @@ -0,0 +1,87 @@ +source common.sh + +try () { + printf "%s" "$2" > $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 + fi +} + +try md5 "" "d41d8cd98f00b204e9800998ecf8427e" +try md5 "a" "0cc175b9c0f1b6a831c399e269772661" +try md5 "abc" "900150983cd24fb0d6963f7d28e17f72" +try md5 "message digest" "f96b697d7cb7938d525a2f31aaf161d0" +try md5 "abcdefghijklmnopqrstuvwxyz" "c3fcd3d76192e4007dfb496cca67e13b" +try md5 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" "d174ab98d277d9f5a5611c2c9f419d9f" +try md5 "12345678901234567890123456789012345678901234567890123456789012345678901234567890" "57edf4a22be3c955ac49da2e2107b67a" + +try sha1 "" "da39a3ee5e6b4b0d3255bfef95601890afd80709" +try sha1 "abc" "a9993e364706816aba3e25717850c26c9cd0d89d" +try sha1 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" "84983e441c3bd26ebaae4aa1f95129e5e54670f1" + +try sha256 "" "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" +try sha256 "abc" "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" +try sha256 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1" + +try sha512 "" "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e" +try sha512 "abc" "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f" +try sha512 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" "204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445" + +EXTRA=--base32 +try sha256 "abc" "1b8m03r63zqhnjf7l5wnldhh7c134ap5vpj0850ymkq1iyzicy5s" +EXTRA= + +EXTRA=--sri +try sha512 "" "sha512-z4PhNX7vuL3xVChQ1m2AB9Yg5AULVxXcg/SpIdNs6c5H0NE8XYXysP+DGNKHfuwvY7kxvUdBeoGlODJ6+SfaPg==" +try sha512 "abc" "sha512-3a81oZNherrMQXNJriBBMRLm+k6JqX6iCp7u5ktV05ohkpkqJ0/BqDa6PCOj/uu9RU1EI2Q86A4qmslPpUyknw==" +try sha512 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" "sha512-IEqPxt2oLwoM7XvrjgikFlfBbvRosiioJ5vjMacDwzWW/RXBOxsH+aodO+pXeJygMa2Fx6cd1wNU7GMSOMo0RQ==" +try sha256 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" "sha256-JI1qYdIGOLjlwCaTDD5gOaM85Flk/yFn9uzt1BnbBsE=" + +try2 () { + hash=$(nix-hash --type "$1" $TEST_ROOT/hash-path) + if test "$hash" != "$2"; then + echo "hash $1, expected $2, got $hash" + exit 1 + fi +} + +rm -rf $TEST_ROOT/hash-path +mkdir $TEST_ROOT/hash-path +echo "Hello World" > $TEST_ROOT/hash-path/hello + +try2 md5 "ea9b55537dd4c7e104515b2ccfaf4100" + +# Execute bit matters. +chmod +x $TEST_ROOT/hash-path/hello +try2 md5 "20f3ffe011d4cfa7d72bfabef7882836" + +# Mtime and other bits don't. +touch -r . $TEST_ROOT/hash-path/hello +chmod 744 $TEST_ROOT/hash-path/hello +try2 md5 "20f3ffe011d4cfa7d72bfabef7882836" + +# File type (e.g., symlink) does. +rm $TEST_ROOT/hash-path/hello +ln -s x $TEST_ROOT/hash-path/hello +try2 md5 "f78b733a68f5edbdf9413899339eaa4a" + +# Conversion. +try3() { + h64=$(nix to-base64 --type "$1" "$2") + [ "$h64" = "$4" ] + sri=$(nix 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" = "$2" ] + h16=$(nix to-base16 "$sri") + [ "$h16" = "$2" ] +} +try3 sha1 "800d59cfcd3c05e900cb4e214be48f6b886a08df" "vw46m23bizj4n8afrc0fj19wrp7mj3c0" "gA1Zz808BekAy04hS+SPa4hqCN8=" +try3 sha256 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" "1b8m03r63zqhnjf7l5wnldhh7c134ap5vpj0850ymkq1iyzicy5s" "ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0=" +try3 sha512 "204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445" "12k9jiq29iyqm03swfsgiw5mlqs173qazm3n7daz43infy12pyrcdf30fkk3qwv4yl2ick8yipc2mqnlh48xsvvxl60lbx8vp38yji0" "IEqPxt2oLwoM7XvrjgikFlfBbvRosiioJ5vjMacDwzWW/RXBOxsH+aodO+pXeJygMa2Fx6cd1wNU7GMSOMo0RQ==" diff --git a/third_party/nix/tests/import-derivation.nix b/third_party/nix/tests/import-derivation.nix new file mode 100644 index 000000000000..44fa9a45d7e1 --- /dev/null +++ b/third_party/nix/tests/import-derivation.nix @@ -0,0 +1,26 @@ +with import ./config.nix; + +let + + bar = mkDerivation { + name = "bar"; + builder = builtins.toFile "builder.sh" + '' + echo 'builtins.add 123 456' > $out + ''; + }; + + value = + # Test that pathExists can check the existence of /nix/store paths + assert builtins.pathExists bar; + import bar; + +in + +mkDerivation { + name = "foo"; + builder = builtins.toFile "builder.sh" + '' + echo -n FOO${toString value} > $out + ''; +} diff --git a/third_party/nix/tests/import-derivation.sh b/third_party/nix/tests/import-derivation.sh new file mode 100644 index 000000000000..98d61ef49b9c --- /dev/null +++ b/third_party/nix/tests/import-derivation.sh @@ -0,0 +1,12 @@ +source common.sh + +clearStore + +if nix-instantiate --readonly-mode ./import-derivation.nix; then + echo "read-only evaluation of an imported derivation unexpectedly failed" + exit 1 +fi + +outPath=$(nix-build ./import-derivation.nix --no-out-link) + +[ "$(cat $outPath)" = FOO579 ] diff --git a/third_party/nix/tests/init.sh b/third_party/nix/tests/init.sh new file mode 100644 index 000000000000..19a12c1e2d9e --- /dev/null +++ b/third_party/nix/tests/init.sh @@ -0,0 +1,34 @@ +source common.sh + +test -n "$TEST_ROOT" +if test -d "$TEST_ROOT"; then + chmod -R u+w "$TEST_ROOT" + rm -rf "$TEST_ROOT" +fi +mkdir "$TEST_ROOT" + +mkdir "$NIX_STORE_DIR" +mkdir "$NIX_LOCALSTATE_DIR" +mkdir -p "$NIX_LOG_DIR"/drvs +mkdir "$NIX_STATE_DIR" +mkdir "$NIX_CONF_DIR" + +cat > "$NIX_CONF_DIR"/nix.conf <<EOF +build-users-group = +keep-derivations = false +sandbox = false +include nix.conf.extra +EOF + +cat > "$NIX_CONF_DIR"/nix.conf.extra <<EOF +fsync-metadata = false +!include nix.conf.extra.not-there +EOF + +# Initialise the database. +nix-store --init + +# Did anything happen? +test -e "$NIX_STATE_DIR"/db/db.sqlite + +echo 'Hello World' > ./dummy diff --git a/third_party/nix/tests/install-darwin.sh b/third_party/nix/tests/install-darwin.sh new file mode 100755 index 000000000000..9933eba94431 --- /dev/null +++ b/third_party/nix/tests/install-darwin.sh @@ -0,0 +1,96 @@ +#!/bin/sh + +set -eux + +cleanup() { + PLIST="/Library/LaunchDaemons/org.nixos.nix-daemon.plist" + if sudo launchctl list | grep -q nix-daemon; then + sudo launchctl unload "$PLIST" + fi + + if [ -f "$PLIST" ]; then + sudo rm /Library/LaunchDaemons/org.nixos.nix-daemon.plist + fi + + profiles=(/etc/profile /etc/bashrc /etc/zshrc) + for profile in "${profiles[@]}"; do + if [ -f "${profile}.backup-before-nix" ]; then + sudo mv "${profile}.backup-before-nix" "${profile}" + fi + done + + for file in ~/.bash_profile ~/.bash_login ~/.profile ~/.zshenv ~/.zprofile ~/.zshrc ~/.zlogin; do + if [ -e "$file" ]; then + cat "$file" | grep -v nix-profile > "$file.next" + mv "$file.next" "$file" + fi + done + + for i in $(seq 1 $(sysctl -n hw.ncpu)); do + sudo /usr/bin/dscl . -delete "/Users/nixbld$i" || true + done + sudo /usr/bin/dscl . -delete "/Groups/nixbld" || true + + sudo rm -rf /etc/nix \ + /nix \ + /var/root/.nix-profile /var/root/.nix-defexpr /var/root/.nix-channels \ + "$HOME/.nix-profile" "$HOME/.nix-defexpr" "$HOME/.nix-channels" +} + +verify() { + set +e + output=$(echo "nix-shell -p bash --run 'echo toow | rev'" | bash -l) + set -e + + test "$output" = "woot" +} + +scratch=$(mktemp -d -t tmp.XXXXXXXXXX) +function finish { + rm -rf "$scratch" +} +trap finish EXIT + +# First setup Nix +cleanup +curl -o install https://nixos.org/nix/install +yes | bash ./install +verify + + +( + set +e + ( + echo "cd $(pwd)" + echo nix-build ./release.nix -A binaryTarball.x86_64-darwin + ) | bash -l + set -e + cp ./result/nix-*.tar.bz2 $scratch/nix.tar.bz2 +) + +( + cd $scratch + tar -xf ./nix.tar.bz2 + + cd nix-* + + set -eux + + cleanup + + yes | ./install + verify + cleanup + + echo -n "" | ./install + verify + cleanup + + sudo mkdir -p /nix/store + sudo touch /nix/store/.silly-hint + echo -n "" | ALLOW_PREEXISTING_INSTALLATION=true ./install + verify + test -e /nix/store/.silly-hint + + cleanup +) diff --git a/third_party/nix/tests/lang.sh b/third_party/nix/tests/lang.sh new file mode 100644 index 000000000000..151a71316683 --- /dev/null +++ b/third_party/nix/tests/lang.sh @@ -0,0 +1,68 @@ +export TEST_VAR=foo # for eval-okay-getenv.nix + +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) +nix-instantiate --show-trace --eval -E 'builtins.addErrorContext "Hello" (throw "Foo")' 2>&1 | grep -q Hello + +set +x + +fail=0 + +for i in lang/parse-fail-*.nix; do + echo "parsing $i (should fail)"; + i=$(basename $i .nix) + if nix-instantiate --parse - < lang/$i.nix; then + echo "FAIL: $i shouldn't parse" + fail=1 + fi +done + +for i in lang/parse-okay-*.nix; do + echo "parsing $i (should succeed)"; + i=$(basename $i .nix) + if ! nix-instantiate --parse - < lang/$i.nix > lang/$i.out; then + echo "FAIL: $i should parse" + fail=1 + fi +done + +for i in lang/eval-fail-*.nix; do + echo "evaluating $i (should fail)"; + i=$(basename $i .nix) + if nix-instantiate --eval lang/$i.nix; then + echo "FAIL: $i shouldn't evaluate" + fail=1 + fi +done + +for i in lang/eval-okay-*.nix; do + echo "evaluating $i (should succeed)"; + i=$(basename $i .nix) + + if test -e lang/$i.exp; then + flags= + if test -e lang/$i.flags; then + flags=$(cat lang/$i.flags) + fi + if ! NIX_PATH=lang/dir3:lang/dir4 nix-instantiate $flags --eval --strict lang/$i.nix > lang/$i.out; then + echo "FAIL: $i should evaluate" + fail=1 + elif ! diff lang/$i.out lang/$i.exp; then + echo "FAIL: evaluation result of $i not as expected" + fail=1 + fi + fi + + if test -e lang/$i.exp.xml; then + if ! nix-instantiate --eval --xml --no-location --strict \ + lang/$i.nix > lang/$i.out.xml; then + echo "FAIL: $i should evaluate" + fail=1 + elif ! cmp -s lang/$i.out.xml lang/$i.exp.xml; then + echo "FAIL: XML evaluation result of $i not as expected" + fail=1 + fi + fi +done + +exit $fail diff --git a/third_party/nix/tests/linux-sandbox.sh b/third_party/nix/tests/linux-sandbox.sh new file mode 100644 index 000000000000..52967d07dda2 --- /dev/null +++ b/third_party/nix/tests/linux-sandbox.sh @@ -0,0 +1,30 @@ +source common.sh + +clearStore + +if ! canUseSandbox; then exit; 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 + +chmod -R u+w $TEST_ROOT/store0 || true +rm -rf $TEST_ROOT/store0 + +export NIX_STORE_DIR=/my/store +export NIX_REMOTE=$TEST_ROOT/store0 + +outPath=$(nix-build dependencies.nix --no-out-link --sandbox-paths /nix/store) + +[[ $outPath =~ /my/store/.*-dependencies ]] + +nix path-info -r $outPath | grep input-2 + +nix ls-store -R -l $outPath | grep foobar + +nix cat-store $outPath/foobar | grep FOOBAR + +# Test --check without hash rewriting. +nix-build dependencies.nix --no-out-link --check --sandbox-paths /nix/store diff --git a/third_party/nix/tests/logging.sh b/third_party/nix/tests/logging.sh new file mode 100644 index 000000000000..c894ad3ff079 --- /dev/null +++ b/third_party/nix/tests/logging.sh @@ -0,0 +1,15 @@ +source common.sh + +clearStore + +path=$(nix-build dependencies.nix --no-out-link) + +# Test nix-store -l. +[ "$(nix-store -l $path)" = FOO ] + +# Test compressed logs. +clearStore +rm -rf $NIX_LOG_DIR +(! nix-store -l $path) +nix-build dependencies.nix --no-out-link --compress-build-log +[ "$(nix-store -l $path)" = FOO ] diff --git a/third_party/nix/tests/misc.sh b/third_party/nix/tests/misc.sh new file mode 100644 index 000000000000..eda0164167f2 --- /dev/null +++ b/third_party/nix/tests/misc.sh @@ -0,0 +1,19 @@ +source common.sh + +# Tests miscellaneous commands. + +# Do all commands have help? +#nix-env --help | grep -q install +#nix-store --help | grep -q realise +#nix-instantiate --help | grep -q eval +#nix-hash --help | grep -q base32 + +# Can we ask for the version number? +nix-env --version | grep "$version" + +# Usage errors. +nix-env --foo 2>&1 | grep "no operation" +nix-env -q --foo 2>&1 | grep "unknown flag" + +# Eval Errors. +nix-instantiate --eval -E 'let a = {} // a; in a.foo' 2>&1 | grep "infinite recursion encountered, at .*(string).*:1:15$" diff --git a/third_party/nix/tests/multiple-outputs.nix b/third_party/nix/tests/multiple-outputs.nix new file mode 100644 index 000000000000..4a9010d1868e --- /dev/null +++ b/third_party/nix/tests/multiple-outputs.nix @@ -0,0 +1,68 @@ +with import ./config.nix; + +rec { + + a = mkDerivation { + name = "multiple-outputs-a"; + outputs = [ "first" "second" ]; + 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!"; + }; + + b = mkDerivation { + defaultOutput = assert a.second.helloString == "Hello, world!"; a; + firstOutput = assert a.outputName == "first"; a.first.first; + secondOutput = assert a.second.outputName == "second"; a.second.first.first.second.second.first.second; + allOutputs = a.all; + name = "multiple-outputs-b"; + builder = builtins.toFile "builder.sh" + '' + mkdir $out + test "$firstOutput $secondOutput" = "$allOutputs" + test "$defaultOutput" = "$firstOutput" + test "$(cat $firstOutput/file)" = "first" + test "$(cat $secondOutput/file)" = "second" + echo "success" > $out/file + ''; + }; + + c = mkDerivation { + name = "multiple-outputs-c"; + drv = b.drvPath; + builder = builtins.toFile "builder.sh" + '' + mkdir $out + ln -s $drv $out/drv + ''; + }; + + d = mkDerivation { + name = "multiple-outputs-d"; + drv = builtins.unsafeDiscardOutputDependency b.drvPath; + builder = builtins.toFile "builder.sh" + '' + mkdir $out + echo $drv > $out/drv + ''; + }; + + cyclic = (mkDerivation { + name = "cyclic-outputs"; + outputs = [ "a" "b" "c" ]; + builder = builtins.toFile "builder.sh" + '' + mkdir $a $b $c + echo $a > $b/foo + echo $b > $c/bar + echo $c > $a/baz + ''; + }).a; + +} diff --git a/third_party/nix/tests/multiple-outputs.sh b/third_party/nix/tests/multiple-outputs.sh new file mode 100644 index 000000000000..bedbc39a4ebf --- /dev/null +++ b/third_party/nix/tests/multiple-outputs.sh @@ -0,0 +1,76 @@ +source common.sh + +clearStore + +rm -f $TEST_ROOT/result* + +# Test whether read-only evaluation works when referring to the +# ‘drvPath’ attribute. +echo "evaluating c..." +#drvPath=$(nix-instantiate multiple-outputs.nix -A c --readonly-mode) + +# And check whether the resulting derivation explicitly depends on all +# outputs. +drvPath=$(nix-instantiate multiple-outputs.nix -A c) +#[ "$drvPath" = "$drvPath2" ] +grep -q 'multiple-outputs-a.drv",\["first","second"\]' $drvPath +grep -q 'multiple-outputs-b.drv",\["out"\]' $drvPath + +# While we're at it, test the ‘unsafeDiscardOutputDependency’ primop. +outPath=$(nix-build multiple-outputs.nix -A d --no-out-link) +drvPath=$(cat $outPath/drv) +outPath=$(nix-store -q $drvPath) +(! [ -e "$outPath" ]) + +# Do a build of something that depends on a derivation with multiple +# outputs. +echo "building b..." +outPath=$(nix-build multiple-outputs.nix -A b --no-out-link) +echo "output path is $outPath" +[ "$(cat "$outPath"/file)" = "success" ] + +# Test nix-build on a derivation with multiple outputs. +outPath1=$(nix-build multiple-outputs.nix -A a -o $TEST_ROOT/result) +[ -e $TEST_ROOT/result-first ] +(! [ -e $TEST_ROOT/result-second ]) +nix-build multiple-outputs.nix -A a.all -o $TEST_ROOT/result +[ "$(cat $TEST_ROOT/result-first/file)" = "first" ] +[ "$(cat $TEST_ROOT/result-second/file)" = "second" ] +[ "$(cat $TEST_ROOT/result-second/link/file)" = "first" ] +hash1=$(nix-store -q --hash $TEST_ROOT/result-second) + +outPath2=$(nix-build $(nix-instantiate multiple-outputs.nix -A a) --no-out-link) +[[ $outPath1 = $outPath2 ]] + +outPath2=$(nix-build $(nix-instantiate multiple-outputs.nix -A a.first) --no-out-link) +[[ $outPath1 = $outPath2 ]] + +outPath2=$(nix-build $(nix-instantiate multiple-outputs.nix -A a.second) --no-out-link) +[[ $(cat $outPath2/file) = second ]] + +[[ $(nix-build $(nix-instantiate multiple-outputs.nix -A a.all) --no-out-link | wc -l) -eq 2 ]] + +# Delete one of the outputs and rebuild it. This will cause a hash +# rewrite. +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" ] +hash2=$(nix-store -q --hash $TEST_ROOT/result-second) +[ "$hash1" = "$hash2" ] + +# Make sure that nix-build works on derivations with multiple outputs. +echo "building a.first..." +nix-build multiple-outputs.nix -A a.first --no-out-link + +# Cyclic outputs should be rejected. +echo "building cyclic..." +if nix-build multiple-outputs.nix -A cyclic --no-out-link; then + echo "Cyclic outputs incorrectly accepted!" + exit 1 +fi + +echo "collecting garbage..." +rm $TEST_ROOT/result* +nix-store --gc --keep-derivations --keep-outputs +nix-store --gc --print-roots diff --git a/third_party/nix/tests/nar-access.nix b/third_party/nix/tests/nar-access.nix new file mode 100644 index 000000000000..0e2a7f721135 --- /dev/null +++ b/third_party/nix/tests/nar-access.nix @@ -0,0 +1,23 @@ +with import ./config.nix; + +rec { + a = mkDerivation { + name = "nar-index-a"; + builder = builtins.toFile "builder.sh" + '' + mkdir $out + mkdir $out/foo + touch $out/foo-x + touch $out/foo/bar + touch $out/foo/baz + touch $out/qux + mkdir $out/zyx + + cat >$out/foo/data <<EOF + lasjdöaxnasd +asdom 12398 +ä"§Æẞ¢«»”alsd +EOF + ''; + }; +} \ No newline at end of file diff --git a/third_party/nix/tests/nar-access.sh b/third_party/nix/tests/nar-access.sh new file mode 100644 index 000000000000..553d6ca89d7d --- /dev/null +++ b/third_party/nix/tests/nar-access.sh @@ -0,0 +1,44 @@ +source common.sh + +echo "building test path" +storePath="$(nix-build nar-access.nix -A a --no-out-link)" + +cd "$TEST_ROOT" + +# Dump path to nar. +narFile="$TEST_ROOT/path.nar" +nix-store --dump $storePath > $narFile + +# Check that find and ls-nar match. +( cd $storePath; find . | sort ) > files.find +nix ls-nar -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 +diff -u data.cat-nar $storePath/foo/data + +# Check that file contents of baz match. +nix cat-nar $narFile /foo/baz > baz.cat-nar +diff -u baz.cat-nar $storePath/foo/baz + +nix cat-store $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}' ]] + +# 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' + +# Test failure to dump. +if nix-store --dump $storePath >/dev/full ; then + echo "dumping to /dev/full should fail" + exit -1 +fi diff --git a/third_party/nix/tests/nix-build.sh b/third_party/nix/tests/nix-build.sh new file mode 100644 index 000000000000..395264863196 --- /dev/null +++ b/third_party/nix/tests/nix-build.sh @@ -0,0 +1,25 @@ +source common.sh + +clearStore + +outPath=$(nix-build dependencies.nix -o $TEST_ROOT/result) +test "$(cat $TEST_ROOT/result/foobar)" = FOOBAR + +# The result should be retained by a GC. +echo A +target=$(readLink $TEST_ROOT/result) +echo B +echo target is $target +nix-store --gc +test -e $target/foobar + +# But now it should be gone. +rm $TEST_ROOT/result +nix-store --gc +if test -e $target/foobar; then false; fi + +outPath2=$(nix-build $(nix-instantiate dependencies.nix) --no-out-link) +[[ $outPath = $outPath2 ]] + +outPath2=$(nix-build $(nix-instantiate dependencies.nix)!out --no-out-link) +[[ $outPath = $outPath2 ]] diff --git a/third_party/nix/tests/nix-channel.sh b/third_party/nix/tests/nix-channel.sh new file mode 100644 index 000000000000..93f837befcec --- /dev/null +++ b/third_party/nix/tests/nix-channel.sh @@ -0,0 +1,59 @@ +source common.sh + +clearProfiles + +rm -f $TEST_HOME/.nix-channels $TEST_HOME/.nix-profile + +# Test add/list/remove. +nix-channel --add http://foo/bar xyzzy +nix-channel --list | grep -q http://foo/bar +nix-channel --remove xyzzy + +[ -e $TEST_HOME/.nix-channels ] +[ "$(cat $TEST_HOME/.nix-channels)" = '' ] + +# Create a channel. +rm -rf $TEST_ROOT/foo +mkdir -p $TEST_ROOT/foo +nix copy --to file://$TEST_ROOT/foo?compression="bzip2" $(nix-store -r $(nix-instantiate dependencies.nix)) +rm -rf $TEST_ROOT/nixexprs +mkdir -p $TEST_ROOT/nixexprs +cp config.nix dependencies.nix dependencies.builder*.sh $TEST_ROOT/nixexprs/ +ln -s dependencies.nix $TEST_ROOT/nixexprs/default.nix +(cd $TEST_ROOT && tar cvf - nixexprs) | bzip2 > $TEST_ROOT/foo/nixexprs.tar.bz2 + +# Test the update action. +nix-channel --add file://$TEST_ROOT/foo +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"' $TEST_ROOT/meta.xml + +# Do an install. +nix-env -i dependencies +[ -e $TEST_HOME/.nix-profile/foobar ] + +clearProfiles +rm -f $TEST_HOME/.nix-channels + +# Test updating from a tarball +nix-channel --add file://$TEST_ROOT/foo/nixexprs.tar.bz2 foo +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"' $TEST_ROOT/meta.xml + +# Do an install. +nix-env -i dependencies +[ -e $TEST_HOME/.nix-profile/foobar ] + diff --git a/third_party/nix/tests/nix-copy-closure.nix b/third_party/nix/tests/nix-copy-closure.nix new file mode 100644 index 000000000000..0dc147fb34e9 --- /dev/null +++ b/third_party/nix/tests/nix-copy-closure.nix @@ -0,0 +1,64 @@ +# Test ‘nix-copy-closure’. + +{ nixpkgs, system, nix }: + +with import (nixpkgs + "/nixos/lib/testing.nix") { inherit system; }; + +makeTest (let pkgA = pkgs.cowsay; pkgB = pkgs.wget; pkgC = pkgs.hello; in { + + nodes = + { client = + { config, pkgs, ... }: + { virtualisation.writableStore = true; + virtualisation.pathsInNixDB = [ pkgA ]; + nix.package = nix; + nix.binaryCaches = [ ]; + }; + + server = + { config, pkgs, ... }: + { services.openssh.enable = true; + virtualisation.writableStore = true; + virtualisation.pathsInNixDB = [ pkgB pkgC ]; + nix.package = nix; + }; + }; + + 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 -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 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'"); + + # 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}"); + # 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/third_party/nix/tests/nix-copy-ssh.sh b/third_party/nix/tests/nix-copy-ssh.sh new file mode 100644 index 000000000000..eb801548d2f1 --- /dev/null +++ b/third_party/nix/tests/nix-copy-ssh.sh @@ -0,0 +1,20 @@ +source common.sh + +clearStore +clearCache + +remoteRoot=$TEST_ROOT/store2 +chmod -R u+w "$remoteRoot" || true +rm -rf "$remoteRoot" + +outPath=$(nix-build --no-out-link dependencies.nix) + +nix copy --to "ssh://localhost?store=$NIX_STORE_DIR&remote-store=$remoteRoot%3fstore=$NIX_STORE_DIR%26real=$remoteRoot$NIX_STORE_DIR" $outPath + +[ -f $remoteRoot$outPath/foobar ] + +clearStore + +nix copy --no-check-sigs --from "ssh://localhost?store=$NIX_STORE_DIR&remote-store=$remoteRoot%3fstore=$NIX_STORE_DIR%26real=$remoteRoot$NIX_STORE_DIR" $outPath + +[ -f $outPath/foobar ] diff --git a/third_party/nix/tests/nix-profile.sh b/third_party/nix/tests/nix-profile.sh new file mode 100644 index 000000000000..e2e0d1090804 --- /dev/null +++ b/third_party/nix/tests/nix-profile.sh @@ -0,0 +1,9 @@ +source common.sh + +sed -e "s|@localstatedir@|$TEST_ROOT/profile-var|g" -e "s|@coreutils@|$coreutils|g" < ../scripts/nix-profile.sh.in > $TEST_ROOT/nix-profile.sh + +user=$(whoami) +rm -rf $TEST_HOME $TEST_ROOT/profile-var +mkdir -p $TEST_HOME +USER=$user $SHELL -e -c ". $TEST_ROOT/nix-profile.sh; set" +USER=$user $SHELL -e -c ". $TEST_ROOT/nix-profile.sh" # test idempotency diff --git a/third_party/nix/tests/nix-shell.sh b/third_party/nix/tests/nix-shell.sh new file mode 100644 index 000000000000..ee502dddb955 --- /dev/null +++ b/third_party/nix/tests/nix-shell.sh @@ -0,0 +1,57 @@ +source common.sh + +clearStore + +# Test nix-shell -A +export IMPURE_VAR=foo +export SELECTED_IMPURE_VAR=baz +export NIX_BUILD_SHELL=$SHELL +output=$(nix-shell --pure shell.nix -A shellDrv --run \ + 'echo "$IMPURE_VAR - $VAR_FROM_STDENV_SETUP - $VAR_FROM_NIX"') + +[ "$output" = " - foo - bar" ] + +# Test --keep +output=$(nix-shell --pure --keep SELECTED_IMPURE_VAR shell.nix -A shellDrv --run \ + 'echo "$IMPURE_VAR - $VAR_FROM_STDENV_SETUP - $VAR_FROM_NIX - $SELECTED_IMPURE_VAR"') + +[ "$output" = " - foo - bar - baz" ] + +# Test nix-shell on a .drv +[[ $(nix-shell --pure $(nix-instantiate shell.nix -A shellDrv) --run \ + 'echo "$IMPURE_VAR - $VAR_FROM_STDENV_SETUP - $VAR_FROM_NIX"') = " - foo - bar" ]] + +[[ $(nix-shell --pure $(nix-instantiate shell.nix -A shellDrv) --run \ + 'echo "$IMPURE_VAR - $VAR_FROM_STDENV_SETUP - $VAR_FROM_NIX"') = " - foo - bar" ]] + +# 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-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-shell --pure $TEST_ROOT/shell --run \ + 'echo "$IMPURE_VAR - $VAR_FROM_STDENV_SETUP - $VAR_FROM_NIX"') = " - foo - bar" ]] + +# Test nix-shell -p +output=$(NIX_PATH=nixpkgs=shell.nix nix-shell --pure -p foo bar --run 'echo "$(foo) $(bar)"') +[ "$output" = "foo bar" ] + +# Test nix-shell shebang mode +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 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 +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' ] diff --git a/third_party/nix/tests/optimise-store.sh b/third_party/nix/tests/optimise-store.sh new file mode 100644 index 000000000000..61e3df2f9f7e --- /dev/null +++ b/third_party/nix/tests/optimise-store.sh @@ -0,0 +1,43 @@ +source common.sh + +clearStore + +outPath1=$(echo 'with import ./config.nix; mkDerivation { name = "foo1"; builder = builtins.toFile "builder" "mkdir $out; echo hello > $out/foo"; }' | nix-build - --no-out-link --auto-optimise-store) +outPath2=$(echo 'with import ./config.nix; mkDerivation { name = "foo2"; builder = builtins.toFile "builder" "mkdir $out; echo hello > $out/foo"; }' | nix-build - --no-out-link --auto-optimise-store) + +inode1="$(stat --format=%i $outPath1/foo)" +inode2="$(stat --format=%i $outPath2/foo)" +if [ "$inode1" != "$inode2" ]; then + echo "inodes do not match" + exit 1 +fi + +nlink="$(stat --format=%h $outPath1/foo)" +if [ "$nlink" != 3 ]; then + echo "link count incorrect" + exit 1 +fi + +outPath3=$(echo 'with import ./config.nix; mkDerivation { name = "foo3"; builder = builtins.toFile "builder" "mkdir $out; echo hello > $out/foo"; }' | nix-build - --no-out-link) + +inode3="$(stat --format=%i $outPath3/foo)" +if [ "$inode1" = "$inode3" ]; then + echo "inodes match unexpectedly" + exit 1 +fi + +nix-store --optimise + +inode1="$(stat --format=%i $outPath1/foo)" +inode3="$(stat --format=%i $outPath3/foo)" +if [ "$inode1" != "$inode3" ]; then + echo "inodes do not match" + exit 1 +fi + +nix-store --gc + +if [ -n "$(ls $NIX_STORE_DIR/.links)" ]; then + echo ".links directory not empty after GC" + exit 1 +fi diff --git a/third_party/nix/tests/parallel.builder.sh b/third_party/nix/tests/parallel.builder.sh new file mode 100644 index 000000000000..d092bc5a6bd4 --- /dev/null +++ b/third_party/nix/tests/parallel.builder.sh @@ -0,0 +1,29 @@ +echo "DOING $text" + + +# increase counter +while ! ln -s x $shared.lock 2> /dev/null; do + sleep 1 +done +test -f $shared.cur || echo 0 > $shared.cur +test -f $shared.max || echo 0 > $shared.max +new=$(($(cat $shared.cur) + 1)) +if test $new -gt $(cat $shared.max); then + echo $new > $shared.max +fi +echo $new > $shared.cur +rm $shared.lock + + +echo -n $(cat $inputs)$text > $out + +sleep $sleepTime + + +# decrease counter +while ! ln -s x $shared.lock 2> /dev/null; do + sleep 1 +done +test -f $shared.cur || echo 0 > $shared.cur +echo $(($(cat $shared.cur) - 1)) > $shared.cur +rm $shared.lock diff --git a/third_party/nix/tests/parallel.nix b/third_party/nix/tests/parallel.nix new file mode 100644 index 000000000000..23f142059f58 --- /dev/null +++ b/third_party/nix/tests/parallel.nix @@ -0,0 +1,19 @@ +{sleepTime ? 3}: + +with import ./config.nix; + +let + + mkDrv = text: inputs: mkDerivation { + name = "parallel"; + builder = ./parallel.builder.sh; + inherit text inputs shared sleepTime; + }; + + a = mkDrv "a" []; + b = mkDrv "b" [a]; + c = mkDrv "c" [a]; + d = mkDrv "d" [a]; + e = mkDrv "e" [b c d]; + +in e diff --git a/third_party/nix/tests/parallel.sh b/third_party/nix/tests/parallel.sh new file mode 100644 index 000000000000..3b7bbe5a2251 --- /dev/null +++ b/third_party/nix/tests/parallel.sh @@ -0,0 +1,56 @@ +source common.sh + + +# First, test that -jN performs builds in parallel. +echo "testing nix-build -j..." + +clearStore + +rm -f $_NIX_TEST_SHARED.cur $_NIX_TEST_SHARED.max + +outPath=$(nix-build -j10000 parallel.nix --no-out-link) + +echo "output path is $outPath" + +text=$(cat "$outPath") +if test "$text" != "abacade"; then exit 1; fi + +if test "$(cat $_NIX_TEST_SHARED.cur)" != 0; then fail "wrong current process count"; fi +if test "$(cat $_NIX_TEST_SHARED.max)" != 3; then fail "not enough parallelism"; fi + + +# Second, test that parallel invocations of nix-build perform builds +# in parallel, and don't block waiting on locks held by the others. +echo "testing multiple nix-build -j1..." + +clearStore + +rm -f $_NIX_TEST_SHARED.cur $_NIX_TEST_SHARED.max + +drvPath=$(nix-instantiate parallel.nix --argstr sleepTime 15) + +cmd="nix-store -j1 -r $drvPath" + +$cmd & +pid1=$! +echo "pid 1 is $pid1" + +$cmd & +pid2=$! +echo "pid 2 is $pid2" + +$cmd & +pid3=$! +echo "pid 3 is $pid3" + +$cmd & +pid4=$! +echo "pid 4 is $pid4" + +wait $pid1 || fail "instance 1 failed: $?" +wait $pid2 || fail "instance 2 failed: $?" +wait $pid3 || fail "instance 3 failed: $?" +wait $pid4 || fail "instance 4 failed: $?" + +if test "$(cat $_NIX_TEST_SHARED.cur)" != 0; then fail "wrong current process count"; fi +if test "$(cat $_NIX_TEST_SHARED.max)" != 3; then fail "not enough parallelism"; fi diff --git a/third_party/nix/tests/pass-as-file.sh b/third_party/nix/tests/pass-as-file.sh new file mode 100644 index 000000000000..2c0bc5031ad7 --- /dev/null +++ b/third_party/nix/tests/pass-as-file.sh @@ -0,0 +1,18 @@ +source common.sh + +clearStore + +outPath=$(nix-build --no-out-link -E " +with import ./config.nix; + +mkDerivation { + name = \"pass-as-file\"; + passAsFile = [ \"foo\" ]; + foo = [ \"xyzzy\" ]; + builder = builtins.toFile \"builder.sh\" '' + [ \"\$(basename \$fooPath)\" = .attr-1bp7cri8hplaz6hbz0v4f0nl44rl84q1sg25kgwqzipzd1mv89ic ] + [ \"\$(cat \$fooPath)\" = xyzzy ] + touch \$out + ''; +} +") diff --git a/third_party/nix/tests/placeholders.sh b/third_party/nix/tests/placeholders.sh new file mode 100644 index 000000000000..cd1bb7bc2aac --- /dev/null +++ b/third_party/nix/tests/placeholders.sh @@ -0,0 +1,20 @@ +source common.sh + +clearStore + +nix-build --no-out-link -E ' + with import ./config.nix; + + mkDerivation { + name = "placeholders"; + outputs = [ "out" "bin" "dev" ]; + buildCommand = " + echo foo1 > $out + echo foo2 > $bin + echo foo3 > $dev + [[ $(cat ${placeholder "out"}) = foo1 ]] + [[ $(cat ${placeholder "bin"}) = foo2 ]] + [[ $(cat ${placeholder "dev"}) = foo3 ]] + "; + } +' diff --git a/third_party/nix/tests/post-hook.sh b/third_party/nix/tests/post-hook.sh new file mode 100644 index 000000000000..a026572154db --- /dev/null +++ b/third_party/nix/tests/post-hook.sh @@ -0,0 +1,15 @@ +source common.sh + +clearStore + +export REMOTE_STORE=$TEST_ROOT/remote_store + +# 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 + +clearStore + +# Ensure that we the remote store contains both the runtime and buildtime +# closure of what we've just built +nix copy --from "$REMOTE_STORE" --no-require-sigs -f dependencies.nix +nix copy --from "$REMOTE_STORE" --no-require-sigs -f dependencies.nix input1_drv diff --git a/third_party/nix/tests/pure-eval.nix b/third_party/nix/tests/pure-eval.nix new file mode 100644 index 000000000000..ed25b3d45637 --- /dev/null +++ b/third_party/nix/tests/pure-eval.nix @@ -0,0 +1,3 @@ +{ + x = 123; +} diff --git a/third_party/nix/tests/pure-eval.sh b/third_party/nix/tests/pure-eval.sh new file mode 100644 index 000000000000..49c8564487c3 --- /dev/null +++ b/third_party/nix/tests/pure-eval.sh @@ -0,0 +1,18 @@ +source common.sh + +clearStore + +nix eval --pure-eval '(assert 1 + 2 == 3; true)' + +[[ $(nix eval '(builtins.readFile ./pure-eval.sh)') =~ clearStore ]] + +(! nix eval --pure-eval '(builtins.readFile ./pure-eval.sh)') + +(! nix eval --pure-eval '(builtins.currentTime)') +(! nix eval --pure-eval '(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)" diff --git a/third_party/nix/tests/push-to-store.sh b/third_party/nix/tests/push-to-store.sh new file mode 100755 index 000000000000..6aadb916ba0b --- /dev/null +++ b/third_party/nix/tests/push-to-store.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +echo Pushing "$@" to "$REMOTE_STORE" +printf "%s" "$OUT_PATHS" | xargs -d: nix copy --to "$REMOTE_STORE" --no-require-sigs diff --git a/third_party/nix/tests/referrers.sh b/third_party/nix/tests/referrers.sh new file mode 100644 index 000000000000..8ab8e5ddfe87 --- /dev/null +++ b/third_party/nix/tests/referrers.sh @@ -0,0 +1,36 @@ +source common.sh + +clearStore + +max=500 + +reference=$NIX_STORE_DIR/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +touch $reference +(echo $reference && echo && echo 0) | nix-store --register-validity + +echo "making registration..." + +set +x +for ((n = 0; n < $max; n++)); do + storePath=$NIX_STORE_DIR/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-$n + echo -n > $storePath + ref2=$NIX_STORE_DIR/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-$((n+1)) + if test $((n+1)) = $max; then + ref2=$reference + fi + echo $storePath; echo; echo 2; echo $reference; echo $ref2 +done > $TEST_ROOT/reg_info +set -x + +echo "registering..." + +nix-store --register-validity < $TEST_ROOT/reg_info + +echo "collecting garbage..." +ln -sfn $reference "$NIX_STATE_DIR"/gcroots/ref +nix-store --gc + +if [ -n "$(type -p sqlite3)" -a "$(sqlite3 $NIX_STATE_DIR/db/db.sqlite 'select count(*) from Refs')" -ne 0 ]; then + echo "referrers not cleaned up" + exit 1 +fi diff --git a/third_party/nix/tests/remote-builds.nix b/third_party/nix/tests/remote-builds.nix new file mode 100644 index 000000000000..b867f13b4995 --- /dev/null +++ b/third_party/nix/tests/remote-builds.nix @@ -0,0 +1,108 @@ +# Test Nix's remote build feature. + +{ nixpkgs, system, nix }: + +with import (nixpkgs + "/nixos/lib/testing.nix") { inherit system; }; + +makeTest ( + +let + + # The configuration of the remote builders. + builder = + { config, pkgs, ... }: + { services.openssh.enable = true; + virtualisation.writableStore = true; + nix.package = nix; + nix.useSandbox = true; + }; + + # Trivial Nix expression to build remotely. + expr = config: nr: pkgs.writeText "expr.nix" + '' + let utils = builtins.storePath ${config.system.build.extraUtils}; in + derivation { + name = "hello-${toString nr}"; + system = "i686-linux"; + PATH = "''${utils}/bin"; + builder = "''${utils}/bin/sh"; + args = [ "-c" "if [ ${toString nr} = 5 ]; then echo FAIL; exit 1; fi; echo Hello; mkdir $out $foo; cat /proc/sys/kernel/hostname > $out/host; ln -s $out $foo/bar; sleep 10" ]; + outputs = [ "out" "foo" ]; + } + ''; + +in + +{ + + nodes = + { builder1 = builder; + builder2 = builder; + + client = + { config, pkgs, ... }: + { nix.maxJobs = 0; # force remote building + nix.distributedBuilds = true; + nix.buildMachines = + [ { hostName = "builder1"; + sshUser = "root"; + sshKey = "/root/.ssh/id_ed25519"; + system = "i686-linux"; + maxJobs = 1; + } + { hostName = "builder2"; + sshUser = "root"; + sshKey = "/root/.ssh/id_ed25519"; + system = "i686-linux"; + maxJobs = 1; + } + ]; + virtualisation.writableStore = true; + virtualisation.pathsInNixDB = [ config.system.build.extraUtils ]; + nix.package = nix; + nix.binaryCaches = [ ]; + 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}"); + ''; + +}) diff --git a/third_party/nix/tests/remote-store.sh b/third_party/nix/tests/remote-store.sh new file mode 100644 index 000000000000..77437658ead6 --- /dev/null +++ b/third_party/nix/tests/remote-store.sh @@ -0,0 +1,19 @@ +source common.sh + +clearStore + +startDaemon + +storeCleared=1 $SHELL ./user-envs.sh + +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) +[ -e $NIX_STATE_DIR/gcroots/per-user/$user ] +[ -e $NIX_STATE_DIR/profiles/per-user/$user ] diff --git a/third_party/nix/tests/repair.sh b/third_party/nix/tests/repair.sh new file mode 100644 index 000000000000..ec7ad5dcaff4 --- /dev/null +++ b/third_party/nix/tests/repair.sh @@ -0,0 +1,77 @@ +source common.sh + +clearStore + +path=$(nix-build dependencies.nix -o $TEST_ROOT/result) +path2=$(nix-store -qR $path | grep input-2) + +nix-store --verify --check-contents -v + +hash=$(nix-hash $path2) + +# Corrupt a path and check whether nix-build --repair can fix it. +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 + +# The path can be repaired by rebuilding the derivation. +nix-store --verify --check-contents --repair + +nix-store --verify-path $path2 + +# Re-corrupt and delete the deriver. Now --verify --repair should +# not work. +chmod u+w $path2 +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-build dependencies.nix -o $TEST_ROOT/result --repair + +if [ "$(nix-hash $path2)" != "$hash" -o -e $path2/bad ]; then + echo "path not repaired properly" >&2 + exit 1 +fi + +# Corrupt a path that has a substitute and check whether nix-store +# --verify can fix it. +clearCache + +nix copy --to file://$cacheDir $path + +chmod u+w $path2 +rm -rf $path2 + +nix-store --verify --check-contents --repair --substituters "file://$cacheDir" --no-require-sigs + +if [ "$(nix-hash $path2)" != "$hash" -o -e $path2/bad ]; then + echo "path not repaired properly" >&2 + exit 1 +fi + +# Check --verify-path and --repair-path. +nix-store --verify-path $path2 + +chmod u+w $path2 +rm -rf $path2 + +if nix-store --verify-path $path2; then + echo "nix-store --verify-path succeeded unexpectedly" >&2 + exit 1 +fi + +nix-store --repair-path $path2 --substituters "file://$cacheDir" --no-require-sigs + +if [ "$(nix-hash $path2)" != "$hash" -o -e $path2/bad ]; then + echo "path not repaired properly" >&2 + exit 1 +fi diff --git a/third_party/nix/tests/restricted.nix b/third_party/nix/tests/restricted.nix new file mode 100644 index 000000000000..e0ef5840209c --- /dev/null +++ b/third_party/nix/tests/restricted.nix @@ -0,0 +1 @@ +1 + 2 diff --git a/third_party/nix/tests/restricted.sh b/third_party/nix/tests/restricted.sh new file mode 100644 index 000000000000..e02becc60e38 --- /dev/null +++ b/third_party/nix/tests/restricted.sh @@ -0,0 +1,51 @@ +source common.sh + +clearStore + +nix-instantiate --restrict-eval --eval -E '1 + 2' +(! nix-instantiate --restrict-eval ./restricted.nix) +(! nix-instantiate --eval --restrict-eval <(echo '1 + 2')) +nix-instantiate --restrict-eval ./simple.nix -I src=. +nix-instantiate --restrict-eval ./simple.nix -I src1=simple.nix -I src2=config.nix -I src3=./simple.builder.sh + +(! nix-instantiate --restrict-eval --eval -E 'builtins.readFile ./simple.nix') +nix-instantiate --restrict-eval --eval -E 'builtins.readFile ./simple.nix' -I src=.. + +(! nix-instantiate --restrict-eval --eval -E 'builtins.readDir ../src/nix-channel') +nix-instantiate --restrict-eval --eval -E 'builtins.readDir ../src/nix-channel' -I src=../src + +(! 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)") +cmp $p restricted.sh + +(! nix eval --raw "(builtins.fetchurl file://$(pwd)/restricted.sh)" --restrict-eval) + +(! nix eval --raw "(builtins.fetchurl file://$(pwd)/restricted.sh)" --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 "(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) + +ln -sfn $(pwd)/restricted.nix $TEST_ROOT/restricted.nix +[[ $(nix-instantiate --eval $TEST_ROOT/restricted.nix) == 3 ]] +(! nix-instantiate --eval --restrict-eval $TEST_ROOT/restricted.nix) +(! nix-instantiate --eval --restrict-eval $TEST_ROOT/restricted.nix -I $TEST_ROOT) +(! 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!' ]] + +# Check whether we can leak symlink information through directory traversal. +traverseDir="$(pwd)/restricted-traverse-me" +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\")" \ + 2>&1 || :)" +echo "$output" | grep "is forbidden" +! echo "$output" | grep -F restricted-secret diff --git a/third_party/nix/tests/run.nix b/third_party/nix/tests/run.nix new file mode 100644 index 000000000000..77dcbd2a9df0 --- /dev/null +++ b/third_party/nix/tests/run.nix @@ -0,0 +1,17 @@ +with import ./config.nix; + +{ + hello = mkDerivation { + name = "hello"; + buildCommand = + '' + mkdir -p $out/bin + cat > $out/bin/hello <<EOF + #! ${shell} + who=\$1 + echo "Hello \''${who:-World} from $out/bin/hello" + EOF + chmod +x $out/bin/hello + ''; + }; +} diff --git a/third_party/nix/tests/run.sh b/third_party/nix/tests/run.sh new file mode 100644 index 000000000000..d1dbfd6bd4a6 --- /dev/null +++ b/third_party/nix/tests/run.sh @@ -0,0 +1,28 @@ +source common.sh + +clearStore +clearCache + +nix run -f run.nix hello -c hello | grep 'Hello World' +nix run -f run.nix hello -c hello NixOS | grep 'Hello NixOS' + +if ! canUseSandbox; then exit; fi + +chmod -R u+w $TEST_ROOT/store0 || true +rm -rf $TEST_ROOT/store0 + +clearStore + +path=$(nix eval --raw -f run.nix hello) + +# Note: we need the sandbox paths to ensure that the shell is +# visible in the sandbox. +nix run --sandbox-build-dir /build-tmp \ + --sandbox-paths '/nix? /bin? /lib? /lib64? /usr?' \ + --store $TEST_ROOT/store0 -f run.nix hello -c hello | grep 'Hello World' + +path2=$(nix run --sandbox-paths '/nix? /bin? /lib? /lib64? /usr?' --store $TEST_ROOT/store0 -f run.nix hello -c $SHELL -c 'type -p hello') + +[[ $path/bin/hello = $path2 ]] + +[[ -e $TEST_ROOT/store0/nix/store/$(basename $path)/bin/hello ]] diff --git a/third_party/nix/tests/search.nix b/third_party/nix/tests/search.nix new file mode 100644 index 000000000000..fea6e7a7a647 --- /dev/null +++ b/third_party/nix/tests/search.nix @@ -0,0 +1,25 @@ +with import ./config.nix; + +{ + hello = mkDerivation rec { + name = "hello-${version}"; + version = "0.1"; + buildCommand = "touch $out"; + meta.description = "Empty file"; + }; + foo = mkDerivation rec { + name = "foo-5"; + buildCommand = '' + mkdir -p $out + echo ${name} > $out/${name} + ''; + }; + bar = mkDerivation rec { + name = "bar-3"; + buildCommand = '' + echo "Does not build successfully" + exit 1 + ''; + meta.description = "broken bar"; + }; +} diff --git a/third_party/nix/tests/search.sh b/third_party/nix/tests/search.sh new file mode 100644 index 000000000000..14da3127b0d5 --- /dev/null +++ b/third_party/nix/tests/search.sh @@ -0,0 +1,43 @@ +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 )) + +# Check descriptions are searched +(( $(nix search broken | wc -l) > 0 )) + +# Check search that matches nothing +(( $(nix search nosuchpackageexists | wc -l) == 0 )) + +# Search for multiple arguments +(( $(nix search hello empty | wc -l) == 3 )) + +# Multiple arguments will not exist +(( $(nix search 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 diff --git a/third_party/nix/tests/secure-drv-outputs.nix b/third_party/nix/tests/secure-drv-outputs.nix new file mode 100644 index 000000000000..b4ac8ff531f8 --- /dev/null +++ b/third_party/nix/tests/secure-drv-outputs.nix @@ -0,0 +1,23 @@ +with import ./config.nix; + +{ + + good = mkDerivation { + name = "good"; + builder = builtins.toFile "builder" + '' + mkdir $out + echo > $out/good + ''; + }; + + bad = mkDerivation { + name = "good"; + builder = builtins.toFile "builder" + '' + mkdir $out + echo > $out/bad + ''; + }; + +} diff --git a/third_party/nix/tests/secure-drv-outputs.sh b/third_party/nix/tests/secure-drv-outputs.sh new file mode 100644 index 000000000000..50a9c4428d30 --- /dev/null +++ b/third_party/nix/tests/secure-drv-outputs.sh @@ -0,0 +1,36 @@ +# Test that users cannot register specially-crafted derivations that +# produce output paths belonging to other derivations. This could be +# used to inject malware into the store. + +source common.sh + +clearStore + +startDaemon + +# Determine the output path of the "good" derivation. +goodOut=$(nix-store -q $(nix-instantiate ./secure-drv-outputs.nix -A good)) + +# Instantiate the "bad" derivation. +badDrv=$(nix-instantiate ./secure-drv-outputs.nix -A bad) +badOut=$(nix-store -q $badDrv) + +# Rewrite the bad derivation to produce the output path of the good +# derivation. +rm -f $TEST_ROOT/bad.drv +sed -e "s|$badOut|$goodOut|g" < $badDrv > $TEST_ROOT/bad.drv + +# Add the manipulated derivation to the store and build it. This +# should fail. +if badDrv2=$(nix-store --add $TEST_ROOT/bad.drv); then + nix-store -r "$badDrv2" +fi + +# Now build the good derivation. +goodOut2=$(nix-build ./secure-drv-outputs.nix -A good --no-out-link) +test "$goodOut" = "$goodOut2" + +if ! test -e "$goodOut"/good; then + echo "Bad derivation stole the output path of the good derivation!" + exit 1 +fi diff --git a/third_party/nix/tests/setuid.nix b/third_party/nix/tests/setuid.nix new file mode 100644 index 000000000000..77e83c8d6c2c --- /dev/null +++ b/third_party/nix/tests/setuid.nix @@ -0,0 +1,108 @@ +# Verify that Linux builds cannot create setuid or setgid binaries. + +{ nixpkgs, system, nix }: + +with import (nixpkgs + "/nixos/lib/testing.nix") { inherit system; }; + +makeTest { + + machine = + { config, lib, pkgs, ... }: + { virtualisation.writableStore = true; + nix.package = nix; + nix.binaryCaches = [ ]; + 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"); + ''; + +} diff --git a/third_party/nix/tests/shell.nix b/third_party/nix/tests/shell.nix new file mode 100644 index 000000000000..eb39f9039a88 --- /dev/null +++ b/third_party/nix/tests/shell.nix @@ -0,0 +1,56 @@ +{ }: + +with import ./config.nix; + +let pkgs = rec { + setupSh = builtins.toFile "setup" '' + export VAR_FROM_STDENV_SETUP=foo + for pkg in $buildInputs; do + export PATH=$PATH:$pkg/bin + done + ''; + + stdenv = mkDerivation { + name = "stdenv"; + buildCommand = '' + mkdir -p $out + ln -s ${setupSh} $out/setup + ''; + }; + + shellDrv = mkDerivation { + name = "shellDrv"; + builder = "/does/not/exist"; + VAR_FROM_NIX = "bar"; + inherit stdenv; + }; + + # Used by nix-shell -p + runCommand = name: args: buildCommand: mkDerivation (args // { + inherit name buildCommand stdenv; + }); + + foo = runCommand "foo" {} '' + mkdir -p $out/bin + echo 'echo foo' > $out/bin/foo + chmod a+rx $out/bin/foo + ln -s ${shell} $out/bin/bash + ''; + + bar = runCommand "bar" {} '' + mkdir -p $out/bin + echo 'echo bar' > $out/bin/bar + chmod a+rx $out/bin/bar + ''; + + bash = shell; + + # ruby "interpreter" that outputs "$@" + ruby = runCommand "ruby" {} '' + mkdir -p $out/bin + echo 'printf -- "$*"' > $out/bin/ruby + chmod a+rx $out/bin/ruby + ''; + + inherit pkgs; +}; in pkgs diff --git a/third_party/nix/tests/shell.shebang.rb b/third_party/nix/tests/shell.shebang.rb new file mode 100644 index 000000000000..ea67eb09c1c6 --- /dev/null +++ b/third_party/nix/tests/shell.shebang.rb @@ -0,0 +1,7 @@ +#! @SHELL_PROG@ +#! ruby +#! nix-shell -I nixpkgs=shell.nix --no-substitute +#! nix-shell --pure -p ruby -i ruby + +# Contents doesn't matter. +abort("This shouldn't be executed.") diff --git a/third_party/nix/tests/shell.shebang.sh b/third_party/nix/tests/shell.shebang.sh new file mode 100755 index 000000000000..f7132043de44 --- /dev/null +++ b/third_party/nix/tests/shell.shebang.sh @@ -0,0 +1,4 @@ +#! @ENV_PROG@ nix-shell +#! nix-shell -I nixpkgs=shell.nix --no-substitute +#! nix-shell --pure -i bash -p foo bar +echo "$(foo) $(bar) $@" diff --git a/third_party/nix/tests/signing.sh b/third_party/nix/tests/signing.sh new file mode 100644 index 000000000000..9e29e3fbf063 --- /dev/null +++ b/third_party/nix/tests/signing.sh @@ -0,0 +1,105 @@ +source common.sh + +clearStore +clearCache + +nix-store --generate-binary-cache-key cache1.example.org $TEST_ROOT/sk1 $TEST_ROOT/pk1 +pk1=$(cat $TEST_ROOT/pk1) +nix-store --generate-binary-cache-key cache2.example.org $TEST_ROOT/sk2 $TEST_ROOT/pk2 +pk2=$(cat $TEST_ROOT/pk2) + +# Build a path. +outPath=$(nix-build dependencies.nix --no-out-link --secret-key-files "$TEST_ROOT/sk1 $TEST_ROOT/sk2") + +# Verify that the path got signed. +info=$(nix path-info --json $outPath) +[[ $info =~ '"ultimate":true' ]] +[[ $info =~ 'cache1.example.org' ]] +[[ $info =~ 'cache2.example.org' ]] + +# Test "nix verify". +nix verify -r $outPath + +expect 2 nix verify -r $outPath --sigs-needed 1 + +nix verify -r $outPath --sigs-needed 1 --trusted-public-keys $pk1 + +expect 2 nix verify -r $outPath --sigs-needed 2 --trusted-public-keys $pk1 + +nix verify -r $outPath --sigs-needed 2 --trusted-public-keys "$pk1 $pk2" + +nix 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 + +# 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 + +expect 2 nix verify -r $outPath2 --sigs-needed 1 + +expect 2 nix verify -r $outPath2 --sigs-needed 1 --trusted-public-keys $pk1 + +# Test "nix sign-paths". +nix sign-paths --key-file $TEST_ROOT/sk1 $outPath2 + +nix 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) + +[[ $(nix path-info --json $outPathCA) =~ '"ca":"fixed:md5:' ]] + +# Content-addressed paths don't need signatures, so they verify +# regardless of --sigs-needed. +nix verify $outPathCA +nix 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 + +# Copy to a binary cache. +nix copy --to file://$cacheDir $outPath2 + +# Verify that signatures got copied. +info=$(nix path-info --store file://$cacheDir --json $outPath2) +(! [[ $info =~ '"ultimate":true' ]]) +[[ $info =~ 'cache1.example.org' ]] +(! [[ $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 +info=$(nix path-info --store file://$cacheDir --json $outPath2) +[[ $info =~ 'cache1.example.org' ]] +[[ $info =~ 'cache2.example.org' ]] + +# Copying to a diverted store should fail due to a lack of valid signatures. +chmod -R u+w $TEST_ROOT/store0 || true +rm -rf $TEST_ROOT/store0 +(! nix copy --to $TEST_ROOT/store0 $outPath) + +# 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 + +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" + +# 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 + +# Content-addressed stuff can be copied without signatures. +nix copy --to $TEST_ROOT/store0 $outPathCA diff --git a/third_party/nix/tests/simple.builder.sh b/third_party/nix/tests/simple.builder.sh new file mode 100644 index 000000000000..569e8ca88c1e --- /dev/null +++ b/third_party/nix/tests/simple.builder.sh @@ -0,0 +1,11 @@ +echo "PATH=$PATH" + +# Verify that the PATH is empty. +if mkdir foo 2> /dev/null; then exit 1; fi + +# Set a PATH (!!! impure). +export PATH=$goodPath + +mkdir $out + +echo "Hello World!" > $out/hello \ No newline at end of file diff --git a/third_party/nix/tests/simple.nix b/third_party/nix/tests/simple.nix new file mode 100644 index 000000000000..4223c0f23a5b --- /dev/null +++ b/third_party/nix/tests/simple.nix @@ -0,0 +1,8 @@ +with import ./config.nix; + +mkDerivation { + name = "simple"; + builder = ./simple.builder.sh; + PATH = ""; + goodPath = path; +} diff --git a/third_party/nix/tests/simple.sh b/third_party/nix/tests/simple.sh new file mode 100644 index 000000000000..37631b648c67 --- /dev/null +++ b/third_party/nix/tests/simple.sh @@ -0,0 +1,25 @@ +source common.sh + +drvPath=$(nix-instantiate simple.nix) + +test "$(nix-store -q --binding system "$drvPath")" = "$system" + +echo "derivation is $drvPath" + +outPath=$(nix-store -rvv "$drvPath") + +echo "output path is $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 + +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 + echo "hashDerivationModulo appears broken, got $outPath" + exit 1 +fi diff --git a/third_party/nix/tests/structured-attrs.nix b/third_party/nix/tests/structured-attrs.nix new file mode 100644 index 000000000000..6c77a43913a7 --- /dev/null +++ b/third_party/nix/tests/structured-attrs.nix @@ -0,0 +1,66 @@ +with import ./config.nix; + +let + + dep = mkDerivation { + name = "dep"; + buildCommand = '' + mkdir $out; echo bla > $out/bla + ''; + }; + +in + +mkDerivation { + name = "structured"; + + __structuredAttrs = true; + + buildCommand = '' + set -x + + [[ $int = 123456789 ]] + [[ -z $float ]] + [[ -n $boolTrue ]] + [[ -z $boolFalse ]] + [[ -n ''${hardening[format]} ]] + [[ -z ''${hardening[fortify]} ]] + [[ ''${#buildInputs[@]} = 7 ]] + [[ ''${buildInputs[2]} = c ]] + [[ -v nothing ]] + [[ -z $nothing ]] + + mkdir ''${outputs[out]} + echo bar > $dest + + json=$(cat .attrs.json) + [[ $json =~ '"narHash":"sha256:1r7yc43zqnzl5b0als5vnyp649gk17i37s7mj00xr8kc47rjcybk"' ]] + [[ $json =~ '"narSize":288' ]] + [[ $json =~ '"closureSize":288' ]] + [[ $json =~ '"references":[]' ]] + ''; + + buildInputs = [ "a" "b" "c" 123 "'" "\"" null ]; + + hardening.format = true; + hardening.fortify = false; + + outer.inner = [ 1 2 3 ]; + + int = 123456789; + + float = 123.456; + + boolTrue = true; + boolFalse = false; + + nothing = null; + + dest = "${placeholder "out"}/foo"; + + "foo bar" = "BAD"; + "1foobar" = "BAD"; + "foo$" = "BAD"; + + exportReferencesGraph.refs = [ dep ]; +} diff --git a/third_party/nix/tests/structured-attrs.sh b/third_party/nix/tests/structured-attrs.sh new file mode 100644 index 000000000000..9ba2672b6833 --- /dev/null +++ b/third_party/nix/tests/structured-attrs.sh @@ -0,0 +1,7 @@ +source common.sh + +clearStore + +outPath=$(nix-build structured-attrs.nix --no-out-link) + +[[ $(cat $outPath/foo) = bar ]] diff --git a/third_party/nix/tests/tarball.sh b/third_party/nix/tests/tarball.sh new file mode 100644 index 000000000000..ba534c6261ad --- /dev/null +++ b/third_party/nix/tests/tarball.sh @@ -0,0 +1,28 @@ +source common.sh + +clearStore + +rm -rf $TEST_HOME + +tarroot=$TEST_ROOT/tarball +rm -rf $tarroot +mkdir -p $tarroot +cp dependencies.nix $tarroot/default.nix +cp config.nix dependencies.builder*.sh $tarroot/ + +tarball=$TEST_ROOT/tarball.tar.xz +(cd $TEST_ROOT && tar c tarball) | xz > $tarball + +nix-env -f file://$tarball -qa --out-path | grep -q dependencies + +nix-build -o $TEST_ROOT/result file://$tarball + +nix-build -o $TEST_ROOT/result '<foo>' -I foo=file://$tarball + +nix-build -o $TEST_ROOT/result -E "import (fetchTarball file://$tarball)" + +nix-instantiate --eval -E '1 + 2' -I fnord=file://no-such-tarball.tar.xz +nix-instantiate --eval -E 'with <fnord/xyzzy>; 1 + 2' -I fnord=file://no-such-tarball.tar.xz +(! nix-instantiate --eval -E '<fnord/xyzzy> 1' -I fnord=file://no-such-tarball.tar.xz) + +nix-instantiate --eval -E '<fnord/config.nix>' -I fnord=file://no-such-tarball.tar.xz -I fnord=. diff --git a/third_party/nix/tests/timeout.nix b/third_party/nix/tests/timeout.nix new file mode 100644 index 000000000000..d0e949e31498 --- /dev/null +++ b/third_party/nix/tests/timeout.nix @@ -0,0 +1,31 @@ +with import ./config.nix; + +{ + + infiniteLoop = mkDerivation { + name = "timeout"; + buildCommand = '' + touch $out + echo "'timeout' builder entering an infinite loop" + while true ; do echo -n .; done + ''; + }; + + silent = mkDerivation { + name = "silent"; + buildCommand = '' + touch $out + sleep 60 + ''; + }; + + closeLog = mkDerivation { + name = "silent"; + buildCommand = '' + touch $out + exec > /dev/null 2>&1 + sleep 1000000000 + ''; + }; + +} diff --git a/third_party/nix/tests/timeout.sh b/third_party/nix/tests/timeout.sh new file mode 100644 index 000000000000..eea9b5731da0 --- /dev/null +++ b/third_party/nix/tests/timeout.sh @@ -0,0 +1,40 @@ +# Test the `--timeout' option. + +source common.sh + + +set +e +messages=$(nix-build -Q timeout.nix -A infiniteLoop --timeout 2 2>&1) +status=$? +set -e + +if [ $status -ne 101 ]; then + echo "error: 'nix-store' exited with '$status'; should have exited 101" + exit 1 +fi + +if ! echo "$messages" | grep -q "timed out"; then + echo "error: build may have failed for reasons other than timeout; output:" + echo "$messages" >&2 + exit 1 +fi + +if nix-build -Q timeout.nix -A infiniteLoop --max-build-log-size 100; then + echo "build should have failed" + exit 1 +fi + +if nix-build timeout.nix -A silent --max-silent-time 2; then + echo "build should have failed" + exit 1 +fi + +if nix-build timeout.nix -A closeLog; then + echo "build should have failed" + exit 1 +fi + +if nix build -f timeout.nix silent --max-silent-time 2; then + echo "build should have failed" + exit 1 +fi diff --git a/third_party/nix/tests/user-envs.builder.sh b/third_party/nix/tests/user-envs.builder.sh new file mode 100644 index 000000000000..5fafa797f11e --- /dev/null +++ b/third_party/nix/tests/user-envs.builder.sh @@ -0,0 +1,5 @@ +mkdir $out +mkdir $out/bin +echo "#! $shell" > $out/bin/$progName +echo "echo $name" >> $out/bin/$progName +chmod +x $out/bin/$progName diff --git a/third_party/nix/tests/user-envs.nix b/third_party/nix/tests/user-envs.nix new file mode 100644 index 000000000000..1aa410cc9680 --- /dev/null +++ b/third_party/nix/tests/user-envs.nix @@ -0,0 +1,29 @@ +# Some dummy arguments... +{ foo ? "foo" +}: + +with import ./config.nix; + +assert foo == "foo"; + +let + + makeDrv = name: progName: (mkDerivation { + inherit name progName system; + builder = ./user-envs.builder.sh; + } // { + meta = { + description = "A silly test package"; + }; + }); + +in + + [ + (makeDrv "foo-1.0" "foo") + (makeDrv "foo-2.0pre1" "foo") + (makeDrv "bar-0.1" "bar") + (makeDrv "foo-2.0" "foo") + (makeDrv "bar-0.1.1" "bar") + (makeDrv "foo-0.1" "foo" // { meta.priority = 10; }) + ] diff --git a/third_party/nix/tests/user-envs.sh b/third_party/nix/tests/user-envs.sh new file mode 100644 index 000000000000..aebf6a2a2b87 --- /dev/null +++ b/third_party/nix/tests/user-envs.sh @@ -0,0 +1,181 @@ +source common.sh + +if [ -z "$storeCleared" ]; then + clearStore +fi + +clearProfiles + +# Query installed: should be empty. +test "$(nix-env -p $profiles/test -q '*' | wc -l)" -eq 0 + +mkdir -p $TEST_HOME +nix-env --switch-profile $profiles/test + +# Query available: should contain several. +test "$(nix-env -f ./user-envs.nix -qa '*' | wc -l)" -eq 6 +outPath10=$(nix-env -f ./user-envs.nix -qa --out-path --no-name '*' | grep foo-1.0) +drvPath10=$(nix-env -f ./user-envs.nix -qa --drv-path --no-name '*' | grep foo-1.0) +[ -n "$outPath10" -a -n "$drvPath10" ] + +# Query descriptions. +nix-env -f ./user-envs.nix -qa '*' --description | grep -q silly +rm -rf $HOME/.nix-defexpr +ln -s $(pwd)/user-envs.nix $HOME/.nix-defexpr +nix-env -qa '*' --description | grep -q silly + +# Query the system. +nix-env -qa '*' --system | grep -q $system + +# Install "foo-1.0". +nix-env -i foo-1.0 + +# Query installed: should contain foo-1.0 now (which should be +# executable). +test "$(nix-env -q '*' | wc -l)" -eq 1 +nix-env -q '*' | grep -q foo-1.0 +test "$($profiles/test/bin/foo)" = "foo-1.0" + +# Test nix-env -qc to compare installed against available packages, and vice versa. +nix-env -qc '*' | grep -q '< 2.0' +nix-env -qac '*' | grep -q '> 1.0' + +# Test the -b flag to filter out source-only packages. +[ "$(nix-env -qab | wc -l)" -eq 1 ] + +# Test the -s flag to get package status. +nix-env -qas | grep -q 'IP- foo-1.0' +nix-env -qas | grep -q -- '--- bar-0.1' + +# Disable foo. +nix-env --set-flag active false foo +(! [ -e "$profiles/test/bin/foo" ]) + +# Enable foo. +nix-env --set-flag active true foo +[ -e "$profiles/test/bin/foo" ] + +# Store the path of foo-1.0. +outPath10_=$(nix-env -q --out-path --no-name '*' | grep foo-1.0) +echo "foo-1.0 = $outPath10" +[ "$outPath10" = "$outPath10_" ] + +# Install "foo-2.0pre1": should remove foo-1.0. +nix-env -i foo-2.0pre1 + +# Query installed: should contain foo-2.0pre1 now. +test "$(nix-env -q '*' | wc -l)" -eq 1 +nix-env -q '*' | grep -q foo-2.0pre1 +test "$($profiles/test/bin/foo)" = "foo-2.0pre1" + +# Upgrade "foo": should install foo-2.0. +NIX_PATH=nixpkgs=./user-envs.nix:$NIX_PATH nix-env -f '<nixpkgs>' -u foo + +# Query installed: should contain foo-2.0 now. +test "$(nix-env -q '*' | wc -l)" -eq 1 +nix-env -q '*' | grep -q foo-2.0 +test "$($profiles/test/bin/foo)" = "foo-2.0" + +# Store the path of foo-2.0. +outPath20=$(nix-env -q --out-path --no-name '*' | grep foo-2.0) +test -n "$outPath20" + +# Install bar-0.1, uninstall foo. +nix-env -i bar-0.1 +nix-env -e foo + +# Query installed: should only contain bar-0.1 now. +if nix-env -q '*' | grep -q foo; then false; fi +nix-env -q '*' | grep -q bar + +# Rollback: should bring "foo" back. +oldGen="$(nix-store -q --resolve $profiles/test)" +nix-env --rollback +[ "$(nix-store -q --resolve $profiles/test)" != "$oldGen" ] +nix-env -q '*' | grep -q foo-2.0 +nix-env -q '*' | grep -q bar + +# Rollback again: should remove "bar". +nix-env --rollback +nix-env -q '*' | grep -q foo-2.0 +if nix-env -q '*' | grep -q bar; then false; fi + +# Count generations. +nix-env --list-generations +test "$(nix-env --list-generations | wc -l)" -eq 7 + +# Doing the same operation twice results in the same generation, which triggers +# "lazy" behaviour and does not create a new symlink. + +nix-env -i foo +nix-env -i foo + +# Count generations. +nix-env --list-generations +test "$(nix-env --list-generations | wc -l)" -eq 8 + +# Switch to a specified generation. +nix-env --switch-generation 7 +[ "$(nix-store -q --resolve $profiles/test)" = "$oldGen" ] + +# Install foo-1.0, now using its store path. +nix-env -i "$outPath10" +nix-env -q '*' | grep -q foo-1.0 +nix-store -qR $profiles/test | grep "$outPath10" +nix-store -q --referrers-closure $profiles/test | grep "$(nix-store -q --resolve $profiles/test)" +[ "$(nix-store -q --deriver "$outPath10")" = $drvPath10 ] + +# Uninstall foo-1.0, using a symlink to its store path. +ln -sfn $outPath10/bin/foo $TEST_ROOT/symlink +nix-env -e $TEST_ROOT/symlink +if nix-env -q '*' | grep -q foo; then false; fi +(! nix-store -qR $profiles/test | grep "$outPath10") + +# Install foo-1.0, now using a symlink to its store path. +nix-env -i $TEST_ROOT/symlink +nix-env -q '*' | grep -q foo + +# Delete all old generations. +nix-env --delete-generations old + +# Run the garbage collector. This should get rid of foo-2.0 but not +# foo-1.0. +nix-collect-garbage +test -e "$outPath10" +(! [ -e "$outPath20" ]) + +# Uninstall everything +nix-env -e '*' +test "$(nix-env -q '*' | wc -l)" -eq 0 + +# Installing "foo" should only install the newest foo. +nix-env -i foo +test "$(nix-env -q '*' | grep foo- | wc -l)" -eq 1 +nix-env -q '*' | grep -q foo-2.0 + +# On the other hand, this should install both (and should fail due to +# a collision). +nix-env -e '*' +(! nix-env -i foo-1.0 foo-2.0) + +# Installing "*" should install one foo and one bar. +nix-env -e '*' +nix-env -i '*' +test "$(nix-env -q '*' | wc -l)" -eq 2 +nix-env -q '*' | grep -q foo-2.0 +nix-env -q '*' | grep -q bar-0.1.1 + +# Test priorities: foo-0.1 has a lower priority than foo-1.0, so it +# should be possible to install both without a collision. Also test +# ‘--set-flag priority’ to manually override the declared priorities. +nix-env -e '*' +nix-env -i foo-0.1 foo-1.0 +[ "$($profiles/test/bin/foo)" = "foo-1.0" ] +nix-env --set-flag priority 1 foo-0.1 +[ "$($profiles/test/bin/foo)" = "foo-0.1" ] + +# Test nix-env --set. +nix-env --set $outPath10 +[ "$(nix-store -q --resolve $profiles/test)" = $outPath10 ] +nix-env --set $drvPath10 +[ "$(nix-store -q --resolve $profiles/test)" = $outPath10 ] |