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)

`