@@ -207,6 +207,7 @@ run_teardown() {
207207trap run_teardown EXIT
208208
209209TOTAL=0
210+ PASSED=0
210211SKIPPED=0
211212# Set as the last statement of each branch that runs tests, and checked before
212213# the summary. A shell expansion error (a bad arithmetic expansion, say) unwinds
@@ -246,6 +247,7 @@ should_skip() {
246247 fi
247248 if [ " $1 " == " $EXCLUDE " ]; then
248249 echo " Test '$1 ' is excluded. Skipping."
250+ TOTAL=$(( TOTAL+ 1 ))
249251 SKIPPED=$(( SKIPPED+ 1 ))
250252 return 0
251253 fi
@@ -260,6 +262,19 @@ matches() {
260262 [ -z " $MATCH " ] || [ " $1 " == " $MATCH " ]
261263}
262264
265+ # Counts each named test as skipped, for tests that need a local daemon on a run
266+ # against an external host. Takes the names rather than a number so the count
267+ # cannot drift from the tests it stands in for.
268+ skip_local_only () {
269+ local test
270+ for test in " $@ " ; do
271+ if matches " $test " ; then
272+ TOTAL=$(( TOTAL+ 1 ))
273+ SKIPPED=$(( SKIPPED+ 1 ))
274+ fi
275+ done
276+ }
277+
263278# Collect the directories above $1 that wolfSSHd's StrictModes check will
264279# reject: a group or world writable directory anywhere above authorized_keys
265280# makes the daemon refuse to read it, unless the directory is sticky. This
@@ -350,6 +365,7 @@ run_test() {
350365 SKIPPED=$(( SKIPPED+ 1 ))
351366 elif [ " $RESULT " == 0 ]; then
352367 printf " PASSED\n"
368+ PASSED=$(( PASSED+ 1 ))
353369 else
354370 printf " FAILED!\n"
355371 cat stdout.txt
401417 TOTAL=$(( TOTAL+ 1 ))
402418 if grep -q " group or world readable" strictmodes_log.txt; then
403419 printf " PASSED\n"
420+ PASSED=$(( PASSED+ 1 ))
404421 else
405422 printf " FAILED!\n"
406423 cat strictmodes_log.txt
459476 grep -q " but this build cannot enforce it" upn_nofpki_log.txt &&
460477 ! grep -q " Refusing to load" upn_nofpki_log.txt; then
461478 printf " PASSED\n"
479+ PASSED=$(( PASSED+ 1 ))
462480 else
463481 printf " FAILED!\n"
464482 cat upn_nofpki_log.txt
@@ -518,6 +536,7 @@ run_strictmodes_authkeys_negative_test() {
518536 after=${after:- 0}
519537 if [ " $result " != 0 ] && [ " $after " -gt " $before " ]; then
520538 printf " PASSED\n"
539+ PASSED=$(( PASSED+ 1 ))
521540 else
522541 printf " FAILED! (expected StrictModes rejection: client exit=%s, new log matches=%s)\n" \
523542 " $result " " $(( after - before)) "
654673 rm -rf " $HK_WORK "
655674 printf " PASSED (mode and owner cases skipped, built with "
656675 printf " WOLFSSH_NO_HOSTKEY_PERMS)\n"
676+ PASSED=$(( PASSED+ 1 ))
657677 return
658678 fi
659679
673693
674694 rm -rf " $HK_WORK "
675695 printf " PASSED\n"
696+ PASSED=$(( PASSED+ 1 ))
676697}
677698
678699# Run the tests. There is one path whether or not --match was given: every test
@@ -711,15 +732,15 @@ run_hostkey_perm_check
711732# rejected. Reads the local ./log.txt, so only when we own the daemon.
712733if [ " $USING_LOCAL_HOST " == 1 ]; then
713734 run_test " sshd_pubkey_reject_test.sh"
714- elif matches " sshd_pubkey_reject_test.sh " ; then
715- SKIPPED= $(( SKIPPED + 1 ))
735+ else
736+ skip_local_only " sshd_pubkey_reject_test.sh "
716737fi
717738
718739# exercise the authorized_keys StrictModes path against the running sshd
719740if [ " $USING_LOCAL_HOST " == 1 ]; then
720741 run_strictmodes_authkeys_negative_test
721- elif matches " strictmodes_authkeys_negative " ; then
722- SKIPPED= $(( SKIPPED + 1 ))
742+ else
743+ skip_local_only " strictmodes_authkeys_negative "
723744fi
724745
725746if [ " $USING_LOCAL_HOST " == 1 ]; then
@@ -728,27 +749,32 @@ if [ "$USING_LOCAL_HOST" == 1 ]; then
728749fi
729750
730751# these tests require setting up an sshd
752+ local_sshd_tests=(
753+ " sshd_forcedcmd_test.sh"
754+ " sshd_match_overlap_test.sh"
755+ " sshd_window_full_test.sh"
756+ " sshd_stderr_eof_test.sh"
757+ " sshd_empty_password_test.sh"
758+ " sshd_permitroot_test.sh"
759+ " sshd_permitroot_prohibit_password.sh"
760+ " sshd_permitroot_forced_cmd.sh"
761+ " strictmodes_hostkey_negative"
762+ " upn_unenforceable_negative"
763+ " sshd_login_grace_test.sh"
764+ " sshd_privdrop_fail_test.sh"
765+ " sshd_chroot_fail_test.sh"
766+ )
731767if [ " $USING_LOCAL_HOST " == 1 ]; then
732- run_test " sshd_forcedcmd_test.sh"
733- run_test " sshd_match_overlap_test.sh"
734- run_test " sshd_window_full_test.sh"
735- run_test " sshd_stderr_eof_test.sh"
736- run_test " sshd_empty_password_test.sh"
737- run_test " sshd_permitroot_test.sh"
738- run_test " sshd_permitroot_prohibit_password.sh"
739- run_test " sshd_permitroot_forced_cmd.sh"
740- run_strictmodes_negative_test
741- run_upn_unenforceable_negative_test
742- run_test " sshd_login_grace_test.sh"
743- run_test " sshd_privdrop_fail_test.sh"
744- run_test " sshd_chroot_fail_test.sh"
768+ for test in " ${local_sshd_tests[@]} " ; do
769+ case " $test " in
770+ strictmodes_hostkey_negative) run_strictmodes_negative_test ;;
771+ upn_unenforceable_negative) run_upn_unenforceable_negative_test ;;
772+ * ) run_test " $test " ;;
773+ esac
774+ done
745775else
746776 printf " Skipping tests that need to setup local SSHD\n"
747- # the thirteen calls above; with --match at most one of them was going to run,
748- # and should_skip() has already counted it if it was excluded
749- if [ -z " $MATCH " ]; then
750- SKIPPED=$(( SKIPPED+ 13 ))
751- fi
777+ skip_local_only " ${local_sshd_tests[@]} "
752778fi
753779
754780# these tests run with X509 sshd-config loaded. The matches() guard keeps a
767793# negative test: a certificate UPN realm outside AuthorizedUPNDomains must
768794# be rejected. Needs the dedicated bad-domain config, so only runs when we
769795# control the local daemon.
770- if [ " $USING_LOCAL_HOST " == 1 ] && matches " sshd_x509_upn_fail.sh" ; then
796+ if [ " $USING_LOCAL_HOST " != 1 ]; then
797+ skip_local_only " sshd_x509_upn_fail.sh"
798+ elif matches " sshd_x509_upn_fail.sh" ; then
771799 start_wolfsshd " sshd_config_test_x509_upn_bad"
772800 run_test " sshd_x509_upn_fail.sh"
773801 printf " Shutting down test wolfSSHd\n"
779807# sshd_config_test_mldsa has no other host key, so an ML-DSA-less build
780808# cannot start the daemon; check out here, not in the test script. The check
781809# is the composite, not the umbrella: the ECDSA half can be missing on its own.
782- if [ " $USING_LOCAL_HOST " == 1 ] && matches " sshd_mldsa_composite_test.sh" ; then
810+ if [ " $USING_LOCAL_HOST " != 1 ]; then
811+ skip_local_only " sshd_mldsa_composite_test.sh"
812+ elif matches " sshd_mldsa_composite_test.sh" ; then
783813 if wolfssh_has MLDSA87_ES384; then
784814 start_wolfsshd " sshd_config_test_mldsa"
785815 run_test " sshd_mldsa_composite_test.sh"
798828# client when present.
799829if [ " $USING_LOCAL_HOST " == 1 ]; then
800830 run_test " sshd_ossh_cert_test.sh"
831+ else
832+ skip_local_only " sshd_ossh_cert_test.sh"
801833fi
802834RUN_COMPLETE=1
803835}
@@ -808,14 +840,35 @@ if [ "$RUN_COMPLETE" != 1 ]; then
808840fi
809841
810842# A --match that reached no call site ran nothing and skipped nothing, which
811- # would otherwise report a clean run. The local-only tests are unreachable
812- # against an external host, so a name that is valid on a local run selects
813- # nothing here; say so rather than exit 0 on an empty run.
843+ # would otherwise add up and report a clean "0 run". Every name is counted
844+ # somewhere -- the local-only ones as skipped against an external host -- so
845+ # this catches a call site that stopped counting; say so rather than exit 0 on
846+ # an empty run.
814847if [ -n " $MATCH " ] && [ " $TOTAL " -eq 0 ]; then
815848 printf " ERROR: --match %s selected no test that could run here\n" " $MATCH "
816849 exit 1
817850fi
818851
819- printf " All tests ran, $TOTAL passed, $SKIPPED skipped\n"
852+ # TOTAL counts every test that was reached, skips included, so it is a "ran"
853+ # count and not a pass count. Print the three separately, and assert they add
854+ # up: a skip site that bumps one counter and not the other then fails the run
855+ # instead of quietly printing a wrong number.
856+ printf " All tests ran, %d run, %d passed, %d skipped\n" \
857+ " $TOTAL " " $PASSED " " $SKIPPED "
858+
859+ if [ " $(( PASSED + SKIPPED)) " -ne " $TOTAL " ]; then
860+ printf " ERROR: counter mismatch (ran %d, passed %d, skipped %d)\n" \
861+ " $TOTAL " " $PASSED " " $SKIPPED "
862+ exit 1
863+ fi
864+
865+ # Without --match every known test is reached once, run or skipped, so a
866+ # name no call site reaches -- one dropped from local_sshd_tests, say --
867+ # shows up here as a short count.
868+ KNOWN=$(( ${# test_cases[@]} + ${# extra_test_cases[@]} ))
869+ if [ -z " $MATCH " ] && [ " $TOTAL " -ne " $KNOWN " ]; then
870+ printf " ERROR: %d tests known but %d reached\n" " $KNOWN " " $TOTAL "
871+ exit 1
872+ fi
820873
821874exit 0
0 commit comments