summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@plope.com>2011-12-30 02:06:46 -0500
committerChris McDonough <chrism@plope.com>2011-12-30 02:06:46 -0500
commitb33f1aeb9f24010a4e0ed68585dd931efb900531 (patch)
tree5f1ec319d3ede92a672ea664301822209fa0b948
parentc68c03332f0f2639ceb118c2d0e5e9f1a6c6a7a6 (diff)
downloadwaitress-pipelinefix.tar.gz
coveragepipelinefix
-rw-r--r--docs/differences.rst2
-rw-r--r--waitress/buffers.py10
-rw-r--r--waitress/channel.py2
-rw-r--r--waitress/tests/test_adjustments.py4
-rw-r--r--waitress/tests/test_buffers.py16
-rw-r--r--waitress/tests/test_channel.py68
-rw-r--r--waitress/tests/test_functional.py8
-rw-r--r--waitress/tests/test_parser.py24
-rw-r--r--waitress/tests/test_receiver.py7
-rw-r--r--waitress/tests/test_task.py397
10 files changed, 329 insertions, 209 deletions
diff --git a/docs/differences.rst b/docs/differences.rst
index 94e7e50..99a32af 100644
--- a/docs/differences.rst
+++ b/docs/differences.rst
@@ -55,4 +55,4 @@ Differences from ``zope.server``
premature channel closes).
- Send a 500 error to the client when a task raises an uncaught exception
- (with optional traceback rendering).
+ (with optional traceback rendering via "expose_traceback" adjustment).
diff --git a/waitress/buffers.py b/waitress/buffers.py
index 6c855ed..6e8eab2 100644
--- a/waitress/buffers.py
+++ b/waitress/buffers.py
@@ -45,10 +45,10 @@ class FileBasedBuffer(object):
def __len__(self):
return self.remain
- def __bool__(self):
- return self.remain >= 0
+ def __nonzero__(self):
+ return self.remain > 0
- __nonzero__ = __bool__
+ __bool__ = __nonzero__ # py3
def append(self, s):
file = self.file
@@ -157,10 +157,10 @@ class OverflowableBuffer(object):
else:
return len(self.strbuf)
- def __bool__(self):
+ def __nonzero__(self):
return bool(len(self))
- __nonzero__ = __bool__
+ __bool__ = __nonzero__ # py3
def _create_buffer(self):
strbuf = self.strbuf
diff --git a/waitress/channel.py b/waitress/channel.py
index b00743d..0c3f5a6 100644
--- a/waitress/channel.py
+++ b/waitress/channel.py
@@ -134,7 +134,7 @@ class HTTPChannel(logging_dispatcher, object):
return False
chunk = self.inbuf.get(self.adj.recv_bytes)
if not chunk:
- return
+ return False
if self.request is None:
self.request = self.parser_class(self.adj)
request = self.request
diff --git a/waitress/tests/test_adjustments.py b/waitress/tests/test_adjustments.py
index aeaa0d2..7a9767d 100644
--- a/waitress/tests/test_adjustments.py
+++ b/waitress/tests/test_adjustments.py
@@ -49,7 +49,8 @@ class TestAdjustments(unittest.TestCase):
send_bytes='300', outbuf_overflow='400', inbuf_overflow='500',
connection_limit='1000', cleanup_interval='1100',
channel_timeout='1200', log_socket_errors='true',
- max_request_header_size='1300', max_request_body_size='1400')
+ max_request_header_size='1300', max_request_body_size='1400',
+ expose_tracebacks='true')
self.assertEqual(inst.host, 'host')
self.assertEqual(inst.port, 8080)
self.assertEqual(inst.threads, 5)
@@ -65,6 +66,7 @@ class TestAdjustments(unittest.TestCase):
self.assertEqual(inst.log_socket_errors, True)
self.assertEqual(inst.max_request_header_size, 1300)
self.assertEqual(inst.max_request_body_size, 1400)
+ self.assertEqual(inst.expose_tracebacks, True)
def test_badvar(self):
self.assertRaises(ValueError, self._makeOne, nope=True)
diff --git a/waitress/tests/test_buffers.py b/waitress/tests/test_buffers.py
index 7766536..19d79df 100644
--- a/waitress/tests/test_buffers.py
+++ b/waitress/tests/test_buffers.py
@@ -24,6 +24,13 @@ class TestFileBasedBuffer(unittest.TestCase):
inst.remain = 10
self.assertEqual(len(inst), 10)
+ def test___nonzero__(self):
+ inst = self._makeOne()
+ inst.remain = 10
+ self.assertEqual(bool(inst), True)
+ inst.remain = 0
+ self.assertEqual(bool(inst), False)
+
def test_append(self):
f = io.BytesIO(b'data')
inst = self._makeOne(f)
@@ -137,9 +144,16 @@ class TestOverflowableBuffer(unittest.TestCase):
def test___len__buf_is_not_None(self):
inst = self._makeOne()
- inst.buf = 'abc'
+ inst.buf = b'abc'
self.assertEqual(len(inst), 3)
+ def test___nonzero__(self):
+ inst = self._makeOne()
+ inst.buf = b'abc'
+ self.assertEqual(bool(inst), True)
+ inst.buf = b''
+ self.assertEqual(bool(inst), False)
+
def test__create_buffer_large(self):
from waitress.buffers import TempfileBasedBuffer
inst = self._makeOne()
diff --git a/waitress/tests/test_channel.py b/waitress/tests/test_channel.py
index 744883d..fffd357 100644
--- a/waitress/tests/test_channel.py
+++ b/waitress/tests/test_channel.py
@@ -99,6 +99,15 @@ class TestHTTPChannel(unittest.TestCase):
inst.task = True
self.assertEqual(inst.readable(), False)
+ def test_readable_with_nonempty_inbuf_calls_received(self):
+ inst, sock, map = self._makeOneWithMap()
+ L = []
+ inst.received = lambda: L.append(True)
+ inst.task = None
+ inst.inbuf = True
+ self.assertEqual(inst.readable(), True)
+ self.assertEqual(len(L), 1)
+
def test_handle_read_no_error(self):
inst, sock, map = self._makeOneWithMap()
inst.will_close = False
@@ -216,6 +225,15 @@ class TestHTTPChannel(unittest.TestCase):
self.assertEqual(inst.server.tasks, [inst])
self.assertTrue(inst.task)
+ def test_received_with_task(self):
+ inst, sock, map = self._makeOneWithMap()
+ inst.task = True
+ self.assertEqual(inst.received(), False)
+
+ def test_received_no_chunk(self):
+ inst, sock, map = self._makeOneWithMap()
+ self.assertEqual(inst.received(), False)
+
def test_received_preq_not_completed(self):
inst, sock, map = self._makeOneWithMap()
inst.server = DummyServer()
@@ -228,7 +246,7 @@ class TestHTTPChannel(unittest.TestCase):
self.assertEqual(inst.task, None)
self.assertEqual(inst.server.tasks, [])
- def test_received_preq_completed(self):
+ def test_received_preq_completed_empty(self):
inst, sock, map = self._makeOneWithMap()
inst.server = DummyServer()
preq = DummyParser()
@@ -240,6 +258,19 @@ class TestHTTPChannel(unittest.TestCase):
self.assertEqual(inst.request, None)
self.assertEqual(inst.server.tasks, [])
+ def test_received_preq_error(self):
+ inst, sock, map = self._makeOneWithMap()
+ inst.server = DummyServer()
+ preq = DummyParser()
+ inst.request = preq
+ preq.completed = True
+ preq.error = True
+ inst.inbuf.append(b'GET / HTTP/1.1\n\n')
+ inst.received()
+ self.assertEqual(inst.request, None)
+ self.assertEqual(len(inst.server.tasks), 1)
+ self.assertTrue(inst.task)
+
def test_received_preq_completed_connection_close(self):
inst, sock, map = self._makeOneWithMap()
inst.server = DummyServer()
@@ -248,10 +279,12 @@ class TestHTTPChannel(unittest.TestCase):
preq.completed = True
preq.empty = True
preq.connection_close = True
- inst.inbuf.append(b'GET / HTTP/1.1\n\n')
+ inbuf = inst.inbuf
+ inbuf.append(b'GET / HTTP/1.1\n\n' + b'a' * 50000)
inst.received()
self.assertEqual(inst.request, None)
self.assertEqual(inst.server.tasks, [])
+ self.assertNotEqual(inst.inbuf, inbuf)
def test_received_preq_completed_n_lt_data(self):
inst, sock, map = self._makeOneWithMap()
@@ -382,14 +415,45 @@ class TestHTTPChannel(unittest.TestCase):
def test_service_with_task_raises(self):
inst, sock, map = self._makeOneWithMap()
+ inst.adj.expose_tracebacks = False
+ inst.server = DummyServer()
+ task = DummyTask(ValueError)
+ task.wrote_header = False
+ inst.task = task
+ inst.logger = DummyLogger()
+ inst.service()
+ self.assertTrue(task.serviced)
+ self.assertEqual(inst.task, None)
+ self.assertEqual(len(inst.logger.exceptions), 1)
+ self.assertTrue(sock.sent)
+
+ def test_service_with_task_raises_with_expose_tbs(self):
+ inst, sock, map = self._makeOneWithMap()
+ inst.adj.expose_tracebacks = True
+ inst.server = DummyServer()
+ task = DummyTask(ValueError)
+ task.wrote_header = False
+ inst.task = task
+ inst.logger = DummyLogger()
+ inst.service()
+ self.assertTrue(task.serviced)
+ self.assertEqual(inst.task, None)
+ self.assertEqual(len(inst.logger.exceptions), 1)
+ self.assertTrue(sock.sent)
+
+ def test_service_with_task_raises_already_wrote_header(self):
+ inst, sock, map = self._makeOneWithMap()
+ inst.adj.expose_tracebacks = False
inst.server = DummyServer()
task = DummyTask(ValueError)
+ task.wrote_header = True
inst.task = task
inst.logger = DummyLogger()
inst.service()
self.assertTrue(task.serviced)
self.assertEqual(inst.task, None)
self.assertEqual(len(inst.logger.exceptions), 1)
+ self.assertFalse(sock.sent)
def test_cancel_no_task(self):
inst, sock, map = self._makeOneWithMap()
diff --git a/waitress/tests/test_functional.py b/waitress/tests/test_functional.py
index 87c316e..9016375 100644
--- a/waitress/tests/test_functional.py
+++ b/waitress/tests/test_functional.py
@@ -791,7 +791,8 @@ def parse_headers(fp):
class ConnectionClosed(Exception):
pass
-def read_http(fp):
+# stolen from gevent
+def read_http(fp): # pragma: no cover
try:
response_line = fp.readline()
except socket.error as exc:
@@ -827,8 +828,9 @@ def read_http(fp):
body = fp.read()
return response_line, headers, body
-
-def get_errno(exc):
+
+# stolen from gevent
+def get_errno(exc): # pragma: no cover
""" Get the error code out of socket.error objects.
socket.error in <2.5 does not have errno attribute
socket.error in 3.x does not allow indexing access
diff --git a/waitress/tests/test_parser.py b/waitress/tests/test_parser.py
index 2e8d469..8111e3f 100644
--- a/waitress/tests/test_parser.py
+++ b/waitress/tests/test_parser.py
@@ -128,7 +128,7 @@ GET /foobar HTTP/8.4
self.assertEqual(result, 0)
def test_received_cl_too_large(self):
- from waitress.parser import RequestEntityTooLarge
+ from waitress.utilities import RequestEntityTooLarge
self.parser.adj.max_request_body_size = 2
data = b"""\
GET /foobar HTTP/8.4
@@ -141,7 +141,7 @@ Content-Length: 10
self.assertTrue(isinstance(self.parser.error, RequestEntityTooLarge))
def test_received_headers_too_large(self):
- from waitress.parser import RequestHeaderFieldsTooLarge
+ from waitress.utilities import RequestHeaderFieldsTooLarge
self.parser.adj.max_request_header_size = 2
data = b"""\
GET /foobar HTTP/8.4
@@ -154,7 +154,7 @@ X-Foo: 1
RequestHeaderFieldsTooLarge))
def test_received_body_too_large(self):
- from waitress.parser import RequestEntityTooLarge
+ from waitress.utilities import RequestEntityTooLarge
self.parser.adj.max_request_body_size = 2
data = b"""\
GET /foobar HTTP/1.1
@@ -171,6 +171,24 @@ This string has 32 characters\r
self.assertTrue(isinstance(self.parser.error,
RequestEntityTooLarge))
+ def test_received_error_from_parser(self):
+ from waitress.utilities import BadRequest
+ data = b"""\
+GET /foobar HTTP/1.1
+Transfer-Encoding: chunked
+X-Foo: 1
+
+garbage
+"""
+ # header
+ result = self.parser.received(data)
+ # body
+ result = self.parser.received(data[result:])
+ self.assertEqual(result, 8)
+ self.assertTrue(self.parser.completed)
+ self.assertTrue(isinstance(self.parser.error,
+ BadRequest))
+
def test_parse_header_gardenpath(self):
data = b"""\
GET /foobar HTTP/8.4
diff --git a/waitress/tests/test_receiver.py b/waitress/tests/test_receiver.py
index a331d73..a7b0e93 100644
--- a/waitress/tests/test_receiver.py
+++ b/waitress/tests/test_receiver.py
@@ -66,6 +66,13 @@ class TestChunkedReceiver(unittest.TestCase):
self.assertEqual(result, 1)
self.assertEqual(inst.completed, False)
+ def test_received_control_line_finished_garbage_in_input(self):
+ buf = DummyBuffer()
+ inst = self._makeOne(buf)
+ result = inst.received(b'garbage\n')
+ self.assertEqual(result, 8)
+ self.assertTrue(inst.error)
+
def test_received_control_line_finished_all_chunks_not_received(self):
buf = DummyBuffer()
inst = self._makeOne(buf)
diff --git a/waitress/tests/test_task.py b/waitress/tests/test_task.py
index 4429bfc..2c651f1 100644
--- a/waitress/tests/test_task.py
+++ b/waitress/tests/test_task.py
@@ -91,37 +91,20 @@ class TestThreadedTaskDispatcher(unittest.TestCase):
self.assertEqual(inst.shutdown(cancel_pending=False, timeout=.01),
False)
-class TestWSGITask(unittest.TestCase):
+class TestTask(unittest.TestCase):
def _makeOne(self, channel=None, request=None):
if channel is None:
channel = DummyChannel()
if request is None:
request = DummyParser()
- from waitress.task import WSGITask
- return WSGITask(channel, request)
+ from waitress.task import Task
+ return Task(channel, request)
- def test_service(self):
- inst = self._makeOne()
- def execute():
- inst.executed = True
- inst.execute = execute
- inst.complete = True
- inst.service()
- self.assertTrue(inst.start_time)
- self.assertTrue(inst.close_on_finish)
- self.assertTrue(inst.channel.written)
- self.assertEqual(inst.executed, True)
-
- def test_service_server_raises_socket_error(self):
- import socket
- inst = self._makeOne()
- def execute():
- raise socket.error
- inst.execute = execute
- self.assertRaises(socket.error, inst.service)
- self.assertTrue(inst.start_time)
- self.assertTrue(inst.close_on_finish)
- self.assertFalse(inst.channel.written)
+ def test_ctor_version_not_in_known(self):
+ request = DummyParser()
+ request.version = '8.4'
+ inst = self._makeOne(request=request)
+ self.assertEqual(inst.version, '1.0')
def test_cancel(self):
inst = self._makeOne()
@@ -132,125 +115,6 @@ class TestWSGITask(unittest.TestCase):
inst = self._makeOne()
self.assertEqual(inst.defer(), None)
- def test_execute_app_calls_start_response_twice_wo_exc_info(self):
- def app(environ, start_response):
- start_response('200 OK', [])
- start_response('200 OK', [])
- inst = self._makeOne()
- inst.channel.server.application = app
- self.assertRaises(AssertionError, inst.execute)
-
- def test_execute_app_calls_start_response_w_exc_info_complete(self):
- def app(environ, start_response):
- start_response('200 OK', [], [ValueError, ValueError(), None])
- inst = self._makeOne()
- inst.complete = True
- inst.channel.server.application = app
- self.assertRaises(ValueError, inst.execute)
-
- def test_execute_app_calls_start_response_w_exc_info_incomplete(self):
- def app(environ, start_response):
- start_response('200 OK', [], [ValueError, None, None])
- return [b'a']
- inst = self._makeOne()
- inst.complete = False
- inst.channel.server.application = app
- inst.execute()
- self.assertTrue(inst.complete)
- self.assertEqual(inst.status, '200 OK')
- self.assertTrue(inst.channel.written)
-
- def test_execute_bad_header_key(self):
- def app(environ, start_response):
- start_response('200 OK', [(None, 'a')])
- inst = self._makeOne()
- inst.channel.server.application = app
- self.assertRaises(AssertionError, inst.execute)
-
- def test_execute_bad_header_value(self):
- def app(environ, start_response):
- start_response('200 OK', [('a', None)])
- inst = self._makeOne()
- inst.channel.server.application = app
- self.assertRaises(AssertionError, inst.execute)
-
- def test_execute_bad_status_value(self):
- def app(environ, start_response):
- start_response(None, [])
- inst = self._makeOne()
- inst.channel.server.application = app
- self.assertRaises(AssertionError, inst.execute)
-
- def test_execute_with_content_length_header(self):
- def app(environ, start_response):
- start_response('200 OK', [('Content-Length', '1')])
- return [b'a']
- inst = self._makeOne()
- inst.channel.server.application = app
- inst.execute()
- self.assertEqual(inst.content_length, 1)
-
- def test_execute_app_calls_write(self):
- def app(environ, start_response):
- write = start_response('200 OK', [('Content-Length', '3')])
- write(b'abc')
- return []
- inst = self._makeOne()
- inst.channel.server.application = app
- inst.execute()
- self.assertEqual(inst.channel.written[-3:], b'abc')
-
- def test_execute_app_returns_len1_chunk_without_cl(self):
- def app(environ, start_response):
- start_response('200 OK', [])
- return [b'abc']
- inst = self._makeOne()
- inst.channel.server.application = app
- inst.execute()
- self.assertEqual(inst.content_length, 3)
-
- def test_execute_app_returns_empty_chunk_as_first(self):
- def app(environ, start_response):
- start_response('200 OK', [])
- return ['', b'abc']
- inst = self._makeOne()
- inst.channel.server.application = app
- inst.execute()
- self.assertEqual(inst.content_length, -1)
-
- def test_execute_app_returns_too_many_bytes(self):
- def app(environ, start_response):
- start_response('200 OK', [('Content-Length', '1')])
- return [b'abc']
- inst = self._makeOne()
- inst.channel.server.application = app
- inst.execute()
- self.assertEqual(inst.close_on_finish, True)
- self.assertTrue(inst.channel.server.logged)
-
- def test_execute_app_returns_too_few_bytes(self):
- def app(environ, start_response):
- start_response('200 OK', [('Content-Length', '3')])
- return [b'a']
- inst = self._makeOne()
- inst.channel.server.application = app
- inst.execute()
- self.assertEqual(inst.close_on_finish, True)
- self.assertTrue(inst.channel.server.logged)
-
- def test_execute_app_returns_closeable(self):
- class closeable(list):
- def close(self):
- self.closed = True
- foo = closeable([b'abc'])
- def app(environ, start_response):
- start_response('200 OK', [('Content-Length', '3')])
- return foo
- inst = self._makeOne()
- inst.channel.server.application = app
- inst.execute()
- self.assertEqual(foo.closed, True)
-
def test_build_response_header_v10_keepalive_no_content_length(self):
inst = self._makeOne()
inst.request = DummyParser()
@@ -438,6 +302,203 @@ class TestWSGITask(unittest.TestCase):
self.assertTrue(lines[2].startswith(b'Date:'))
self.assertEqual(lines[3], b'Server: waitress')
+ def test_start(self):
+ inst = self._makeOne()
+ inst.start()
+ self.assertTrue(inst.start_time)
+
+ def test_finish_didnt_write_header(self):
+ inst = self._makeOne()
+ inst.wrote_header = False
+ inst.complete = True
+ inst.finish()
+ self.assertTrue(inst.channel.written)
+
+ def test_finish_wrote_header(self):
+ inst = self._makeOne()
+ inst.wrote_header = True
+ inst.finish()
+ self.assertFalse(inst.channel.written)
+
+ def test_write_wrote_header(self):
+ inst = self._makeOne()
+ inst.wrote_header = True
+ inst.complete = True
+ inst.write(b'abc')
+ self.assertEqual(inst.channel.written, b'abc')
+
+ def test_write_header_not_written(self):
+ inst = self._makeOne()
+ inst.wrote_header = False
+ inst.complete = True
+ inst.write(b'abc')
+ self.assertTrue(inst.channel.written)
+ self.assertEqual(inst.wrote_header, True)
+
+ def test_write_start_response_uncalled(self):
+ inst = self._makeOne()
+ self.assertRaises(RuntimeError, inst.write, b'')
+
+ def test_write_preexisting_content_length(self):
+ inst = self._makeOne()
+ inst.wrote_header = True
+ inst.complete = True
+ inst.content_length = 1
+ inst.write(b'abc')
+ self.assertTrue(inst.channel.written)
+ self.assertEqual(inst.logged_write_excess, True)
+
+class TestWSGITask(unittest.TestCase):
+ def _makeOne(self, channel=None, request=None):
+ if channel is None:
+ channel = DummyChannel()
+ if request is None:
+ request = DummyParser()
+ from waitress.task import WSGITask
+ return WSGITask(channel, request)
+
+ def test_service(self):
+ inst = self._makeOne()
+ def execute():
+ inst.executed = True
+ inst.execute = execute
+ inst.complete = True
+ inst.service()
+ self.assertTrue(inst.start_time)
+ self.assertTrue(inst.close_on_finish)
+ self.assertTrue(inst.channel.written)
+ self.assertEqual(inst.executed, True)
+
+ def test_service_server_raises_socket_error(self):
+ import socket
+ inst = self._makeOne()
+ def execute():
+ raise socket.error
+ inst.execute = execute
+ self.assertRaises(socket.error, inst.service)
+ self.assertTrue(inst.start_time)
+ self.assertTrue(inst.close_on_finish)
+ self.assertFalse(inst.channel.written)
+
+ def test_execute_app_calls_start_response_twice_wo_exc_info(self):
+ def app(environ, start_response):
+ start_response('200 OK', [])
+ start_response('200 OK', [])
+ inst = self._makeOne()
+ inst.channel.server.application = app
+ self.assertRaises(AssertionError, inst.execute)
+
+ def test_execute_app_calls_start_response_w_exc_info_complete(self):
+ def app(environ, start_response):
+ start_response('200 OK', [], [ValueError, ValueError(), None])
+ inst = self._makeOne()
+ inst.complete = True
+ inst.channel.server.application = app
+ self.assertRaises(ValueError, inst.execute)
+
+ def test_execute_app_calls_start_response_w_exc_info_incomplete(self):
+ def app(environ, start_response):
+ start_response('200 OK', [], [ValueError, None, None])
+ return [b'a']
+ inst = self._makeOne()
+ inst.complete = False
+ inst.channel.server.application = app
+ inst.execute()
+ self.assertTrue(inst.complete)
+ self.assertEqual(inst.status, '200 OK')
+ self.assertTrue(inst.channel.written)
+
+ def test_execute_bad_header_key(self):
+ def app(environ, start_response):
+ start_response('200 OK', [(None, 'a')])
+ inst = self._makeOne()
+ inst.channel.server.application = app
+ self.assertRaises(AssertionError, inst.execute)
+
+ def test_execute_bad_header_value(self):
+ def app(environ, start_response):
+ start_response('200 OK', [('a', None)])
+ inst = self._makeOne()
+ inst.channel.server.application = app
+ self.assertRaises(AssertionError, inst.execute)
+
+ def test_execute_bad_status_value(self):
+ def app(environ, start_response):
+ start_response(None, [])
+ inst = self._makeOne()
+ inst.channel.server.application = app
+ self.assertRaises(AssertionError, inst.execute)
+
+ def test_execute_with_content_length_header(self):
+ def app(environ, start_response):
+ start_response('200 OK', [('Content-Length', '1')])
+ return [b'a']
+ inst = self._makeOne()
+ inst.channel.server.application = app
+ inst.execute()
+ self.assertEqual(inst.content_length, 1)
+
+ def test_execute_app_calls_write(self):
+ def app(environ, start_response):
+ write = start_response('200 OK', [('Content-Length', '3')])
+ write(b'abc')
+ return []
+ inst = self._makeOne()
+ inst.channel.server.application = app
+ inst.execute()
+ self.assertEqual(inst.channel.written[-3:], b'abc')
+
+ def test_execute_app_returns_len1_chunk_without_cl(self):
+ def app(environ, start_response):
+ start_response('200 OK', [])
+ return [b'abc']
+ inst = self._makeOne()
+ inst.channel.server.application = app
+ inst.execute()
+ self.assertEqual(inst.content_length, 3)
+
+ def test_execute_app_returns_empty_chunk_as_first(self):
+ def app(environ, start_response):
+ start_response('200 OK', [])
+ return ['', b'abc']
+ inst = self._makeOne()
+ inst.channel.server.application = app
+ inst.execute()
+ self.assertEqual(inst.content_length, -1)
+
+ def test_execute_app_returns_too_many_bytes(self):
+ def app(environ, start_response):
+ start_response('200 OK', [('Content-Length', '1')])
+ return [b'abc']
+ inst = self._makeOne()
+ inst.channel.server.application = app
+ inst.execute()
+ self.assertEqual(inst.close_on_finish, True)
+ self.assertTrue(inst.channel.server.logged)
+
+ def test_execute_app_returns_too_few_bytes(self):
+ def app(environ, start_response):
+ start_response('200 OK', [('Content-Length', '3')])
+ return [b'a']
+ inst = self._makeOne()
+ inst.channel.server.application = app
+ inst.execute()
+ self.assertEqual(inst.close_on_finish, True)
+ self.assertTrue(inst.channel.server.logged)
+
+ def test_execute_app_returns_closeable(self):
+ class closeable(list):
+ def close(self):
+ self.closed = True
+ foo = closeable([b'abc'])
+ def app(environ, start_response):
+ start_response('200 OK', [('Content-Length', '3')])
+ return foo
+ inst = self._makeOne()
+ inst.channel.server.application = app
+ inst.execute()
+ self.assertEqual(foo.closed, True)
+
def test_get_environment_already_cached(self):
inst = self._makeOne()
inst.environ = object()
@@ -504,52 +565,6 @@ class TestWSGITask(unittest.TestCase):
self.assertEqual(environ['wsgi.input'], 'stream')
self.assertEqual(inst.environ, environ)
- def test_start(self):
- inst = self._makeOne()
- inst.start()
- self.assertTrue(inst.start_time)
-
- def test_finish_didnt_write_header(self):
- inst = self._makeOne()
- inst.wrote_header = False
- inst.complete = True
- inst.finish()
- self.assertTrue(inst.channel.written)
-
- def test_finish_wrote_header(self):
- inst = self._makeOne()
- inst.wrote_header = True
- inst.finish()
- self.assertFalse(inst.channel.written)
-
- def test_write_wrote_header(self):
- inst = self._makeOne()
- inst.wrote_header = True
- inst.complete = True
- inst.write(b'abc')
- self.assertEqual(inst.channel.written, b'abc')
-
- def test_write_header_not_written(self):
- inst = self._makeOne()
- inst.wrote_header = False
- inst.complete = True
- inst.write(b'abc')
- self.assertTrue(inst.channel.written)
- self.assertEqual(inst.wrote_header, True)
-
- def test_write_start_response_uncalled(self):
- inst = self._makeOne()
- self.assertRaises(RuntimeError, inst.write, b'')
-
- def test_write_preexisting_content_length(self):
- inst = self._makeOne()
- inst.wrote_header = True
- inst.complete = True
- inst.content_length = 1
- inst.write(b'abc')
- self.assertTrue(inst.channel.written)
- self.assertEqual(inst.logged_write_excess, True)
-
class TestErrorTask(unittest.TestCase):
def _makeOne(self, channel=None, request=None):
if channel is None:
@@ -624,8 +639,6 @@ class DummyChannel(object):
server = DummyServer()
self.server = server
self.written = b''
- def close_when_done(self):
- self.closed_when_done = True
def write(self, data):
self.written += data
return len(data)