diff options
author | Chris McDonough <chrism@plope.com> | 2011-12-28 07:22:03 -0500 |
---|---|---|
committer | Chris McDonough <chrism@plope.com> | 2011-12-28 07:22:03 -0500 |
commit | f2d825f15dba2919128fada60c1b7f80a3054fd8 (patch) | |
tree | b3166393894f92eed91c0fe20f8847ae89aaaf13 | |
parent | 791547c55249c07de6a3e27ed514d0f134716f19 (diff) | |
download | waitress-f2d825f15dba2919128fada60c1b7f80a3054fd8.tar.gz |
add trigger tests
-rw-r--r-- | waitress/task.py | 5 | ||||
-rw-r--r-- | waitress/tests/test_adjustments.py | 5 | ||||
-rw-r--r-- | waitress/tests/test_channel.py | 23 | ||||
-rw-r--r-- | waitress/tests/test_trigger.py | 102 | ||||
-rw-r--r-- | waitress/tests/test_utilities.py | 23 | ||||
-rw-r--r-- | waitress/trigger.py | 21 | ||||
-rw-r--r-- | waitress/utilities.py | 3 |
7 files changed, 165 insertions, 17 deletions
diff --git a/waitress/task.py b/waitress/task.py index 9ddb1ad..8cefce4 100644 --- a/waitress/task.py +++ b/waitress/task.py @@ -350,7 +350,10 @@ class WSGITask(Task): raise ValueError( 'Header value %r is not a string in %s' % (v, (k, v)) ) - if k == 'Content-Length': + if k in ('content-length', 'Content-Length', 'Content-length', + 'CONTENT-LENGTH'): + # reduce funccalls by not calling .lower at small risk of + # being wrong self.content_length = int(v) self.response_headers.extend(headers) diff --git a/waitress/tests/test_adjustments.py b/waitress/tests/test_adjustments.py index 5ce2a5c..aeaa0d2 100644 --- a/waitress/tests/test_adjustments.py +++ b/waitress/tests/test_adjustments.py @@ -48,7 +48,8 @@ class TestAdjustments(unittest.TestCase): url_scheme='https', backlog='20', recv_bytes='200', send_bytes='300', outbuf_overflow='400', inbuf_overflow='500', connection_limit='1000', cleanup_interval='1100', - channel_timeout='1200', log_socket_errors='true') + channel_timeout='1200', log_socket_errors='true', + max_request_header_size='1300', max_request_body_size='1400') self.assertEqual(inst.host, 'host') self.assertEqual(inst.port, 8080) self.assertEqual(inst.threads, 5) @@ -62,6 +63,8 @@ class TestAdjustments(unittest.TestCase): self.assertEqual(inst.cleanup_interval, 1100) self.assertEqual(inst.channel_timeout, 1200) self.assertEqual(inst.log_socket_errors, True) + self.assertEqual(inst.max_request_header_size, 1300) + self.assertEqual(inst.max_request_body_size, 1400) def test_badvar(self): self.assertRaises(ValueError, self._makeOne, nope=True) diff --git a/waitress/tests/test_channel.py b/waitress/tests/test_channel.py index 1bf8f3d..02f048e 100644 --- a/waitress/tests/test_channel.py +++ b/waitress/tests/test_channel.py @@ -296,6 +296,18 @@ class TestHTTPChannel(unittest.TestCase): self.assertEqual(inst.proto_request, None) self.assertEqual(inst.server.tasks, []) + def test_received_preq_completed_connection_close(self): + inst, sock, map = self._makeOneWithMap() + inst.server = DummyServer() + preq = DummyParser() + inst.proto_request = preq + preq.completed = True + preq.empty = True + preq.connection_close = True + inst.received(b'GET / HTTP/1.1\n\n') + self.assertEqual(inst.proto_request, None) + self.assertEqual(inst.server.tasks, []) + def test_received_preq_completed_n_lt_data(self): inst, sock, map = self._makeOneWithMap() inst.server = DummyServer() @@ -345,6 +357,17 @@ class TestHTTPChannel(unittest.TestCase): inst.handle_request(req) self.assertEqual(inst.server.tasks, [inst]) self.assertEqual(len(inst.tasks), 1) + self.assertEqual(inst.tasks[0].__class__.__name__, 'WSGITask') + + def test_handle_request_error(self): + req = DummyParser() + req.error = True + inst, sock, map = self._makeOneWithMap() + inst.server = DummyServer() + inst.handle_request(req) + self.assertEqual(inst.server.tasks, [inst]) + self.assertEqual(len(inst.tasks), 1) + self.assertEqual(inst.tasks[0].__class__.__name__, 'ErrorTask') def test_handle_error_reraises_SystemExit(self): inst, sock, map = self._makeOneWithMap() diff --git a/waitress/tests/test_trigger.py b/waitress/tests/test_trigger.py new file mode 100644 index 0000000..1e06071 --- /dev/null +++ b/waitress/tests/test_trigger.py @@ -0,0 +1,102 @@ +import unittest +import os + +class Test_trigger(unittest.TestCase): + def _makeOne(self, map): + from waitress.trigger import trigger + return trigger(map) + + def test__close(self): + map = {} + inst = self._makeOne(map) + fd = os.open(os.path.abspath(__file__), os.O_RDONLY) + inst._fds = (fd,) + inst.close() + self.assertRaises(OSError, os.read, fd, 1) + + def test__physical_pull(self): + map = {} + inst = self._makeOne(map) + inst._physical_pull() + r = os.read(inst._fds[0], 1) + self.assertEqual(r, b'x') + + def test_readable(self): + map = {} + inst = self._makeOne(map) + self.assertEqual(inst.readable(), True) + + def test_writable(self): + map = {} + inst = self._makeOne(map) + self.assertEqual(inst.writable(), False) + + def test_handle_connect(self): + map = {} + inst = self._makeOne(map) + self.assertEqual(inst.handle_connect(), None) + + def test_close(self): + map = {} + inst = self._makeOne(map) + self.assertEqual(inst.close(), None) + self.assertEqual(inst._closed, True) + + def test_handle_close(self): + map = {} + inst = self._makeOne(map) + self.assertEqual(inst.handle_close(), None) + self.assertEqual(inst._closed, True) + + def test_pull_trigger_nothunk(self): + map = {} + inst = self._makeOne(map) + self.assertEqual(inst.pull_trigger(), None) + r = os.read(inst._fds[0], 1) + self.assertEqual(r, b'x') + + def test_pull_trigger_thunk(self): + map = {} + inst = self._makeOne(map) + self.assertEqual(inst.pull_trigger(True), None) + self.assertEqual(len(inst.thunks), 1) + r = os.read(inst._fds[0], 1) + self.assertEqual(r, b'x') + + def test_handle_read_socket_error(self): + map = {} + inst = self._makeOne(map) + result = inst.handle_read() + self.assertEqual(result, None) + + def test_handle_read_no_socket_error(self): + map = {} + inst = self._makeOne(map) + inst.pull_trigger() + result = inst.handle_read() + self.assertEqual(result, None) + + def test_handle_read_thunk(self): + map = {} + inst = self._makeOne(map) + inst.pull_trigger() + L = [] + inst.thunks = [lambda: L.append(True)] + result = inst.handle_read() + self.assertEqual(result, None) + self.assertEqual(L, [True]) + self.assertEqual(inst.thunks, []) + + def test_handle_read_thunk_error(self): + map = {} + inst = self._makeOne(map) + def errorthunk(): + raise ValueError + inst.pull_trigger(errorthunk) + L = [] + inst.log_info = lambda *arg: L.append(arg) + result = inst.handle_read() + self.assertEqual(result, None) + self.assertEqual(len(L), 1) + self.assertEqual(inst.thunks, []) + diff --git a/waitress/tests/test_utilities.py b/waitress/tests/test_utilities.py index b0e6ebf..3bbd0a2 100644 --- a/waitress/tests/test_utilities.py +++ b/waitress/tests/test_utilities.py @@ -83,3 +83,26 @@ class Test_find_double_newline(unittest.TestCase): def test_mixed(self): self.assertEqual(self._callFUT(b'\n\n00\r\n\r\n'), 2) + +class Test_logging_dispatcher(unittest.TestCase): + def _makeOne(self): + from waitress.utilities import logging_dispatcher + return logging_dispatcher(map={}) + + def test_log_info(self): + import logging + inst = self._makeOne() + logger = DummyLogger() + inst.logger = logger + inst.log_info('message', 'warning') + self.assertEqual(logger.severity, logging.WARN) + self.assertEqual(logger.message, 'message') + + +class DummyLogger(object): + def log(self, severity, message): + self.severity = severity + self.message = message + + + diff --git a/waitress/trigger.py b/waitress/trigger.py index a3f1ecb..073c5d7 100644 --- a/waitress/trigger.py +++ b/waitress/trigger.py @@ -67,10 +67,10 @@ class _triggerbase(object): self.thunks = [] def readable(self): - return 1 + return True def writable(self): - return 0 + return False def handle_connect(self): pass @@ -88,9 +88,6 @@ class _triggerbase(object): self.del_channel() self._close() # subclass does OS-specific stuff - def _close(self): # see close() above; subclass must supply - raise NotImplementedError - def pull_trigger(self, thunk=None): if thunk: self.lock.acquire() @@ -100,15 +97,10 @@ class _triggerbase(object): self.lock.release() self._physical_pull() - # Subclass must supply _physical_pull, which does whatever the OS - # needs to do to provoke the "write" end of the trigger. - def _physical_pull(self): - raise NotImplementedError - def handle_read(self): try: self.recv(8192) - except socket.error: + except (OSError, socket.error): return self.lock.acquire() try: @@ -117,8 +109,9 @@ class _triggerbase(object): thunk() except: nil, t, v, tbinfo = asyncore.compact_traceback() - print ('exception in trigger thunk:' - ' (%s:%s %s)' % (t, v, tbinfo)) + self.log_info( + 'exception in trigger thunk: (%s:%s %s)' % + (t, v, tbinfo)) self.thunks = [] finally: self.lock.release() @@ -141,7 +134,7 @@ if os.name == 'posix': def _physical_pull(self): os.write(self.trigger, b'x') -else: +else: # pragma: no cover # Windows version; uses just sockets, because a pipe isn't select'able # on Windows. diff --git a/waitress/utilities.py b/waitress/utilities.py index 65e5a70..ad84127 100644 --- a/waitress/utilities.py +++ b/waitress/utilities.py @@ -167,10 +167,11 @@ def parse_http_date(d): return retval class logging_dispatcher(asyncore.dispatcher): + logger = logger def log_info(self, message, type='info'): severity = { 'info': logging.INFO, 'warning': logging.WARN, 'error': logging.ERROR, } - logger.log(severity.get(type, logging.INFO), message) + self.logger.log(severity.get(type, logging.INFO), message) |