Tests: reworked TestUnitHTTP.
This commit is contained in:
@@ -52,14 +52,14 @@ def application(environ, start_response):
|
|||||||
|
|
||||||
body = 'Test body string.'
|
body = 'Test body string.'
|
||||||
|
|
||||||
r = unit.TestUnitHTTP.post(headers={
|
resp = self.post(headers={
|
||||||
'Host': 'localhost',
|
'Host': 'localhost',
|
||||||
'Content-Type': 'text/html',
|
'Content-Type': 'text/html',
|
||||||
'Custom-Header': 'blah'
|
'Custom-Header': 'blah'
|
||||||
}, data=body)
|
}, body=body)
|
||||||
|
|
||||||
self.assertEqual(r.status_code, 200, 'status')
|
self.assertEqual(resp['status'], 200, 'status')
|
||||||
headers = dict(r.headers)
|
headers = resp['headers']
|
||||||
self.assertRegex(headers.pop('Server'), r'unit/[\d\.]+',
|
self.assertRegex(headers.pop('Server'), r'unit/[\d\.]+',
|
||||||
'server header')
|
'server header')
|
||||||
self.assertDictEqual(headers, {
|
self.assertDictEqual(headers, {
|
||||||
@@ -71,7 +71,7 @@ def application(environ, start_response):
|
|||||||
'Server-Protocol': 'HTTP/1.1',
|
'Server-Protocol': 'HTTP/1.1',
|
||||||
'Custom-Header': 'blah'
|
'Custom-Header': 'blah'
|
||||||
}, 'headers')
|
}, 'headers')
|
||||||
self.assertEqual(r.content, body.encode(), 'body')
|
self.assertEqual(resp['body'], body, 'body')
|
||||||
|
|
||||||
def test_python_application_query_string(self):
|
def test_python_application_query_string(self):
|
||||||
code, name = """
|
code, name = """
|
||||||
@@ -89,12 +89,10 @@ def application(environ, start_response):
|
|||||||
self.python_application(name, code)
|
self.python_application(name, code)
|
||||||
self.conf_with_name(name)
|
self.conf_with_name(name)
|
||||||
|
|
||||||
r = unit.TestUnitHTTP.get(uri='/?var1=val1&var2=val2', headers={
|
resp = self.get(url='/?var1=val1&var2=val2')
|
||||||
'Host': 'localhost'
|
|
||||||
})
|
|
||||||
|
|
||||||
self.assertEqual(r.status_code, 200, 'status')
|
self.assertEqual(resp['status'], 200, 'status')
|
||||||
headers = dict(r.headers)
|
headers = resp['headers']
|
||||||
headers.pop('Server')
|
headers.pop('Server')
|
||||||
self.assertDictEqual(headers, {
|
self.assertDictEqual(headers, {
|
||||||
'Content-Length': '0',
|
'Content-Length': '0',
|
||||||
@@ -118,9 +116,7 @@ def application(environ, start_response):
|
|||||||
self.python_application(name, code)
|
self.python_application(name, code)
|
||||||
self.conf_with_name(name)
|
self.conf_with_name(name)
|
||||||
|
|
||||||
r = unit.TestUnitHTTP.get(headers={'Host': 'localhost'})
|
self.assertEqual(self.get()['headers']['Server-Port'], '7080',
|
||||||
|
|
||||||
self.assertEqual(r.headers.pop('Server-Port'), '7080',
|
|
||||||
'Server-Port header')
|
'Server-Port header')
|
||||||
|
|
||||||
@unittest.expectedFailure
|
@unittest.expectedFailure
|
||||||
@@ -137,8 +133,7 @@ def application(environ, start_response):
|
|||||||
self.python_application(name, code)
|
self.python_application(name, code)
|
||||||
self.conf_with_name(name)
|
self.conf_with_name(name)
|
||||||
|
|
||||||
r = unit.TestUnitHTTP.get(headers={'Host': 'localhost'})
|
self.assertNotIn('Transfer-Encoding', self.get()['headers'],
|
||||||
self.assertNotIn('Transfer-Encoding', r.headers,
|
|
||||||
'204 header transfer encoding')
|
'204 header transfer encoding')
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ def application(env, start_response):
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
unit.TestUnitHTTP.get()
|
self.get()
|
||||||
|
|
||||||
self.conf({
|
self.conf({
|
||||||
"listeners": {},
|
"listeners": {},
|
||||||
|
|||||||
165
test/unit.py
165
test/unit.py
@@ -5,9 +5,9 @@ import json
|
|||||||
import time
|
import time
|
||||||
import shutil
|
import shutil
|
||||||
import socket
|
import socket
|
||||||
|
import select
|
||||||
import tempfile
|
import tempfile
|
||||||
import unittest
|
import unittest
|
||||||
from requests import Request, Session
|
|
||||||
from subprocess import call
|
from subprocess import call
|
||||||
from multiprocessing import Process
|
from multiprocessing import Process
|
||||||
|
|
||||||
@@ -144,25 +144,59 @@ class TestUnit(unittest.TestCase):
|
|||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
class TestUnitControl(TestUnit):
|
class TestUnitHTTP(TestUnit):
|
||||||
|
|
||||||
# TODO socket reuse
|
def http(self, start_str, **kwargs):
|
||||||
# TODO http client
|
sock_type = 'ipv4' if 'sock_type' not in kwargs else kwargs['sock_type']
|
||||||
|
port = 7080 if 'port' not in kwargs else kwargs['port']
|
||||||
|
url = '/' if 'url' not in kwargs else kwargs['url']
|
||||||
|
http = 'HTTP/1.0' if 'http_10' in kwargs else 'HTTP/1.1'
|
||||||
|
headers = {'Host': 'localhost'} if 'headers' not in kwargs else kwargs['headers']
|
||||||
|
body = b'' if 'body' not in kwargs else kwargs['body']
|
||||||
|
crlf = '\r\n'
|
||||||
|
|
||||||
def conf(self, conf, path='/'):
|
if 'addr' not in kwargs:
|
||||||
if isinstance(conf, dict):
|
addr = '::1' if sock_type == 'ipv6' else '127.0.0.1'
|
||||||
conf = json.dumps(conf)
|
else:
|
||||||
|
addr = kwargs['addr']
|
||||||
|
|
||||||
return self._body_json(self.put(path, conf))
|
sock_types = {
|
||||||
|
'ipv4': socket.AF_INET,
|
||||||
|
'ipv6': socket.AF_INET6,
|
||||||
|
'unix': socket.AF_UNIX
|
||||||
|
}
|
||||||
|
|
||||||
def conf_get(self, path='/'):
|
if 'sock' not in kwargs:
|
||||||
return self._body_json(self.get(path))
|
sock = socket.socket(sock_types[sock_type], socket.SOCK_STREAM)
|
||||||
|
|
||||||
def conf_delete(self, path='/'):
|
if sock_type == 'unix':
|
||||||
return self._body_json(self.delete(path))
|
sock.connect(addr)
|
||||||
|
else:
|
||||||
|
sock.connect((addr, port))
|
||||||
|
|
||||||
|
else:
|
||||||
|
sock = kwargs['sock']
|
||||||
|
|
||||||
|
sock.setblocking(False)
|
||||||
|
|
||||||
|
if 'raw' not in kwargs:
|
||||||
|
req = ' '.join([start_str, url, http]) + crlf
|
||||||
|
|
||||||
|
if body is not b'':
|
||||||
|
if isinstance(body, str):
|
||||||
|
body = body.encode()
|
||||||
|
|
||||||
|
if 'Content-Length' not in headers:
|
||||||
|
headers['Content-Length'] = len(body)
|
||||||
|
|
||||||
|
for header, value in headers.items():
|
||||||
|
req += header + ': ' + str(value) + crlf
|
||||||
|
|
||||||
|
req = (req + crlf).encode() + body
|
||||||
|
|
||||||
|
else:
|
||||||
|
req = start_str
|
||||||
|
|
||||||
def http(self, req):
|
|
||||||
with self._control_sock() as sock:
|
|
||||||
sock.sendall(req)
|
sock.sendall(req)
|
||||||
|
|
||||||
if '--verbose' in sys.argv:
|
if '--verbose' in sys.argv:
|
||||||
@@ -173,72 +207,83 @@ class TestUnitControl(TestUnit):
|
|||||||
if '--verbose' in sys.argv:
|
if '--verbose' in sys.argv:
|
||||||
print('<<<', resp, sep='\n')
|
print('<<<', resp, sep='\n')
|
||||||
|
|
||||||
|
if 'raw_resp' not in kwargs:
|
||||||
|
resp = self._resp_to_dict(resp)
|
||||||
|
|
||||||
|
if 'start' not in kwargs:
|
||||||
|
sock.close()
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
def get(self, path='/'):
|
return (resp, sock)
|
||||||
resp = self.http(('GET ' + path
|
|
||||||
+ ' HTTP/1.1\r\nHost: localhost\r\n\r\n').encode())
|
|
||||||
|
|
||||||
return resp
|
def delete(self, **kwargs):
|
||||||
|
return self.http('DELETE', **kwargs)
|
||||||
|
|
||||||
def delete(self, path='/'):
|
def get(self, **kwargs):
|
||||||
resp = self.http(('DELETE ' + path
|
return self.http('GET', **kwargs)
|
||||||
+ ' HTTP/1.1\r\nHost: localhost\r\n\r\n').encode())
|
|
||||||
|
|
||||||
return resp
|
def post(self, **kwargs):
|
||||||
|
return self.http('POST', **kwargs)
|
||||||
|
|
||||||
def put(self, path='/', data=''):
|
def put(self, **kwargs):
|
||||||
if isinstance(data, str):
|
return self.http('PUT', **kwargs)
|
||||||
data = data.encode()
|
|
||||||
|
|
||||||
resp = self.http(('PUT ' + path + ' HTTP/1.1\nHost: localhost\n'
|
|
||||||
+ 'Content-Length: ' + str(len(data))
|
|
||||||
+ '\r\n\r\n').encode() + data)
|
|
||||||
|
|
||||||
return resp
|
|
||||||
|
|
||||||
def _control_sock(self):
|
|
||||||
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
||||||
sock.connect(self.testdir + '/control.unit.sock')
|
|
||||||
return sock
|
|
||||||
|
|
||||||
def _recvall(self, sock, buff_size=4096):
|
def _recvall(self, sock, buff_size=4096):
|
||||||
data = ''
|
data = ''
|
||||||
while True:
|
while select.select([sock], [], [], 1)[0]:
|
||||||
part = sock.recv(buff_size).decode()
|
part = sock.recv(buff_size).decode()
|
||||||
data += part
|
data += part
|
||||||
if len(part) < buff_size:
|
if part is '':
|
||||||
break
|
break
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def _body_json(self, resp):
|
def _resp_to_dict(self, resp):
|
||||||
m = re.search('.*?\x0d\x0a?\x0d\x0a?(.*)', resp, re.M | re.S)
|
m = re.search('(.*?\x0d\x0a?)\x0d\x0a?(.*)', resp, re.M | re.S)
|
||||||
return json.loads(m.group(1))
|
headers_text, body = m.group(1), m.group(2)
|
||||||
|
|
||||||
class TestUnitHTTP():
|
p = re.compile('(.*?)\x0d\x0a?', re.M | re.S)
|
||||||
|
headers_lines = p.findall(headers_text)
|
||||||
|
|
||||||
@classmethod
|
status = re.search('^HTTP\/\d\.\d\s(\d+)|$', headers_lines.pop(0)).group(1)
|
||||||
def http(self, method, **kwargs):
|
|
||||||
host = '127.0.0.1:7080' if 'host' not in kwargs else kwargs['host']
|
|
||||||
uri = '/' if 'uri' not in kwargs else kwargs['uri']
|
|
||||||
sess = Session() if 'sess' not in kwargs else kwargs['sess']
|
|
||||||
data = None if 'data' not in kwargs else kwargs['data']
|
|
||||||
headers = None if 'headers' not in kwargs else kwargs['headers']
|
|
||||||
|
|
||||||
req = Request(method, 'http://' + host + uri, data=data,
|
headers = {}
|
||||||
headers=headers)
|
for line in headers_lines:
|
||||||
|
m = re.search('(.*)\:\s(.*)', line)
|
||||||
|
headers[m.group(1)] = m.group(2)
|
||||||
|
|
||||||
r = sess.send(req.prepare())
|
return {
|
||||||
|
'status': int(status),
|
||||||
|
'headers': headers,
|
||||||
|
'body': body
|
||||||
|
}
|
||||||
|
|
||||||
if 'keep' not in kwargs:
|
class TestUnitControl(TestUnitHTTP):
|
||||||
sess.close()
|
|
||||||
return r
|
|
||||||
|
|
||||||
return (r, sess)
|
# TODO socket reuse
|
||||||
|
# TODO http client
|
||||||
|
|
||||||
def get(**kwargs):
|
def conf(self, conf, path='/'):
|
||||||
return TestUnitHTTP.http('GET', **kwargs)
|
if isinstance(conf, dict):
|
||||||
|
conf = json.dumps(conf)
|
||||||
|
|
||||||
def post(**kwargs):
|
return json.loads(self.put(
|
||||||
return TestUnitHTTP.http('POST', **kwargs)
|
url=path,
|
||||||
|
body=conf,
|
||||||
|
sock_type='unix',
|
||||||
|
addr=self.testdir + '/control.unit.sock'
|
||||||
|
)['body'])
|
||||||
|
|
||||||
|
def conf_get(self, path='/'):
|
||||||
|
return json.loads(self.get(
|
||||||
|
url=path,
|
||||||
|
sock_type='unix',
|
||||||
|
addr=self.testdir + '/control.unit.sock'
|
||||||
|
)['body'])
|
||||||
|
|
||||||
|
def conf_delete(self, path='/'):
|
||||||
|
return json.loads(self.delete(
|
||||||
|
url=path,
|
||||||
|
sock_type='unix',
|
||||||
|
addr=self.testdir + '/control.unit.sock'
|
||||||
|
)['body'])
|
||||||
|
|||||||
Reference in New Issue
Block a user