2010-04-14 18:06:50 +00:00
# 2010 April 14
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
# ***********************************************************************
# This file contains code used by several different test scripts. The
# code in this file allows testfixture to control another process (or
# processes) to test locking.
#
2010-06-15 19:07:42 +00:00
proc do_multiclient_test { varname script} {
2018-12-24 15:22:47 +00:00
foreach { tn code} [ list 1 {
2010-12-03 10:32:06 +00:00
if { [ info exists : : G( valgrind ) ] } { db close ; continue }
2010-06-15 19:07:42 +00:00
set : : code2_chan [ launch_testfixture ]
set : : code3_chan [ launch_testfixture ]
proc code2 { tcl } { testfixture $::code2_chan $tcl }
proc code3 { tcl } { testfixture $::code3_chan $tcl }
2018-12-24 15:22:47 +00:00
} 2 {
2010-06-15 19:07:42 +00:00
proc code2 { tcl } { uplevel # 0 $tcl }
proc code3 { tcl } { uplevel # 0 $tcl }
} ] {
2018-12-24 15:22:47 +00:00
# Do not run multi-process tests with the unix-excl VFS.
#
if { $tn == 1 && [ permutation ] == " u n i x - e x c l " } continue
2010-06-15 19:07:42 +00:00
faultsim_delete_and_reopen
2010-08-12 11:25:47 +00:00
proc code1 { tcl } { uplevel # 0 $tcl }
2010-06-15 19:07:42 +00:00
# Open connections [db2] and [db3]. Depending on which iteration this
# is, the connections may be created in this interpreter, or in
# interpreters running in other OS processes. As such, the [db2] and [db3]
# commands should only be accessed within [code2] and [code3] blocks,
# respectively.
#
eval $code
code2 { sqlite3 db2 test.db }
code3 { sqlite3 db3 test.db }
# Shorthand commands. Execute SQL using database connection [db2] or
# [db3]. Return the results.
#
proc sql1 { sql } { db eval $sql }
proc sql2 { sql } { code2 [ list db2 eval $sql ] }
proc sql3 { sql } { code3 [ list db3 eval $sql ] }
proc csql1 { sql } { list [ catch { sql1 $sql } msg] $msg }
proc csql2 { sql } { list [ catch { sql2 $sql } msg] $msg }
proc csql3 { sql } { list [ catch { sql3 $sql } msg] $msg }
uplevel set $varname $tn
uplevel $script
2011-05-10 17:31:29 +00:00
catch { code2 { db2 close } }
catch { code3 { db3 close } }
2010-06-15 19:07:42 +00:00
catch { close $::code2_chan }
catch { close $::code3_chan }
2010-09-15 11:42:04 +00:00
catch { db close }
2010-06-15 19:07:42 +00:00
}
}
2010-04-14 18:06:50 +00:00
# Launch another testfixture process to be controlled by this one. A
# channel name is returned that may be passed as the first argument to proc
# 'testfixture' to execute a command. The child testfixture process is shut
# down by closing the channel.
2010-08-19 11:05:53 +00:00
proc launch_testfixture { { prg " " } } {
2010-06-22 15:18:44 +00:00
write_main_loop
2010-08-20 12:43:01 +00:00
if { $prg eq " " } { set prg [ info nameofexec] }
if { $prg eq " " } { set prg testfixture }
2010-08-20 12:31:30 +00:00
if { [ file tail $prg ] == $prg } { set prg [ file join . $prg ] }
2010-04-14 18:06:50 +00:00
set chan [ open " | $ p r g t f _ m a i n . t c l " r+ ]
fconfigure $chan - buffering line
2010-08-19 11:05:53 +00:00
set rc [ catch {
testfixture $chan " s q l i t e 3 _ t e s t _ c o n t r o l _ p e n d i n g _ b y t e $ : : s q l i t e _ p e n d i n g _ b y t e "
} ]
if { $rc } {
testfixture $chan " s e t : : s q l i t e _ p e n d i n g _ b y t e $ : : s q l i t e _ p e n d i n g _ b y t e "
}
2010-04-14 18:06:50 +00:00
return $chan
}
# Execute a command in a child testfixture process, connected by two-way
# channel $chan. Return the result of the command, or an error message.
2010-06-15 17:44:47 +00:00
#
2015-03-17 16:01:29 +00:00
proc testfixture { chan cmd args} {
if { [ llength $args ] == 0 } {
fconfigure $chan - blocking 1
puts $chan $cmd
puts $chan OVER
set r " "
while { 1 } {
set line [ gets $chan ]
if { $line == " O V E R " } {
set res [ lindex $r 1 ]
if { [ lindex $r 0 ] } { error $res }
return $res
}
if { [ eof $chan ] } {
return " E R R O R : C h i l d p r o c e s s h u n g u p "
}
append r $line
2010-04-14 18:06:50 +00:00
}
2015-03-17 16:01:29 +00:00
return $r
} else {
set : : tfnb( $chan ) " "
fconfigure $chan - blocking 0 - buffering none
puts $chan $cmd
puts $chan OVER
fileevent $chan readable [ list testfixture_script_cb $chan [ lindex $args 0 ] ]
return " "
}
}
proc testfixture_script_cb { chan script} {
if { [ eof $chan ] } {
append : : tfnb( $chan ) " E R R O R : C h i l d p r o c e s s h u n g u p "
set line " O V E R "
} else {
set line [ gets $chan ]
}
if { $line == " O V E R " } {
uplevel # 0 $script [ list [ lindex $::tfnb ( $chan ) 1 ] ]
unset : : tfnb( $chan )
fileevent $chan readable " "
} else {
append : : tfnb( $chan ) $line
2010-04-14 18:06:50 +00:00
}
}
2010-04-28 17:48:44 +00:00
proc testfixture_nb_cb { varname chan} {
2010-06-01 14:12:45 +00:00
if { [ eof $chan ] } {
append : : tfnb( $chan ) " E R R O R : C h i l d p r o c e s s h u n g u p "
set line " O V E R "
} else {
set line [ gets $chan ]
}
2010-04-28 17:48:44 +00:00
if { $line == " O V E R " } {
2010-06-15 17:44:47 +00:00
set $varname [ lindex $::tfnb ( $chan ) 1 ]
2010-04-28 17:48:44 +00:00
unset : : tfnb( $chan )
close $chan
} else {
append : : tfnb( $chan ) $line
}
}
proc testfixture_nb { varname cmd} {
set chan [ launch_testfixture ]
set : : tfnb( $chan ) " "
fconfigure $chan - blocking 0 - buffering none
puts $chan $cmd
puts $chan OVER
fileevent $chan readable [ list testfixture_nb_cb $varname $chan ]
return " "
}
2010-04-14 18:06:50 +00:00
# Write the main loop for the child testfixture processes into file
# tf_main.tcl. The parent (this script) interacts with the child processes
# via a two way pipe. The parent writes a script to the stdin of the child
# process, followed by the word "OVER" on a line of its own. The child
# process evaluates the script and writes the results to stdout, followed
# by an "OVER" of its own.
2010-06-22 15:18:44 +00:00
#
set main_loop_written 0
proc write_main_loop { } {
if { $::main_loop_written } return
set wrapper " "
if { [ sqlite3 - has-codec] && [ info exists : : do_not_use_codec] == 0 } {
set wrapper "
rename sqlite3 sqlite_orig
proc sqlite3 { args } { [ info body sqlite3] }
"
}
set fd [ open tf_main.tcl w]
puts $fd [ string map [ list % WRAPPER% $wrapper ] {
% WRAPPER %
set script " "
while { ! [ eof stdin] } {
2010-04-14 18:06:50 +00:00
flush stdout
2010-06-22 15:18:44 +00:00
set line [ gets stdin]
if { $line == " O V E R " } {
set rc [ catch { eval $script } result]
puts [ list $rc $result ]
puts OVER
flush stdout
set script " "
} else {
append script $line
append script " \n "
}
2010-04-14 18:06:50 +00:00
}
2010-06-22 15:18:44 +00:00
} ]
close $fd
set main_loop_written 1
2010-04-14 18:06:50 +00:00
}
2010-06-22 15:18:44 +00:00