@@ -270,26 +270,28 @@ async def send_signal(proc):
270
270
finally :
271
271
signal .signal (signal .SIGHUP , old_handler )
272
272
273
- def prepare_broken_pipe_test (self ):
273
+ def test_stdin_broken_pipe (self ):
274
274
# buffer large enough to feed the whole pipe buffer
275
275
large_data = b'x' * support .PIPE_MAX_SIZE
276
276
277
+ rfd , wfd = os .pipe ()
278
+ self .addCleanup (os .close , rfd )
279
+ self .addCleanup (os .close , wfd )
280
+ code = f'import os; fd = { rfd } ; os.read(fd, 1)'
281
+
277
282
# the program ends before the stdin can be fed
278
283
proc = self .loop .run_until_complete (
279
284
asyncio .create_subprocess_exec (
280
- sys .executable , '-c' , 'pass' ,
285
+ sys .executable , '-c' , code ,
281
286
stdin = subprocess .PIPE ,
287
+ pass_fds = (rfd ,),
282
288
)
283
289
)
284
290
285
- return (proc , large_data )
286
-
287
- def test_stdin_broken_pipe (self ):
288
- proc , large_data = self .prepare_broken_pipe_test ()
289
-
290
291
async def write_stdin (proc , data ):
291
- await asyncio .sleep (0.5 )
292
292
proc .stdin .write (data )
293
+ # Only exit the child process once the write buffer is filled
294
+ os .write (wfd , b'go' )
293
295
await proc .stdin .drain ()
294
296
295
297
coro = write_stdin (proc , large_data )
@@ -300,7 +302,16 @@ async def write_stdin(proc, data):
300
302
self .loop .run_until_complete (proc .wait ())
301
303
302
304
def test_communicate_ignore_broken_pipe (self ):
303
- proc , large_data = self .prepare_broken_pipe_test ()
305
+ # buffer large enough to feed the whole pipe buffer
306
+ large_data = b'x' * support .PIPE_MAX_SIZE
307
+
308
+ # the program ends before the stdin can be fed
309
+ proc = self .loop .run_until_complete (
310
+ asyncio .create_subprocess_exec (
311
+ sys .executable , '-c' , 'pass' ,
312
+ stdin = subprocess .PIPE ,
313
+ )
314
+ )
304
315
305
316
# communicate() must ignore BrokenPipeError when feeding stdin
306
317
self .loop .set_exception_handler (lambda loop , msg : None )
0 commit comments