aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorJohn Ericson <John.Ericson@Obsidian.Systems>2023-04-07 09:40:36 -0400
committerJohn Ericson <John.Ericson@Obsidian.Systems>2023-04-07 09:40:36 -0400
commitc036de086e2f06e6dee1c31e29e05a802f6ccf80 (patch)
treea3760ae3cec9cabbab39bd95bd2eaab8e2ce2bdf /tests
parentc863e5f338947ecff275a67725ecf50b2a47bdb5 (diff)
parent81dfc2b01231c65137017de092c8506838fadd94 (diff)
Merge remote-tracking branch 'upstream/master' into trustless-remote-builder-simple
Diffstat (limited to 'tests')
-rw-r--r--tests/bash-profile.sh9
-rw-r--r--tests/binary-cache.sh28
-rw-r--r--tests/build-delete.sh54
-rw-r--r--tests/build-dry.sh23
-rw-r--r--tests/build-hook-ca-fixed.nix10
-rw-r--r--tests/build-hook-ca-floating.nix55
-rw-r--r--tests/build-hook.nix19
-rw-r--r--tests/build-remote-content-addressed-floating.sh2
-rw-r--r--tests/build-remote.sh47
-rw-r--r--tests/build.sh110
-rw-r--r--tests/ca-shell.nix2
-rw-r--r--tests/ca/build-dry.sh6
-rw-r--r--tests/ca/build.sh18
-rw-r--r--tests/ca/common.sh2
-rw-r--r--tests/ca/content-addressed.nix7
-rw-r--r--tests/ca/duplicate-realisation-in-closure.sh2
-rw-r--r--tests/ca/new-build-cmd.sh5
-rwxr-xr-xtests/ca/nix-copy.sh3
-rwxr-xr-xtests/ca/nix-run.sh2
-rwxr-xr-xtests/ca/nix-shell.sh2
-rwxr-xr-xtests/ca/post-hook.sh2
-rwxr-xr-xtests/ca/recursive.sh4
-rwxr-xr-xtests/ca/selfref-gc.sh11
-rw-r--r--tests/ca/signatures.sh3
-rw-r--r--tests/ca/substitute.sh13
-rw-r--r--tests/ca/why-depends.sh5
-rw-r--r--tests/check-refs.nix7
-rw-r--r--tests/check-refs.sh19
-rw-r--r--tests/check-reqs.sh4
-rw-r--r--tests/check.nix2
-rw-r--r--tests/check.sh14
-rw-r--r--tests/common.sh12
-rw-r--r--tests/common.sh.in180
-rw-r--r--tests/common/vars-and-functions.sh.in276
-rw-r--r--tests/completions.sh68
-rw-r--r--tests/compute-levels.sh2
-rw-r--r--tests/config.sh5
-rw-r--r--tests/db-migration.sh11
-rw-r--r--tests/dependencies.sh6
-rw-r--r--tests/describe-stores.sh8
-rw-r--r--tests/eval-store.sh2
-rw-r--r--tests/eval.nix5
-rw-r--r--tests/eval.sh35
-rw-r--r--tests/experimental-features.sh40
-rw-r--r--tests/export-graph.sh2
-rw-r--r--tests/fetchClosure.sh73
-rw-r--r--tests/fetchGit.sh67
-rw-r--r--tests/fetchGitRefs.sh7
-rw-r--r--tests/fetchGitSubmodules.sh39
-rw-r--r--tests/fetchMercurial.sh15
-rw-r--r--tests/fetchPath.sh6
-rw-r--r--tests/fetchTree-file.sh105
-rw-r--r--tests/fetchurl.sh6
-rw-r--r--tests/flakes/absolute-paths.sh17
-rw-r--r--tests/flakes/build-paths.sh66
-rw-r--r--tests/flakes/bundle.sh (renamed from tests/flake-bundler.sh)9
-rw-r--r--tests/flakes/check.sh77
-rw-r--r--tests/flakes/circular.sh49
-rw-r--r--tests/flakes/common.sh70
-rw-r--r--tests/flakes/config.sh (renamed from tests/flake-local-settings.sh)5
-rw-r--r--tests/flakes/flake-in-submodule.sh52
-rw-r--r--tests/flakes/flakes.sh (renamed from tests/flakes.sh)490
-rw-r--r--tests/flakes/follow-paths.sh150
-rw-r--r--tests/flakes/init.sh87
-rw-r--r--tests/flakes/inputs.sh80
-rw-r--r--tests/flakes/mercurial.sh43
-rw-r--r--tests/flakes/run.sh29
-rw-r--r--tests/flakes/search-root.sh (renamed from tests/flake-searching.sh)24
-rw-r--r--tests/flakes/show.sh87
-rw-r--r--tests/flakes/unlocked-override.sh30
-rw-r--r--tests/fmt.sh33
-rwxr-xr-xtests/fmt.simple.sh1
-rwxr-xr-xtests/function-trace.sh40
-rw-r--r--tests/gc-runtime.sh2
-rw-r--r--tests/gc.sh17
-rw-r--r--tests/hash.sh32
-rw-r--r--tests/impure-derivations.nix63
-rw-r--r--tests/impure-derivations.sh56
-rwxr-xr-x[-rw-r--r--]tests/init.sh5
-rwxr-xr-xtests/install-darwin.sh2
-rw-r--r--tests/installer/default.nix244
-rw-r--r--tests/installer/vagrant_insecure_key27
-rw-r--r--tests/lang.sh29
-rw-r--r--tests/lang/eval-fail-foldlStrict-strict-op-application.nix5
-rw-r--r--tests/lang/eval-okay-closure.exp1
-rw-r--r--tests/lang/eval-okay-context-introspection.exp2
-rw-r--r--tests/lang/eval-okay-context-introspection.nix23
-rw-r--r--tests/lang/eval-okay-eq.exp1
-rw-r--r--tests/lang/eval-okay-eq.exp.disabled1
-rw-r--r--tests/lang/eval-okay-foldlStrict-lazy-elements.exp1
-rw-r--r--tests/lang/eval-okay-foldlStrict-lazy-elements.nix9
-rw-r--r--tests/lang/eval-okay-foldlStrict-lazy-initial-accumulator.exp1
-rw-r--r--tests/lang/eval-okay-foldlStrict-lazy-initial-accumulator.nix6
-rw-r--r--tests/lang/eval-okay-fromjson.nix49
-rw-r--r--tests/lang/eval-okay-functionargs.exp1
-rw-r--r--tests/lang/eval-okay-ind-string.nix2
-rw-r--r--tests/lang/eval-okay-intersectAttrs.exp1
-rw-r--r--tests/lang/eval-okay-intersectAttrs.nix50
-rw-r--r--tests/lang/eval-okay-path-antiquotation.exp1
-rw-r--r--tests/lang/eval-okay-path.exp1
-rw-r--r--tests/lang/eval-okay-readDir.exp2
-rw-r--r--tests/lang/eval-okay-readFileType.exp1
-rw-r--r--tests/lang/eval-okay-readFileType.nix6
-rw-r--r--tests/lang/eval-okay-versions.nix3
-rw-r--r--tests/lang/parse-fail-eof-in-string.nix3
l---------tests/lang/readDir/ldir1
l---------tests/lang/readDir/linked1
-rw-r--r--tests/legacy-ssh-store.sh4
-rw-r--r--tests/linux-sandbox.sh11
-rw-r--r--tests/local-store.sh3
-rw-r--r--tests/local.mk53
-rw-r--r--tests/logging.sh11
-rw-r--r--tests/misc.sh12
-rw-r--r--tests/multiple-outputs.nix47
-rw-r--r--tests/multiple-outputs.sh7
-rw-r--r--tests/nar-access.sh4
-rw-r--r--tests/nix-channel.sh25
-rw-r--r--tests/nix-profile.sh181
-rw-r--r--tests/nix-shell.sh51
-rw-r--r--tests/nix_path.sh3
-rw-r--r--tests/nixos/authorization.nix79
-rw-r--r--tests/nixos/containers/containers.nix63
-rw-r--r--tests/nixos/containers/id-test.nix8
-rw-r--r--tests/nixos/containers/systemd-nspawn.nix78
-rw-r--r--tests/nixos/github-flakes.nix (renamed from tests/github-flakes.nix)123
-rw-r--r--tests/nixos/nix-copy-closure.nix (renamed from tests/nix-copy-closure.nix)23
-rw-r--r--tests/nixos/nix-copy.nix85
-rw-r--r--tests/nixos/nss-preload.nix (renamed from tests/nss-preload.nix)88
-rw-r--r--tests/nixos/remote-builds.nix (renamed from tests/remote-builds.nix)27
-rw-r--r--tests/nixos/setuid.nix (renamed from tests/setuid.nix)17
-rw-r--r--tests/nixos/sourcehut-flakes.nix (renamed from tests/sourcehut-flakes.nix)31
-rw-r--r--tests/output-normalization.sh9
-rw-r--r--tests/path-from-hash-part.sh10
-rw-r--r--tests/plugins.sh4
-rw-r--r--tests/plugins/local.mk2
-rw-r--r--tests/plugins/plugintest.cc2
-rw-r--r--tests/post-hook.sh14
-rw-r--r--tests/pure-eval.sh4
-rwxr-xr-xtests/push-to-store-old.sh10
-rwxr-xr-xtests/push-to-store.sh6
-rw-r--r--tests/readfile-context.builder.sh1
-rw-r--r--tests/readfile-context.nix19
-rw-r--r--tests/recursive.sh2
-rw-r--r--tests/remote-store.sh15
-rw-r--r--tests/repl.sh82
-rw-r--r--tests/restricted.sh4
-rw-r--r--tests/search.sh20
-rw-r--r--tests/selfref-gc.sh30
-rw-r--r--tests/shell-hello.nix11
-rw-r--r--tests/shell.sh6
-rw-r--r--tests/signing.sh2
-rw-r--r--tests/store-ping.sh4
-rw-r--r--tests/suggestions.sh44
-rw-r--r--tests/tarball.sh8
-rw-r--r--tests/test-infra.sh85
-rw-r--r--tests/timeout.sh7
-rw-r--r--tests/toString-path.sh8
-rw-r--r--tests/user-envs-migration.sh35
-rw-r--r--tests/user-envs.nix3
-rw-r--r--tests/user-envs.sh61
-rw-r--r--tests/why-depends.sh13
161 files changed, 3965 insertions, 1138 deletions
diff --git a/tests/bash-profile.sh b/tests/bash-profile.sh
new file mode 100644
index 000000000..e2e0d1090
--- /dev/null
+++ b/tests/bash-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/tests/binary-cache.sh b/tests/binary-cache.sh
index 2368884f7..7c64a115c 100644
--- a/tests/binary-cache.sh
+++ b/tests/binary-cache.sh
@@ -1,6 +1,6 @@
source common.sh
-needLocalStore "“--no-require-sigs” can’t be used with the daemon"
+needLocalStore "'--no-require-sigs' can’t be used with the daemon"
# We can produce drvs directly into the binary cache
clearStore
@@ -15,15 +15,15 @@ outPath=$(nix-build dependencies.nix --no-out-link)
nix copy --to file://$cacheDir $outPath
# Test copying build logs to the binary cache.
-nix log --store file://$cacheDir $outPath 2>&1 | grep 'is not available'
+expect 1 nix log --store file://$cacheDir $outPath 2>&1 | grep 'is not available'
nix store copy-log --to file://$cacheDir $outPath
nix log --store file://$cacheDir $outPath | grep FOO
rm -rf $TEST_ROOT/var/log/nix
-nix log $outPath 2>&1 | grep 'is not available'
+expect 1 nix log $outPath 2>&1 | grep 'is not available'
nix log --substituters file://$cacheDir $outPath | grep FOO
# Test copying build logs from the binary cache.
-nix store copy-log --from file://$cacheDir $(nix-store -qd $outPath)
+nix store copy-log --from file://$cacheDir $(nix-store -qd $outPath)^'*'
nix log $outPath | grep FOO
basicDownloadTests() {
@@ -78,8 +78,8 @@ 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
+expect 1 nix-build --substituters "file://$cacheDir" --no-require-sigs dependencies.nix -o $TEST_ROOT/result 2>&1 | tee $TEST_ROOT/log
+grepQuiet "hash mismatch" $TEST_ROOT/log
mv $nar.good $nar
@@ -126,9 +126,9 @@ clearStore
rm -v $(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.*input-0" $TEST_ROOT/log
-grep -q "copying path.*input-2" $TEST_ROOT/log
-grep -q "copying path.*top" $TEST_ROOT/log
+grepQuiet "copying path.*input-0" $TEST_ROOT/log
+grepQuiet "copying path.*input-2" $TEST_ROOT/log
+grepQuiet "copying path.*top" $TEST_ROOT/log
# Idem, but without cached .narinfo.
@@ -136,11 +136,11 @@ clearStore
clearCacheCache
nix-build --substituters "file://$cacheDir" --no-require-sigs dependencies.nix -o $TEST_ROOT/result 2>&1 | tee $TEST_ROOT/log
-grep -q "don't know how to build" $TEST_ROOT/log
-grep -q "building.*input-1" $TEST_ROOT/log
-grep -q "building.*input-2" $TEST_ROOT/log
-grep -q "copying path.*input-0" $TEST_ROOT/log
-grep -q "copying path.*top" $TEST_ROOT/log
+grepQuiet "don't know how to build" $TEST_ROOT/log
+grepQuiet "building.*input-1" $TEST_ROOT/log
+grepQuiet "building.*input-2" $TEST_ROOT/log
+grepQuiet "copying path.*input-0" $TEST_ROOT/log
+grepQuiet "copying path.*top" $TEST_ROOT/log
# Create a signed binary cache.
diff --git a/tests/build-delete.sh b/tests/build-delete.sh
new file mode 100644
index 000000000..9c56b00e8
--- /dev/null
+++ b/tests/build-delete.sh
@@ -0,0 +1,54 @@
+source common.sh
+
+clearStore
+
+# https://github.com/NixOS/nix/issues/6572
+issue_6572_independent_outputs() {
+ nix build -f multiple-outputs.nix --json independent --no-link > $TEST_ROOT/independent.json
+
+ # Make sure that 'nix build' can build a derivation that depends on both outputs of another derivation.
+ p=$(nix build -f multiple-outputs.nix use-independent --no-link --print-out-paths)
+ nix-store --delete "$p" # Clean up for next test
+
+ # Make sure that 'nix build' tracks input-outputs correctly when a single output is already present.
+ nix-store --delete "$(jq -r <$TEST_ROOT/independent.json .[0].outputs.first)"
+ p=$(nix build -f multiple-outputs.nix use-independent --no-link --print-out-paths)
+ cmp $p <<EOF
+first
+second
+EOF
+ nix-store --delete "$p" # Clean up for next test
+
+ # Make sure that 'nix build' tracks input-outputs correctly when a single output is already present.
+ nix-store --delete "$(jq -r <$TEST_ROOT/independent.json .[0].outputs.second)"
+ p=$(nix build -f multiple-outputs.nix use-independent --no-link --print-out-paths)
+ cmp $p <<EOF
+first
+second
+EOF
+ nix-store --delete "$p" # Clean up for next test
+}
+issue_6572_independent_outputs
+
+
+# https://github.com/NixOS/nix/issues/6572
+issue_6572_dependent_outputs() {
+
+ nix build -f multiple-outputs.nix --json a --no-link > $TEST_ROOT/a.json
+
+ # # Make sure that 'nix build' can build a derivation that depends on both outputs of another derivation.
+ p=$(nix build -f multiple-outputs.nix use-a --no-link --print-out-paths)
+ nix-store --delete "$p" # Clean up for next test
+
+ # Make sure that 'nix build' tracks input-outputs correctly when a single output is already present.
+ nix-store --delete "$(jq -r <$TEST_ROOT/a.json .[0].outputs.second)"
+ p=$(nix build -f multiple-outputs.nix use-a --no-link --print-out-paths)
+ cmp $p <<EOF
+first
+second
+EOF
+ nix-store --delete "$p" # Clean up for next test
+}
+if isDaemonNewer "2.12pre0"; then
+ issue_6572_dependent_outputs
+fi
diff --git a/tests/build-dry.sh b/tests/build-dry.sh
index e72533e70..6d1754af5 100644
--- a/tests/build-dry.sh
+++ b/tests/build-dry.sh
@@ -18,9 +18,6 @@ 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
@@ -28,7 +25,6 @@ clearCache
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
@@ -50,3 +46,22 @@ nix build -f dependencies.nix -o $RESULT --dry-run
nix build -f dependencies.nix -o $RESULT
[[ -h $RESULT ]]
+
+###################################################
+# Check the JSON output
+clearStore
+clearCache
+
+RES=$(nix build -f dependencies.nix --dry-run --json)
+
+if [[ -z "${NIX_TESTS_CA_BY_DEFAULT-}" ]]; then
+ echo "$RES" | jq '.[0] | [
+ (.drvPath | test("'$NIX_STORE_DIR'.*\\.drv")),
+ (.outputs.out | test("'$NIX_STORE_DIR'"))
+ ] | all'
+else
+ echo "$RES" | jq '.[0] | [
+ (.drvPath | test("'$NIX_STORE_DIR'.*\\.drv")),
+ .outputs.out == null
+ ] | all'
+fi
diff --git a/tests/build-hook-ca-fixed.nix b/tests/build-hook-ca-fixed.nix
index ec7171ac9..4cb9e85d1 100644
--- a/tests/build-hook-ca-fixed.nix
+++ b/tests/build-hook-ca-fixed.nix
@@ -11,13 +11,13 @@ let
args = ["sh" "-e" args.builder or (builtins.toFile "builder-${args.name}.sh" "if [ -e .attrs.sh ]; then source .attrs.sh; fi; eval \"$buildCommand\"")];
outputHashMode = "recursive";
outputHashAlgo = "sha256";
- } // removeAttrs args ["builder" "meta"])
- // { meta = args.meta or {}; };
+ } // removeAttrs args ["builder" "meta" "passthru"])
+ // { meta = args.meta or {}; passthru = args.passthru or {}; };
input1 = mkDerivation {
shell = busybox;
name = "build-remote-input-1";
- buildCommand = "echo FOO > $out";
+ buildCommand = "echo hi-input1; echo FOO > $out";
requiredSystemFeatures = ["foo"];
outputHash = "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=";
};
@@ -25,7 +25,7 @@ let
input2 = mkDerivation {
shell = busybox;
name = "build-remote-input-2";
- buildCommand = "echo BAR > $out";
+ buildCommand = "echo hi; echo BAR > $out";
requiredSystemFeatures = ["bar"];
outputHash = "sha256-XArauVH91AVwP9hBBQNlkX9ccuPpSYx9o0zeIHb6e+Q=";
};
@@ -34,6 +34,7 @@ let
shell = busybox;
name = "build-remote-input-3";
buildCommand = ''
+ echo hi-input3
read x < ${input2}
echo $x BAZ > $out
'';
@@ -46,6 +47,7 @@ in
mkDerivation {
shell = busybox;
name = "build-remote";
+ passthru = { inherit input1 input2 input3; };
buildCommand =
''
read x < ${input1}
diff --git a/tests/build-hook-ca-floating.nix b/tests/build-hook-ca-floating.nix
index 67295985f..dfdbb82da 100644
--- a/tests/build-hook-ca-floating.nix
+++ b/tests/build-hook-ca-floating.nix
@@ -1,53 +1,6 @@
{ busybox }:
-with import ./config.nix;
-
-let
-
- mkDerivation = args:
- derivation ({
- inherit system;
- builder = busybox;
- args = ["sh" "-e" args.builder or (builtins.toFile "builder-${args.name}.sh" "if [ -e .attrs.sh ]; then source .attrs.sh; fi; eval \"$buildCommand\"")];
- outputHashMode = "recursive";
- outputHashAlgo = "sha256";
- __contentAddressed = true;
- } // removeAttrs args ["builder" "meta"])
- // { meta = args.meta or {}; };
-
- input1 = mkDerivation {
- shell = busybox;
- name = "build-remote-input-1";
- buildCommand = "echo FOO > $out";
- requiredSystemFeatures = ["foo"];
- };
-
- input2 = mkDerivation {
- shell = busybox;
- name = "build-remote-input-2";
- buildCommand = "echo BAR > $out";
- requiredSystemFeatures = ["bar"];
- };
-
- input3 = mkDerivation {
- shell = busybox;
- name = "build-remote-input-3";
- buildCommand = ''
- read x < ${input2}
- echo $x BAZ > $out
- '';
- requiredSystemFeatures = ["baz"];
- };
-
-in
-
- mkDerivation {
- shell = busybox;
- name = "build-remote";
- buildCommand =
- ''
- read x < ${input1}
- read y < ${input3}
- echo "$x $y" > $out
- '';
- }
+import ./build-hook.nix {
+ inherit busybox;
+ contentAddressed = true;
+}
diff --git a/tests/build-hook.nix b/tests/build-hook.nix
index eb16676f0..7effd7903 100644
--- a/tests/build-hook.nix
+++ b/tests/build-hook.nix
@@ -1,28 +1,35 @@
-{ busybox }:
+{ busybox, contentAddressed ? false }:
with import ./config.nix;
let
+ caArgs = if contentAddressed then {
+ outputHashMode = "recursive";
+ outputHashAlgo = "sha256";
+ __contentAddressed = true;
+ } else {};
+
mkDerivation = args:
derivation ({
inherit system;
builder = busybox;
args = ["sh" "-e" args.builder or (builtins.toFile "builder-${args.name}.sh" "if [ -e .attrs.sh ]; then source .attrs.sh; fi; eval \"$buildCommand\"")];
- } // removeAttrs args ["builder" "meta"])
- // { meta = args.meta or {}; };
+ } // removeAttrs args ["builder" "meta" "passthru"]
+ // caArgs)
+ // { meta = args.meta or {}; passthru = args.passthru or {}; };
input1 = mkDerivation {
shell = busybox;
name = "build-remote-input-1";
- buildCommand = "echo FOO > $out";
+ buildCommand = "echo hi-input1; echo FOO > $out";
requiredSystemFeatures = ["foo"];
};
input2 = mkDerivation {
shell = busybox;
name = "build-remote-input-2";
- buildCommand = "echo BAR > $out";
+ buildCommand = "echo hi; echo BAR > $out";
requiredSystemFeatures = ["bar"];
};
@@ -30,6 +37,7 @@ let
shell = busybox;
name = "build-remote-input-3";
buildCommand = ''
+ echo hi-input3
read x < ${input2}
echo $x BAZ > $out
'';
@@ -41,6 +49,7 @@ in
mkDerivation {
shell = busybox;
name = "build-remote";
+ passthru = { inherit input1 input2 input3; };
buildCommand =
''
read x < ${input1}
diff --git a/tests/build-remote-content-addressed-floating.sh b/tests/build-remote-content-addressed-floating.sh
index 13ef47d2d..e83b42b41 100644
--- a/tests/build-remote-content-addressed-floating.sh
+++ b/tests/build-remote-content-addressed-floating.sh
@@ -2,7 +2,7 @@ source common.sh
file=build-hook-ca-floating.nix
-sed -i 's/experimental-features .*/& ca-derivations/' "$NIX_CONF_DIR"/nix.conf
+enableFeatures "ca-derivations"
CONTENT_ADDRESSED=true
diff --git a/tests/build-remote.sh b/tests/build-remote.sh
index 806c6d261..78e12b477 100644
--- a/tests/build-remote.sh
+++ b/tests/build-remote.sh
@@ -1,5 +1,5 @@
-if ! canUseSandbox; then exit 99; fi
-if ! [[ $busybox =~ busybox ]]; then exit 99; fi
+requireSandboxSupport
+[[ $busybox =~ busybox ]] || skipTest "no busybox"
unset NIX_STORE_DIR
unset NIX_STATE_DIR
@@ -7,7 +7,7 @@ unset NIX_STATE_DIR
function join_by { local d=$1; shift; echo -n "$1"; shift; printf "%s" "${@/#/$d}"; }
EXTRA_SYSTEM_FEATURES=()
-if [[ -n "$CONTENT_ADDRESSED" ]]; then
+if [[ -n "${CONTENT_ADDRESSED-}" ]]; then
EXTRA_SYSTEM_FEATURES=("ca-derivations")
fi
@@ -34,28 +34,43 @@ outPath=$(readlink -f $TEST_ROOT/result)
grep 'FOO BAR BAZ' $TEST_ROOT/machine0/$outPath
-set -o pipefail
+testPrintOutPath=$(nix build -L -v -f $file --no-link --print-out-paths --max-jobs 0 \
+ --arg busybox $busybox \
+ --store $TEST_ROOT/machine0 \
+ --builders "$(join_by '; ' "${builders[@]}")"
+)
+
+[[ $testPrintOutPath =~ store.*build-remote ]]
# Ensure that input1 was built on store1 due to the required feature.
-nix path-info --store $TEST_ROOT/machine1 --all \
- | grep builder-build-remote-input-1.sh \
- | grep -v builder-build-remote-input-2.sh \
- | grep -v builder-build-remote-input-3.sh
+output=$(nix path-info --store $TEST_ROOT/machine1 --all)
+echo "$output" | grepQuiet builder-build-remote-input-1.sh
+echo "$output" | grepQuietInverse builder-build-remote-input-2.sh
+echo "$output" | grepQuietInverse builder-build-remote-input-3.sh
+unset output
# Ensure that input2 was built on store2 due to the required feature.
-nix path-info --store $TEST_ROOT/machine2 --all \
- | grep -v builder-build-remote-input-1.sh \
- | grep builder-build-remote-input-2.sh \
- | grep -v builder-build-remote-input-3.sh
+output=$(nix path-info --store $TEST_ROOT/machine2 --all)
+echo "$output" | grepQuietInverse builder-build-remote-input-1.sh
+echo "$output" | grepQuiet builder-build-remote-input-2.sh
+echo "$output" | grepQuietInverse builder-build-remote-input-3.sh
+unset output
# Ensure that input3 was built on store3 due to the required feature.
-nix path-info --store $TEST_ROOT/machine3 --all \
- | grep -v builder-build-remote-input-1.sh \
- | grep -v builder-build-remote-input-2.sh \
- | grep builder-build-remote-input-3.sh
+output=$(nix path-info --store $TEST_ROOT/machine3 --all)
+echo "$output" | grepQuietInverse builder-build-remote-input-1.sh
+echo "$output" | grepQuietInverse builder-build-remote-input-2.sh
+echo "$output" | grepQuiet builder-build-remote-input-3.sh
+unset output
+
+
+for i in input1 input3; do
+nix log --store $TEST_ROOT/machine0 --file "$file" --arg busybox $busybox passthru."$i" | grep hi-$i
+done
# Behavior of keep-failed
out="$(nix-build 2>&1 failing.nix \
+ --no-out-link \
--builders "$(join_by '; ' "${builders[@]}")" \
--keep-failed \
--store $TEST_ROOT/machine0 \
diff --git a/tests/build.sh b/tests/build.sh
index c77f620f7..b579fc374 100644
--- a/tests/build.sh
+++ b/tests/build.sh
@@ -1,19 +1,107 @@
source common.sh
-expectedJSONRegex='\[\{"drvPath":".*multiple-outputs-a.drv","outputs":\{"first":".*multiple-outputs-a-first","second":".*multiple-outputs-a-second"}},\{"drvPath":".*multiple-outputs-b.drv","outputs":\{"out":".*multiple-outputs-b"}}]'
-nix build -f multiple-outputs.nix --json a.all b.all --no-link | jq --exit-status '
+clearStore
+
+# Make sure that 'nix build' returns all outputs by default.
+nix build -f multiple-outputs.nix --json a b --no-link | jq --exit-status '
(.[0] |
(.drvPath | match(".*multiple-outputs-a.drv")) and
- (.outputs.first | match(".*multiple-outputs-a-first")) and
- (.outputs.second | match(".*multiple-outputs-a-second")))
+ (.outputs |
+ (keys | length == 2) and
+ (.first | match(".*multiple-outputs-a-first")) and
+ (.second | match(".*multiple-outputs-a-second"))))
and (.[1] |
(.drvPath | match(".*multiple-outputs-b.drv")) and
- (.outputs.out | match(".*multiple-outputs-b")))
+ (.outputs |
+ (keys | length == 1) and
+ (.out | match(".*multiple-outputs-b"))))
+'
+
+# Test output selection using the '^' syntax.
+nix build -f multiple-outputs.nix --json a^first --no-link | jq --exit-status '
+ (.[0] |
+ (.drvPath | match(".*multiple-outputs-a.drv")) and
+ (.outputs | keys == ["first"]))
+'
+
+nix build -f multiple-outputs.nix --json a^second,first --no-link | jq --exit-status '
+ (.[0] |
+ (.drvPath | match(".*multiple-outputs-a.drv")) and
+ (.outputs | keys == ["first", "second"]))
+'
+
+nix build -f multiple-outputs.nix --json 'a^*' --no-link | jq --exit-status '
+ (.[0] |
+ (.drvPath | match(".*multiple-outputs-a.drv")) and
+ (.outputs | keys == ["first", "second"]))
+'
+
+# Test that 'outputsToInstall' is respected by default.
+nix build -f multiple-outputs.nix --json e --no-link | jq --exit-status '
+ (.[0] |
+ (.drvPath | match(".*multiple-outputs-e.drv")) and
+ (.outputs | keys == ["a_a", "b"]))
+'
+
+# But not when it's overriden.
+nix build -f multiple-outputs.nix --json e^a_a --no-link
+nix build -f multiple-outputs.nix --json e^a_a --no-link | jq --exit-status '
+ (.[0] |
+ (.drvPath | match(".*multiple-outputs-e.drv")) and
+ (.outputs | keys == ["a_a"]))
+'
+
+nix build -f multiple-outputs.nix --json 'e^*' --no-link | jq --exit-status '
+ (.[0] |
+ (.drvPath | match(".*multiple-outputs-e.drv")) and
+ (.outputs | keys == ["a_a", "b", "c"]))
+'
+
+# Test building from raw store path to drv not expression.
+
+drv=$(nix eval -f multiple-outputs.nix --raw a.drvPath)
+if nix build "$drv^not-an-output" --no-link --json; then
+ fail "'not-an-output' should fail to build"
+fi
+
+if nix build "$drv^" --no-link --json; then
+ fail "'empty outputs list' should fail to build"
+fi
+
+if nix build "$drv^*nope" --no-link --json; then
+ fail "'* must be entire string' should fail to build"
+fi
+
+nix build "$drv^first" --no-link --json | jq --exit-status '
+ (.[0] |
+ (.drvPath | match(".*multiple-outputs-a.drv")) and
+ (.outputs |
+ (keys | length == 1) and
+ (.first | match(".*multiple-outputs-a-first")) and
+ (has("second") | not)))
'
-testNormalization () {
- clearStore
- outPath=$(nix-build ./simple.nix --no-out-link)
- test "$(stat -c %Y $outPath)" -eq 1
-}
-testNormalization
+nix build "$drv^first,second" --no-link --json | jq --exit-status '
+ (.[0] |
+ (.drvPath | match(".*multiple-outputs-a.drv")) and
+ (.outputs |
+ (keys | length == 2) and
+ (.first | match(".*multiple-outputs-a-first")) and
+ (.second | match(".*multiple-outputs-a-second"))))
+'
+
+nix build "$drv^*" --no-link --json | jq --exit-status '
+ (.[0] |
+ (.drvPath | match(".*multiple-outputs-a.drv")) and
+ (.outputs |
+ (keys | length == 2) and
+ (.first | match(".*multiple-outputs-a-first")) and
+ (.second | match(".*multiple-outputs-a-second"))))
+'
+
+# Make sure that `--impure` works (regression test for https://github.com/NixOS/nix/issues/6488)
+nix build --impure -f multiple-outputs.nix --json e --no-link | jq --exit-status '
+ (.[0] |
+ (.drvPath | match(".*multiple-outputs-e.drv")) and
+ (.outputs | keys == ["a_a", "b"]))
+'
diff --git a/tests/ca-shell.nix b/tests/ca-shell.nix
index ad2ab6aff..36e1d1526 100644
--- a/tests/ca-shell.nix
+++ b/tests/ca-shell.nix
@@ -1 +1 @@
-{ ... }@args: import ./shell.nix (args // { contentAddressed = true; })
+{ inNixShell ? false, ... }@args: import ./shell.nix (args // { contentAddressed = true; })
diff --git a/tests/ca/build-dry.sh b/tests/ca/build-dry.sh
new file mode 100644
index 000000000..9a72075ec
--- /dev/null
+++ b/tests/ca/build-dry.sh
@@ -0,0 +1,6 @@
+source common.sh
+
+export NIX_TESTS_CA_BY_DEFAULT=1
+
+cd .. && source build-dry.sh
+
diff --git a/tests/ca/build.sh b/tests/ca/build.sh
index c8877f87f..98e1c5125 100644
--- a/tests/ca/build.sh
+++ b/tests/ca/build.sh
@@ -2,14 +2,14 @@
source common.sh
-drv=$(nix-instantiate --experimental-features ca-derivations ./content-addressed.nix -A rootCA --arg seed 1)
-nix --experimental-features 'nix-command ca-derivations' show-derivation --derivation "$drv" --arg seed 1
+drv=$(nix-instantiate ./content-addressed.nix -A rootCA --arg seed 1)
+nix show-derivation "$drv" --arg seed 1
buildAttr () {
local derivationPath=$1
local seedValue=$2
shift; shift
- local args=("--experimental-features" "ca-derivations" "./content-addressed.nix" "-A" "$derivationPath" --arg seed "$seedValue" "--no-out-link")
+ local args=("./content-addressed.nix" "-A" "$derivationPath" --arg seed "$seedValue" "--no-out-link")
args+=("$@")
nix-build "${args[@]}"
}
@@ -19,7 +19,7 @@ testRemoteCache () {
local outPath=$(buildAttr dependentNonCA 1)
nix copy --to file://$cacheDir $outPath
clearStore
- buildAttr dependentNonCA 1 --option substituters file://$cacheDir --no-require-sigs |& (! grep "building dependent-non-ca")
+ buildAttr dependentNonCA 1 --option substituters file://$cacheDir --no-require-sigs |& grepQuietInverse "building dependent-non-ca"
}
testDeterministicCA () {
@@ -37,7 +37,7 @@ testCutoffFor () {
}
testCutoff () {
- # Don't directly build depenentCA, that way we'll make sure we dodn't rely on
+ # Don't directly build dependentCA, that way we'll make sure we don't rely on
# dependent derivations always being already built.
#testDerivation dependentCA
testCutoffFor transitivelyDependentCA
@@ -46,17 +46,17 @@ testCutoff () {
}
testGC () {
- nix-instantiate --experimental-features ca-derivations ./content-addressed.nix -A rootCA --arg seed 5
- nix-collect-garbage --experimental-features ca-derivations --option keep-derivations true
+ nix-instantiate ./content-addressed.nix -A rootCA --arg seed 5
+ nix-collect-garbage --option keep-derivations true
clearStore
buildAttr rootCA 1 --out-link $TEST_ROOT/rootCA
- nix-collect-garbage --experimental-features ca-derivations
+ nix-collect-garbage
buildAttr rootCA 1 -j0
}
testNixCommand () {
clearStore
- nix build --experimental-features 'nix-command ca-derivations' --file ./content-addressed.nix --no-link
+ nix build --file ./content-addressed.nix --no-link
}
# Regression test for https://github.com/NixOS/nix/issues/4775
diff --git a/tests/ca/common.sh b/tests/ca/common.sh
index c5aa34334..b104b5a78 100644
--- a/tests/ca/common.sh
+++ b/tests/ca/common.sh
@@ -1,5 +1,5 @@
source ../common.sh
-sed -i 's/experimental-features .*/& ca-derivations ca-references/' "$NIX_CONF_DIR"/nix.conf
+enableFeatures "ca-derivations"
restartDaemon
diff --git a/tests/ca/content-addressed.nix b/tests/ca/content-addressed.nix
index d328fc92c..81bc4bf5c 100644
--- a/tests/ca/content-addressed.nix
+++ b/tests/ca/content-addressed.nix
@@ -23,7 +23,7 @@ rec {
};
rootCA = mkCADerivation {
name = "rootCA";
- outputs = [ "out" "dev" "foo"];
+ outputs = [ "out" "dev" "foo" ];
buildCommand = ''
echo "building a CA derivation"
echo "The seed is ${toString seed}"
@@ -64,8 +64,7 @@ rec {
dependentFixedOutput = mkDerivation {
name = "dependent-fixed-output";
outputHashMode = "recursive";
- outputHashAlgo = "sha256";
- outputHash = "sha256-QvtAMbUl/uvi+LCObmqOhvNOapHdA2raiI4xG5zI5pA=";
+ outputHash = "sha512-7aJcmSuEuYP5tGKcmGY8bRr/lrCjJlOxP2mIUjO/vMQeg6gx/65IbzRWES8EKiPDOs9z+wF30lEfcwxM/cT4pw==";
buildCommand = ''
cat ${dependentCA}/dep
echo foo > $out
@@ -76,7 +75,7 @@ rec {
buildCommand = ''
mkdir -p $out/bin
echo ${rootCA} # Just to make it depend on it
- echo "" > $out/bin/${name}
+ echo "#! ${shell}" > $out/bin/${name}
chmod +x $out/bin/${name}
'';
};
diff --git a/tests/ca/duplicate-realisation-in-closure.sh b/tests/ca/duplicate-realisation-in-closure.sh
index 74c5d25fd..da9cd8fb4 100644
--- a/tests/ca/duplicate-realisation-in-closure.sh
+++ b/tests/ca/duplicate-realisation-in-closure.sh
@@ -2,8 +2,6 @@ source ./common.sh
requireDaemonNewerThan "2.4pre20210625"
-sed -i 's/experimental-features .*/& ca-derivations ca-references/' "$NIX_CONF_DIR"/nix.conf
-
export REMOTE_STORE_DIR="$TEST_ROOT/remote_store"
export REMOTE_STORE="file://$REMOTE_STORE_DIR"
diff --git a/tests/ca/new-build-cmd.sh b/tests/ca/new-build-cmd.sh
new file mode 100644
index 000000000..432d4d132
--- /dev/null
+++ b/tests/ca/new-build-cmd.sh
@@ -0,0 +1,5 @@
+source common.sh
+
+export NIX_TESTS_CA_BY_DEFAULT=1
+cd ..
+source ./build.sh
diff --git a/tests/ca/nix-copy.sh b/tests/ca/nix-copy.sh
index 2e0dea2d2..7a8307a4e 100755
--- a/tests/ca/nix-copy.sh
+++ b/tests/ca/nix-copy.sh
@@ -2,9 +2,6 @@
source common.sh
-# Globally enable the ca derivations experimental flag
-sed -i 's/experimental-features = .*/& ca-derivations ca-references/' "$NIX_CONF_DIR/nix.conf"
-
export REMOTE_STORE_DIR="$TEST_ROOT/remote_store"
export REMOTE_STORE="file://$REMOTE_STORE_DIR"
diff --git a/tests/ca/nix-run.sh b/tests/ca/nix-run.sh
index 81402af10..5f46518e8 100755
--- a/tests/ca/nix-run.sh
+++ b/tests/ca/nix-run.sh
@@ -2,8 +2,6 @@
source common.sh
-sed -i 's/experimental-features .*/& ca-derivations ca-references nix-command flakes/' "$NIX_CONF_DIR"/nix.conf
-
FLAKE_PATH=path:$PWD
nix run --no-write-lock-file $FLAKE_PATH#runnable
diff --git a/tests/ca/nix-shell.sh b/tests/ca/nix-shell.sh
index 7f1a3a73e..1c5a6639f 100755
--- a/tests/ca/nix-shell.sh
+++ b/tests/ca/nix-shell.sh
@@ -2,8 +2,6 @@
source common.sh
-sed -i 's/experimental-features .*/& ca-derivations ca-references nix-command flakes/' "$NIX_CONF_DIR"/nix.conf
-
CONTENT_ADDRESSED=true
cd ..
source ./nix-shell.sh
diff --git a/tests/ca/post-hook.sh b/tests/ca/post-hook.sh
index 1c9d4f700..705bde9d4 100755
--- a/tests/ca/post-hook.sh
+++ b/tests/ca/post-hook.sh
@@ -4,8 +4,6 @@ source common.sh
requireDaemonNewerThan "2.4pre20210626"
-sed -i 's/experimental-features .*/& ca-derivations ca-references nix-command flakes/' "$NIX_CONF_DIR"/nix.conf
-
export NIX_TESTS_CA_BY_DEFAULT=1
cd ..
source ./post-hook.sh
diff --git a/tests/ca/recursive.sh b/tests/ca/recursive.sh
index 648bf0a91..cd6736b24 100755
--- a/tests/ca/recursive.sh
+++ b/tests/ca/recursive.sh
@@ -4,10 +4,6 @@ source common.sh
requireDaemonNewerThan "2.4pre20210623"
-sed -i 's/experimental-features .*/& ca-derivations ca-references nix-command flakes/' "$NIX_CONF_DIR"/nix.conf
-
export NIX_TESTS_CA_BY_DEFAULT=1
cd ..
source ./recursive.sh
-
-
diff --git a/tests/ca/selfref-gc.sh b/tests/ca/selfref-gc.sh
new file mode 100755
index 000000000..248778894
--- /dev/null
+++ b/tests/ca/selfref-gc.sh
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+
+source common.sh
+
+requireDaemonNewerThan "2.4pre20210626"
+
+enableFeatures "ca-derivations nix-command flakes"
+
+export NIX_TESTS_CA_BY_DEFAULT=1
+cd ..
+source ./selfref-gc.sh
diff --git a/tests/ca/signatures.sh b/tests/ca/signatures.sh
index 0c7d974ea..eb18a4130 100644
--- a/tests/ca/signatures.sh
+++ b/tests/ca/signatures.sh
@@ -1,8 +1,5 @@
source common.sh
-# Globally enable the ca derivations experimental flag
-sed -i 's/experimental-features = .*/& ca-derivations ca-references/' "$NIX_CONF_DIR/nix.conf"
-
clearStore
clearCache
diff --git a/tests/ca/substitute.sh b/tests/ca/substitute.sh
index 3d9001bb8..ea981adc4 100644
--- a/tests/ca/substitute.sh
+++ b/tests/ca/substitute.sh
@@ -25,7 +25,14 @@ buildDrvs --substitute --substituters $REMOTE_STORE --no-require-sigs -j0 transi
# Check that the thing we’ve just substituted has its realisation stored
nix realisation info --file ./content-addressed.nix transitivelyDependentCA
# Check that its dependencies have it too
-nix realisation info --file ./content-addressed.nix dependentCA rootCA
+nix realisation info --file ./content-addressed.nix dependentCA
+# nix realisation info --file ./content-addressed.nix rootCA --outputs out
+
+if isDaemonNewer "2.13"; then
+ pushToStore="../push-to-store.sh"
+else
+ pushToStore="../push-to-store-old.sh"
+fi
# Same thing, but
# 1. With non-ca derivations
@@ -36,7 +43,7 @@ nix realisation info --file ./content-addressed.nix dependentCA rootCA
#
# Regression test for #4725
clearStore
-nix build --file ../simple.nix -L --no-link --post-build-hook ../push-to-store.sh
+nix build --file ../simple.nix -L --no-link --post-build-hook "$pushToStore"
clearStore
rm -r "$REMOTE_STORE_DIR/realisations"
nix build --file ../simple.nix -L --no-link --substitute --substituters "$REMOTE_STORE" --no-require-sigs -j0
@@ -51,7 +58,7 @@ if [[ -z "$(ls "$REMOTE_STORE_DIR/realisations")" ]]; then
fi
# Test the local realisation disk cache
-buildDrvs --post-build-hook ../push-to-store.sh
+buildDrvs --post-build-hook "$pushToStore"
clearStore
# Add the realisations of rootCA to the cachecache
clearCacheCache
diff --git a/tests/ca/why-depends.sh b/tests/ca/why-depends.sh
new file mode 100644
index 000000000..0c079f63b
--- /dev/null
+++ b/tests/ca/why-depends.sh
@@ -0,0 +1,5 @@
+source common.sh
+
+export NIX_TESTS_CA_BY_DEFAULT=1
+
+cd .. && source why-depends.sh
diff --git a/tests/check-refs.nix b/tests/check-refs.nix
index 9d90b0920..99d69a226 100644
--- a/tests/check-refs.nix
+++ b/tests/check-refs.nix
@@ -67,4 +67,11 @@ rec {
disallowedReferences = [test5];
};
+ test11 = makeTest 11 {
+ __structuredAttrs = true;
+ unsafeDiscardReferences.out = true;
+ outputChecks.out.allowedReferences = [];
+ buildCommand = ''echo ${dep} > "''${outputs[out]}"'';
+ };
+
}
diff --git a/tests/check-refs.sh b/tests/check-refs.sh
index 16bbabc40..2778e491d 100644
--- a/tests/check-refs.sh
+++ b/tests/check-refs.sh
@@ -8,14 +8,14 @@ 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
+nix-store -q --references $test1 | grepQuietInverse $test1
+nix-store -q --references $test1 | grepQuiet $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
+nix-store -q --references $test2 | grepQuietInverse $test2
+nix-store -q --references $test2 | grepQuietInverse $dep
+nix-store -q --references $test2 | grepQuiet aux-ref
# test3 should fail (unallowed ref).
(! nix-build -o $RESULT check-refs.nix -A test3)
@@ -40,3 +40,12 @@ nix-build -o $RESULT check-refs.nix -A test7
# test10 should succeed (no disallowed references).
nix-build -o $RESULT check-refs.nix -A test10
+
+if isDaemonNewer 2.12pre20230103; then
+ enableFeatures discard-references
+ restartDaemon
+
+ # test11 should succeed.
+ test11=$(nix-build -o $RESULT check-refs.nix -A test11)
+ [[ -z $(nix-store -q --references "$test11") ]]
+fi
diff --git a/tests/check-reqs.sh b/tests/check-reqs.sh
index e9f65fc2a..856c94cec 100644
--- a/tests/check-reqs.sh
+++ b/tests/check-reqs.sh
@@ -8,8 +8,8 @@ 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 test4) 2>&1 | grepQuiet 'check-reqs-dep1'
+(! nix-build -o $RESULT check-reqs.nix -A test4) 2>&1 | grepQuiet 'check-reqs-dep2'
(! nix-build -o $RESULT check-reqs.nix -A test5)
(! nix-build -o $RESULT check-reqs.nix -A test6)
diff --git a/tests/check.nix b/tests/check.nix
index ed91ff845..ddab8eea9 100644
--- a/tests/check.nix
+++ b/tests/check.nix
@@ -44,7 +44,7 @@ with import ./config.nix;
};
hashmismatch = import <nix/fetchurl.nix> {
- url = "file://" + builtins.getEnv "TMPDIR" + "/dummy";
+ url = "file://" + builtins.getEnv "TEST_ROOT" + "/dummy";
sha256 = "0mdqa9w1p6cmli6976v4wi0sw9r4p5prkj7lzfd1877wk11c9c73";
};
diff --git a/tests/check.sh b/tests/check.sh
index ab48ff865..645b90222 100644
--- a/tests/check.sh
+++ b/tests/check.sh
@@ -37,7 +37,7 @@ checkBuildTempDirRemoved $TEST_ROOT/log
nix-build check.nix -A deterministic --argstr checkBuildId $checkBuildId \
--no-out-link --check --keep-failed 2> $TEST_ROOT/log
-if grep -q 'may not be deterministic' $TEST_ROOT/log; then false; fi
+if grepQuiet 'may not be deterministic' $TEST_ROOT/log; then false; fi
checkBuildTempDirRemoved $TEST_ROOT/log
nix-build check.nix -A nondeterministic --argstr checkBuildId $checkBuildId \
@@ -58,12 +58,6 @@ if checkBuildTempDirRemoved $TEST_ROOT/log; then false; fi
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)
chmod +w $path
@@ -77,13 +71,13 @@ nix-build check.nix -A fetchurl --no-out-link --check
nix-build check.nix -A fetchurl --no-out-link --repair
[[ $(cat $path) != foo ]]
-echo 'Hello World' > $TMPDIR/dummy
+echo 'Hello World' > $TEST_ROOT/dummy
nix-build check.nix -A hashmismatch --no-out-link || status=$?
[ "$status" = "102" ]
-echo -n > $TMPDIR/dummy
+echo -n > $TEST_ROOT/dummy
nix-build check.nix -A hashmismatch --no-out-link
-echo 'Hello World' > $TMPDIR/dummy
+echo 'Hello World' > $TEST_ROOT/dummy
nix-build check.nix -A hashmismatch --no-out-link --check || status=$?
[ "$status" = "102" ]
diff --git a/tests/common.sh b/tests/common.sh
new file mode 100644
index 000000000..8941671d6
--- /dev/null
+++ b/tests/common.sh
@@ -0,0 +1,12 @@
+set -eu -o pipefail
+
+if [[ -z "${COMMON_SH_SOURCED-}" ]]; then
+
+COMMON_SH_SOURCED=1
+
+source "$(readlink -f "$(dirname "${BASH_SOURCE[0]}")")/common/vars-and-functions.sh"
+if [[ -n "${NIX_DAEMON_PACKAGE:-}" ]]; then
+ startDaemon
+fi
+
+fi # COMMON_SH_SOURCED
diff --git a/tests/common.sh.in b/tests/common.sh.in
deleted file mode 100644
index 49068f1c3..000000000
--- a/tests/common.sh.in
+++ /dev/null
@@ -1,180 +0,0 @@
-set -e
-
-if [[ -z "$COMMON_SH_SOURCED" ]]; then
-
-COMMON_SH_SOURCED=1
-
-export TEST_ROOT=$(realpath ${TMPDIR:-/tmp}/nix-test)/${TEST_NAME:-default}
-export NIX_STORE_DIR
-if ! NIX_STORE_DIR=$(readlink -f $TEST_ROOT/store 2> /dev/null); then
- # 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_DAEMON_SOCKET_PATH=$TEST_ROOT/dSocket
-unset NIX_USER_CONF_FILES
-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_CONFIG_HOME
-unset XDG_CONFIG_DIRS
-unset XDG_CACHE_HOME
-mkdir -p $TEST_HOME
-
-export PATH=@bindir@:$PATH
-if [[ -n "${NIX_CLIENT_PACKAGE:-}" ]]; then
- export PATH="$NIX_CLIENT_PACKAGE/bin":$PATH
-fi
-DAEMON_PATH="$PATH"
-if [[ -n "${NIX_DAEMON_PACKAGE:-}" ]]; then
- DAEMON_PATH="${NIX_DAEMON_PACKAGE}/bin:$DAEMON_PATH"
-fi
-coreutils=@coreutils@
-
-export dot=@dot@
-export SHELL="@bash@"
-export PAGER=cat
-export busybox="@sandbox_shell@"
-
-export version=@PACKAGE_VERSION@
-export system=@system@
-
-export IMPURE_VAR1=foo
-export IMPURE_VAR2=bar
-
-cacheDir=$TEST_ROOT/binary-cache
-
-readLink() {
- 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"
- clearProfiles
-}
-
-clearCache() {
- rm -rf "$cacheDir"
-}
-
-clearCacheCache() {
- rm -f $TEST_HOME/.cache/nix/binary-cache*
-}
-
-startDaemon() {
- # Don’t start the daemon twice, as this would just make it loop indefinitely
- if [[ "$NIX_REMOTE" == daemon ]]; then
- return
- fi
- # Start the daemon, wait for the socket to appear. !!!
- # ‘nix-daemon’ should have an option to fork into the background.
- rm -f $NIX_DAEMON_SOCKET_PATH
- PATH=$DAEMON_PATH nix daemon &
- for ((i = 0; i < 300; i++)); do
- if [[ -S $NIX_DAEMON_SOCKET_PATH ]]; then break; fi
- sleep 0.1
- done
- pidDaemon=$!
- trap "killDaemon" EXIT
- export NIX_REMOTE=daemon
-}
-
-killDaemon() {
- kill $pidDaemon
- for i in {0..100}; do
- kill -0 $pidDaemon || break
- sleep 0.1
- done
- kill -9 $pidDaemon || true
- wait $pidDaemon || true
- trap "" EXIT
-}
-
-restartDaemon() {
- [[ -z "${pidDaemon:-}" ]] && return 0
-
- killDaemon
- unset NIX_REMOTE
- startDaemon
-}
-
-if [[ $(uname) == Linux ]] && [[ -L /proc/self/ns/user ]] && unshare --user true; then
- _canUseSandbox=1
-fi
-
-isDaemonNewer () {
- [[ -n "${NIX_DAEMON_PACKAGE:-}" ]] || return 0
- local requiredVersion="$1"
- local daemonVersion=$($NIX_DAEMON_PACKAGE/bin/nix-daemon --version | cut -d' ' -f3)
- [[ $(nix eval --expr "builtins.compareVersions ''$daemonVersion'' ''$requiredVersion''") -ge 0 ]]
-}
-
-requireDaemonNewerThan () {
- isDaemonNewer "$1" || exit 99
-}
-
-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 ]]
-}
-
-needLocalStore() {
- if [[ "$NIX_REMOTE" == "daemon" ]]; then
- echo "Can’t run through the daemon ($1), skipping this test..."
- return 99
- fi
-}
-
-# Just to make it easy to find which tests should be fixed
-buggyNeedLocalStore () {
- needLocalStore
-}
-
-set -x
-
-if [[ -n "${NIX_DAEMON_PACKAGE:-}" ]]; then
- startDaemon
-fi
-
-fi # COMMON_SH_SOURCED
diff --git a/tests/common/vars-and-functions.sh.in b/tests/common/vars-and-functions.sh.in
new file mode 100644
index 000000000..a9e6c802f
--- /dev/null
+++ b/tests/common/vars-and-functions.sh.in
@@ -0,0 +1,276 @@
+set -eu -o pipefail
+
+if [[ -z "${COMMON_VARS_AND_FUNCTIONS_SH_SOURCED-}" ]]; then
+
+COMMON_VARS_AND_FUNCTIONS_SH_SOURCED=1
+
+export PS4='+(${BASH_SOURCE[0]}:$LINENO) '
+
+export TEST_ROOT=$(realpath ${TMPDIR:-/tmp}/nix-test)/${TEST_NAME:-default}
+export NIX_STORE_DIR
+if ! NIX_STORE_DIR=$(readlink -f $TEST_ROOT/store 2> /dev/null); then
+ # 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_DAEMON_SOCKET_PATH=$TEST_ROOT/dSocket
+unset NIX_USER_CONF_FILES
+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_STATE_HOME
+unset XDG_DATA_HOME
+unset XDG_CONFIG_HOME
+unset XDG_CONFIG_DIRS
+unset XDG_CACHE_HOME
+mkdir -p $TEST_HOME
+
+export PATH=@bindir@:$PATH
+if [[ -n "${NIX_CLIENT_PACKAGE:-}" ]]; then
+ export PATH="$NIX_CLIENT_PACKAGE/bin":$PATH
+fi
+DAEMON_PATH="$PATH"
+if [[ -n "${NIX_DAEMON_PACKAGE:-}" ]]; then
+ DAEMON_PATH="${NIX_DAEMON_PACKAGE}/bin:$DAEMON_PATH"
+fi
+coreutils=@coreutils@
+
+export dot=@dot@
+export SHELL="@bash@"
+export PAGER=cat
+export busybox="@sandbox_shell@"
+
+export version=@PACKAGE_VERSION@
+export system=@system@
+
+export BUILD_SHARED_LIBS=@BUILD_SHARED_LIBS@
+
+export IMPURE_VAR1=foo
+export IMPURE_VAR2=bar
+
+cacheDir=$TEST_ROOT/binary-cache
+
+readLink() {
+ ls -l "$1" | sed 's/.*->\ //'
+}
+
+clearProfiles() {
+ profiles="$HOME"/.local/state/nix/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"
+ clearProfiles
+}
+
+clearCache() {
+ rm -rf "$cacheDir"
+}
+
+clearCacheCache() {
+ rm -f $TEST_HOME/.cache/nix/binary-cache*
+}
+
+startDaemon() {
+ # Don’t start the daemon twice, as this would just make it loop indefinitely
+ if [[ "${_NIX_TEST_DAEMON_PID-}" != '' ]]; then
+ return
+ fi
+ # Start the daemon, wait for the socket to appear.
+ rm -f $NIX_DAEMON_SOCKET_PATH
+ PATH=$DAEMON_PATH nix-daemon &
+ _NIX_TEST_DAEMON_PID=$!
+ export _NIX_TEST_DAEMON_PID
+ for ((i = 0; i < 300; i++)); do
+ if [[ -S $NIX_DAEMON_SOCKET_PATH ]]; then
+ DAEMON_STARTED=1
+ break;
+ fi
+ sleep 0.1
+ done
+ if [[ -z ${DAEMON_STARTED+x} ]]; then
+ fail "Didn’t manage to start the daemon"
+ fi
+ trap "killDaemon" EXIT
+ # Save for if daemon is killed
+ NIX_REMOTE_OLD=$NIX_REMOTE
+ export NIX_REMOTE=daemon
+}
+
+killDaemon() {
+ # Don’t fail trying to stop a non-existant daemon twice
+ if [[ "${_NIX_TEST_DAEMON_PID-}" == '' ]]; then
+ return
+ fi
+ kill $_NIX_TEST_DAEMON_PID
+ for i in {0..100}; do
+ kill -0 $_NIX_TEST_DAEMON_PID 2> /dev/null || break
+ sleep 0.1
+ done
+ kill -9 $_NIX_TEST_DAEMON_PID 2> /dev/null || true
+ wait $_NIX_TEST_DAEMON_PID || true
+ rm -f $NIX_DAEMON_SOCKET_PATH
+ # Indicate daemon is stopped
+ unset _NIX_TEST_DAEMON_PID
+ # Restore old nix remote
+ NIX_REMOTE=$NIX_REMOTE_OLD
+ trap "" EXIT
+}
+
+restartDaemon() {
+ [[ -z "${_NIX_TEST_DAEMON_PID:-}" ]] && return 0
+
+ killDaemon
+ startDaemon
+}
+
+if [[ $(uname) == Linux ]] && [[ -L /proc/self/ns/user ]] && unshare --user true; then
+ _canUseSandbox=1
+fi
+
+isDaemonNewer () {
+ [[ -n "${NIX_DAEMON_PACKAGE:-}" ]] || return 0
+ local requiredVersion="$1"
+ local daemonVersion=$($NIX_DAEMON_PACKAGE/bin/nix-daemon --version | cut -d' ' -f3)
+ [[ $(nix eval --expr "builtins.compareVersions ''$daemonVersion'' ''$requiredVersion''") -ge 0 ]]
+}
+
+skipTest () {
+ echo "$1, skipping this test..." >&2
+ exit 99
+}
+
+requireDaemonNewerThan () {
+ isDaemonNewer "$1" || skipTest "Daemon is too old"
+}
+
+canUseSandbox() {
+ [[ ${_canUseSandbox-} ]]
+}
+
+requireSandboxSupport () {
+ canUseSandbox || skipTest "Sandboxing not supported"
+}
+
+requireGit() {
+ [[ $(type -p git) ]] || skipTest "Git not installed"
+}
+
+fail() {
+ echo "$1" >&2
+ exit 1
+}
+
+# Run a command failing if it didn't exit with the expected exit code.
+#
+# Has two advantages over the built-in `!`:
+#
+# 1. `!` conflates all non-0 codes. `expect` allows testing for an exact
+# code.
+#
+# 2. `!` unexpectedly negates `set -e`, and cannot be used on individual
+# pipeline stages with `set -o pipefail`. It only works on the entire
+# pipeline, which is useless if we want, say, `nix ...` invocation to
+# *fail*, but a grep on the error message it outputs to *succeed*.
+expect() {
+ local expected res
+ expected="$1"
+ shift
+ "$@" && res=0 || res="$?"
+ if [[ $res -ne $expected ]]; then
+ echo "Expected '$expected' but got '$res' while running '${*@Q}'" >&2
+ return 1
+ fi
+ return 0
+}
+
+# Better than just doing `expect ... >&2` because the "Expected..."
+# message below will *not* be redirected.
+expectStderr() {
+ local expected res
+ expected="$1"
+ shift
+ "$@" 2>&1 && res=0 || res="$?"
+ if [[ $res -ne $expected ]]; then
+ echo "Expected '$expected' but got '$res' while running '${*@Q}'" >&2
+ return 1
+ fi
+ return 0
+}
+
+needLocalStore() {
+ if [[ "$NIX_REMOTE" == "daemon" ]]; then
+ skipTest "Can’t run through the daemon ($1)"
+ fi
+}
+
+# Just to make it easy to find which tests should be fixed
+buggyNeedLocalStore() {
+ needLocalStore "$1"
+}
+
+enableFeatures() {
+ local features="$1"
+ sed -i 's/experimental-features .*/& '"$features"'/' "$NIX_CONF_DIR"/nix.conf
+}
+
+set -x
+
+onError() {
+ set +x
+ echo "$0: test failed at:" >&2
+ for ((i = 1; i < ${#BASH_SOURCE[@]}; i++)); do
+ if [[ -z ${BASH_SOURCE[i]} ]]; then break; fi
+ echo " ${FUNCNAME[i]} in ${BASH_SOURCE[i]}:${BASH_LINENO[i-1]}" >&2
+ done
+}
+
+# `grep -v` doesn't work well for exit codes. We want `!(exist line l. l
+# matches)`. It gives us `exist line l. !(l matches)`.
+#
+# `!` normally doesn't work well with `set -e`, but when we wrap in a
+# function it *does*.
+grepInverse() {
+ ! grep "$@"
+}
+
+# A shorthand, `> /dev/null` is a bit noisy.
+#
+# `grep -q` would seem to do this, no function necessary, but it is a
+# bad fit with pipes and `set -o pipefail`: `-q` will exit after the
+# first match, and then subsequent writes will result in broken pipes.
+#
+# Note that reproducing the above is a bit tricky as it depends on
+# non-deterministic properties such as the timing between the match and
+# the closing of the pipe, the buffering of the pipe, and the speed of
+# the producer into the pipe. But rest assured we've seen it happen in
+# CI reliably.
+grepQuiet() {
+ grep "$@" > /dev/null
+}
+
+# The previous two, combined
+grepQuietInverse() {
+ ! grep "$@" > /dev/null
+}
+
+trap onError ERR
+
+fi # COMMON_VARS_AND_FUNCTIONS_SH_SOURCED
diff --git a/tests/completions.sh b/tests/completions.sh
new file mode 100644
index 000000000..19dc61098
--- /dev/null
+++ b/tests/completions.sh
@@ -0,0 +1,68 @@
+source common.sh
+
+cd "$TEST_ROOT"
+
+mkdir -p dep
+cat <<EOF > dep/flake.nix
+{
+ outputs = i: { };
+}
+EOF
+mkdir -p foo
+cat <<EOF > foo/flake.nix
+{
+ inputs.a.url = "path:$(realpath dep)";
+
+ outputs = i: {
+ sampleOutput = 1;
+ };
+}
+EOF
+mkdir -p bar
+cat <<EOF > bar/flake.nix
+{
+ inputs.b.url = "path:$(realpath dep)";
+
+ outputs = i: {
+ sampleOutput = 1;
+ };
+}
+EOF
+mkdir -p err
+cat <<EOF > err/flake.nix
+throw "error"
+EOF
+
+# Test the completion of a subcommand
+[[ "$(NIX_GET_COMPLETIONS=1 nix buil)" == $'normal\nbuild\t' ]]
+[[ "$(NIX_GET_COMPLETIONS=2 nix flake metad)" == $'normal\nmetadata\t' ]]
+
+# Filename completion
+[[ "$(NIX_GET_COMPLETIONS=2 nix build ./f)" == $'filenames\n./foo\t' ]]
+[[ "$(NIX_GET_COMPLETIONS=2 nix build ./nonexistent)" == $'filenames' ]]
+
+# Input override completion
+[[ "$(NIX_GET_COMPLETIONS=4 nix build ./foo --override-input '')" == $'normal\na\t' ]]
+[[ "$(NIX_GET_COMPLETIONS=5 nix flake show ./foo --override-input '')" == $'normal\na\t' ]]
+## With multiple input flakes
+[[ "$(NIX_GET_COMPLETIONS=5 nix build ./foo ./bar --override-input '')" == $'normal\na\t\nb\t' ]]
+## With tilde expansion
+[[ "$(HOME=$PWD NIX_GET_COMPLETIONS=4 nix build '~/foo' --override-input '')" == $'normal\na\t' ]]
+## Out of order
+[[ "$(NIX_GET_COMPLETIONS=3 nix build --update-input '' ./foo)" == $'normal\na\t' ]]
+[[ "$(NIX_GET_COMPLETIONS=4 nix build ./foo --update-input '' ./bar)" == $'normal\na\t\nb\t' ]]
+
+# Cli flag completion
+NIX_GET_COMPLETIONS=2 nix build --log-form | grep -- "--log-format"
+
+# Config option completion
+## With `--option`
+NIX_GET_COMPLETIONS=3 nix build --option allow-import-from | grep -- "allow-import-from-derivation"
+## As a cli flag – not working atm
+# NIX_GET_COMPLETIONS=2 nix build --allow-import-from | grep -- "allow-import-from-derivation"
+
+# Attr path completions
+[[ "$(NIX_GET_COMPLETIONS=2 nix eval ./foo\#sam)" == $'attrs\n./foo#sampleOutput\t' ]]
+[[ "$(NIX_GET_COMPLETIONS=4 nix eval --file ./foo/flake.nix outp)" == $'attrs\noutputs\t' ]]
+[[ "$(NIX_GET_COMPLETIONS=4 nix eval --file ./err/flake.nix outp 2>&1)" == $'attrs' ]]
+[[ "$(NIX_GET_COMPLETIONS=2 nix eval ./err\# 2>&1)" == $'attrs' ]]
diff --git a/tests/compute-levels.sh b/tests/compute-levels.sh
index e4322dfa1..de3da2ebd 100644
--- a/tests/compute-levels.sh
+++ b/tests/compute-levels.sh
@@ -3,5 +3,5 @@ source common.sh
if [[ $(uname -ms) = "Linux x86_64" ]]; then
# x86_64 CPUs must always support the baseline
# microarchitecture level.
- nix -vv --version | grep -q "x86_64-v1-linux"
+ nix -vv --version | grepQuiet "x86_64-v1-linux"
fi
diff --git a/tests/config.sh b/tests/config.sh
index 3d0da3cef..723f575ed 100644
--- a/tests/config.sh
+++ b/tests/config.sh
@@ -51,3 +51,8 @@ exp_features=$(nix show-config | grep '^experimental-features' | cut -d '=' -f 2
[[ $prev != $exp_cores ]]
[[ $exp_cores == "4242" ]]
[[ $exp_features == "flakes nix-command" ]]
+
+# Test that it's possible to retrieve a single setting's value
+val=$(nix show-config | grep '^warn-dirty' | cut -d '=' -f 2 | xargs)
+val2=$(nix show-config warn-dirty)
+[[ $val == $val2 ]]
diff --git a/tests/db-migration.sh b/tests/db-migration.sh
index 3f9dc8972..44cd16bc0 100644
--- a/tests/db-migration.sh
+++ b/tests/db-migration.sh
@@ -1,19 +1,18 @@
# Test that we can successfully migrate from an older db schema
+source common.sh
+
# Only run this if we have an older Nix available
# XXX: This assumes that the `daemon` package is older than the `client` one
-if [[ -z "$NIX_DAEMON_PACKAGE" ]]; then
- exit 99
+if [[ -z "${NIX_DAEMON_PACKAGE-}" ]]; then
+ skipTest "not using the Nix daemon"
fi
-source common.sh
-
killDaemon
-unset NIX_REMOTE
# Fill the db using the older Nix
PATH_WITH_NEW_NIX="$PATH"
-export PATH="$NIX_DAEMON_PACKAGE/bin:$PATH"
+export PATH="${NIX_DAEMON_PACKAGE}/bin:$PATH"
clearStore
nix-build simple.nix --no-out-link
nix-store --generate-binary-cache-key cache1.example.org $TEST_ROOT/sk1 $TEST_ROOT/pk1
diff --git a/tests/dependencies.sh b/tests/dependencies.sh
index 092950aa7..f9da0c6bc 100644
--- a/tests/dependencies.sh
+++ b/tests/dependencies.sh
@@ -36,10 +36,10 @@ deps=$(nix-store -quR "$drvPath")
echo "output closure contains $deps"
# The output path should be in the closure.
-echo "$deps" | grep -q "$outPath"
+echo "$deps" | grepQuiet "$outPath"
# Input-1 is not retained.
-if echo "$deps" | grep -q "dependencies-input-1"; then exit 1; fi
+if echo "$deps" | grepQuiet "dependencies-input-1"; then exit 1; fi
# Input-2 is retained.
input2OutPath=$(echo "$deps" | grep "dependencies-input-2")
@@ -49,4 +49,4 @@ 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"
+nix-store -q --deriver "$input2OutPath" | grepQuiet -- "-input-2.drv"
diff --git a/tests/describe-stores.sh b/tests/describe-stores.sh
deleted file mode 100644
index 3fea61483..000000000
--- a/tests/describe-stores.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-source common.sh
-
-# Query an arbitrary value in `nix describe-stores --json`'s output just to
-# check that it has the right structure
-[[ $(nix --experimental-features 'nix-command flakes' describe-stores --json | jq '.["SSH Store"]["compress"]["defaultValue"]') == false ]]
-
-# Ensure that the output of `nix describe-stores` isn't empty
-[[ -n $(nix --experimental-features 'nix-command flakes' describe-stores) ]]
diff --git a/tests/eval-store.sh b/tests/eval-store.sh
index 679da5741..8fc859730 100644
--- a/tests/eval-store.sh
+++ b/tests/eval-store.sh
@@ -2,7 +2,7 @@ source common.sh
# Using `--eval-store` with the daemon will eventually copy everything
# to the build store, invalidating most of the tests here
-needLocalStore
+needLocalStore "“--eval-store” doesn't achieve much with the daemon"
eval_store=$TEST_ROOT/eval-store
diff --git a/tests/eval.nix b/tests/eval.nix
new file mode 100644
index 000000000..befbd17a9
--- /dev/null
+++ b/tests/eval.nix
@@ -0,0 +1,5 @@
+{
+ int = 123;
+ str = "foo";
+ attr.foo = "bar";
+}
diff --git a/tests/eval.sh b/tests/eval.sh
new file mode 100644
index 000000000..ffae08a6a
--- /dev/null
+++ b/tests/eval.sh
@@ -0,0 +1,35 @@
+source common.sh
+
+clearStore
+
+testStdinHeredoc=$(nix eval -f - <<EOF
+{
+ bar = 3 + 1;
+ foo = 2 + 2;
+}
+EOF
+)
+[[ $testStdinHeredoc == '{ bar = 4; foo = 4; }' ]]
+
+nix eval --expr 'assert 1 + 2 == 3; true'
+
+[[ $(nix eval int -f "./eval.nix") == 123 ]]
+[[ $(nix eval str -f "./eval.nix") == '"foo"' ]]
+[[ $(nix eval str --raw -f "./eval.nix") == 'foo' ]]
+[[ $(nix eval attr -f "./eval.nix") == '{ foo = "bar"; }' ]]
+[[ $(nix eval attr --json -f "./eval.nix") == '{"foo":"bar"}' ]]
+[[ $(nix eval int -f - < "./eval.nix") == 123 ]]
+
+# Check if toFile can be utilized during restricted eval
+[[ $(nix eval --restrict-eval --expr 'import (builtins.toFile "source" "42")') == 42 ]]
+
+nix-instantiate --eval -E 'assert 1 + 2 == 3; true'
+[[ $(nix-instantiate -A int --eval "./eval.nix") == 123 ]]
+[[ $(nix-instantiate -A str --eval "./eval.nix") == '"foo"' ]]
+[[ $(nix-instantiate -A attr --eval "./eval.nix") == '{ foo = "bar"; }' ]]
+[[ $(nix-instantiate -A attr --eval --json "./eval.nix") == '{"foo":"bar"}' ]]
+[[ $(nix-instantiate -A int --eval - < "./eval.nix") == 123 ]]
+
+# Check that symlink cycles don't cause a hang.
+ln -sfn cycle.nix $TEST_ROOT/cycle.nix
+(! nix eval --file $TEST_ROOT/cycle.nix)
diff --git a/tests/experimental-features.sh b/tests/experimental-features.sh
new file mode 100644
index 000000000..a4d55f5f4
--- /dev/null
+++ b/tests/experimental-features.sh
@@ -0,0 +1,40 @@
+source common.sh
+
+# Without flakes, flake options should not show up
+# With flakes, flake options should show up
+
+function both_ways {
+ nix --experimental-features 'nix-command' "$@" | grepQuietInverse flake
+ nix --experimental-features 'nix-command flakes' "$@" | grepQuiet flake
+
+ # Also, the order should not matter
+ nix "$@" --experimental-features 'nix-command' | grepQuietInverse flake
+ nix "$@" --experimental-features 'nix-command flakes' | grepQuiet flake
+}
+
+# Simple case, the configuration effects the running command
+both_ways show-config
+
+# Skipping for now, because we actually *do* want these to show up in
+# the manual, just be marked experimental. Will reenable once the manual
+# generation takes advantage of the JSON metadata on this.
+
+# both_ways store gc --help
+
+expect 1 nix --experimental-features 'nix-command' show-config --flake-registry 'https://no'
+nix --experimental-features 'nix-command flakes' show-config --flake-registry 'https://no'
+
+# Double check these are stable
+nix --experimental-features '' --help
+nix --experimental-features '' doctor --help
+nix --experimental-features '' repl --help
+nix --experimental-features '' upgrade-nix --help
+
+# These 3 arguments are currently given to all commands, which is wrong (as not
+# all care). To deal with fixing later, we simply make them require the
+# nix-command experimental features --- it so happens that the commands we wish
+# stabilizing to do not need them anyways.
+for arg in '--print-build-logs' '--offline' '--refresh'; do
+ nix --experimental-features 'nix-command' "$arg" --help
+ ! nix --experimental-features '' "$arg" --help
+done
diff --git a/tests/export-graph.sh b/tests/export-graph.sh
index a1449b34e..1f6232a40 100644
--- a/tests/export-graph.sh
+++ b/tests/export-graph.sh
@@ -4,7 +4,7 @@ clearStore
clearProfiles
checkRef() {
- nix-store -q --references $TEST_ROOT/result | grep -q "$1" || fail "missing reference $1"
+ nix-store -q --references $TEST_ROOT/result | grepQuiet "$1"'$' || fail "missing reference $1"
}
# Test the export of the runtime dependency graph.
diff --git a/tests/fetchClosure.sh b/tests/fetchClosure.sh
new file mode 100644
index 000000000..a207f647c
--- /dev/null
+++ b/tests/fetchClosure.sh
@@ -0,0 +1,73 @@
+source common.sh
+
+enableFeatures "fetch-closure"
+
+clearStore
+clearCacheCache
+
+# Initialize binary cache.
+nonCaPath=$(nix build --json --file ./dependencies.nix --no-link | jq -r .[].outputs.out)
+caPath=$(nix store make-content-addressed --json $nonCaPath | jq -r '.rewrites | map(.) | .[]')
+nix copy --to file://$cacheDir $nonCaPath
+
+# Test basic fetchClosure rewriting from non-CA to CA.
+clearStore
+
+[ ! -e $nonCaPath ]
+[ ! -e $caPath ]
+
+[[ $(nix eval -v --raw --expr "
+ builtins.fetchClosure {
+ fromStore = \"file://$cacheDir\";
+ fromPath = $nonCaPath;
+ toPath = $caPath;
+ }
+") = $caPath ]]
+
+[ ! -e $nonCaPath ]
+[ -e $caPath ]
+
+if [[ "$NIX_REMOTE" != "daemon" ]]; then
+
+ # In impure mode, we can use non-CA paths.
+ [[ $(nix eval --raw --no-require-sigs --impure --expr "
+ builtins.fetchClosure {
+ fromStore = \"file://$cacheDir\";
+ fromPath = $nonCaPath;
+ }
+ ") = $nonCaPath ]]
+
+ [ -e $nonCaPath ]
+
+fi
+
+# 'toPath' set to empty string should fail but print the expected path.
+expectStderr 1 nix eval -v --json --expr "
+ builtins.fetchClosure {
+ fromStore = \"file://$cacheDir\";
+ fromPath = $nonCaPath;
+ toPath = \"\";
+ }
+" | grep "error: rewriting.*$nonCaPath.*yielded.*$caPath"
+
+# If fromPath is CA, then toPath isn't needed.
+nix copy --to file://$cacheDir $caPath
+
+[[ $(nix eval -v --raw --expr "
+ builtins.fetchClosure {
+ fromStore = \"file://$cacheDir\";
+ fromPath = $caPath;
+ }
+") = $caPath ]]
+
+# Check that URL query parameters aren't allowed.
+clearStore
+narCache=$TEST_ROOT/nar-cache
+rm -rf $narCache
+(! nix eval -v --raw --expr "
+ builtins.fetchClosure {
+ fromStore = \"file://$cacheDir?local-nar-cache=$narCache\";
+ fromPath = $caPath;
+ }
+")
+(! [ -e $narCache ])
diff --git a/tests/fetchGit.sh b/tests/fetchGit.sh
index 89294d8d2..e2ccb0e97 100644
--- a/tests/fetchGit.sh
+++ b/tests/fetchGit.sh
@@ -1,17 +1,16 @@
source common.sh
-if [[ -z $(type -p git) ]]; then
- echo "Git not installed; skipping Git tests"
- exit 99
-fi
+requireGit
clearStore
-repo=$TEST_ROOT/git
+# Intentionally not in a canonical form
+# See https://github.com/NixOS/nix/issues/6195
+repo=$TEST_ROOT/./git
export _NIX_FORCE_HTTP=1
-rm -rf $repo ${repo}-tmp $TEST_HOME/.cache/nix $TEST_ROOT/worktree $TEST_ROOT/shallow
+rm -rf $repo ${repo}-tmp $TEST_HOME/.cache/nix $TEST_ROOT/worktree $TEST_ROOT/shallow $TEST_ROOT/minimal
git init $repo
git -C $repo config user.email "foobar@example.com"
@@ -22,12 +21,14 @@ touch $repo/.gitignore
git -C $repo add hello .gitignore
git -C $repo commit -m 'Bla1'
rev1=$(git -C $repo rev-parse HEAD)
+git -C $repo tag -a tag1 -m tag1
echo world > $repo/hello
git -C $repo commit -m 'Bla2' -a
git -C $repo worktree add $TEST_ROOT/worktree
echo hello >> $TEST_ROOT/worktree/hello
rev2=$(git -C $repo rev-parse HEAD)
+git -C $repo tag -a tag2 -m tag2
# Fetch a worktree
unset _NIX_FORCE_HTTP
@@ -118,6 +119,7 @@ git -C $repo commit -m 'Bla3' -a
path4=$(nix eval --impure --refresh --raw --expr "(builtins.fetchGit file://$repo).outPath")
[[ $path2 = $path4 ]]
+status=0
nix eval --impure --raw --expr "(builtins.fetchGit { url = $repo; rev = \"$rev2\"; narHash = \"sha256-B5yIPHhEm0eysJKEsO7nqxprh9vcblFxpJG11gXJus1=\"; }).outPath" || status=$?
[[ "$status" = "102" ]]
@@ -147,13 +149,26 @@ path3=$(nix eval --impure --raw --expr "(builtins.fetchGit $repo).outPath")
# (check dirty-tree handling was used)
[[ $(nix eval --impure --raw --expr "(builtins.fetchGit $repo).rev") = 0000000000000000000000000000000000000000 ]]
[[ $(nix eval --impure --raw --expr "(builtins.fetchGit $repo).shortRev") = 0000000 ]]
+# Making a dirty tree clean again and fetching it should
+# record correct revision information. See: #4140
+echo world > $repo/hello
+[[ $(nix eval --impure --raw --expr "(builtins.fetchGit $repo).rev") = $rev2 ]]
# Committing shouldn't change store path, or switch to using 'master'
+echo dev > $repo/hello
git -C $repo commit -m 'Bla5' -a
path4=$(nix eval --impure --raw --expr "(builtins.fetchGit $repo).outPath")
[[ $(cat $path4/hello) = dev ]]
[[ $path3 = $path4 ]]
+# Using remote path with branch other than 'master' should fetch the HEAD revision.
+# (--tarball-ttl 0 to prevent using the cached repo above)
+export _NIX_FORCE_HTTP=1
+path4=$(nix eval --tarball-ttl 0 --impure --raw --expr "(builtins.fetchGit $repo).outPath")
+[[ $(cat $path4/hello) = dev ]]
+[[ $path3 = $path4 ]]
+unset _NIX_FORCE_HTTP
+
# Confirm same as 'dev' branch
path5=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = $repo; ref = \"dev\"; }).outPath")
[[ $path3 = $path5 ]]
@@ -170,6 +185,14 @@ NIX=$(command -v nix)
path5=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = $repo; ref = \"dev\"; }).outPath")
[[ $path3 = $path5 ]]
+# Fetching from a repo with only a specific revision and no branches should
+# not fall back to copying files and record correct revision information. See: #5302
+mkdir $TEST_ROOT/minimal
+git -C $TEST_ROOT/minimal init
+git -C $TEST_ROOT/minimal fetch $repo $rev2
+git -C $TEST_ROOT/minimal checkout $rev2
+[[ $(nix eval --impure --raw --expr "(builtins.fetchGit { url = $TEST_ROOT/minimal; }).rev") = $rev2 ]]
+
# Fetching a shallow repo shouldn't work by default, because we can't
# return a revCount.
git clone --depth 1 file://$repo $TEST_ROOT/shallow
@@ -193,3 +216,35 @@ rev4_nix=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = \"file://$
# The name argument should be handled
path9=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = \"file://$repo\"; ref = \"HEAD\"; name = \"foo\"; }).outPath")
[[ $path9 =~ -foo$ ]]
+
+# Specifying a ref without a rev shouldn't pick a cached rev for a different ref
+export _NIX_FORCE_HTTP=1
+rev_tag1_nix=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = \"file://$repo\"; ref = \"refs/tags/tag1\"; }).rev")
+rev_tag1=$(git -C $repo rev-parse refs/tags/tag1)
+[[ $rev_tag1_nix = $rev_tag1 ]]
+rev_tag2_nix=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = \"file://$repo\"; ref = \"refs/tags/tag2\"; }).rev")
+rev_tag2=$(git -C $repo rev-parse refs/tags/tag2)
+[[ $rev_tag2_nix = $rev_tag2 ]]
+unset _NIX_FORCE_HTTP
+
+# should fail if there is no repo
+rm -rf $repo/.git
+(! nix eval --impure --raw --expr "(builtins.fetchGit \"file://$repo\").outPath")
+
+# should succeed for a repo without commits
+git init $repo
+path10=$(nix eval --impure --raw --expr "(builtins.fetchGit \"file://$repo\").outPath")
+
+# should succeed for a path with a space
+# regression test for #7707
+repo="$TEST_ROOT/a b"
+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'
+cd "$repo"
+path11=$(nix eval --impure --raw --expr "(builtins.fetchGit ./.).outPath")
diff --git a/tests/fetchGitRefs.sh b/tests/fetchGitRefs.sh
index 52926040b..d643fea04 100644
--- a/tests/fetchGitRefs.sh
+++ b/tests/fetchGitRefs.sh
@@ -1,9 +1,6 @@
source common.sh
-if [[ -z $(type -p git) ]]; then
- echo "Git not installed; skipping Git tests"
- exit 99
-fi
+requireGit
clearStore
@@ -56,7 +53,7 @@ invalid_ref() {
else
(! git check-ref-format --branch "$1" >/dev/null 2>&1)
fi
- nix --debug eval --raw --impure --expr "(builtins.fetchGit { url = $repo; ref = ''$1''; }).outPath" 2>&1 | grep 'invalid Git branch/tag name' >/dev/null
+ expect 1 nix --debug eval --raw --impure --expr "(builtins.fetchGit { url = $repo; ref = ''$1''; }).outPath" 2>&1 | grep 'invalid Git branch/tag name' >/dev/null
}
diff --git a/tests/fetchGitSubmodules.sh b/tests/fetchGitSubmodules.sh
index 5f104355f..df81232e5 100644
--- a/tests/fetchGitSubmodules.sh
+++ b/tests/fetchGitSubmodules.sh
@@ -2,10 +2,7 @@ source common.sh
set -u
-if [[ -z $(type -p git) ]]; then
- echo "Git not installed; skipping Git submodule tests"
- exit 99
-fi
+requireGit
clearStore
@@ -14,6 +11,15 @@ subRepo=$TEST_ROOT/gitSubmodulesSub
rm -rf ${rootRepo} ${subRepo} $TEST_HOME/.cache/nix
+# Submodules can't be fetched locally by default, which can cause
+# information leakage vulnerabilities, but for these tests our
+# submodule is intentionally local and it's all trusted, so we
+# disable this restriction. Setting it per repo is not sufficient, as
+# the repo-local config does not apply to the commands run from
+# outside the repos by Nix.
+export XDG_CONFIG_HOME=$TEST_HOME/.config
+git config --global protocol.file.allow always
+
initGitRepo() {
git init $1
git -C $1 config user.email "foobar@example.com"
@@ -95,3 +101,28 @@ noSubmoduleRepoBaseline=$(nix eval --raw --expr "(builtins.fetchGit { url = file
noSubmoduleRepo=$(nix eval --raw --expr "(builtins.fetchGit { url = file://$subRepo; rev = \"$subRev\"; submodules = true; }).outPath")
[[ $noSubmoduleRepoBaseline == $noSubmoduleRepo ]]
+
+# Test relative submodule URLs.
+rm $TEST_HOME/.cache/nix/fetcher-cache*
+rm -rf $rootRepo/.git $rootRepo/.gitmodules $rootRepo/sub
+initGitRepo $rootRepo
+git -C $rootRepo submodule add ../gitSubmodulesSub sub
+git -C $rootRepo commit -m "Add submodule"
+rev2=$(git -C $rootRepo rev-parse HEAD)
+pathWithRelative=$(nix eval --raw --expr "(builtins.fetchGit { url = file://$rootRepo; rev = \"$rev2\"; submodules = true; }).outPath")
+diff -r -x .gitmodules $pathWithSubmodules $pathWithRelative
+
+# Test clones that have an upstream with relative submodule URLs.
+rm $TEST_HOME/.cache/nix/fetcher-cache*
+cloneRepo=$TEST_ROOT/a/b/gitSubmodulesClone # NB /a/b to make the relative path not work relative to $cloneRepo
+git clone $rootRepo $cloneRepo
+pathIndirect=$(nix eval --raw --expr "(builtins.fetchGit { url = file://$cloneRepo; rev = \"$rev2\"; submodules = true; }).outPath")
+[[ $pathIndirect = $pathWithRelative ]]
+
+# Test that if the clone has the submodule already, we're not fetching
+# it again.
+git -C $cloneRepo submodule update --init
+rm $TEST_HOME/.cache/nix/fetcher-cache*
+rm -rf $subRepo
+pathSubmoduleGone=$(nix eval --raw --expr "(builtins.fetchGit { url = file://$cloneRepo; rev = \"$rev2\"; submodules = true; }).outPath")
+[[ $pathSubmoduleGone = $pathWithRelative ]]
diff --git a/tests/fetchMercurial.sh b/tests/fetchMercurial.sh
index 726840664..e6f8525c6 100644
--- a/tests/fetchMercurial.sh
+++ b/tests/fetchMercurial.sh
@@ -1,13 +1,12 @@
source common.sh
-if [[ -z $(type -p hg) ]]; then
- echo "Mercurial not installed; skipping Mercurial tests"
- exit 99
-fi
+[[ $(type -p hq) ]] || skipTest "Mercurial not installed"
clearStore
-repo=$TEST_ROOT/hg
+# Intentionally not in a canonical form
+# See https://github.com/NixOS/nix/issues/6195
+repo=$TEST_ROOT/./hg
rm -rf $repo ${repo}-tmp $TEST_HOME/.cache/nix
@@ -28,6 +27,12 @@ echo world > $repo/hello
hg commit --cwd $repo -m 'Bla2'
rev2=$(hg log --cwd $repo -r tip --template '{node}')
+# Fetch an unclean branch.
+echo unclean > $repo/hello
+path=$(nix eval --impure --raw --expr "(builtins.fetchMercurial file://$repo).outPath")
+[[ $(cat $path/hello) = unclean ]]
+hg revert --cwd $repo --all
+
# Fetch the default branch.
path=$(nix eval --impure --raw --expr "(builtins.fetchMercurial file://$repo).outPath")
[[ $(cat $path/hello) = world ]]
diff --git a/tests/fetchPath.sh b/tests/fetchPath.sh
new file mode 100644
index 000000000..29be38ce2
--- /dev/null
+++ b/tests/fetchPath.sh
@@ -0,0 +1,6 @@
+source common.sh
+
+touch $TEST_ROOT/foo -t 202211111111
+# We only check whether 2022-11-1* **:**:** is the last modified date since
+# `lastModified` is transformed into UTC in `builtins.fetchTarball`.
+[[ "$(nix eval --impure --raw --expr "(builtins.fetchTree \"path://$TEST_ROOT/foo\").lastModifiedDate")" =~ 2022111.* ]]
diff --git a/tests/fetchTree-file.sh b/tests/fetchTree-file.sh
new file mode 100644
index 000000000..fe569cfb8
--- /dev/null
+++ b/tests/fetchTree-file.sh
@@ -0,0 +1,105 @@
+source common.sh
+
+clearStore
+
+cd "$TEST_ROOT"
+
+test_fetch_file () {
+ echo foo > test_input
+
+ input_hash="$(nix hash path test_input)"
+
+ nix eval --impure --file - <<EOF
+ let
+ tree = builtins.fetchTree { type = "file"; url = "file://$PWD/test_input"; };
+ in
+ assert (tree.narHash == "$input_hash");
+ tree
+EOF
+}
+
+# Make sure that `http(s)` and `file` flake inputs are properly extracted when
+# they should be, and treated as opaque files when they should be
+test_file_flake_input () {
+ rm -fr "$TEST_ROOT/testFlake";
+ mkdir "$TEST_ROOT/testFlake";
+ pushd testFlake
+
+ mkdir inputs
+ echo foo > inputs/test_input_file
+ tar cfa test_input.tar.gz inputs
+ cp test_input.tar.gz test_input_no_ext
+ input_tarball_hash="$(nix hash path test_input.tar.gz)"
+ input_directory_hash="$(nix hash path inputs)"
+
+ cat <<EOF > flake.nix
+ {
+ inputs.no_ext_default_no_unpack = {
+ url = "file://$PWD/test_input_no_ext";
+ flake = false;
+ };
+ inputs.no_ext_explicit_unpack = {
+ url = "tarball+file://$PWD/test_input_no_ext";
+ flake = false;
+ };
+ inputs.tarball_default_unpack = {
+ url = "file://$PWD/test_input.tar.gz";
+ flake = false;
+ };
+ inputs.tarball_explicit_no_unpack = {
+ url = "file+file://$PWD/test_input.tar.gz";
+ flake = false;
+ };
+ outputs = { ... }: {};
+ }
+EOF
+
+ nix flake update
+ nix eval --file - <<EOF
+ with (builtins.fromJSON (builtins.readFile ./flake.lock));
+
+ # Url inputs whose extension doesn’t match a known archive format should
+ # not be unpacked by default
+ assert (nodes.no_ext_default_no_unpack.locked.type == "file");
+ assert (nodes.no_ext_default_no_unpack.locked.unpack or false == false);
+ assert (nodes.no_ext_default_no_unpack.locked.narHash == "$input_tarball_hash");
+
+ # For backwards compatibility, flake inputs that correspond to the
+ # old 'tarball' fetcher should still have their type set to 'tarball'
+ assert (nodes.tarball_default_unpack.locked.type == "tarball");
+ # Unless explicitely specified, the 'unpack' parameter shouldn’t appear here
+ # because that would break older Nix versions
+ assert (!nodes.tarball_default_unpack.locked ? unpack);
+ assert (nodes.tarball_default_unpack.locked.narHash == "$input_directory_hash");
+
+ # Explicitely passing the unpack parameter should enforce the desired behavior
+ assert (nodes.no_ext_explicit_unpack.locked.narHash == nodes.tarball_default_unpack.locked.narHash);
+ assert (nodes.tarball_explicit_no_unpack.locked.narHash == nodes.no_ext_default_no_unpack.locked.narHash);
+ true
+EOF
+ popd
+
+ [[ -z "${NIX_DAEMON_PACKAGE-}" ]] && return 0
+
+ # Ensure that a lockfile generated by the current Nix for tarball inputs
+ # can still be read by an older Nix
+
+ cat <<EOF > flake.nix
+ {
+ inputs.tarball = {
+ url = "file://$PWD/test_input.tar.gz";
+ flake = false;
+ };
+ outputs = { self, tarball }: {
+ foo = builtins.readFile "\${tarball}/test_input_file";
+ };
+ }
+ nix flake update
+
+ clearStore
+ "$NIX_DAEMON_PACKAGE/bin/nix" eval .#foo
+EOF
+}
+
+test_fetch_file
+test_file_flake_input
diff --git a/tests/fetchurl.sh b/tests/fetchurl.sh
index 3d1685f43..8cd40c09f 100644
--- a/tests/fetchurl.sh
+++ b/tests/fetchurl.sh
@@ -9,6 +9,10 @@ outPath=$(nix-build -vvvvv --expr 'import <nix/fetchurl.nix>' --argstr url file:
cmp $outPath fetchurl.sh
+# Do not re-fetch paths already present.
+outPath2=$(nix-build -vvvvv --expr 'import <nix/fetchurl.nix>' --argstr url file:///does-not-exist/must-remain-unused/fetchurl.sh --argstr sha256 $hash --no-out-link)
+test "$outPath" == "$outPath2"
+
# Now using a base-64 hash.
clearStore
@@ -58,7 +62,7 @@ hash=$(nix-hash --flat --type sha256 $nar)
outPath=$(nix-build -vvvvv --expr 'import <nix/fetchurl.nix>' --argstr url file://$nar --argstr sha256 $hash \
--arg unpack true --argstr name xyzzy --no-out-link)
-echo $outPath | grep -q 'xyzzy'
+echo $outPath | grepQuiet 'xyzzy'
test -x $outPath/fetchurl.sh
test -L $outPath/symlink
diff --git a/tests/flakes/absolute-paths.sh b/tests/flakes/absolute-paths.sh
new file mode 100644
index 000000000..e7bfba12d
--- /dev/null
+++ b/tests/flakes/absolute-paths.sh
@@ -0,0 +1,17 @@
+source ./common.sh
+
+requireGit
+
+flake1Dir=$TEST_ROOT/flake1
+flake2Dir=$TEST_ROOT/flake2
+
+createGitRepo $flake1Dir
+cat > $flake1Dir/flake.nix <<EOF
+{
+ outputs = { self }: { x = builtins.readFile $(pwd)/absolute-paths.sh; };
+}
+EOF
+git -C $flake1Dir add flake.nix
+git -C $flake1Dir commit -m Initial
+
+nix eval --impure --json $flake1Dir#x
diff --git a/tests/flakes/build-paths.sh b/tests/flakes/build-paths.sh
new file mode 100644
index 000000000..b399a066e
--- /dev/null
+++ b/tests/flakes/build-paths.sh
@@ -0,0 +1,66 @@
+source ./common.sh
+
+flake1Dir=$TEST_ROOT/flake1
+flake2Dir=$TEST_ROOT/flake2
+
+mkdir -p $flake1Dir $flake2Dir
+
+writeSimpleFlake $flake2Dir
+tar cfz $TEST_ROOT/flake.tar.gz -C $TEST_ROOT flake2
+hash=$(nix hash path $flake2Dir)
+
+dep=$(nix store add-path ./common.sh)
+
+cat > $flake1Dir/flake.nix <<EOF
+{
+ inputs.flake2.url = "file://$TEST_ROOT/flake.tar.gz";
+
+ outputs = { self, flake2 }: {
+
+ a1 = builtins.fetchTarball {
+ #type = "tarball";
+ url = "file://$TEST_ROOT/flake.tar.gz";
+ sha256 = "$hash";
+ };
+
+ a2 = ./foo;
+
+ a3 = ./.;
+
+ a4 = self.outPath;
+
+ # FIXME
+ a5 = self;
+
+ a6 = flake2.outPath;
+
+ # FIXME
+ a7 = "\${flake2}/config.nix";
+
+ # This is only allowed in impure mode.
+ a8 = builtins.storePath $dep;
+
+ a9 = "$dep";
+ };
+}
+EOF
+
+echo bar > $flake1Dir/foo
+
+nix build --json --out-link $TEST_ROOT/result $flake1Dir#a1
+[[ -e $TEST_ROOT/result/simple.nix ]]
+
+nix build --json --out-link $TEST_ROOT/result $flake1Dir#a2
+[[ $(cat $TEST_ROOT/result) = bar ]]
+
+nix build --json --out-link $TEST_ROOT/result $flake1Dir#a3
+
+nix build --json --out-link $TEST_ROOT/result $flake1Dir#a4
+
+nix build --json --out-link $TEST_ROOT/result $flake1Dir#a6
+[[ -e $TEST_ROOT/result/simple.nix ]]
+
+nix build --impure --json --out-link $TEST_ROOT/result $flake1Dir#a8
+diff common.sh $TEST_ROOT/result
+
+(! nix build --impure --json --out-link $TEST_ROOT/result $flake1Dir#a9)
diff --git a/tests/flake-bundler.sh b/tests/flakes/bundle.sh
index 9496b8f92..67bbb05ac 100644
--- a/tests/flake-bundler.sh
+++ b/tests/flakes/bundle.sh
@@ -1,9 +1,6 @@
source common.sh
-clearStore
-rm -rf $TEST_HOME/.cache $TEST_HOME/.config $TEST_HOME/.local
-
-cp ./simple.nix ./simple.builder.sh ./config.nix $TEST_HOME
+cp ../simple.nix ../simple.builder.sh ../config.nix $TEST_HOME
cd $TEST_HOME
@@ -25,6 +22,7 @@ cat <<EOF > flake.nix
};
}
EOF
+
nix build .#
nix bundle --bundler .# .#
nix bundle --bundler .#bundlers.$system.default .#packages.$system.default
@@ -32,6 +30,3 @@ nix bundle --bundler .#bundlers.$system.simple .#packages.$system.default
nix bundle --bundler .#bundlers.$system.default .#apps.$system.default
nix bundle --bundler .#bundlers.$system.simple .#apps.$system.default
-
-clearStore
-
diff --git a/tests/flakes/check.sh b/tests/flakes/check.sh
new file mode 100644
index 000000000..865ca61b4
--- /dev/null
+++ b/tests/flakes/check.sh
@@ -0,0 +1,77 @@
+source common.sh
+
+flakeDir=$TEST_ROOT/flake3
+mkdir -p $flakeDir
+
+cat > $flakeDir/flake.nix <<EOF
+{
+ outputs = { self }: {
+ overlay = final: prev: {
+ };
+ };
+}
+EOF
+
+nix flake check $flakeDir
+
+cat > $flakeDir/flake.nix <<EOF
+{
+ outputs = { self }: {
+ overlay = finalll: prev: {
+ };
+ };
+}
+EOF
+
+(! nix flake check $flakeDir)
+
+cat > $flakeDir/flake.nix <<EOF
+{
+ outputs = { self }: {
+ nixosModules.foo = {
+ a.b.c = 123;
+ foo = true;
+ };
+ };
+}
+EOF
+
+nix flake check $flakeDir
+
+cat > $flakeDir/flake.nix <<EOF
+{
+ outputs = { self }: {
+ nixosModules.foo = assert false; {
+ a.b.c = 123;
+ foo = true;
+ };
+ };
+}
+EOF
+
+(! nix flake check $flakeDir)
+
+cat > $flakeDir/flake.nix <<EOF
+{
+ outputs = { self }: {
+ nixosModule = { config, pkgs, ... }: {
+ a.b.c = 123;
+ };
+ };
+}
+EOF
+
+nix flake check $flakeDir
+
+cat > $flakeDir/flake.nix <<EOF
+{
+ outputs = { self }: {
+ packages.system-1.default = "foo";
+ packages.system-2.default = "bar";
+ };
+}
+EOF
+
+checkRes=$(nix flake check --keep-going $flakeDir 2>&1 && fail "nix flake check should have failed" || true)
+echo "$checkRes" | grepQuiet "packages.system-1.default"
+echo "$checkRes" | grepQuiet "packages.system-2.default"
diff --git a/tests/flakes/circular.sh b/tests/flakes/circular.sh
new file mode 100644
index 000000000..09cd02edf
--- /dev/null
+++ b/tests/flakes/circular.sh
@@ -0,0 +1,49 @@
+# Test circular flake dependencies.
+source ./common.sh
+
+requireGit
+
+flakeA=$TEST_ROOT/flakeA
+flakeB=$TEST_ROOT/flakeB
+
+createGitRepo $flakeA
+createGitRepo $flakeB
+
+cat > $flakeA/flake.nix <<EOF
+{
+ inputs.b.url = git+file://$flakeB;
+ inputs.b.inputs.a.follows = "/";
+
+ outputs = { self, b }: {
+ foo = 123 + b.bar;
+ xyzzy = 1000;
+ };
+}
+EOF
+
+git -C $flakeA add flake.nix
+
+cat > $flakeB/flake.nix <<EOF
+{
+ inputs.a.url = git+file://$flakeA;
+
+ outputs = { self, a }: {
+ bar = 456 + a.xyzzy;
+ };
+}
+EOF
+
+git -C $flakeB add flake.nix
+git -C $flakeB commit -a -m 'Foo'
+
+[[ $(nix eval $flakeA#foo) = 1579 ]]
+[[ $(nix eval $flakeA#foo) = 1579 ]]
+
+sed -i $flakeB/flake.nix -e 's/456/789/'
+git -C $flakeB commit -a -m 'Foo'
+
+[[ $(nix eval --update-input b $flakeA#foo) = 1912 ]]
+
+# Test list-inputs with circular dependencies
+nix flake metadata $flakeA
+
diff --git a/tests/flakes/common.sh b/tests/flakes/common.sh
new file mode 100644
index 000000000..427abcdde
--- /dev/null
+++ b/tests/flakes/common.sh
@@ -0,0 +1,70 @@
+source ../common.sh
+
+registry=$TEST_ROOT/registry.json
+
+writeSimpleFlake() {
+ local flakeDir="$1"
+ cat > $flakeDir/flake.nix <<EOF
+{
+ description = "Bla bla";
+
+ outputs = inputs: rec {
+ packages.$system = rec {
+ foo = import ./simple.nix;
+ default = foo;
+ };
+ packages.someOtherSystem = rec {
+ foo = import ./simple.nix;
+ default = foo;
+ };
+
+ # To test "nix flake init".
+ legacyPackages.$system.hello = import ./simple.nix;
+ };
+}
+EOF
+
+ cp ../simple.nix ../simple.builder.sh ../config.nix $flakeDir/
+}
+
+createSimpleGitFlake() {
+ local flakeDir="$1"
+ writeSimpleFlake $flakeDir
+ git -C $flakeDir add flake.nix simple.nix simple.builder.sh config.nix
+ git -C $flakeDir commit -m 'Initial'
+}
+
+writeDependentFlake() {
+ local flakeDir="$1"
+ cat > $flakeDir/flake.nix <<EOF
+{
+ outputs = { self, flake1 }: {
+ packages.$system.default = flake1.packages.$system.default;
+ expr = assert builtins.pathExists ./flake.lock; 123;
+ };
+}
+EOF
+}
+
+writeTrivialFlake() {
+ local flakeDir="$1"
+ cat > $flakeDir/flake.nix <<EOF
+{
+ outputs = { self }: {
+ expr = 123;
+ };
+}
+EOF
+}
+
+createGitRepo() {
+ local repo="$1"
+ local extraArgs="${2-}"
+
+ rm -rf $repo $repo.tmp
+ mkdir -p $repo
+
+ git -C $repo init $extraArgs
+ git -C $repo config user.email "foobar@example.com"
+ git -C $repo config user.name "Foobar"
+}
diff --git a/tests/flake-local-settings.sh b/tests/flakes/config.sh
index e92c16f87..d1941a6be 100644
--- a/tests/flake-local-settings.sh
+++ b/tests/flakes/config.sh
@@ -1,9 +1,6 @@
source common.sh
-clearStore
-rm -rf $TEST_HOME/.cache $TEST_HOME/.config $TEST_HOME/.local
-
-cp ./simple.nix ./simple.builder.sh ./config.nix $TEST_HOME
+cp ../simple.nix ../simple.builder.sh ../config.nix $TEST_HOME
cd $TEST_HOME
diff --git a/tests/flakes/flake-in-submodule.sh b/tests/flakes/flake-in-submodule.sh
new file mode 100644
index 000000000..21a4b52de
--- /dev/null
+++ b/tests/flakes/flake-in-submodule.sh
@@ -0,0 +1,52 @@
+source common.sh
+
+# Tests that:
+# - flake.nix may reside inside of a git submodule
+# - the flake can access content outside of the submodule
+#
+# rootRepo
+# ├── root.nix
+# └── submodule
+# ├── flake.nix
+# └── sub.nix
+
+
+requireGit
+
+clearStore
+
+# Submodules can't be fetched locally by default.
+# See fetchGitSubmodules.sh
+export XDG_CONFIG_HOME=$TEST_HOME/.config
+git config --global protocol.file.allow always
+
+
+rootRepo=$TEST_ROOT/rootRepo
+subRepo=$TEST_ROOT/submodule
+
+
+createGitRepo $subRepo
+cat > $subRepo/flake.nix <<EOF
+{
+ outputs = { self }: {
+ sub = import ./sub.nix;
+ root = import ../root.nix;
+ };
+}
+EOF
+echo '"expression in submodule"' > $subRepo/sub.nix
+git -C $subRepo add flake.nix sub.nix
+git -C $subRepo commit -m Initial
+
+createGitRepo $rootRepo
+
+git -C $rootRepo submodule init
+git -C $rootRepo submodule add $subRepo submodule
+echo '"expression in root repo"' > $rootRepo/root.nix
+git -C $rootRepo add root.nix
+git -C $rootRepo commit -m "Add root.nix"
+
+# Flake can live inside a submodule and can be accessed via ?dir=submodule
+[[ $(nix eval --json git+file://$rootRepo\?submodules=1\&dir=submodule#sub ) = '"expression in submodule"' ]]
+# The flake can access content outside of the submodule
+[[ $(nix eval --json git+file://$rootRepo\?submodules=1\&dir=submodule#root ) = '"expression in root repo"' ]]
diff --git a/tests/flakes.sh b/tests/flakes/flakes.sh
index ea629ae70..f2e216435 100644
--- a/tests/flakes.sh
+++ b/tests/flakes/flakes.sh
@@ -1,60 +1,30 @@
-source common.sh
+source ./common.sh
-if [[ -z $(type -p git) ]]; then
- echo "Git not installed; skipping flake tests"
- exit 99
-fi
+requireGit
clearStore
rm -rf $TEST_HOME/.cache $TEST_HOME/.config
-registry=$TEST_ROOT/registry.json
-
flake1Dir=$TEST_ROOT/flake1
flake2Dir=$TEST_ROOT/flake2
flake3Dir=$TEST_ROOT/flake3
flake5Dir=$TEST_ROOT/flake5
-flake6Dir=$TEST_ROOT/flake6
flake7Dir=$TEST_ROOT/flake7
-templatesDir=$TEST_ROOT/templates
nonFlakeDir=$TEST_ROOT/nonFlake
badFlakeDir=$TEST_ROOT/badFlake
-flakeA=$TEST_ROOT/flakeA
-flakeB=$TEST_ROOT/flakeB
flakeGitBare=$TEST_ROOT/flakeGitBare
-flakeFollowsA=$TEST_ROOT/follows/flakeA
-flakeFollowsB=$TEST_ROOT/follows/flakeA/flakeB
-flakeFollowsC=$TEST_ROOT/follows/flakeA/flakeB/flakeC
-flakeFollowsD=$TEST_ROOT/follows/flakeA/flakeD
-flakeFollowsE=$TEST_ROOT/follows/flakeA/flakeE
-
-for repo in $flake1Dir $flake2Dir $flake3Dir $flake7Dir $templatesDir $nonFlakeDir $flakeA $flakeB $flakeFollowsA; do
- rm -rf $repo $repo.tmp
- mkdir -p $repo
- git -C $repo init
- git -C $repo config user.email "foobar@example.com"
- git -C $repo config user.name "Foobar"
-done
-
-cat > $flake1Dir/flake.nix <<EOF
-{
- description = "Bla bla";
- outputs = inputs: rec {
- packages.$system = rec {
- foo = import ./simple.nix;
- default = foo;
- };
+for repo in $flake1Dir $flake2Dir $flake3Dir $flake7Dir $nonFlakeDir; do
+ # Give one repo a non-main initial branch.
+ extraArgs=
+ if [[ $repo == $flake2Dir ]]; then
+ extraArgs="--initial-branch=main"
+ fi
- # To test "nix flake init".
- legacyPackages.x86_64-linux.hello = import ./simple.nix;
- };
-}
-EOF
+ createGitRepo "$repo" "$extraArgs"
+done
-cp ./simple.nix ./simple.builder.sh ./config.nix $flake1Dir/
-git -C $flake1Dir add flake.nix simple.nix simple.builder.sh config.nix
-git -C $flake1Dir commit -m 'Initial'
+createSimpleGitFlake $flake1Dir
cat > $flake2Dir/flake.nix <<EOF
{
@@ -83,7 +53,11 @@ cat > $flake3Dir/flake.nix <<EOF
}
EOF
-git -C $flake3Dir add flake.nix
+cat > $flake3Dir/default.nix <<EOF
+{ x = 123; }
+EOF
+
+git -C $flake3Dir add flake.nix default.nix
git -C $flake3Dir commit -m 'Initial'
cat > $nonFlakeDir/README.md <<EOF
@@ -98,21 +72,21 @@ nix registry add --registry $registry flake1 git+file://$flake1Dir
nix registry add --registry $registry flake2 git+file://$flake2Dir
nix registry add --registry $registry flake3 git+file://$flake3Dir
nix registry add --registry $registry flake4 flake3
-nix registry add --registry $registry flake5 hg+file://$flake5Dir
nix registry add --registry $registry nixpkgs flake1
-nix registry add --registry $registry templates git+file://$templatesDir
-# Test 'nix flake list'.
-[[ $(nix registry list | wc -l) == 7 ]]
+# Test 'nix registry list'.
+[[ $(nix registry list | wc -l) == 5 ]]
+nix registry list | grep '^global'
+nix registry list | grepInverse '^user' # nothing in user registry
# Test 'nix flake metadata'.
nix flake metadata flake1
-nix flake metadata flake1 | grep -q 'Locked URL:.*flake1.*'
+nix flake metadata flake1 | grepQuiet 'Locked URL:.*flake1.*'
# Test 'nix flake metadata' on a local flake.
-(cd $flake1Dir && nix flake metadata) | grep -q 'URL:.*flake1.*'
-(cd $flake1Dir && nix flake metadata .) | grep -q 'URL:.*flake1.*'
-nix flake metadata $flake1Dir | grep -q 'URL:.*flake1.*'
+(cd $flake1Dir && nix flake metadata) | grepQuiet 'URL:.*flake1.*'
+(cd $flake1Dir && nix flake metadata .) | grepQuiet 'URL:.*flake1.*'
+nix flake metadata $flake1Dir | grepQuiet 'URL:.*flake1.*'
# Test 'nix flake metadata --json'.
json=$(nix flake metadata flake1 --json | jq .)
@@ -122,7 +96,9 @@ json=$(nix flake metadata flake1 --json | jq .)
hash1=$(echo "$json" | jq -r .revision)
echo -n '# foo' >> $flake1Dir/flake.nix
+flake1OriginalCommit=$(git -C $flake1Dir rev-parse HEAD)
git -C $flake1Dir commit -a -m 'Foo'
+flake1NewCommit=$(git -C $flake1Dir rev-parse HEAD)
hash2=$(nix flake metadata flake1 --json --refresh | jq -r .revision)
[[ $hash1 != $hash2 ]]
@@ -141,11 +117,12 @@ nix build -o $TEST_ROOT/result git+file://$flake1Dir
nix build -o $flake1Dir/result git+file://$flake1Dir
nix path-info $flake1Dir/result
-# 'getFlake' on a mutable flakeref should fail in pure mode, but succeed in impure mode.
+# 'getFlake' on an unlocked flakeref should fail in pure mode, but
+# succeed in impure mode.
(! nix build -o $TEST_ROOT/result --expr "(builtins.getFlake \"$flake1Dir\").packages.$system.default")
nix build -o $TEST_ROOT/result --expr "(builtins.getFlake \"$flake1Dir\").packages.$system.default" --impure
-# 'getFlake' on an immutable flakeref should succeed even in pure mode.
+# 'getFlake' on a locked flakeref should succeed even in pure mode.
nix build -o $TEST_ROOT/result --expr "(builtins.getFlake \"git+file://$flake1Dir?rev=$hash2\").packages.$system.default"
# Building a flake with an unlocked dependency should fail in pure mode.
@@ -156,20 +133,21 @@ nix build -o $TEST_ROOT/result --expr "(builtins.getFlake \"git+file://$flake1Di
# But should succeed in impure mode.
(! nix build -o $TEST_ROOT/result flake2#bar --impure)
nix build -o $TEST_ROOT/result flake2#bar --impure --no-write-lock-file
+nix eval --expr "builtins.getFlake \"$flake2Dir\"" --impure
# Building a local flake with an unlocked dependency should fail with --no-update-lock-file.
-nix build -o $TEST_ROOT/result $flake2Dir#bar --no-update-lock-file 2>&1 | grep 'requires lock file changes'
+expect 1 nix build -o $TEST_ROOT/result $flake2Dir#bar --no-update-lock-file 2>&1 | grep 'requires lock file changes'
# But it should succeed without that flag.
nix build -o $TEST_ROOT/result $flake2Dir#bar --no-write-lock-file
-nix build -o $TEST_ROOT/result $flake2Dir#bar --no-update-lock-file 2>&1 | grep 'requires lock file changes'
+expect 1 nix build -o $TEST_ROOT/result $flake2Dir#bar --no-update-lock-file 2>&1 | grep 'requires lock file changes'
nix build -o $TEST_ROOT/result $flake2Dir#bar --commit-lock-file
[[ -e $flake2Dir/flake.lock ]]
-[[ -z $(git -C $flake2Dir diff master) ]]
+[[ -z $(git -C $flake2Dir diff main || echo failed) ]]
# Rerunning the build should not change the lockfile.
nix build -o $TEST_ROOT/result $flake2Dir#bar
-[[ -z $(git -C $flake2Dir diff master) ]]
+[[ -z $(git -C $flake2Dir diff main || echo failed) ]]
# Building with a lockfile should not require a fetch of the registry.
nix build -o $TEST_ROOT/result --flake-registry file:///no-registry.json $flake2Dir#bar --refresh
@@ -178,7 +156,7 @@ nix build -o $TEST_ROOT/result --no-use-registries $flake2Dir#bar --refresh
# Updating the flake should not change the lockfile.
nix flake lock $flake2Dir
-[[ -z $(git -C $flake2Dir diff master) ]]
+[[ -z $(git -C $flake2Dir diff main || echo failed) ]]
# Now we should be able to build the flake in pure mode.
nix build -o $TEST_ROOT/result flake2#bar
@@ -213,17 +191,17 @@ nix build -o $TEST_ROOT/result $flake3Dir#"sth sth"
nix build -o $TEST_ROOT/result $flake3Dir#"sth%20sth"
# Check whether it saved the lockfile
-(! [[ -z $(git -C $flake3Dir diff master) ]])
+[[ -n $(git -C $flake3Dir diff master) ]]
git -C $flake3Dir add flake.lock
git -C $flake3Dir commit -m 'Add lockfile'
# Test whether registry caching works.
-nix registry list --flake-registry file://$registry | grep -q flake3
+nix registry list --flake-registry file://$registry | grepQuiet flake3
mv $registry $registry.tmp
nix store gc
-nix registry list --flake-registry file://$registry --refresh | grep -q flake3
+nix registry list --flake-registry file://$registry --refresh | grepQuiet flake3
mv $registry.tmp $registry
# Test whether flakes are registered as GC roots for offline use.
@@ -283,7 +261,7 @@ cat > $flake3Dir/flake.nix <<EOF
}
EOF
-cp ./config.nix $flake3Dir
+cp ../config.nix $flake3Dir
git -C $flake3Dir add flake.nix config.nix
git -C $flake3Dir commit -m 'Add nonFlakeInputs'
@@ -313,10 +291,10 @@ nix build -o $TEST_ROOT/result flake4#xyzzy
# Test 'nix flake update' and --override-flake.
nix flake lock $flake3Dir
-[[ -z $(git -C $flake3Dir diff master) ]]
+[[ -z $(git -C $flake3Dir diff master || echo failed) ]]
nix flake update $flake3Dir --override-flake flake2 nixpkgs
-[[ ! -z $(git -C $flake3Dir diff master) ]]
+[[ ! -z $(git -C $flake3Dir diff master || echo failed) ]]
# Make branch "removeXyzzy" where flake3 doesn't have xyzzy anymore
git -C $flake3Dir checkout -b removeXyzzy
@@ -358,158 +336,29 @@ nix build -o $TEST_ROOT/result flake4/removeXyzzy#sth
# Testing the nix CLI
nix registry add flake1 flake3
-[[ $(nix registry list | wc -l) == 8 ]]
+[[ $(nix registry list | wc -l) == 6 ]]
nix registry pin flake1
-[[ $(nix registry list | wc -l) == 8 ]]
+[[ $(nix registry list | wc -l) == 6 ]]
nix registry pin flake1 flake3
-[[ $(nix registry list | wc -l) == 8 ]]
+[[ $(nix registry list | wc -l) == 6 ]]
nix registry remove flake1
-[[ $(nix registry list | wc -l) == 7 ]]
-
-# Test 'nix flake init'.
-cat > $templatesDir/flake.nix <<EOF
-{
- description = "Some templates";
-
- outputs = { self }: {
- templates = rec {
- trivial = {
- path = ./trivial;
- description = "A trivial flake";
- };
- default = trivial;
- };
- };
-}
-EOF
-
-mkdir $templatesDir/trivial
-
-cat > $templatesDir/trivial/flake.nix <<EOF
-{
- description = "A flake for building Hello World";
-
- outputs = { self, nixpkgs }: {
- packages.x86_64-linux = rec {
- hello = nixpkgs.legacyPackages.x86_64-linux.hello;
- default = hello;
- };
- };
-}
-EOF
-
-git -C $templatesDir add flake.nix trivial/flake.nix
-git -C $templatesDir commit -m 'Initial'
-
-nix flake check templates
-nix flake show templates
-nix flake show templates --json | jq
-
-(cd $flake7Dir && nix flake init)
-(cd $flake7Dir && nix flake init) # check idempotence
-git -C $flake7Dir add flake.nix
-nix flake check $flake7Dir
-nix flake show $flake7Dir
-nix flake show $flake7Dir --json | jq
-git -C $flake7Dir commit -a -m 'Initial'
-
-# Test 'nix flake new'.
-rm -rf $flake6Dir
-nix flake new -t templates#trivial $flake6Dir
-nix flake new -t templates#trivial $flake6Dir # check idempotence
-nix flake check $flake6Dir
+[[ $(nix registry list | wc -l) == 5 ]]
+
+# Test 'nix registry list' with a disabled global registry.
+nix registry add user-flake1 git+file://$flake1Dir
+nix registry add user-flake2 git+file://$flake2Dir
+[[ $(nix --flake-registry "" registry list | wc -l) == 2 ]]
+nix --flake-registry "" registry list | grepQuietInverse '^global' # nothing in global registry
+nix --flake-registry "" registry list | grepQuiet '^user'
+nix registry remove user-flake1
+nix registry remove user-flake2
+[[ $(nix registry list | wc -l) == 5 ]]
# Test 'nix flake clone'.
rm -rf $TEST_ROOT/flake1-v2
nix flake clone flake1 --dest $TEST_ROOT/flake1-v2
[ -e $TEST_ROOT/flake1-v2/flake.nix ]
-# More 'nix flake check' tests.
-cat > $flake3Dir/flake.nix <<EOF
-{
- outputs = { flake1, self }: {
- overlay = final: prev: {
- };
- };
-}
-EOF
-
-nix flake check $flake3Dir
-
-cat > $flake3Dir/flake.nix <<EOF
-{
- outputs = { flake1, self }: {
- overlay = finalll: prev: {
- };
- };
-}
-EOF
-
-(! nix flake check $flake3Dir)
-
-cat > $flake3Dir/flake.nix <<EOF
-{
- outputs = { flake1, self }: {
- nixosModules.foo = {
- a.b.c = 123;
- foo = true;
- };
- };
-}
-EOF
-
-nix flake check $flake3Dir
-
-cat > $flake3Dir/flake.nix <<EOF
-{
- outputs = { flake1, self }: {
- nixosModules.foo = {
- a.b.c = 123;
- foo = assert false; true;
- };
- };
-}
-EOF
-
-(! nix flake check $flake3Dir)
-
-cat > $flake3Dir/flake.nix <<EOF
-{
- outputs = { flake1, self }: {
- nixosModule = { config, pkgs, ... }: {
- a.b.c = 123;
- };
- };
-}
-EOF
-
-nix flake check $flake3Dir
-
-cat > $flake3Dir/flake.nix <<EOF
-{
- outputs = { flake1, self }: {
- nixosModule = { config, pkgs }: {
- a.b.c = 123;
- };
- };
-}
-EOF
-
-(! nix flake check $flake3Dir)
-
-cat > $flake3Dir/flake.nix <<EOF
-{
- outputs = { flake1, self }: {
- packages.system-1.default = "foo";
- packages.system-2.default = "bar";
- };
-}
-EOF
-
-checkRes=$(nix flake check --keep-going $flake3Dir 2>&1 && fail "nix flake check should have failed" || true)
-echo "$checkRes" | grep -q "packages.system-1.default"
-echo "$checkRes" | grep -q "packages.system-2.default"
-
# Test 'follows' inputs.
cat > $flake3Dir/flake.nix <<EOF
{
@@ -552,6 +401,10 @@ nix flake lock $flake3Dir
[[ $(jq -c .nodes.root.inputs.bar $flake3Dir/flake.lock) = '["flake2"]' ]]
# Test overriding inputs of inputs.
+writeTrivialFlake $flake7Dir
+git -C $flake7Dir add flake.nix
+git -C $flake7Dir commit -m 'Initial'
+
cat > $flake3Dir/flake.nix <<EOF
{
inputs.flake2.inputs.flake1 = {
@@ -586,50 +439,9 @@ rm -rf $flakeGitBare
git clone --bare $flake1Dir $flakeGitBare
nix build -o $TEST_ROOT/result git+file://$flakeGitBare
-# Test Mercurial flakes.
-rm -rf $flake5Dir
-mkdir $flake5Dir
-
-cat > $flake5Dir/flake.nix <<EOF
-{
- outputs = { self, flake1 }: {
- packages.$system.default = flake1.packages.$system.default;
- expr = assert builtins.pathExists ./flake.lock; 123;
- };
-}
-EOF
-
-if [[ -n $(type -p hg) ]]; then
- hg init $flake5Dir
-
- hg add $flake5Dir/flake.nix
- hg commit --config ui.username=foobar@example.org $flake5Dir -m 'Initial commit'
-
- nix build -o $TEST_ROOT/result hg+file://$flake5Dir
- [[ -e $TEST_ROOT/result/hello ]]
-
- (! nix flake metadata --json hg+file://$flake5Dir | jq -e -r .revision)
-
- nix eval hg+file://$flake5Dir#expr
-
- nix eval hg+file://$flake5Dir#expr
-
- (! nix eval hg+file://$flake5Dir#expr --no-allow-dirty)
-
- (! nix flake metadata --json hg+file://$flake5Dir | jq -e -r .revision)
-
- hg commit --config ui.username=foobar@example.org $flake5Dir -m 'Add lock file'
-
- nix flake metadata --json hg+file://$flake5Dir --refresh | jq -e -r .revision
- nix flake metadata --json hg+file://$flake5Dir
- [[ $(nix flake metadata --json hg+file://$flake5Dir | jq -e -r .revCount) = 1 ]]
-
- nix build -o $TEST_ROOT/result hg+file://$flake5Dir --no-registries --no-allow-dirty
- nix build -o $TEST_ROOT/result hg+file://$flake5Dir --no-use-registries --no-allow-dirty
-fi
-
# Test path flakes.
-rm -rf $flake5Dir/.hg $flake5Dir/flake.lock
+mkdir -p $flake5Dir
+writeDependentFlake $flake5Dir
nix flake lock path://$flake5Dir
# Test tarball flakes.
@@ -644,7 +456,7 @@ url=$(nix flake metadata --json file://$TEST_ROOT/flake.tar.gz | jq -r .url)
nix build -o $TEST_ROOT/result $url
# Building with an incorrect SRI hash should fail.
-nix build -o $TEST_ROOT/result "file://$TEST_ROOT/flake.tar.gz?narHash=sha256-qQ2Zz4DNHViCUrp6gTS7EE4+RMqFQtUfWF2UNUtJKS0=" 2>&1 | grep 'NAR hash mismatch'
+expectStderr 102 nix build -o $TEST_ROOT/result "file://$TEST_ROOT/flake.tar.gz?narHash=sha256-qQ2Zz4DNHViCUrp6gTS7EE4+RMqFQtUfWF2UNUtJKS0=" | grep 'NAR hash mismatch'
# Test --override-input.
git -C $flake3Dir reset --hard
@@ -667,166 +479,7 @@ nix flake lock $flake3Dir --update-input flake2/flake1
# Test 'nix flake metadata --json'.
nix flake metadata $flake3Dir --json | jq .
-# Test circular flake dependencies.
-cat > $flakeA/flake.nix <<EOF
-{
- inputs.b.url = git+file://$flakeB;
- inputs.b.inputs.a.follows = "/";
-
- outputs = { self, nixpkgs, b }: {
- foo = 123 + b.bar;
- xyzzy = 1000;
- };
-}
-EOF
-
-git -C $flakeA add flake.nix
-
-cat > $flakeB/flake.nix <<EOF
-{
- inputs.a.url = git+file://$flakeA;
-
- outputs = { self, nixpkgs, a }: {
- bar = 456 + a.xyzzy;
- };
-}
-EOF
-
-git -C $flakeB add flake.nix
-git -C $flakeB commit -a -m 'Foo'
-
-[[ $(nix eval $flakeA#foo) = 1579 ]]
-[[ $(nix eval $flakeA#foo) = 1579 ]]
-
-sed -i $flakeB/flake.nix -e 's/456/789/'
-git -C $flakeB commit -a -m 'Foo'
-
-[[ $(nix eval --update-input b $flakeA#foo) = 1912 ]]
-
-# Test list-inputs with circular dependencies
-nix flake metadata $flakeA
-
-# Test flake follow paths
-mkdir -p $flakeFollowsB
-mkdir -p $flakeFollowsC
-mkdir -p $flakeFollowsD
-mkdir -p $flakeFollowsE
-
-cat > $flakeFollowsA/flake.nix <<EOF
-{
- description = "Flake A";
- inputs = {
- B = {
- url = "path:./flakeB";
- inputs.foobar.follows = "foobar";
- };
-
- foobar.url = "path:$flakeFollowsA/flakeE";
- };
- outputs = { ... }: {};
-}
-EOF
-
-cat > $flakeFollowsB/flake.nix <<EOF
-{
- description = "Flake B";
- inputs = {
- foobar.url = "path:$flakeFollowsA/flakeE";
- goodoo.follows = "C/goodoo";
- C = {
- url = "path:./flakeC";
- inputs.foobar.follows = "foobar";
- };
- };
- outputs = { ... }: {};
-}
-EOF
-
-cat > $flakeFollowsC/flake.nix <<EOF
-{
- description = "Flake C";
- inputs = {
- foobar.url = "path:$flakeFollowsA/flakeE";
- goodoo.follows = "foobar";
- };
- outputs = { ... }: {};
-}
-EOF
-
-cat > $flakeFollowsD/flake.nix <<EOF
-{
- description = "Flake D";
- inputs = {};
- outputs = { ... }: {};
-}
-EOF
-
-cat > $flakeFollowsE/flake.nix <<EOF
-{
- description = "Flake E";
- inputs = {};
- outputs = { ... }: {};
-}
-EOF
-
-git -C $flakeFollowsA add flake.nix flakeB/flake.nix \
- flakeB/flakeC/flake.nix flakeD/flake.nix flakeE/flake.nix
-
-nix flake metadata $flakeFollowsA
-
-nix flake update $flakeFollowsA
-
-oldLock="$(cat "$flakeFollowsA/flake.lock")"
-
-# Ensure that locking twice doesn't change anything
-
-nix flake lock $flakeFollowsA
-
-newLock="$(cat "$flakeFollowsA/flake.lock")"
-
-diff <(echo "$newLock") <(echo "$oldLock")
-
-[[ $(jq -c .nodes.B.inputs.C $flakeFollowsA/flake.lock) = '"C"' ]]
-[[ $(jq -c .nodes.B.inputs.foobar $flakeFollowsA/flake.lock) = '["foobar"]' ]]
-[[ $(jq -c .nodes.C.inputs.foobar $flakeFollowsA/flake.lock) = '["B","foobar"]' ]]
-
-# Ensure removing follows from flake.nix removes them from the lockfile
-
-cat > $flakeFollowsA/flake.nix <<EOF
-{
- description = "Flake A";
- inputs = {
- B = {
- url = "path:./flakeB";
- inputs.nonFlake.follows = "D";
- };
- D.url = "path:./flakeD";
- };
- outputs = { ... }: {};
-}
-EOF
-
-nix flake lock $flakeFollowsA
-
-[[ $(jq -c .nodes.B.inputs.foobar $flakeFollowsA/flake.lock) = '"foobar"' ]]
-jq -r -c '.nodes | keys | .[]' $flakeFollowsA/flake.lock | grep "^foobar$"
-
-# Ensure a relative path is not allowed to go outside the store path
-cat > $flakeFollowsA/flake.nix <<EOF
-{
- description = "Flake A";
- inputs = {
- B.url = "path:../flakeB";
- };
- outputs = { ... }: {};
-}
-EOF
-
-git -C $flakeFollowsA add flake.nix
-
-nix flake lock $flakeFollowsA 2>&1 | grep 'points outside'
-
-# Test flake in store does not evaluate
+# Test flake in store does not evaluate.
rm -rf $badFlakeDir
mkdir $badFlakeDir
echo INVALID > $badFlakeDir/flake.nix
@@ -834,3 +487,20 @@ nix store delete $(nix store add-path $badFlakeDir)
[[ $(nix path-info $(nix store add-path $flake1Dir)) =~ flake1 ]]
[[ $(nix path-info path:$(nix store add-path $flake1Dir)) =~ simple ]]
+
+# Test fetching flakerefs in the legacy CLI.
+[[ $(nix-instantiate --eval flake:flake3 -A x) = 123 ]]
+[[ $(nix-instantiate --eval flake:git+file://$flake3Dir -A x) = 123 ]]
+[[ $(nix-instantiate -I flake3=flake:flake3 --eval '<flake3>' -A x) = 123 ]]
+[[ $(NIX_PATH=flake3=flake:flake3 nix-instantiate --eval '<flake3>' -A x) = 123 ]]
+
+# Test alternate lockfile paths.
+nix flake lock $flake2Dir --output-lock-file $TEST_ROOT/flake2.lock
+cmp $flake2Dir/flake.lock $TEST_ROOT/flake2.lock >/dev/null # lockfiles should be identical, since we're referencing flake2's original one
+
+nix flake lock $flake2Dir --output-lock-file $TEST_ROOT/flake2-overridden.lock --override-input flake1 git+file://$flake1Dir?rev=$flake1OriginalCommit
+expectStderr 1 cmp $flake2Dir/flake.lock $TEST_ROOT/flake2-overridden.lock
+nix flake metadata $flake2Dir --reference-lock-file $TEST_ROOT/flake2-overridden.lock | grepQuiet $flake1OriginalCommit
+
+# reference-lock-file can only be used if allow-dirty is set.
+expectStderr 1 nix flake metadata $flake2Dir --no-allow-dirty --reference-lock-file $TEST_ROOT/flake2-overridden.lock
diff --git a/tests/flakes/follow-paths.sh b/tests/flakes/follow-paths.sh
new file mode 100644
index 000000000..fe9b51c65
--- /dev/null
+++ b/tests/flakes/follow-paths.sh
@@ -0,0 +1,150 @@
+source ./common.sh
+
+requireGit
+
+flakeFollowsA=$TEST_ROOT/follows/flakeA
+flakeFollowsB=$TEST_ROOT/follows/flakeA/flakeB
+flakeFollowsC=$TEST_ROOT/follows/flakeA/flakeB/flakeC
+flakeFollowsD=$TEST_ROOT/follows/flakeA/flakeD
+flakeFollowsE=$TEST_ROOT/follows/flakeA/flakeE
+
+# Test following path flakerefs.
+createGitRepo $flakeFollowsA
+mkdir -p $flakeFollowsB
+mkdir -p $flakeFollowsC
+mkdir -p $flakeFollowsD
+mkdir -p $flakeFollowsE
+
+cat > $flakeFollowsA/flake.nix <<EOF
+{
+ description = "Flake A";
+ inputs = {
+ B = {
+ url = "path:./flakeB";
+ inputs.foobar.follows = "foobar";
+ };
+
+ foobar.url = "path:$flakeFollowsA/flakeE";
+ };
+ outputs = { ... }: {};
+}
+EOF
+
+cat > $flakeFollowsB/flake.nix <<EOF
+{
+ description = "Flake B";
+ inputs = {
+ foobar.url = "path:$flakeFollowsA/flakeE";
+ goodoo.follows = "C/goodoo";
+ C = {
+ url = "path:./flakeC";
+ inputs.foobar.follows = "foobar";
+ };
+ };
+ outputs = { ... }: {};
+}
+EOF
+
+cat > $flakeFollowsC/flake.nix <<EOF
+{
+ description = "Flake C";
+ inputs = {
+ foobar.url = "path:$flakeFollowsA/flakeE";
+ goodoo.follows = "foobar";
+ };
+ outputs = { ... }: {};
+}
+EOF
+
+cat > $flakeFollowsD/flake.nix <<EOF
+{
+ description = "Flake D";
+ inputs = {};
+ outputs = { ... }: {};
+}
+EOF
+
+cat > $flakeFollowsE/flake.nix <<EOF
+{
+ description = "Flake E";
+ inputs = {};
+ outputs = { ... }: {};
+}
+EOF
+
+git -C $flakeFollowsA add flake.nix flakeB/flake.nix \
+ flakeB/flakeC/flake.nix flakeD/flake.nix flakeE/flake.nix
+
+nix flake metadata $flakeFollowsA
+
+nix flake update $flakeFollowsA
+
+nix flake lock $flakeFollowsA
+
+oldLock="$(cat "$flakeFollowsA/flake.lock")"
+
+# Ensure that locking twice doesn't change anything
+
+nix flake lock $flakeFollowsA
+
+newLock="$(cat "$flakeFollowsA/flake.lock")"
+
+diff <(echo "$newLock") <(echo "$oldLock")
+
+[[ $(jq -c .nodes.B.inputs.C $flakeFollowsA/flake.lock) = '"C"' ]]
+[[ $(jq -c .nodes.B.inputs.foobar $flakeFollowsA/flake.lock) = '["foobar"]' ]]
+[[ $(jq -c .nodes.C.inputs.foobar $flakeFollowsA/flake.lock) = '["B","foobar"]' ]]
+
+# Ensure removing follows from flake.nix removes them from the lockfile
+
+cat > $flakeFollowsA/flake.nix <<EOF
+{
+ description = "Flake A";
+ inputs = {
+ B = {
+ url = "path:./flakeB";
+ };
+ D.url = "path:./flakeD";
+ };
+ outputs = { ... }: {};
+}
+EOF
+
+nix flake lock $flakeFollowsA
+
+[[ $(jq -c .nodes.B.inputs.foobar $flakeFollowsA/flake.lock) = '"foobar"' ]]
+jq -r -c '.nodes | keys | .[]' $flakeFollowsA/flake.lock | grep "^foobar$"
+
+# Ensure a relative path is not allowed to go outside the store path
+cat > $flakeFollowsA/flake.nix <<EOF
+{
+ description = "Flake A";
+ inputs = {
+ B.url = "path:../flakeB";
+ };
+ outputs = { ... }: {};
+}
+EOF
+
+git -C $flakeFollowsA add flake.nix
+
+expect 1 nix flake lock $flakeFollowsA 2>&1 | grep 'points outside'
+
+# Non-existant follows should print a warning.
+cat >$flakeFollowsA/flake.nix <<EOF
+{
+ description = "Flake A";
+ inputs.B = {
+ url = "path:./flakeB";
+ inputs.invalid.follows = "D";
+ inputs.invalid2.url = "path:./flakeD";
+ };
+ inputs.D.url = "path:./flakeD";
+ outputs = { ... }: {};
+}
+EOF
+
+git -C $flakeFollowsA add flake.nix
+
+nix flake lock $flakeFollowsA 2>&1 | grep "warning: input 'B' has an override for a non-existent input 'invalid'"
+nix flake lock $flakeFollowsA 2>&1 | grep "warning: input 'B' has an override for a non-existent input 'invalid2'"
diff --git a/tests/flakes/init.sh b/tests/flakes/init.sh
new file mode 100644
index 000000000..2d4c77ba1
--- /dev/null
+++ b/tests/flakes/init.sh
@@ -0,0 +1,87 @@
+source ./common.sh
+
+requireGit
+
+templatesDir=$TEST_ROOT/templates
+flakeDir=$TEST_ROOT/flake
+nixpkgsDir=$TEST_ROOT/nixpkgs
+
+nix registry add --registry $registry templates git+file://$templatesDir
+nix registry add --registry $registry nixpkgs git+file://$nixpkgsDir
+
+createGitRepo $nixpkgsDir
+createSimpleGitFlake $nixpkgsDir
+
+# Test 'nix flake init'.
+createGitRepo $templatesDir
+
+cat > $templatesDir/flake.nix <<EOF
+{
+ description = "Some templates";
+
+ outputs = { self }: {
+ templates = rec {
+ trivial = {
+ path = ./trivial;
+ description = "A trivial flake";
+ welcomeText = ''
+ Welcome to my trivial flake
+ '';
+ };
+ default = trivial;
+ };
+ };
+}
+EOF
+
+mkdir $templatesDir/trivial
+
+cat > $templatesDir/trivial/flake.nix <<EOF
+{
+ description = "A flake for building Hello World";
+
+ outputs = { self, nixpkgs }: {
+ packages.$system = rec {
+ hello = nixpkgs.legacyPackages.$system.hello;
+ default = hello;
+ };
+ };
+}
+EOF
+echo a > $templatesDir/trivial/a
+echo b > $templatesDir/trivial/b
+
+git -C $templatesDir add flake.nix trivial/
+git -C $templatesDir commit -m 'Initial'
+
+nix flake check templates
+nix flake show templates
+nix flake show templates --json | jq
+
+createGitRepo $flakeDir
+(cd $flakeDir && nix flake init)
+(cd $flakeDir && nix flake init) # check idempotence
+git -C $flakeDir add flake.nix
+nix flake check $flakeDir
+nix flake show $flakeDir
+nix flake show $flakeDir --json | jq
+git -C $flakeDir commit -a -m 'Initial'
+
+# Test 'nix flake init' with benign conflicts
+createGitRepo "$flakeDir"
+echo a > $flakeDir/a
+(cd $flakeDir && nix flake init) # check idempotence
+
+# Test 'nix flake init' with conflicts
+createGitRepo "$flakeDir"
+echo b > $flakeDir/a
+pushd $flakeDir
+(! nix flake init) |& grep "refusing to overwrite existing file '$flakeDir/a'"
+popd
+git -C $flakeDir commit -a -m 'Changed'
+
+# Test 'nix flake new'.
+rm -rf $flakeDir
+nix flake new -t templates#trivial $flakeDir
+nix flake new -t templates#trivial $flakeDir # check idempotence
+nix flake check $flakeDir
diff --git a/tests/flakes/inputs.sh b/tests/flakes/inputs.sh
new file mode 100644
index 000000000..80620488a
--- /dev/null
+++ b/tests/flakes/inputs.sh
@@ -0,0 +1,80 @@
+source ./common.sh
+
+requireGit
+
+
+test_subdir_self_path() {
+ baseDir=$TEST_ROOT/$RANDOM
+ flakeDir=$baseDir/b-low
+ mkdir -p $flakeDir
+ writeSimpleFlake $baseDir
+ writeSimpleFlake $flakeDir
+
+ echo all good > $flakeDir/message
+ cat > $flakeDir/flake.nix <<EOF
+{
+ outputs = inputs: rec {
+ packages.$system = rec {
+ default =
+ assert builtins.readFile ./message == "all good\n";
+ assert builtins.readFile (inputs.self + "/message") == "all good\n";
+ import ./simple.nix;
+ };
+ };
+}
+EOF
+ (
+ nix build $baseDir?dir=b-low --no-link
+ )
+}
+test_subdir_self_path
+
+
+test_git_subdir_self_path() {
+ repoDir=$TEST_ROOT/repo-$RANDOM
+ createGitRepo $repoDir
+ flakeDir=$repoDir/b-low
+ mkdir -p $flakeDir
+ writeSimpleFlake $repoDir
+ writeSimpleFlake $flakeDir
+
+ echo all good > $flakeDir/message
+ cat > $flakeDir/flake.nix <<EOF
+{
+ outputs = inputs: rec {
+ packages.$system = rec {
+ default =
+ assert builtins.readFile ./message == "all good\n";
+ assert builtins.readFile (inputs.self + "/message") == "all good\n";
+ assert inputs.self.outPath == inputs.self.sourceInfo.outPath + "/b-low";
+ import ./simple.nix;
+ };
+ };
+}
+EOF
+ (
+ cd $flakeDir
+ git add .
+ git commit -m init
+ # nix build
+ )
+
+ clientDir=$TEST_ROOT/client-$RANDOM
+ mkdir -p $clientDir
+ cat > $clientDir/flake.nix <<EOF
+{
+ inputs.inp = {
+ type = "git";
+ url = "file://$repoDir";
+ dir = "b-low";
+ };
+
+ outputs = inputs: rec {
+ packages = inputs.inp.packages;
+ };
+}
+EOF
+ nix build $clientDir --no-link
+
+}
+test_git_subdir_self_path
diff --git a/tests/flakes/mercurial.sh b/tests/flakes/mercurial.sh
new file mode 100644
index 000000000..0622c79b7
--- /dev/null
+++ b/tests/flakes/mercurial.sh
@@ -0,0 +1,43 @@
+source ./common.sh
+
+[[ $(type -p hq) ]] || skipTest "Mercurial not installed"
+
+flake1Dir=$TEST_ROOT/flake-hg1
+mkdir -p $flake1Dir
+writeSimpleFlake $flake1Dir
+hg init $flake1Dir
+
+nix registry add --registry $registry flake1 hg+file://$flake1Dir
+
+flake2Dir=$TEST_ROOT/flake-hg2
+mkdir -p $flake2Dir
+writeDependentFlake $flake2Dir
+hg init $flake2Dir
+
+hg add $flake1Dir/*
+hg commit --config ui.username=foobar@example.org $flake1Dir -m 'Initial commit'
+
+hg add $flake2Dir/flake.nix
+hg commit --config ui.username=foobar@example.org $flake2Dir -m 'Initial commit'
+
+nix build -o $TEST_ROOT/result hg+file://$flake2Dir
+[[ -e $TEST_ROOT/result/hello ]]
+
+(! nix flake metadata --json hg+file://$flake2Dir | jq -e -r .revision)
+
+nix eval hg+file://$flake2Dir#expr
+
+nix eval hg+file://$flake2Dir#expr
+
+(! nix eval hg+file://$flake2Dir#expr --no-allow-dirty)
+
+(! nix flake metadata --json hg+file://$flake2Dir | jq -e -r .revision)
+
+hg commit --config ui.username=foobar@example.org $flake2Dir -m 'Add lock file'
+
+nix flake metadata --json hg+file://$flake2Dir --refresh | jq -e -r .revision
+nix flake metadata --json hg+file://$flake2Dir
+[[ $(nix flake metadata --json hg+file://$flake2Dir | jq -e -r .revCount) = 1 ]]
+
+nix build -o $TEST_ROOT/result hg+file://$flake2Dir --no-registries --no-allow-dirty
+nix build -o $TEST_ROOT/result hg+file://$flake2Dir --no-use-registries --no-allow-dirty
diff --git a/tests/flakes/run.sh b/tests/flakes/run.sh
new file mode 100644
index 000000000..9fa51d1c7
--- /dev/null
+++ b/tests/flakes/run.sh
@@ -0,0 +1,29 @@
+source ../common.sh
+
+clearStore
+rm -rf $TEST_HOME/.cache $TEST_HOME/.config $TEST_HOME/.local
+cp ../shell-hello.nix ../config.nix $TEST_HOME
+cd $TEST_HOME
+
+cat <<EOF > flake.nix
+{
+ outputs = {self}: {
+ packages.$system.pkgAsPkg = (import ./shell-hello.nix).hello;
+ packages.$system.appAsApp = self.packages.$system.appAsApp;
+
+ apps.$system.pkgAsApp = self.packages.$system.pkgAsPkg;
+ apps.$system.appAsApp = {
+ type = "app";
+ program = "\${(import ./shell-hello.nix).hello}/bin/hello";
+ };
+ };
+}
+EOF
+nix run --no-write-lock-file .#appAsApp
+nix run --no-write-lock-file .#pkgAsPkg
+
+! nix run --no-write-lock-file .#pkgAsApp || fail "'nix run' shouldn’t accept an 'app' defined under 'packages'"
+! nix run --no-write-lock-file .#appAsPkg || fail "elements of 'apps' should be of type 'app'"
+
+clearStore
+
diff --git a/tests/flake-searching.sh b/tests/flakes/search-root.sh
index db241f6d2..d8586dc8a 100644
--- a/tests/flake-searching.sh
+++ b/tests/flakes/search-root.sh
@@ -1,15 +1,11 @@
source common.sh
-if [[ -z $(type -p git) ]]; then
- echo "Git not installed; skipping flake search tests"
- exit 99
-fi
-
clearStore
-cp ./simple.nix ./simple.builder.sh ./config.nix $TEST_HOME
+writeSimpleFlake $TEST_HOME
cd $TEST_HOME
mkdir -p foo/subdir
+
echo '{ outputs = _: {}; }' > foo/flake.nix
cat <<EOF > flake.nix
{
@@ -43,10 +39,12 @@ nix build --override-input foo . || fail "flake should search up directories whe
sed "s,$PWD/foo,$PWD/foo/subdir,g" -i flake.nix
! nix build || fail "flake should not search upwards when part of inputs"
-pushd subdir
-git init
-for i in "${success[@]}" "${failure[@]}"; do
- ! nix build $i || fail "flake should not search past a git repository"
-done
-rm -rf .git
-popd
+if [[ -n $(type -p git) ]]; then
+ pushd subdir
+ git init
+ for i in "${success[@]}" "${failure[@]}"; do
+ ! nix build $i || fail "flake should not search past a git repository"
+ done
+ rm -rf .git
+ popd
+fi
diff --git a/tests/flakes/show.sh b/tests/flakes/show.sh
new file mode 100644
index 000000000..a3d300552
--- /dev/null
+++ b/tests/flakes/show.sh
@@ -0,0 +1,87 @@
+source ./common.sh
+
+flakeDir=$TEST_ROOT/flake
+mkdir -p "$flakeDir"
+
+writeSimpleFlake "$flakeDir"
+cd "$flakeDir"
+
+
+# By default: Only show the packages content for the current system and no
+# legacyPackages at all
+nix flake show --json > show-output.json
+nix eval --impure --expr '
+let show_output = builtins.fromJSON (builtins.readFile ./show-output.json);
+in
+assert show_output.packages.someOtherSystem.default == {};
+assert show_output.packages.${builtins.currentSystem}.default.name == "simple";
+assert show_output.legacyPackages.${builtins.currentSystem} == {};
+true
+'
+
+# With `--all-systems`, show the packages for all systems
+nix flake show --json --all-systems > show-output.json
+nix eval --impure --expr '
+let show_output = builtins.fromJSON (builtins.readFile ./show-output.json);
+in
+assert show_output.packages.someOtherSystem.default.name == "simple";
+assert show_output.legacyPackages.${builtins.currentSystem} == {};
+true
+'
+
+# With `--legacy`, show the legacy packages
+nix flake show --json --legacy > show-output.json
+nix eval --impure --expr '
+let show_output = builtins.fromJSON (builtins.readFile ./show-output.json);
+in
+assert show_output.legacyPackages.${builtins.currentSystem}.hello.name == "simple";
+true
+'
+
+# Test that attributes are only reported when they have actual content
+cat >flake.nix <<EOF
+{
+ description = "Bla bla";
+
+ outputs = inputs: rec {
+ apps.$system = { };
+ checks.$system = { };
+ devShells.$system = { };
+ legacyPackages.$system = { };
+ packages.$system = { };
+ packages.someOtherSystem = { };
+
+ formatter = { };
+ nixosConfigurations = { };
+ nixosModules = { };
+ };
+}
+EOF
+nix flake show --json --all-systems > show-output.json
+nix eval --impure --expr '
+let show_output = builtins.fromJSON (builtins.readFile ./show-output.json);
+in
+assert show_output == { };
+true
+'
+
+# Test that attributes with errors are handled correctly.
+# nixpkgs.legacyPackages is a particularly prominent instance of this.
+cat >flake.nix <<EOF
+{
+ outputs = inputs: {
+ legacyPackages.$system = {
+ AAAAAASomeThingsFailToEvaluate = throw "nooo";
+ simple = import ./simple.nix;
+ };
+ };
+}
+EOF
+nix flake show --json --legacy --all-systems > show-output.json
+nix eval --impure --expr '
+let show_output = builtins.fromJSON (builtins.readFile ./show-output.json);
+in
+assert show_output.legacyPackages.${builtins.currentSystem}.AAAAAASomeThingsFailToEvaluate == { };
+assert show_output.legacyPackages.${builtins.currentSystem}.simple.name == "simple";
+true
+'
diff --git a/tests/flakes/unlocked-override.sh b/tests/flakes/unlocked-override.sh
new file mode 100644
index 000000000..8abc8b7d3
--- /dev/null
+++ b/tests/flakes/unlocked-override.sh
@@ -0,0 +1,30 @@
+source ./common.sh
+
+requireGit
+
+flake1Dir=$TEST_ROOT/flake1
+flake2Dir=$TEST_ROOT/flake2
+
+createGitRepo $flake1Dir
+cat > $flake1Dir/flake.nix <<EOF
+{
+ outputs = { self }: { x = import ./x.nix; };
+}
+EOF
+echo 123 > $flake1Dir/x.nix
+git -C $flake1Dir add flake.nix x.nix
+git -C $flake1Dir commit -m Initial
+
+createGitRepo $flake2Dir
+cat > $flake2Dir/flake.nix <<EOF
+{
+ outputs = { self, flake1 }: { x = flake1.x; };
+}
+EOF
+git -C $flake2Dir add flake.nix
+
+[[ $(nix eval --json $flake2Dir#x --override-input flake1 $TEST_ROOT/flake1) = 123 ]]
+
+echo 456 > $flake1Dir/x.nix
+
+[[ $(nix eval --json $flake2Dir#x --override-input flake1 $TEST_ROOT/flake1) = 456 ]]
diff --git a/tests/fmt.sh b/tests/fmt.sh
new file mode 100644
index 000000000..3c1bd9989
--- /dev/null
+++ b/tests/fmt.sh
@@ -0,0 +1,33 @@
+source common.sh
+
+clearStore
+rm -rf $TEST_HOME/.cache $TEST_HOME/.config $TEST_HOME/.local
+
+cp ./simple.nix ./simple.builder.sh ./fmt.simple.sh ./config.nix $TEST_HOME
+
+cd $TEST_HOME
+
+nix fmt --help | grep "Format"
+
+cat << EOF > flake.nix
+{
+ outputs = _: {
+ formatter.$system =
+ with import ./config.nix;
+ mkDerivation {
+ name = "formatter";
+ buildCommand = ''
+ mkdir -p \$out/bin
+ echo "#! ${shell}" > \$out/bin/formatter
+ cat \${./fmt.simple.sh} >> \$out/bin/formatter
+ chmod +x \$out/bin/formatter
+ '';
+ };
+ };
+}
+EOF
+nix fmt ./file ./folder | grep 'Formatting: ./file ./folder'
+nix flake check
+nix flake show | grep -P "package 'formatter'"
+
+clearStore
diff --git a/tests/fmt.simple.sh b/tests/fmt.simple.sh
new file mode 100755
index 000000000..4c8c67ebb
--- /dev/null
+++ b/tests/fmt.simple.sh
@@ -0,0 +1 @@
+echo Formatting: "${@}"
diff --git a/tests/function-trace.sh b/tests/function-trace.sh
index 0b7f49d82..bd804bf18 100755
--- a/tests/function-trace.sh
+++ b/tests/function-trace.sh
@@ -10,17 +10,15 @@ expect_trace() {
--trace-function-calls \
--expr "$expr" 2>&1 \
| grep "function-trace" \
- | sed -e 's/ [0-9]*$//'
- );
+ | sed -e 's/ [0-9]*$//' \
+ || true
+ )
echo -n "Tracing expression '$expr'"
- set +e
msg=$(diff -swB \
<(echo "$expect") \
<(echo "$actual")
- );
- result=$?
- set -e
+ ) && result=0 || result=$?
if [ $result -eq 0 ]; then
echo " ok."
else
@@ -32,40 +30,38 @@ expect_trace() {
# failure inside a tryEval
expect_trace 'builtins.tryEval (throw "example")' "
-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
+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 (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
"
# Too many arguments to a formal function
expect_trace '({ x }: x) { x = "x"; y = "y"; }' "
-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 enough arguments to a lambda
expect_trace '(x: y: x + y) 1' "
-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
"
# Too many arguments to a lambda
expect_trace '(x: x) 1 2' "
-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 (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
"
-
-set -e
diff --git a/tests/gc-runtime.sh b/tests/gc-runtime.sh
index 6094959cb..dc1826a55 100644
--- a/tests/gc-runtime.sh
+++ b/tests/gc-runtime.sh
@@ -4,7 +4,7 @@ case $system in
*linux*)
;;
*)
- exit 99;
+ skipTest "Not running Linux";
esac
set -m # enable job control, needed for kill
diff --git a/tests/gc.sh b/tests/gc.sh
index ad09a8b39..98d6cb032 100644
--- a/tests/gc.sh
+++ b/tests/gc.sh
@@ -50,3 +50,20 @@ if test -e $outPath/foobar; then false; fi
# Check that the store is empty.
rmdir $NIX_STORE_DIR/.links
rmdir $NIX_STORE_DIR
+
+## Test `nix-collect-garbage -d`
+# `nix-env` doesn't work with CA derivations, so let's ignore that bit if we're
+# using them
+if [[ -z "${NIX_TESTS_CA_BY_DEFAULT:-}" ]]; then
+ clearProfiles
+ # Run two `nix-env` commands, should create two generations of
+ # the profile
+ nix-env -f ./user-envs.nix -i foo-1.0
+ nix-env -f ./user-envs.nix -i foo-2.0pre1
+ [[ $(nix-env --list-generations | wc -l) -eq 2 ]]
+
+ # Clear the profile history. There should be only one generation
+ # left
+ nix-collect-garbage -d
+ [[ $(nix-env --list-generations | wc -l) -eq 1 ]]
+fi
diff --git a/tests/hash.sh b/tests/hash.sh
index e5f75e2cf..34c1bb38a 100644
--- a/tests/hash.sh
+++ b/tests/hash.sh
@@ -2,13 +2,19 @@ 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"
+ hash="$(nix-hash --flat ${FORMAT_FLAG-} --type "$1" "$TEST_ROOT/vector")"
+ if ! (( "${NO_TEST_CLASSIC-}" )) && test "$hash" != "$3"; then
+ echo "try nix-hash: hash $1, expected $3, got $hash"
+ exit 1
+ fi
+ hash="$(nix hash file ${FORMAT_FLAG-} --type "$1" "$TEST_ROOT/vector")"
+ if ! (( "${NO_TEST_NIX_COMMAND-}" )) && test "$hash" != "$3"; then
+ echo "try nix hash: hash $1, expected $3, got $hash"
exit 1
fi
}
+FORMAT_FLAG=--base16
try md5 "" "d41d8cd98f00b204e9800998ecf8427e"
try md5 "a" "0cc175b9c0f1b6a831c399e269772661"
try md5 "abc" "900150983cd24fb0d6963f7d28e17f72"
@@ -28,16 +34,24 @@ try sha256 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" "248d6a61d
try sha512 "" "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"
try sha512 "abc" "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"
try sha512 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" "204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445"
+unset FORMAT_FLAG
-EXTRA=--base32
+FORMAT_FLAG=--base32
try sha256 "abc" "1b8m03r63zqhnjf7l5wnldhh7c134ap5vpj0850ymkq1iyzicy5s"
-EXTRA=
+unset FORMAT_FLAG
-EXTRA=--sri
+FORMAT_FLAG=--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="
+unset FORMAT_FLAG
+
+# nix-hash [--flat] defaults to the Base16 format
+NO_TEST_NIX_COMMAND=1 try sha512 "abc" "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"
+
+# nix hash [file|path] defaults to the SRI format
+NO_TEST_CLASSIC=1 try sha512 "abc" "sha512-3a81oZNherrMQXNJriBBMRLm+k6JqX6iCp7u5ktV05ohkpkqJ0/BqDa6PCOj/uu9RU1EI2Q86A4qmslPpUyknw=="
try2 () {
hash=$(nix-hash --type "$1" $TEST_ROOT/hash-path)
@@ -69,12 +83,18 @@ try2 md5 "f78b733a68f5edbdf9413899339eaa4a"
# Conversion.
try3() {
+ h64=$(nix-hash --type "$1" --to-base64 "$2")
+ [ "$h64" = "$4" ]
h64=$(nix hash to-base64 --type "$1" "$2")
[ "$h64" = "$4" ]
+ sri=$(nix-hash --type "$1" --to-sri "$2")
+ [ "$sri" = "$1-$4" ]
sri=$(nix hash to-sri --type "$1" "$2")
[ "$sri" = "$1-$4" ]
h32=$(nix-hash --type "$1" --to-base32 "$2")
[ "$h32" = "$3" ]
+ h32=$(nix hash to-base32 --type "$1" "$2")
+ [ "$h32" = "$3" ]
h16=$(nix-hash --type "$1" --to-base16 "$h32")
[ "$h16" = "$2" ]
h16=$(nix hash to-base16 --type "$1" "$h64")
diff --git a/tests/impure-derivations.nix b/tests/impure-derivations.nix
new file mode 100644
index 000000000..98547e6c1
--- /dev/null
+++ b/tests/impure-derivations.nix
@@ -0,0 +1,63 @@
+with import ./config.nix;
+
+rec {
+
+ impure = mkDerivation {
+ name = "impure";
+ outputs = [ "out" "stuff" ];
+ buildCommand =
+ ''
+ echo impure
+ x=$(< $TEST_ROOT/counter)
+ mkdir $out $stuff
+ echo $x > $out/n
+ ln -s $out/n $stuff/bla
+ printf $((x + 1)) > $TEST_ROOT/counter
+ '';
+ __impure = true;
+ impureEnvVars = [ "TEST_ROOT" ];
+ };
+
+ impureOnImpure = mkDerivation {
+ name = "impure-on-impure";
+ buildCommand =
+ ''
+ echo impure-on-impure
+ x=$(< ${impure}/n)
+ mkdir $out
+ printf X$x > $out/n
+ ln -s ${impure.stuff} $out/symlink
+ ln -s $out $out/self
+ '';
+ __impure = true;
+ };
+
+ # This is not allowed.
+ inputAddressed = mkDerivation {
+ name = "input-addressed";
+ buildCommand =
+ ''
+ cat ${impure} > $out
+ '';
+ };
+
+ contentAddressed = mkDerivation {
+ name = "content-addressed";
+ buildCommand =
+ ''
+ echo content-addressed
+ x=$(< ${impureOnImpure}/n)
+ printf ''${x:0:1} > $out
+ '';
+ outputHashMode = "recursive";
+ outputHash = "sha256-eBYxcgkuWuiqs4cKNgKwkb3vY/HR0vVsJnqe8itJGcQ=";
+ };
+
+ inputAddressedAfterCA = mkDerivation {
+ name = "input-addressed-after-ca";
+ buildCommand =
+ ''
+ cat ${contentAddressed} > $out
+ '';
+ };
+}
diff --git a/tests/impure-derivations.sh b/tests/impure-derivations.sh
new file mode 100644
index 000000000..7595fdd35
--- /dev/null
+++ b/tests/impure-derivations.sh
@@ -0,0 +1,56 @@
+source common.sh
+
+requireDaemonNewerThan "2.8pre20220311"
+
+enableFeatures "ca-derivations impure-derivations"
+restartDaemon
+
+clearStore
+
+# Basic test of impure derivations: building one a second time should not use the previous result.
+printf 0 > $TEST_ROOT/counter
+
+nix build --dry-run --json --file ./impure-derivations.nix impure.all
+json=$(nix build -L --no-link --json --file ./impure-derivations.nix impure.all)
+path1=$(echo $json | jq -r .[].outputs.out)
+path1_stuff=$(echo $json | jq -r .[].outputs.stuff)
+[[ $(< $path1/n) = 0 ]]
+[[ $(< $path1_stuff/bla) = 0 ]]
+
+[[ $(nix path-info --json $path1 | jq .[].ca) =~ fixed:r:sha256: ]]
+
+path2=$(nix build -L --no-link --json --file ./impure-derivations.nix impure | jq -r .[].outputs.out)
+[[ $(< $path2/n) = 1 ]]
+
+# Test impure derivations that depend on impure derivations.
+path3=$(nix build -L --no-link --json --file ./impure-derivations.nix impureOnImpure | jq -r .[].outputs.out)
+[[ $(< $path3/n) = X2 ]]
+
+path4=$(nix build -L --no-link --json --file ./impure-derivations.nix impureOnImpure | jq -r .[].outputs.out)
+[[ $(< $path4/n) = X3 ]]
+
+# Test that (self-)references work.
+[[ $(< $path4/symlink/bla) = 3 ]]
+[[ $(< $path4/self/n) = X3 ]]
+
+# Input-addressed derivations cannot depend on impure derivations directly.
+(! nix build -L --no-link --json --file ./impure-derivations.nix inputAddressed 2>&1) | grep 'depends on impure derivation'
+
+drvPath=$(nix eval --json --file ./impure-derivations.nix impure.drvPath | jq -r .)
+[[ $(nix show-derivation $drvPath | jq ".[\"$drvPath\"].outputs.out.impure") = true ]]
+[[ $(nix show-derivation $drvPath | jq ".[\"$drvPath\"].outputs.stuff.impure") = true ]]
+
+# Fixed-output derivations *can* depend on impure derivations.
+path5=$(nix build -L --no-link --json --file ./impure-derivations.nix contentAddressed | jq -r .[].outputs.out)
+[[ $(< $path5) = X ]]
+[[ $(< $TEST_ROOT/counter) = 5 ]]
+
+# And they should not be rebuilt.
+path5=$(nix build -L --no-link --json --file ./impure-derivations.nix contentAddressed | jq -r .[].outputs.out)
+[[ $(< $path5) = X ]]
+[[ $(< $TEST_ROOT/counter) = 5 ]]
+
+# Input-addressed derivations can depend on fixed-output derivations that depend on impure derivations.
+path6=$(nix build -L --no-link --json --file ./impure-derivations.nix inputAddressedAfterCA | jq -r .[].outputs.out)
+[[ $(< $path6) = X ]]
+[[ $(< $TEST_ROOT/counter) = 5 ]]
diff --git a/tests/init.sh b/tests/init.sh
index 909b50f63..2c4f4a2f3 100644..100755
--- a/tests/init.sh
+++ b/tests/init.sh
@@ -1,8 +1,11 @@
-source common.sh
+# Don't start the daemon
+source common/vars-and-functions.sh
test -n "$TEST_ROOT"
if test -d "$TEST_ROOT"; then
chmod -R u+w "$TEST_ROOT"
+ # We would delete any daemon socket, so let's stop the daemon first.
+ killDaemon
rm -rf "$TEST_ROOT"
fi
mkdir "$TEST_ROOT"
diff --git a/tests/install-darwin.sh b/tests/install-darwin.sh
index 7e44e54c4..ea2b75323 100755
--- a/tests/install-darwin.sh
+++ b/tests/install-darwin.sh
@@ -4,7 +4,7 @@ set -eux
cleanup() {
PLIST="/Library/LaunchDaemons/org.nixos.nix-daemon.plist"
- if sudo launchctl list | grep -q nix-daemon; then
+ if sudo launchctl list | grepQuiet nix-daemon; then
sudo launchctl unload "$PLIST"
fi
diff --git a/tests/installer/default.nix b/tests/installer/default.nix
new file mode 100644
index 000000000..49cfd2bcc
--- /dev/null
+++ b/tests/installer/default.nix
@@ -0,0 +1,244 @@
+{ binaryTarballs
+, nixpkgsFor
+}:
+
+let
+
+ installScripts = {
+ install-default = {
+ script = ''
+ tar -xf ./nix.tar.xz
+ mv ./nix-* nix
+ ./nix/install --no-channel-add
+ '';
+ };
+
+ install-force-no-daemon = {
+ script = ''
+ tar -xf ./nix.tar.xz
+ mv ./nix-* nix
+ ./nix/install --no-daemon --no-channel-add
+ '';
+ };
+
+ install-force-daemon = {
+ script = ''
+ tar -xf ./nix.tar.xz
+ mv ./nix-* nix
+ ./nix/install --daemon --no-channel-add
+ '';
+ };
+ };
+
+ mockChannel = pkgs:
+ pkgs.runCommandNoCC "mock-channel" {} ''
+ mkdir nixexprs
+ mkdir -p $out/channel
+ echo -n 'someContent' > nixexprs/someFile
+ tar cvf - nixexprs | bzip2 > $out/channel/nixexprs.tar.bz2
+ '';
+
+ disableSELinux = "sudo setenforce 0";
+
+ images = {
+
+ /*
+ "ubuntu-14-04" = {
+ image = import <nix/fetchurl.nix> {
+ url = "https://app.vagrantup.com/ubuntu/boxes/trusty64/versions/20190514.0.0/providers/virtualbox.box";
+ hash = "sha256-iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8=";
+ };
+ rootDisk = "box-disk1.vmdk";
+ system = "x86_64-linux";
+ };
+ */
+
+ "ubuntu-16-04" = {
+ image = import <nix/fetchurl.nix> {
+ url = "https://app.vagrantup.com/generic/boxes/ubuntu1604/versions/4.1.12/providers/libvirt.box";
+ hash = "sha256-lO4oYQR2tCh5auxAYe6bPOgEqOgv3Y3GC1QM1tEEEU8=";
+ };
+ rootDisk = "box.img";
+ system = "x86_64-linux";
+ };
+
+ "ubuntu-22-04" = {
+ image = import <nix/fetchurl.nix> {
+ url = "https://app.vagrantup.com/generic/boxes/ubuntu2204/versions/4.1.12/providers/libvirt.box";
+ hash = "sha256-HNll0Qikw/xGIcogni5lz01vUv+R3o8xowP2EtqjuUQ=";
+ };
+ rootDisk = "box.img";
+ system = "x86_64-linux";
+ };
+
+ "fedora-36" = {
+ image = import <nix/fetchurl.nix> {
+ url = "https://app.vagrantup.com/generic/boxes/fedora36/versions/4.1.12/providers/libvirt.box";
+ hash = "sha256-rxPgnDnFkTDwvdqn2CV3ZUo3re9AdPtSZ9SvOHNvaks=";
+ };
+ rootDisk = "box.img";
+ system = "x86_64-linux";
+ postBoot = disableSELinux;
+ };
+
+ # Currently fails with 'error while loading shared libraries:
+ # libsodium.so.23: cannot stat shared object: Invalid argument'.
+ /*
+ "rhel-6" = {
+ image = import <nix/fetchurl.nix> {
+ url = "https://app.vagrantup.com/generic/boxes/rhel6/versions/4.1.12/providers/libvirt.box";
+ hash = "sha256-QwzbvRoRRGqUCQptM7X/InRWFSP2sqwRt2HaaO6zBGM=";
+ };
+ rootDisk = "box.img";
+ system = "x86_64-linux";
+ };
+ */
+
+ "rhel-7" = {
+ image = import <nix/fetchurl.nix> {
+ url = "https://app.vagrantup.com/generic/boxes/rhel7/versions/4.1.12/providers/libvirt.box";
+ hash = "sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U=";
+ };
+ rootDisk = "box.img";
+ system = "x86_64-linux";
+ };
+
+ "rhel-8" = {
+ image = import <nix/fetchurl.nix> {
+ url = "https://app.vagrantup.com/generic/boxes/rhel8/versions/4.1.12/providers/libvirt.box";
+ hash = "sha256-zFOPjSputy1dPgrQRixBXmlyN88cAKjJ21VvjSWUCUY=";
+ };
+ rootDisk = "box.img";
+ system = "x86_64-linux";
+ postBoot = disableSELinux;
+ };
+
+ "rhel-9" = {
+ image = import <nix/fetchurl.nix> {
+ url = "https://app.vagrantup.com/generic/boxes/rhel9/versions/4.1.12/providers/libvirt.box";
+ hash = "sha256-vL/FbB3kK1rcSaR627nWmScYGKGk4seSmAdq6N5diMg=";
+ };
+ rootDisk = "box.img";
+ system = "x86_64-linux";
+ postBoot = disableSELinux;
+ extraQemuOpts = "-cpu Westmere-v2";
+ };
+
+ };
+
+ makeTest = imageName: testName:
+ let image = images.${imageName}; in
+ with nixpkgsFor.${image.system}.native;
+ runCommand
+ "installer-test-${imageName}-${testName}"
+ { buildInputs = [ qemu_kvm openssh ];
+ image = image.image;
+ postBoot = image.postBoot or "";
+ installScript = installScripts.${testName}.script;
+ binaryTarball = binaryTarballs.${system};
+ }
+ ''
+ shopt -s nullglob
+
+ echo "Unpacking Vagrant box $image..."
+ tar xvf $image
+
+ image_type=$(qemu-img info ${image.rootDisk} | sed 's/file format: \(.*\)/\1/; t; d')
+
+ qemu-img create -b ./${image.rootDisk} -F "$image_type" -f qcow2 ./disk.qcow2
+
+ extra_qemu_opts="${image.extraQemuOpts or ""}"
+
+ # Add the config disk, required by the Ubuntu images.
+ config_drive=$(echo *configdrive.vmdk || true)
+ if [[ -n $config_drive ]]; then
+ extra_qemu_opts+=" -drive id=disk2,file=$config_drive,if=virtio"
+ fi
+
+ echo "Starting qemu..."
+ qemu-kvm -m 4096 -nographic \
+ -drive id=disk1,file=./disk.qcow2,if=virtio \
+ -netdev user,id=net0,restrict=yes,hostfwd=tcp::20022-:22 -device virtio-net-pci,netdev=net0 \
+ $extra_qemu_opts &
+ qemu_pid=$!
+ trap "kill $qemu_pid" EXIT
+
+ if ! [ -e ./vagrant_insecure_key ]; then
+ cp ${./vagrant_insecure_key} vagrant_insecure_key
+ fi
+
+ chmod 0400 ./vagrant_insecure_key
+
+ ssh_opts="-o StrictHostKeyChecking=no -o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa -i ./vagrant_insecure_key"
+ ssh="ssh -p 20022 -q $ssh_opts vagrant@localhost"
+
+ echo "Waiting for SSH..."
+ for ((i = 0; i < 120; i++)); do
+ echo "[ssh] Trying to connect..."
+ if $ssh -- true; then
+ echo "[ssh] Connected!"
+ break
+ fi
+ if ! kill -0 $qemu_pid; then
+ echo "qemu died unexpectedly"
+ exit 1
+ fi
+ sleep 1
+ done
+
+ if [[ -n $postBoot ]]; then
+ echo "Running post-boot commands..."
+ $ssh "set -ex; $postBoot"
+ fi
+
+ echo "Copying installer..."
+ scp -P 20022 $ssh_opts $binaryTarball/nix-*.tar.xz vagrant@localhost:nix.tar.xz
+
+ echo "Running installer..."
+ $ssh "set -eux; $installScript"
+
+ echo "Copying the mock channel"
+ # `scp -r` doesn't seem to work properly on some rhel instances, so let's
+ # use a plain tarpipe instead
+ tar -C ${mockChannel pkgs} -c channel | ssh -p 20022 $ssh_opts vagrant@localhost tar x -f-
+
+ echo "Testing Nix installation..."
+ $ssh <<EOF
+ set -ex
+
+ # FIXME: get rid of this; ideally ssh should just work.
+ source ~/.bash_profile || true
+ source ~/.bash_login || true
+ source ~/.profile || true
+ source /etc/bashrc || true
+
+ nix-env --version
+ nix --extra-experimental-features nix-command store ping
+
+ out=\$(nix-build --no-substitute -E 'derivation { name = "foo"; system = "x86_64-linux"; builder = "/bin/sh"; args = ["-c" "echo foobar > \$out"]; }')
+ [[ \$(cat \$out) = foobar ]]
+
+ if pgrep nix-daemon; then
+ MAYBESUDO="sudo"
+ else
+ MAYBESUDO=""
+ fi
+
+
+ $MAYBESUDO \$(which nix-channel) --add file://\$HOME/channel myChannel
+ $MAYBESUDO \$(which nix-channel) --update
+ [[ \$(nix-instantiate --eval --expr 'builtins.readFile <myChannel/someFile>') = '"someContent"' ]]
+ EOF
+
+ echo "Done!"
+ touch $out
+ '';
+
+in
+
+builtins.mapAttrs (imageName: image:
+ { ${image.system} = builtins.mapAttrs (testName: test:
+ makeTest imageName testName
+ ) installScripts;
+ }
+) images
diff --git a/tests/installer/vagrant_insecure_key b/tests/installer/vagrant_insecure_key
new file mode 100644
index 000000000..7d6a08390
--- /dev/null
+++ b/tests/installer/vagrant_insecure_key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzI
+w+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoP
+kcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2
+hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NO
+Td0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcW
+yLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQIBIwKCAQEA4iqWPJXtzZA68mKd
+ELs4jJsdyky+ewdZeNds5tjcnHU5zUYE25K+ffJED9qUWICcLZDc81TGWjHyAqD1
+Bw7XpgUwFgeUJwUlzQurAv+/ySnxiwuaGJfhFM1CaQHzfXphgVml+fZUvnJUTvzf
+TK2Lg6EdbUE9TarUlBf/xPfuEhMSlIE5keb/Zz3/LUlRg8yDqz5w+QWVJ4utnKnK
+iqwZN0mwpwU7YSyJhlT4YV1F3n4YjLswM5wJs2oqm0jssQu/BT0tyEXNDYBLEF4A
+sClaWuSJ2kjq7KhrrYXzagqhnSei9ODYFShJu8UWVec3Ihb5ZXlzO6vdNQ1J9Xsf
+4m+2ywKBgQD6qFxx/Rv9CNN96l/4rb14HKirC2o/orApiHmHDsURs5rUKDx0f9iP
+cXN7S1uePXuJRK/5hsubaOCx3Owd2u9gD6Oq0CsMkE4CUSiJcYrMANtx54cGH7Rk
+EjFZxK8xAv1ldELEyxrFqkbE4BKd8QOt414qjvTGyAK+OLD3M2QdCQKBgQDtx8pN
+CAxR7yhHbIWT1AH66+XWN8bXq7l3RO/ukeaci98JfkbkxURZhtxV/HHuvUhnPLdX
+3TwygPBYZFNo4pzVEhzWoTtnEtrFueKxyc3+LjZpuo+mBlQ6ORtfgkr9gBVphXZG
+YEzkCD3lVdl8L4cw9BVpKrJCs1c5taGjDgdInQKBgHm/fVvv96bJxc9x1tffXAcj
+3OVdUN0UgXNCSaf/3A/phbeBQe9xS+3mpc4r6qvx+iy69mNBeNZ0xOitIjpjBo2+
+dBEjSBwLk5q5tJqHmy/jKMJL4n9ROlx93XS+njxgibTvU6Fp9w+NOFD/HvxB3Tcz
+6+jJF85D5BNAG3DBMKBjAoGBAOAxZvgsKN+JuENXsST7F89Tck2iTcQIT8g5rwWC
+P9Vt74yboe2kDT531w8+egz7nAmRBKNM751U/95P9t88EDacDI/Z2OwnuFQHCPDF
+llYOUI+SpLJ6/vURRbHSnnn8a/XG+nzedGH5JGqEJNQsz+xT2axM0/W/CRknmGaJ
+kda/AoGANWrLCz708y7VYgAtW2Uf1DPOIYMdvo6fxIB5i9ZfISgcJ/bbCUkFrhoH
++vq/5CIWxCPp0f85R4qxxQ5ihxJ0YDQT9Jpx4TMss4PSavPaBH3RXow5Ohe+bYoQ
+NE5OgEXk2wVfZczCZpigBKbKZHNYcelXtTt/nP3rsCuGcM4h53s=
+-----END RSA PRIVATE KEY-----
diff --git a/tests/lang.sh b/tests/lang.sh
index 61bb444ba..8170cb39d 100644
--- a/tests/lang.sh
+++ b/tests/lang.sh
@@ -2,10 +2,21 @@ source common.sh
export TEST_VAR=foo # for eval-okay-getenv.nix
export NIX_REMOTE=dummy://
+export NIX_STORE_DIR=/nix/store
-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
+nix-instantiate --eval -E 'builtins.trace "Hello" 123' 2>&1 | grepQuiet Hello
+nix-instantiate --eval -E 'builtins.trace "Hello" 123' 2>/dev/null | grepQuiet 123
+nix-instantiate --eval -E 'builtins.addErrorContext "Hello" 123' 2>&1
+nix-instantiate --trace-verbose --eval -E 'builtins.traceVerbose "Hello" 123' 2>&1 | grepQuiet Hello
+nix-instantiate --eval -E 'builtins.traceVerbose "Hello" 123' 2>&1 | grepQuietInverse Hello
+nix-instantiate --show-trace --eval -E 'builtins.addErrorContext "Hello" 123' 2>&1 | grepQuietInverse Hello
+expectStderr 1 nix-instantiate --show-trace --eval -E 'builtins.addErrorContext "Hello" (throw "Foo")' | grepQuiet Hello
+
+nix-instantiate --eval -E 'let x = builtins.trace { x = x; } true; in x' \
+ 2>&1 | grepQuiet -E 'trace: { x = «potential infinite recursion»; }'
+
+nix-instantiate --eval -E 'let x = { repeating = x; tracing = builtins.trace x true; }; in x.tracing'\
+ 2>&1 | grepQuiet -F 'trace: { repeating = «repeated»; tracing = «potential infinite recursion»; }'
set +x
@@ -14,7 +25,7 @@ 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
+ if ! expect 1 nix-instantiate --parse - < lang/$i.nix; then
echo "FAIL: $i shouldn't parse"
fail=1
fi
@@ -23,7 +34,7 @@ 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
+ if ! expect 0 nix-instantiate --parse - < lang/$i.nix > lang/$i.out; then
echo "FAIL: $i should parse"
fail=1
fi
@@ -32,7 +43,7 @@ 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
+ if ! expect 1 nix-instantiate --eval lang/$i.nix; then
echo "FAIL: $i shouldn't evaluate"
fail=1
fi
@@ -47,17 +58,17 @@ for i in lang/eval-okay-*.nix; do
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
+ if ! expect 0 env NIX_PATH=lang/dir3:lang/dir4 HOME=/fake-home 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
+ elif ! diff <(< lang/$i.out sed -e "s|$(pwd)|/pwd|g") 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 \
+ if ! expect 0 nix-instantiate --eval --xml --no-location --strict \
lang/$i.nix > lang/$i.out.xml; then
echo "FAIL: $i should evaluate"
fail=1
diff --git a/tests/lang/eval-fail-foldlStrict-strict-op-application.nix b/tests/lang/eval-fail-foldlStrict-strict-op-application.nix
new file mode 100644
index 000000000..1620cc76e
--- /dev/null
+++ b/tests/lang/eval-fail-foldlStrict-strict-op-application.nix
@@ -0,0 +1,5 @@
+# Tests that the result of applying op is forced even if the value is never used
+builtins.foldl'
+ (_: f: f null)
+ null
+ [ (_: throw "Not the final value, but is still forced!") (_: 23) ]
diff --git a/tests/lang/eval-okay-closure.exp b/tests/lang/eval-okay-closure.exp
new file mode 100644
index 000000000..e7dbf9781
--- /dev/null
+++ b/tests/lang/eval-okay-closure.exp
@@ -0,0 +1 @@
+[ { foo = true; key = -13; } { foo = true; key = -12; } { foo = true; key = -11; } { foo = true; key = -9; } { foo = true; key = -8; } { foo = true; key = -7; } { foo = true; key = -5; } { foo = true; key = -4; } { foo = true; key = -3; } { key = -1; } { foo = true; key = 0; } { foo = true; key = 1; } { foo = true; key = 2; } { foo = true; key = 4; } { foo = true; key = 5; } { foo = true; key = 6; } { key = 8; } { foo = true; key = 9; } { foo = true; key = 10; } { foo = true; key = 13; } { foo = true; key = 14; } { foo = true; key = 15; } { key = 17; } { foo = true; key = 18; } { foo = true; key = 19; } { foo = true; key = 22; } { foo = true; key = 23; } { key = 26; } { foo = true; key = 27; } { foo = true; key = 28; } { foo = true; key = 31; } { foo = true; key = 32; } { key = 35; } { foo = true; key = 36; } { foo = true; key = 40; } { foo = true; key = 41; } { key = 44; } { foo = true; key = 45; } { foo = true; key = 49; } { key = 53; } { foo = true; key = 54; } { foo = true; key = 58; } { key = 62; } { foo = true; key = 67; } { key = 71; } { key = 80; } ]
diff --git a/tests/lang/eval-okay-context-introspection.exp b/tests/lang/eval-okay-context-introspection.exp
index 27ba77dda..03b400cc8 100644
--- a/tests/lang/eval-okay-context-introspection.exp
+++ b/tests/lang/eval-okay-context-introspection.exp
@@ -1 +1 @@
-true
+[ true true true true true true ]
diff --git a/tests/lang/eval-okay-context-introspection.nix b/tests/lang/eval-okay-context-introspection.nix
index 43178bd2e..50a78d946 100644
--- a/tests/lang/eval-okay-context-introspection.nix
+++ b/tests/lang/eval-okay-context-introspection.nix
@@ -18,7 +18,24 @@ let
};
};
- legit-context = builtins.getContext "${path}${drv.outPath}${drv.foo.outPath}${drv.drvPath}";
+ combo-path = "${path}${drv.outPath}${drv.foo.outPath}${drv.drvPath}";
+ legit-context = builtins.getContext combo-path;
- constructed-context = builtins.getContext (builtins.appendContext "" desired-context);
-in legit-context == constructed-context
+ reconstructed-path = builtins.appendContext
+ (builtins.unsafeDiscardStringContext combo-path)
+ desired-context;
+
+ # Eta rule for strings with context.
+ etaRule = str:
+ str == builtins.appendContext
+ (builtins.unsafeDiscardStringContext str)
+ (builtins.getContext str);
+
+in [
+ (legit-context == desired-context)
+ (reconstructed-path == combo-path)
+ (etaRule "foo")
+ (etaRule drv.drvPath)
+ (etaRule drv.foo.outPath)
+ (etaRule (builtins.unsafeDiscardOutputDependency drv.drvPath))
+]
diff --git a/tests/lang/eval-okay-eq.exp b/tests/lang/eval-okay-eq.exp
new file mode 100644
index 000000000..27ba77dda
--- /dev/null
+++ b/tests/lang/eval-okay-eq.exp
@@ -0,0 +1 @@
+true
diff --git a/tests/lang/eval-okay-eq.exp.disabled b/tests/lang/eval-okay-eq.exp.disabled
deleted file mode 100644
index 2015847b6..000000000
--- a/tests/lang/eval-okay-eq.exp.disabled
+++ /dev/null
@@ -1 +0,0 @@
-Bool(True)
diff --git a/tests/lang/eval-okay-foldlStrict-lazy-elements.exp b/tests/lang/eval-okay-foldlStrict-lazy-elements.exp
new file mode 100644
index 000000000..d81cc0710
--- /dev/null
+++ b/tests/lang/eval-okay-foldlStrict-lazy-elements.exp
@@ -0,0 +1 @@
+42
diff --git a/tests/lang/eval-okay-foldlStrict-lazy-elements.nix b/tests/lang/eval-okay-foldlStrict-lazy-elements.nix
new file mode 100644
index 000000000..c666e07f3
--- /dev/null
+++ b/tests/lang/eval-okay-foldlStrict-lazy-elements.nix
@@ -0,0 +1,9 @@
+# Tests that the rhs argument of op is not forced unconditionally
+let
+ lst = builtins.foldl'
+ (acc: x: acc ++ [ x ])
+ [ ]
+ [ 42 (throw "this shouldn't be evaluated") ];
+in
+
+builtins.head lst
diff --git a/tests/lang/eval-okay-foldlStrict-lazy-initial-accumulator.exp b/tests/lang/eval-okay-foldlStrict-lazy-initial-accumulator.exp
new file mode 100644
index 000000000..d81cc0710
--- /dev/null
+++ b/tests/lang/eval-okay-foldlStrict-lazy-initial-accumulator.exp
@@ -0,0 +1 @@
+42
diff --git a/tests/lang/eval-okay-foldlStrict-lazy-initial-accumulator.nix b/tests/lang/eval-okay-foldlStrict-lazy-initial-accumulator.nix
new file mode 100644
index 000000000..abcd5366a
--- /dev/null
+++ b/tests/lang/eval-okay-foldlStrict-lazy-initial-accumulator.nix
@@ -0,0 +1,6 @@
+# Checks that the nul value for the accumulator is not forced unconditionally.
+# Some languages provide a foldl' that is strict in this argument, but Nix does not.
+builtins.foldl'
+ (_: x: x)
+ (throw "This is never forced")
+ [ "but the results of applying op are" 42 ]
diff --git a/tests/lang/eval-okay-fromjson.nix b/tests/lang/eval-okay-fromjson.nix
index 102ee82b5..e1c0f86cc 100644
--- a/tests/lang/eval-okay-fromjson.nix
+++ b/tests/lang/eval-okay-fromjson.nix
@@ -1,36 +1,35 @@
-# RFC 7159, section 13.
builtins.fromJSON
''
{
- "Image": {
- "Width": 800,
- "Height": 600,
- "Title": "View from 15th Floor",
- "Thumbnail": {
- "Url": "http://www.example.com/image/481989943",
- "Height": 125,
- "Width": 100
+ "Video": {
+ "Title": "The Penguin Chronicles",
+ "Width": 1920,
+ "Height": 1080,
+ "EmbeddedData": [3.14159, 23493,null, true ,false, -10],
+ "Thumb": {
+ "Url": "http://www.example.com/video/5678931",
+ "Width": 200,
+ "Height": 250
},
- "Animated" : false,
- "IDs": [116, 943, 234, 38793, true ,false,null, -100],
- "Latitude": 37.7668,
- "Longitude": -122.3959
+ "Subtitle" : false,
+ "Latitude": 46.2051,
+ "Longitude": 6.0723
}
}
''
==
- { Image =
- { Width = 800;
- Height = 600;
- Title = "View from 15th Floor";
- Thumbnail =
- { Url = http://www.example.com/image/481989943;
- Height = 125;
- Width = 100;
+ { Video =
+ { Title = "The Penguin Chronicles";
+ Width = 1920;
+ Height = 1080;
+ EmbeddedData = [ 3.14159 23493 null true false (0-10) ];
+ Thumb =
+ { Url = "http://www.example.com/video/5678931";
+ Width = 200;
+ Height = 250;
};
- Animated = false;
- IDs = [ 116 943 234 38793 true false null (0-100) ];
- Latitude = 37.7668;
- Longitude = -122.3959;
+ Subtitle = false;
+ Latitude = 46.2051;
+ Longitude = 6.0723;
};
}
diff --git a/tests/lang/eval-okay-functionargs.exp b/tests/lang/eval-okay-functionargs.exp
new file mode 100644
index 000000000..c1c9f8ffa
--- /dev/null
+++ b/tests/lang/eval-okay-functionargs.exp
@@ -0,0 +1 @@
+[ "stdenv" "fetchurl" "aterm-stdenv" "aterm-stdenv2" "libX11" "libXv" "mplayer-stdenv2.libXv-libX11" "mplayer-stdenv2.libXv-libX11_2" "nix-stdenv-aterm-stdenv" "nix-stdenv2-aterm2-stdenv2" ]
diff --git a/tests/lang/eval-okay-ind-string.nix b/tests/lang/eval-okay-ind-string.nix
index 1669dc064..95d59b508 100644
--- a/tests/lang/eval-okay-ind-string.nix
+++ b/tests/lang/eval-okay-ind-string.nix
@@ -110,7 +110,7 @@ let
And finally to interpret \n etc. as in a string: ''\n, ''\r, ''\t.
'';
- # Regression test: antiquotation in '${x}' should work, but didn't.
+ # Regression test: string interpolation in '${x}' should work, but didn't.
s15 = let x = "bla"; in ''
foo
'${x}'
diff --git a/tests/lang/eval-okay-intersectAttrs.exp b/tests/lang/eval-okay-intersectAttrs.exp
new file mode 100644
index 000000000..50445bc0e
--- /dev/null
+++ b/tests/lang/eval-okay-intersectAttrs.exp
@@ -0,0 +1 @@
+[ { } { a = 1; } { a = 1; } { a = "a"; } { m = 1; } { m = "m"; } { n = 1; } { n = "n"; } { n = 1; p = 2; } { n = "n"; p = "p"; } { n = 1; p = 2; } { n = "n"; p = "p"; } { a = "a"; b = "b"; c = "c"; d = "d"; e = "e"; f = "f"; g = "g"; h = "h"; i = "i"; j = "j"; k = "k"; l = "l"; m = "m"; n = "n"; o = "o"; p = "p"; q = "q"; r = "r"; s = "s"; t = "t"; u = "u"; v = "v"; w = "w"; x = "x"; y = "y"; z = "z"; } true ]
diff --git a/tests/lang/eval-okay-intersectAttrs.nix b/tests/lang/eval-okay-intersectAttrs.nix
new file mode 100644
index 000000000..39d49938c
--- /dev/null
+++ b/tests/lang/eval-okay-intersectAttrs.nix
@@ -0,0 +1,50 @@
+let
+ alphabet =
+ { a = "a";
+ b = "b";
+ c = "c";
+ d = "d";
+ e = "e";
+ f = "f";
+ g = "g";
+ h = "h";
+ i = "i";
+ j = "j";
+ k = "k";
+ l = "l";
+ m = "m";
+ n = "n";
+ o = "o";
+ p = "p";
+ q = "q";
+ r = "r";
+ s = "s";
+ t = "t";
+ u = "u";
+ v = "v";
+ w = "w";
+ x = "x";
+ y = "y";
+ z = "z";
+ };
+ foo = {
+ inherit (alphabet) f o b a r z q u x;
+ aa = throw "aa";
+ };
+ alphabetFail = builtins.mapAttrs throw alphabet;
+in
+[ (builtins.intersectAttrs { a = abort "l1"; } { b = abort "r1"; })
+ (builtins.intersectAttrs { a = abort "l2"; } { a = 1; })
+ (builtins.intersectAttrs alphabetFail { a = 1; })
+ (builtins.intersectAttrs { a = abort "laa"; } alphabet)
+ (builtins.intersectAttrs alphabetFail { m = 1; })
+ (builtins.intersectAttrs { m = abort "lam"; } alphabet)
+ (builtins.intersectAttrs alphabetFail { n = 1; })
+ (builtins.intersectAttrs { n = abort "lan"; } alphabet)
+ (builtins.intersectAttrs alphabetFail { n = 1; p = 2; })
+ (builtins.intersectAttrs { n = abort "lan2"; p = abort "lap"; } alphabet)
+ (builtins.intersectAttrs alphabetFail { n = 1; p = 2; })
+ (builtins.intersectAttrs { n = abort "lan2"; p = abort "lap"; } alphabet)
+ (builtins.intersectAttrs alphabetFail alphabet)
+ (builtins.intersectAttrs alphabet foo == builtins.intersectAttrs foo alphabet)
+]
diff --git a/tests/lang/eval-okay-path-antiquotation.exp b/tests/lang/eval-okay-path-antiquotation.exp
new file mode 100644
index 000000000..5b8ea0243
--- /dev/null
+++ b/tests/lang/eval-okay-path-antiquotation.exp
@@ -0,0 +1 @@
+{ absolute = /foo; expr = /pwd/lang/foo/bar; home = /fake-home/foo; notfirst = /pwd/lang/bar/foo; simple = /pwd/lang/foo; slashes = /foo/bar; surrounded = /pwd/lang/a-foo-b; }
diff --git a/tests/lang/eval-okay-path.exp b/tests/lang/eval-okay-path.exp
new file mode 100644
index 000000000..3ce7f8283
--- /dev/null
+++ b/tests/lang/eval-okay-path.exp
@@ -0,0 +1 @@
+"/nix/store/ya937r4ydw0l6kayq8jkyqaips9c75jm-output"
diff --git a/tests/lang/eval-okay-readDir.exp b/tests/lang/eval-okay-readDir.exp
index bf8d2c14e..6413f6d4f 100644
--- a/tests/lang/eval-okay-readDir.exp
+++ b/tests/lang/eval-okay-readDir.exp
@@ -1 +1 @@
-{ bar = "regular"; foo = "directory"; }
+{ bar = "regular"; foo = "directory"; ldir = "symlink"; linked = "symlink"; }
diff --git a/tests/lang/eval-okay-readFileType.exp b/tests/lang/eval-okay-readFileType.exp
new file mode 100644
index 000000000..6413f6d4f
--- /dev/null
+++ b/tests/lang/eval-okay-readFileType.exp
@@ -0,0 +1 @@
+{ bar = "regular"; foo = "directory"; ldir = "symlink"; linked = "symlink"; }
diff --git a/tests/lang/eval-okay-readFileType.nix b/tests/lang/eval-okay-readFileType.nix
new file mode 100644
index 000000000..174fb6c3a
--- /dev/null
+++ b/tests/lang/eval-okay-readFileType.nix
@@ -0,0 +1,6 @@
+{
+ bar = builtins.readFileType ./readDir/bar;
+ foo = builtins.readFileType ./readDir/foo;
+ linked = builtins.readFileType ./readDir/linked;
+ ldir = builtins.readFileType ./readDir/ldir;
+}
diff --git a/tests/lang/eval-okay-versions.nix b/tests/lang/eval-okay-versions.nix
index e63c36586..e9111f5f4 100644
--- a/tests/lang/eval-okay-versions.nix
+++ b/tests/lang/eval-okay-versions.nix
@@ -4,6 +4,7 @@ let
name2 = "hello";
name3 = "915resolution-0.5.2";
name4 = "xf86-video-i810-1.7.4";
+ name5 = "name-that-ends-with-dash--1.0";
eq = 0;
lt = builtins.sub 0 1;
@@ -23,6 +24,8 @@ let
((builtins.parseDrvName name3).version == "0.5.2")
((builtins.parseDrvName name4).name == "xf86-video-i810")
((builtins.parseDrvName name4).version == "1.7.4")
+ ((builtins.parseDrvName name5).name == "name-that-ends-with-dash")
+ ((builtins.parseDrvName name5).version == "-1.0")
(versionTest "1.0" "2.3" lt)
(versionTest "2.1" "2.3" lt)
(versionTest "2.3" "2.3" eq)
diff --git a/tests/lang/parse-fail-eof-in-string.nix b/tests/lang/parse-fail-eof-in-string.nix
new file mode 100644
index 000000000..19775d2ec
--- /dev/null
+++ b/tests/lang/parse-fail-eof-in-string.nix
@@ -0,0 +1,3 @@
+# https://github.com/NixOS/nix/issues/6562
+# Note that this file must not end with a newline.
+a 1"$ \ No newline at end of file
diff --git a/tests/lang/readDir/ldir b/tests/lang/readDir/ldir
new file mode 120000
index 000000000..191028156
--- /dev/null
+++ b/tests/lang/readDir/ldir
@@ -0,0 +1 @@
+foo \ No newline at end of file
diff --git a/tests/lang/readDir/linked b/tests/lang/readDir/linked
new file mode 120000
index 000000000..c503f86a0
--- /dev/null
+++ b/tests/lang/readDir/linked
@@ -0,0 +1 @@
+foo/git-hates-directories \ No newline at end of file
diff --git a/tests/legacy-ssh-store.sh b/tests/legacy-ssh-store.sh
new file mode 100644
index 000000000..71b716b84
--- /dev/null
+++ b/tests/legacy-ssh-store.sh
@@ -0,0 +1,4 @@
+source common.sh
+
+# Check that store ping trusted doesn't yet work with ssh://
+nix --store ssh://localhost?remote-store=$TEST_ROOT/other-store store ping --json | jq -e 'has("trusted") | not'
diff --git a/tests/linux-sandbox.sh b/tests/linux-sandbox.sh
index 3f304ac2f..5a2cf7abd 100644
--- a/tests/linux-sandbox.sh
+++ b/tests/linux-sandbox.sh
@@ -4,13 +4,13 @@ needLocalStore "the sandbox only runs on the builder side, so it makes no sense
clearStore
-if ! canUseSandbox; then exit 99; fi
+requireSandboxSupport
# 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 99; fi
+if [[ ! $SHELL =~ /nix/store ]]; then skipTest "Shell is not from Nix store"; fi
chmod -R u+w $TEST_ROOT/store0 || true
rm -rf $TEST_ROOT/store0
@@ -35,5 +35,8 @@ nix-build dependencies.nix --no-out-link --check --sandbox-paths /nix/store
nix-build check.nix -A nondeterministic --sandbox-paths /nix/store --no-out-link
(! nix-build check.nix -A nondeterministic --sandbox-paths /nix/store --no-out-link --check -K 2> $TEST_ROOT/log)
-if grep -q 'error: renaming' $TEST_ROOT/log; then false; fi
-grep -q 'may not be deterministic' $TEST_ROOT/log
+if grepQuiet 'error: renaming' $TEST_ROOT/log; then false; fi
+grepQuiet 'may not be deterministic' $TEST_ROOT/log
+
+# Test that sandboxed builds cannot write to /etc easily
+(! nix-build -E 'with import ./config.nix; mkDerivation { name = "etc-write"; buildCommand = "echo > /etc/test"; }' --no-out-link --sandbox-paths /nix/store)
diff --git a/tests/local-store.sh b/tests/local-store.sh
index 0247346f1..89502f864 100644
--- a/tests/local-store.sh
+++ b/tests/local-store.sh
@@ -17,3 +17,6 @@ PATH2=$(nix path-info --store "$PWD/x" $CORRECT_PATH)
PATH3=$(nix path-info --store "local?root=$PWD/x" $CORRECT_PATH)
[ $CORRECT_PATH == $PATH3 ]
+
+# Ensure store ping trusted works with local store
+nix --store ./x store ping --json | jq -e '.trusted'
diff --git a/tests/local.mk b/tests/local.mk
index 7074579c9..0c002a37c 100644
--- a/tests/local.mk
+++ b/tests/local.mk
@@ -1,15 +1,33 @@
nix_tests = \
- flakes.sh \
+ test-infra.sh \
+ init.sh \
+ flakes/flakes.sh \
+ flakes/run.sh \
+ flakes/mercurial.sh \
+ flakes/circular.sh \
+ flakes/init.sh \
+ flakes/inputs.sh \
+ flakes/follow-paths.sh \
+ flakes/bundle.sh \
+ flakes/check.sh \
+ flakes/unlocked-override.sh \
+ flakes/absolute-paths.sh \
+ flakes/build-paths.sh \
+ flakes/flake-in-submodule.sh \
ca/gc.sh \
gc.sh \
remote-store.sh \
+ legacy-ssh-store.sh \
lang.sh \
+ experimental-features.sh \
fetchMercurial.sh \
gc-auto.sh \
user-envs.sh \
+ user-envs-migration.sh \
binary-cache.sh \
multiple-outputs.sh \
ca/build.sh \
+ ca/new-build-cmd.sh \
nix-build.sh \
gc-concurrent.sh \
repair.sh \
@@ -21,6 +39,8 @@ nix_tests = \
tarball.sh \
fetchGit.sh \
fetchurl.sh \
+ fetchPath.sh \
+ fetchTree-file.sh \
simple.sh \
referrers.sh \
optimise-store.sh \
@@ -41,7 +61,7 @@ nix_tests = \
secure-drv-outputs.sh \
restricted.sh \
fetchGitSubmodules.sh \
- flake-searching.sh \
+ flakes/search-root.sh \
ca/duplicate-realisation-in-closure.sh \
readfile-context.sh \
nix-channel.sh \
@@ -57,6 +77,7 @@ nix_tests = \
build-remote-trustless-should-fail-0.sh \
nar-access.sh \
pure-eval.sh \
+ eval.sh \
ca/post-hook.sh \
repl.sh \
ca/repl.sh \
@@ -81,9 +102,11 @@ nix_tests = \
nix-copy-ssh.sh \
post-hook.sh \
function-trace.sh \
- flake-local-settings.sh \
+ flakes/config.sh \
+ fmt.sh \
eval-store.sh \
why-depends.sh \
+ ca/why-depends.sh \
import-derivation.sh \
ca/import-derivation.sh \
nix_path.sh \
@@ -92,12 +115,22 @@ nix_tests = \
ssh-relay.sh \
plugins.sh \
build.sh \
+ build-delete.sh \
+ output-normalization.sh \
ca/nix-run.sh \
+ selfref-gc.sh ca/selfref-gc.sh \
db-migration.sh \
- nix-profile.sh \
+ bash-profile.sh \
pass-as-file.sh \
- describe-stores.sh \
- store-ping.sh
+ nix-profile.sh \
+ suggestions.sh \
+ store-ping.sh \
+ fetchClosure.sh \
+ completions.sh \
+ flakes/show.sh \
+ impure-derivations.sh \
+ path-from-hash-part.sh \
+ toString-path.sh
ifeq ($(HAVE_LIBCPUID), 1)
nix_tests += compute-levels.sh
@@ -105,8 +138,10 @@ endif
install-tests += $(foreach x, $(nix_tests), tests/$(x))
-tests-environment = NIX_REMOTE= $(bash) -e
+clean-files += $(d)/common/vars-and-functions.sh $(d)/config.nix $(d)/ca/config.nix
-clean-files += $(d)/common.sh $(d)/config.nix $(d)/ca/config.nix
+test-deps += tests/common/vars-and-functions.sh tests/config.nix tests/ca/config.nix
-test-deps += tests/common.sh tests/config.nix tests/ca/config.nix tests/plugins/libplugintest.$(SO_EXT)
+ifeq ($(BUILD_SHARED_LIBS), 1)
+ test-deps += tests/plugins/libplugintest.$(SO_EXT)
+endif
diff --git a/tests/logging.sh b/tests/logging.sh
index c894ad3ff..1481b9b36 100644
--- a/tests/logging.sh
+++ b/tests/logging.sh
@@ -13,3 +13,14 @@ rm -rf $NIX_LOG_DIR
(! nix-store -l $path)
nix-build dependencies.nix --no-out-link --compress-build-log
[ "$(nix-store -l $path)" = FOO ]
+
+# test whether empty logs work fine with `nix log`.
+builder="$(mktemp)"
+echo -e "#!/bin/sh\nmkdir \$out" > "$builder"
+outp="$(nix-build -E \
+ 'with import ./config.nix; mkDerivation { name = "fnord"; builder = '"$builder"'; }' \
+ --out-link "$(mktemp -d)/result")"
+
+test -d "$outp"
+
+nix log "$outp"
diff --git a/tests/misc.sh b/tests/misc.sh
index 2830856ae..60d58310e 100644
--- a/tests/misc.sh
+++ b/tests/misc.sh
@@ -3,17 +3,17 @@ 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
+#nix-env --help | grepQuiet install
+#nix-store --help | grepQuiet realise
+#nix-instantiate --help | grepQuiet eval
+#nix-hash --help | grepQuiet 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"
+expect 1 nix-env --foo 2>&1 | grep "no operation"
+expect 1 nix-env -q --foo 2>&1 | grep "unknown flag"
# Eval Errors.
eval_arg_res=$(nix-instantiate --eval -E 'let a = {} // a; in a.foo' 2>&1 || true)
diff --git a/tests/multiple-outputs.nix b/tests/multiple-outputs.nix
index b915493f7..413d392e4 100644
--- a/tests/multiple-outputs.nix
+++ b/tests/multiple-outputs.nix
@@ -31,6 +31,15 @@ rec {
helloString = "Hello, world!";
};
+ use-a = mkDerivation {
+ name = "use-a";
+ inherit (a) first second;
+ builder = builtins.toFile "builder.sh"
+ ''
+ cat $first/file $second/file >$out
+ '';
+ };
+
b = mkDerivation {
defaultOutput = assert a.second.helloString == "Hello, world!"; a;
firstOutput = assert a.outputName == "first"; a.first.first;
@@ -80,4 +89,42 @@ rec {
'';
}).a;
+ e = mkDerivation {
+ name = "multiple-outputs-e";
+ outputs = [ "a_a" "b" "c" ];
+ meta.outputsToInstall = [ "a_a" "b" ];
+ buildCommand = "mkdir $a_a $b $c";
+ };
+
+ independent = mkDerivation {
+ name = "multiple-outputs-independent";
+ outputs = [ "first" "second" ];
+ builder = builtins.toFile "builder.sh"
+ ''
+ mkdir $first $second
+ test -z $all
+ echo "first" > $first/file
+ echo "second" > $second/file
+ '';
+ };
+
+ use-independent = mkDerivation {
+ name = "use-independent";
+ inherit (a) first second;
+ builder = builtins.toFile "builder.sh"
+ ''
+ cat $first/file $second/file >$out
+ '';
+ };
+
+ invalid-output-name-1 = mkDerivation {
+ name = "invalid-output-name-1";
+ outputs = [ "out/"];
+ };
+
+ invalid-output-name-2 = mkDerivation {
+ name = "invalid-output-name-2";
+ outputs = [ "x" "foo$"];
+ };
+
}
diff --git a/tests/multiple-outputs.sh b/tests/multiple-outputs.sh
index 0d45ad35b..330600d08 100644
--- a/tests/multiple-outputs.sh
+++ b/tests/multiple-outputs.sh
@@ -19,8 +19,8 @@ echo "evaluating c..."
# 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
+grepQuiet 'multiple-outputs-a.drv",\["first","second"\]' $drvPath
+grepQuiet '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)
@@ -83,3 +83,6 @@ nix-store --gc --keep-derivations --keep-outputs
nix-store --gc --print-roots
rm -rf $NIX_STORE_DIR/.links
rmdir $NIX_STORE_DIR
+
+expect 1 nix build -f multiple-outputs.nix invalid-output-name-1 2>&1 | grep 'contains illegal character'
+expect 1 nix build -f multiple-outputs.nix invalid-output-name-2 2>&1 | grep 'contains illegal character'
diff --git a/tests/nar-access.sh b/tests/nar-access.sh
index dcc2e8a36..d487d58d2 100644
--- a/tests/nar-access.sh
+++ b/tests/nar-access.sh
@@ -46,8 +46,8 @@ diff -u \
<(echo '{"type":"regular","size":0}' | jq -S)
# Test missing files.
-nix store ls --json -R $storePath/xyzzy 2>&1 | grep 'does not exist in NAR'
-nix store ls $storePath/xyzzy 2>&1 | grep 'does not exist'
+expect 1 nix store ls --json -R $storePath/xyzzy 2>&1 | grep 'does not exist in NAR'
+expect 1 nix store ls $storePath/xyzzy 2>&1 | grep 'does not exist'
# Test failure to dump.
if nix-store --dump $storePath >/dev/full ; then
diff --git a/tests/nix-channel.sh b/tests/nix-channel.sh
index 54b8f5979..dbb3114f1 100644
--- a/tests/nix-channel.sh
+++ b/tests/nix-channel.sh
@@ -6,12 +6,25 @@ 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 --list | grepQuiet http://foo/bar
nix-channel --remove xyzzy
[ -e $TEST_HOME/.nix-channels ]
[ "$(cat $TEST_HOME/.nix-channels)" = '' ]
+# Test the XDG Base Directories support
+
+export NIX_CONFIG="use-xdg-base-directories = true"
+
+nix-channel --add http://foo/bar xyzzy
+nix-channel --list | grepQuiet http://foo/bar
+nix-channel --remove xyzzy
+
+unset NIX_CONFIG
+
+[ -e $TEST_HOME/.local/state/nix/channels ]
+[ "$(cat $TEST_HOME/.local/state/nix/channels)" = '' ]
+
# Create a channel.
rm -rf $TEST_ROOT/foo
mkdir -p $TEST_ROOT/foo
@@ -28,8 +41,8 @@ nix-channel --update
# Do a query.
nix-env -qa \* --meta --xml --out-path > $TEST_ROOT/meta.xml
-grep -q 'meta.*description.*Random test package' $TEST_ROOT/meta.xml
-grep -q 'item.*attrPath="foo".*name="dependencies-top"' $TEST_ROOT/meta.xml
+grepQuiet 'meta.*description.*Random test package' $TEST_ROOT/meta.xml
+grepQuiet 'item.*attrPath="foo".*name="dependencies-top"' $TEST_ROOT/meta.xml
# Do an install.
nix-env -i dependencies-top
@@ -41,9 +54,9 @@ nix-channel --update
# Do a query.
nix-env -qa \* --meta --xml --out-path > $TEST_ROOT/meta.xml
-grep -q 'meta.*description.*Random test package' $TEST_ROOT/meta.xml
-grep -q 'item.*attrPath="bar".*name="dependencies-top"' $TEST_ROOT/meta.xml
-grep -q 'item.*attrPath="foo".*name="dependencies-top"' $TEST_ROOT/meta.xml
+grepQuiet 'meta.*description.*Random test package' $TEST_ROOT/meta.xml
+grepQuiet 'item.*attrPath="bar".*name="dependencies-top"' $TEST_ROOT/meta.xml
+grepQuiet 'item.*attrPath="foo".*name="dependencies-top"' $TEST_ROOT/meta.xml
# Do an install.
nix-env -i dependencies-top
diff --git a/tests/nix-profile.sh b/tests/nix-profile.sh
index e2e0d1090..652e8a8f2 100644
--- a/tests/nix-profile.sh
+++ b/tests/nix-profile.sh
@@ -1,9 +1,178 @@
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
+clearStore
+clearProfiles
-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
+enableFeatures "ca-derivations"
+restartDaemon
+
+# Make a flake.
+flake1Dir=$TEST_ROOT/flake1
+mkdir -p $flake1Dir
+
+cat > $flake1Dir/flake.nix <<EOF
+{
+ description = "Bla bla";
+
+ outputs = { self }: with import ./config.nix; rec {
+ packages.$system.default = mkDerivation {
+ name = "profile-test-\${builtins.readFile ./version}";
+ outputs = [ "out" "man" "dev" ];
+ builder = builtins.toFile "builder.sh"
+ ''
+ mkdir -p \$out/bin
+ cat > \$out/bin/hello <<EOF
+ #! ${shell}
+ echo Hello \${builtins.readFile ./who}
+ EOF
+ chmod +x \$out/bin/hello
+ echo DONE
+ mkdir -p \$man/share/man
+ mkdir -p \$dev/include
+ '';
+ __contentAddressed = import ./ca.nix;
+ outputHashMode = "recursive";
+ outputHashAlgo = "sha256";
+ meta.outputsToInstall = [ "out" "man" ];
+ };
+ };
+}
+EOF
+
+printf World > $flake1Dir/who
+printf 1.0 > $flake1Dir/version
+printf false > $flake1Dir/ca.nix
+
+cp ./config.nix $flake1Dir/
+
+# Test upgrading from nix-env.
+nix-env -f ./user-envs.nix -i foo-1.0
+nix profile list | grep '0 - - .*-foo-1.0'
+nix profile install $flake1Dir -L
+[[ $($TEST_HOME/.nix-profile/bin/hello) = "Hello World" ]]
+[ -e $TEST_HOME/.nix-profile/share/man ]
+(! [ -e $TEST_HOME/.nix-profile/include ])
+nix profile history
+nix profile history | grep "packages.$system.default: ∅ -> 1.0"
+nix profile diff-closures | grep 'env-manifest.nix: ε → ∅'
+
+# Test XDG Base Directories support
+
+export NIX_CONFIG="use-xdg-base-directories = true"
+nix profile remove 1
+nix profile install $flake1Dir
+[[ $($TEST_HOME/.local/state/nix/profile/bin/hello) = "Hello World" ]]
+unset NIX_CONFIG
+
+# Test upgrading a package.
+printf NixOS > $flake1Dir/who
+printf 2.0 > $flake1Dir/version
+nix profile upgrade 1
+[[ $($TEST_HOME/.nix-profile/bin/hello) = "Hello NixOS" ]]
+nix profile history | grep "packages.$system.default: 1.0, 1.0-man -> 2.0, 2.0-man"
+
+# Test 'history', 'diff-closures'.
+nix profile diff-closures
+
+# Test rollback.
+nix profile rollback
+[[ $($TEST_HOME/.nix-profile/bin/hello) = "Hello World" ]]
+
+# Test uninstall.
+[ -e $TEST_HOME/.nix-profile/bin/foo ]
+nix profile remove 0
+(! [ -e $TEST_HOME/.nix-profile/bin/foo ])
+nix profile history | grep 'foo: 1.0 -> ∅'
+nix profile diff-closures | grep 'Version 3 -> 4'
+
+# Test installing a non-flake package.
+nix profile install --file ./simple.nix ''
+[[ $(cat $TEST_HOME/.nix-profile/hello) = "Hello World!" ]]
+nix profile remove 1
+nix profile install $(nix-build --no-out-link ./simple.nix)
+[[ $(cat $TEST_HOME/.nix-profile/hello) = "Hello World!" ]]
+
+# Test wipe-history.
+nix profile wipe-history
+[[ $(nix profile history | grep Version | wc -l) -eq 1 ]]
+
+# Test upgrade to CA package.
+printf true > $flake1Dir/ca.nix
+printf 3.0 > $flake1Dir/version
+nix profile upgrade 0
+nix profile history | grep "packages.$system.default: 1.0, 1.0-man -> 3.0, 3.0-man"
+
+# Test new install of CA package.
+nix profile remove 0
+printf 4.0 > $flake1Dir/version
+printf Utrecht > $flake1Dir/who
+nix profile install $flake1Dir
+[[ $($TEST_HOME/.nix-profile/bin/hello) = "Hello Utrecht" ]]
+[[ $(nix path-info --json $(realpath $TEST_HOME/.nix-profile/bin/hello) | jq -r .[].ca) =~ fixed:r:sha256: ]]
+
+# Override the outputs.
+nix profile remove 0 1
+nix profile install "$flake1Dir^*"
+[[ $($TEST_HOME/.nix-profile/bin/hello) = "Hello Utrecht" ]]
+[ -e $TEST_HOME/.nix-profile/share/man ]
+[ -e $TEST_HOME/.nix-profile/include ]
+
+printf Nix > $flake1Dir/who
+nix profile upgrade 0
+[[ $($TEST_HOME/.nix-profile/bin/hello) = "Hello Nix" ]]
+[ -e $TEST_HOME/.nix-profile/share/man ]
+[ -e $TEST_HOME/.nix-profile/include ]
+
+nix profile remove 0
+nix profile install "$flake1Dir^man"
+(! [ -e $TEST_HOME/.nix-profile/bin/hello ])
+[ -e $TEST_HOME/.nix-profile/share/man ]
+(! [ -e $TEST_HOME/.nix-profile/include ])
+
+# test priority
+nix profile remove 0
+
+# Make another flake.
+flake2Dir=$TEST_ROOT/flake2
+printf World > $flake1Dir/who
+cp -r $flake1Dir $flake2Dir
+printf World2 > $flake2Dir/who
+
+nix profile install $flake1Dir
+[[ $($TEST_HOME/.nix-profile/bin/hello) = "Hello World" ]]
+expect 1 nix profile install $flake2Dir
+diff -u <(
+ nix --offline profile install $flake2Dir 2>&1 1> /dev/null \
+ | grep -vE "^warning: " \
+ || true
+) <(cat << EOF
+error: An existing package already provides the following file:
+
+ $(nix build --no-link --print-out-paths ${flake1Dir}"#default.out")/bin/hello
+
+ This is the conflicting file from the new package:
+
+ $(nix build --no-link --print-out-paths ${flake2Dir}"#default.out")/bin/hello
+
+ To remove the existing package:
+
+ nix profile remove path:${flake1Dir}
+
+ The new package can also be installed next to the existing one by assigning a different priority.
+ The conflicting packages have a priority of 5.
+ To prioritise the new package:
+
+ nix profile install path:${flake2Dir} --priority 4
+
+ To prioritise the existing package:
+
+ nix profile install path:${flake2Dir} --priority 6
+EOF
+)
+[[ $($TEST_HOME/.nix-profile/bin/hello) = "Hello World" ]]
+nix profile install $flake2Dir --priority 100
+[[ $($TEST_HOME/.nix-profile/bin/hello) = "Hello World" ]]
+nix profile install $flake2Dir --priority 0
+[[ $($TEST_HOME/.nix-profile/bin/hello) = "Hello World2" ]]
+# nix profile install $flake1Dir --priority 100
+# [[ $($TEST_HOME/.nix-profile/bin/hello) = "Hello World" ]]
diff --git a/tests/nix-shell.sh b/tests/nix-shell.sh
index 3241d7a0f..044b96d54 100644
--- a/tests/nix-shell.sh
+++ b/tests/nix-shell.sh
@@ -88,17 +88,48 @@ output=$($TEST_ROOT/spaced\ \\\'\"shell.shebang.rb abc ruby)
nix develop -f "$shellDotNix" shellDrv -c bash -c '[[ -n $stdenv ]]'
# Ensure `nix develop -c` preserves stdin
-echo foo | nix develop -f "$shellDotNix" shellDrv -c cat | grep -q foo
+echo foo | nix develop -f "$shellDotNix" shellDrv -c cat | grepQuiet foo
# Ensure `nix develop -c` actually executes the command if stdout isn't a terminal
-nix develop -f "$shellDotNix" shellDrv -c echo foo |& grep -q foo
+nix develop -f "$shellDotNix" shellDrv -c echo foo |& grepQuiet foo
# Test 'nix print-dev-env'.
-[[ $(nix print-dev-env -f "$shellDotNix" shellDrv --json | jq -r .variables.arr1.value[2]) = '3 4' ]]
-
-source <(nix print-dev-env -f "$shellDotNix" shellDrv)
-[[ -n $stdenv ]]
-[[ ${arr1[2]} = "3 4" ]]
-[[ ${arr2[1]} = $'\n' ]]
-[[ ${arr2[2]} = $'x\ny' ]]
-[[ $(fun) = blabla ]]
+
+nix print-dev-env -f "$shellDotNix" shellDrv > $TEST_ROOT/dev-env.sh
+nix print-dev-env -f "$shellDotNix" shellDrv --json > $TEST_ROOT/dev-env.json
+
+# Ensure `nix print-dev-env --json` contains variable assignments.
+[[ $(jq -r .variables.arr1.value[2] $TEST_ROOT/dev-env.json) = '3 4' ]]
+
+# Run tests involving `source <(nix print-dev-inv)` in subshells to avoid modifying the current
+# environment.
+
+set +u # FIXME: Make print-dev-env `set -u` compliant (issue #7951)
+
+# Ensure `source <(nix print-dev-env)` modifies the environment.
+(
+ path=$PATH
+ source $TEST_ROOT/dev-env.sh
+ [[ -n $stdenv ]]
+ [[ ${arr1[2]} = "3 4" ]]
+ [[ ${arr2[1]} = $'\n' ]]
+ [[ ${arr2[2]} = $'x\ny' ]]
+ [[ $(fun) = blabla ]]
+ [[ $PATH = $(jq -r .variables.PATH.value $TEST_ROOT/dev-env.json):$path ]]
+)
+
+# Ensure `source <(nix print-dev-env)` handles the case when PATH is empty.
+(
+ path=$PATH
+ PATH=
+ source $TEST_ROOT/dev-env.sh
+ [[ $PATH = $(PATH=$path jq -r .variables.PATH.value $TEST_ROOT/dev-env.json) ]]
+)
+
+# Test nix-shell with ellipsis and no `inNixShell` argument (for backwards compat with old nixpkgs)
+cat >$TEST_ROOT/shell-ellipsis.nix <<EOF
+{ system ? "x86_64-linux", ... }@args:
+assert (!(args ? inNixShell));
+(import $shellDotNix { }).shellDrv
+EOF
+nix-shell $TEST_ROOT/shell-ellipsis.nix --run "true"
diff --git a/tests/nix_path.sh b/tests/nix_path.sh
index d3657abf0..2b222b4a1 100644
--- a/tests/nix_path.sh
+++ b/tests/nix_path.sh
@@ -9,3 +9,6 @@ nix-instantiate --eval -E '<by-relative-path/simple.nix>' --restrict-eval
# Should ideally also test this, but there’s no pure way to do it, so just trust me that it works
# nix-instantiate --eval -E '<nixpkgs>' -I nixpkgs=channel:nixos-unstable --restrict-eval
+
+[[ $(nix-instantiate --find-file by-absolute-path/simple.nix) = $PWD/simple.nix ]]
+[[ $(nix-instantiate --find-file by-relative-path/simple.nix) = $PWD/simple.nix ]]
diff --git a/tests/nixos/authorization.nix b/tests/nixos/authorization.nix
new file mode 100644
index 000000000..7e8744dd9
--- /dev/null
+++ b/tests/nixos/authorization.nix
@@ -0,0 +1,79 @@
+{
+ name = "authorization";
+
+ nodes.machine = {
+ virtualisation.writableStore = true;
+ # TODO add a test without allowed-users setting. allowed-users is uncommon among NixOS users.
+ nix.settings.allowed-users = ["alice" "bob"];
+ nix.settings.trusted-users = ["alice"];
+
+ users.users.alice.isNormalUser = true;
+ users.users.bob.isNormalUser = true;
+ users.users.mallory.isNormalUser = true;
+
+ nix.settings.experimental-features = "nix-command";
+ };
+
+ testScript =
+ let
+ pathFour = "/nix/store/20xfy868aiic0r0flgzq4n5dq1yvmxkn-four";
+ in
+ ''
+ machine.wait_for_unit("multi-user.target")
+ machine.succeed("""
+ exec 1>&2
+ echo kSELDhobKaF8/VdxIxdP7EQe+Q > one
+ diff $(nix store add-file one) one
+ """)
+ machine.succeed("""
+ su --login alice -c '
+ set -x
+ cd ~
+ echo ehHtmfuULXYyBV6NBk6QUi8iE0 > two
+ ls
+ diff $(echo $(nix store add-file two)) two' 1>&2
+ """)
+ machine.succeed("""
+ su --login bob -c '
+ set -x
+ cd ~
+ echo 0Jw8RNp7cK0W2AdNbcquofcOVk > three
+ diff $(nix store add-file three) three
+ ' 1>&2
+ """)
+
+ # We're going to check that a path is not created
+ machine.succeed("""
+ ! [[ -e ${pathFour} ]]
+ """)
+ machine.succeed("""
+ su --login mallory -c '
+ set -x
+ cd ~
+ echo 5mgtDj0ohrWkT50TLR0f4tIIxY > four;
+ (! nix store add-file four 2>&1) | grep -F "cannot open connection to remote store"
+ (! nix store add-file four 2>&1) | grep -F "Connection reset by peer"
+ ! [[ -e ${pathFour} ]]
+ ' 1>&2
+ """)
+
+ # Check that the file _can_ be added, and matches the expected path we were checking
+ machine.succeed("""
+ exec 1>&2
+ echo 5mgtDj0ohrWkT50TLR0f4tIIxY > four
+ four="$(nix store add-file four)"
+ diff $four four
+ diff <(echo $four) <(echo ${pathFour})
+ """)
+
+ machine.succeed("""
+ su --login alice -c 'nix-store --verify --repair'
+ """)
+
+ machine.succeed("""
+ set -x
+ su --login bob -c '(! nix-store --verify --repair 2>&1)' | tee diag 1>&2
+ grep -F "you are not privileged to repair paths" diag
+ """)
+ '';
+}
diff --git a/tests/nixos/containers/containers.nix b/tests/nixos/containers/containers.nix
new file mode 100644
index 000000000..c8ee78a4a
--- /dev/null
+++ b/tests/nixos/containers/containers.nix
@@ -0,0 +1,63 @@
+# Test whether we can run a NixOS container inside a Nix build using systemd-nspawn.
+{ lib, nixpkgs, ... }:
+
+{
+ name = "containers";
+
+ nodes =
+ {
+ host =
+ { config, lib, pkgs, nodes, ... }:
+ { virtualisation.writableStore = true;
+ virtualisation.diskSize = 2048;
+ virtualisation.additionalPaths =
+ [ pkgs.stdenvNoCC
+ (import ./systemd-nspawn.nix { inherit nixpkgs; }).toplevel
+ ];
+ virtualisation.memorySize = 4096;
+ nix.settings.substituters = lib.mkForce [ ];
+ nix.extraOptions =
+ ''
+ extra-experimental-features = nix-command auto-allocate-uids cgroups
+ extra-system-features = uid-range
+ '';
+ nix.nixPath = [ "nixpkgs=${nixpkgs}" ];
+ };
+ };
+
+ testScript = { nodes }: ''
+ start_all()
+
+ host.succeed("nix --version >&2")
+
+ # Test that 'id' gives the expected result in various configurations.
+
+ # Existing UIDs, sandbox.
+ host.succeed("nix build -v --no-auto-allocate-uids --sandbox -L --offline --impure --file ${./id-test.nix} --argstr name id-test-1")
+ host.succeed("[[ $(cat ./result) = 'uid=1000(nixbld) gid=100(nixbld) groups=100(nixbld)' ]]")
+
+ # Existing UIDs, no sandbox.
+ host.succeed("nix build -v --no-auto-allocate-uids --no-sandbox -L --offline --impure --file ${./id-test.nix} --argstr name id-test-2")
+ host.succeed("[[ $(cat ./result) = 'uid=30001(nixbld1) gid=30000(nixbld) groups=30000(nixbld)' ]]")
+
+ # Auto-allocated UIDs, sandbox.
+ host.succeed("nix build -v --auto-allocate-uids --sandbox -L --offline --impure --file ${./id-test.nix} --argstr name id-test-3")
+ host.succeed("[[ $(cat ./result) = 'uid=1000(nixbld) gid=100(nixbld) groups=100(nixbld)' ]]")
+
+ # Auto-allocated UIDs, no sandbox.
+ host.succeed("nix build -v --auto-allocate-uids --no-sandbox -L --offline --impure --file ${./id-test.nix} --argstr name id-test-4")
+ host.succeed("[[ $(cat ./result) = 'uid=872415232 gid=30000(nixbld) groups=30000(nixbld)' ]]")
+
+ # Auto-allocated UIDs, UID range, sandbox.
+ host.succeed("nix build -v --auto-allocate-uids --sandbox -L --offline --impure --file ${./id-test.nix} --argstr name id-test-5 --arg uidRange true")
+ host.succeed("[[ $(cat ./result) = 'uid=0(root) gid=0(root) groups=0(root)' ]]")
+
+ # Auto-allocated UIDs, UID range, no sandbox.
+ host.fail("nix build -v --auto-allocate-uids --no-sandbox -L --offline --impure --file ${./id-test.nix} --argstr name id-test-6 --arg uidRange true")
+
+ # Run systemd-nspawn in a Nix build.
+ host.succeed("nix build -v --auto-allocate-uids --sandbox -L --offline --impure --file ${./systemd-nspawn.nix} --argstr nixpkgs ${nixpkgs}")
+ host.succeed("[[ $(cat ./result/msg) = 'Hello World' ]]")
+ '';
+
+}
diff --git a/tests/nixos/containers/id-test.nix b/tests/nixos/containers/id-test.nix
new file mode 100644
index 000000000..8eb9d38f9
--- /dev/null
+++ b/tests/nixos/containers/id-test.nix
@@ -0,0 +1,8 @@
+{ name, uidRange ? false }:
+
+with import <nixpkgs> {};
+
+runCommand name
+ { requiredSystemFeatures = if uidRange then ["uid-range"] else [];
+ }
+ "id; id > $out"
diff --git a/tests/nixos/containers/systemd-nspawn.nix b/tests/nixos/containers/systemd-nspawn.nix
new file mode 100644
index 000000000..f54f32f2a
--- /dev/null
+++ b/tests/nixos/containers/systemd-nspawn.nix
@@ -0,0 +1,78 @@
+{ nixpkgs }:
+
+let
+
+ machine = { config, pkgs, ... }:
+ {
+ system.stateVersion = "22.05";
+ boot.isContainer = true;
+ systemd.services.console-getty.enable = false;
+ networking.dhcpcd.enable = false;
+
+ services.httpd = {
+ enable = true;
+ adminAddr = "nixos@example.org";
+ };
+
+ systemd.services.test = {
+ wantedBy = [ "multi-user.target" ];
+ after = [ "httpd.service" ];
+ script = ''
+ source /.env
+ echo "Hello World" > $out/msg
+ ls -lR /dev > $out/dev
+ ${pkgs.curl}/bin/curl -sS --fail http://localhost/ > $out/page.html
+ '';
+ unitConfig = {
+ FailureAction = "exit-force";
+ FailureActionExitStatus = 42;
+ SuccessAction = "exit-force";
+ };
+ };
+ };
+
+ cfg = (import (nixpkgs + "/nixos/lib/eval-config.nix") {
+ modules = [ machine ];
+ system = "x86_64-linux";
+ });
+
+ config = cfg.config;
+
+in
+
+with cfg._module.args.pkgs;
+
+runCommand "test"
+ { buildInputs = [ config.system.path ];
+ requiredSystemFeatures = [ "uid-range" ];
+ toplevel = config.system.build.toplevel;
+ }
+ ''
+ root=$(pwd)/root
+ mkdir -p $root $root/etc
+
+ export > $root/.env
+
+ # Make /run a tmpfs to shut up a systemd warning.
+ mkdir /run
+ mount -t tmpfs none /run
+
+ mount -t cgroup2 none /sys/fs/cgroup
+
+ mkdir -p $out
+
+ chmod +w /etc
+ touch /etc/os-release
+ echo a5ea3f98dedc0278b6f3cc8c37eeaeac > /etc/machine-id
+
+ SYSTEMD_NSPAWN_UNIFIED_HIERARCHY=1 \
+ ${config.systemd.package}/bin/systemd-nspawn \
+ --keep-unit \
+ -M ${config.networking.hostName} -D "$root" \
+ --register=no \
+ --resolv-conf=off \
+ --bind-ro=/nix/store \
+ --bind=$out \
+ --private-network \
+ $toplevel/init
+ ''
diff --git a/tests/github-flakes.nix b/tests/nixos/github-flakes.nix
index 7ac397d81..e4d347691 100644
--- a/tests/github-flakes.nix
+++ b/tests/nixos/github-flakes.nix
@@ -1,14 +1,9 @@
-{ nixpkgs, system, overlay }:
-
-with import (nixpkgs + "/nixos/lib/testing-python.nix") {
- inherit system;
- extraConfigurations = [ { nixpkgs.overlays = [ overlay ]; } ];
-};
-
+{ lib, config, nixpkgs, ... }:
let
+ pkgs = config.nodes.client.nixpkgs.pkgs;
- # Generate a fake root CA and a fake github.com certificate.
- cert = pkgs.runCommand "cert" { buildInputs = [ pkgs.openssl ]; }
+ # Generate a fake root CA and a fake api.github.com / github.com / channels.nixos.org certificate.
+ cert = pkgs.runCommand "cert" { nativeBuildInputs = [ pkgs.openssl ]; }
''
mkdir -p $out
@@ -18,7 +13,7 @@ let
openssl req -newkey rsa:2048 -nodes -keyout $out/server.key \
-subj "/C=CN/ST=Denial/L=Springfield/O=Dis/CN=github.com" -out server.csr
- openssl x509 -req -extfile <(printf "subjectAltName=DNS:api.github.com,DNS:github.com,DNS:raw.githubusercontent.com") \
+ openssl x509 -req -extfile <(printf "subjectAltName=DNS:api.github.com,DNS:github.com,DNS:channels.nixos.org") \
-days 36500 -in server.csr -CA $out/ca.crt -CAkey ca.key -CAcreateserial -out $out/server.crt
'';
@@ -37,6 +32,17 @@ let
"owner": "NixOS",
"repo": "nixpkgs"
}
+ },
+ {
+ "from": {
+ "type": "indirect",
+ "id": "private-flake"
+ },
+ "to": {
+ "type": "github",
+ "owner": "fancy-enterprise",
+ "repo": "private-flake"
+ }
}
],
"version": 2
@@ -45,29 +51,47 @@ let
destination = "/flake-registry.json";
};
- api = pkgs.runCommand "nixpkgs-flake" {}
+ private-flake-rev = "9f1dd0df5b54a7dc75b618034482ed42ce34383d";
+
+ private-flake-api = pkgs.runCommand "private-flake" {}
''
- mkdir -p $out/tarball
+ mkdir -p $out/{commits,tarball}
- dir=NixOS-nixpkgs-${nixpkgs.shortRev}
- cp -prd ${nixpkgs} $dir
- # Set the correct timestamp in the tarball.
- find $dir -print0 | xargs -0 touch -t ${builtins.substring 0 12 nixpkgs.lastModifiedDate}.${builtins.substring 12 2 nixpkgs.lastModifiedDate} --
- tar cfz $out/tarball/${nixpkgs.rev} $dir --hard-dereference
+ # Setup https://docs.github.com/en/rest/commits/commits#get-a-commit
+ echo '{"sha": "${private-flake-rev}"}' > $out/commits/HEAD
+
+ # Setup tarball download via API
+ dir=private-flake
+ mkdir $dir
+ echo '{ outputs = {...}: {}; }' > $dir/flake.nix
+ tar cfz $out/tarball/${private-flake-rev} $dir --hard-dereference
+ '';
+ nixpkgs-api = pkgs.runCommand "nixpkgs-flake" {}
+ ''
mkdir -p $out/commits
+
+ # Setup https://docs.github.com/en/rest/commits/commits#get-a-commit
echo '{"sha": "${nixpkgs.rev}"}' > $out/commits/HEAD
'';
-in
+ archive = pkgs.runCommand "nixpkgs-flake" {}
+ ''
+ mkdir -p $out/archive
-makeTest (
+ dir=NixOS-nixpkgs-${nixpkgs.shortRev}
+ cp -prd ${nixpkgs} $dir
+ # Set the correct timestamp in the tarball.
+ find $dir -print0 | xargs -0 touch -t ${builtins.substring 0 12 nixpkgs.lastModifiedDate}.${builtins.substring 12 2 nixpkgs.lastModifiedDate} --
+ tar cfz $out/archive/${nixpkgs.rev}.tar.gz $dir --hard-dereference
+ '';
+in
{
name = "github-flakes";
nodes =
- { # Impersonate github.com and api.github.com.
+ {
github =
{ config, pkgs, ... }:
{ networking.firewall.allowedTCPPorts = [ 80 443 ];
@@ -77,12 +101,12 @@ makeTest (
services.httpd.extraConfig = ''
ErrorLog syslog:local6
'';
- services.httpd.virtualHosts."github.com" =
+ services.httpd.virtualHosts."channels.nixos.org" =
{ forceSSL = true;
sslServerKey = "${cert}/server.key";
sslServerCert = "${cert}/server.crt";
servedDirs =
- [ { urlPath = "/NixOS/flake-registry/raw/master";
+ [ { urlPath = "/";
dir = registry;
}
];
@@ -93,7 +117,20 @@ makeTest (
sslServerCert = "${cert}/server.crt";
servedDirs =
[ { urlPath = "/repos/NixOS/nixpkgs";
- dir = api;
+ dir = nixpkgs-api;
+ }
+ { urlPath = "/repos/fancy-enterprise/private-flake";
+ dir = private-flake-api;
+ }
+ ];
+ };
+ services.httpd.virtualHosts."github.com" =
+ { forceSSL = true;
+ sslServerKey = "${cert}/server.key";
+ sslServerCert = "${cert}/server.crt";
+ servedDirs =
+ [ { urlPath = "/NixOS/nixpkgs";
+ dir = archive;
}
];
};
@@ -103,13 +140,12 @@ makeTest (
{ config, lib, pkgs, nodes, ... }:
{ virtualisation.writableStore = true;
virtualisation.diskSize = 2048;
- virtualisation.pathsInNixDB = [ pkgs.hello pkgs.fuse ];
+ virtualisation.additionalPaths = [ pkgs.hello pkgs.fuse ];
virtualisation.memorySize = 4096;
- nix.binaryCaches = lib.mkForce [ ];
+ nix.settings.substituters = lib.mkForce [ ];
nix.extraOptions = "experimental-features = nix-command flakes";
- environment.systemPackages = [ pkgs.jq ];
networking.hosts.${(builtins.head nodes.github.config.networking.interfaces.eth1.ipv4.addresses).address} =
- [ "github.com" "api.github.com" "raw.githubusercontent.com" ];
+ [ "channels.nixos.org" "api.github.com" "github.com" ];
security.pki.certificateFiles = [ "${cert}/ca.crt" ];
};
};
@@ -121,22 +157,39 @@ makeTest (
start_all()
+ def cat_log():
+ github.succeed("cat /var/log/httpd/*.log >&2")
+
github.wait_for_unit("httpd.service")
client.succeed("curl -v https://github.com/ >&2")
- client.succeed("nix registry list | grep nixpkgs")
-
- rev = client.succeed("nix flake info nixpkgs --json | jq -r .revision")
- assert rev.strip() == "${nixpkgs.rev}", "revision mismatch"
+ out = client.succeed("nix registry list")
+ print(out)
+ assert "github:NixOS/nixpkgs" in out, "nixpkgs flake not found"
+ assert "github:fancy-enterprise/private-flake" in out, "private flake not found"
+ cat_log()
+
+ # If no github access token is provided, nix should use the public archive url...
+ out = client.succeed("nix flake metadata nixpkgs --json")
+ print(out)
+ info = json.loads(out)
+ assert info["revision"] == "${nixpkgs.rev}", f"revision mismatch: {info['revision']} != ${nixpkgs.rev}"
+ cat_log()
+
+ # ... otherwise it should use the API
+ out = client.succeed("nix flake metadata private-flake --json --access-tokens github.com=ghp_000000000000000000000000000000000000 --tarball-ttl 0")
+ print(out)
+ info = json.loads(out)
+ assert info["revision"] == "${private-flake-rev}", f"revision mismatch: {info['revision']} != ${private-flake-rev}"
+ cat_log()
client.succeed("nix registry pin nixpkgs")
-
- client.succeed("nix flake info nixpkgs --tarball-ttl 0 >&2")
+ client.succeed("nix flake metadata nixpkgs --tarball-ttl 0 >&2")
# Shut down the web server. The flake should be cached on the client.
github.succeed("systemctl stop httpd.service")
- info = json.loads(client.succeed("nix flake info nixpkgs --json"))
+ info = json.loads(client.succeed("nix flake metadata nixpkgs --json"))
date = time.strftime("%Y%m%d%H%M%S", time.gmtime(info['lastModified']))
assert date == "${nixpkgs.lastModifiedDate}", "time mismatch"
@@ -147,4 +200,4 @@ makeTest (
client.succeed("nix build nixpkgs#fuse --tarball-ttl 0")
'';
-})
+}
diff --git a/tests/nix-copy-closure.nix b/tests/nixos/nix-copy-closure.nix
index 1b63a3fca..66cbfb033 100644
--- a/tests/nix-copy-closure.nix
+++ b/tests/nixos/nix-copy-closure.nix
@@ -1,28 +1,31 @@
# Test ‘nix-copy-closure’.
-{ nixpkgs, system, overlay }:
+{ lib, config, nixpkgs, hostPkgs, ... }:
-with import (nixpkgs + "/nixos/lib/testing-python.nix") {
- inherit system;
- extraConfigurations = [ { nixpkgs.overlays = [ overlay ]; } ];
-};
+let
+ pkgs = config.nodes.client.nixpkgs.pkgs;
-makeTest (let pkgA = pkgs.cowsay; pkgB = pkgs.wget; pkgC = pkgs.hello; pkgD = pkgs.tmux; in {
+ pkgA = pkgs.cowsay;
+ pkgB = pkgs.wget;
+ pkgC = pkgs.hello;
+ pkgD = pkgs.tmux;
+
+in {
name = "nix-copy-closure";
nodes =
{ client =
{ config, lib, pkgs, ... }:
{ virtualisation.writableStore = true;
- virtualisation.pathsInNixDB = [ pkgA pkgD.drvPath ];
- nix.binaryCaches = lib.mkForce [ ];
+ virtualisation.additionalPaths = [ pkgA pkgD.drvPath ];
+ nix.settings.substituters = lib.mkForce [ ];
};
server =
{ config, pkgs, ... }:
{ services.openssh.enable = true;
virtualisation.writableStore = true;
- virtualisation.pathsInNixDB = [ pkgB pkgC ];
+ virtualisation.additionalPaths = [ pkgB pkgC ];
};
};
@@ -74,4 +77,4 @@ makeTest (let pkgA = pkgs.cowsay; pkgB = pkgs.wget; pkgC = pkgs.hello; pkgD = pk
# )
# client.succeed("nix-store --check-validity ${pkgC}")
'';
-})
+}
diff --git a/tests/nixos/nix-copy.nix b/tests/nixos/nix-copy.nix
new file mode 100644
index 000000000..ee8b77100
--- /dev/null
+++ b/tests/nixos/nix-copy.nix
@@ -0,0 +1,85 @@
+# Test that ‘nix copy’ works over ssh.
+
+{ lib, config, nixpkgs, hostPkgs, ... }:
+
+let
+ pkgs = config.nodes.client.nixpkgs.pkgs;
+
+ pkgA = pkgs.cowsay;
+ pkgB = pkgs.wget;
+ pkgC = pkgs.hello;
+ pkgD = pkgs.tmux;
+
+in {
+ name = "nix-copy";
+
+ enableOCR = true;
+
+ nodes =
+ { client =
+ { config, lib, pkgs, ... }:
+ { virtualisation.writableStore = true;
+ virtualisation.additionalPaths = [ pkgA pkgD.drvPath ];
+ nix.settings.substituters = lib.mkForce [ ];
+ nix.settings.experimental-features = [ "nix-command" ];
+ services.getty.autologinUser = "root";
+ };
+
+ server =
+ { config, pkgs, ... }:
+ { services.openssh.enable = true;
+ services.openssh.permitRootLogin = "yes";
+ users.users.root.password = "foobar";
+ virtualisation.writableStore = true;
+ virtualisation.additionalPaths = [ pkgB pkgC ];
+ };
+ };
+
+ testScript = { nodes }: ''
+ # fmt: off
+ import subprocess
+
+ # Create an SSH key on the client.
+ subprocess.run([
+ "${pkgs.openssh}/bin/ssh-keygen", "-t", "ed25519", "-f", "key", "-N", ""
+ ], capture_output=True, check=True)
+
+ start_all()
+
+ server.wait_for_unit("sshd")
+ client.wait_for_unit("network.target")
+ client.wait_for_unit("getty@tty1.service")
+ client.wait_for_text("]#")
+
+ # Copy the closure of package A from the client to the server using password authentication,
+ # and check that all prompts are visible
+ server.fail("nix-store --check-validity ${pkgA}")
+ client.send_chars("nix copy --to ssh://server ${pkgA} >&2; echo done\n")
+ client.wait_for_text("continue connecting")
+ client.send_chars("yes\n")
+ client.wait_for_text("Password:")
+ client.send_chars("foobar\n")
+ client.wait_for_text("done")
+ server.succeed("nix-store --check-validity ${pkgA}")
+
+ client.copy_from_host("key", "/root/.ssh/id_ed25519")
+ client.succeed("chmod 600 /root/.ssh/id_ed25519")
+
+ # Install the SSH key on the server.
+ server.copy_from_host("key.pub", "/root/.ssh/authorized_keys")
+ server.succeed("systemctl restart sshd")
+ client.succeed(f"ssh -o StrictHostKeyChecking=no {server.name} 'echo hello world'")
+
+ # Copy the closure of package B from the server to the client, using ssh-ng.
+ client.fail("nix-store --check-validity ${pkgB}")
+ # Shouldn't download untrusted paths by default
+ client.fail("nix copy --from ssh-ng://server ${pkgB} >&2")
+ client.succeed("nix copy --no-check-sigs --from ssh-ng://server ${pkgB} >&2")
+ client.succeed("nix-store --check-validity ${pkgB}")
+
+ # Copy the derivation of package D's derivation from the client to the server.
+ server.fail("nix-store --check-validity ${pkgD.drvPath}")
+ client.succeed("nix copy --derivation --to ssh://server ${pkgD.drvPath} >&2")
+ server.succeed("nix-store --check-validity ${pkgD.drvPath}")
+ '';
+}
diff --git a/tests/nss-preload.nix b/tests/nixos/nss-preload.nix
index 2610d2b30..cef62e95b 100644
--- a/tests/nss-preload.nix
+++ b/tests/nixos/nss-preload.nix
@@ -1,13 +1,45 @@
-{ nixpkgs, system, overlay }:
+{ lib, config, nixpkgs, ... }:
-with import (nixpkgs + "/nixos/lib/testing-python.nix") {
- inherit system;
- extraConfigurations = [ { nixpkgs.overlays = [ overlay ]; } ];
-};
+let
-makeTest (
+ pkgs = config.nodes.client.nixpkgs.pkgs;
-rec {
+ nix-fetch = pkgs.writeText "fetch.nix" ''
+ derivation {
+ # This derivation is an copy from what is available over at
+ # nix.git:corepkgs/fetchurl.nix
+ builder = "builtin:fetchurl";
+
+ # We're going to fetch data from the http_dns instance created before
+ # we expect the content to be the same as the content available there.
+ # ```
+ # $ nix-hash --type sha256 --to-base32 $(echo "hello world" | sha256sum | cut -d " " -f 1)
+ # 0ix4jahrkll5zg01wandq78jw3ab30q4nscph67rniqg5x7r0j59
+ # ```
+ outputHash = "0ix4jahrkll5zg01wandq78jw3ab30q4nscph67rniqg5x7r0j59";
+ outputHashAlgo = "sha256";
+ outputHashMode = "flat";
+
+ name = "example.com";
+ url = "http://example.com";
+
+ unpack = false;
+ executable = false;
+
+ system = "builtin";
+
+ preferLocalBuild = true;
+
+ impureEnvVars = [
+ "http_proxy" "https_proxy" "ftp_proxy" "all_proxy" "no_proxy"
+ ];
+
+ urls = [ "http://example.com" ];
+ }
+ '';
+in
+
+{
name = "nss-preload";
nodes = {
@@ -62,46 +94,12 @@ rec {
{ address = "192.168.0.10"; prefixLength = 24; }
];
- nix.sandboxPaths = lib.mkForce [];
- nix.binaryCaches = lib.mkForce [];
- nix.useSandbox = lib.mkForce true;
+ nix.settings.extra-sandbox-paths = lib.mkForce [];
+ nix.settings.substituters = lib.mkForce [];
+ nix.settings.sandbox = lib.mkForce true;
};
};
- nix-fetch = pkgs.writeText "fetch.nix" ''
- derivation {
- # This derivation is an copy from what is available over at
- # nix.git:corepkgs/fetchurl.nix
- builder = "builtin:fetchurl";
-
- # We're going to fetch data from the http_dns instance created before
- # we expect the content to be the same as the content available there.
- # ```
- # $ nix-hash --type sha256 --to-base32 $(echo "hello world" | sha256sum | cut -d " " -f 1)
- # 0ix4jahrkll5zg01wandq78jw3ab30q4nscph67rniqg5x7r0j59
- # ```
- outputHash = "0ix4jahrkll5zg01wandq78jw3ab30q4nscph67rniqg5x7r0j59";
- outputHashAlgo = "sha256";
- outputHashMode = "flat";
-
- name = "example.com";
- url = "http://example.com";
-
- unpack = false;
- executable = false;
-
- system = "builtin";
-
- preferLocalBuild = true;
-
- impureEnvVars = [
- "http_proxy" "https_proxy" "ftp_proxy" "all_proxy" "no_proxy"
- ];
-
- urls = [ "http://example.com" ];
- }
- '';
-
testScript = { nodes, ... }: ''
http_dns.wait_for_unit("nginx")
http_dns.wait_for_open_port(80)
@@ -120,4 +118,4 @@ rec {
nix-build ${nix-fetch} >&2
""")
'';
-})
+}
diff --git a/tests/remote-builds.nix b/tests/nixos/remote-builds.nix
index b9e7352c0..1c96cc787 100644
--- a/tests/remote-builds.nix
+++ b/tests/nixos/remote-builds.nix
@@ -1,22 +1,21 @@
# Test Nix's remote build feature.
-{ nixpkgs, system, overlay }:
-
-with import (nixpkgs + "/nixos/lib/testing-python.nix") {
- inherit system;
- extraConfigurations = [ { nixpkgs.overlays = [ overlay ]; } ];
-};
-
-makeTest (
+{ config, lib, hostPkgs, ... }:
let
+ pkgs = config.nodes.client.nixpkgs.pkgs;
# The configuration of the remote builders.
builder =
{ config, pkgs, ... }:
{ services.openssh.enable = true;
virtualisation.writableStore = true;
- nix.useSandbox = true;
+ nix.settings.sandbox = true;
+
+ # Regression test for use of PID namespaces when /proc has
+ # filesystems mounted on top of it
+ # (i.e. /proc/sys/fs/binfmt_misc).
+ boot.binfmt.emulatedSystems = [ "aarch64-linux" ];
};
# Trivial Nix expression to build remotely.
@@ -44,7 +43,7 @@ in
client =
{ config, lib, pkgs, ... }:
- { nix.maxJobs = 0; # force remote building
+ { nix.settings.max-jobs = 0; # force remote building
nix.distributedBuilds = true;
nix.buildMachines =
[ { hostName = "builder1";
@@ -61,8 +60,8 @@ in
}
];
virtualisation.writableStore = true;
- virtualisation.pathsInNixDB = [ config.system.build.extraUtils ];
- nix.binaryCaches = lib.mkForce [ ];
+ virtualisation.additionalPaths = [ config.system.build.extraUtils ];
+ nix.settings.substituters = lib.mkForce [ ];
programs.ssh.extraConfig = "ConnectTimeout 30";
};
};
@@ -75,7 +74,7 @@ in
# Create an SSH key on the client.
subprocess.run([
- "${pkgs.openssh}/bin/ssh-keygen", "-t", "ed25519", "-f", "key", "-N", ""
+ "${hostPkgs.openssh}/bin/ssh-keygen", "-t", "ed25519", "-f", "key", "-N", ""
], capture_output=True, check=True)
client.succeed("mkdir -p -m 700 /root/.ssh")
client.copy_from_host("key", "/root/.ssh/id_ed25519")
@@ -109,4 +108,4 @@ in
builder1.block()
client.succeed("nix-build ${expr nodes.client.config 4}")
'';
-})
+}
diff --git a/tests/setuid.nix b/tests/nixos/setuid.nix
index 35eb304ed..2b66320dd 100644
--- a/tests/setuid.nix
+++ b/tests/nixos/setuid.nix
@@ -1,21 +1,20 @@
# Verify that Linux builds cannot create setuid or setgid binaries.
-{ nixpkgs, system, overlay }:
+{ lib, config, nixpkgs, ... }:
-with import (nixpkgs + "/nixos/lib/testing-python.nix") {
- inherit system;
- extraConfigurations = [ { nixpkgs.overlays = [ overlay ]; } ];
-};
+let
+ pkgs = config.nodes.machine.nixpkgs.pkgs;
-makeTest {
+in
+{
name = "setuid";
- machine =
+ nodes.machine =
{ config, lib, pkgs, ... }:
{ virtualisation.writableStore = true;
- nix.binaryCaches = lib.mkForce [ ];
+ nix.settings.substituters = lib.mkForce [ ];
nix.nixPath = [ "nixpkgs=${lib.cleanSource pkgs.path}" ];
- virtualisation.pathsInNixDB = [ pkgs.stdenv pkgs.pkgsi686Linux.stdenv ];
+ virtualisation.additionalPaths = [ pkgs.stdenvNoCC pkgs.pkgsi686Linux.stdenvNoCC ];
};
testScript = { nodes }: ''
diff --git a/tests/sourcehut-flakes.nix b/tests/nixos/sourcehut-flakes.nix
index d1d89d149..a76fed020 100644
--- a/tests/sourcehut-flakes.nix
+++ b/tests/nixos/sourcehut-flakes.nix
@@ -1,12 +1,8 @@
-{ nixpkgs, system, overlay }:
-
-with import (nixpkgs + "/nixos/lib/testing-python.nix")
-{
- inherit system;
- extraConfigurations = [{ nixpkgs.overlays = [ overlay ]; }];
-};
+{ lib, config, hostPkgs, nixpkgs, ... }:
let
+ pkgs = config.nodes.sourcehut.nixpkgs.pkgs;
+
# Generate a fake root CA and a fake git.sr.ht certificate.
cert = pkgs.runCommand "cert" { buildInputs = [ pkgs.openssl ]; }
''
@@ -59,13 +55,11 @@ let
echo 'ref: refs/heads/master' > $out/HEAD
mkdir -p $out/info
- echo '${nixpkgs.rev} refs/heads/master' > $out/info/refs
+ echo -e '${nixpkgs.rev}\trefs/heads/master\n${nixpkgs.rev}\trefs/tags/foo-bar' > $out/info/refs
'';
in
-makeTest (
-
{
name = "sourcehut-flakes";
@@ -106,9 +100,9 @@ makeTest (
{
virtualisation.writableStore = true;
virtualisation.diskSize = 2048;
- virtualisation.pathsInNixDB = [ pkgs.hello pkgs.fuse ];
+ virtualisation.additionalPaths = [ pkgs.hello pkgs.fuse ];
virtualisation.memorySize = 4096;
- nix.binaryCaches = lib.mkForce [ ];
+ nix.settings.substituters = lib.mkForce [ ];
nix.extraOptions = ''
experimental-features = nix-command flakes
flake-registry = https://git.sr.ht/~NixOS/flake-registry/blob/master/flake-registry.json
@@ -132,6 +126,17 @@ makeTest (
client.succeed("curl -v https://git.sr.ht/ >&2")
client.succeed("nix registry list | grep nixpkgs")
+ # Test that it resolves HEAD
+ rev = client.succeed("nix flake info sourcehut:~NixOS/nixpkgs --json | jq -r .revision")
+ assert rev.strip() == "${nixpkgs.rev}", "revision mismatch"
+ # Test that it resolves branches
+ rev = client.succeed("nix flake info sourcehut:~NixOS/nixpkgs/master --json | jq -r .revision")
+ assert rev.strip() == "${nixpkgs.rev}", "revision mismatch"
+ # Test that it resolves tags
+ rev = client.succeed("nix flake info sourcehut:~NixOS/nixpkgs/foo-bar --json | jq -r .revision")
+ assert rev.strip() == "${nixpkgs.rev}", "revision mismatch"
+
+ # Registry and pinning test
rev = client.succeed("nix flake info nixpkgs --json | jq -r .revision")
assert rev.strip() == "${nixpkgs.rev}", "revision mismatch"
@@ -153,4 +158,4 @@ makeTest (
client.succeed("nix build nixpkgs#fuse --tarball-ttl 0")
'';
- })
+}
diff --git a/tests/output-normalization.sh b/tests/output-normalization.sh
new file mode 100644
index 000000000..0f6df5e31
--- /dev/null
+++ b/tests/output-normalization.sh
@@ -0,0 +1,9 @@
+source common.sh
+
+testNormalization () {
+ clearStore
+ outPath=$(nix-build ./simple.nix --no-out-link)
+ test "$(stat -c %Y $outPath)" -eq 1
+}
+
+testNormalization
diff --git a/tests/path-from-hash-part.sh b/tests/path-from-hash-part.sh
new file mode 100644
index 000000000..bdd104434
--- /dev/null
+++ b/tests/path-from-hash-part.sh
@@ -0,0 +1,10 @@
+source common.sh
+
+path=$(nix build --no-link --print-out-paths -f simple.nix)
+
+hash_part=$(basename $path)
+hash_part=${hash_part:0:32}
+
+path2=$(nix store path-from-hash-part $hash_part)
+
+[[ $path = $path2 ]]
diff --git a/tests/plugins.sh b/tests/plugins.sh
index e22bf4408..baf71a362 100644
--- a/tests/plugins.sh
+++ b/tests/plugins.sh
@@ -1,6 +1,8 @@
source common.sh
-set -o pipefail
+if [[ $BUILD_SHARED_LIBS != 1 ]]; then
+ skipTest "Plugins are not supported"
+fi
res=$(nix --option setting-set true --option plugin-files $PWD/plugins/libplugintest* eval --expr builtins.anotherNull)
diff --git a/tests/plugins/local.mk b/tests/plugins/local.mk
index 82ad99402..8182a6a83 100644
--- a/tests/plugins/local.mk
+++ b/tests/plugins/local.mk
@@ -8,4 +8,4 @@ libplugintest_ALLOW_UNDEFINED := 1
libplugintest_EXCLUDE_FROM_LIBRARY_LIST := 1
-libplugintest_CXXFLAGS := -I src/libutil -I src/libexpr
+libplugintest_CXXFLAGS := -I src/libutil -I src/libstore -I src/libexpr
diff --git a/tests/plugins/plugintest.cc b/tests/plugins/plugintest.cc
index cd7c9f8b1..04b791021 100644
--- a/tests/plugins/plugintest.cc
+++ b/tests/plugins/plugintest.cc
@@ -13,7 +13,7 @@ MySettings mySettings;
static GlobalConfig::Register rs(&mySettings);
-static void prim_anotherNull (EvalState & state, const Pos & pos, Value ** args, Value & v)
+static void prim_anotherNull (EvalState & state, const PosIdx pos, Value ** args, Value & v)
{
if (mySettings.settingSet)
v.mkNull();
diff --git a/tests/post-hook.sh b/tests/post-hook.sh
index 049e40749..0266eb15d 100644
--- a/tests/post-hook.sh
+++ b/tests/post-hook.sh
@@ -9,12 +9,18 @@ echo 'require-sigs = false' >> $NIX_CONF_DIR/nix.conf
restartDaemon
-# Build the dependencies and push them to the remote store
-nix-build -o $TEST_ROOT/result dependencies.nix --post-build-hook $PWD/push-to-store.sh
+if isDaemonNewer "2.13"; then
+ pushToStore="$PWD/push-to-store.sh"
+else
+ pushToStore="$PWD/push-to-store-old.sh"
+fi
+
+# Build the dependencies and push them to the remote store.
+nix-build -o $TEST_ROOT/result dependencies.nix --post-build-hook "$pushToStore"
clearStore
-# Ensure that we the remote store contains both the runtime and buildtime
-# closure of what we've just built
+# Ensure that the remote store contains both the runtime and build-time
+# 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/tests/pure-eval.sh b/tests/pure-eval.sh
index 1a4568ea6..5334bf28e 100644
--- a/tests/pure-eval.sh
+++ b/tests/pure-eval.sh
@@ -8,7 +8,7 @@ nix eval --expr 'assert 1 + 2 == 3; true'
missingImpureErrorMsg=$(! nix eval --expr 'builtins.readFile ./pure-eval.sh' 2>&1)
-echo "$missingImpureErrorMsg" | grep -q -- --impure || \
+echo "$missingImpureErrorMsg" | grepQuiet -- --impure || \
fail "The error message should mention the “--impure” flag to unblock users"
[[ $(nix eval --expr 'builtins.pathExists ./pure-eval.sh') == false ]] || \
@@ -30,3 +30,5 @@ nix eval --store dummy:// --write-to $TEST_ROOT/eval-out --expr '{ x = "foo" + "
rm -rf $TEST_ROOT/eval-out
(! nix eval --store dummy:// --write-to $TEST_ROOT/eval-out --expr '{ "." = "bla"; }')
+
+(! nix eval --expr '~/foo')
diff --git a/tests/push-to-store-old.sh b/tests/push-to-store-old.sh
new file mode 100755
index 000000000..b1495c9e2
--- /dev/null
+++ b/tests/push-to-store-old.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+set -x
+set -e
+
+[ -n "$OUT_PATHS" ]
+[ -n "$DRV_PATH" ]
+
+echo Pushing "$OUT_PATHS" to "$REMOTE_STORE"
+printf "%s" "$DRV_PATH" | xargs nix copy --to "$REMOTE_STORE" --no-require-sigs
diff --git a/tests/push-to-store.sh b/tests/push-to-store.sh
index 25352c751..0b090e1b3 100755
--- a/tests/push-to-store.sh
+++ b/tests/push-to-store.sh
@@ -1,6 +1,10 @@
#!/bin/sh
set -x
+set -e
+
+[ -n "$OUT_PATHS" ]
+[ -n "$DRV_PATH" ]
echo Pushing "$OUT_PATHS" to "$REMOTE_STORE"
-printf "%s" "$DRV_PATH" | xargs nix copy --to "$REMOTE_STORE" --no-require-sigs
+printf "%s" "$DRV_PATH"^'*' | xargs nix copy --to "$REMOTE_STORE" --no-require-sigs
diff --git a/tests/readfile-context.builder.sh b/tests/readfile-context.builder.sh
deleted file mode 100644
index 7084a08cb..000000000
--- a/tests/readfile-context.builder.sh
+++ /dev/null
@@ -1 +0,0 @@
-echo "$input" > $out
diff --git a/tests/readfile-context.nix b/tests/readfile-context.nix
index 600036a94..54cd1afd9 100644
--- a/tests/readfile-context.nix
+++ b/tests/readfile-context.nix
@@ -6,14 +6,23 @@ let
dependent = mkDerivation {
name = "dependent";
- builder = ./readfile-context.builder.sh;
- input = "${input}/hello";
+ buildCommand = ''
+ mkdir -p $out
+ echo -n "$input1" > "$out/file1"
+ echo -n "$input2" > "$out/file2"
+ '';
+ input1 = "${input}/hello";
+ input2 = "hello";
};
readDependent = mkDerivation {
- name = "read-dependent";
- builder = ./readfile-context.builder.sh;
- input = builtins.readFile dependent;
+ # Will evaluate correctly because file2 doesn't have any references,
+ # even though the `dependent` derivation does.
+ name = builtins.readFile (dependent + "/file2");
+ buildCommand = ''
+ echo "$input" > "$out"
+ '';
+ input = builtins.readFile (dependent + "/file1");
};
in readDependent
diff --git a/tests/recursive.sh b/tests/recursive.sh
index 91518d67d..6335d44a5 100644
--- a/tests/recursive.sh
+++ b/tests/recursive.sh
@@ -4,7 +4,7 @@ sed -i 's/experimental-features .*/& recursive-nix/' "$NIX_CONF_DIR"/nix.conf
restartDaemon
# FIXME
-if [[ $(uname) != Linux ]]; then exit 99; fi
+if [[ $(uname) != Linux ]]; then skipTest "Not running Linux"; fi
clearStore
diff --git a/tests/remote-store.sh b/tests/remote-store.sh
index 31210ab47..ea32a20d3 100644
--- a/tests/remote-store.sh
+++ b/tests/remote-store.sh
@@ -5,8 +5,19 @@ clearStore
# Ensure "fake ssh" remote store works just as legacy fake ssh would.
nix --store ssh-ng://localhost?remote-store=$TEST_ROOT/other-store doctor
+# Ensure that store ping trusted works with ssh-ng://
+nix --store ssh-ng://localhost?remote-store=$TEST_ROOT/other-store store ping --json | jq -e '.trusted'
+
startDaemon
+if isDaemonNewer "2.15pre0"; then
+ # Ensure that ping works trusted with new daemon
+ nix store ping --json | jq -e '.trusted'
+else
+ # And the the field is absent with the old daemon
+ nix store ping --json | jq -e 'has("trusted") | not'
+fi
+
# Test import-from-derivation through the daemon.
[[ $(nix eval --impure --raw --expr '
with import ./config.nix;
@@ -30,7 +41,3 @@ NIX_REMOTE= nix-store --dump-db > $TEST_ROOT/d2
cmp $TEST_ROOT/d1 $TEST_ROOT/d2
killDaemon
-
-user=$(whoami)
-[ -e $NIX_STATE_DIR/gcroots/per-user/$user ]
-[ -e $NIX_STATE_DIR/profiles/per-user/$user ]
diff --git a/tests/repl.sh b/tests/repl.sh
index 6505f1741..be8adb742 100644
--- a/tests/repl.sh
+++ b/tests/repl.sh
@@ -1,39 +1,52 @@
source common.sh
+testDir="$PWD"
+cd "$TEST_ROOT"
+
replCmds="
simple = 1
-simple = import ./simple.nix
-:b simple
+simple = import $testDir/simple.nix
+:bl simple
:log simple
"
replFailingCmds="
-failing = import ./simple-failing.nix
+failing = import $testDir/simple-failing.nix
:b failing
:log failing
"
replUndefinedVariable="
-import ./undefined-variable.nix
+import $testDir/undefined-variable.nix
"
testRepl () {
local nixArgs=("$@")
+ rm -rf repl-result-out || true # cleanup from other runs backed by a foreign nix store
local replOutput="$(nix repl "${nixArgs[@]}" <<< "$replCmds")"
echo "$replOutput"
local outPath=$(echo "$replOutput" |&
grep -o -E "$NIX_STORE_DIR/\w*-simple")
nix path-info "${nixArgs[@]}" "$outPath"
+ [ "$(realpath ./repl-result-out)" == "$outPath" ] || fail "nix repl :bl doesn't make a symlink"
+ # run it again without checking the output to ensure the previously created symlink gets overwritten
+ nix repl "${nixArgs[@]}" <<< "$replCmds" || fail "nix repl does not work twice with the same inputs"
+
# simple.nix prints a PATH during build
- echo "$replOutput" | grep -qs 'PATH=' || fail "nix repl :log doesn't output logs"
+ echo "$replOutput" | grepQuiet -s 'PATH=' || fail "nix repl :log doesn't output logs"
local replOutput="$(nix repl "${nixArgs[@]}" <<< "$replFailingCmds" 2>&1)"
echo "$replOutput"
- echo "$replOutput" | grep -qs 'This should fail' \
+ echo "$replOutput" | grepQuiet -s 'This should fail' \
|| fail "nix repl :log doesn't output logs for a failed derivation"
local replOutput="$(nix repl --show-trace "${nixArgs[@]}" <<< "$replUndefinedVariable" 2>&1)"
echo "$replOutput"
- echo "$replOutput" | grep -qs "while evaluating the file" \
+ echo "$replOutput" | grepQuiet -s "while evaluating the file" \
|| fail "nix repl --show-trace doesn't show the trace"
+
+ nix repl "${nixArgs[@]}" --option pure-eval true 2>&1 <<< "builtins.currentSystem" \
+ | grep "attribute 'currentSystem' missing"
+ nix repl "${nixArgs[@]}" 2>&1 <<< "builtins.currentSystem" \
+ | grep "$(nix-instantiate --eval -E 'builtins.currentSystem')"
}
# Simple test, try building a drv
@@ -42,15 +55,17 @@ testRepl
testRepl --store "$TEST_ROOT/store?real=$NIX_STORE_DIR"
testReplResponse () {
- local response="$(nix repl <<< "$1")"
- echo "$response" | grep -qs "$2" \
+ local commands="$1"; shift
+ local expectedResponse="$1"; shift
+ local response="$(nix repl "$@" <<< "$commands")"
+ echo "$response" | grepQuiet -s "$expectedResponse" \
|| fail "repl command set:
-$1
+$commands
does not respond with:
-$2
+$expectedResponse
but with:
@@ -63,3 +78,48 @@ testReplResponse '
:a { a = "2"; }
"result: ${a}"
' "result: 2"
+
+testReplResponse '
+drvPath
+' '".*-simple.drv"' \
+$testDir/simple.nix
+
+testReplResponse '
+drvPath
+' '".*-simple.drv"' \
+--file $testDir/simple.nix --experimental-features 'ca-derivations'
+
+testReplResponse '
+drvPath
+' '".*-simple.drv"' \
+--file $testDir/simple.nix --extra-experimental-features 'repl-flake ca-derivations'
+
+mkdir -p flake && cat <<EOF > flake/flake.nix
+{
+ outputs = { self }: {
+ foo = 1;
+ bar.baz = 2;
+
+ changingThing = "beforeChange";
+ };
+}
+EOF
+testReplResponse '
+foo + baz
+' "3" \
+ ./flake ./flake\#bar --experimental-features 'flakes repl-flake'
+
+# Test the `:reload` mechansim with flakes:
+# - Eval `./flake#changingThing`
+# - Modify the flake
+# - Re-eval it
+# - Check that the result has changed
+replResult=$( (
+echo "changingThing"
+sleep 1 # Leave the repl the time to eval 'foo'
+sed -i 's/beforeChange/afterChange/' flake/flake.nix
+echo ":reload"
+echo "changingThing"
+) | nix repl ./flake --experimental-features 'flakes repl-flake')
+echo "$replResult" | grepQuiet -s beforeChange
+echo "$replResult" | grepQuiet -s afterChange
diff --git a/tests/restricted.sh b/tests/restricted.sh
index 242b901dd..776893a56 100644
--- a/tests/restricted.sh
+++ b/tests/restricted.sh
@@ -3,7 +3,7 @@ source common.sh
clearStore
nix-instantiate --restrict-eval --eval -E '1 + 2'
-(! nix-instantiate --restrict-eval ./restricted.nix)
+(! nix-instantiate --eval --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
@@ -48,4 +48,4 @@ output="$(nix eval --raw --restrict-eval -I "$traverseDir" \
--expr "builtins.readFile \"$traverseDir/$goUp$(pwd)/restricted-innocent\"" \
2>&1 || :)"
echo "$output" | grep "is forbidden"
-! echo "$output" | grep -F restricted-secret
+echo "$output" | grepInverse -F restricted-secret
diff --git a/tests/search.sh b/tests/search.sh
index 52e12f381..8742f8736 100644
--- a/tests/search.sh
+++ b/tests/search.sh
@@ -20,19 +20,27 @@ clearCache
## Search expressions
# Check that empty search string matches all
-nix search -f search.nix '' |grep -q foo
-nix search -f search.nix '' |grep -q bar
-nix search -f search.nix '' |grep -q hello
+nix search -f search.nix '' |grepQuiet foo
+nix search -f search.nix '' |grepQuiet bar
+nix search -f search.nix '' |grepQuiet hello
## Tests for multiple regex/match highlighting
e=$'\x1b' # grep doesn't support \e, \033 or even \x1b
# Multiple overlapping regexes
-(( $(nix search -f search.nix '' 'oo' 'foo' 'oo' | grep "$e\[32;1mfoo$e\\[0;1m" | wc -l) == 1 ))
-(( $(nix search -f search.nix '' 'broken b' 'en bar' | grep "$e\[32;1mbroken bar$e\\[0m" | wc -l) == 1 ))
+(( $(nix search -f search.nix '' 'oo' 'foo' 'oo' | grep -c "$e\[32;1mfoo$e\\[0;1m") == 1 ))
+(( $(nix search -f search.nix '' 'broken b' 'en bar' | grep -c "$e\[32;1mbroken bar$e\\[0m") == 1 ))
# Multiple matches
# Searching for 'o' should yield the 'o' in 'broken bar', the 'oo' in foo and 'o' in hello
-(( $(nix search -f search.nix '' 'o' | grep -Eo "$e\[32;1mo{1,2}$e\[(0|0;1)m" | wc -l) == 3 ))
+(( $(nix search -f search.nix '' 'o' | grep -Eoc "$e\[32;1mo{1,2}$e\[(0|0;1)m") == 3 ))
# Searching for 'b' should yield the 'b' in bar and the two 'b's in 'broken bar'
+# NOTE: This does not work with `grep -c` because it counts the two 'b's in 'broken bar' as one matched line
(( $(nix search -f search.nix '' 'b' | grep -Eo "$e\[32;1mb$e\[(0|0;1)m" | wc -l) == 3 ))
+
+## Tests for --exclude
+(( $(nix search -f search.nix -e hello | grep -c hello) == 0 ))
+
+(( $(nix search -f search.nix foo --exclude 'foo|bar' | grep -Ec 'foo|bar') == 0 ))
+(( $(nix search -f search.nix foo -e foo --exclude bar | grep -Ec 'foo|bar') == 0 ))
+[[ $(nix search -f search.nix -e bar --json | jq -c 'keys') == '["foo","hello"]' ]]
diff --git a/tests/selfref-gc.sh b/tests/selfref-gc.sh
new file mode 100644
index 000000000..3f1f50eea
--- /dev/null
+++ b/tests/selfref-gc.sh
@@ -0,0 +1,30 @@
+source common.sh
+
+requireDaemonNewerThan "2.6.0pre20211215"
+
+clearStore
+
+nix-build --no-out-link -E '
+ with import ./config.nix;
+
+ let d1 = mkDerivation {
+ name = "selfref-gc";
+ outputs = [ "out" ];
+ buildCommand = "
+ echo SELF_REF: $out > $out
+ ";
+ }; in
+
+ # the only change from d1 is d1 as an (unused) build input
+ # to get identical store path in CA.
+ mkDerivation {
+ name = "selfref-gc";
+ outputs = [ "out" ];
+ buildCommand = "
+ echo UNUSED: ${d1}
+ echo SELF_REF: $out > $out
+ ";
+ }
+'
+
+nix-collect-garbage
diff --git a/tests/shell-hello.nix b/tests/shell-hello.nix
index 77dcbd2a9..3fdd3501d 100644
--- a/tests/shell-hello.nix
+++ b/tests/shell-hello.nix
@@ -3,15 +3,24 @@ with import ./config.nix;
{
hello = mkDerivation {
name = "hello";
+ outputs = [ "out" "dev" ];
+ meta.outputsToInstall = [ "out" ];
buildCommand =
''
- mkdir -p $out/bin
+ mkdir -p $out/bin $dev/bin
+
cat > $out/bin/hello <<EOF
#! ${shell}
who=\$1
echo "Hello \''${who:-World} from $out/bin/hello"
EOF
chmod +x $out/bin/hello
+
+ cat > $dev/bin/hello2 <<EOF
+ #! ${shell}
+ echo "Hello2"
+ EOF
+ chmod +x $dev/bin/hello2
'';
};
}
diff --git a/tests/shell.sh b/tests/shell.sh
index 2b85bb337..d2f7cf14e 100644
--- a/tests/shell.sh
+++ b/tests/shell.sh
@@ -6,7 +6,11 @@ clearCache
nix shell -f shell-hello.nix hello -c hello | grep 'Hello World'
nix shell -f shell-hello.nix hello -c hello NixOS | grep 'Hello NixOS'
-if ! canUseSandbox; then exit 99; fi
+# Test output selection.
+nix shell -f shell-hello.nix hello^dev -c hello2 | grep 'Hello2'
+nix shell -f shell-hello.nix 'hello^*' -c hello2 | grep 'Hello2'
+
+requireSandboxSupport
chmod -R u+w $TEST_ROOT/store0 || true
rm -rf $TEST_ROOT/store0
diff --git a/tests/signing.sh b/tests/signing.sh
index 6aafbeb91..9b673c609 100644
--- a/tests/signing.sh
+++ b/tests/signing.sh
@@ -81,7 +81,7 @@ 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.
+# Copying to a diverted store should fail due to a lack of signatures by trusted keys.
chmod -R u+w $TEST_ROOT/store0 || true
rm -rf $TEST_ROOT/store0
(! nix copy --to $TEST_ROOT/store0 $outPath)
diff --git a/tests/store-ping.sh b/tests/store-ping.sh
index f9427cf0a..9846c7d3d 100644
--- a/tests/store-ping.sh
+++ b/tests/store-ping.sh
@@ -1,13 +1,17 @@
source common.sh
STORE_INFO=$(nix store ping 2>&1)
+STORE_INFO_JSON=$(nix store ping --json)
echo "$STORE_INFO" | grep "Store URL: ${NIX_REMOTE}"
if [[ -v NIX_DAEMON_PACKAGE ]] && isDaemonNewer "2.7.0pre20220126"; then
DAEMON_VERSION=$($NIX_DAEMON_PACKAGE/bin/nix-daemon --version | cut -d' ' -f3)
echo "$STORE_INFO" | grep "Version: $DAEMON_VERSION"
+ [[ "$(echo "$STORE_INFO_JSON" | jq -r ".version")" == "$DAEMON_VERSION" ]]
fi
expect 127 NIX_REMOTE=unix:$PWD/store nix store ping || \
fail "nix store ping on a non-existent store should fail"
+
+[[ "$(echo "$STORE_INFO_JSON" | jq -r ".url")" == "${NIX_REMOTE:-local}" ]]
diff --git a/tests/suggestions.sh b/tests/suggestions.sh
new file mode 100644
index 000000000..f18fefef9
--- /dev/null
+++ b/tests/suggestions.sh
@@ -0,0 +1,44 @@
+source common.sh
+
+clearStore
+
+cd "$TEST_HOME"
+
+cat <<EOF > flake.nix
+{
+ outputs = a: {
+ packages.$system = {
+ foo = 1;
+ fo1 = 1;
+ fo2 = 1;
+ fooo = 1;
+ foooo = 1;
+ fooooo = 1;
+ fooooo1 = 1;
+ fooooo2 = 1;
+ fooooo3 = 1;
+ fooooo4 = 1;
+ fooooo5 = 1;
+ fooooo6 = 1;
+ };
+ };
+}
+EOF
+
+# Probable typo in the requested attribute path. Suggest some close possibilities
+NIX_BUILD_STDERR_WITH_SUGGESTIONS=$(! nix build .\#fob 2>&1 1>/dev/null)
+[[ "$NIX_BUILD_STDERR_WITH_SUGGESTIONS" =~ "Did you mean one of fo1, fo2, foo or fooo?" ]] || \
+ fail "The nix build stderr should suggest the three closest possiblities"
+
+# None of the possible attributes is close to `bar`, so shouldn’t suggest anything
+NIX_BUILD_STDERR_WITH_NO_CLOSE_SUGGESTION=$(! nix build .\#bar 2>&1 1>/dev/null)
+[[ ! "$NIX_BUILD_STDERR_WITH_NO_CLOSE_SUGGESTION" =~ "Did you mean" ]] || \
+ fail "The nix build stderr shouldn’t suggest anything if there’s nothing relevant to suggest"
+
+NIX_EVAL_STDERR_WITH_SUGGESTIONS=$(! nix build --impure --expr '(builtins.getFlake (builtins.toPath ./.)).packages.'$system'.fob' 2>&1 1>/dev/null)
+[[ "$NIX_EVAL_STDERR_WITH_SUGGESTIONS" =~ "Did you mean one of fo1, fo2, foo or fooo?" ]] || \
+ fail "The evaluator should suggest the three closest possiblities"
+
+NIX_EVAL_STDERR_WITH_SUGGESTIONS=$(! nix build --impure --expr '({ foo }: foo) { foo = 1; fob = 2; }' 2>&1 1>/dev/null)
+[[ "$NIX_EVAL_STDERR_WITH_SUGGESTIONS" =~ "Did you mean foo?" ]] || \
+ fail "The evaluator should suggest the three closest possiblities"
diff --git a/tests/tarball.sh b/tests/tarball.sh
index 1301922a5..5f39658c9 100644
--- a/tests/tarball.sh
+++ b/tests/tarball.sh
@@ -19,18 +19,22 @@ test_tarball() {
tarball=$TEST_ROOT/tarball.tar$ext
(cd $TEST_ROOT && tar cf - tarball) | $compressor > $tarball
- nix-env -f file://$tarball -qa --out-path | grep -q dependencies
+ nix-env -f file://$tarball -qa --out-path | grepQuiet 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)"
+ # Do not re-fetch paths already present
+ nix-build -o $TEST_ROOT/result -E "import (fetchTarball { url = file:///does-not-exist/must-remain-unused/$tarball; sha256 = \"$hash\"; })"
nix-build -o $TEST_ROOT/result -E "import (fetchTree file://$tarball)"
nix-build -o $TEST_ROOT/result -E "import (fetchTree { type = \"tarball\"; url = file://$tarball; })"
nix-build -o $TEST_ROOT/result -E "import (fetchTree { type = \"tarball\"; url = file://$tarball; narHash = \"$hash\"; })"
- nix-build -o $TEST_ROOT/result -E "import (fetchTree { type = \"tarball\"; url = file://$tarball; narHash = \"sha256-xdKv2pq/IiwLSnBBJXW8hNowI4MrdZfW+SYqDQs7Tzc=\"; })" 2>&1 | grep 'NAR hash mismatch in input'
+ # Do not re-fetch paths already present
+ nix-build -o $TEST_ROOT/result -E "import (fetchTree { type = \"tarball\"; url = file:///does-not-exist/must-remain-unused/$tarball; narHash = \"$hash\"; })"
+ expectStderr 102 nix-build -o $TEST_ROOT/result -E "import (fetchTree { type = \"tarball\"; url = file://$tarball; narHash = \"sha256-xdKv2pq/IiwLSnBBJXW8hNowI4MrdZfW+SYqDQs7Tzc=\"; })" | grep 'NAR hash mismatch in input'
nix-instantiate --strict --eval -E "!((import (fetchTree { type = \"tarball\"; url = file://$tarball; narHash = \"$hash\"; })) ? submodules)" >&2
nix-instantiate --strict --eval -E "!((import (fetchTree { type = \"tarball\"; url = file://$tarball; narHash = \"$hash\"; })) ? submodules)" 2>&1 | grep 'true'
diff --git a/tests/test-infra.sh b/tests/test-infra.sh
new file mode 100644
index 000000000..54ae120e7
--- /dev/null
+++ b/tests/test-infra.sh
@@ -0,0 +1,85 @@
+# Test the functions for testing themselves!
+# Also test some assumptions on how bash works that they rely on.
+source common.sh
+
+# `true` should exit with 0
+expect 0 true
+
+# `false` should exit with 1
+expect 1 false
+
+# `expect` will fail when we get it wrong
+expect 1 expect 0 false
+
+noisyTrue () {
+ echo YAY! >&2
+ true
+}
+
+noisyFalse () {
+ echo NAY! >&2
+ false
+}
+
+# These should redirect standard error to standard output
+expectStderr 0 noisyTrue | grepQuiet YAY
+expectStderr 1 noisyFalse | grepQuiet NAY
+
+# `set -o pipefile` is enabled
+
+pipefailure () {
+ # shellcheck disable=SC2216
+ true | false | true
+}
+expect 1 pipefailure
+unset pipefailure
+
+pipefailure () {
+ # shellcheck disable=SC2216
+ false | true | true
+}
+expect 1 pipefailure
+unset pipefailure
+
+commandSubstitutionPipeFailure () {
+ # shellcheck disable=SC2216
+ res=$(set -eu -o pipefail; false | true | echo 0)
+}
+expect 1 commandSubstitutionPipeFailure
+
+# `set -u` is enabled
+
+# note (...), making function use subshell, as unbound variable errors
+# in the outer shell are *rightly* not recoverable.
+useUnbound () (
+ set -eu
+ # shellcheck disable=SC2154
+ echo "$thisVariableIsNotBound"
+)
+expect 1 useUnbound
+
+# ! alone unfortunately negates `set -e`, but it works in functions:
+# shellcheck disable=SC2251
+! true
+funBang () {
+ ! true
+}
+expect 1 funBang
+unset funBang
+
+# `grep -v -q` is not what we want for exit codes, but `grepInverse` is
+# Avoid `grep -v -q`. The following line proves the point, and if it fails,
+# we'll know that `grep` had a breaking change or `-v -q` may not be portable.
+{ echo foo; echo bar; } | grep -v -q foo
+{ echo foo; echo bar; } | expect 1 grepInverse foo
+
+# `grepQuiet` is quiet
+res=$(set -eu -o pipefail; echo foo | grepQuiet foo | wc -c)
+(( res == 0 ))
+unset res
+
+# `greqQietInverse` is both
+{ echo foo; echo bar; } | expect 1 grepQuietInverse foo
+res=$(set -eu -o pipefail; echo foo | expect 1 grepQuietInverse foo | wc -c)
+(( res == 0 ))
+unset res
diff --git a/tests/timeout.sh b/tests/timeout.sh
index e3fb3ebcc..b179b79a2 100644
--- a/tests/timeout.sh
+++ b/tests/timeout.sh
@@ -5,17 +5,14 @@ source common.sh
# XXX: This shouldn’t be, but #4813 cause this test to fail
needLocalStore "see #4813"
-set +e
-messages=$(nix-build -Q timeout.nix -A infiniteLoop --timeout 2 2>&1)
-status=$?
-set -e
+messages=$(nix-build -Q timeout.nix -A infiniteLoop --timeout 2 2>&1) && status=0 || status=$?
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
+if echo "$messages" | grepQuietInvert "timed out"; then
echo "error: build may have failed for reasons other than timeout; output:"
echo "$messages" >&2
exit 1
diff --git a/tests/toString-path.sh b/tests/toString-path.sh
new file mode 100644
index 000000000..07eb87465
--- /dev/null
+++ b/tests/toString-path.sh
@@ -0,0 +1,8 @@
+source common.sh
+
+mkdir -p $TEST_ROOT/foo
+echo bla > $TEST_ROOT/foo/bar
+
+[[ $(nix eval --raw --impure --expr "builtins.readFile (builtins.toString (builtins.fetchTree { type = \"path\"; path = \"$TEST_ROOT/foo\"; } + \"/bar\"))") = bla ]]
+
+[[ $(nix eval --json --impure --expr "builtins.readDir (builtins.toString (builtins.fetchTree { type = \"path\"; path = \"$TEST_ROOT/foo\"; }))") = '{"bar":"regular"}' ]]
diff --git a/tests/user-envs-migration.sh b/tests/user-envs-migration.sh
new file mode 100644
index 000000000..187372b16
--- /dev/null
+++ b/tests/user-envs-migration.sh
@@ -0,0 +1,35 @@
+# Test that the migration of user environments
+# (https://github.com/NixOS/nix/pull/5226) does preserve everything
+
+source common.sh
+
+if isDaemonNewer "2.4pre20211005"; then
+ skipTest "Daemon is too new"
+fi
+
+
+killDaemon
+unset NIX_REMOTE
+
+clearStore
+clearProfiles
+rm -rf ~/.nix-profile
+
+# Fill the environment using the older Nix
+PATH_WITH_NEW_NIX="$PATH"
+export PATH="$NIX_DAEMON_PACKAGE/bin:$PATH"
+
+nix-env -f user-envs.nix -i foo-1.0
+nix-env -f user-envs.nix -i bar-0.1
+
+# Migrate to the new profile dir, and ensure that everything’s there
+export PATH="$PATH_WITH_NEW_NIX"
+nix-env -q # Trigger the migration
+( [[ -L ~/.nix-profile ]] && \
+ [[ $(readlink ~/.nix-profile) == ~/.local/share/nix/profiles/profile ]] ) || \
+ fail "The nix profile should point to the new location"
+
+(nix-env -q | grep foo && nix-env -q | grep bar && \
+ [[ -e ~/.nix-profile/bin/foo ]] && \
+ [[ $(nix-env --list-generations | wc -l) == 2 ]]) ||
+ fail "The nix profile should have the same content as before the migration"
diff --git a/tests/user-envs.nix b/tests/user-envs.nix
index 6ac896ed8..46f8b51dd 100644
--- a/tests/user-envs.nix
+++ b/tests/user-envs.nix
@@ -8,6 +8,8 @@ assert foo == "foo";
let
+ platforms = let x = "foobar"; in [ x x ];
+
makeDrv = name: progName: (mkDerivation {
name = assert progName != "fail"; name;
inherit progName system;
@@ -15,6 +17,7 @@ let
} // {
meta = {
description = "A silly test package with some \${escaped anti-quotation} in it";
+ inherit platforms;
};
});
diff --git a/tests/user-envs.sh b/tests/user-envs.sh
index aebf6a2a2..d1260ba04 100644
--- a/tests/user-envs.sh
+++ b/tests/user-envs.sh
@@ -1,6 +1,6 @@
source common.sh
-if [ -z "$storeCleared" ]; then
+if [ -z "${storeCleared-}" ]; then
clearStore
fi
@@ -9,7 +9,6 @@ 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.
@@ -18,14 +17,24 @@ outPath10=$(nix-env -f ./user-envs.nix -qa --out-path --no-name '*' | grep foo-1
drvPath10=$(nix-env -f ./user-envs.nix -qa --drv-path --no-name '*' | grep foo-1.0)
[ -n "$outPath10" -a -n "$drvPath10" ]
+# Query with json
+nix-env -f ./user-envs.nix -qa --json | jq -e '.[] | select(.name == "bar-0.1") | [
+ .outputName == "out",
+ .outputs.out == null
+] | all'
+nix-env -f ./user-envs.nix -qa --json --out-path | jq -e '.[] | select(.name == "bar-0.1") | [
+ .outputName == "out",
+ (.outputs.out | test("'$NIX_STORE_DIR'.*-0\\.1"))
+] | all'
+
# Query descriptions.
-nix-env -f ./user-envs.nix -qa '*' --description | grep -q silly
+nix-env -f ./user-envs.nix -qa '*' --description | grepQuiet silly
rm -rf $HOME/.nix-defexpr
ln -s $(pwd)/user-envs.nix $HOME/.nix-defexpr
-nix-env -qa '*' --description | grep -q silly
+nix-env -qa '*' --description | grepQuiet silly
# Query the system.
-nix-env -qa '*' --system | grep -q $system
+nix-env -qa '*' --system | grepQuiet $system
# Install "foo-1.0".
nix-env -i foo-1.0
@@ -33,19 +42,19 @@ 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
+nix-env -q '*' | grepQuiet 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'
+nix-env -qc '*' | grepQuiet '< 2.0'
+nix-env -qac '*' | grepQuiet '> 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'
+nix-env -qas | grepQuiet 'IP- foo-1.0'
+nix-env -qas | grepQuiet -- '--- bar-0.1'
# Disable foo.
nix-env --set-flag active false foo
@@ -65,15 +74,15 @@ 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
+nix-env -q '*' | grepQuiet 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
+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
+nix-env -q '*' | grepQuiet foo-2.0
test "$($profiles/test/bin/foo)" = "foo-2.0"
# Store the path of foo-2.0.
@@ -85,20 +94,20 @@ 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
+if nix-env -q '*' | grepQuiet foo; then false; fi
+nix-env -q '*' | grepQuiet 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
+nix-env -q '*' | grepQuiet foo-2.0
+nix-env -q '*' | grepQuiet 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
+nix-env -q '*' | grepQuiet foo-2.0
+if nix-env -q '*' | grepQuiet bar; then false; fi
# Count generations.
nix-env --list-generations
@@ -120,7 +129,7 @@ nix-env --switch-generation 7
# Install foo-1.0, now using its store path.
nix-env -i "$outPath10"
-nix-env -q '*' | grep -q foo-1.0
+nix-env -q '*' | grepQuiet 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 ]
@@ -128,12 +137,12 @@ nix-store -q --referrers-closure $profiles/test | grep "$(nix-store -q --resolve
# 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")
+if nix-env -q '*' | grepQuiet foo; then false; fi
+nix-store -qR $profiles/test | grepInverse "$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
+nix-env -q '*' | grepQuiet foo
# Delete all old generations.
nix-env --delete-generations old
@@ -151,7 +160,7 @@ 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
+nix-env -q '*' | grepQuiet foo-2.0
# On the other hand, this should install both (and should fail due to
# a collision).
@@ -162,8 +171,8 @@ nix-env -e '*'
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
+nix-env -q '*' | grepQuiet foo-2.0
+nix-env -q '*' | grepQuiet 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
diff --git a/tests/why-depends.sh b/tests/why-depends.sh
index c12941e76..b35a0d1cf 100644
--- a/tests/why-depends.sh
+++ b/tests/why-depends.sh
@@ -6,6 +6,9 @@ cp ./dependencies.nix ./dependencies.builder0.sh ./config.nix $TEST_HOME
cd $TEST_HOME
+nix why-depends --derivation --file ./dependencies.nix input2_drv input1_drv
+nix why-depends --file ./dependencies.nix input2_drv input1_drv
+
nix-build ./dependencies.nix -A input0_drv -o dep
nix-build ./dependencies.nix -o toplevel
@@ -13,9 +16,9 @@ FAST_WHY_DEPENDS_OUTPUT=$(nix why-depends ./toplevel ./dep)
PRECISE_WHY_DEPENDS_OUTPUT=$(nix why-depends ./toplevel ./dep --precise)
# Both outputs should show that `input-2` is in the dependency chain
-echo "$FAST_WHY_DEPENDS_OUTPUT" | grep -q input-2
-echo "$PRECISE_WHY_DEPENDS_OUTPUT" | grep -q input-2
+echo "$FAST_WHY_DEPENDS_OUTPUT" | grepQuiet input-2
+echo "$PRECISE_WHY_DEPENDS_OUTPUT" | grepQuiet input-2
-# But only the “precise” one should refere to `reference-to-input-2`
-echo "$FAST_WHY_DEPENDS_OUTPUT" | (! grep -q reference-to-input-2)
-echo "$PRECISE_WHY_DEPENDS_OUTPUT" | grep -q reference-to-input-2
+# But only the “precise” one should refer to `reference-to-input-2`
+echo "$FAST_WHY_DEPENDS_OUTPUT" | grepQuietInverse reference-to-input-2
+echo "$PRECISE_WHY_DEPENDS_OUTPUT" | grepQuiet reference-to-input-2