@@ -87,6 +87,18 @@ class DummyConnectionNonBlocking(mitogen.parent.Connection):
8787 name_prefix = "dummy_non_blocking"
8888
8989
90+ class DummyConnectionClosedStderr (mitogen .parent .Connection ):
91+ """Dummy closed stderr connection"""
92+
93+ pipe_size = 4096 if getattr (fcntl , "F_SETPIPE_SZ" , None ) else None
94+ create_child = staticmethod (
95+ functools .partial (
96+ own_create_child , blocking = True , pipe_size = pipe_size , preexec_fn = lambda : os .close (2 )
97+ )
98+ )
99+ name_prefix = "dummy_closed_stderr"
100+
101+
90102class ConnectionTest (testlib .RouterMixin , testlib .TestCase ):
91103 def test_stdin_non_blocking (self ):
92104 """Test that first stage works with non-blocking STDIN
@@ -126,6 +138,25 @@ def test_stdin_blocking(self):
126138 self .assertEqual (3 , ctx .call (operator .add , 1 , 2 ))
127139 logs = log .stop ()
128140
141+ def test_stderr_closed (self ):
142+ """Test that first stage works with closed STDERR
143+
144+ The boot command should read the preamble from STDIN, write all ECO
145+ markers to STDOUT, and then execute the preamble.
146+
147+ This test writes the complete preamble to blocking STDIN.
148+
149+ 1. Fork child reads from blocking STDIN
150+ 2. Fork child writes all data as expected by the protocol.
151+ 3. A context call works as expected.
152+
153+ """
154+ log = testlib .LogCapturer ()
155+ log .start ()
156+ ctx = self .router ._connect (DummyConnectionClosedStderr , connect_timeout = 0.5 )
157+ self .assertEqual (3 , ctx .call (operator .add , 1 , 2 ))
158+ logs = log .stop ()
159+
129160
130161class CommandLineTest (testlib .RouterMixin , testlib .TestCase ):
131162 # Ensure this version of Python produces a command line that is sufficient
0 commit comments