Skip to content

Commit 474e901

Browse files
committed
test: new regression test to verify multi-chain deps
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
1 parent 9f26886 commit 474e901

File tree

2 files changed

+124
-0
lines changed

2 files changed

+124
-0
lines changed

test/Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ EXTRA_DIST += add-remove-dynamic-service-sub-config.sh
3232
EXTRA_DIST += bootstrap-crash.sh
3333
EXTRA_DIST += cond-start-task.sh
3434
EXTRA_DIST += crashing.sh
35+
EXTRA_DIST += dep-chain-reload.sh
3536
EXTRA_DIST += depserv.sh
3637
EXTRA_DIST += devmon.sh
3738
EXTRA_DIST += failing-sysv.sh
@@ -74,6 +75,7 @@ TESTS += add-remove-dynamic-service-sub-config.sh
7475
TESTS += bootstrap-crash.sh
7576
TESTS += cond-start-task.sh
7677
TESTS += crashing.sh
78+
TESTS += dep-chain-reload.sh
7779
TESTS += depserv.sh
7880
TESTS += devmon.sh
7981
TESTS += failing-sysv.sh

test/dep-chain-reload.sh

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
#!/bin/sh
2+
# Verify transitive dependency chain during reload and crash
3+
#
4+
# Three services in a chain: A → B → C, where B depends on pid/A
5+
# and C depends on pid/B. B is placed in a sub-config file so
6+
# we can use 'initctl touch' on it. B uses <!pid/svc_a> (with
7+
# leading '!') so it does not support SIGHUP, causing a full
8+
# stop/start cycle on 'initctl touch svc_b.conf' + reload.
9+
#
10+
# Test 1 - touch + reload:
11+
# After 'initctl touch svc_b.conf' + 'initctl reload':
12+
# - A should be unaffected (same PID)
13+
# - B is restarted (config was touched, noreload)
14+
# - C must be restarted (transitive, depends on pid/B)
15+
#
16+
# Test 2 - crash (kill -9):
17+
# When B is killed with SIGKILL the crash path (RUNNING →
18+
# HALTED) bypasses STOPPING, where cond_clear() used to be
19+
# the only call site. The pidfile plugin only watches for
20+
# IN_CLOSE_WRITE, so neither the pidfile removal (IN_DELETE)
21+
# nor a pidfile touch (IN_ATTRIB) triggers an inotify event.
22+
# Without the fix in service_cleanup(), pid/B is never
23+
# invalidated and C is never restarted.
24+
25+
set -eu
26+
27+
TEST_DIR=$(dirname "$0")
28+
29+
test_teardown()
30+
{
31+
say "Running test teardown."
32+
run "rm -f $FINIT_RCSD/svc_b.conf"
33+
}
34+
35+
pidof()
36+
{
37+
texec initctl -j status "$1" | jq .pid
38+
}
39+
40+
test_setup()
41+
{
42+
run "cat >> $FINIT_CONF" <<EOF
43+
service log:stdout notify:pid name:svc_a serv -np -i svc_a -- Chain root
44+
service log:stdout notify:pid <pid/svc_b> name:svc_c serv -np -i svc_c -- Needs B
45+
EOF
46+
run "echo 'service log:stdout notify:pid <!pid/svc_a> name:svc_b serv -np -i svc_b -- Needs A' > $FINIT_RCSD/svc_b.conf"
47+
}
48+
49+
# shellcheck source=/dev/null
50+
. "$TEST_DIR/lib/setup.sh"
51+
52+
sep "Configuration"
53+
run "cat $FINIT_CONF"
54+
run "cat $FINIT_RCSD/svc_b.conf"
55+
56+
say "Reload Finit to start all services"
57+
run "initctl reload"
58+
59+
say "Wait for full chain to start"
60+
retry 'assert_status "svc_c" "running"' 10 1
61+
62+
run "initctl status"
63+
run "initctl cond dump"
64+
65+
# ――――――――――――――――――――――――――――――――――――――――――――――――――――――
66+
# Test 1: touch + reload
67+
# ――――――――――――――――――――――――――――――――――――――――――――――――――――――
68+
sep "Test 1: Touch B and global reload"
69+
70+
pid_a=$(pidof svc_a)
71+
pid_b=$(pidof svc_b)
72+
pid_c=$(pidof svc_c)
73+
say "PIDs before: A=$pid_a B=$pid_b C=$pid_c"
74+
75+
run "initctl touch svc_b.conf"
76+
run "initctl reload"
77+
78+
say "Wait for chain to settle"
79+
retry 'assert_status "svc_c" "running"' 15 1
80+
81+
run "initctl status"
82+
run "initctl cond dump"
83+
84+
new_pid_a=$(pidof svc_a)
85+
new_pid_b=$(pidof svc_b)
86+
new_pid_c=$(pidof svc_c)
87+
say "PIDs after: A=$new_pid_a B=$new_pid_b C=$new_pid_c"
88+
89+
# shellcheck disable=SC2086
90+
assert "A was not restarted" $new_pid_a -eq $pid_a
91+
# shellcheck disable=SC2086
92+
assert "B was restarted (touched)" $new_pid_b -ne $pid_b
93+
# shellcheck disable=SC2086
94+
assert "C was restarted (transitive dep)" $new_pid_c -ne $pid_c
95+
96+
# ――――――――――――――――――――――――――――――――――――――――――――――――――――――
97+
# Test 2: crash (kill -9), bypasses STOPPING
98+
# ――――――――――――――――――――――――――――――――――――――――――――――――――――――
99+
sep "Test 2: Kill B with SIGKILL (bypasses STOPPING)"
100+
101+
pid_b=$(pidof svc_b)
102+
pid_c=$(pidof svc_c)
103+
say "PIDs before: B=$pid_b C=$pid_c"
104+
105+
run "kill -9 $pid_b"
106+
107+
say "Wait for B to respawn and chain to settle"
108+
retry 'assert_status "svc_c" "running"' 15 1
109+
110+
run "initctl status"
111+
run "initctl cond dump"
112+
113+
new_pid_b=$(pidof svc_b)
114+
new_pid_c=$(pidof svc_c)
115+
say "PIDs after: B=$new_pid_b C=$new_pid_c"
116+
117+
# shellcheck disable=SC2086
118+
assert "B was restarted (crashed+respawn)" $new_pid_b -ne $pid_b
119+
# shellcheck disable=SC2086
120+
assert "C was restarted (transitive dep)" $new_pid_c -ne $pid_c
121+
122+
return 0

0 commit comments

Comments
 (0)