Skip to content

Commit

Permalink
tests: simplify initialisation and wiring
Browse files Browse the repository at this point in the history
pararameterisation is not actually needed the way things are currently
set up, and it confused me when trying to understand what the code does.

all but one test sources vars-and-functions.sh, which nominally only
defines variables, but in practice is always coupled with the actual
initialisation. while the cleaner way of making this more legible would
be to source variables and initialisation separately, this would produce
a huge diff.

the change requires a few small fixes to keep the tests working:

- only create test home directory during initialisation

  that vars-and-functions.sh wrote to the file system seems not write

- fix creation of the test directory

  due to statefulness, the test home directory was implicitly creating
  the test root, too. decoupling that made it apparent that this was
  probably not intentional, and certainly confusing.

- only source vars-and-functions.sh if init.sh is not needed

  there is one test case that only needs a helper function but no
  initialisation side effects

- remove some unnecessary cleanups and split parts of re-used test code

  there were confusing bits in how initialisation code was repurposed,
  which break if trying to refactor the outer layers naively...
  • Loading branch information
fricklerhandwerk committed May 8, 2024
1 parent fcbc36c commit 3dd505b
Show file tree
Hide file tree
Showing 14 changed files with 215 additions and 225 deletions.
6 changes: 3 additions & 3 deletions doc/manual/src/contributing/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,14 +162,14 @@ ran test tests/functional/${testName}.sh... [PASS]
or without `make`:

```shell-session
$ ./mk/run-test.sh tests/functional/${testName}.sh tests/functional/init.sh
$ ./mk/run-test.sh tests/functional/${testName}.sh
ran test tests/functional/${testName}.sh... [PASS]
```

To see the complete output, one can also run:

```shell-session
$ ./mk/debug-test.sh tests/functional/${testName}.sh tests/functional/init.sh
$ ./mk/debug-test.sh tests/functional/${testName}.sh
+(${testName}.sh:1) foo
output from foo
+(${testName}.sh:2) bar
Expand Down Expand Up @@ -204,7 +204,7 @@ edit it like so:
Then, running the test with `./mk/debug-test.sh` will drop you into GDB once the script reaches that point:

```shell-session
$ ./mk/debug-test.sh tests/functional/${testName}.sh tests/functional/init.sh
$ ./mk/debug-test.sh tests/functional/${testName}.sh
...
+ gdb blash blub
GNU gdb (GDB) 12.1
Expand Down
4 changes: 0 additions & 4 deletions mk/debug-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,8 @@
set -eu -o pipefail

test=$1
init=${2-}

dir="$(dirname "${BASH_SOURCE[0]}")"
source "$dir/common-test.sh"

if [ -n "$init" ]; then
(run "$init" 2>/dev/null > /dev/null)
fi
run "$test"
7 changes: 3 additions & 4 deletions mk/lib.mk
Original file line number Diff line number Diff line change
Expand Up @@ -87,15 +87,14 @@ $(foreach script, $(bin-scripts), $(eval $(call install-program-in,$(script),$(b
$(foreach script, $(bin-scripts), $(eval programs-list += $(script)))
$(foreach script, $(noinst-scripts), $(eval programs-list += $(script)))
$(foreach template, $(template-files), $(eval $(call instantiate-template,$(template))))
install_test_init=tests/functional/init.sh
$(foreach test, $(install-tests), \
$(eval $(call run-test,$(test),$(install_test_init))) \
$(eval $(call run-test,$(test))) \
$(eval installcheck: $(test).test))
$(foreach test-group, $(install-tests-groups), \
$(eval $(call run-test-group,$(test-group),$(install_test_init))) \
$(eval $(call run-test-group,$(test-group))) \
$(eval installcheck: $(test-group).test-group) \
$(foreach test, $($(test-group)-tests), \
$(eval $(call run-test,$(test),$(install_test_init))) \
$(eval $(call run-test,$(test))) \
$(eval $(test-group).test-group: $(test).test)))

# Compilation database.
Expand Down
4 changes: 0 additions & 4 deletions mk/run-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ yellow=""
normal=""

test=$1
init=${2-}

dir="$(dirname "${BASH_SOURCE[0]}")"
source "$dir/common-test.sh"
Expand All @@ -22,9 +21,6 @@ if [ -t 1 ]; then
fi

run_test () {
if [ -n "$init" ]; then
(run "$init" 2>/dev/null > /dev/null)
fi
log="$(run "$test" 2>&1)" && status=0 || status=$?
}

Expand Down
4 changes: 2 additions & 2 deletions mk/tests.mk
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ endef

define run-test

$(eval $(call run-bash,$1.test,$1 $(test-deps),mk/run-test.sh $1 $2))
$(eval $(call run-bash,$1.test-debug,$1 $(test-deps),mk/debug-test.sh $1 $2))
$(eval $(call run-bash,$1.test,$1 $(test-deps),mk/run-test.sh $1))
$(eval $(call run-bash,$1.test-debug,$1 $(test-deps),mk/debug-test.sh $1))

endef

Expand Down
6 changes: 5 additions & 1 deletion tests/functional/common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ if [[ -z "${COMMON_SH_SOURCED-}" ]]; then

COMMON_SH_SOURCED=1

source "$(readlink -f "$(dirname "${BASH_SOURCE[0]-$0}")")/common/vars-and-functions.sh"
dir="$(readlink -f "$(dirname "${BASH_SOURCE[0]-$0}")")"

source "$dir"/common/vars-and-functions.sh
source "$dir"/common/init.sh

if [[ -n "${NIX_DAEMON_PACKAGE:-}" ]]; then
startDaemon
fi
Expand Down
10 changes: 4 additions & 6 deletions tests/functional/init.sh → tests/functional/common/init.sh
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
# Don't start the daemon
source common/vars-and-functions.sh

test -n "$TEST_ROOT"
if test -d "$TEST_ROOT"; then
chmod -R u+rw "$TEST_ROOT"
# We would delete any daemon socket, so let's stop the daemon first.
killDaemon
rm -rf "$TEST_ROOT"
fi
mkdir "$TEST_ROOT"
mkdir -p "$TEST_ROOT"
mkdir "$TEST_HOME"

mkdir "$NIX_STORE_DIR"
mkdir "$NIX_LOCALSTATE_DIR"
Expand Down Expand Up @@ -36,7 +34,7 @@ extra-experimental-features = flakes
EOF

# Initialise the database.
# The flag itself does nothing, but running the command touches the store
nix-store --init

# Did anything happen?
# Sanity check
test -e "$NIX_STATE_DIR"/db/db.sqlite
3 changes: 2 additions & 1 deletion tests/functional/common/vars-and-functions.sh.in
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# NOTE: instances of @variable@ are substituted as defined in /mk/templates.mk

set -eu -o pipefail

if [[ -z "${COMMON_VARS_AND_FUNCTIONS_SH_SOURCED-}" ]]; then
Expand Down Expand Up @@ -34,7 +36,6 @@ unset XDG_DATA_HOME
unset XDG_CONFIG_HOME
unset XDG_CONFIG_DIRS
unset XDG_CACHE_HOME
mkdir -p $TEST_HOME

export PATH=@bindir@:$PATH
if [[ -n "${NIX_CLIENT_PACKAGE:-}" ]]; then
Expand Down
2 changes: 1 addition & 1 deletion tests/functional/lang.sh
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ for i in lang/eval-fail-*.nix; do
if [[ -e "lang/$i.flags" ]]; then
sed -e 's/#.*//' < "lang/$i.flags"
else
# note that show-trace is also set by init.sh
# note that show-trace is also set by common/init.sh
echo "--eval --strict --show-trace"
fi
)"
Expand Down
2 changes: 1 addition & 1 deletion tests/functional/local-overlay-store/common.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
source ../common.sh
source ../common/vars-and-functions.sh

# The new Linux mount interface does not seem to support remounting
# OverlayFS mount points.
Expand Down
1 change: 0 additions & 1 deletion tests/functional/local.mk
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
nix_tests = \
test-infra.sh \
init.sh \
flakes/flakes.sh \
flakes/develop.sh \
flakes/run.sh \
Expand Down
2 changes: 1 addition & 1 deletion tests/functional/remote-store.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ fi
# Test import-from-derivation through the daemon.
[[ $(nix eval --impure --raw --file ./ifd.nix) = hi ]]

storeCleared=1 NIX_REMOTE_=$NIX_REMOTE $SHELL ./user-envs.sh
NIX_REMOTE_=$NIX_REMOTE $SHELL ./user-envs-test-case.sh

nix-store --gc --max-freed 1K

Expand Down
191 changes: 191 additions & 0 deletions tests/functional/user-envs-test-case.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
clearProfiles

# Query installed: should be empty.
test "$(nix-env -p $profiles/test -q '*' | wc -l)" -eq 0

nix-env --switch-profile $profiles/test

# Query available: should contain several.
test "$(nix-env -f ./user-envs.nix -qa '*' | wc -l)" -eq 6
outPath10=$(nix-env -f ./user-envs.nix -qa --out-path --no-name '*' | grep foo-1.0)
drvPath10=$(nix-env -f ./user-envs.nix -qa --drv-path --no-name '*' | grep foo-1.0)
[ -n "$outPath10" -a -n "$drvPath10" ]

# Query with json
nix-env -f ./user-envs.nix -qa --json | jq -e '.[] | select(.name == "bar-0.1") | [
.outputName == "out",
.outputs.out == null
] | all'
nix-env -f ./user-envs.nix -qa --json --out-path | jq -e '.[] | select(.name == "bar-0.1") | [
.outputName == "out",
(.outputs.out | test("'$NIX_STORE_DIR'.*-0\\.1"))
] | all'
nix-env -f ./user-envs.nix -qa --json --drv-path | jq -e '.[] | select(.name == "bar-0.1") | (.drvPath | test("'$NIX_STORE_DIR'.*-0\\.1\\.drv"))'

# Query descriptions.
nix-env -f ./user-envs.nix -qa '*' --description | grepQuiet silly
rm -rf $HOME/.nix-defexpr
ln -s $(pwd)/user-envs.nix $HOME/.nix-defexpr
nix-env -qa '*' --description | grepQuiet silly

# Query the system.
nix-env -qa '*' --system | grepQuiet $system

# Install "foo-1.0".
nix-env -i foo-1.0

# Query installed: should contain foo-1.0 now (which should be
# executable).
test "$(nix-env -q '*' | wc -l)" -eq 1
nix-env -q '*' | grepQuiet foo-1.0
test "$($profiles/test/bin/foo)" = "foo-1.0"

# Test nix-env -qc to compare installed against available packages, and vice versa.
nix-env -qc '*' | grepQuiet '< 2.0'
nix-env -qac '*' | grepQuiet '> 1.0'

# Test the -b flag to filter out source-only packages.
[ "$(nix-env -qab | wc -l)" -eq 1 ]

# Test the -s flag to get package status.
nix-env -qas | grepQuiet 'IP- foo-1.0'
nix-env -qas | grepQuiet -- '--- bar-0.1'

# Disable foo.
nix-env --set-flag active false foo
(! [ -e "$profiles/test/bin/foo" ])

# Enable foo.
nix-env --set-flag active true foo
[ -e "$profiles/test/bin/foo" ]

# Store the path of foo-1.0.
outPath10_=$(nix-env -q --out-path --no-name '*' | grep foo-1.0)
echo "foo-1.0 = $outPath10"
[ "$outPath10" = "$outPath10_" ]

# Install "foo-2.0pre1": should remove foo-1.0.
nix-env -i foo-2.0pre1

# Query installed: should contain foo-2.0pre1 now.
test "$(nix-env -q '*' | wc -l)" -eq 1
nix-env -q '*' | grepQuiet foo-2.0pre1
test "$($profiles/test/bin/foo)" = "foo-2.0pre1"

# Upgrade "foo": should install foo-2.0.
NIX_PATH=nixpkgs=./user-envs.nix:${NIX_PATH-} nix-env -f '<nixpkgs>' -u foo

# Query installed: should contain foo-2.0 now.
test "$(nix-env -q '*' | wc -l)" -eq 1
nix-env -q '*' | grepQuiet foo-2.0
test "$($profiles/test/bin/foo)" = "foo-2.0"

# Store the path of foo-2.0.
outPath20=$(nix-env -q --out-path --no-name '*' | grep foo-2.0)
test -n "$outPath20"

# Install bar-0.1, uninstall foo.
nix-env -i bar-0.1
nix-env -e foo

# Query installed: should only contain bar-0.1 now.
if nix-env -q '*' | grepQuiet foo; then false; fi
nix-env -q '*' | grepQuiet bar

# Rollback: should bring "foo" back.
oldGen="$(nix-store -q --resolve $profiles/test)"
nix-env --rollback
[ "$(nix-store -q --resolve $profiles/test)" != "$oldGen" ]
nix-env -q '*' | grepQuiet foo-2.0
nix-env -q '*' | grepQuiet bar

# Rollback again: should remove "bar".
nix-env --rollback
nix-env -q '*' | grepQuiet foo-2.0
if nix-env -q '*' | grepQuiet bar; then false; fi

# Count generations.
nix-env --list-generations
test "$(nix-env --list-generations | wc -l)" -eq 7

# Doing the same operation twice results in the same generation, which triggers
# "lazy" behaviour and does not create a new symlink.

nix-env -i foo
nix-env -i foo

# Count generations.
nix-env --list-generations
test "$(nix-env --list-generations | wc -l)" -eq 8

# Switch to a specified generation.
nix-env --switch-generation 7
[ "$(nix-store -q --resolve $profiles/test)" = "$oldGen" ]

# Install foo-1.0, now using its store path.
nix-env -i "$outPath10"
nix-env -q '*' | grepQuiet foo-1.0
nix-store -qR $profiles/test | grep "$outPath10"
nix-store -q --referrers-closure $profiles/test | grep "$(nix-store -q --resolve $profiles/test)"
[ "$(nix-store -q --deriver "$outPath10")" = $drvPath10 ]

# Uninstall foo-1.0, using a symlink to its store path.
ln -sfn $outPath10/bin/foo $TEST_ROOT/symlink
nix-env -e $TEST_ROOT/symlink
if nix-env -q '*' | grepQuiet foo; then false; fi
nix-store -qR $profiles/test | grepInverse "$outPath10"

# Install foo-1.0, now using a symlink to its store path.
nix-env -i $TEST_ROOT/symlink
nix-env -q '*' | grepQuiet foo

# Delete all old generations.
nix-env --delete-generations old

# Run the garbage collector. This should get rid of foo-2.0 but not
# foo-1.0.
nix-collect-garbage
test -e "$outPath10"
(! [ -e "$outPath20" ])

# Uninstall everything
nix-env -e '*'
test "$(nix-env -q '*' | wc -l)" -eq 0

# Installing "foo" should only install the newest foo.
nix-env -i foo
test "$(nix-env -q '*' | grep foo- | wc -l)" -eq 1
nix-env -q '*' | grepQuiet foo-2.0

# On the other hand, this should install both (and should fail due to
# a collision).
nix-env -e '*'
(! nix-env -i foo-1.0 foo-2.0)

# Installing "*" should install one foo and one bar.
nix-env -e '*'
nix-env -i '*'
test "$(nix-env -q '*' | wc -l)" -eq 2
nix-env -q '*' | grepQuiet foo-2.0
nix-env -q '*' | grepQuiet bar-0.1.1

# Test priorities: foo-0.1 has a lower priority than foo-1.0, so it
# should be possible to install both without a collision. Also test
# ‘--set-flag priority’ to manually override the declared priorities.
nix-env -e '*'
nix-env -i foo-0.1 foo-1.0
[ "$($profiles/test/bin/foo)" = "foo-1.0" ]
nix-env --set-flag priority 1 foo-0.1
[ "$($profiles/test/bin/foo)" = "foo-0.1" ]

# Test nix-env --set.
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

0 comments on commit 3dd505b

Please sign in to comment.