# These tests are design especially for the vfork() implementation # of exec where sh -c must be used and thus we must take extra care # in quoting arguments to exec. source [file dirname [info script]]/testing.tcl needs cmd exec testCmdConstraints signal wait alarm after # Jim needs [pipe] to implement [open |command] if {[testConstraint tcl]} { testConstraint pipe 1 } else { testCmdConstraints pipe } # Some Windows platforms (e.g. AppVeyor) produce ENOSPC rather than killing # the child with SIGPIPE). So turn off this test for that platform if {[info exists env(MSYSTEM)] && $env(MSYSTEM) eq "MINGW32"} { testConstraint nomingw32 0 } else { testConstraint nomingw32 1 } set d \" set s ' set b \\ array set saveenv [array get env] test exec2-1.1 "Quoting - Result" { exec echo ${d}double quoted${d} ${s}single quoted${s} ${b}backslash quoted${b} } "\"double\ quoted\"\ 'single quoted'\ \\backslash\ quoted\\" test exec2-1.2 "Quoting - Word Grouping" { string trim [exec echo ${d}double quoted${d} ${s}single quoted${s} ${b}backslash quoted${b} | wc -w] } {6} test exec2-2.1 "Add to exec environment" { set env(TESTENV) "the value" exec printenv | sed -n -e /^TESTENV=/p } {TESTENV=the value} test exec2-2.2 "Remove from exec environment" { set env(TESTENV2) "new value" unset env(TESTENV) exec printenv | sed -n -e /^TESTENV=/p } {} test exec2-2.3 "Remove all exec environment" { array unset env * exec printenv | sed -n -e /^TESTENV2=/p } {} test exec2-2.4 "Remove all env var" { unset -nocomplain env exec printenv | sed -n -e /^TESTENV2=/p } {} array set env [array get saveenv] test exec2-3.1 "close pipeline return value" pipe { set f [open |false] set rc [catch {close $f} msg opts] lassign [dict get $opts -errorcode] status pid exitcode list $rc $msg $status $exitcode } {1 {child process exited abnormally} CHILDSTATUS 1} test exec2-3.2 "close pipeline return value" -constraints {jim pipe nomingw32} -body { # Create a pipe and immediately close the read end lassign [pipe] r w close $r # Write more than 64KB which is maximum size of the pipe buffers # on all systems we have seen set bigstring [string repeat a 100000] set f [open [list |cat << $bigstring >$@w]] set rc [catch {close $f} msg opts] lassign [dict get $opts -errorcode] status pid exitcode list $rc $msg $status $exitcode } -match glob -result {1 {child killed*} CHILDKILLED SIGPIPE} test exec2-3.3 "close pipeline with SIGPIPE blocked" -constraints {pipe signal nomingw32} -body { # Create a pipe and immediately close the read end lassign [pipe] r w close $r signal block SIGPIPE # Write more than 64KB which is maximum size of the pipe buffers # on all systems we have seen set bigstring [string repeat a 100000] set f [open [list |cat << $bigstring >$@w 2>/dev/null]] set rc [catch {close $f} msg opts] lassign [dict get $opts -errorcode] status pid exitcode list $rc $msg $status $exitcode } -match glob -result {1 {child process exited*} CHILDSTATUS 1} -cleanup { signal default SIGPIPE } test exec2-3.4 "wait for background task" -constraints wait -body { set pid [exec sleep 0.1 &] lassign [wait $pid] status newpid exitcode if {$pid != $newpid} { error "Got wrong pid from wait" } else { list $status $exitcode } } -result {CHILDSTATUS 0} test exec2-4.1 {redirect from invalid filehandle} -body { exec cat <@bogus } -returnCodes error -match glob -result {*"bogus"} test exec2-4.2 {env is invalid dict} -constraints jim -body { set saveenv $env lappend env bogus catch {exec pwd} } -result {0} -cleanup { set env $saveenv } test exec2-4.3 {signalled process during foreground exec} -constraints {jim alarm} -body { # We need to exec a pipeline and then have one process # be killed by a signal exec [info nameofexecutable] -e {alarm 0.1; sleep 0.5} } -returnCodes error -result {child killed by signal SIGALRM} test exec2-4.4 {exec - consecutive |} -body { exec echo | | test } -returnCodes error -result {illegal use of | or |& in command} test exec2-4.5 {exec - consecutive | with &} -body { exec echo | | test & } -returnCodes error -result {illegal use of | or |& in command} test exec2-4.6 {exec - illegal channel} -body { exec echo hello >@nonexistent } -returnCodes error -match glob -result {*"nonexistent"} test exec2-5.1 {wait with invalid pid} wait { wait 9999999 } {NONE -1 -1} test exec2-5.2 {wait with invalid pid} -constraints wait -body { wait blah } -returnCodes error -result {expected integer but got "blah"} test exec2-5.3 {wait - bad args} -constraints wait -body { wait too many args } -returnCodes error -result {wrong # args: should be "wait ?-nohang? ?pid?"} test exec2-5.4 {wait -nohang} -constraints wait -body { set pid [exec sleep 0.2 &] # first wait will do nothing as the process is not finished wait -nohang $pid wait $pid } -match glob -result {CHILDSTATUS * 0} test exec2-5.5 {wait for all children} -constraints {after jim} -body { # We want to have children finish at different times # so that we test the handling of the wait table foreach i {0.1 0.2 0.6 0.5 0.4 0.3} { exec sleep $i & } # reap zombies, there should not be any wait after 300 # reap zombies, 2-3 should be finished now wait after 400 # reap zombies, all processes should be finished now wait } -result {} testreport