]> granicus.if.org Git - python/commitdiff
bpo-34130: Fix test_signal.test_warn_on_full_buffer() (GH-8327)
authorVictor Stinner <vstinner@redhat.com>
Wed, 18 Jul 2018 16:29:54 +0000 (18:29 +0200)
committerGitHub <noreply@github.com>
Wed, 18 Jul 2018 16:29:54 +0000 (18:29 +0200)
On Windows, sometimes test_signal.test_warn_on_full_buffer() fails to
fill the socketpair buffer. In that case, the C signal handler
succeed to write into the socket, it doesn't log the expected send
error, and so the test fail.

On Windows, the test now uses a timeout of 50 ms to fill the
socketpair buffer to fix this race condition.

Other changes:

* Begin with large chunk size to fill the buffer to speed up the
  test.
* Add error messages to assertion errors to more easily identify
  which assertion failed.
* Don't set the read end of the socketpair as non-blocking.

Lib/test/test_signal.py

index e69db79909cc9795ba23884d9d7366806762be54..ecdffa60a65c03ee4d6f18d2ab74dbd26639a170 100644 (file)
@@ -479,26 +479,51 @@ class WakeupSocketSignalTests(unittest.TestCase):
         signal.signal(signum, handler)
 
         read, write = socket.socketpair()
-        read.setblocking(False)
-        write.setblocking(False)
 
-        # Fill the send buffer
+        # Fill the socketpair buffer
+        if sys.platform == 'win32':
+            # bpo-34130: On Windows, sometimes non-blocking send fails to fill
+            # the full socketpair buffer, so use a timeout of 50 ms instead.
+            write.settimeout(0.050)
+        else:
+            write.setblocking(False)
+
+        # Start with large chunk size to reduce the
+        # number of send needed to fill the buffer.
+        written = 0
+        for chunk_size in (2 ** 16, 2 ** 8, 1):
+            chunk = b"x" * chunk_size
+            try:
+                while True:
+                    write.send(chunk)
+                    written += chunk_size
+            except (BlockingIOError, socket.timeout):
+                pass
+
+        print(f"%s bytes written into the socketpair" % written, flush=True)
+
+        write.setblocking(False)
         try:
-            while True:
-                write.send(b"x")
+            write.send(b"x")
         except BlockingIOError:
+            # The socketpair buffer seems full
             pass
+        else:
+            raise AssertionError("%s bytes failed to fill the socketpair "
+                                 "buffer" % written)
 
         # By default, we get a warning when a signal arrives
+        msg = ('Exception ignored when trying to {action} '
+               'to the signal wakeup fd')
         signal.set_wakeup_fd(write.fileno())
 
         with captured_stderr() as err:
             _testcapi.raise_signal(signum)
 
         err = err.getvalue()
-        if ('Exception ignored when trying to {action} to the signal wakeup fd'
-            not in err):
-            raise AssertionError(err)
+        if msg not in err:
+            raise AssertionError("first set_wakeup_fd() test failed, "
+                                 "stderr: %r" % err)
 
         # And also if warn_on_full_buffer=True
         signal.set_wakeup_fd(write.fileno(), warn_on_full_buffer=True)
@@ -507,9 +532,9 @@ class WakeupSocketSignalTests(unittest.TestCase):
             _testcapi.raise_signal(signum)
 
         err = err.getvalue()
-        if ('Exception ignored when trying to {action} to the signal wakeup fd'
-            not in err):
-            raise AssertionError(err)
+        if msg not in err:
+            raise AssertionError("set_wakeup_fd(warn_on_full_buffer=True) "
+                                 "test failed, stderr: %r" % err)
 
         # But not if warn_on_full_buffer=False
         signal.set_wakeup_fd(write.fileno(), warn_on_full_buffer=False)
@@ -519,7 +544,8 @@ class WakeupSocketSignalTests(unittest.TestCase):
 
         err = err.getvalue()
         if err != "":
-            raise AssertionError("got unexpected output %r" % (err,))
+            raise AssertionError("set_wakeup_fd(warn_on_full_buffer=False) "
+                                 "test failed, stderr: %r" % err)
 
         # And then check the default again, to make sure warn_on_full_buffer
         # settings don't leak across calls.
@@ -529,9 +555,9 @@ class WakeupSocketSignalTests(unittest.TestCase):
             _testcapi.raise_signal(signum)
 
         err = err.getvalue()
-        if ('Exception ignored when trying to {action} to the signal wakeup fd'
-            not in err):
-            raise AssertionError(err)
+        if msg not in err:
+            raise AssertionError("second set_wakeup_fd() test failed, "
+                                 "stderr: %r" % err)
 
         """.format(action=action)
         assert_python_ok('-c', code)