summaryrefslogtreecommitdiff
path: root/waitress/tests/test_channel.py
diff options
context:
space:
mode:
Diffstat (limited to 'waitress/tests/test_channel.py')
-rw-r--r--waitress/tests/test_channel.py109
1 files changed, 91 insertions, 18 deletions
diff --git a/waitress/tests/test_channel.py b/waitress/tests/test_channel.py
index 9376fde..835681c 100644
--- a/waitress/tests/test_channel.py
+++ b/waitress/tests/test_channel.py
@@ -1,4 +1,5 @@
import unittest
+import io
class TestHTTPChannel(unittest.TestCase):
def _makeOne(self, sock, addr, adj, map=None):
@@ -12,6 +13,7 @@ class TestHTTPChannel(unittest.TestCase):
sock = DummySock()
map = {}
inst = self._makeOne(sock, '127.0.0.1', adj, map=map)
+ inst.outbuf_lock = DummyLock()
return inst, sock, map
def test_ctor(self):
@@ -21,23 +23,20 @@ class TestHTTPChannel(unittest.TestCase):
def test_writable_something_in_outbuf(self):
inst, sock, map = self._makeOneWithMap()
- inst.outbuf = 'abc'
+ inst.outbufs[0].append(b'abc')
self.assertTrue(inst.writable())
def test_writable_nothing_in_outbuf(self):
inst, sock, map = self._makeOneWithMap()
- inst.outbuf = ''
self.assertFalse(inst.writable())
def test_writable_nothing_in_outbuf_will_close(self):
inst, sock, map = self._makeOneWithMap()
- inst.outbuf = ''
inst.will_close = True
self.assertTrue(inst.writable())
def test_handle_write_not_connected(self):
inst, sock, map = self._makeOneWithMap()
- inst.outbuf = ''
inst.connected = False
self.assertFalse(inst.handle_write())
@@ -52,7 +51,7 @@ class TestHTTPChannel(unittest.TestCase):
def test_handle_write_no_request_with_outbuf(self):
inst, sock, map = self._makeOneWithMap()
inst.requests = []
- inst.outbuf = DummyBuffer(b'abc')
+ inst.outbufs = [DummyBuffer(b'abc')]
inst.last_activity = 0
result = inst.handle_write()
self.assertEqual(result, None)
@@ -63,7 +62,8 @@ class TestHTTPChannel(unittest.TestCase):
import socket
inst, sock, map = self._makeOneWithMap()
inst.requests = []
- inst.outbuf = DummyBuffer(b'abc', socket.error)
+ outbuf = DummyBuffer(b'abc', socket.error)
+ inst.outbufs = [outbuf]
inst.last_activity = 0
inst.logger = DummyLogger()
result = inst.handle_write()
@@ -71,11 +71,27 @@ class TestHTTPChannel(unittest.TestCase):
self.assertEqual(inst.last_activity, 0)
self.assertEqual(sock.sent, b'')
self.assertEqual(len(inst.logger.exceptions), 1)
+ self.assertTrue(outbuf.closed)
+
+ def test_handle_write_outbuf_raises_othererror(self):
+ inst, sock, map = self._makeOneWithMap()
+ inst.requests = []
+ outbuf = DummyBuffer(b'abc', IOError)
+ inst.outbufs = [outbuf]
+ inst.last_activity = 0
+ inst.logger = DummyLogger()
+ result = inst.handle_write()
+ self.assertEqual(result, None)
+ self.assertEqual(inst.last_activity, 0)
+ self.assertEqual(sock.sent, b'')
+ self.assertEqual(len(inst.logger.exceptions), 1)
+ self.assertTrue(outbuf.closed)
def test_handle_write_no_requests_no_outbuf_will_close(self):
inst, sock, map = self._makeOneWithMap()
inst.requests = []
- inst.outbuf = DummyBuffer(b'')
+ outbuf = DummyBuffer(b'')
+ inst.outbufs = [outbuf]
inst.will_close = True
inst.last_activity = 0
result = inst.handle_write()
@@ -83,37 +99,39 @@ class TestHTTPChannel(unittest.TestCase):
self.assertEqual(inst.connected, False)
self.assertEqual(sock.closed, True)
self.assertEqual(inst.last_activity, 0)
+ self.assertTrue(outbuf.closed)
def test_handle_write_no_requests_force_flush(self):
inst, sock, map = self._makeOneWithMap()
inst.requests = [True]
- inst.outbuf = DummyBuffer(b'abc')
+ inst.outbufs = [DummyBuffer(b'abc')]
inst.will_close = False
inst.force_flush = True
inst.last_activity = 0
result = inst.handle_write()
self.assertEqual(result, None)
self.assertEqual(inst.will_close, False)
- self.assertTrue(inst.outbuf.lock.acquired)
+ self.assertTrue(inst.outbuf_lock.acquired)
self.assertEqual(inst.force_flush, False)
self.assertEqual(sock.sent, b'abc')
def test_handle_write_no_requests_outbuf_gt_send_bytes(self):
inst, sock, map = self._makeOneWithMap()
inst.requests = [True]
- inst.outbuf = DummyBuffer(b'abc')
+ inst.outbufs = [DummyBuffer(b'abc')]
inst.adj.send_bytes = 2
inst.will_close = False
inst.last_activity = 0
result = inst.handle_write()
self.assertEqual(result, None)
self.assertEqual(inst.will_close, False)
- self.assertTrue(inst.outbuf.lock.acquired)
+ self.assertTrue(inst.outbuf_lock.acquired)
self.assertEqual(sock.sent, b'abc')
def test_handle_write_close_when_flushed(self):
inst, sock, map = self._makeOneWithMap()
- inst.outbuf = DummyBuffer(b'abc')
+ outbuf = DummyBuffer(b'abc')
+ inst.outbufs = [outbuf]
inst.will_close = False
inst.close_when_flushed = True
inst.last_activity = 0
@@ -122,6 +140,7 @@ class TestHTTPChannel(unittest.TestCase):
self.assertEqual(inst.will_close, True)
self.assertEqual(inst.close_when_flushed, False)
self.assertEqual(sock.sent, b'abc')
+ self.assertTrue(outbuf.closed)
def test_readable_no_requests_not_will_close(self):
inst, sock, map = self._makeOneWithMap()
@@ -169,13 +188,28 @@ class TestHTTPChannel(unittest.TestCase):
inst, sock, map = self._makeOneWithMap()
wrote = inst.write_soon(b'')
self.assertEqual(wrote, 0)
- self.assertEqual(len(inst.outbuf), 0)
+ self.assertEqual(len(inst.outbufs[0]), 0)
def test_write_soon_nonempty_byte(self):
inst, sock, map = self._makeOneWithMap()
wrote = inst.write_soon(b'a')
self.assertEqual(wrote, 1)
- self.assertEqual(len(inst.outbuf), 1)
+ self.assertEqual(len(inst.outbufs[0]), 1)
+
+ def test_write_soon_filewrapper(self):
+ from waitress.buffers import ReadOnlyFileBasedBuffer
+ f = io.BytesIO(b'abc')
+ wrapper = ReadOnlyFileBasedBuffer(f, 8192)
+ wrapper.prepare()
+ inst, sock, map = self._makeOneWithMap()
+ outbufs = inst.outbufs
+ orig_outbuf = outbufs[0]
+ wrote = inst.write_soon(wrapper)
+ self.assertEqual(wrote, 3)
+ self.assertEqual(len(outbufs), 3)
+ self.assertEqual(outbufs[0], orig_outbuf)
+ self.assertEqual(outbufs[1], wrapper)
+ self.assertEqual(outbufs[2].__class__.__name__, 'OverflowableBuffer')
def test__flush_some_empty_outbuf(self):
inst, sock, map = self._makeOneWithMap()
@@ -184,23 +218,44 @@ class TestHTTPChannel(unittest.TestCase):
def test__flush_some_full_outbuf_socket_returns_nonzero(self):
inst, sock, map = self._makeOneWithMap()
- inst.outbuf.append(b'abc')
+ inst.outbufs[0].append(b'abc')
result = inst._flush_some()
self.assertEqual(result, True)
def test__flush_some_full_outbuf_socket_returns_zero(self):
inst, sock, map = self._makeOneWithMap()
sock.send = lambda x: False
- inst.outbuf.append(b'abc')
+ inst.outbufs[0].append(b'abc')
result = inst._flush_some()
self.assertEqual(result, False)
+ def test_flush_some_multiple_buffers_first_empty(self):
+ inst, sock, map = self._makeOneWithMap()
+ sock.send = lambda x: len(x)
+ buffer = DummyBuffer(b'abc')
+ inst.outbufs.append(buffer)
+ result = inst._flush_some()
+ self.assertEqual(result, True)
+ self.assertEqual(buffer.skipped, 3)
+ self.assertEqual(inst.outbufs, [buffer])
+
def test_handle_close(self):
inst, sock, map = self._makeOneWithMap()
inst.handle_close()
self.assertEqual(inst.connected, False)
self.assertEqual(sock.closed, True)
+ def test_handle_close_outbuf_raises_on_close(self):
+ inst, sock, map = self._makeOneWithMap()
+ def doraise():
+ raise NotImplementedError
+ inst.outbufs[0]._close = doraise
+ inst.logger = DummyLogger()
+ inst.handle_close()
+ self.assertEqual(inst.connected, False)
+ self.assertEqual(sock.closed, True)
+ self.assertEqual(len(inst.logger.exceptions), 1)
+
def test_add_channel(self):
inst, sock, map = self._makeOneWithMap()
fileno = inst._fileno
@@ -300,7 +355,7 @@ class TestHTTPChannel(unittest.TestCase):
inst.received(b'GET / HTTP/1.1\n\n')
self.assertEqual(inst.request, preq)
self.assertEqual(inst.server.tasks, [])
- self.assertEqual(inst.outbuf.get(100), b'')
+ self.assertEqual(inst.outbufs[0].get(100), b'')
def test_received_headers_finished_expect_continue(self):
inst, sock, map = self._makeOneWithMap()
@@ -334,6 +389,7 @@ class TestHTTPChannel(unittest.TestCase):
inst.service()
self.assertEqual(inst.requests, [])
self.assertTrue(request.serviced)
+ self.assertTrue(request.closed)
def test_service_with_one_error_request(self):
inst, sock, map = self._makeOneWithMap()
@@ -344,6 +400,7 @@ class TestHTTPChannel(unittest.TestCase):
inst.service()
self.assertEqual(inst.requests, [])
self.assertTrue(request.serviced)
+ self.assertTrue(request.closed)
def test_service_with_multiple_requests(self):
inst, sock, map = self._makeOneWithMap()
@@ -355,6 +412,8 @@ class TestHTTPChannel(unittest.TestCase):
self.assertEqual(inst.requests, [])
self.assertTrue(request1.serviced)
self.assertTrue(request2.serviced)
+ self.assertTrue(request1.closed)
+ self.assertTrue(request2.closed)
def test_service_with_request_raises(self):
inst, sock, map = self._makeOneWithMap()
@@ -374,6 +433,7 @@ class TestHTTPChannel(unittest.TestCase):
self.assertTrue(inst.last_activity)
self.assertFalse(inst.will_close)
self.assertEqual(inst.error_task_class.serviced, True)
+ self.assertTrue(request.closed)
def test_service_with_requests_raises_already_wrote_header(self):
inst, sock, map = self._makeOneWithMap()
@@ -392,6 +452,7 @@ class TestHTTPChannel(unittest.TestCase):
self.assertTrue(inst.last_activity)
self.assertTrue(inst.close_when_flushed)
self.assertEqual(inst.error_task_class.serviced, False)
+ self.assertTrue(request.closed)
def test_service_with_requests_raises_didnt_write_header_expose_tbs(self):
inst, sock, map = self._makeOneWithMap()
@@ -411,6 +472,7 @@ class TestHTTPChannel(unittest.TestCase):
self.assertTrue(inst.force_flush)
self.assertTrue(inst.last_activity)
self.assertEqual(inst.error_task_class.serviced, True)
+ self.assertTrue(request.closed)
def test_service_with_requests_raises_didnt_write_header(self):
inst, sock, map = self._makeOneWithMap()
@@ -428,6 +490,7 @@ class TestHTTPChannel(unittest.TestCase):
self.assertTrue(inst.force_flush)
self.assertTrue(inst.last_activity)
self.assertTrue(inst.close_when_flushed)
+ self.assertTrue(request.closed)
def test_cancel_no_requests(self):
inst, sock, map = self._makeOneWithMap()
@@ -471,12 +534,16 @@ class DummyLock(object):
return self.acquirable
def release(self):
self.released = True
+ def __exit__(self, type, val, traceback):
+ self.acquire(True)
+ def __enter__(self):
+ pass
class DummyBuffer(object):
+ closed = False
def __init__(self, data, toraise=None):
self.data = data
self.toraise = toraise
- self.lock = DummyLock()
def get(self, *arg):
if self.toraise:
@@ -491,6 +558,9 @@ class DummyBuffer(object):
def __len__(self):
return len(self.data)
+ def _close(self):
+ self.closed = True
+
class DummyAdjustments(object):
outbuf_overflow = 1048576
inbuf_overflow = 512000
@@ -535,8 +605,11 @@ class DummyRequest(object):
error = None
path = '/'
version = '1.0'
+ closed = False
def __init__(self):
self.headers = {}
+ def _close(self):
+ self.closed = True
class DummyLogger(object):
def __init__(self):