diff options
Diffstat (limited to '')
-rw-r--r-- | tests/README.md | 5 | ||||
-rw-r--r-- | tests/infrastructure/default.nix | 22 | ||||
-rw-r--r-- | tests/infrastructure/driver.sh | 92 |
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 |