3 set testdir
[file normalize
[file dirname
$argv0]]
6 source [file join $testdir testrunner_data.tcl
]
7 source [file join $testdir permutations.test
]
11 # This script requires an interpreter that supports [package require sqlite3]
12 # to run. If this is not such an intepreter, see if there is a [testfixture]
13 # in the current directory. If so, run the command using it. If not,
14 # recommend that the user build one.
16 proc find_interpreter
{} {
17 set interpreter
[file tail
[info nameofexec
]]
18 set rc
[catch { package require sqlite3
}]
20 if { [string match
-nocase testfixture
* $interpreter]==0
21 && [file executable .
/testfixture
]
23 puts "Failed to find tcl package sqlite3. Restarting with ./testfixture.."
25 exec .
/testfixture
[info script
] {*}$::argv >@ stdout
31 puts stderr
"Failed to find tcl package sqlite3"
32 puts stderr
"Run \"make testfixture\" and then try again..."
38 # Usually this script is run by [testfixture]. But it can also be run
39 # by a regular [tclsh]. For these cases, emulate the [clock_milliseconds]
41 if {[info commands clock_milliseconds
]==""} {
42 proc clock_milliseconds
{} {
47 #-------------------------------------------------------------------------
51 set a0
[file tail
$::argv0]
53 puts stderr
[string trim
[subst -nocommands {
55 $a0 ?SWITCHES? ?PERMUTATION? ?PATTERNS?
62 --zipvfs ZIPVFS-SOURCE-DIR
64 Interesting values
for PERMUTATION are
:
66 veryquick
- a fast subset of the tcl test scripts. This is the
default.
67 full
- all tcl test scripts.
68 all
- all tcl test scripts
, plus a subset of test scripts rerun
69 with various permutations.
70 release
- full release test with various builds.
72 If no PATTERN arguments are present
, all tests specified by the PERMUTATION
73 are run. Otherwise
, each pattern is interpreted as a
glob pattern. Only
74 those tcl tests
for which the final component of the
filename matches at
75 least one specified pattern are run.
77 If no PATTERN arguments are present
, then various fuzztest
, threadtest
78 and other tests are run as part of the
"release" permutation. These are
79 omitted
if any PATTERN arguments are specified on the command line.
81 If a PERMUTATION is specified and is followed by the path to a
Tcl script
82 instead of a
list of patterns
, then that single
Tcl test script is run
83 with the specified permutation.
85 The
"status" and
"njob" commands are designed to be run from the same
86 directory as a running testrunner.tcl script that is running tests. The
87 "status" command prints a report describing the current state and progress
88 of the tests. The
"njob" command may be used to query or modify the number
89 of sub-processes the test script uses to run tests.
94 #-------------------------------------------------------------------------
96 #-------------------------------------------------------------------------
97 # Try to estimate a the number of processes to use.
99 # Command [guess_number_of_cores] attempts to glean the number of logical
100 # cores. Command [default_njob] returns the default value for the --jobs
103 proc guess_number_of_cores
{} {
104 if {[catch {number_of_cores
} ret
]} {
107 if {$::tcl_platform(platform
)=="windows"} {
108 catch { set ret
$::env(NUMBER_OF_PROCESSORS
) }
110 if {$::tcl_platform(os
)=="Darwin"} {
111 set cmd
"sysctl -n hw.logicalcpu"
116 set fd
[open "|$cmd" r
]
126 proc default_njob
{} {
127 set nCore
[guess_number_of_cores
]
131 set nHelper
[expr int
($nCore*0.5)]
135 #-------------------------------------------------------------------------
137 #-------------------------------------------------------------------------
138 # Setup various default values in the global TRG() array.
140 set TRG
(dbname
) [file normalize testrunner.db
]
141 set TRG
(logname
) [file normalize testrunner.log
]
142 set TRG
(build.logname
) [file normalize testrunner_build.log
]
143 set TRG
(info_script
) [file normalize
[info script
]]
144 set TRG
(timeout
) 10000 ;# Default busy-timeout for testrunner.db
145 set TRG
(nJob
) [default_njob
] ;# Default number of helper processes
146 set TRG
(patternlist
) [list]
147 set TRG
(cmdline
) $argv
148 set TRG
(reporttime
) 2000
149 set TRG
(fuzztest
) 0 ;# is the fuzztest option present.
150 set TRG
(zipvfs
) "" ;# -zipvfs option, if any
152 switch -nocase -glob -- $tcl_platform(os
) {
154 set TRG
(platform
) osx
155 set TRG
(make
) make.sh
156 set TRG
(makecmd
) "bash make.sh"
157 set TRG
(testfixture
) testfixture
159 set TRG
(runcmd
) "bash run.sh"
162 set TRG
(platform
) linux
163 set TRG
(make
) make.sh
164 set TRG
(makecmd
) "bash make.sh"
165 set TRG
(testfixture
) testfixture
167 set TRG
(runcmd
) "bash run.sh"
170 set TRG
(platform
) win
171 set TRG
(make
) make.bat
172 set TRG
(makecmd
) make.bat
173 set TRG
(testfixture
) testfixture.exe
175 set TRG
(runcmd
) "run.bat"
178 error "cannot determine platform!"
181 #-------------------------------------------------------------------------
183 #-------------------------------------------------------------------------
184 # The database schema used by the testrunner.db database.
187 DROP TABLE IF EXISTS jobs
;
188 DROP TABLE IF EXISTS config
;
191 ** This table contains one row
for each job that testrunner.tcl must run
192 ** before the entire test run is finished.
195 ** Unique identifier
for each job. Must be a
+ve non-zero number.
198 ** 3 or
4 letter mnemonic
for the class of tests this belongs to e.g.
199 ** "fuzz", "tcl", "make" etc.
202 ** Name
/description of job. For display purposes.
205 ** If the job requires a make.bat
/make.sh make wrapper
(i.e. to build
206 ** something
), the name of the build configuration it uses. See
207 ** testrunner_data.tcl
for a
list of build configs. e.g.
"Win32-MemDebug".
210 ** If the job should use a well-known directory name
for its
211 ** sub-directory instead of an anonymous
"testdir[1234...]" sub-dir
212 ** that is deleted
after the job is finished.
215 ** Bash or batch script to run the job.
218 ** The jobid value of a job that this job depends on. This job may not
219 ** be run before its depid job has finished successfully.
222 ** Higher values run first. Sometimes.
225 /* Fields populated when db is initialized
*/
226 jobid INTEGER PRIMARY KEY
, -- id to identify job
227 displaytype TEXT NOT NULL
, -- Type of test
(for one line report
)
228 displayname TEXT NOT NULL
, -- Human readable job name
229 build TEXT NOT NULL DEFAULT ''
, -- make.sh
/make.bat
file request
, if any
230 dirname TEXT NOT NULL DEFAULT ''
, -- directory name
, if required
231 cmd TEXT NOT NULL
, -- shell command to run
232 depid INTEGER
, -- identifier of dependency
(or ''
)
233 priority INTEGER NOT NULL
, -- higher priority jobs may run earlier
235 /* Fields updated as jobs run
*/
238 state TEXT CHECK
( state IN
(''
, 'ready'
, 'running'
, 'done'
, 'failed'
) ),
243 name TEXT COLLATE nocase PRIMARY KEY
,
247 CREATE INDEX i1 ON jobs
(state
, priority
);
248 CREATE INDEX i2 ON jobs
(depid
);
250 #-------------------------------------------------------------------------
252 #--------------------------------------------------------------------------
253 # Check if this script is being invoked to run a single file. If so,
256 if {[llength $argv]==2
257 && ([lindex $argv 0]=="" ||
[info exists
::testspec([lindex $argv 0])])
258 && [file exists
[lindex $argv 1]]
260 set permutation
[lindex $argv 0]
261 set script
[file normalize
[lindex $argv 1]]
264 set testdir
[file dirname
$argv0]
265 source $::testdir/tester.tcl
267 if {$permutation=="full"} {
269 unset -nocomplain ::G(isquick
)
272 } elseif
{$permutation!="default" && $permutation!=""} {
274 if {[info exists
::testspec($permutation)]==0} {
275 error "no such permutation: $permutation"
278 array set O
$::testspec($permutation)
279 set ::G(perm
:name
) $permutation
280 set ::G(perm
:prefix
) $O(-prefix)
282 set ::G(perm
:dbconfig
) $O(-dbconfig)
283 set ::G(perm
:presql
) $O(-presql)
285 rename finish_test helper_finish_test
286 proc finish_test
{} "
300 #--------------------------------------------------------------------------
302 #--------------------------------------------------------------------------
303 # Check if this is the "njob" command:
305 if {([llength $argv]==2 ||
[llength $argv]==1)
306 && [string compare
-nocase njob
[lindex $argv 0]]==0
308 sqlite3 mydb
$TRG(dbname
)
309 if {[llength $argv]==2} {
310 set param
[lindex $argv 1]
311 if {[string is integer
$param]==0 ||
$param<1 ||
$param>128} {
312 puts stderr
"parameter must be an integer between 1 and 128"
316 mydb
eval { REPLACE INTO config VALUES
('njob'
, $param); }
318 set res
[mydb one
{ SELECT value FROM config WHERE name
='njob'
}]
323 #--------------------------------------------------------------------------
325 #--------------------------------------------------------------------------
326 # Check if this is the "script" command:
328 if {[string compare
-nocase script
[lindex $argv 0]]==0} {
329 if {[llength $argv]!=2 && !([llength $argv]==3&&[lindex $argv 1]=="-msvc")} {
333 set bMsvc
[expr ([llength $argv]==3)]
334 set config
[lindex $argv [expr [llength $argv]-1]]
336 puts [trd_buildscript
$config [file dirname
$testdir] $bMsvc]
341 #--------------------------------------------------------------------------
342 # Check if this is the "status" command:
344 if {[llength $argv]==1
345 && [string compare
-nocase status
[lindex $argv 0]]==0
348 proc display_job
{jobdict
{tm
""}} {
349 array set job
$jobdict
351 set dfname
[format %-60s $job(displayname
)]
354 if {$tm!=""} { set dtm
"\[[expr {$tm-$job(starttime)}]ms\]" }
358 sqlite3 mydb
$TRG(dbname
)
362 set cmdline
[mydb one
{ SELECT value FROM config WHERE name
='cmdline'
}]
363 set nJob
[mydb one
{ SELECT value FROM config WHERE name
='njob'
}]
365 set now
[clock_milliseconds
]
368 COALESCE
((SELECT value FROM config WHERE name
='end'
), $now) -
369 (SELECT value FROM config WHERE name
='start'
)
373 foreach s
{"" ready running done failed
} { set S
($s) 0 }
375 SELECT state
, count
(*) AS cnt FROM jobs GROUP BY
1
380 set fin
[expr $S(done
)+$S(failed
)]
381 if {$cmdline!=""} {set cmdline
" $cmdline"}
385 set f
"$S(failed) FAILED, "
387 puts "Command line: \[testrunner.tcl$cmdline\]"
389 puts "Summary: ${tm}ms, ($fin/$total) finished, ${f}$S(running) running"
391 set srcdir
[file dirname
[file dirname
$TRG(info_script
)]]
395 SELECT
* FROM jobs WHERE state
='running' ORDER BY starttime
397 display_job
[array get job
] $now
403 SELECT
* FROM jobs WHERE state
='failed' ORDER BY starttime
405 display_job
[array get job
]
413 #-------------------------------------------------------------------------
414 # Parse the command line.
416 for {set ii
0} {$ii < [llength $argv]} {incr ii
} {
417 set isLast
[expr $ii==([llength $argv]-1)]
418 set a
[lindex $argv $ii]
419 set n
[string length
$a]
421 if {[string range
$a 0 0]=="-"} {
422 if {($n>2 && [string match
"$a*" --jobs]) ||
$a=="-j"} {
424 set TRG
(nJob
) [lindex $argv $ii]
425 if {$isLast} { usage
}
426 } elseif
{($n>2 && [string match
"$a*" --zipvfs]) ||
$a=="-z"} {
428 set TRG
(zipvfs
) [file normalize
[lindex $argv $ii]]
429 if {$isLast} { usage
}
434 lappend TRG
(patternlist
) [string map
{% *} $a]
441 # This script runs individual tests - tcl scripts or [make xyz] commands -
442 # in directories named "testdir$N", where $N is an integer. This variable
443 # contains a list of integers indicating the directories in use.
445 # This variable is accessed only via the following commands:
448 # Return the number of entries currently in the list.
451 # Remove value IDIR from the list. It is an error if it is not present.
454 # Select a value that is not already in the list. Add it to the list
457 set TRG
(dirs_in_use
) [list]
459 proc dirs_nHelper
{} {
461 llength $TRG(dirs_in_use
)
463 proc dirs_freeDir
{iDir
} {
466 foreach d
$TRG(dirs_in_use
) {
467 if {$iDir!=$d} { lappend out
$d }
469 if {[llength $out]!=[llength $TRG(dirs_in_use
)]-1} {
470 error "dirs_freeDir could not find $iDir"
472 set TRG
(dirs_in_use
) $out
474 proc dirs_allocDir
{} {
476 array set inuse
[list]
477 foreach d
$TRG(dirs_in_use
) {
480 for {set iRet
0} {[info exists inuse
($iRet)]} {incr iRet
} { }
481 lappend TRG
(dirs_in_use
) $iRet
485 # Check that directory $dir exists. If it does not, create it. If
486 # it does, delete its contents.
488 proc create_or_clear_dir
{dir
} {
489 set dir
[file normalize
$dir]
490 catch { file mkdir
$dir }
491 foreach f
[glob -nocomplain [file join $dir *]] {
492 catch { file delete
-force $f }
496 proc build_to_dirname
{bname
} {
497 set fold
[string tolower
[string map
{- _
} $bname]]
498 return "testrunner_build_$fold"
501 #-------------------------------------------------------------------------
503 proc r_write_db
{tcl
} {
504 trdb
eval { BEGIN EXCLUSIVE
}
509 # Obtain a new job to be run by worker $iJob (an integer). A job is
510 # returned as a three element list:
512 # {$build $config $file}
514 proc r_get_next_job
{iJob
} {
518 set orderby
"ORDER BY priority ASC"
520 set orderby
"ORDER BY priority DESC"
527 SELECT * FROM jobs AS j WHERE state='ready' $orderby LIMIT 1
529 trdb
eval $query job
{
530 set tm
[clock_milliseconds
]
532 set jobid
$job(jobid
)
535 UPDATE jobs SET starttime
=$tm, state
='running' WHERE jobid
=$jobid
538 set ret
[array get job
]
545 #rename r_get_next_job r_get_next_job_r
546 #proc r_get_next_job {iJob} {
547 #puts [time { set res [r_get_next_job_r $iJob] }]
553 # add_job OPTION ARG OPTION ARG...
555 # where available OPTIONS are:
565 # Returns the jobid value for the new job.
567 proc add_job
{args
} {
570 -displaytype -displayname -build -dirname
571 -cmd -depid -priority
574 # Set default values of options.
582 # Check all required options are present. And that no extras are present.
584 if {[info exists A
($o)]==0} { error "missing required option $o" }
586 foreach o
[array names A
] {
587 if {[lsearch -exact $options $o]<0} { error "unrecognized option: $o" }
591 if {$A(-depid)==""} { set state ready
}
595 displaytype
, displayname
, build
, dirname
, cmd
, depid
, priority
,
609 trdb last_insert_rowid
612 proc add_tcl_jobs
{build config patternlist
} {
615 set topdir
[file dirname
$::testdir]
616 set testrunner_tcl
[file normalize
[info script
]]
619 set testfixture
[info nameofexec
]
621 set testfixture
[file join [lindex $build 1] $TRG(testfixture
)]
623 if {[lindex $build 2]=="Valgrind"} {
624 set setvar
"export OMIT_MISUSE=1\n"
625 set testfixture
"${setvar}valgrind -v --error-exitcode=1 $testfixture"
628 # The ::testspec array is populated by permutations.test
629 foreach f
[dict get
$::testspec($config) -files] {
631 if {[llength $patternlist]>0} {
633 foreach p
$patternlist {
634 if {[string match
$p [file tail
$f]]} {
639 if {$bMatch==0} continue
642 if {[file pathtype
$f]!="absolute"} { set f
[file join $::testdir $f] }
643 set f
[file normalize
$f]
645 set displayname
[string map
[list $topdir/ {}] $f]
646 if {$config=="full" ||
$config=="veryquick"} {
647 set cmd
"$testfixture $f"
649 set cmd
"$testfixture $testrunner_tcl $config $f"
650 set displayname
"config=$config $displayname"
653 set displayname
"[lindex $build 2] $displayname"
656 set lProp
[trd_test_script_properties
$f]
658 if {[lsearch $lProp slow
]>=0} { set priority
2 }
659 if {[lsearch $lProp superslow
]>=0} { set priority
4 }
663 -displayname $displayname \
665 -depid [lindex $build 0] \
671 proc add_build_job
{buildname target
} {
674 set dirname
"[string tolower [string map {- _} $buildname]]_$target"
675 set dirname
"testrunner_bld_$dirname"
679 -displayname "Build $buildname ($target)" \
682 -cmd "$TRG(makecmd) $target" \
686 list $id [file normalize
$dirname] $buildname
689 proc add_make_job
{bld target
} {
692 if {$TRG(platform
)=="win"} {
693 set path
[string map
{/ \\} [lindex $bld 1]]
694 set cmd
"xcopy /S $path\\* ."
696 set cmd
"cp -r [lindex $bld 1]/* ."
698 append cmd
"\n$TRG(makecmd) $target"
702 -displayname "[lindex $bld 2] make $target" \
704 -depid [lindex $bld 0] \
708 proc add_fuzztest_jobs
{buildname
} {
710 foreach {interpreter scripts
} [trd_fuzztest_data
] {
711 set subcmd
[lrange $interpreter 1 end
]
712 set interpreter
[lindex $interpreter 0]
714 set bld
[add_build_job
$buildname $interpreter]
715 foreach {depid dirname displayname
} $bld {}
719 # Fuzz data files fuzzdata1.db and fuzzdata2.db are larger than
720 # the others. So ensure that these are run as a higher priority.
721 set tail
[file tail
$s]
722 if {$tail=="fuzzdata1.db" ||
$tail=="fuzzdata2.db"} {
730 -displayname "$buildname $interpreter $tail" \
732 -cmd "[file join $dirname $interpreter] $subcmd $s" \
738 proc add_zipvfs_jobs
{} {
740 source [file join $TRG(zipvfs
) test zipvfs_testrunner.tcl
]
742 set bld
[add_build_job Zipvfs
$TRG(testfixture
)]
743 foreach s
[zipvfs_testrunner_files
] {
744 set cmd
"[file join [lindex $bld 1] $TRG(testfixture)] $s"
747 -displayname "Zipvfs [file tail $s]" \
749 -depid [lindex $bld 0]
752 set ::env(SQLITE_TEST_DIR
) $::testdir
755 proc add_jobs_from_cmdline
{patternlist
} {
758 if {$TRG(zipvfs
)!=""} {
760 if {[llength $patternlist]==0} return
763 if {[llength $patternlist]==0} {
764 set patternlist
[list veryquick
]
767 set first
[lindex $patternlist 0]
770 set patternlist
[lrange $patternlist 1 end
]
771 set clist
[trd_all_configs
]
773 add_tcl_jobs
"" $c $patternlist
778 foreach b
[list All-O0 All-Debug
] {
779 set bld
[add_build_job
$b $TRG(testfixture
)]
780 add_tcl_jobs
$bld veryquick
""
786 foreach b
[list All-Sanitize All-Debug
] {
787 set bld
[add_build_job
$b $TRG(testfixture
)]
788 add_tcl_jobs
$bld veryquick
""
794 foreach b
[trd_builds
$TRG(platform
)] {
795 set bld
[add_build_job
$b $TRG(testfixture
)]
796 foreach c
[trd_configs
$TRG(platform
) $b] {
797 add_tcl_jobs
$bld $c ""
800 foreach e
[trd_extras
$TRG(platform
) $b] {
801 if {$e=="fuzztest"} {
811 if {[info exists
::testspec($first)]} {
812 add_tcl_jobs
"" $first [lrange $patternlist 1 end
]
814 add_tcl_jobs
"" full
$patternlist
820 proc make_new_testset
{} {
824 trdb
eval $TRG(schema
)
826 set cmdline
$TRG(cmdline
)
827 set tm
[clock_milliseconds
]
828 trdb
eval { REPLACE INTO config VALUES
('njob'
, $nJob ); }
829 trdb
eval { REPLACE INTO config VALUES
('cmdline'
, $cmdline ); }
830 trdb
eval { REPLACE INTO config VALUES
('start'
, $tm ); }
832 add_jobs_from_cmdline
$TRG(patternlist
)
837 proc script_input_ready
{fd iJob jobid
} {
843 trdb
eval { SELECT
* FROM jobs WHERE jobid
=$jobid } job
{}
845 # If this job specified a directory name, then delete the run.sh/run.bat
846 # file from it before continuing. This is because the contents of this
847 # directory might be copied by some other job, and we don't want to copy
848 # the run.sh file in this case.
849 if {$job(dirname
)!=""} {
850 file delete
-force [file join $job(dirname
) $TRG(run
)]
854 fconfigure $fd -blocking 1
856 set rc
[catch { close $fd } msg
]
858 if {[info exists TRG
(reportlength
)]} {
859 puts -nonewline "[string repeat " " $TRG(reportlength)]\r"
861 puts "FAILED: $job(displayname) ($iJob)"
865 set tm
[clock_milliseconds
]
866 set jobtm
[expr {$tm - $job(starttime
)}]
868 puts $TRG(log
) "### $job(displayname) ${jobtm}ms ($state)"
869 puts $TRG(log
) [string trim
$O($iJob)]
875 SET output
=$output, state
=$state, endtime
=$tm
877 UPDATE jobs SET state
='ready' WHERE depid
=$jobid;
885 set rc
[catch { gets $fd line
} res
]
890 append O
($iJob) "$line\n"
900 proc launch_another_job
{iJob
} {
905 set testfixture
[info nameofexec
]
906 set script
$TRG(info_script
)
910 set jobdict
[r_get_next_job
$iJob]
911 if {$jobdict==""} { return 0 }
912 array set job
$jobdict
914 set dir
$job(dirname
)
915 if {$dir==""} { set dir
[dirname
$iJob] }
916 create_or_clear_dir
$dir
918 if {$job(build
)!=""} {
919 set srcdir
[file dirname
$::testdir]
920 if {$job(build
)=="Zipvfs"} {
921 set script
[zipvfs_testrunner_script
]
923 set bWin
[expr {$TRG(platform
)=="win"}]
924 set script
[trd_buildscript
$job(build
) $srcdir $bWin]
926 set fd
[open [file join $dir $TRG(make
)] w
]
933 set fd
[open $TRG(run
) w
]
936 set fd
[open "|$TRG(runcmd) 2>@1" r
]
939 fconfigure $fd -blocking false
940 fileevent $fd readable
[list script_input_ready
$fd $iJob $job(jobid
)]
945 proc one_line_report
{} {
948 set tm
[expr [clock_milliseconds
] - $TRG(starttime
)]
949 set tm
[format "%d" [expr int
($tm/1000.0 + 0.5)]]
953 SELECT displaytype
, state
, count
(*) AS cnt
957 set v
($state,$displaytype) $cnt
958 incr t
($displaytype) $cnt
963 foreach j
[lsort [array names t
]] {
964 foreach k
{done failed running
} { incr v
($k,$j) 0 }
965 set fin
[expr $v(done
,$j) + $v(failed
,$j)]
966 lappend text "${j}($fin/$t($j))"
967 if {$v(failed
,$j)>0} {
968 lappend text "f$v(failed,$j)"
970 if {$v(running
,$j)>0} {
971 lappend text "r$v(running,$j)"
975 if {[info exists TRG
(reportlength
)]} {
976 puts -nonewline "[string repeat " " $TRG(reportlength)]\r"
978 set report
"${tm} [join $text { }]"
979 set TRG
(reportlength
) [string length
$report]
980 if {[string length
$report]<100} {
981 puts -nonewline "$report\r"
987 after $TRG(reporttime
) one_line_report
990 proc launch_some_jobs
{} {
992 set nJob
[trdb one
{ SELECT value FROM config WHERE name
='njob'
}]
994 while {[dirs_nHelper
]<$nJob} {
995 set iDir
[dirs_allocDir
]
996 if {0==[launch_another_job
$iDir]} {
1003 proc run_testset
{} {
1007 set TRG
(starttime
) [clock_milliseconds
]
1008 set TRG
(log
) [open $TRG(logname
) w
]
1013 while {[dirs_nHelper
]>0} {
1014 after 500 {incr ::wakeup}
1021 set tm
[clock_milliseconds
]
1022 trdb
eval { REPLACE INTO config VALUES
('end'
, $tm ); }
1023 set nErr
[trdb one
{SELECT count
(*) FROM jobs WHERE state
='failed'
}]
1025 puts "$nErr failures:"
1027 SELECT displayname FROM jobs WHERE state
='failed'
1029 puts "FAILED: $displayname"
1034 puts "\nTest database is $TRG(dbname)"
1035 puts "Test log is $TRG(logname)"
1039 sqlite3 trdb
$TRG(dbname
)
1040 trdb timeout
$TRG(timeout
)
1041 set tm
[lindex [time { make_new_testset
}] 0]
1043 puts "splitting work across $TRG(nJob) jobs"
1045 puts "built testset in [expr $tm/1000]ms.."