Commit 784e3789 authored by Jason Madden's avatar Jason Madden

Refactor test__server[_pywsgi].py for finer control. Adjust the timeouts for pypy/libuv.

parent ea983355
......@@ -26,7 +26,6 @@ import sys
import types
import unittest
from unittest import TestCase as BaseTestCase
from unittest.util import safe_repr
import time
import os
from os.path import basename, splitext
......@@ -153,7 +152,7 @@ else:
skipIf = unittest.skipIf
EXPECT_POOR_TIMER_RESOLUTION = PYPY3 or RUNNING_ON_APPVEYOR
EXPECT_POOR_TIMER_RESOLUTION = PYPY3 or RUNNING_ON_APPVEYOR or (LIBUV and PYPY)
skipOnLibuv = _do_not_skip
skipOnLibuvOnCI = _do_not_skip
......@@ -167,6 +166,18 @@ if LIBUV:
if PYPY:
skipOnLibuvOnCIOnPyPy = unittest.skip
CONN_ABORTED_ERRORS = []
try:
from errno import WSAECONNABORTED
CONN_ABORTED_ERRORS.append(WSAECONNABORTED)
except ImportError:
pass
from errno import ECONNRESET
CONN_ABORTED_ERRORS.append(ECONNRESET)
CONN_ABORTED_ERRORS = frozenset(CONN_ABORTED_ERRORS)
class ExpectedException(Exception):
"""An exception whose traceback should be ignored by the hub"""
......@@ -622,7 +633,7 @@ class TestCase(TestCaseMetaClass("NewBase", (BaseTestCase,), {})):
def assertMonkeyPatchedFuncSignatures(self, mod_name, func_names=(), exclude=()):
# We use inspect.getargspec because it's the only thing available
# in Python 2.7, but it is deprecated
# pylint:disable=deprecated-method
# pylint:disable=deprecated-method,too-many-locals
import inspect
import warnings
from gevent.monkey import get_original
......@@ -738,8 +749,7 @@ class _DelayWaitMixin(object):
timeout = gevent.Timeout.start_new(0.001, ref=False)
try:
with self.assertRaises(gevent.Timeout) as exc:
result = self.wait(timeout=1)
self.wait(timeout=1)
self.assertIs(exc.exception, timeout)
finally:
timeout.cancel()
......@@ -760,7 +770,7 @@ class GenericWaitTestCase(_DelayWaitMixin, TestCase):
def test_returns_none_after_timeout(self):
result = self._wait_and_check()
# join and wait simply return after timeout expires
assert result is None, repr(result)
self.assertIsNone(result)
class GenericGetTestCase(_DelayWaitMixin, TestCase):
......@@ -787,10 +797,10 @@ class GenericGetTestCase(_DelayWaitMixin, TestCase):
def test_raises_timeout_Timeout_exc_customized(self):
error = RuntimeError('expected error')
timeout = gevent.Timeout(self._default_wait_timeout, exception=error)
try:
with self.assertRaises(RuntimeError) as exc:
self._wait_and_check(timeout=timeout)
except RuntimeError as ex:
self.assertIs(ex, error)
self.assertIs(exc.exception, error)
self.cleanup()
......
......@@ -52,21 +52,12 @@ from gevent.pywsgi import Input
CONTENT_LENGTH = 'Content-Length'
CONN_ABORTED_ERRORS = []
CONN_ABORTED_ERRORS = greentest.CONN_ABORTED_ERRORS
server_implements_chunked = True
server_implements_pipeline = True
server_implements_100continue = True
DEBUG = '-v' in sys.argv
try:
from errno import WSAECONNABORTED
CONN_ABORTED_ERRORS.append(WSAECONNABORTED)
except ImportError:
pass
from errno import ECONNRESET
CONN_ABORTED_ERRORS.append(ECONNRESET)
REASONS = {200: 'OK',
500: 'Internal Server Error'}
......
from __future__ import print_function
import unittest
import errno
import os
import greentest
from greentest import PY3
from gevent import socket
import gevent
from gevent.server import StreamServer
import errno
import os
# Timeouts very flaky on appveyor and PyPy3
_DEFAULT_SOCKET_TIMEOUT = 0.1 if not greentest.EXPECT_POOR_TIMER_RESOLUTION else 1.0
......@@ -13,14 +16,14 @@ _DEFAULT_SOCKET_TIMEOUT = 0.1 if not greentest.EXPECT_POOR_TIMER_RESOLUTION else
class SimpleStreamServer(StreamServer):
def handle(self, client_socket, address):
def handle(self, client_socket, _address):
fd = client_socket.makefile()
try:
request_line = fd.readline()
if not request_line:
return
try:
method, path, rest = request_line.split(' ', 3)
_method, path, _rest = request_line.split(' ', 3)
except Exception:
print('Failed to parse request line: %r' % (request_line, ))
raise
......@@ -38,39 +41,42 @@ class SimpleStreamServer(StreamServer):
fd.close()
class Settings:
class _Settings(object):
ServerClass = StreamServer
ServerSubClass = SimpleStreamServer
restartable = True
close_socket_detected = True
@staticmethod
def assertAcceptedConnectionError(self):
conn = self.makefile()
def assertAcceptedConnectionError(inst):
conn = inst.makefile()
result = conn.read()
assert not result, repr(result)
inst.assertFalse(result)
assert500 = assertAcceptedConnectionError
@staticmethod
def assert503(self):
def assert503(inst):
# regular reads timeout
self.assert500()
inst.assert500()
# attempt to send anything reset the connection
try:
self.send_request()
inst.send_request()
except socket.error as ex:
if ex.args[0] != errno.ECONNRESET:
if ex.args[0] not in greentest.CONN_ABORTED_ERRORS:
raise
@staticmethod
def assertPoolFull(self):
self.assertRaises(socket.timeout, self.assertRequestSucceeded, timeout=0.01)
def assertPoolFull(inst):
with inst.assertRaises(socket.timeout):
inst.assertRequestSucceeded(timeout=0.01)
class TestCase(greentest.TestCase):
__timeout__ = greentest.LARGE_TIMEOUT
Settings = _Settings
server = None
def cleanup(self):
if getattr(self, 'server', None) is not None:
......@@ -130,27 +136,24 @@ class TestCase(greentest.TestCase):
return conn
def assertConnectionRefused(self):
try:
with self.assertRaises(socket.error) as exc:
conn = self.makefile()
try:
raise AssertionError('Connection was not refused: %r' % (conn._sock, ))
finally:
conn.close()
except socket.error as ex:
if ex.args[0] not in (errno.ECONNREFUSED, errno.EADDRNOTAVAIL):
raise
conn.close()
ex = exc.exception
self.assertIn(ex.args[0], (errno.ECONNREFUSED, errno.EADDRNOTAVAIL))
def assert500(self):
Settings.assert500(self)
self.Settings.assert500(self)
def assert503(self):
Settings.assert503(self)
self.Settings.assert503(self)
def assertAcceptedConnectionError(self):
Settings.assertAcceptedConnectionError(self)
self.Settings.assertAcceptedConnectionError(self)
def assertPoolFull(self):
Settings.assertPoolFull(self)
self.Settings.assertPoolFull(self)
def assertNotAccepted(self):
conn = self.makefile()
......@@ -185,11 +188,10 @@ class TestCase(greentest.TestCase):
self.server.stop()
self.assertConnectionRefused()
def report_netstat(self, msg):
if 0:
print(msg)
os.system('sudo netstat -anp | grep %s' % os.getpid())
print('^^^^^')
def report_netstat(self, _msg):
# At one point this would call 'sudo netstat -anp | grep PID'
# with os.system. We can probably do better with psutil.
return
def _create_server(self):
return self.ServerSubClass((greentest.DEFAULT_BIND_ADDR, 0))
......@@ -221,12 +223,14 @@ class TestCase(greentest.TestCase):
def ServerClass(self, *args, **kwargs):
kwargs.setdefault('spawn', self.get_spawn())
return Settings.ServerClass(*args, **kwargs)
return self.Settings.ServerClass(*args, **kwargs)
def ServerSubClass(self, *args, **kwargs):
kwargs.setdefault('spawn', self.get_spawn())
return Settings.ServerSubClass(*args, **kwargs)
return self.Settings.ServerSubClass(*args, **kwargs)
def get_spawn(self):
return None
class TestDefaultSpawn(TestCase):
......@@ -237,7 +241,7 @@ class TestDefaultSpawn(TestCase):
self.report_netstat('before start')
self.start_server()
self.report_netstat('after start')
if restartable and Settings.restartable:
if restartable and self.Settings.restartable:
self.server.stop_accepting()
self.report_netstat('after stop_accepting')
self.assertNotAccepted()
......@@ -341,13 +345,6 @@ class TestDefaultSpawn(TestCase):
self.expect_one_error()
self.assertAcceptedConnectionError()
self.assert_error(ExpectedError, error)
return
if Settings.restartable:
assert not self.server.started
else:
assert self.server.started
gevent.sleep(0.1)
assert self.server.started
def test_server_repr_when_handle_is_instancemethod(self):
# PR 501
......@@ -424,9 +421,9 @@ class TestNoneSpawn(TestCase):
self._test_invalid_callback()
def test_assertion_in_blocking_func(self):
def sleep(*args):
def sleep(*_args):
gevent.sleep(0)
self.server = Settings.ServerClass((greentest.DEFAULT_BIND_ADDR, 0), sleep, spawn=None)
self.server = self.Settings.ServerClass((greentest.DEFAULT_BIND_ADDR, 0), sleep, spawn=None)
self.server.start()
self.expect_one_error()
self.assert500()
......@@ -437,52 +434,48 @@ class ExpectedError(Exception):
pass
if hasattr(socket, 'ssl'):
class TestSSLSocketNotAllowed(TestCase):
class TestSSLSocketNotAllowed(TestCase):
switch_expected = False
switch_expected = False
def get_spawn(self):
return gevent.spawn
def get_spawn(self):
return gevent.spawn
def test(self):
from gevent.socket import ssl, socket
listener = socket()
listener.bind(('0.0.0.0', 0))
listener.listen(5)
listener = ssl(listener)
self.assertRaises(TypeError, self.ServerSubClass, listener)
@unittest.skipUnless(hasattr(socket, 'ssl'), "Uses socket.ssl")
def test(self):
from gevent.socket import ssl
from gevent.socket import socket as gsocket
listener = gsocket()
listener.bind(('0.0.0.0', 0))
listener.listen(5)
listener = ssl(listener)
self.assertRaises(TypeError, self.ServerSubClass, listener)
try:
__import__('ssl')
except ImportError:
pass
else:
def _file(name, here=os.path.dirname(__file__)):
return os.path.abspath(os.path.join(here, name))
def _file(name, here=os.path.dirname(__file__)):
return os.path.abspath(os.path.join(here, name))
class TestSSLGetCertificate(TestCase):
class TestSSLGetCertificate(TestCase):
def _create_server(self):
return self.ServerSubClass((greentest.DEFAULT_BIND_ADDR, 0),
keyfile=_file('server.key'),
certfile=_file('server.crt'))
def _create_server(self):
return self.ServerSubClass((greentest.DEFAULT_BIND_ADDR, 0),
keyfile=_file('server.key'),
certfile=_file('server.crt'))
def get_spawn(self):
return gevent.spawn
def get_spawn(self):
return gevent.spawn
def test_certificate(self):
# Issue 801
from gevent import monkey, ssl
# only broken if *not* monkey patched
self.assertFalse(monkey.is_module_patched('ssl'))
self.assertFalse(monkey.is_module_patched('socket'))
def test_certificate(self):
# Issue 801
from gevent import monkey, ssl
# only broken if *not* monkey patched
self.assertFalse(monkey.is_module_patched('ssl'))
self.assertFalse(monkey.is_module_patched('socket'))
self.init_server()
self.init_server()
server_host, server_port, _family = self.get_server_host_port_family()
ssl.get_server_certificate((server_host, server_port))
server_host, server_port, _family = self.get_server_host_port_family()
ssl.get_server_certificate((server_host, server_port))
# test non-socket.error exception in accept call: fatal
# test error in spawn(): non-fatal
......
import socket
import greentest
import gevent
from gevent import pywsgi
import test__server
from test__server import *
from test__server import Settings as server_Settings
def application(self, environ, start_response):
def application(environ, start_response):
if environ['PATH_INFO'] == '/':
start_response("200 OK", [])
return [b"PONG"]
if environ['PATH_INFO'] == '/ping':
start_response("200 OK", [])
return [b"PONG"]
elif environ['PATH_INFO'] == '/short':
if environ['PATH_INFO'] == '/short':
gevent.sleep(0.5)
start_response("200 OK", [])
return []
elif environ['PATH_INFO'] == '/long':
if environ['PATH_INFO'] == '/long':
gevent.sleep(10)
start_response("200 OK", [])
return []
else:
start_response("404 pywsgi WTF?", [])
return []
start_response("404 pywsgi WTF?", [])
return []
class SimpleWSGIServer(pywsgi.WSGIServer):
application = application
application = staticmethod(application)
internal_error_start = b'HTTP/1.1 500 Internal Server Error\n'.replace(b'\n', b'\r\n')
......@@ -41,7 +42,7 @@ Content-length: 31
Service Temporarily Unavailable'''.replace(b'\n', b'\r\n')
class Settings:
class Settings(object):
ServerClass = pywsgi.WSGIServer
ServerSubClass = SimpleWSGIServer
close_socket_detected = True
......@@ -49,36 +50,51 @@ class Settings:
close_socket_detected = False
@staticmethod
def assert500(self):
conn = self.makefile()
def assert500(inst):
conn = inst.makefile()
conn.write(b'GET / HTTP/1.0\r\n\r\n')
result = conn.read()
assert result.startswith(internal_error_start), (result, internal_error_start)
assert result.endswith(internal_error_end), (result, internal_error_end)
assertAcceptedConnectionError = assert500
inst.assertTrue(result.startswith(internal_error_start),
(result, internal_error_start))
inst.assertTrue(result.endswith(internal_error_end),
(result, internal_error_end))
@staticmethod
def assert503(self):
conn = self.makefile()
def assert503(inst):
conn = inst.makefile()
conn.write(b'GET / HTTP/1.0\r\n\r\n')
result = conn.read()
assert result == internal_error503, (result, internal_error503)
inst.assertEqual(result, internal_error503)
@staticmethod
def assertPoolFull(self):
self.assertRaises(socket.timeout, self.assertRequestSucceeded)
def assertPoolFull(inst):
with inst.assertRaises(socket.timeout):
inst.assertRequestSucceeded()
@staticmethod
def assertAcceptedConnectionError(self):
conn = self.makefile()
def assertAcceptedConnectionError(inst):
conn = inst.makefile()
result = conn.read()
assert not result, repr(result)
inst.assertFalse(result)
class TestCase(test__server.TestCase):
Settings = Settings
class TestDefaultSpawn(test__server.TestDefaultSpawn):
Settings = Settings
class TestSSLSocketNotAllowed(test__server.TestSSLSocketNotAllowed):
Settings = Settings
class TestRawSpawn(test__server.TestRawSpawn):
Settings = Settings
test__server.Settings = Settings
class TestSSLGetCertificate(test__server.TestSSLGetCertificate):
Settings = Settings
del TestNoneSpawn
class TestPoolSpawn(test__server.TestPoolSpawn):
Settings = Settings
if __name__ == '__main__':
greentest.main()
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