Commit 9b87786b authored by Jason Madden's avatar Jason Madden

More refactoring to separate concurrent from synchronous FileObject tests.

This cleans up the skips needed.
parent ab6536fd
......@@ -465,6 +465,7 @@ if LIBUV:
# mostly but not exclusively on Python 2.
'test_socket.BufferIOTest.testRecvFromIntoBytearray',
'test_socket.BufferIOTest.testRecvFromIntoArray',
'test_socket.BufferIOTest.testRecvIntoArray',
'test_socket.BufferIOTest.testRecvFromIntoEmptyBuffer',
'test_socket.BufferIOTest.testRecvFromIntoMemoryview',
'test_socket.BufferIOTest.testRecvFromIntoSmallBuffer',
......
......@@ -12,7 +12,7 @@ import gevent.testing as greentest
from gevent.testing.sysinfo import PY3
from gevent.testing.flaky import reraiseFlakyTestRaceConditionLibuv
from gevent.testing.skipping import skipOnLibuvOnCIOnPyPy
from gevent.testing.skipping import skipOnWindows
try:
ResourceWarning
......@@ -28,24 +28,26 @@ def writer(fobj, line):
fobj.close()
class TestFileObjectThread(greentest.TestCase):
def close_fd_quietly(fd):
try:
os.close(fd)
except (IOError, OSError):
pass
class TestFileObjectBlock(greentest.TestCase):
def _getTargetClass(self):
return fileobject.FileObjectThread
return fileobject.FileObjectBlock
def _makeOne(self, *args, **kwargs):
return self._getTargetClass()(*args, **kwargs)
def _test_del(self, **kwargs):
pipe = os.pipe()
try:
self._do_test_del(pipe, **kwargs)
finally:
for f in pipe:
try:
os.close(f)
except (IOError, OSError):
pass
r, w = os.pipe()
self.addCleanup(close_fd_quietly, r)
self.addCleanup(close_fd_quietly, w)
self._do_test_del((r, w), **kwargs)
def _do_test_del(self, pipe, **kwargs):
r, w = pipe
......@@ -76,48 +78,13 @@ class TestFileObjectThread(greentest.TestCase):
with self._makeOne(r, 'rb') as fobj:
self.assertEqual(fobj.read(), b'x')
# We only use FileObjectThread on Win32. Sometimes the
# visibility of the 'close' operation, which happens in a
# background thread, doesn't make it to the foreground
# thread in a timely fashion, leading to 'os.close(4) must
# not succeed' in test_del_close. We have the same thing
# with flushing and closing in test_newlines. Both of
# these are most commonly (only?) observed on Py27/64-bit.
# They also appear on 64-bit 3.6 with libuv
@skipOnWindows("Thread race conditions")
def test_del(self):
# Close should be true by default
self._test_del()
@skipOnWindows("Thread race conditions")
def test_del_close(self):
self._test_del(close=True)
# FileObjectThread uses os.fdopen() when passed a file-descriptor, which returns
# an object with a destructor that can't be bypassed, so we can't even
# create one that way
def test_del_noclose(self):
with self.assertRaisesRegex(TypeError,
'FileObjectThread does not support close=False on an fd.'):
self._test_del(close=False)
def test_newlines(self):
import warnings
r, w = os.pipe()
lines = [b'line1\n', b'line2\r', b'line3\r\n', b'line4\r\nline5', b'\nline6']
g = gevent.spawn(writer, self._makeOne(w, 'wb'), lines)
try:
with warnings.catch_warnings():
warnings.simplefilter('ignore', DeprecationWarning)
# U is deprecated in Python 3, shows up on FileObjectThread
fobj = self._makeOne(r, 'rU')
result = fobj.read()
fobj.close()
self.assertEqual('line1\nline2\nline3\nline4\nline5\nline6', result)
finally:
g.kill()
@skipOnLibuvOnCIOnPyPy("This appears to crash on libuv/pypy/travis.")
# No idea why, can't duplicate locally.
def test_seek(self):
......@@ -144,7 +111,9 @@ class TestFileObjectThread(greentest.TestCase):
# That shouldn't have any effect on io watchers, though, which were
# already being explicitly closed.
reraiseFlakyTestRaceConditionLibuv()
if PY3 or not isinstance(f, fileobject.FileObjectThread):
if PY3 or hasattr(f, 'seekable'):
# On Python 3, all objects should have seekable.
# On Python 2, only our custom objects do.
self.assertTrue(f.seekable())
f.seek(15)
self.assertEqual(15, f.tell())
......@@ -161,6 +130,11 @@ class TestFileObjectThread(greentest.TestCase):
x.close()
y.close()
class ConcurrentFileObjectMixin(object):
# Additional tests for fileobjects that cooperate
# and we have full control of the implementation
def test_read1(self):
# Issue #840
r, w = os.pipe()
......@@ -170,7 +144,6 @@ class TestFileObjectThread(greentest.TestCase):
self._close_on_teardown(y)
self.assertTrue(hasattr(x, 'read1'))
#if FileObject is not FileObjectThread:
def test_bufsize_0(self):
# Issue #840
r, w = os.pipe()
......@@ -186,27 +159,72 @@ class TestFileObjectThread(greentest.TestCase):
b = x.read(1)
self.assertEqual(b, b'2')
def test_newlines(self):
import warnings
r, w = os.pipe()
lines = [b'line1\n', b'line2\r', b'line3\r\n', b'line4\r\nline5', b'\nline6']
g = gevent.spawn(writer, self._makeOne(w, 'wb'), lines)
try:
with warnings.catch_warnings():
warnings.simplefilter('ignore', DeprecationWarning)
# U is deprecated in Python 3, shows up on FileObjectThread
fobj = self._makeOne(r, 'rU')
result = fobj.read()
fobj.close()
self.assertEqual('line1\nline2\nline3\nline4\nline5\nline6', result)
finally:
g.kill()
class TestFileObjectThread(ConcurrentFileObjectMixin,
TestFileObjectBlock):
def _getTargetClass(self):
return fileobject.FileObjectThread
# FileObjectThread uses os.fdopen() when passed a file-descriptor,
# which returns an object with a destructor that can't be
# bypassed, so we can't even create one that way
def test_del_noclose(self):
with self.assertRaisesRegex(TypeError,
'FileObjectThread does not support close=False on an fd.'):
self._test_del(close=False)
# We don't test this with FileObjectThread. Sometimes the
# visibility of the 'close' operation, which happens in a
# background thread, doesn't make it to the foreground
# thread in a timely fashion, leading to 'os.close(4) must
# not succeed' in test_del_close. We have the same thing
# with flushing and closing in test_newlines. Both of
# these are most commonly (only?) observed on Py27/64-bit.
# They also appear on 64-bit 3.6 with libuv
def test_del(self):
raise unittest.SkipTest("Race conditions")
def test_del_close(self):
raise unittest.SkipTest("Race conditions")
@unittest.skipUnless(
hasattr(fileobject, 'FileObjectPosix'),
"Needs FileObjectPosix"
)
class TestFileObjectPosix(TestFileObjectThread):
class TestFileObjectPosix(ConcurrentFileObjectMixin,
TestFileObjectBlock):
def _getTargetClass(self):
return fileobject.FileObjectPosix
def test_del_noclose(self):
self._test_del(close=False)
def test_seek_raises_ioerror(self):
# https://github.com/gevent/gevent/issues/1323
# Get a non-seekable file descriptor
r, w = os.pipe()
self.addCleanup(os.close, r)
self.addCleanup(os.close, w)
self.addCleanup(close_fd_quietly, r)
self.addCleanup(close_fd_quietly, w)
with self.assertRaises(OSError) as ctx:
os.lseek(r, 0, os.SEEK_SET)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment