Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpo-31158: Fix nondeterministic read in test_pty #3808

Merged
merged 3 commits into from
Oct 2, 2017

Conversation

diekmann
Copy link
Contributor

@diekmann diekmann commented Sep 28, 2017

Sometimes, the test suite fails in test_pty.test_basic()

https://bugs.python.org/issue31158

Acks to @Haypo !!

https://bugs.python.org/issue31158

@pitrou
Copy link
Member

pitrou commented Sep 28, 2017

Why not use FileIO instead? Something like:

with io.FileIO(master_fd) as master:
    ...
    s1 = master.readline()
    ...

@diekmann
Copy link
Contributor Author

Thanks @pitrou for the suggestion. The following also works on my machine:

diff --git a/Lib/test/test_pty.py b/Lib/test/test_pty.py
index f283e19..ee9b589 100644
--- a/Lib/test/test_pty.py
+++ b/Lib/test/test_pty.py
@@ -10,6 +10,7 @@ import sys
 import select
 import signal
 import socket
+import io
 import unittest
 
 TEST_STRING_1 = b"I wish to buy a fish license.\n"
@@ -92,17 +93,18 @@ class PtyTest(unittest.TestCase):
             # Restore the original flags.
             os.set_blocking(master_fd, blocking)
 
-        debug("Writing to slave_fd")
-        os.write(slave_fd, TEST_STRING_1)
-        s1 = os.read(master_fd, 1024)
-        self.assertEqual(b'I wish to buy a fish license.\n',
-                         normalize_output(s1))
-
-        debug("Writing chunked output")
-        os.write(slave_fd, TEST_STRING_2[:5])
-        os.write(slave_fd, TEST_STRING_2[5:])
-        s2 = os.read(master_fd, 1024)
-        self.assertEqual(b'For my pet fish, Eric.\n', normalize_output(s2))
+        with io.FileIO(master_fd, mode='rb', closefd=False) as master:
+            debug("Writing to slave_fd")
+            os.write(slave_fd, TEST_STRING_1)
+            s1 = master.readline()
+            self.assertEqual(b'I wish to buy a fish license.\n',
+                             normalize_output(s1))
+
+            debug("Writing chunked output")
+            os.write(slave_fd, TEST_STRING_2[:5])
+            os.write(slave_fd, TEST_STRING_2[5:])
+            s2 = master.readline()
+            self.assertEqual(b'For my pet fish, Eric.\n', normalize_output(s2))
 
         os.close(slave_fd)
         os.close(master_fd)

Which version is better?

Problem in version 1:

  • Re-implementing readline

Problem in version 2:

  • Depends on the io module, while the pty module usually only uses the raw os.read and os.write calls. A failure could make debugging harder (is it the pty module or a change in the io module?).
  • I don't like that we have both, master and master_fd hanging around

@diekmann
Copy link
Contributor Author

I hope we now have the best of both worlds.

@@ -43,6 +54,12 @@ def normalize_output(data):

return data

def _readline(fd):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure you still need a helper function. Just use the FileIO object directly from the test method.

Also, if you remove closefd=False, you don't need the os.close(master_fd) at the end.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea of keeping the helper function was to have it close to the comment I added above. And the comment is both about _readline and normalize_output.

We have os.close(slave_fd). I think it would be very asymmetric if we don't close(master_fd) as well in the code explicitly?

Ideally, this commit is fixuped into the previous commit. Since there is
already a comment on github, I won't rebase.
@vstinner vstinner merged commit e6f62f6 into python:master Oct 2, 2017
@miss-islington
Copy link
Contributor

Thanks @diekmann for the PR, and @Haypo for merging it 🌮🎉.. I'm working now to backport this PR to: 3.6.
🐍🍒⛏🤖

@bedevere-bot
Copy link

GH-3852 is a backport of this pull request to the 3.6 branch.

miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Oct 2, 2017
* bpo-31158: Fix nondeterministic read in test_pty

* Reuse existing readline implementation from io.

Thx to @pitrou

* Updated comment

Ideally, this commit is fixuped into the previous commit. Since there is
already a comment on github, I won't rebase.
(cherry picked from commit e6f62f6)
@vstinner
Copy link
Member

vstinner commented Oct 2, 2017

While the test is not perfect, I don't think that we need perfect quality here. I merged the PR to fix this very old bug: test_pty.test_basic() was failing randomly since 1 or 2 years! (well, probably since the test was written)

@vstinner
Copy link
Member

vstinner commented Oct 2, 2017

Oh. I should have fixed the commit message. I just hate the UI for merge a PR. I always miss the commit message edit area.

@vstinner
Copy link
Member

vstinner commented Oct 2, 2017

I backported the change manually to 2.7: PR #3853.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants