about summary refs log tree commit diff stats
path: root/tests/infrastructure/driver.sh
blob: 4992b5bc269a4256411d4430555ee197c446c4bc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#! /usr/bin/env bash
set -e

msg() {
    if [ "$#" -ne 0 ]; then
        echo "$@" | tee --append "$__TEST_EVAL_LOG_FILE" >&2
    else
        cat | tee --append "$__TEST_EVAL_LOG_FILE" >&2
    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"
    file="$1"

    awk --file "$__TEST_EVAL_AWK_CLEAN_FILE" "$file" | while read -r cmd args; do
        case "$cmd" in
        "Type")
            msg "Sending keys to application '$args'.."
            "$tmux" send-keys -t "$tpane": "$args"
            ;;
        "Sleep")
            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 get_plane_text | grep "$args"; then
                matched=true
            else
                matched=false
            fi

            case "$cmd" in
            "Expect")
                if [ "$matched" = true ]; then
                    msg "Regex matched."
                else
                    msg "Failed to find string, matched by regex '$args' on the screen"
                    msg current screen:
                    get_plane_text | msg

                    exit 1
                fi
                ;;
            "ExpectNot")
                if [ "$matched" = false ]; then
                    msg "Regex successfully not matched."
                else
                    msg "Found to find string, matched by regex '$args' on the screen. But expected none"
                    msg current screen:
                    get_plane_text | msg

                    exit 1
                fi
                ;;
            *)
                msg "Entered unrechable code. This is a bug."
                exit 1
                ;;
            esac
            ;;
        "SetGolden")
            msg "Trying to set '$args' as golden file."
            [ -f "$args" ] || {
                msg "Argument is not a file!"
                exit 1
            }
            printf "%s" "$args" >"$__TEST_EVAL_GOLDEN_FILE"
            msg "Set golden file to: '$args'"
            ;;
        *)
            msg "Unrecognized command: '$cmd'"
            exit 1
            ;;
        esac
    done
}