2
2
"""
3
3
Test OSH in interactive mode.
4
4
5
- Usage ( run from project root) :
5
+ To invoke this file, run the shell wrapper :
6
6
7
- test/interactive.py
7
+ test/interactive.sh all
8
8
9
9
Env Vars:
10
10
- OSH_TEST_INTERACTIVE_SHELL: override default shell path (default, bin/osh)
26
26
import sys
27
27
import time
28
28
29
+ from test import spec_lib # Using this for a common interface
30
+
29
31
30
32
SHELL = os .environ .get ("OSH_TEST_INTERACTIVE_SHELL" , "bin/osh" )
31
33
TIMEOUT = int (os .environ .get ("OSH_TEST_INTERACTIVE_TIMEOUT" , 3 ))
@@ -42,22 +44,22 @@ def get_pid_by_name(name):
42
44
# XXX: make sure this is restricted to subprocesses under us.
43
45
# This could be problematic on the continuous build if many tests are running
44
46
# in parallel.
45
- output = pexpect .run ('pgrep --exact --newest cat' )
47
+ output = pexpect .run ('pgrep --exact --newest %s' % name )
46
48
return int (output .split ()[- 1 ])
47
49
48
50
51
+ def send_signal (name , sig_num ):
52
+ """Kill the most recent process matching `name`."""
53
+ os .kill (get_pid_by_name (name ), sig_num )
54
+
55
+
49
56
# XXX: osh.sendcontrol("z") does not suspend the foreground process :(
50
57
#
51
58
# why does osh.sendcontrol("c") generate SIGINT, while osh.sendcontrol("z")
52
59
# appears to do nothing?
53
60
def stop_process__hack (name ):
54
61
"""Send sigstop to the most recent process matching `name`"""
55
- os .kill (get_pid_by_name (name ), signal .SIGSTOP )
56
-
57
-
58
- def kill_process (name ):
59
- """Kill the most recent process matching `name`."""
60
- os .kill (get_pid_by_name (name ), signal .SIGINT )
62
+ send_signal (name , signal .SIGSTOP )
61
63
62
64
63
65
class InteractiveTest (object ):
@@ -78,18 +80,27 @@ def __init__(self, description, program=SHELL):
78
80
self .description = description
79
81
80
82
def __enter__ (self ):
81
- if DEBUG :
82
- print (self .description )
83
- else :
84
- print (self .description , end = '' )
83
+ if 0 :
84
+ if DEBUG :
85
+ print (self .description )
86
+ else :
87
+ print (self .description , end = '' )
85
88
86
89
#env = dict(os.environ)
87
90
#env['PS1'] = 'test$ '
88
91
env = None
89
92
93
+ sh_argv = ['--rcfile' , '/dev/null' ]
94
+
95
+ # Why the heck is --norc different from --rcfile /dev/null in bash??? This
96
+ # makes it so the prompt of the parent shell doesn't leak. Very annoying.
97
+ if self .program == 'bash' :
98
+ sh_argv .append ('--norc' )
99
+ #print(sh_argv)
100
+
90
101
# Python 3: encoding required
91
102
self .shell = pexpect .spawn (
92
- self .program , [ '--rcfile' , '/dev/null' ] , env = env , encoding = 'utf-8' ,
103
+ self .program , sh_argv , env = env , encoding = 'utf-8' ,
93
104
timeout = TIMEOUT )
94
105
95
106
# suppress output when DEBUG is not set.
@@ -118,111 +129,199 @@ def __exit__(self, t, v, tb):
118
129
pass
119
130
120
131
121
- def main (argv ):
122
- with InteractiveTest ('Ctrl-C during external command' ) as osh :
123
- osh .sendline ('sleep 5' )
124
132
125
- time .sleep (0.1 )
126
- osh .sendintr () # SIGINT
133
+ CASES = []
134
+
135
+ def register (skip_shells = None ):
136
+ if skip_shells is None :
137
+ skip_shells = []
138
+
139
+ def decorator (func ):
140
+ CASES .append ((func .__doc__ , func , skip_shells ))
141
+ return func
142
+ return decorator
143
+
144
+
145
+ # TODO: Make this pass in OSH
146
+ @register (skip_shells = ['osh' ])
147
+ def a (sh ):
148
+ 'wait builtin then SIGWINCH (issue 1067)'
149
+
150
+ sh .sendline ('sleep 1 &' )
151
+ sh .sendline ('wait' )
152
+
153
+ time .sleep (0.1 )
154
+
155
+ # simulate window size change
156
+ sh .kill (signal .SIGWINCH )
157
+
158
+ sh .expect (r'.*\$' ) # expect prompt
159
+
160
+ sh .sendline ('echo status=$?' )
161
+ sh .expect ('status=0' )
162
+
127
163
128
- osh .expect (r'.*\$' ) # expect prompt
164
+ @register ()
165
+ def b (sh ):
166
+ 'Ctrl-C during external command'
129
167
130
- osh .sendline ('echo status=$?' )
131
- osh .expect ('status=130' )
168
+ sh .sendline ('sleep 5' )
132
169
133
- with InteractiveTest ( 'Ctrl-C during read builtin' ) as osh :
134
- osh . sendline ( 'read' )
170
+ time . sleep ( 0.1 )
171
+ sh . sendintr () # SIGINT
135
172
136
- time .sleep (0.1 )
137
- osh .sendintr () # SIGINT
173
+ sh .expect (r'.*\$' ) # expect prompt
138
174
139
- osh .expect (r'.*\$' ) # expect prompt
175
+ sh .sendline ('echo status=$?' )
176
+ sh .expect ('status=130' )
140
177
141
- osh .sendline ('echo status=$?' )
142
- osh .expect ('status=130' )
143
178
144
- with InteractiveTest ( 'Ctrl-C during wait builtin' ) as osh :
145
- osh . sendline ( 'sleep 5 &' )
146
- osh . sendline ( 'wait' )
179
+ @ register ()
180
+ def c ( sh ):
181
+ 'Ctrl-C during read builtin'
147
182
148
- time .sleep (0.1 )
149
- osh .sendintr () # SIGINT
183
+ sh .sendline ('read' )
150
184
151
- osh .expect (r'.*\$' ) # expect prompt
185
+ time .sleep (0.1 )
186
+ sh .sendintr () # SIGINT
152
187
153
- osh .sendline ('echo status=$?' )
154
- # TODO: Should be exit code 130 like bash
155
- osh .expect ('status=0' )
188
+ sh .expect (r'.*\$' ) # expect prompt
156
189
157
- with InteractiveTest ( 'Ctrl-C during pipeline' ) as osh :
158
- osh . sendline ( 'sleep 5 | cat ' )
190
+ sh . sendline ( 'echo status=$?' )
191
+ sh . expect ( 'status=130 ' )
159
192
160
- time .sleep (0.1 )
161
- osh .sendintr () # SIGINT
162
193
163
- osh .expect (r'.*\$' ) # expect prompt
194
+ # TODO: make it work on bash
195
+ @register (skip_shells = ['bash' ])
196
+ def d (sh ):
197
+ 'Ctrl-C during wait builtin'
164
198
165
- osh .sendline ('echo status=$? ' )
166
- osh . expect ( 'status=130 ' )
199
+ sh .sendline ('sleep 5 & ' )
200
+ sh . sendline ( 'wait ' )
167
201
168
- with InteractiveTest ( "Ctrl-C during Command Sub (issue 467)" ) as osh :
169
- osh . sendline ( '`sleep 5`' )
202
+ time . sleep ( 0.1 )
203
+ sh . sendintr () # SIGINT
170
204
171
- time .sleep (0.1 )
172
- osh .sendintr () # SIGINT
205
+ sh .expect (r'.*\$' ) # expect prompt
173
206
174
- osh .expect (r'.*\$' ) # expect prompt
207
+ sh .sendline ('echo status=$?' )
208
+ # TODO: Should be exit code 130 like bash
209
+ sh .expect ('status=0' )
175
210
176
- osh .sendline ('echo status=$?' )
177
- # TODO: This should be status 130 like bash
178
- osh .expect ('status=0' )
179
211
180
- with InteractiveTest ("fg twice should not result in fatal error (issue 1004)" ) as osh :
181
- osh .expect (r'.*\$ ' )
182
- osh .sendline ("cat" )
183
- stop_process__hack ("cat" )
184
- osh .expect ("\r \n \\ [PID \\ d+\\ ] Stopped" )
185
- osh .expect (r".*\$" )
186
- osh .sendline ("fg" )
187
- osh .expect (r"Continue PID \d+" )
212
+ @register ()
213
+ def e (sh ):
214
+ 'Ctrl-C during pipeline'
215
+ sh .sendline ('sleep 5 | cat' )
188
216
189
- #osh.sendcontrol("c")
190
- osh .sendintr () # SIGINT
217
+ time .sleep (0.1 )
218
+ sh .sendintr () # SIGINT
219
+
220
+ sh .expect (r'.*\$' ) # expect prompt
221
+
222
+ sh .sendline ('echo status=$?' )
223
+ sh .expect ('status=130' )
224
+
225
+
226
+ # TODO: make it work on bash
227
+ @register (skip_shells = ['bash' ])
228
+ def f (sh ):
229
+ 'Ctrl-C during Command Sub (issue 467)'
230
+ sh .sendline ('`sleep 5`' )
231
+
232
+ time .sleep (0.1 )
233
+ sh .sendintr () # SIGINT
234
+
235
+ sh .expect (r'.*\$' ) # expect prompt
236
+
237
+ sh .sendline ('echo status=$?' )
238
+ # TODO: This should be status 130 like bash
239
+ sh .expect ('status=0' )
240
+
241
+
242
+ @register (skip_shells = ['bash' ])
243
+ def g (sh ):
244
+ 'fg twice should not result in fatal error (issue 1004)'
245
+ sh .expect (r'.*\$ ' )
246
+ sh .sendline ("cat" )
247
+ stop_process__hack ("cat" )
248
+ sh .expect ("\r \n \\ [PID \\ d+\\ ] Stopped" )
249
+ sh .expect (r".*\$" )
250
+ sh .sendline ("fg" )
251
+ sh .expect (r"Continue PID \d+" )
252
+
253
+ #sh.sendcontrol("c")
254
+ sh .sendintr () # SIGINT
255
+
256
+ sh .expect (r".*\$" )
257
+ sh .sendline ("fg" )
258
+ sh .expect ("No job to put in the foreground" )
259
+
260
+
261
+ @register (skip_shells = ['bash' ])
262
+ def h (sh ):
263
+ 'Test resuming a killed process'
264
+ sh .expect (r'.*\$ ' )
265
+ sh .sendline ("cat" )
266
+ stop_process__hack ("cat" )
267
+ sh .expect ("\r \n \\ [PID \\ d+\\ ] Stopped" )
268
+ sh .expect (r".*\$" )
269
+ sh .sendline ("fg" )
270
+ sh .expect (r"Continue PID \d+" )
271
+ send_signal ("cat" , signal .SIGINT )
272
+ sh .expect (r".*\$" )
273
+ sh .sendline ("fg" )
274
+ sh .expect ("No job to put in the foreground" )
275
+
276
+
277
+ @register (skip_shells = ['bash' ])
278
+ def j (sh ):
279
+ 'Call fg after process exits (issue 721)'
280
+
281
+ sh .expect (r".*\$" )
282
+ sh .sendline ("cat" )
283
+
284
+ #osh.sendcontrol("c")
285
+ sh .sendintr () # SIGINT
286
+
287
+ sh .expect (r".*\$" )
288
+ sh .sendline ("fg" )
289
+ sh .expect ("No job to put in the foreground" )
290
+ sh .expect (r".*\$" )
291
+ sh .sendline ("fg" )
292
+ sh .expect ("No job to put in the foreground" )
293
+ sh .expect (r".*\$" )
294
+
295
+
296
+
297
+ def main (argv ):
298
+ # NOTE: Some options are ignored
299
+ o = spec_lib .Options ()
300
+ opts , argv = o .parse_args (argv )
191
301
192
- osh .expect (r".*\$" )
193
- osh .sendline ("fg" )
194
- osh .expect ("No job to put in the foreground" )
302
+ shells = argv [1 :]
303
+ shell_pairs = spec_lib .MakeShellPairs (shells )
195
304
196
- with InteractiveTest ('Test resuming a killed process' ) as osh :
197
- osh .expect (r'.*\$ ' )
198
- osh .sendline ("cat" )
199
- stop_process__hack ("cat" )
200
- osh .expect ("\r \n \\ [PID \\ d+\\ ] Stopped" )
201
- osh .expect (r".*\$" )
202
- osh .sendline ("fg" )
203
- osh .expect (r"Continue PID \d+" )
204
- kill_process ("cat" )
205
- osh .expect (r".*\$" )
206
- osh .sendline ("fg" )
207
- osh .expect ("No job to put in the foreground" )
305
+ if 0 :
306
+ print (shell_pairs )
307
+ print (CASES )
208
308
309
+ for i , (desc , func , skip_shells ) in enumerate (CASES ):
310
+ for shell_label , shell_path in shell_pairs :
311
+ skip = shell_label in skip_shells
312
+ skip_str = 'SKIP' if skip else ''
209
313
210
- with InteractiveTest ( 'Call fg after process exits (issue 721)' ) as osh :
211
- osh . expect ( r".*\$" )
212
- osh . sendline ( "cat" )
314
+ print ()
315
+ print ( '%s \t %d \t %s \t %s' % ( skip_str , i , shell_label , desc ) )
316
+ print ( )
213
317
214
- #osh.sendcontrol("c")
215
- osh . sendintr () # SIGINT
318
+ if skip :
319
+ continue
216
320
217
- osh .expect (r".*\$" )
218
- osh .sendline ("fg" )
219
- osh .expect ("No job to put in the foreground" )
220
- osh .expect (r".*\$" )
221
- osh .sendline ("fg" )
222
- osh .expect ("No job to put in the foreground" )
223
- osh .expect (r".*\$" )
321
+ with InteractiveTest (desc , program = shell_path ) as sh :
322
+ func (sh )
224
323
225
- return 1 if g_failures else 0
324
+ return 0
226
325
227
326
228
327
if __name__ == '__main__' :
0 commit comments