blob: da4efde267ee9854a66d447a755344b3ee1b90ee [file] [log] [blame]
dan05058512022-07-12 20:31:16 +00001
dan05058512022-07-12 20:31:16 +00002#-------------------------------------------------------------------------
3# Usage:
4#
5proc usage {} {
dan2bb2d532022-07-13 21:02:07 +00006 set a0 testrunner.tcl
7
danca0720a2022-07-14 18:09:56 +00008 set ::argv [list]
9 uplevel [list source $::testdir/permutations.test]
10
11 puts stderr "Usage: $a0 ?SWITCHES? ?PERMUTATION? ?PATTERNS?"
dan05058512022-07-12 20:31:16 +000012 puts stderr ""
13 puts stderr "where SWITCHES are:"
14 puts stderr " --jobs NUMBER-OF-JOBS"
dan2bb2d532022-07-13 21:02:07 +000015 puts stderr ""
danca0720a2022-07-14 18:09:56 +000016 puts stderr "available PERMUTATION values are:"
17 set ii 0
18 foreach name [lsort [array names ::testspec]] {
19 if {($ii % 3)==0} { puts -nonewline stderr " " }
20 puts -nonewline stderr [format "% -22s" $name]
21 if {($ii % 3)==2} { puts stderr "" }
22 incr ii
23 }
24 puts stderr ""
25 puts stderr ""
dan2bb2d532022-07-13 21:02:07 +000026 puts stderr "Examples:"
danca0720a2022-07-14 18:09:56 +000027 puts stderr " 1) Run the veryquick tests:"
28 puts stderr " $a0"
29 puts stderr " 2) Run all test scripts in the source tree:"
30 puts stderr " $a0 full"
31 puts stderr " 2) Run the 'memsubsys1' permutation:"
32 puts stderr " $a0 memsubsys1"
33 puts stderr " 3) Run all permutations usually run by \[make fulltest\]"
34 puts stderr " $a0 release"
35 puts stderr " 4) Run all scripts that match the pattern 'select%':"
36 puts stderr " $a0 select%"
37 puts stderr " $a0 all select%"
38 puts stderr " $a0 full select%"
39 puts stderr " 5) Run all scripts that are part of the veryquick permutation and match the pattern 'select%':"
40 puts stderr " $a0 veryquick select%"
41 puts stderr " 6) Run the 'memsubsys1' permutation, but just those scripts that match 'window%':"
42 puts stderr " $a0 memsubsys1 window%"
43 puts stderr " 7) Run all the permutations, but only the scripts that match either 'fts5%' or 'rtree%':"
44 puts stderr " $a0 release fts5% rtree%"
dan2bb2d532022-07-13 21:02:07 +000045
dan05058512022-07-12 20:31:16 +000046 exit 1
47}
48#-------------------------------------------------------------------------
49
dane9a7ebe2022-07-13 17:46:42 +000050#-------------------------------------------------------------------------
51# The database schema used by the testrunner.db database.
52#
53set R(schema) {
54 DROP TABLE IF EXISTS script;
55 DROP TABLE IF EXISTS msg;
56 DROP TABLE IF EXISTS malloc;
dan05058512022-07-12 20:31:16 +000057
dane9a7ebe2022-07-13 17:46:42 +000058 CREATE TABLE script(
danca0720a2022-07-14 18:09:56 +000059 config TEXT,
60 filename TEXT, -- full path to test script
dancf2ad7a2022-07-18 19:32:30 +000061 slow BOOLEAN, -- true if script is "slow"
dane9a7ebe2022-07-13 17:46:42 +000062 state TEXT CHECK( state IN ('ready', 'running', 'done') ),
63 testfixtureid, -- Id of process that ran script
64 time INTEGER, -- Time in ms
65 nerr INTEGER, -- if 'done', the number of errors
66 ntest INTEGER, -- if 'done', the number of tests
danca0720a2022-07-14 18:09:56 +000067 output TEXT, -- full output of test script
68 PRIMARY KEY(config, filename)
dane9a7ebe2022-07-13 17:46:42 +000069 );
70
71 CREATE TABLE malloc(
72 id INTEGER PRIMARY KEY,
73 nmalloc INTEGER,
74 nbyte INTEGER,
75 leaker TEXT
76 );
77
78 CREATE TABLE msg(
79 id INTEGER PRIMARY KEY,
80 msg TEXT
81 );
82}
83#-------------------------------------------------------------------------
84
85#-------------------------------------------------------------------------
86# Try to estimate a the number of processes to use.
87#
88# Command [guess_number_of_cores] attempts to glean the number of logical
89# cores. Command [default_njob] returns the default value for the --jobs
90# switch.
91#
92proc guess_number_of_cores {} {
93 set ret 4
dan615aece2022-07-13 21:28:19 +000094
95 if {$::tcl_platform(os)=="Darwin"} {
96 set cmd "sysctl -n hw.logicalcpu"
97 } else {
98 set cmd "nproc"
99 }
dane9a7ebe2022-07-13 17:46:42 +0000100 catch {
dan615aece2022-07-13 21:28:19 +0000101 set fd [open "|$cmd" r]
dane9a7ebe2022-07-13 17:46:42 +0000102 set ret [gets $fd]
103 close $fd
104 set ret [expr $ret]
105 }
106 return $ret
107}
108
109proc default_njob {} {
110 set nCore [guess_number_of_cores]
111 set nHelper [expr int($nCore*0.75)]
112 expr $nHelper>0 ? $nHelper : 1
113}
114#-------------------------------------------------------------------------
115
116
dane9a7ebe2022-07-13 17:46:42 +0000117set R(dbname) [file normalize testrunner.db]
118set R(logname) [file normalize testrunner.log]
119set R(info_script) [file normalize [info script]]
120set R(timeout) 10000 ;# Default busy-timeout for testrunner.
121set R(nJob) [default_njob] ;# Default number of helper processes
122set R(leaker) "" ;# Name of first script to leak memory
123
dan95cc6a52022-07-13 19:57:35 +0000124set R(patternlist) [list]
125
126set testdir [file dirname $argv0]
dane9a7ebe2022-07-13 17:46:42 +0000127
128# Parse the command line options. There are two ways to invoke this
129# script - to create a helper or coordinator process. If there are
130# no helper processes, the coordinator runs test scripts.
131#
132# To create a helper process:
133#
134# testrunner.tcl helper ID
135#
136# where ID is an integer greater than 0. The process will create and
137# run tests in the "testdir$ID" directory. Helper processes are only
138# created by coordinators - there is no need for a user to create
139# helper processes manually.
140#
141# If the first argument is anything other than "helper", then a coordinator
142# process is started. See the implementation of the [usage] proc above for
143# details.
144#
dan05058512022-07-12 20:31:16 +0000145switch -- [lindex $argv 0] {
146 helper {
147 set R(helper) 1
148 set R(helper_id) [lindex $argv 1]
149 set argv [list --testdir=testdir$R(helper_id)]
150 }
151
152 default {
153 set R(helper) 0
154 set R(helper_id) 0
dane9a7ebe2022-07-13 17:46:42 +0000155
dan05058512022-07-12 20:31:16 +0000156 }
157}
dan05058512022-07-12 20:31:16 +0000158if {$R(helper)==0} {
159 for {set ii 0} {$ii < [llength $argv]} {incr ii} {
160 set a [lindex $argv $ii]
161 set n [string length $a]
162
dan95cc6a52022-07-13 19:57:35 +0000163 if {[string range $a 0 0]=="-"} {
164 if {($n>2 && [string match "$a*" --jobs]) || $a=="-j"} {
165 incr ii
166 set R(nJob) [lindex $argv $ii]
167 } else {
168 usage
169 }
dan05058512022-07-12 20:31:16 +0000170 } else {
danca0720a2022-07-14 18:09:56 +0000171 lappend R(patternlist) [string map {% *} $a]
dan05058512022-07-12 20:31:16 +0000172 }
173 }
174
175 set argv [list]
176}
danca0720a2022-07-14 18:09:56 +0000177source $testdir/permutations.test
dan05058512022-07-12 20:31:16 +0000178
danca0720a2022-07-14 18:09:56 +0000179#-------------------------------------------------------------------------
180# Return a list of tests to run. Each element of the list is itself a
181# list of two elements - the name of a permuations.test configuration
182# followed by the full path to a test script. i.e.:
183#
184# {CONFIG FILENAME} {CONFIG FILENAME} ...
185#
186proc testset_patternlist {patternlist} {
187
188 set first [lindex $patternlist 0]
189 if {$first=="all"} { set first "full" }
190
191 if {$first=="release"} {
192
193 # The following mirrors the set of test suites invoked by "all.test".
194 #
195 set clist {
196 full
197 no_optimization memsubsys1 memsubsys2 singlethread
198 multithread onefile utf16 exclusive persistent_journal
199 persistent_journal_error no_journal no_journal_error
200 autovacuum_ioerr no_mutex_try fullmutex journaltest
201 inmemory_journal pcache0 pcache10 pcache50 pcache90
202 pcache100 prepare mmap
203 }
204 ifcapable rbu { lappend clist rbu }
205 if {$::tcl_platform(platform)=="unix"} {
206 ifcapable !default_autovacuum {
207 lappend clist autovacuum_crash
208 }
209 }
210 set patternlist [lrange $patternlist 1 end]
211
212 } elseif {[info exists ::testspec($first)]} {
213 set clist $first
214 set patternlist [lrange $patternlist 1 end]
215 } elseif { [llength $patternlist]==0 } {
216 set clist veryquick
217 } else {
218 set clist full
219 }
220
221 set testset [list]
222
223 foreach config $clist {
224 catch { array unset O }
225 array set O $::testspec($config)
226 foreach f $O(-files) {
227 if {[file pathtype $f]!="absolute"} {
228 set f [file join $::testdir $f]
229 }
230 lappend testset [list $config [file normalize $f]]
231 }
232 }
233
234 if {[llength $patternlist]>0} {
235 foreach t $testset {
236 set tail [file tail [lindex $t 1]]
237 foreach p $patternlist {
238 if {[string match $p $tail]} {
239 lappend ret $t
240 break;
241 }
242 }
243 }
244 } else {
245 set ret $testset
246 }
247
248 set ret
249}
250#--------------------------------------------------------------------------
dan05058512022-07-12 20:31:16 +0000251
dan05058512022-07-12 20:31:16 +0000252
dan05058512022-07-12 20:31:16 +0000253proc r_write_db {tcl} {
254 global R
dande353fb2022-07-14 21:17:22 +0000255
256 sqlite3_test_control_pending_byte 0x010000
dan05058512022-07-12 20:31:16 +0000257 sqlite3 db $R(dbname)
258 db timeout $R(timeout)
259 db eval { BEGIN EXCLUSIVE }
dane9a7ebe2022-07-13 17:46:42 +0000260
dan05058512022-07-12 20:31:16 +0000261 uplevel $tcl
dane9a7ebe2022-07-13 17:46:42 +0000262
dan05058512022-07-12 20:31:16 +0000263 db eval { COMMIT }
264 db close
265}
266
dane9a7ebe2022-07-13 17:46:42 +0000267proc make_new_testset {} {
dan05058512022-07-12 20:31:16 +0000268 global R
dane9a7ebe2022-07-13 17:46:42 +0000269
danca0720a2022-07-14 18:09:56 +0000270 set tests [testset_patternlist $R(patternlist)]
dane9a7ebe2022-07-13 17:46:42 +0000271 r_write_db {
272 db eval $R(schema)
danca0720a2022-07-14 18:09:56 +0000273 foreach t $tests {
274 foreach {c s} $t {}
dancf2ad7a2022-07-18 19:32:30 +0000275 set slow 0
276
277 set fd [open $s]
278 for {set ii 0} {$ii<100 && ![eof $fd]} {incr ii} {
279 set line [gets $fd]
280 if {[string match -nocase *testrunner:* $line]} {
281 regexp -nocase {.*testrunner:(.*)} $line -> properties
282 foreach p $properties {
283 if {$p=="slow"} { set slow 1 }
284 }
285 }
286 }
287 close $fd
288
danca0720a2022-07-14 18:09:56 +0000289 db eval {
dancf2ad7a2022-07-18 19:32:30 +0000290 INSERT INTO script(config, filename, slow, state)
291 VALUES ($c, $s, $slow, 'ready')
danca0720a2022-07-14 18:09:56 +0000292 }
dane9a7ebe2022-07-13 17:46:42 +0000293 }
294 }
295}
296
danca0720a2022-07-14 18:09:56 +0000297# Find the next job in the database and mark it as 'running'. Then return
298# a list consisting of the
299#
300# CONFIG FILENAME
301#
302# pair for the test.
303#
dane9a7ebe2022-07-13 17:46:42 +0000304proc get_next_test {} {
305 global R
306 set myid $R(helper_id)
307
308 r_write_db {
danca0720a2022-07-14 18:09:56 +0000309 set f ""
310 set c ""
311 db eval {
312 SELECT config, filename FROM script WHERE state='ready'
dancf2ad7a2022-07-18 19:32:30 +0000313 ORDER BY
314 (slow * (($myid+1) % 2)) DESC,
315 config!='full',
316 config,
317 filename
318 LIMIT 1
danca0720a2022-07-14 18:09:56 +0000319 } {
320 set c $config
321 set f $filename
322 }
dane9a7ebe2022-07-13 17:46:42 +0000323 if {$f!=""} {
324 db eval {
danca0720a2022-07-14 18:09:56 +0000325 UPDATE script SET state='running', testfixtureid=$myid
326 WHERE (config, filename) = ($c, $f)
dane9a7ebe2022-07-13 17:46:42 +0000327 }
328 }
329 }
330
danca0720a2022-07-14 18:09:56 +0000331 if {$f==""} { return "" }
332 list $c $f
dan05058512022-07-12 20:31:16 +0000333}
334
danca0720a2022-07-14 18:09:56 +0000335proc r_testname {config filename} {
336 set name [file tail $filename]
337 if {$config!="" && $config!="full" && $config!="veryquick"} {
338 set name "$config-$name"
339 }
340 return $name
341}
342
343proc r_set_test_result {config filename ms nerr ntest output} {
dan05058512022-07-12 20:31:16 +0000344 global R
345
danca0720a2022-07-14 18:09:56 +0000346 set f [r_testname $config $filename]
dan05058512022-07-12 20:31:16 +0000347 if {$nerr==0} {
348 set msg "$f... Ok"
349 } else {
350 set msg "$f... FAILED - $nerr errors of $ntest tests"
351 }
352 append msg " (${ms}ms)"
353 if {$R(helper)} {
354 append msg " (helper $R(helper_id))"
355 }
356
dane9a7ebe2022-07-13 17:46:42 +0000357 sqlite3_shutdown
358 set nMalloc [lindex [sqlite3_status SQLITE_STATUS_MALLOC_COUNT 0] 1]
359 set nByte [sqlite3_memory_used]
360 if {($nByte>0 || $nMalloc>0) && $R(leaker)==""} {
danca0720a2022-07-14 18:09:56 +0000361 set R(leaker) $f
dane9a7ebe2022-07-13 17:46:42 +0000362 }
363
dan05058512022-07-12 20:31:16 +0000364 r_write_db {
365 db eval {
366 UPDATE script
dane9a7ebe2022-07-13 17:46:42 +0000367 SET state='done', output=$output, nerr=$nerr, ntest=$ntest, time=$ms
danca0720a2022-07-14 18:09:56 +0000368 WHERE (config, filename)=($config, $filename);
dan05058512022-07-12 20:31:16 +0000369
370 INSERT INTO msg(msg) VALUES ($msg);
371 }
372 }
373}
374
375set R(iNextMsg) 1
376proc r_get_messages {{db ""}} {
377 global R
378
dande353fb2022-07-14 21:17:22 +0000379 sqlite3_test_control_pending_byte 0x010000
380
dan05058512022-07-12 20:31:16 +0000381 if {$db==""} {
382 sqlite3 rgmhandle $R(dbname)
383 set dbhandle rgmhandle
384 $dbhandle timeout $R(timeout)
385 } else {
386 set dbhandle $db
387 }
388
389 $dbhandle transaction {
390 set next $R(iNextMsg)
391 set ret [$dbhandle eval {SELECT msg FROM msg WHERE id>=$next}]
392 set R(iNextMsg) [$dbhandle one {SELECT COALESCE(max(id), 0)+1 FROM msg}]
393 }
394
395 if {$db==""} {
396 rgmhandle close
397 }
398
399 set ret
400}
401
dane9a7ebe2022-07-13 17:46:42 +0000402# This is called after all tests have been run to write the leaked memory
403# report into the malloc table of testrunner.db.
404#
405proc r_memory_report {} {
406 global R
407
408 sqlite3_shutdown
409
410 set nMalloc [lindex [sqlite3_status SQLITE_STATUS_MALLOC_COUNT 0] 1]
411 set nByte [sqlite3_memory_used]
412 set id $R(helper_id)
413 set leaker $R(leaker)
414
415 r_write_db {
416 db eval {
417 INSERT INTO malloc(id, nMalloc, nByte, leaker)
418 VALUES($id, $nMalloc, $nByte, $leaker)
419 }
420 }
421}
422
423
dan05058512022-07-12 20:31:16 +0000424#--------------------------------------------------------------------------
425#
dan05058512022-07-12 20:31:16 +0000426set ::R_INSTALL_PUTS_WRAPPER {
427 proc puts_sts_wrapper {args} {
428 set n [llength $args]
429 if {$n==1 || ($n==2 && [string first [lindex $args 0] -nonewline]==0)} {
430 uplevel puts_into_caller $args
431 } else {
432 # A channel was explicitly specified.
433 uplevel puts_sts_original $args
434 }
435 }
436 rename puts puts_sts_original
437 proc puts {args} { uplevel puts_sts_wrapper $args }
438}
439
440proc r_install_puts_wrapper {} $::R_INSTALL_PUTS_WRAPPER
441proc r_uninstall_puts_wrapper {} {
442 rename puts ""
443 rename puts_sts_original puts
444}
445
446proc slave_test_script {script} {
447
448 # Create the interpreter used to run the test script.
449 interp create tinterp
450
451 # Populate some global variables that tester.tcl expects to see.
452 foreach {var value} [list \
453 ::argv0 $::argv0 \
454 ::argv {} \
455 ::SLAVE 1 \
456 ] {
457 interp eval tinterp [list set $var $value]
458 }
459
460 # The alias used to access the global test counters.
461 tinterp alias set_test_counter set_test_counter
462
463 # Set up an empty ::cmdlinearg array in the slave.
464 interp eval tinterp [list array set ::cmdlinearg [array get ::cmdlinearg]]
465
466 # Set up the ::G array in the slave.
467 interp eval tinterp [list array set ::G [array get ::G]]
468 interp eval tinterp [list set ::G(runner.tcl) 1]
469
470 interp eval tinterp $::R_INSTALL_PUTS_WRAPPER
471 tinterp alias puts_into_caller puts_into_caller
472
473 # Load the various test interfaces implemented in C.
474 load_testfixture_extensions tinterp
475
476 # Run the test script.
477 set rc [catch { interp eval tinterp $script } msg opt]
478 if {$rc} {
479 puts_into_caller $msg
480 puts_into_caller [dict get $opt -errorinfo]
481 incr ::TC(errors)
482 }
483
484 # Check if the interpreter call [run_thread_tests]
485 if { [interp eval tinterp {info exists ::run_thread_tests_called}] } {
486 set ::run_thread_tests_called 1
487 }
488
489 # Delete the interpreter used to run the test script.
490 interp delete tinterp
491}
492
493proc slave_test_file {zFile} {
494 set tail [file tail $zFile]
495
496 # Remember the value of the shared-cache setting. So that it is possible
497 # to check afterwards that it was not modified by the test script.
498 #
499 ifcapable shared_cache { set scs [sqlite3_enable_shared_cache] }
500
501 # Run the test script in a slave interpreter.
502 #
503 unset -nocomplain ::run_thread_tests_called
504 reset_prng_state
505 set ::sqlite_open_file_count 0
506 set time [time { slave_test_script [list source $zFile] }]
507 set ms [expr [lindex $time 0] / 1000]
508
509 r_install_puts_wrapper
510
511 # Test that all files opened by the test script were closed. Omit this
512 # if the test script has "thread" in its name. The open file counter
513 # is not thread-safe.
514 #
515 if {[info exists ::run_thread_tests_called]==0} {
516 do_test ${tail}-closeallfiles { expr {$::sqlite_open_file_count>0} } {0}
517 }
518 set ::sqlite_open_file_count 0
519
520 # Test that the global "shared-cache" setting was not altered by
521 # the test script.
522 #
523 ifcapable shared_cache {
524 set res [expr {[sqlite3_enable_shared_cache] == $scs}]
525 do_test ${tail}-sharedcachesetting [list set {} $res] 1
526 }
527
528 # Add some info to the output.
529 #
530 output2 "Time: $tail $ms ms"
531 show_memstats
532
533 r_uninstall_puts_wrapper
534 return $ms
535}
536
537proc puts_into_caller {args} {
538 global R
539 if {[llength $args]==1} {
540 append R(output) [lindex $args 0]
541 append R(output) "\n"
542 } else {
543 append R(output) [lindex $args 1]
544 }
545}
546
dane9a7ebe2022-07-13 17:46:42 +0000547#-------------------------------------------------------------------------
548#
549proc r_final_report {} {
550 global R
551
dande353fb2022-07-14 21:17:22 +0000552 sqlite3_test_control_pending_byte 0x010000
dane9a7ebe2022-07-13 17:46:42 +0000553 sqlite3 db $R(dbname)
dande353fb2022-07-14 21:17:22 +0000554
dane9a7ebe2022-07-13 17:46:42 +0000555 db timeout $R(timeout)
556
557 set errcode 0
558
559 # Create the text log file. This is just the concatenation of the
560 # 'output' column of the database for every script that was run.
561 set fd [open $R(logname) w]
danca0720a2022-07-14 18:09:56 +0000562 db eval {SELECT output FROM script ORDER BY config!='full',config,filename} {
dane9a7ebe2022-07-13 17:46:42 +0000563 puts $fd $output
564 }
565 close $fd
566
567 # Check if any scripts reported errors. If so, print one line noting
568 # how many errors, and another identifying the scripts in which they
569 # occured. Or, if no errors occurred, print out "no errors at all!".
570 sqlite3 db $R(dbname)
571 db timeout $R(timeout)
572 db eval { SELECT sum(nerr) AS nerr, sum(ntest) AS ntest FROM script } { }
573 puts "$nerr errors from $ntest tests."
574 if {$nerr>0} {
danca0720a2022-07-14 18:09:56 +0000575 db eval { SELECT config, filename FROM script WHERE nerr>0 } {
576 lappend errlist [r_testname $config $filename]
dane9a7ebe2022-07-13 17:46:42 +0000577 }
578 puts "Errors in: $errlist"
579 set errcode 1
580 }
581
582 # Check if any scripts were not run or did not finish. Print out a
583 # line identifying them if there are any.
584 set errlist [list]
danca0720a2022-07-14 18:09:56 +0000585 db eval { SELECT config, filename FROM script WHERE state!='done' } {
586 lappend errlist [r_testname $config $filename]
dane9a7ebe2022-07-13 17:46:42 +0000587 }
588 if {$errlist!=[list]} {
589 puts "Tests DID NOT FINISH (crashed?): $errlist"
590 set errcode 1
591 }
592
593 set bLeak 0
594 db eval {
595 SELECT id, nmalloc, nbyte, leaker FROM malloc
596 WHERE nmalloc>0 OR nbyte>0
597 } {
598 if {$id==0} {
599 set line "This process "
600 } else {
601 set line "Helper $id "
602 }
603 append line "leaked $nbyte byte in $nmalloc allocations"
604 if {$leaker!=""} { append line " (perhaps in [file tail $leaker])" }
605 puts $line
606 set bLeak 1
607 }
608 if {$bLeak==0} {
609 puts "No leaks - all allocations freed."
610 }
611
612 db close
613
614 puts "Test database is $R(dbname)"
615 puts "Test log file is $R(logname)"
616 if {$errcode} {
617 puts "This test has FAILED."
618 }
619 return $errcode
620}
621
622
dan05058512022-07-12 20:31:16 +0000623if {$R(helper)==0} {
dan05058512022-07-12 20:31:16 +0000624 make_new_testset
dane9a7ebe2022-07-13 17:46:42 +0000625}
626
627set R(nHelperRunning) 0
628if {$R(helper)==0 && $R(nJob)>1} {
629 cd $cmdlinearg(TESTFIXTURE_HOME)
630 for {set ii 1} {$ii <= $R(nJob)} {incr ii} {
dan05058512022-07-12 20:31:16 +0000631 set cmd "[info nameofexec] $R(info_script) helper $ii 2>@1"
632 puts "Launching helper $ii ($cmd)"
633 set chan [open "|$cmd" r]
634 fconfigure $chan -blocking false
635 fileevent $chan readable [list r_helper_readable $ii $chan]
636 incr R(nHelperRunning)
637 }
638 cd $cmdlinearg(testdir)
639}
640
641proc r_helper_readable {id chan} {
dane9a7ebe2022-07-13 17:46:42 +0000642 set data [gets $chan]
dande353fb2022-07-14 21:17:22 +0000643 if {$data!=""} { puts "helper $id:$data" }
dan05058512022-07-12 20:31:16 +0000644 if {[eof $chan]} {
dane9a7ebe2022-07-13 17:46:42 +0000645 puts "helper $id is finished"
dan05058512022-07-12 20:31:16 +0000646 incr ::R(nHelperRunning) -1
647 close $chan
648 }
649}
650
dane9a7ebe2022-07-13 17:46:42 +0000651if {$R(nHelperRunning)==0} {
danca0720a2022-07-14 18:09:56 +0000652 while { ""!=[set t [get_next_test]] } {
dan05058512022-07-12 20:31:16 +0000653 set R(output) ""
654 set TC(count) 0
655 set TC(errors) 0
dane9a7ebe2022-07-13 17:46:42 +0000656
danca0720a2022-07-14 18:09:56 +0000657 foreach {config filename} $t {}
658
659 array set O $::testspec($config)
660 set ::G(perm:name) $config
661 set ::G(perm:prefix) $O(-prefix)
662 set ::G(isquick) 1
663 set ::G(perm:dbconfig) $O(-dbconfig)
664 set ::G(perm:presql) $O(-presql)
665
666 eval $O(-initialize)
667 set ms [slave_test_file $filename]
668 eval $O(-shutdown)
669
670 unset -nocomplain ::G(perm:sqlite3_args)
671 unset ::G(perm:name)
672 unset ::G(perm:prefix)
673 unset ::G(perm:dbconfig)
674 unset ::G(perm:presql)
675
676 r_set_test_result $config $filename $ms $TC(errors) $TC(count) $R(output)
dan05058512022-07-12 20:31:16 +0000677
678 if {$R(helper)==0} {
679 foreach msg [r_get_messages] { puts $msg }
680 }
681 }
dan05058512022-07-12 20:31:16 +0000682
dane9a7ebe2022-07-13 17:46:42 +0000683 # Tests are finished - write a record into testrunner.db describing
684 # any memory leaks.
685 r_memory_report
686
687} else {
688 set TTT 0
689 sqlite3 db $R(dbname)
690 db timeout $R(timeout)
691 while {$R(nHelperRunning)>0} {
692 after 250 { incr TTT }
693 vwait TTT
694 foreach msg [r_get_messages db] { puts $msg }
695 }
696 db close
dan05058512022-07-12 20:31:16 +0000697}
dan05058512022-07-12 20:31:16 +0000698
699set errcode 0
700if {$R(helper)==0} {
dane9a7ebe2022-07-13 17:46:42 +0000701 set errcode [r_final_report]
dan05058512022-07-12 20:31:16 +0000702}
703
704exit $errcode
705