Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | import pty, os, sys, signal |
2 | from test.test_support import verbose, TestFailed, TestSkipped | |
3 | ||
4 | TEST_STRING_1 = "I wish to buy a fish license.\n" | |
5 | TEST_STRING_2 = "For my pet fish, Eric.\n" | |
6 | ||
7 | if verbose: | |
8 | def debug(msg): | |
9 | print msg | |
10 | else: | |
11 | def debug(msg): | |
12 | pass | |
13 | ||
14 | # Marginal testing of pty suite. Cannot do extensive 'do or fail' testing | |
15 | # because pty code is not too portable. | |
16 | ||
17 | def test_basic_pty(): | |
18 | try: | |
19 | debug("Calling master_open()") | |
20 | master_fd, slave_name = pty.master_open() | |
21 | debug("Got master_fd '%d', slave_name '%s'"%(master_fd, slave_name)) | |
22 | debug("Calling slave_open(%r)"%(slave_name,)) | |
23 | slave_fd = pty.slave_open(slave_name) | |
24 | debug("Got slave_fd '%d'"%slave_fd) | |
25 | except OSError: | |
26 | # " An optional feature could not be imported " ... ? | |
27 | raise TestSkipped, "Pseudo-terminals (seemingly) not functional." | |
28 | ||
29 | if not os.isatty(slave_fd): | |
30 | raise TestFailed, "slave_fd is not a tty" | |
31 | ||
32 | # IRIX apparently turns \n into \r\n. Allow that, but avoid allowing other | |
33 | # differences (like extra whitespace, trailing garbage, etc.) | |
34 | ||
35 | debug("Writing to slave_fd") | |
36 | os.write(slave_fd, TEST_STRING_1) | |
37 | s1 = os.read(master_fd, 1024) | |
38 | sys.stdout.write(s1.replace("\r\n", "\n")) | |
39 | ||
40 | debug("Writing chunked output") | |
41 | os.write(slave_fd, TEST_STRING_2[:5]) | |
42 | os.write(slave_fd, TEST_STRING_2[5:]) | |
43 | s2 = os.read(master_fd, 1024) | |
44 | sys.stdout.write(s2.replace("\r\n", "\n")) | |
45 | ||
46 | os.close(slave_fd) | |
47 | os.close(master_fd) | |
48 | ||
49 | def handle_sig(sig, frame): | |
50 | raise TestFailed, "isatty hung" | |
51 | ||
52 | # isatty() and close() can hang on some platforms | |
53 | # set an alarm before running the test to make sure we don't hang forever | |
54 | old_alarm = signal.signal(signal.SIGALRM, handle_sig) | |
55 | signal.alarm(10) | |
56 | ||
57 | try: | |
58 | test_basic_pty() | |
59 | finally: | |
60 | # remove alarm, restore old alarm handler | |
61 | signal.alarm(0) | |
62 | signal.signal(signal.SIGALRM, old_alarm) | |
63 | ||
64 | # basic pty passed. | |
65 | ||
66 | debug("calling pty.fork()") | |
67 | pid, master_fd = pty.fork() | |
68 | if pid == pty.CHILD: | |
69 | # stdout should be connected to a tty. | |
70 | if not os.isatty(1): | |
71 | debug("Child's fd 1 is not a tty?!") | |
72 | os._exit(3) | |
73 | ||
74 | # After pty.fork(), the child should already be a session leader. | |
75 | # (on those systems that have that concept.) | |
76 | debug("In child, calling os.setsid()") | |
77 | try: | |
78 | os.setsid() | |
79 | except OSError: | |
80 | # Good, we already were session leader | |
81 | debug("Good: OSError was raised.") | |
82 | pass | |
83 | except AttributeError: | |
84 | # Have pty, but not setsid() ? | |
85 | debug("No setsid() available ?") | |
86 | pass | |
87 | except: | |
88 | # We don't want this error to propagate, escaping the call to | |
89 | # os._exit() and causing very peculiar behavior in the calling | |
90 | # regrtest.py ! | |
91 | # Note: could add traceback printing here. | |
92 | debug("An unexpected error was raised.") | |
93 | os._exit(1) | |
94 | else: | |
95 | debug("os.setsid() succeeded! (bad!)") | |
96 | os._exit(2) | |
97 | os._exit(4) | |
98 | else: | |
99 | debug("Waiting for child (%d) to finish."%pid) | |
100 | (pid, status) = os.waitpid(pid, 0) | |
101 | res = status >> 8 | |
102 | debug("Child (%d) exited with status %d (%d)."%(pid, res, status)) | |
103 | if res == 1: | |
104 | raise TestFailed, "Child raised an unexpected exception in os.setsid()" | |
105 | elif res == 2: | |
106 | raise TestFailed, "pty.fork() failed to make child a session leader." | |
107 | elif res == 3: | |
108 | raise TestFailed, "Child spawned by pty.fork() did not have a tty as stdout" | |
109 | elif res != 4: | |
110 | raise TestFailed, "pty.fork() failed for unknown reasons." | |
111 | ||
112 | os.close(master_fd) | |
113 | ||
114 | # pty.fork() passed. |