Files
deb-python-eventlet/tests/wsgi_test_conntimeout.py
Jakub Stasiak 449c90a509 Python 3 compat: Fix all Travis test failures
This patch consists of the following changes:

* Splitting eventlet.greenio into base, py2 and py3 parts
  (eventlet.greenio should be exporing the same public objects). This
  change is motivated by the size and the number of conditions present
  in the current greenio code
* Connected to the first point: implementing almost completely new
  GreenPipe callable utilizing parts of old GreenPipe code but dropping
  _fileobject/SocketIO inheritance in favour of io.FileIO and making use
  of patched _pyio.open function which wraps raw file-like object in
  various readers and writers (they take care of the buffering,
  encoding/decoding etc.)
* Implementing (from scratch or updating existing versions)
  green versions of the following modules:

  * http.* (needed by Python 3's urllib)
  * selectors (Python >= 3.4, used in subprocess module)
  * urllib.* (needed by various tests and we were already exposing green
    urllib)

* Modifying some tests to make tests pass, which includes:

  * unicode/bytestring issues
  * modifying wsgi_test_conntimeout.py to not pass bufsize and close
    arguments to ExplodingSocketFile - on Python 3 it inherits from
    SocketIO, which doesn't deal with buffering at all as far as I can
    see

* Random cleaning up and reorganizing
* Requiring Python 3.x tests to pass for the whole build to pass

Known issues:

* code repetition
* naming inconsistencies
* possibly breaking some external code using private eventlet.greenio attributes

Closes https://github.com/eventlet/eventlet/issues/108

Affects https://github.com/eventlet/eventlet/issues/6 (I'd call it an
experimental support)

Should help for https://github.com/eventlet/eventlet/issues/145
Should help for https://github.com/eventlet/eventlet/issues/157
2015-02-13 08:52:54 +01:00

167 lines
4.9 KiB
Python

"""Issue #143 - Socket timeouts in wsgi server not caught.
https://bitbucket.org/eventlet/eventlet/issue/143/
This file intentionally ignored by nose.
Caller process (tests.wsgi_test.TestWsgiConnTimeout) handles success / failure
Simulate server connection socket timeout without actually waiting.
Logs 'timed out' if server debug=True (similar to 'accepted' logging)
FAIL: if log (ie, _spawn_n_impl 'except:' catches timeout, logs TB)
NOTE: timeouts are NOT on server_sock, but on the conn sockets produced
by the socket.accept() call
server's socket.listen() sock - NaughtySocketAcceptWrap
/ | \
| | | (1 - many)
V V V
server / client accept() conn - ExplodingConnectionWrap
/ | \
| | | (1 - many)
V V V
connection makefile() file objects - ExplodingSocketFile <-- these raise
"""
from __future__ import print_function
import eventlet
from eventlet.support import six
import socket
import sys
import tests.wsgi_test
# no standard tests in this file, ignore
__test__ = False
# This test might make you wince
class NaughtySocketAcceptWrap(object):
# server's socket.accept(); patches resulting connection sockets
def __init__(self, sock):
self.sock = sock
self.sock._really_accept = self.sock.accept
self.sock.accept = self
self.conn_reg = []
def unwrap(self):
self.sock.accept = self.sock._really_accept
del self.sock._really_accept
for conn_wrap in self.conn_reg:
conn_wrap.unwrap()
def arm(self):
print("ca-click")
for i in self.conn_reg:
i.arm()
def __call__(self):
print(self.__class__.__name__ + ".__call__")
conn, addr = self.sock._really_accept()
self.conn_reg.append(ExplodingConnectionWrap(conn))
return conn, addr
class ExplodingConnectionWrap(object):
# new connection's socket.makefile
# eventlet *tends* to use socket.makefile, not raw socket methods.
# need to patch file operations
def __init__(self, conn):
self.conn = conn
self.conn._really_makefile = self.conn.makefile
self.conn.makefile = self
self.armed = False
self.file_reg = []
def unwrap(self):
self.conn.makefile = self.conn._really_makefile
del self.conn._really_makefile
def arm(self):
print("tick")
for i in self.file_reg:
i.arm()
def __call__(self, mode='r', bufsize=-1):
print(self.__class__.__name__ + ".__call__")
# file_obj = self.conn._really_makefile(*args, **kwargs)
file_obj = ExplodingSocketFile(self.conn._sock, mode, bufsize)
self.file_reg.append(file_obj)
return file_obj
class ExplodingSocketFile(eventlet.greenio._fileobject):
def __init__(self, sock, mode='rb', bufsize=-1, close=False):
args = [bufsize, close] if six.PY2 else []
super(self.__class__, self).__init__(sock, mode, *args)
self.armed = False
def arm(self):
print("beep")
self.armed = True
def _fuse(self):
if self.armed:
print("=== ~* BOOM *~ ===")
raise socket.timeout("timed out")
def readline(self, *args, **kwargs):
print(self.__class__.__name__ + ".readline")
self._fuse()
return super(self.__class__, self).readline(*args, **kwargs)
if __name__ == '__main__':
for debug in (False, True):
print("SEPERATOR_SENTINEL")
print("debug set to: %s" % debug)
server_sock = eventlet.listen(('localhost', 0))
server_addr = server_sock.getsockname()
sock_wrap = NaughtySocketAcceptWrap(server_sock)
eventlet.spawn_n(
eventlet.wsgi.server,
debug=debug,
log=sys.stdout,
max_size=128,
site=tests.wsgi_test.Site(),
sock=server_sock,
)
try:
# req #1 - normal
sock1 = eventlet.connect(server_addr)
sock1.settimeout(0.1)
fd1 = sock1.makefile('rwb')
fd1.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
fd1.flush()
tests.wsgi_test.read_http(sock1)
# let the server socket ops catch up, set bomb
eventlet.sleep(0)
print("arming...")
sock_wrap.arm()
# req #2 - old conn, post-arm - timeout
fd1.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
fd1.flush()
try:
tests.wsgi_test.read_http(sock1)
assert False, 'Expected ConnectionClosed exception'
except tests.wsgi_test.ConnectionClosed:
pass
fd1.close()
sock1.close()
finally:
# reset streams, then output trapped tracebacks
sock_wrap.unwrap()
# check output asserts in tests.wsgi_test.TestHttpd
# test_143_server_connection_timeout_exception