Skip to content

Commit

Permalink
Merge pull request #8 from diazona/ctest/1/dev
Browse files Browse the repository at this point in the history
Add tests using CTest
  • Loading branch information
diazona authored Mar 26, 2024
2 parents 1c4f000 + 1d4843a commit 591d869
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 3 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,4 @@ jobs:
working-directory: ${{steps.strings.outputs.build-output-dir}}
# Note that --build-config is needed because the default Windows generator is a multi-config generator (Visual Studio generator).
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
run: ctest --build-config ${{matrix.build_type}}
run: ctest --build-config ${{matrix.build_type}} --output-on-failure
5 changes: 4 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
cmake_minimum_required(VERSION 3.15)

project(pwait)

cmake_minimum_required(VERSION 2.8)
enable_testing()

add_subdirectory(src)
add_subdirectory(test)
4 changes: 3 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
cmake_minimum_required(VERSION 3.15)

set(CMAKE_INCLUDE_CURRENT_DIR ON)

include(CheckSymbolExists)
Expand All @@ -8,4 +10,4 @@ add_executable(pwait pwait.c)
target_link_libraries(pwait cap)

install(TARGETS pwait RUNTIME DESTINATION bin)
install(CODE "execute_process(COMMAND setcap cap_sys_ptrace+ep pwait WORKING_DIRECTORY ${CMAKE_INSTALL_PREFIX}/bin)")
install(CODE "execute_process(COMMAND sudo setcap cap_sys_ptrace+ep pwait WORKING_DIRECTORY ${CMAKE_INSTALL_PREFIX}/bin)")
14 changes: 14 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
cmake_minimum_required(VERSION 3.22)

add_test(
NAME pwait-setcap
COMMAND sudo setcap cap_sys_ptrace+ep "$<TARGET_FILE:pwait>"
)
set_tests_properties(pwait-setcap PROPERTIES FIXTURES_SETUP pwait-setcap-fixture)

add_test(
NAME test-pwait
COMMAND "${CMAKE_CURRENT_LIST_DIR}/test_pwait.sh"
)
set_tests_properties(test-pwait PROPERTIES ENVIRONMENT PWAIT=$<TARGET_FILE:pwait>)
set_tests_properties(test-pwait PROPERTIES FIXTURES_REQUIRED pwait-setcap-fixture)
132 changes: 132 additions & 0 deletions test/test_pwait.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#!/bin/bash

# A simple test harness for pwait

set -eu -o pipefail


# Start a process that waits for a specified amount of time and then exits with
# a given return code. This function does not wait for the process to finish.
# Its PID is stored in the variable background_pid and then the function returns
# immediately.
start_sleep_and_exit() {
local delay="${1?:Missing delay}" code="${2?:Missing exit code}"
set +e
( sleep "$delay"; exit "$code"; ) &
set -e
background_pid="$!"
}


# Run pwait on a given process ID. This function will wait for pwait to return
# and then store pwait's exit code in the variable pwait_exit_code.
run_pwait() {
local pid="${1?:Missing PID}"
printf "Invoking %s on target pid %d\n" "$PWAIT" "$pid"
set +e
"$PWAIT" "$pid"
pwait_exit_code="$?"
set -e
}


print_test_header() {
printf "BEGIN %s\n" "$test_name"
}


print_test_footer() {
printf "END %s\n" "$test_name"
}


assert() {
local command="$1" message="$2"
shift
if ! eval "$command"; then
printf "FAILED: %s\n %s\n %s\n" "$test_name" "$message" "$command" >&2
return 1
fi
}


process_exists() {
local pid="$1"
pgrep "$pid" >/dev/null
}


# Test that pwait exits with the same code as the target process
test_pwait_exit_code() {
local delay="2s" code="${1?:Missing exit code}" test_name
test_name="${FUNCNAME[0]}_$code"
print_test_header

start_sleep_and_exit "$delay" "$code"

run_pwait "$background_pid"

assert "[[ '$pwait_exit_code' -eq '$code' ]]" "Expected code $code but got $pwait_exit_code"

print_test_footer
}


test_pwait_exit_code 0
test_pwait_exit_code 1
test_pwait_exit_code 128


# Test that the target process does not exist after pwait exits.
test_target_does_not_exist_after_pwait_exit() {
local delay="2s" code="0" test_name="${FUNCNAME[0]}"
print_test_header

start_sleep_and_exit "$delay" "$code"

run_pwait "$background_pid"

assert "! process_exists $background_pid" "Process (pid $background_pid) is still running after pwait finished"

print_test_footer
}


test_target_does_not_exist_after_pwait_exit


# Start a process that waits for a specified amount of time and then ensures
# a pwait process is running. This function does not wait for the process to
# finish. Its PID is stored in the variable background_pid and then the function
# returns immediately.
start_sleep_and_touch() {
local delay="${1?:Missing delay}" filename="${2?:Missing filename}"
set +e
( sleep "$delay"; touch "$filename" ) &
set -e
background_pid="$!"
}


# Test that pwait and its target process exit at roughly the same time.
test_pwait_and_target_exit_times() {
local delay="$1" code="0" test_name tmpdir sleep_time pwait_time
test_name="${FUNCNAME[0]}_$delay"
print_test_header

tmpdir="$(mktemp -d)"
trap "rm -rf '$tmpdir'" RETURN
( /usr/bin/time --format "%e" sleep "$delay" >"$tmpdir/sleep-time.txt" ) &
background_pid="$!"
/usr/bin/time --format "%e" "$PWAIT" "$background_pid" >"$tmpdir/pwait-time.txt"

assert "cmp '$tmpdir/sleep-time.txt' '$tmpdir/pwait-time.txt'" "pwait and target process finished at different times"

print_test_footer
}


test_pwait_and_target_exit_times 0.1s
test_pwait_and_target_exit_times 1s
test_pwait_and_target_exit_times 2s
test_pwait_and_target_exit_times 5s

0 comments on commit 591d869

Please sign in to comment.