Skip to content

Commit 0695970

Browse files
committed
first_stage_test: Add more tests
+ test_stdin_non_blocking + test_stdin_blocking Signed-off-by: Marc Hartmayer <[email protected]>
1 parent ead4a6d commit 0695970

File tree

1 file changed

+121
-0
lines changed

1 file changed

+121
-0
lines changed

tests/first_stage_test.py

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,131 @@
1+
import fcntl
2+
import functools
3+
import operator
4+
15
import mitogen.core
26
import mitogen.parent
37
from mitogen.core import b
48

59
import testlib
610

711

12+
def own_create_child(args, blocking, pipe_size=None, preexec_fn=None):
13+
"""
14+
Create a child process whose stdin/stdout is connected to a pipe.
15+
16+
:param list args:
17+
Program argument vector.
18+
:param bool blocking:
19+
If :data:`True`, the pipes use blocking IO, otherwise non-blocking.
20+
:param int pipe_size:
21+
If not :data:`None`, use the values as the pipe size.
22+
:param function preexec_fn:
23+
If not :data:`None`, a function to run within the post-fork child
24+
before executing the target program.
25+
:returns:
26+
:class:`PopenProcess` instance.
27+
"""
28+
parent_rfp, child_wfp = mitogen.core.pipe(blocking=blocking)
29+
child_rfp, parent_wfp = mitogen.core.pipe(blocking=blocking)
30+
stderr_r, stderr = mitogen.core.pipe(blocking=blocking)
31+
mitogen.core.set_cloexec(stderr_r.fileno())
32+
if pipe_size is not None:
33+
fcntl.fcntl(parent_rfp.fileno(), fcntl.F_SETPIPE_SZ, pipe_size)
34+
fcntl.fcntl(child_rfp.fileno(), fcntl.F_SETPIPE_SZ, pipe_size)
35+
fcntl.fcntl(stderr_r.fileno(), fcntl.F_SETPIPE_SZ, pipe_size)
36+
assert fcntl.fcntl(parent_rfp.fileno(), fcntl.F_GETPIPE_SZ) == pipe_size
37+
assert fcntl.fcntl(child_rfp.fileno(), fcntl.F_GETPIPE_SZ) == pipe_size
38+
assert fcntl.fcntl(stderr_r.fileno(), fcntl.F_GETPIPE_SZ) == pipe_size
39+
40+
try:
41+
proc = testlib.subprocess.Popen(
42+
args=args,
43+
stdin=child_rfp,
44+
stdout=child_wfp,
45+
stderr=stderr,
46+
close_fds=True,
47+
preexec_fn=preexec_fn,
48+
)
49+
except Exception:
50+
child_rfp.close()
51+
child_wfp.close()
52+
parent_rfp.close()
53+
parent_wfp.close()
54+
stderr_r.close()
55+
stderr.close()
56+
raise
57+
58+
child_rfp.close()
59+
child_wfp.close()
60+
stderr.close()
61+
return mitogen.parent.PopenProcess(
62+
proc=proc,
63+
stdin=parent_wfp,
64+
stdout=parent_rfp,
65+
stderr=stderr_r,
66+
)
67+
68+
69+
class DummyConnectionBlocking(mitogen.parent.Connection):
70+
"""Dummy blocking IO connection"""
71+
72+
pipe_size = 4096 if getattr(fcntl, "F_SETPIPE_SZ", None) else None
73+
create_child = staticmethod(
74+
functools.partial(own_create_child, blocking=True, pipe_size=pipe_size)
75+
)
76+
name_prefix = "dummy_blocking"
77+
78+
79+
class DummyConnectionNonBlocking(mitogen.parent.Connection):
80+
"""Dummy non-blocking IO connection"""
81+
82+
pipe_size = 4096 if getattr(fcntl, "F_SETPIPE_SZ", None) else None
83+
create_child = staticmethod(
84+
functools.partial(own_create_child, blocking=False, pipe_size=pipe_size)
85+
)
86+
name_prefix = "dummy_non_blocking"
87+
88+
89+
class ConnectionTest(testlib.RouterMixin, testlib.TestCase):
90+
def test_stdin_non_blocking(self):
91+
"""Test that first stage works with non-blocking STDIN
92+
93+
The boot command should read the preamble from STDIN, write all ECO
94+
markers to STDOUT, and then execute the preamble.
95+
96+
This test writes the complete preamble to non-blocking STDIN.
97+
98+
1. Fork child reads from non-blocking STDIN
99+
2. Fork child writes all data as expected by the protocol.
100+
3. A context call works as expected.
101+
102+
"""
103+
log = testlib.LogCapturer()
104+
log.start()
105+
ctx = self.router._connect(DummyConnectionNonBlocking, connect_timeout=0.5)
106+
self.assertEqual(3, ctx.call(operator.add, 1, 2))
107+
logs = log.stop()
108+
109+
def test_stdin_blocking(self):
110+
"""Test that first stage works with blocking STDIN
111+
112+
The boot command should read the preamble from STDIN, write all ECO
113+
markers to STDOUT, and then execute the preamble.
114+
115+
This test writes the complete preamble to blocking STDIN.
116+
117+
1. Fork child reads from blocking STDIN
118+
2. Fork child writes all data as expected by the protocol.
119+
3. A context call works as expected.
120+
121+
"""
122+
log = testlib.LogCapturer()
123+
log.start()
124+
ctx = self.router._connect(DummyConnectionBlocking, connect_timeout=0.5)
125+
self.assertEqual(3, ctx.call(operator.add, 1, 2))
126+
logs = log.stop()
127+
128+
8129
class CommandLineTest(testlib.RouterMixin, testlib.TestCase):
9130
# Ensure this version of Python produces a command line that is sufficient
10131
# to bootstrap this version of Python.

0 commit comments

Comments
 (0)