Build Functional tests with Meson

Co-Authored-By: Qyriad <qyriad@qyriad.me>
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
This commit is contained in:
John Ericson 2024-07-08 16:07:06 -04:00
parent d434a54b6c
commit 34fe2478a2
29 changed files with 678 additions and 115 deletions

View file

@ -210,6 +210,9 @@
"${nixpkgsPrefix}${pkgName}-${testName}" = test; "${nixpkgsPrefix}${pkgName}-${testName}" = test;
}) })
) )
// lib.optionalAttrs (nixpkgs.stdenv.hostPlatform == nixpkgs.stdenv.buildPlatform) {
"${nixpkgsPrefix}nix-functional-tests" = nixpkgs.nixComponents.nix-functional-tests;
}
) )
// devFlake.checks.${system} or {} // devFlake.checks.${system} or {}
); );
@ -323,6 +326,7 @@
++ lib.optionals havePerl pkgs.nixComponents.nix-perl-bindings.nativeBuildInputs ++ lib.optionals havePerl pkgs.nixComponents.nix-perl-bindings.nativeBuildInputs
++ pkgs.nixComponents.nix-internal-api-docs.nativeBuildInputs ++ pkgs.nixComponents.nix-internal-api-docs.nativeBuildInputs
++ pkgs.nixComponents.nix-external-api-docs.nativeBuildInputs ++ pkgs.nixComponents.nix-external-api-docs.nativeBuildInputs
++ pkgs.nixComponents.nix-functional-tests.baseNativeBuildInputs
++ lib.optional ++ lib.optional
(!stdenv.buildPlatform.canExecute stdenv.hostPlatform (!stdenv.buildPlatform.canExecute stdenv.hostPlatform
# Hack around https://github.com/nixos/nixpkgs/commit/bf7ad8cfbfa102a90463433e2c5027573b462479 # Hack around https://github.com/nixos/nixpkgs/commit/bf7ad8cfbfa102a90463433e2c5027573b462479

View file

@ -42,3 +42,4 @@ subproject('nix-fetchers-tests')
subproject('nix-expr-test-support') subproject('nix-expr-test-support')
subproject('nix-expr-tests') subproject('nix-expr-tests')
subproject('nix-flake-tests') subproject('nix-flake-tests')
subproject('nix-functional-tests')

View file

@ -59,6 +59,8 @@ in
# Will replace `nix` once the old build system is gone. # Will replace `nix` once the old build system is gone.
nix-ng = callPackage ../src/nix/package.nix { version = fineVersion; }; nix-ng = callPackage ../src/nix/package.nix { version = fineVersion; };
nix-functional-tests = callPackage ../src/nix-functional-tests/package.nix { version = fineVersion; };
nix-internal-api-docs = callPackage ../src/internal-api-docs/package.nix { version = fineVersion; }; nix-internal-api-docs = callPackage ../src/internal-api-docs/package.nix { version = fineVersion; };
nix-external-api-docs = callPackage ../src/external-api-docs/package.nix { version = fineVersion; }; nix-external-api-docs = callPackage ../src/external-api-docs/package.nix { version = fineVersion; };

View file

@ -62,6 +62,7 @@ let
"nix-main-c" "nix-main-c"
"nix-cmd" "nix-cmd"
"nix-ng" "nix-ng"
"nix-functional-tests"
]; ];
in in
{ {
@ -75,8 +76,10 @@ in
lib.genAttrs linux64BitSystems (system: nixpkgsFor.${system}.static.nixComponents.${pkgName})); lib.genAttrs linux64BitSystems (system: nixpkgsFor.${system}.static.nixComponents.${pkgName}));
buildCross = forAllPackages (pkgName: buildCross = forAllPackages (pkgName:
forAllCrossSystems (crossSystem: # Hack to avoid non-evaling package
lib.genAttrs [ "x86_64-linux" ] (system: nixpkgsFor.${system}.cross.${crossSystem}.nixComponents.${pkgName}))); (if pkgName == "nix-functional-tests" then lib.flip builtins.removeAttrs ["x86_64-w64-mingw32"] else lib.id)
(forAllCrossSystems (crossSystem:
lib.genAttrs [ "x86_64-linux" ] (system: nixpkgsFor.${system}.cross.${crossSystem}.nixComponents.${pkgName}))));
buildNoGc = forAllSystems (system: buildNoGc = forAllSystems (system:
self.packages.${system}.nix.override { enableGC = false; } self.packages.${system}.nix.override { enableGC = false; }

View file

@ -21,7 +21,7 @@ configdata = configuration_data()
# TODO rename, because it will conflict with downstream projects # TODO rename, because it will conflict with downstream projects
configdata.set_quoted('PACKAGE_VERSION', meson.project_version()) configdata.set_quoted('PACKAGE_VERSION', meson.project_version())
configdata.set_quoted('SYSTEM', host_machine.system()) configdata.set_quoted('SYSTEM', host_machine.cpu_family() + '-' + host_machine.system())
deps_private_maybe_subproject = [ deps_private_maybe_subproject = [
] ]

1
src/nix-functional-tests Symbolic link
View file

@ -0,0 +1 @@
../tests/functional

1
tests/functional/.version Symbolic link
View file

@ -0,0 +1 @@
../../.version

View file

@ -0,0 +1,33 @@
configure_file(
input : 'config.nix.in',
output : 'config.nix',
configuration : test_confdata,
)
suites += {
'name': 'ca',
'deps': [],
'tests': [
'build-with-garbage-path.sh',
'build.sh',
'build-cache.sh',
'concurrent-builds.sh',
'derivation-json.sh',
'duplicate-realisation-in-closure.sh',
'eval-store.sh',
'gc.sh',
'import-derivation.sh',
'new-build-cmd.sh',
'nix-copy.sh',
'nix-run.sh',
'nix-shell.sh',
'post-hook.sh',
'recursive.sh',
'repl.sh',
'selfref-gc.sh',
'signatures.sh',
'substitute.sh',
'why-depends.sh',
],
'workdir': meson.current_build_dir(),
}

View file

@ -8,7 +8,8 @@ COMMON_SH_SOURCED=1
functionalTestsDir="$(readlink -f "$(dirname "${BASH_SOURCE[0]-$0}")")" functionalTestsDir="$(readlink -f "$(dirname "${BASH_SOURCE[0]-$0}")")"
source "$functionalTestsDir/common/vars-and-functions.sh" source "$functionalTestsDir/common/vars.sh"
source "$functionalTestsDir/common/functions.sh"
source "$functionalTestsDir/common/init.sh" source "$functionalTestsDir/common/init.sh"
if [[ -n "${NIX_DAEMON_PACKAGE:-}" ]]; then if [[ -n "${NIX_DAEMON_PACKAGE:-}" ]]; then

View file

@ -1,10 +1,10 @@
# NOTE: instances of @variable@ are substituted as defined in /mk/templates.mk # shellcheck shell=bash
set -eu -o pipefail set -eu -o pipefail
if [[ -z "${COMMON_VARS_AND_FUNCTIONS_SH_SOURCED-}" ]]; then if [[ -z "${COMMON_FUNCTIONS_SH_SOURCED-}" ]]; then
COMMON_VARS_AND_FUNCTIONS_SH_SOURCED=1 COMMON_FUNCTIONS_SH_SOURCED=1
isTestOnNixOS() { isTestOnNixOS() {
[[ "${isTestOnNixOS:-}" == 1 ]] [[ "${isTestOnNixOS:-}" == 1 ]]
@ -15,64 +15,14 @@ die() {
exit 1 exit 1
} }
set +x
commonDir="$(readlink -f "$(dirname "${BASH_SOURCE[0]-$0}")")"
source "$commonDir/subst-vars.sh"
# Make sure shellcheck knows all these will be defined by the above generated snippet
: "${bindir?} ${coreutils?} ${dot?} ${SHELL?} ${PAGER?} ${busybox?} ${version?} ${system?} ${BUILD_SHARED_LIBS?}"
source "$commonDir/paths.sh"
source "$commonDir/test-root.sh"
test_nix_conf_dir=$TEST_ROOT/etc
test_nix_conf=$test_nix_conf_dir/nix.conf
export TEST_HOME=$TEST_ROOT/test-home
if ! isTestOnNixOS; then
export NIX_STORE_DIR
if ! NIX_STORE_DIR=$(readlink -f $TEST_ROOT/store 2> /dev/null); then
# Maybe the build directory is symlinked.
export NIX_IGNORE_SYMLINK_STORE=1
NIX_STORE_DIR=$TEST_ROOT/store
fi
export NIX_LOCALSTATE_DIR=$TEST_ROOT/var
export NIX_LOG_DIR=$TEST_ROOT/var/log/nix
export NIX_STATE_DIR=$TEST_ROOT/var/nix
export NIX_CONF_DIR=$test_nix_conf_dir
export NIX_DAEMON_SOCKET_PATH=$TEST_ROOT/dSocket
unset NIX_USER_CONF_FILES
export _NIX_TEST_SHARED=$TEST_ROOT/shared
if [[ -n $NIX_STORE ]]; then
export _NIX_TEST_NO_SANDBOX=1
fi
export _NIX_IN_TEST=$TEST_ROOT/shared
export _NIX_TEST_NO_LSOF=1
export NIX_REMOTE=${NIX_REMOTE_-}
fi # ! isTestOnNixOS
unset NIX_PATH
export HOME=$TEST_HOME
unset XDG_STATE_HOME
unset XDG_DATA_HOME
unset XDG_CONFIG_HOME
unset XDG_CONFIG_DIRS
unset XDG_CACHE_HOME
export IMPURE_VAR1=foo
export IMPURE_VAR2=bar
cacheDir=$TEST_ROOT/binary-cache
readLink() { readLink() {
# TODO fix this
# shellcheck disable=SC2012
ls -l "$1" | sed 's/.*->\ //' ls -l "$1" | sed 's/.*->\ //'
} }
clearProfiles() { clearProfiles() {
profiles="$HOME"/.local/state/nix/profiles profiles="$HOME/.local/state/nix/profiles"
rm -rf "$profiles" rm -rf "$profiles"
} }
@ -105,11 +55,11 @@ doClearStore() {
} }
clearCache() { clearCache() {
rm -rf "$cacheDir" rm -rf "${cacheDir?}"
} }
clearCacheCache() { clearCacheCache() {
rm -f $TEST_HOME/.cache/nix/binary-cache* rm -f "$TEST_HOME/.cache/nix/binary-cache"*
} }
startDaemon() { startDaemon() {
@ -122,7 +72,7 @@ startDaemon() {
return return
fi fi
# Start the daemon, wait for the socket to appear. # Start the daemon, wait for the socket to appear.
rm -f $NIX_DAEMON_SOCKET_PATH rm -f "$NIX_DAEMON_SOCKET_PATH"
PATH=$DAEMON_PATH nix --extra-experimental-features 'nix-command' daemon & PATH=$DAEMON_PATH nix --extra-experimental-features 'nix-command' daemon &
_NIX_TEST_DAEMON_PID=$! _NIX_TEST_DAEMON_PID=$!
export _NIX_TEST_DAEMON_PID export _NIX_TEST_DAEMON_PID
@ -151,14 +101,14 @@ killDaemon() {
if [[ "${_NIX_TEST_DAEMON_PID-}" == '' ]]; then if [[ "${_NIX_TEST_DAEMON_PID-}" == '' ]]; then
return return
fi fi
kill $_NIX_TEST_DAEMON_PID kill "$_NIX_TEST_DAEMON_PID"
for i in {0..100}; do for i in {0..100}; do
kill -0 $_NIX_TEST_DAEMON_PID 2> /dev/null || break kill -0 "$_NIX_TEST_DAEMON_PID" 2> /dev/null || break
sleep 0.1 sleep 0.1
done done
kill -9 $_NIX_TEST_DAEMON_PID 2> /dev/null || true kill -9 "$_NIX_TEST_DAEMON_PID" 2> /dev/null || true
wait $_NIX_TEST_DAEMON_PID || true wait "$_NIX_TEST_DAEMON_PID" || true
rm -f $NIX_DAEMON_SOCKET_PATH rm -f "$NIX_DAEMON_SOCKET_PATH"
# Indicate daemon is stopped # Indicate daemon is stopped
unset _NIX_TEST_DAEMON_PID unset _NIX_TEST_DAEMON_PID
# Restore old nix remote # Restore old nix remote
@ -177,14 +127,11 @@ restartDaemon() {
startDaemon startDaemon
} }
if [[ $(uname) == Linux ]] && [[ -L /proc/self/ns/user ]] && unshare --user true; then
_canUseSandbox=1
fi
isDaemonNewer () { isDaemonNewer () {
[[ -n "${NIX_DAEMON_PACKAGE:-}" ]] || return 0 [[ -n "${NIX_DAEMON_PACKAGE:-}" ]] || return 0
local requiredVersion="$1" local requiredVersion="$1"
local daemonVersion=$($NIX_DAEMON_PACKAGE/bin/nix daemon --version | cut -d' ' -f3) local daemonVersion
daemonVersion=$("$NIX_DAEMON_PACKAGE/bin/nix" daemon --version | cut -d' ' -f3)
[[ $(nix eval --expr "builtins.compareVersions ''$daemonVersion'' ''$requiredVersion''") -ge 0 ]] [[ $(nix eval --expr "builtins.compareVersions ''$daemonVersion'' ''$requiredVersion''") -ge 0 ]]
} }
@ -237,7 +184,7 @@ expect() {
shift shift
"$@" && res=0 || res="$?" "$@" && res=0 || res="$?"
# also match "negative" codes, which wrap around to >127 # also match "negative" codes, which wrap around to >127
if [[ $res -ne $expected && $res -ne $[256 + expected] ]]; then if [[ $res -ne $expected && $res -ne $((256 + expected)) ]]; then
echo "Expected exit code '$expected' but got '$res' from command ${*@Q}" >&2 echo "Expected exit code '$expected' but got '$res' from command ${*@Q}" >&2
return 1 return 1
fi fi
@ -252,7 +199,7 @@ expectStderr() {
shift shift
"$@" 2>&1 && res=0 || res="$?" "$@" 2>&1 && res=0 || res="$?"
# also match "negative" codes, which wrap around to >127 # also match "negative" codes, which wrap around to >127
if [[ $res -ne $expected && $res -ne $[256 + expected] ]]; then if [[ $res -ne $expected && $res -ne $((256 + expected)) ]]; then
echo "Expected exit code '$expected' but got '$res' from command ${*@Q}" >&2 echo "Expected exit code '$expected' but got '$res' from command ${*@Q}" >&2
return 1 return 1
fi fi
@ -267,7 +214,7 @@ expectStderr() {
# error: This error is expected # error: This error is expected
# EOF # EOF
assertStderr() { assertStderr() {
diff -u /dev/stdin <($@ 2>/dev/null 2>&1) diff -u /dev/stdin <("$@" 2>/dev/null 2>&1)
} }
needLocalStore() { needLocalStore() {
@ -283,11 +230,9 @@ buggyNeedLocalStore() {
enableFeatures() { enableFeatures() {
local features="$1" local features="$1"
sed -i 's/experimental-features .*/& '"$features"'/' "$test_nix_conf_dir"/nix.conf sed -i 's/experimental-features .*/& '"$features"'/' "${test_nix_conf?}"
} }
set -x
onError() { onError() {
set +x set +x
echo "$0: test failed at:" >&2 echo "$0: test failed at:" >&2
@ -311,15 +256,15 @@ callerPrefix() {
local i file line fn savedFn local i file line fn savedFn
# Use `caller` # Use `caller`
for i in $(seq 0 100); do for i in $(seq 0 100); do
caller $i > /dev/null || { caller "$i" > /dev/null || {
if [[ -n "${file:-}" ]]; then if [[ -n "${file:-}" ]]; then
echo "$file:$line: ${savedFn+in call to $savedFn: }" echo "$file:$line: ${savedFn+in call to $savedFn: }"
fi fi
break break
} }
line="$(caller $i | cut -d' ' -f1)" line="$(caller "$i" | cut -d' ' -f1)"
fn="$(caller $i | cut -d' ' -f2)" fn="$(caller "$i" | cut -d' ' -f2)"
file="$(caller $i | cut -d' ' -f3)" file="$(caller "$i" | cut -d' ' -f3)"
if [[ $file != "${BASH_SOURCE[0]}" ]]; then if [[ $file != "${BASH_SOURCE[0]}" ]]; then
echo "$file:$line: ${savedFn+in call to $savedFn: }" echo "$file:$line: ${savedFn+in call to $savedFn: }"
return return
@ -342,7 +287,7 @@ checkGrepArgs() {
for arg in "$@"; do for arg in "$@"; do
if [[ "$arg" != "${arg//$'\n'/_}" ]]; then if [[ "$arg" != "${arg//$'\n'/_}" ]]; then
echo "$(callerPrefix)newline not allowed in arguments; grep would try each line individually as if connected by an OR operator" >&2 echo "$(callerPrefix)newline not allowed in arguments; grep would try each line individually as if connected by an OR operator" >&2
return -101 return 155 # = -101 mod 256
fi fi
done done
} }
@ -400,4 +345,4 @@ count() {
trap onError ERR trap onError ERR
fi # COMMON_VARS_AND_FUNCTIONS_SH_SOURCED fi # COMMON_FUNCTIONS_SH_SOURCED

View file

@ -7,10 +7,10 @@ if isTestOnNixOS; then
mkdir -p "$test_nix_conf_dir" "$TEST_HOME" mkdir -p "$test_nix_conf_dir" "$TEST_HOME"
export NIX_USER_CONF_FILES="$test_nix_conf_dir/nix.conf" export NIX_USER_CONF_FILES="$test_nix_conf"
mkdir -p "$test_nix_conf_dir" "$TEST_HOME" mkdir -p "$test_nix_conf_dir" "$TEST_HOME"
! test -e "$test_nix_conf" ! test -e "$test_nix_conf"
cat > "$test_nix_conf_dir/nix.conf" <<EOF cat > "$test_nix_conf" <<EOF
# TODO: this is not needed for all tests and prevents stable commands from be tested in isolation # TODO: this is not needed for all tests and prevents stable commands from be tested in isolation
experimental-features = nix-command flakes experimental-features = nix-command flakes
flake-registry = $TEST_ROOT/registry.json flake-registry = $TEST_ROOT/registry.json

View file

@ -0,0 +1,5 @@
configure_file(
input : 'subst-vars.sh.in',
output : 'subst-vars.sh',
configuration : test_confdata,
)

View file

@ -1,14 +1,25 @@
# shellcheck shell=bash # shellcheck shell=bash
set -eu -o pipefail
if [[ -z "${COMMON_PATHS_SH_SOURCED-}" ]]; then
COMMON_PATHS_SH_SOURCED=1
commonDir="$(readlink -f "$(dirname "${BASH_SOURCE[0]-$0}")")" commonDir="$(readlink -f "$(dirname "${BASH_SOURCE[0]-$0}")")"
# Since this is a generated file # Since these are generated files
# shellcheck disable=SC1091
source "$commonDir/functions.sh"
# shellcheck disable=SC1091 # shellcheck disable=SC1091
source "$commonDir/subst-vars.sh" source "$commonDir/subst-vars.sh"
# Make sure shellcheck knows this will be defined by the above generated snippet # Make sure shellcheck knows this will be defined by the above generated snippet
: "${bindir?}" : "${bash?}" "${bindir?}"
if ! isTestOnNixOS; then
export SHELL="$bash"
export PATH="$bindir:$PATH" export PATH="$bindir:$PATH"
fi
if [[ -n "${NIX_CLIENT_PACKAGE:-}" ]]; then if [[ -n "${NIX_CLIENT_PACKAGE:-}" ]]; then
export PATH="$NIX_CLIENT_PACKAGE/bin":$PATH export PATH="$NIX_CLIENT_PACKAGE/bin":$PATH
@ -18,3 +29,5 @@ DAEMON_PATH="$PATH"
if [[ -n "${NIX_DAEMON_PACKAGE:-}" ]]; then if [[ -n "${NIX_DAEMON_PACKAGE:-}" ]]; then
DAEMON_PATH="${NIX_DAEMON_PACKAGE}/bin:$DAEMON_PATH" DAEMON_PATH="${NIX_DAEMON_PACKAGE}/bin:$DAEMON_PATH"
fi fi
fi # COMMON_PATHS_SH_SOURCED

View file

@ -4,22 +4,14 @@ if [[ -z "${COMMON_SUBST_VARS_SH_SOURCED-}" ]]; then
COMMON_SUBST_VARS_SH_SOURCED=1 COMMON_SUBST_VARS_SH_SOURCED=1
bash=@bash@
bindir=@bindir@ bindir=@bindir@
export coreutils=@coreutils@ coreutils=@coreutils@
#lsof=@lsof@
export dot=@dot@ dot=@dot@
export PAGER=cat busybox="@sandbox_shell@"
export busybox="@sandbox_shell@"
export version=@PACKAGE_VERSION@ version=@PACKAGE_VERSION@
export system=@system@ system=@system@
export BUILD_SHARED_LIBS=@BUILD_SHARED_LIBS@
if ! isTestOnNixOS; then
export SHELL="@bash@"
export PATH=@bindir@:$PATH
fi
fi fi

View file

@ -0,0 +1,72 @@
# shellcheck shell=bash
set -eu -o pipefail
if [[ -z "${COMMON_VARS_SH_SOURCED-}" ]]; then
COMMON_VARS_SH_SOURCED=1
commonDir="$(readlink -f "$(dirname "${BASH_SOURCE[0]-$0}")")"
# Since this is a generated file
# shellcheck disable=SC1091
source "$commonDir/subst-vars.sh"
# Make sure shellcheck knows all these will be defined by the above generated snippet
: "${bindir?} ${coreutils?} ${dot?} ${SHELL?} ${busybox?} ${version?} ${system?}"
export coreutils dot busybox version system
export PAGER=cat
source "$commonDir/paths.sh"
source "$commonDir/test-root.sh"
test_nix_conf_dir=$TEST_ROOT/etc
# Used in other files
# shellcheck disable=SC2034
test_nix_conf=$test_nix_conf_dir/nix.conf
export TEST_HOME=$TEST_ROOT/test-home
if ! isTestOnNixOS; then
export NIX_STORE_DIR
if ! NIX_STORE_DIR=$(readlink -f "$TEST_ROOT/store" 2> /dev/null); then
# Maybe the build directory is symlinked.
export NIX_IGNORE_SYMLINK_STORE=1
NIX_STORE_DIR=$TEST_ROOT/store
fi
export NIX_LOCALSTATE_DIR=$TEST_ROOT/var
export NIX_LOG_DIR=$TEST_ROOT/var/log/nix
export NIX_STATE_DIR=$TEST_ROOT/var/nix
export NIX_CONF_DIR=$test_nix_conf_dir
export NIX_DAEMON_SOCKET_PATH=$TEST_ROOT/dSocket
unset NIX_USER_CONF_FILES
export _NIX_TEST_SHARED=$TEST_ROOT/shared
if [[ -n $NIX_STORE ]]; then
export _NIX_TEST_NO_SANDBOX=1
fi
export _NIX_IN_TEST=$TEST_ROOT/shared
export _NIX_TEST_NO_LSOF=1
export NIX_REMOTE=${NIX_REMOTE_-}
fi # ! isTestOnNixOS
unset NIX_PATH
export HOME=$TEST_HOME
unset XDG_STATE_HOME
unset XDG_DATA_HOME
unset XDG_CONFIG_HOME
unset XDG_CONFIG_DIRS
unset XDG_CACHE_HOME
export IMPURE_VAR1=foo
export IMPURE_VAR2=bar
# Used in other files
# shellcheck disable=SC2034
cacheDir=$TEST_ROOT/binary-cache
if [[ $(uname) == Linux ]] && [[ -L /proc/self/ns/user ]] && unshare --user true; then
_canUseSandbox=1
fi
fi # COMMON_VARS_SH_SOURCED

View file

@ -3,7 +3,7 @@
source common/test-root.sh source common/test-root.sh
source common/paths.sh source common/paths.sh
set -o pipefail set -eu -o pipefail
source characterisation/framework.sh source characterisation/framework.sh

View file

@ -0,0 +1,19 @@
configure_file(
input : 'config.nix.in',
output : 'config.nix',
configuration : test_confdata,
)
suites += {
'name': 'dyn-drv',
'deps': [],
'tests': [
'text-hashed-output.sh',
'recursive-mod-json.sh',
'build-built-drv.sh',
'eval-outputOf.sh',
'dep-built-drv.sh',
'old-daemon-error-hack.sh',
],
'workdir': meson.current_build_dir(),
}

View file

@ -0,0 +1,28 @@
suites += {
'name': 'flakes',
'deps': [],
'tests': [
'flakes.sh',
'develop.sh',
'edit.sh',
'run.sh',
'mercurial.sh',
'circular.sh',
'init.sh',
'inputs.sh',
'follow-paths.sh',
'bundle.sh',
'check.sh',
'unlocked-override.sh',
'absolute-paths.sh',
'absolute-attr-paths.sh',
'build-paths.sh',
'flake-in-submodule.sh',
'prefetch.sh',
'eval-cache.sh',
'search-root.sh',
'config.sh',
'show.sh',
],
'workdir': meson.current_build_dir(),
}

View file

@ -0,0 +1,8 @@
suites += {
'name': 'git-hashing',
'deps': [],
'tests': [
'simple.sh',
],
'workdir': meson.current_build_dir(),
}

View file

@ -1,4 +1,5 @@
source ../common/vars-and-functions.sh source ../common/vars.sh
source ../common/functions.sh
TODO_NixOS TODO_NixOS

View file

@ -0,0 +1,18 @@
suites += {
'name': 'local-overlay-store',
'deps': [],
'tests': [
'check-post-init.sh',
'redundant-add.sh',
'build.sh',
'bad-uris.sh',
'add-lower.sh',
'delete-refs.sh',
'delete-duplicate.sh',
'gc.sh',
'verify.sh',
'optimise.sh',
'stale-file-handle.sh',
],
'workdir': meson.current_build_dir(),
}

View file

@ -0,0 +1,266 @@
project('nix-functional-tests', 'cpp',
version : files('.version'),
default_options : [
'cpp_std=c++2a',
# TODO(Qyriad): increase the warning level
'warning_level=1',
'debug=true',
'optimization=2',
'errorlogs=true', # Please print logs for tests that fail
],
meson_version : '>= 1.3',
license : 'LGPL-2.1-or-later',
)
fs = import('fs')
# Need to combine source and build trees
run_command(
'rsync',
'-a',
'--copy-unsafe-links',
meson.current_source_dir() / '',
meson.current_build_dir() / '',
)
# This current-source-escaping relative is no good because we don't know
# where the build directory will be, therefore we fix it up. Once the
# Make build system is gone, we should think about doing this better.
scripts_dir = fs.relative_to(
meson.current_source_dir() / '..' / '..' / 'scripts',
meson.current_build_dir(),
)
run_command(
'sed',
'-i', meson.current_build_dir() / 'bash-profile.sh',
'-e', 's^../../scripts^@0@^'.format(scripts_dir),
)
nix = find_program('nix')
bash = find_program('bash', native : true)
busybox = find_program('busybox', native : true, required : false)
coreutils = find_program('coreutils', native : true)
dot = find_program('dot', native : true, required : false)
nix_bin_dir = fs.parent(nix.full_path())
test_confdata = {
'bindir': nix_bin_dir,
'coreutils': fs.parent(coreutils.full_path()),
'dot': dot.found() ? dot.full_path() : '',
'bash': bash.full_path(),
'sandbox_shell': busybox.found() ? busybox.full_path() : '',
'PACKAGE_VERSION': meson.project_version(),
'system': host_machine.cpu_family() + '-' + host_machine.system(),
}
# Just configures `common/vars-and-functions.sh.in`.
# Done as a subdir() so Meson places it under `common` in the build directory as well.
subdir('common')
config_nix_in = configure_file(
input : 'config.nix.in',
output : 'config.nix',
configuration : test_confdata,
)
suites = [
{
'name' : 'main',
'deps': [],
'tests': [
'test-infra.sh',
'gc.sh',
'nix-collect-garbage-d.sh',
'remote-store.sh',
'legacy-ssh-store.sh',
'lang.sh',
'lang-gc.sh',
'characterisation-test-infra.sh',
'experimental-features.sh',
'fetchMercurial.sh',
'gc-auto.sh',
'user-envs.sh',
'user-envs-migration.sh',
'binary-cache.sh',
'multiple-outputs.sh',
'nix-build.sh',
'gc-concurrent.sh',
'repair.sh',
'fixed.sh',
'export-graph.sh',
'timeout.sh',
'fetchGitRefs.sh',
'gc-runtime.sh',
'tarball.sh',
'fetchGit.sh',
'fetchurl.sh',
'fetchPath.sh',
'fetchTree-file.sh',
'simple.sh',
'referrers.sh',
'optimise-store.sh',
'substitute-with-invalid-ca.sh',
'signing.sh',
'hash-convert.sh',
'hash-path.sh',
'gc-non-blocking.sh',
'check.sh',
'nix-shell.sh',
'check-refs.sh',
'build-remote-input-addressed.sh',
'secure-drv-outputs.sh',
'restricted.sh',
'fetchGitSubmodules.sh',
'fetchGitVerification.sh',
'readfile-context.sh',
'nix-channel.sh',
'recursive.sh',
'dependencies.sh',
'check-reqs.sh',
'build-remote-content-addressed-fixed.sh',
'build-remote-content-addressed-floating.sh',
'build-remote-trustless-should-pass-0.sh',
'build-remote-trustless-should-pass-1.sh',
'build-remote-trustless-should-pass-2.sh',
'build-remote-trustless-should-pass-3.sh',
'build-remote-trustless-should-fail-0.sh',
'build-remote-with-mounted-ssh-ng.sh',
'nar-access.sh',
'impure-eval.sh',
'pure-eval.sh',
'eval.sh',
'repl.sh',
'binary-cache-build-remote.sh',
'search.sh',
'logging.sh',
'export.sh',
'config.sh',
'add.sh',
'chroot-store.sh',
'filter-source.sh',
'misc.sh',
'dump-db.sh',
'linux-sandbox.sh',
'supplementary-groups.sh',
'build-dry.sh',
'structured-attrs.sh',
'shell.sh',
'brotli.sh',
'zstd.sh',
'compression-levels.sh',
'nix-copy-ssh.sh',
'nix-copy-ssh-ng.sh',
'post-hook.sh',
'function-trace.sh',
'fmt.sh',
'eval-store.sh',
'why-depends.sh',
'derivation-json.sh',
'derivation-advanced-attributes.sh',
'import-derivation.sh',
'nix_path.sh',
'case-hack.sh',
'placeholders.sh',
'ssh-relay.sh',
'build.sh',
'build-delete.sh',
'output-normalization.sh',
'selfref-gc.sh',
'db-migration.sh',
'bash-profile.sh',
'pass-as-file.sh',
'nix-profile.sh',
'suggestions.sh',
'store-info.sh',
'fetchClosure.sh',
'completions.sh',
'impure-derivations.sh',
'path-from-hash-part.sh',
'path-info.sh',
'toString-path.sh',
'read-only-store.sh',
'nested-sandboxing.sh',
'impure-env.sh',
'debugger.sh',
'extra-sandbox-profile.sh',
'help.sh',
],
'workdir': meson.current_build_dir(),
},
]
nix_store = dependency('nix-store', required : false)
if nix_store.found()
subdir('test-libstoreconsumer')
suites += {
'name': 'libstoreconsumer',
'deps': [
libstoreconsumer_tester,
],
'tests': [
'test-libstoreconsumer.sh',
],
'workdir': meson.current_build_dir(),
}
endif
# Plugin tests require shared libraries support.
nix_expr = dependency('nix-expr', required : false)
if nix_expr.found() and get_option('default_library') != 'static'
subdir('plugins')
suites += {
'name': 'plugins',
'deps': [
libplugintest,
],
'tests': [
'plugins.sh',
],
'workdir': meson.current_build_dir(),
}
endif
subdir('ca')
subdir('dyn-drv')
subdir('flakes')
subdir('git-hashing')
subdir('local-overlay-store')
foreach suite : suites
foreach script : suite['tests']
workdir = suite['workdir']
prefix = fs.relative_to(workdir, meson.project_build_root())
script = script
# Turns, e.g., `tests/functional/flakes/show.sh` into a Meson test target called
# `functional-flakes-show`.
name = fs.replace_suffix(prefix / script, '')
test(
name,
bash,
args: [
'-x',
'-e',
'-u',
'-o', 'pipefail',
script,
],
suite : suite['name'],
env : {
'TEST_NAME': name,
'NIX_REMOTE': '',
'PS4': '+(${BASH_SOURCE[0]-$0}:$LINENO) ',
},
# some tests take 15+ seconds even on an otherwise idle machine, on a loaded machine
# this can easily drive them to failure. give them more time than default of 30sec
timeout : 300,
# Used for target dependency/ordering tracking, not adding compiler flags or anything.
depends : suite['deps'],
workdir : workdir,
# Won't pass until man pages are generated
should_fail : suite['name'] == 'main' and script == 'help.sh'
)
endforeach
endforeach

View file

@ -1,3 +1,5 @@
set -eu -o pipefail
export NIX_BIN_DIR=$(dirname $(type -p nix)) export NIX_BIN_DIR=$(dirname $(type -p nix))
# TODO Get Nix and its closure more flexibly # TODO Get Nix and its closure more flexibly
export EXTRA_SANDBOX="/nix/store $(dirname $NIX_BIN_DIR)" export EXTRA_SANDBOX="/nix/store $(dirname $NIX_BIN_DIR)"

View file

@ -6,7 +6,10 @@ mkDerivation {
name = "nested-sandboxing"; name = "nested-sandboxing";
busybox = builtins.getEnv "busybox"; busybox = builtins.getEnv "busybox";
EXTRA_SANDBOX = builtins.getEnv "EXTRA_SANDBOX"; EXTRA_SANDBOX = builtins.getEnv "EXTRA_SANDBOX";
buildCommand = if altitude == 0 then '' buildCommand = ''
set -x
set -eu -o pipefail
'' + (if altitude == 0 then ''
echo Deep enough! > $out echo Deep enough! > $out
'' else '' '' else ''
cp -r ${../common} ./common cp -r ${../common} ./common
@ -20,5 +23,5 @@ mkDerivation {
source ./nested-sandboxing/command.sh source ./nested-sandboxing/command.sh
runNixBuild ${storeFun} ${toString altitude} >> $out runNixBuild ${storeFun} ${toString altitude} >> $out
''; '');
} }

View file

@ -0,0 +1,117 @@
{ lib
, stdenv
, mkMesonDerivation
, releaseTools
, meson
, ninja
, pkg-config
, rsync
, jq
, git
, mercurial
, util-linux
, nix-store
, nix-expr
, nix-ng
, rapidcheck
, gtest
, runCommand
, busybox-sandbox-shell ? null
# Configuration Options
, version
# For running the functional tests against a different pre-built Nix.
, test-daemon ? null
}:
let
inherit (lib) fileset;
in
mkMesonDerivation (finalAttrs: {
pname = "nix-functional-tests";
inherit version;
workDir = ./.;
fileset = fileset.unions [
../../scripts/nix-profile.sh.in
../../.version
../../tests/functional
./.
];
# Hack for sake of the dev shell
passthru.baseNativeBuildInputs = [
meson
ninja
pkg-config
rsync
jq
git
mercurial
] ++ lib.optionals stdenv.hostPlatform.isLinux [
# For various sandboxing tests that needs a statically-linked shell,
# etc.
busybox-sandbox-shell
# For Overlay FS tests need `mount`, `umount`, and `unshare`.
# TODO use `unixtools` to be precise over which executables instead?
util-linux
];
nativeBuildInputs = finalAttrs.passthru.baseNativeBuildInputs ++ [
nix-ng
];
buildInputs = [
nix-store
nix-expr
];
preConfigure =
# "Inline" .version so it's not a symlink, and includes the suffix.
# Do the meson utils, without modification.
''
chmod u+w ./.version
echo ${version} > ../../../.version
''
# TEMP hack for Meson before make is gone, where
# `src/nix-functional-tests` is during the transition a symlink and
# not the actual directory directory.
+ ''
cd $(readlink -e $PWD)
echo $PWD | grep tests/functional
'';
mesonCheckFlags = [
"--print-errorlogs"
];
preCheck =
# See https://github.com/NixOS/nix/issues/2523
# Occurs often in tests since https://github.com/NixOS/nix/pull/9900
lib.optionalString stdenv.hostPlatform.isDarwin ''
export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES
'';
doCheck = true;
installPhase = ''
touch $out
'';
meta = {
platforms = lib.platforms.unix;
};
} // lib.optionalAttrs (test-daemon != null) {
NIX_DAEMON_PACKAGE = test-daemon;
})

View file

@ -2,10 +2,11 @@
source common.sh source common.sh
if [[ $BUILD_SHARED_LIBS != 1 ]]; then for ext in so dylib; do
skipTest "Plugins are not supported" plugin="$PWD/plugins/libplugintest.$ext"
fi [[ -f "$plugin" ]] && break
done
res=$(nix --option setting-set true --option plugin-files $PWD/plugins/libplugintest* eval --expr builtins.anotherNull) res=$(nix --option setting-set true --option plugin-files "$plugin" eval --expr builtins.anotherNull)
[ "$res"x = "nullx" ] [ "$res"x = "nullx" ]

View file

@ -0,0 +1,16 @@
libplugintest = shared_module(
'plugintest',
'plugintest.cc',
cpp_args : [
# TODO(Qyriad): Yes this is how the autoconf+Make system did it.
# It would be nice for our headers to be idempotent instead.
'-include', 'config-util.hh',
'-include', 'config-store.hh',
# '-include', 'config-fetchers.hh',
'-include', 'config-expr.hh',
],
dependencies : [
dependency('nix-expr'),
],
build_by_default : false,
)

View file

@ -16,9 +16,6 @@ nix-instantiate --restrict-eval ./simple.nix -I src1=simple.nix -I src2=config.n
(! nix-instantiate --restrict-eval --eval -E 'builtins.readFile ./simple.nix') (! nix-instantiate --restrict-eval --eval -E 'builtins.readFile ./simple.nix')
nix-instantiate --restrict-eval --eval -E 'builtins.readFile ./simple.nix' -I src=../.. nix-instantiate --restrict-eval --eval -E 'builtins.readFile ./simple.nix' -I src=../..
(! nix-instantiate --restrict-eval --eval -E 'builtins.readDir ../../src/nix-channel')
nix-instantiate --restrict-eval --eval -E 'builtins.readDir ../../src/nix-channel' -I src=../../src
expectStderr 1 nix-instantiate --restrict-eval --eval -E 'let __nixPath = [ { prefix = "foo"; path = ./.; } ]; in builtins.readFile <foo/simple.nix>' | grepQuiet "forbidden in restricted mode" expectStderr 1 nix-instantiate --restrict-eval --eval -E 'let __nixPath = [ { prefix = "foo"; path = ./.; } ]; in builtins.readFile <foo/simple.nix>' | grepQuiet "forbidden in restricted mode"
nix-instantiate --restrict-eval --eval -E 'let __nixPath = [ { prefix = "foo"; path = ./.; } ]; in builtins.readFile <foo/simple.nix>' -I src=. nix-instantiate --restrict-eval --eval -E 'let __nixPath = [ { prefix = "foo"; path = ./.; } ]; in builtins.readFile <foo/simple.nix>' -I src=.

View file

@ -0,0 +1,14 @@
libstoreconsumer_tester = executable(
'test-libstoreconsumer',
'main.cc',
cpp_args : [
# TODO(Qyriad): Yes this is how the autoconf+Make system did it.
# It would be nice for our headers to be idempotent instead.
'-include', 'config-util.hh',
'-include', 'config-store.hh',
],
dependencies : [
dependency('nix-store'),
],
build_by_default : false,
)