mirror of
https://github.com/NixOS/nix
synced 2025-07-07 01:51:47 +02:00
Merge remote-tracking branch 'origin/master' into finish-value
This commit is contained in:
commit
6a3ecdaa39
271 changed files with 7672 additions and 1195 deletions
|
@ -14,6 +14,14 @@ outPath=$(nix-build dependencies.nix --no-out-link)
|
|||
|
||||
nix copy --to file://$cacheDir $outPath
|
||||
|
||||
readarray -t paths < <(nix path-info --all --json --store file://$cacheDir | jq 'keys|sort|.[]' -r)
|
||||
[[ "${#paths[@]}" -eq 3 ]]
|
||||
for path in "${paths[@]}"; do
|
||||
[[ "$path" =~ -dependencies-input-0$ ]] \
|
||||
|| [[ "$path" =~ -dependencies-input-2$ ]] \
|
||||
|| [[ "$path" =~ -dependencies-top$ ]]
|
||||
done
|
||||
|
||||
# Test copying build logs to the binary cache.
|
||||
expect 1 nix log --store file://$cacheDir $outPath 2>&1 | grep 'is not available'
|
||||
nix store copy-log --to file://$cacheDir $outPath
|
||||
|
|
|
@ -34,6 +34,21 @@ nix-build check.nix -A failed --argstr checkBuildId $checkBuildId \
|
|||
[ "$status" = "100" ]
|
||||
if checkBuildTempDirRemoved $TEST_ROOT/log; then false; fi
|
||||
|
||||
test_custom_build_dir() {
|
||||
local customBuildDir="$TEST_ROOT/custom-build-dir"
|
||||
|
||||
# Nix does not create the parent directories, and perhaps it shouldn't try to
|
||||
# decide the permissions of build-dir.
|
||||
mkdir "$customBuildDir"
|
||||
nix-build check.nix -A failed --argstr checkBuildId $checkBuildId \
|
||||
--no-out-link --keep-failed --option build-dir "$TEST_ROOT/custom-build-dir" 2> $TEST_ROOT/log || status=$?
|
||||
[ "$status" = "100" ]
|
||||
[[ 1 == "$(count "$customBuildDir/nix-build-"*)" ]]
|
||||
local buildDir="$customBuildDir/nix-build-"*
|
||||
grep $checkBuildId $buildDir/checkBuildId
|
||||
}
|
||||
test_custom_build_dir
|
||||
|
||||
nix-build check.nix -A deterministic --argstr checkBuildId $checkBuildId \
|
||||
--no-out-link 2> $TEST_ROOT/log
|
||||
checkBuildTempDirRemoved $TEST_ROOT/log
|
||||
|
|
45
tests/functional/chroot-store.sh
Normal file
45
tests/functional/chroot-store.sh
Normal file
|
@ -0,0 +1,45 @@
|
|||
source common.sh
|
||||
|
||||
echo example > $TEST_ROOT/example.txt
|
||||
mkdir -p $TEST_ROOT/x
|
||||
|
||||
export NIX_STORE_DIR=/nix2/store
|
||||
|
||||
CORRECT_PATH=$(cd $TEST_ROOT && nix-store --store ./x --add example.txt)
|
||||
|
||||
[[ $CORRECT_PATH =~ ^/nix2/store/.*-example.txt$ ]]
|
||||
|
||||
PATH1=$(cd $TEST_ROOT && nix path-info --store ./x $CORRECT_PATH)
|
||||
[ $CORRECT_PATH == $PATH1 ]
|
||||
|
||||
PATH2=$(nix path-info --store "$TEST_ROOT/x" $CORRECT_PATH)
|
||||
[ $CORRECT_PATH == $PATH2 ]
|
||||
|
||||
PATH3=$(nix path-info --store "local?root=$TEST_ROOT/x" $CORRECT_PATH)
|
||||
[ $CORRECT_PATH == $PATH3 ]
|
||||
|
||||
# Ensure store info trusted works with local store
|
||||
nix --store $TEST_ROOT/x store info --json | jq -e '.trusted'
|
||||
|
||||
# Test building in a chroot store.
|
||||
if canUseSandbox; then
|
||||
|
||||
flakeDir=$TEST_ROOT/flake
|
||||
mkdir -p $flakeDir
|
||||
|
||||
cat > $flakeDir/flake.nix <<EOF
|
||||
{
|
||||
outputs = inputs: rec {
|
||||
packages.$system.default = import ./simple.nix;
|
||||
};
|
||||
}
|
||||
EOF
|
||||
|
||||
cp simple.nix shell.nix simple.builder.sh config.nix $flakeDir/
|
||||
|
||||
outPath=$(nix build --print-out-paths --no-link --sandbox-paths '/nix? /bin? /lib? /lib64? /usr?' --store $TEST_ROOT/x path:$flakeDir)
|
||||
|
||||
[[ $outPath =~ ^/nix2/store/.*-simple$ ]]
|
||||
|
||||
[[ $(cat $TEST_ROOT/x/nix/store/$(basename $outPath)/hello) = 'Hello World!' ]]
|
||||
fi
|
|
@ -283,6 +283,11 @@ grepQuietInverse() {
|
|||
! grep "$@" > /dev/null
|
||||
}
|
||||
|
||||
# Return the number of arguments
|
||||
count() {
|
||||
echo $#
|
||||
}
|
||||
|
||||
trap onError ERR
|
||||
|
||||
fi # COMMON_VARS_AND_FUNCTIONS_SH_SOURCED
|
||||
|
|
|
@ -43,6 +43,16 @@ export NIX_USER_CONF_FILES=$here/config/nix-with-substituters.conf
|
|||
var=$(nix config show | grep '^substituters =' | cut -d '=' -f 2 | xargs)
|
||||
[[ $var == https://example.com ]]
|
||||
|
||||
# Test that we can include a file.
|
||||
export NIX_USER_CONF_FILES=$here/config/nix-with-include.conf
|
||||
var=$(nix config show | grep '^allowed-uris =' | cut -d '=' -f 2 | xargs)
|
||||
[[ $var == https://github.com/NixOS/nix ]]
|
||||
|
||||
# Test that we can !include a file.
|
||||
export NIX_USER_CONF_FILES=$here/config/nix-with-bang-include.conf
|
||||
var=$(nix config show | grep '^experimental-features =' | cut -d '=' -f 2 | xargs)
|
||||
[[ $var == nix-command ]]
|
||||
|
||||
# Test that it's possible to load config from the environment
|
||||
prev=$(nix config show | grep '^cores' | cut -d '=' -f 2 | xargs)
|
||||
export NIX_CONFIG="cores = 4242"$'\n'"experimental-features = nix-command flakes"
|
||||
|
@ -56,4 +66,4 @@ exp_features=$(nix config show | grep '^experimental-features' | cut -d '=' -f 2
|
|||
# Test that it's possible to retrieve a single setting's value
|
||||
val=$(nix config show | grep '^warn-dirty' | cut -d '=' -f 2 | xargs)
|
||||
val2=$(nix config show warn-dirty)
|
||||
[[ $val == $val2 ]]
|
||||
[[ $val == $val2 ]]
|
1
tests/functional/config/extra-config.conf
Normal file
1
tests/functional/config/extra-config.conf
Normal file
|
@ -0,0 +1 @@
|
|||
allowed-uris = https://github.com/NixOS/nix
|
2
tests/functional/config/nix-with-bang-include.conf
Normal file
2
tests/functional/config/nix-with-bang-include.conf
Normal file
|
@ -0,0 +1,2 @@
|
|||
experimental-features = nix-command
|
||||
!include ./missing-extra-config.conf
|
2
tests/functional/config/nix-with-include.conf
Normal file
2
tests/functional/config/nix-with-include.conf
Normal file
|
@ -0,0 +1,2 @@
|
|||
experimental-features = nix-command
|
||||
include ./extra-config.conf
|
|
@ -1,6 +1,6 @@
|
|||
source common.sh
|
||||
|
||||
[[ $(type -p hq) ]] || skipTest "Mercurial not installed"
|
||||
[[ $(type -p hg) ]] || skipTest "Mercurial not installed"
|
||||
|
||||
clearStore
|
||||
|
||||
|
|
|
@ -64,4 +64,6 @@ rec {
|
|||
(f2 "bar" ./fixed.builder2.sh "recursive" "md5" "3670af73070fa14077ad74e0f5ea4e42")
|
||||
];
|
||||
|
||||
# Can use "nar" instead of "recursive" now.
|
||||
nar-not-recursive = f2 "foo" ./fixed.builder2.sh "nar" "md5" "3670af73070fa14077ad74e0f5ea4e42";
|
||||
}
|
||||
|
|
|
@ -61,3 +61,7 @@ out3=$(nix-store --add-fixed --recursive sha256 $TEST_ROOT/fixed)
|
|||
|
||||
out4=$(nix-store --print-fixed-path --recursive sha256 "1ixr6yd3297ciyp9im522dfxpqbkhcw0pylkb2aab915278fqaik" fixed)
|
||||
[ "$out" = "$out4" ]
|
||||
|
||||
# Can use `outputHashMode = "nar";` instead of `"recursive"` now.
|
||||
clearStore
|
||||
nix-build fixed.nix -A nar-not-recursive --no-out-link
|
||||
|
|
|
@ -56,6 +56,23 @@ cat > $flake1Dir/flake.nix <<EOF
|
|||
a12 = self.drvCall.outPath;
|
||||
|
||||
a13 = "\${self.drvCall.drvPath}\${self.drvCall.outPath}";
|
||||
|
||||
a14 = with import ./config.nix; let
|
||||
top = mkDerivation {
|
||||
name = "dot-installable";
|
||||
outputs = [ "foo" "out" ];
|
||||
meta.outputsToInstall = [ "out" ];
|
||||
buildCommand = ''
|
||||
mkdir \$foo \$out
|
||||
echo "foo" > \$foo/file
|
||||
echo "out" > \$out/file
|
||||
'';
|
||||
};
|
||||
in top // {
|
||||
foo = top.foo // {
|
||||
outputSpecified = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
EOF
|
||||
|
@ -94,3 +111,10 @@ nix build --json --out-link $TEST_ROOT/result $flake1Dir#a12
|
|||
|
||||
expectStderr 1 nix build --impure --json --out-link $TEST_ROOT/result $flake1Dir#a13 \
|
||||
| grepQuiet "has 2 entries in its context. It should only have exactly one entry"
|
||||
|
||||
# Test accessing output in installables with `.` (foobarbaz.<output>)
|
||||
nix build --json --no-link $flake1Dir#a14.foo | jq --exit-status '
|
||||
(.[0] |
|
||||
(.drvPath | match(".*dot-installable.drv")) and
|
||||
(.outputs | keys == ["foo"]))
|
||||
'
|
||||
|
|
|
@ -93,6 +93,24 @@ foo
|
|||
EOF
|
||||
chmod +x $nonFlakeDir/shebang-comments.sh
|
||||
|
||||
cat > $nonFlakeDir/shebang-different-comments.sh <<EOF
|
||||
#! $(type -P env) nix
|
||||
# some comments
|
||||
// some comments
|
||||
/* some comments
|
||||
* some comments
|
||||
\ some comments
|
||||
% some comments
|
||||
@ some comments
|
||||
-- some comments
|
||||
(* some comments
|
||||
#! nix --offline shell
|
||||
#! nix flake1#fooScript
|
||||
#! nix --no-write-lock-file --command cat
|
||||
foo
|
||||
EOF
|
||||
chmod +x $nonFlakeDir/shebang-different-comments.sh
|
||||
|
||||
cat > $nonFlakeDir/shebang-reject.sh <<EOF
|
||||
#! $(type -P env) nix
|
||||
# some comments
|
||||
|
@ -607,6 +625,7 @@ expectStderr 1 nix flake metadata "$flake2Dir" --no-allow-dirty --reference-lock
|
|||
[[ $($nonFlakeDir/shebang.sh) = "foo" ]]
|
||||
[[ $($nonFlakeDir/shebang.sh "bar") = "foo"$'\n'"bar" ]]
|
||||
[[ $($nonFlakeDir/shebang-comments.sh ) = "foo" ]]
|
||||
[[ "$($nonFlakeDir/shebang-different-comments.sh)" = "$(cat $nonFlakeDir/shebang-different-comments.sh)" ]]
|
||||
[[ $($nonFlakeDir/shebang-inline-expr.sh baz) = "foo"$'\n'"baz" ]]
|
||||
[[ $($nonFlakeDir/shebang-file.sh baz) = "foo"$'\n'"baz" ]]
|
||||
expect 1 $nonFlakeDir/shebang-reject.sh 2>&1 | grepQuiet -F 'error: unsupported unquoted character in nix shebang: *. Use double backticks to escape?'
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
source ./common.sh
|
||||
|
||||
[[ $(type -p hq) ]] || skipTest "Mercurial not installed"
|
||||
[[ $(type -p hg) ]] || skipTest "Mercurial not installed"
|
||||
|
||||
flake1Dir=$TEST_ROOT/flake-hg1
|
||||
mkdir -p $flake1Dir
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
{ busybox, seed }:
|
||||
{ busybox
|
||||
, seed
|
||||
# If we want the final derivation output to have references to its
|
||||
# dependencies. Some tests need/want this, other don't.
|
||||
, withFinalRefs ? false
|
||||
}:
|
||||
|
||||
with import ./config.nix;
|
||||
|
||||
|
@ -40,7 +45,7 @@ let
|
|||
buildCommand = ''
|
||||
echo hi-input3
|
||||
read x < ${input2}
|
||||
echo $x BAZ > $out
|
||||
echo ${input2} $x BAZ > $out
|
||||
'';
|
||||
};
|
||||
|
||||
|
@ -54,6 +59,6 @@ in
|
|||
''
|
||||
read x < ${input1}
|
||||
read y < ${input3}
|
||||
echo "$x $y" > $out
|
||||
echo ${if (builtins.trace withFinalRefs withFinalRefs) then "${input1} ${input3}" else ""} "$x $y" > $out
|
||||
'';
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ source common/vars-and-functions.sh
|
|||
|
||||
test -n "$TEST_ROOT"
|
||||
if test -d "$TEST_ROOT"; then
|
||||
chmod -R u+w "$TEST_ROOT"
|
||||
chmod -R u+rw "$TEST_ROOT"
|
||||
# We would delete any daemon socket, so let's stop the daemon first.
|
||||
killDaemon
|
||||
rm -rf "$TEST_ROOT"
|
||||
|
|
|
@ -68,8 +68,16 @@ done
|
|||
for i in lang/eval-fail-*.nix; do
|
||||
echo "evaluating $i (should fail)";
|
||||
i=$(basename "$i" .nix)
|
||||
flags="$(
|
||||
if [[ -e "lang/$i.flags" ]]; then
|
||||
sed -e 's/#.*//' < "lang/$i.flags"
|
||||
else
|
||||
# note that show-trace is also set by init.sh
|
||||
echo "--eval --strict --show-trace"
|
||||
fi
|
||||
)"
|
||||
if
|
||||
expectStderr 1 nix-instantiate --eval --strict --show-trace "lang/$i.nix" \
|
||||
expectStderr 1 nix-instantiate $flags "lang/$i.nix" \
|
||||
| sed "s!$(pwd)!/pwd!g" > "lang/$i.err"
|
||||
then
|
||||
diffAndAccept "$i" err err.exp
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
error:
|
||||
… while counting down; n = 10
|
||||
|
||||
… while counting down; n = 9
|
||||
|
||||
… while counting down; n = 8
|
||||
|
||||
… while counting down; n = 7
|
||||
|
||||
… while counting down; n = 6
|
||||
|
||||
… while counting down; n = 5
|
||||
|
||||
… while counting down; n = 4
|
||||
|
||||
… while counting down; n = 3
|
||||
|
||||
… while counting down; n = 2
|
||||
|
||||
… while counting down; n = 1
|
||||
|
||||
(stack trace truncated; use '--show-trace' to show the full, detailed trace)
|
||||
|
||||
error: kaboom
|
|
@ -0,0 +1 @@
|
|||
--eval --strict --no-show-trace
|
|
@ -0,0 +1,9 @@
|
|||
let
|
||||
countDown = n:
|
||||
if n == 0
|
||||
then throw "kaboom"
|
||||
else
|
||||
builtins.addErrorContext
|
||||
"while counting down; n = ${toString n}"
|
||||
("x" + countDown (n - 1));
|
||||
in countDown 10
|
1
tests/functional/lang/eval-okay-baseNameOf.exp
Normal file
1
tests/functional/lang/eval-okay-baseNameOf.exp
Normal file
|
@ -0,0 +1 @@
|
|||
"ok"
|
32
tests/functional/lang/eval-okay-baseNameOf.nix
Normal file
32
tests/functional/lang/eval-okay-baseNameOf.nix
Normal file
|
@ -0,0 +1,32 @@
|
|||
assert baseNameOf "" == "";
|
||||
assert baseNameOf "." == ".";
|
||||
assert baseNameOf ".." == "..";
|
||||
assert baseNameOf "a" == "a";
|
||||
assert baseNameOf "a." == "a.";
|
||||
assert baseNameOf "a.." == "a..";
|
||||
assert baseNameOf "a.b" == "a.b";
|
||||
assert baseNameOf "a.b." == "a.b.";
|
||||
assert baseNameOf "a.b.." == "a.b..";
|
||||
assert baseNameOf "a/" == "a";
|
||||
assert baseNameOf "a/." == ".";
|
||||
assert baseNameOf "a/.." == "..";
|
||||
assert baseNameOf "a/b" == "b";
|
||||
assert baseNameOf "a/b." == "b.";
|
||||
assert baseNameOf "a/b.." == "b..";
|
||||
assert baseNameOf "a/b/c" == "c";
|
||||
assert baseNameOf "a/b/c." == "c.";
|
||||
assert baseNameOf "a/b/c.." == "c..";
|
||||
assert baseNameOf "a/b/c/d" == "d";
|
||||
assert baseNameOf "a/b/c/d." == "d.";
|
||||
assert baseNameOf "a\\b" == "a\\b";
|
||||
assert baseNameOf "C:a" == "C:a";
|
||||
assert baseNameOf "a//b" == "b";
|
||||
|
||||
# It's been like this for close to a decade. We ought to commit to it.
|
||||
# https://github.com/NixOS/nix/pull/582#issuecomment-121014450
|
||||
assert baseNameOf "a//" == "";
|
||||
|
||||
assert baseNameOf ./foo == "foo";
|
||||
assert baseNameOf ./foo/bar == "bar";
|
||||
|
||||
"ok"
|
|
@ -1,4 +1,9 @@
|
|||
source common.sh
|
||||
|
||||
store_uri="ssh://localhost?remote-store=$TEST_ROOT/other-store"
|
||||
|
||||
# Check that store info trusted doesn't yet work with ssh://
|
||||
nix --store ssh://localhost?remote-store=$TEST_ROOT/other-store store info --json | jq -e 'has("trusted") | not'
|
||||
nix --store "$store_uri" store info --json | jq -e 'has("trusted") | not'
|
||||
|
||||
# Suppress grumpiness about multiple nixes on PATH
|
||||
(nix --store "$store_uri" doctor || true) 2>&1 | grep "doesn't have a notion of trusted user"
|
||||
|
|
|
@ -60,7 +60,13 @@ testCert () {
|
|||
|
||||
nocert=$TEST_ROOT/no-cert-file.pem
|
||||
cert=$TEST_ROOT/some-cert-file.pem
|
||||
symlinkcert=$TEST_ROOT/symlink-cert-file.pem
|
||||
transitivesymlinkcert=$TEST_ROOT/transitive-symlink-cert-file.pem
|
||||
symlinkDir=$TEST_ROOT/symlink-dir
|
||||
echo -n "CERT_CONTENT" > $cert
|
||||
ln -s $cert $symlinkcert
|
||||
ln -s $symlinkcert $transitivesymlinkcert
|
||||
ln -s $TEST_ROOT $symlinkDir
|
||||
|
||||
# No cert in sandbox when not a fixed-output derivation
|
||||
testCert missing normal "$cert"
|
||||
|
@ -73,3 +79,15 @@ testCert missing fixed-output "$nocert"
|
|||
|
||||
# Cert in sandbox when ssl-cert-file is set to an existing file
|
||||
testCert present fixed-output "$cert"
|
||||
|
||||
# Cert in sandbox when ssl-cert-file is set to a (potentially transitive) symlink to an existing file
|
||||
testCert present fixed-output "$symlinkcert"
|
||||
testCert present fixed-output "$transitivesymlinkcert"
|
||||
|
||||
# Symlinks should be added in the sandbox directly and not followed
|
||||
nix-sandbox-build symlink-derivation.nix -A depends_on_symlink
|
||||
nix-sandbox-build symlink-derivation.nix -A test_sandbox_paths \
|
||||
--option extra-sandbox-paths "/file=$cert" \
|
||||
--option extra-sandbox-paths "/dir=$TEST_ROOT" \
|
||||
--option extra-sandbox-paths "/symlinkDir=$symlinkDir" \
|
||||
--option extra-sandbox-paths "/symlink=$symlinkcert"
|
||||
|
|
31
tests/functional/local-overlay-store/add-lower-inner.sh
Executable file
31
tests/functional/local-overlay-store/add-lower-inner.sh
Executable file
|
@ -0,0 +1,31 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
set -x
|
||||
|
||||
source common.sh
|
||||
|
||||
# Avoid store dir being inside sandbox build-dir
|
||||
unset NIX_STORE_DIR
|
||||
unset NIX_STATE_DIR
|
||||
|
||||
setupStoreDirs
|
||||
|
||||
initLowerStore
|
||||
|
||||
mountOverlayfs
|
||||
|
||||
# Add something to the overlay store
|
||||
overlayPath=$(addTextToStore "$storeB" "overlay-file" "Add to overlay store")
|
||||
stat "$storeBRoot/$overlayPath"
|
||||
|
||||
# Now add something to the lower store
|
||||
lowerPath=$(addTextToStore "$storeA" "lower-file" "Add to lower store")
|
||||
stat "$storeVolume/store-a/$lowerPath"
|
||||
|
||||
# Remount overlayfs to ensure synchronization
|
||||
remountOverlayfs
|
||||
|
||||
# Path should be accessible via overlay store
|
||||
stat "$storeBRoot/$lowerPath"
|
5
tests/functional/local-overlay-store/add-lower.sh
Executable file
5
tests/functional/local-overlay-store/add-lower.sh
Executable file
|
@ -0,0 +1,5 @@
|
|||
source common.sh
|
||||
|
||||
requireEnvironment
|
||||
setupConfig
|
||||
execUnshare ./add-lower-inner.sh
|
25
tests/functional/local-overlay-store/bad-uris.sh
Normal file
25
tests/functional/local-overlay-store/bad-uris.sh
Normal file
|
@ -0,0 +1,25 @@
|
|||
source common.sh
|
||||
|
||||
requireEnvironment
|
||||
setupConfig
|
||||
setupStoreDirs
|
||||
|
||||
mkdir -p $TEST_ROOT/bad_test
|
||||
badTestRoot=$TEST_ROOT/bad_test
|
||||
storeBadRoot="local-overlay://?root=$badTestRoot&lower-store=$storeA&upper-layer=$storeBTop"
|
||||
storeBadLower="local-overlay://?root=$storeBRoot&lower-store=$badTestRoot&upper-layer=$storeBTop"
|
||||
storeBadUpper="local-overlay://?root=$storeBRoot&lower-store=$storeA&upper-layer=$badTestRoot"
|
||||
|
||||
declare -a storesBad=(
|
||||
"$storeBadRoot" "$storeBadLower" "$storeBadUpper"
|
||||
)
|
||||
|
||||
for i in "${storesBad[@]}"; do
|
||||
echo $i
|
||||
unshare --mount --map-root-user bash <<EOF
|
||||
source common.sh
|
||||
setupStoreDirs
|
||||
mountOverlayfs
|
||||
expectStderr 1 nix doctor --store "$i" | grepQuiet "overlay filesystem .* mounted incorrectly"
|
||||
EOF
|
||||
done
|
30
tests/functional/local-overlay-store/build-inner.sh
Executable file
30
tests/functional/local-overlay-store/build-inner.sh
Executable file
|
@ -0,0 +1,30 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
set -x
|
||||
|
||||
source common.sh
|
||||
|
||||
# Avoid store dir being inside sandbox build-dir
|
||||
unset NIX_STORE_DIR
|
||||
unset NIX_STATE_DIR
|
||||
|
||||
setupStoreDirs
|
||||
|
||||
initLowerStore
|
||||
|
||||
mountOverlayfs
|
||||
|
||||
### Do a build in overlay store
|
||||
|
||||
path=$(nix-build ../hermetic.nix --arg busybox $busybox --arg seed 2 --store "$storeB" --no-out-link)
|
||||
|
||||
# Checking for path in lower layer (should fail)
|
||||
expect 1 stat $(toRealPath "$storeA/nix/store" "$path")
|
||||
|
||||
# Checking for path in upper layer
|
||||
stat $(toRealPath "$storeBTop" "$path")
|
||||
|
||||
# Verifying path in overlay store
|
||||
nix-store --verify-path --store "$storeB" "$path"
|
5
tests/functional/local-overlay-store/build.sh
Executable file
5
tests/functional/local-overlay-store/build.sh
Executable file
|
@ -0,0 +1,5 @@
|
|||
source common.sh
|
||||
|
||||
requireEnvironment
|
||||
setupConfig
|
||||
execUnshare ./build-inner.sh
|
71
tests/functional/local-overlay-store/check-post-init-inner.sh
Executable file
71
tests/functional/local-overlay-store/check-post-init-inner.sh
Executable file
|
@ -0,0 +1,71 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
set -x
|
||||
|
||||
source common.sh
|
||||
|
||||
# Avoid store dir being inside sandbox build-dir
|
||||
unset NIX_STORE_DIR
|
||||
unset NIX_STATE_DIR
|
||||
|
||||
setupStoreDirs
|
||||
|
||||
initLowerStore
|
||||
|
||||
mountOverlayfs
|
||||
|
||||
### Check status
|
||||
|
||||
# Checking for path in lower layer
|
||||
stat $(toRealPath "$storeA/nix/store" "$pathInLowerStore")
|
||||
|
||||
# Checking for path in upper layer (should fail)
|
||||
expect 1 stat $(toRealPath "$storeBTop" "$pathInLowerStore")
|
||||
|
||||
# Checking for path in overlay store matching lower layer
|
||||
diff $(toRealPath "$storeA/nix/store" "$pathInLowerStore") $(toRealPath "$storeBRoot/nix/store" "$pathInLowerStore")
|
||||
|
||||
# Checking requisites query agreement
|
||||
[[ \
|
||||
$(nix-store --store $storeA --query --requisites $drvPath) \
|
||||
== \
|
||||
$(nix-store --store $storeB --query --requisites $drvPath) \
|
||||
]]
|
||||
|
||||
# Checking referrers query agreement
|
||||
busyboxStore=$(nix store --store $storeA add-path $busybox)
|
||||
[[ \
|
||||
$(nix-store --store $storeA --query --referrers $busyboxStore) \
|
||||
== \
|
||||
$(nix-store --store $storeB --query --referrers $busyboxStore) \
|
||||
]]
|
||||
|
||||
# Checking derivers query agreement
|
||||
[[ \
|
||||
$(nix-store --store $storeA --query --deriver $pathInLowerStore) \
|
||||
== \
|
||||
$(nix-store --store $storeB --query --deriver $pathInLowerStore) \
|
||||
]]
|
||||
|
||||
# Checking outputs query agreement
|
||||
[[ \
|
||||
$(nix-store --store $storeA --query --outputs $drvPath) \
|
||||
== \
|
||||
$(nix-store --store $storeB --query --outputs $drvPath) \
|
||||
]]
|
||||
|
||||
# Verifying path in lower layer
|
||||
nix-store --verify-path --store "$storeA" "$pathInLowerStore"
|
||||
|
||||
# Verifying path in merged-store
|
||||
nix-store --verify-path --store "$storeB" "$pathInLowerStore"
|
||||
|
||||
hashPart=$(echo $pathInLowerStore | sed "s^${NIX_STORE_DIR:-/nix/store}/^^" | sed 's/-.*//')
|
||||
|
||||
# Lower store can find from hash part
|
||||
[[ $(nix store --store $storeA path-from-hash-part $hashPart) == $pathInLowerStore ]]
|
||||
|
||||
# merged store can find from hash part
|
||||
[[ $(nix store --store $storeB path-from-hash-part $hashPart) == $pathInLowerStore ]]
|
5
tests/functional/local-overlay-store/check-post-init.sh
Executable file
5
tests/functional/local-overlay-store/check-post-init.sh
Executable file
|
@ -0,0 +1,5 @@
|
|||
source common.sh
|
||||
|
||||
requireEnvironment
|
||||
setupConfig
|
||||
execUnshare ./check-post-init-inner.sh
|
106
tests/functional/local-overlay-store/common.sh
Normal file
106
tests/functional/local-overlay-store/common.sh
Normal file
|
@ -0,0 +1,106 @@
|
|||
source ../common.sh
|
||||
|
||||
# The new Linux mount interface does not seem to support remounting
|
||||
# OverlayFS mount points.
|
||||
#
|
||||
# It is not clear whether this is intentional or not:
|
||||
#
|
||||
# The kernel source code [1] would seem to indicate merely remounting
|
||||
# while *changing* mount options is now an error because it erroneously
|
||||
# succeeded (by ignoring those new options) before. However, we are
|
||||
# *not* trying to remount with changed options, and are still hitting
|
||||
# the failure when using the new interface.
|
||||
#
|
||||
# For further details, see these `util-linux` issues:
|
||||
#
|
||||
# - https://github.com/util-linux/util-linux/issues/2528
|
||||
# - https://github.com/util-linux/util-linux/issues/2576
|
||||
#
|
||||
# In the meantime, setting this environment variable to "always" will
|
||||
# force the use of the old mount interface, keeping the remounting
|
||||
# working and these tests passing.
|
||||
#
|
||||
# [1]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/fs/overlayfs/params.c?id=3006adf3be79cde4d14b1800b963b82b6e5572e0#n549
|
||||
export LIBMOUNT_FORCE_MOUNT2=always
|
||||
|
||||
requireEnvironment () {
|
||||
requireSandboxSupport
|
||||
[[ $busybox =~ busybox ]] || skipTest "no busybox"
|
||||
if [[ $(uname) != Linux ]]; then skipTest "Need Linux for overlayfs"; fi
|
||||
needLocalStore "The test uses --store always so we would just be bypassing the daemon"
|
||||
}
|
||||
|
||||
addConfig () {
|
||||
echo "$1" >> "$NIX_CONF_DIR/nix.conf"
|
||||
}
|
||||
|
||||
setupConfig () {
|
||||
addConfig "require-drop-supplementary-groups = false"
|
||||
addConfig "build-users-group = "
|
||||
}
|
||||
|
||||
enableFeatures "local-overlay-store"
|
||||
|
||||
setupStoreDirs () {
|
||||
# Attempt to create store dirs on tmpfs volume.
|
||||
# This ensures lowerdir, upperdir and workdir will be on
|
||||
# a consistent filesystem that fully supports OverlayFS.
|
||||
storeVolume="$TEST_ROOT/stores"
|
||||
mkdir -p "$storeVolume"
|
||||
mount -t tmpfs tmpfs "$storeVolume" || true # But continue anyway if that fails.
|
||||
|
||||
storeA="$storeVolume/store-a"
|
||||
storeBTop="$storeVolume/store-b"
|
||||
storeBRoot="$storeVolume/merged-store"
|
||||
storeB="local-overlay://?root=$storeBRoot&lower-store=$storeA&upper-layer=$storeBTop"
|
||||
# Creating testing directories
|
||||
mkdir -p "$storeVolume"/{store-a/nix/store,store-b,merged-store/nix/store,workdir}
|
||||
}
|
||||
|
||||
# Mounting Overlay Store
|
||||
mountOverlayfs () {
|
||||
mount -t overlay overlay \
|
||||
-o lowerdir="$storeA/nix/store" \
|
||||
-o upperdir="$storeBTop" \
|
||||
-o workdir="$storeVolume/workdir" \
|
||||
"$storeBRoot/nix/store" \
|
||||
|| skipTest "overlayfs is not supported"
|
||||
|
||||
cleanupOverlay () {
|
||||
umount "$storeBRoot/nix/store"
|
||||
rm -r $storeVolume/workdir
|
||||
}
|
||||
trap cleanupOverlay EXIT
|
||||
}
|
||||
|
||||
remountOverlayfs () {
|
||||
mount -o remount "$storeBRoot/nix/store"
|
||||
}
|
||||
|
||||
toRealPath () {
|
||||
storeDir=$1; shift
|
||||
storePath=$1; shift
|
||||
echo $storeDir$(echo $storePath | sed "s^${NIX_STORE_DIR:-/nix/store}^^")
|
||||
}
|
||||
|
||||
initLowerStore () {
|
||||
# Init lower store with some stuff
|
||||
nix-store --store "$storeA" --add ../dummy
|
||||
|
||||
# Build something in lower store
|
||||
drvPath=$(nix-instantiate --store $storeA ../hermetic.nix --arg withFinalRefs true --arg busybox "$busybox" --arg seed 1)
|
||||
pathInLowerStore=$(nix-store --store "$storeA" --realise $drvPath)
|
||||
}
|
||||
|
||||
execUnshare () {
|
||||
exec unshare --mount --map-root-user "$SHELL" "$@"
|
||||
}
|
||||
|
||||
addTextToStore() {
|
||||
storeDir=$1; shift
|
||||
filename=$1; shift
|
||||
content=$1; shift
|
||||
filePath="$TEST_HOME/$filename"
|
||||
echo "$content" > "$filePath"
|
||||
nix-store --store "$storeDir" --add "$filePath"
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
set -x
|
||||
|
||||
source common.sh
|
||||
|
||||
# Avoid store dir being inside sandbox build-dir
|
||||
unset NIX_STORE_DIR
|
||||
unset NIX_STATE_DIR
|
||||
|
||||
setupStoreDirs
|
||||
|
||||
initLowerStore
|
||||
|
||||
mountOverlayfs
|
||||
|
||||
# Add to overlay before lower to ensure file is duplicated
|
||||
upperPath=$(nix-store --store "$storeB" --add delete-duplicate.sh)
|
||||
lowerPath=$(nix-store --store "$storeA" --add delete-duplicate.sh)
|
||||
[[ "$upperPath" = "$lowerPath" ]]
|
||||
|
||||
# Check there really are two files with different inodes
|
||||
upperInode=$(stat -c %i "$storeBRoot/$upperPath")
|
||||
lowerInode=$(stat -c %i "$storeA/$lowerPath")
|
||||
[[ "$upperInode" != "$lowerInode" ]]
|
||||
|
||||
# Now delete file via the overlay store
|
||||
nix-store --store "$storeB&remount-hook=$PWD/remount.sh" --delete "$upperPath"
|
||||
|
||||
# Check there is no longer a file in upper layer
|
||||
expect 1 stat "$storeBTop/${upperPath##/nix/store/}"
|
||||
|
||||
# Check that overlay file is now the one in lower layer
|
||||
upperInode=$(stat -c %i "$storeBRoot/$upperPath")
|
||||
lowerInode=$(stat -c %i "$storeA/$lowerPath")
|
||||
[[ "$upperInode" = "$lowerInode" ]]
|
5
tests/functional/local-overlay-store/delete-duplicate.sh
Normal file
5
tests/functional/local-overlay-store/delete-duplicate.sh
Normal file
|
@ -0,0 +1,5 @@
|
|||
source common.sh
|
||||
|
||||
requireEnvironment
|
||||
setupConfig
|
||||
execUnshare ./delete-duplicate-inner.sh
|
39
tests/functional/local-overlay-store/delete-refs-inner.sh
Normal file
39
tests/functional/local-overlay-store/delete-refs-inner.sh
Normal file
|
@ -0,0 +1,39 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
source common.sh
|
||||
|
||||
# Avoid store dir being inside sandbox build-dir
|
||||
unset NIX_STORE_DIR
|
||||
unset NIX_STATE_DIR
|
||||
|
||||
setupStoreDirs
|
||||
|
||||
initLowerStore
|
||||
|
||||
mountOverlayfs
|
||||
|
||||
export NIX_REMOTE="$storeB"
|
||||
stateB="$storeBRoot/nix/var/nix"
|
||||
hermetic=$(nix-build ../hermetic.nix --no-out-link --arg busybox "$busybox" --arg withFinalRefs true --arg seed 2)
|
||||
input1=$(nix-build ../hermetic.nix --no-out-link --arg busybox "$busybox" --arg withFinalRefs true --arg seed 2 -A passthru.input1 -j0)
|
||||
input2=$(nix-build ../hermetic.nix --no-out-link --arg busybox "$busybox" --arg withFinalRefs true --arg seed 2 -A passthru.input2 -j0)
|
||||
input3=$(nix-build ../hermetic.nix --no-out-link --arg busybox "$busybox" --arg withFinalRefs true --arg seed 2 -A passthru.input3 -j0)
|
||||
|
||||
# Can't delete because referenced
|
||||
expectStderr 1 nix-store --delete $input1 | grepQuiet "Cannot delete path"
|
||||
expectStderr 1 nix-store --delete $input2 | grepQuiet "Cannot delete path"
|
||||
expectStderr 1 nix-store --delete $input3 | grepQuiet "Cannot delete path"
|
||||
|
||||
# These same paths are referenced in the lower layer (by the seed 1
|
||||
# build done in `initLowerStore`).
|
||||
expectStderr 1 nix-store --store "$storeA" --delete $input2 | grepQuiet "Cannot delete path"
|
||||
expectStderr 1 nix-store --store "$storeA" --delete $input3 | grepQuiet "Cannot delete path"
|
||||
|
||||
# Can delete
|
||||
nix-store --delete $hermetic
|
||||
|
||||
# Now unreferenced in upper layer, can delete
|
||||
nix-store --delete $input3
|
||||
nix-store --delete $input2
|
5
tests/functional/local-overlay-store/delete-refs.sh
Executable file
5
tests/functional/local-overlay-store/delete-refs.sh
Executable file
|
@ -0,0 +1,5 @@
|
|||
source common.sh
|
||||
|
||||
requireEnvironment
|
||||
setupConfig
|
||||
execUnshare ./delete-refs-inner.sh
|
57
tests/functional/local-overlay-store/gc-inner.sh
Normal file
57
tests/functional/local-overlay-store/gc-inner.sh
Normal file
|
@ -0,0 +1,57 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
source common.sh
|
||||
|
||||
# Avoid store dir being inside sandbox build-dir
|
||||
unset NIX_STORE_DIR
|
||||
unset NIX_STATE_DIR
|
||||
|
||||
setupStoreDirs
|
||||
|
||||
initLowerStore
|
||||
|
||||
mountOverlayfs
|
||||
|
||||
export NIX_REMOTE="$storeB"
|
||||
stateB="$storeBRoot/nix/var/nix"
|
||||
outPath=$(nix-build ../hermetic.nix --no-out-link --arg busybox "$busybox" --arg seed 2)
|
||||
|
||||
# Set a GC root.
|
||||
mkdir -p "$stateB"
|
||||
rm -f "$stateB"/gcroots/foo
|
||||
ln -sf $outPath "$stateB"/gcroots/foo
|
||||
|
||||
[ "$(nix-store -q --roots $outPath)" = "$stateB/gcroots/foo -> $outPath" ]
|
||||
|
||||
nix-store --gc --print-roots | grep $outPath
|
||||
nix-store --gc --print-live | grep $outPath
|
||||
if nix-store --gc --print-dead | grep -E $outPath$; then false; fi
|
||||
|
||||
nix-store --gc --print-dead
|
||||
|
||||
expect 1 nix-store --delete $outPath
|
||||
test -e "$storeBRoot/$outPath"
|
||||
|
||||
shopt -s nullglob
|
||||
for i in $storeBRoot/*; do
|
||||
if [[ $i =~ /trash ]]; then continue; fi # compat with old daemon
|
||||
touch $i.lock
|
||||
touch $i.chroot
|
||||
done
|
||||
|
||||
nix-collect-garbage
|
||||
|
||||
# Check that the root and its dependencies haven't been deleted.
|
||||
cat "$storeBRoot/$outPath"
|
||||
|
||||
rm "$stateB"/gcroots/foo
|
||||
|
||||
nix-collect-garbage
|
||||
|
||||
# Check that the output has been GC'd.
|
||||
test ! -e $outPath
|
||||
|
||||
# Check that the store is empty.
|
||||
[ "$(ls -1 "$storeBTop" | wc -l)" = "0" ]
|
5
tests/functional/local-overlay-store/gc.sh
Executable file
5
tests/functional/local-overlay-store/gc.sh
Executable file
|
@ -0,0 +1,5 @@
|
|||
source common.sh
|
||||
|
||||
requireEnvironment
|
||||
setupConfig
|
||||
execUnshare ./gc-inner.sh
|
14
tests/functional/local-overlay-store/local.mk
Normal file
14
tests/functional/local-overlay-store/local.mk
Normal file
|
@ -0,0 +1,14 @@
|
|||
local-overlay-store-tests := \
|
||||
$(d)/check-post-init.sh \
|
||||
$(d)/redundant-add.sh \
|
||||
$(d)/build.sh \
|
||||
$(d)/bad-uris.sh \
|
||||
$(d)/add-lower.sh \
|
||||
$(d)/delete-refs.sh \
|
||||
$(d)/delete-duplicate.sh \
|
||||
$(d)/gc.sh \
|
||||
$(d)/verify.sh \
|
||||
$(d)/optimise.sh \
|
||||
$(d)/stale-file-handle.sh
|
||||
|
||||
install-tests-groups += local-overlay-store
|
51
tests/functional/local-overlay-store/optimise-inner.sh
Executable file
51
tests/functional/local-overlay-store/optimise-inner.sh
Executable file
|
@ -0,0 +1,51 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
set -x
|
||||
|
||||
source common.sh
|
||||
|
||||
# Avoid store dir being inside sandbox build-dir
|
||||
unset NIX_STORE_DIR
|
||||
unset NIX_STATE_DIR
|
||||
|
||||
setupStoreDirs
|
||||
|
||||
initLowerStore
|
||||
|
||||
mountOverlayfs
|
||||
|
||||
# Create a file to add to store
|
||||
dupFilePath="$TEST_ROOT/dup-file"
|
||||
echo Duplicate > "$dupFilePath"
|
||||
|
||||
# Add it to the overlay store (it will be written to the upper layer)
|
||||
dupFileStorePath=$(nix-store --store "$storeB" --add "$dupFilePath")
|
||||
|
||||
# Now add it to the lower store so the store path is duplicated
|
||||
nix-store --store "$storeA" --add "$dupFilePath"
|
||||
|
||||
# Ensure overlayfs and layers and synchronised
|
||||
remountOverlayfs
|
||||
|
||||
dupFilename="${dupFileStorePath#/nix/store}"
|
||||
lowerPath="$storeA/$dupFileStorePath"
|
||||
upperPath="$storeBTop/$dupFilename"
|
||||
overlayPath="$storeBRoot/nix/store/$dupFilename"
|
||||
|
||||
# Check store path exists in both layers and overlay
|
||||
lowerInode=$(stat -c %i "$lowerPath")
|
||||
upperInode=$(stat -c %i "$upperPath")
|
||||
overlayInode=$(stat -c %i "$overlayPath")
|
||||
[[ $upperInode == $overlayInode ]]
|
||||
[[ $upperInode != $lowerInode ]]
|
||||
|
||||
# Run optimise to deduplicate store paths
|
||||
nix-store --store "$storeB" --optimise
|
||||
remountOverlayfs
|
||||
|
||||
# Check path only exists in lower store
|
||||
stat "$lowerPath"
|
||||
stat "$overlayPath"
|
||||
expect 1 stat "$upperPath"
|
5
tests/functional/local-overlay-store/optimise.sh
Executable file
5
tests/functional/local-overlay-store/optimise.sh
Executable file
|
@ -0,0 +1,5 @@
|
|||
source common.sh
|
||||
|
||||
requireEnvironment
|
||||
setupConfig
|
||||
execUnshare ./optimise-inner.sh
|
35
tests/functional/local-overlay-store/redundant-add-inner.sh
Executable file
35
tests/functional/local-overlay-store/redundant-add-inner.sh
Executable file
|
@ -0,0 +1,35 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
set -x
|
||||
|
||||
source common.sh
|
||||
|
||||
# Avoid store dir being inside sandbox build-dir
|
||||
unset NIX_STORE_DIR
|
||||
unset NIX_STATE_DIR
|
||||
|
||||
setupStoreDirs
|
||||
|
||||
initLowerStore
|
||||
|
||||
mountOverlayfs
|
||||
|
||||
### Do a redundant add
|
||||
|
||||
# (Already done in `initLowerStore`, but repeated here for clarity.)
|
||||
pathInLowerStore=$(nix-store --store "$storeA" --add ../dummy)
|
||||
|
||||
# upper layer should not have it
|
||||
expect 1 stat $(toRealPath "$storeBTop/nix/store" "$pathInLowerStore")
|
||||
|
||||
pathFromB=$(nix-store --store "$storeB" --add ../dummy)
|
||||
|
||||
[[ $pathInLowerStore == $pathFromB ]]
|
||||
|
||||
# lower store should have it from before
|
||||
stat $(toRealPath "$storeA/nix/store" "$pathInLowerStore")
|
||||
|
||||
# upper layer should still not have it (no redundant copy)
|
||||
expect 1 stat $(toRealPath "$storeBTop" "$pathInLowerStore")
|
5
tests/functional/local-overlay-store/redundant-add.sh
Executable file
5
tests/functional/local-overlay-store/redundant-add.sh
Executable file
|
@ -0,0 +1,5 @@
|
|||
source common.sh
|
||||
|
||||
requireEnvironment
|
||||
setupConfig
|
||||
execUnshare ./redundant-add-inner.sh
|
2
tests/functional/local-overlay-store/remount.sh
Executable file
2
tests/functional/local-overlay-store/remount.sh
Executable file
|
@ -0,0 +1,2 @@
|
|||
#!/bin/sh
|
||||
mount -o remount "$1"
|
47
tests/functional/local-overlay-store/stale-file-handle-inner.sh
Executable file
47
tests/functional/local-overlay-store/stale-file-handle-inner.sh
Executable file
|
@ -0,0 +1,47 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
set -x
|
||||
|
||||
source common.sh
|
||||
|
||||
# Avoid store dir being inside sandbox build-dir
|
||||
unset NIX_STORE_DIR
|
||||
unset NIX_STATE_DIR
|
||||
|
||||
setupStoreDirs
|
||||
|
||||
initLowerStore
|
||||
|
||||
mountOverlayfs
|
||||
|
||||
buildInStore () {
|
||||
nix-build --store "$1" ../hermetic.nix --arg busybox "$busybox" --arg seed 1 --no-out-link
|
||||
}
|
||||
|
||||
triggerStaleFileHandle () {
|
||||
# Arrange it so there are duplicate paths
|
||||
nix-store --store "$storeA" --gc # Clear lower store
|
||||
buildInStore "$storeB" # Build into upper layer first
|
||||
buildInStore "$storeA" # Then build in lower store
|
||||
|
||||
# Duplicate paths mean GC will have to delete via upper layer
|
||||
nix-store --store "$storeB" --gc
|
||||
|
||||
# Clear lower store again to force building in upper layer
|
||||
nix-store --store "$storeA" --gc
|
||||
|
||||
# Now attempting to build in upper layer will fail
|
||||
buildInStore "$storeB"
|
||||
}
|
||||
|
||||
# Without remounting, we should encounter errors
|
||||
expectStderr 1 triggerStaleFileHandle | grepQuiet 'Stale file handle'
|
||||
|
||||
# Configure remount-hook and reset OverlayFS
|
||||
storeB="$storeB&remount-hook=$PWD/remount.sh"
|
||||
remountOverlayfs
|
||||
|
||||
# Now it should succeed
|
||||
triggerStaleFileHandle
|
5
tests/functional/local-overlay-store/stale-file-handle.sh
Executable file
5
tests/functional/local-overlay-store/stale-file-handle.sh
Executable file
|
@ -0,0 +1,5 @@
|
|||
source common.sh
|
||||
|
||||
requireEnvironment
|
||||
setupConfig
|
||||
execUnshare ./stale-file-handle-inner.sh
|
69
tests/functional/local-overlay-store/verify-inner.sh
Executable file
69
tests/functional/local-overlay-store/verify-inner.sh
Executable file
|
@ -0,0 +1,69 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
set -x
|
||||
|
||||
source common.sh
|
||||
|
||||
# Avoid store dir being inside sandbox build-dir
|
||||
unset NIX_STORE_DIR
|
||||
unset NIX_STATE_DIR
|
||||
|
||||
setupStoreDirs
|
||||
|
||||
initLowerStore
|
||||
|
||||
mountOverlayfs
|
||||
|
||||
|
||||
## Initialise stores for test
|
||||
|
||||
# Realise a derivation from the lower store to propagate paths to overlay DB
|
||||
nix-store --store "$storeB" --realise $drvPath
|
||||
|
||||
# Also ensure dummy file exists in overlay DB
|
||||
dummyPath=$(nix-store --store "$storeB" --add ../dummy)
|
||||
|
||||
# Add something to the lower store that will not be propagated to overlay DB
|
||||
lowerOnlyPath=$(addTextToStore "$storeA" lower-only "Only in lower store")
|
||||
|
||||
# Verify should be successful at this point
|
||||
nix-store --store "$storeB" --verify --check-contents
|
||||
|
||||
# Make a backup so we can repair later
|
||||
backupStore="$storeVolume/backup"
|
||||
mkdir "$backupStore"
|
||||
cp -ar "$storeBRoot/nix" "$backupStore"
|
||||
|
||||
|
||||
## Deliberately corrupt store paths
|
||||
|
||||
# Delete one of the derivation inputs in the lower store
|
||||
inputDrvFullPath=$(find "$storeA" -name "*-hermetic-input-1.drv")
|
||||
inputDrvPath=${inputDrvFullPath/*\/nix\/store\///nix/store/}
|
||||
rm -v "$inputDrvFullPath"
|
||||
|
||||
# Truncate the contents of dummy file in lower store
|
||||
find "$storeA" -name "*-dummy" -exec truncate -s 0 {} \;
|
||||
|
||||
# Also truncate the file that only exists in lower store
|
||||
truncate -s 0 "$storeA/$lowerOnlyPath"
|
||||
|
||||
# Ensure overlayfs is synchronised
|
||||
remountOverlayfs
|
||||
|
||||
|
||||
## Now test that verify and repair work as expected
|
||||
|
||||
# Verify overlay store without attempting to repair it
|
||||
verifyOutput=$(expectStderr 1 nix-store --store "$storeB" --verify --check-contents)
|
||||
<<<"$verifyOutput" grepQuiet "path '$inputDrvPath' disappeared, but it still has valid referrers!"
|
||||
<<<"$verifyOutput" grepQuiet "path '$dummyPath' was modified! expected hash"
|
||||
<<<"$verifyOutput" expectStderr 1 grepQuiet "$lowerOnlyPath" # Expect no error for corrupted lower-only path
|
||||
|
||||
# Attempt to repair using backup
|
||||
addConfig "substituters = $backupStore"
|
||||
repairOutput=$(nix-store --store "$storeB" --verify --check-contents --repair 2>&1)
|
||||
<<<"$repairOutput" grepQuiet "copying path '$inputDrvPath'"
|
||||
<<<"$repairOutput" grepQuiet "copying path '$dummyPath'"
|
5
tests/functional/local-overlay-store/verify.sh
Executable file
5
tests/functional/local-overlay-store/verify.sh
Executable file
|
@ -0,0 +1,5 @@
|
|||
source common.sh
|
||||
|
||||
requireEnvironment
|
||||
setupConfig
|
||||
execUnshare ./verify-inner.sh
|
|
@ -1,22 +0,0 @@
|
|||
source common.sh
|
||||
|
||||
cd $TEST_ROOT
|
||||
|
||||
echo example > example.txt
|
||||
mkdir -p ./x
|
||||
|
||||
NIX_STORE_DIR=$TEST_ROOT/x
|
||||
|
||||
CORRECT_PATH=$(nix-store --store ./x --add example.txt)
|
||||
|
||||
PATH1=$(nix path-info --store ./x $CORRECT_PATH)
|
||||
[ $CORRECT_PATH == $PATH1 ]
|
||||
|
||||
PATH2=$(nix path-info --store "$PWD/x" $CORRECT_PATH)
|
||||
[ $CORRECT_PATH == $PATH2 ]
|
||||
|
||||
PATH3=$(nix path-info --store "local?root=$PWD/x" $CORRECT_PATH)
|
||||
[ $CORRECT_PATH == $PATH3 ]
|
||||
|
||||
# Ensure store info trusted works with local store
|
||||
nix --store ./x store info --json | jq -e '.trusted'
|
|
@ -83,7 +83,7 @@ nix_tests = \
|
|||
export.sh \
|
||||
config.sh \
|
||||
add.sh \
|
||||
local-store.sh \
|
||||
chroot-store.sh \
|
||||
filter-source.sh \
|
||||
misc.sh \
|
||||
dump-db.sh \
|
||||
|
|
|
@ -8,4 +8,4 @@ libplugintest_ALLOW_UNDEFINED := 1
|
|||
|
||||
libplugintest_EXCLUDE_FROM_LIBRARY_LIST := 1
|
||||
|
||||
libplugintest_CXXFLAGS := -I src/libutil -I src/libstore -I src/libexpr -I src/libfetchers
|
||||
libplugintest_CXXFLAGS := $(INCLUDE_libutil) $(INCLUDE_libstore) $(INCLUDE_libexpr) $(INCLUDE_libfetchers)
|
||||
|
|
|
@ -13,6 +13,8 @@ startDaemon
|
|||
if isDaemonNewer "2.15pre0"; then
|
||||
# Ensure that ping works trusted with new daemon
|
||||
nix store info --json | jq -e '.trusted'
|
||||
# Suppress grumpiness about multiple nixes on PATH
|
||||
(nix doctor || true) 2>&1 | grep 'You are trusted by'
|
||||
else
|
||||
# And the the field is absent with the old daemon
|
||||
nix store info --json | jq -e 'has("trusted") | not'
|
||||
|
|
|
@ -47,6 +47,9 @@ testRepl () {
|
|||
| grep "attribute 'currentSystem' missing"
|
||||
nix repl "${nixArgs[@]}" 2>&1 <<< "builtins.currentSystem" \
|
||||
| grep "$(nix-instantiate --eval -E 'builtins.currentSystem')"
|
||||
|
||||
expectStderr 1 nix repl ${testDir}/simple.nix \
|
||||
| grepQuiet -s "error: path '$testDir/simple.nix' is not a flake"
|
||||
}
|
||||
|
||||
# Simple test, try building a drv
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
with import ./config.nix;
|
||||
|
||||
{
|
||||
rec {
|
||||
hello = mkDerivation {
|
||||
name = "hello";
|
||||
outputs = [ "out" "dev" ];
|
||||
|
@ -24,6 +24,22 @@ with import ./config.nix;
|
|||
'';
|
||||
};
|
||||
|
||||
hello-symlink = mkDerivation {
|
||||
name = "hello-symlink";
|
||||
buildCommand =
|
||||
''
|
||||
ln -s ${hello} $out
|
||||
'';
|
||||
};
|
||||
|
||||
forbidden-symlink = mkDerivation {
|
||||
name = "forbidden-symlink";
|
||||
buildCommand =
|
||||
''
|
||||
ln -s /tmp/foo/bar $out
|
||||
'';
|
||||
};
|
||||
|
||||
salve-mundi = mkDerivation {
|
||||
name = "salve-mundi";
|
||||
outputs = [ "out" ];
|
||||
|
|
|
@ -21,14 +21,6 @@ let pkgs = rec {
|
|||
export PATH=$PATH:$pkg/bin
|
||||
done
|
||||
|
||||
# mimic behavior of stdenv for `$out` etc. for structured attrs.
|
||||
if [ -n "''${NIX_ATTRS_SH_FILE}" ]; then
|
||||
for o in "''${!outputs[@]}"; do
|
||||
eval "''${o}=''${outputs[$o]}"
|
||||
export "''${o}"
|
||||
done
|
||||
fi
|
||||
|
||||
declare -a arr1=(1 2 "3 4" 5)
|
||||
declare -a arr2=(x $'\n' $'x\ny')
|
||||
fun() {
|
||||
|
|
|
@ -10,6 +10,11 @@ nix shell -f shell-hello.nix hello -c hello NixOS | grep 'Hello NixOS'
|
|||
nix shell -f shell-hello.nix hello^dev -c hello2 | grep 'Hello2'
|
||||
nix shell -f shell-hello.nix 'hello^*' -c hello2 | grep 'Hello2'
|
||||
|
||||
# Test output paths that are a symlink.
|
||||
nix shell -f shell-hello.nix hello-symlink -c hello | grep 'Hello World'
|
||||
|
||||
# Test that symlinks outside of the store don't work.
|
||||
expect 1 nix shell -f shell-hello.nix forbidden-symlink -c hello 2>&1 | grepQuiet "is not in the Nix store"
|
||||
|
||||
if isDaemonNewer "2.20.0pre20231220"; then
|
||||
# Test that command line attribute ordering is reflected in the PATH
|
||||
|
|
|
@ -32,4 +32,4 @@ jsonOut="$(nix print-dev-env -f structured-attrs-shell.nix --json)"
|
|||
|
||||
test "$(<<<"$jsonOut" jq '.structuredAttrs|keys|.[]' -r)" = "$(printf ".attrs.json\n.attrs.sh")"
|
||||
|
||||
test "$(<<<"$jsonOut" jq '.variables.out.value' -r)" = "$(<<<"$jsonOut" jq '.structuredAttrs.".attrs.json"' -r | jq -r '.outputs.out')"
|
||||
test "$(<<<"$jsonOut" jq '.variables.outputs.value.out' -r)" = "$(<<<"$jsonOut" jq '.structuredAttrs.".attrs.json"' -r | jq -r '.outputs.out')"
|
||||
|
|
59
tests/functional/symlink-derivation.nix
Normal file
59
tests/functional/symlink-derivation.nix
Normal file
|
@ -0,0 +1,59 @@
|
|||
with import ./config.nix;
|
||||
|
||||
let
|
||||
foo_in_store = builtins.toFile "foo" "foo";
|
||||
foo_symlink = mkDerivation {
|
||||
name = "foo-symlink";
|
||||
buildCommand = ''
|
||||
ln -s ${foo_in_store} $out
|
||||
'';
|
||||
};
|
||||
symlink_to_not_in_store = mkDerivation {
|
||||
name = "symlink-to-not-in-store";
|
||||
buildCommand = ''
|
||||
ln -s ${builtins.toString ./.} $out
|
||||
'';
|
||||
};
|
||||
in
|
||||
{
|
||||
depends_on_symlink = mkDerivation {
|
||||
name = "depends-on-symlink";
|
||||
buildCommand = ''
|
||||
(
|
||||
set -x
|
||||
|
||||
# `foo_symlink` should be a symlink pointing to `foo_in_store`
|
||||
[[ -L ${foo_symlink} ]]
|
||||
[[ $(readlink ${foo_symlink}) == ${foo_in_store} ]]
|
||||
|
||||
# `symlink_to_not_in_store` should be a symlink pointing to `./.`, which
|
||||
# is not available in the sandbox
|
||||
[[ -L ${symlink_to_not_in_store} ]]
|
||||
[[ $(readlink ${symlink_to_not_in_store}) == ${builtins.toString ./.} ]]
|
||||
(! ls ${symlink_to_not_in_store}/)
|
||||
|
||||
# Native paths
|
||||
)
|
||||
echo "Success!" > $out
|
||||
'';
|
||||
};
|
||||
|
||||
test_sandbox_paths = mkDerivation {
|
||||
# Depends on the caller to set a bunch of `--sandbox-path` arguments
|
||||
name = "test-sandbox-paths";
|
||||
buildCommand = ''
|
||||
(
|
||||
set -x
|
||||
[[ -f /file ]]
|
||||
[[ -d /dir ]]
|
||||
|
||||
# /symlink and /symlinkDir should be available as raw symlinks
|
||||
# (pointing to files outside of the sandbox)
|
||||
[[ -L /symlink ]] && [[ ! -e $(readlink /symlink) ]]
|
||||
[[ -L /symlinkDir ]] && [[ ! -e $(readlink /symlinkDir) ]]
|
||||
)
|
||||
|
||||
touch $out
|
||||
'';
|
||||
};
|
||||
}
|
|
@ -8,7 +8,7 @@ test-libstoreconsumer_INSTALL_DIR :=
|
|||
test-libstoreconsumer_SOURCES := \
|
||||
$(wildcard $(d)/*.cc) \
|
||||
|
||||
test-libstoreconsumer_CXXFLAGS += -I src/libutil -I src/libstore
|
||||
test-libstoreconsumer_CXXFLAGS += $(INCLUDE_libutil) $(INCLUDE_libstore)
|
||||
|
||||
test-libstoreconsumer_LIBS = libstore libutil
|
||||
|
||||
|
|
|
@ -189,3 +189,9 @@ nix-env --set $outPath10
|
|||
[ "$(nix-store -q --resolve $profiles/test)" = $outPath10 ]
|
||||
nix-env --set $drvPath10
|
||||
[ "$(nix-store -q --resolve $profiles/test)" = $outPath10 ]
|
||||
|
||||
# Test the case where $HOME contains a symlink.
|
||||
mkdir -p $TEST_ROOT/real-home/alice/.nix-defexpr/channels
|
||||
ln -sfn $TEST_ROOT/real-home $TEST_ROOT/home
|
||||
ln -sfn $(pwd)/user-envs.nix $TEST_ROOT/home/alice/.nix-defexpr/channels/foo
|
||||
HOME=$TEST_ROOT/home/alice nix-env -i foo-0.1
|
||||
|
|
|
@ -145,6 +145,8 @@ in
|
|||
|
||||
githubFlakes = runNixOSTestFor "x86_64-linux" ./github-flakes.nix;
|
||||
|
||||
gitSubmodules = runNixOSTestFor "x86_64-linux" ./git-submodules.nix;
|
||||
|
||||
sourcehutFlakes = runNixOSTestFor "x86_64-linux" ./sourcehut-flakes.nix;
|
||||
|
||||
tarballFlakes = runNixOSTestFor "x86_64-linux" ./tarball-flakes.nix;
|
||||
|
@ -158,4 +160,6 @@ in
|
|||
fetch-git = runNixOSTestFor "x86_64-linux" ./fetch-git;
|
||||
|
||||
ca-fd-leak = runNixOSTestFor "x86_64-linux" ./ca-fd-leak;
|
||||
|
||||
gzip-content-encoding = runNixOSTestFor "x86_64-linux" ./gzip-content-encoding.nix;
|
||||
}
|
||||
|
|
70
tests/nixos/git-submodules.nix
Normal file
70
tests/nixos/git-submodules.nix
Normal file
|
@ -0,0 +1,70 @@
|
|||
# Test Nix's remote build feature.
|
||||
|
||||
{ lib, hostPkgs, ... }:
|
||||
|
||||
{
|
||||
config = {
|
||||
name = lib.mkDefault "git-submodules";
|
||||
|
||||
nodes =
|
||||
{
|
||||
remote =
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
services.openssh.enable = true;
|
||||
environment.systemPackages = [ pkgs.git ];
|
||||
};
|
||||
|
||||
client =
|
||||
{ config, lib, pkgs, ... }:
|
||||
{
|
||||
programs.ssh.extraConfig = "ConnectTimeout 30";
|
||||
environment.systemPackages = [ pkgs.git ];
|
||||
nix.extraOptions = "experimental-features = nix-command flakes";
|
||||
};
|
||||
};
|
||||
|
||||
testScript = { nodes }: ''
|
||||
# fmt: off
|
||||
import subprocess
|
||||
|
||||
start_all()
|
||||
|
||||
# Create an SSH key on the client.
|
||||
subprocess.run([
|
||||
"${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")
|
||||
client.succeed("chmod 600 /root/.ssh/id_ed25519")
|
||||
|
||||
# Install the SSH key on the builders.
|
||||
client.wait_for_unit("network.target")
|
||||
|
||||
remote.succeed("mkdir -p -m 700 /root/.ssh")
|
||||
remote.copy_from_host("key.pub", "/root/.ssh/authorized_keys")
|
||||
remote.wait_for_unit("sshd")
|
||||
client.succeed(f"ssh -o StrictHostKeyChecking=no {remote.name} 'echo hello world'")
|
||||
|
||||
remote.succeed("""
|
||||
git init bar
|
||||
git -C bar config user.email foobar@example.com
|
||||
git -C bar config user.name Foobar
|
||||
echo test >> bar/content
|
||||
git -C bar add content
|
||||
git -C bar commit -m 'Initial commit'
|
||||
""")
|
||||
|
||||
client.succeed(f"""
|
||||
git init foo
|
||||
git -C foo config user.email foobar@example.com
|
||||
git -C foo config user.name Foobar
|
||||
git -C foo submodule add root@{remote.name}:/tmp/bar sub
|
||||
git -C foo add sub
|
||||
git -C foo commit -m 'Add submodule'
|
||||
""")
|
||||
|
||||
client.succeed("nix --flake-registry \"\" flake prefetch 'git+file:///tmp/foo?submodules=1&ref=master'")
|
||||
'';
|
||||
};
|
||||
}
|
|
@ -187,9 +187,14 @@ in
|
|||
client.succeed("nix flake metadata nixpkgs --tarball-ttl 0 >&2")
|
||||
|
||||
# Test fetchTree on a github URL.
|
||||
hash = client.succeed(f"nix eval --raw --expr '(fetchTree {info['url']}).narHash'")
|
||||
hash = client.succeed(f"nix eval --no-trust-tarballs-from-git-forges --raw --expr '(fetchTree {info['url']}).narHash'")
|
||||
assert hash == info['locked']['narHash']
|
||||
|
||||
# Fetching without a narHash should succeed if trust-github is set and fail otherwise.
|
||||
client.succeed(f"nix eval --raw --expr 'builtins.fetchTree github:github:fancy-enterprise/private-flake/{info['revision']}'")
|
||||
out = client.fail(f"nix eval --no-trust-tarballs-from-git-forges --raw --expr 'builtins.fetchTree github:github:fancy-enterprise/private-flake/{info['revision']}' 2>&1")
|
||||
assert "will not fetch unlocked input" in out, "--no-trust-tarballs-from-git-forges did not fail with the expected error"
|
||||
|
||||
# Shut down the web server. The flake should be cached on the client.
|
||||
github.succeed("systemctl stop httpd.service")
|
||||
|
||||
|
|
71
tests/nixos/gzip-content-encoding.nix
Normal file
71
tests/nixos/gzip-content-encoding.nix
Normal file
|
@ -0,0 +1,71 @@
|
|||
# Test that compressed files fetched from server with compressed responses
|
||||
# do not get excessively decompressed.
|
||||
# E.g. fetching a zstd compressed tarball from a server,
|
||||
# which compresses the response with `Content-Encoding: gzip`.
|
||||
# The expected result is that the fetched file is a zstd archive.
|
||||
|
||||
{ lib, config, ... }:
|
||||
|
||||
let
|
||||
pkgs = config.nodes.machine.nixpkgs.pkgs;
|
||||
|
||||
ztdCompressedFile = pkgs.stdenv.mkDerivation {
|
||||
name = "dummy-zstd-compressed-archive";
|
||||
dontUnpack = true;
|
||||
nativeBuildInputs = with pkgs; [ zstd ];
|
||||
buildPhase = ''
|
||||
mkdir archive
|
||||
for _ in {1..100}; do echo "lorem" > archive/file1; done
|
||||
for _ in {1..100}; do echo "ipsum" > archive/file2; done
|
||||
tar --zstd -cf archive.tar.zst archive
|
||||
'';
|
||||
installPhase = ''
|
||||
install -Dm 644 -T archive.tar.zst $out/share/archive
|
||||
'';
|
||||
};
|
||||
|
||||
fileCmd = "${pkgs.file}/bin/file";
|
||||
in
|
||||
|
||||
{
|
||||
name = "gzip-content-encoding";
|
||||
|
||||
nodes =
|
||||
{ machine =
|
||||
{ config, pkgs, ... }:
|
||||
{ networking.firewall.allowedTCPPorts = [ 80 ];
|
||||
|
||||
services.nginx.enable = true;
|
||||
services.nginx.virtualHosts."localhost" =
|
||||
{ root = "${ztdCompressedFile}/share/";
|
||||
# Make sure that nginx really tries to compress the
|
||||
# file on the fly with no regard to size/mime.
|
||||
# http://nginx.org/en/docs/http/ngx_http_gzip_module.html
|
||||
extraConfig = ''
|
||||
gzip on;
|
||||
gzip_types *;
|
||||
gzip_proxied any;
|
||||
gzip_min_length 0;
|
||||
'';
|
||||
};
|
||||
virtualisation.writableStore = true;
|
||||
virtualisation.additionalPaths = with pkgs; [ file ];
|
||||
nix.settings.substituters = lib.mkForce [ ];
|
||||
};
|
||||
};
|
||||
|
||||
# Check that when nix-prefetch-url is used with a zst tarball it does not get decompressed.
|
||||
testScript = { nodes }: ''
|
||||
# fmt: off
|
||||
start_all()
|
||||
|
||||
machine.wait_for_unit("nginx.service")
|
||||
machine.succeed("""
|
||||
# Make sure that the file is properly compressed as the test would be meaningless otherwise
|
||||
curl --compressed -v http://localhost/archive |& tr -s ' ' |& grep --ignore-case 'content-encoding: gzip'
|
||||
archive_path=$(nix-prefetch-url http://localhost/archive --print-path | tail -n1)
|
||||
[[ $(${fileCmd} --brief --mime-type $archive_path) == "application/zstd" ]]
|
||||
tar --zstd -xf $archive_path
|
||||
""")
|
||||
'';
|
||||
}
|
31
tests/unit/libexpr-support/tests/nix_api_expr.hh
Normal file
31
tests/unit/libexpr-support/tests/nix_api_expr.hh
Normal file
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
///@file
|
||||
#include "nix_api_expr.h"
|
||||
#include "nix_api_value.h"
|
||||
#include "tests/nix_api_store.hh"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace nixC {
|
||||
|
||||
class nix_api_expr_test : public nix_api_store_test
|
||||
{
|
||||
protected:
|
||||
|
||||
nix_api_expr_test()
|
||||
{
|
||||
nix_libexpr_init(ctx);
|
||||
state = nix_state_create(nullptr, nullptr, store);
|
||||
value = nix_alloc_value(nullptr, state);
|
||||
}
|
||||
~nix_api_expr_test()
|
||||
{
|
||||
nix_gc_decref(nullptr, value);
|
||||
nix_state_free(state);
|
||||
}
|
||||
|
||||
EvalState * state;
|
||||
Value * value;
|
||||
};
|
||||
|
||||
}
|
|
@ -23,15 +23,18 @@ libexpr-tests_EXTRA_INCLUDES = \
|
|||
-I tests/unit/libexpr-support \
|
||||
-I tests/unit/libstore-support \
|
||||
-I tests/unit/libutil-support \
|
||||
-I src/libexpr \
|
||||
-I src/libfetchers \
|
||||
-I src/libstore \
|
||||
-I src/libutil
|
||||
$(INCLUDE_libexpr) \
|
||||
$(INCLUDE_libexprc) \
|
||||
$(INCLUDE_libfetchers) \
|
||||
$(INCLUDE_libstore) \
|
||||
$(INCLUDE_libstorec) \
|
||||
$(INCLUDE_libutil) \
|
||||
$(INCLUDE_libutilc)
|
||||
|
||||
libexpr-tests_CXXFLAGS += $(libexpr-tests_EXTRA_INCLUDES)
|
||||
|
||||
libexpr-tests_LIBS = \
|
||||
libexpr-test-support libstore-test-support libutils-test-support \
|
||||
libexpr libfetchers libstore libutil
|
||||
libexpr-test-support libstore-test-support libutil-test-support \
|
||||
libexpr libexprc libfetchers libstore libstorec libutil libutilc
|
||||
|
||||
libexpr-tests_LDFLAGS := -lrapidcheck $(GTEST_LIBS) -lgmock
|
||||
|
|
39
tests/unit/libexpr/main.cc
Normal file
39
tests/unit/libexpr/main.cc
Normal file
|
@ -0,0 +1,39 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <cstdlib>
|
||||
#include "globals.hh"
|
||||
#include "logging.hh"
|
||||
|
||||
using namespace nix;
|
||||
|
||||
int main (int argc, char **argv) {
|
||||
if (argc > 1 && std::string_view(argv[1]) == "__build-remote") {
|
||||
printError("test-build-remote: not supported in libexpr unit tests");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Disable build hook. We won't be testing remote builds in these unit tests. If we do, fix the above build hook.
|
||||
settings.buildHook = {};
|
||||
|
||||
#if __linux__ // should match the conditional around sandboxBuildDir declaration.
|
||||
|
||||
// When building and testing nix within the host's Nix sandbox, our store dir will be located in the host's sandboxBuildDir, e.g.:
|
||||
// Host
|
||||
// storeDir = /nix/store
|
||||
// sandboxBuildDir = /build
|
||||
// This process
|
||||
// storeDir = /build/foo/bar/store
|
||||
// sandboxBuildDir = /build
|
||||
// However, we have a rule that the store dir must not be inside the storeDir, so we need to pick a different sandboxBuildDir.
|
||||
settings.sandboxBuildDir = "/test-build-dir-instead-of-usual-build-dir";
|
||||
#endif
|
||||
|
||||
#if __APPLE__
|
||||
// Avoid this error, when already running in a sandbox:
|
||||
// sandbox-exec: sandbox_apply: Operation not permitted
|
||||
settings.sandboxMode = smDisabled;
|
||||
setEnv("_NIX_TEST_NO_SANDBOX", "1");
|
||||
#endif
|
||||
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
194
tests/unit/libexpr/nix_api_expr.cc
Normal file
194
tests/unit/libexpr/nix_api_expr.cc
Normal file
|
@ -0,0 +1,194 @@
|
|||
#include "nix_api_store.h"
|
||||
#include "nix_api_store_internal.h"
|
||||
#include "nix_api_util.h"
|
||||
#include "nix_api_util_internal.h"
|
||||
#include "nix_api_expr.h"
|
||||
#include "nix_api_value.h"
|
||||
|
||||
#include "tests/nix_api_expr.hh"
|
||||
#include "tests/string_callback.hh"
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace nixC {
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_expr_eval_from_string)
|
||||
{
|
||||
nix_expr_eval_from_string(nullptr, state, "builtins.nixVersion", ".", value);
|
||||
nix_value_force(nullptr, state, value);
|
||||
std::string result;
|
||||
nix_get_string(nullptr, value, OBSERVE_STRING(result));
|
||||
|
||||
ASSERT_STREQ(PACKAGE_VERSION, result.c_str());
|
||||
}
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_expr_eval_add_numbers)
|
||||
{
|
||||
nix_expr_eval_from_string(nullptr, state, "1 + 1", ".", value);
|
||||
nix_value_force(nullptr, state, value);
|
||||
auto result = nix_get_int(nullptr, value);
|
||||
|
||||
ASSERT_EQ(2, result);
|
||||
}
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_expr_eval_drv)
|
||||
{
|
||||
auto expr = R"(derivation { name = "myname"; builder = "mybuilder"; system = "mysystem"; })";
|
||||
nix_expr_eval_from_string(nullptr, state, expr, ".", value);
|
||||
ASSERT_EQ(NIX_TYPE_ATTRS, nix_get_type(nullptr, value));
|
||||
|
||||
EvalState * stateFn = nix_state_create(nullptr, nullptr, store);
|
||||
Value * valueFn = nix_alloc_value(nullptr, state);
|
||||
nix_expr_eval_from_string(nullptr, stateFn, "builtins.toString", ".", valueFn);
|
||||
ASSERT_EQ(NIX_TYPE_FUNCTION, nix_get_type(nullptr, valueFn));
|
||||
|
||||
EvalState * stateResult = nix_state_create(nullptr, nullptr, store);
|
||||
Value * valueResult = nix_alloc_value(nullptr, stateResult);
|
||||
nix_value_call(ctx, stateResult, valueFn, value, valueResult);
|
||||
ASSERT_EQ(NIX_TYPE_STRING, nix_get_type(nullptr, valueResult));
|
||||
|
||||
std::string p;
|
||||
nix_get_string(nullptr, valueResult, OBSERVE_STRING(p));
|
||||
std::string pEnd = "-myname";
|
||||
ASSERT_EQ(pEnd, p.substr(p.size() - pEnd.size()));
|
||||
|
||||
// Clean up
|
||||
nix_gc_decref(nullptr, valueFn);
|
||||
nix_state_free(stateFn);
|
||||
|
||||
nix_gc_decref(nullptr, valueResult);
|
||||
nix_state_free(stateResult);
|
||||
}
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_build_drv)
|
||||
{
|
||||
auto expr = R"(derivation { name = "myname";
|
||||
system = builtins.currentSystem;
|
||||
builder = "/bin/sh";
|
||||
args = [ "-c" "echo foo > $out" ];
|
||||
})";
|
||||
nix_expr_eval_from_string(nullptr, state, expr, ".", value);
|
||||
|
||||
Value * drvPathValue = nix_get_attr_byname(nullptr, value, state, "drvPath");
|
||||
std::string drvPath;
|
||||
nix_get_string(nullptr, drvPathValue, OBSERVE_STRING(drvPath));
|
||||
|
||||
std::string p = drvPath;
|
||||
std::string pEnd = "-myname.drv";
|
||||
ASSERT_EQ(pEnd, p.substr(p.size() - pEnd.size()));
|
||||
|
||||
// NOTE: .drvPath should be usually be ignored. Output paths are more versatile.
|
||||
// See https://github.com/NixOS/nix/issues/6507
|
||||
// Use e.g. nix_string_realise to realise the output.
|
||||
StorePath * drvStorePath = nix_store_parse_path(ctx, store, drvPath.c_str());
|
||||
ASSERT_EQ(true, nix_store_is_valid_path(ctx, store, drvStorePath));
|
||||
|
||||
Value * outPathValue = nix_get_attr_byname(ctx, value, state, "outPath");
|
||||
std::string outPath;
|
||||
nix_get_string(ctx, outPathValue, OBSERVE_STRING(outPath));
|
||||
|
||||
p = outPath;
|
||||
pEnd = "-myname";
|
||||
ASSERT_EQ(pEnd, p.substr(p.size() - pEnd.size()));
|
||||
ASSERT_EQ(true, drvStorePath->path.isDerivation());
|
||||
|
||||
StorePath * outStorePath = nix_store_parse_path(ctx, store, outPath.c_str());
|
||||
ASSERT_EQ(false, nix_store_is_valid_path(ctx, store, outStorePath));
|
||||
|
||||
nix_store_realise(ctx, store, drvStorePath, nullptr, nullptr);
|
||||
auto is_valid_path = nix_store_is_valid_path(ctx, store, outStorePath);
|
||||
ASSERT_EQ(true, is_valid_path);
|
||||
|
||||
// Clean up
|
||||
nix_store_path_free(drvStorePath);
|
||||
nix_store_path_free(outStorePath);
|
||||
}
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_expr_realise_context_bad_value)
|
||||
{
|
||||
auto expr = "true";
|
||||
nix_expr_eval_from_string(ctx, state, expr, ".", value);
|
||||
assert_ctx_ok();
|
||||
auto r = nix_string_realise(ctx, state, value, false);
|
||||
ASSERT_EQ(nullptr, r);
|
||||
ASSERT_EQ(ctx->last_err_code, NIX_ERR_NIX_ERROR);
|
||||
ASSERT_THAT(ctx->last_err, testing::Optional(testing::HasSubstr("cannot coerce")));
|
||||
}
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_expr_realise_context_bad_build)
|
||||
{
|
||||
auto expr = R"(
|
||||
derivation { name = "letsbuild";
|
||||
system = builtins.currentSystem;
|
||||
builder = "/bin/sh";
|
||||
args = [ "-c" "echo failing a build for testing purposes; exit 1;" ];
|
||||
}
|
||||
)";
|
||||
nix_expr_eval_from_string(ctx, state, expr, ".", value);
|
||||
assert_ctx_ok();
|
||||
auto r = nix_string_realise(ctx, state, value, false);
|
||||
ASSERT_EQ(nullptr, r);
|
||||
ASSERT_EQ(ctx->last_err_code, NIX_ERR_NIX_ERROR);
|
||||
ASSERT_THAT(ctx->last_err, testing::Optional(testing::HasSubstr("failed with exit code 1")));
|
||||
}
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_expr_realise_context)
|
||||
{
|
||||
// TODO (ca-derivations): add a content-addressed derivation output, which produces a placeholder
|
||||
auto expr = R"(
|
||||
''
|
||||
a derivation output: ${
|
||||
derivation { name = "letsbuild";
|
||||
system = builtins.currentSystem;
|
||||
builder = "/bin/sh";
|
||||
args = [ "-c" "echo foo > $out" ];
|
||||
}}
|
||||
a path: ${builtins.toFile "just-a-file" "ooh file good"}
|
||||
a derivation path by itself: ${
|
||||
builtins.unsafeDiscardOutputDependency
|
||||
(derivation {
|
||||
name = "not-actually-built-yet";
|
||||
system = builtins.currentSystem;
|
||||
builder = "/bin/sh";
|
||||
args = [ "-c" "echo foo > $out" ];
|
||||
}).drvPath}
|
||||
''
|
||||
)";
|
||||
nix_expr_eval_from_string(ctx, state, expr, ".", value);
|
||||
assert_ctx_ok();
|
||||
auto r = nix_string_realise(ctx, state, value, false);
|
||||
assert_ctx_ok();
|
||||
ASSERT_NE(nullptr, r);
|
||||
|
||||
auto s = std::string(nix_realised_string_get_buffer_start(r), nix_realised_string_get_buffer_size(r));
|
||||
|
||||
EXPECT_THAT(s, testing::StartsWith("a derivation output:"));
|
||||
EXPECT_THAT(s, testing::HasSubstr("-letsbuild\n"));
|
||||
EXPECT_THAT(s, testing::Not(testing::HasSubstr("-letsbuild.drv")));
|
||||
EXPECT_THAT(s, testing::HasSubstr("a path:"));
|
||||
EXPECT_THAT(s, testing::HasSubstr("-just-a-file"));
|
||||
EXPECT_THAT(s, testing::Not(testing::HasSubstr("-just-a-file.drv")));
|
||||
EXPECT_THAT(s, testing::Not(testing::HasSubstr("ooh file good")));
|
||||
EXPECT_THAT(s, testing::HasSubstr("a derivation path by itself:"));
|
||||
EXPECT_THAT(s, testing::EndsWith("-not-actually-built-yet.drv\n"));
|
||||
|
||||
std::vector<std::string> names;
|
||||
size_t n = nix_realised_string_get_store_path_count(r);
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
const StorePath * p = nix_realised_string_get_store_path(r, i);
|
||||
ASSERT_NE(nullptr, p);
|
||||
std::string name;
|
||||
nix_store_path_name(p, OBSERVE_STRING(name));
|
||||
names.push_back(name);
|
||||
}
|
||||
std::sort(names.begin(), names.end());
|
||||
ASSERT_EQ(3, names.size());
|
||||
EXPECT_THAT(names[0], testing::StrEq("just-a-file"));
|
||||
EXPECT_THAT(names[1], testing::StrEq("letsbuild"));
|
||||
EXPECT_THAT(names[2], testing::StrEq("not-actually-built-yet.drv"));
|
||||
|
||||
nix_realised_string_free(r);
|
||||
}
|
||||
|
||||
} // namespace nixC
|
68
tests/unit/libexpr/nix_api_external.cc
Normal file
68
tests/unit/libexpr/nix_api_external.cc
Normal file
|
@ -0,0 +1,68 @@
|
|||
#include "nix_api_store.h"
|
||||
#include "nix_api_store_internal.h"
|
||||
#include "nix_api_util.h"
|
||||
#include "nix_api_util_internal.h"
|
||||
#include "nix_api_expr.h"
|
||||
#include "nix_api_expr_internal.h"
|
||||
#include "nix_api_value.h"
|
||||
#include "nix_api_external.h"
|
||||
|
||||
#include "tests/nix_api_expr.hh"
|
||||
#include "tests/string_callback.hh"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace nixC {
|
||||
|
||||
class MyExternalValueDesc : public NixCExternalValueDesc
|
||||
{
|
||||
public:
|
||||
MyExternalValueDesc(int x)
|
||||
: _x(x)
|
||||
{
|
||||
print = print_function;
|
||||
showType = show_type_function;
|
||||
typeOf = type_of_function;
|
||||
}
|
||||
|
||||
private:
|
||||
int _x;
|
||||
static void print_function(void * self, nix_printer * printer) {}
|
||||
|
||||
static void show_type_function(void * self, nix_string_return * res) {}
|
||||
|
||||
static void type_of_function(void * self, nix_string_return * res)
|
||||
{
|
||||
MyExternalValueDesc * obj = static_cast<MyExternalValueDesc *>(self);
|
||||
|
||||
std::string type_string = "nix-external<MyExternalValueDesc( ";
|
||||
type_string += std::to_string(obj->_x);
|
||||
type_string += " )>";
|
||||
res->str = &*type_string.begin();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_expr_eval_external)
|
||||
{
|
||||
MyExternalValueDesc * external = new MyExternalValueDesc(42);
|
||||
ExternalValue * val = nix_create_external_value(ctx, external, external);
|
||||
nix_init_external(ctx, value, val);
|
||||
|
||||
EvalState * stateResult = nix_state_create(nullptr, nullptr, store);
|
||||
Value * valueResult = nix_alloc_value(nullptr, stateResult);
|
||||
|
||||
EvalState * stateFn = nix_state_create(nullptr, nullptr, store);
|
||||
Value * valueFn = nix_alloc_value(nullptr, stateFn);
|
||||
|
||||
nix_expr_eval_from_string(nullptr, state, "builtins.typeOf", ".", valueFn);
|
||||
|
||||
ASSERT_EQ(NIX_TYPE_EXTERNAL, nix_get_type(nullptr, value));
|
||||
|
||||
nix_value_call(ctx, state, valueFn, value, valueResult);
|
||||
|
||||
std::string string_value;
|
||||
nix_get_string(nullptr, valueResult, OBSERVE_STRING(string_value));
|
||||
ASSERT_STREQ("nix-external<MyExternalValueDesc( 42 )>", string_value.c_str());
|
||||
}
|
||||
|
||||
}
|
190
tests/unit/libexpr/nix_api_value.cc
Normal file
190
tests/unit/libexpr/nix_api_value.cc
Normal file
|
@ -0,0 +1,190 @@
|
|||
#include "nix_api_store.h"
|
||||
#include "nix_api_store_internal.h"
|
||||
#include "nix_api_util.h"
|
||||
#include "nix_api_util_internal.h"
|
||||
#include "nix_api_expr.h"
|
||||
#include "nix_api_value.h"
|
||||
|
||||
#include "tests/nix_api_expr.hh"
|
||||
#include "tests/string_callback.hh"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace nixC {
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_value_set_get_int)
|
||||
{
|
||||
ASSERT_EQ(0, nix_get_int(ctx, nullptr));
|
||||
ASSERT_DEATH(nix_get_int(ctx, value), "");
|
||||
|
||||
int myInt = 1;
|
||||
nix_init_int(ctx, value, myInt);
|
||||
|
||||
ASSERT_EQ(myInt, nix_get_int(ctx, value));
|
||||
ASSERT_STREQ("an integer", nix_get_typename(ctx, value));
|
||||
ASSERT_EQ(NIX_TYPE_INT, nix_get_type(ctx, value));
|
||||
}
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_value_set_get_float)
|
||||
{
|
||||
ASSERT_FLOAT_EQ(0.0, nix_get_float(ctx, nullptr));
|
||||
ASSERT_DEATH(nix_get_float(ctx, value), "");
|
||||
|
||||
float myDouble = 1.0;
|
||||
nix_init_float(ctx, value, myDouble);
|
||||
|
||||
ASSERT_FLOAT_EQ(myDouble, nix_get_float(ctx, value));
|
||||
ASSERT_STREQ("a float", nix_get_typename(ctx, value));
|
||||
ASSERT_EQ(NIX_TYPE_FLOAT, nix_get_type(ctx, value));
|
||||
}
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_value_set_get_bool)
|
||||
{
|
||||
ASSERT_EQ(false, nix_get_bool(ctx, nullptr));
|
||||
ASSERT_DEATH(nix_get_bool(ctx, value), "");
|
||||
|
||||
bool myBool = true;
|
||||
nix_init_bool(ctx, value, myBool);
|
||||
|
||||
ASSERT_EQ(myBool, nix_get_bool(ctx, value));
|
||||
ASSERT_STREQ("a Boolean", nix_get_typename(ctx, value));
|
||||
ASSERT_EQ(NIX_TYPE_BOOL, nix_get_type(ctx, value));
|
||||
}
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_value_set_get_string)
|
||||
{
|
||||
std::string string_value;
|
||||
ASSERT_EQ(NIX_ERR_UNKNOWN, nix_get_string(ctx, nullptr, OBSERVE_STRING(string_value)));
|
||||
ASSERT_DEATH(nix_get_string(ctx, value, OBSERVE_STRING(string_value)), "");
|
||||
|
||||
const char * myString = "some string";
|
||||
nix_init_string(ctx, value, myString);
|
||||
|
||||
nix_get_string(ctx, value, OBSERVE_STRING(string_value));
|
||||
ASSERT_STREQ(myString, string_value.c_str());
|
||||
ASSERT_STREQ("a string", nix_get_typename(ctx, value));
|
||||
ASSERT_EQ(NIX_TYPE_STRING, nix_get_type(ctx, value));
|
||||
}
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_value_set_get_null)
|
||||
{
|
||||
ASSERT_DEATH(nix_get_typename(ctx, value), "");
|
||||
|
||||
nix_init_null(ctx, value);
|
||||
|
||||
ASSERT_STREQ("null", nix_get_typename(ctx, value));
|
||||
ASSERT_EQ(NIX_TYPE_NULL, nix_get_type(ctx, value));
|
||||
}
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_value_set_get_path)
|
||||
{
|
||||
ASSERT_EQ(nullptr, nix_get_path_string(ctx, nullptr));
|
||||
ASSERT_DEATH(nix_get_path_string(ctx, value), "");
|
||||
|
||||
const char * p = "/nix/store/40s0qmrfb45vlh6610rk29ym318dswdr-myname";
|
||||
nix_init_path_string(ctx, state, value, p);
|
||||
|
||||
ASSERT_STREQ(p, nix_get_path_string(ctx, value));
|
||||
ASSERT_STREQ("a path", nix_get_typename(ctx, value));
|
||||
ASSERT_EQ(NIX_TYPE_PATH, nix_get_type(ctx, value));
|
||||
}
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_build_and_init_list)
|
||||
{
|
||||
ASSERT_EQ(nullptr, nix_get_list_byidx(ctx, nullptr, state, 0));
|
||||
ASSERT_EQ(0, nix_get_list_size(ctx, nullptr));
|
||||
|
||||
ASSERT_DEATH(nix_get_list_byidx(ctx, value, state, 0), "");
|
||||
ASSERT_DEATH(nix_get_list_size(ctx, value), "");
|
||||
|
||||
int size = 10;
|
||||
ListBuilder * builder = nix_make_list_builder(ctx, state, size);
|
||||
|
||||
Value * intValue = nix_alloc_value(ctx, state);
|
||||
nix_init_int(ctx, intValue, 42);
|
||||
nix_list_builder_insert(ctx, builder, 0, intValue);
|
||||
nix_make_list(ctx, builder, value);
|
||||
nix_list_builder_free(builder);
|
||||
|
||||
ASSERT_EQ(42, nix_get_int(ctx, nix_get_list_byidx(ctx, value, state, 0)));
|
||||
ASSERT_EQ(nullptr, nix_get_list_byidx(ctx, value, state, 1));
|
||||
ASSERT_EQ(10, nix_get_list_size(ctx, value));
|
||||
|
||||
ASSERT_STREQ("a list", nix_get_typename(ctx, value));
|
||||
ASSERT_EQ(NIX_TYPE_LIST, nix_get_type(ctx, value));
|
||||
|
||||
// Clean up
|
||||
nix_gc_decref(ctx, intValue);
|
||||
}
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_build_and_init_attr)
|
||||
{
|
||||
ASSERT_EQ(nullptr, nix_get_attr_byname(ctx, nullptr, state, 0));
|
||||
ASSERT_EQ(nullptr, nix_get_attr_byidx(ctx, nullptr, state, 0, nullptr));
|
||||
ASSERT_EQ(nullptr, nix_get_attr_name_byidx(ctx, nullptr, state, 0));
|
||||
ASSERT_EQ(0, nix_get_attrs_size(ctx, nullptr));
|
||||
ASSERT_EQ(false, nix_has_attr_byname(ctx, nullptr, state, "no-value"));
|
||||
|
||||
ASSERT_DEATH(nix_get_attr_byname(ctx, value, state, 0), "");
|
||||
ASSERT_DEATH(nix_get_attr_byidx(ctx, value, state, 0, nullptr), "");
|
||||
ASSERT_DEATH(nix_get_attr_name_byidx(ctx, value, state, 0), "");
|
||||
ASSERT_DEATH(nix_get_attrs_size(ctx, value), "");
|
||||
ASSERT_DEATH(nix_has_attr_byname(ctx, value, state, "no-value"), "");
|
||||
|
||||
int size = 10;
|
||||
const char ** out_name = (const char **) malloc(sizeof(char *));
|
||||
|
||||
BindingsBuilder * builder = nix_make_bindings_builder(ctx, state, size);
|
||||
|
||||
Value * intValue = nix_alloc_value(ctx, state);
|
||||
nix_init_int(ctx, intValue, 42);
|
||||
|
||||
Value * stringValue = nix_alloc_value(ctx, state);
|
||||
nix_init_string(ctx, stringValue, "foo");
|
||||
|
||||
nix_bindings_builder_insert(ctx, builder, "a", intValue);
|
||||
nix_bindings_builder_insert(ctx, builder, "b", stringValue);
|
||||
nix_make_attrs(ctx, value, builder);
|
||||
nix_bindings_builder_free(builder);
|
||||
|
||||
ASSERT_EQ(2, nix_get_attrs_size(ctx, value));
|
||||
|
||||
Value * out_value = nix_get_attr_byname(ctx, value, state, "a");
|
||||
ASSERT_EQ(42, nix_get_int(ctx, out_value));
|
||||
nix_gc_decref(ctx, out_value);
|
||||
|
||||
out_value = nix_get_attr_byidx(ctx, value, state, 0, out_name);
|
||||
ASSERT_EQ(42, nix_get_int(ctx, out_value));
|
||||
ASSERT_STREQ("a", *out_name);
|
||||
nix_gc_decref(ctx, out_value);
|
||||
|
||||
ASSERT_STREQ("a", nix_get_attr_name_byidx(ctx, value, state, 0));
|
||||
|
||||
ASSERT_EQ(true, nix_has_attr_byname(ctx, value, state, "b"));
|
||||
ASSERT_EQ(false, nix_has_attr_byname(ctx, value, state, "no-value"));
|
||||
|
||||
out_value = nix_get_attr_byname(ctx, value, state, "b");
|
||||
std::string string_value;
|
||||
nix_get_string(ctx, out_value, OBSERVE_STRING(string_value));
|
||||
ASSERT_STREQ("foo", string_value.c_str());
|
||||
nix_gc_decref(nullptr, out_value);
|
||||
|
||||
out_value = nix_get_attr_byidx(ctx, value, state, 1, out_name);
|
||||
nix_get_string(ctx, out_value, OBSERVE_STRING(string_value));
|
||||
ASSERT_STREQ("foo", string_value.c_str());
|
||||
ASSERT_STREQ("b", *out_name);
|
||||
nix_gc_decref(nullptr, out_value);
|
||||
|
||||
ASSERT_STREQ("b", nix_get_attr_name_byidx(ctx, value, state, 1));
|
||||
|
||||
ASSERT_STREQ("a set", nix_get_typename(ctx, value));
|
||||
ASSERT_EQ(NIX_TYPE_ATTRS, nix_get_type(ctx, value));
|
||||
|
||||
// Clean up
|
||||
nix_gc_decref(ctx, intValue);
|
||||
nix_gc_decref(ctx, stringValue);
|
||||
free(out_name);
|
||||
}
|
||||
|
||||
}
|
|
@ -91,7 +91,7 @@ namespace nix {
|
|||
}
|
||||
|
||||
TEST_F(PrimOpTest, getEnv) {
|
||||
setenv("_NIX_UNIT_TEST_ENV_VALUE", "test value", 1);
|
||||
setEnv("_NIX_UNIT_TEST_ENV_VALUE", "test value");
|
||||
auto v = eval("builtins.getEnv \"_NIX_UNIT_TEST_ENV_VALUE\"");
|
||||
ASSERT_THAT(v, IsStringEq("test value"));
|
||||
}
|
||||
|
|
32
tests/unit/libfetchers/local.mk
Normal file
32
tests/unit/libfetchers/local.mk
Normal file
|
@ -0,0 +1,32 @@
|
|||
check: libfetchers-tests_RUN
|
||||
|
||||
programs += libfetchers-tests
|
||||
|
||||
libfetchers-tests_NAME = libnixfetchers-tests
|
||||
|
||||
libfetchers-tests_ENV := _NIX_TEST_UNIT_DATA=$(d)/data
|
||||
|
||||
libfetchers-tests_DIR := $(d)
|
||||
|
||||
ifeq ($(INSTALL_UNIT_TESTS), yes)
|
||||
libfetchers-tests_INSTALL_DIR := $(checkbindir)
|
||||
else
|
||||
libfetchers-tests_INSTALL_DIR :=
|
||||
endif
|
||||
|
||||
libfetchers-tests_SOURCES := $(wildcard $(d)/*.cc)
|
||||
|
||||
libfetchers-tests_EXTRA_INCLUDES = \
|
||||
-I tests/unit/libstore-support \
|
||||
-I tests/unit/libutil-support \
|
||||
$(INCLUDE_libfetchers) \
|
||||
$(INCLUDE_libstore) \
|
||||
$(INCLUDE_libutil)
|
||||
|
||||
libfetchers-tests_CXXFLAGS += $(libfetchers-tests_EXTRA_INCLUDES)
|
||||
|
||||
libfetchers-tests_LIBS = \
|
||||
libstore-test-support libutil-test-support \
|
||||
libfetchers libstore libutil
|
||||
|
||||
libfetchers-tests_LDFLAGS := -lrapidcheck $(GTEST_LIBS)
|
18
tests/unit/libfetchers/public-key.cc
Normal file
18
tests/unit/libfetchers/public-key.cc
Normal file
|
@ -0,0 +1,18 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include "fetchers.hh"
|
||||
#include "json-utils.hh"
|
||||
|
||||
namespace nix {
|
||||
TEST(PublicKey, jsonSerialization) {
|
||||
auto json = nlohmann::json(fetchers::PublicKey { .key = "ABCDE" });
|
||||
|
||||
ASSERT_EQ(json, R"({ "key": "ABCDE", "type": "ssh-ed25519" })"_json);
|
||||
}
|
||||
TEST(PublicKey, jsonDeserialization) {
|
||||
auto pubKeyJson = R"({ "key": "ABCDE", "type": "ssh-ed25519" })"_json;
|
||||
fetchers::PublicKey pubKey = pubKeyJson;
|
||||
|
||||
ASSERT_EQ(pubKey.key, "ABCDE");
|
||||
ASSERT_EQ(pubKey.type, "ssh-ed25519");
|
||||
}
|
||||
}
|
66
tests/unit/libstore-support/tests/nix_api_store.hh
Normal file
66
tests/unit/libstore-support/tests/nix_api_store.hh
Normal file
|
@ -0,0 +1,66 @@
|
|||
#pragma once
|
||||
///@file
|
||||
#include "tests/nix_api_util.hh"
|
||||
|
||||
#include "file-system.hh"
|
||||
|
||||
#include "nix_api_store.h"
|
||||
#include "nix_api_store_internal.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace nixC {
|
||||
class nix_api_store_test : public nix_api_util_context
|
||||
{
|
||||
public:
|
||||
nix_api_store_test()
|
||||
{
|
||||
nix_libstore_init(ctx);
|
||||
init_local_store();
|
||||
};
|
||||
|
||||
~nix_api_store_test() override
|
||||
{
|
||||
nix_store_free(store);
|
||||
|
||||
for (auto & path : fs::recursive_directory_iterator(nixDir)) {
|
||||
fs::permissions(path, fs::perms::owner_all);
|
||||
}
|
||||
fs::remove_all(nixDir);
|
||||
}
|
||||
|
||||
Store * store;
|
||||
std::string nixDir;
|
||||
std::string nixStoreDir;
|
||||
|
||||
protected:
|
||||
void init_local_store()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// no `mkdtemp` with MinGW
|
||||
auto tmpl = nix::defaultTempDir() + "/tests_nix-store.";
|
||||
for (size_t i = 0; true; ++i) {
|
||||
nixDir = tmpl + std::string { i };
|
||||
if (fs::create_directory(nixDir)) break;
|
||||
}
|
||||
#else
|
||||
auto tmpl = nix::defaultTempDir() + "/tests_nix-store.XXXXXX";
|
||||
nixDir = mkdtemp((char *) tmpl.c_str());
|
||||
#endif
|
||||
|
||||
nixStoreDir = nixDir + "/my_nix_store";
|
||||
|
||||
// Options documented in `nix help-stores`
|
||||
const char * p1[] = {"store", nixStoreDir.c_str()};
|
||||
const char * p2[] = {"state", (new std::string(nixDir + "/my_state"))->c_str()};
|
||||
const char * p3[] = {"log", (new std::string(nixDir + "/my_log"))->c_str()};
|
||||
|
||||
const char ** params[] = {p1, p2, p3, nullptr};
|
||||
|
||||
store = nix_store_open(ctx, "local", params);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -19,13 +19,15 @@ libstore-tests_SOURCES := $(wildcard $(d)/*.cc)
|
|||
libstore-tests_EXTRA_INCLUDES = \
|
||||
-I tests/unit/libstore-support \
|
||||
-I tests/unit/libutil-support \
|
||||
-I src/libstore \
|
||||
-I src/libutil
|
||||
$(INCLUDE_libstore) \
|
||||
$(INCLUDE_libstorec) \
|
||||
$(INCLUDE_libutil) \
|
||||
$(INCLUDE_libutilc)
|
||||
|
||||
libstore-tests_CXXFLAGS += $(libstore-tests_EXTRA_INCLUDES)
|
||||
|
||||
libstore-tests_LIBS = \
|
||||
libstore-test-support libutil-test-support \
|
||||
libstore libutil
|
||||
libstore libstorec libutil libutilc
|
||||
|
||||
libstore-tests_LDFLAGS := -lrapidcheck $(GTEST_LIBS)
|
||||
|
|
89
tests/unit/libstore/nix_api_store.cc
Normal file
89
tests/unit/libstore/nix_api_store.cc
Normal file
|
@ -0,0 +1,89 @@
|
|||
#include "nix_api_util.h"
|
||||
#include "nix_api_util_internal.h"
|
||||
#include "nix_api_store.h"
|
||||
#include "nix_api_store_internal.h"
|
||||
|
||||
#include "tests/nix_api_store.hh"
|
||||
#include "tests/string_callback.hh"
|
||||
|
||||
namespace nixC {
|
||||
|
||||
std::string PATH_SUFFIX = "/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-name";
|
||||
|
||||
TEST_F(nix_api_util_context, nix_libstore_init)
|
||||
{
|
||||
auto ret = nix_libstore_init(ctx);
|
||||
ASSERT_EQ(NIX_OK, ret);
|
||||
}
|
||||
|
||||
TEST_F(nix_api_store_test, nix_store_get_uri)
|
||||
{
|
||||
std::string str;
|
||||
auto ret = nix_store_get_uri(ctx, store, OBSERVE_STRING(str));
|
||||
ASSERT_EQ(NIX_OK, ret);
|
||||
ASSERT_STREQ("local", str.c_str());
|
||||
}
|
||||
|
||||
TEST_F(nix_api_store_test, InvalidPathFails)
|
||||
{
|
||||
nix_store_parse_path(ctx, store, "invalid-path");
|
||||
ASSERT_EQ(ctx->last_err_code, NIX_ERR_NIX_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(nix_api_store_test, ReturnsValidStorePath)
|
||||
{
|
||||
StorePath * result = nix_store_parse_path(ctx, store, (nixStoreDir + PATH_SUFFIX).c_str());
|
||||
ASSERT_NE(result, nullptr);
|
||||
ASSERT_STREQ("name", result->path.name().data());
|
||||
ASSERT_STREQ(PATH_SUFFIX.substr(1).c_str(), result->path.to_string().data());
|
||||
}
|
||||
|
||||
TEST_F(nix_api_store_test, SetsLastErrCodeToNixOk)
|
||||
{
|
||||
nix_store_parse_path(ctx, store, (nixStoreDir + PATH_SUFFIX).c_str());
|
||||
ASSERT_EQ(ctx->last_err_code, NIX_OK);
|
||||
}
|
||||
|
||||
TEST_F(nix_api_store_test, DoesNotCrashWhenContextIsNull)
|
||||
{
|
||||
ASSERT_NO_THROW(nix_store_parse_path(ctx, store, (nixStoreDir + PATH_SUFFIX).c_str()));
|
||||
}
|
||||
|
||||
TEST_F(nix_api_store_test, get_version)
|
||||
{
|
||||
std::string str;
|
||||
auto ret = nix_store_get_version(ctx, store, OBSERVE_STRING(str));
|
||||
ASSERT_EQ(NIX_OK, ret);
|
||||
ASSERT_STREQ(PACKAGE_VERSION, str.c_str());
|
||||
}
|
||||
|
||||
TEST_F(nix_api_util_context, nix_store_open_dummy)
|
||||
{
|
||||
nix_libstore_init(ctx);
|
||||
Store * store = nix_store_open(ctx, "dummy://", nullptr);
|
||||
ASSERT_EQ(NIX_OK, ctx->last_err_code);
|
||||
ASSERT_STREQ("dummy", store->ptr->getUri().c_str());
|
||||
|
||||
std::string str;
|
||||
nix_store_get_version(ctx, store, OBSERVE_STRING(str));
|
||||
ASSERT_STREQ("", str.c_str());
|
||||
|
||||
nix_store_free(store);
|
||||
}
|
||||
|
||||
TEST_F(nix_api_util_context, nix_store_open_invalid)
|
||||
{
|
||||
nix_libstore_init(ctx);
|
||||
Store * store = nix_store_open(ctx, "invalid://", nullptr);
|
||||
ASSERT_EQ(NIX_ERR_NIX_ERROR, ctx->last_err_code);
|
||||
ASSERT_EQ(nullptr, store);
|
||||
nix_store_free(store);
|
||||
}
|
||||
|
||||
TEST_F(nix_api_store_test, nix_store_is_valid_path_not_in_store)
|
||||
{
|
||||
StorePath * path = nix_store_parse_path(ctx, store, (nixStoreDir + PATH_SUFFIX).c_str());
|
||||
ASSERT_EQ(false, nix_store_is_valid_path(ctx, store, path));
|
||||
}
|
||||
|
||||
}
|
37
tests/unit/libutil-support/tests/nix_api_util.hh
Normal file
37
tests/unit/libutil-support/tests/nix_api_util.hh
Normal file
|
@ -0,0 +1,37 @@
|
|||
#pragma once
|
||||
///@file
|
||||
#include "nix_api_util.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace nixC {
|
||||
|
||||
class nix_api_util_context : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
|
||||
nix_api_util_context()
|
||||
{
|
||||
ctx = nix_c_context_create();
|
||||
nix_libutil_init(ctx);
|
||||
};
|
||||
|
||||
~nix_api_util_context() override
|
||||
{
|
||||
nix_c_context_free(ctx);
|
||||
ctx = nullptr;
|
||||
}
|
||||
|
||||
nix_c_context * ctx;
|
||||
|
||||
inline void assert_ctx_ok() {
|
||||
if (nix_err_code(ctx) == NIX_OK) {
|
||||
return;
|
||||
}
|
||||
unsigned int n;
|
||||
const char * p = nix_err_msg(nullptr, ctx, &n);
|
||||
std::string msg(p, n);
|
||||
FAIL() << "nix_err_code(ctx) != NIX_OK, message: " << msg;
|
||||
}
|
||||
};
|
||||
}
|
10
tests/unit/libutil-support/tests/string_callback.cc
Normal file
10
tests/unit/libutil-support/tests/string_callback.cc
Normal file
|
@ -0,0 +1,10 @@
|
|||
#include "string_callback.hh"
|
||||
|
||||
namespace nix::testing {
|
||||
|
||||
void observe_string_cb(const char * start, unsigned int n, std::string * user_data)
|
||||
{
|
||||
*user_data = std::string(start);
|
||||
}
|
||||
|
||||
}
|
16
tests/unit/libutil-support/tests/string_callback.hh
Normal file
16
tests/unit/libutil-support/tests/string_callback.hh
Normal file
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
|
||||
namespace nix::testing {
|
||||
|
||||
void observe_string_cb(const char * start, unsigned int n, std::string * user_data);
|
||||
|
||||
inline void * observe_string_cb_data(std::string & out)
|
||||
{
|
||||
return (void *) &out;
|
||||
};
|
||||
|
||||
#define OBSERVE_STRING(str) \
|
||||
(nix_get_string_callback) nix::testing::observe_string_cb, nix::testing::observe_string_cb_data(str)
|
||||
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "error.hh"
|
||||
#include "json-utils.hh"
|
||||
|
||||
namespace nix {
|
||||
|
@ -55,4 +56,120 @@ TEST(from_json, vectorOfOptionalInts) {
|
|||
ASSERT_FALSE(vals.at(1).has_value());
|
||||
}
|
||||
|
||||
TEST(valueAt, simpleObject) {
|
||||
auto simple = R"({ "hello": "world" })"_json;
|
||||
|
||||
ASSERT_EQ(valueAt(getObject(simple), "hello"), "world");
|
||||
|
||||
auto nested = R"({ "hello": { "world": "" } })"_json;
|
||||
|
||||
auto & nestedObject = valueAt(getObject(nested), "hello");
|
||||
|
||||
ASSERT_EQ(valueAt(nestedObject, "world"), "");
|
||||
}
|
||||
|
||||
TEST(valueAt, missingKey) {
|
||||
auto json = R"({ "hello": { "nested": "world" } })"_json;
|
||||
|
||||
auto & obj = getObject(json);
|
||||
|
||||
ASSERT_THROW(valueAt(obj, "foo"), Error);
|
||||
}
|
||||
|
||||
TEST(getObject, rightAssertions) {
|
||||
auto simple = R"({ "object": {} })"_json;
|
||||
|
||||
ASSERT_EQ(getObject(valueAt(getObject(simple), "object")), (nlohmann::json::object_t {}));
|
||||
|
||||
auto nested = R"({ "object": { "object": {} } })"_json;
|
||||
|
||||
auto & nestedObject = getObject(valueAt(getObject(nested), "object"));
|
||||
|
||||
ASSERT_EQ(nestedObject, getObject(nlohmann::json::parse(R"({ "object": {} })")));
|
||||
ASSERT_EQ(getObject(valueAt(getObject(nestedObject), "object")), (nlohmann::json::object_t {}));
|
||||
}
|
||||
|
||||
TEST(getObject, wrongAssertions) {
|
||||
auto json = R"({ "object": {}, "array": [], "string": "", "int": 0, "boolean": false })"_json;
|
||||
|
||||
auto & obj = getObject(json);
|
||||
|
||||
ASSERT_THROW(getObject(valueAt(obj, "array")), Error);
|
||||
ASSERT_THROW(getObject(valueAt(obj, "string")), Error);
|
||||
ASSERT_THROW(getObject(valueAt(obj, "int")), Error);
|
||||
ASSERT_THROW(getObject(valueAt(obj, "boolean")), Error);
|
||||
}
|
||||
|
||||
TEST(getArray, rightAssertions) {
|
||||
auto simple = R"({ "array": [] })"_json;
|
||||
|
||||
ASSERT_EQ(getArray(valueAt(getObject(simple), "array")), (nlohmann::json::array_t {}));
|
||||
}
|
||||
|
||||
TEST(getArray, wrongAssertions) {
|
||||
auto json = R"({ "object": {}, "array": [], "string": "", "int": 0, "boolean": false })"_json;
|
||||
|
||||
ASSERT_THROW(getArray(valueAt(json, "object")), Error);
|
||||
ASSERT_THROW(getArray(valueAt(json, "string")), Error);
|
||||
ASSERT_THROW(getArray(valueAt(json, "int")), Error);
|
||||
ASSERT_THROW(getArray(valueAt(json, "boolean")), Error);
|
||||
}
|
||||
|
||||
TEST(getString, rightAssertions) {
|
||||
auto simple = R"({ "string": "" })"_json;
|
||||
|
||||
ASSERT_EQ(getString(valueAt(getObject(simple), "string")), "");
|
||||
}
|
||||
|
||||
TEST(getString, wrongAssertions) {
|
||||
auto json = R"({ "object": {}, "array": [], "string": "", "int": 0, "boolean": false })"_json;
|
||||
|
||||
ASSERT_THROW(getString(valueAt(json, "object")), Error);
|
||||
ASSERT_THROW(getString(valueAt(json, "array")), Error);
|
||||
ASSERT_THROW(getString(valueAt(json, "int")), Error);
|
||||
ASSERT_THROW(getString(valueAt(json, "boolean")), Error);
|
||||
}
|
||||
|
||||
TEST(getInteger, rightAssertions) {
|
||||
auto simple = R"({ "int": 0 })"_json;
|
||||
|
||||
ASSERT_EQ(getInteger(valueAt(getObject(simple), "int")), 0);
|
||||
}
|
||||
|
||||
TEST(getInteger, wrongAssertions) {
|
||||
auto json = R"({ "object": {}, "array": [], "string": "", "int": 0, "boolean": false })"_json;
|
||||
|
||||
ASSERT_THROW(getInteger(valueAt(json, "object")), Error);
|
||||
ASSERT_THROW(getInteger(valueAt(json, "array")), Error);
|
||||
ASSERT_THROW(getInteger(valueAt(json, "string")), Error);
|
||||
ASSERT_THROW(getInteger(valueAt(json, "boolean")), Error);
|
||||
}
|
||||
|
||||
TEST(getBoolean, rightAssertions) {
|
||||
auto simple = R"({ "boolean": false })"_json;
|
||||
|
||||
ASSERT_EQ(getBoolean(valueAt(getObject(simple), "boolean")), false);
|
||||
}
|
||||
|
||||
TEST(getBoolean, wrongAssertions) {
|
||||
auto json = R"({ "object": {}, "array": [], "string": "", "int": 0, "boolean": false })"_json;
|
||||
|
||||
ASSERT_THROW(getBoolean(valueAt(json, "object")), Error);
|
||||
ASSERT_THROW(getBoolean(valueAt(json, "array")), Error);
|
||||
ASSERT_THROW(getBoolean(valueAt(json, "string")), Error);
|
||||
ASSERT_THROW(getBoolean(valueAt(json, "int")), Error);
|
||||
}
|
||||
|
||||
TEST(optionalValueAt, existing) {
|
||||
auto json = R"({ "string": "ssh-rsa" })"_json;
|
||||
|
||||
ASSERT_EQ(optionalValueAt(json, "string"), std::optional { "ssh-rsa" });
|
||||
}
|
||||
|
||||
TEST(optionalValueAt, empty) {
|
||||
auto json = R"({})"_json;
|
||||
|
||||
ASSERT_EQ(optionalValueAt(json, "string2"), std::nullopt);
|
||||
}
|
||||
|
||||
} /* namespace nix */
|
||||
|
|
|
@ -18,11 +18,12 @@ libutil-tests_SOURCES := $(wildcard $(d)/*.cc)
|
|||
|
||||
libutil-tests_EXTRA_INCLUDES = \
|
||||
-I tests/unit/libutil-support \
|
||||
-I src/libutil
|
||||
$(INCLUDE_libutil) \
|
||||
$(INCLUDE_libutilc)
|
||||
|
||||
libutil-tests_CXXFLAGS += $(libutil-tests_EXTRA_INCLUDES)
|
||||
|
||||
libutil-tests_LIBS = libutil-test-support libutil
|
||||
libutil-tests_LIBS = libutil-test-support libutil libutilc
|
||||
|
||||
libutil-tests_LDFLAGS := -lrapidcheck $(GTEST_LIBS)
|
||||
|
||||
|
|
141
tests/unit/libutil/nix_api_util.cc
Normal file
141
tests/unit/libutil/nix_api_util.cc
Normal file
|
@ -0,0 +1,141 @@
|
|||
#include "config.hh"
|
||||
#include "args.hh"
|
||||
#include "nix_api_util.h"
|
||||
#include "nix_api_util_internal.h"
|
||||
#include "tests/nix_api_util.hh"
|
||||
#include "tests/string_callback.hh"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace nixC {
|
||||
|
||||
TEST_F(nix_api_util_context, nix_context_error)
|
||||
{
|
||||
std::string err_msg_ref;
|
||||
try {
|
||||
throw nix::Error("testing error");
|
||||
} catch (nix::Error & e) {
|
||||
err_msg_ref = e.what();
|
||||
nix_context_error(ctx);
|
||||
}
|
||||
ASSERT_EQ(ctx->last_err_code, NIX_ERR_NIX_ERROR);
|
||||
ASSERT_EQ(ctx->name, "nix::Error");
|
||||
ASSERT_EQ(*ctx->last_err, err_msg_ref);
|
||||
ASSERT_EQ(ctx->info->msg.str(), "testing error");
|
||||
|
||||
try {
|
||||
throw std::runtime_error("testing exception");
|
||||
} catch (std::exception & e) {
|
||||
err_msg_ref = e.what();
|
||||
nix_context_error(ctx);
|
||||
}
|
||||
ASSERT_EQ(ctx->last_err_code, NIX_ERR_UNKNOWN);
|
||||
ASSERT_EQ(*ctx->last_err, err_msg_ref);
|
||||
}
|
||||
|
||||
TEST_F(nix_api_util_context, nix_set_err_msg)
|
||||
{
|
||||
ASSERT_EQ(ctx->last_err_code, NIX_OK);
|
||||
nix_set_err_msg(ctx, NIX_ERR_UNKNOWN, "unknown test error");
|
||||
ASSERT_EQ(ctx->last_err_code, NIX_ERR_UNKNOWN);
|
||||
ASSERT_EQ(*ctx->last_err, "unknown test error");
|
||||
}
|
||||
|
||||
TEST(nix_api_util, nix_version_get)
|
||||
{
|
||||
ASSERT_EQ(std::string(nix_version_get()), PACKAGE_VERSION);
|
||||
}
|
||||
|
||||
struct MySettings : nix::Config
|
||||
{
|
||||
nix::Setting<std::string> settingSet{this, "empty", "setting-name", "Description"};
|
||||
};
|
||||
|
||||
MySettings mySettings;
|
||||
static nix::GlobalConfig::Register rs(&mySettings);
|
||||
|
||||
TEST_F(nix_api_util_context, nix_setting_get)
|
||||
{
|
||||
ASSERT_EQ(ctx->last_err_code, NIX_OK);
|
||||
std::string setting_value;
|
||||
nix_err result = nix_setting_get(ctx, "invalid-key", OBSERVE_STRING(setting_value));
|
||||
ASSERT_EQ(result, NIX_ERR_KEY);
|
||||
|
||||
result = nix_setting_get(ctx, "setting-name", OBSERVE_STRING(setting_value));
|
||||
ASSERT_EQ(result, NIX_OK);
|
||||
ASSERT_STREQ("empty", setting_value.c_str());
|
||||
}
|
||||
|
||||
TEST_F(nix_api_util_context, nix_setting_set)
|
||||
{
|
||||
nix_err result = nix_setting_set(ctx, "invalid-key", "new-value");
|
||||
ASSERT_EQ(result, NIX_ERR_KEY);
|
||||
|
||||
result = nix_setting_set(ctx, "setting-name", "new-value");
|
||||
ASSERT_EQ(result, NIX_OK);
|
||||
|
||||
std::string setting_value;
|
||||
result = nix_setting_get(ctx, "setting-name", OBSERVE_STRING(setting_value));
|
||||
ASSERT_EQ(result, NIX_OK);
|
||||
ASSERT_STREQ("new-value", setting_value.c_str());
|
||||
}
|
||||
|
||||
TEST_F(nix_api_util_context, nix_err_msg)
|
||||
{
|
||||
// no error
|
||||
EXPECT_THROW(nix_err_msg(nullptr, ctx, NULL), nix::Error);
|
||||
|
||||
// set error
|
||||
nix_set_err_msg(ctx, NIX_ERR_UNKNOWN, "unknown test error");
|
||||
|
||||
// basic usage
|
||||
std::string err_msg = nix_err_msg(NULL, ctx, NULL);
|
||||
ASSERT_EQ(err_msg, "unknown test error");
|
||||
|
||||
// advanced usage
|
||||
unsigned int sz;
|
||||
err_msg = nix_err_msg(nix_c_context_create(), ctx, &sz);
|
||||
ASSERT_EQ(sz, err_msg.size());
|
||||
}
|
||||
|
||||
TEST_F(nix_api_util_context, nix_err_info_msg)
|
||||
{
|
||||
std::string err_info;
|
||||
|
||||
// no error
|
||||
EXPECT_THROW(nix_err_info_msg(NULL, ctx, OBSERVE_STRING(err_info)), nix::Error);
|
||||
|
||||
try {
|
||||
throw nix::Error("testing error");
|
||||
} catch (...) {
|
||||
nix_context_error(ctx);
|
||||
}
|
||||
nix_err_info_msg(nix_c_context_create(), ctx, OBSERVE_STRING(err_info));
|
||||
ASSERT_STREQ("testing error", err_info.c_str());
|
||||
}
|
||||
|
||||
TEST_F(nix_api_util_context, nix_err_name)
|
||||
{
|
||||
std::string err_name;
|
||||
|
||||
// no error
|
||||
EXPECT_THROW(nix_err_name(NULL, ctx, OBSERVE_STRING(err_name)), nix::Error);
|
||||
|
||||
std::string err_msg_ref;
|
||||
try {
|
||||
throw nix::Error("testing error");
|
||||
} catch (...) {
|
||||
nix_context_error(ctx);
|
||||
}
|
||||
nix_err_name(nix_c_context_create(), ctx, OBSERVE_STRING(err_name));
|
||||
ASSERT_EQ(std::string(err_name), "nix::Error");
|
||||
}
|
||||
|
||||
TEST_F(nix_api_util_context, nix_err_code)
|
||||
{
|
||||
ASSERT_EQ(nix_err_code(ctx), NIX_OK);
|
||||
nix_set_err_msg(ctx, NIX_ERR_UNKNOWN, "unknown test error");
|
||||
ASSERT_EQ(nix_err_code(ctx), NIX_ERR_UNKNOWN);
|
||||
}
|
||||
|
||||
}
|
|
@ -151,6 +151,16 @@ namespace nix {
|
|||
ASSERT_EQ(p1, "dir");
|
||||
}
|
||||
|
||||
TEST(baseNameOf, trailingSlashes) {
|
||||
auto p1 = baseNameOf("/dir//");
|
||||
ASSERT_EQ(p1, "dir");
|
||||
}
|
||||
|
||||
TEST(baseNameOf, absoluteNothingSlashNothing) {
|
||||
auto p1 = baseNameOf("//");
|
||||
ASSERT_EQ(p1, "");
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* isInDir
|
||||
* --------------------------------------------------------------------------*/
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue