fish-shell/tests/pexpects/signals.py

130 lines
3.7 KiB
Python
Raw Normal View History

2020-06-13 13:38:54 +00:00
#!/usr/bin/env python3
from pexpect_helper import SpawnedProc
sp = SpawnedProc(timeout=10)
2020-06-13 13:38:54 +00:00
send, sendline, sleep, expect_prompt, expect_re, expect_str = (
sp.send,
sp.sendline,
sp.sleep,
sp.expect_prompt,
sp.expect_re,
sp.expect_str,
)
from time import sleep
import os
import platform
2020-06-13 13:38:54 +00:00
import signal
import subprocess
import sys
2020-06-13 13:38:54 +00:00
if "CI" in os.environ and platform.system() == "Darwin":
sys.exit(127)
if platform.system() == "FreeBSD": # Spurious failure. TODO Only disable this in CI.
sys.exit(127)
2020-06-13 13:38:54 +00:00
expect_prompt()
# Verify that SIGINT inside a command sub cancels it.
# Negate the pid to send to the pgroup (which should include sleep).
sendline("while true; echo (sleep 2000); end")
sleep(0.5)
os.kill(-sp.spawn.pid, signal.SIGINT)
expect_prompt()
# SIGINT should be ignored by background processes.
sendline("sleep 1234 &")
2020-06-13 13:38:54 +00:00
expect_prompt()
os.kill(-sp.spawn.pid, signal.SIGINT)
2020-06-13 13:38:54 +00:00
sleep(0.010)
sendline("jobs")
expect_prompt("sleep 1234")
2020-06-13 13:38:54 +00:00
sendline("kill %1")
expect_prompt()
2020-06-13 13:38:54 +00:00
# Verify that the fish_postexec handler is called after SIGINT.
sendline("function postexec --on-event fish_postexec; echo fish_postexec spotted; end")
expect_prompt()
sendline("read")
2024-04-25 19:36:31 +00:00
expect_re(r"\r\n?read> (\x1b\[\?1004h)?$", timeout=10)
2024-04-29 20:47:24 +00:00
sleep(0.1)
2020-06-13 13:38:54 +00:00
os.kill(sp.spawn.pid, signal.SIGINT)
2024-04-25 19:36:31 +00:00
expect_str("fish_postexec spotted", timeout=10)
2020-06-13 13:38:54 +00:00
expect_prompt()
# Verify that the fish_kill_signal is set.
sendline(
"functions -e postexec; function postexec --on-event fish_postexec; echo fish_kill_signal $fish_kill_signal; end"
)
2020-06-13 13:38:54 +00:00
expect_prompt()
sendline("sleep 5")
2024-04-23 18:38:09 +00:00
sleep(0.300)
subprocess.call(["pkill", "-INT", "-P", str(sp.spawn.pid), "sleep"])
2020-06-13 13:38:54 +00:00
expect_str("fish_kill_signal 2")
expect_prompt()
sendline("sleep 5")
sleep(0.200)
subprocess.call(["pkill", "-TERM", "-P", str(sp.spawn.pid), "sleep"])
2020-06-13 13:38:54 +00:00
expect_str("fish_kill_signal 15")
expect_prompt()
# See that open() is only interruptible by SIGINT.
sendline("mkfifo fifoo")
expect_prompt()
sendline("cat >fifoo")
subprocess.call(["kill", "-WINCH", str(sp.spawn.pid)])
expect_re("open: ", shouldfail=True, timeout=10)
subprocess.call(["kill", "-INT", str(sp.spawn.pid)])
expect_prompt()
2020-06-13 13:38:54 +00:00
# Verify that sending SIGHUP to the shell, such as will happen when the tty is
# closed by the terminal, terminates the shell and the foreground command and
# any background commands run from that shell.
#
# Save the pids for later to check if they are still running.
pids = []
send("sleep 130 & echo $last_pid\r")
2024-04-02 20:40:45 +00:00
pids += [expect_re("\\d+\r\n").group().strip()]
2020-06-13 13:38:54 +00:00
expect_prompt()
send("sleep 131 & echo $last_pid\r")
2024-04-02 20:40:45 +00:00
pids += [expect_re("\\d+\r\n").group().strip()]
2020-06-13 13:38:54 +00:00
expect_prompt()
send("sleep 9999999\r")
2023-01-18 15:48:49 +00:00
sleep(0.500) # ensure fish kicks off the above sleep before it gets HUP - see #7288
2020-06-13 13:38:54 +00:00
os.kill(sp.spawn.pid, signal.SIGHUP)
# Verify the spawned fish shell has exited.
sp.spawn.wait()
# Verify all child processes have been killed. We don't use `-p $pid` because
# if the shell has a bug the child processes might have been reparented to pid
# 1 rather than killed.
proc = subprocess.run(
["pgrep", "-l", "-f", "sleep 13"], stdout=subprocess.PIPE, stderr=subprocess.PIPE
)
2023-06-01 16:20:19 +00:00
remaining = []
2020-06-13 13:38:54 +00:00
if proc.returncode == 0:
# If any sleeps exist, we check them against our pids,
# to avoid false-positives (any other `sleep 13xyz` running on the system)
2020-06-13 13:38:54 +00:00
print(proc.stdout)
2023-06-01 16:20:19 +00:00
for line in proc.stdout.split(b"\n"):
pid = line.split(b" ", maxsplit=1)[0].decode("utf-8")
if pid in pids:
remaining += [pid]
2023-06-01 16:20:19 +00:00
# Kill any remaining sleeps ourselves, otherwise rerunning this is pointless.
for pid in remaining:
try:
os.kill(int(pid), signal.SIGTERM)
except ProcessLookupError:
continue
if remaining:
# We still have processes left over!
print("Commands were still running!")
print(remaining)
2020-06-13 13:38:54 +00:00
sys.exit(1)