summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@plope.com>2011-12-28 07:22:03 -0500
committerChris McDonough <chrism@plope.com>2011-12-28 07:22:03 -0500
commitf2d825f15dba2919128fada60c1b7f80a3054fd8 (patch)
treeb3166393894f92eed91c0fe20f8847ae89aaaf13
parent791547c55249c07de6a3e27ed514d0f134716f19 (diff)
downloadwaitress-f2d825f15dba2919128fada60c1b7f80a3054fd8.tar.gz
add trigger tests
-rw-r--r--waitress/task.py5
-rw-r--r--waitress/tests/test_adjustments.py5
-rw-r--r--waitress/tests/test_channel.py23
-rw-r--r--waitress/tests/test_trigger.py102
-rw-r--r--waitress/tests/test_utilities.py23
-rw-r--r--waitress/trigger.py21
-rw-r--r--waitress/utilities.py3
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)