|
| 1 | +#!/bin/bash |
| 2 | +# |
| 3 | +# Dummy script that only creates test result file for the bot, without actually checking anything |
| 4 | +# |
| 5 | +# This script is part of the EESSI software layer, see |
| 6 | +# https://github.com/EESSI/software-layer.git |
| 7 | +# |
| 8 | +# author: Kenneth Hoste (HPC-UGent) |
| 9 | +# |
| 10 | +# license: GPLv2 |
| 11 | +# |
| 12 | +job_dir=${PWD} |
| 13 | +job_out="slurm-${SLURM_JOB_ID}.out" |
| 14 | +job_test_result_file="_bot_job${SLURM_JOB_ID}.test" |
| 15 | + |
| 16 | +# Check that job output file is found |
| 17 | +[[ ${VERBOSE} -ne 0 ]] && echo ">> searching for job output file(s) matching '"${job_out}"'" |
| 18 | +if [[ -f ${job_out} ]]; then |
| 19 | + SLURM_OUTPUT_FOUND=1 |
| 20 | + [[ ${VERBOSE} -ne 0 ]] && echo " found slurm output file '"${job_out}"'" |
| 21 | +else |
| 22 | + SLURM_OUTPUT_FOUND=0 |
| 23 | + [[ ${VERBOSE} -ne 0 ]] && echo " Slurm output file '"${job_out}"' NOT found" |
| 24 | +fi |
| 25 | + |
| 26 | +# ReFrame prints e.g. |
| 27 | +#[----------] start processing checks |
| 28 | +#[ RUN ] GROMACS_EESSI %benchmark_info=HECBioSim/Crambin %nb_impl=cpu %scale=2_nodes %module_name=GROMACS/2021.3-foss-2021a /d597cff4 @snellius:rome+default |
| 29 | +#[ RUN ] GROMACS_EESSI %benchmark_info=HECBioSim/Crambin %nb_impl=cpu %scale=2_nodes %module_name=GROMACS/2021.3-foss-2021a /d597cff4 @snellius:genoa+default |
| 30 | +#[ RUN ] GROMACS_EESSI %benchmark_info=HECBioSim/Crambin %nb_impl=cpu %scale=1_cpn_2_nodes %module_name=GROMACS/2021.3-foss-2021a /f4194106 @snellius:genoa+default |
| 31 | +#[ FAIL ] (1/3) GROMACS_EESSI %benchmark_info=HECBioSim/Crambin %nb_impl=cpu %scale=2_nodes %module_name=GROMACS/2021.3-foss-2021a /d597cff4 @snellius:genoa+default |
| 32 | +#==> test failed during 'sanity': test staged in '/scratch-shared/casparl/reframe_output/staging/snellius/genoa/default/GROMACS_EESSI_d597cff4' |
| 33 | +#[ OK ] (2/3) GROMACS_EESSI %benchmark_info=HECBioSim/Crambin %nb_impl=cpu %scale=2_nodes %module_name=GROMACS/2021.3-foss-2021a /d597cff4 @snellius:rome+default |
| 34 | +#P: perf: 8.441 ns/day (r:0, l:None, u:None) |
| 35 | +#[ FAIL ] (3/3) GROMACS_EESSI %benchmark_info=HECBioSim/Crambin %nb_impl=cpu %scale=1_cpn_2_nodes %module_name=GROMACS/2021.3-foss-2021a /f4194106 @snellius:genoa+default |
| 36 | +#==> test failed during 'sanity': test staged in '/scratch-shared/casparl/reframe_output/staging/snellius/genoa/default/GROMACS_EESSI_f4194106' |
| 37 | +#[----------] all spawned checks have finished |
| 38 | +#[ FAILED ] Ran 3/3 test case(s) from 2 check(s) (2 failure(s), 0 skipped, 0 aborted) |
| 39 | + |
| 40 | +# We will grep for the last and final line, since this reflects the overall result |
| 41 | +# Specifically, we grep for FAILED, since this is also what we print if a step in the test script itself fails |
| 42 | +FAILED=-1 |
| 43 | +if [[ ${SLURM_OUTPUT_FOUND} -eq 1 ]]; then |
| 44 | + GP_failed='\[\s*FAILED\s*\].*Ran .* test case' |
| 45 | + grep_reframe_failed=$(grep -v "^>> searching for " ${job_dir}/${job_out} | grep "${GP_failed}") |
| 46 | + [[ $? -eq 0 ]] && FAILED=1 || FAILED=0 |
| 47 | + # have to be careful to not add searched for pattern into slurm out file |
| 48 | + [[ ${VERBOSE} -ne 0 ]] && echo ">> searching for '"${GP_failed}"'" |
| 49 | + [[ ${VERBOSE} -ne 0 ]] && echo "${grep_reframe_failed}" |
| 50 | +fi |
| 51 | + |
| 52 | +# Here, we grep for 'ERROR:', which is printed if a fatal_error is encountered when executing the test step |
| 53 | +# I.e. this is an error in execution of the run_tests.sh itself, NOT in running the actual tests |
| 54 | +ERROR=-1 |
| 55 | +if [[ ${SLURM_OUTPUT_FOUND} -eq 1 ]]; then |
| 56 | + GP_error='ERROR: ' |
| 57 | + grep_out=$(grep -v "^>> searching for " ${job_dir}/${job_out} | grep "${GP_error}") |
| 58 | + [[ $? -eq 0 ]] && ERROR=1 || ERROR=0 |
| 59 | + # have to be careful to not add searched for pattern into slurm out file |
| 60 | + [[ ${VERBOSE} -ne 0 ]] && echo ">> searching for '"${GP_error}"'" |
| 61 | + [[ ${VERBOSE} -ne 0 ]] && echo "${grep_out}" |
| 62 | +fi |
| 63 | + |
| 64 | +SUCCESS=-1 |
| 65 | +# Grep for the success pattern, so we can report the amount of tests run |
| 66 | +if [[ ${SLURM_OUTPUT_FOUND} -eq 1 ]]; then |
| 67 | + GP_success='\[\s*PASSED\s*\].*Ran .* test case' |
| 68 | + grep_reframe_success=$(grep -v "^>> searching for " ${job_dir}/${job_out} | grep "${GP_success}") |
| 69 | + [[ $? -eq 0 ]] && SUCCESS=1 || SUCCESS=0 |
| 70 | + # have to be careful to not add searched for pattern into slurm out file |
| 71 | + [[ ${VERBOSE} -ne 0 ]] && echo ">> searching for '"${GP_success}"'" |
| 72 | + [[ ${VERBOSE} -ne 0 ]] && echo "${grep_reframe_success}" |
| 73 | +fi |
| 74 | + |
| 75 | +if [[ ! -z ${grep_reframe_failed} ]]; then |
| 76 | + grep_reframe_result=${grep_reframe_failed} |
| 77 | +else |
| 78 | + # Grep the entire output of ReFrame, so that we can report it in the foldable section of the test report |
| 79 | + GP_success_full='(?s)\[----------\] start processing checks.*?\[==========\] Finished on [a-zA-Z0-9 ]*' |
| 80 | + # Grab the full ReFrame report, than cut the irrelevant parts |
| 81 | + # Note that the character limit for messages in github is around 65k, so cutting is important |
| 82 | + grep_reframe_success_full=$( \ |
| 83 | + grep -v "^>> searching for " ${job_dir}/${job_out} | \ |
| 84 | + # Use -z |
| 85 | + grep -Pzo "${GP_success_full}" | \ |
| 86 | + # Replace null character with newline, to undo the -z option |
| 87 | + sed 's/\x00/\n/g' | \ |
| 88 | + # Remove the [ RUN ] lines from reframe, they are not very informative |
| 89 | + grep -v -P '\[\s*RUN\s*]' | \ |
| 90 | + # Remove the line '[----------] all spawned checks have finished' |
| 91 | + grep -v '\[-*\]' | \ |
| 92 | + # Remove the line '[==========] Finished on Mon Oct 7 21' |
| 93 | + grep -v '\[=*\]' | \ |
| 94 | + # Remove blank line(s) from the report |
| 95 | + grep -v '^$' | \ |
| 96 | + # Remove warnings about the local spawner not supporting memory requests |
| 97 | + grep -v 'WARNING\: hooks\.req_memory_per_node does not support the scheduler you configured .local.*$' | \ |
| 98 | + # Strip color coding characters |
| 99 | + sed 's/\x1B\[[0-9;]*m//g' | \ |
| 100 | + # Replace all newline characters with <br/> |
| 101 | + sed ':a;N;$!ba;s/\n/<br\/>/g' | \ |
| 102 | + # Replace % with %%. Use \%\% to interpret both %% as (non-special) characters |
| 103 | + sed 's/\%/\%\%/g' \ |
| 104 | + ) |
| 105 | + # TODO (optional): we could impose a character limit here, and truncate if too long |
| 106 | + # (though we should do that before inserting the <br/> statements). |
| 107 | + # If we do, we should probably re-append the final summary, e.g. |
| 108 | + # [ PASSED ] Ran 10/10 test case(s) from 10 check(s) (0 failure(s), 0 skipped, 0 aborted) |
| 109 | + # so that that is always displayed |
| 110 | + # However, that's not implemented yet - let's see if this ever even becomes an issue |
| 111 | + grep_reframe_result=${grep_reframe_success_full} |
| 112 | +fi |
| 113 | +echo "grep_reframe_result: ${grep_reframe_result}" |
| 114 | + |
| 115 | +echo "[TEST]" > ${job_test_result_file} |
| 116 | +if [[ ${SLURM_OUTPUT_FOUND} -eq 0 ]]; then |
| 117 | + summary=":cry: FAILURE" |
| 118 | + reason="Job output file not found, cannot check test results." |
| 119 | + status="FAILURE" |
| 120 | +# Should come before general errors: if SUCCESS==1, it indicates the test suite ran succesfully |
| 121 | +# regardless of other things that might have gone wrong |
| 122 | +elif [[ ${SUCCESS} -eq 1 ]]; then |
| 123 | + summary=":grin: SUCCESS" |
| 124 | + reason="" |
| 125 | + status="SUCCESS" |
| 126 | +# Should come before general errors: if FAILED==1, it indicates the test suite ran |
| 127 | +# otherwise the pattern wouldn't have been there |
| 128 | +elif [[ ${FAILED} -eq 1 ]]; then |
| 129 | + summary=":cry: FAILURE" |
| 130 | + reason="EESSI test suite produced failures." |
| 131 | + status="FAILURE" |
| 132 | +elif [[ ${ERROR} -eq 1 ]]; then |
| 133 | + summary=":cry: FAILURE" |
| 134 | + reason="EESSI test suite was not run, test step itself failed to execute." |
| 135 | + status="FAILURE" |
| 136 | +else |
| 137 | + summary=":cry: FAILURE" |
| 138 | + reason="Failed for unknown reason" |
| 139 | + status="FAILURE" |
| 140 | +fi |
| 141 | + |
| 142 | + |
| 143 | +echo "[TEST]" > ${job_test_result_file} |
| 144 | +echo -n "comment_description = " >> ${job_test_result_file} |
| 145 | + |
| 146 | +# Use template for writing PR comment with details |
| 147 | +# construct and write complete PR comment details: implements third alternative |
| 148 | +comment_template="<details>__SUMMARY_FMT__<dl>__REASON_FMT____REFRAME_FMT____DETAILS_FMT__</dl></details>" |
| 149 | +comment_success_item_fmt=":white_check_mark: __ITEM__" |
| 150 | +comment_failure_item_fmt=":x: __ITEM__" |
| 151 | + |
| 152 | +# Initialize comment_description |
| 153 | +comment_description=${comment_template} |
| 154 | + |
| 155 | +# Now, start replacing template items one by one |
| 156 | +comment_summary_fmt="<summary>__SUMMARY__ _(click triangle for details)_</summary>" |
| 157 | +comment_summary="${comment_summary_fmt/__SUMMARY__/${summary}}" |
| 158 | +comment_description=${comment_description/__SUMMARY_FMT__/${comment_summary}} |
| 159 | + |
| 160 | + |
| 161 | +# Only add if there is a reason (e.g. no reason for successful runs) |
| 162 | +if [[ ! -z ${reason} ]]; then |
| 163 | + comment_reason_fmt="<dt>_Reason_</dt><dd>__REASONS__</dd>" |
| 164 | + reason_details="${comment_reason_fmt/__REASONS__/${reason}}" |
| 165 | + comment_description=${comment_description/__REASON_FMT__/${reason_details}} |
| 166 | +else |
| 167 | + comment_description=${comment_description/__REASON_FMT__/""} |
| 168 | +fi |
| 169 | + |
| 170 | +# Only add if there is a reframe summary (e.g. no reframe summary if reframe wasn't launched succesfully) |
| 171 | +echo "ReFrame result:" |
| 172 | +echo "${grep_reframe_result}" |
| 173 | +if [[ ! -z ${grep_reframe_result} ]]; then |
| 174 | + comment_reframe_fmt="<dt>_ReFrame Summary_</dt><dd>__REFRAME_SUMMARY__</dd>" |
| 175 | + reframe_summary=${comment_reframe_fmt/__REFRAME_SUMMARY__/${grep_reframe_result}} |
| 176 | + comment_description=${comment_description/__REFRAME_FMT__/${reframe_summary}} |
| 177 | +else |
| 178 | + comment_description=${comment_description/__REFRAME_FMT__/""} |
| 179 | +fi |
| 180 | + |
| 181 | +# Declare functions |
| 182 | +function print_br_item() { |
| 183 | + format="${1}" |
| 184 | + item="${2}" |
| 185 | + echo -n "${format//__ITEM__/${item}}<br/>" |
| 186 | +} |
| 187 | + |
| 188 | +function success() { |
| 189 | + format="${comment_success_item_fmt}" |
| 190 | + item="$1" |
| 191 | + print_br_item "${format}" "${item}" |
| 192 | +} |
| 193 | + |
| 194 | +function failure() { |
| 195 | + format="${comment_failure_item_fmt}" |
| 196 | + item="$1" |
| 197 | + print_br_item "${format}" "${item}" |
| 198 | +} |
| 199 | + |
| 200 | +function add_detail() { |
| 201 | + actual=${1} |
| 202 | + expected=${2} |
| 203 | + success_msg="${3}" |
| 204 | + failure_msg="${4}" |
| 205 | + if [[ ${actual} -eq ${expected} ]]; then |
| 206 | + success "${success_msg}" |
| 207 | + else |
| 208 | + failure "${failure_msg}" |
| 209 | + fi |
| 210 | +} |
| 211 | + |
| 212 | +# first construct comment_details_list, abbreviated comment_details_list |
| 213 | +# then use it to set comment_details |
| 214 | +comment_details_list="" |
| 215 | + |
| 216 | +success_msg="job output file <code>${job_out}</code>" |
| 217 | +failure_msg="no job output file <code>${job_out}</code>" |
| 218 | +comment_details_list=${comment_details_list}$(add_detail ${SLURM_OUTPUT_FOUND} 1 "${success_msg}" "${failure_msg}") |
| 219 | + |
| 220 | +success_msg="no message matching <code>${GP_error}</code>" |
| 221 | +failure_msg="found message matching <code>${GP_error}</code>" |
| 222 | +comment_details_list=${comment_details_list}$(add_detail ${ERROR} 0 "${success_msg}" "${failure_msg}") |
| 223 | + |
| 224 | +# Add an escape character to every *, for it to be printed correctly in the comment on GitHub |
| 225 | +GP_failed="${GP_failed//\*/\\*}" |
| 226 | +success_msg="no message matching <code>""${GP_failed}""</code>" |
| 227 | +failure_msg="found message matching <code>""${GP_failed}""</code>" |
| 228 | +comment_details_list=${comment_details_list}$(add_detail ${FAILED} 0 "${success_msg}" "${failure_msg}") |
| 229 | + |
| 230 | +comment_details_fmt="<dt>_Details_</dt><dd>__DETAILS_LIST__</dd>" |
| 231 | +comment_details="${comment_details_fmt/__DETAILS_LIST__/${comment_details_list}}" |
| 232 | +comment_description=${comment_description/__DETAILS_FMT__/${comment_details}} |
| 233 | + |
| 234 | +# Actually writing the comment description to the result file |
| 235 | +echo "${comment_description}" >> ${job_test_result_file} |
| 236 | +echo "status = ${status}" >> ${job_test_result_file} |
| 237 | + |
| 238 | +exit 0 |
0 commit comments