mirror of
https://github.com/logos-storage/logos-storage-local-harness.git
synced 2026-01-02 13:33:11 +00:00
273 lines
5.2 KiB
Bash
273 lines
5.2 KiB
Bash
#!/usr/bin/env bats
|
|
# shellcheck disable=SC2128,SC2317
|
|
setup() {
|
|
load test_helper/common_setup
|
|
common_setup
|
|
|
|
# shellcheck source=./src/procmon.bash
|
|
source "${LIB_SRC}/procmon.bash"
|
|
|
|
pm_set_outputs "${TEST_OUTPUTS}/pm"
|
|
}
|
|
|
|
@test "should allow awaiting for a process" {
|
|
job() {
|
|
sleep 0.1
|
|
}
|
|
|
|
pm_start
|
|
|
|
pm_async job
|
|
pid=$result
|
|
|
|
assert await "$pid"
|
|
pm_stop
|
|
}
|
|
|
|
@test "should allow awaiting for a process up until a timeout" {
|
|
job() {
|
|
sleep 5000
|
|
}
|
|
|
|
pm_start
|
|
|
|
pm_async job
|
|
pid=$result
|
|
|
|
refute await "$pid" 1
|
|
pm_stop
|
|
}
|
|
|
|
@test "should kill processes recursively" {
|
|
# Note that this is fragile. We need to structure
|
|
# the process tree such that the parent does not exit
|
|
# before the child, or the child will be reparented to
|
|
# init and won't be killed. The defensive thing to do
|
|
# here is to wait on any child you'd like cleaned before
|
|
# exiting its parent subshell.
|
|
(
|
|
# each backgrounded process generates two processes:
|
|
# the process itself, and its subshell.
|
|
sleep 500 &
|
|
sl1=$!
|
|
(
|
|
sleep 500 &
|
|
await $!
|
|
) &
|
|
sh1=$!
|
|
(
|
|
sleep 500 &
|
|
await $!
|
|
) &
|
|
sh2=$!
|
|
await $sl1
|
|
await $sh1
|
|
await $sh2
|
|
) &
|
|
parent=$!
|
|
|
|
pm_list_descendants "$parent"
|
|
assert_equal "${#result[@]}" 9
|
|
|
|
pm_kill_rec "$parent"
|
|
await "$parent" 5
|
|
|
|
pm_list_descendants "$parent"
|
|
# the parent will still show amongst its descendants,
|
|
# even though it is dead.
|
|
assert_equal "${#result[@]}" 1
|
|
}
|
|
|
|
@test "should not start process monitor twice" {
|
|
assert_equal "$(pm_state)" "halted"
|
|
|
|
assert pm_start
|
|
assert_equal "$(pm_state)" "running"
|
|
|
|
refute pm_start
|
|
|
|
assert pm_stop
|
|
assert_equal "$(pm_state)" "halted"
|
|
}
|
|
|
|
@test "should not stop the process monitor if it wasn't started" {
|
|
refute pm_stop
|
|
}
|
|
|
|
@test "should keep track of process IDs" {
|
|
assert pm_start
|
|
|
|
pm_known_pids
|
|
assert [ ${#result[@]} -eq 0 ]
|
|
|
|
# shellcheck disable=SC2317
|
|
job() {
|
|
while [ ! -f "${_pm_output}/sync" ]; do
|
|
sleep 0.1
|
|
done
|
|
}
|
|
|
|
pm_async job
|
|
p1=$result
|
|
|
|
pm_async job
|
|
p2=$result
|
|
|
|
pm_known_pids
|
|
assert [ ${#result[@]} -eq 2 ]
|
|
|
|
touch "${_pm_output}/sync"
|
|
|
|
await "$p1"
|
|
await "$p2"
|
|
|
|
# This should be more than enough for the process monitor to
|
|
# catch the exits. The alternative would be implementing temporal
|
|
# predicates.
|
|
sleep 1
|
|
|
|
pm_known_pids
|
|
assert [ ${#result[@]} -eq 0 ]
|
|
|
|
pm_stop
|
|
}
|
|
|
|
@test "should stop the monitor and all other processes if one process fails" {
|
|
assert pm_start
|
|
|
|
# shellcheck disable=SC2317
|
|
job() {
|
|
exit_code=$1
|
|
while [ ! -f "${_pm_output}/sync" ]; do
|
|
sleep 0.1
|
|
done
|
|
return 1
|
|
}
|
|
|
|
pm_async job 0
|
|
p1=$result
|
|
|
|
pm_async job 1
|
|
p2=$result
|
|
|
|
touch "${_pm_output}/sync"
|
|
|
|
await "$p1"
|
|
await "$p2"
|
|
|
|
pm_join 3
|
|
|
|
assert_equal "$(pm_state)" "halted_process_failure"
|
|
}
|
|
|
|
@test "should no longer track a process if requested" {
|
|
assert pm_start
|
|
|
|
job() {
|
|
echoerr "starting job"
|
|
touch "${_pm_output}/sync"
|
|
sleep 50
|
|
}
|
|
|
|
pm_async job
|
|
pid1=$result
|
|
|
|
while [ ! -f "${_pm_output}/sync" ]; do
|
|
sleep 0.1
|
|
done
|
|
|
|
pm_stop_tracking "$pid1" # remove this and the test should fail
|
|
pm_kill_rec "$pid1"
|
|
await "$pid1"
|
|
|
|
# Sleeps a bit to let the procmon catch up.
|
|
sleep 3
|
|
|
|
pm_stop
|
|
|
|
assert_equal "$(pm_state)" "halted"
|
|
}
|
|
|
|
callback() {
|
|
local event="$1" proc_type="$2" pid="$3" exit_code
|
|
|
|
if [ "$event" = "start" ]; then
|
|
shift 3
|
|
touch "${_pm_output}/${pid}-${proc_type}-start"
|
|
elif [ "$event" = "exit" ]; then
|
|
exit_code="$4"
|
|
shift 4
|
|
touch "${_pm_output}/${pid}-${proc_type}-${exit_code}-exit"
|
|
fi
|
|
|
|
if [ "$#" -gt 0 ]; then
|
|
echo "$*" > "${_pm_output}/${pid}-${proc_type}-${event}-args"
|
|
fi
|
|
}
|
|
|
|
@test "should call lifecycle callbacks when processes start and stop" {
|
|
|
|
pm_register_callback "sleepy" "callback"
|
|
|
|
pm_start
|
|
|
|
pm_async sleep 0.1 -%- "sleepy"
|
|
pid1=$result
|
|
pm_async sleep 0.1 -%- "sleepy"
|
|
pid2=$result
|
|
pm_async sleep 0.1 -%- "awake"
|
|
pid3=$result
|
|
|
|
await "$pid1"
|
|
await "$pid2"
|
|
await "$pid3"
|
|
|
|
pm_stop
|
|
|
|
assert_equal "$(pm_state)" "halted"
|
|
|
|
assert [ -f "${_pm_output}/${pid1}-sleepy-start" ]
|
|
assert [ -f "${_pm_output}/${pid1}-sleepy-0-exit" ]
|
|
assert [ -f "${_pm_output}/${pid1}-sleepy-start" ]
|
|
assert [ -f "${_pm_output}/${pid2}-sleepy-0-exit" ]
|
|
assert [ ! -f "${_pm_output}/${pid3}-awake-start" ]
|
|
assert [ ! -f "${_pm_output}/${pid3}-awake-0-exit" ]
|
|
}
|
|
|
|
@test "should invoke lifecycle callback when process is killed" {
|
|
pm_register_callback "sleepy" "callback"
|
|
|
|
pm_start
|
|
|
|
pm_async sleep 10 -%- "sleepy"
|
|
pid1=$result
|
|
echoerr "Run this line"
|
|
pm_async false -%- "sleepy"
|
|
pid2=$result
|
|
|
|
pm_join
|
|
|
|
assert_equal "$(pm_state)" "halted_process_failure"
|
|
|
|
assert [ -f "${_pm_output}/${pid1}-sleepy-start" ]
|
|
assert [ -f "${_pm_output}/${pid1}-sleepy-killed-exit" ]
|
|
assert [ -f "${_pm_output}/${pid2}-sleepy-start" ]
|
|
assert [ -f "${_pm_output}/${pid2}-sleepy-1-exit" ]
|
|
}
|
|
|
|
@test "should allow passing custom arguments to lifecycle callback" {
|
|
pm_register_callback "sleepy" "callback"
|
|
|
|
pm_start
|
|
|
|
pm_async sleep 0.1 -%- "sleepy" "arg1" "arg2"
|
|
pid=$result
|
|
|
|
await "$pid"
|
|
|
|
assert_equal "$(cat "${_pm_output}/${pid}-sleepy-start-args")" "arg1 arg2"
|
|
assert_equal "$(cat "${_pm_output}/${pid}-sleepy-exit-args")" "arg1 arg2"
|
|
|
|
pm_stop
|
|
}
|