Commit 15992102 authored by Jason Madden's avatar Jason Madden

Merge pull request #575 from gevent/travis-container

Use the TravisCI container infrastructure and enable linters
parents dedb08cf c24f612e
[pep8]
ignore=E702,E265,E402,E731,E266
ignore=E702,E265,E402,E731,E266,E261,W503
max_line_length=160
exclude=.git,build,2.6,2.7,2.7pypy,3.3,test_support.py,test_queue.py,patched_tests_setup.py,test_threading_2.py,lock_tests.py,_sslgte279.py
exclude=.tox,.git,build,2.6,2.7,2.7pypy,3.3,test_support.py,test_queue.py,patched_tests_setup.py,test_threading_2.py,lock_tests.py,_sslgte279.py
language: python
sudo: false
python:
- "2.6"
- "2.7"
- "3.3"
- "3.4"
- "pypy"
- 2.6
- 2.7
- pypy
- 3.3
- 3.4
env:
- LINT=true
- LINT=false
install:
# First install a newer pip so that it can use the wheel cache
# (only needed until travis upgrades pip to 7.x)
- travis_retry pip install -U pip
# Then start installing our deps. Note that use of --build-options / --global-options / --install-options
# disables the cache.
- travis_retry pip install -U tox cython greenlet pep8 pyflakes
script:
- if [[ $TRAVIS_PYTHON_VERSION == 'pypy' ]]; then NWORKERS=4 PYTHON=pypy make travis_pypy; fi
- if [[ $TRAVIS_PYTHON_VERSION != 'pypy' ]]; then NWORKERS=4 PYTHON=python$TRAVIS_PYTHON_VERSION make travis_cpython; fi
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' && $LINT == true ]]; then python setup.py develop && make travis_test_linters; elif [[ $LINT == false && $TRAVIS_PYTHON_VERSION == 'pypy' ]]; then python setup.py develop && make toxtest; elif [[ $LINT == false ]]; then python setup.py develop && make fulltoxtest; fi
notifications:
email: false
# cache: pip seems not to work
cache:
directories:
- $HOME/.cache/pip
before_cache:
- rm -f $HOME/.cache/pip/log/debug.log
......@@ -35,7 +35,7 @@ doc:
cd doc && PYTHONPATH=.. make html
whitespace:
! find . -not -path "./.git/*" -not -path "./build/*" -not -path "./libev/*" -not -path "./c-ares/*" -not -path "./doc/_build/*" -not -path "./doc/mytheme/static/*" -type f | xargs egrep -l " $$"
! find . -not -path "./.tox/*" -not -path "*/__pycache__/*" -not -path "*.so" -not -path "*.pyc" -not -path "./.git/*" -not -path "./build/*" -not -path "./libev/*" -not -path "./gevent/libev/*" -not -path "./gevent.egg-info/*" -not -path "./dist/*" -not -path "./.DS_Store" -not -path "./c-ares/*" -not -path "./gevent/gevent.*.[ch]" -not -path "./gevent/core.pyx" -not -path "./doc/_build/*" -not -path "./doc/mytheme/static/*" -type f | xargs egrep -l " $$"
pep8:
${PYTHON} `which pep8` .
......@@ -43,13 +43,12 @@ pep8:
pyflakes:
${PYTHON} util/pyflakes.py
lint: whitespace pep8 pyflakes
lint: whitespace pyflakes pep8
travistest:
which ${PYTHON}
${PYTHON} --version
cd greenlet-* && ${PYTHON} setup.py install -q
${PYTHON} -c 'import greenlet; print(greenlet, greenlet.__version__)'
${PYTHON} setup.py install
......@@ -67,11 +66,13 @@ fulltoxtest:
cd greentest && GEVENT_RESOLVER=ares GEVENTARES_SERVERS=8.8.8.8 python testrunner.py --config ../known_failures.py --ignore tests_that_dont_use_resolver.txt
cd greentest && GEVENT_FILE=thread python testrunner.py --config ../known_failures.py `grep -l subprocess test_*.py`
leaktest:
GEVENTSETUP_EV_VERIFY=3 GEVENTTEST_LEAKCHECK=1 make travistest
bench:
${PYTHON} greentest/bench_sendall.py
travis_pypy:
# no need to repeat linters here
which ${PYTHON}
${PYTHON} --version
${PYTHON} setup.py install
......@@ -79,24 +80,13 @@ travis_pypy:
cd greentest && ${PYTHON} testrunner.py --config ../known_failures.py
travis_cpython:
sudo add-apt-repository -y ppa:chris-lea/cython
# somehow travis changed something and python2.6 and python3.3 no longer accessible anymore
sudo add-apt-repository -y ppa:fkrull/deadsnakes
sudo apt-get -qq -y update
sudo -E apt-get -qq -y install ${PYTHON} ${PYTHON}-dev
sudo apt-get -qq -y install cython
cython --version
pip install -q --download . greenlet
unzip -q greenlet-*.zip
sudo -E make travistest
pip install cython greenlet
sudo -E apt-get install ${PYTHON}-dbg
make travistest
sudo -E PYTHON=${PYTHON}-dbg GEVENTSETUP_EV_VERIFY=3 make travistest
travis_test_linters:
make lint
make leaktest
.PHONY: clean all doc pep8 whitespace pyflakes lint travistest travis
......@@ -40,12 +40,24 @@ To install the latest development version:
running tests
-------------
There are a few different ways to run the tests. To simply run the
tests on one version of Python during development, try this:
python setup.py build
cd greentest
PYTHONPATH=.. python testrunner.py --config ../known_failures.py
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
using pep8 and pyflakes. This is what is done on Travis CI. Locally it
can be done using tox:
pip install tox
tox
.. _gevent: http://www.gevent.org
.. _greenlet: http://pypi.python.org/pypi/greenlet
......@@ -61,4 +73,3 @@ running tests
.. _mailing list: http://groups.google.com/group/gevent
.. _blog: http://blog.gevent.org
.. _twitter (@gevent): http://twitter.com/gevent
......@@ -298,7 +298,7 @@ class socket(object):
while True:
data_sent += self.send(_get_memory(data, data_sent), flags, timeout=timeleft)
if data_sent >= len(data):
break
return
timeleft = end - time.time()
if timeleft <= 0:
raise timeout('timed out')
......@@ -398,6 +398,7 @@ else:
if hasattr(__socket__, 'ssl'):
from gevent.hub import PYGTE279
def ssl(sock, keyfile=None, certfile=None):
# deprecated in 2.7.9 but still present
if PYGTE279:
......
......@@ -127,6 +127,7 @@ class BaseServer(object):
def do_handle(self, *args):
spawn = self._spawn
handle = self._handle
def _close_when_done(*args):
try:
return handle(*args)
......
......@@ -1058,6 +1058,7 @@ class child(watcher):
def rstatus(self, value):
self._watcher.rstatus = value
class stat(watcher):
_watcher_start = libev.ev_stat_start
_watcher_stop = libev.ev_stat_stop
......@@ -1106,6 +1107,7 @@ class stat(watcher):
def interval(self):
return self._watcher.interval
def _syserr_cb(msg):
try:
msg = ffi.string(msg)
......
......@@ -41,7 +41,7 @@ if PYPY:
# otherwise we get a new DummyThread, which cannot be joined.
# Fixes tests in test_threading_2
if _get_ident() not in __threading__._active and len(__threading__._active) == 1:
k,v = __threading__._active.items()[0]
k, v = __threading__._active.items()[0]
del __threading__._active[k]
__threading__._active[_get_ident()] = v
......
......@@ -85,9 +85,33 @@ def wrap_timeout(timeout, method):
def wrap_refcount(method):
if gettotalrefcount is None:
if not os.getenv('GEVENTTEST_LEAKCHECK'):
return method
# Some builtin things that we ignore
IGNORED_TYPES = (tuple, dict)
def type_hist():
import collections
d = collections.defaultdict(int)
for x in gc.get_objects():
k = type(x)
if k in IGNORED_TYPES:
continue
d[k] += 1
return d
def report_diff(a, b):
diff_lines = []
for k, v in sorted(a.items()):
if b[k] != v:
diff_lines.append("%s: %s != %s" % (k, v, b[k]))
if not diff_lines:
return None
diff = '\n'.join(diff_lines)
return diff
@wraps(method)
def wrapped(self, *args, **kwargs):
gc.collect()
......@@ -98,16 +122,29 @@ def wrap_refcount(method):
gc.disable()
try:
while True:
d = gettotalrefcount()
# Grab current snapshot
hist_before = type_hist()
d = sum(hist_before.values())
self.setUp()
method(self, *args, **kwargs)
self.tearDown()
# Grab post snapshot
if 'urlparse' in sys.modules:
sys.modules['urlparse'].clear_cache()
if 'urllib.parse' in sys.modules:
sys.modules['urllib.parse'].clear_cache()
d = gettotalrefcount() - d
hist_after = type_hist()
d = sum(hist_after.values()) - d
deltas.append(d)
# Reset and check for cycles
gc.collect()
if gc.garbage:
raise AssertionError("Generated uncollectable garbage")
# the following configurations are classified as "no leak"
# [0, 0]
# [x, 0, 0]
......@@ -122,7 +159,8 @@ def wrap_refcount(method):
elif len(deltas) >= 4 and sum(deltas[-4:]) == 0:
break
elif len(deltas) >= 3 and deltas[-1] > 0 and deltas[-1] == deltas[-2] and deltas[-2] == deltas[-3]:
raise AssertionError('refcount increased by %r' % (deltas, ))
diff = report_diff(hist_before, hist_after)
raise AssertionError('refcount increased by %r\n%s' % (deltas, diff))
# OK, we don't know for sure yet. Let's search for more
if sum(deltas[-3:]) <= 0 or sum(deltas[-4:]) <= 0 or deltas[-4:].count(0) >= 2:
# this is suspicious, so give a few more runs
......@@ -130,7 +168,7 @@ def wrap_refcount(method):
else:
limit = 7
if len(deltas) >= limit:
raise AssertionError('refcount increased by %r' % (deltas, ))
raise AssertionError('refcount increased by %r\n%s' % (deltas, report_diff(hist_before, hist_after)))
finally:
gc.enable()
self.skipTearDown = True
......
......@@ -10,6 +10,7 @@ import util
import ssl
class Test_wsgiserver(util.TestServer):
server = 'wsgiserver.py'
URL = 'http://127.0.0.1:8088'
......
......@@ -10,7 +10,6 @@ except ImportError as ex:
sys.exit(0)
class TestPickle(greentest.TestCase):
# Issue 104: ares.ares_host_result unpickleable
......@@ -24,7 +23,7 @@ class TestPickle(greentest.TestCase):
for i in range(0, pickle.HIGHEST_PROTOCOL):
def make_test(j):
return lambda self: self._test(j)
setattr(TestPickle, 'test' + str(i), make_test(i) )
setattr(TestPickle, 'test' + str(i), make_test(i))
if __name__ == '__main__':
......
......@@ -25,7 +25,6 @@ class Test(greentest.TestCase):
def test(self):
server = backdoor.BackdoorServer(('127.0.0.1', 0))
server.start()
def connect():
conn = create_connection(('127.0.0.1', server.server_port))
......@@ -34,9 +33,12 @@ class Test(greentest.TestCase):
line = conn.makefile().readline()
assert line.strip() == '4', repr(line)
jobs = [gevent.spawn(connect) for _ in xrange(10)]
gevent.joinall(jobs)
server.close()
server.start()
try:
jobs = [gevent.spawn(connect) for _ in xrange(10)]
gevent.joinall(jobs, raise_error=True)
finally:
server.close()
#self.assertEqual(conn.recv(1), '')
def test_quit(self):
......
......@@ -266,6 +266,7 @@ class TestStuff(greentest.TestCase):
self.assertEqual(e.get(), 1)
def test_wait_error(self):
def x():
sleep(DELAY)
return 1
......@@ -293,6 +294,7 @@ class TestStuff(greentest.TestCase):
# works.
def raises_but_ignored():
raise ExpectedError("count")
def sleep_forever():
while True:
sleep(0.1)
......
......@@ -1000,7 +1000,6 @@ class ChunkedInputTests(TestCase):
self.assert_error(IOError, 'unexpected end of file while parsing chunked data')
class Expect100ContinueTests(TestCase):
validator = None
......
......@@ -25,6 +25,7 @@ are not leaked by the hub.
from __future__ import print_function
from _socket import socket
class Socket(socket):
"Something we can have a weakref to"
......
......@@ -33,6 +33,7 @@ class SimpleStreamServer(StreamServer):
finally:
fd.close()
class Settings:
ServerClass = StreamServer
ServerSubClass = SimpleStreamServer
......
......@@ -51,11 +51,12 @@ class TestTCP(greentest.TestCase):
self.port = listener.getsockname()[1]
def cleanup(self):
try:
self.listener.close()
except:
pass
del self.listener
if hasattr(self, 'listener'):
try:
self.listener.close()
except:
pass
del self.listener
def create_connection(self):
sock = socket.socket()
......@@ -146,20 +147,25 @@ class TestTCP(greentest.TestCase):
if sys.platform != 'win32':
def test_sendall_timeout(self):
# Travis-CI container infrastructure is configured with
# large socket buffers, at least 2MB, as-of Jun 3, 2015,
# so we must be sure to send more data than that.
data_sent = b'hello' * 1000000
client_sock = []
acceptor = Thread(target=lambda: client_sock.append(self.listener.accept()))
client = self.create_connection()
time.sleep(0.1)
assert client_sock
client.settimeout(0.1)
data_sent = b'h' * 1000000
start = time.time()
self.assertRaises(self.TIMEOUT_ERROR, client.sendall, data_sent)
took = time.time() - start
assert 0.1 - 0.01 <= took <= 0.1 + 0.1, took
acceptor.join()
client.close()
client_sock[0][0].close()
try:
self.assertRaises(self.TIMEOUT_ERROR, client.sendall, data_sent)
took = time.time() - start
assert 0.1 - 0.01 <= took <= 0.1 + 0.1, took
finally:
acceptor.join()
client.close()
client_sock[0][0].close()
def test_makefile(self):
......
......@@ -105,7 +105,7 @@ def compare_relaxed(a, b):
a_segments = a.count(':')
b_segments = b.count(':')
if a_segments and b_segments:
if a_segments == b_segments and a_segments in (4,5,6,7):
if a_segments == b_segments and a_segments in (4, 5, 6, 7):
return True
if a.rstrip(':').startswith(b.rstrip(':')) or b.rstrip(':').startswith(a.rstrip(':')):
return True
......@@ -245,8 +245,7 @@ class TestCase(greentest.TestCase):
# because it calls assertSequenceEqual, which highlights the exact
# difference in the tuple
msg = format_call(func, args)
self.assertEqual((msg,gevent_result), (msg,real_result))
self.assertEqual((msg, gevent_result), (msg, real_result))
class TestTypeError(TestCase):
......
[tox]
envlist =
py26,py27,pypy,py33,py34
py26,py27,pypy,py33,py34,lint
[testenv]
deps =
greenlet
cython
whitelist_externals =
*
commands =
......@@ -17,3 +18,27 @@ commands =
[testenv:pypy]
deps =
[testenv:lint]
basepython =
python2.7
deps =
{[testenv]deps}
pep8
pyflakes
commands =
make lint
[testenv:travis-lint]
basepython =
python2.7
deps =
{[testenv:lint]deps}
commands =
make travis_test_linters
[testenv:leak]
basepython =
python2.7
commonds =
make leaktest
......@@ -15,6 +15,7 @@ gevent/subprocess.py:\d+: undefined name
gevent/_?ssl[23]?.py:\d+: undefined name
gevent/__init__.py:\d+:.*imported but unused
gevent/__init__.py:\d+: redefinition of unused 'signal' from line
gevent/__init__.py:\d+: redefinition of unused 'socket' from line
gevent/coros.py:\d+: 'from gevent.lock import *' used; unable to detect undefined names
gevent/coros.py:\d+: '__all__' imported but unused
gevent/hub.py:\d+: 'reraise' imported but unused
......
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