debug-test.sh
1 #!/bin/bash 2 3 PROG=${0##*/} 4 build_dir="build-ci-debug" 5 6 # Print Color Commands 7 red=$(tput setaf 1) 8 green=$(tput setaf 2) 9 yellow=$(tput setaf 3) 10 blue=$(tput setaf 4) 11 magenta=$(tput setaf 5) 12 cyan=$(tput setaf 6) 13 normal=$(tput sgr0) 14 15 16 # Print Help Message 17 #################### 18 19 print_full_help() { 20 cat << EOF 21 Usage: $PROG [OPTION]... <test_regex> (test_number) 22 Debug specific ctest program. 23 24 Options: 25 -h, --help display this help and exit 26 -g run in gdb mode 27 28 Arguments: 29 <test_regex> (Mandatory) Supply one regex to the script to filter tests 30 (test_number) (Optional) Test number to run a specific test 31 32 Example: 33 $PROG test-tokenizer 34 $PROG test-tokenizer 3 35 EOF 36 } 37 38 abort() { 39 echo "Error: $1" >&2 40 cat << EOF >&2 41 Usage: $PROG [OPTION]... <test_regex> (test_number) 42 Debug specific ctest program. 43 Refer to --help for full instructions. 44 EOF 45 exit 1 46 } 47 48 49 # Dependency Sanity Check 50 ######################### 51 52 check_dependency() { 53 command -v "$1" >/dev/null 2>&1 || { 54 abort "$1 is required but not found. Please install it and try again." 55 } 56 } 57 58 check_dependency ctest 59 check_dependency cmake 60 61 62 # Step 0: Check the args 63 ######################## 64 65 if [ x"$1" = x"-h" ] || [ x"$1" = x"--help" ]; then 66 print_full_help >&2 67 exit 0 68 fi 69 70 # Parse command-line options 71 gdb_mode=false 72 while getopts "g" opt; do 73 case $opt in 74 g) 75 gdb_mode=true 76 echo "gdb_mode Mode Enabled" 77 ;; 78 esac 79 done 80 81 # Shift the option parameters 82 shift $((OPTIND - 1)) 83 84 # Positionial Argument Processing : <test_regex> 85 if [ -z "${1}" ]; then 86 abort "Test regex is required" 87 else 88 test_suite=${1:-} 89 fi 90 91 # Positionial Argument Processing : (test_number) 92 test_number=${2:-} 93 94 95 # Step 1: Reset and Setup folder context 96 ######################################## 97 98 ## Sanity check that we are actually in a git repo 99 repo_root=$(git rev-parse --show-toplevel) 100 if [ ! -d "$repo_root" ]; then 101 abort "Not in a Git repository." 102 fi 103 104 ## Reset folder to root context of git repo and Create and enter build directory 105 pushd "$repo_root" 106 rm -rf "$build_dir" && mkdir "$build_dir" || abort "Failed to make $build_dir" 107 108 109 # Step 2: Setup Build Environment and Compile Test Binaries 110 ########################################################### 111 112 # Note: test-eval-callback requires -DLLAMA_CURL 113 cmake -B "./$build_dir" -DCMAKE_BUILD_TYPE=Debug -DLLAMA_CUDA=1 -DLLAMA_CURL=1 || abort "Failed to build enviroment" 114 pushd "$build_dir" 115 make -j || abort "Failed to compile" 116 popd > /dev/null || exit 1 117 118 119 # Step 3: Find all tests available that matches REGEX 120 #################################################### 121 122 # Ctest Gather Tests 123 # `-R test-tokenizer` : looks for all the test files named `test-tokenizer*` (R=Regex) 124 # `-N` : "show-only" disables test execution & shows test commands that you can feed to GDB. 125 # `-V` : Verbose Mode 126 printf "\n\nGathering tests that fit REGEX: ${test_suite} ...\n" 127 pushd "$build_dir" 128 tests=($(ctest -R ${test_suite} -V -N | grep -E " +Test +#[0-9]+*" | cut -d':' -f2 | awk '{$1=$1};1')) 129 if [ ${#tests[@]} -eq 0 ]; then 130 abort "No tests avaliable... check your compliation process..." 131 fi 132 popd > /dev/null || exit 1 133 134 135 # Step 4: Identify Test Command for Debugging 136 ############################################# 137 138 # Select test number 139 if [ -z $test_number ]; then 140 # List out avaliable tests 141 printf "Which test would you like to debug?\n" 142 id=0 143 for s in "${tests[@]}" 144 do 145 echo "Test# ${id}" 146 echo " $s" 147 ((id++)) 148 done 149 150 # Prompt user which test they wanted to run 151 printf "\nRun test#? " 152 read test_number 153 154 else 155 printf "\nUser Already Requested #${test_number}\n" 156 157 fi 158 159 # Grab all tests commands 160 pushd "$build_dir" 161 sIFS=$IFS # Save Initial IFS (Internal Field Separator) 162 IFS=$'\n' # Change IFS (Internal Field Separator) (So we split ctest output by newline rather than by spaces) 163 test_args=($(ctest -R ${test_suite} -V -N | grep "Test command" | cut -d':' -f3 | awk '{$1=$1};1' )) # Get test args 164 IFS=$sIFS # Reset IFS (Internal Field Separator) 165 popd > /dev/null || exit 1 166 167 # Grab specific test command 168 single_test_name="${tests[test_number]}" 169 single_test_command="${test_args[test_number]}" 170 171 172 # Step 5: Execute or GDB Debug 173 ############################## 174 175 printf "${magenta}Running Test #${test_number}: ${single_test_name}${normal}\n" 176 printf "${cyan}single_test_command: ${single_test_command}${normal}\n" 177 178 if [ "$gdb_mode" = "true" ]; then 179 # Execute debugger 180 pushd "$repo_root" || exit 1 181 eval "gdb --args ${single_test_command}" 182 popd > /dev/null || exit 1 183 184 else 185 # Execute Test 186 pushd "$repo_root" || exit 1 187 eval "${single_test_command}" 188 exit_code=$? 189 popd > /dev/null || exit 1 190 191 # Print Result 192 printf "${blue}Ran Test #${test_number}: ${single_test_name}${normal}\n" 193 printf "${yellow}Command: ${single_test_command}${normal}\n" 194 if [ $exit_code -eq 0 ]; then 195 printf "${green}TEST PASS${normal}\n" 196 else 197 printf "${red}TEST FAIL${normal}\n" 198 fi 199 200 fi 201 202 # Return to the directory from which the user ran the command. 203 popd > /dev/null || exit 1