1e264d983Sdan# 2010 April 14 2e264d983Sdan# 3e264d983Sdan# The author disclaims copyright to this source code. In place of 4e264d983Sdan# a legal notice, here is a blessing: 5e264d983Sdan# 6e264d983Sdan# May you do good and not evil. 7e264d983Sdan# May you find forgiveness for yourself and forgive others. 8e264d983Sdan# May you share freely, never taking more than you give. 9e264d983Sdan# 10e264d983Sdan#*********************************************************************** 11e264d983Sdan# This file contains code used by several different test scripts. The 12e264d983Sdan# code in this file allows testfixture to control another process (or 13e264d983Sdan# processes) to test locking. 14e264d983Sdan# 15e264d983Sdan 16a4a9095eSdanproc do_multiclient_test {varname script} { 17a4a9095eSdan 18*94e95ea4Sdan foreach {tn code} [list 1 { 1925568441Sdan if {[info exists ::G(valgrind)]} { db close ; continue } 20a4a9095eSdan set ::code2_chan [launch_testfixture] 21a4a9095eSdan set ::code3_chan [launch_testfixture] 22a4a9095eSdan proc code2 {tcl} { testfixture $::code2_chan $tcl } 23a4a9095eSdan proc code3 {tcl} { testfixture $::code3_chan $tcl } 24*94e95ea4Sdan } 2 { 25a4a9095eSdan proc code2 {tcl} { uplevel #0 $tcl } 26a4a9095eSdan proc code3 {tcl} { uplevel #0 $tcl } 27a4a9095eSdan }] { 28*94e95ea4Sdan # Do not run multi-process tests with the unix-excl VFS. 29*94e95ea4Sdan # 30*94e95ea4Sdan if {$tn==1 && [permutation]=="unix-excl"} continue 31*94e95ea4Sdan 32a4a9095eSdan faultsim_delete_and_reopen 335653e4daSdan 345653e4daSdan proc code1 {tcl} { uplevel #0 $tcl } 35a4a9095eSdan 36a4a9095eSdan # Open connections [db2] and [db3]. Depending on which iteration this 37a4a9095eSdan # is, the connections may be created in this interpreter, or in 38a4a9095eSdan # interpreters running in other OS processes. As such, the [db2] and [db3] 39a4a9095eSdan # commands should only be accessed within [code2] and [code3] blocks, 40a4a9095eSdan # respectively. 41a4a9095eSdan # 42a4a9095eSdan eval $code 43a4a9095eSdan code2 { sqlite3 db2 test.db } 44a4a9095eSdan code3 { sqlite3 db3 test.db } 45a4a9095eSdan 46a4a9095eSdan # Shorthand commands. Execute SQL using database connection [db2] or 47a4a9095eSdan # [db3]. Return the results. 48a4a9095eSdan # 49a4a9095eSdan proc sql1 {sql} { db eval $sql } 50a4a9095eSdan proc sql2 {sql} { code2 [list db2 eval $sql] } 51a4a9095eSdan proc sql3 {sql} { code3 [list db3 eval $sql] } 52a4a9095eSdan 53a4a9095eSdan proc csql1 {sql} { list [catch { sql1 $sql } msg] $msg } 54a4a9095eSdan proc csql2 {sql} { list [catch { sql2 $sql } msg] $msg } 55a4a9095eSdan proc csql3 {sql} { list [catch { sql3 $sql } msg] $msg } 56a4a9095eSdan 57a4a9095eSdan uplevel set $varname $tn 58a4a9095eSdan uplevel $script 59a4a9095eSdan 604edc6bf3Sdan catch { code2 { db2 close } } 614edc6bf3Sdan catch { code3 { db3 close } } 62a4a9095eSdan catch { close $::code2_chan } 63a4a9095eSdan catch { close $::code3_chan } 642969a587Sdan catch { db close } 65a4a9095eSdan } 66a4a9095eSdan} 67a4a9095eSdan 68e264d983Sdan# Launch another testfixture process to be controlled by this one. A 69e264d983Sdan# channel name is returned that may be passed as the first argument to proc 70e264d983Sdan# 'testfixture' to execute a command. The child testfixture process is shut 71e264d983Sdan# down by closing the channel. 728311c47dSdanproc launch_testfixture {{prg ""}} { 7347ee386fSdan write_main_loop 744f05e38fSdan if {$prg eq ""} { set prg [info nameofexec] } 754f05e38fSdan if {$prg eq ""} { set prg testfixture } 763d579059Sdan if {[file tail $prg]==$prg} { set prg [file join . $prg] } 77e264d983Sdan set chan [open "|$prg tf_main.tcl" r+] 78e264d983Sdan fconfigure $chan -buffering line 798311c47dSdan set rc [catch { 8031f98fc8Sdan testfixture $chan "sqlite3_test_control_pending_byte $::sqlite_pending_byte" 818311c47dSdan }] 828311c47dSdan if {$rc} { 838311c47dSdan testfixture $chan "set ::sqlite_pending_byte $::sqlite_pending_byte" 848311c47dSdan } 85e264d983Sdan return $chan 86e264d983Sdan} 87e264d983Sdan 88e264d983Sdan# Execute a command in a child testfixture process, connected by two-way 89e264d983Sdan# channel $chan. Return the result of the command, or an error message. 90e91a54e1Sdan# 91363fc9e7Sdanproc testfixture {chan cmd args} { 92363fc9e7Sdan 93363fc9e7Sdan if {[llength $args] == 0} { 94363fc9e7Sdan fconfigure $chan -blocking 1 95e264d983Sdan puts $chan $cmd 96e264d983Sdan puts $chan OVER 97363fc9e7Sdan 98e264d983Sdan set r "" 99e264d983Sdan while { 1 } { 100e264d983Sdan set line [gets $chan] 101e264d983Sdan if { $line == "OVER" } { 102e91a54e1Sdan set res [lindex $r 1] 103e91a54e1Sdan if { [lindex $r 0] } { error $res } 104e91a54e1Sdan return $res 105e264d983Sdan } 106e264d983Sdan if {[eof $chan]} { 107e264d983Sdan return "ERROR: Child process hung up" 108e264d983Sdan } 109e264d983Sdan append r $line 110e264d983Sdan } 111363fc9e7Sdan return $r 112363fc9e7Sdan } else { 113363fc9e7Sdan set ::tfnb($chan) "" 114363fc9e7Sdan fconfigure $chan -blocking 0 -buffering none 115363fc9e7Sdan puts $chan $cmd 116363fc9e7Sdan puts $chan OVER 117363fc9e7Sdan fileevent $chan readable [list testfixture_script_cb $chan [lindex $args 0]] 118363fc9e7Sdan return "" 119363fc9e7Sdan } 120363fc9e7Sdan} 121363fc9e7Sdan 122363fc9e7Sdanproc testfixture_script_cb {chan script} { 123363fc9e7Sdan if {[eof $chan]} { 124363fc9e7Sdan append ::tfnb($chan) "ERROR: Child process hung up" 125363fc9e7Sdan set line "OVER" 126363fc9e7Sdan } else { 127363fc9e7Sdan set line [gets $chan] 128363fc9e7Sdan } 129363fc9e7Sdan 130363fc9e7Sdan if { $line == "OVER" } { 131363fc9e7Sdan uplevel #0 $script [list [lindex $::tfnb($chan) 1]] 132363fc9e7Sdan unset ::tfnb($chan) 133363fc9e7Sdan fileevent $chan readable "" 134363fc9e7Sdan } else { 135363fc9e7Sdan append ::tfnb($chan) $line 136363fc9e7Sdan } 137e264d983Sdan} 138e264d983Sdan 1395e0ce87aSdanproc testfixture_nb_cb {varname chan} { 140f9b76710Sdan if {[eof $chan]} { 141f9b76710Sdan append ::tfnb($chan) "ERROR: Child process hung up" 142f9b76710Sdan set line "OVER" 143f9b76710Sdan } else { 1445e0ce87aSdan set line [gets $chan] 145f9b76710Sdan } 146f9b76710Sdan 1475e0ce87aSdan if { $line == "OVER" } { 148e91a54e1Sdan set $varname [lindex $::tfnb($chan) 1] 1495e0ce87aSdan unset ::tfnb($chan) 1505e0ce87aSdan close $chan 1515e0ce87aSdan } else { 1525e0ce87aSdan append ::tfnb($chan) $line 1535e0ce87aSdan } 1545e0ce87aSdan} 1555e0ce87aSdan 1565e0ce87aSdanproc testfixture_nb {varname cmd} { 1575e0ce87aSdan set chan [launch_testfixture] 1585e0ce87aSdan set ::tfnb($chan) "" 1595e0ce87aSdan fconfigure $chan -blocking 0 -buffering none 1605e0ce87aSdan puts $chan $cmd 1615e0ce87aSdan puts $chan OVER 1625e0ce87aSdan fileevent $chan readable [list testfixture_nb_cb $varname $chan] 1635e0ce87aSdan return "" 1645e0ce87aSdan} 1655e0ce87aSdan 166e264d983Sdan# Write the main loop for the child testfixture processes into file 167e264d983Sdan# tf_main.tcl. The parent (this script) interacts with the child processes 168e264d983Sdan# via a two way pipe. The parent writes a script to the stdin of the child 169e264d983Sdan# process, followed by the word "OVER" on a line of its own. The child 170e264d983Sdan# process evaluates the script and writes the results to stdout, followed 171e264d983Sdan# by an "OVER" of its own. 17247ee386fSdan# 17347ee386fSdanset main_loop_written 0 17447ee386fSdanproc write_main_loop {} { 17547ee386fSdan if {$::main_loop_written} return 17647ee386fSdan set wrapper "" 17747ee386fSdan if {[sqlite3 -has-codec] && [info exists ::do_not_use_codec]==0} { 17847ee386fSdan set wrapper " 17947ee386fSdan rename sqlite3 sqlite_orig 18047ee386fSdan proc sqlite3 {args} {[info body sqlite3]} 18147ee386fSdan " 18247ee386fSdan } 18347ee386fSdan 18447ee386fSdan set fd [open tf_main.tcl w] 18547ee386fSdan puts $fd [string map [list %WRAPPER% $wrapper] { 18647ee386fSdan %WRAPPER% 187e264d983Sdan set script "" 188e264d983Sdan while {![eof stdin]} { 189e264d983Sdan flush stdout 190e264d983Sdan set line [gets stdin] 191e264d983Sdan if { $line == "OVER" } { 1925e0ce87aSdan set rc [catch {eval $script} result] 193e91a54e1Sdan puts [list $rc $result] 194e264d983Sdan puts OVER 195e264d983Sdan flush stdout 196e264d983Sdan set script "" 197e264d983Sdan } else { 198e264d983Sdan append script $line 1995e0ce87aSdan append script "\n" 200e264d983Sdan } 201e264d983Sdan } 20247ee386fSdan }] 20347ee386fSdan close $fd 20447ee386fSdan set main_loop_written 1 205e264d983Sdan} 20647ee386fSdan 207