Commit a2c56938 authored by Jason Madden's avatar Jason Madden Committed by GitHub

Merge pull request #1309 from gevent/issue1293

Refactoring greentest
parents a8c1f171 b77e9acd
...@@ -12,12 +12,11 @@ omit = ...@@ -12,12 +12,11 @@ omit =
src/gevent/_ssl2.py src/gevent/_ssl2.py
src/gevent/libev/_corecffi_build.py src/gevent/libev/_corecffi_build.py
src/gevent/libuv/_corecffi_build.py src/gevent/libuv/_corecffi_build.py
src/gevent/win32util.py src/gevent/win32util.py
# having concurrency=greenlet means that the Queue class # having concurrency=greenlet means that the Queue class
# which is used from multiple real threads doesn't # which is used from multiple real threads doesn't
# properly get covered. # properly get covered.
src/gevent/_threading.py src/gevent/_threading.py
test_*
# local.so sometimes gets included, and it can't be parsed # local.so sometimes gets included, and it can't be parsed
# as source, so it fails the whole process. # as source, so it fails the whole process.
*.so *.so
...@@ -43,3 +42,4 @@ omit = ...@@ -43,3 +42,4 @@ omit =
# as source, so it fails the whole process. # as source, so it fails the whole process.
# coverage 4.5 needs this specified here, 4.4.2 needed it in [run] # coverage 4.5 needs this specified here, 4.4.2 needed it in [run]
*.so *.so
/tmp/test_*
...@@ -35,9 +35,9 @@ Makefile.ext ...@@ -35,9 +35,9 @@ Makefile.ext
MANIFEST MANIFEST
*_flymake.py *_flymake.py
src/greentest/.coverage\.* .coverage\.*
src/greentest/htmlcov htmlcov/
src/greentest/.coverage .coverage
doc/_build doc/_build
doc/__pycache__ doc/__pycache__
......
...@@ -98,7 +98,7 @@ ignored-classes=SSLContext, SSLSocket, greenlet, Greenlet, parent, dead ...@@ -98,7 +98,7 @@ ignored-classes=SSLContext, SSLSocket, greenlet, Greenlet, parent, dead
# (useful for modules/projects where namespaces are manipulated during runtime # (useful for modules/projects where namespaces are manipulated during runtime
# and thus existing member attributes cannot be deduced by static analysis. It # and thus existing member attributes cannot be deduced by static analysis. It
# supports qualified module names, as well as Unix pattern matching. # supports qualified module names, as well as Unix pattern matching.
ignored-modules=gevent._corecffi,gevent.os,os,greenlet,threading,gevent.libev.corecffi ignored-modules=gevent._corecffi,gevent.os,os,greenlet,threading,gevent.libev.corecffi,gevent.socket,gevent.core
[DESIGN] [DESIGN]
max-attributes=12 max-attributes=12
......
...@@ -9,6 +9,11 @@ env: ...@@ -9,6 +9,11 @@ env:
global: global:
- BUILD_RUNTIMES=$HOME/.runtimes - BUILD_RUNTIMES=$HOME/.runtimes
- PYTHONHASHSEED=random - PYTHONHASHSEED=random
- CC="ccache gcc"
- CCACHE_NOCPP2=true
- CCACHE_SLOPPINESS=file_macro,time_macros,include_file_ctime,include_file_mtime
- CCACHE_NOHASHDIR=true
- CFLAGS="-g -pipe"
matrix: matrix:
# These are ordered to get as much diversity in the # These are ordered to get as much diversity in the
...@@ -38,7 +43,7 @@ cache: ...@@ -38,7 +43,7 @@ cache:
- $HOME/.venv - $HOME/.venv
- $HOME/.runtimes - $HOME/.runtimes
- $HOME/.wheelhouse - $HOME/.wheelhouse
- $HOME/.ccache
before_cache: before_cache:
- rm -f $HOME/.cache/pip/log/debug.log - rm -f $HOME/.cache/pip/log/debug.log
...@@ -42,6 +42,10 @@ ...@@ -42,6 +42,10 @@
Objects/tupleobject.c: bad argument to internal function``. Reported Objects/tupleobject.c: bad argument to internal function``. Reported
in :issue:`1302` by Ulrich Petri. in :issue:`1302` by Ulrich Petri.
- Refactored the gevent test runner and test suite to make them more
reusable. In particular, the tests are now run with ``python -m
gevent.tests``. See :issue:`1293`.
1.3.7 (2018-10-12) 1.3.7 (2018-10-12)
================== ==================
......
...@@ -22,7 +22,7 @@ clean: ...@@ -22,7 +22,7 @@ clean:
rm -rf src/gevent/libev/*.o src/gevent/libuv/*.o src/gevent/*.o rm -rf src/gevent/libev/*.o src/gevent/libuv/*.o src/gevent/*.o
rm -rf src/gevent/__pycache__ src/greentest/__pycache__ src/greentest/greentest/__pycache__ src/gevent/libev/__pycache__ rm -rf src/gevent/__pycache__ src/greentest/__pycache__ src/greentest/greentest/__pycache__ src/gevent/libev/__pycache__
rm -rf src/gevent/*.pyc src/greentest/*.pyc src/gevent/libev/*.pyc rm -rf src/gevent/*.pyc src/greentest/*.pyc src/gevent/libev/*.pyc
rm -rf src/greentest/htmlcov src/greentest/.coverage rm -rf htmlcov .coverage
rm -rf build rm -rf build
distclean: clean distclean: clean
...@@ -33,8 +33,6 @@ distclean: clean ...@@ -33,8 +33,6 @@ distclean: clean
doc: doc:
cd doc && PYTHONPATH=.. make html cd doc && PYTHONPATH=.. make html
whitespace:
! find . -not -path "*.pem" -not -path "./.eggs/*" -not -path "./src/greentest/htmlcov/*" -not -path "./src/greentest/.coverage.*" -not -path "./.tox/*" -not -path "*/__pycache__/*" -not -path "*.so" -not -path "*.pyc" -not -path "./.git/*" -not -path "./build/*" -not -path "./src/gevent/libev/*" -not -path "./src/gevent.egg-info/*" -not -path "./dist/*" -not -path "./.DS_Store" -not -path "./deps/*" -not -path "./src/gevent/libev/corecext.*.[ch]" -not -path "./src/gevent/resolver/cares.*" -not -path "./doc/_build/*" -not -path "./doc/mytheme/static/*" -type f | xargs egrep -l " $$"
prospector: prospector:
which pylint which pylint
...@@ -59,28 +57,25 @@ test_prelim: ...@@ -59,28 +57,25 @@ test_prelim:
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 GEVENT_RESOLVER=thread ${PYTHON} -mgevent.tests --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 ${PYTHON} testrunner.py --config known_failures.py --ignore tests_that_dont_use_resolver.txt --quiet GEVENT_RESOLVER=ares ${PYTHON} -mgevent.tests --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 GEVENT_RESOLVER=dnspython ${PYTHON} -mgevent.tests --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.
@${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/gevent/tests && GEVENT_FILE=thread ${PYTHON} -mgevent.tests --config known_failures.py test__*subprocess*.py --quiet
@${PYTHON} scripts/travis.py fold_end thread @${PYTHON} scripts/travis.py fold_end thread
threadfiletest:
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
...@@ -101,7 +96,7 @@ cffibackendtest: ...@@ -101,7 +96,7 @@ cffibackendtest:
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 GEVENT_RESOLVER=thread GEVENTTEST_LEAKCHECK=1 ${PYTHON} -mgevent.tests --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
@${PYTHON} scripts/travis.py fold_start default "Testing default backend pure python" @${PYTHON} scripts/travis.py fold_start default "Testing default backend pure python"
PURE_PYTHON=1 GEVENTTEST_COVERAGE=1 make basictest PURE_PYTHON=1 GEVENTTEST_COVERAGE=1 make basictest
...@@ -116,8 +111,9 @@ travis_test_linters: ...@@ -116,8 +111,9 @@ travis_test_linters:
make cffibackendtest make cffibackendtest
coverage_combine: coverage_combine:
coverage combine . src/greentest/ coverage combine .
-coveralls --rcfile=src/greentest/.coveragerc coverage report -i
-coveralls
.PHONY: clean doc prospector lint travistest travis .PHONY: clean doc prospector lint travistest travis
...@@ -191,7 +187,7 @@ test-py34: $(PY34) ...@@ -191,7 +187,7 @@ test-py34: $(PY34)
PYTHON=python3.4.8 PATH=$(BUILD_RUNTIMES)/versions/python3.4.8/bin:$(PATH) make develop basictest PYTHON=python3.4.8 PATH=$(BUILD_RUNTIMES)/versions/python3.4.8/bin:$(PATH) make develop basictest
test-py35: $(PY35) test-py35: $(PY35)
PYTHON=python3.5.5 PATH=$(BUILD_RUNTIMES)/versions/python3.5.5/bin:$(PATH) make develop basictest PYTHON=python3.5.5 PATH=$(BUILD_RUNTIMES)/versions/python3.5.5/bin:$(PATH) GEVENTTEST_COVERAGE=1 make develop basictest coverage_combine
test-py36: $(PY36) test-py36: $(PY36)
PYTHON=python3.6.7 PATH=$(BUILD_RUNTIMES)/versions/python3.6.7/bin:$(PATH) make develop lint basictest PYTHON=python3.6.7 PATH=$(BUILD_RUNTIMES)/versions/python3.6.7/bin:$(PATH) make develop lint basictest
......
...@@ -138,23 +138,13 @@ cache: ...@@ -138,23 +138,13 @@ cache:
- '%LOCALAPPDATA%\pip\Cache' - '%LOCALAPPDATA%\pip\Cache'
build_script: build_script:
# Build the compiled extension. First we make an sdist, then - "%PYEXE% -m pip install -U --upgrade-strategy=eager -e .[test,events,dnspython]"
# we install from that, to test sdist building issues. Finally we
# build a wheel for downloading purposes
- "%CMD_IN_ENV% %PYEXE% setup.py sdist --formats=gztar"
- ps: "ls dist"
# Now install the sdist.
# I couldn't get wildcards to work for pip install, so stuff it
# into a variable, using python to glob.
- "%PYEXE% -c \"import glob; print(glob.glob('dist/*gz')[0])\" > whl.txt"
- set /p PYWHL=<whl.txt
- "%PYEXE% -m pip install -U --upgrade-strategy=eager %PYWHL%[test,events,dnspython]"
test_script: test_script:
# Run the project tests # Run the project tests
- "%PYEXE% -c \"import gevent.core; print(gevent.core.loop)\"" - "%PYEXE% -c \"import gevent.core; print(gevent.core.loop)\""
- "%PYEXE% -c \"import gevent; print(gevent.config.settings['resolver'].get_options())\"" - "%PYEXE% -c \"import gevent; print(gevent.config.settings['resolver'].get_options())\""
- "cd src/greentest && %PYEXE% testrunner.py --config known_failures.py --quiet && cd ../.." - "%PYEXE% -mgevent.tests --config known_failures.py --quiet"
after_test: after_test:
- "%CMD_IN_ENV% %PYEXE% setup.py bdist_wheel" - "%CMD_IN_ENV% %PYEXE% setup.py bdist_wheel"
......
...@@ -177,8 +177,7 @@ tests on one version of Python during development, begin with the ...@@ -177,8 +177,7 @@ tests on one version of Python during development, begin with the
above instructions to install gevent in a virtual environment and then above instructions to install gevent in a virtual environment and then
run:: run::
(env) $ cd src/greentest (env) $ python -mgevent.tests
(env) $ python ./testrunner.py
Before submitting a pull request, it's a good idea to run the tests Before submitting a pull request, it's a good idea to run the tests
across all supported versions of Python, and to check the code quality across all supported versions of Python, and to check the code quality
...@@ -192,8 +191,7 @@ The testrunner accepts a ``--coverage`` argument to enable code ...@@ -192,8 +191,7 @@ The testrunner accepts a ``--coverage`` argument to enable code
coverage metrics through the `coverage.py`_ package. That would go coverage metrics through the `coverage.py`_ package. That would go
something like this:: something like this::
cd src/greentest python -m gevent.tests --coverage
python testrunner.py --coverage
coverage combine coverage combine
coverage html -i coverage html -i
<open htmlcov/index.html> <open htmlcov/index.html>
......
...@@ -373,7 +373,7 @@ def run_setup(ext_modules, run_make): ...@@ -373,7 +373,7 @@ def run_setup(ext_modules, run_make):
# We don't run coverage on Windows, and pypy can't build it there # We don't run coverage on Windows, and pypy can't build it there
# anyway (coveralls -> cryptopgraphy -> openssl) # anyway (coveralls -> cryptopgraphy -> openssl)
'coverage>=4.0 ; sys_platform != "win32"', 'coverage>=5.0a3 ; sys_platform != "win32"',
'coveralls>=1.0 ; sys_platform != "win32"', 'coveralls>=1.0 ; sys_platform != "win32"',
'futures ; python_version == "2.7"', 'futures ; python_version == "2.7"',
......
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
# Nothing public here
__all__ = []
...@@ -5,6 +5,10 @@ import sys ...@@ -5,6 +5,10 @@ import sys
from gevent.libev import _corecffi # pylint:disable=no-name-in-module,import-error from gevent.libev import _corecffi # pylint:disable=no-name-in-module,import-error
# Nothing public here
__all__ = []
ffi = _corecffi.ffi # pylint:disable=no-member ffi = _corecffi.ffi # pylint:disable=no-member
libev = _corecffi.lib # pylint:disable=no-member libev = _corecffi.lib # pylint:disable=no-member
......
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
# Nothing public here
__all__ = []
...@@ -7,6 +7,9 @@ import sys ...@@ -7,6 +7,9 @@ import sys
from gevent.libuv import _corecffi # pylint:disable=no-name-in-module,import-error from gevent.libuv import _corecffi # pylint:disable=no-name-in-module,import-error
# Nothing public here
__all__ = []
ffi = _corecffi.ffi ffi = _corecffi.ffi
libuv = _corecffi.lib libuv = _corecffi.lib
......
...@@ -16,6 +16,8 @@ from gevent.socket import EAI_SERVICE ...@@ -16,6 +16,8 @@ from gevent.socket import EAI_SERVICE
from gevent.socket import AF_INET from gevent.socket import AF_INET
from gevent.socket import AI_PASSIVE from gevent.socket import AI_PASSIVE
# Nothing public here.
__all__ = []
def _lookup_port(port, socktype): def _lookup_port(port, socktype):
# pylint:disable=too-many-branches # pylint:disable=too-many-branches
......
...@@ -2,6 +2,10 @@ ...@@ -2,6 +2,10 @@
import _socket import _socket
__all__ = [
'Resolver',
]
class Resolver(object): class Resolver(object):
""" """
A resolver that directly uses the system's resolver functions. A resolver that directly uses the system's resolver functions.
......
...@@ -75,8 +75,8 @@ from _socket import AF_UNSPEC ...@@ -75,8 +75,8 @@ from _socket import AF_UNSPEC
import socket import socket
from . import AbstractResolver from gevent.resolver import AbstractResolver
from . import hostname_types from gevent.resolver import hostname_types
from gevent._compat import string_types from gevent._compat import string_types
from gevent._compat import iteritems from gevent._compat import iteritems
......
...@@ -3,7 +3,14 @@ ...@@ -3,7 +3,14 @@
.. deprecated:: 1.3 .. deprecated:: 1.3
Use :mod:`gevent.resolver.ares` Use :mod:`gevent.resolver.ares`
""" """
import warnings
warnings.warn(
"gevent.resolver_ares is deprecated and will be removed in 1.5. "
"Use gevent.resolver.ares instead.",
DeprecationWarning,
stacklevel=2
)
del warnings
from gevent.resolver.ares import * # pylint:disable=wildcard-import,unused-wildcard-import from gevent.resolver.ares import * # pylint:disable=wildcard-import,unused-wildcard-import
import gevent.resolver.ares as _ares import gevent.resolver.ares as _ares
__all__ = _ares.__all__ __all__ = _ares.__all__
......
"""Backwards compatibility alias for :mod:`gevent.resolver.thread`. """Backwards compatibility alias for :mod:`gevent.resolver.thread`.
.. deprecated:: 1.3 .. deprecated:: 1.3
Use :mod:`gevent.resolver.cares` Use :mod:`gevent.resolver.thread`
""" """
import warnings
warnings.warn(
"gevent.resolver_thread is deprecated and will be removed in 1.5. "
"Use gevent.resolver.thread instead.",
DeprecationWarning,
stacklevel=2
)
del warnings
from gevent.resolver.thread import * # pylint:disable=wildcard-import,unused-wildcard-import from gevent.resolver.thread import * # pylint:disable=wildcard-import,unused-wildcard-import
import gevent.resolver.thread as _thread import gevent.resolver.thread as _thread
__all__ = _thread.__all__ __all__ = _thread.__all__
......
...@@ -20,106 +20,107 @@ ...@@ -20,106 +20,107 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE. # THE SOFTWARE.
# package is named greentest, not test, so it won't be confused with test in stdlib
import unittest import unittest
# pylint:disable=unused-import # pylint:disable=unused-import
from greentest.sysinfo import VERBOSE from .sysinfo import VERBOSE
from greentest.sysinfo import WIN from .sysinfo import WIN
from greentest.sysinfo import LINUX from .sysinfo import LINUX
from greentest.sysinfo import LIBUV from .sysinfo import LIBUV
from greentest.sysinfo import CFFI_BACKEND from .sysinfo import CFFI_BACKEND
from greentest.sysinfo import DEBUG from .sysinfo import DEBUG
from greentest.sysinfo import RUN_LEAKCHECKS from .sysinfo import RUN_LEAKCHECKS
from greentest.sysinfo import RUN_COVERAGE from .sysinfo import RUN_COVERAGE
from greentest.sysinfo import PY2 from .sysinfo import PY2
from greentest.sysinfo import PY3 from .sysinfo import PY3
from greentest.sysinfo import PY34 from .sysinfo import PY34
from greentest.sysinfo import PY36 from .sysinfo import PY36
from greentest.sysinfo import PY37 from .sysinfo import PY37
from greentest.sysinfo import PYPY from .sysinfo import PYPY
from greentest.sysinfo import PYPY3 from .sysinfo import PYPY3
from greentest.sysinfo import CPYTHON from .sysinfo import CPYTHON
from greentest.sysinfo import PLATFORM_SPECIFIC_SUFFIXES from .sysinfo import PLATFORM_SPECIFIC_SUFFIXES
from greentest.sysinfo import NON_APPLICABLE_SUFFIXES from .sysinfo import NON_APPLICABLE_SUFFIXES
from greentest.sysinfo import SHARED_OBJECT_EXTENSION from .sysinfo import SHARED_OBJECT_EXTENSION
from greentest.sysinfo import RUNNING_ON_TRAVIS from .sysinfo import RUNNING_ON_TRAVIS
from greentest.sysinfo import RUNNING_ON_APPVEYOR from .sysinfo import RUNNING_ON_APPVEYOR
from greentest.sysinfo import RUNNING_ON_CI from .sysinfo import RUNNING_ON_CI
from greentest.sysinfo import RESOLVER_NOT_SYSTEM from .sysinfo import RESOLVER_NOT_SYSTEM
from greentest.sysinfo import RESOLVER_DNSPYTHON from .sysinfo import RESOLVER_DNSPYTHON
from greentest.sysinfo import RESOLVER_ARES from .sysinfo import RESOLVER_ARES
from greentest.sysinfo import EXPECT_POOR_TIMER_RESOLUTION from .sysinfo import EXPECT_POOR_TIMER_RESOLUTION
from greentest.sysinfo import CONN_ABORTED_ERRORS from .sysinfo import CONN_ABORTED_ERRORS
from greentest.skipping import skipOnWindows from .skipping import skipOnWindows
from greentest.skipping import skipOnAppVeyor from .skipping import skipOnAppVeyor
from greentest.skipping import skipOnCI from .skipping import skipOnCI
from greentest.skipping import skipOnPyPy3OnCI from .skipping import skipOnPyPy3OnCI
from greentest.skipping import skipOnPyPy from .skipping import skipOnPyPy
from greentest.skipping import skipOnPyPyOnCI from .skipping import skipOnPyPyOnCI
from greentest.skipping import skipOnPyPy3 from .skipping import skipOnPyPy3
from greentest.skipping import skipIf from .skipping import skipIf
from greentest.skipping import skipOnLibev from .skipping import skipOnLibev
from greentest.skipping import skipOnLibuv from .skipping import skipOnLibuv
from greentest.skipping import skipOnLibuvOnWin from .skipping import skipOnLibuvOnWin
from greentest.skipping import skipOnLibuvOnCI from .skipping import skipOnLibuvOnCI
from greentest.skipping import skipOnLibuvOnCIOnPyPy from .skipping import skipOnLibuvOnCIOnPyPy
from greentest.skipping import skipOnLibuvOnPyPyOnWin from .skipping import skipOnLibuvOnPyPyOnWin
from greentest.skipping import skipOnPurePython from .skipping import skipOnPurePython
from greentest.skipping import skipWithCExtensions from .skipping import skipWithCExtensions
from greentest.skipping import skipOnLibuvOnTravisOnCPython27 from .skipping import skipOnLibuvOnTravisOnCPython27
from greentest.skipping import skipOnPy37 from .skipping import skipOnPy37
from greentest.exception import ExpectedException from .exception import ExpectedException
from greentest.leakcheck import ignores_leakcheck from .leakcheck import ignores_leakcheck
from greentest.params import LARGE_TIMEOUT from .params import LARGE_TIMEOUT
from greentest.params import DEFAULT_LOCAL_HOST_ADDR from .params import DEFAULT_LOCAL_HOST_ADDR
from greentest.params import DEFAULT_LOCAL_HOST_ADDR6 from .params import DEFAULT_LOCAL_HOST_ADDR6
from greentest.params import DEFAULT_BIND_ADDR from .params import DEFAULT_BIND_ADDR
from greentest.params import DEFAULT_SOCKET_TIMEOUT from .params import DEFAULT_SOCKET_TIMEOUT
from greentest.params import DEFAULT_XPC_SOCKET_TIMEOUT from .params import DEFAULT_XPC_SOCKET_TIMEOUT
main = unittest.main main = unittest.main
from greentest.hub import QuietHub from .hub import QuietHub
import gevent.hub import gevent.hub
gevent.hub.set_default_hub_class(QuietHub) gevent.hub.set_default_hub_class(QuietHub)
from greentest.sockets import bind_and_listen from .sockets import bind_and_listen
from greentest.sockets import tcp_listener from .sockets import tcp_listener
from greentest.openfiles import get_number_open_files from .openfiles import get_number_open_files
from greentest.openfiles import get_open_files from .openfiles import get_open_files
from greentest.testcase import TestCase from .testcase import TestCase
from greentest.modules import walk_modules from .modules import walk_modules
BaseTestCase = unittest.TestCase BaseTestCase = unittest.TestCase
from greentest.flaky import reraiseFlakyTestTimeout from .flaky import reraiseFlakyTestTimeout
from greentest.flaky import reraiseFlakyTestRaceCondition from .flaky import reraiseFlakyTestRaceCondition
from .flaky import reraises_flaky_timeout
from .flaky import reraises_flaky_race_condition
try: try:
from unittest import mock from unittest import mock
......
...@@ -25,8 +25,8 @@ import unittest ...@@ -25,8 +25,8 @@ import unittest
from gevent.util import dump_stacks from gevent.util import dump_stacks
from greentest import sysinfo from . import sysinfo
from greentest import six from . import six
class FlakyAssertionError(AssertionError): class FlakyAssertionError(AssertionError):
"Re-raised so that we know it's a known-flaky test." "Re-raised so that we know it's a known-flaky test."
...@@ -96,7 +96,7 @@ if sysinfo.RUNNING_ON_CI or (sysinfo.PYPY and sysinfo.WIN): ...@@ -96,7 +96,7 @@ if sysinfo.RUNNING_ON_CI or (sysinfo.PYPY and sysinfo.WIN):
reraiseFlakyTestTimeoutLibuv = reraiseFlakyTestTimeout reraiseFlakyTestTimeoutLibuv = reraiseFlakyTestTimeout
def reraises_flaky_timeout(exc_kind): def reraises_flaky_timeout(exc_kind=AssertionError, _func=reraiseFlakyTestTimeout):
def wrapper(f): def wrapper(f):
@functools.wraps(f) @functools.wraps(f)
...@@ -104,7 +104,10 @@ def reraises_flaky_timeout(exc_kind): ...@@ -104,7 +104,10 @@ def reraises_flaky_timeout(exc_kind):
try: try:
f(*args) f(*args)
except exc_kind: except exc_kind:
reraiseFlakyTestTimeout() _func()
return m return m
return wrapper return wrapper
def reraises_flaky_race_condition(exc_kind=AssertionError):
return reraises_flaky_timeout(exc_kind, _func=reraiseFlakyTestRaceCondition)
...@@ -22,7 +22,7 @@ from __future__ import absolute_import, print_function, division ...@@ -22,7 +22,7 @@ from __future__ import absolute_import, print_function, division
from gevent.hub import Hub from gevent.hub import Hub
from greentest.exception import ExpectedException from .exception import ExpectedException
class QuietHub(Hub): class QuietHub(Hub):
......
...@@ -68,7 +68,11 @@ class _RefCountChecker(object): ...@@ -68,7 +68,11 @@ class _RefCountChecker(object):
self.needs_setUp = False self.needs_setUp = False
def _ignore_object_p(self, obj): def _ignore_object_p(self, obj):
if obj is self or obj in self.__dict__.values() or obj == self._ignore_object_p: if (
obj is self
or obj in self.__dict__.values()
or obj == self._ignore_object_p # pylint:disable=comparison-with-callable
):
return False return False
kind = type(obj) kind = type(obj)
if kind in self.IGNORED_TYPES: if kind in self.IGNORED_TYPES:
......
...@@ -19,14 +19,21 @@ ...@@ -19,14 +19,21 @@
# THE SOFTWARE. # THE SOFTWARE.
from __future__ import absolute_import, print_function, division from __future__ import absolute_import, print_function, division
import importlib
import os.path import os.path
import warnings
import gevent import gevent
from greentest import sysinfo from . import sysinfo
from greentest import six
OPTIONAL_MODULES = ['resolver_ares']
OPTIONAL_MODULES = [
'gevent.resolver_ares',
'gevent.resolver.ares',
'gevent.libev',
'gevent.libev.watcher',
]
def walk_modules(basedir=None, modpath=None, include_so=False, recursive=False): def walk_modules(basedir=None, modpath=None, include_so=False, recursive=False):
...@@ -45,6 +52,8 @@ def walk_modules(basedir=None, modpath=None, include_so=False, recursive=False): ...@@ -45,6 +52,8 @@ def walk_modules(basedir=None, modpath=None, include_so=False, recursive=False):
if os.path.isdir(path): if os.path.isdir(path):
if not recursive: if not recursive:
continue continue
if fn in ['testing', 'tests']:
continue
pkg_init = os.path.join(path, '__init__.py') pkg_init = os.path.join(path, '__init__.py')
if os.path.exists(pkg_init): if os.path.exists(pkg_init):
yield pkg_init, modpath + fn yield pkg_init, modpath + fn
...@@ -58,12 +67,15 @@ def walk_modules(basedir=None, modpath=None, include_so=False, recursive=False): ...@@ -58,12 +67,15 @@ def walk_modules(basedir=None, modpath=None, include_so=False, recursive=False):
if x in ['__init__', 'core', 'ares', '_util', '_semaphore', if x in ['__init__', 'core', 'ares', '_util', '_semaphore',
'corecffi', '_corecffi', '_corecffi_build']: 'corecffi', '_corecffi', '_corecffi_build']:
continue continue
if x in OPTIONAL_MODULES: modname = modpath + x
if modname in OPTIONAL_MODULES:
try: try:
six.exec_("import %s" % x, {}) with warnings.catch_warnings():
warnings.simplefilter('ignore', DeprecationWarning)
importlib.import_module(modname)
except ImportError: except ImportError:
continue continue
yield path, modpath + x yield path, modname
elif include_so and fn.endswith(sysinfo.SHARED_OBJECT_EXTENSION): elif include_so and fn.endswith(sysinfo.SHARED_OBJECT_EXTENSION):
if '.pypy-' in fn: if '.pypy-' in fn:
continue continue
......
...@@ -18,9 +18,9 @@ print('Running with patch_all(%s): %s' % (','.join('%s=%r' % x for x in kwargs.i ...@@ -18,9 +18,9 @@ print('Running with patch_all(%s): %s' % (','.join('%s=%r' % x for x in kwargs.i
from gevent import monkey from gevent import monkey
monkey.patch_all(**kwargs) monkey.patch_all(**kwargs)
from greentest.sysinfo import RUNNING_ON_APPVEYOR from .sysinfo import RUNNING_ON_APPVEYOR
from greentest.sysinfo import PY37 from .sysinfo import PY37
from greentest.patched_tests_setup import disable_tests_in_source from .patched_tests_setup import disable_tests_in_source
try: try:
from test import support from test import support
except ImportError: except ImportError:
......
...@@ -23,7 +23,7 @@ import os ...@@ -23,7 +23,7 @@ import os
import unittest import unittest
import re import re
from greentest import sysinfo from . import sysinfo
# Linux/OS X/BSD platforms can implement this by calling out to lsof # Linux/OS X/BSD platforms can implement this by calling out to lsof
...@@ -75,11 +75,11 @@ def default_get_number_open_files(): ...@@ -75,11 +75,11 @@ def default_get_number_open_files():
# Linux only # Linux only
fd_directory = '/proc/%d/fd' % os.getpid() fd_directory = '/proc/%d/fd' % os.getpid()
return len(os.listdir(fd_directory)) return len(os.listdir(fd_directory))
else:
try: try:
return len(get_open_files(pipes=True)) - 1 return len(get_open_files(pipes=True)) - 1
except (OSError, AssertionError, unittest.SkipTest): except (OSError, AssertionError, unittest.SkipTest):
return 0 return 0
lsof_get_open_files = default_get_open_files lsof_get_open_files = default_get_open_files
......
...@@ -19,26 +19,26 @@ ...@@ -19,26 +19,26 @@
# THE SOFTWARE. # THE SOFTWARE.
from greentest.sysinfo import PY3 from .sysinfo import PY3
from greentest.sysinfo import PYPY from .sysinfo import PYPY
from greentest.sysinfo import WIN from .sysinfo import WIN
from greentest.sysinfo import LIBUV from .sysinfo import LIBUV
from greentest.sysinfo import OSX from .sysinfo import OSX
from greentest.sysinfo import RUNNING_ON_TRAVIS from .sysinfo import RUNNING_ON_TRAVIS
from greentest.sysinfo import RUNNING_ON_APPVEYOR from .sysinfo import RUNNING_ON_APPVEYOR
from greentest.sysinfo import EXPECT_POOR_TIMER_RESOLUTION from .sysinfo import EXPECT_POOR_TIMER_RESOLUTION
from greentest.sysinfo import RESOLVER_ARES from .sysinfo import RESOLVER_ARES
# Travis is slow and overloaded; Appveyor used to be faster, but # Travis is slow and overloaded; Appveyor used to be faster, but
# as of Dec 2015 it's almost always slower and/or has much worse timer # as of Dec 2015 it's almost always slower and/or has much worse timer
# resolution # resolution
CI_TIMEOUT = 10 CI_TIMEOUT = 15
if (PY3 and PYPY) or (PYPY and WIN and LIBUV): if (PY3 and PYPY) or (PYPY and WIN and LIBUV):
# pypy3 is very slow right now, # pypy3 is very slow right now,
# as is PyPy2 on windows (which only has libuv) # as is PyPy2 on windows (which only has libuv)
CI_TIMEOUT = 15 CI_TIMEOUT = 20
if PYPY and LIBUV: if PYPY and LIBUV:
# slow and flaky timeouts # slow and flaky timeouts
LOCAL_TIMEOUT = CI_TIMEOUT LOCAL_TIMEOUT = CI_TIMEOUT
......
# pylint:disable=missing-docstring,invalid-name # pylint:disable=missing-docstring,invalid-name,too-many-lines
from __future__ import print_function, absolute_import, division from __future__ import print_function, absolute_import, division
import collections import collections
...@@ -13,26 +13,28 @@ import os ...@@ -13,26 +13,28 @@ import os
# import platform # import platform
import re import re
from greentest.sysinfo import RUNNING_ON_APPVEYOR as APPVEYOR from .sysinfo import RUNNING_ON_APPVEYOR as APPVEYOR
from greentest.sysinfo import RUNNING_ON_TRAVIS as TRAVIS from .sysinfo import RUNNING_ON_TRAVIS as TRAVIS
from greentest.sysinfo import RESOLVER_NOT_SYSTEM as ARES from .sysinfo import RESOLVER_NOT_SYSTEM as ARES
from greentest.sysinfo import RUN_COVERAGE from .sysinfo import RUN_COVERAGE
from greentest.sysinfo import PYPY from .sysinfo import PYPY
from greentest.sysinfo import PYPY3 from .sysinfo import PYPY3
from greentest.sysinfo import PY3 from .sysinfo import PY3
from greentest.sysinfo import PY2 from .sysinfo import PY2
from greentest.sysinfo import PY34 from .sysinfo import PY34
from greentest.sysinfo import PY35 from .sysinfo import PY35
from greentest.sysinfo import PY36 from .sysinfo import PY36
from greentest.sysinfo import PY37 from .sysinfo import PY37
from greentest.sysinfo import WIN from .sysinfo import WIN
from greentest.sysinfo import OSX from .sysinfo import OSX
from greentest.sysinfo import LIBUV from .sysinfo import LIBUV
from greentest.sysinfo import CFFI_BACKEND from .sysinfo import CFFI_BACKEND
from . import flaky
CPYTHON = not PYPY CPYTHON = not PYPY
...@@ -536,6 +538,14 @@ def _gc_at_end(): ...@@ -536,6 +538,14 @@ def _gc_at_end():
gc.collect() gc.collect()
gc.collect() gc.collect()
@contextlib.contextmanager
def _flaky_socket_timeout():
import socket
try:
yield
except socket.timeout:
flaky.reraiseFlakyTestTimeout()
# Map from FQN to a context manager that will be wrapped around # Map from FQN to a context manager that will be wrapped around
# that test. # that test.
wrapped_tests = { wrapped_tests = {
...@@ -577,6 +587,13 @@ if WIN: ...@@ -577,6 +587,13 @@ if WIN:
'test_ssl.ThreadedTests.test_socketserver', 'test_ssl.ThreadedTests.test_socketserver',
] ]
# These are a problem on 3.5; on 3.6+ they wind up getting (accidentally) disabled.
wrapped_tests.update({
'test_socket.SendfileUsingSendTest.testWithTimeout': _flaky_socket_timeout,
'test_socket.SendfileUsingSendTest.testOffset': _flaky_socket_timeout,
'test_socket.SendfileUsingSendTest.testRegularFile': _flaky_socket_timeout,
})
if PYPY: if PYPY:
disabled_tests += [ disabled_tests += [
# Does not exist in the CPython test suite, tests for a specific bug # Does not exist in the CPython test suite, tests for a specific bug
...@@ -690,12 +707,7 @@ if PYPY3: ...@@ -690,12 +707,7 @@ if PYPY3:
] ]
if PYPY and sys.pypy_version_info[:4] in ( # pylint:disable=no-member if PYPY and PY3:
(5, 8, 0, 'beta'), (5, 9, 0, 'beta'), (5, 10, 1, 'final')):
# 3.5 is beta. Hard to say what are real bugs in us vs real bugs in pypy.
# For that reason, we pin these patches exactly to the version in use.
disabled_tests += [ disabled_tests += [
# This fails to close all the FDs, at least on CI. On OS X, many of the # This fails to close all the FDs, at least on CI. On OS X, many of the
# POSIXProcessTestCase fd tests have issues. # POSIXProcessTestCase fd tests have issues.
...@@ -1074,7 +1086,7 @@ def disable_tests_in_source(source, filename): ...@@ -1074,7 +1086,7 @@ def disable_tests_in_source(source, filename):
# If we do it on a def-by-def basis, we can break syntax # If we do it on a def-by-def basis, we can break syntax
# if the function is already decorated # if the function is already decorated
pattern = r'^import .*' pattern = r'^import .*'
replacement = r'from greentest import patched_tests_setup as _GEVENT_PTS;' replacement = r'from gevent.testing import patched_tests_setup as _GEVENT_PTS;'
replacement += r'import unittest as _GEVENT_UTS;' replacement += r'import unittest as _GEVENT_UTS;'
replacement += r'\g<0>' replacement += r'\g<0>'
source, n = re.subn(pattern, replacement, source, 1, re.MULTILINE) source, n = re.subn(pattern, replacement, source, 1, re.MULTILINE)
...@@ -1085,9 +1097,10 @@ def disable_tests_in_source(source, filename): ...@@ -1085,9 +1097,10 @@ def disable_tests_in_source(source, filename):
# so use [ \t]+. Without indentation, test_main, commonly used as the # so use [ \t]+. Without indentation, test_main, commonly used as the
# __main__ function at the top level, could get matched. \s matches # __main__ function at the top level, could get matched. \s matches
# newlines even in MULTILINE mode so it would still match that. # newlines even in MULTILINE mode so it would still match that.
my_disabled_testcases = set()
for test in my_disabled_tests: for test in my_disabled_tests:
testcase = test.split('.')[-1] testcase = test.split('.')[-1]
my_disabled_testcases.add(testcase)
# def foo_bar(self) # def foo_bar(self)
# -> # ->
# @_GEVENT_UTS.skip('Removed by patched_tests_setup') # @_GEVENT_UTS.skip('Removed by patched_tests_setup')
...@@ -1101,6 +1114,10 @@ def disable_tests_in_source(source, filename): ...@@ -1101,6 +1114,10 @@ def disable_tests_in_source(source, filename):
for test in my_wrapped_tests: for test in my_wrapped_tests:
testcase = test.split('.')[-1] testcase = test.split('.')[-1]
if testcase in my_disabled_testcases:
print("Not wrapping %s because it is skipped" % (test,))
continue
# def foo_bar(self) # def foo_bar(self)
# -> # ->
# @_GEVENT_PTS._PatchedTest('file.Case.name') # @_GEVENT_PTS._PatchedTest('file.Case.name')
......
...@@ -21,7 +21,7 @@ from __future__ import absolute_import, print_function, division ...@@ -21,7 +21,7 @@ from __future__ import absolute_import, print_function, division
import unittest import unittest
from greentest import sysinfo from . import sysinfo
def _identity(f): def _identity(f):
return f return f
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
# THE SOFTWARE. # THE SOFTWARE.
from __future__ import absolute_import, print_function, division from __future__ import absolute_import, print_function, division
from greentest.params import DEFAULT_BIND_ADDR_TUPLE from .params import DEFAULT_BIND_ADDR_TUPLE
def bind_and_listen(sock, address=DEFAULT_BIND_ADDR_TUPLE, backlog=50, reuse_addr=True): def bind_and_listen(sock, address=DEFAULT_BIND_ADDR_TUPLE, backlog=50, reuse_addr=True):
from socket import SOL_SOCKET, SO_REUSEADDR, error from socket import SOL_SOCKET, SO_REUSEADDR, error
......
...@@ -23,9 +23,9 @@ from functools import wraps ...@@ -23,9 +23,9 @@ from functools import wraps
from gevent.hub import _get_hub from gevent.hub import _get_hub
from greentest.hub import QuietHub from .hub import QuietHub
from greentest.patched_tests_setup import get_switch_expected from .patched_tests_setup import get_switch_expected
def wrap_switch_count_check(method): def wrap_switch_count_check(method):
@wraps(method) @wraps(method)
......
...@@ -49,9 +49,9 @@ RUN_COVERAGE = os.getenv("COVERAGE_PROCESS_START") or os.getenv("GEVENTTEST_COVE ...@@ -49,9 +49,9 @@ RUN_COVERAGE = os.getenv("COVERAGE_PROCESS_START") or os.getenv("GEVENTTEST_COVE
# Generally, ignore the portions that are only implemented # Generally, ignore the portions that are only implemented
# on particular platforms; they generally contain partial # on particular platforms; they generally contain partial
# implementations completed in different modules. # implementations completed in different modules.
PLATFORM_SPECIFIC_SUFFIXES = ['2', '279', '3'] PLATFORM_SPECIFIC_SUFFIXES = ('2', '279', '3')
if WIN: if WIN:
PLATFORM_SPECIFIC_SUFFIXES.append('posix') PLATFORM_SPECIFIC_SUFFIXES += ('posix',)
PY2 = None PY2 = None
PY3 = None PY3 = None
...@@ -60,10 +60,10 @@ PY35 = None ...@@ -60,10 +60,10 @@ PY35 = None
PY36 = None PY36 = None
PY37 = None PY37 = None
NON_APPLICABLE_SUFFIXES = [] NON_APPLICABLE_SUFFIXES = ()
if sys.version_info[0] == 3: if sys.version_info[0] == 3:
# Python 3 # Python 3
NON_APPLICABLE_SUFFIXES.extend(('2', '279')) NON_APPLICABLE_SUFFIXES += ('2', '279')
PY2 = False PY2 = False
PY3 = True PY3 = True
if sys.version_info[1] >= 4: if sys.version_info[1] >= 4:
...@@ -79,11 +79,11 @@ elif sys.version_info[0] == 2: ...@@ -79,11 +79,11 @@ elif sys.version_info[0] == 2:
# Any python 2 # Any python 2
PY3 = False PY3 = False
PY2 = True PY2 = True
NON_APPLICABLE_SUFFIXES.append('3') NON_APPLICABLE_SUFFIXES += ('3',)
if (sys.version_info[1] < 7 if (sys.version_info[1] < 7
or (sys.version_info[1] == 7 and sys.version_info[2] < 9)): or (sys.version_info[1] == 7 and sys.version_info[2] < 9)):
# Python 2, < 2.7.9 # Python 2, < 2.7.9
NON_APPLICABLE_SUFFIXES.append('279') NON_APPLICABLE_SUFFIXES += ('279',)
PYPY3 = PYPY and PY3 PYPY3 = PYPY and PY3
...@@ -96,9 +96,9 @@ PYGTE279 = ( ...@@ -96,9 +96,9 @@ PYGTE279 = (
) )
if WIN: if WIN:
NON_APPLICABLE_SUFFIXES.append("posix") NON_APPLICABLE_SUFFIXES += ("posix",)
# This is intimately tied to FileObjectPosix # This is intimately tied to FileObjectPosix
NON_APPLICABLE_SUFFIXES.append("fileobject2") NON_APPLICABLE_SUFFIXES += ("fileobject2",)
SHARED_OBJECT_EXTENSION = ".pyd" SHARED_OBJECT_EXTENSION = ".pyd"
else: else:
SHARED_OBJECT_EXTENSION = ".so" SHARED_OBJECT_EXTENSION = ".so"
...@@ -111,7 +111,7 @@ RUNNING_ON_CI = RUNNING_ON_TRAVIS or RUNNING_ON_APPVEYOR ...@@ -111,7 +111,7 @@ RUNNING_ON_CI = RUNNING_ON_TRAVIS or RUNNING_ON_APPVEYOR
if RUNNING_ON_APPVEYOR: if RUNNING_ON_APPVEYOR:
# We can't exec corecext on appveyor if we haven't run setup.py in # We can't exec corecext on appveyor if we haven't run setup.py in
# 'develop' mode (i.e., we install) # 'develop' mode (i.e., we install)
NON_APPLICABLE_SUFFIXES.append('corecext') NON_APPLICABLE_SUFFIXES += ('corecext',)
EXPECT_POOR_TIMER_RESOLUTION = (PYPY3 EXPECT_POOR_TIMER_RESOLUTION = (PYPY3
or RUNNING_ON_APPVEYOR or RUNNING_ON_APPVEYOR
......
...@@ -20,21 +20,24 @@ ...@@ -20,21 +20,24 @@
from __future__ import absolute_import, print_function, division from __future__ import absolute_import, print_function, division
import sys import sys
from time import time
import os.path import os.path
from contextlib import contextmanager
from unittest import TestCase as BaseTestCase from unittest import TestCase as BaseTestCase
from functools import wraps from functools import wraps
import gevent import gevent
from greentest import sysinfo from . import sysinfo
from greentest import params from . import params
from greentest import leakcheck from . import leakcheck
from greentest import errorhandler from . import errorhandler
from greentest import flaky from . import flaky
from greentest.patched_tests_setup import get_switch_expected from .patched_tests_setup import get_switch_expected
class TimeAssertMixin(object): class TimeAssertMixin(object):
@flaky.reraises_flaky_timeout()
def assertTimeoutAlmostEqual(self, first, second, places=None, msg=None, delta=None): def assertTimeoutAlmostEqual(self, first, second, places=None, msg=None, delta=None):
try: try:
self.assertAlmostEqual(first, second, places=places, msg=msg, delta=delta) self.assertAlmostEqual(first, second, places=places, msg=msg, delta=delta)
...@@ -51,6 +54,28 @@ class TimeAssertMixin(object): ...@@ -51,6 +54,28 @@ class TimeAssertMixin(object):
self.assertLessEqual(time_taken, max_time) self.assertLessEqual(time_taken, max_time)
self.assertGreaterEqual(time_taken, min_time) self.assertGreaterEqual(time_taken, min_time)
@contextmanager
def runs_in_given_time(self, expected, fuzzy=None):
if fuzzy is None:
if sysinfo.EXPECT_POOR_TIMER_RESOLUTION or sysinfo.LIBUV:
# The noted timer jitter issues on appveyor/pypy3
fuzzy = expected * 5.0
else:
fuzzy = expected / 2.0
start = time()
yield
elapsed = time() - start
try:
self.assertTrue(
expected - fuzzy <= elapsed <= expected + fuzzy,
'Expected: %r; elapsed: %r; fuzzy %r' % (expected, elapsed, fuzzy))
except AssertionError:
flaky.reraiseFlakyTestRaceCondition()
def runs_in_no_time(
self,
fuzzy=(0.01 if not sysinfo.EXPECT_POOR_TIMER_RESOLUTION and not sysinfo.LIBUV else 1.0)):
return self.runs_in_given_time(0.0, fuzzy)
def _wrap_timeout(timeout, method): def _wrap_timeout(timeout, method):
......
...@@ -22,9 +22,9 @@ import time ...@@ -22,9 +22,9 @@ import time
import gevent import gevent
from greentest import sysinfo from . import sysinfo
from greentest import leakcheck from . import leakcheck
from greentest.testcase import TestCase from .testcase import TestCase
SMALLEST_RELIABLE_DELAY = 0.001 # 1ms, because of libuv SMALLEST_RELIABLE_DELAY = 0.001 # 1ms, because of libuv
......
import sys import sys
import os import os
from greentest import six from . import six
import traceback import traceback
import unittest import unittest
import threading import threading
...@@ -298,8 +298,18 @@ def run(command, **kwargs): ...@@ -298,8 +298,18 @@ def run(command, **kwargs):
return RunResult(result, out, name) return RunResult(result, out, name)
def find_setup_py_above(a_file):
"Return the directory containing setup.py somewhere above *a_file*"
root = os.path.dirname(os.path.abspath(a_file))
while not os.path.exists(os.path.join(root, 'setup.py')):
prev, root = root, os.path.dirname(root)
if root == prev:
# Let's avoid infinite loops at root
raise AssertionError('could not find my setup.py')
return root
class TestServer(unittest.TestCase): class TestServer(unittest.TestCase):
cwd = '../../examples/'
args = [] args = []
before_delay = 3 before_delay = 3
after_delay = 0.5 after_delay = 0.5
...@@ -307,6 +317,19 @@ class TestServer(unittest.TestCase): ...@@ -307,6 +317,19 @@ class TestServer(unittest.TestCase):
server = None # subclasses define this to be the path to the server.py server = None # subclasses define this to be the path to the server.py
start_kwargs = None start_kwargs = None
def find_setup_py(self):
"Return the directory containing setup.py"
return find_setup_py_above(__file__)
# XXX: We need to extend this if we want it to be useful
# for other packages; our __file__ won't work for them.
# We can look at the CWD, and we can look at the __file__ of the
# sys.modules[type(self).__module__].
@property
def cwd(self):
root = self.find_setup_py()
return os.path.join(root, 'examples')
def start(self): def start(self):
kwargs = self.start_kwargs or {} kwargs = self.start_kwargs or {}
return start([sys.executable, '-u', self.server] + self.args, cwd=self.cwd, **kwargs) return start([sys.executable, '-u', self.server] + self.args, cwd=self.cwd, **kwargs)
......
-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANtb0+YrKuxevGpm
LrjaUhZSgz6zFAmuGFmKmUbdjmfv9zSmmdsQIksK++jK0Be9LeZy20j6ahOfuVa0
ufEmPoP7Fy4hXegKZR9cCWcIe/A6H2xWF1IIJLRTLaU8ol/I7T+um5HD5AwAwNPP
USNU0Eegmvp+xxWu3NX2m1Veot85AgMBAAECgYA3ZdZ673X0oexFlq7AAmrutkHt
CL7LvwrpOiaBjhyTxTeSNWzvtQBkIU8DOI0bIazA4UreAFffwtvEuPmonDb3F+Iq
SMAu42XcGyVZEl+gHlTPU9XRX7nTOXVt+MlRRRxL6t9GkGfUAXI3XxJDXW3c0vBK
UL9xqD8cORXOfE06rQJBAP8mEX1ERkR64Ptsoe4281vjTlNfIbs7NMPkUnrn9N/Y
BLhjNIfQ3HFZG8BTMLfX7kCS9D593DW5tV4Z9BP/c6cCQQDcFzCcVArNh2JSywOQ
ZfTfRbJg/Z5Lt9Fkngv1meeGNPgIMLN8Sg679pAOOWmzdMO3V706rNPzSVMME7E5
oPIfAkEA8pDddarP5tCvTTgUpmTFbakm0KoTZm2+FzHcnA4jRh+XNTjTOv98Y6Ik
eO5d1ZnKXseWvkZncQgxfdnMqqpj5wJAcNq/RVne1DbYlwWchT2Si65MYmmJ8t+F
0mcsULqjOnEMwf5e+ptq5LzwbyrHZYq5FNk7ocufPv/ZQrcSSC+cFwJBAKvOJByS
x56qyGeZLOQlWS2JS3KJo59XuLFGqcbgN9Om9xFa41Yb4N9NvplFivsvZdw3m1Q/
SPIXQuT8RMPDVNQ=
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIICVDCCAb2gAwIBAgIJANfHOBkZr8JOMA0GCSqGSIb3DQEBBQUAMF8xCzAJBgNV
BAYTAlhZMRcwFQYDVQQHEw5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9u
IFNvZnR3YXJlIEZvdW5kYXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0xMDEw
MDgyMzAxNTZaFw0yMDEwMDUyMzAxNTZaMF8xCzAJBgNVBAYTAlhZMRcwFQYDVQQH
Ew5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9uIFNvZnR3YXJlIEZvdW5k
YXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
gYkCgYEA21vT5isq7F68amYuuNpSFlKDPrMUCa4YWYqZRt2OZ+/3NKaZ2xAiSwr7
6MrQF70t5nLbSPpqE5+5VrS58SY+g/sXLiFd6AplH1wJZwh78DofbFYXUggktFMt
pTyiX8jtP66bkcPkDADA089RI1TQR6Ca+n7HFa7c1fabVV6i3zkCAwEAAaMYMBYw
FAYDVR0RBA0wC4IJbG9jYWxob3N0MA0GCSqGSIb3DQEBBQUAA4GBAHPctQBEQ4wd
BJ6+JcpIraopLn8BGhbjNWj40mmRqWB/NAWF6M5ne7KpGAu7tLeG4hb1zLaldK8G
lxy2GPSRF6LFS48dpEj2HbMv2nvv6xxalDMJ9+DicWgAKTQ6bcX2j3GUkCR0g/T1
CRlNBAAlvhKzO7Clpf9l0YKBEfraJByX
-----END CERTIFICATE-----
...@@ -2,5 +2,5 @@ ...@@ -2,5 +2,5 @@
from __future__ import print_function, absolute_import, division from __future__ import print_function, absolute_import, division
if __name__ == '__main__': if __name__ == '__main__':
from greentest import testrunner from gevent.testing import testrunner
testrunner.main() testrunner.main()
...@@ -6,17 +6,17 @@ import os ...@@ -6,17 +6,17 @@ import os
import sys import sys
import struct import struct
from greentest.sysinfo import RUNNING_ON_APPVEYOR as APPVEYOR from gevent.testing.sysinfo import RUNNING_ON_APPVEYOR as APPVEYOR
from greentest.sysinfo import RUNNING_ON_TRAVIS as TRAVIS from gevent.testing.sysinfo import RUNNING_ON_TRAVIS as TRAVIS
from greentest.sysinfo import RUN_LEAKCHECKS as LEAKTEST from gevent.testing.sysinfo import RUN_LEAKCHECKS as LEAKTEST
from greentest.sysinfo import RUN_COVERAGE as COVERAGE from gevent.testing.sysinfo import RUN_COVERAGE as COVERAGE
from greentest.sysinfo import RESOLVER_NOT_SYSTEM from gevent.testing.sysinfo import RESOLVER_NOT_SYSTEM
from greentest.sysinfo import PYPY from gevent.testing.sysinfo import PYPY
from greentest.sysinfo import PY3 from gevent.testing.sysinfo import PY3
from greentest.sysinfo import PY35 from gevent.testing.sysinfo import PY35
from greentest.sysinfo import LIBUV from gevent.testing.sysinfo import LIBUV
IGNORED_TESTS = [] IGNORED_TESTS = []
...@@ -85,6 +85,32 @@ if sys.platform == 'win32': ...@@ -85,6 +85,32 @@ if sys.platform == 'win32':
# too tight for appveyor. This happens even if Event isn't # too tight for appveyor. This happens even if Event isn't
# monkey-patched # monkey-patched
'FLAKY test_threading.py', 'FLAKY test_threading.py',
# Starting in November 2018, on Python 3.7.0, we observe this test crashing.
# I can't reproduce locally.
# | C:\Python37-x64\python.exe -u -mgevent.tests.test__greenness
# 127.0.0.1 - - [09/Nov/2018 16:34:12] code 501, message Unsupported method ('GET')
# 127.0.0.1 - - [09/Nov/2018 16:34:12] "GET / HTTP/1.1" 501 -
# .
# ----------------------------------------------------------------------
# Ran 1 test in 0.031s
# OK
# Windows fatal exception: access violation
# Current thread 0x000003c8 (most recent call first):
# File "c:\projects\gevent\src\gevent\threadpool.py", line 261 in _worker
# Thread 0x00000600 (most recent call first):
# File "c:\projects\gevent\src\gevent\libuv\watcher.py", line 577 in send
# File "c:\projects\gevent\src\gevent\threadpool.py", line 408 in set
# File "c:\projects\gevent\src\gevent\threadpool.py", line 290 in _worker
# Thread 0x000007d4 (most recent call first):
# File "C:\Python37-x64\lib\weakref.py", line 356 in remove
# ! C:\Python37-x64\python.exe -u -mgevent.tests.test__greenness [code 3221225477] [took 1.3s]
'FLAKY test__greenness.py',
] ]
if not PY35: if not PY35:
...@@ -189,7 +215,7 @@ if PYPY: ...@@ -189,7 +215,7 @@ if PYPY:
# This test, which normally takes 4-5s, sometimes # This test, which normally takes 4-5s, sometimes
# hangs forever after running two tests. I cannot reproduce, # hangs forever after running two tests. I cannot reproduce,
# it seems highly load dependent. Observed with both libev and libuv. # it seems highly load dependent. Observed with both libev and libuv.
'test_threading_2.py', 'test__threading_2.py',
] ]
if PY3 and TRAVIS: if PY3 and TRAVIS:
...@@ -236,5 +262,71 @@ if COVERAGE: ...@@ -236,5 +262,71 @@ if COVERAGE:
FAILING_TESTS = [x.strip() for x in set(FAILING_TESTS) if x.strip()] FAILING_TESTS = [x.strip() for x in set(FAILING_TESTS) if x.strip()]
# A mapping from test file basename to a dictionary of
# options that will be applied on top of the DEFAULT_RUN_OPTIONS.
TEST_FILE_OPTIONS = {
}
# tests that don't do well when run on busy box
RUN_ALONE = [
'test__threadpool.py',
'test__examples.py',
]
if APPVEYOR or TRAVIS:
RUN_ALONE += [
# Partial workaround for the _testcapi issue on PyPy,
# but also because signal delivery can sometimes be slow, and this
# spawn processes of its own
'test_signal.py',
]
if LEAKTEST and PY3:
# On a heavily loaded box, these can all take upwards of 200s
RUN_ALONE += [
'test__pool.py',
'test__pywsgi.py',
'test__queue.py',
]
if PYPY:
# This often takes much longer on PyPy on CI.
TEST_FILE_OPTIONS['test__threadpool.py'] = {'timeout': 180}
TEST_FILE_OPTIONS['test__threading_2.py'] = {'timeout': 180}
if PY3:
RUN_ALONE += [
# Sometimes shows unexpected timeouts
'test_socket.py',
]
if LIBUV:
RUN_ALONE += [
# https://bitbucket.org/pypy/pypy/issues/2769/systemerror-unexpected-internal-exception
'test__pywsgi.py',
]
# tests that can't be run when coverage is enabled
IGNORE_COVERAGE = [
# Hangs forever
'test__threading_vs_settrace.py',
# times out
'test_socket.py',
# Doesn't get the exceptions it expects
'test_selectors.py',
# XXX ?
'test__issue302monkey.py',
"test_subprocess.py",
]
if PYPY:
IGNORE_COVERAGE += [
# Tends to timeout
'test__refcount.py',
'test__greenletset.py'
]
if __name__ == '__main__': if __name__ == '__main__':
print('known_failures:\n', FAILING_TESTS) print('known_failures:\n', FAILING_TESTS)
""" """
Various tests for synchronization primitives. Various tests for synchronization primitives.
""" """
# pylint:disable=no-member,abstract-method
import sys import sys
import time import time
try: try:
...@@ -15,7 +16,7 @@ try: ...@@ -15,7 +16,7 @@ try:
except ImportError: except ImportError:
from test import test_support as support from test import test_support as support
from greentest.testcase import TimeAssertMixin from gevent.testing.testcase import TimeAssertMixin
def _wait(): def _wait():
# A crude wait/yield function not relying on synchronization primitives. # A crude wait/yield function not relying on synchronization primitives.
...@@ -131,7 +132,7 @@ class BaseLockTests(BaseTestCase): ...@@ -131,7 +132,7 @@ class BaseLockTests(BaseTestCase):
def _with(err=None): def _with(err=None):
with lock: with lock:
if err is not None: if err is not None:
raise err raise err # pylint:disable=raising-bad-type
_with() _with()
# Check the lock is unacquired # Check the lock is unacquired
Bunch(f, 1).wait_for_finished() Bunch(f, 1).wait_for_finished()
...@@ -153,7 +154,7 @@ class BaseLockTests(BaseTestCase): ...@@ -153,7 +154,7 @@ class BaseLockTests(BaseTestCase):
self.assertEqual(n, len(threading.enumerate())) self.assertEqual(n, len(threading.enumerate()))
class LockTests(BaseLockTests): class LockTests(BaseLockTests): # pylint:disable=abstract-method
""" """
Tests for non-recursive, weak locks Tests for non-recursive, weak locks
(which can be acquired and released from different threads). (which can be acquired and released from different threads).
...@@ -168,7 +169,7 @@ class LockTests(BaseLockTests): ...@@ -168,7 +169,7 @@ class LockTests(BaseLockTests):
lock.acquire() lock.acquire()
phase.append(None) phase.append(None)
start_new_thread(f, ()) start_new_thread(f, ())
while len(phase) == 0: while not phase:
_wait() _wait()
_wait() _wait()
self.assertEqual(len(phase), 1) self.assertEqual(len(phase), 1)
...@@ -436,9 +437,10 @@ class BaseSemaphoreTests(BaseTestCase): ...@@ -436,9 +437,10 @@ class BaseSemaphoreTests(BaseTestCase):
raise NotImplementedError() raise NotImplementedError()
def test_constructor(self): def test_constructor(self):
self.assertRaises(ValueError, self.semtype, value = -1) self.assertRaises(ValueError, self.semtype, value=-1)
# Py3 doesn't have sys.maxint # Py3 doesn't have sys.maxint
self.assertRaises(ValueError, self.semtype, value = -getattr(sys, 'maxint', getattr(sys, 'maxsize', None))) self.assertRaises(ValueError, self.semtype,
value=-getattr(sys, 'maxint', getattr(sys, 'maxsize', None)))
def test_acquire(self): def test_acquire(self):
sem = self.semtype(1) sem = self.semtype(1)
...@@ -509,7 +511,7 @@ class BaseSemaphoreTests(BaseTestCase): ...@@ -509,7 +511,7 @@ class BaseSemaphoreTests(BaseTestCase):
# There can be a thread switch between acquiring the semaphore and # There can be a thread switch between acquiring the semaphore and
# appending the result, therefore results will not necessarily be # appending the result, therefore results will not necessarily be
# ordered. # ordered.
self.assertEqual(sorted(results), [False] * 7 + [True] * 3 ) self.assertEqual(sorted(results), [False] * 7 + [True] * 3)
def test_default_value(self): def test_default_value(self):
# The default initial value is 1. # The default initial value is 1.
...@@ -534,7 +536,7 @@ class BaseSemaphoreTests(BaseTestCase): ...@@ -534,7 +536,7 @@ class BaseSemaphoreTests(BaseTestCase):
with sem: with sem:
self.assertFalse(sem.acquire(False)) self.assertFalse(sem.acquire(False))
if err: if err:
raise err raise err # pylint:disable=raising-bad-type
_with() _with()
self.assertTrue(sem.acquire(False)) self.assertTrue(sem.acquire(False))
sem.release() sem.release()
...@@ -603,7 +605,7 @@ class BarrierTests(BaseTestCase): ...@@ -603,7 +605,7 @@ class BarrierTests(BaseTestCase):
""" """
Test that a barrier is passed in lockstep Test that a barrier is passed in lockstep
""" """
results = [[],[]] results = [[], []]
def f(): def f():
self.multipass(results, passes) self.multipass(results, passes)
self.run_threads(f) self.run_threads(f)
...@@ -657,7 +659,6 @@ class BarrierTests(BaseTestCase): ...@@ -657,7 +659,6 @@ class BarrierTests(BaseTestCase):
results2.append(True) results2.append(True)
except RuntimeError: except RuntimeError:
self.barrier.abort() self.barrier.abort()
pass
self.run_threads(f) self.run_threads(f)
self.assertEqual(len(results1), 0) self.assertEqual(len(results1), 0)
...@@ -713,7 +714,7 @@ class BarrierTests(BaseTestCase): ...@@ -713,7 +714,7 @@ class BarrierTests(BaseTestCase):
results2.append(True) results2.append(True)
except RuntimeError: except RuntimeError:
self.barrier.abort() self.barrier.abort()
pass
# Synchronize and reset the barrier. Must synchronize first so # Synchronize and reset the barrier. Must synchronize first so
# that everyone has left it when we reset, and after so that no # that everyone has left it when we reset, and after so that no
# one enters it before the reset. # one enters it before the reset.
......
...@@ -9,10 +9,10 @@ from unittest import SkipTest ...@@ -9,10 +9,10 @@ from unittest import SkipTest
import socket import socket
import ssl import ssl
import greentest import gevent.testing as greentest
from greentest import DEFAULT_XPC_SOCKET_TIMEOUT from gevent.testing import DEFAULT_XPC_SOCKET_TIMEOUT
from greentest import util from gevent.testing import util
from greentest import params from gevent.testing import params
@greentest.skipOnCI("Timing issues sometimes lead to a connection refused") @greentest.skipOnCI("Timing issues sometimes lead to a connection refused")
class Test_wsgiserver(util.TestServer): class Test_wsgiserver(util.TestServer):
......
...@@ -8,7 +8,7 @@ from __future__ import print_function ...@@ -8,7 +8,7 @@ from __future__ import print_function
import gc import gc
import greentest import gevent.testing as greentest
from gevent._ident import IdentRegistry from gevent._ident import IdentRegistry
from gevent._compat import PYPY from gevent._compat import PYPY
......
...@@ -11,7 +11,7 @@ from gevent.monkey import get_original ...@@ -11,7 +11,7 @@ from gevent.monkey import get_original
from gevent._compat import thread_mod_name from gevent._compat import thread_mod_name
from gevent._compat import NativeStrIO from gevent._compat import NativeStrIO
from greentest.skipping import skipOnPyPyOnWindows from gevent.testing.skipping import skipOnPyPyOnWindows
from gevent import _monitor as monitor from gevent import _monitor as monitor
from gevent import config as GEVENT_CONFIG from gevent import config as GEVENT_CONFIG
......
...@@ -5,7 +5,11 @@ import glob ...@@ -5,7 +5,11 @@ import glob
import atexit import atexit
# subprocess: include in subprocess tests # subprocess: include in subprocess tests
from greentest import util from gevent.testing import util
# XXX: Generalize this so other packages can use it.
setup_py = util.find_setup_py_above(__file__)
greentest = os.path.join(setup_py, 'src', 'greentest')
TIMEOUT = 120 TIMEOUT = 120
directory = '%s.%s' % sys.version_info[:2] directory = '%s.%s' % sys.version_info[:2]
...@@ -13,6 +17,10 @@ full_directory = '%s.%s.%s' % sys.version_info[:3] ...@@ -13,6 +17,10 @@ full_directory = '%s.%s.%s' % sys.version_info[:3]
if hasattr(sys, 'pypy_version_info'): if hasattr(sys, 'pypy_version_info'):
directory += 'pypy' directory += 'pypy'
full_directory += 'pypy' full_directory += 'pypy'
directory = os.path.join(greentest, directory)
full_directory = os.path.join(greentest, full_directory)
version = '%s.%s.%s' % sys.version_info[:3] version = '%s.%s.%s' % sys.version_info[:3]
if sys.version_info[3] == 'alpha': if sys.version_info[3] == 'alpha':
version += 'a%s' % sys.version_info[4] version += 'a%s' % sys.version_info[4]
...@@ -62,7 +70,7 @@ def TESTRUNNER(tests=None): ...@@ -62,7 +70,7 @@ def TESTRUNNER(tests=None):
if tests and not sys.platform.startswith("win"): if tests and not sys.platform.startswith("win"):
atexit.register(os.system, 'rm -f */@test*') atexit.register(os.system, 'rm -f */@test*')
basic_args = [sys.executable, '-u', '-W', 'ignore', '-m' 'greentest.monkey_test'] basic_args = [sys.executable, '-u', '-W', 'ignore', '-m' 'gevent.testing.monkey_test']
for filename in tests: for filename in tests:
if filename in version_tests: if filename in version_tests:
util.log("Overriding %s from %s with file from %s", filename, directory, full_directory) util.log("Overriding %s from %s with file from %s", filename, directory, full_directory)
...@@ -75,7 +83,7 @@ def TESTRUNNER(tests=None): ...@@ -75,7 +83,7 @@ def TESTRUNNER(tests=None):
def main(): def main():
from greentest import testrunner from gevent.testing import testrunner
return testrunner.run_many(list(TESTRUNNER(sys.argv[1:]))) return testrunner.run_many(list(TESTRUNNER(sys.argv[1:])))
......
"""Check __all__, __implements__, __extensions__, __imports__ of the modules""" """Check __all__, __implements__, __extensions__, __imports__ of the modules"""
from __future__ import print_function from __future__ import print_function
from greentest import six
import sys import sys
import unittest import unittest
import types import types
from greentest.modules import walk_modules import importlib
from greentest.sysinfo import PLATFORM_SPECIFIC_SUFFIXES import warnings
from gevent.testing import six
from gevent.testing.modules import walk_modules
from gevent.testing.sysinfo import PLATFORM_SPECIFIC_SUFFIXES
from gevent._patcher import MAPPING from gevent._patcher import MAPPING
...@@ -30,7 +34,9 @@ COULD_BE_MISSING = { ...@@ -30,7 +34,9 @@ COULD_BE_MISSING = {
'subprocess': ['_posixsubprocess'], 'subprocess': ['_posixsubprocess'],
} }
NO_ALL = [ # Things without an __all__ should generally be internal implementation
# helpers
NO_ALL = {
'gevent.threading', 'gevent.threading',
'gevent._util', 'gevent._util',
'gevent._compat', 'gevent._compat',
...@@ -40,7 +46,8 @@ NO_ALL = [ ...@@ -40,7 +46,8 @@ NO_ALL = [
'gevent._tblib', 'gevent._tblib',
'gevent._corecffi', 'gevent._corecffi',
'gevent._patcher', 'gevent._patcher',
] 'gevent._ffi',
}
ALLOW_IMPLEMENTS = [ ALLOW_IMPLEMENTS = [
'gevent._queue', 'gevent._queue',
...@@ -133,7 +140,7 @@ class Test(unittest.TestCase): ...@@ -133,7 +140,7 @@ class Test(unittest.TestCase):
if hasattr(self.stdlib_module, name): if hasattr(self.stdlib_module, name):
raise AssertionError("'%r' is not an extension, it is found in %r" % (name, self.stdlib_module)) raise AssertionError("'%r' is not an extension, it is found in %r" % (name, self.stdlib_module))
def check_completeness(self): def check_completeness(self): # pylint:disable=too-many-branches
"""Check that __all__ (or dir()) of the corresponsing stdlib is a subset of __all__ of this module""" """Check that __all__ (or dir()) of the corresponsing stdlib is a subset of __all__ of this module"""
missed = [] missed = []
for name in self.stdlib_all: for name in self.stdlib_all:
...@@ -175,13 +182,13 @@ are missing from %r: ...@@ -175,13 +182,13 @@ are missing from %r:
raise AssertionError(msg) raise AssertionError(msg)
def _test(self, modname): def _test(self, modname):
for x in PLATFORM_SPECIFIC_SUFFIXES: if modname.endswith(PLATFORM_SPECIFIC_SUFFIXES):
if modname.endswith(x): return
return
self.modname = modname self.modname = modname
six.exec_("import %s" % modname, {}) with warnings.catch_warnings():
self.module = sys.modules[modname] warnings.simplefilter('ignore', DeprecationWarning)
self.module = importlib.import_module(modname)
self.check_all() self.check_all()
...@@ -216,14 +223,17 @@ are missing from %r: ...@@ -216,14 +223,17 @@ are missing from %r:
path = modname = orig_modname = None path = modname = orig_modname = None
for path, modname in walk_modules(include_so=True): for path, modname in walk_modules(include_so=False, recursive=True):
orig_modname = modname orig_modname = modname
modname = modname.replace('gevent.', '').split('.')[0] modname = modname.replace('gevent.', '').split('.')[0]
if not modname: if not modname:
print("WARNING: No such module '%s' at '%s'" % (orig_modname, path), print("WARNING: No such module '%s' at '%s'" % (orig_modname, path),
file=sys.stderr) file=sys.stderr)
continue continue
exec('''def test_%s(self): self._test("gevent.%s")''' % (modname, modname)) exec(
'''def test_%s(self): self._test("%s")''' % (
orig_modname.replace('.', '_').replace('-', '_'), orig_modname)
)
del path, modname, orig_modname del path, modname, orig_modname
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE. # THE SOFTWARE.
import greentest import gevent.testing as greentest
import gevent import gevent
from gevent import util, socket from gevent import util, socket
...@@ -36,10 +36,10 @@ class Test(greentest.TestCase): ...@@ -36,10 +36,10 @@ class Test(greentest.TestCase):
try: try:
state.append('start') state.append('start')
gevent.sleep(DELAY * 3.0) gevent.sleep(DELAY * 3.0)
except: except: # pylint:disable=bare-except
state.append('except') state.append('except')
# catching GreenletExit # catching GreenletExit
pass
state.append('finished') state.append('finished')
g = gevent.spawn(test) g = gevent.spawn(test)
...@@ -68,7 +68,9 @@ class Test(greentest.TestCase): ...@@ -68,7 +68,9 @@ class Test(greentest.TestCase):
def _test_wait_read_invalid_switch(self, sleep): def _test_wait_read_invalid_switch(self, sleep):
sock1, sock2 = socket.socketpair() sock1, sock2 = socket.socketpair()
try: try:
p = gevent.spawn(util.wrap_errors(AssertionError, socket.wait_read), sock1.fileno()) p = gevent.spawn(util.wrap_errors(AssertionError,
socket.wait_read), # pylint:disable=no-member
sock1.fileno())
gevent.get_hub().loop.run_callback(switch_None, p) gevent.get_hub().loop.run_callback(switch_None, p)
if sleep is not None: if sleep is not None:
gevent.sleep(sleep) gevent.sleep(sleep)
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
# THE SOFTWARE. # THE SOFTWARE.
import sys import sys
import greentest import gevent.testing as greentest
import weakref import weakref
import time import time
import gc import gc
...@@ -30,7 +30,8 @@ from gevent import Timeout ...@@ -30,7 +30,8 @@ from gevent import Timeout
from gevent import get_hub from gevent import get_hub
from greentest.timing import SMALL_TICK as DELAY from gevent.testing.timing import SMALL_TICK as DELAY
from gevent.testing import flaky
class Error(Exception): class Error(Exception):
...@@ -106,6 +107,8 @@ class Test(greentest.TestCase): ...@@ -106,6 +107,8 @@ class Test(greentest.TestCase):
@greentest.skipOnAppVeyor("Timing is flaky, especially under Py 3.4/64-bit") @greentest.skipOnAppVeyor("Timing is flaky, especially under Py 3.4/64-bit")
@greentest.skipOnPyPy3OnCI("Timing is flaky, especially under Py 3.4/64-bit")
@greentest.reraises_flaky_timeout(Timeout)
def test_api(self): def test_api(self):
# Nothing happens if with-block finishes before the timeout expires # Nothing happens if with-block finishes before the timeout expires
t = Timeout(DELAY * 2) t = Timeout(DELAY * 2)
...@@ -173,7 +176,7 @@ class Test(greentest.TestCase): ...@@ -173,7 +176,7 @@ class Test(greentest.TestCase):
gc.collect() gc.collect()
self.assertFalse(err_ref(), err_ref) self.assertFalse(err_ref(), err_ref)
@flaky.reraises_flaky_race_condition()
def test_nested_timeout(self): def test_nested_timeout(self):
with Timeout(DELAY, False): with Timeout(DELAY, False):
with Timeout(DELAY * 10, False): with Timeout(DELAY * 10, False):
......
...@@ -2,7 +2,7 @@ from __future__ import print_function ...@@ -2,7 +2,7 @@ from __future__ import print_function
import pickle import pickle
import sys import sys
import greentest import gevent.testing as greentest
try: try:
from gevent.resolver.cares import ares_host_result from gevent.resolver.cares import ares_host_result
except ImportError as ex: except ImportError as ex:
......
from __future__ import print_function
import errno
import unittest
import gevent
try:
from gevent.resolver.ares import Resolver
except ImportError as ex:
Resolver = None
from gevent import socket
import gevent.testing as greentest
@unittest.skipIf(
Resolver is None,
"Needs ares resolver"
)
class TestTimeout(greentest.TestCase):
__timeout__ = 30
address = ('', 7153)
def test(self):
listener = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
listener.bind(self.address)
except socket.error as ex:
if ex.errno in (errno.EPERM, errno.EADDRNOTAVAIL) or 'permission denied' in str(ex).lower():
raise unittest.SkipTest(
'This test binds on port a port that was already in use or not allowed.\n'
)
raise
def reader():
while True:
listener.recvfrom(10000)
gevent.spawn(reader)
r = Resolver(servers=['127.0.0.1'], timeout=0.001, tries=1,
udp_port=self.address[-1])
with self.assertRaisesRegex(socket.gaierror, "ARES_ETIMEOUT"):
r.gethostbyname('www.google.com')
if __name__ == '__main__':
greentest.main()
from __future__ import print_function from __future__ import print_function
import greentest import gevent.testing as greentest
import gevent import gevent
from gevent import socket from gevent import socket
from gevent import backdoor from gevent import backdoor
......
from __future__ import print_function
import os
import unittest
import gevent
from gevent import core
@unittest.skipUnless(
getattr(core, 'LIBEV_EMBED', False),
"Needs embedded libev. "
"hub.loop.fileno is only defined when "
"we embed libev for some reason. "
"Choosing specific backends is also only supported by libev "
"(not libuv), and besides, libuv has a nasty tendency to "
"abort() the process if its FD gets closed. "
)
class Test(unittest.TestCase):
# NOTE that we extend unittest.TestCase, not greentest.TestCase
# Extending the later causes the wrong hub to get used.
assertRaisesRegex = getattr(unittest.TestCase, 'assertRaisesRegex',
getattr(unittest.TestCase, 'assertRaisesRegexp'))
def _check_backend(self, backend):
hub = gevent.get_hub(backend, default=False)
try:
self.assertEqual(hub.loop.backend, backend)
gevent.sleep(0.001)
fileno = hub.loop.fileno()
if fileno is None:
raise unittest.SkipTest("backend %s lacks fileno" % (backend,))
os.close(fileno)
with self.assertRaisesRegex(SystemError, "(libev)"):
gevent.sleep(0.001)
hub.destroy()
self.assertIn('destroyed', repr(hub))
finally:
if hub.loop is not None:
hub.destroy()
def _make_test(count, backend): # pylint:disable=no-self-argument
def test(self):
self._check_backend(backend)
test.__name__ = 'test_' + backend + '_' + str(count)
return test.__name__, test
count = backend = None
for count in range(2):
for backend in core.supported_backends():
name, func = _make_test(count, backend)
locals()[name] = func
name = func = None
del count
del backend
del _make_test
if __name__ == '__main__':
unittest.main()
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
from __future__ import absolute_import, print_function, division from __future__ import absolute_import, print_function, division
import sys import sys
import unittest import unittest
import greentest import gevent.testing as greentest
from gevent import core from gevent import core
......
from __future__ import print_function from __future__ import print_function
import gevent.monkey; gevent.monkey.patch_all() import gevent.monkey
gevent.monkey.patch_all()
import gevent import gevent
import os import os
......
...@@ -6,11 +6,11 @@ import test__core_loop_run # this runs main tests, fails if signal() is not call ...@@ -6,11 +6,11 @@ import test__core_loop_run # this runs main tests, fails if signal() is not call
assert test__core_loop_run # pyflakes assert test__core_loop_run # pyflakes
from gevent.hub import signal as hub_signal from gevent.hub import signal as hub_signal
from gevent import signal from gevent import signal as top_signal # pylint:disable=reimported
assert gevent.signal is hub_signal assert gevent.signal is hub_signal
assert gevent.signal is signal assert gevent.signal is top_signal
assert hasattr(gevent.signal, 'signal') assert hasattr(gevent.signal, 'signal')
s = signal(2, sys.stderr.write, 'INTERRUPT') s = top_signal(2, sys.stderr.write, 'INTERRUPT')
assert isinstance(s, signal) assert isinstance(s, top_signal)
assert isinstance(s, hub_signal) assert isinstance(s, hub_signal)
...@@ -7,8 +7,8 @@ import time ...@@ -7,8 +7,8 @@ import time
import gevent import gevent
import gevent.core import gevent.core
import greentest import gevent.testing as greentest
import greentest.flaky import gevent.testing.flaky
#pylint: disable=protected-access #pylint: disable=protected-access
...@@ -83,7 +83,7 @@ class TestCoreStat(greentest.TestCase): ...@@ -83,7 +83,7 @@ class TestCoreStat(greentest.TestCase):
if reaction <= 0.0: if reaction <= 0.0:
# Sigh. This is especially true on PyPy on Windows # Sigh. This is especially true on PyPy on Windows
raise greentest.flaky.FlakyTestRaceCondition( raise gevent.testing.flaky.FlakyTestRaceCondition(
"Bad timer resolution (on Windows?), test is useless. Start %s, now %s" % (start, now)) "Bad timer resolution (on Windows?), test is useless. Start %s, now %s" % (start, now))
self.assertGreaterEqual( self.assertGreaterEqual(
......
from __future__ import print_function from __future__ import print_function
from gevent import config from gevent import config
import greentest import gevent.testing as greentest
from greentest import TestCase from gevent.testing import TestCase
from greentest import LARGE_TIMEOUT from gevent.testing import LARGE_TIMEOUT
from greentest.sysinfo import CFFI_BACKEND from gevent.testing.sysinfo import CFFI_BACKEND
from greentest.flaky import reraises_flaky_timeout from gevent.testing.flaky import reraises_flaky_timeout
class Test(TestCase): class Test(TestCase):
...@@ -94,7 +94,7 @@ class TestTimerResolution(Test): ...@@ -94,7 +94,7 @@ class TestTimerResolution(Test):
# On CI, with *all* backends, sometimes we get timer values of # On CI, with *all* backends, sometimes we get timer values of
# 0.02 or higher. # 0.02 or higher.
@reraises_flaky_timeout(AssertionError) @reraises_flaky_timeout(AssertionError)
def test_resolution(self): def test_resolution(self): # pylint:disable=too-many-locals
# Make sure that having an active IO watcher # Make sure that having an active IO watcher
# doesn't badly throw off our timer resolution. # doesn't badly throw off our timer resolution.
# (This was a specific problem with libuv) # (This was a specific problem with libuv)
......
from __future__ import absolute_import, print_function from __future__ import absolute_import, print_function
import greentest import gevent.testing as greentest
from gevent import config from gevent import config
from greentest.sysinfo import CFFI_BACKEND from gevent.testing.sysinfo import CFFI_BACKEND
from gevent.core import READ # pylint:disable=no-name-in-module from gevent.core import READ # pylint:disable=no-name-in-module
from gevent.core import WRITE # pylint:disable=no-name-in-module from gevent.core import WRITE # pylint:disable=no-name-in-module
......
from __future__ import print_function from __future__ import print_function
import doctest import doctest
import functools import functools
import os import os
import re import re
import sys import sys
import traceback
import unittest import unittest
import gevent import gevent
from gevent import socket from gevent import socket
from greentest import walk_modules from gevent.testing import walk_modules
from greentest import sysinfo from gevent.testing import sysinfo
from gevent.testing import util
# Ignore tracebacks: ZeroDivisionError # Ignore tracebacks: ZeroDivisionError
def myfunction(*args, **kwargs): def myfunction(*_args, **_kwargs):
pass pass
...@@ -44,29 +45,44 @@ if sysinfo.WIN: ...@@ -44,29 +45,44 @@ if sysinfo.WIN:
'gevent.subprocess', 'gevent.subprocess',
} }
if __name__ == '__main__': class Modules(object):
def __init__(self, allowed_modules):
self.allowed_modules = allowed_modules
self.modules = set()
for path, module in walk_modules():
self.add_module(module, path)
def add_module(self, name, path):
if self.allowed_modules and name not in self.allowed_modules:
return
if name in FORBIDDEN_MODULES:
return
self.modules.add((name, path))
def __bool__(self):
return bool(self.modules)
__nonzero__ = __bool__
def __iter__(self):
return iter(self.modules)
def main():
cwd = os.getcwd() cwd = os.getcwd()
try: try:
allowed_modules = sys.argv[1:] allowed_modules = sys.argv[1:]
sys.path.append('.') sys.path.append('.')
base = os.path.dirname(gevent.__file__) os.chdir(util.find_setup_py_above(__file__))
print(base)
os.chdir('../..')
globs = {'myfunction': myfunction, 'gevent': gevent, 'socket': socket} globs = {'myfunction': myfunction, 'gevent': gevent, 'socket': socket}
modules = set() modules = Modules(allowed_modules)
def add_module(name, path): modules.add_module('setup', 'setup.py')
if allowed_modules and name not in allowed_modules:
return
if name in FORBIDDEN_MODULES:
return
modules.add((name, path))
for path, module in walk_modules():
add_module(module, path)
add_module('setup', 'setup.py')
if not modules: if not modules:
sys.exit('No modules found matching %s' % ' '.join(allowed_modules)) sys.exit('No modules found matching %s' % ' '.join(allowed_modules))
...@@ -88,18 +104,18 @@ if __name__ == '__main__': ...@@ -88,18 +104,18 @@ if __name__ == '__main__':
with open(path, 'rb') as f: with open(path, 'rb') as f:
contents = f.read() contents = f.read()
if re.search(br'^\s*>>> ', contents, re.M): if re.search(br'^\s*>>> ', contents, re.M):
try: s = doctest.DocTestSuite(m, extraglobs=globs, checker=checker)
s = doctest.DocTestSuite(m, extraglobs=globs, checker=checker) test_count = len(s._tests)
test_count = len(s._tests) # pylint: disable=W0212 print('%s (from %s): %s tests' % (m, path, test_count))
print('%s (from %s): %s tests' % (m, path, test_count)) suite.addTest(s)
suite.addTest(s) modules_count += 1
modules_count += 1 tests_count += test_count
tests_count += test_count
except Exception:
traceback.print_exc()
sys.stderr.write('Failed to process %s\n\n' % path)
print('Total: %s tests in %s modules' % (tests_count, modules_count)) print('Total: %s tests in %s modules' % (tests_count, modules_count))
# TODO: Pass this off to unittest.main()
runner = unittest.TextTestRunner(verbosity=2) runner = unittest.TextTestRunner(verbosity=2)
runner.run(suite) runner.run(suite)
finally: finally:
os.chdir(cwd) os.chdir(cwd)
if __name__ == '__main__':
main()
...@@ -6,7 +6,7 @@ import subprocess ...@@ -6,7 +6,7 @@ import subprocess
if sys.argv[1:] == []: if sys.argv[1:] == []:
os.environ['GEVENT_BACKEND'] = 'select' os.environ['GEVENT_BACKEND'] = 'select'
popen = subprocess.Popen([sys.executable, 'test__environ.py', '1']) popen = subprocess.Popen([sys.executable, __file__, '1'])
assert popen.wait() == 0, popen.poll() assert popen.wait() == 0, popen.poll()
else: else:
hub = gevent.get_hub() hub = gevent.get_hub()
......
...@@ -5,13 +5,13 @@ import weakref ...@@ -5,13 +5,13 @@ import weakref
import gevent import gevent
from gevent.event import Event, AsyncResult from gevent.event import Event, AsyncResult
import greentest import gevent.testing as greentest
from greentest.six import xrange from gevent.testing.six import xrange
from greentest.timing import AbstractGenericGetTestCase from gevent.testing.timing import AbstractGenericGetTestCase
from greentest.timing import AbstractGenericWaitTestCase from gevent.testing.timing import AbstractGenericWaitTestCase
from greentest.timing import SMALL_TICK from gevent.testing.timing import SMALL_TICK
from greentest.timing import SMALL_TICK_MAX_ADJ from gevent.testing.timing import SMALL_TICK_MAX_ADJ
DELAY = SMALL_TICK + SMALL_TICK_MAX_ADJ DELAY = SMALL_TICK + SMALL_TICK_MAX_ADJ
......
from gevent.socket import create_connection, timeout from gevent.socket import create_connection, timeout
import greentest import gevent.testing as greentest
import gevent import gevent
from greentest import util from gevent.testing import util
from greentest import params from gevent.testing import params
class Test(util.TestServer): class Test(util.TestServer):
server = 'echoserver.py' server = 'echoserver.py'
......
...@@ -8,8 +8,8 @@ from time import sleep ...@@ -8,8 +8,8 @@ from time import sleep
import gevent import gevent
from gevent.server import StreamServer from gevent.server import StreamServer
import greentest import gevent.testing as greentest
from greentest import util from gevent.testing import util
@greentest.skipOnLibuvOnCIOnPyPy("Timing issues sometimes lead to connection refused") @greentest.skipOnLibuvOnCIOnPyPy("Timing issues sometimes lead to connection refused")
class Test(util.TestServer): class Test(util.TestServer):
......
from gevent import monkey; monkey.patch_all(subprocess=True) from gevent import monkey
monkey.patch_all(subprocess=True)
import sys import sys
from gevent.server import DatagramServer from gevent.server import DatagramServer
from unittest import TestCase
from greentest.util import run
from greentest import main
class Test_udp_client(TestCase): from gevent.testing.util import run
from gevent.testing import util
from gevent.testing import main
class Test_udp_client(util.TestServer):
def test(self): def test(self):
log = [] log = []
...@@ -18,7 +21,7 @@ class Test_udp_client(TestCase): ...@@ -18,7 +21,7 @@ class Test_udp_client(TestCase):
server.start() server.start()
try: try:
run([sys.executable, '-W', 'ignore', '-u', 'udp_client.py', 'Test_udp_client'], run([sys.executable, '-W', 'ignore', '-u', 'udp_client.py', 'Test_udp_client'],
timeout=10, cwd='../../examples/') timeout=10, cwd=self.cwd)
finally: finally:
server.close() server.close()
self.assertEqual(log, [b'Test_udp_client']) self.assertEqual(log, [b'Test_udp_client'])
......
import socket import socket
from greentest import util from gevent.testing import util
from greentest import main from gevent.testing import main
class Test(util.TestServer): class Test(util.TestServer):
......
...@@ -3,8 +3,8 @@ import os ...@@ -3,8 +3,8 @@ import os
import glob import glob
import time import time
import greentest import gevent.testing as greentest
from greentest import util from gevent.testing import util
cwd = '../../examples/' cwd = '../../examples/'
......
import gevent import gevent
import sys import sys
import greentest import gevent.testing as greentest
from greentest import six from gevent.testing import six
from greentest import ExpectedException as ExpectedError from gevent.testing import ExpectedException as ExpectedError
if not six.PY3: if not six.PY3:
sys.exc_clear() sys.exc_clear()
......
import unittest import unittest
import warnings
from greentest.modules import walk_modules from gevent.testing.modules import walk_modules
from greentest import main from gevent.testing import main
from greentest.sysinfo import NON_APPLICABLE_SUFFIXES from gevent.testing.sysinfo import NON_APPLICABLE_SUFFIXES
from greentest import six from gevent.testing import six
class TestExec(unittest.TestCase): class TestExec(unittest.TestCase):
...@@ -14,28 +15,25 @@ class TestExec(unittest.TestCase): ...@@ -14,28 +15,25 @@ class TestExec(unittest.TestCase):
def make_exec_test(path, module): def make_exec_test(path, module):
def test(self): def test(_):
#sys.stderr.write('%s %s\n' % (module, path))
with open(path, 'rb') as f: with open(path, 'rb') as f:
src = f.read() src = f.read()
six.exec_(src, {'__file__': path}) with warnings.catch_warnings():
warnings.simplefilter('ignore', DeprecationWarning)
six.exec_(src, {'__file__': path})
name = "test_" + module.replace(".", "_") name = "test_" + module.replace(".", "_")
test.__name__ = name test.__name__ = name
setattr(TestExec, name, test) setattr(TestExec, name, test)
def make_all_tests():
for path, module in walk_modules(recursive=True):
if module.endswith(NON_APPLICABLE_SUFFIXES):
continue
make_exec_test(path, module)
for path, module in walk_modules():
ignored = False
for x in NON_APPLICABLE_SUFFIXES:
if module.endswith(x):
ignored = True
break
if ignored:
continue
make_exec_test(path, module)
make_all_tests()
if __name__ == '__main__': if __name__ == '__main__':
main() main()
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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