summaryrefslogtreecommitdiffstats
path: root/bin/runtest
blob: 3afa711b1f884540625787a60e327351a61880d9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
#! /bin/sh
#
# Copyright by the Board of Trustees of the University of Illinois.
# All rights reserved.
#
# This file is part of HDF5.  The full HDF5 copyright notice, including
# terms governing use, modification, and redistribution, is contained in
# the files COPYING and Copyright.html.  COPYING can be found at the root
# of the source code distribution tree; Copyright.html can be found at the
# root level of an installed copy of the electronic HDF5 document set and
# is linked from the top-level documents page.  It can also be found at
# http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html.  If you do not have
# access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu.
#

# run the hdf5/bin/snapshot
# Usage:
#	runtest		run the test for the local host
#	runtest <hostname>	run the test for <hostname>
#	runtest -all		run the test for all predefined hosts
#
# Assumptions in knowing where to find the right scripts to execute.
# 1. assume we are at the top level of the hdf5 source.  So, bin/* are
#    where the script files are.
# 2. after the cvs update is completed, we can go to the snapshot area
#    hdf5 source tree and use the bin/* there.
# 3. Cannot use the snapshot area scripts from the beginning because
#    for one, the current directory is renamed as previous right after
#    a snapshot release; and for another, some scripts may be changed
#    by the cvs update while it is being used.

# local setup
DEBUGMODE=""
test -n "$DEBUGMODE" && echo "******** DEBUGMODE is $DEBUGMODE ************"
WHEREAMI='pwd'

# the name of this program
PROGNAME="bin/runtest $DEBUGMODE"

# Setup
HOSTNAME=`hostname | cut -f1 -d.`	# no domain part
TODAY=`date +%y%m%d`
WEEKDAY=`date +%a`
H5VER=			# default to current CVS version
H5VERSION=		# default to current CVS version

# Default to do checkout (only once) and test, no release.
# Will run test only if there is significant differences from previous version.
# If srcdir is not used, don't launched multiple tests
SNAPSHOT="${DEBUGMODE:+echo }bin/snapshot"
SRCDIR="srcdir"
# Default standard Snaptest commands
SNAPCMD="$SRCDIR test clean"
# Default Standard snaptest command options
STANDARD_OPT=""
ENABLE_PARALLEL="--enable-parallel"
CONFIGNAME=$HOSTNAME	# Name used in the SNAPTESTCFG file

# test host default as local host.
TESTHOST=""

#################################
# Function definitions
#################################

# Print messages to stdout
# Use this to show output heading to stdout
PRINT()
{
    echo "$*"
}

# Show seconds since midnight.
# This is used to calculate seconds elapsed
SecOfDay()
{
    set `date '+%H %M %S'`
    t_sec=`expr $1 \* 3600 + $2 \* 60 + $3`
    echo $t_sec
}

# Calculated the elapsed time (in seconds) between the first
# and second time.  If second time is smaller than the first,
# we assume the clock has passed midnight and calculate appropriately.
ElapsedTime()
{
    if [ $2 -lt $1 ]; then
	t_sec=`expr 3600 \* 24 - $1 + $2`
    else
	t_sec=`expr $2 - $1`
    fi
    echo `expr $t_sec / 60`m `expr $t_sec % 60`s
}

# Report errors
# $1--an error message to be printed
REPORT_ERR()
{
    ERRMSG=$1
    # print it with a banner shifted right a bit
    PRINT "	*************************************"
    PRINT "	`date`"
    PRINT "	$ERRMSG"
    PRINT "	*************************************"
    # report it in the FAILED-LOG file too
    PRINT "$ERRMSG" >> $FAILEDLOG
}

#
# Report results of the last test done
REPORT_RESULT()
{
    if [ $retcode -eq 0 ]; then
	if [ $skiptest = yes ]; then
	    PRINT "SKIPPED ${HOSTNAME}: $TEST_TYPE" | tee -a $PASSEDLOG
	else
	    PRINT "PASSED ${HOSTNAME}: $TEST_TYPE" | tee -a $PASSEDLOG
	fi
    else
	# test failed.
	REPORT_ERR "****FAILED ${HOSTNAME}: $TEST_TYPE****"
    fi
}

# Print a blank line
PRINT_BLANK()
{
    PRINT
}

# Print test trailer
PRINT_TEST_TRAILER()
{
    PRINT "*** finished $TEST_TYPE tests for $HOSTNAME ***"
    date; EndTime=`SecOfDay`
    PRINT Total time = `ElapsedTime $StartTime $EndTime`
    PRINT_BLANK
}

# Print trailer summary
PRINT_TRAILER()
{
    PRINT "*** finished tests in $HOSTNAME ***"
    date; TotalEndTime=`SecOfDay`
    PRINT "${HOSTNAME}: Ran $n_test $runtest_type, Grand total test time = " \
          "`ElapsedTime $TotalStartTime $TotalEndTime`" | tee -a $TIMELOG
    PRINT_BLANK
}

# Figure out which remote command to use to reach a host.
# Try rsh first, then ssh.
# $1--hostname to reach.
CHECK_RSH()
{
    # Figure out how to use ping command in this host.
    # Some hosts use "ping host count", some use "ping -c count host"
    # Test "ping -c ..." style first because some '-c' machines treat
    # the command 'ping localhost 3' means to ping host '3'.
    if [ -z "$PING" ]; then
	if ping -c 3 -w 5 localhost >/dev/null 2>&1; then
	    PING='ping -c 3 -w 5'
	    PINGCOUNT=
	elif ping localhost 3 >/dev/null 2>&1; then
	    PING=ping
	    PINGCOUNT=3
	else	# don't know how to use ping.
	    PING=no_ping
	    PINGCOUNT=
	fi
    fi
    #
    host=$1
    # Try remote command with host if it responds to ping.
    # Still try it if we don't know how to do ping.
    if [ no_ping = "$PING" ] || $PING $host $PINGCOUNT >/dev/null 2>&1; then
	if rsh $host -n hostname >/dev/null 2>&1; then
	    RSH=rsh
	elif ssh $host -n hostname >/dev/null 2>&1; then
	    RSH=ssh
	else
	    PRINT cannot remote command with $host
	    RSH="NoRemoteCommand"
	fi
    else
	RSH="NotReachable"
    fi
}


# Wait for a file for at most number of minutes
# $1--the file
# $2--number of minutes
# WAIT_STATUS set to:
#	-1 if errors encountered
#	0  if file found within time limit
#	1  if file not found within time limit
WAITFOR()
{
    wait_file=$1
    nminutes=$2
    if [ -z "$wait_file" -o ! "$nminutes" -ge 0 ]
    then
	PRINT "errors in argument of WAITFOR(): wait_file($1) or nminutes($2)"
	WAIT_STATUS=-1
	return
    fi
    while [ ! -f $wait_file ]; do
	if [ $nminutes -gt 0 ]; then
	    PRINT "Wait For $wait_file to appear"
	    sleep 60			#sleep 1 minute
	else
	    WAIT_STATUS=1
	    return
	fi
	nminutes=`expr $nminutes - 1`
    done
    WAIT_STATUS=0
    return
}


# Wait till a file disappears for at most number of minutes.
# Useful to wait till a lock is removed by another process.
# $1--the file
# $2--number of minutes
# WAIT_STATUS set to:
#	-1 if errors encountered
#	0  if file disappears within time limit
#	1  if file has not disappeared within time limit
WAITTILL()
{
    wait_file=$1
    nminutes=$2
    if [ -z "$wait_file" -o ! "$nminutes" -ge 0 ]
    then
	PRINT "errors in argument of WAITTILL(): wait_file($1) or nminutes($2)"
	WAIT_STATUS=-1
	return
    fi
    while [ -f $wait_file ]; do
	if [ $nminutes -gt 0 ]; then
	    PRINT "Wait till $wait_file has disappeared"
	    sleep 60			#sleep 1 minute
	else
	    WAIT_STATUS=1
	    return
	fi
	nminutes=`expr $nminutes - 1`
    done
    WAIT_STATUS=0
    return
}


# Run one snapshot test
# $*--Types of test being run
RUNSNAPTEST()
{
    SNAPCMD_OPT="$STANDARD_OPT"		# snapshot test option
    SRCDIRNAME=""
    # restore CC, PATH in case they were changed in the last test.
    CC="$CC_SAVED"
    PATH=$PATH_SAVED
    export PATH			# DEC OSF1 needs to export PATH explicitly
    TEST_TYPE=$*
    retcode=0
    skiptest=no
    date
    PRINT "*** starting $TEST_TYPE tests in $HOSTNAME ***"
    PRINT "Uname -a: `uname -a`"

    # Parse the test type and set options accordingly.
    # See comments of SNAPTEST_CONFIG_PARSE().
    while [ $# -gt 0 ]; do
	case $1 in
	    -n32) # want -n32 option
		SRCDIRNAME=${SRCDIRNAME}-n32
		CC="cc -n32"
		export CC
		;;
	    parallel) # want parallel test
		SNAPCMD_OPT="$SNAPCMD_OPT $ENABLE_PARALLEL"
		SRCDIRNAME=${SRCDIRNAME}-pp
		;;
	    standard) # standard test
		;;
	    --*)
		# option for configure
		SNAPCMD_OPT="$SNAPCMD_OPT $1"
		;;
	    op-configure)
		# option for configure
		SNAPCMD_OPT="$SNAPCMD_OPT $1 $2"
		shift
		;;
	    setenv)
		# set environment variable
		shift
		eval $1="$2"
		export $1
		shift
		;;
	    setenv2)
		# set environment variable with 2 values
		# a kludge now--the extra single quotes are needed
		# else eval complains.
		shift
		eval $1="'$2 $3'"
		export $1
		shift; shift
		;;
	    skip)
		# skip this test
		skiptest=yes
		;;
	    *) # unknown test
		PRINT "$0: unknown type of test ($1)"
		retcode=1
		;;
	esac
	shift
    done

    if [ $retcode -ne 0 -o $skiptest = yes ]; then
	errcode=$retcode 
	return $retcode
    fi

    # Track down the zlib software
    ans=`$SNAPYARD/current/bin/locate_sw zlib`
    if [ $? = 0 ]; then
	Z_INC=`echo $ans | cut -f1 -d,`
	Z_LIB=`echo $ans | cut -f2 -d,`
	SNAPCMD_OPT="$SNAPCMD_OPT zlib $Z_INC,$Z_LIB"
    else
	# cannot locate zlib software.
	# continue the test, maybe configure can find it.
	:
    fi

    if [ -n "${SRCDIRNAME}" ]; then
	SNAPCMD_OPT="$SNAPCMD_OPT srcdirname ${SRCDIRNAME}"
    fi

    # Setup log file name to save test output
    THIS_MINUTE=`date +%H%M`
    LOGFILE=${LOGBASENAME}${SRCDIRNAME}_${TODAY}_${THIS_MINUTE}
    PRINT "Running snapshot with output saved in"
    PRINT "   $LOGFILE"
    (date; PRINT Hostname=$HOSTNAME) >> $LOGFILE

    (
    cd $SNAPYARD/current
    $SNAPSHOT $SNAPCMD $SNAPCMD_OPT
    ) >> $LOGFILE 2>&1
    retcode=$?
    [ $retcode -ne 0 ] && errcode=$retcode

    date >> $LOGFILE
}


# configuration parsing.
# Taking configuration from input.
# This should be invoke with configure file as stdin.
# Syntax of the configure file:
#    All lines started with the # are comment lines and are ignored.
#    Blank lines are ignored too.
#    Each config line starts with a "Scope" followed by test types.
#
# Scope can be:
#    standard ...          # what the standard test types are.
#    <host>: <test>        Do <test> for <host> 
#    all: <test>           Do <test> for all hosts. 
#    <weekday>/...         Use this scope if the <weekday> matches.
#                          <weekday> can be {Mon,Tue,Wed,Thu,Fri,Sat,Sun}
#    If no <host>: input for a <host>, the standard test is used.
#
# Test types:
#    standard		tests defined in standard scope.
#    -n32		-n32 mode.  Apply to 64/32 bit OS such as IRIX64.
#    parallel		parallel mode.
#    op-configure <option>	configure option
#    --*		configure option
#    setenv <name> <value>	set environment variable <name> to <value>
#    skip		skip this test
SNAPTEST_CONFIG_PARSE()
{
    while read x y ; do
	# Scan for entry for this weekday.
	xd=`echo $x | cut -f1 -d/`
	if [ "$xd" = ${WEEKDAY} ]; then
	    # strip away the weekday/ part.
	    x=`echo $x | cut -f2 -d/`
	fi
	case "$x" in
	    '' | '#'*)
		# blank or comment lines.  Continue.
	    	;;
	    ???/*)
		# Ignore any entry not of this weekday.
		;;
	    standard)
		#standard configuration
		STANDARD_OPT="$y"
		;;
	    all: | ${CONFIGNAME}:)
		# types of test for all hosts or this host
		if [ -n "$TEST_TYPES" ]; then
		    TEST_TYPES="$TEST_TYPES ; $y"
		else
		    TEST_TYPES="$y"
		fi
		;;
	    *:)	# ignore types of test for other hosts
		;;
	    *)	# unknown configuration option
		PRINT $x $y
		PRINT "***Unknown configuration option. Ignored.***"
		;;
	esac
    done
}

# Snap Test configuration parsing.
# If TEST_TYPES is not set, set it to do the "standard" test.
SNAPTEST_CONFIG()
{
    TEST_TYPES=
    STANDARD_OPT=
    if [ -f $SNAPTESTCFG ]; then
	SNAPTEST_CONFIG_PARSE < $SNAPTESTCFG
    fi
    TEST_TYPES=${TEST_TYPES:-'standard'}
}


# Flush the AFS files if applicable.
# Hopefully the flushing is done when the tests of this
# host are done rather than when the launching site try
# to pull them in at the same time.  This way, the afs
# server updates are spread out.
FLUSH_FILES()
{
    /usr/afsws/bin/fs flush $SNAPYARD
}


# Show usage page
USAGE()
{
cat <<EOF
Usage: runtest [-h] [-debug] [-r<version>] [-all] [-nocvs] [-nodiff] [<host> ...]
    -h
	print this help page
    -debug
	turn on debug mode
    -r<version>
	do runtest for <version>
    -all
	launch tests for all pre-defined testing hosts
    -nocvs
	do not do cvs commands
    -nodiff
	do not do diff commands
    -configname <name>
	use <name> as hostname in the parsing of the snaptest configure file
    <host>
	launch tests for <host>
    
-all and <host> are contradictory and whichever is specified last, is
the one to take effect.  If neither are given, do the test for the
local host.
EOF
}


#################################
# Main
#################################
#################################
# Set up global variables
#################################
retcode=0			# error code of individula task
errcode=0			# error code of the whole test
skiptest=no			# if test is skipped
CC_SAVED="$CC"			# CC & PATH maybe changed within a test.
PATH_SAVED=$PATH		# These save the original values.


#################################
# Parse options
#################################
while [ $# -gt 0 ]; do
    case "$1" in
	-h) # help--show usage
	    USAGE
	    exit 0
	    ;;
	-debug*)
	    # set debug mode
	    DEBUGMODE="$1"
	    SNAPSHOT="echo bin/snapshot"
	    PROGNAME="$PROGNAME $DEBUGMODE"
	    PRINT "******** DEBUGMODE is $DEBUGMODE ************"
	    ;;
	-r*)
	    # version string
	    H5VER="$1"
	    ;;
	-all)
	    # Test all hosts.
	    TESTHOST=-all
	    ;;
	-nocvs)
	    # do not do cvs commands
	    NOCVS=nocvs
	    ;;
	-nodiff)
	    # do not do diff commands
	    NODIFF=nodiff
	    ;;
	-configname)
	    # use <name> as hostname in the parsing of the snaptest configure file
	    shift
	    CONFIGNAME=$1
	    ;;
	-*) # Unknow option
	    PRINT "Unknown option ($1)"
	    USAGE
	    exit 1
	    ;;
	*)
	    TESTHOST=$*
	    break
	    ;;
    esac
    shift
done

# setup H5VER if not set yet
if [ -z "$H5VER" -a -f bin/snapshot_version ]
then
    . bin/snapshot_version
fi

if [ -n "$H5VER" ]
then
    H5VERSION=hdf5_`echo $H5VER | sed -e s/-r// -e s/\\\./_/g`
    PROGNAME="$PROGNAME $H5VER"
else
    H5VERSION=hdf5
fi

#################################
# Setup snapshot test directories
#################################
# Show the real physical path rather than the symbolic path
SNAPYARD=`cd $HOME/snapshots-${H5VERSION} && /bin/pwd`
# Log file basename
LOGBASENAME=${SNAPYARD}/log/${HOSTNAME}
PASSEDLOG=${SNAPYARD}/log/PASSED_LOG_${TODAY}
FAILEDLOG=${SNAPYARD}/log/FAILED_LOG_${TODAY}
TIMELOG=${SNAPYARD}/log/TIME_LOG_${TODAY}
CVSLOG=${SNAPYARD}/log/CVS_LOG_${TODAY}
CVSLOG_LOCK=${SNAPYARD}/log/CVS_LOG_LOCK_${TODAY}
DIFFLOG=${SNAPYARD}/log/DIFF_LOG_${TODAY}
# Snap Test Configuration file
SNAPTESTCFG=${SNAPYARD}/snaptest.cfg


#################################
# Setup test host(s)
#################################
ALLHOSTSFILE=${SNAPYARD}/allhostfile
if [ "$TESTHOST" = -all ]; then
    if [ -f $ALLHOSTSFILE ]; then
	TESTHOST=`sed -e s/#.*// $ALLHOSTSFILE`
    else
	PRINT "could not access the all-hosts-file ($ALLHOSTSFILE)"
	USAGE
	exit 1
    fi
fi


#################################
# Setup to print a trailer summary when exiting not via
# the normal end of the script.
#################################
trap PRINT_TRAILER 0

#
TotalStartTime=`SecOfDay`

# Process the configuration
SNAPTEST_CONFIG
PRINT STANDARD_OPT=$STANDARD_OPT
PRINT TEST_TYPES=$TEST_TYPES
PRINT_BLANK

# Do a checkout if one has not been done today
# Also check MANIFEST file
if [ -z "$NOCVS" -a ! -f $CVSLOG ]; then
    PRINT "Running CVS checkout with output saved in"
    PRINT "   $CVSLOG"
    # Set CVS lock first
    touch $CVSLOG_LOCK
    ($SNAPSHOT checkout ) >> $CVSLOG 2>&1
    # Save error code and remove the lock
    errcode=$?
    rm -f $CVSLOG_LOCK
    if [ $errcode -ne 0 ]; then
	# test failed.
	REPORT_ERR "****FAILED ${HOSTNAME}: CVS checkout****"
	exit $errcode
    fi
    PRINT Checking MAINFEST file ...
    (cd $SNAPYARD/current; bin/chkmanifest)
    errcode=$?
    if [ $errcode -ne 0 ]; then
	# test failed.
	REPORT_ERR "****FAILED ${HOSTNAME}: MANIFEST check****"
    fi
    PRINT_BLANK
else
    # make sure the cvs update, if done by another host, has completed.
    # First wait for the presence of $CVSLOG which signals some host
    # has started the cvs update.  Then wait for the absense of $CVSLOG_LOCK
    # which signals the host has completed the cvs update.
    WAITFOR $CVSLOG 90
    if [ $WAIT_STATUS -ne 0 ]; then
	errcode=$WAIT_STATUS
	REPORT_ERR "****FAILED ${HOSTNAME}: Time expired waiting CVS update to start****"
	exit $errcode
    fi
    WAITTILL $CVSLOG_LOCK 10
    if [ $WAIT_STATUS -ne 0 ]; then
	errcode=$WAIT_STATUS
	REPORT_ERR "****FAILED ${HOSTNAME}: Time expired waiting CVS update to finish****"
	exit $errcode
    fi
fi

# run a snapshot diff to see if any significant differences between
# the current and previous versions
if [ -z "$NODIFF" ]; then
    $SNAPSHOT diff >> $DIFFLOG 2>&1
    errcode=$?
    # check the errcode only if NOT in DEBUG MODE
    if [ -z "$DEBUGMODE" -a $errcode -eq 0 ]; then
	# no need to run test
	PRINT "NO TEST: no significant differences between current and previous versions" |
	    tee -a $PASSEDLOG
	exit 0
    fi
fi

# we can use the version of script in SNAPYARD/current now
# Don't do the diff any more.
PROGNAME="$SNAPYARD/current/$PROGNAME -nodiff"

# Decide to do test for the local host or for remote hosts
if [ -n "$TESTHOST" -a $HOSTNAME != "$TESTHOST" ]; then
    date
    PRINT "*** launching tests from $HOSTNAME ***"
    PRINT_BLANK
    TEST_TYPE="launching"
    cd ${SNAPYARD}/log
    n_test=0
    runtest_type="hosts"
    for h in $TESTHOST; do
	n_test=`expr $n_test + 1`
	TMP_OUTPUT="#$h.out"
	(PRINT "=============="
	 PRINT "Testing $h"
	 PRINT "==============") > $TMP_OUTPUT
	CHECK_RSH $h
	# run the remote shell command with output to $TMP_OUTPUT
	case "$RSH" in
	    rsh|ssh)
		CMD="$RSH $h -n $PROGNAME -configname $h"
		PRINT $CMD
		# kludge: some how eirene and houdin can not have
                # rsh connections too close.  wait a few seconds
		test $h = houdin && echo "wait 10 sec for houdin" && sleep 10

		# launch concurrent tests only if srcdir is used
		if [ -n "$SRCDIR" ]; then
		    $CMD &
		else
		    $CMD
		fi
		;;
	    NoRemoteCommand)
		PRINT $h does not accept Remote Command
		;;
	    NotReachable)
		PRINT $h is not reachable 
		;;
	    *)
		PRINT "CHECK_RSH for $h returned unknow result ($RSH)"
		;;
	esac >> $TMP_OUTPUT 2>&1
    done
    # wait for all launched tests to finish, then cat them back out.
    wait
    for h in $TESTHOST; do
	TMP_OUTPUT="#$h.out"
	cat $TMP_OUTPUT
	# Verify test script did complete by checking the last lines
	(tail -2 $TMP_OUTPUT | grep -s 'Grand total' > /dev/null 2>&1) ||
	    (REPORT_ERR "****FAILED ${h}: snaptest did not complete****" &&
		PRINT_BLANK)
	rm $TMP_OUTPUT
    done
    exit 0
fi

# run the test(s)
# Note that first field is cut without -s but all subsequent cut
# must use -s.  If -s is not used at all, a $TEST_TYPES that has
# no ';' (only 1 test), will pass through intact in all cut. That
# results in infinite looping.
# If -s is used with the first field, it will suppress completely
# a $TYPE_TYPES that has no ';' (only 1 tst ).  That results in no
# test at all.
# Note that n_test must start as 1.
# 
n_test=1
runtest_type="tests"
TEST="`echo $TEST_TYPES | cut -f$n_test -d';'`"
while [ -n "$TEST" ]; do
    StartTime=`SecOfDay`
    RUNSNAPTEST $TEST
    REPORT_RESULT
    PRINT_TEST_TRAILER

    n_test=`expr $n_test + 1`
    TEST="`echo $TEST_TYPES | cut -f$n_test -s -d';'`"
done
# dec n_test to show the actual number of tests ran.
n_test=`expr $n_test - 1`

FLUSH_FILES

PRINT_TRAILER

# disable trailer summary printing since all trailers have been
# printed and we are exiting normally.
trap 0
exit $errcode