Skip to content

Commit 03777b0

Browse files
committed
tests: Add first_stage_test that checks that the stage handles an too early EOF
Add first_stage_test that checks that the first stage handles an too early EOF. Without the next commit, the process enters an infinite loop, causing the Python interpreter to consume up to 100% of a CPU core. The test kills this process after running into the test timeout of 10s. Signed-off-by: Marc Hartmayer <[email protected]>
1 parent f466cc3 commit 03777b0

File tree

1 file changed

+50
-0
lines changed

1 file changed

+50
-0
lines changed

tests/first_stage_test.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,53 @@ def test_stage(self):
9191
b(""),
9292
stderr,
9393
)
94+
95+
def test_eof_too_early(self):
96+
options = mitogen.parent.Options(max_message_size=123)
97+
conn = mitogen.parent.Connection(options, self.router)
98+
conn.context = mitogen.core.Context(None, 123)
99+
args = conn.get_boot_command()
100+
preamble = conn.get_preamble()
101+
102+
# The boot command should write an ECO marker to stdout, read the
103+
# preamble from stdin, then execute it.
104+
105+
# This test writes some data to STDIN and closes it then to create an
106+
# EOF situation.
107+
# 1. Fork child tries to read from STDIN, but stops as EOF is received.
108+
# 2. Fork child crashes (trying to decompress the junk data)
109+
# 3. Fork child's file descriptors (write pipes) are closed by the OS
110+
# 4. Fork parent does `dup(<read pipe>, <stdin>)` and `exec(<python>)`
111+
# 5. Python reads `b''` (i.e. EOF) from stdin (a closed pipe)
112+
# 6. Python runs `''` (a valid script) and exits with success
113+
114+
proc = mitogen.parent.popen(args=args,
115+
stdout=subprocess.PIPE,
116+
stderr=subprocess.PIPE,
117+
stdin=subprocess.PIPE,
118+
)
119+
120+
# Do not send all of the data from the preamble
121+
proc.stdin.write(preamble[:-128])
122+
proc.stdin.flush()
123+
proc.stdin.close()
124+
try:
125+
try:
126+
returncode = proc.wait(timeout=10)
127+
except TypeError:
128+
returncode = proc.wait()
129+
except:
130+
proc.kill()
131+
self.fail("First stage did not handle EOF on STDIN")
132+
else:
133+
try:
134+
self.assertEqual(0, returncode)
135+
self.assertEqual(proc.stdout.read(),
136+
mitogen.parent.BootstrapProtocol.EC0_MARKER+b('\n'))
137+
self.assertIn(
138+
b("Error -5 while decompressing data"),
139+
proc.stderr.read(),
140+
)
141+
finally:
142+
proc.stdout.close()
143+
proc.stderr.close()

0 commit comments

Comments
 (0)