TEST-80-NOTIFYACCESS: Add notify-reload signal handler validation test
Add a new integration test to verify the signal handler validation for Type=notify-reload services, as introduced in the previous commit. The test adds a shell harness and four service files to cover all scenarios: 1. `notify-reload-no-handler.service`: Verifies that the service fails to start with Result=protocol when the handler is missing at the first READY=1. 2. `notify-reload-sigstop.service`: Verifies that SIGSTOP is exempt from handler validation because it cannot be caught or blocked. 3. `notify-reload-toggle-handler.service`: Verifies that removing the handler at runtime results in a warning on reload, but the signal is still sent, causing the service to terminate from unhandled SIGHUP. 4. `notify-reload-well-behaved.service`: Verifies the happy path where a service with a handler starts and reloads successfully. Use bounded FIFO operations and journal cursors so failures are prompt and log assertions cannot race a relative time window.
This commit is contained in:
@@ -172,4 +172,85 @@ assert_eq "$(systemctl show fdstore-nopin.service -P NFileDescriptorStore)" 0
|
||||
assert_eq "$(systemctl show fdstore-pin.service -P SubState)" dead
|
||||
assert_eq "$(systemctl show fdstore-nopin.service -P SubState)" dead
|
||||
|
||||
# Test notify-reload signal handler validation
|
||||
|
||||
cleanup_notify_reload() {
|
||||
systemctl stop notify-reload-no-handler.service \
|
||||
notify-reload-sigstop.service \
|
||||
notify-reload-toggle-handler.service \
|
||||
notify-reload-well-behaved.service || :
|
||||
systemctl reset-failed notify-reload-no-handler.service \
|
||||
notify-reload-sigstop.service \
|
||||
notify-reload-toggle-handler.service \
|
||||
notify-reload-well-behaved.service || :
|
||||
rm -f /tmp/reload-nohandler-in /tmp/reload-nohandler-out \
|
||||
/tmp/reload-nohandler-cursor \
|
||||
/tmp/reload-sigstop-in /tmp/reload-sigstop-out \
|
||||
/tmp/reload-toggle-in /tmp/reload-toggle-out \
|
||||
/tmp/reload-toggle-cursor \
|
||||
/tmp/reload-wellbehaved-in /tmp/reload-wellbehaved-out
|
||||
}
|
||||
|
||||
trap cleanup_notify_reload EXIT
|
||||
cleanup_notify_reload
|
||||
|
||||
# Test 1: Service without signal handler should fail to start
|
||||
mkfifo /tmp/reload-nohandler-in /tmp/reload-nohandler-out
|
||||
journalctl -q -n 0 --cursor-file=/tmp/reload-nohandler-cursor
|
||||
(! systemctl start notify-reload-no-handler.service)
|
||||
assert_eq "$(systemctl show notify-reload-no-handler.service -P SubState)" "failed"
|
||||
assert_eq "$(systemctl show notify-reload-no-handler.service -P Result)" "protocol"
|
||||
# Verify error was logged about missing signal handler
|
||||
journalctl --sync
|
||||
journalctl -u notify-reload-no-handler.service --cursor-file=/tmp/reload-nohandler-cursor \
|
||||
--grep "lacks handler for reload signal" >/dev/null
|
||||
systemctl reset-failed notify-reload-no-handler.service
|
||||
rm -f /tmp/reload-nohandler-in /tmp/reload-nohandler-out
|
||||
|
||||
# Test 2: SIGSTOP cannot be caught or blocked, so it is exempt from handler validation
|
||||
mkfifo /tmp/reload-sigstop-in /tmp/reload-sigstop-out
|
||||
systemctl start notify-reload-sigstop.service
|
||||
assert_eq "$(systemctl show notify-reload-sigstop.service -P SubState)" "running"
|
||||
systemctl stop notify-reload-sigstop.service
|
||||
rm -f /tmp/reload-sigstop-in /tmp/reload-sigstop-out
|
||||
|
||||
# Test 3: Service that removes handler should warn on reload but still reload
|
||||
mkfifo /tmp/reload-toggle-in /tmp/reload-toggle-out
|
||||
systemctl start notify-reload-toggle-handler.service
|
||||
assert_eq "$(systemctl show notify-reload-toggle-handler.service -P SubState)" "running"
|
||||
|
||||
# Command service to remove its signal handler
|
||||
timeout 10 bash -c 'echo "remove-handler" >/tmp/reload-toggle-in'
|
||||
response="$(timeout 10 cat /tmp/reload-toggle-out)"
|
||||
assert_eq "$response" "handler-removed"
|
||||
|
||||
# Reload should succeed (with warning) even though handler is gone - service will be killed by SIGHUP
|
||||
# but that's intentional after the first start succeeds
|
||||
journalctl -q -n 0 --cursor-file=/tmp/reload-toggle-cursor
|
||||
systemctl reload --no-block notify-reload-toggle-handler.service
|
||||
# The service will die from SIGHUP since the handler is removed
|
||||
timeout 10 bash -c 'while systemctl is-active --quiet notify-reload-toggle-handler.service; do sleep .5; done'
|
||||
# Verify warning was logged
|
||||
journalctl --sync
|
||||
journalctl -u notify-reload-toggle-handler.service --cursor-file=/tmp/reload-toggle-cursor \
|
||||
--grep "lacks handler for reload signal" >/dev/null
|
||||
rm -f /tmp/reload-toggle-in /tmp/reload-toggle-out
|
||||
|
||||
# Test 4: Well-behaved service with handler should work correctly
|
||||
mkfifo /tmp/reload-wellbehaved-in /tmp/reload-wellbehaved-out
|
||||
systemctl start notify-reload-well-behaved.service
|
||||
assert_eq "$(systemctl show notify-reload-well-behaved.service -P SubState)" "running"
|
||||
|
||||
# Reload should succeed
|
||||
systemctl reload --no-block notify-reload-well-behaved.service
|
||||
timeout 10 bash -c 'until [[ $(systemctl show notify-reload-well-behaved.service -P SubState) == "reload-signal" ]]; do sleep .5; done'
|
||||
response="$(timeout 10 cat /tmp/reload-wellbehaved-out)"
|
||||
assert_eq "$response" "reload"
|
||||
timeout 10 bash -c 'until [[ $(systemctl show notify-reload-well-behaved.service -P SubState) == "running" ]]; do sleep .5; done'
|
||||
assert_eq "$(systemctl show notify-reload-well-behaved.service -P ReloadResult)" "success"
|
||||
|
||||
timeout 10 bash -c 'echo "exit" >/tmp/reload-wellbehaved-in'
|
||||
systemctl stop notify-reload-well-behaved.service
|
||||
rm -f /tmp/reload-wellbehaved-in /tmp/reload-wellbehaved-out
|
||||
|
||||
touch /testok
|
||||
|
||||
Reference in New Issue
Block a user