tests: Add hydraJobs.tests.functional_*

This commit is contained in:
Robert Hensing 2024-06-16 12:13:07 +02:00
parent dc720f89f2
commit 439022c5ac
13 changed files with 273 additions and 28 deletions

View file

@ -23,7 +23,7 @@ EOF
chmod +x "$TEST_ROOT/post-build-hook.sh" chmod +x "$TEST_ROOT/post-build-hook.sh"
rm -f "$TEST_ROOT/post-hook-counter" rm -f "$TEST_ROOT/post-hook-counter"
echo "post-build-hook = $TEST_ROOT/post-build-hook.sh" >> "$NIX_CONF_DIR/nix.conf" echo "post-build-hook = $TEST_ROOT/post-build-hook.sh" >> "$test_nix_conf"
} }
registerBuildHook registerBuildHook

View file

@ -1,5 +1,30 @@
# shellcheck shell=bash # shellcheck shell=bash
# for shellcheck
: "${test_nix_conf_dir?}" "${test_nix_conf?}"
if isTestOnNixOS; then
mkdir -p "$test_nix_conf_dir" "$TEST_HOME"
export NIX_USER_CONF_FILES="$test_nix_conf_dir/nix.conf"
mkdir -p "$test_nix_conf_dir" "$TEST_HOME"
! test -e "$test_nix_conf"
cat > "$test_nix_conf_dir/nix.conf" <<EOF
experimental-features = nix-command flakes
flake-registry = $TEST_ROOT/registry.json
show-trace = true
EOF
# When we're doing everything in the same store, we need to bring
# dependencies into context.
sed -i "$(dirname "${BASH_SOURCE[0]}")"/../config.nix \
-e 's^\(shell\) = "/nix/store/\([^/]*\)/\(.*\)";^\1 = builtins.appendContext "/nix/store/\2" { "/nix/store/\2".path = true; } + "/\3";^' \
-e 's^\(path\) = "/nix/store/\([^/]*\)/\(.*\)";^\1 = builtins.appendContext "/nix/store/\2" { "/nix/store/\2".path = true; } + "/\3";^' \
;
else
test -n "$TEST_ROOT" test -n "$TEST_ROOT"
# We would delete any daemon socket, so let's stop the daemon first. # We would delete any daemon socket, so let's stop the daemon first.
killDaemon killDaemon
@ -41,3 +66,5 @@ EOF
nix-store --init nix-store --init
# Sanity check # Sanity check
test -e "$NIX_STATE_DIR"/db/db.sqlite test -e "$NIX_STATE_DIR"/db/db.sqlite
fi # !isTestOnNixOS

View file

@ -1,11 +1,14 @@
# NOTE: instances of @variable@ are substituted as defined in /mk/templates.mk # NOTE: instances of @variable@ are substituted as defined in /mk/templates.mk
export PATH=@bindir@:$PATH if ! isTestOnNixOS; then
export SHELL="@bash@"
export PATH=@bindir@:$PATH
fi
export coreutils=@coreutils@ export coreutils=@coreutils@
#lsof=@lsof@ #lsof=@lsof@
export dot=@dot@ export dot=@dot@
export SHELL="@bash@"
export PAGER=cat export PAGER=cat
export busybox="@sandbox_shell@" export busybox="@sandbox_shell@"

View file

@ -6,6 +6,15 @@ if [[ -z "${COMMON_VARS_AND_FUNCTIONS_SH_SOURCED-}" ]]; then
COMMON_VARS_AND_FUNCTIONS_SH_SOURCED=1 COMMON_VARS_AND_FUNCTIONS_SH_SOURCED=1
isTestOnNixOS() {
[[ "${isTestOnNixOS:-}" == 1 ]]
}
die() {
echo "fatal error: $*" >&2
exit 1
}
set +x set +x
commonDir="$(readlink -f "$(dirname "${BASH_SOURCE[0]-$0}")")" commonDir="$(readlink -f "$(dirname "${BASH_SOURCE[0]-$0}")")"
@ -15,27 +24,35 @@ source "$commonDir/subst-vars.sh"
: "${PATH?} ${coreutils?} ${dot?} ${SHELL?} ${PAGER?} ${busybox?} ${version?} ${system?} ${BUILD_SHARED_LIBS?}" : "${PATH?} ${coreutils?} ${dot?} ${SHELL?} ${PAGER?} ${busybox?} ${version?} ${system?} ${BUILD_SHARED_LIBS?}"
export TEST_ROOT=$(realpath ${TMPDIR:-/tmp}/nix-test)/${TEST_NAME:-default/tests\/functional//} export TEST_ROOT=$(realpath ${TMPDIR:-/tmp}/nix-test)/${TEST_NAME:-default/tests\/functional//}
export NIX_STORE_DIR test_nix_conf_dir=$TEST_ROOT/etc
if ! NIX_STORE_DIR=$(readlink -f $TEST_ROOT/store 2> /dev/null); then test_nix_conf=$test_nix_conf_dir/nix.conf
# Maybe the build directory is symlinked.
export NIX_IGNORE_SYMLINK_STORE=1
NIX_STORE_DIR=$TEST_ROOT/store
fi
export NIX_LOCALSTATE_DIR=$TEST_ROOT/var
export NIX_LOG_DIR=$TEST_ROOT/var/log/nix
export NIX_STATE_DIR=$TEST_ROOT/var/nix
export NIX_CONF_DIR=$TEST_ROOT/etc
export NIX_DAEMON_SOCKET_PATH=$TEST_ROOT/dSocket
unset NIX_USER_CONF_FILES
export _NIX_TEST_SHARED=$TEST_ROOT/shared
if [[ -n $NIX_STORE ]]; then
export _NIX_TEST_NO_SANDBOX=1
fi
export _NIX_IN_TEST=$TEST_ROOT/shared
export _NIX_TEST_NO_LSOF=1
export NIX_REMOTE=${NIX_REMOTE_-}
unset NIX_PATH
export TEST_HOME=$TEST_ROOT/test-home export 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 export HOME=$TEST_HOME
unset XDG_STATE_HOME unset XDG_STATE_HOME
unset XDG_DATA_HOME unset XDG_DATA_HOME
@ -66,6 +83,10 @@ clearProfiles() {
} }
clearStore() { clearStore() {
if isTestOnNixOS; then
die "clearStore: not supported when testing on NixOS. Is it really needed? If so add conditionals; e.g. if ! isTestOnNixOS; then ..."
fi
echo "clearing store..." echo "clearing store..."
chmod -R +w "$NIX_STORE_DIR" chmod -R +w "$NIX_STORE_DIR"
rm -rf "$NIX_STORE_DIR" rm -rf "$NIX_STORE_DIR"
@ -84,6 +105,10 @@ clearCacheCache() {
} }
startDaemon() { startDaemon() {
if isTestOnNixOS; then
die "startDaemon: not supported when testing on NixOS. Is it really needed? If so add conditionals; e.g. if ! isTestOnNixOS; then ..."
fi
# Dont start the daemon twice, as this would just make it loop indefinitely # Dont start the daemon twice, as this would just make it loop indefinitely
if [[ "${_NIX_TEST_DAEMON_PID-}" != '' ]]; then if [[ "${_NIX_TEST_DAEMON_PID-}" != '' ]]; then
return return
@ -110,6 +135,10 @@ startDaemon() {
} }
killDaemon() { killDaemon() {
if isTestOnNixOS; then
die "killDaemon: not supported when testing on NixOS. Is it really needed? If so add conditionals; e.g. if ! isTestOnNixOS; then ..."
fi
# Dont fail trying to stop a non-existant daemon twice # Dont fail trying to stop a non-existant daemon twice
if [[ "${_NIX_TEST_DAEMON_PID-}" == '' ]]; then if [[ "${_NIX_TEST_DAEMON_PID-}" == '' ]]; then
return return
@ -130,6 +159,10 @@ killDaemon() {
} }
restartDaemon() { restartDaemon() {
if isTestOnNixOS; then
die "restartDaemon: not supported when testing on NixOS. Is it really needed? If so add conditionals; e.g. if ! isTestOnNixOS; then ..."
fi
[[ -z "${_NIX_TEST_DAEMON_PID:-}" ]] && return 0 [[ -z "${_NIX_TEST_DAEMON_PID:-}" ]] && return 0
killDaemon killDaemon
@ -152,6 +185,12 @@ skipTest () {
exit 99 exit 99
} }
TODO_NixOS() {
if isTestOnNixOS; then
skipTest "This test has not been adapted for NixOS yet"
fi
}
requireDaemonNewerThan () { requireDaemonNewerThan () {
isDaemonNewer "$1" || skipTest "Daemon is too old" isDaemonNewer "$1" || skipTest "Daemon is too old"
} }
@ -234,7 +273,7 @@ buggyNeedLocalStore() {
enableFeatures() { enableFeatures() {
local features="$1" local features="$1"
sed -i 's/experimental-features .*/& '"$features"'/' "$NIX_CONF_DIR"/nix.conf sed -i 's/experimental-features .*/& '"$features"'/' "$test_nix_conf_dir"/nix.conf
} }
set -x set -x

View file

@ -20,13 +20,13 @@ startDaemon
varTest env_name value --impure-env env_name=value varTest env_name value --impure-env env_name=value
echo 'impure-env = set_in_config=config_value' >> "$NIX_CONF_DIR/nix.conf" echo 'impure-env = set_in_config=config_value' >> "$test_nix_conf"
set_in_config=daemon_value restartDaemon set_in_config=daemon_value restartDaemon
varTest set_in_config config_value varTest set_in_config config_value
varTest set_in_config client_value --impure-env set_in_config=client_value varTest set_in_config client_value --impure-env set_in_config=client_value
sed -i -e '/^trusted-users =/d' "$NIX_CONF_DIR/nix.conf" sed -i -e '/^trusted-users =/d' "$test_nix_conf"
env_name=daemon_value restartDaemon env_name=daemon_value restartDaemon

View file

@ -31,7 +31,7 @@ requireEnvironment () {
} }
addConfig () { addConfig () {
echo "$1" >> "$NIX_CONF_DIR/nix.conf" echo "$1" >> "$test_nix_conf"
} }
setupConfig () { setupConfig () {

View file

@ -7,7 +7,7 @@ clearStore
rm -f $TEST_ROOT/result rm -f $TEST_ROOT/result
export REMOTE_STORE=file:$TEST_ROOT/remote_store export REMOTE_STORE=file:$TEST_ROOT/remote_store
echo 'require-sigs = false' >> $NIX_CONF_DIR/nix.conf echo 'require-sigs = false' >> $test_nix_conf
restartDaemon restartDaemon

View file

@ -132,4 +132,11 @@ in
ca-fd-leak = runNixOSTestFor "x86_64-linux" ./ca-fd-leak; ca-fd-leak = runNixOSTestFor "x86_64-linux" ./ca-fd-leak;
gzip-content-encoding = runNixOSTestFor "x86_64-linux" ./gzip-content-encoding.nix; gzip-content-encoding = runNixOSTestFor "x86_64-linux" ./gzip-content-encoding.nix;
functional_user = runNixOSTestFor "x86_64-linux" ./functional/as-user.nix;
functional_trusted = runNixOSTestFor "x86_64-linux" ./functional/as-trusted-user.nix;
functional_root = runNixOSTestFor "x86_64-linux" ./functional/as-root.nix;
} }

View file

@ -0,0 +1,12 @@
{
name = "functional-tests-on-nixos_root";
imports = [ ./common.nix ];
testScript = ''
machine.wait_for_unit("multi-user.target")
machine.succeed("""
run-test-suite >&2
""")
'';
}

View file

@ -0,0 +1,18 @@
{
name = "functional-tests-on-nixos_trusted-user";
imports = [ ./common.nix ];
nodes.machine = {
users.users.alice = { isNormalUser = true; };
nix.settings.trusted-users = [ "alice" ];
};
testScript = ''
machine.wait_for_unit("multi-user.target")
machine.succeed("""
export TEST_TRUSTED_USER=1
su --login --command "run-test-suite" alice >&2
""")
'';
}

View file

@ -0,0 +1,16 @@
{
name = "functional-tests-on-nixos_user";
imports = [ ./common.nix ];
nodes.machine = {
users.users.alice = { isNormalUser = true; };
};
testScript = ''
machine.wait_for_unit("multi-user.target")
machine.succeed("""
su --login --command "run-test-suite" alice >&2
""")
'';
}

View file

@ -0,0 +1,76 @@
{ lib, ... }:
let
# FIXME (roberth) reference issue
inputDerivation = pkg: (pkg.overrideAttrs (o: {
disallowedReferences = [ ];
})).inputDerivation;
in
{
imports = [
# Add the quickBuild attribute to the check package
./quick-build.nix
];
# We rarely change the script in a way that benefits from type checking, so
# we skip it to save time.
skipTypeCheck = true;
nodes.machine = { config, pkgs, ... }: {
virtualisation.writableStore = true;
system.extraDependencies = [
(inputDerivation config.nix.package)
];
nix.settings.substituters = lib.mkForce [];
environment.systemPackages = let
run-test-suite = pkgs.writeShellApplication {
name = "run-test-suite";
runtimeInputs = [ pkgs.gnumake pkgs.jq pkgs.git ];
text = ''
set -x
cat /proc/sys/fs/file-max
ulimit -Hn
ulimit -Sn
cd ~
cp -r ${pkgs.nix.overrideAttrs (o: {
name = "nix-configured-source";
outputs = [ "out" ];
separateDebugInfo = false;
disallowedReferences = [ ];
buildPhase = ":";
checkPhase = ":";
installPhase = ''
cp -r . $out
'';
installCheckPhase = ":";
fixupPhase = ":";
doInstallCheck = true;
})} nix
chmod -R +w nix
cd nix
# Tests we don't need
echo >tests/functional/plugins/local.mk
sed -i tests/functional/local.mk \
-e 's!nix_tests += plugins\.sh!!' \
-e 's!nix_tests += test-libstoreconsumer\.sh!!' \
;
export isTestOnNixOS=1
export version=${config.nix.package.version}
export NIX_REMOTE_=daemon
export NIX_REMOTE=daemon
export NIX_STORE=${builtins.storeDir}
make -j1 installcheck --keep-going
'';
};
in [
run-test-suite
pkgs.git
];
};
}

View file

@ -0,0 +1,47 @@
test@{ lib, extendModules, ... }:
let
inherit (lib) mkOption types;
in
{
options = {
quickBuild = mkOption {
description = ''
Whether to perform a "quick" build of the Nix package to test.
When iterating on the functional tests, it's recommended to "set" this
to `true`, so that changes to the functional tests don't require any
recompilation of the package.
You can do so by buildin the `.quickBuild` attribute on the check package,
e.g:
```console
nix build .#hydraJobs.functional_user.quickBuild
```
We don't enable this by default to avoid the mostly unnecessary work of
performing an additional build of the package in cases where we build
the package normally anyway, such as in our pre-merge CI.
'';
type = types.bool;
default = false;
};
};
config = {
passthru.quickBuild =
let withQuickBuild = extendModules { modules = [{ quickBuild = true; }]; };
in withQuickBuild.config.test;
defaults = { pkgs, ... }: {
config = lib.mkIf test.config.quickBuild {
nix.package = pkgs.nix_noTests;
system.forbiddenDependenciesRegexes = [
# This would indicate that the quickBuild feature is broken.
# It could happen if NixOS has a dependency on pkgs.nix instead of
# config.nix.package somewhere.
(builtins.unsafeDiscardStringContext pkgs.nix.outPath)
];
};
};
};
}