From dd166e5a4d4349241aa3408c8d7f7340cb0a90fb Mon Sep 17 00:00:00 2001 From: tv Date: Sat, 14 Nov 2026 00:33:20 +0000 Subject: tests: populate's tests of its own, krops' using them populate's tests are in pkgs/populate/tests, independent of krops. They run the program, with the sources as JSON from populate's Nix library, and target strings for the remote targets, leaving the user and whether the target is local to populate, so they cover its command line too. Phases expecting populate to refuse its arguments, e.g. a source name or a target path that can't be used, expect the program's refusal, with refused, the message, since nothing checks them during evaluation there. builder.nix is what builds the scenarios, which krops' tests use as well, with a function running the phases, and whether that checks the arguments during evaluation. vm.nix takes a module for both machines, for what else the scenarios run, and fixtures.nix and smoke.nix are what both use of the fixtures and the smoke test. krops' tests are deploy, writeDeploy's arguments to nixos-rebuild, with the stand-in for nixos-rebuild in the module, and populate, populate's scenarios that expect refusals, which pkgs.populate makes evaluation fail with, and those of populate's smoke test, all through pkgs.populate with target attribute sets as mkTarget returns them. -A only selects from all of populate's scenarios and krops' own. --- pkgs/populate/tests/fixtures.sh | 498 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 498 insertions(+) create mode 100755 pkgs/populate/tests/fixtures.sh (limited to 'pkgs/populate/tests/fixtures.sh') diff --git a/pkgs/populate/tests/fixtures.sh b/pkgs/populate/tests/fixtures.sh new file mode 100755 index 0000000..85701a1 --- /dev/null +++ b/pkgs/populate/tests/fixtures.sh @@ -0,0 +1,498 @@ +#! /bin/sh +# Creates the fixtures the tests deploy from in /fixtures. +# +# usage: fixtures.sh URL GIT_HEAD +# +# URL is where /fixtures/www gets served via HTTP, e.g. http://deployer:8000. +# The tarball flakes there get locked against it, so it must be served while +# this script runs. /fixtures/git gets served by git daemon. GIT_HEAD is the +# commit the tests expect as HEAD of /fixtures/gitsrc. +set -efu + +url=$1 +git_head=$2 + +nix() { + command nix --extra-experimental-features 'nix-command flakes' "$@" +} + +export GIT_AUTHOR_NAME=krops GIT_AUTHOR_EMAIL=spam@krebsco.de +export GIT_COMMITTER_NAME=krops GIT_COMMITTER_EMAIL=spam@krebsco.de +export GIT_AUTHOR_DATE='1000000000 +0000' GIT_COMMITTER_DATE='1000000000 +0000' +# Configuration such as commit.gpgsign would change the commits. +export GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_NOSYSTEM=1 + +# Commits everything in the current directory. Commits are deterministic, so +# the tests can refer to them by hash. +commit() { + git add -A + git commit -q -m "$1" +} + +tarball() { + tar -C /fixtures/www/src --sort=name --mtime=@1 --owner=0 --group=0 \ + --numeric-owner -czf /fixtures/www/"$1".tar.gz "$1" +} + +rm -fR /fixtures +mkdir -p /fixtures/www/src + +# Tarball flakes, fetched via HTTP: inner, dep (with input inner), mono (with +# a flake in subdirectory sub), and remote (with input dep). +mkdir /fixtures/www/src/inner +cat > /fixtures/www/src/inner/flake.nix <<'NIX' +{ outputs = _: { who = "inner"; }; } +NIX +tarball inner + +mkdir /fixtures/www/src/dep +cat > /fixtures/www/src/dep/flake.nix < /fixtures/www/src/mono/README +cat > /fixtures/www/src/mono/sub/flake.nix <<'NIX' +{ outputs = _: { who = "sub"; }; } +NIX +tarball mono + +mkdir /fixtures/www/src/remote +cat > /fixtures/www/src/remote/flake.nix < /fixtures/top/flake.nix < /fixtures/alt/flake.nix <<'NIX' +{ outputs = _: { greeting = "alt"; who = "alt"; }; } +NIX + +# usegone: a flake with an input locked to a path that doesn't exist anymore. +mkdir /fixtures/gone /fixtures/usegone +cat > /fixtures/gone/flake.nix <<'NIX' +{ outputs = _: {}; } +NIX +cat > /fixtures/usegone/flake.nix <<'NIX' +{ + inputs.gone.url = "path:/fixtures/gone"; + outputs = _: {}; +} +NIX +(cd /fixtures/usegone && nix flake lock) +rm -R /fixtures/gone + +# kropsremote: a registry entry for remote, so it has an indirect reference. +nix registry add kropsremote "$url/remote.tar.gz" + +# monoin: a Git work tree with a flake in subdirectory sub that has an input. +mkdir -p /fixtures/monoin/sub +echo monoin > /fixtures/monoin/README +cat > /fixtures/monoin/sub/flake.nix < /fixtures/dirty/untracked + +# unlocked: a flake whose lock file is missing. +mkdir /fixtures/unlocked +cat > /fixtures/unlocked/flake.nix < /fixtures/uselocal/flake.nix <<'NIX' +{ + inputs.a.url = "path:/fixtures/alt"; + outputs = { a, ... }: { msg = "uselocal:${a.who}"; }; +} +NIX +(cd /fixtures/uselocal && nix flake lock) + +# follow: a flake whose input dep draws its input inner from the flake's own +# input inner, which is inner2, so the lock file records a follows path, and +# dep's own lock file pins another inner than the flake's. +mkdir /fixtures/www/src/inner2 +cat > /fixtures/www/src/inner2/flake.nix <<'NIX' +{ outputs = _: { who = "inner2"; }; } +NIX +tarball inner2 +mkdir /fixtures/follow +cat > /fixtures/follow/flake.nix < /fixtures/nofollow/flake.nix < /fixtures/www/src/$name/flake.nix < /fixtures/cyc/flake.nix < /fixtures/rel/lib/flake.nix <<'NIX' +{ outputs = _: { who = "lib"; }; } +NIX +cat > /fixtures/rel/flake.nix <<'NIX' +{ + inputs.lib.url = "path:./lib"; + outputs = { lib, ... }: { msg = "rel:${lib.who}"; }; +} +NIX +(cd /fixtures/rel && nix flake lock && git init -q && commit rel) + +# two, c1, c2: a flake with two inputs, and two flakes to draw them from. +mkdir /fixtures/two /fixtures/c1 /fixtures/c2 +cat > /fixtures/two/flake.nix < /fixtures/c1/flake.nix <<'NIX' +{ outputs = _: { who = "c1"; }; } +NIX +cat > /fixtures/c2/flake.nix <<'NIX' +{ outputs = _: { who = "c2"; }; } +NIX + +# usedata, data: a flake with an input that isn't a flake, and a directory +# to draw it from. +mkdir /fixtures/usedata /fixtures/data +cat > /fixtures/usedata/flake.nix <<'NIX' +{ + inputs.data = { url = "path:/nonexistent"; flake = false; }; + outputs = { data, ... }: { msg = "data:${builtins.readFile (data + "/value")}"; }; +} +NIX +printf hello > /fixtures/data/value + +# pipe2: a command for the pipe source type whose output the tests change. +cat > /fixtures/pipe2 <<'SH' +#! /bin/sh +cat /fixtures/pipe2-data +SH +chmod +x /fixtures/pipe2 +echo piped > /fixtures/pipe2-data + +# alt2: like alt, with other outputs, to change a source to. +mkdir /fixtures/alt2 +cat > /fixtures/alt2/flake.nix <<'NIX' +{ outputs = _: { greeting = "alt2"; who = "alt2"; }; } +NIX + +# filtered, filtered-link: a directory with an .rsync-filter, and a symlink to +# it that neither root nor the user deploying owns, through which rsync 3.5.0 +# and later can't read that file. +mkdir /fixtures/filtered +printf -- '- /garbage\n' > /fixtures/filtered/.rsync-filter +echo keep > /fixtures/filtered/keep +echo garbage > /fixtures/filtered/garbage +ln -s filtered /fixtures/filtered-link +chown -h nobody /fixtures/filtered-link + +# noflake: a directory without flake.nix. +mkdir /fixtures/noflake +echo noflake > /fixtures/noflake/README + +# filesrc: a copy of top, with files for testing the file source type's +# options. same has the same size and modification time as the file the +# tests put on the target beforehand, while skip-ex and skip-f have the same +# size but an older modification time than theirs, so rsync's quick check +# tells them apart. +mkdir /fixtures/filesrc +cp /fixtures/top/flake.nix /fixtures/top/flake.lock /fixtures/filesrc +echo keep > /fixtures/filesrc/keep +echo src > /fixtures/filesrc/skip-ex +echo src > /fixtures/filesrc/skip-f +echo AAAA > /fixtures/filesrc/same +touch -d @1000000000 /fixtures/filesrc/same +touch -d @999999999 /fixtures/filesrc/skip-ex /fixtures/filesrc/skip-f + +# gitsrc: a Git repository with two commits, served by git daemon. Its flake +# has an input that only exists when drawn from a source. +mkdir /fixtures/gitsrc +cat > /fixtures/gitsrc/flake.nix <<'NIX' +{ + inputs.dep.url = "path:/nonexistent"; + outputs = { dep, ... }: { msg = "git:${dep.greeting}"; }; +} +NIX +(cd /fixtures/gitsrc && git init -q -b master && commit one) +echo two > /fixtures/gitsrc/two +(cd /fixtures/gitsrc && commit two) +if test "$(git -C /fixtures/gitsrc rev-parse HEAD)" != "$git_head"; then + >&2 printf 'error: HEAD of /fixtures/gitsrc is %s, but the tests expect %s\n' \ + "$(git -C /fixtures/gitsrc rev-parse HEAD)" "$git_head" + exit 1 +fi +mkdir /fixtures/git +git clone -q --bare /fixtures/gitsrc /fixtures/git/gitsrc.git +git -C /fixtures/git/gitsrc.git config uploadpack.allowReachableSHA1InWant true + +# withsub: a Git repository with gitsrc as its submodule sub, served by git +# daemon like gitsrc, which the tests reach as git://deployer/gitsrc.git. +mkdir /fixtures/withsub +cat > /fixtures/withsub/.gitmodules <<'GIT' +[submodule "sub"] + path = sub + url = git://deployer/gitsrc.git +GIT +( + cd /fixtures/withsub + git init -q -b master + git update-index --add --cacheinfo 160000,"$git_head",sub + git add .gitmodules + git commit -q -m withsub +) +git clone -q --bare /fixtures/withsub /fixtures/git/withsub.git + +# pass: password stores with x/a, without and with Git. +if ! gpg --list-secret-keys spam@krebsco.de >/dev/null 2>&1; then + gpg --batch --passphrase '' --quick-gen-key spam@krebsco.de default default never +fi +for store in pass pass-git; do + export PASSWORD_STORE_DIR=/fixtures/$store + pass init spam@krebsco.de >/dev/null + if test $store = pass-git; then + pass git init >/dev/null + fi + printf 'secret-a\n' | pass insert -m x/a >/dev/null +done +unset PASSWORD_STORE_DIR + +# passage: a passage store with x/a. +mkdir -p /fixtures/passage/store +age-keygen -o /fixtures/passage/identities 2>/dev/null +age-keygen -y /fixtures/passage/identities > /fixtures/passage/store/.age-recipients +printf 'secret-a\n' | + PASSAGE_DIR=/fixtures/passage/store \ + PASSAGE_IDENTITIES_FILE=/fixtures/passage/identities \ + passage insert -m x/a >/dev/null + +# pipe: a command for the pipe source type. +cat > /fixtures/pipe <<'SH' +#! /bin/sh +echo piped +SH +chmod +x /fixtures/pipe + +# pipe-slow: a command that takes longer than the tests wait for it. +cat > /fixtures/pipe-slow <<'SH' +#! /bin/sh +sleep 60 +echo piped +SH +chmod +x /fixtures/pipe-slow + +# patches: hello and hello2 change dep's greeting, hello2 only after hello; +# sub changes the flake in mono's subdirectory; bad applies to nothing. +mkdir -p /fixtures/patches +# Prints a patch of file $1 in the directory $2, replacing $3 by $4. +patch_of() { + sed "s/$3/$4/" "$2/$1" > /fixtures/patches/new + diff -u --label a/"$1" --label b/"$1" "$2/$1" /fixtures/patches/new || test $? = 1 + rm /fixtures/patches/new +} +patch_of flake.nix /fixtures/www/src/dep 'dep+' 'hello+' > /fixtures/patches/hello.patch +mkdir /fixtures/patches/dep-hello +sed 's/dep+/hello+/' /fixtures/www/src/dep/flake.nix > /fixtures/patches/dep-hello/flake.nix +patch_of flake.nix /fixtures/patches/dep-hello 'hello+' 'hello2+' > /fixtures/patches/hello2.patch +rm -R /fixtures/patches/dep-hello +patch_of flake.nix /fixtures/www/src/mono/sub '"sub"' '"patched"' > /fixtures/patches/sub.patch +cat > /fixtures/patches/bad.patch <<'PATCH' +--- a/flake.nix ++++ b/flake.nix +@@ -1 +1 @@ +-nothing like this ++anything +PATCH + +# broken: a flake with an input that can't be fetched anymore. +mkdir /fixtures/www/src/vanishing +cat > /fixtures/www/src/vanishing/flake.nix <<'NIX' +{ outputs = _: { who = "vanishing"; }; } +NIX +tarball vanishing +mkdir /fixtures/broken +cat > /fixtures/broken/flake.nix < /fixtures/www/src/pinned/flake.nix < /fixtures/usepinned/flake.nix < /fixtures/www/src/stale/flake.nix < /fixtures/www/src/stale/flake.nix < /fixtures/usestale/flake.nix < /fixtures/www/src/gap/flake.nix <<'NIX' +{ outputs = _: { who = "gap"; }; } +NIX +tarball gap +mkdir /fixtures/offline +cat > /fixtures/offline/flake.nix < /fixtures/c3/flake.nix < /fixtures/filtered-parent/.rsync-filter +echo keep > /fixtures/filtered-parent/sub/keep +echo garbage > /fixtures/filtered-parent/sub/garbage +ln -s filtered-parent /fixtures/filtered-parent-link +chown -h nobody /fixtures/filtered-parent-link + +# filtered-name, filtered-name-link: like filtered, but the filter file is in +# a subdirectory whose name has a byte that rsync prints escaped in the C +# locale. +mkdir -p /fixtures/filtered-name/bär +printf -- '- garbage\n' > /fixtures/filtered-name/bär/.rsync-filter +echo keep > /fixtures/filtered-name/bär/keep +echo garbage > /fixtures/filtered-name/bär/garbage +ln -s filtered-name /fixtures/filtered-name-link +chown -h nobody /fixtures/filtered-name-link -- cgit v1.3.1