mirror of
https://github.com/tmux/tmux.git
synced 2026-10-28 10:04:33 +08:00
Update some tests.
This commit is contained in:
1 parent
48b95b56ea
commit
98bac274e0
10 files changed
+166
-58
No files matched your search
@@ -6,6 +6,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
command -v python3 >/dev/null || exit 101
|
||||
|
||||
python3 - "$TEST_TMUX" "$(dirname "$0")/../tmux-protocol.h" <<'PY'
|
||||
import os
|
||||
|
||||
@@ -1,38 +1,113 @@
|
||||
#!/bin/sh
|
||||
|
||||
# A waited run-shell command can complete after a control client has closed its
|
||||
# input and exited. The command queue still references the client until the job
|
||||
# callback runs, but control_stop has already destroyed c->control_state. Late
|
||||
# command output must be discarded instead of dereferencing the stopped control
|
||||
# state and killing the server.
|
||||
. ./regress-common.inc
|
||||
|
||||
# Late command output and parse errors must be safe after a control client
|
||||
# has exited or lost its session. Keep a separate session alive throughout.
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
export PATH TERM
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest$$"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
DIR=$(test_tmpdir) || exit 1
|
||||
TMUX="$TEST_TMUX -S$DIR/socket -f/dev/null"
|
||||
OUT=$DIR/output
|
||||
pid=
|
||||
|
||||
OUT=$(mktemp)
|
||||
trap "$TMUX kill-server 2>/dev/null; rm -f $OUT" 0 1 15
|
||||
cleanup()
|
||||
{
|
||||
# Release any shell still waiting, including on a failed assertion.
|
||||
touch "$DIR/go"
|
||||
exec 3>&-
|
||||
if [ -n "$pid" ]; then
|
||||
kill -CONT "$pid" 2>/dev/null
|
||||
kill "$pid" 2>/dev/null
|
||||
wait "$pid" 2>/dev/null
|
||||
fi
|
||||
stop_server $TMUX || exit 1
|
||||
rm -rf "$DIR"
|
||||
}
|
||||
trap cleanup 0
|
||||
trap 'exit 1' 1 2 15
|
||||
|
||||
$TMUX -f/dev/null new-session -d -s main || exit 1
|
||||
|
||||
printf '%s\n' 'run-shell "sleep 0.2; echo TEST"' |
|
||||
$TMUX -f/dev/null -C >"$OUT" 2>&1
|
||||
|
||||
sleep 1
|
||||
|
||||
$TMUX has-session -t main 2>/dev/null || {
|
||||
echo "server exited after late run-shell output"
|
||||
cat "$OUT"
|
||||
fail()
|
||||
{
|
||||
echo "$*" >&2
|
||||
[ ! -f "$OUT" ] || cat "$OUT" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
grep -q '^%exit' "$OUT" || {
|
||||
echo "control client did not exit"
|
||||
cat "$OUT"
|
||||
exit 1
|
||||
# The shell signals that it has started, then waits for the test to release it.
|
||||
# Neither the job callback nor its output can run before the client is lost.
|
||||
GATE="touch '$DIR/started'; while [ ! -f '$DIR/go' ]; do sleep 0.05; done"
|
||||
|
||||
start_client()
|
||||
{
|
||||
rm -f "$DIR/go" "$DIR/started"
|
||||
$TMUX -C attach -t "$1" <"$DIR/input" >"$OUT" 2>&1 &
|
||||
pid=$!
|
||||
exec 3>"$DIR/input"
|
||||
wait_for_clients 1 $TMUX || fail "control client did not attach"
|
||||
}
|
||||
|
||||
lose_client()
|
||||
{
|
||||
exec 3>&-
|
||||
wait_for_exit "$pid" || fail "control client did not exit"
|
||||
wait "$pid" || fail "control client failed"
|
||||
pid=
|
||||
wait_for_clients 0 $TMUX || fail "server did not lose control client"
|
||||
grep -q '^%exit' "$OUT" || fail "control client did not report exit"
|
||||
}
|
||||
|
||||
error_or_exit()
|
||||
{
|
||||
! $TMUX has-session -t main 2>/dev/null ||
|
||||
output_has "Unknown command: $1" $TMUX show-messages
|
||||
}
|
||||
|
||||
late_error()
|
||||
{
|
||||
wait_until error_or_exit "$1" || fail "no late error from $1"
|
||||
$TMUX has-session -t main || fail "server exited after $1"
|
||||
}
|
||||
|
||||
mkfifo "$DIR/input" || exit 1
|
||||
$TMUX new-session -d -s main || exit 1
|
||||
|
||||
# A waited run-shell retains a queue reference after control_stop has freed
|
||||
# the control state. Its output must be discarded once the client is lost.
|
||||
start_client main
|
||||
printf 'run-shell "%s; echo TEST"\n' "$GATE" >&3
|
||||
wait_until test -f "$DIR/started" || fail "run-shell did not start"
|
||||
lose_client
|
||||
touch "$DIR/go"
|
||||
# Wait for the job callback and its output handling, not just the shell exit.
|
||||
wait_for_output '' $TMUX show-messages -J || fail "late run-shell did not finish"
|
||||
$TMUX has-session -t main || fail "server exited after late run-shell output"
|
||||
|
||||
start_client main
|
||||
printf 'if-shell -b "%s" wibble1\n' "$GATE" >&3
|
||||
wait_until test -f "$DIR/started" || fail "if-shell did not start"
|
||||
lose_client
|
||||
touch "$DIR/go"
|
||||
late_error wibble1
|
||||
|
||||
# A stopped client cannot finish the exit handshake when its session dies.
|
||||
$TMUX new-session -d -s stopped || exit 1
|
||||
start_client stopped
|
||||
printf 'if-shell -b "%s" wibble3\n' "$GATE" >&3
|
||||
wait_until test -f "$DIR/started" || fail "stopped if-shell did not start"
|
||||
kill -STOP "$pid" || exit 1
|
||||
# Arm the timer and destroy its target session in one command queue. The
|
||||
# timer cannot parse wibble2 until that queue has cleared the client's session.
|
||||
$TMUX run-shell -b -d 0.01 -t stopped -C wibble2 \; \
|
||||
kill-session -t stopped || fail "destroy stopped session failed"
|
||||
$TMUX has-session -t stopped 2>/dev/null && fail "stopped session still exists"
|
||||
kill -0 "$pid" || fail "stopped client disappeared"
|
||||
touch "$DIR/go"
|
||||
late_error wibble2
|
||||
late_error wibble3
|
||||
|
||||
exit 0
|
||||
@@ -16,22 +16,18 @@ OUTER="$TEST_TMUX -LtestO$$ -f/dev/null"
|
||||
|
||||
cleanup()
|
||||
{
|
||||
$OUTER kill-server 2>/dev/null
|
||||
$INNER kill-server 2>/dev/null
|
||||
}
|
||||
trap cleanup 0 1 15
|
||||
|
||||
has_client()
|
||||
{
|
||||
[ -n "$($INNER list-clients -F x 2>/dev/null)" ]
|
||||
stop_server $OUTER || exit 1
|
||||
stop_server $INNER || exit 1
|
||||
}
|
||||
trap cleanup 0
|
||||
trap 'exit 1' 1 2 15
|
||||
|
||||
cleanup
|
||||
$INNER new-session -d -s inner -x40 -y10 'exec sleep 100' || exit 1
|
||||
$INNER set-option -g status off || exit 1
|
||||
$OUTER new-session -d -s outer -x40 -y10 "$INNER attach -t inner" || exit 1
|
||||
$OUTER set-option -g status off || exit 1
|
||||
wait_until has_client || exit 1
|
||||
wait_for_clients 1 $INNER || exit 1
|
||||
|
||||
# U+00E4 is two bytes in UTF-8, U+20AC three.
|
||||
$INNER bind-key -n ä set-option -g @a yes || exit 1
|
||||
|
||||
@@ -10,6 +10,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
command -v python3 >/dev/null || exit 101
|
||||
|
||||
python3 - "$TEST_TMUX" <<'PY'
|
||||
import os
|
||||
@@ -25,7 +26,7 @@ server = [tmux, "-L" + label, "-f/dev/null"]
|
||||
|
||||
def run(*args, check=True):
|
||||
return subprocess.run(server + list(args), check=check,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=10)
|
||||
|
||||
def attach():
|
||||
pid, fd = os.forkpty()
|
||||
@@ -37,9 +38,9 @@ def attach():
|
||||
return pid, fd
|
||||
|
||||
def read_until(fd, needle, timeout=5):
|
||||
end = time.time() + timeout
|
||||
end = time.monotonic() + timeout
|
||||
data = b""
|
||||
while time.time() < end:
|
||||
while time.monotonic() < end:
|
||||
r, _, _ = select.select([fd], [], [], 0.05)
|
||||
if fd in r:
|
||||
try:
|
||||
@@ -87,7 +88,10 @@ run("kill-server", check=False)
|
||||
run("new-session", "-d", "-x", "80", "-y", "24", "-s", "dead", "sleep 60")
|
||||
pid, fd = attach()
|
||||
try:
|
||||
time.sleep(0.5)
|
||||
deadline = time.monotonic() + 10
|
||||
while not run("list-clients").stdout.strip():
|
||||
assert time.monotonic() < deadline, "client did not attach"
|
||||
time.sleep(.05)
|
||||
run("set-option", "-g", "remain-on-exit", "on")
|
||||
run("set-option", "-s", "set-clipboard", "on")
|
||||
run("set-option", "-s", "get-clipboard", "request")
|
||||
@@ -104,6 +108,8 @@ try:
|
||||
# waiting; if it timed out before the answer arrived, try again.
|
||||
run("set-option", "-s", "get-clipboard", "both")
|
||||
for attempt in range(5):
|
||||
# A previous attempt must not make a timed-out reply look successful.
|
||||
run("delete-buffer", check=False)
|
||||
request(query)
|
||||
os.write(fd, b"\033]52;c;UmVwbHk=\033\\")
|
||||
end = time.monotonic() + 1
|
||||
|
||||
@@ -11,6 +11,8 @@ TERM=screen
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
stop_server $TMUX || exit 1
|
||||
trap 'stop_server $TMUX || exit 1' 0
|
||||
trap 'exit 1' 1 2 15
|
||||
|
||||
# The only pane of the only session: the server must not exit.
|
||||
$TMUX new -d 'sleep 1000' || exit 1
|
||||
|
||||
@@ -10,6 +10,7 @@ LC_ALL=C.UTF-8
|
||||
export PATH TERM LC_ALL
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
command -v python3 >/dev/null || exit 101
|
||||
|
||||
python3 - "$TEST_TMUX" <<'PY'
|
||||
import re
|
||||
|
||||
+33
-15
@@ -1,5 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
. ./regress-common.inc
|
||||
|
||||
# Status drags must target the window under the pointer as it moves.
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
@@ -9,12 +11,15 @@ export PATH TERM
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -LtestB$$ -f/dev/null"
|
||||
DIR=$(test_tmpdir) || exit 1
|
||||
CAPTURE=$DIR/capture
|
||||
|
||||
# Stop both isolated servers.
|
||||
cleanup()
|
||||
{
|
||||
$TMUX2 kill-server >/dev/null 2>&1
|
||||
$TMUX kill-server >/dev/null 2>&1
|
||||
stop_server $TMUX2 || exit 1
|
||||
stop_server $TMUX || exit 1
|
||||
rm -rf "$DIR"
|
||||
}
|
||||
trap cleanup 0
|
||||
trap 'exit 1' 1 2 15
|
||||
@@ -31,15 +36,23 @@ mouse()
|
||||
{
|
||||
seq=$(printf '\033[<%s;%s;%s%s' "$1" "$2" "$3" "$4")
|
||||
$TMUX2 send-keys -t outer:0.0 -l "$seq" || fail 'send mouse failed'
|
||||
sleep 0.2
|
||||
}
|
||||
|
||||
# Check the window order after each drag update.
|
||||
check_order()
|
||||
{
|
||||
got=$($TMUX list-windows -F '#{window_name}') || fail 'server exited'
|
||||
[ "$got" = "$(printf '%s\n' "$@")" ] ||
|
||||
fail "window order '$got', expected '$*'"
|
||||
wait_for_output "$(printf '%s\n' "$@")" \
|
||||
$TMUX list-windows -F '#{window_name}' ||
|
||||
fail "window order did not become '$*'"
|
||||
}
|
||||
|
||||
# Check the actual terminal columns before sending mouse input to a side line.
|
||||
side_drawn()
|
||||
{
|
||||
$TMUX2 capture-pane -p -S0 -E2 >"$CAPTURE" || return 1
|
||||
awk -v column="$1" '
|
||||
{ text = substr($0, column, 12); gsub(/[^A-Z]/, "", text); print text }
|
||||
' "$CAPTURE"
|
||||
}
|
||||
|
||||
$TMUX new-session -d -s inner -n AAA -x 60 -y 20 'sleep 180' || exit 1
|
||||
@@ -59,13 +72,14 @@ $TMUX bind -n MouseDragEnd1Status set -u @drag_window || exit 1
|
||||
$TMUX2 new-session -d -s outer -x 60 -y 20 'sleep 180' || exit 1
|
||||
$TMUX2 set -g status off || exit 1
|
||||
$TMUX2 respawn-pane -k -t outer:0.0 "$TMUX attach -t inner" || exit 1
|
||||
sleep 1
|
||||
wait_for_clients 1 $TMUX || fail 'inner client did not attach'
|
||||
|
||||
for position in bottom top; do
|
||||
$TMUX set -g status-position "$position" || exit 1
|
||||
row=20
|
||||
[ "$position" = top ] && row=1
|
||||
sleep 0.5
|
||||
wait_for_text 'AAA BBB CCC' $TMUX2 capture-pane -p \
|
||||
-S "$((row - 1))" -E "$((row - 1))" || fail 'status did not draw'
|
||||
|
||||
# Establish the drag on AAA, then cross BBB and CCC without releasing.
|
||||
mouse 0 1 "$row" M
|
||||
@@ -75,7 +89,7 @@ for position in bottom top; do
|
||||
mouse 32 9 "$row" M
|
||||
check_order BBB CCC AAA
|
||||
mouse 0 9 "$row" m
|
||||
[ -z "$($TMUX show -qv @drag_window)" ] ||
|
||||
wait_for_output '' $TMUX show -qv @drag_window ||
|
||||
fail 'drag end did not clear the saved window'
|
||||
|
||||
# Restore the order for the next position.
|
||||
@@ -91,7 +105,10 @@ for side in left right; do
|
||||
$TMUX set -g side-status "$side" || exit 1
|
||||
column=2
|
||||
[ "$side" = right ] && column=48
|
||||
sleep 0.5
|
||||
start=1
|
||||
[ "$side" = right ] && start=49
|
||||
wait_for_output "$(printf 'AAA\nBBB\nCCC')" side_drawn "$start" ||
|
||||
fail 'side status did not draw'
|
||||
mouse 0 "$column" 1 M
|
||||
mouse 32 "$((column + 1))" 1 M
|
||||
mouse 32 "$column" 2 M
|
||||
@@ -99,7 +116,7 @@ for side in left right; do
|
||||
mouse 32 "$column" 3 M
|
||||
check_order BBB CCC AAA
|
||||
mouse 0 "$column" 3 m
|
||||
[ -z "$($TMUX show -qv @drag_window)" ] ||
|
||||
wait_for_output '' $TMUX show -qv @drag_window ||
|
||||
fail 'side drag end did not clear the saved window'
|
||||
$TMUX swap-window -d -s inner:2 -t inner:1 || exit 1
|
||||
$TMUX swap-window -d -s inner:1 -t inner:0 || exit 1
|
||||
@@ -116,20 +133,21 @@ $TMUX bind -n MouseDrag1Status \
|
||||
$TMUX bind -n MouseDrag1Control0 set -g @control yes || exit 1
|
||||
$TMUX bind -n MouseDrag1Pane set -g @pane yes || exit 1
|
||||
$TMUX bind -n MouseDrag1Empty set -g @pane yes || exit 1
|
||||
sleep 0.5
|
||||
wait_for_text CONTROL $TMUX2 capture-pane -p -S1 -E1 ||
|
||||
fail 'second status line did not draw'
|
||||
mouse 0 1 1 M
|
||||
mouse 32 2 1 M
|
||||
mouse 32 2 2 M
|
||||
[ "$($TMUX show -gv @control)" = yes ] ||
|
||||
wait_for_output yes $TMUX show -gv @control ||
|
||||
fail 'drag did not target the second status line'
|
||||
mouse 32 3 6 M
|
||||
[ "$($TMUX show -gv @position)" = 2,5 ] ||
|
||||
wait_for_output 2,5 $TMUX show -gv @position ||
|
||||
fail 'status drag did not retain the pointer coordinates outside status'
|
||||
|
||||
# Changing the status height during a drag must leave it usable.
|
||||
$TMUX set -g status on || exit 1
|
||||
mouse 32 3 5 M
|
||||
[ "$($TMUX show -gv @position)" = 2,4 ] ||
|
||||
wait_for_output 2,4 $TMUX show -gv @position ||
|
||||
fail 'status drag stopped after the status height changed'
|
||||
[ -z "$($TMUX show -qgv @pane)" ] ||
|
||||
fail 'status drag invoked a pane binding'
|
||||
|
||||
@@ -8,6 +8,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
command -v python3 >/dev/null || exit 101
|
||||
|
||||
python3 -B - "$TEST_TMUX" <<'PY'
|
||||
import fcntl
|
||||
|
||||
@@ -8,6 +8,7 @@ TERM=screen
|
||||
export PATH TERM
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
command -v python3 >/dev/null || exit 101
|
||||
|
||||
python3 -B - "$TEST_TMUX" <<'PY'
|
||||
import fcntl
|
||||
@@ -25,7 +26,7 @@ server = [tmux, "-LtestWinsize%d" % os.getpid(), "-f/dev/null"]
|
||||
pid = fd = None
|
||||
|
||||
def run(*args, check=True):
|
||||
p = subprocess.run(server + list(args), capture_output=True)
|
||||
p = subprocess.run(server + list(args), capture_output=True, timeout=10)
|
||||
if check and p.returncode != 0:
|
||||
raise RuntimeError("%r: %s" % (args, p.stderr.decode()))
|
||||
return p.stdout.decode().strip()
|
||||
@@ -59,9 +60,13 @@ def check_escape(context):
|
||||
os.write(fd, b"\033")
|
||||
pump(.15)
|
||||
os.write(fd, b"\r")
|
||||
pump(.1)
|
||||
actual = run("show-option", "-gv", "@seen")
|
||||
assert actual == "EER", (context, "expected EER", actual)
|
||||
deadline = time.monotonic() + 1
|
||||
while True:
|
||||
pump(.01)
|
||||
actual = run("show-option", "-gv", "@seen")
|
||||
if actual == "EER":
|
||||
break
|
||||
assert time.monotonic() < deadline, (context, "expected EER", actual)
|
||||
|
||||
try:
|
||||
run("new-session", "-d", "-s", "winsize", "-x80", "-y24", "sleep 60")
|
||||
@@ -92,9 +97,11 @@ try:
|
||||
# A successful reply must release the delay without waiting five seconds.
|
||||
resize(26, 82)
|
||||
os.write(fd, b"\033[8;26;82t\033[4;520;820t")
|
||||
pump(.1)
|
||||
assert run("list-clients", "-F",
|
||||
"#{client_cell_width}x#{client_cell_height}") == "10x20"
|
||||
deadline = time.monotonic() + 1
|
||||
while run("list-clients", "-F",
|
||||
"#{client_cell_width}x#{client_cell_height}") != "10x20":
|
||||
assert time.monotonic() < deadline, "window size reply not handled"
|
||||
pump(.01)
|
||||
check_escape("answered resize query")
|
||||
|
||||
# Disconnect while a query is pending. Its timer must not outlive the
|
||||
|
||||
@@ -11,6 +11,7 @@ LC_ALL=C.UTF-8
|
||||
export PATH TERM LC_ALL
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
command -v python3 >/dev/null || exit 101
|
||||
DIR=$(test_tmpdir) || exit 1
|
||||
TMUX_TMPDIR=$DIR
|
||||
export TMUX_TMPDIR
|
||||
|
||||
Reference in new issue
Block a user