bpo-31158: Fix nondeterministic read in test_pty (#3808) (#3853) · python/cpython@20cbc1d (original) (raw)
`@@ -11,6 +11,7 @@
`
11
11
`import select
`
12
12
`import signal
`
13
13
`import socket
`
``
14
`+
import io # readline
`
14
15
`import unittest
`
15
16
``
16
17
`TEST_STRING_1 = "I wish to buy a fish license.\n"
`
`@@ -24,6 +25,16 @@ def debug(msg):
`
24
25
`pass
`
25
26
``
26
27
``
``
28
`+
Note that os.read() is nondeterministic so we need to be very careful
`
``
29
`+
to make the test suite deterministic. A normal call to os.read() may
`
``
30
`+
give us less than expected.
`
``
31
`+
`
``
32
`+
Beware, on my Linux system, if I put 'foo\n' into a terminal fd, I get
`
``
33
`+
back 'foo\r\n' at the other end. The behavior depends on the termios
`
``
34
`+
setting. The newline translation may be OS-specific. To make the
`
``
35
`+
test suite deterministic and OS-independent, the functions _readline
`
``
36
`+
and normalize_output can be used.
`
``
37
+
27
38
`def normalize_output(data):
`
28
39
`# Some operating systems do conversions on newline. We could possibly
`
29
40
`# fix that by doing the appropriate termios.tcsetattr()s. I couldn't
`
`@@ -45,6 +56,12 @@ def normalize_output(data):
`
45
56
``
46
57
`return data
`
47
58
``
``
59
`+
def _readline(fd):
`
``
60
`+
"""Read one line. May block forever if no newline is read."""
`
``
61
`+
reader = io.FileIO(fd, mode='rb', closefd=False)
`
``
62
`+
return reader.readline()
`
``
63
+
``
64
+
48
65
``
49
66
`# Marginal testing of pty suite. Cannot do extensive 'do or fail' testing
`
50
67
`# because pty code is not too portable.
`
`@@ -97,14 +114,14 @@ def test_basic(self):
`
97
114
``
98
115
`debug("Writing to slave_fd")
`
99
116
`os.write(slave_fd, TEST_STRING_1)
`
100
``
`-
s1 = os.read(master_fd, 1024)
`
``
117
`+
s1 = _readline(master_fd)
`
101
118
`self.assertEqual('I wish to buy a fish license.\n',
`
102
119
`normalize_output(s1))
`
103
120
``
104
121
`debug("Writing chunked output")
`
105
122
`os.write(slave_fd, TEST_STRING_2[:5])
`
106
123
`os.write(slave_fd, TEST_STRING_2[5:])
`
107
``
`-
s2 = os.read(master_fd, 1024)
`
``
124
`+
s2 = _readline(master_fd)
`
108
125
`self.assertEqual('For my pet fish, Eric.\n', normalize_output(s2))
`
109
126
``
110
127
`os.close(slave_fd)
`