Skip to content

Commit a176320

Browse files
committed
first_stage_test: Add test_closed_stdin and test_closed_stdout
Signed-off-by: Marc Hartmayer <[email protected]>
1 parent e536398 commit a176320

File tree

1 file changed

+73
-0
lines changed

1 file changed

+73
-0
lines changed

tests/first_stage_test.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import fcntl
22
import functools
33
import operator
4+
import os
45

56
import mitogen.core
67
import mitogen.parent
@@ -260,3 +261,75 @@ def test_timeout_error(self):
260261
b("TimeoutError"),
261262
stderr,
262263
)
264+
265+
def test_closed_stdin(self):
266+
"""
267+
The boot command should write an ECO marker to stdout, read the
268+
preamble from stdin, then execute it.
269+
270+
TODO UNDER DISCUSSION
271+
272+
This test attaches closes stdin to create a specific failure
273+
1. Fork child tries to read from STDIN, but fails as it is closed
274+
2. Fork child raises TimeoutError
275+
3. Fork child's file descriptors (write pipes) are closed by the OS
276+
4. Fork parent does `dup(<read pipe>, <stdin>)` and `exec(<python>)`
277+
5. Python reads `b''` (i.e. EOF) from stdin (a closed pipe)
278+
6. Python runs `''` (a valid script) and exits with success
279+
"""
280+
# We do not want to wait the default of 10s, change it to 0.1s
281+
self.conn._first_stage_timeout = 0.1
282+
args = self.conn.get_boot_command()
283+
284+
proc = testlib.subprocess.Popen(
285+
args=args,
286+
stdout=testlib.subprocess.PIPE,
287+
stderr=testlib.subprocess.PIPE,
288+
preexec_fn=lambda: os.close(0),
289+
close_fds=True,
290+
)
291+
try:
292+
stdout, stderr = proc.communicate(timeout=12)
293+
except testlib.subprocess.TimeoutExpired:
294+
proc.kill()
295+
self.fail("Timeout situation was not recognized")
296+
self.assertEqual(1, proc.returncode)
297+
self.assertEqual(stdout, b"")
298+
self.assertIn(
299+
b("Bad file descriptor"),
300+
stderr,
301+
)
302+
303+
def test_closed_stdout(self):
304+
"""The boot command should write an ECO marker to stdout, read the
305+
preamble from stdin, then execute it.
306+
307+
TODO UNDER DISCUSSION
308+
309+
This test writes some data to STDIN and closes it then to create an
310+
EOF situation.
311+
1. Fork child tries to read from STDIN, but stops as EOF is received.
312+
2. Fork child crashes (trying to decompress the junk data)
313+
3. Fork child's file descriptors (write pipes) are closed by the OS
314+
4. Fork parent does `dup(<read pipe>, <stdin>)` and `exec(<python>)`
315+
5. Python reads `b''` (i.e. EOF) from stdin (a closed pipe)
316+
6. Python runs `''` (a valid script) and exits with success"""
317+
318+
proc = testlib.subprocess.Popen(
319+
args=self.args,
320+
stderr=testlib.subprocess.PIPE,
321+
preexec_fn=lambda: os.close(1),
322+
close_fds=True,
323+
)
324+
325+
try:
326+
returncode = proc.wait(timeout=10)
327+
except testlib.subprocess.TimeoutExpired:
328+
proc.kill()
329+
self.fail("First stage did not work with closed STDOUT")
330+
else:
331+
self.assertEqual(1, returncode)
332+
self.assertIn(
333+
b("Bad file descriptor"),
334+
proc.stderr.read(),
335+
)

0 commit comments

Comments
 (0)