summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_io.py
diff options
context:
space:
mode:
authorbenfogle <benfogle@gmail.com>2017-11-10 21:03:40 (GMT)
committerAntoine Pitrou <pitrou@free.fr>2017-11-10 21:03:40 (GMT)
commit9703f092abc0259926d88c7855afeae4a78afc7d (patch)
treed19e75bea4faacf58155861dd056f544a584f146 /Lib/test/test_io.py
parent4652bf2acc0d1ddabd224efabbfee0c3125da18b (diff)
downloadcpython-9703f092abc0259926d88c7855afeae4a78afc7d.zip
cpython-9703f092abc0259926d88c7855afeae4a78afc7d.tar.gz
cpython-9703f092abc0259926d88c7855afeae4a78afc7d.tar.bz2
bpo-31976: Fix race condition when flushing a file is slow. (#4331)
Diffstat (limited to 'Lib/test/test_io.py')
-rw-r--r--Lib/test/test_io.py31
1 files changed, 30 insertions, 1 deletions
diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py
index 3158729..2ac2e17 100644
--- a/Lib/test/test_io.py
+++ b/Lib/test/test_io.py
@@ -168,6 +168,22 @@ class PyMisbehavedRawIO(MisbehavedRawIO, pyio.RawIOBase):
pass
+class SlowFlushRawIO(MockRawIO):
+ def __init__(self):
+ super().__init__()
+ self.in_flush = threading.Event()
+
+ def flush(self):
+ self.in_flush.set()
+ time.sleep(0.25)
+
+class CSlowFlushRawIO(SlowFlushRawIO, io.RawIOBase):
+ pass
+
+class PySlowFlushRawIO(SlowFlushRawIO, pyio.RawIOBase):
+ pass
+
+
class CloseFailureIO(MockRawIO):
closed = 0
@@ -1726,6 +1742,18 @@ class BufferedWriterTest(unittest.TestCase, CommonBufferedTests):
self.assertRaises(OSError, b.close) # exception not swallowed
self.assertTrue(b.closed)
+ def test_slow_close_from_thread(self):
+ # Issue #31976
+ rawio = self.SlowFlushRawIO()
+ bufio = self.tp(rawio, 8)
+ t = threading.Thread(target=bufio.close)
+ t.start()
+ rawio.in_flush.wait()
+ self.assertRaises(ValueError, bufio.write, b'spam')
+ self.assertTrue(bufio.closed)
+ t.join()
+
+
class CBufferedWriterTest(BufferedWriterTest, SizeofTest):
tp = io.BufferedWriter
@@ -4085,7 +4113,8 @@ def load_tests(*args):
# Put the namespaces of the IO module we are testing and some useful mock
# classes in the __dict__ of each test.
mocks = (MockRawIO, MisbehavedRawIO, MockFileIO, CloseFailureIO,
- MockNonBlockWriterIO, MockUnseekableIO, MockRawIOWithoutRead)
+ MockNonBlockWriterIO, MockUnseekableIO, MockRawIOWithoutRead,
+ SlowFlushRawIO)
all_members = io.__all__ + ["IncrementalNewlineDecoder"]
c_io_ns = {name : getattr(io, name) for name in all_members}
py_io_ns = {name : getattr(pyio, name) for name in all_members}