Files
podman/test/system/450-interactive.bats
Shuai Yuan f5efef5043 exec: honor ConsoleSize so the terminal is sized at creation
The exec API accepts a ConsoleSize but it is dropped: the exec
pseudo-terminal is created at its default size and only corrected
afterwards by an asynchronous resize. A short-lived exec that reads its
window size at startup (e.g. `stty size`) can therefore observe the wrong
size, because the resize may arrive after the process has already read it.
docker applies the size at creation.

Carry the requested ConsoleSize through ExecConfig and into the exec OCI
process spec (process.consoleSize) so the runtime sizes the terminal
before the process starts, removing the race. The local and remote CLIs
capture the caller's terminal size when -t is given and pass it through
ExecOptions, matching the behavior of `podman run`.

Re-enable the previously flaky `podman exec` case in the interactive
system test, which this change makes deterministic.

Signed-off-by: Shuai Yuan <shuaiyuanzju@gmail.com>
2026-06-22 10:36:10 +08:00

147 lines
4.7 KiB
Bash

# -*- bats -*-
#
# tests of podman commands that require an interactive pty
#
load helpers
# bats file_tags=ci:parallel
###############################################################################
# BEGIN setup/teardown
function setup() {
basic_setup
# Each test runs with its own PTY, managed by socat.
PODMAN_TEST_PTY=$PODMAN_TMPDIR/podman_pty
PODMAN_DUMMY=$PODMAN_TMPDIR/podman_dummy
PODMAN_SOCAT_PID=
# Create a pty. Run under 'timeout' because BATS reaps child processes
# and if we exit before killing socat, bats will hang forever.
timeout 10 socat \
PTY,link=$PODMAN_TEST_PTY,raw,echo=0 \
PTY,link=$PODMAN_DUMMY,raw,echo=0 &
PODMAN_SOCAT_PID=$!
# Wait for pty
retries=5
while [[ ! -e $PODMAN_TEST_PTY ]]; do
retries=$(( retries - 1 ))
assert $retries -gt 0 "Timed out waiting for $PODMAN_TEST_PTY"
sleep 0.5
done
}
function teardown() {
if [[ -n $PODMAN_SOCAT_PID ]]; then
kill $PODMAN_SOCAT_PID
PODMAN_SOCAT_PID=
fi
rm -f $PODMAN_TEST_PTY $PODMAN_DUMMY_PTY
basic_teardown
}
# END setup/teardown
###############################################################################
# BEGIN tests
@test "podman detects correct tty size" {
# Set the pty to a random size. Make rows/columns odd/even, to guarantee
# that they can never be the same
rows=$(( 15 + RANDOM % 60 | 1 ))
cols=$(( 15 + RANDOM % 60 & 126 ))
stty rows $rows cols $cols <$PODMAN_TEST_PTY
CR=$'\r'
# ...and make sure stty under podman reads that.
# This flakes often ("stty: standard input"), so, retry.
run_podman run -it --name mystty $IMAGE stty size <$PODMAN_TEST_PTY
if [[ "$output" =~ stty ]]; then
echo "# stty flaked, retrying: $output" >&3
run_podman rm -f mystty
sleep 1
run_podman run -it --name mystty $IMAGE stty size <$PODMAN_TEST_PTY
fi
is "$output" "$rows $cols$CR" "stty under podman run reads the correct dimensions"
run_podman rm -t 0 -f mystty
# The same must hold for podman exec. The exec pseudo-terminal is now sized
# at creation (honoring the requested ConsoleSize), so stty reads the right
# dimensions immediately instead of racing the asynchronous resize that
# previously followed attach (see #10710).
run_podman run -d --name mystty $IMAGE top
run_podman exec -it mystty stty size <$PODMAN_TEST_PTY
is "$output" "$rows $cols$CR" "stty under podman exec reads the correct dimensions"
run_podman rm -t 0 -f mystty
}
@test "podman load - will not read from tty" {
run_podman 125 load <$PODMAN_TEST_PTY
is "$output" \
"Error: cannot read from terminal, use command-line redirection or the --input flag" \
"Diagnostic from 'podman load' without redirection or -i"
}
@test "podman run --tty -i failure with no tty" {
run_podman 0+w run --tty -i --rm $IMAGE echo hello < /dev/null
require_warning "The input device is not a TTY.*" "-it _without_ a tty"
CR=$'\r'
run_podman run --tty -i --rm $IMAGE echo hello <$PODMAN_TEST_PTY
is "$output" "hello$CR" "-it _with_ a pty"
run_podman run --tty=false -i --rm $IMAGE echo hello < /dev/null
is "$output" "hello" "-tty=false: no warning"
run_podman run --tty -i=false --rm $IMAGE echo hello < /dev/null
is "$output" "hello$CR" "-i=false: no warning"
}
@test "podman run -l passthrough-tty" {
skip_if_remote
# Requires conmon 2.1.10 or greater
want=2.1.10
run_podman info --format '{{.Host.Conmon.Path}}'
conmon_path="$output"
conmon_version=$($conmon_path --version | sed -ne 's/^.* version //p')
if ! printf "%s\n%s\n" "$want" "$conmon_version" | sort --check=quiet --version-sort; then
skip "need conmon >= $want; have $conmon_version"
fi
run tty <$PODMAN_TEST_PTY
expected_tty="$output"
run_podman run --rm -v/dev:/dev --log-driver=passthrough-tty $IMAGE tty <$PODMAN_TEST_PTY
is "$output" "$expected_tty" "passthrough-tty: tty matches"
}
@test "podman volume export should fail when stdout is a tty" {
run_podman volume create testVol
run_podman run --rm -v testVol:/data $IMAGE sh -c "echo data > /data/file.txt"
# Positive Case
"${PODMAN_CMD[@]}" volume export testVol --output=/dev/null >$PODMAN_TEST_PTY ||
die "$PODMAN volume export testVol --output=/dev/null failed when connected to terminal."
# Negative Case
local rc=0
"${PODMAN_CMD[@]}" volume export testVol >$PODMAN_TEST_PTY 2>$PODMAN_TMPDIR/out || rc=$?
is "$rc" "125" "Exit code should be 125"
is "$(<$PODMAN_TMPDIR/out)" "Error: cannot write to terminal, use command-line redirection or the --output flag" "Should refuse to export to terminal."
run_podman volume rm testVol --force
}
# vim: filetype=sh