Skip to content

Commit e2d31d4

Browse files
committed
first_stage_test: Add test_closed_stderr
Signed-off-by: Marc Hartmayer <[email protected]>
1 parent 30de9fd commit e2d31d4

File tree

1 file changed

+45
-0
lines changed

1 file changed

+45
-0
lines changed

tests/first_stage_test.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import fcntl
22
import functools
3+
import sys
34
import operator
45
import os
56

@@ -90,6 +91,24 @@ class DummyConnectionNonBlocking(mitogen.parent.Connection):
9091
name_prefix = "dummy_non_blocking"
9192

9293

94+
class DummyConnectionClosedStderr(mitogen.parent.Connection):
95+
"""Dummy closed stderr connection"""
96+
97+
pipe_size = 4096 if getattr(fcntl, "F_SETPIPE_SZ", None) else None
98+
create_child = staticmethod(
99+
functools.partial(
100+
own_create_child,
101+
blocking=True,
102+
pipe_size=pipe_size,
103+
pass_stderr=False,
104+
# `os.close(2)` does not work here as we use file objects in
105+
# `create_child` and that would cause problems with Python2.
106+
preexec_fn=lambda: sys.stderr.close(),
107+
)
108+
)
109+
name_prefix = "dummy_closed_stderr"
110+
111+
93112
class ConnectionTest(testlib.RouterMixin, testlib.TestCase):
94113
def test_stdin_non_blocking(self):
95114
"""Test that first stage works with non-blocking STDIN
@@ -129,6 +148,32 @@ def test_stdin_blocking(self):
129148
self.assertEqual(3, ctx.call(operator.add, 1, 2))
130149
logs = log.stop()
131150

151+
def test_stderr_closed(self):
152+
"""Test that first stage works with closed STDERR
153+
154+
The boot command should read the preamble from STDIN, write all ECO
155+
markers to STDOUT, and then execute the preamble.
156+
157+
This test writes the complete preamble to blocking STDIN.
158+
159+
1. Fork child reads from blocking STDIN
160+
2. Fork child decompresses the data, does send the handshakes MITO001 and MITO002
161+
3. Fork child crashes (when it tries to close the already closed
162+
STDERR), but that's non-critical as the parent can read the data
163+
already written by the fork child.
164+
4. Fork child's file descriptors (write pipes) are closed by the OS
165+
5. Fork parent does `dup(<read pipe>, <stdin>)` and `exec(<python>)`
166+
6. Python reads all data from stdin
167+
7. Python runs the preamble code
168+
8. A context call works as expected.
169+
170+
"""
171+
log = testlib.LogCapturer()
172+
log.start()
173+
ctx = self.router._connect(DummyConnectionClosedStderr, connect_timeout=0.5)
174+
self.assertEqual(3, ctx.call(operator.add, 1, 2))
175+
logs = log.stop()
176+
132177

133178
class CommandLineTest(testlib.RouterMixin, testlib.TestCase):
134179
# Ensure this version of Python produces a command line that is sufficient

0 commit comments

Comments
 (0)