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"
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

View file

@ -1,5 +1,30 @@
# 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"
# We would delete any daemon socket, so let's stop the daemon first.
killDaemon
@ -41,3 +66,5 @@ EOF
nix-store --init
# Sanity check
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
export PATH=@bindir@:$PATH
if ! isTestOnNixOS; then
export SHELL="@bash@"
export PATH=@bindir@:$PATH
fi
export coreutils=@coreutils@
#lsof=@lsof@
export dot=@dot@
export SHELL="@bash@"
export PAGER=cat
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
isTestOnNixOS() {
[[ "${isTestOnNixOS:-}" == 1 ]]
}
die() {
echo "fatal error: $*" >&2
exit 1
}
set +x
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?}"
export TEST_ROOT=$(realpath ${TMPDIR:-/tmp}/nix-test)/${TEST_NAME:-default/tests\/functional//}
export NIX_STORE_DIR
if ! NIX_STORE_DIR=$(readlink -f $TEST_ROOT/store 2> /dev/null); then
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_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
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
export _NIX_IN_TEST=$TEST_ROOT/shared
export _NIX_TEST_NO_LSOF=1
export NIX_REMOTE=${NIX_REMOTE_-}
fi # ! isTestOnNixOS
unset NIX_PATH
export TEST_HOME=$TEST_ROOT/test-home
export HOME=$TEST_HOME
unset XDG_STATE_HOME
unset XDG_DATA_HOME
@ -66,6 +83,10 @@ clearProfiles() {
}
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..."
chmod -R +w "$NIX_STORE_DIR"
rm -rf "$NIX_STORE_DIR"
@ -84,6 +105,10 @@ clearCacheCache() {
}
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
if [[ "${_NIX_TEST_DAEMON_PID-}" != '' ]]; then
return
@ -110,6 +135,10 @@ startDaemon() {
}
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
if [[ "${_NIX_TEST_DAEMON_PID-}" == '' ]]; then
return
@ -130,6 +159,10 @@ killDaemon() {
}
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
killDaemon
@ -152,6 +185,12 @@ skipTest () {
exit 99
}
TODO_NixOS() {
if isTestOnNixOS; then
skipTest "This test has not been adapted for NixOS yet"
fi
}
requireDaemonNewerThan () {
isDaemonNewer "$1" || skipTest "Daemon is too old"
}
@ -234,7 +273,7 @@ buggyNeedLocalStore() {
enableFeatures() {
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

View file

@ -20,13 +20,13 @@ startDaemon
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
varTest set_in_config config_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

View file

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

View file

@ -7,7 +7,7 @@ clearStore
rm -f $TEST_ROOT/result
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

View file

@ -132,4 +132,11 @@ in
ca-fd-leak = runNixOSTestFor "x86_64-linux" ./ca-fd-leak;
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)
];
};
};
};
}