@@ -40,8 +40,10 @@ PYTEST_FLAGS="--continue-on-collection-errors"
4040
4141# Global variables for test execution
4242FAILED_TESTS=" "
43+ NO_RESULT_TESTS=" "
4344TOTAL_TESTS=0
4445PASSED_TESTS=0
46+ NO_RESULT_COUNT=0
4547TOTAL_TEST_CASES=0
4648SAMPLED_TEST_CASES=0
4749# shellcheck disable=SC2034 # EXIT_CODE is used by calling scripts
@@ -187,6 +189,47 @@ collect_tests() {
187189 ALL_NODE_IDS=$( echo " $COLLECTION_OUTPUT " | grep " ::" || true)
188190}
189191
192+ # Return the expected JUnit XML path for a test file
193+ junit_file_for_test () {
194+ local test_file=$1
195+ local flattened_test_file=${test_file// \/ / _}
196+ local test_hash
197+ test_hash=$( printf ' %s' " $test_file " | cksum | awk ' {print $1}' )
198+ echo " ${JUNIT_DIR} /${flattened_test_file} .${test_hash} .xml"
199+ }
200+
201+ # Record a failed test file in the execution summary
202+ record_failed_test () {
203+ local test_file=$1
204+ FAILED_TESTS=" $FAILED_TESTS \n - $test_file "
205+ # shellcheck disable=SC2034 # EXIT_CODE is used by calling scripts
206+ EXIT_CODE=1
207+ }
208+
209+ # Record a test file that produced no result artifacts
210+ record_no_result_test () {
211+ local test_file=$1
212+ NO_RESULT_TESTS=" $NO_RESULT_TESTS \n - $test_file "
213+ NO_RESULT_COUNT=$(( NO_RESULT_COUNT + 1 ))
214+ }
215+
216+ # Describe which execution artifacts are missing for a test file
217+ describe_missing_artifacts () {
218+ local result_file=$1
219+ local junit_file=$2
220+ local -a missing=()
221+
222+ if [ -n " $result_file " ] && [ ! -f " $result_file " ]; then
223+ missing+=(" result marker" )
224+ fi
225+ if [ ! -f " $junit_file " ]; then
226+ missing+=(" JUnit XML: $junit_file " )
227+ fi
228+
229+ local IFS=' , '
230+ echo " ${missing[*]} "
231+ }
232+
190233# Sample tests based on SAMPLE_RATE and SAMPLE_OFFSET
191234sample_tests () {
192235 local all_node_ids=$1
@@ -240,8 +283,9 @@ dry_run_full_file() {
240283 local test_file=$1
241284
242285 TOTAL_TESTS=$(( TOTAL_TESTS + 1 ))
243- JUNIT_FILENAME=" ${test_file// \/ / _} .xml"
244- JUNIT_FLAG=" --junitxml=${JUNIT_DIR} /${JUNIT_FILENAME} "
286+ local junit_file
287+ junit_file=$( junit_file_for_test " $test_file " )
288+ JUNIT_FLAG=" --junitxml=${junit_file} "
245289 # shellcheck disable=SC2086 # PYTEST_COMMAND_PREFIX needs word splitting
246290 echo " $TOTAL_TESTS . ${PYTEST_COMMAND_PREFIX} pytest $PYTEST_FLAGS ${JUNIT_FLAG} \" ${test_file} \" "
247291}
@@ -289,6 +333,8 @@ print_dry_run_summary() {
289333run_sanity_test_file () {
290334 local test_file=$1
291335 local file_count=$2
336+ local junit_file
337+ junit_file=$( junit_file_for_test " $test_file " )
292338
293339 echo " =========================================="
294340 echo " [$file_count ] Processing: $test_file "
@@ -328,21 +374,29 @@ run_sanity_test_file() {
328374 # Create a bash array with the node IDs
329375 mapfile -t SAMPLED_NODE_IDS_ARRAY <<< " $SAMPLED_NODE_IDS"
330376
331- JUNIT_FILENAME=" ${test_file// \/ / _} .xml"
332- JUNIT_FLAG=" --junitxml=${JUNIT_DIR} /${JUNIT_FILENAME} "
377+ JUNIT_FLAG=" --junitxml=${junit_file} "
333378
334379 # Run pytest with the sampled node IDs
335380 TOTAL_TESTS=$(( TOTAL_TESTS + 1 ))
381+ rm -f " $junit_file "
336382
337383 # shellcheck disable=SC2086 # PYTEST_COMMAND_PREFIX and PYTEST_FLAGS need word splitting
338384 if ${PYTEST_COMMAND_PREFIX} pytest $PYTEST_FLAGS " ${JUNIT_FLAG} " " ${SAMPLED_NODE_IDS_ARRAY[@]} " ; then
339- echo " ✅ PASSED: $test_file ($SAMPLED_IN_FILE /$TOTAL_IN_FILE tests)"
340- PASSED_TESTS=$(( PASSED_TESTS + 1 ))
385+ if [ -f " $junit_file " ]; then
386+ echo " ✅ PASSED: $test_file ($SAMPLED_IN_FILE /$TOTAL_IN_FILE tests)"
387+ PASSED_TESTS=$(( PASSED_TESTS + 1 ))
388+ else
389+ echo " ⚠️ NO RESULT: $test_file ($SAMPLED_IN_FILE /$TOTAL_IN_FILE tests, missing JUnit XML: $junit_file )"
390+ record_no_result_test " $test_file "
391+ fi
341392 else
342- echo " ❌ FAILED: $test_file ($SAMPLED_IN_FILE /$TOTAL_IN_FILE tests)"
343- FAILED_TESTS=" $FAILED_TESTS \n - $test_file "
344- # shellcheck disable=SC2034 # EXIT_CODE is used by calling scripts
345- EXIT_CODE=1
393+ if [ -f " $junit_file " ]; then
394+ echo " ❌ FAILED: $test_file ($SAMPLED_IN_FILE /$TOTAL_IN_FILE tests)"
395+ record_failed_test " $test_file "
396+ else
397+ echo " ⚠️ NO RESULT: $test_file ($SAMPLED_IN_FILE /$TOTAL_IN_FILE tests, missing JUnit XML: $junit_file )"
398+ record_no_result_test " $test_file "
399+ fi
346400 fi
347401
348402 echo " "
@@ -351,25 +405,35 @@ run_sanity_test_file() {
351405# Run a single test file in full mode
352406run_full_test_file () {
353407 local test_file=$1
408+ local junit_file
409+ junit_file=$( junit_file_for_test " $test_file " )
354410
355411 echo " =========================================="
356- JUNIT_FILENAME=" ${test_file// \/ / _} .xml"
357- JUNIT_FLAG=" --junitxml=${JUNIT_DIR} /${JUNIT_FILENAME} "
412+ JUNIT_FLAG=" --junitxml=${junit_file} "
358413 # shellcheck disable=SC2086 # PYTEST_COMMAND_PREFIX needs word splitting
359414 echo " Running: ${PYTEST_COMMAND_PREFIX} pytest $PYTEST_FLAGS ${JUNIT_FLAG} \" ${test_file} \" "
360415 echo " =========================================="
361416
362417 TOTAL_TESTS=$(( TOTAL_TESTS + 1 ))
418+ rm -f " $junit_file "
363419
364420 # shellcheck disable=SC2086 # PYTEST_COMMAND_PREFIX and PYTEST_FLAGS need word splitting
365421 if ${PYTEST_COMMAND_PREFIX} pytest $PYTEST_FLAGS " ${JUNIT_FLAG} " " ${test_file} " ; then
366- echo " ✅ PASSED: $test_file "
367- PASSED_TESTS=$(( PASSED_TESTS + 1 ))
422+ if [ -f " $junit_file " ]; then
423+ echo " ✅ PASSED: $test_file "
424+ PASSED_TESTS=$(( PASSED_TESTS + 1 ))
425+ else
426+ echo " ⚠️ NO RESULT: $test_file (missing JUnit XML: $junit_file )"
427+ record_no_result_test " $test_file "
428+ fi
368429 else
369- echo " ❌ FAILED: $test_file "
370- FAILED_TESTS=" $FAILED_TESTS \n - $test_file "
371- # shellcheck disable=SC2034 # EXIT_CODE is used by calling scripts
372- EXIT_CODE=1
430+ if [ -f " $junit_file " ]; then
431+ echo " ❌ FAILED: $test_file "
432+ record_failed_test " $test_file "
433+ else
434+ echo " ⚠️ NO RESULT: $test_file (missing JUnit XML: $junit_file )"
435+ record_no_result_test " $test_file "
436+ fi
373437 fi
374438
375439 echo " "
@@ -475,13 +539,16 @@ run_tests_parallel() {
475539 local file_index=$3
476540 local result_file=" $PARALLEL_TMP_DIR /result_${file_index} "
477541 local log_file=" $PARALLEL_TMP_DIR /log_${file_index} "
542+ local junit_file
543+ junit_file=$( junit_file_for_test " $test_file " )
478544
479545 (
480546 # Set GPU for this test
481547 export CUDA_VISIBLE_DEVICES=$gpu_id
482548
483549 # Redirect output to log file
484550 exec > " $log_file " 2>&1
551+ rm -f " $junit_file "
485552
486553 echo " =========================================="
487554 echo " [$file_index /$total_files ] Processing: $test_file "
@@ -513,8 +580,7 @@ run_tests_parallel() {
513580 fi
514581
515582 mapfile -t SAMPLED_NODE_IDS_ARRAY <<< " $SAMPLED_NODE_IDS"
516- JUNIT_FILENAME=" ${test_file// \/ / _} .xml"
517- JUNIT_FLAG=" --junitxml=${JUNIT_DIR} /${JUNIT_FILENAME} "
583+ JUNIT_FLAG=" --junitxml=${junit_file} "
518584
519585 # shellcheck disable=SC2086
520586 if ${PYTEST_COMMAND_PREFIX} pytest $PYTEST_FLAGS " ${JUNIT_FLAG} " " ${SAMPLED_NODE_IDS_ARRAY[@]} " ; then
@@ -526,8 +592,7 @@ run_tests_parallel() {
526592 fi
527593 else
528594 # Run full test
529- JUNIT_FILENAME=" ${test_file// \/ / _} .xml"
530- JUNIT_FLAG=" --junitxml=${JUNIT_DIR} /${JUNIT_FILENAME} "
595+ JUNIT_FLAG=" --junitxml=${junit_file} "
531596
532597 # shellcheck disable=SC2086
533598 if ${PYTEST_COMMAND_PREFIX} pytest $PYTEST_FLAGS " ${JUNIT_FLAG} " " ${test_file} " ; then
@@ -541,7 +606,7 @@ run_tests_parallel() {
541606 ) &
542607
543608 local pid=$!
544- echo " $pid :$test_file :$result_file :$log_file :$file_index "
609+ echo " $pid :$test_file :$result_file :$log_file :$file_index : $junit_file "
545610 }
546611
547612 # Launch tests in parallel with GPU queue
@@ -582,9 +647,9 @@ run_tests_parallel() {
582647 job_info=$( run_single_test_background " $test_file " " $gpu_id " " $file_index " )
583648
584649 # Parse job info
585- local pid result_file log_file
586- IFS=' :' read -r pid test_file result_file log_file file_index <<< " $job_info"
587- test_result_files[$pid ]=" $result_file :$test_file :$log_file :$file_index "
650+ local pid result_file log_file junit_file
651+ IFS=' :' read -r pid test_file result_file log_file file_index junit_file <<< " $job_info"
652+ test_result_files[$pid ]=" $result_file :$test_file :$log_file :$file_index : $junit_file "
588653 test_pid_map[$pid ]=" $test_file "
589654 test_gpu_map[$pid ]=" $gpu_id "
590655
@@ -609,8 +674,8 @@ run_tests_parallel() {
609674 # Sort results by file_index for deterministic output
610675 local -a sorted_pids=()
611676 for pid in " ${! test_result_files[@]} " ; do
612- local result_file test_file log_file file_index
613- IFS=' :' read -r result_file test_file log_file file_index <<< " ${test_result_files[$pid]}"
677+ local result_file test_file log_file file_index junit_file
678+ IFS=' :' read -r result_file test_file log_file file_index junit_file <<< " ${test_result_files[$pid]}"
614679 sorted_pids+=(" $file_index :$pid " )
615680 done
616681 local sorted_list
@@ -620,8 +685,8 @@ run_tests_parallel() {
620685 # Process results in order
621686 for entry in " ${sorted_pids[@]} " ; do
622687 local pid=" ${entry#*: } "
623- local result_file test_file log_file file_index
624- IFS=' :' read -r result_file test_file log_file file_index <<< " ${test_result_files[$pid]}"
688+ local result_file test_file log_file file_index junit_file
689+ IFS=' :' read -r result_file test_file log_file file_index junit_file <<< " ${test_result_files[$pid]}"
625690
626691 # Show log output
627692 if [ -f " $log_file " ]; then
@@ -633,45 +698,52 @@ run_tests_parallel() {
633698 if [ -f " $result_file " ]; then
634699 local result
635700 result=$( cat " $result_file " )
701+ if [[ " $result " == SKIPPED* ]]; then
702+ continue
703+ fi
704+
636705 TOTAL_TESTS=$(( TOTAL_TESTS + 1 ))
637706
707+ if [ " $mode " = " sanity" ] && [[ " $result " == PASSED:* || " $result " == FAILED:* ]]; then
708+ local total_in_file sampled_in_file
709+ # shellcheck disable=SC2034 # status is part of the read but unused
710+ IFS=' :' read -r _ total_in_file sampled_in_file <<< " $result"
711+ TOTAL_TEST_CASES=$(( TOTAL_TEST_CASES + total_in_file))
712+ SAMPLED_TEST_CASES=$(( SAMPLED_TEST_CASES + sampled_in_file))
713+ fi
714+
715+ if [ ! -f " $junit_file " ]; then
716+ echo " ⚠️ NO RESULT: $test_file (missing JUnit XML: $junit_file )"
717+ record_no_result_test " $test_file "
718+ continue
719+ fi
720+
638721 if [[ " $result " == PASSED* ]]; then
639722 PASSED_TESTS=$(( PASSED_TESTS + 1 ))
640- if [ " $mode " = " sanity" ]; then
641- local total_in_file sampled_in_file
642- # shellcheck disable=SC2034 # status is part of the read but unused
643- IFS=' :' read -r _ total_in_file sampled_in_file <<< " $result"
644- TOTAL_TEST_CASES=$(( TOTAL_TEST_CASES + total_in_file))
645- SAMPLED_TEST_CASES=$(( SAMPLED_TEST_CASES + sampled_in_file))
646- fi
647723 elif [[ " $result " == FAILED* ]]; then
648- FAILED_TESTS=" $FAILED_TESTS \n - $test_file "
649- # shellcheck disable=SC2034 # EXIT_CODE is used by calling scripts
650- EXIT_CODE=1
651- if [ " $mode " = " sanity" ]; then
652- local total_in_file sampled_in_file
653- # shellcheck disable=SC2034 # status is part of the read but unused
654- IFS=' :' read -r _ total_in_file sampled_in_file <<< " $result"
655- TOTAL_TEST_CASES=$(( TOTAL_TEST_CASES + total_in_file))
656- SAMPLED_TEST_CASES=$(( SAMPLED_TEST_CASES + sampled_in_file))
657- fi
658- elif [[ " $result " == SKIPPED* ]]; then
659- # Don't count skipped tests as passed
660- TOTAL_TESTS=$(( TOTAL_TESTS - 1 ))
724+ record_failed_test " $test_file "
661725 fi
726+ else
727+ TOTAL_TESTS=$(( TOTAL_TESTS + 1 ))
728+ local missing_artifacts
729+ missing_artifacts=$( describe_missing_artifacts " $result_file " " $junit_file " )
730+ echo " ⚠️ NO RESULT: $test_file (missing ${missing_artifacts} )"
731+ record_no_result_test " $test_file "
662732 fi
663733 done
664734}
665735
666736# Print execution summary
667737print_execution_summary () {
668738 if [ " $SANITY_TEST " == " true" ]; then
739+ local failed_count=$(( TOTAL_TESTS - PASSED_TESTS - NO_RESULT_COUNT))
669740 echo " =========================================="
670741 echo " SANITY TEST SUMMARY"
671742 echo " =========================================="
672743 echo " Total test files executed: $TOTAL_TESTS "
673744 echo " Test files passed: $PASSED_TESTS "
674- echo " Test files failed: $(( TOTAL_TESTS - PASSED_TESTS)) "
745+ echo " Test files failed: $failed_count "
746+ echo " Test files with no result: $NO_RESULT_COUNT "
675747 echo " "
676748 echo " Total test cases (full suite): $TOTAL_TEST_CASES "
677749 echo " Sampled test cases (executed): $SAMPLED_TEST_CASES "
@@ -685,19 +757,27 @@ print_execution_summary() {
685757 echo " To reproduce this exact run:"
686758 echo " SAMPLE_RATE=${SAMPLE_RATE} SAMPLE_OFFSET=${SAMPLE_OFFSET} $0 --sanity-test"
687759 else
760+ local failed_count=$(( TOTAL_TESTS - PASSED_TESTS - NO_RESULT_COUNT))
688761 echo " =========================================="
689762 echo " TEST SUMMARY"
690763 echo " =========================================="
691764 echo " Total test files executed: $TOTAL_TESTS "
692765 echo " Passed: $PASSED_TESTS "
693- echo " Failed: $(( TOTAL_TESTS - PASSED_TESTS)) "
766+ echo " Failed: $failed_count "
767+ echo " No result: $NO_RESULT_COUNT "
694768 fi
695769
696770 if [ -n " $FAILED_TESTS " ]; then
697771 echo " "
698772 echo " Failed test files:"
699773 echo -e " $FAILED_TESTS "
700774 fi
775+
776+ if [ -n " $NO_RESULT_TESTS " ]; then
777+ echo " "
778+ echo " Test files with no result:"
779+ echo -e " $NO_RESULT_TESTS "
780+ fi
701781}
702782
703783# Main execution function for dry run mode
0 commit comments