xref: /freebsd/usr.sbin/daemon/tests/daemon_test.sh (revision 9ab59e900c1dd693b4d14285389a035e81341789)
13b57d80cSAlan Somers#!/bin/sh
23b57d80cSAlan Somers#
34d846d26SWarner Losh# SPDX-License-Identifier: BSD-2-Clause
43b57d80cSAlan Somers#
53b57d80cSAlan Somers# Copyright (c) 2021 Axcient
63b57d80cSAlan Somers#
73b57d80cSAlan Somers# Redistribution and use in source and binary forms, with or without
83b57d80cSAlan Somers# modification, are permitted provided that the following conditions
93b57d80cSAlan Somers# are met:
103b57d80cSAlan Somers# 1. Redistributions of source code must retain the above copyright
113b57d80cSAlan Somers#    notice, this list of conditions and the following disclaimer.
123b57d80cSAlan Somers# 2. Redistributions in binary form must reproduce the above copyright
133b57d80cSAlan Somers#    notice, this list of conditions and the following disclaimer in the
143b57d80cSAlan Somers#    documentation and/or other materials provided with the distribution.
153b57d80cSAlan Somers#
163b57d80cSAlan Somers# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
173b57d80cSAlan Somers# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
183b57d80cSAlan Somers# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
193b57d80cSAlan Somers# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
203b57d80cSAlan Somers# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
213b57d80cSAlan Somers# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
223b57d80cSAlan Somers# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
233b57d80cSAlan Somers# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
243b57d80cSAlan Somers# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
253b57d80cSAlan Somers# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
263b57d80cSAlan Somers# SUCH DAMAGE.
273b57d80cSAlan Somers
283b57d80cSAlan Somersatf_test_case both_pidfile cleanup
293b57d80cSAlan Somersboth_pidfile_head() {
303b57d80cSAlan Somers	atf_set "descr" "daemon should write pid files for itself and its child"
313b57d80cSAlan Somers}
323b57d80cSAlan Somersboth_pidfile_body() {
333b57d80cSAlan Somers	daemon -P daemon.pid -p sleep.pid sleep 300
343b57d80cSAlan Somers	atf_check -s exit:0 test -f daemon.pid
353b57d80cSAlan Somers	atf_check -s exit:0 -o match:"daemon: sleep" ps -p `cat daemon.pid`
363b57d80cSAlan Somers	atf_check -s exit:0 test -f sleep.pid
373b57d80cSAlan Somers	atf_check -s exit:0 -o match:"[0-9] sleep 300$" ps -p `cat sleep.pid`
383b57d80cSAlan Somers}
393b57d80cSAlan Somersboth_pidfile_cleanup() {
403b57d80cSAlan Somers	if [ -f daemon.pid ]; then
413b57d80cSAlan Somers		daemon_pid=`cat daemon.pid`
423b57d80cSAlan Somers	fi
433b57d80cSAlan Somers	if [ -f sleep_pid ]; then
443b57d80cSAlan Somers		sleep_pid=`cat sleep.pid`
453b57d80cSAlan Somers	fi
463b57d80cSAlan Somers	[ -n "$sleep_pid" ] && kill $sleep_pid
473b57d80cSAlan Somers	# NB: killing the sleep should kill the daemon too, so we musn't fail
483b57d80cSAlan Somers	# the test if the second kill fails with ESRCH
493b57d80cSAlan Somers	[ -n "$daemon_pid" ] && kill $daemon_pid || true
503b57d80cSAlan Somers}
513b57d80cSAlan Somers
523b57d80cSAlan Somersatf_test_case chdir cleanup
533b57d80cSAlan Somerschdir_head() {
543b57d80cSAlan Somers	atf_set "descr" "daemon should chdir to /"
553b57d80cSAlan Somers}
563b57d80cSAlan Somerschdir_body() {
573b57d80cSAlan Somers	# Executing sleep by relative path will only work from /
583b57d80cSAlan Somers	daemon -p ${PWD}/sleep.pid -c bin/sleep 300
593b57d80cSAlan Somers	atf_check -s exit:0 test -f sleep.pid
603b57d80cSAlan Somers	atf_check -s exit:0 -o match:"[0-9] bin/sleep 300$" \
613b57d80cSAlan Somers		ps -p `cat sleep.pid`
623b57d80cSAlan Somers}
633b57d80cSAlan Somerschdir_cleanup() {
643b57d80cSAlan Somers	[ -f sleep.pid ] && kill `cat sleep.pid`
653b57d80cSAlan Somers}
663b57d80cSAlan Somers
673b57d80cSAlan Somersatf_test_case child_pidfile cleanup
683b57d80cSAlan Somerschild_pidfile_head() {
693b57d80cSAlan Somers	atf_set "descr" "daemon should write its child's pid to a pidfile"
703b57d80cSAlan Somers}
713b57d80cSAlan Somerschild_pidfile_body() {
723b57d80cSAlan Somers	daemon -p sleep.pid sleep 300
733b57d80cSAlan Somers	atf_check -s exit:0 test -f sleep.pid
743b57d80cSAlan Somers	atf_check -s exit:0 -o match:"[0-9] sleep 300$" ps -p `cat sleep.pid`
753b57d80cSAlan Somers}
763b57d80cSAlan Somerschild_pidfile_cleanup() {
773b57d80cSAlan Somers	[ -f sleep.pid ] && kill `cat sleep.pid`
783b57d80cSAlan Somers}
793b57d80cSAlan Somers
803b57d80cSAlan Somersatf_test_case child_pidfile_lock cleanup
813b57d80cSAlan Somerschild_pidfile_lock_head() {
823b57d80cSAlan Somers	atf_set "descr" "daemon should refuse to clobber an existing child"
833b57d80cSAlan Somers}
843b57d80cSAlan Somerschild_pidfile_lock_body() {
853b57d80cSAlan Somers	daemon -p sleep.pid sleep 300
863b57d80cSAlan Somers	atf_check -s exit:0 test -f sleep.pid
873b57d80cSAlan Somers	atf_check -s not-exit:0 -e match:"process already running" \
883b57d80cSAlan Somers		daemon -p sleep.pid sleep 300
893b57d80cSAlan Somers}
903b57d80cSAlan Somerschild_pidfile_lock_cleanup() {
913b57d80cSAlan Somers	[ -f sleep.pid ] && kill `cat sleep.pid`
923b57d80cSAlan Somers}
933b57d80cSAlan Somers
943b57d80cSAlan Somersatf_test_case newsyslog cleanup
953b57d80cSAlan Somersnewsyslog_head() {
963b57d80cSAlan Somers	atf_set "descr" "daemon should close and reopen the output file on SIGHUP"
973b57d80cSAlan Somers}
983b57d80cSAlan Somersnewsyslog_body() {
993b57d80cSAlan Somers	cat > child.sh <<HERE
1003b57d80cSAlan Somers#! /bin/sh
1013b57d80cSAlan Somerswhile true ; do
1023b57d80cSAlan Somers	echo "my output"
1033b57d80cSAlan Somers	sleep 0.1
1043b57d80cSAlan Somersdone
1053b57d80cSAlan SomersHERE
1063b57d80cSAlan Somers	chmod +x child.sh
1073b57d80cSAlan Somers	daemon -P daemon.pid -H -o output_file ./child.sh
1083b57d80cSAlan Somers	atf_check -s exit:0 test -f daemon.pid
1093b57d80cSAlan Somers	sleep 0.2
1103b57d80cSAlan Somers	mv output_file output_file.0
1113b57d80cSAlan Somers	kill -HUP `cat daemon.pid`
1123b57d80cSAlan Somers	sleep 0.2
1133b57d80cSAlan Somers	atf_check -s exit:0 test -s output_file.0
1143b57d80cSAlan Somers	atf_check -s exit:0 test -s output_file
1153b57d80cSAlan Somers}
1163b57d80cSAlan Somersnewsyslog_cleanup() {
1173b57d80cSAlan Somers	[ -f daemon.pid ] && kill `cat daemon.pid`
1183b57d80cSAlan Somers}
1193b57d80cSAlan Somers
1203b57d80cSAlan Somersatf_test_case output_file
1213b57d80cSAlan Somersoutput_file_head() {
1223b57d80cSAlan Somers	atf_set "descr" "daemon should redirect stdout to a file"
1233b57d80cSAlan Somers}
1243b57d80cSAlan Somersoutput_file_body() {
1253b57d80cSAlan Somers	daemon -o output_file seq 1 5
1263b57d80cSAlan Somers	seq 1 5 > expected_file
1273b57d80cSAlan Somers	atf_check -s exit:0 cmp output_file expected_file
1283b57d80cSAlan Somers}
1293b57d80cSAlan Somers
1303b57d80cSAlan Somersatf_test_case restart_child cleanup
1313b57d80cSAlan Somersrestart_child_head() {
1323b57d80cSAlan Somers	atf_set "descr" "daemon should restart a dead child"
1333b57d80cSAlan Somers}
1343b57d80cSAlan Somersrestart_child_body() {
1353b57d80cSAlan Somers	daemon -rP daemon.pid -p sleep.pid sleep 300
1363b57d80cSAlan Somers	atf_check -s exit:0 test -f daemon.pid
1373b57d80cSAlan Somers	atf_check -s exit:0 test -f sleep.pid
1383b57d80cSAlan Somers	orig_sleep_pid=`cat sleep.pid`
1393b57d80cSAlan Somers	kill $orig_sleep_pid
1403b57d80cSAlan Somers	# Wait up to 10s for the daemon to restart the child.
1413b57d80cSAlan Somers	for t in `seq 0 0.1 10`; do
142aa8722ccSKyle Evans		if [ -s "sleep.pid" ]; then
1433b57d80cSAlan Somers			new_sleep_pid=`cat sleep.pid`
1443b57d80cSAlan Somers			[ "$orig_sleep_pid" -ne "$new_sleep_pid" ] && break
145aa8722ccSKyle Evans		fi
146aa8722ccSKyle Evans
1473b57d80cSAlan Somers		sleep 0.1
1483b57d80cSAlan Somers	done
1493b57d80cSAlan Somers	[ "$orig_sleep_pid" -ne "$new_sleep_pid" ] || \
1503b57d80cSAlan Somers		atf_fail "child was not restarted"
1513b57d80cSAlan Somers
1523b57d80cSAlan Somers}
1533b57d80cSAlan Somersrestart_child_cleanup() {
1543b57d80cSAlan Somers	[ -f daemon.pid ] && kill `cat daemon.pid`
1553b57d80cSAlan Somers}
1563b57d80cSAlan Somers
157*9ab59e90SKyle Evansatf_test_case restart_hang cleanup
158*9ab59e90SKyle Evansrestart_hang_head() {
159*9ab59e90SKyle Evans	atf_set "descr" "daemon should terminate with SIGTERM even pending child restart"
160*9ab59e90SKyle Evans}
161*9ab59e90SKyle Evansrestart_hang_body() {
162*9ab59e90SKyle Evans	daemon -rP daemon.pid -R 10 -p sleep.pid sleep 300
163*9ab59e90SKyle Evans	atf_check -s exit:0 test -f daemon.pid
164*9ab59e90SKyle Evans	atf_check -s exit:0 test -f sleep.pid
165*9ab59e90SKyle Evans	read sleep_pid < sleep.pid
166*9ab59e90SKyle Evans	1>&2 echo "$sleep_pid"
167*9ab59e90SKyle Evans	kill "$sleep_pid"
168*9ab59e90SKyle Evans
169*9ab59e90SKyle Evans	# Wait up to 5s for the child to exit
170*9ab59e90SKyle Evans	for t in `seq 0 0.1 5`; do
171*9ab59e90SKyle Evans		[ ! -s "sleep.pid" ] && break
172*9ab59e90SKyle Evans		sleep 0.1
173*9ab59e90SKyle Evans	done
174*9ab59e90SKyle Evans
175*9ab59e90SKyle Evans	atf_check test ! -s "sleep.pid"
176*9ab59e90SKyle Evans
177*9ab59e90SKyle Evans	read daemon_pid < daemon.pid
178*9ab59e90SKyle Evans	kill -TERM "$daemon_pid"
179*9ab59e90SKyle Evans
180*9ab59e90SKyle Evans	# Wait up to 10s for the daemon to terminate
181*9ab59e90SKyle Evans	for t in `seq 0 0.1 10`; do
182*9ab59e90SKyle Evans		[ ! -f "daemon.pid" ] && break
183*9ab59e90SKyle Evans		sleep 0.1
184*9ab59e90SKyle Evans	done
185*9ab59e90SKyle Evans
186*9ab59e90SKyle Evans	atf_check test ! -f "daemon.pid"
187*9ab59e90SKyle Evans	atf_check test ! -f "sleep.pid"
188*9ab59e90SKyle Evans}
189*9ab59e90SKyle Evansrestart_hang_cleanup() {
190*9ab59e90SKyle Evans	[ -s daemon.pid ] && kill -9 `cat daemon.pid`
191*9ab59e90SKyle Evans	true
192*9ab59e90SKyle Evans}
193*9ab59e90SKyle Evans
1943b57d80cSAlan Somersatf_test_case supervisor_pidfile cleanup
1953b57d80cSAlan Somerssupervisor_pidfile_head() {
1963b57d80cSAlan Somers	atf_set "descr" "daemon should write its own pid to a pidfile"
1973b57d80cSAlan Somers}
1983b57d80cSAlan Somerssupervisor_pidfile_body() {
1993b57d80cSAlan Somers	daemon -P daemon.pid sleep 300
2003b57d80cSAlan Somers	atf_check -s exit:0 test -f daemon.pid
2013b57d80cSAlan Somers	atf_check -s exit:0 -o match:"daemon: sleep" ps -p `cat daemon.pid`
2023b57d80cSAlan Somers}
2033b57d80cSAlan Somerssupervisor_pidfile_cleanup() {
2043b57d80cSAlan Somers	[ -f daemon.pid ] && kill `cat daemon.pid`
2053b57d80cSAlan Somers}
2063b57d80cSAlan Somers
2073b57d80cSAlan Somersatf_test_case supervisor_pidfile_lock cleanup
2083b57d80cSAlan Somerssupervisor_pidfile_lock_head() {
2093b57d80cSAlan Somers	atf_set "descr" "daemon should refuse to clobber an existing instance"
2103b57d80cSAlan Somers}
2113b57d80cSAlan Somerssupervisor_pidfile_lock_body() {
2123b57d80cSAlan Somers	daemon -P daemon.pid sleep 300
2133b57d80cSAlan Somers	atf_check -s exit:0 test -f daemon.pid
2143b57d80cSAlan Somers	atf_check -s not-exit:0 -e match:"process already running" \
2153b57d80cSAlan Somers		daemon -p daemon.pid sleep 300
2163b57d80cSAlan Somers}
2173b57d80cSAlan Somerssupervisor_pidfile_lock_cleanup() {
2183b57d80cSAlan Somers	[ -f daemon.pid ] && kill `cat daemon.pid`
2193b57d80cSAlan Somers}
2203b57d80cSAlan Somers
2213b57d80cSAlan Somersatf_test_case title cleanup
2223b57d80cSAlan Somerstitle_head() {
2233b57d80cSAlan Somers	atf_set "descr" "daemon should change its process title"
2243b57d80cSAlan Somers}
2253b57d80cSAlan Somerstitle_body() {
2263b57d80cSAlan Somers	daemon -P daemon.pid -t "I'm a title!" sleep 300
2273b57d80cSAlan Somers	atf_check -s exit:0 test -f daemon.pid
2283b57d80cSAlan Somers	atf_check -s exit:0 -o match:"daemon: I'm a title!" \
2293b57d80cSAlan Somers		ps -p `cat daemon.pid`
2303b57d80cSAlan Somers}
2313b57d80cSAlan Somerstitle_cleanup() {
2323b57d80cSAlan Somers	[ -f daemon.pid ] && kill `cat daemon.pid`
2333b57d80cSAlan Somers}
2343b57d80cSAlan Somers
2353b57d80cSAlan Somersatf_test_case user cleanup
2363b57d80cSAlan Somersuser_head() {
2373b57d80cSAlan Somers	atf_set "descr" "daemon should drop privileges"
2383b57d80cSAlan Somers	atf_set "require.user" "root"
2393b57d80cSAlan Somers}
2403b57d80cSAlan Somersuser_body() {
2413b57d80cSAlan Somers	daemon -p sleep.pid -u nobody sleep 300
2423b57d80cSAlan Somers	atf_check -s exit:0 test -f sleep.pid
2433b57d80cSAlan Somers	atf_check -s exit:0 -o match:"^nobody" ps -up `cat sleep.pid`
2443b57d80cSAlan Somers}
2453b57d80cSAlan Somersuser_cleanup() {
2463b57d80cSAlan Somers	[ -f sleep.pid ] && kill `cat sleep.pid`
2473b57d80cSAlan Somers}
2483b57d80cSAlan Somers
2493b57d80cSAlan Somers
2503b57d80cSAlan Somersatf_init_test_cases() {
2513b57d80cSAlan Somers	atf_add_test_case both_pidfile
2523b57d80cSAlan Somers	atf_add_test_case chdir
2533b57d80cSAlan Somers	atf_add_test_case child_pidfile
2543b57d80cSAlan Somers	atf_add_test_case child_pidfile_lock
2553b57d80cSAlan Somers	atf_add_test_case newsyslog
2563b57d80cSAlan Somers	atf_add_test_case output_file
2573b57d80cSAlan Somers	atf_add_test_case restart_child
258*9ab59e90SKyle Evans	atf_add_test_case restart_hang
2593b57d80cSAlan Somers	atf_add_test_case supervisor_pidfile
2603b57d80cSAlan Somers	atf_add_test_case supervisor_pidfile_lock
2613b57d80cSAlan Somers	atf_add_test_case title
2623b57d80cSAlan Somers	atf_add_test_case user
2633b57d80cSAlan Somers}
264