aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tests/README.md5
-rw-r--r--tests/infrastructure/default.nix22
-rw-r--r--tests/infrastructure/driver.sh92
3 files changed, 112 insertions, 7 deletions
diff --git a/tests/README.md b/tests/README.md
index 698c5d83..f789c990 100644
--- a/tests/README.md
+++ b/tests/README.md
@@ -90,3 +90,8 @@ regex does not match.
Set the golden file (the file used for the hash generation) to `ARGS`.
`ARGS` must be a valid file path.
+
+#### `Exec`
+
+Executes the command (`ARGS`) and waits until it finishes.
+This will hang forever, when the command that does not exit.
diff --git a/tests/infrastructure/default.nix b/tests/infrastructure/default.nix
index 0e0408e7..e0ad6889 100644
--- a/tests/infrastructure/default.nix
+++ b/tests/infrastructure/default.nix
@@ -12,6 +12,8 @@
description,
hash,
testData,
+ testShell ? pkgs.dash,
+ alternateScreen ? false,
}:
nixos-lib.runTest {
hostPkgs = pkgs; # the Nixpkgs package set used outside the VMs
@@ -56,6 +58,7 @@ nixos-lib.runTest {
testDir = "${nodes.machine.home-manager.users.soispha.home.homeDirectory}/test";
goldenFile = "${testDir}/__test_golden";
logFile = "${testDir}/__test_log";
+ testTmux = lib.getExe pkgs.tmux;
in
/*
python
@@ -63,6 +66,8 @@ nixos-lib.runTest {
''
start_all()
+ __TEST_TMUX="${testTmux}"
+
machine.succeed("sudo -u soispha ${pkgs.writeShellScript "mkTestEnvironment" ''
set -e
@@ -91,9 +96,15 @@ nixos-lib.runTest {
cd "${testDir}"
- __TEST_TMUX="${lib.getExe pkgs.tmux}"
+ __TEST_TMUX="${testTmux}"
+ __TEST_SHELL="${lib.getExe testShell}"
__TEST_TMUX_PANE="__TEST_TMUX_PANE"
+ __TEST_EVAL_USE_ALTERNATE_SCREEN="${
+ if alternateScreen
+ then "true"
+ else "false"
+ }"
__TEST_EVAL_AWK_CLEAN_FILE="${./clean.awk}"
__TEST_EVAL_LOG_FILE="${logFile}"
__TEST_EVAL_GOLDEN_FILE="$(mktemp)"
@@ -101,12 +112,17 @@ nixos-lib.runTest {
. ${./driver.sh}
- "$__TEST_TMUX" new-session -d -s "$__TEST_TMUX_PANE"
+ "$__TEST_TMUX" new-session -d -s "$__TEST_TMUX_PANE" "$__TEST_SHELL"
+
+ # Warm up the shell in the tmux sesssion
+ "$__TEST_TMUX" send-keys -t "$__TEST_TMUX_PANE" "echo hi" "Enter" "clear" "Enter"
+ sleep 2
+
"$__TEST_TMUX" pipe-pane -t "$__TEST_TMUX_PANE" -o 'cat >>${goldenFile}'
__test_eval "${description}"
- # Clear the pipe again
+ # Remove the pipe
"$__TEST_TMUX" pipe-pane -t "$__TEST_TMUX_PANE"
# Check if the golden file was changed.
diff --git a/tests/infrastructure/driver.sh b/tests/infrastructure/driver.sh
index f8688161..4992b5bc 100644
--- a/tests/infrastructure/driver.sh
+++ b/tests/infrastructure/driver.sh
@@ -1,4 +1,4 @@
-#! /usr/bin/env sh
+#! /usr/bin/env bash
set -e
msg() {
@@ -9,6 +9,65 @@ msg() {
fi
}
+# Use bash built-ins to trim a string
+# source: https://stackoverflow.com/a/3352015
+trim() {
+ local var="$*"
+ # remove leading whitespace characters
+ var="${var#"${var%%[![:space:]]*}"}"
+ # remove trailing whitespace characters
+ var="${var%"${var##*[![:space:]]}"}"
+ printf '%s' "$var"
+}
+
+# contains(string, substring)
+#
+# Returns 0 if the specified string contains the specified substring,
+# otherwise returns 1.
+contains() {
+ string="$1"
+ substring="$2"
+ if [ "${string#*"$substring"}" != "$string" ]; then
+ return 0 # $substring is in $string
+ else
+ return 1 # $substring is not in $string
+ fi
+}
+
+__test_wait_for_pid() {
+ local pre_pids_file="$1"
+
+ exec_pids="$(mktemp)"
+ ps -eo tty,pid | awk "--assign=tmuxTty=$tmux_tty" '{if ($1 == tmuxTty) {print $2}}' >"$exec_pids"
+
+ while read -r pid; do
+ sed --in-place "s/$pid//" "$exec_pids"
+ done <"$pre_pids_file"
+
+ gawk --include inplace '{if (NF) {print $0}}' "$exec_pids"
+
+ if [ "$(wc -l <"$exec_pids")" -eq 0 ]; then
+ # No further spawned processes left
+ return 0
+ else
+ # Some other program is still running
+ pid="$(tail -n 1 "$exec_pids")"
+ rm "$exec_pids"
+ name="$(trim "$(tr '\0' ' ' <"/proc/$pid/cmdline")")"
+
+ msg "Waiting until command ('$name') finishes (has pid: $pid).."
+
+ # This allows waiting for non-children of the current shell
+ # source: https://stackoverflow.com/a/76046235
+ tail --pid "$pid" --follow /dev/null &
+ wait $!
+
+ # Give the `testShell` some time, to process the next command from a chained command.
+ sleep 0.2
+ __test_wait_for_pid "$pre_pids_file"
+ fi
+}
+
__test_eval() {
tmux="$__TEST_TMUX"
tpane="$__TEST_TMUX_PANE"
@@ -24,11 +83,36 @@ __test_eval() {
msg "Sleeping for '$args' seconds.."
sleep "$args"
;;
+ "Exec")
+ local pre_exec_pids
+ local tmux_tty
+
+ msg "Executing command '$args'.."
+ tmux_tty="$("$tmux" list-panes -t "$tpane" -F "#{pane_tty}" | sed 's|/dev/||')"
+
+ pre_exec_pids="$(mktemp)"
+ ps -eo tty,pid | awk "--assign=tmuxTty=$tmux_tty" '{if ($1 == tmuxTty) {print $2}}' >"$pre_exec_pids"
+
+ "$tmux" send-keys -t "$tpane": "$args" "Enter"
+ sleep 1
+
+ __test_wait_for_pid "$pre_exec_pids"
+
+ rm "$pre_exec_pids"
+ msg "Finished command '$args'."
+ ;;
"Expect" | "ExpectNot")
msg "Trying to match regex ('$args') for currently visible content.."
+ get_plane_text() {
+ alternate=""
+ [ "$__TEST_EVAL_USE_ALTERNATE_SCREEN" = "true" ] && alternate="-a"
+
+ "$tmux" capture-pane -t "$tpane" -p $alternate -S 0 -E -
+ }
+
matched=""
- if "$tmux" capture-pane -t "$tpane" -p -S 0 -E - | grep "$args"; then
+ if get_plane_text | grep "$args"; then
matched=true
else
matched=false
@@ -41,7 +125,7 @@ __test_eval() {
else
msg "Failed to find string, matched by regex '$args' on the screen"
msg current screen:
- "$tmux" capture-pane -t "$tpane" -p -S 0 -E - | msg
+ get_plane_text | msg
exit 1
fi
@@ -52,7 +136,7 @@ __test_eval() {
else
msg "Found to find string, matched by regex '$args' on the screen. But expected none"
msg current screen:
- "$tmux" capture-pane -t "$tpane" -p -S 0 -E - | msg
+ get_plane_text | msg
exit 1
fi