blob: fa28ec76003f11687fd555516e8f1d29dbabe8f0 [file] [log] [blame]
dane6391282019-04-11 19:03:15 +00001#!/bin/sh
dana3020dc2019-04-09 19:53:32 +00002# \
3exec wapptclsh "$0" ${1+"$@"}
4
dan523fb532019-04-10 18:56:30 +00005# package required wapp
6source [file join [file dirname [info script]] wapp.tcl]
7
dana3020dc2019-04-09 19:53:32 +00008# Variables set by the "control" form:
9#
10# G(platform) - User selected platform.
drhebdf4c02022-07-11 22:20:39 +000011# G(cfgglob) - Glob pattern that all configurations must match
dana3020dc2019-04-09 19:53:32 +000012# G(test) - Set to "Normal", "Veryquick", "Smoketest" or "Build-Only".
13# G(keep) - Boolean. True to delete no files after each test.
14# G(msvc) - Boolean. True to use MSVC as the compiler.
15# G(tcl) - Use Tcl from this directory for builds.
16# G(jobs) - How many sub-processes to run simultaneously.
17#
18set G(platform) $::tcl_platform(os)-$::tcl_platform(machine)
drhf0af3db2022-07-12 10:46:02 +000019set G(cfgglob) *
dana3020dc2019-04-09 19:53:32 +000020set G(test) Normal
danc97001f2019-05-01 15:25:38 +000021set G(keep) 1
danee253f72019-05-02 17:06:01 +000022set G(msvc) 0
dane6391282019-04-11 19:03:15 +000023set G(tcl) [::tcl::pkgconfig get libdir,install]
dana3020dc2019-04-09 19:53:32 +000024set G(jobs) 3
dane6391282019-04-11 19:03:15 +000025set G(debug) 0
dana3020dc2019-04-09 19:53:32 +000026
danee253f72019-05-02 17:06:01 +000027set G(noui) 0
28set G(stdout) 0
29
30
dan523fb532019-04-10 18:56:30 +000031proc wapptest_init {} {
32 global G
dana3020dc2019-04-09 19:53:32 +000033
drhf0af3db2022-07-12 10:46:02 +000034 set lSave [list platform test keep msvc tcl jobs debug noui stdout cfgglob]
dan523fb532019-04-10 18:56:30 +000035 foreach k $lSave { set A($k) $G($k) }
36 array unset G
37 foreach k $lSave { set G($k) $A($k) }
dana3020dc2019-04-09 19:53:32 +000038
dan523fb532019-04-10 18:56:30 +000039 # The root of the SQLite source tree.
40 set G(srcdir) [file dirname [file dirname [info script]]]
dana3020dc2019-04-09 19:53:32 +000041
dan523fb532019-04-10 18:56:30 +000042 set G(sqlite_version) "unknown"
dana3020dc2019-04-09 19:53:32 +000043
dan523fb532019-04-10 18:56:30 +000044 # Either "config", "running" or "stopped":
45 set G(state) "config"
dan93673622019-04-10 19:45:19 +000046
dane6391282019-04-11 19:03:15 +000047 set G(hostname) "(unknown host)"
48 catch { set G(hostname) [exec hostname] }
49 set G(host) $G(hostname)
dan93673622019-04-10 19:45:19 +000050 append G(host) " $::tcl_platform(os) $::tcl_platform(osVersion)"
51 append G(host) " $::tcl_platform(machine) $::tcl_platform(byteOrder)"
dan523fb532019-04-10 18:56:30 +000052}
dana3020dc2019-04-09 19:53:32 +000053
danee253f72019-05-02 17:06:01 +000054proc wapptest_run {} {
55 global G
56 set_test_array
57 set G(state) "running"
58
59 wapptest_openlog
60
61 wapptest_output "Running the following for $G(platform). $G(jobs) jobs."
62 foreach t $G(test_array) {
63 set config [dict get $t config]
64 set target [dict get $t target]
65 wapptest_output [format " %-25s%s" $config $target]
66 }
67 wapptest_output [string repeat * 70]
68}
69
dan45cb2aa2019-07-31 21:08:55 +000070proc releasetest_data {args} {
71 global G
72 set rtd [file join $G(srcdir) test releasetest_data.tcl]
73 set fd [open "|[info nameofexecutable] $rtd $args" r+]
74 set ret [read $fd]
75 close $fd
76 return $ret
77}
78
dan91945892019-04-30 20:43:10 +000079# Generate the text for the box at the top of the UI. The current SQLite
80# version, according to fossil, along with a warning if there are
81# uncommitted changes in the checkout.
dana3020dc2019-04-09 19:53:32 +000082#
dane6391282019-04-11 19:03:15 +000083proc generate_fossil_info {} {
84 global G
85 set pwd [pwd]
86 cd $G(srcdir)
dan91945892019-04-30 20:43:10 +000087 set rc [catch {
88 set r1 [exec fossil info]
89 set r2 [exec fossil changes]
90 }]
dane6391282019-04-11 19:03:15 +000091 cd $pwd
dan91945892019-04-30 20:43:10 +000092 if {$rc} return
dane6391282019-04-11 19:03:15 +000093
94 foreach line [split $r1 "\n"] {
95 if {[regexp {^checkout: *(.*)$} $line -> co]} {
96 wapp-trim { <br> %html($co) }
97 }
98 }
99
100 if {[string trim $r2]!=""} {
101 wapp-trim {
102 <br><span class=warning>
103 WARNING: Uncommitted changes in checkout
104 </span>
105 }
106 }
107}
108
dana3020dc2019-04-09 19:53:32 +0000109# If the application is in "config" state, set the contents of the
110# ::G(test_array) global to reflect the tests that will be run. If the
111# app is in some other state ("running" or "stopped"), this command
112# is a no-op.
113#
114proc set_test_array {} {
115 global G
116 if { $G(state)=="config" } {
117 set G(test_array) [list]
dan45cb2aa2019-07-31 21:08:55 +0000118 set debug "-debug"
119 if {$G(debug)==0} { set debug "-nodebug"}
120 foreach {config target} [releasetest_data tests $debug $G(platform)] {
dana3020dc2019-04-09 19:53:32 +0000121
drhebdf4c02022-07-11 22:20:39 +0000122 # All configuration names must match $g(cfgglob), which defaults to *
123 #
124 if {![string match -nocase $G(cfgglob) $config]} continue
125
dana3020dc2019-04-09 19:53:32 +0000126 # If using MSVC, do not run sanitize or valgrind tests. Or the
127 # checksymbols test.
128 if {$G(msvc) && (
129 "Sanitize" == $config
130 || "checksymbols" in $target
131 || "valgrindtest" in $target
132 )} {
133 continue
134 }
135
136 # If the test mode is not "Normal", override the target.
137 #
138 if {$target!="checksymbols" && $G(platform)!="Failure-Detection"} {
139 switch -- $G(test) {
140 Veryquick { set target quicktest }
141 Smoketest { set target smoketest }
142 Build-Only {
143 set target testfixture
144 if {$::tcl_platform(platform)=="windows"} {
145 set target testfixture.exe
146 }
147 }
148 }
149 }
150
151 lappend G(test_array) [dict create config $config target $target]
152 }
153 }
154}
155
156proc count_tests_and_errors {name logfile} {
157 global G
158
159 set fd [open $logfile rb]
160 set seen 0
161 while {![eof $fd]} {
162 set line [gets $fd]
163 if {[regexp {(\d+) errors out of (\d+) tests} $line all nerr ntest]} {
164 incr G(test.$name.nError) $nerr
165 incr G(test.$name.nTest) $ntest
166 set seen 1
167 if {$nerr>0} {
168 set G(test.$name.errmsg) $line
169 }
170 }
171 if {[regexp {runtime error: +(.*)} $line all msg]} {
172 # skip over "value is outside range" errors
drhc08716a2020-08-11 21:53:42 +0000173 if {[regexp {.* is outside the range of representable} $line]} {
dana3020dc2019-04-09 19:53:32 +0000174 # noop
175 } else {
176 incr G(test.$name.nError)
177 if {$G(test.$name.errmsg)==""} {
178 set G(test.$name.errmsg) $msg
179 }
180 }
181 }
182 if {[regexp {fatal error +(.*)} $line all msg]} {
183 incr G(test.$name.nError)
184 if {$G(test.$name.errmsg)==""} {
185 set G(test.$name.errmsg) $msg
186 }
187 }
188 if {[regexp {ERROR SUMMARY: (\d+) errors.*} $line all cnt] && $cnt>0} {
189 incr G(test.$name.nError)
190 if {$G(test.$name.errmsg)==""} {
191 set G(test.$name.errmsg) $all
192 }
193 }
194 if {[regexp {^VERSION: 3\.\d+.\d+} $line]} {
195 set v [string range $line 9 end]
196 if {$G(sqlite_version) eq "unknown"} {
197 set G(sqlite_version) $v
198 } elseif {$G(sqlite_version) ne $v} {
199 set G(test.$name.errmsg) "version conflict: {$G(sqlite_version)} vs. {$v}"
200 }
201 }
202 }
203 close $fd
204 if {$G(test) == "Build-Only"} {
205 incr G(test.$name.nTest)
206 if {$G(test.$name.nError)>0} {
207 set errmsg "Build failed"
208 }
209 } elseif {!$seen} {
210 set G(test.$name.errmsg) "Test did not complete"
211 if {[file readable core]} {
212 append G(test.$name.errmsg) " - core file exists"
213 }
214 }
215}
216
danee253f72019-05-02 17:06:01 +0000217proc wapptest_output {str} {
218 global G
219 if {$G(stdout)} { puts $str }
220 if {[info exists G(log)]} {
221 puts $G(log) $str
222 flush $G(log)
223 }
224}
225proc wapptest_openlog {} {
226 global G
227 set G(log) [open wapptest-out.txt w+]
228}
229proc wapptest_closelog {} {
230 global G
231 close $G(log)
232 unset G(log)
233}
234
235proc format_seconds {seconds} {
236 set min [format %.2d [expr ($seconds / 60) % 60]]
237 set hr [format %.2d [expr $seconds / 3600]]
238 set sec [format %.2d [expr $seconds % 60]]
239 return "$hr:$min:$sec"
240}
241
danc97001f2019-05-01 15:25:38 +0000242# This command is invoked once a slave process has finished running its
243# tests, successfully or otherwise. Parameter $name is the name of the
244# test, $rc the exit code returned by the slave process.
245#
dan523fb532019-04-10 18:56:30 +0000246proc slave_test_done {name rc} {
247 global G
248 set G(test.$name.done) [clock seconds]
249 set G(test.$name.nError) 0
250 set G(test.$name.nTest) 0
251 set G(test.$name.errmsg) ""
252 if {$rc} {
253 incr G(test.$name.nError)
254 }
255 if {[file exists $G(test.$name.log)]} {
256 count_tests_and_errors $name $G(test.$name.log)
257 }
danc97001f2019-05-01 15:25:38 +0000258
259 # If the "keep files" checkbox is clear, delete all files except for
260 # the executables and test logs. And any core file that is present.
261 if {$G(keep)==0} {
262 set keeplist {
263 testfixture testfixture.exe
264 sqlite3 sqlite3.exe
265 test.log test-out.txt
266 core
dan0de0ab82019-05-01 17:32:36 +0000267 wapptest_make.sh
268 wapptest_configure.sh
269 wapptest_run.tcl
danc97001f2019-05-01 15:25:38 +0000270 }
271 foreach f [glob -nocomplain [file join $G(test.$name.dir) *]] {
272 set t [file tail $f]
273 if {[lsearch $keeplist $t]<0} {
274 catch { file delete -force $f }
275 }
276 }
277 }
danee253f72019-05-02 17:06:01 +0000278
279 # Format a message regarding the success or failure of hte test.
280 set t [format_seconds [expr $G(test.$name.done) - $G(test.$name.start)]]
281 set res "OK"
282 if {$G(test.$name.nError)} { set res "FAILED" }
283 set dots [string repeat . [expr 60 - [string length $name]]]
284 set msg "$name $dots $res ($t)"
285
286 wapptest_output $msg
287 if {[info exists G(test.$name.errmsg)] && $G(test.$name.errmsg)!=""} {
dan79d8aa22019-07-04 16:30:41 +0000288 wapptest_output " $G(test.$name.errmsg)"
danee253f72019-05-02 17:06:01 +0000289 }
dan523fb532019-04-10 18:56:30 +0000290}
291
danc97001f2019-05-01 15:25:38 +0000292# This is a fileevent callback invoked each time a file-descriptor that
293# connects this process to a slave process is readable.
294#
dana3020dc2019-04-09 19:53:32 +0000295proc slave_fileevent {name} {
296 global G
297 set fd $G(test.$name.channel)
298
299 if {[eof $fd]} {
300 fconfigure $fd -blocking 1
301 set rc [catch { close $fd }]
302 unset G(test.$name.channel)
dan523fb532019-04-10 18:56:30 +0000303 slave_test_done $name $rc
dana3020dc2019-04-09 19:53:32 +0000304 } else {
305 set line [gets $fd]
306 if {[string trim $line] != ""} { puts "Trace : $name - \"$line\"" }
307 }
308
309 do_some_stuff
310}
311
danc97001f2019-05-01 15:25:38 +0000312# Return the contents of the "slave script" - the script run by slave
dan401593e2019-08-01 15:18:51 +0000313# processes to actually perform the test. All it does is execute the
314# test script already written to disk (wapptest_cmd.sh or wapptest_cmd.bat).
danc97001f2019-05-01 15:25:38 +0000315#
dan91945892019-04-30 20:43:10 +0000316proc wapptest_slave_script {} {
317 global G
dan45cb2aa2019-07-31 21:08:55 +0000318 if {$G(msvc)==0} {
319 set dir [file join .. $G(srcdir)]
320 set res [subst -nocommands {
321 set rc [catch "exec sh wapptest_cmd.sh {$dir} >>& test.log" ]
322 exit [set rc]
323 }]
324 } else {
325 set dir [file nativename [file normalize $G(srcdir)]]
326 set dir [string map [list "\\" "\\\\"] $dir]
327 set res [subst -nocommands {
328 set rc [catch "exec wapptest_cmd.bat {$dir} >>& test.log" ]
329 exit [set rc]
330 }]
dan91945892019-04-30 20:43:10 +0000331 }
332
dan91945892019-04-30 20:43:10 +0000333 set res
334}
335
336
337# Launch a slave process to run a test.
338#
dan45cb2aa2019-07-31 21:08:55 +0000339proc slave_launch {name target dir} {
dan91945892019-04-30 20:43:10 +0000340 global G
341
342 catch { file mkdir $dir } msg
343 foreach f [glob -nocomplain [file join $dir *]] {
344 catch { file delete -force $f }
345 }
danc97001f2019-05-01 15:25:38 +0000346 set G(test.$name.dir) $dir
dan91945892019-04-30 20:43:10 +0000347
dan45cb2aa2019-07-31 21:08:55 +0000348 # Write the test command to wapptest_cmd.sh|bat.
dan91945892019-04-30 20:43:10 +0000349 #
dan45cb2aa2019-07-31 21:08:55 +0000350 set ext sh
351 if {$G(msvc)} { set ext bat }
352 set fd1 [open [file join $dir wapptest_cmd.$ext] w]
353 if {$G(msvc)} {
354 puts $fd1 [releasetest_data script -msvc $name $target]
355 } else {
356 puts $fd1 [releasetest_data script $name $target]
dan91945892019-04-30 20:43:10 +0000357 }
358 close $fd1
359
dan91945892019-04-30 20:43:10 +0000360 # Write the wapptest_run.tcl script to the test directory. To run the
361 # commands in the other two files.
362 #
363 set fd3 [open [file join $dir wapptest_run.tcl] w]
364 puts $fd3 [wapptest_slave_script]
365 close $fd3
366
367 set pwd [pwd]
368 cd $dir
369 set fd [open "|[info nameofexecutable] wapptest_run.tcl" r+]
370 cd $pwd
371
372 set G(test.$name.channel) $fd
373 fconfigure $fd -blocking 0
374 fileevent $fd readable [list slave_fileevent $name]
375}
376
dana3020dc2019-04-09 19:53:32 +0000377proc do_some_stuff {} {
378 global G
379
380 # Count the number of running jobs. A running job has an entry named
381 # "channel" in its dictionary.
382 set nRunning 0
383 set bFinished 1
384 foreach j $G(test_array) {
385 set name [dict get $j config]
386 if { [info exists G(test.$name.channel)]} { incr nRunning }
387 if {![info exists G(test.$name.done)]} { set bFinished 0 }
388 }
389
390 if {$bFinished} {
391 set nError 0
392 set nTest 0
393 set nConfig 0
394 foreach j $G(test_array) {
395 set name [dict get $j config]
396 incr nError $G(test.$name.nError)
397 incr nTest $G(test.$name.nTest)
398 incr nConfig
399 }
400 set G(result) "$nError errors from $nTest tests in $nConfig configurations."
danee253f72019-05-02 17:06:01 +0000401 wapptest_output [string repeat * 70]
402 wapptest_output $G(result)
dana3020dc2019-04-09 19:53:32 +0000403 catch {
404 append G(result) " SQLite version $G(sqlite_version)"
danee253f72019-05-02 17:06:01 +0000405 wapptest_output " SQLite version $G(sqlite_version)"
dana3020dc2019-04-09 19:53:32 +0000406 }
dan523fb532019-04-10 18:56:30 +0000407 set G(state) "stopped"
danee253f72019-05-02 17:06:01 +0000408 wapptest_closelog
409 if {$G(noui)} { exit 0 }
dana3020dc2019-04-09 19:53:32 +0000410 } else {
411 set nLaunch [expr $G(jobs) - $nRunning]
412 foreach j $G(test_array) {
413 if {$nLaunch<=0} break
414 set name [dict get $j config]
415 if { ![info exists G(test.$name.channel)]
416 && ![info exists G(test.$name.done)]
417 } {
dan91945892019-04-30 20:43:10 +0000418
dana3020dc2019-04-09 19:53:32 +0000419 set target [dict get $j target]
dan45cb2aa2019-07-31 21:08:55 +0000420 set dir [string tolower [string map {" " _ "-" _} $name]]
dana3020dc2019-04-09 19:53:32 +0000421 set G(test.$name.start) [clock seconds]
dan45cb2aa2019-07-31 21:08:55 +0000422 set G(test.$name.log) [file join $dir test.log]
dane6391282019-04-11 19:03:15 +0000423
dan45cb2aa2019-07-31 21:08:55 +0000424 slave_launch $name $target $dir
dane6391282019-04-11 19:03:15 +0000425
dana3020dc2019-04-09 19:53:32 +0000426 incr nLaunch -1
427 }
428 }
429 }
430}
431
dan523fb532019-04-10 18:56:30 +0000432proc generate_select_widget {label id lOpt opt} {
433 wapp-trim {
434 <label> %string($label) </label>
435 <select id=%string($id) name=%string($id)>
436 }
437 foreach o $lOpt {
438 set selected ""
439 if {$o==$opt} { set selected " selected=1" }
440 wapp-subst "<option $selected>$o</option>"
441 }
442 wapp-trim { </select> }
443}
444
dana3020dc2019-04-09 19:53:32 +0000445proc generate_main_page {{extra {}}} {
446 global G
447 set_test_array
448
dane6391282019-04-11 19:03:15 +0000449 set hostname $G(hostname)
dana3020dc2019-04-09 19:53:32 +0000450 wapp-trim {
451 <html>
452 <head>
dane6391282019-04-11 19:03:15 +0000453 <title> %html($hostname): wapptest.tcl </title>
dana3020dc2019-04-09 19:53:32 +0000454 <link rel="stylesheet" type="text/css" href="style.css"/>
455 </head>
456 <body>
457 }
458
dan93673622019-04-10 19:45:19 +0000459 set host $G(host)
dana3020dc2019-04-09 19:53:32 +0000460 wapp-trim {
dane6391282019-04-11 19:03:15 +0000461 <div class="border">%string($host)
462 }
463 generate_fossil_info
464 wapp-trim {
465 </div>
466 <div class="border" id=controls>
467 <form action="control" method="post" name="control">
dana3020dc2019-04-09 19:53:32 +0000468 }
dan523fb532019-04-10 18:56:30 +0000469
470 # Build the "platform" select widget.
dan45cb2aa2019-07-31 21:08:55 +0000471 set lOpt [releasetest_data platforms]
dan523fb532019-04-10 18:56:30 +0000472 generate_select_widget Platform control_platform $lOpt $G(platform)
473
474 # Build the "test" select widget.
475 set lOpt [list Normal Veryquick Smoketest Build-Only]
476 generate_select_widget Test control_test $lOpt $G(test)
477
478 # Build the "jobs" select widget. Options are 1 to 8.
479 generate_select_widget Jobs control_jobs {1 2 3 4 5 6 7 8} $G(jobs)
480
481 switch $G(state) {
482 config {
483 set txt "Run Tests!"
484 set id control_run
485 }
486 running {
487 set txt "STOP Tests!"
488 set id control_stop
489 }
490 stopped {
491 set txt "Reset!"
492 set id control_reset
493 }
dana3020dc2019-04-09 19:53:32 +0000494 }
495 wapp-trim {
dan523fb532019-04-10 18:56:30 +0000496 <div class=right>
497 <input id=%string($id) name=%string($id) type=submit value="%string($txt)">
498 </input>
499 </div>
dana3020dc2019-04-09 19:53:32 +0000500 }
dan523fb532019-04-10 18:56:30 +0000501
502 wapp-trim {
503 <br><br>
dana3020dc2019-04-09 19:53:32 +0000504 <label> Tcl: </label>
505 <input id="control_tcl" name="control_tcl"></input>
dana3020dc2019-04-09 19:53:32 +0000506 <label> Keep files: </label>
507 <input id="control_keep" name="control_keep" type=checkbox value=1>
508 </input>
509 <label> Use MSVC: </label>
510 <input id="control_msvc" name="control_msvc" type=checkbox value=1>
dane6391282019-04-11 19:03:15 +0000511 <label> Debug tests: </label>
512 <input id="control_debug" name="control_debug" type=checkbox value=1>
dana3020dc2019-04-09 19:53:32 +0000513 </input>
dana3020dc2019-04-09 19:53:32 +0000514 }
515 wapp-trim {
dana3020dc2019-04-09 19:53:32 +0000516 </form>
dana3020dc2019-04-09 19:53:32 +0000517 }
dan523fb532019-04-10 18:56:30 +0000518 wapp-trim {
519 </div>
dane6391282019-04-11 19:03:15 +0000520 <div id=tests>
dan523fb532019-04-10 18:56:30 +0000521 }
522 wapp-page-tests
523
524 set script "script/$G(state).js"
525 wapp-trim {
526 </div>
527 <script src=%string($script)></script>
528 </body>
529 </html>
530 }
531}
532
533proc wapp-default {} {
534 generate_main_page
535}
536
537proc wapp-page-tests {} {
538 global G
dane6391282019-04-11 19:03:15 +0000539 wapp-trim { <table class="border" width=100%> }
dana3020dc2019-04-09 19:53:32 +0000540 foreach t $G(test_array) {
541 set config [dict get $t config]
542 set target [dict get $t target]
543
544 set class "testwait"
545 set seconds ""
546
547 if {[info exists G(test.$config.log)]} {
548 if {[info exists G(test.$config.channel)]} {
549 set class "testrunning"
550 set seconds [expr [clock seconds] - $G(test.$config.start)]
551 } elseif {[info exists G(test.$config.done)]} {
552 if {$G(test.$config.nError)>0} {
553 set class "testfail"
554 } else {
555 set class "testdone"
556 }
557 set seconds [expr $G(test.$config.done) - $G(test.$config.start)]
558 }
danee253f72019-05-02 17:06:01 +0000559 set seconds [format_seconds $seconds]
dana3020dc2019-04-09 19:53:32 +0000560 }
561
562 wapp-trim {
563 <tr class=%string($class)>
dane6391282019-04-11 19:03:15 +0000564 <td class="nowrap"> %html($config)
565 <td class="padleft nowrap"> %html($target)
566 <td class="padleft nowrap"> %html($seconds)
567 <td class="padleft nowrap">
dana3020dc2019-04-09 19:53:32 +0000568 }
569 if {[info exists G(test.$config.log)]} {
570 set log $G(test.$config.log)
571 set uri "log/$log"
572 wapp-trim {
573 <a href=%url($uri)> %html($log) </a>
574 }
575 }
576 if {[info exists G(test.$config.errmsg)] && $G(test.$config.errmsg)!=""} {
577 set errmsg $G(test.$config.errmsg)
578 wapp-trim {
579 <tr class=testfail>
dane6391282019-04-11 19:03:15 +0000580 <td> <td class="padleft" colspan=3> %html($errmsg)
dana3020dc2019-04-09 19:53:32 +0000581 }
582 }
583 }
584
dan523fb532019-04-10 18:56:30 +0000585 wapp-trim { </table> }
586
dana3020dc2019-04-09 19:53:32 +0000587 if {[info exists G(result)]} {
588 set res $G(result)
589 wapp-trim {
dan523fb532019-04-10 18:56:30 +0000590 <div class=border id=result> %string($res) </div>
dana3020dc2019-04-09 19:53:32 +0000591 }
592 }
dana3020dc2019-04-09 19:53:32 +0000593}
594
dan523fb532019-04-10 18:56:30 +0000595# URI: /control
596#
597# Whenever the form at the top of the application page is submitted, it
598# is submitted here.
599#
dana3020dc2019-04-09 19:53:32 +0000600proc wapp-page-control {} {
601 global G
dan523fb532019-04-10 18:56:30 +0000602 if {$::G(state)=="config"} {
dane6391282019-04-11 19:03:15 +0000603 set lControls [list platform test tcl jobs keep msvc debug]
dan523fb532019-04-10 18:56:30 +0000604 set G(msvc) 0
605 set G(keep) 0
dane6391282019-04-11 19:03:15 +0000606 set G(debug) 0
dan523fb532019-04-10 18:56:30 +0000607 } else {
608 set lControls [list jobs]
609 }
610 foreach v $lControls {
dana3020dc2019-04-09 19:53:32 +0000611 if {[wapp-param-exists control_$v]} {
612 set G($v) [wapp-param control_$v]
dana3020dc2019-04-09 19:53:32 +0000613 }
614 }
615
dan523fb532019-04-10 18:56:30 +0000616 if {[wapp-param-exists control_run]} {
617 # This is a "run test" command.
danee253f72019-05-02 17:06:01 +0000618 wapptest_run
dana3020dc2019-04-09 19:53:32 +0000619 }
620
dan523fb532019-04-10 18:56:30 +0000621 if {[wapp-param-exists control_stop]} {
622 # A "STOP tests" command.
623 set G(state) "stopped"
624 set G(result) "Test halted by user"
625 foreach j $G(test_array) {
626 set name [dict get $j config]
627 if { [info exists G(test.$name.channel)] } {
628 close $G(test.$name.channel)
629 unset G(test.$name.channel)
630 slave_test_done $name 1
631 }
632 }
danee253f72019-05-02 17:06:01 +0000633 wapptest_closelog
dan523fb532019-04-10 18:56:30 +0000634 }
635
636 if {[wapp-param-exists control_reset]} {
637 # A "reset app" command.
638 set G(state) "config"
639 wapptest_init
640 }
641
dana3020dc2019-04-09 19:53:32 +0000642 if {$::G(state) == "running"} {
643 do_some_stuff
644 }
dana3020dc2019-04-09 19:53:32 +0000645 wapp-redirect /
646}
647
dan523fb532019-04-10 18:56:30 +0000648# URI: /style.css
649#
650# Return the stylesheet for the application main page.
651#
dana3020dc2019-04-09 19:53:32 +0000652proc wapp-page-style.css {} {
653 wapp-subst {
dana3020dc2019-04-09 19:53:32 +0000654
dane6391282019-04-11 19:03:15 +0000655 /* The boxes with black borders use this class */
dan523fb532019-04-10 18:56:30 +0000656 .border {
657 border: 3px groove #444444;
658 padding: 1em;
659 margin-top: 1em;
660 margin-bottom: 1em;
661 }
662
dane6391282019-04-11 19:03:15 +0000663 /* Float to the right (used for the Run/Stop/Reset button) */
664 .right { float: right; }
dan523fb532019-04-10 18:56:30 +0000665
dane6391282019-04-11 19:03:15 +0000666 /* Style for the large red warning at the top of the page */
dana3020dc2019-04-09 19:53:32 +0000667 .warning {
dana3020dc2019-04-09 19:53:32 +0000668 color: red;
dana3020dc2019-04-09 19:53:32 +0000669 font-weight: bold;
670 }
671
dane6391282019-04-11 19:03:15 +0000672 /* Styles used by cells in the test table */
673 .padleft { padding-left: 5ex; }
674 .nowrap { white-space: nowrap; }
dana3020dc2019-04-09 19:53:32 +0000675
dane6391282019-04-11 19:03:15 +0000676 /* Styles for individual tests, depending on the outcome */
677 .testwait { }
678 .testrunning { color: blue }
679 .testdone { color: green }
680 .testfail { color: red }
dana3020dc2019-04-09 19:53:32 +0000681 }
682}
683
dan523fb532019-04-10 18:56:30 +0000684# URI: /script/${state}.js
685#
686# The last part of this URI is always "config.js", "running.js" or
687# "stopped.js", depending on the state of the application. It returns
688# the javascript part of the front-end for the requested state to the
689# browser.
690#
691proc wapp-page-script {} {
692 regexp {[^/]*$} [wapp-param REQUEST_URI] script
dana3020dc2019-04-09 19:53:32 +0000693
694 set tcl $::G(tcl)
695 set keep $::G(keep)
696 set msvc $::G(msvc)
dane6391282019-04-11 19:03:15 +0000697 set debug $::G(debug)
dana3020dc2019-04-09 19:53:32 +0000698
699 wapp-subst {
dan523fb532019-04-10 18:56:30 +0000700 var lElem = \["control_platform", "control_test", "control_msvc",
dane6391282019-04-11 19:03:15 +0000701 "control_jobs", "control_debug"
dan523fb532019-04-10 18:56:30 +0000702 \];
dana3020dc2019-04-09 19:53:32 +0000703 lElem.forEach(function(e) {
704 var elem = document.getElementById(e);
705 elem.addEventListener("change", function() { control.submit() } );
706 })
707
708 elem = document.getElementById("control_tcl");
709 elem.value = "%string($tcl)"
710
711 elem = document.getElementById("control_keep");
712 elem.checked = %string($keep);
713
714 elem = document.getElementById("control_msvc");
715 elem.checked = %string($msvc);
dane6391282019-04-11 19:03:15 +0000716
717 elem = document.getElementById("control_debug");
718 elem.checked = %string($debug);
dana3020dc2019-04-09 19:53:32 +0000719 }
720
dan523fb532019-04-10 18:56:30 +0000721 if {$script != "config.js"} {
dana3020dc2019-04-09 19:53:32 +0000722 wapp-subst {
723 var lElem = \["control_platform", "control_test",
dan37eca052019-04-12 13:40:54 +0000724 "control_tcl", "control_keep", "control_msvc",
725 "control_debug"
dana3020dc2019-04-09 19:53:32 +0000726 \];
727 lElem.forEach(function(e) {
728 var elem = document.getElementById(e);
729 elem.disabled = true;
730 })
731 }
732 }
dan523fb532019-04-10 18:56:30 +0000733
734 if {$script == "running.js"} {
735 wapp-subst {
736 function reload_tests() {
737 fetch('tests')
738 .then( data => data.text() )
739 .then( data => {
740 document.getElementById("tests").innerHTML = data;
741 })
742 .then( data => {
743 if( document.getElementById("result") ){
744 document.location = document.location;
745 } else {
746 setTimeout(reload_tests, 1000)
747 }
748 });
749 }
750
751 setTimeout(reload_tests, 1000)
752 }
753 }
dana3020dc2019-04-09 19:53:32 +0000754}
755
dan523fb532019-04-10 18:56:30 +0000756# URI: /env
757#
758# This is for debugging only. Serves no other purpose.
759#
dana3020dc2019-04-09 19:53:32 +0000760proc wapp-page-env {} {
761 wapp-allow-xorigin-params
762 wapp-trim {
763 <h1>Wapp Environment</h1>\n<pre>
764 <pre>%html([wapp-debug-env])</pre>
765 }
766}
767
dan523fb532019-04-10 18:56:30 +0000768# URI: /log/dirname/test.log
769#
770# This URI reads file "dirname/test.log" from disk, wraps it in a <pre>
771# block, and returns it to the browser. Use for viewing log files.
772#
dana3020dc2019-04-09 19:53:32 +0000773proc wapp-page-log {} {
774 set log [string range [wapp-param REQUEST_URI] 5 end]
775 set fd [open $log]
776 set data [read $fd]
777 close $fd
778 wapp-trim {
779 <pre>
780 %html($data)
781 </pre>
782 }
783}
784
danee253f72019-05-02 17:06:01 +0000785# Print out a usage message. Then do [exit 1].
786#
787proc wapptest_usage {} {
788 puts stderr {
789This Tcl script is used to test various configurations of SQLite. By
790default it uses "wapp" to provide an interactive interface. Supported
791command line options (all optional) are:
792
793 --platform PLATFORM (which tests to run)
drhebdf4c02022-07-11 22:20:39 +0000794 --config GLOB (only run configurations matching GLOB)
danee253f72019-05-02 17:06:01 +0000795 --smoketest (run "make smoketest" only)
796 --veryquick (run veryquick.test only)
797 --buildonly (build executables, do not run tests)
798 --jobs N (number of concurrent jobs)
799 --tcl DIR (where to find tclConfig.sh)
800 --deletefiles (delete extra files after each test)
801 --msvc (Use MS Visual C)
802 --debug (Also run [n]debugging versions of tests)
803 --noui (do not use wapp)
804 }
805 exit 1
806}
807
808# Sort command line arguments into two groups: those that belong to wapp,
809# and those that belong to the application.
810set WAPPARG(-server) 1
811set WAPPARG(-local) 1
812set WAPPARG(-scgi) 1
813set WAPPARG(-remote-scgi) 1
814set WAPPARG(-fromip) 1
815set WAPPARG(-nowait) 0
816set WAPPARG(-cgi) 0
817set lWappArg [list]
818set lTestArg [list]
819for {set i 0} {$i < [llength $argv]} {incr i} {
820 set arg [lindex $argv $i]
821 if {[string range $arg 0 1]=="--"} {
822 set arg [string range $arg 1 end]
823 }
824 if {[info exists WAPPARG($arg)]} {
825 lappend lWappArg $arg
826 if {$WAPPARG($arg)} {
827 incr i
828 lappend lWappArg [lindex $argv $i]
829 }
830 } else {
831 lappend lTestArg $arg
832 }
833}
834
dan367b8d72019-10-03 13:44:08 +0000835wapptest_init
danee253f72019-05-02 17:06:01 +0000836for {set i 0} {$i < [llength $lTestArg]} {incr i} {
dan367b8d72019-10-03 13:44:08 +0000837 set opt [lindex $lTestArg $i]
838 if {[string range $opt 0 1]=="--"} {
839 set opt [string range $opt 1 end]
840 }
841 switch -- $opt {
danee253f72019-05-02 17:06:01 +0000842 -platform {
843 if {$i==[llength $lTestArg]-1} { wapptest_usage }
844 incr i
845 set arg [lindex $lTestArg $i]
dan45cb2aa2019-07-31 21:08:55 +0000846 set lPlatform [releasetest_data platforms]
danee253f72019-05-02 17:06:01 +0000847 if {[lsearch $lPlatform $arg]<0} {
848 puts stderr "No such platform: $arg. Platforms are: $lPlatform"
849 exit -1
850 }
851 set G(platform) $arg
852 }
853
854 -smoketest { set G(test) Smoketest }
855 -veryquick { set G(test) Veryquick }
856 -buildonly { set G(test) Build-Only }
857 -jobs {
858 if {$i==[llength $lTestArg]-1} { wapptest_usage }
859 incr i
860 set G(jobs) [lindex $lTestArg $i]
861 }
862
863 -tcl {
864 if {$i==[llength $lTestArg]-1} { wapptest_usage }
865 incr i
866 set G(tcl) [lindex $lTestArg $i]
867 }
868
869 -deletefiles {
870 set G(keep) 0
871 }
872
873 -msvc {
874 set G(msvc) 1
875 }
876
877 -debug {
878 set G(debug) 1
879 }
880
881 -noui {
882 set G(noui) 1
883 set G(stdout) 1
884 }
885
drhebdf4c02022-07-11 22:20:39 +0000886 -config {
887 if {$i==[llength $lTestArg]-1} { wapptest_usage }
888 incr i
889 set G(cfgglob) [lindex $lTestArg $i]
890 }
891
danee253f72019-05-02 17:06:01 +0000892 -stdout {
893 set G(stdout) 1
894 }
895
896 default {
897 puts stderr "Unrecognized option: [lindex $lTestArg $i]"
898 wapptest_usage
899 }
900 }
901}
902
danee253f72019-05-02 17:06:01 +0000903if {$G(noui)==0} {
904 wapp-start $lWappArg
905} else {
906 wapptest_run
907 do_some_stuff
908 vwait forever
909}