1#!/bin/sh 2# 3# SPDX-License-Identifier: BSD-2-Clause-FreeBSD 4# 5# Copyright (c) 2021 Axcient 6# 7# Redistribution and use in source and binary forms, with or without 8# modification, are permitted provided that the following conditions 9# are met: 10# 1. Redistributions of source code must retain the above copyright 11# notice, this list of conditions and the following disclaimer. 12# 2. Redistributions in binary form must reproduce the above copyright 13# notice, this list of conditions and the following disclaimer in the 14# documentation and/or other materials provided with the distribution. 15# 16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26# SUCH DAMAGE. 27 28# $FreeBSD$ 29 30atf_test_case both_pidfile cleanup 31both_pidfile_head() { 32 atf_set "descr" "daemon should write pid files for itself and its child" 33} 34both_pidfile_body() { 35 daemon -P daemon.pid -p sleep.pid sleep 300 36 atf_check -s exit:0 test -f daemon.pid 37 atf_check -s exit:0 -o match:"daemon: sleep" ps -p `cat daemon.pid` 38 atf_check -s exit:0 test -f sleep.pid 39 atf_check -s exit:0 -o match:"[0-9] sleep 300$" ps -p `cat sleep.pid` 40} 41both_pidfile_cleanup() { 42 if [ -f daemon.pid ]; then 43 daemon_pid=`cat daemon.pid` 44 fi 45 if [ -f sleep_pid ]; then 46 sleep_pid=`cat sleep.pid` 47 fi 48 [ -n "$sleep_pid" ] && kill $sleep_pid 49 # NB: killing the sleep should kill the daemon too, so we musn't fail 50 # the test if the second kill fails with ESRCH 51 [ -n "$daemon_pid" ] && kill $daemon_pid || true 52} 53 54atf_test_case chdir cleanup 55chdir_head() { 56 atf_set "descr" "daemon should chdir to /" 57} 58chdir_body() { 59 # Executing sleep by relative path will only work from / 60 daemon -p ${PWD}/sleep.pid -c bin/sleep 300 61 atf_check -s exit:0 test -f sleep.pid 62 atf_check -s exit:0 -o match:"[0-9] bin/sleep 300$" \ 63 ps -p `cat sleep.pid` 64} 65chdir_cleanup() { 66 [ -f sleep.pid ] && kill `cat sleep.pid` 67} 68 69atf_test_case child_pidfile cleanup 70child_pidfile_head() { 71 atf_set "descr" "daemon should write its child's pid to a pidfile" 72} 73child_pidfile_body() { 74 daemon -p sleep.pid sleep 300 75 atf_check -s exit:0 test -f sleep.pid 76 atf_check -s exit:0 -o match:"[0-9] sleep 300$" ps -p `cat sleep.pid` 77} 78child_pidfile_cleanup() { 79 [ -f sleep.pid ] && kill `cat sleep.pid` 80} 81 82atf_test_case child_pidfile_lock cleanup 83child_pidfile_lock_head() { 84 atf_set "descr" "daemon should refuse to clobber an existing child" 85} 86child_pidfile_lock_body() { 87 daemon -p sleep.pid sleep 300 88 atf_check -s exit:0 test -f sleep.pid 89 atf_check -s not-exit:0 -e match:"process already running" \ 90 daemon -p sleep.pid sleep 300 91} 92child_pidfile_lock_cleanup() { 93 [ -f sleep.pid ] && kill `cat sleep.pid` 94} 95 96atf_test_case newsyslog cleanup 97newsyslog_head() { 98 atf_set "descr" "daemon should close and reopen the output file on SIGHUP" 99} 100newsyslog_body() { 101 cat > child.sh <<HERE 102#! /bin/sh 103while true ; do 104 echo "my output" 105 sleep 0.1 106done 107HERE 108 chmod +x child.sh 109 daemon -P daemon.pid -H -o output_file ./child.sh 110 atf_check -s exit:0 test -f daemon.pid 111 sleep 0.2 112 mv output_file output_file.0 113 kill -HUP `cat daemon.pid` 114 sleep 0.2 115 atf_check -s exit:0 test -s output_file.0 116 atf_check -s exit:0 test -s output_file 117} 118newsyslog_cleanup() { 119 [ -f daemon.pid ] && kill `cat daemon.pid` 120} 121 122atf_test_case output_file 123output_file_head() { 124 atf_set "descr" "daemon should redirect stdout to a file" 125} 126output_file_body() { 127 daemon -o output_file seq 1 5 128 seq 1 5 > expected_file 129 atf_check -s exit:0 cmp output_file expected_file 130} 131 132atf_test_case restart_child cleanup 133restart_child_head() { 134 atf_set "descr" "daemon should restart a dead child" 135} 136restart_child_body() { 137 daemon -rP daemon.pid -p sleep.pid sleep 300 138 atf_check -s exit:0 test -f daemon.pid 139 atf_check -s exit:0 test -f sleep.pid 140 orig_sleep_pid=`cat sleep.pid` 141 kill $orig_sleep_pid 142 # Wait up to 10s for the daemon to restart the child. 143 for t in `seq 0 0.1 10`; do 144 new_sleep_pid=`cat sleep.pid` 145 [ "$orig_sleep_pid" -ne "$new_sleep_pid" ] && break 146 sleep 0.1 147 done 148 [ "$orig_sleep_pid" -ne "$new_sleep_pid" ] || \ 149 atf_fail "child was not restarted" 150 151} 152restart_child_cleanup() { 153 [ -f daemon.pid ] && kill `cat daemon.pid` 154} 155 156atf_test_case supervisor_pidfile cleanup 157supervisor_pidfile_head() { 158 atf_set "descr" "daemon should write its own pid to a pidfile" 159} 160supervisor_pidfile_body() { 161 daemon -P daemon.pid sleep 300 162 atf_check -s exit:0 test -f daemon.pid 163 atf_check -s exit:0 -o match:"daemon: sleep" ps -p `cat daemon.pid` 164} 165supervisor_pidfile_cleanup() { 166 [ -f daemon.pid ] && kill `cat daemon.pid` 167} 168 169atf_test_case supervisor_pidfile_lock cleanup 170supervisor_pidfile_lock_head() { 171 atf_set "descr" "daemon should refuse to clobber an existing instance" 172} 173supervisor_pidfile_lock_body() { 174 daemon -P daemon.pid sleep 300 175 atf_check -s exit:0 test -f daemon.pid 176 atf_check -s not-exit:0 -e match:"process already running" \ 177 daemon -p daemon.pid sleep 300 178} 179supervisor_pidfile_lock_cleanup() { 180 [ -f daemon.pid ] && kill `cat daemon.pid` 181} 182 183atf_test_case title cleanup 184title_head() { 185 atf_set "descr" "daemon should change its process title" 186} 187title_body() { 188 daemon -P daemon.pid -t "I'm a title!" sleep 300 189 atf_check -s exit:0 test -f daemon.pid 190 atf_check -s exit:0 -o match:"daemon: I'm a title!" \ 191 ps -p `cat daemon.pid` 192} 193title_cleanup() { 194 [ -f daemon.pid ] && kill `cat daemon.pid` 195} 196 197atf_test_case user cleanup 198user_head() { 199 atf_set "descr" "daemon should drop privileges" 200 atf_set "require.user" "root" 201} 202user_body() { 203 daemon -p sleep.pid -u nobody sleep 300 204 atf_check -s exit:0 test -f sleep.pid 205 atf_check -s exit:0 -o match:"^nobody" ps -up `cat sleep.pid` 206} 207user_cleanup() { 208 [ -f sleep.pid ] && kill `cat sleep.pid` 209} 210 211 212atf_init_test_cases() { 213 atf_add_test_case both_pidfile 214 atf_add_test_case chdir 215 atf_add_test_case child_pidfile 216 atf_add_test_case child_pidfile_lock 217 atf_add_test_case newsyslog 218 atf_add_test_case output_file 219 atf_add_test_case restart_child 220 atf_add_test_case supervisor_pidfile 221 atf_add_test_case supervisor_pidfile_lock 222 atf_add_test_case title 223 atf_add_test_case user 224} 225