freeswitch/tests/unit/run-tests.sh

203 lines
4.8 KiB
Bash
Executable File

#!/usr/bin/env bash
### shfmt -w -s -ci -sr -kp -fn tests/unit/run-tests.sh
#------------------------------------------------------------------------------
# Test Runner Script
# Runs tests in chunks, distributing them across processors
# Supports moving test artifacts to specified output directory
#------------------------------------------------------------------------------
# Exit on error, undefined vars, and propagate pipe failures
set -euo pipefail
# Global variable for test failures
declare -i TESTS_FAILED=0
# Function to show usage
show_usage()
{
echo "Usage: $0 [chunks] [chunk_number] [options]"
echo " chunks : Number of chunks to split tests into (default: 1)"
echo " chunk_number : Which chunk to run (default: 1)"
echo "Options:"
echo " --dry-run : Show test distribution without running tests"
echo " --output-dir : Directory to store test artifacts (will be created if needed)"
echo " -h|--help : Show this help message"
exit 1
}
# Function to validate numeric input
validate_number()
{
local val=$1
local name=$2
if ! [[ $val =~ ^[0-9]+$ ]]; then
echo "Error: $name must be a positive number, got: $val"
exit 1
fi
if [ "$val" -lt 1 ]; then
echo "Error: $name must be greater than 0, got: $val"
exit 1
fi
}
# Function to format duration in human-readable form
format_duration()
{
local duration=$1
local minutes=$((duration / 60))
local seconds=$((duration % 60))
printf "%02d:%02d" $minutes $seconds
}
# Function to move test artifacts to output directory
move_artifacts()
{
local output_dir=$1
# Create output directory if it doesn't exist
mkdir -p "$output_dir"
# Move HTML logs and backtrace files if they exist
# Using || true to prevent script failure if no files match
(mv log_run-tests_*.html "$output_dir" 2> /dev/null || true)
(mv backtrace_*.txt "$output_dir" 2> /dev/null || true)
# Check if any files were moved
if [ -n "$(ls -A "$output_dir" 2> /dev/null)" ]; then
echo "Test artifacts moved to: $output_dir"
else
echo "No test artifacts found to move"
fi
}
# Parse command line arguments
chunks=1
chunk_number=1
dry_run=false
output_dir=""
while [[ $# -gt 0 ]]; do
case $1 in
--dry-run)
dry_run=true
shift
;;
--output-dir)
if [ -n "${2:-}" ]; then
output_dir="$2"
shift 2
else
echo "Error: --output-dir requires a directory path"
exit 1
fi
;;
-h | --help)
show_usage
;;
*)
if [[ $chunks -eq 1 ]]; then
chunks=$1
elif [[ $chunk_number -eq 1 ]]; then
chunk_number=$1
else
echo "Error: Unknown argument $1"
show_usage
fi
shift
;;
esac
done
# Validate numeric inputs
validate_number "$chunks" "chunks"
validate_number "$chunk_number" "chunk_number"
# Validate chunk parameters
if [ "$chunk_number" -gt "$chunks" ]; then
echo "Error: chunk_number ($chunk_number) cannot be greater than total chunks ($chunks)"
exit 1
fi
# Get list of tests from make
echo "Fetching test list..."
TESTS=$(make -s -C ../.. print_tests 2>/dev/null) || {
echo "Error: Failed to fetch test list"
exit 1
}
# Split tests into array
IFS=$'\n' read -d '' -r -a all_tests <<< "$TESTS" || true # || true to handle last line without newline
# Check if any tests were found
if [ ${#all_tests[@]} -eq 0 ]; then
echo "Error: No tests found!"
exit 1
fi
# Get total number of tests from array length
total_tests=${#all_tests[@]}
# Select tests for this chunk
chunk_tests=()
for ((i = chunk_number - 1; i < total_tests; i += chunks)); do
chunk_tests+=("${all_tests[$i]}")
done
# Size of this chunk
chunk_size=${#chunk_tests[@]}
# Print execution information
echo ""
echo "Test Distribution Information:"
echo "Total tests found: $total_tests"
echo "Chunk size: $chunk_size"
echo "Running chunk $chunk_number/$chunks"
if [ -n "$output_dir" ]; then
echo "Artifacts will be stored in: $output_dir"
fi
echo ""
echo "Tests to be executed:"
for i in "${!chunk_tests[@]}"; do
printf "%3d) %s\n" "$((i + 1))" "${chunk_tests[$i]}"
done
echo ""
# Exit here if dry run
if [ "$dry_run" = true ]; then
echo "Dry run complete. Use without --dry-run to execute tests."
exit 0
fi
# Record start time
start_time=$(date +%s)
# Run tests sequentially within the chunk
if ! make -f run-tests.mk TEST_LIST="${chunk_tests[*]}"; then
TESTS_FAILED=1
fi
# Move artifacts if output directory was specified
if [ -n "$output_dir" ]; then
move_artifacts "$output_dir"
fi
# Record end time and calculate duration
end_time=$(date +%s)
duration=$((end_time - start_time))
# Print timing results and statistics
echo ""
echo "Execution Summary for chunk $chunk_number/$chunks:"
echo "Started at : $(date -d @$start_time '+%Y-%m-%d %H:%M:%S')"
echo "Finished at: $(date -d @$end_time '+%Y-%m-%d %H:%M:%S')"
echo "Duration : $(format_duration $duration)"
echo "Status : $([ $TESTS_FAILED -eq 0 ] && echo "SUCCESS" || echo "FAILED")"
echo ""
# Exit with appropriate status code
exit $TESTS_FAILED