tests/test-stdio.py
changeset 45148 a37f290a7124
parent 45147 c2c862b9b544
child 45830 c102b704edb5
equal deleted inserted replaced
45147:c2c862b9b544 45148:a37f290a7124
    11 import subprocess
    11 import subprocess
    12 import sys
    12 import sys
    13 import tempfile
    13 import tempfile
    14 import unittest
    14 import unittest
    15 
    15 
    16 from mercurial import pycompat
    16 from mercurial import pycompat, util
    17 
    17 
    18 
    18 
    19 if pycompat.ispy3:
    19 if pycompat.ispy3:
    20 
    20 
    21     def set_noninheritable(fd):
    21     def set_noninheritable(fd):
    66 with os.fdopen(
    66 with os.fdopen(
    67     os.open({write_result_fn!r}, os.O_WRONLY | getattr(os, 'O_TEMPORARY', 0)),
    67     os.open({write_result_fn!r}, os.O_WRONLY | getattr(os, 'O_TEMPORARY', 0)),
    68     'w',
    68     'w',
    69 ) as write_result_f:
    69 ) as write_result_f:
    70     write_result_f.write(str(write_result))
    70     write_result_f.write(str(write_result))
       
    71 '''
       
    72 
       
    73 
       
    74 TEST_BROKEN_PIPE_CHILD_SCRIPT = r'''
       
    75 import os
       
    76 import pickle
       
    77 
       
    78 from mercurial import dispatch
       
    79 from mercurial.utils import procutil
       
    80 
       
    81 dispatch.initstdio()
       
    82 procutil.stdin.read(1)  # wait until parent process closed pipe
       
    83 try:
       
    84     procutil.{stream}.write(b'test')
       
    85     procutil.{stream}.flush()
       
    86 except EnvironmentError as e:
       
    87     with os.fdopen(
       
    88         os.open(
       
    89             {err_fn!r},
       
    90             os.O_WRONLY
       
    91             | getattr(os, 'O_BINARY', 0)
       
    92             | getattr(os, 'O_TEMPORARY', 0),
       
    93         ),
       
    94         'wb',
       
    95     ) as err_f:
       
    96         pickle.dump(e, err_f)
       
    97 # Exit early to suppress further broken pipe errors at interpreter shutdown.
       
    98 os._exit(0)
    71 '''
    99 '''
    72 
   100 
    73 
   101 
    74 @contextlib.contextmanager
   102 @contextlib.contextmanager
    75 def _closing(fds):
   103 def _closing(fds):
   146         stream,
   174         stream,
   147         rwpair_generator,
   175         rwpair_generator,
   148         check_output,
   176         check_output,
   149         python_args=[],
   177         python_args=[],
   150         post_child_check=None,
   178         post_child_check=None,
       
   179         stdin_generator=None,
   151     ):
   180     ):
   152         assert stream in ('stdout', 'stderr')
   181         assert stream in ('stdout', 'stderr')
   153         with rwpair_generator() as (stream_receiver, child_stream), open(
   182         if stdin_generator is None:
   154             os.devnull, 'rb'
   183             stdin_generator = open(os.devnull, 'rb')
   155         ) as child_stdin:
   184         with rwpair_generator() as (
       
   185             stream_receiver,
       
   186             child_stream,
       
   187         ), stdin_generator as child_stdin:
   156             proc = subprocess.Popen(
   188             proc = subprocess.Popen(
   157                 [sys.executable] + python_args + ['-c', child_script],
   189                 [sys.executable] + python_args + ['-c', child_script],
   158                 stdin=child_stdin,
   190                 stdin=child_stdin,
   159                 stdout=child_stream if stream == 'stdout' else None,
   191                 stdout=child_stream if stream == 'stdout' else None,
   160                 stderr=child_stream if stream == 'stderr' else None,
   192                 stderr=child_stream if stream == 'stderr' else None,
   293         self._test_large_write('stderr', _pipes, python_args=['-u'])
   325         self._test_large_write('stderr', _pipes, python_args=['-u'])
   294 
   326 
   295     def test_large_write_stderr_ptys_unbuffered(self):
   327     def test_large_write_stderr_ptys_unbuffered(self):
   296         self._test_large_write('stderr', _ptys, python_args=['-u'])
   328         self._test_large_write('stderr', _ptys, python_args=['-u'])
   297 
   329 
       
   330     def _test_broken_pipe(self, stream):
       
   331         assert stream in ('stdout', 'stderr')
       
   332 
       
   333         def check_output(stream_receiver, proc):
       
   334             os.close(stream_receiver)
       
   335             proc.stdin.write(b'x')
       
   336             proc.stdin.close()
       
   337 
       
   338         def post_child_check():
       
   339             err = util.pickle.load(err_f)
       
   340             self.assertEqual(err.errno, errno.EPIPE)
       
   341             self.assertEqual(err.strerror, "Broken pipe")
       
   342 
       
   343         with tempfile.NamedTemporaryFile('rb') as err_f:
       
   344             self._test(
       
   345                 TEST_BROKEN_PIPE_CHILD_SCRIPT.format(
       
   346                     stream=stream, err_fn=err_f.name
       
   347                 ),
       
   348                 stream,
       
   349                 _pipes,
       
   350                 check_output,
       
   351                 post_child_check=post_child_check,
       
   352                 stdin_generator=util.nullcontextmanager(subprocess.PIPE),
       
   353             )
       
   354 
       
   355     def test_broken_pipe_stdout(self):
       
   356         self._test_broken_pipe('stdout')
       
   357 
       
   358     def test_broken_pipe_stderr(self):
       
   359         self._test_broken_pipe('stderr')
       
   360 
   298 
   361 
   299 if __name__ == '__main__':
   362 if __name__ == '__main__':
   300     import silenttestrunner
   363     import silenttestrunner
   301 
   364 
   302     silenttestrunner.main(__name__)
   365     silenttestrunner.main(__name__)