diff --git a/tests/functional/build-remote-input-addressed.sh b/tests/functional/build-remote-input-addressed.sh index 986692dbc..11199a408 100755 --- a/tests/functional/build-remote-input-addressed.sh +++ b/tests/functional/build-remote-input-addressed.sh @@ -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 diff --git a/tests/functional/common/init.sh b/tests/functional/common/init.sh index 4f2a393af..19cef5af9 100755 --- a/tests/functional/common/init.sh +++ b/tests/functional/common/init.sh @@ -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" <&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 - # 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 +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 @@ -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 + # Don’t 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 + # Don’t 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 diff --git a/tests/functional/impure-env.sh b/tests/functional/impure-env.sh index 3c7df169e..e65c78b00 100755 --- a/tests/functional/impure-env.sh +++ b/tests/functional/impure-env.sh @@ -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 diff --git a/tests/functional/local-overlay-store/common.sh b/tests/functional/local-overlay-store/common.sh index 0e6097861..bbe84847a 100644 --- a/tests/functional/local-overlay-store/common.sh +++ b/tests/functional/local-overlay-store/common.sh @@ -31,7 +31,7 @@ requireEnvironment () { } addConfig () { - echo "$1" >> "$NIX_CONF_DIR/nix.conf" + echo "$1" >> "$test_nix_conf" } setupConfig () { diff --git a/tests/functional/post-hook.sh b/tests/functional/post-hook.sh index c0b1ab3aa..7540d1045 100755 --- a/tests/functional/post-hook.sh +++ b/tests/functional/post-hook.sh @@ -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 diff --git a/tests/nixos/default.nix b/tests/nixos/default.nix index 710f8a273..2ab00b336 100644 --- a/tests/nixos/default.nix +++ b/tests/nixos/default.nix @@ -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; + } diff --git a/tests/nixos/functional/as-root.nix b/tests/nixos/functional/as-root.nix new file mode 100644 index 000000000..96be3d593 --- /dev/null +++ b/tests/nixos/functional/as-root.nix @@ -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 + """) + ''; +} diff --git a/tests/nixos/functional/as-trusted-user.nix b/tests/nixos/functional/as-trusted-user.nix new file mode 100644 index 000000000..d6f825697 --- /dev/null +++ b/tests/nixos/functional/as-trusted-user.nix @@ -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 + """) + ''; +} \ No newline at end of file diff --git a/tests/nixos/functional/as-user.nix b/tests/nixos/functional/as-user.nix new file mode 100644 index 000000000..1443f6e6c --- /dev/null +++ b/tests/nixos/functional/as-user.nix @@ -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 + """) + ''; +} diff --git a/tests/nixos/functional/common.nix b/tests/nixos/functional/common.nix new file mode 100644 index 000000000..493791a7b --- /dev/null +++ b/tests/nixos/functional/common.nix @@ -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 + ]; + }; +} diff --git a/tests/nixos/functional/quick-build.nix b/tests/nixos/functional/quick-build.nix new file mode 100644 index 000000000..10f4215e5 --- /dev/null +++ b/tests/nixos/functional/quick-build.nix @@ -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) + ]; + }; + }; + }; +} \ No newline at end of file