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?
59 $a0 script ?
-msvc? CONFIG
63 --buildonly Build test exes but do not run tests
64 --config CONFIGS Only use configs on comma-separate
list CONFIGS
65 --dryrun Write what would have happened to testrunner.log
66 --explain Write summary to stdout
67 --jobs NUM Run tests using NUM separate processes
68 --omit CONFIGS Omit configs on comma-separated
list CONFIGS
69 --stop-on
-coredump Stop running
if any test segfaults
70 --stop-on
-error Stop running
after any reported
error
71 --zipvfs ZIPVFSDIR ZIPVFS
source directory
73 Special values
for PERMUTATION that work with plain tclsh
:
75 list - show all allowed PERMUTATION arguments.
76 mdevtest
- tests recommended prior to normal development check-ins.
77 release
- full release test with various builds.
78 sdevtest
- like mdevtest but using ASAN and UBSAN.
80 Other PERMUTATION arguments must be run using testfixture
, not tclsh
:
82 all
- all tcl test scripts
, plus a subset of test scripts rerun
83 with various permutations.
84 full
- all tcl test scripts.
85 veryquick
- a fast subset of the tcl test scripts. This is the
default.
87 If no PATTERN arguments are present
, all tests specified by the PERMUTATION
88 are run. Otherwise
, each pattern is interpreted as a
glob pattern. Only
89 those tcl tests
for which the final component of the
filename matches at
90 least one specified pattern are run.
92 If no PATTERN arguments are present
, then various fuzztest
, threadtest
93 and other tests are run as part of the
"release" permutation. These are
94 omitted
if any PATTERN arguments are specified on the command line.
96 If a PERMUTATION is specified and is followed by the path to a
Tcl script
97 instead of a
list of patterns
, then that single
Tcl test script is run
98 with the specified permutation.
100 The
"status" and
"njob" commands are designed to be run from the same
101 directory as a running testrunner.tcl script that is running tests. The
102 "status" command prints a report describing the current state and progress
103 of the tests. The
"njob" command may be used to query or modify the number
104 of sub-processes the test script uses to run tests.
106 The
"script" command outputs the script used to build a configuration.
107 Add the
"-msvc" option for a Windows-compatible script. For a
list of
108 available configurations enter
"$a0 script help".
110 Full documentation here
: https
://sqlite.org
/src
/doc
/trunk
/doc
/testrunner.md
115 #-------------------------------------------------------------------------
117 #-------------------------------------------------------------------------
118 # Try to estimate a the number of processes to use.
120 # Command [guess_number_of_cores] attempts to glean the number of logical
121 # cores. Command [default_njob] returns the default value for the --jobs
124 proc guess_number_of_cores
{} {
125 if {[catch {number_of_cores
} ret
]} {
128 if {$::tcl_platform(platform
)=="windows"} {
129 catch { set ret
$::env(NUMBER_OF_PROCESSORS
) }
131 if {$::tcl_platform(os
)=="Darwin"} {
132 set cmd
"sysctl -n hw.logicalcpu"
137 set fd
[open "|$cmd" r
]
147 proc default_njob
{} {
149 if {[info exists env
(NJOB
)] && $env(NJOB
)>=1} {
152 set nCore
[guess_number_of_cores
]
156 set nHelper
[expr int
($nCore*0.5)]
160 #-------------------------------------------------------------------------
162 #-------------------------------------------------------------------------
163 # Setup various default values in the global TRG() array.
165 set TRG
(dbname
) [file normalize testrunner.db
]
166 set TRG
(logname
) [file normalize testrunner.log
]
167 set TRG
(build.logname
) [file normalize testrunner_build.log
]
168 set TRG
(info_script
) [file normalize
[info script
]]
169 set TRG
(timeout
) 10000 ;# Default busy-timeout for testrunner.db
170 set TRG
(nJob
) [default_njob
] ;# Default number of helper processes
171 set TRG
(patternlist
) [list]
172 set TRG
(cmdline
) $argv
173 set TRG
(reporttime
) 2000
174 set TRG
(fuzztest
) 0 ;# is the fuzztest option present.
175 set TRG
(zipvfs
) "" ;# -zipvfs option, if any
176 set TRG
(buildonly
) 0 ;# True if --buildonly option
177 set TRG
(config
) {} ;# Only build the named configurations
178 set TRG
(omitconfig
) {} ;# Do not build these configurations
179 set TRG
(dryrun
) 0 ;# True if --dryrun option
180 set TRG
(explain
) 0 ;# True for the --explain option
181 set TRG
(stopOnError
) 0 ;# Stop running at first failure
182 set TRG
(stopOnCore
) 0 ;# Stop on a core-dump
184 switch -nocase -glob -- $tcl_platform(os
) {
186 set TRG
(platform
) osx
187 set TRG
(make
) make.sh
188 set TRG
(makecmd
) "bash make.sh"
189 set TRG
(testfixture
) testfixture
190 set TRG
(shell
) sqlite3
192 set TRG
(runcmd
) "bash run.sh"
195 set TRG
(platform
) linux
196 set TRG
(make
) make.sh
197 set TRG
(makecmd
) "bash make.sh"
198 set TRG
(testfixture
) testfixture
199 set TRG
(shell
) sqlite3
201 set TRG
(runcmd
) "bash run.sh"
204 set TRG
(platform
) win
205 set TRG
(make
) make.bat
206 set TRG
(makecmd
) "call make.bat"
207 set TRG
(testfixture
) testfixture.exe
208 set TRG
(shell
) sqlite3.exe
210 set TRG
(runcmd
) "run.bat"
213 error "cannot determine platform!"
216 #-------------------------------------------------------------------------
218 #-------------------------------------------------------------------------
219 # The database schema used by the testrunner.db database.
222 DROP TABLE IF EXISTS jobs
;
223 DROP TABLE IF EXISTS config
;
226 ** This table contains one row
for each job that testrunner.tcl must run
227 ** before the entire test run is finished.
230 ** Unique identifier
for each job. Must be a
+ve non-zero number.
233 ** 3 or
4 letter mnemonic
for the class of tests this belongs to e.g.
234 ** "fuzz", "tcl", "make" etc.
237 ** Name
/description of job. For display purposes.
240 ** If the job requires a make.bat
/make.sh make wrapper
(i.e. to build
241 ** something
), the name of the build configuration it uses. See
242 ** testrunner_data.tcl
for a
list of build configs. e.g.
"Win32-MemDebug".
245 ** If the job should use a well-known directory name
for its
246 ** sub-directory instead of an anonymous
"testdir[1234...]" sub-dir
247 ** that is deleted
after the job is finished.
250 ** Bash or batch script to run the job.
253 ** The jobid value of a job that this job depends on. This job may not
254 ** be run before its depid job has finished successfully.
257 ** Higher values run first. Sometimes.
260 /* Fields populated when db is initialized
*/
261 jobid INTEGER PRIMARY KEY
, -- id to identify job
262 displaytype TEXT NOT NULL
, -- Type of test
(for one line report
)
263 displayname TEXT NOT NULL
, -- Human readable job name
264 build TEXT NOT NULL DEFAULT ''
, -- make.sh
/make.bat
file request
, if any
265 dirname TEXT NOT NULL DEFAULT ''
, -- directory name
, if required
266 cmd TEXT NOT NULL
, -- shell command to run
267 depid INTEGER
, -- identifier of dependency
(or ''
)
268 priority INTEGER NOT NULL
, -- higher priority jobs may run earlier
270 /* Fields updated as jobs run
*/
273 state TEXT CHECK
( state IN
(''
, 'ready'
, 'running'
, 'done'
, 'failed'
) ),
278 name TEXT COLLATE nocase PRIMARY KEY
,
282 CREATE INDEX i1 ON jobs
(state
, priority
);
283 CREATE INDEX i2 ON jobs
(depid
);
285 #-------------------------------------------------------------------------
287 #--------------------------------------------------------------------------
288 # Check if this script is being invoked to run a single file. If so,
291 if {[llength $argv]==2
292 && ([lindex $argv 0]=="" ||
[info exists
::testspec([lindex $argv 0])])
293 && [file exists
[lindex $argv 1]]
295 set permutation
[lindex $argv 0]
296 set script
[file normalize
[lindex $argv 1]]
299 set testdir
[file dirname
$argv0]
300 source $::testdir/tester.tcl
302 if {$permutation=="full"} {
304 unset -nocomplain ::G(isquick
)
307 } elseif
{$permutation!="default" && $permutation!=""} {
309 if {[info exists
::testspec($permutation)]==0} {
310 error "no such permutation: $permutation"
313 array set O
$::testspec($permutation)
314 set ::G(perm
:name
) $permutation
315 set ::G(perm
:prefix
) $O(-prefix)
317 set ::G(perm
:dbconfig
) $O(-dbconfig)
318 set ::G(perm
:presql
) $O(-presql)
320 rename finish_test helper_finish_test
321 proc finish_test
{} "
335 #--------------------------------------------------------------------------
337 #--------------------------------------------------------------------------
338 # Check if this is the "njob" command:
340 if {([llength $argv]==2 ||
[llength $argv]==1)
341 && [string compare
-nocase njob
[lindex $argv 0]]==0
343 sqlite3 mydb
$TRG(dbname
)
344 if {[llength $argv]==2} {
345 set param
[lindex $argv 1]
346 if {[string is integer
$param]==0 ||
$param<1 ||
$param>128} {
347 puts stderr
"parameter must be an integer between 1 and 128"
351 mydb
eval { REPLACE INTO config VALUES
('njob'
, $param); }
353 set res
[mydb one
{ SELECT value FROM config WHERE name
='njob'
}]
358 #--------------------------------------------------------------------------
360 #--------------------------------------------------------------------------
361 # Check if this is the "help" command:
363 if {[string compare
-nocase help
[lindex $argv 0]]==0} {
366 #--------------------------------------------------------------------------
368 #--------------------------------------------------------------------------
369 # Check if this is the "script" command:
371 if {[string compare
-nocase script
[lindex $argv 0]]==0} {
372 if {[llength $argv]!=2 && !([llength $argv]==3&&[lindex $argv 1]=="-msvc")} {
376 set bMsvc
[expr ([llength $argv]==3)]
377 set config
[lindex $argv [expr [llength $argv]-1]]
379 puts [trd_buildscript
$config [file dirname
$testdir] $bMsvc]
384 #--------------------------------------------------------------------------
385 # Check if this is the "status" command:
387 if {[llength $argv]==1
388 && [string compare
-nocase status
[lindex $argv 0]]==0
391 proc display_job
{jobdict
{tm
""}} {
392 array set job
$jobdict
394 set dfname
[format %-60s $job(displayname
)]
397 if {$tm!=""} { set dtm
"\[[expr {$tm-$job(starttime)}]ms\]" }
401 sqlite3 mydb
$TRG(dbname
)
405 set cmdline
[mydb one
{ SELECT value FROM config WHERE name
='cmdline'
}]
406 set nJob
[mydb one
{ SELECT value FROM config WHERE name
='njob'
}]
408 set now
[clock_milliseconds
]
411 COALESCE
((SELECT value FROM config WHERE name
='end'
), $now) -
412 (SELECT value FROM config WHERE name
='start'
)
416 foreach s
{"" ready running done failed
} { set S
($s) 0 }
418 SELECT state
, count
(*) AS cnt FROM jobs GROUP BY
1
423 set fin
[expr $S(done
)+$S(failed
)]
424 if {$cmdline!=""} {set cmdline
" $cmdline"}
428 set f
"$S(failed) FAILED, "
430 puts "Command line: \[testrunner.tcl$cmdline\]"
432 puts "Summary: ${tm}ms, ($fin/$total) finished, ${f}$S(running) running"
434 set srcdir
[file dirname
[file dirname
$TRG(info_script
)]]
438 SELECT
* FROM jobs WHERE state
='running' ORDER BY starttime
440 display_job
[array get job
] $now
446 SELECT
* FROM jobs WHERE state
='failed' ORDER BY starttime
448 display_job
[array get job
]
456 #-------------------------------------------------------------------------
457 # Parse the command line.
459 for {set ii
0} {$ii < [llength $argv]} {incr ii
} {
460 set isLast
[expr $ii==([llength $argv]-1)]
461 set a
[lindex $argv $ii]
462 set n
[string length
$a]
464 if {[string range
$a 0 0]=="-"} {
465 if {($n>2 && [string match
"$a*" --jobs]) ||
$a=="-j"} {
467 set TRG
(nJob
) [lindex $argv $ii]
468 if {$isLast} { usage
}
469 } elseif
{($n>2 && [string match
"$a*" --zipvfs]) ||
$a=="-z"} {
471 set TRG
(zipvfs
) [file normalize
[lindex $argv $ii]]
472 if {$isLast} { usage
}
473 } elseif
{($n>2 && [string match
"$a*" --buildonly]) ||
$a=="-b"} {
475 } elseif
{($n>2 && [string match
"$a*" --config]) ||
$a=="-c"} {
477 set TRG
(config
) [lindex $argv $ii]
478 } elseif
{($n>2 && [string match
"$a*" --dryrun]) ||
$a=="-d"} {
480 } elseif
{($n>2 && [string match
"$a*" --explain]) ||
$a=="-e"} {
482 } elseif
{($n>2 && [string match
"$a*" --omit]) ||
$a=="-c"} {
484 set TRG
(omitconfig
) [lindex $argv $ii]
485 } elseif
{[string match
"$a*" --stop-on
-error
]} {
486 set TRG
(stopOnError
) 1
487 } elseif
{[string match
"$a*" --stop-on
-coredump
]} {
488 set TRG
(stopOnCore
) 1
493 lappend TRG
(patternlist
) [string map
{% *} $a]
498 # This script runs individual tests - tcl scripts or [make xyz] commands -
499 # in directories named "testdir$N", where $N is an integer. This variable
500 # contains a list of integers indicating the directories in use.
502 # This variable is accessed only via the following commands:
505 # Return the number of entries currently in the list.
508 # Remove value IDIR from the list. It is an error if it is not present.
511 # Select a value that is not already in the list. Add it to the list
514 set TRG
(dirs_in_use
) [list]
516 proc dirs_nHelper
{} {
518 llength $TRG(dirs_in_use
)
520 proc dirs_freeDir
{iDir
} {
523 foreach d
$TRG(dirs_in_use
) {
524 if {$iDir!=$d} { lappend out
$d }
526 if {[llength $out]!=[llength $TRG(dirs_in_use
)]-1} {
527 error "dirs_freeDir could not find $iDir"
529 set TRG
(dirs_in_use
) $out
531 proc dirs_allocDir
{} {
533 array set inuse
[list]
534 foreach d
$TRG(dirs_in_use
) {
537 for {set iRet
0} {[info exists inuse
($iRet)]} {incr iRet
} { }
538 lappend TRG
(dirs_in_use
) $iRet
542 # Check that directory $dir exists. If it does not, create it. If
543 # it does, delete its contents.
545 proc create_or_clear_dir
{dir
} {
546 set dir
[file normalize
$dir]
547 catch { file mkdir
$dir }
548 foreach f
[glob -nocomplain [file join $dir *]] {
549 catch { file delete
-force $f }
553 proc build_to_dirname
{bname
} {
554 set fold
[string tolower
[string map
{- _
} $bname]]
555 return "testrunner_build_$fold"
558 #-------------------------------------------------------------------------
560 proc r_write_db
{tcl
} {
561 trdb
eval { BEGIN EXCLUSIVE
}
566 # Obtain a new job to be run by worker $iJob (an integer). A job is
567 # returned as a three element list:
569 # {$build $config $file}
571 proc r_get_next_job
{iJob
} {
575 set orderby
"ORDER BY priority ASC"
577 set orderby
"ORDER BY priority DESC"
584 SELECT * FROM jobs AS j WHERE state='ready' $orderby LIMIT 1
586 trdb
eval $query job
{
587 set tm
[clock_milliseconds
]
589 set jobid
$job(jobid
)
592 UPDATE jobs SET starttime
=$tm, state
='running' WHERE jobid
=$jobid
595 set ret
[array get job
]
602 #rename r_get_next_job r_get_next_job_r
603 #proc r_get_next_job {iJob} {
604 #puts [time { set res [r_get_next_job_r $iJob] }]
610 # add_job OPTION ARG OPTION ARG...
612 # where available OPTIONS are:
622 # Returns the jobid value for the new job.
624 proc add_job
{args
} {
627 -displaytype -displayname -build -dirname
628 -cmd -depid -priority
631 # Set default values of options.
639 # Check all required options are present. And that no extras are present.
641 if {[info exists A
($o)]==0} { error "missing required option $o" }
643 foreach o
[array names A
] {
644 if {[lsearch -exact $options $o]<0} { error "unrecognized option: $o" }
648 if {$A(-depid)==""} { set state ready
}
652 displaytype
, displayname
, build
, dirname
, cmd
, depid
, priority
,
666 trdb last_insert_rowid
669 # Argument $build is either an empty string, or else a list of length 3
670 # describing the job to build testfixture. In the usual form:
672 # {ID DIRNAME DISPLAYNAME}
676 # {1 /home/user/sqlite/test/testrunner_bld_xyz All-Debug}
678 proc add_tcl_jobs
{build config patternlist
{shelldepid
""}} {
681 set topdir
[file dirname
$::testdir]
682 set testrunner_tcl
[file normalize
[info script
]]
685 set testfixture
[info nameofexec
]
687 set testfixture
[file join [lindex $build 1] $TRG(testfixture
)]
689 if {[lindex $build 2]=="Valgrind"} {
690 set setvar
"export OMIT_MISUSE=1\n"
691 set testfixture
"${setvar}valgrind -v --error-exitcode=1 $testfixture"
694 # The ::testspec array is populated by permutations.test
695 foreach f
[dict get
$::testspec($config) -files] {
697 if {[llength $patternlist]>0} {
699 foreach p
$patternlist {
700 if {[string match
$p [file tail
$f]]} {
705 if {$bMatch==0} continue
708 if {[file pathtype
$f]!="absolute"} { set f
[file join $::testdir $f] }
709 set f
[file normalize
$f]
711 set displayname
[string map
[list $topdir/ {}] $f]
712 if {$config=="full" ||
$config=="veryquick"} {
713 set cmd
"$testfixture $f"
715 set cmd
"$testfixture $testrunner_tcl $config $f"
716 set displayname
"config=$config $displayname"
719 set displayname
"[lindex $build 2] $displayname"
722 set lProp
[trd_test_script_properties
$f]
724 if {[lsearch $lProp slow
]>=0} { set priority
2 }
725 if {[lsearch $lProp superslow
]>=0} { set priority
4 }
727 set depid
[lindex $build 0]
728 if {$shelldepid!="" && [lsearch $lProp shell
]>=0} { set depid
$shelldepid }
732 -displayname $displayname \
739 proc add_build_job
{buildname target
{postcmd
""} {depid
""}} {
742 set dirname
"[string tolower [string map {- _} $buildname]]_$target"
743 set dirname
"testrunner_bld_$dirname"
745 set cmd
"$TRG(makecmd) $target"
753 -displayname "Build $buildname ($target)" \
761 list $id [file normalize
$dirname] $buildname
764 proc add_shell_build_job
{buildname dirname depid
} {
767 if {$TRG(platform
)=="win"} {
768 set path
[string map
{/ \\} "$dirname/"]
769 set copycmd
"xcopy $TRG(shell) $path"
771 set copycmd
"cp $TRG(shell) $dirname/"
775 add_build_job
$buildname $TRG(shell
) $copycmd $depid
780 proc add_make_job
{bld target
} {
783 if {$TRG(platform
)=="win"} {
784 set path
[string map
{/ \\} [lindex $bld 1]]
785 set cmd
"xcopy /S $path\\* ."
787 set cmd
"cp -r [lindex $bld 1]/* ."
789 append cmd
"\n$TRG(makecmd) $target"
793 -displayname "[lindex $bld 2] make $target" \
795 -depid [lindex $bld 0] \
799 proc add_fuzztest_jobs
{buildname
} {
801 foreach {interpreter scripts
} [trd_fuzztest_data
] {
802 set subcmd
[lrange $interpreter 1 end
]
803 set interpreter
[lindex $interpreter 0]
805 set bld
[add_build_job
$buildname $interpreter]
806 foreach {depid dirname displayname
} $bld {}
810 # Fuzz data files fuzzdata1.db and fuzzdata2.db are larger than
811 # the others. So ensure that these are run as a higher priority.
812 set tail
[file tail
$s]
813 if {$tail=="fuzzdata1.db" ||
$tail=="fuzzdata2.db"} {
821 -displayname "$buildname $interpreter $tail" \
823 -cmd "[file join $dirname $interpreter] $subcmd $s" \
829 proc add_zipvfs_jobs
{} {
831 source [file join $TRG(zipvfs
) test zipvfs_testrunner.tcl
]
833 set bld
[add_build_job Zipvfs
$TRG(testfixture
)]
834 foreach s
[zipvfs_testrunner_files
] {
835 set cmd
"[file join [lindex $bld 1] $TRG(testfixture)] $s"
838 -displayname "Zipvfs [file tail $s]" \
840 -depid [lindex $bld 0]
843 set ::env(SQLITE_TEST_DIR
) $::testdir
846 # Used to add jobs for "mdevtest" and "sdevtest".
848 proc add_devtest_jobs
{lBld patternlist
} {
852 set bld
[add_build_job
$b $TRG(testfixture
)]
853 add_tcl_jobs
$bld veryquick
$patternlist SHELL
854 if {$patternlist==""} {
858 if {[trdb one
"SELECT EXISTS (SELECT 1 FROM jobs WHERE depid='SHELL')"]} {
859 set sbld
[add_shell_build_job
$b [lindex $bld 1] [lindex $bld 0]]
860 set sbldid
[lindex $sbld 0]
862 UPDATE jobs SET depid
=$sbldid WHERE depid
='SHELL'
869 # Check to ensure that the interpreter is a full-blown "testfixture"
870 # build and not just a "tclsh". If this is not the case, issue an
871 # error message and exit.
873 proc must_be_testfixture
{} {
874 if {[lsearch [info commands
] sqlite3_soft_heap_limit
]<0} {
875 puts "Use testfixture, not tclsh, for these arguments."
880 proc add_jobs_from_cmdline
{patternlist
} {
883 if {$TRG(zipvfs
)!=""} {
885 if {[llength $patternlist]==0} return
888 if {[llength $patternlist]==0} {
889 set patternlist
[list veryquick
]
892 set first
[lindex $patternlist 0]
896 set patternlist
[lrange $patternlist 1 end
]
897 set clist
[trd_all_configs
]
899 add_tcl_jobs
"" $c $patternlist
908 add_devtest_jobs
$config_set [lrange $patternlist 1 end
]
916 add_devtest_jobs
$config_set [lrange $patternlist 1 end
]
920 set patternlist
[lrange $patternlist 1 end
]
921 foreach b
[trd_builds
$TRG(platform
)] {
922 if {$TRG(config
)!="" && ![regexp "\\y$b\\y" $TRG(config
)]} continue
923 if {[regexp "\\y$b\\y" $TRG(omitconfig
)]} continue
924 set bld
[add_build_job
$b $TRG(testfixture
)]
925 foreach c
[trd_configs
$TRG(platform
) $b] {
926 add_tcl_jobs
$bld $c $patternlist
929 if {$patternlist==""} {
930 foreach e
[trd_extras
$TRG(platform
) $b] {
931 if {$e=="fuzztest"} {
942 set allperm
[array names
::testspec]
943 lappend allperm all mdevtest sdevtest release
list
944 puts "Allowed values for the PERMUTATION argument: [lsort $allperm]"
950 if {[info exists
::testspec($first)]} {
951 add_tcl_jobs
"" $first [lrange $patternlist 1 end
]
953 add_tcl_jobs
"" full
$patternlist
959 proc make_new_testset
{} {
963 trdb
eval $TRG(schema
)
965 set cmdline
$TRG(cmdline
)
966 set tm
[clock_milliseconds
]
967 trdb
eval { REPLACE INTO config VALUES
('njob'
, $nJob ); }
968 trdb
eval { REPLACE INTO config VALUES
('cmdline'
, $cmdline ); }
969 trdb
eval { REPLACE INTO config VALUES
('start'
, $tm ); }
971 add_jobs_from_cmdline
$TRG(patternlist
)
976 proc mark_job_as_finished
{jobid output state endtm
} {
980 SET output
=$output, state
=$state, endtime
=$endtm
982 UPDATE jobs SET state
='ready' WHERE depid
=$jobid;
987 proc script_input_ready
{fd iJob jobid
} {
993 trdb
eval { SELECT
* FROM jobs WHERE jobid
=$jobid } job
{}
995 # If this job specified a directory name, then delete the run.sh/run.bat
996 # file from it before continuing. This is because the contents of this
997 # directory might be copied by some other job, and we don't want to copy
998 # the run.sh file in this case.
999 if {$job(dirname
)!=""} {
1000 file delete
-force [file join $job(dirname
) $TRG(run
)]
1004 fconfigure $fd -blocking 1
1006 set rc
[catch { close $fd } msg
]
1008 if {[info exists TRG
(reportlength
)]} {
1009 puts -nonewline "[string repeat " " $TRG(reportlength)]\r"
1011 puts "FAILED: $job(displayname) ($iJob)"
1013 if {$TRG(stopOnError
)} {
1014 puts "OUTPUT: $O($iJob)"
1017 if {$TRG(stopOnCore
) && [string first
{core dumped
} $O($iJob)]>0} {
1018 puts "OUTPUT: $O($iJob)"
1023 set tm
[clock_milliseconds
]
1024 set jobtm
[expr {$tm - $job(starttime
)}]
1026 puts $TRG(log
) "### $job(displayname) ${jobtm}ms ($state)"
1027 puts $TRG(log
) [string trim
$O($iJob)]
1029 mark_job_as_finished
$jobid $O($iJob) $state $tm
1035 set rc
[catch { gets $fd line
} res
]
1040 append O
($iJob) "$line\n"
1050 proc launch_another_job
{iJob
} {
1055 set testfixture
[info nameofexec
]
1056 set script
$TRG(info_script
)
1060 set jobdict
[r_get_next_job
$iJob]
1061 if {$jobdict==""} { return 0 }
1062 array set job
$jobdict
1064 set dir
$job(dirname
)
1065 if {$dir==""} { set dir
[dirname
$iJob] }
1066 create_or_clear_dir
$dir
1068 if {$job(build
)!=""} {
1069 set srcdir
[file dirname
$::testdir]
1070 if {$job(build
)=="Zipvfs"} {
1071 set script
[zipvfs_testrunner_script
]
1073 set bWin
[expr {$TRG(platform
)=="win"}]
1074 set script
[trd_buildscript
$job(build
) $srcdir $bWin]
1076 set fd
[open [file join $dir $TRG(make
)] w
]
1081 # Add a batch/shell file command to set the directory used for temp
1082 # files to the test's working directory. Otherwise, tests that use
1083 # large numbers of temp files (e.g. zipvfs), might generate temp
1084 # filename collisions.
1085 if {$TRG(platform
)=="win"} {
1086 set set_tmp_dir
"SET SQLITE_TMPDIR=[file normalize $dir]"
1088 set set_tmp_dir
"export SQLITE_TMPDIR=\"[file normalize $dir]\""
1091 if { $TRG(dryrun
) } {
1093 mark_job_as_finished
$job(jobid
) "" done
0
1095 if {$job(build
)!=""} {
1096 puts $TRG(log
) "(cd $dir ; $job(cmd) )"
1098 puts $TRG(log
) "$job(cmd)"
1104 set fd
[open $TRG(run
) w
]
1105 puts $fd $set_tmp_dir
1108 set fd
[open "|$TRG(runcmd) 2>@1" r
]
1111 fconfigure $fd -blocking false
1112 fileevent $fd readable
[list script_input_ready
$fd $iJob $job(jobid
)]
1118 proc one_line_report
{} {
1121 set tm
[expr [clock_milliseconds
] - $TRG(starttime
)]
1122 set tm
[format "%d" [expr int
($tm/1000.0 + 0.5)]]
1126 SELECT displaytype
, state
, count
(*) AS cnt
1130 set v
($state,$displaytype) $cnt
1131 incr t
($displaytype) $cnt
1136 foreach j
[lsort [array names t
]] {
1137 foreach k
{done failed running
} { incr v
($k,$j) 0 }
1138 set fin
[expr $v(done
,$j) + $v(failed
,$j)]
1139 lappend text "${j}($fin/$t($j))"
1140 if {$v(failed
,$j)>0} {
1141 lappend text "f$v(failed,$j)"
1143 if {$v(running
,$j)>0} {
1144 lappend text "r$v(running,$j)"
1148 if {[info exists TRG
(reportlength
)]} {
1149 puts -nonewline "[string repeat " " $TRG(reportlength)]\r"
1151 set report
"${tm} [join $text { }]"
1152 set TRG
(reportlength
) [string length
$report]
1153 if {[string length
$report]<100} {
1154 puts -nonewline "$report\r"
1160 after $TRG(reporttime
) one_line_report
1163 proc launch_some_jobs
{} {
1165 set nJob
[trdb one
{ SELECT value FROM config WHERE name
='njob'
}]
1167 while {[dirs_nHelper
]<$nJob} {
1168 set iDir
[dirs_allocDir
]
1169 if {0==[launch_another_job
$iDir]} {
1176 proc run_testset
{} {
1180 set TRG
(starttime
) [clock_milliseconds
]
1181 set TRG
(log
) [open $TRG(logname
) w
]
1186 while {[dirs_nHelper
]>0} {
1187 after 500 {incr ::wakeup}
1194 set tm
[clock_milliseconds
]
1195 trdb
eval { REPLACE INTO config VALUES
('end'
, $tm ); }
1196 set nErr
[trdb one
{SELECT count
(*) FROM jobs WHERE state
='failed'
}]
1198 puts "$nErr failures:"
1200 SELECT displayname FROM jobs WHERE state
='failed'
1202 puts "FAILED: $displayname"
1207 puts "\nTest database is $TRG(dbname)"
1208 puts "Test log is $TRG(logname)"
1211 # Handle the --buildonly option, if it was specified.
1213 proc handle_buildonly
{} {
1215 if {$TRG(buildonly
)} {
1217 trdb
eval { DELETE FROM jobs WHERE displaytype
!='bld'
}
1222 # Handle the --explain option. Provide a human-readable
1223 # explanation of all the tests that are in the trdb database jobs
1226 proc explain_layer
{indent depid
} {
1228 if {$TRG(buildonly
)} {
1233 trdb
eval {SELECT jobid
, displayname
, displaytype
, dirname
1234 FROM jobs WHERE depid
=$depid ORDER BY displayname
} {
1235 if {$displaytype=="bld"} {
1236 puts "${indent}$displayname in $dirname"
1237 explain_layer
"${indent} " $jobid
1238 } elseif
{$showtests} {
1239 puts "${indent}[lindex $displayname end]"
1243 proc explain_tests
{} {
1247 sqlite3 trdb
$TRG(dbname
)
1248 trdb timeout
$TRG(timeout
)
1249 set tm
[lindex [time { make_new_testset
}] 0]
1250 if {$TRG(explain
)} {
1254 puts "splitting work across $TRG(nJob) jobs"
1256 puts "built testset in [expr $tm/1000]ms.."