github.com/jdgcs/sqlite3@v1.12.1-0.20210908114423-bc5f96e4dd51/testdata/tcl/releasetest.tcl (about) 1 #!/usr/bin/tclsh 2 # 3 # Documentation for this script. This may be output to stderr 4 # if the script is invoked incorrectly. See the [process_options] 5 # proc below. 6 # 7 set ::USAGE_MESSAGE { 8 This Tcl script is used to test the various configurations required 9 before releasing a new version. Supported command line options (all 10 optional) are: 11 12 --buildonly (Just build testfixture - do not run) 13 --config CONFIGNAME (Run only CONFIGNAME) 14 --dryrun (Print what would have happened) 15 -f|--force (Run even if uncommitted changes) 16 --info (Show diagnostic info) 17 --jobs N (Use N processes - default 1) 18 --keep (Delete no files after each test run) 19 --msvc (Use MSVC as the compiler) 20 --platform PLATFORM (see below) 21 --progress (Show progress messages) 22 --quick (Run "veryquick.test" only) 23 --veryquick (Run "make smoketest" only) 24 --with-tcl=DIR (Use TCL build at DIR) 25 26 The script determines the default value for --platform using the 27 $tcl_platform(os) and $tcl_platform(machine) variables. Supported 28 platforms are "Linux-x86", "Linux-x86_64", "Darwin-i386", 29 "Darwin-x86_64", "Windows NT-intel", and "Windows NT-amd64". 30 31 Every test begins with a fresh run of the configure script at the top 32 of the SQLite source tree. 33 } 34 35 # Return a timestamp of the form HH:MM:SS 36 # 37 proc now {} { 38 return [clock format [clock seconds] -format %H:%M:%S] 39 } 40 41 # Omit comments (text between # and \n) in a long multi-line string. 42 # 43 proc strip_comments {in} { 44 regsub -all {#[^\n]*\n} $in {} out 45 return $out 46 } 47 48 array set ::Configs [strip_comments { 49 "Default" { 50 -O2 51 --disable-amalgamation --disable-shared 52 --enable-session 53 } 54 "Sanitize" { 55 CC=clang -fsanitize=undefined 56 -DSQLITE_ENABLE_STAT4 57 -DCONFIG_SLOWDOWN_FACTOR=5.0 58 --enable-session 59 } 60 "Stdcall" { 61 -DUSE_STDCALL=1 62 -O2 63 } 64 "Have-Not" { 65 # The "Have-Not" configuration sets all possible -UHAVE_feature options 66 # in order to verify that the code works even on platforms that lack 67 # these support services. 68 -DHAVE_FDATASYNC=0 69 -DHAVE_GMTIME_R=0 70 -DHAVE_ISNAN=0 71 -DHAVE_LOCALTIME_R=0 72 -DHAVE_LOCALTIME_S=0 73 -DHAVE_MALLOC_USABLE_SIZE=0 74 -DHAVE_STRCHRNUL=0 75 -DHAVE_USLEEP=0 76 -DHAVE_UTIME=0 77 } 78 "Unlock-Notify" { 79 -O2 80 -DSQLITE_ENABLE_UNLOCK_NOTIFY 81 -DSQLITE_THREADSAFE 82 -DSQLITE_TCL_DEFAULT_FULLMUTEX=1 83 } 84 "User-Auth" { 85 -O2 86 -DSQLITE_USER_AUTHENTICATION=1 87 } 88 "Secure-Delete" { 89 -O2 90 -DSQLITE_SECURE_DELETE=1 91 -DSQLITE_SOUNDEX=1 92 } 93 "Update-Delete-Limit" { 94 -O2 95 -DSQLITE_DEFAULT_FILE_FORMAT=4 96 -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1 97 -DSQLITE_ENABLE_STMT_SCANSTATUS 98 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS 99 -DSQLITE_ENABLE_CURSOR_HINTS 100 --enable-json1 101 } 102 "Check-Symbols" { 103 -DSQLITE_MEMDEBUG=1 104 -DSQLITE_ENABLE_FTS3_PARENTHESIS=1 105 -DSQLITE_ENABLE_FTS3=1 106 -DSQLITE_ENABLE_RTREE=1 107 -DSQLITE_ENABLE_MEMSYS5=1 108 -DSQLITE_ENABLE_MEMSYS3=1 109 -DSQLITE_ENABLE_COLUMN_METADATA=1 110 -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1 111 -DSQLITE_SECURE_DELETE=1 112 -DSQLITE_SOUNDEX=1 113 -DSQLITE_ENABLE_ATOMIC_WRITE=1 114 -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 115 -DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1 116 -DSQLITE_ENABLE_STAT4 117 -DSQLITE_ENABLE_STMT_SCANSTATUS 118 --enable-json1 --enable-fts5 --enable-session 119 } 120 "Debug-One" { 121 --disable-shared 122 -O2 -funsigned-char 123 -DSQLITE_DEBUG=1 124 -DSQLITE_MEMDEBUG=1 125 -DSQLITE_MUTEX_NOOP=1 126 -DSQLITE_TCL_DEFAULT_FULLMUTEX=1 127 -DSQLITE_ENABLE_FTS3=1 128 -DSQLITE_ENABLE_RTREE=1 129 -DSQLITE_ENABLE_MEMSYS5=1 130 -DSQLITE_ENABLE_COLUMN_METADATA=1 131 -DSQLITE_ENABLE_STAT4 132 -DSQLITE_ENABLE_HIDDEN_COLUMNS 133 -DSQLITE_MAX_ATTACHED=125 134 -DSQLITE_MUTATION_TEST 135 --enable-fts5 --enable-json1 136 } 137 "Fast-One" { 138 -O6 139 -DSQLITE_ENABLE_FTS4=1 140 -DSQLITE_ENABLE_RTREE=1 141 -DSQLITE_ENABLE_STAT4 142 -DSQLITE_ENABLE_RBU 143 -DSQLITE_MAX_ATTACHED=125 144 -DLONGDOUBLE_TYPE=double 145 --enable-session 146 } 147 "Device-One" { 148 -O2 149 -DSQLITE_DEBUG=1 150 -DSQLITE_DEFAULT_AUTOVACUUM=1 151 -DSQLITE_DEFAULT_CACHE_SIZE=64 152 -DSQLITE_DEFAULT_PAGE_SIZE=1024 153 -DSQLITE_DEFAULT_TEMP_CACHE_SIZE=32 154 -DSQLITE_DISABLE_LFS=1 155 -DSQLITE_ENABLE_ATOMIC_WRITE=1 156 -DSQLITE_ENABLE_IOTRACE=1 157 -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 158 -DSQLITE_MAX_PAGE_SIZE=4096 159 -DSQLITE_OMIT_LOAD_EXTENSION=1 160 -DSQLITE_OMIT_PROGRESS_CALLBACK=1 161 -DSQLITE_OMIT_VIRTUALTABLE=1 162 -DSQLITE_ENABLE_HIDDEN_COLUMNS 163 -DSQLITE_TEMP_STORE=3 164 --enable-json1 165 } 166 "Device-Two" { 167 -DSQLITE_4_BYTE_ALIGNED_MALLOC=1 168 -DSQLITE_DEFAULT_AUTOVACUUM=1 169 -DSQLITE_DEFAULT_CACHE_SIZE=1000 170 -DSQLITE_DEFAULT_LOCKING_MODE=0 171 -DSQLITE_DEFAULT_PAGE_SIZE=1024 172 -DSQLITE_DEFAULT_TEMP_CACHE_SIZE=1000 173 -DSQLITE_DISABLE_LFS=1 174 -DSQLITE_ENABLE_FTS3=1 175 -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 176 -DSQLITE_ENABLE_RTREE=1 177 -DSQLITE_MAX_COMPOUND_SELECT=50 178 -DSQLITE_MAX_PAGE_SIZE=32768 179 -DSQLITE_OMIT_TRACE=1 180 -DSQLITE_TEMP_STORE=3 181 -DSQLITE_THREADSAFE=2 182 --enable-json1 --enable-fts5 --enable-session 183 } 184 "Locking-Style" { 185 -O2 186 -DSQLITE_ENABLE_LOCKING_STYLE=1 187 } 188 "Apple" { 189 -Os 190 -DHAVE_GMTIME_R=1 191 -DHAVE_ISNAN=1 192 -DHAVE_LOCALTIME_R=1 193 -DHAVE_PREAD=1 194 -DHAVE_PWRITE=1 195 -DHAVE_USLEEP=1 196 -DHAVE_USLEEP=1 197 -DHAVE_UTIME=1 198 -DSQLITE_DEFAULT_CACHE_SIZE=1000 199 -DSQLITE_DEFAULT_CKPTFULLFSYNC=1 200 -DSQLITE_DEFAULT_MEMSTATUS=1 201 -DSQLITE_DEFAULT_PAGE_SIZE=1024 202 -DSQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS=1 203 -DSQLITE_ENABLE_API_ARMOR=1 204 -DSQLITE_ENABLE_AUTO_PROFILE=1 205 -DSQLITE_ENABLE_FLOCKTIMEOUT=1 206 -DSQLITE_ENABLE_FTS3=1 207 -DSQLITE_ENABLE_FTS3_PARENTHESIS=1 208 -DSQLITE_ENABLE_FTS3_TOKENIZER=1 209 if:os=="Darwin" -DSQLITE_ENABLE_LOCKING_STYLE=1 210 -DSQLITE_ENABLE_PERSIST_WAL=1 211 -DSQLITE_ENABLE_PURGEABLE_PCACHE=1 212 -DSQLITE_ENABLE_RTREE=1 213 -DSQLITE_ENABLE_SNAPSHOT=1 214 # -DSQLITE_ENABLE_SQLLOG=1 215 -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1 216 -DSQLITE_MAX_LENGTH=2147483645 217 -DSQLITE_MAX_VARIABLE_NUMBER=500000 218 # -DSQLITE_MEMDEBUG=1 219 -DSQLITE_NO_SYNC=1 220 -DSQLITE_OMIT_AUTORESET=1 221 -DSQLITE_OMIT_LOAD_EXTENSION=1 222 -DSQLITE_PREFER_PROXY_LOCKING=1 223 -DSQLITE_SERIES_CONSTRAINT_VERIFY=1 224 -DSQLITE_THREADSAFE=2 225 -DSQLITE_USE_URI=1 226 -DSQLITE_WRITE_WALFRAME_PREBUFFERED=1 227 -DUSE_GUARDED_FD=1 228 -DUSE_PREAD=1 229 --enable-json1 --enable-fts5 230 } 231 "Extra-Robustness" { 232 -DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1 233 -DSQLITE_MAX_ATTACHED=62 234 } 235 "Devkit" { 236 -DSQLITE_DEFAULT_FILE_FORMAT=4 237 -DSQLITE_MAX_ATTACHED=30 238 -DSQLITE_ENABLE_COLUMN_METADATA 239 -DSQLITE_ENABLE_FTS4 240 -DSQLITE_ENABLE_FTS5 241 -DSQLITE_ENABLE_FTS4_PARENTHESIS 242 -DSQLITE_DISABLE_FTS4_DEFERRED 243 -DSQLITE_ENABLE_RTREE 244 --enable-json1 --enable-fts5 245 } 246 "No-lookaside" { 247 -DSQLITE_TEST_REALLOC_STRESS=1 248 -DSQLITE_OMIT_LOOKASIDE=1 249 -DHAVE_USLEEP=1 250 } 251 "Valgrind" { 252 -DSQLITE_ENABLE_STAT4 253 -DSQLITE_ENABLE_FTS4 254 -DSQLITE_ENABLE_RTREE 255 -DSQLITE_ENABLE_HIDDEN_COLUMNS 256 -DCONFIG_SLOWDOWN_FACTOR=8.0 257 --enable-json1 258 } 259 260 # The next group of configurations are used only by the 261 # Failure-Detection platform. They are all the same, but we need 262 # different names for them all so that they results appear in separate 263 # subdirectories. 264 # 265 Fail0 {-O0} 266 Fail2 {-O0} 267 Fail3 {-O0} 268 Fail4 {-O0} 269 FuzzFail1 {-O0} 270 FuzzFail2 {-O0} 271 }] 272 273 array set ::Platforms [strip_comments { 274 Linux-x86_64 { 275 "Check-Symbols" checksymbols 276 "Fast-One" "fuzztest test" 277 "Debug-One" "mptest test" 278 "Have-Not" test 279 "Secure-Delete" test 280 "Unlock-Notify" "QUICKTEST_INCLUDE=notify2.test test" 281 "User-Auth" tcltest 282 "Update-Delete-Limit" test 283 "Extra-Robustness" test 284 "Device-Two" "threadtest test" 285 "No-lookaside" test 286 "Devkit" test 287 "Apple" test 288 "Sanitize" {QUICKTEST_OMIT=func4.test,nan.test test} 289 "Device-One" fulltest 290 "Default" "threadtest fulltest" 291 "Valgrind" valgrindtest 292 } 293 Linux-i686 { 294 "Devkit" test 295 "Have-Not" test 296 "Unlock-Notify" "QUICKTEST_INCLUDE=notify2.test test" 297 "Device-One" test 298 "Device-Two" test 299 "Default" "threadtest fulltest" 300 } 301 Darwin-i386 { 302 "Locking-Style" "mptest test" 303 "Have-Not" test 304 "Apple" "threadtest fulltest" 305 } 306 Darwin-x86_64 { 307 "Locking-Style" "mptest test" 308 "Have-Not" test 309 "Apple" "threadtest fulltest" 310 } 311 "Windows NT-intel" { 312 "Stdcall" test 313 "Have-Not" test 314 "Default" "mptest fulltestonly" 315 } 316 "Windows NT-amd64" { 317 "Stdcall" test 318 "Have-Not" test 319 "Default" "mptest fulltestonly" 320 } 321 322 # The Failure-Detection platform runs various tests that deliberately 323 # fail. This is used as a test of this script to verify that this script 324 # correctly identifies failures. 325 # 326 Failure-Detection { 327 Fail0 "TEST_FAILURE=0 test" 328 Sanitize "TEST_FAILURE=1 test" 329 Fail2 "TEST_FAILURE=2 valgrindtest" 330 Fail3 "TEST_FAILURE=3 valgrindtest" 331 Fail4 "TEST_FAILURE=4 test" 332 FuzzFail1 "TEST_FAILURE=5 test" 333 FuzzFail2 "TEST_FAILURE=5 valgrindtest" 334 } 335 }] 336 337 338 # End of configuration section. 339 ######################################################################### 340 ######################################################################### 341 342 # Configuration verification: Check that each entry in the list of configs 343 # specified for each platforms exists. 344 # 345 foreach {key value} [array get ::Platforms] { 346 foreach {v t} $value { 347 if {0==[info exists ::Configs($v)]} { 348 puts stderr "No such configuration: \"$v\"" 349 exit -1 350 } 351 } 352 } 353 354 # Output log. Disabled for slave interpreters. 355 # 356 if {[lindex $argv end]!="--slave"} { 357 set LOG [open releasetest-out.txt w] 358 proc PUTS {txt} { 359 puts $txt 360 puts $::LOG $txt 361 flush $::LOG 362 } 363 proc PUTSNNL {txt} { 364 puts -nonewline $txt 365 puts -nonewline $::LOG $txt 366 flush $::LOG 367 } 368 proc PUTSERR {txt} { 369 puts stderr $txt 370 puts $::LOG $txt 371 flush $::LOG 372 } 373 puts $LOG "$argv0 $argv" 374 set tm0 [clock format [clock seconds] -format {%Y-%m-%d %H:%M:%S} -gmt 1] 375 puts $LOG "start-time: $tm0 UTC" 376 } else { 377 proc PUTS {txt} { 378 puts $txt 379 } 380 proc PUTSNNL {txt} { 381 puts -nonewline $txt 382 } 383 proc PUTSERR {txt} { 384 puts stderr $txt 385 } 386 } 387 388 # Open the file $logfile and look for a report on the number of errors 389 # and the number of test cases run. Add these values to the global 390 # $::NERRCASE and $::NTESTCASE variables. 391 # 392 # If any errors occur, then write into $errmsgVar the text of an appropriate 393 # one-line error message to show on the output. 394 # 395 proc count_tests_and_errors {logfile rcVar errmsgVar} { 396 if {$::DRYRUN} return 397 upvar 1 $rcVar rc $errmsgVar errmsg 398 set fd [open $logfile rb] 399 set seen 0 400 while {![eof $fd]} { 401 set line [gets $fd] 402 if {[regexp {(\d+) errors out of (\d+) tests} $line all nerr ntest]} { 403 incr ::NERRCASE $nerr 404 incr ::NTESTCASE $ntest 405 set seen 1 406 if {$nerr>0} { 407 set rc 1 408 set errmsg $line 409 } 410 } 411 if {[regexp {runtime error: +(.*)} $line all msg]} { 412 # skip over "value is outside range" errors 413 if {[regexp {value .* is outside the range of representable} $line]} { 414 # noop 415 } elseif {[regexp {overflow: .* cannot be represented} $line]} { 416 # noop 417 } else { 418 incr ::NERRCASE 419 if {$rc==0} { 420 set rc 1 421 set errmsg $msg 422 } 423 } 424 } 425 if {[regexp {fatal error +(.*)} $line all msg]} { 426 incr ::NERRCASE 427 if {$rc==0} { 428 set rc 1 429 set errmsg $msg 430 } 431 } 432 if {[regexp {ERROR SUMMARY: (\d+) errors.*} $line all cnt] && $cnt>0} { 433 incr ::NERRCASE 434 if {$rc==0} { 435 set rc 1 436 set errmsg $all 437 } 438 } 439 if {[regexp {^VERSION: 3\.\d+.\d+} $line]} { 440 set v [string range $line 9 end] 441 if {$::SQLITE_VERSION eq ""} { 442 set ::SQLITE_VERSION $v 443 } elseif {$::SQLITE_VERSION ne $v} { 444 set rc 1 445 set errmsg "version conflict: {$::SQLITE_VERSION} vs. {$v}" 446 } 447 } 448 } 449 close $fd 450 if {$::BUILDONLY} { 451 incr ::NTESTCASE 452 if {$rc!=0} { 453 set errmsg "Build failed" 454 } 455 } elseif {!$seen} { 456 set rc 1 457 set errmsg "Test did not complete" 458 if {[file readable core]} { 459 append errmsg " - core file exists" 460 } 461 } 462 } 463 464 #-------------------------------------------------------------------------- 465 # This command is invoked as the [main] routine for scripts run with the 466 # "--slave" option. 467 # 468 # For each test (i.e. "configure && make test" execution), the master 469 # process spawns a process with the --slave option. It writes two lines 470 # to the slaves stdin. The first contains a single boolean value - the 471 # value of ::TRACE to use in the slave script. The second line contains a 472 # list in the same format as each element of the list passed to the 473 # [run_all_test_suites] command in the master process. 474 # 475 # The slave then runs the "configure && make test" commands specified. It 476 # exits successfully if the tests passes, or with a non-zero error code 477 # otherwise. 478 # 479 proc run_slave_test {} { 480 # Read global vars configuration from stdin. 481 set V [gets stdin] 482 foreach {::TRACE ::MSVC ::DRYRUN ::KEEPFILES} $V {} 483 484 # Read the test-suite configuration from stdin. 485 set T [gets stdin] 486 foreach {title dir configOpts testtarget makeOpts cflags opts} $T {} 487 488 # Create and switch to the test directory. 489 set normaldir [file normalize $dir] 490 set ::env(SQLITE_TMPDIR) $normaldir 491 trace_cmd file mkdir $dir 492 trace_cmd cd $dir 493 catch {file delete core} 494 catch {file delete test.log} 495 496 # Run the "./configure && make" commands. 497 set rc 0 498 set rc [catch [configureCommand $configOpts]] 499 if {!$rc} { 500 if {[info exists ::env(TCLSH_CMD)]} { 501 set savedEnv(TCLSH_CMD) $::env(TCLSH_CMD) 502 } else { 503 unset -nocomplain savedEnv(TCLSH_CMD) 504 } 505 set ::env(TCLSH_CMD) [file nativename [info nameofexecutable]] 506 507 # Create a file called "makecommand.sh" containing the text of 508 # the make command line. 509 catch { 510 set cmd [makeCommand $testtarget $makeOpts $cflags $opts] 511 set fd [open makecommand.sh w] 512 foreach e $cmd { 513 if {[string first " " $e]>=0} { 514 puts -nonewline $fd "\"$e\"" 515 } else { 516 puts -nonewline $fd $e 517 } 518 puts -nonewline $fd " " 519 } 520 puts $fd "" 521 close $fd 522 } msg 523 524 # Run the make command. 525 set rc [catch {trace_cmd exec {*}$cmd >>& test.log} msg] 526 if {[info exists savedEnv(TCLSH_CMD)]} { 527 set ::env(TCLSH_CMD) $savedEnv(TCLSH_CMD) 528 } else { 529 unset -nocomplain ::env(TCLSH_CMD) 530 } 531 } 532 533 # Clean up lots of extra files if --keep was not specified. 534 if {$::KEEPFILES==0} { cleanup $normaldir } 535 536 # Exis successfully if the test passed, or with a non-zero error code 537 # otherwise. 538 exit $rc 539 } 540 541 # This command is invoked in the master process each time a slave 542 # file-descriptor is readable. 543 # 544 proc slave_fileevent {fd T tm1} { 545 global G 546 foreach {title dir configOpts testtarget makeOpts cflags opts} $T {} 547 548 if {[eof $fd]} { 549 fconfigure $fd -blocking 1 550 set rc [catch { close $fd }] 551 552 set errmsg {} 553 set logfile [file join $dir test.log] 554 if {[file exists $logfile]} { 555 count_tests_and_errors [file join $dir test.log] rc errmsg 556 } elseif {$rc==0 && !$::DRYRUN} { 557 set rc 1 558 set errmsg "no test.log file..." 559 } 560 561 if {!$::TRACE} { 562 set tm2 [clock seconds] 563 set hours [expr {($tm2-$tm1)/3600}] 564 set minutes [expr {(($tm2-$tm1)/60)%60}] 565 set seconds [expr {($tm2-$tm1)%60}] 566 set tm [format (%02d:%02d:%02d) $hours $minutes $seconds] 567 568 if {$rc} { 569 set status FAIL 570 incr ::NERR 571 } else { 572 set status Ok 573 } 574 575 set n [string length $title] 576 if {$::PROGRESS_MSGS} { 577 PUTS "finished: ${title}[string repeat . [expr {53-$n}]] $status $tm" 578 } else { 579 PUTS "${title}[string repeat . [expr {63-$n}]] $status $tm" 580 } 581 if {$errmsg!=""} {PUTS " $errmsg"} 582 flush stdout 583 } 584 585 incr G(nJob) -1 586 } else { 587 set line [gets $fd] 588 if {[string trim $line] != ""} { 589 puts "Trace : $title - \"$line\"" 590 } 591 } 592 } 593 594 #-------------------------------------------------------------------------- 595 # The only argument passed to this function is a list of test-suites to 596 # run. Each "test-suite" is itself a list consisting of the following 597 # elements: 598 # 599 # * Test title (for display). 600 # * The name of the directory to run the test in. 601 # * The argument for [configureCommand] 602 # * The first argument for [makeCommand] 603 # * The second argument for [makeCommand] 604 # * The third argument for [makeCommand] 605 # 606 proc run_all_test_suites {alltests} { 607 global G 608 set tests $alltests 609 610 set G(nJob) 0 611 612 while {[llength $tests]>0 || $G(nJob)>0} { 613 if {$G(nJob)>=$::JOBS || [llength $tests]==0} { 614 vwait G(nJob) 615 } 616 617 if {[llength $tests]>0} { 618 set T [lindex $tests 0] 619 set tests [lrange $tests 1 end] 620 foreach {title dir configOpts testtarget makeOpts cflags opts} $T {} 621 if {$::PROGRESS_MSGS && !$::TRACE} { 622 set n [string length $title] 623 PUTS "starting: ${title} at [now]" 624 flush stdout 625 } 626 627 # Run the job. 628 # 629 set tm1 [clock seconds] 630 incr G(nJob) 631 set script [file normalize [info script]] 632 set fd [open "|[info nameofexecutable] $script --slave" r+] 633 fconfigure $fd -blocking 0 634 fileevent $fd readable [list slave_fileevent $fd $T $tm1] 635 puts $fd [list $::TRACE $::MSVC $::DRYRUN $::KEEPFILES] 636 puts $fd [list {*}$T] 637 flush $fd 638 } 639 } 640 } 641 642 proc add_test_suite {listvar name testtarget config} { 643 upvar $listvar alltests 644 645 # Tcl variable $opts is used to build up the value used to set the 646 # OPTS Makefile variable. Variable $cflags holds the value for 647 # CFLAGS. The makefile will pass OPTS to both gcc and lemon, but 648 # CFLAGS is only passed to gcc. 649 # 650 set makeOpts "" 651 set cflags [expr {$::MSVC ? "-Zi" : "-g"}] 652 set opts "" 653 set title ${name}($testtarget) 654 set configOpts $::WITHTCL 655 set skip 0 656 657 regsub -all {#[^\n]*\n} $config \n config 658 foreach arg $config { 659 if {$skip} { 660 set skip 0 661 continue 662 } 663 if {[regexp {^-[UD]} $arg]} { 664 lappend opts $arg 665 } elseif {[regexp {^[A-Z]+=} $arg]} { 666 lappend testtarget $arg 667 } elseif {[regexp {^if:([a-z]+)(.*)} $arg all key tail]} { 668 # Arguments of the form 'if:os=="Linux"' will cause the subsequent 669 # argument to be skipped if the $tcl_platform(os) is not "Linux", for 670 # example... 671 set skip [expr !(\$::tcl_platform($key)$tail)] 672 } elseif {[regexp {^--(enable|disable)-} $arg]} { 673 if {$::MSVC} { 674 if {$arg eq "--disable-amalgamation"} { 675 lappend makeOpts USE_AMALGAMATION=0 676 continue 677 } 678 if {$arg eq "--disable-shared"} { 679 lappend makeOpts USE_CRT_DLL=0 DYNAMIC_SHELL=0 680 continue 681 } 682 if {$arg eq "--enable-fts5"} { 683 lappend opts -DSQLITE_ENABLE_FTS5 684 continue 685 } 686 if {$arg eq "--enable-json1"} { 687 lappend opts -DSQLITE_ENABLE_JSON1 688 continue 689 } 690 if {$arg eq "--enable-shared"} { 691 lappend makeOpts USE_CRT_DLL=1 DYNAMIC_SHELL=1 692 continue 693 } 694 } 695 lappend configOpts $arg 696 } else { 697 if {$::MSVC} { 698 if {$arg eq "-g"} { 699 lappend cflags -Zi 700 continue 701 } 702 if {[regexp -- {^-O(\d+)$} $arg all level]} then { 703 lappend makeOpts OPTIMIZATIONS=$level 704 continue 705 } 706 } 707 lappend cflags $arg 708 } 709 } 710 711 # Disable sync to make testing faster. 712 # 713 lappend opts -DSQLITE_NO_SYNC=1 714 715 # Some configurations already set HAVE_USLEEP; in that case, skip it. 716 # 717 if {[lsearch -regexp $opts {^-DHAVE_USLEEP(?:=|$)}]==-1} { 718 lappend opts -DHAVE_USLEEP=1 719 } 720 721 # Add the define for this platform. 722 # 723 if {$::tcl_platform(platform)=="windows"} { 724 lappend opts -DSQLITE_OS_WIN=1 725 } else { 726 lappend opts -DSQLITE_OS_UNIX=1 727 } 728 729 # Set the sub-directory to use. 730 # 731 set dir [string tolower [string map {- _ " " _} $name]] 732 733 # Join option lists into strings, using space as delimiter. 734 # 735 set makeOpts [join $makeOpts " "] 736 set cflags [join $cflags " "] 737 set opts [join $opts " "] 738 739 lappend alltests [list \ 740 $title $dir $configOpts $testtarget $makeOpts $cflags $opts] 741 } 742 743 # The following procedure returns the "configure" command to be exectued for 744 # the current platform, which may be Windows (via MinGW, etc). 745 # 746 proc configureCommand {opts} { 747 if {$::MSVC} return [list]; # This is not needed for MSVC. 748 set result [list trace_cmd exec] 749 if {$::tcl_platform(platform)=="windows"} { 750 lappend result sh 751 } 752 lappend result $::SRCDIR/configure --enable-load-extension 753 foreach x $opts {lappend result $x} 754 lappend result >& test.log 755 } 756 757 # The following procedure returns the "make" command to be executed for the 758 # specified targets, compiler flags, and options. 759 # 760 proc makeCommand { targets makeOpts cflags opts } { 761 set result [list] 762 if {$::MSVC} { 763 set nmakeDir [file nativename $::SRCDIR] 764 set nmakeFile [file nativename [file join $nmakeDir Makefile.msc]] 765 lappend result nmake /f $nmakeFile TOP=$nmakeDir 766 set tclDir [file nativename [file normalize \ 767 [file dirname [file dirname [info nameofexecutable]]]]] 768 lappend result "TCLDIR=$tclDir" 769 if {[regexp {USE_STDCALL=1} $cflags]} { 770 lappend result USE_STDCALL=1 771 } 772 } else { 773 lappend result make 774 } 775 foreach makeOpt $makeOpts { 776 lappend result $makeOpt 777 } 778 lappend result clean 779 foreach target $targets { 780 lappend result $target 781 } 782 lappend result CFLAGS=$cflags OPTS=$opts 783 } 784 785 # The following procedure prints its arguments if ::TRACE is true. 786 # And it executes the command of its arguments in the calling context 787 # if ::DRYRUN is false. 788 # 789 proc trace_cmd {args} { 790 if {$::TRACE} { 791 PUTS $args 792 } 793 set res "" 794 if {!$::DRYRUN} { 795 set res [uplevel 1 $args] 796 } 797 return $res 798 } 799 800 801 # This proc processes the command line options passed to this script. 802 # Currently the only option supported is "-makefile", default 803 # "releasetest.mk". Set the ::MAKEFILE variable to the value of this 804 # option. 805 # 806 proc process_options {argv} { 807 set ::SRCDIR [file normalize [file dirname [file dirname $::argv0]]] 808 set ::QUICK 0 809 set ::MSVC 0 810 set ::BUILDONLY 0 811 set ::DRYRUN 0 812 set ::TRACE 0 813 set ::JOBS 1 814 set ::PROGRESS_MSGS 0 815 set ::WITHTCL {} 816 set ::FORCE 0 817 set ::KEEPFILES 0 ;# Keep extra files after test run 818 set config {} 819 set platform $::tcl_platform(os)-$::tcl_platform(machine) 820 821 for {set i 0} {$i < [llength $argv]} {incr i} { 822 set x [lindex $argv $i] 823 if {[regexp {^--[a-z]} $x]} {set x [string range $x 1 end]} 824 switch -glob -- $x { 825 -slave { 826 run_slave_test 827 exit 828 } 829 830 # Undocumented legacy option: --srcdir DIRECTORY 831 # 832 # DIRECTORY is the root of the SQLite checkout. This sets the 833 # SRCDIR global variable. But that variable is already set 834 # automatically so there really is no reason to have this option. 835 # 836 -srcdir { 837 incr i 838 set ::SRCDIR [file normalize [lindex $argv $i]] 839 } 840 841 -platform { 842 incr i 843 set platform [lindex $argv $i] 844 } 845 846 -jobs { 847 incr i 848 set ::JOBS [lindex $argv $i] 849 } 850 851 -progress { 852 set ::PROGRESS_MSGS 1 853 } 854 855 -quick { 856 set ::QUICK 1 857 } 858 -veryquick { 859 set ::QUICK 2 860 } 861 862 -config { 863 incr i 864 set config [lindex $argv $i] 865 } 866 867 -msvc { 868 set ::MSVC 1 869 } 870 871 -buildonly { 872 set ::BUILDONLY 1 873 } 874 875 -dryrun { 876 set ::DRYRUN 1 877 } 878 879 -force - 880 -f { 881 set ::FORCE 1 882 } 883 884 -trace { 885 set ::TRACE 1 886 } 887 888 -info { 889 PUTS "Command-line Options:" 890 PUTS " --srcdir $::SRCDIR" 891 PUTS " --platform [list $platform]" 892 PUTS " --config [list $config]" 893 if {$::QUICK} { 894 if {$::QUICK==1} {PUTS " --quick"} 895 if {$::QUICK==2} {PUTS " --veryquick"} 896 } 897 if {$::MSVC} {PUTS " --msvc"} 898 if {$::BUILDONLY} {PUTS " --buildonly"} 899 if {$::DRYRUN} {PUTS " --dryrun"} 900 if {$::TRACE} {PUTS " --trace"} 901 PUTS "\nAvailable --platform options:" 902 foreach y [lsort [array names ::Platforms]] { 903 PUTS " [list $y]" 904 } 905 PUTS "\nAvailable --config options:" 906 foreach y [lsort [array names ::Configs]] { 907 PUTS " [list $y]" 908 } 909 exit 910 } 911 912 -g { 913 lappend ::EXTRACONFIG [lindex $argv $i] 914 } 915 916 -keep { 917 set ::KEEPFILES 1 918 } 919 920 -with-tcl=* { 921 set ::WITHTCL -$x 922 } 923 924 -D* - 925 -O* - 926 -enable-* - 927 -disable-* - 928 *=* { 929 lappend ::EXTRACONFIG [lindex $argv $i] 930 } 931 932 default { 933 PUTSERR "" 934 PUTSERR [string trim $::USAGE_MESSAGE] 935 exit -1 936 } 937 } 938 } 939 940 if {0==[info exists ::Platforms($platform)]} { 941 PUTS "Unknown platform: $platform" 942 PUTSNNL "Set the -platform option to " 943 set print [list] 944 foreach p [array names ::Platforms] { 945 lappend print "\"$p\"" 946 } 947 lset print end "or [lindex $print end]" 948 PUTS "[join $print {, }]." 949 exit 950 } 951 952 if {$config!=""} { 953 if {[llength $config]==1} {lappend config fulltest} 954 set ::CONFIGLIST $config 955 } else { 956 if {$::JOBS>1} { 957 set ::CONFIGLIST {} 958 foreach {target zConfig} [lreverse $::Platforms($platform)] { 959 append ::CONFIGLIST [format " %-25s %s\n" \ 960 [list $zConfig] [list $target]] 961 } 962 } else { 963 set ::CONFIGLIST $::Platforms($platform) 964 } 965 } 966 PUTS "Running the following test configurations for $platform:" 967 PUTS " [string trim $::CONFIGLIST]" 968 PUTSNNL "Flags:" 969 if {$::PROGRESS_MSGS} {PUTSNNL " --progress"} 970 if {$::DRYRUN} {PUTSNNL " --dryrun"} 971 if {$::BUILDONLY} {PUTSNNL " --buildonly"} 972 if {$::MSVC} {PUTSNNL " --msvc"} 973 switch -- $::QUICK { 974 1 {PUTSNNL " --quick"} 975 2 {PUTSNNL " --veryquick"} 976 } 977 if {$::JOBS>1} {PUTSNNL " --jobs $::JOBS"} 978 PUTS "" 979 } 980 981 # Check to see if there are uncommitted changes in the SQLite source 982 # checkout. Exit if there are. Except: Do nothing if the --force 983 # flag is used. Also, ignore this test if the fossil binary is 984 # unavailable, or if the source tree is not a valid fossil checkout. 985 # 986 proc check_uncommitted {} { 987 if {$::FORCE} return 988 set pwd [pwd] 989 cd $::SRCDIR 990 if {[catch {exec fossil changes} res]==0 && [string trim $res]!=""} { 991 puts "ERROR: The check-out contains uncommitted changes:" 992 puts $res 993 puts "Use the -f or --force options to override" 994 exit 1 995 } 996 cd $pwd 997 } 998 999 # A test run has just finished in directory $dir. This command deletes all 1000 # non-essential files from the directory. Specifically, everything except 1001 # 1002 # * The "testfixture" and "sqlite3" binaries, 1003 # * The "test-out.log" and "test.log" log files. 1004 # 1005 proc cleanup {dir} { 1006 set K(testfixture) 1 1007 set K(testfixture.exe) 1 1008 set K(sqlite3) 1 1009 set K(sqlite3.exe) 1 1010 set K(test-out.txt) 1 1011 set K(test.log) 1 1012 1013 foreach f [glob -nocomplain [file join $dir *]] { 1014 set tail [file tail $f] 1015 if {[info exists K($tail)]==0} { 1016 file delete -force $f 1017 } 1018 } 1019 } 1020 1021 1022 # Main routine. 1023 # 1024 proc main {argv} { 1025 1026 # Process any command line options. 1027 set ::EXTRACONFIG {} 1028 process_options $argv 1029 if {!$::DRYRUN} check_uncommitted 1030 PUTS [string repeat * 79] 1031 1032 set ::NERR 0 1033 set ::NTEST 0 1034 set ::NTESTCASE 0 1035 set ::NERRCASE 0 1036 set ::SQLITE_VERSION {} 1037 set STARTTIME [clock seconds] 1038 foreach {zConfig target} $::CONFIGLIST { 1039 if {$::MSVC && ($zConfig eq "Sanitize" || "checksymbols" in $target 1040 || "valgrindtest" in $target)} { 1041 PUTS "Skipping $zConfig / $target for MSVC..." 1042 continue 1043 } 1044 if {$target ne "checksymbols"} { 1045 switch -- $::QUICK { 1046 1 {set target quicktest} 1047 2 {set target smoketest} 1048 } 1049 if {$::BUILDONLY} { 1050 set target testfixture 1051 if {$::tcl_platform(platform)=="windows"} { 1052 append target .exe 1053 } 1054 } 1055 } 1056 set config_options [concat $::Configs($zConfig) $::EXTRACONFIG] 1057 1058 incr NTEST 1059 add_test_suite all $zConfig $target $config_options 1060 1061 # If the configuration included the SQLITE_DEBUG option, then remove 1062 # it and run veryquick.test. If it did not include the SQLITE_DEBUG option 1063 # add it and run veryquick.test. 1064 if {$target!="checksymbols" && $target!="valgrindtest" 1065 && $target!="fuzzoomtest" && !$::BUILDONLY && $::QUICK<2} { 1066 set debug_idx [lsearch -glob $config_options -DSQLITE_DEBUG*] 1067 set xtarget $target 1068 regsub -all {fulltest[a-z]*} $xtarget test xtarget 1069 regsub -all {fuzzoomtest} $xtarget fuzztest xtarget 1070 if {$debug_idx < 0} { 1071 incr NTEST 1072 append config_options " -DSQLITE_DEBUG=1 -DSQLITE_EXTRA_IFNULLROW=1" 1073 add_test_suite all "${zConfig}_debug" $xtarget $config_options 1074 } else { 1075 incr NTEST 1076 regsub { *-DSQLITE_MEMDEBUG[^ ]* *} $config_options { } config_options 1077 regsub { *-DSQLITE_DEBUG[^ ]* *} $config_options { } config_options 1078 add_test_suite all "${zConfig}_ndebug" $xtarget $config_options 1079 } 1080 } 1081 } 1082 1083 run_all_test_suites $all 1084 1085 set elapsetime [expr {[clock seconds]-$STARTTIME}] 1086 set hr [expr {$elapsetime/3600}] 1087 set min [expr {($elapsetime/60)%60}] 1088 set sec [expr {$elapsetime%60}] 1089 set etime [format (%02d:%02d:%02d) $hr $min $sec] 1090 if {$::JOBS>1} {append etime " $::JOBS cores"} 1091 if {[catch {exec hostname} HNAME]==0} {append etime " on $HNAME"} 1092 PUTS [string repeat * 79] 1093 incr ::NERRCASE $::NERR 1094 PUTS "$::NERRCASE failures out of $::NTESTCASE tests in $etime" 1095 if {$::SQLITE_VERSION ne ""} { 1096 PUTS "SQLite $::SQLITE_VERSION" 1097 } 1098 } 1099 1100 main $argv