Commit 4fae43f1 authored by Jason Madden's avatar Jason Madden

Fix test__core_timer.py by not destroying the default loop. D'oh!

Before I realized that was the root cause, I refactored to avoid
starting the hub greenlet *at all*, and that also fixed the problem.

The problem was that some versions of CPython using the libev-cext
loop (and only that one) would crash garbage collecting a
greenlet (presumably the hub greenlet, which was attached to a
destroyed loop):

0   libsystem_kernel.dylib        	0x00007fff66455e3e __pthread_kill + 10
1   libsystem_pthread.dylib       	0x00007fff66594150 pthread_kill + 333
2   libsystem_c.dylib             	0x00007fff663648fe raise + 26
3   libsystem_platform.dylib      	0x00007fff66587f5a _sigtramp + 26
4   ???                           	000000000000000000 0 + 0
5   greenlet.cpython-35m-darwin.so	0x000000010d76b297 green_clear + 183
6   org.python.python             	0x000000010c707e0c collect + 1824
7   org.python.python             	0x000000010c7076e3 _PyGC_CollectNoFail + 43
8   org.python.python             	0x000000010c6e81d4 PyImport_Cleanup + 968
9   org.python.python             	0x000000010c6f1b49 Py_Finalize + 92
10  org.python.python             	0x000000010c6f20d5 Py_Exit + 13
11  org.python.python             	0x000000010c6f4631 handle_system_exit + 320
12  org.python.python             	0x000000010c6f42a1 PyErr_PrintEx + 42

We should take a look at that and see if we can do something more graceful.
parent ecd1bd10
...@@ -45,43 +45,43 @@ prospector: ...@@ -45,43 +45,43 @@ prospector:
lint: prospector lint: prospector
test_prelim: test_prelim:
which ${PYTHON} @which ${PYTHON}
${PYTHON} --version @${PYTHON} --version
${PYTHON} -c 'import greenlet; print(greenlet, greenlet.__version__)' @${PYTHON} -c 'import greenlet; print(greenlet, greenlet.__version__)'
${PYTHON} -c 'import gevent.core; print(gevent.core.loop)' @${PYTHON} -c 'import gevent.core; print(gevent.core.loop)'
${PYTHON} -c 'import gevent.ares; print(gevent.ares)' @${PYTHON} -c 'import gevent.ares; print(gevent.ares)'
make bench @make bench
# Folding from https://github.com/travis-ci/travis-rubies/blob/9f7962a881c55d32da7c76baefc58b89e3941d91/build.sh#L38-L44 # Folding from https://github.com/travis-ci/travis-rubies/blob/9f7962a881c55d32da7c76baefc58b89e3941d91/build.sh#L38-L44
basictest: test_prelim basictest: test_prelim
${PYTHON} scripts/travis.py fold_start basictest "Running basic tests" @${PYTHON} scripts/travis.py fold_start basictest "Running basic tests"
cd src/greentest && GEVENT_RESOLVER=thread ${PYTHON} testrunner.py --config known_failures.py --quiet cd src/greentest && GEVENT_RESOLVER=thread ${PYTHON} testrunner.py --config known_failures.py --quiet
${PYTHON} scripts/travis.py fold_end basictest @${PYTHON} scripts/travis.py fold_end basictest
alltest: basictest alltest: basictest
${PYTHON} scripts/travis.py fold_start ares "Running c-ares tests" @${PYTHON} scripts/travis.py fold_start ares "Running c-ares tests"
cd src/greentest && GEVENT_RESOLVER=ares GEVENTARES_SERVERS=8.8.8.8 ${PYTHON} testrunner.py --config known_failures.py --ignore tests_that_dont_use_resolver.txt --quiet cd src/greentest && GEVENT_RESOLVER=ares GEVENTARES_SERVERS=8.8.8.8 ${PYTHON} testrunner.py --config known_failures.py --ignore tests_that_dont_use_resolver.txt --quiet
${PYTHON} scripts/travis.py fold_end ares @${PYTHON} scripts/travis.py fold_end ares
${PYTHON} scripts/travis.py fold_start dnspython "Running dnspython tests" @${PYTHON} scripts/travis.py fold_start dnspython "Running dnspython tests"
cd src/greentest && GEVENT_RESOLVER=dnspython ${PYTHON} testrunner.py --config known_failures.py --ignore tests_that_dont_use_resolver.txt --quiet cd src/greentest && GEVENT_RESOLVER=dnspython ${PYTHON} testrunner.py --config known_failures.py --ignore tests_that_dont_use_resolver.txt --quiet
${PYTHON} scripts/travis.py fold_end dnspython @${PYTHON} scripts/travis.py fold_end dnspython
# In the past, we included all test files that had a reference to 'subprocess'' somewhere in their # In the past, we included all test files that had a reference to 'subprocess'' somewhere in their
# text. The monkey-patched stdlib tests were specifically included here. # text. The monkey-patched stdlib tests were specifically included here.
# However, we now always also test on AppVeyor (Windows) which only has GEVENT_FILE=thread, # However, we now always also test on AppVeyor (Windows) which only has GEVENT_FILE=thread,
# so we can save a lot of CI time by reducing the set and excluding the stdlib tests without # so we can save a lot of CI time by reducing the set and excluding the stdlib tests without
# losing any coverage. See the `threadfiletest` for what command used to run. # losing any coverage. See the `threadfiletest` for what command used to run.
${PYTHON} scripts/travis.py fold_start thread "Running GEVENT_FILE=thread tests" @${PYTHON} scripts/travis.py fold_start thread "Running GEVENT_FILE=thread tests"
cd src/greentest && GEVENT_FILE=thread ${PYTHON} testrunner.py --config known_failures.py test__*subprocess*.py --quiet cd src/greentest && GEVENT_FILE=thread ${PYTHON} testrunner.py --config known_failures.py test__*subprocess*.py --quiet
${PYTHON} scripts/travis.py fold_end thread @${PYTHON} scripts/travis.py fold_end thread
threadfiletest: threadfiletest:
cd src/greentest && GEVENT_FILE=thread ${PYTHON} testrunner.py --config known_failures.py `grep -l subprocess test_*.py` --quiet cd src/greentest && GEVENT_FILE=thread ${PYTHON} testrunner.py --config known_failures.py `grep -l subprocess test_*.py` --quiet
allbackendtest: allbackendtest:
${PYTHON} scripts/travis.py fold_start default "Testing default backend" @${PYTHON} scripts/travis.py fold_start default "Testing default backend"
GEVENTTEST_COVERAGE=1 make alltest GEVENTTEST_COVERAGE=1 make alltest
${PYTHON} scripts/travis.py fold_end default @${PYTHON} scripts/travis.py fold_end default
GEVENTTEST_COVERAGE=1 make cffibackendtest GEVENTTEST_COVERAGE=1 make cffibackendtest
# because we set parallel=true, each run produces new and different coverage files; they all need # because we set parallel=true, each run produces new and different coverage files; they all need
# to be combined # to be combined
...@@ -89,17 +89,17 @@ allbackendtest: ...@@ -89,17 +89,17 @@ allbackendtest:
cffibackendtest: cffibackendtest:
${PYTHON} scripts/travis.py fold_start libuv "Testing libuv backend" @${PYTHON} scripts/travis.py fold_start libuv "Testing libuv backend"
GEVENT_LOOP=libuv GEVENTTEST_COVERAGE=1 make alltest GEVENT_LOOP=libuv GEVENTTEST_COVERAGE=1 make alltest
${PYTHON} scripts/travis.py fold_end libuv @${PYTHON} scripts/travis.py fold_end libuv
${PYTHON} scripts/travis.py fold_start libev "Testing libev CFFI backend" @${PYTHON} scripts/travis.py fold_start libev "Testing libev CFFI backend"
GEVENT_LOOP=libev-cffi make alltest GEVENT_LOOP=libev-cffi make alltest
${PYTHON} scripts/travis.py fold_end libev @${PYTHON} scripts/travis.py fold_end libev
leaktest: test_prelim leaktest: test_prelim
${PYTHON} scripts/travis.py fold_start leaktest "Running leak tests" @${PYTHON} scripts/travis.py fold_start leaktest "Running leak tests"
cd src/greentest && GEVENT_RESOLVER=thread GEVENTTEST_LEAKCHECK=1 ${PYTHON} testrunner.py --config known_failures.py --quiet --ignore tests_that_dont_do_leakchecks.txt cd src/greentest && GEVENT_RESOLVER=thread GEVENTTEST_LEAKCHECK=1 ${PYTHON} testrunner.py --config known_failures.py --quiet --ignore tests_that_dont_do_leakchecks.txt
${PYTHON} scripts/travis.py fold_end leaktest @${PYTHON} scripts/travis.py fold_end leaktest
bench: bench:
${PYTHON} src/greentest/bench_sendall.py ${PYTHON} src/greentest/bench_sendall.py
...@@ -197,7 +197,13 @@ test-pypy3: $(PYPY3) ...@@ -197,7 +197,13 @@ test-pypy3: $(PYPY3)
PYTHON=$(PYPY3) PATH=$(BUILD_RUNTIMES)/versions/pypy3.5_5101/bin:$(PATH) make develop basictest PYTHON=$(PYPY3) PATH=$(BUILD_RUNTIMES)/versions/pypy3.5_5101/bin:$(PATH) make develop basictest
test-py27-noembed: $(PY27) test-py27-noembed: $(PY27)
@${PYTHON} scripts/travis.py fold_start conf_libev "Configuring libev"
cd deps/libev && ./configure --disable-dependency-tracking && make cd deps/libev && ./configure --disable-dependency-tracking && make
@${PYTHON} scripts/travis.py fold_end conf_libev
@${PYTHON} scripts/travis.py fold_start conf_cares "Configuring cares"
cd deps/c-ares && ./configure --disable-dependency-tracking && make cd deps/c-ares && ./configure --disable-dependency-tracking && make
@${PYTHON} scripts/travis.py fold_end conf_cares
@${PYTHON} scripts/travis.py fold_start conf_libuv "Configuring libuv"
cd deps/libuv && ./autogen.sh && ./configure --disable-static && make cd deps/libuv && ./autogen.sh && ./configure --disable-static && make
@${PYTHON} scripts/travis.py fold_end conf_libuv
CPPFLAGS="-Ideps/libev -Ideps/c-ares -Ideps/libuv/include" LDFLAGS="-Ldeps/libev/.libs -Ldeps/c-ares/.libs -Ldeps/libuv/.libs" LD_LIBRARY_PATH="$(PWD)/deps/libev/.libs:$(PWD)/deps/c-ares/.libs:$(PWD)/deps/libuv/.libs" EMBED=0 GEVENT_LOOP=libev-cext PYTHON=python2.7.14 PATH=$(BUILD_RUNTIMES)/versions/python2.7.14/bin:$(PATH) make develop basictest CPPFLAGS="-Ideps/libev -Ideps/c-ares -Ideps/libuv/include" LDFLAGS="-Ldeps/libev/.libs -Ldeps/c-ares/.libs -Ldeps/libuv/.libs" LD_LIBRARY_PATH="$(PWD)/deps/libev/.libs:$(PWD)/deps/c-ares/.libs:$(PWD)/deps/libuv/.libs" EMBED=0 GEVENT_LOOP=libev-cext PYTHON=python2.7.14 PATH=$(BUILD_RUNTIMES)/versions/python2.7.14/bin:$(PATH) make develop basictest
...@@ -101,8 +101,6 @@ from greentest.openfiles import get_number_open_files ...@@ -101,8 +101,6 @@ from greentest.openfiles import get_number_open_files
from greentest.openfiles import get_open_files from greentest.openfiles import get_open_files
from greentest.testcase import TestCase from greentest.testcase import TestCase
from greentest.timing import AbstractGenericGetTestCase as GenericGetTestCase
from greentest.timing import AbstractGenericWaitTestCase as GenericWaitTestCase
from greentest.modules import walk_modules from greentest.modules import walk_modules
......
...@@ -95,7 +95,9 @@ class TestCaseMetaClass(type): ...@@ -95,7 +95,9 @@ class TestCaseMetaClass(type):
if sysinfo.RUN_LEAKCHECKS and timeout is not None: if sysinfo.RUN_LEAKCHECKS and timeout is not None:
timeout *= 6 timeout *= 6
check_totalrefcount = _get_class_attr(classDict, bases, 'check_totalrefcount', True) check_totalrefcount = _get_class_attr(classDict, bases, 'check_totalrefcount', True)
error_fatal = _get_class_attr(classDict, bases, 'error_fatal', True) error_fatal = _get_class_attr(classDict, bases, 'error_fatal', True)
uses_handle_error = _get_class_attr(classDict, bases, 'uses_handle_error', True)
# Python 3: must copy, we mutate the classDict. Interestingly enough, # Python 3: must copy, we mutate the classDict. Interestingly enough,
# it doesn't actually error out, but under 3.6 we wind up wrapping # it doesn't actually error out, but under 3.6 we wind up wrapping
# and re-wrapping the same items over and over and over. # and re-wrapping the same items over and over and over.
...@@ -108,7 +110,8 @@ class TestCaseMetaClass(type): ...@@ -108,7 +110,8 @@ class TestCaseMetaClass(type):
error_fatal = getattr(value, 'error_fatal', error_fatal) error_fatal = getattr(value, 'error_fatal', error_fatal)
if error_fatal: if error_fatal:
value = errorhandler.wrap_error_fatal(value) value = errorhandler.wrap_error_fatal(value)
value = errorhandler.wrap_restore_handle_error(value) if uses_handle_error:
value = errorhandler.wrap_restore_handle_error(value)
if check_totalrefcount and sysinfo.RUN_LEAKCHECKS: if check_totalrefcount and sysinfo.RUN_LEAKCHECKS:
value = leakcheck.wrap_refcount(value) value = leakcheck.wrap_refcount(value)
classDict[key] = value classDict[key] = value
...@@ -122,6 +125,7 @@ class TestCase(TestCaseMetaClass("NewBase", (TimeAssertMixin, BaseTestCase,), {} ...@@ -122,6 +125,7 @@ class TestCase(TestCaseMetaClass("NewBase", (TimeAssertMixin, BaseTestCase,), {}
switch_expected = 'default' switch_expected = 'default'
error_fatal = True error_fatal = True
uses_handle_error = True
close_on_teardown = () close_on_teardown = ()
def run(self, *args, **kwargs): def run(self, *args, **kwargs):
......
...@@ -105,9 +105,10 @@ class TestTimers(greentest.TestCase): ...@@ -105,9 +105,10 @@ class TestTimers(greentest.TestCase):
gevent.sleep(0.02) gevent.sleep(0.02)
gevent.spawn(func) gevent.spawn(func)
assert lst == [1], lst self.assertEqual(lst, [1])
gevent.sleep(0.03) gevent.sleep(0.1)
assert lst == [], lst self.assertEqual(lst, [])
def test_spawn_is_not_cancelled(self): def test_spawn_is_not_cancelled(self):
lst = [1] lst = [1]
...@@ -116,8 +117,8 @@ class TestTimers(greentest.TestCase): ...@@ -116,8 +117,8 @@ class TestTimers(greentest.TestCase):
gevent.spawn(lst.pop) gevent.spawn(lst.pop)
# exiting immediately, but self.lst.pop must be called # exiting immediately, but self.lst.pop must be called
gevent.spawn(func) gevent.spawn(func)
gevent.sleep(0.01) gevent.sleep(0.1)
assert lst == [], lst self.assertEqual(lst, [])
if __name__ == '__main__': if __name__ == '__main__':
......
...@@ -9,11 +9,12 @@ from greentest.sysinfo import CFFI_BACKEND ...@@ -9,11 +9,12 @@ from greentest.sysinfo import CFFI_BACKEND
class Test(TestCase): class Test(TestCase):
__timeout__ = LARGE_TIMEOUT __timeout__ = LARGE_TIMEOUT
repeat = 0 repeat = 0
def setUp(self): def setUp(self):
self.called = [] self.called = []
self.loop = config.loop(default=True) self.loop = config.loop(default=False)
self.timer = self.loop.timer(0.001, repeat=self.repeat) self.timer = self.loop.timer(0.001, repeat=self.repeat)
def cleanup(self): def cleanup(self):
...@@ -74,6 +75,8 @@ class TestAgain(Test): ...@@ -74,6 +75,8 @@ class TestAgain(Test):
self.assertEqual(x.args, (x,)) self.assertEqual(x.args, (x,))
# XXX: On libev, this takes 1 second. On libuv,
# it takes the expected time.
self.loop.run() self.loop.run()
self.assertEqual(self.called, [1]) self.assertEqual(self.called, [1])
......
...@@ -6,11 +6,13 @@ from gevent.event import Event, AsyncResult ...@@ -6,11 +6,13 @@ from gevent.event import Event, AsyncResult
import greentest import greentest
from greentest.skipping import skipUnderCoverage from greentest.skipping import skipUnderCoverage
from greentest.six import xrange from greentest.six import xrange
from greentest.timing import AbstractGenericGetTestCase
from greentest.timing import AbstractGenericWaitTestCase
DELAY = 0.01 DELAY = 0.01
class TestEventWait(greentest.GenericWaitTestCase): class TestEventWait(AbstractGenericWaitTestCase):
def wait(self, timeout): def wait(self, timeout):
Event().wait(timeout=timeout) Event().wait(timeout=timeout)
...@@ -19,7 +21,7 @@ class TestEventWait(greentest.GenericWaitTestCase): ...@@ -19,7 +21,7 @@ class TestEventWait(greentest.GenericWaitTestCase):
str(Event()) str(Event())
class TestWaitEvent(greentest.GenericWaitTestCase): class TestWaitEvent(AbstractGenericWaitTestCase):
def wait(self, timeout): def wait(self, timeout):
gevent.wait([Event()], timeout=timeout) gevent.wait([Event()], timeout=timeout)
...@@ -58,19 +60,19 @@ class TestWaitEvent(greentest.GenericWaitTestCase): ...@@ -58,19 +60,19 @@ class TestWaitEvent(greentest.GenericWaitTestCase):
gevent.spawn(waiter).join() gevent.spawn(waiter).join()
class TestAsyncResultWait(greentest.GenericWaitTestCase): class TestAsyncResultWait(AbstractGenericWaitTestCase):
def wait(self, timeout): def wait(self, timeout):
AsyncResult().wait(timeout=timeout) AsyncResult().wait(timeout=timeout)
class TestWaitAsyncResult(greentest.GenericWaitTestCase): class TestWaitAsyncResult(AbstractGenericWaitTestCase):
def wait(self, timeout): def wait(self, timeout):
gevent.wait([AsyncResult()], timeout=timeout) gevent.wait([AsyncResult()], timeout=timeout)
class TestAsyncResultGet(greentest.GenericGetTestCase): class TestAsyncResultGet(AbstractGenericGetTestCase):
def wait(self, timeout): def wait(self, timeout):
AsyncResult().get(timeout=timeout) AsyncResult().get(timeout=timeout)
...@@ -232,5 +234,8 @@ class TestWait_count2(TestWait): ...@@ -232,5 +234,8 @@ class TestWait_count2(TestWait):
count = 2 count = 2
del AbstractGenericGetTestCase
del AbstractGenericWaitTestCase
if __name__ == '__main__': if __name__ == '__main__':
greentest.main() greentest.main()
This diff is collapsed.
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
# THE SOFTWARE. # THE SOFTWARE.
import greentest import greentest
import greentest.timing
import time import time
import re import re
import gevent import gevent
...@@ -71,7 +72,7 @@ class TestExceptionInMainloop(greentest.TestCase): ...@@ -71,7 +72,7 @@ class TestExceptionInMainloop(greentest.TestCase):
class TestSleep(greentest.GenericWaitTestCase): class TestSleep(greentest.timing.AbstractGenericWaitTestCase):
def wait(self, timeout): def wait(self, timeout):
gevent.sleep(timeout) gevent.sleep(timeout)
...@@ -80,7 +81,7 @@ class TestSleep(greentest.GenericWaitTestCase): ...@@ -80,7 +81,7 @@ class TestSleep(greentest.GenericWaitTestCase):
gevent.sleep(0) gevent.sleep(0)
class TestWaiterGet(greentest.GenericWaitTestCase): class TestWaiterGet(greentest.timing.AbstractGenericWaitTestCase):
def setUp(self): def setUp(self):
super(TestWaiterGet, self).setUp() super(TestWaiterGet, self).setUp()
......
from time import time from time import time
import gevent import gevent
from gevent import pool import gevent.pool
from gevent.event import Event from gevent.event import Event
from gevent.queue import Queue from gevent.queue import Queue
from gevent.timeout import Timeout
import greentest import greentest
import greentest.timing
import random import random
from greentest import ExpectedException from greentest import ExpectedException
from greentest import six from greentest import six
...@@ -13,12 +14,12 @@ import unittest ...@@ -13,12 +14,12 @@ import unittest
class TestCoroutinePool(unittest.TestCase): class TestCoroutinePool(unittest.TestCase):
klass = pool.Pool klass = gevent.pool.Pool
def test_apply_async(self): def test_apply_async(self):
done = Event() done = Event()
def some_work(x): def some_work(_):
done.set() done.set()
pool = self.klass(2) pool = self.klass(2)
...@@ -125,18 +126,18 @@ class TestCoroutinePool(unittest.TestCase): ...@@ -125,18 +126,18 @@ class TestCoroutinePool(unittest.TestCase):
pool.join() pool.join()
def crash(*args, **kw): def crash(*_args, **_kw):
raise RuntimeError("Whoa") raise RuntimeError("Whoa")
class FakeFile(object): class FakeFile(object):
def write(*args): def write(self, *_args):
raise RuntimeError('Whaaa') raise RuntimeError('Whaaa')
class PoolBasicTests(greentest.TestCase): class PoolBasicTests(greentest.TestCase):
klass = pool.Pool klass = gevent.pool.Pool
def test_execute_async(self): def test_execute_async(self):
p = self.klass(size=2) p = self.klass(size=2)
...@@ -208,7 +209,7 @@ class PoolBasicTests(greentest.TestCase): ...@@ -208,7 +209,7 @@ class PoolBasicTests(greentest.TestCase):
second = gevent.spawn(gevent.sleep, 1000) second = gevent.spawn(gevent.sleep, 1000)
try: try:
p.add(first) p.add(first)
with self.assertRaises(pool.PoolFull): with self.assertRaises(gevent.pool.PoolFull):
p.add(second, blocking=False) p.add(second, blocking=False)
finally: finally:
second.kill() second.kill()
...@@ -223,7 +224,7 @@ class PoolBasicTests(greentest.TestCase): ...@@ -223,7 +224,7 @@ class PoolBasicTests(greentest.TestCase):
second = gevent.spawn(gevent.sleep, 1000) second = gevent.spawn(gevent.sleep, 1000)
try: try:
p.add(first) p.add(first)
with self.assertRaises(pool.PoolFull): with self.assertRaises(gevent.pool.PoolFull):
p.add(second, timeout=0.100) p.add(second, timeout=0.100)
finally: finally:
second.kill() second.kill()
...@@ -238,7 +239,7 @@ class PoolBasicTests(greentest.TestCase): ...@@ -238,7 +239,7 @@ class PoolBasicTests(greentest.TestCase):
second = gevent.Greenlet(gevent.sleep, 1000) second = gevent.Greenlet(gevent.sleep, 1000)
try: try:
p.add(first) p.add(first)
with self.assertRaises(pool.PoolFull): with self.assertRaises(gevent.pool.PoolFull):
p.start(second, timeout=0.100) p.start(second, timeout=0.100)
finally: finally:
second.kill() second.kill()
...@@ -304,13 +305,13 @@ if greentest.PYPY and greentest.WIN: ...@@ -304,13 +305,13 @@ if greentest.PYPY and greentest.WIN:
elif greentest.RUNNING_ON_CI or greentest.EXPECT_POOR_TIMER_RESOLUTION: elif greentest.RUNNING_ON_CI or greentest.EXPECT_POOR_TIMER_RESOLUTION:
LARGE_RANGE = 100 LARGE_RANGE = 100
class TestPool(greentest.TestCase): class TestPool(greentest.TestCase): # pylint:disable=too-many-public-methods
__timeout__ = greentest.LARGE_TIMEOUT __timeout__ = greentest.LARGE_TIMEOUT
size = 1 size = 1
def setUp(self): def setUp(self):
greentest.TestCase.setUp(self) greentest.TestCase.setUp(self)
self.pool = pool.Pool(self.size) self.pool = gevent.pool.Pool(self.size)
def cleanup(self): def cleanup(self):
self.pool.join() self.pool.join()
...@@ -438,17 +439,11 @@ class TestPool(greentest.TestCase): ...@@ -438,17 +439,11 @@ class TestPool(greentest.TestCase):
running = [0] running = [0]
def short_running_func(i, j): def short_running_func(i, _j):
running[0] += 1 running[0] += 1
return i return i
# Send two iterables to make sure varargs and kwargs are handled def make_reader(mapping):
# correctly
for meth in self.pool.imap_unordered, self.pool.imap:
running[0] = 0
mapping = meth(short_running_func, iterable, iterable,
maxsize=1)
# Simulate a long running reader. No matter how many workers # Simulate a long running reader. No matter how many workers
# we have, we will never have a queue more than size 1 # we have, we will never have a queue more than size 1
def reader(): def reader():
...@@ -459,7 +454,16 @@ class TestPool(greentest.TestCase): ...@@ -459,7 +454,16 @@ class TestPool(greentest.TestCase):
gevent.sleep(0.01) gevent.sleep(0.01)
self.assertTrue(len(mapping.queue) <= 2, len(mapping.queue)) self.assertTrue(len(mapping.queue) <= 2, len(mapping.queue))
return result return result
return reader
# Send two iterables to make sure varargs and kwargs are handled
# correctly
for meth in self.pool.imap_unordered, self.pool.imap:
running[0] = 0
mapping = meth(short_running_func, iterable, iterable,
maxsize=1)
reader = make_reader(mapping)
l = reader() l = reader()
self.assertEqual(sorted(l), iterable) self.assertEqual(sorted(l), iterable)
...@@ -484,16 +488,16 @@ class TestPool0(greentest.TestCase): ...@@ -484,16 +488,16 @@ class TestPool0(greentest.TestCase):
size = 0 size = 0
def test_wait_full(self): def test_wait_full(self):
p = pool.Pool(size=0) p = gevent.pool.Pool(size=0)
self.assertEqual(0, p.free_count()) self.assertEqual(0, p.free_count())
self.assertTrue(p.full()) self.assertTrue(p.full())
self.assertEqual(0, p.wait_available(timeout=0.01)) self.assertEqual(0, p.wait_available(timeout=0.01))
class TestJoinSleep(greentest.GenericWaitTestCase): class TestJoinSleep(greentest.timing.AbstractGenericWaitTestCase):
def wait(self, timeout): def wait(self, timeout):
p = pool.Pool() p = gevent.pool.Pool()
g = p.spawn(gevent.sleep, 10) g = p.spawn(gevent.sleep, 10)
try: try:
p.join(timeout=timeout) p.join(timeout=timeout)
...@@ -501,10 +505,10 @@ class TestJoinSleep(greentest.GenericWaitTestCase): ...@@ -501,10 +505,10 @@ class TestJoinSleep(greentest.GenericWaitTestCase):
g.kill() g.kill()
class TestJoinSleep_raise_error(greentest.GenericWaitTestCase): class TestJoinSleep_raise_error(greentest.timing.AbstractGenericWaitTestCase):
def wait(self, timeout): def wait(self, timeout):
p = pool.Pool() p = gevent.pool.Pool()
g = p.spawn(gevent.sleep, 10) g = p.spawn(gevent.sleep, 10)
try: try:
p.join(timeout=timeout, raise_error=True) p.join(timeout=timeout, raise_error=True)
...@@ -516,7 +520,7 @@ class TestJoinEmpty(greentest.TestCase): ...@@ -516,7 +520,7 @@ class TestJoinEmpty(greentest.TestCase):
switch_expected = False switch_expected = False
def test(self): def test(self):
p = pool.Pool() p = gevent.pool.Pool()
res = p.join() res = p.join()
self.assertTrue(res, "empty should return true") self.assertTrue(res, "empty should return true")
...@@ -525,7 +529,7 @@ class TestSpawn(greentest.TestCase): ...@@ -525,7 +529,7 @@ class TestSpawn(greentest.TestCase):
switch_expected = True switch_expected = True
def test(self): def test(self):
p = pool.Pool(1) p = gevent.pool.Pool(1)
self.assertEqual(len(p), 0) self.assertEqual(len(p), 0)
p.spawn(gevent.sleep, 0.1) p.spawn(gevent.sleep, 0.1)
self.assertEqual(len(p), 1) self.assertEqual(len(p), 1)
...@@ -535,7 +539,7 @@ class TestSpawn(greentest.TestCase): ...@@ -535,7 +539,7 @@ class TestSpawn(greentest.TestCase):
self.assertEqual(len(p), 0) self.assertEqual(len(p), 0)
def testSpawnAndWait(self): def testSpawnAndWait(self):
p = pool.Pool(1) p = gevent.pool.Pool(1)
self.assertEqual(len(p), 0) self.assertEqual(len(p), 0)
p.spawn(gevent.sleep, 0.1) p.spawn(gevent.sleep, 0.1)
self.assertEqual(len(p), 1) self.assertEqual(len(p), 1)
...@@ -555,12 +559,12 @@ class TestErrorInIterator(greentest.TestCase): ...@@ -555,12 +559,12 @@ class TestErrorInIterator(greentest.TestCase):
error_fatal = False error_fatal = False
def test(self): def test(self):
p = pool.Pool(3) p = gevent.pool.Pool(3)
self.assertRaises(ExpectedException, p.map, lambda x: None, error_iter()) self.assertRaises(ExpectedException, p.map, lambda x: None, error_iter())
gevent.sleep(0.001) gevent.sleep(0.001)
def test_unordered(self): def test_unordered(self):
p = pool.Pool(3) p = gevent.pool.Pool(3)
def unordered(): def unordered():
return list(p.imap_unordered(lambda x: None, error_iter())) return list(p.imap_unordered(lambda x: None, error_iter()))
...@@ -577,11 +581,11 @@ class TestErrorInHandler(greentest.TestCase): ...@@ -577,11 +581,11 @@ class TestErrorInHandler(greentest.TestCase):
error_fatal = False error_fatal = False
def test_map(self): def test_map(self):
p = pool.Pool(3) p = gevent.pool.Pool(3)
self.assertRaises(ZeroDivisionError, p.map, divide_by, [1, 0, 2]) self.assertRaises(ZeroDivisionError, p.map, divide_by, [1, 0, 2])
def test_imap(self): def test_imap(self):
p = pool.Pool(1) p = gevent.pool.Pool(1)
it = p.imap(divide_by, [1, 0, 2]) it = p.imap(divide_by, [1, 0, 2])
self.assertEqual(next(it), 1.0) self.assertEqual(next(it), 1.0)
self.assertRaises(ZeroDivisionError, next, it) self.assertRaises(ZeroDivisionError, next, it)
...@@ -589,7 +593,7 @@ class TestErrorInHandler(greentest.TestCase): ...@@ -589,7 +593,7 @@ class TestErrorInHandler(greentest.TestCase):
self.assertRaises(StopIteration, next, it) self.assertRaises(StopIteration, next, it)
def test_imap_unordered(self): def test_imap_unordered(self):
p = pool.Pool(1) p = gevent.pool.Pool(1)
it = p.imap_unordered(divide_by, [1, 0, 2]) it = p.imap_unordered(divide_by, [1, 0, 2])
self.assertEqual(next(it), 1.0) self.assertEqual(next(it), 1.0)
self.assertRaises(ZeroDivisionError, next, it) self.assertRaises(ZeroDivisionError, next, it)
......
import greentest import greentest
from greentest import TestCase, main, GenericGetTestCase from greentest import TestCase, main
import gevent import gevent
from gevent.hub import get_hub, LoopExit from gevent.hub import get_hub, LoopExit
from gevent import util from gevent import util
from gevent import queue from gevent import queue
from gevent.queue import Empty, Full from gevent.queue import Empty, Full
from gevent.event import AsyncResult from gevent.event import AsyncResult
from greentest.timing import AbstractGenericGetTestCase
# pylint:disable=too-many-ancestors
class TestQueue(TestCase): class TestQueue(TestCase):
...@@ -372,7 +374,7 @@ class TestJoinEmpty(TestCase): ...@@ -372,7 +374,7 @@ class TestJoinEmpty(TestCase):
q.join() q.join()
class TestGetInterrupt(GenericGetTestCase): class TestGetInterrupt(AbstractGenericGetTestCase):
Timeout = Empty Timeout = Empty
...@@ -397,7 +399,7 @@ class TestGetInterruptChannel(TestGetInterrupt): ...@@ -397,7 +399,7 @@ class TestGetInterruptChannel(TestGetInterrupt):
kind = queue.Channel kind = queue.Channel
class TestPutInterrupt(GenericGetTestCase): class TestPutInterrupt(AbstractGenericGetTestCase):
kind = queue.Queue kind = queue.Queue
Timeout = Full Timeout = Full
...@@ -430,7 +432,7 @@ class TestPutInterruptChannel(TestPutInterrupt): ...@@ -430,7 +432,7 @@ class TestPutInterruptChannel(TestPutInterrupt):
return self.kind() return self.kind()
del GenericGetTestCase del AbstractGenericGetTestCase
if __name__ == '__main__': if __name__ == '__main__':
......
...@@ -5,86 +5,87 @@ import errno ...@@ -5,86 +5,87 @@ import errno
from gevent import select, socket from gevent import select, socket
import gevent.core import gevent.core
import greentest import greentest
import greentest.timing
import unittest import unittest
class TestSelect(greentest.GenericWaitTestCase): class TestSelect(greentest.timing.AbstractGenericWaitTestCase):
def wait(self, timeout): def wait(self, timeout):
select.select([], [], [], timeout) select.select([], [], [], timeout)
if sys.platform != 'win32':
class TestSelectRead(greentest.GenericWaitTestCase): @greentest.skipOnWindows("Cant select on files")
class TestSelectRead(greentest.timing.AbstractGenericWaitTestCase):
def wait(self, timeout): def wait(self, timeout):
r, w = os.pipe() r, w = os.pipe()
try:
select.select([r], [], [], timeout)
finally:
os.close(r)
os.close(w)
# Issue #12367: http://www.freebsd.org/cgi/query-pr.cgi?pr=kern/155606
@unittest.skipIf(sys.platform.startswith('freebsd'),
'skip because of a FreeBSD bug: kern/155606')
def test_errno(self):
# Backported from test_select.py in 3.4
with open(__file__, 'rb') as fp:
fd = fp.fileno()
fp.close()
try: try:
select.select([r], [], [], timeout) select.select([fd], [], [], 0)
finally: except OSError as err:
os.close(r) # Python 3
os.close(w) self.assertEqual(err.errno, errno.EBADF)
except select.error as err: # pylint:disable=duplicate-except
# Issue #12367: http://www.freebsd.org/cgi/query-pr.cgi?pr=kern/155606 # Python 2 (select.error is OSError on py3)
@unittest.skipIf(sys.platform.startswith('freebsd'), self.assertEqual(err.args[0], errno.EBADF)
'skip because of a FreeBSD bug: kern/155606') else:
def test_errno(self): self.fail("exception not raised")
# Backported from test_select.py in 3.4
with open(__file__, 'rb') as fp:
fd = fp.fileno() @unittest.skipUnless(hasattr(select, 'poll'), "Needs poll")
fp.close() @greentest.skipOnWindows("Cant poll on files")
try: class TestPollRead(greentest.timing.AbstractGenericWaitTestCase):
select.select([fd], [], [], 0) def wait(self, timeout):
except OSError as err: # On darwin, the read pipe is reported as writable
# Python 3 # immediately, for some reason. So we carefully register
self.assertEqual(err.errno, errno.EBADF) # it only for read events (the default is read and write)
except select.error as err: # pylint:disable=duplicate-except r, w = os.pipe()
# Python 2 (select.error is OSError on py3) try:
self.assertEqual(err.args[0], errno.EBADF) poll = select.poll()
else: poll.register(r, select.POLLIN)
self.fail("exception not raised") poll.poll(timeout * 1000)
finally:
poll.unregister(r)
if hasattr(select, 'poll'): os.close(r)
os.close(w)
class TestPollRead(greentest.GenericWaitTestCase):
def wait(self, timeout): def test_unregister_never_registered(self):
# On darwin, the read pipe is reported as writable # "Attempting to remove a file descriptor that was
# immediately, for some reason. So we carefully register # never registered causes a KeyError exception to be
# it only for read events (the default is read and write) # raised."
r, w = os.pipe() poll = select.poll()
try: self.assertRaises(KeyError, poll.unregister, 5)
poll = select.poll()
poll.register(r, select.POLLIN) @unittest.skipIf(hasattr(gevent.core, 'libuv'),
poll.poll(timeout * 1000) "Depending on whether the fileno is reused or not this either crashes or does nothing."
finally: "libuv won't open a watcher for a closed file on linux.")
poll.unregister(r) def test_poll_invalid(self):
os.close(r) with open(__file__, 'rb') as fp:
os.close(w) fd = fp.fileno()
def test_unregister_never_registered(self): poll = select.poll()
# "Attempting to remove a file descriptor that was poll.register(fd, select.POLLIN)
# never registered causes a KeyError exception to be # Close after registering; libuv refuses to even
# raised." # create a watcher if it would get EBADF (so this turns into
poll = select.poll() # a test of whether or not we successfully initted the watcher).
self.assertRaises(KeyError, poll.unregister, 5) fp.close()
result = poll.poll(0)
@unittest.skipIf(hasattr(gevent.core, 'libuv'), self.assertEqual(result, [(fd, select.POLLNVAL)]) # pylint:disable=no-member
"Depending on whether the fileno is reused or not this either crashes or does nothing."
"libuv won't open a watcher for a closed file on linux.")
def test_poll_invalid(self):
with open(__file__, 'rb') as fp:
fd = fp.fileno()
poll = select.poll()
poll.register(fd, select.POLLIN)
# Close after registering; libuv refuses to even
# create a watcher if it would get EBADF (so this turns into
# a test of whether or not we successfully initted the watcher).
fp.close()
result = poll.poll(0)
self.assertEqual(result, [(fd, select.POLLNVAL)]) # pylint:disable=no-member
class TestSelectTypes(greentest.TestCase): class TestSelectTypes(greentest.TestCase):
......
...@@ -27,6 +27,7 @@ from greentest.sysinfo import RESOLVER_NOT_SYSTEM ...@@ -27,6 +27,7 @@ from greentest.sysinfo import RESOLVER_NOT_SYSTEM
from greentest.sysinfo import RESOLVER_DNSPYTHON from greentest.sysinfo import RESOLVER_DNSPYTHON
from greentest.sysinfo import RESOLVER_ARES from greentest.sysinfo import RESOLVER_ARES
from greentest.sysinfo import PY2 from greentest.sysinfo import PY2
import greentest.timing
assert gevent_socket.gaierror is socket.gaierror assert gevent_socket.gaierror is socket.gaierror
...@@ -570,7 +571,7 @@ add(TestInternational, u'президент.рф', 'russian', ...@@ -570,7 +571,7 @@ add(TestInternational, u'президент.рф', 'russian',
add(TestInternational, u'президент.рф'.encode('idna'), 'idna') add(TestInternational, u'президент.рф'.encode('idna'), 'idna')
class TestInterrupted_gethostbyname(greentest.GenericWaitTestCase): class TestInterrupted_gethostbyname(greentest.timing.AbstractGenericWaitTestCase):
# There are refs to a Waiter in the C code that don't go # There are refs to a Waiter in the C code that don't go
# away yet; one gc may or may not do it. # away yet; one gc may or may not do it.
......
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