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 16*a4a9095eSdanproc do_multiclient_test {varname script} { 17*a4a9095eSdan 18*a4a9095eSdan foreach code [list { 19*a4a9095eSdan set ::code2_chan [launch_testfixture] 20*a4a9095eSdan set ::code3_chan [launch_testfixture] 21*a4a9095eSdan proc code2 {tcl} { testfixture $::code2_chan $tcl } 22*a4a9095eSdan proc code3 {tcl} { testfixture $::code3_chan $tcl } 23*a4a9095eSdan set tn 1 24*a4a9095eSdan } { 25*a4a9095eSdan proc code2 {tcl} { uplevel #0 $tcl } 26*a4a9095eSdan proc code3 {tcl} { uplevel #0 $tcl } 27*a4a9095eSdan set tn 2 28*a4a9095eSdan }] { 29*a4a9095eSdan faultsim_delete_and_reopen 30*a4a9095eSdan 31*a4a9095eSdan # Open connections [db2] and [db3]. Depending on which iteration this 32*a4a9095eSdan # is, the connections may be created in this interpreter, or in 33*a4a9095eSdan # interpreters running in other OS processes. As such, the [db2] and [db3] 34*a4a9095eSdan # commands should only be accessed within [code2] and [code3] blocks, 35*a4a9095eSdan # respectively. 36*a4a9095eSdan # 37*a4a9095eSdan eval $code 38*a4a9095eSdan code2 { sqlite3 db2 test.db } 39*a4a9095eSdan code3 { sqlite3 db3 test.db } 40*a4a9095eSdan 41*a4a9095eSdan # Shorthand commands. Execute SQL using database connection [db2] or 42*a4a9095eSdan # [db3]. Return the results. 43*a4a9095eSdan # 44*a4a9095eSdan proc sql1 {sql} { db eval $sql } 45*a4a9095eSdan proc sql2 {sql} { code2 [list db2 eval $sql] } 46*a4a9095eSdan proc sql3 {sql} { code3 [list db3 eval $sql] } 47*a4a9095eSdan 48*a4a9095eSdan proc csql1 {sql} { list [catch { sql1 $sql } msg] $msg } 49*a4a9095eSdan proc csql2 {sql} { list [catch { sql2 $sql } msg] $msg } 50*a4a9095eSdan proc csql3 {sql} { list [catch { sql3 $sql } msg] $msg } 51*a4a9095eSdan 52*a4a9095eSdan uplevel set $varname $tn 53*a4a9095eSdan uplevel $script 54*a4a9095eSdan 55*a4a9095eSdan code2 { db2 close } 56*a4a9095eSdan code3 { db3 close } 57*a4a9095eSdan catch { close $::code2_chan } 58*a4a9095eSdan catch { close $::code3_chan } 59*a4a9095eSdan } 60*a4a9095eSdan} 61*a4a9095eSdan 62e264d983Sdan# Launch another testfixture process to be controlled by this one. A 63e264d983Sdan# channel name is returned that may be passed as the first argument to proc 64e264d983Sdan# 'testfixture' to execute a command. The child testfixture process is shut 65e264d983Sdan# down by closing the channel. 66e264d983Sdanproc launch_testfixture {} { 67e264d983Sdan set prg [info nameofexec] 68e264d983Sdan if {$prg eq ""} { 69e264d983Sdan set prg [file join . testfixture] 70e264d983Sdan } 71e264d983Sdan set chan [open "|$prg tf_main.tcl" r+] 72e264d983Sdan fconfigure $chan -buffering line 7331f98fc8Sdan testfixture $chan "sqlite3_test_control_pending_byte $::sqlite_pending_byte" 74e264d983Sdan return $chan 75e264d983Sdan} 76e264d983Sdan 77e264d983Sdan# Execute a command in a child testfixture process, connected by two-way 78e264d983Sdan# channel $chan. Return the result of the command, or an error message. 79e91a54e1Sdan# 80e264d983Sdanproc testfixture {chan cmd} { 81e264d983Sdan puts $chan $cmd 82e264d983Sdan puts $chan OVER 83e264d983Sdan set r "" 84e264d983Sdan while { 1 } { 85e264d983Sdan set line [gets $chan] 86e264d983Sdan if { $line == "OVER" } { 87e91a54e1Sdan set res [lindex $r 1] 88e91a54e1Sdan if { [lindex $r 0] } { error $res } 89e91a54e1Sdan return $res 90e264d983Sdan } 91e264d983Sdan if {[eof $chan]} { 92e264d983Sdan return "ERROR: Child process hung up" 93e264d983Sdan } 94e264d983Sdan append r $line 95e264d983Sdan } 96e264d983Sdan} 97e264d983Sdan 985e0ce87aSdanproc testfixture_nb_cb {varname chan} { 99f9b76710Sdan if {[eof $chan]} { 100f9b76710Sdan append ::tfnb($chan) "ERROR: Child process hung up" 101f9b76710Sdan set line "OVER" 102f9b76710Sdan } else { 1035e0ce87aSdan set line [gets $chan] 104f9b76710Sdan } 105f9b76710Sdan 1065e0ce87aSdan if { $line == "OVER" } { 107e91a54e1Sdan set $varname [lindex $::tfnb($chan) 1] 1085e0ce87aSdan unset ::tfnb($chan) 1095e0ce87aSdan close $chan 1105e0ce87aSdan } else { 1115e0ce87aSdan append ::tfnb($chan) $line 1125e0ce87aSdan } 1135e0ce87aSdan} 1145e0ce87aSdan 1155e0ce87aSdanproc testfixture_nb {varname cmd} { 1165e0ce87aSdan set chan [launch_testfixture] 1175e0ce87aSdan set ::tfnb($chan) "" 1185e0ce87aSdan fconfigure $chan -blocking 0 -buffering none 1195e0ce87aSdan puts $chan $cmd 1205e0ce87aSdan puts $chan OVER 1215e0ce87aSdan fileevent $chan readable [list testfixture_nb_cb $varname $chan] 1225e0ce87aSdan return "" 1235e0ce87aSdan} 1245e0ce87aSdan 125e264d983Sdan# Write the main loop for the child testfixture processes into file 126e264d983Sdan# tf_main.tcl. The parent (this script) interacts with the child processes 127e264d983Sdan# via a two way pipe. The parent writes a script to the stdin of the child 128e264d983Sdan# process, followed by the word "OVER" on a line of its own. The child 129e264d983Sdan# process evaluates the script and writes the results to stdout, followed 130e264d983Sdan# by an "OVER" of its own. 131e264d983Sdanset f [open tf_main.tcl w] 132e264d983Sdanputs $f { 133e264d983Sdan set l [open log w] 134e264d983Sdan set script "" 135e264d983Sdan while {![eof stdin]} { 136e264d983Sdan flush stdout 137e264d983Sdan set line [gets stdin] 138e264d983Sdan puts $l "READ $line" 139e264d983Sdan if { $line == "OVER" } { 1405e0ce87aSdan set rc [catch {eval $script} result] 141e91a54e1Sdan puts [list $rc $result] 142e91a54e1Sdan puts $l "WRITE [list $rc $result]" 143e264d983Sdan puts OVER 144e264d983Sdan puts $l "WRITE OVER" 145e264d983Sdan flush stdout 146e264d983Sdan set script "" 147e264d983Sdan } else { 148e264d983Sdan append script $line 1495e0ce87aSdan append script "\n" 150e264d983Sdan } 151e264d983Sdan } 152e264d983Sdan close $l 153e264d983Sdan} 154e264d983Sdanclose $f 155