aboutsummaryrefslogtreecommitdiff
path: root/tests/exec2.test
blob: 9daef58c17debd1f0f5f226ab0f0be24718a3ff2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# 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
constraint cmd signal
constraint cmd wait
constraint cmd alarm
constraint cmd after

# Jim needs [pipe] to implement [open |command]
if {[testConstraint tcl]} {
	testConstraint pipe 1
} else {
	constraint cmd pipe
}

# Some Windows platforms (e.g. AppVeyor) produce ENOSPC rather than killing
# the child with SIGPIPE). So turn off this test for that platform
constraint expr nomingw32 {![info exists env(MSYSTEM)] || $env(MSYSTEM) ne "MINGW32"}

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 {pipe signal nomingw32} -body {
	signal ignore 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]]
	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 {
	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 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 "wait $pid returned pid=$newpid"
	} 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 {}

test exec2-5.6 {wait -1 to wait for any child} -constraints {after jim nomingw32} -body {
	set pid [exec sleep 0.1 &]
	# Now wait for any child
	lassign [wait -1] status waitpid code
	list $status $($waitpid == $pid) $code
} -result {CHILDSTATUS 1 0}

testreport