diff options
Diffstat (limited to '')
30 files changed, 1139 insertions, 1837 deletions
diff --git a/test/go/404/app.go b/test/go/404/app.go index 08fe56c9..7eba2cf4 100644 --- a/test/go/404/app.go +++ b/test/go/404/app.go @@ -4,7 +4,7 @@ import ( "io" "io/ioutil" "net/http" - "nginx/unit" + "unit.nginx.org/go" ) func handler(w http.ResponseWriter, r *http.Request) { diff --git a/test/go/command_line_arguments/app.go b/test/go/command_line_arguments/app.go index 234e565e..1101e1cf 100644 --- a/test/go/command_line_arguments/app.go +++ b/test/go/command_line_arguments/app.go @@ -4,7 +4,7 @@ import ( "fmt" "io" "net/http" - "nginx/unit" + "unit.nginx.org/go" "os" "strings" ) diff --git a/test/go/cookies/app.go b/test/go/cookies/app.go index e6647ea8..2216e153 100644 --- a/test/go/cookies/app.go +++ b/test/go/cookies/app.go @@ -2,7 +2,7 @@ package main import ( "net/http" - "nginx/unit" + "unit.nginx.org/go" ) func handler(w http.ResponseWriter, r *http.Request) { diff --git a/test/go/empty/app.go b/test/go/empty/app.go index 6e0fce1b..9326a19b 100644 --- a/test/go/empty/app.go +++ b/test/go/empty/app.go @@ -2,7 +2,7 @@ package main import ( "net/http" - "nginx/unit" + "unit.nginx.org/go" ) func handler(w http.ResponseWriter, r *http.Request) {} diff --git a/test/go/get_variables/app.go b/test/go/get_variables/app.go index 4dcc0e7b..1c0205a8 100644 --- a/test/go/get_variables/app.go +++ b/test/go/get_variables/app.go @@ -2,7 +2,7 @@ package main import ( "net/http" - "nginx/unit" + "unit.nginx.org/go" ) func handler(w http.ResponseWriter, r *http.Request) { diff --git a/test/go/mirror/app.go b/test/go/mirror/app.go index 748aa7ee..78f047c3 100644 --- a/test/go/mirror/app.go +++ b/test/go/mirror/app.go @@ -4,7 +4,7 @@ import ( "fmt" "io" "net/http" - "nginx/unit" + "unit.nginx.org/go" ) func handler(w http.ResponseWriter, r *http.Request) { diff --git a/test/go/ns_inspect/app.go b/test/go/ns_inspect/app.go index ebecbb00..d9b561c9 100644 --- a/test/go/ns_inspect/app.go +++ b/test/go/ns_inspect/app.go @@ -4,7 +4,7 @@ import ( "encoding/json" "fmt" "net/http" - "nginx/unit" + "unit.nginx.org/go" "os" "strconv" ) @@ -70,6 +70,8 @@ func handler(w http.ResponseWriter, r *http.Request) { return } + w.Header().Add("Content-Type", "application/json") + w.Write(data) } diff --git a/test/go/post_variables/app.go b/test/go/post_variables/app.go index 947976d2..e6279ac6 100644 --- a/test/go/post_variables/app.go +++ b/test/go/post_variables/app.go @@ -2,7 +2,7 @@ package main import ( "net/http" - "nginx/unit" + "unit.nginx.org/go" ) func handler(w http.ResponseWriter, r *http.Request) { diff --git a/test/go/variables/app.go b/test/go/variables/app.go index fdcbf7e8..4be60cb7 100644 --- a/test/go/variables/app.go +++ b/test/go/variables/app.go @@ -4,7 +4,7 @@ import ( "fmt" "io" "net/http" - "nginx/unit" + "unit.nginx.org/go" ) func handler(w http.ResponseWriter, r *http.Request) { diff --git a/test/python/user_group/wsgi.py b/test/python/user_group/wsgi.py new file mode 100644 index 00000000..f5deb87d --- /dev/null +++ b/test/python/user_group/wsgi.py @@ -0,0 +1,18 @@ +import json +import os + +def application(environ, start_response): + uid = os.geteuid() + gid = os.getegid() + + out = json.dumps({ + 'UID': uid, + 'GID': gid, + }).encode('utf-8') + + start_response('200 OK', [ + ('Content-Length', str(len(out))), + ('Content-Type', 'application/json') + ]) + + return [out] diff --git a/test/test_go_isolation.py b/test/test_go_isolation.py index ee5ddf47..7884274d 100644 --- a/test/test_go_isolation.py +++ b/test/test_go_isolation.py @@ -1,4 +1,5 @@ -import os +import pwd +import grp import json import unittest from unit.applications.lang.go import TestApplicationGo @@ -18,20 +19,25 @@ class TestGoIsolation(TestApplicationGo): return unit if not complete_check else unit.complete() + def unpriv_creds(self): + nobody_uid = pwd.getpwnam('nobody').pw_uid + + try: + nogroup_gid = grp.getgrnam('nogroup').gr_gid + nogroup = 'nogroup' + except: + nogroup_gid = grp.getgrnam('nobody').gr_gid + nogroup = 'nobody' + + return (nobody_uid, nogroup_gid, nogroup) + def isolation_key(self, key): return key in self.available['features']['isolation'].keys() - def conf_isolation(self, isolation): - self.assertIn( - 'success', - self.conf(isolation, 'applications/ns_inspect/isolation'), - 'configure isolation', - ) - def test_isolation_values(self): self.load('ns_inspect') - obj = self.isolation.parsejson(self.get()['body']) + obj = self.getjson()['body'] for ns, ns_value in self.available['features']['isolation'].items(): if ns.upper() in obj['NS']: @@ -39,44 +45,155 @@ class TestGoIsolation(TestApplicationGo): obj['NS'][ns.upper()], ns_value, '%s match' % ns ) - def test_isolation_user(self): + def test_isolation_unpriv_user(self): if not self.isolation_key('unprivileged_userns_clone'): print('unprivileged clone is not available') raise unittest.SkipTest() + if self.is_su: + print('privileged tests, skip this') + raise unittest.SkipTest() + self.load('ns_inspect') - obj = self.isolation.parsejson(self.get()['body']) + obj = self.getjson()['body'] - self.assertTrue(obj['UID'] != 0, 'uid not zero') - self.assertTrue(obj['GID'] != 0, 'gid not zero') - self.assertEqual(obj['UID'], os.getuid(), 'uid match') - self.assertEqual(obj['GID'], os.getgid(), 'gid match') + self.assertEqual(obj['UID'], self.uid, 'uid match') + self.assertEqual(obj['GID'], self.gid, 'gid match') - self.conf_isolation({"namespaces": {"credential": True}}) + self.load('ns_inspect', isolation={'namespaces': {'credential': True}}) - obj = self.isolation.parsejson(self.get()['body']) + obj = self.getjson()['body'] - # default uid and gid maps current user to nobody - self.assertEqual(obj['UID'], 65534, 'uid nobody') - self.assertEqual(obj['GID'], 65534, 'gid nobody') + nobody_uid, nogroup_gid, nogroup = self.unpriv_creds() - self.conf_isolation( - { - "namespaces": {"credential": True}, - "uidmap": [ - {"container": 1000, "host": os.geteuid(), "size": 1} - ], - "gidmap": [ - {"container": 1000, "host": os.getegid(), "size": 1} + # unprivileged unit map itself to nobody in the container by default + self.assertEqual(obj['UID'], nobody_uid, 'uid of nobody') + self.assertEqual(obj['GID'], nogroup_gid, 'gid of %s' % nogroup) + + self.load( + 'ns_inspect', + user='root', + isolation={'namespaces': {'credential': True}}, + ) + + obj = self.getjson()['body'] + + self.assertEqual(obj['UID'], 0, 'uid match user=root') + self.assertEqual(obj['GID'], 0, 'gid match user=root') + + self.load( + 'ns_inspect', + user='root', + group=nogroup, + isolation={'namespaces': {'credential': True}}, + ) + + obj = self.getjson()['body'] + + self.assertEqual(obj['UID'], 0, 'uid match user=root group=nogroup') + self.assertEqual( + obj['GID'], nogroup_gid, 'gid match user=root group=nogroup' + ) + + self.load( + 'ns_inspect', + user='root', + group='root', + isolation={ + 'namespaces': {'credential': True}, + 'uidmap': [{'container': 0, 'host': self.uid, 'size': 1}], + 'gidmap': [{'container': 0, 'host': self.gid, 'size': 1}], + }, + ) + + obj = self.getjson()['body'] + + self.assertEqual(obj['UID'], 0, 'uid match uidmap') + self.assertEqual(obj['GID'], 0, 'gid match gidmap') + + def test_isolation_priv_user(self): + if not self.is_su: + print('unprivileged tests, skip this') + raise unittest.SkipTest() + + self.load('ns_inspect') + + nobody_uid, nogroup_gid, nogroup = self.unpriv_creds() + + obj = self.getjson()['body'] + + self.assertEqual(obj['UID'], nobody_uid, 'uid match') + self.assertEqual(obj['GID'], nogroup_gid, 'gid match') + + self.load('ns_inspect', isolation={'namespaces': {'credential': True}}) + + obj = self.getjson()['body'] + + # privileged unit map app creds in the container by default + self.assertEqual(obj['UID'], nobody_uid, 'uid nobody') + self.assertEqual(obj['GID'], nogroup_gid, 'gid nobody') + + self.load( + 'ns_inspect', + user='root', + isolation={'namespaces': {'credential': True}}, + ) + + obj = self.getjson()['body'] + + self.assertEqual(obj['UID'], 0, 'uid nobody user=root') + self.assertEqual(obj['GID'], 0, 'gid nobody user=root') + + self.load( + 'ns_inspect', + user='root', + group=nogroup, + isolation={'namespaces': {'credential': True}}, + ) + + obj = self.getjson()['body'] + + self.assertEqual(obj['UID'], 0, 'uid match user=root group=nogroup') + self.assertEqual( + obj['GID'], nogroup_gid, 'gid match user=root group=nogroup' + ) + + self.load( + 'ns_inspect', + user='root', + group='root', + isolation={ + 'namespaces': {'credential': True}, + 'uidmap': [{'container': 0, 'host': 0, 'size': 1}], + 'gidmap': [{'container': 0, 'host': 0, 'size': 1}], + }, + ) + + obj = self.getjson()['body'] + + self.assertEqual(obj['UID'], 0, 'uid match uidmap user=root') + self.assertEqual(obj['GID'], 0, 'gid match gidmap user=root') + + # map 65535 uids + self.load( + 'ns_inspect', + user='nobody', + isolation={ + 'namespaces': {'credential': True}, + 'uidmap': [ + {'container': 0, 'host': 0, 'size': nobody_uid + 1} ], - } + }, ) - obj = self.isolation.parsejson(self.get()['body']) + obj = self.getjson()['body'] - # default uid and gid maps current user to root - self.assertEqual(obj['UID'], 1000, 'uid root') - self.assertEqual(obj['GID'], 1000, 'gid root') + self.assertEqual( + obj['UID'], nobody_uid, 'uid match uidmap user=nobody' + ) + self.assertEqual( + obj['GID'], nogroup_gid, 'gid match uidmap user=nobody' + ) def test_isolation_mnt(self): if not self.isolation_key('mnt'): @@ -87,12 +204,12 @@ class TestGoIsolation(TestApplicationGo): print('unprivileged clone is not available') raise unittest.SkipTest() - self.load('ns_inspect') - self.conf_isolation( - {"namespaces": {"mount": True, "credential": True}} + self.load( + 'ns_inspect', + isolation={'namespaces': {'mount': True, 'credential': True}}, ) - obj = self.isolation.parsejson(self.get()['body']) + obj = self.getjson()['body'] # all but user and mnt allns = list(self.available['features']['isolation'].keys()) @@ -119,14 +236,16 @@ class TestGoIsolation(TestApplicationGo): print('pid namespace is not supported') raise unittest.SkipTest() - if not self.isolation_key('unprivileged_userns_clone'): - print('unprivileged clone is not available') + if not (self.is_su or self.isolation_key('unprivileged_userns_clone')): + print('requires root or unprivileged_userns_clone') raise unittest.SkipTest() - self.load('ns_inspect') - self.conf_isolation({"namespaces": {"pid": True, "credential": True}}) + self.load( + 'ns_inspect', + isolation={'namespaces': {'pid': True, 'credential': True}}, + ) - obj = self.isolation.parsejson(self.get()['body']) + obj = self.getjson()['body'] self.assertEqual(obj['PID'], 1, 'pid of container is 1') @@ -150,9 +269,9 @@ class TestGoIsolation(TestApplicationGo): else: namespaces[ns] = False - self.conf_isolation({"namespaces": namespaces}) + self.load('ns_inspect', isolation={'namespaces': namespaces}) - obj = self.isolation.parsejson(self.get()['body']) + obj = self.getjson()['body'] for ns in allns: if ns.upper() in obj['NS']: diff --git a/test/test_java_application.py b/test/test_java_application.py index 2e937718..d2b97f88 100644 --- a/test/test_java_application.py +++ b/test/test_java_application.py @@ -1,3 +1,4 @@ +import os import time import unittest from unit.applications.lang.java import TestApplicationJava @@ -1217,7 +1218,13 @@ class TestJavaApplication(TestApplicationJava): def test_java_application_multipart(self): self.load('multipart') - body = """Preamble. Should be ignored.\r + reldst = '/uploads' + fulldst = self.testdir + reldst + os.mkdir(fulldst) + self.public_dir(fulldst) + + body = ( + """Preamble. Should be ignored.\r \r --12345\r Content-Disposition: form-data; name="file"; filename="sample.txt"\r @@ -1234,7 +1241,9 @@ Content-Disposition: form-data; name="upload"\r Upload\r --12345--\r \r -Epilogue. Should be ignored.""" % self.testdir +Epilogue. Should be ignored.""" + % fulldst + ) resp = self.post( headers={ @@ -1246,9 +1255,13 @@ Epilogue. Should be ignored.""" % self.testdir ) self.assertEqual(resp['status'], 200, 'multipart status') - self.assertRegex(resp['body'], r'sample\.txt created', 'multipart body') + self.assertRegex( + resp['body'], r'sample\.txt created', 'multipart body' + ) self.assertIsNotNone( - self.search_in_log(r'^Data from sample file$', name='sample.txt'), + self.search_in_log( + r'^Data from sample file$', name=reldst + '/sample.txt' + ), 'file created', ) diff --git a/test/test_node_application.py b/test/test_node_application.py index a5b4a108..b80d17d3 100644 --- a/test/test_node_application.py +++ b/test/test_node_application.py @@ -141,7 +141,7 @@ class TestNodeApplication(TestApplicationNode): self.load('write_buffer') self.assertEqual( - self.get()['body'], '6\r\nbuffer\r\n0\r\n\r\n', 'write buffer' + self.get()['body'], 'buffer', 'write buffer' ) def test_node_application_write_callback(self): @@ -149,7 +149,7 @@ class TestNodeApplication(TestApplicationNode): self.assertEqual( self.get()['body'], - '5\r\nhello\r\n5\r\nworld\r\n0\r\n\r\n', + 'helloworld', 'write callback order', ) self.assertTrue( @@ -173,7 +173,7 @@ class TestNodeApplication(TestApplicationNode): self.assertEqual( self.get()['body'], - '4\r\nbody\r\n4\r\ntrue\r\n0\r\n\r\n', + 'bodytrue', 'write return', ) diff --git a/test/test_perl_application.py b/test/test_perl_application.py index bf3c65d5..a4bac623 100644 --- a/test/test_perl_application.py +++ b/test/test_perl_application.py @@ -157,7 +157,7 @@ class TestPerlApplication(TestApplicationPerl): def test_perl_application_body_empty(self): self.load('body_empty') - self.assertEqual(self.get()['body'], '0\r\n\r\n', 'body empty') + self.assertEqual(self.get()['body'], '', 'body empty') def test_perl_application_body_array(self): self.load('body_array') diff --git a/test/test_python_application.py b/test/test_python_application.py index ae8f01ca..818816d0 100644 --- a/test/test_python_application.py +++ b/test/test_python_application.py @@ -1,4 +1,7 @@ import re +import os +import grp +import pwd import time import unittest from unit.applications.lang.python import TestApplicationPython @@ -540,7 +543,7 @@ Connection: close } ) self.assertEqual(resp['status'], 200, 'status') - self.assertEqual(resp['body'][-5:], '0\r\n\r\n', 'body') + self.assertEqual(resp['body'], 'XXXXXXX', 'body') # Exception before start_response(). @@ -607,12 +610,11 @@ Connection: close 'X-Skip': '2', 'X-Chunked': '1', 'Connection': 'close', - } + }, + raw_resp=True ) - if 'body' in resp: - self.assertNotEqual( - resp['body'][-5:], '0\r\n\r\n', 'incomplete body' - ) + if resp: + self.assertNotEqual(resp[-5:], '0\r\n\r\n', 'incomplete body') self.assertEqual( len(self.findall(r'Traceback')), 4, 'traceback count 4' ) @@ -646,12 +648,11 @@ Connection: close 'X-Skip': '3', 'X-Chunked': '1', 'Connection': 'close', - } + }, + raw_resp=True ) - if 'body' in resp: - self.assertNotEqual( - resp['body'][-5:], '0\r\n\r\n', 'incomplete body 2' - ) + if resp: + self.assertNotEqual(resp[-5:], '0\r\n\r\n', 'incomplete body 2') self.assertEqual( len(self.findall(r'Traceback')), 6, 'traceback count 6' ) @@ -678,5 +679,79 @@ Connection: close len(self.findall(r'Traceback')), 8, 'traceback count 8' ) + def test_python_user_group(self): + if not self.is_su: + print("requires root") + raise unittest.SkipTest() + + nobody_uid = pwd.getpwnam('nobody').pw_uid + + group = 'nobody' + + try: + group_id = grp.getgrnam(group).gr_gid + except: + group = 'nogroup' + group_id = grp.getgrnam(group).gr_gid + + self.load('user_group') + + obj = self.getjson()['body'] + self.assertEqual(obj['UID'], nobody_uid, 'nobody uid') + self.assertEqual(obj['GID'], group_id, 'nobody gid') + + self.load('user_group', user='nobody') + + obj = self.getjson()['body'] + self.assertEqual(obj['UID'], nobody_uid, 'nobody uid user=nobody') + self.assertEqual(obj['GID'], group_id, 'nobody gid user=nobody') + + self.load('user_group', user='nobody', group=group) + + obj = self.getjson()['body'] + self.assertEqual( + obj['UID'], nobody_uid, 'nobody uid user=nobody group=%s' % group + ) + + self.assertEqual( + obj['GID'], group_id, 'nobody gid user=nobody group=%s' % group + ) + + self.load('user_group', group=group) + + obj = self.getjson()['body'] + self.assertEqual( + obj['UID'], nobody_uid, 'nobody uid group=%s' % group + ) + + self.assertEqual(obj['GID'], group_id, 'nobody gid group=%s' % group) + + self.load('user_group', user='root') + + obj = self.getjson()['body'] + self.assertEqual(obj['UID'], 0, 'root uid user=root') + self.assertEqual(obj['GID'], 0, 'root gid user=root') + + group = 'root' + + try: + grp.getgrnam(group) + group = True + except: + group = False + + if group: + self.load('user_group', user='root', group='root') + + obj = self.getjson()['body'] + self.assertEqual(obj['UID'], 0, 'root uid user=root group=root') + self.assertEqual(obj['GID'], 0, 'root gid user=root group=root') + + self.load('user_group', group='root') + + obj = self.getjson()['body'] + self.assertEqual(obj['UID'], nobody_uid, 'root uid group=root') + self.assertEqual(obj['GID'], 0, 'root gid group=root') + if __name__ == '__main__': TestPythonApplication.main() diff --git a/test/test_python_environment.py b/test/test_python_environment.py index fe0baa13..f808f795 100644 --- a/test/test_python_environment.py +++ b/test/test_python_environment.py @@ -136,27 +136,27 @@ class TestPythonEnvironment(TestApplicationPython): def test_python_environment_replace_default(self): self.load('environment') - pwd_default = self.get( + home_default = self.get( headers={ 'Host': 'localhost', - 'X-Variables': 'PWD', + 'X-Variables': 'HOME', 'Connection': 'close', } )['body'] - self.assertGreater(len(pwd_default), 1, 'get default') + self.assertGreater(len(home_default), 1, 'get default') - self.conf({"PWD": "new/pwd"}, 'applications/environment/environment') + self.conf({"HOME": "/"}, 'applications/environment/environment') self.assertEqual( self.get( headers={ 'Host': 'localhost', - 'X-Variables': 'PWD', + 'X-Variables': 'HOME', 'Connection': 'close', } )['body'], - 'new/pwd,', + '/,', 'replace default', ) @@ -166,11 +166,11 @@ class TestPythonEnvironment(TestApplicationPython): self.get( headers={ 'Host': 'localhost', - 'X-Variables': 'PWD', + 'X-Variables': 'HOME', 'Connection': 'close', } )['body'], - pwd_default, + home_default, 'restore default', ) diff --git a/test/test_routing.py b/test/test_routing.py index 2960f978..eb7b2fd8 100644 --- a/test/test_routing.py +++ b/test/test_routing.py @@ -45,409 +45,160 @@ class TestRouting(TestApplicationProto): def route(self, route): return self.conf([route], 'routes') - def test_routes_match_method_positive(self): - self.assertEqual(self.get()['status'], 200, 'method positive GET') - self.assertEqual(self.post()['status'], 404, 'method positive POST') - - def test_routes_match_method_positive_many(self): + def route_match(self, match): self.assertIn( 'success', self.route( - { - "match": {"method": ["GET", "POST"]}, - "action": {"pass": "applications/empty"}, - } + {"match": match, "action": {"pass": "applications/empty"}} ), - 'method positive many configure', - ) - - self.assertEqual(self.get()['status'], 200, 'method positive many GET') - self.assertEqual( - self.post()['status'], 200, 'method positive many POST' - ) - self.assertEqual( - self.delete()['status'], 404, 'method positive many DELETE' + 'route match configure', ) - def test_routes_match_method_negative(self): + def route_match_invalid(self, match): self.assertIn( - 'success', - self.route( - { - "match": {"method": "!GET"}, - "action": {"pass": "applications/empty"}, - } - ), - 'method negative configure', - ) - - self.assertEqual(self.get()['status'], 404, 'method negative GET') - self.assertEqual(self.post()['status'], 200, 'method negative POST') - - def test_routes_match_method_negative_many(self): - self.assertIn( - 'success', + 'error', self.route( - { - "match": {"method": ["!GET", "!POST"]}, - "action": {"pass": "applications/empty"}, - } + {"match": match, "action": {"pass": "applications/empty"}} ), - 'method negative many configure', + 'route match configure invalid', ) - self.assertEqual(self.get()['status'], 404, 'method negative many GET') + def host(self, host, status): self.assertEqual( - self.post()['status'], 404, 'method negative many POST' + self.get(headers={'Host': host, 'Connection': 'close'})[ + 'status' + ], + status, + 'match host', ) + + def cookie(self, cookie, status): self.assertEqual( - self.delete()['status'], 200, 'method negative many DELETE' + self.get( + headers={ + 'Host': 'localhost', + 'Cookie': cookie, + 'Connection': 'close', + }, + )['status'], + status, + 'match cookie', ) - def test_routes_match_method_wildcard_left(self): - self.assertIn( - 'success', - self.route( - { - "match": {"method": "*ET"}, - "action": {"pass": "applications/empty"}, - } - ), - 'method wildcard left configure', - ) + def test_routes_match_method_positive(self): + self.assertEqual(self.get()['status'], 200, 'GET') + self.assertEqual(self.post()['status'], 404, 'POST') - self.assertEqual(self.get()['status'], 200, 'method wildcard left GET') - self.assertEqual( - self.post()['status'], 404, 'method wildcard left POST' - ) + def test_routes_match_method_positive_many(self): + self.route_match({"method": ["GET", "POST"]}) - def test_routes_match_method_wildcard_right(self): - self.assertIn( - 'success', - self.route( - { - "match": {"method": "GE*"}, - "action": {"pass": "applications/empty"}, - } - ), - 'method wildcard right configure', - ) + self.assertEqual(self.get()['status'], 200, 'GET') + self.assertEqual(self.post()['status'], 200, 'POST') + self.assertEqual(self.delete()['status'], 404, 'DELETE') - self.assertEqual( - self.get()['status'], 200, 'method wildcard right GET' - ) - self.assertEqual( - self.post()['status'], 404, 'method wildcard right POST' - ) + def test_routes_match_method_negative(self): + self.route_match({"method": "!GET"}) - def test_routes_match_method_wildcard_left_right(self): - self.assertIn( - 'success', - self.route( - { - "match": {"method": "*GET*"}, - "action": {"pass": "applications/empty"}, - } - ), - 'method wildcard left right configure', - ) + self.assertEqual(self.get()['status'], 404, 'GET') + self.assertEqual(self.post()['status'], 200, 'POST') - self.assertEqual( - self.get()['status'], 200, 'method wildcard right GET' - ) - self.assertEqual( - self.post()['status'], 404, 'method wildcard right POST' - ) + def test_routes_match_method_negative_many(self): + self.route_match({"method": ["!GET", "!POST"]}) - def test_routes_match_method_wildcard(self): - self.assertIn( - 'success', - self.route( - { - "match": {"method": "*"}, - "action": {"pass": "applications/empty"}, - } - ), - 'method wildcard configure', - ) + self.assertEqual(self.get()['status'], 404, 'GET') + self.assertEqual(self.post()['status'], 404, 'POST') + self.assertEqual(self.delete()['status'], 200, 'DELETE') - self.assertEqual(self.get()['status'], 200, 'method wildcard') + def test_routes_match_method_wildcard_left(self): + self.route_match({"method": "*ET"}) - def test_routes_match_invalid(self): - self.assertIn( - 'error', - self.route( - { - "match": {"method": "**"}, - "action": {"pass": "applications/empty"}, - } - ), - 'wildcard invalid', - ) + self.assertEqual(self.get()['status'], 200, 'GET') + self.assertEqual(self.post()['status'], 404, 'POST') - self.assertIn( - 'error', - self.route( - { - "match": {"method": "blah**"}, - "action": {"pass": "applications/empty"}, - } - ), - 'wildcard invalid 2', - ) + def test_routes_match_method_wildcard_right(self): + self.route_match({"method": "GE*"}) - self.assertIn( - 'error', - self.route( - { - "match": {"host": "*blah*blah"}, - "action": {"pass": "applications/empty"}, - } - ), - 'wildcard invalid 3', - ) + self.assertEqual(self.get()['status'], 200, 'GET') + self.assertEqual(self.post()['status'], 404, 'POST') - self.assertIn( - 'error', - self.route( - { - "match": {"host": "blah*blah*blah"}, - "action": {"pass": "applications/empty"}, - } - ), - 'wildcard invalid 4', - ) + def test_routes_match_method_wildcard_left_right(self): + self.route_match({"method": "*GET*"}) - self.assertIn( - 'error', - self.route( - { - "match": {"host": "blah*blah*"}, - "action": {"pass": "applications/empty"}, - } - ), - 'wildcard invalid 5', - ) + self.assertEqual(self.get()['status'], 200, 'GET') + self.assertEqual(self.post()['status'], 404, 'POST') - def test_routes_match_wildcard_middle(self): - self.assertIn( - 'success', - self.route( - { - "match": {"host": "ex*le"}, - "action": {"pass": "applications/empty"}, - } - ), - 'host wildcard middle configure', - ) + def test_routes_match_method_wildcard(self): + self.route_match({"method": "*"}) - self.assertEqual( - self.get(headers={'Host': 'example', 'Connection': 'close'})[ - 'status' - ], - 200, - 'host wildcard middle', - ) + self.assertEqual(self.get()['status'], 200, 'GET') - self.assertEqual( - self.get(headers={'Host': 'www.example', 'Connection': 'close'})[ - 'status' - ], - 404, - 'host wildcard middle 2', - ) + def test_routes_match_invalid(self): + self.route_match_invalid({"method": "**"}) + self.route_match_invalid({"method": "blah**"}) + self.route_match_invalid({"host": "*blah*blah"}) + self.route_match_invalid({"host": "blah*blah*blah"}) + self.route_match_invalid({"host": "blah*blah*"}) - self.assertEqual( - self.get(headers={'Host': 'example.com', 'Connection': 'close'})[ - 'status' - ], - 404, - 'host wildcard middle 3', - ) + def test_routes_match_wildcard_middle(self): + self.route_match({"host": "ex*le"}) - self.assertEqual( - self.get(headers={'Host': 'exampl', 'Connection': 'close'})[ - 'status' - ], - 404, - 'host wildcard middle 4', - ) + self.host('example', 200) + self.host('www.example', 404) + self.host('example.com', 404) + self.host('exampl', 404) def test_routes_match_method_case_insensitive(self): - self.assertIn( - 'success', - self.route( - { - "match": {"method": "get"}, - "action": {"pass": "applications/empty"}, - } - ), - 'method case insensitive configure', - ) + self.route_match({"method": "get"}) - self.assertEqual(self.get()['status'], 200, 'method case insensitive') + self.assertEqual(self.get()['status'], 200, 'GET') def test_routes_match_wildcard_left_case_insensitive(self): - self.assertIn( - 'success', - self.route( - { - "match": {"method": "*et"}, - "action": {"pass": "applications/empty"}, - } - ), - 'match wildcard case insensitive configure', - ) + self.route_match({"method": "*get"}) + self.assertEqual(self.get()['status'], 200, 'GET') - self.assertEqual( - self.get()['status'], 200, 'match wildcard case insensitive' - ) + self.route_match({"method": "*et"}) + self.assertEqual(self.get()['status'], 200, 'GET') def test_routes_match_wildcard_middle_case_insensitive(self): - self.assertIn( - 'success', - self.route( - { - "match": {"method": "g*t"}, - "action": {"pass": "applications/empty"}, - } - ), - 'match wildcard case insensitive configure', - ) + self.route_match({"method": "g*t"}) - self.assertEqual( - self.get()['status'], 200, 'match wildcard case insensitive' - ) + self.assertEqual(self.get()['status'], 200, 'GET') def test_routes_match_wildcard_right_case_insensitive(self): - self.assertIn( - 'success', - self.route( - { - "match": {"method": "get*"}, - "action": {"pass": "applications/empty"}, - } - ), - 'match wildcard case insensitive configure', - ) + self.route_match({"method": "get*"}) + self.assertEqual(self.get()['status'], 200, 'GET') - self.assertEqual( - self.get()['status'], 200, 'match wildcard case insensitive' - ) + self.route_match({"method": "ge*"}) + self.assertEqual(self.get()['status'], 200, 'GET') def test_routes_match_wildcard_substring_case_insensitive(self): - self.assertIn( - 'success', - self.route( - { - "match": {"method": "*et*"}, - "action": {"pass": "applications/empty"}, - } - ), - 'match wildcard substring case insensitive configure', - ) + self.route_match({"method": "*et*"}) - self.assertEqual( - self.get()['status'], - 200, - 'match wildcard substring case insensitive', - ) + self.assertEqual(self.get()['status'], 200, 'GET') def test_routes_match_wildcard_left_case_sensitive(self): - self.assertIn( - 'success', - self.route( - { - "match": {"uri": "*blah"}, - "action": {"pass": "applications/empty"}, - } - ), - 'match wildcard left case sensitive configure', - ) + self.route_match({"uri": "*blah"}) - self.assertEqual( - self.get(url='/blah')['status'], - 200, - 'match wildcard left case sensitive /blah', - ) - - self.assertEqual( - self.get(url='/BLAH')['status'], - 404, - 'match wildcard left case sensitive /BLAH', - ) + self.assertEqual(self.get(url='/blah')['status'], 200, '/blah') + self.assertEqual(self.get(url='/BLAH')['status'], 404, '/BLAH') def test_routes_match_wildcard_middle_case_sensitive(self): - self.assertIn( - 'success', - self.route( - { - "match": {"uri": "/b*h"}, - "action": {"pass": "applications/empty"}, - } - ), - 'match wildcard middle case sensitive configure', - ) + self.route_match({"uri": "/b*h"}) - self.assertEqual( - self.get(url='/blah')['status'], - 200, - 'match wildcard middle case sensitive /blah', - ) - - self.assertEqual( - self.get(url='/BLAH')['status'], - 404, - 'match wildcard middle case sensitive /BLAH', - ) + self.assertEqual(self.get(url='/blah')['status'], 200, '/blah') + self.assertEqual(self.get(url='/BLAH')['status'], 404, '/BLAH') def test_routes_match_wildcard_right_case_sensitive(self): - self.assertIn( - 'success', - self.route( - { - "match": {"uri": "/bla*"}, - "action": {"pass": "applications/empty"}, - } - ), - 'match wildcard right case sensitive configure', - ) - - self.assertEqual( - self.get(url='/blah')['status'], - 200, - 'match wildcard right case sensitive /blah', - ) + self.route_match({"uri": "/bla*"}) - self.assertEqual( - self.get(url='/BLAH')['status'], - 404, - 'match wildcard right case sensitive /BLAH', - ) + self.assertEqual(self.get(url='/blah')['status'], 200, '/blah') + self.assertEqual(self.get(url='/BLAH')['status'], 404, '/BLAH') def test_routes_match_wildcard_substring_case_sensitive(self): - self.assertIn( - 'success', - self.route( - { - "match": {"uri": "*bla*"}, - "action": {"pass": "applications/empty"}, - } - ), - 'match wildcard substring case sensitive configure', - ) - - self.assertEqual( - self.get(url='/blah')['status'], - 200, - 'match wildcard substring case sensitive /blah', - ) + self.route_match({"uri": "*bla*"}) - self.assertEqual( - self.get(url='/BLAH')['status'], - 404, - 'match wildcard substring case sensitive /BLAH', - ) + self.assertEqual(self.get(url='/blah')['status'], 200, '/blah') + self.assertEqual(self.get(url='/BLAH')['status'], 404, '/BLAH') def test_routes_absent(self): self.conf( @@ -616,65 +367,18 @@ class TestRouting(TestApplicationProto): self.assertEqual(self.get()['status'], 200, 'routes two') def test_routes_match_host_positive(self): - self.assertIn( - 'success', - self.route( - { - "match": {"host": "localhost"}, - "action": {"pass": "applications/empty"}, - } - ), - 'match host positive configure', - ) - - self.assertEqual( - self.get()['status'], 200, 'match host positive localhost' - ) - - self.assertEqual( - self.get(headers={'Host': 'localhost.', 'Connection': 'close'})[ - 'status' - ], - 200, - 'match host positive trailing dot', - ) - - self.assertEqual( - self.get(headers={'Host': 'www.localhost', 'Connection': 'close'})[ - 'status' - ], - 404, - 'match host positive www.localhost', - ) - - self.assertEqual( - self.get(headers={'Host': 'localhost1', 'Connection': 'close'})[ - 'status' - ], - 404, - 'match host positive localhost1', - ) + self.route_match({"host": "localhost"}) - self.assertEqual( - self.get(headers={'Host': 'example.com', 'Connection': 'close'})[ - 'status' - ], - 404, - 'match host positive example.com', - ) + self.assertEqual(self.get()['status'], 200, 'localhost') + self.host('localhost.', 200) + self.host('localhost.', 200) + self.host('.localhost', 404) + self.host('www.localhost', 404) + self.host('localhost1', 404) @unittest.skip('not yet') def test_routes_match_host_absent(self): - self.assertIn( - 'success', - self.route( - { - "match": {"host": "localhost"}, - "action": {"pass": "applications/empty"}, - } - ), - 'match host absent configure', - ) + self.route_match({"host": "localhost"}) self.assertEqual( self.get(headers={'Connection': 'close'})['status'], @@ -683,212 +387,52 @@ class TestRouting(TestApplicationProto): ) def test_routes_match_host_ipv4(self): - self.assertIn( - 'success', - self.route( - { - "match": {"host": "127.0.0.1"}, - "action": {"pass": "applications/empty"}, - } - ), - 'match host ipv4 configure', - ) + self.route_match({"host": "127.0.0.1"}) - self.assertEqual( - self.get(headers={'Host': '127.0.0.1', 'Connection': 'close'})[ - 'status' - ], - 200, - 'match host ipv4', - ) + self.host('127.0.0.1', 200) + self.host('127.0.0.1:7080', 200) def test_routes_match_host_ipv6(self): - self.assertIn( - 'success', - self.route( - { - "match": {"host": "[::1]"}, - "action": {"pass": "applications/empty"}, - } - ), - 'match host ipv6 configure', - ) + self.route_match({"host": "[::1]"}) - self.assertEqual( - self.get(headers={'Host': '[::1]', 'Connection': 'close'})[ - 'status' - ], - 200, - 'match host ipv6', - ) - - self.assertEqual( - self.get(headers={'Host': '[::1]:7080', 'Connection': 'close'})[ - 'status' - ], - 200, - 'match host ipv6 port', - ) + self.host('[::1]', 200) + self.host('[::1]:7080', 200) def test_routes_match_host_positive_many(self): - self.assertIn( - 'success', - self.route( - { - "match": {"host": ["localhost", "example.com"]}, - "action": {"pass": "applications/empty"}, - } - ), - 'match host positive many configure', - ) - - self.assertEqual( - self.get()['status'], 200, 'match host positive many localhost' - ) + self.route_match({"host": ["localhost", "example.com"]}) - self.assertEqual( - self.get(headers={'Host': 'example.com', 'Connection': 'close'})[ - 'status' - ], - 200, - 'match host positive many example.com', - ) + self.assertEqual(self.get()['status'], 200, 'localhost') + self.host('example.com', 200) def test_routes_match_host_positive_and_negative(self): - self.assertIn( - 'success', - self.route( - { - "match": {"host": ["*example.com", "!www.example.com"]}, - "action": {"pass": "applications/empty"}, - } - ), - 'match host positive and negative configure', - ) + self.route_match({"host": ["*example.com", "!www.example.com"]}) - self.assertEqual( - self.get()['status'], - 404, - 'match host positive and negative localhost', - ) - - self.assertEqual( - self.get(headers={'Host': 'example.com', 'Connection': 'close'})[ - 'status' - ], - 200, - 'match host positive and negative example.com', - ) - - self.assertEqual( - self.get( - headers={'Host': 'www.example.com', 'Connection': 'close'} - )['status'], - 404, - 'match host positive and negative www.example.com', - ) - - self.assertEqual( - self.get( - headers={'Host': '!www.example.com', 'Connection': 'close'} - )['status'], - 200, - 'match host positive and negative !www.example.com', - ) + self.assertEqual(self.get()['status'], 404, 'localhost') + self.host('example.com', 200) + self.host('www.example.com', 404) + self.host('!www.example.com', 200) def test_routes_match_host_positive_and_negative_wildcard(self): - self.assertIn( - 'success', - self.route( - { - "match": {"host": ["*example*", "!www.example*"]}, - "action": {"pass": "applications/empty"}, - } - ), - 'match host positive and negative wildcard configure', - ) + self.route_match({"host": ["*example*", "!www.example*"]}) - self.assertEqual( - self.get(headers={'Host': 'example.com', 'Connection': 'close'})[ - 'status' - ], - 200, - 'match host positive and negative wildcard example.com', - ) - - self.assertEqual( - self.get( - headers={'Host': 'www.example.com', 'Connection': 'close'} - )['status'], - 404, - 'match host positive and negative wildcard www.example.com', - ) + self.host('example.com', 200) + self.host('www.example.com', 404) def test_routes_match_host_case_insensitive(self): - self.assertIn( - 'success', - self.route( - { - "match": {"host": "Example.com"}, - "action": {"pass": "applications/empty"}, - } - ), - 'host case insensitive configure', - ) + self.route_match({"host": "Example.com"}) - self.assertEqual( - self.get(headers={'Host': 'example.com', 'Connection': 'close'})[ - 'status' - ], - 200, - 'host case insensitive example.com', - ) - - self.assertEqual( - self.get(headers={'Host': 'EXAMPLE.COM', 'Connection': 'close'})[ - 'status' - ], - 200, - 'host case insensitive EXAMPLE.COM', - ) + self.host('example.com', 200) + self.host('EXAMPLE.COM', 200) def test_routes_match_host_port(self): - self.assertIn( - 'success', - self.route( - { - "match": {"host": "example.com"}, - "action": {"pass": "applications/empty"}, - } - ), - 'match host port configure', - ) + self.route_match({"host": "example.com"}) - self.assertEqual( - self.get( - headers={'Host': 'example.com:7080', 'Connection': 'close'} - )['status'], - 200, - 'match host port', - ) + self.host('example.com:7080', 200) def test_routes_match_host_empty(self): - self.assertIn( - 'success', - self.route( - { - "match": {"host": ""}, - "action": {"pass": "applications/empty"}, - } - ), - 'match host empty configure', - ) + self.route_match({"host": ""}) - self.assertEqual( - self.get(headers={'Host': '', 'Connection': 'close'})['status'], - 200, - 'match host empty', - ) + self.host('', 200) self.assertEqual( self.get(http_10=True, headers={})['status'], 200, @@ -897,160 +441,80 @@ class TestRouting(TestApplicationProto): self.assertEqual(self.get()['status'], 404, 'match host empty 3') def test_routes_match_uri_positive(self): - self.assertIn( - 'success', - self.route( - { - "match": {"uri": ["/blah", "/slash/"]}, - "action": {"pass": "applications/empty"}, - } - ), - 'match uri positive configure', - ) + self.route_match({"uri": ["/blah", "/slash/"]}) - self.assertEqual(self.get()['status'], 404, 'match uri positive') - self.assertEqual( - self.get(url='/blah')['status'], 200, 'match uri positive blah' - ) - self.assertEqual( - self.get(url='/blah#foo')['status'], - 200, - 'match uri positive #foo', - ) - self.assertEqual( - self.get(url='/blah?var')['status'], 200, 'match uri args' - ) - self.assertEqual( - self.get(url='//blah')['status'], 200, 'match uri adjacent slashes' - ) - self.assertEqual( - self.get(url='/slash/foo/../')['status'], - 200, - 'match uri relative path', - ) + self.assertEqual(self.get()['status'], 404, '/') + self.assertEqual(self.get(url='/blah')['status'], 200, '/blah') + self.assertEqual(self.get(url='/blah#foo')['status'], 200, '/blah#foo') + self.assertEqual(self.get(url='/blah?var')['status'], 200, '/blah?var') + self.assertEqual(self.get(url='//blah')['status'], 200, '//blah') self.assertEqual( - self.get(url='/slash/./')['status'], - 200, - 'match uri relative path 2', - ) - self.assertEqual( - self.get(url='/slash//.//')['status'], - 200, - 'match uri adjacent slashes 2', - ) - self.assertEqual( - self.get(url='/%')['status'], 400, 'match uri percent' + self.get(url='/slash/foo/../')['status'], 200, 'relative' ) + self.assertEqual(self.get(url='/slash/./')['status'], 200, '/slash/./') self.assertEqual( - self.get(url='/%1')['status'], 400, 'match uri percent digit' + self.get(url='/slash//.//')['status'], 200, 'adjacent slashes' ) + self.assertEqual(self.get(url='/%')['status'], 400, 'percent') + self.assertEqual(self.get(url='/%1')['status'], 400, 'percent digit') + self.assertEqual(self.get(url='/%A')['status'], 400, 'percent letter') self.assertEqual( - self.get(url='/%A')['status'], 400, 'match uri percent letter' + self.get(url='/slash/.?args')['status'], 200, 'dot args' ) self.assertEqual( - self.get(url='/slash/.?args')['status'], 200, 'match uri dot args' - ) - self.assertEqual( - self.get(url='/slash/.#frag')['status'], 200, 'match uri dot frag' + self.get(url='/slash/.#frag')['status'], 200, 'dot frag' ) self.assertEqual( self.get(url='/slash/foo/..?args')['status'], 200, - 'match uri dot dot args', + 'dot dot args', ) self.assertEqual( self.get(url='/slash/foo/..#frag')['status'], 200, - 'match uri dot dot frag', + 'dot dot frag', ) self.assertEqual( - self.get(url='/slash/.')['status'], 200, 'match uri trailing dot' + self.get(url='/slash/.')['status'], 200, 'trailing dot' ) self.assertEqual( self.get(url='/slash/foo/..')['status'], 200, - 'match uri trailing dot dot', + 'trailing dot dot', ) def test_routes_match_uri_case_sensitive(self): - self.assertIn( - 'success', - self.route( - { - "match": {"uri": "/BLAH"}, - "action": {"pass": "applications/empty"}, - } - ), - 'match uri case sensitive configure', - ) + self.route_match({"uri": "/BLAH"}) - self.assertEqual( - self.get(url='/blah')['status'], - 404, - 'match uri case sensitive blah', - ) - self.assertEqual( - self.get(url='/BlaH')['status'], - 404, - 'match uri case sensitive BlaH', - ) - self.assertEqual( - self.get(url='/BLAH')['status'], - 200, - 'match uri case sensitive BLAH', - ) + self.assertEqual(self.get(url='/blah')['status'], 404, '/blah') + self.assertEqual(self.get(url='/BlaH')['status'], 404, '/BlaH') + self.assertEqual(self.get(url='/BLAH')['status'], 200, '/BLAH') def test_routes_match_uri_normalize(self): - self.assertIn( - 'success', - self.route( - { - "match": {"uri": "/blah"}, - "action": {"pass": "applications/empty"}, - } - ), - 'match uri normalize configure', - ) + self.route_match({"uri": "/blah"}) self.assertEqual( - self.get(url='/%62%6c%61%68')['status'], 200, 'match uri normalize' + self.get(url='/%62%6c%61%68')['status'], 200, 'normalize' ) def test_routes_match_empty_array(self): - self.assertIn( - 'success', - self.route( - { - "match": {"uri": []}, - "action": {"pass": "applications/empty"}, - } - ), - 'match empty array configure', - ) + self.route_match({"uri": []}) - self.assertEqual( - self.get(url='/blah')['status'], - 200, - 'match empty array', - ) + self.assertEqual(self.get(url='/blah')['status'], 200, 'empty array') def test_routes_reconfigure(self): - self.assertIn('success', self.conf([], 'routes'), 'routes redefine') - self.assertEqual(self.get()['status'], 404, 'routes redefine request') + self.assertIn('success', self.conf([], 'routes'), 'redefine') + self.assertEqual(self.get()['status'], 404, 'redefine request') self.assertIn( 'success', self.conf([{"action": {"pass": "applications/empty"}}], 'routes'), - 'routes redefine 2', - ) - self.assertEqual( - self.get()['status'], 200, 'routes redefine request 2' + 'redefine 2', ) + self.assertEqual(self.get()['status'], 200, 'redefine request 2') - self.assertIn('success', self.conf([], 'routes'), 'routes redefine 3') - self.assertEqual( - self.get()['status'], 404, 'routes redefine request 3' - ) + self.assertIn('success', self.conf([], 'routes'), 'redefine 3') + self.assertEqual(self.get()['status'], 404, 'redefine request 3') self.assertIn( 'success', @@ -1072,63 +536,46 @@ class TestRouting(TestApplicationProto): }, } ), - 'routes redefine 4', - ) - self.assertEqual( - self.get()['status'], 200, 'routes redefine request 4' + 'redefine 4', ) + self.assertEqual(self.get()['status'], 200, 'redefine request 4') self.assertIn( - 'success', self.conf_delete('routes/main/0'), 'routes redefine 5' - ) - self.assertEqual( - self.get()['status'], 404, 'routes redefine request 5' + 'success', self.conf_delete('routes/main/0'), 'redefine 5' ) + self.assertEqual(self.get()['status'], 404, 'redefine request 5') self.assertIn( 'success', self.conf_post( {"action": {"pass": "applications/empty"}}, 'routes/main' ), - 'routes redefine 6', - ) - self.assertEqual( - self.get()['status'], 200, 'routes redefine request 6' + 'redefine 6', ) + self.assertEqual(self.get()['status'], 200, 'redefine request 6') self.assertIn( 'error', self.conf( {"action": {"pass": "applications/empty"}}, 'routes/main/2' ), - 'routes redefine 7', + 'redefine 7', ) self.assertIn( 'success', self.conf( {"action": {"pass": "applications/empty"}}, 'routes/main/1' ), - 'routes redefine 8', + 'redefine 8', ) self.assertEqual( - len(self.conf_get('routes/main')), 2, 'routes redefine conf 8' - ) - self.assertEqual( - self.get()['status'], 200, 'routes redefine request 8' + len(self.conf_get('routes/main')), 2, 'redefine conf 8' ) + self.assertEqual(self.get()['status'], 200, 'redefine request 8') def test_routes_edit(self): - self.assertIn( - 'success', - self.route( - { - "match": {"method": "GET"}, - "action": {"pass": "applications/empty"}, - } - ), - 'routes edit configure', - ) + self.route_match({"method": "GET"}) self.assertEqual(self.get()['status'], 200, 'routes edit GET') self.assertEqual(self.post()['status'], 404, 'routes edit POST') @@ -1260,16 +707,7 @@ class TestRouting(TestApplicationProto): def test_match_edit(self): self.skip_alerts.append(r'failed to apply new conf') - self.assertIn( - 'success', - self.route( - { - "match": {"method": ["GET", "POST"]}, - "action": {"pass": "applications/empty"}, - } - ), - 'match edit configure', - ) + self.route_match({"method": ["GET", "POST"]}) self.assertEqual(self.get()['status'], 200, 'match edit GET') self.assertEqual(self.post()['status'], 200, 'match edit POST') @@ -1390,20 +828,7 @@ class TestRouting(TestApplicationProto): self.assertEqual(self.get()['status'], 200, 'match edit GET 8') def test_routes_match_rules(self): - self.assertIn( - 'success', - self.route( - { - "match": { - "method": "GET", - "host": "localhost", - "uri": "/", - }, - "action": {"pass": "applications/empty"}, - } - ), - 'routes match rules configure', - ) + self.route_match({"method": "GET", "host": "localhost", "uri": "/"}) self.assertEqual(self.get()['status'], 200, 'routes match rules') @@ -1417,75 +842,18 @@ class TestRouting(TestApplicationProto): self.assertEqual(self.get()['status'], 500, 'routes loop') def test_routes_match_headers(self): - self.assertIn( - 'success', - self.route( - { - "match": {"headers": {"host": "localhost"}}, - "action": {"pass": "applications/empty"}, - } - ), - 'match headers configure', - ) + self.route_match({"headers": {"host": "localhost"}}) self.assertEqual(self.get()['status'], 200, 'match headers') - self.assertEqual( - self.get( - headers={ - "Host": "Localhost", - "Connection": "close", - } - )['status'], - 200, - 'match headers case insensitive', - ) - self.assertEqual( - self.get( - headers={ - "Host": "localhost.com", - "Connection": "close", - } - )['status'], - 404, - 'match headers exact', - ) - self.assertEqual( - self.get( - headers={ - "Host": "llocalhost", - "Connection": "close", - } - )['status'], - 404, - 'match headers exact 2', - ) - self.assertEqual( - self.get( - headers={ - "Host": "host", - "Connection": "close", - } - )['status'], - 404, - 'match headers exact 3', - ) + self.host('Localhost', 200) + self.host('localhost.com', 404) + self.host('llocalhost', 404) + self.host('host', 404) def test_routes_match_headers_multiple(self): - self.assertIn( - 'success', - self.route( - { - "match": { - "headers": {"host": "localhost", "x-blah": "test"} - }, - "action": {"pass": "applications/empty"}, - } - ), - 'match headers multiple configure', - ) + self.route_match({"headers": {"host": "localhost", "x-blah": "test"}}) self.assertEqual(self.get()['status'], 404, 'match headers multiple') - self.assertEqual( self.get( headers={ @@ -1511,16 +879,7 @@ class TestRouting(TestApplicationProto): ) def test_routes_match_headers_multiple_values(self): - self.assertIn( - 'success', - self.route( - { - "match": {"headers": {"x-blah": "test"}}, - "action": {"pass": "applications/empty"}, - } - ), - 'match headers multiple values configure', - ) + self.route_match({"headers": {"x-blah": "test"}}) self.assertEqual( self.get( @@ -1557,21 +916,11 @@ class TestRouting(TestApplicationProto): ) def test_routes_match_headers_multiple_rules(self): - self.assertIn( - 'success', - self.route( - { - "match": {"headers": {"x-blah": ["test", "blah"]}}, - "action": {"pass": "applications/empty"}, - } - ), - 'match headers multiple rules configure', - ) + self.route_match({"headers": {"x-blah": ["test", "blah"]}}) self.assertEqual( self.get()['status'], 404, 'match headers multiple rules' ) - self.assertEqual( self.get( headers={ @@ -1583,7 +932,6 @@ class TestRouting(TestApplicationProto): 200, 'match headers multiple rules 2', ) - self.assertEqual( self.get( headers={ @@ -1595,7 +943,6 @@ class TestRouting(TestApplicationProto): 200, 'match headers multiple rules 3', ) - self.assertEqual( self.get( headers={ @@ -1621,16 +968,7 @@ class TestRouting(TestApplicationProto): ) def test_routes_match_headers_case_insensitive(self): - self.assertIn( - 'success', - self.route( - { - "match": {"headers": {"X-BLAH": "TEST"}}, - "action": {"pass": "applications/empty"}, - } - ), - 'match headers case insensitive configure', - ) + self.route_match({"headers": {"X-BLAH": "TEST"}}) self.assertEqual( self.get( @@ -1645,104 +983,27 @@ class TestRouting(TestApplicationProto): ) def test_routes_match_headers_invalid(self): - self.assertIn( - 'error', - self.route( - { - "match": {"headers": ["blah"]}, - "action": {"pass": "applications/empty"}, - } - ), - 'match headers invalid', - ) - - self.assertIn( - 'error', - self.route( - { - "match": {"headers": {"foo": ["bar", {}]}}, - "action": {"pass": "applications/empty"}, - } - ), - 'match headers invalid 2', - ) + self.route_match_invalid({"headers": ["blah"]}) + self.route_match_invalid({"headers": {"foo": ["bar", {}]}}) + self.route_match_invalid({"headers": {"": "blah"}}) def test_routes_match_headers_empty_rule(self): - self.assertIn( - 'success', - self.route( - { - "match": {"headers": {"host": ""}}, - "action": {"pass": "applications/empty"}, - } - ), - 'match headers empty rule configure', - ) - - self.assertEqual(self.get()['status'], 404, 'match headers empty rule') - - self.assertEqual( - self.get(headers={"Host": "", "Connection": "close"})['status'], - 200, - 'match headers empty rule 2', - ) + self.route_match({"headers": {"host": ""}}) - def test_routes_match_headers_rule_field_empty(self): - self.assertIn( - 'error', - self.route( - { - "match": {"headers": {"": "blah"}}, - "action": {"pass": "applications/empty"}, - } - ), - 'match headers rule field empty configure', - ) + self.assertEqual(self.get()['status'], 404, 'localhost') + self.host('', 200) def test_routes_match_headers_empty(self): - self.assertIn( - 'success', - self.route( - { - "match": {"headers": {}}, - "action": {"pass": "applications/empty"}, - } - ), - 'match headers empty configure', - ) - - self.assertEqual(self.get()['status'], 200, 'match headers empty') + self.route_match({"headers": {}}) + self.assertEqual(self.get()['status'], 200, 'empty') - self.assertIn( - 'success', - self.route( - { - "match": {"headers": []}, - "action": {"pass": "applications/empty"}, - } - ), - 'match headers array empty configure 2', - ) - - self.assertEqual( - self.get()['status'], 200, 'match headers array empty 2' - ) + self.route_match({"headers": []}) + self.assertEqual(self.get()['status'], 200, 'empty 2') def test_routes_match_headers_rule_array_empty(self): - self.assertIn( - 'success', - self.route( - { - "match": {"headers": {"blah": []}}, - "action": {"pass": "applications/empty"}, - } - ), - 'match headers rule array empty configure', - ) + self.route_match({"headers": {"blah": []}}) - self.assertEqual( - self.get()['status'], 404, 'match headers rule array empty' - ) + self.assertEqual(self.get()['status'], 404, 'array empty') self.assertEqual( self.get( headers={ @@ -1754,22 +1015,15 @@ class TestRouting(TestApplicationProto): ) def test_routes_match_headers_array(self): - self.assertIn( - 'success', - self.route( - { - "match": { - "headers": [ - {"x-header1": "foo*"}, - {"x-header2": "bar"}, - {"x-header3": ["foo", "bar"]}, - {"x-header1": "bar", "x-header4": "foo"}, - ] - }, - "action": {"pass": "applications/empty"}, - } - ), - 'match headers array configure', + self.route_match( + { + "headers": [ + {"x-header1": "foo*"}, + {"x-header2": "bar"}, + {"x-header3": ["foo", "bar"]}, + {"x-header1": "bar", "x-header4": "foo"}, + ] + } ) self.assertEqual(self.get()['status'], 404, 'match headers array') @@ -1860,352 +1114,128 @@ class TestRouting(TestApplicationProto): ) def test_routes_match_arguments(self): - self.assertIn( - 'success', - self.route( - { - "match": {"arguments": {"foo": "bar"}}, - "action": {"pass": "applications/empty"}, - } - ), - 'match arguments configure', - ) + self.route_match({"arguments": {"foo": "bar"}}) - self.assertEqual(self.get()['status'], 404, 'match arguments') - self.assertEqual( - self.get(url='/?foo=bar')['status'], 200, 'match arguments 2' - ) - - self.assertEqual( - self.get(url='/?Foo=bar')['status'], - 404, - 'match arguments case sensitive', - ) - self.assertEqual( - self.get(url='/?foo=Bar')['status'], - 404, - 'match arguments case sensitive 2', - ) - self.assertEqual( - self.get(url='/?foo=bar1')['status'], - 404, - 'match arguments exact', - ) - self.assertEqual( - self.get(url='/?1foo=bar')['status'], - 404, - 'match arguments exact 2', - ) + self.assertEqual(self.get()['status'], 404, 'args') + self.assertEqual(self.get(url='/?foo=bar')['status'], 200, 'args 2') + self.assertEqual(self.get(url='/?foo=bar1')['status'], 404, 'args 3') + self.assertEqual(self.get(url='/?1foo=bar')['status'], 404, 'args 4') + self.assertEqual(self.get(url='/?Foo=bar')['status'], 404, 'case') + self.assertEqual(self.get(url='/?foo=Bar')['status'], 404, 'case 2') def test_routes_match_arguments_empty(self): - self.assertIn( - 'success', - self.route( - { - "match": {"arguments": {}}, - "action": {"pass": "applications/empty"}, - } - ), - 'match arguments empty configure', - ) + self.route_match({"arguments": {}}) + self.assertEqual(self.get()['status'], 200, 'arguments empty') - self.assertEqual(self.get()['status'], 200, 'match arguments empty') - - self.assertIn( - 'success', - self.route( - { - "match": {"arguments": []}, - "action": {"pass": "applications/empty"}, - } - ), - 'match arguments empty configure 2', - ) - - self.assertEqual(self.get()['status'], 200, 'match arguments empty 2') + self.route_match({"arguments": []}) + self.assertEqual(self.get()['status'], 200, 'arguments empty 2') def test_routes_match_arguments_invalid(self): - self.assertIn( - 'error', - self.route( - { - "match": {"arguments": ["var"]}, - "action": {"pass": "applications/empty"}, - } - ), - 'match arguments invalid', - ) - - self.assertIn( - 'error', - self.route( - { - "match": {"arguments": [{"var1": {}}]}, - "action": {"pass": "applications/empty"}, - } - ), - 'match arguments invalid 2', - ) - - self.assertIn( - 'error', - self.route( - { - "match": {"arguments": {"": "bar"}}, - "action": {"pass": "applications/empty"}, - } - ), - 'match arguments invalid 3', - ) + self.route_match_invalid({"arguments": ["var"]}) + self.route_match_invalid({"arguments": [{"var1": {}}]}) + self.route_match_invalid({"arguments": {"": "bar"}}) @unittest.skip('not yet') def test_routes_match_arguments_space(self): - self.assertIn( - 'success', - self.route( - { - "match": {"arguments": {"foo": "bar "}}, - "action": {"pass": "applications/empty"}, - } - ), - 'match arguments space configure', - ) + self.route_match({"arguments": {"foo": "bar "}}) - self.assertEqual( - self.get(url='/?foo=bar &')['status'], - 200, - 'match arguments space', - ) - self.assertEqual( - self.get(url='/?foo=bar+&')['status'], - 200, - 'match arguments space 2', - ) # FAIL - self.assertEqual( - self.get(url='/?foo=bar%20&')['status'], - 200, - 'match arguments space 3', - ) # FAIL + self.assertEqual(self.get(url='/?foo=bar &')['status'], 200, 'sp') + # FAIL + self.assertEqual(self.get(url='/?foo=bar+&')['status'], 200, 'sp 2') + # FAIL + self.assertEqual(self.get(url='/?foo=bar%20&')['status'], 200, 'sp 3') @unittest.skip('not yet') def test_routes_match_arguments_plus(self): - self.assertIn( - 'success', - self.route( - { - "match": {"arguments": [{"foo": "bar+"}]}, - "action": {"pass": "applications/empty"}, - } - ), - 'match arguments plus configure', - ) + self.route_match({"arguments": [{"foo": "bar+"}]}) + self.assertEqual(self.get(url='/?foo=bar+&')['status'], 200, 'plus') + # FAIL self.assertEqual( - self.get(url='/?foo=bar+&')['status'], - 200, - 'match arguments plus', + self.get(url='/?foo=bar%2B&')['status'], 200, 'plus 2' ) - self.assertEqual( - self.get(url='/?foo=bar%2B&')['status'], - 200, - 'match arguments plus 2', - ) # FAIL @unittest.skip('not yet') def test_routes_match_arguments_hex(self): - self.assertIn( - 'success', - self.route( - { - "match": {"arguments": [{"foo": "bar"}]}, - "action": {"pass": "applications/empty"}, - } - ), - 'match arguments hex configure', - ) + self.route_match({"arguments": [{"foo": "bar"}]}) self.assertEqual( - self.get(url='/?%66%6F%6f=%62%61%72&')['status'], - 200, - 'match arguments hex', - ) # FAIL + self.get(url='/?%66%6F%6f=%62%61%72&')['status'], 200, 'hex' + ) def test_routes_match_arguments_chars(self): - self.assertIn( - 'success', - self.route( - { - "match": {"arguments": {"foo": "-._()[],;"}}, - "action": {"pass": "applications/empty"}, - } - ), - 'match arguments chars configure', - ) + self.route_match({"arguments": {"foo": "-._()[],;"}}) - self.assertEqual( - self.get(url='/?foo=-._()[],;')['status'], - 200, - 'match arguments chars', - ) + self.assertEqual(self.get(url='/?foo=-._()[],;')['status'], 200, 'chs') def test_routes_match_arguments_complex(self): - self.assertIn( - 'success', - self.route( - { - "match": {"arguments": {"foo": ""}}, - "action": {"pass": "applications/empty"}, - } - ), - 'match arguments complex configure', - ) + self.route_match({"arguments": {"foo": ""}}) + self.assertEqual(self.get(url='/?foo')['status'], 200, 'complex') self.assertEqual( - self.get(url='/?foo')['status'], - 200, - 'match arguments complex', + self.get(url='/?blah=blah&foo=')['status'], 200, 'complex 2' ) self.assertEqual( - self.get(url='/?blah=blah&foo=')['status'], - 200, - 'match arguments complex 2', + self.get(url='/?&&&foo&&&')['status'], 200, 'complex 3' ) self.assertEqual( - self.get(url='/?&&&foo&&&')['status'], - 200, - 'match arguments complex 3', + self.get(url='/?foo&foo=bar&foo')['status'], 404, 'complex 4' ) self.assertEqual( - self.get(url='/?foo&foo=bar&foo')['status'], - 404, - 'match arguments complex 4', + self.get(url='/?foo=&foo')['status'], 200, 'complex 5' ) self.assertEqual( - self.get(url='/?foo=&foo')['status'], - 200, - 'match arguments complex 5', + self.get(url='/?&=&foo&==&')['status'], 200, 'complex 6' ) self.assertEqual( - self.get(url='/?&=&foo&==&')['status'], - 200, - 'match arguments complex 6', - ) - self.assertEqual( - self.get(url='/?&=&bar&==&')['status'], - 404, - 'match arguments complex 7', + self.get(url='/?&=&bar&==&')['status'], 404, 'complex 7' ) def test_routes_match_arguments_multiple(self): - self.assertIn( - 'success', - self.route( - { - "match": {"arguments": {"foo": "bar", "blah": "test"}}, - "action": {"pass": "applications/empty"}, - } - ), - 'match arguments multiple configure', - ) - - self.assertEqual(self.get()['status'], 404, 'match arguments multiple') + self.route_match({"arguments": {"foo": "bar", "blah": "test"}}) + self.assertEqual(self.get()['status'], 404, 'multiple') self.assertEqual( - self.get(url='/?foo=bar&blah=test')['status'], - 200, - 'match arguments multiple 2', + self.get(url='/?foo=bar&blah=test')['status'], 200, 'multiple 2' ) - self.assertEqual( - self.get(url='/?foo=bar&blah')['status'], - 404, - 'match arguments multiple 3', + self.get(url='/?foo=bar&blah')['status'], 404, 'multiple 3' ) def test_routes_match_arguments_multiple_rules(self): - self.assertIn( - 'success', - self.route( - { - "match": {"arguments": {"foo": ["bar", "blah"]}}, - "action": {"pass": "applications/empty"}, - } - ), - 'match arguments multiple rules configure', - ) - - self.assertEqual( - self.get()['status'], 404, 'match arguments multiple rules' - ) - - self.assertEqual( - self.get(url='/?foo=bar')['status'], - 200, - 'match arguments multiple rules 2', - ) - - self.assertEqual( - self.get(url='/?foo=blah')['status'], - 200, - 'match arguments multiple rules 3', - ) + self.route_match({"arguments": {"foo": ["bar", "blah"]}}) + self.assertEqual(self.get()['status'], 404, 'rules') + self.assertEqual(self.get(url='/?foo=bar')['status'], 200, 'rules 2') + self.assertEqual(self.get(url='/?foo=blah')['status'], 200, 'rules 3') self.assertEqual( self.get(url='/?foo=blah&foo=bar&foo=blah')['status'], 200, - 'match arguments multiple rules 4', + 'rules 4', ) - self.assertEqual( - self.get(url='/?foo=blah&foo=bar&foo=')['status'], - 404, - 'match arguments multiple rules 5', + self.get(url='/?foo=blah&foo=bar&foo=')['status'], 404, 'rules 5' ) def test_routes_match_arguments_array(self): - self.assertIn( - 'success', - self.route( - { - "match": { - "arguments": [ - {"var1": "val1*"}, - {"var2": "val2"}, - {"var3": ["foo", "bar"]}, - {"var1": "bar", "var4": "foo"}, - ] - }, - "action": {"pass": "applications/empty"}, - } - ), - 'match arguments array configure', + self.route_match( + { + "arguments": [ + {"var1": "val1*"}, + {"var2": "val2"}, + {"var3": ["foo", "bar"]}, + {"var1": "bar", "var4": "foo"}, + ] + } ) - self.assertEqual(self.get()['status'], 404, 'match arguments array') + self.assertEqual(self.get()['status'], 404, 'arr') + self.assertEqual(self.get(url='/?var1=val123')['status'], 200, 'arr 2') + self.assertEqual(self.get(url='/?var2=val2')['status'], 200, 'arr 3') + self.assertEqual(self.get(url='/?var3=bar')['status'], 200, 'arr 4') + self.assertEqual(self.get(url='/?var1=bar')['status'], 404, 'arr 5') self.assertEqual( - self.get(url='/?var1=val123')['status'], - 200, - 'match arguments array 2', - ) - self.assertEqual( - self.get(url='/?var2=val2')['status'], - 200, - 'match arguments array 3', - ) - self.assertEqual( - self.get(url='/?var3=bar')['status'], - 200, - 'match arguments array 4', - ) - self.assertEqual( - self.get(url='/?var1=bar')['status'], - 404, - 'match arguments array 5', - ) - self.assertEqual( - self.get(url='/?var1=bar&var4=foo')['status'], - 200, - 'match arguments array 6', + self.get(url='/?var1=bar&var4=foo')['status'], 200, 'arr 6' ) self.assertIn( @@ -2214,574 +1244,514 @@ class TestRouting(TestApplicationProto): 'match arguments array configure 2', ) - self.assertEqual( - self.get(url='/?var2=val2')['status'], - 404, - 'match arguments array 7', - ) - self.assertEqual( - self.get(url='/?var3=foo')['status'], - 200, - 'match arguments array 8', - ) + self.assertEqual(self.get(url='/?var2=val2')['status'], 404, 'arr 7') + self.assertEqual(self.get(url='/?var3=foo')['status'], 200, 'arr 8') def test_routes_match_cookies(self): - self.assertIn( - 'success', - self.route( - { - "match": {"cookies": {"foO": "bar"}}, - "action": {"pass": "applications/empty"}, - } - ), - 'match cookie configure', - ) + self.route_match({"cookies": {"foO": "bar"}}) + + self.assertEqual(self.get()['status'], 404, 'cookie') + self.cookie('foO=bar', 200) + self.cookie('foO=bar;1', 200) + self.cookie(['foO=bar', 'blah=blah'], 200) + self.cookie('foO=bar; blah=blah', 200) + self.cookie('Foo=bar', 404) + self.cookie('foO=Bar', 404) + self.cookie('foO=bar1', 404) + self.cookie('1foO=bar;', 404) - self.assertEqual(self.get()['status'], 404, 'match cookie') - self.assertEqual( - self.get( - headers={ - 'Host': 'localhost', - 'Cookie': 'foO=bar', - 'Connection': 'close', - }, - )['status'], - 200, - 'match cookies 2', - ) - self.assertEqual( - self.get( - headers={ - 'Host': 'localhost', - 'Cookie': ['foO=bar', 'blah=blah'], - 'Connection': 'close', - }, - )['status'], - 200, - 'match cookies 3', - ) - self.assertEqual( - self.get( - headers={ - 'Host': 'localhost', - 'Cookie': 'foO=bar; blah=blah', - 'Connection': 'close', - }, - )['status'], - 200, - 'match cookies 4', - ) + def test_routes_match_cookies_empty(self): + self.route_match({"cookies": {}}) + self.assertEqual(self.get()['status'], 200, 'cookies empty') - self.assertEqual( - self.get( - headers={ - 'Host': 'localhost', - 'Cookie': 'Foo=bar', - 'Connection': 'close', - }, - )['status'], - 404, - 'match cookies case sensitive', - ) - self.assertEqual( - self.get( - headers={ - 'Host': 'localhost', - 'Cookie': 'foO=Bar', - 'Connection': 'close', - }, - )['status'], - 404, - 'match cookies case sensitive 2', - ) - self.assertEqual( - self.get( - headers={ - 'Host': 'localhost', - 'Cookie': 'foO=bar1', - 'Connection': 'close', - }, - )['status'], - 404, - 'match cookies exact', - ) - self.assertEqual( - self.get( - headers={ - 'Host': 'localhost', - 'Cookie': '1foO=bar;', - 'Connection': 'close', - }, - )['status'], - 404, - 'match cookies exact 2', - ) - self.assertEqual( - self.get( - headers={ - 'Host': 'localhost', - 'Cookie': 'foO=bar;1', - 'Connection': 'close', - }, - )['status'], - 200, - 'match cookies exact 3', - ) + self.route_match({"cookies": []}) + self.assertEqual(self.get()['status'], 200, 'cookies empty 2') - def test_routes_match_cookies_empty(self): - self.assertIn( - 'success', - self.route( - { - "match": {"cookies": {}}, - "action": {"pass": "applications/empty"}, - } - ), - 'match cookies empty configure', + def test_routes_match_cookies_invalid(self): + self.route_match_invalid({"cookies": ["var"]}) + self.route_match_invalid({"cookies": [{"foo": {}}]}) + + def test_routes_match_cookies_multiple(self): + self.route_match({"cookies": {"foo": "bar", "blah": "blah"}}) + + self.assertEqual(self.get()['status'], 404, 'multiple') + self.cookie('foo=bar; blah=blah', 200) + self.cookie(['foo=bar', 'blah=blah'], 200) + self.cookie(['foo=bar; blah', 'blah'], 404) + self.cookie(['foo=bar; blah=test', 'blah=blah'], 404) + + def test_routes_match_cookies_multiple_values(self): + self.route_match({"cookies": {"blah": "blah"}}) + + self.cookie(['blah=blah', 'blah=blah', 'blah=blah'], 200) + self.cookie(['blah=blah', 'blah=test', 'blah=blah'], 404) + self.cookie(['blah=blah; blah=', 'blah=blah'], 404) + + def test_routes_match_cookies_multiple_rules(self): + self.route_match({"cookies": {"blah": ["test", "blah"]}}) + + self.assertEqual(self.get()['status'], 404, 'multiple rules') + self.cookie('blah=test', 200) + self.cookie('blah=blah', 200) + self.cookie(['blah=blah', 'blah=test', 'blah=blah'], 200) + self.cookie(['blah=blah; blah=test', 'blah=blah'], 200) + self.cookie(['blah=blah', 'blah'], 200) # invalid cookie + + def test_routes_match_cookies_array(self): + self.route_match( + { + "cookies": [ + {"var1": "val1*"}, + {"var2": "val2"}, + {"var3": ["foo", "bar"]}, + {"var1": "bar", "var4": "foo"}, + ] + } ) - self.assertEqual(self.get()['status'], 200, 'match cookies empty') + self.assertEqual(self.get()['status'], 404, 'cookies array') + self.cookie('var1=val123', 200) + self.cookie('var2=val2', 200) + self.cookie(' var2=val2 ', 200) + self.cookie('var3=bar', 200) + self.cookie('var3=bar;', 200) + self.cookie('var1=bar', 404) + self.cookie('var1=bar; var4=foo;', 200) + self.cookie(['var1=bar', 'var4=foo'], 200) self.assertIn( 'success', - self.route( - { - "match": {"cookies": []}, - "action": {"pass": "applications/empty"}, - } - ), - 'match cookies empty configure 2', + self.conf_delete('routes/0/match/cookies/1'), + 'match cookies array configure 2', ) - self.assertEqual(self.get()['status'], 200, 'match cookies empty 2') + self.cookie('var2=val2', 404) + self.cookie('var3=foo', 200) - def test_routes_match_cookies_invalid(self): - self.assertIn( - 'error', - self.route( - { - "match": {"cookies": ["var"]}, - "action": {"pass": "applications/empty"}, - } - ), - 'match cookies invalid', + def test_routes_match_scheme(self): + self.route_match({"scheme": "http"}) + self.route_match({"scheme": "https"}) + self.route_match({"scheme": "HtTp"}) + self.route_match({"scheme": "HtTpS"}) + + def test_routes_match_scheme_invalid(self): + self.route_match_invalid({"scheme": ["http"]}) + self.route_match_invalid({"scheme": "ftp"}) + self.route_match_invalid({"scheme": "ws"}) + self.route_match_invalid({"scheme": "*"}) + self.route_match_invalid({"scheme": ""}) + + def test_routes_source_port(self): + def sock_port(): + _, sock = self.http(b'', start=True, raw=True, no_recv=True) + port = sock.getsockname()[1] + return (sock, port) + + sock, port = sock_port() + sock2, port2 = sock_port() + + self.route_match({"source": "127.0.0.1:" + str(port)}) + self.assertEqual(self.get(sock=sock)['status'], 200, 'exact') + self.assertEqual(self.get(sock=sock2)['status'], 404, 'exact 2') + + sock, port = sock_port() + sock2, port2 = sock_port() + + self.route_match({"source": "!127.0.0.1:" + str(port)}) + self.assertEqual(self.get(sock=sock)['status'], 404, 'negative') + self.assertEqual(self.get(sock=sock2)['status'], 200, 'negative 2') + + sock, port = sock_port() + sock2, port2 = sock_port() + + self.route_match( + {"source": "127.0.0.1:" + str(port) + "-" + str(port)} + ) + self.assertEqual(self.get(sock=sock)['status'], 200, 'range single') + self.assertEqual(self.get(sock=sock2)['status'], 404, 'range single 2') + + socks = [ + sock_port(), + sock_port(), + sock_port(), + sock_port(), + sock_port(), + ] + socks.sort(key=lambda sock: sock[1]) + + self.route_match( + { + "source": "127.0.0.1:" + + str(socks[1][1]) # second port number + + "-" + + str(socks[3][1]) # fourth port number + } ) + self.assertEqual(self.get(sock=socks[0][0])['status'], 404, 'range') + self.assertEqual(self.get(sock=socks[1][0])['status'], 200, 'range 2') + self.assertEqual(self.get(sock=socks[2][0])['status'], 200, 'range 3') + self.assertEqual(self.get(sock=socks[3][0])['status'], 200, 'range 4') + self.assertEqual(self.get(sock=socks[4][0])['status'], 404, 'range 5') - self.assertIn( - 'error', - self.route( - { - "match": {"cookies": [{"foo": {}}]}, - "action": {"pass": "applications/empty"}, - } - ), - 'match cookies invalid 2', + socks = [ + sock_port(), + sock_port(), + sock_port(), + ] + socks.sort(key=lambda sock: sock[1]) + + self.route_match( + { + "source": [ + "127.0.0.1:" + str(socks[0][1]), + "127.0.0.1:" + str(socks[2][1]), + ] + } ) + self.assertEqual(self.get(sock=socks[0][0])['status'], 200, 'array') + self.assertEqual(self.get(sock=socks[1][0])['status'], 404, 'array 2') + self.assertEqual(self.get(sock=socks[2][0])['status'], 200, 'array 3') - def test_routes_match_cookies_multiple(self): + def test_routes_source_addr(self): self.assertIn( 'success', - self.route( + self.conf( { - "match": {"cookies": {"foo": "bar", "blah": "blah"}}, - "action": {"pass": "applications/empty"}, - } + "*:7080": {"pass": "routes"}, + "[::1]:7081": {"pass": "routes"}, + }, + 'listeners', ), - 'match cookies multiple configure', + 'source listeners configure', ) - self.assertEqual(self.get()['status'], 404, 'match cookies multiple') + def get_ipv6(): + return self.get(sock_type='ipv6', port=7081) - self.assertEqual( - self.get( - headers={ - 'Host': 'localhost', - 'Cookie': 'foo=bar; blah=blah', - 'Connection': 'close', - } - )['status'], - 200, - 'match cookies multiple 2', - ) + self.route_match({"source": "127.0.0.1"}) + self.assertEqual(self.get()['status'], 200, 'exact') + self.assertEqual(get_ipv6()['status'], 404, 'exact ipv6') - self.assertEqual( - self.get( - headers={ - 'Host': 'localhost', - 'Cookie': ['foo=bar', 'blah=blah'], - 'Connection': 'close', - } - )['status'], - 200, - 'match cookies multiple 3', - ) + self.route_match({"source": ["127.0.0.1"]}) + self.assertEqual(self.get()['status'], 200, 'exact 2') + self.assertEqual(get_ipv6()['status'], 404, 'exact 2 ipv6') - self.assertEqual( - self.get( - headers={ - 'Host': 'localhost', - 'Cookie': ['foo=bar; blah', 'blah'], - 'Connection': 'close', - } - )['status'], - 404, - 'match cookies multiple 4', - ) + self.route_match({"source": "!127.0.0.1"}) + self.assertEqual(self.get()['status'], 404, 'exact neg') + self.assertEqual(get_ipv6()['status'], 200, 'exact neg ipv6') - self.assertEqual( - self.get( - headers={ - 'Host': 'localhost', - 'Cookie': ['foo=bar; blah=test', 'blah=blah'], - 'Connection': 'close', - } - )['status'], - 404, - 'match cookies multiple 5', - ) + self.route_match({"source": "127.0.0.2"}) + self.assertEqual(self.get()['status'], 404, 'exact 3') + self.assertEqual(get_ipv6()['status'], 404, 'exact 3 ipv6') - def test_routes_match_cookies_multiple_values(self): + self.route_match({"source": "127.0.0.1-127.0.0.1"}) + self.assertEqual(self.get()['status'], 200, 'range single') + self.assertEqual(get_ipv6()['status'], 404, 'range single ipv6') + + self.route_match({"source": "127.0.0.2-127.0.0.2"}) + self.assertEqual(self.get()['status'], 404, 'range single 2') + self.assertEqual(get_ipv6()['status'], 404, 'range single 2 ipv6') + + self.route_match({"source": "127.0.0.2-127.0.0.3"}) + self.assertEqual(self.get()['status'], 404, 'range') + self.assertEqual(get_ipv6()['status'], 404, 'range ipv6') + + self.route_match({"source": "127.0.0.1-127.0.0.2"}) + self.assertEqual(self.get()['status'], 200, 'range 2') + self.assertEqual(get_ipv6()['status'], 404, 'range 2 ipv6') + + self.route_match({"source": "127.0.0.0-127.0.0.2"}) + self.assertEqual(self.get()['status'], 200, 'range 3') + self.assertEqual(get_ipv6()['status'], 404, 'range 3 ipv6') + + self.route_match({"source": "127.0.0.0-127.0.0.1"}) + self.assertEqual(self.get()['status'], 200, 'range 4') + self.assertEqual(get_ipv6()['status'], 404, 'range 4 ipv6') + + self.route_match({"source": "126.0.0.0-127.0.0.0"}) + self.assertEqual(self.get()['status'], 404, 'range 5') + self.assertEqual(get_ipv6()['status'], 404, 'range 5 ipv6') + + self.route_match({"source": "126.126.126.126-127.0.0.2"}) + self.assertEqual(self.get()['status'], 200, 'range 6') + self.assertEqual(get_ipv6()['status'], 404, 'range 6 ipv6') + + def test_routes_source_ipv6(self): self.assertIn( 'success', - self.route( + self.conf( { - "match": {"cookies": {"blah": "blah"}}, - "action": {"pass": "applications/empty"}, - } + "[::1]:7080": {"pass": "routes"}, + "127.0.0.1:7081": {"pass": "routes"}, + }, + 'listeners', ), - 'match cookies multiple values configure', + 'source listeners configure', ) - self.assertEqual( - self.get( - headers={ - 'Host': 'localhost', - 'Cookie': ['blah=blah', 'blah=blah', 'blah=blah'], - 'Connection': 'close', - } - )['status'], - 200, - 'match headers multiple values', - ) - self.assertEqual( - self.get( - headers={ - 'Host': 'localhost', - 'Cookie': ['blah=blah', 'blah=test', 'blah=blah'], - 'Connection': 'close', - } - )['status'], - 404, - 'match cookies multiple values 2', - ) - self.assertEqual( - self.get( - headers={ - 'Host': 'localhost', - 'Cookie': ['blah=blah; blah=', 'blah=blah'], - 'Connection': 'close', - } - )['status'], - 404, - 'match cookies multiple values 3', - ) + self.route_match({"source": "::1"}) + self.assertEqual(self.get(sock_type='ipv6')['status'], 200, 'exact') + self.assertEqual(self.get(port=7081)['status'], 404, 'exact ipv4') - def test_routes_match_cookies_multiple_rules(self): + self.route_match({"source": ["::1"]}) + self.assertEqual(self.get(sock_type='ipv6')['status'], 200, 'exact 2') + self.assertEqual(self.get(port=7081)['status'], 404, 'exact 2 ipv4') + + self.route_match({"source": "!::1"}) + self.assertEqual(self.get(sock_type='ipv6')['status'], 404, 'exact neg') + self.assertEqual(self.get(port=7081)['status'], 200, 'exact neg ipv4') + + self.route_match({"source": "::2"}) + self.assertEqual(self.get(sock_type='ipv6')['status'], 404, 'exact 3') + self.assertEqual(self.get(port=7081)['status'], 404, 'exact 3 ipv4') + + self.route_match({"source": "::1-::1"}) + self.assertEqual(self.get(sock_type='ipv6')['status'], 200, 'range') + self.assertEqual(self.get(port=7081)['status'], 404, 'range ipv4') + + self.route_match({"source": "::2-::2"}) + self.assertEqual(self.get(sock_type='ipv6')['status'], 404, 'range 2') + self.assertEqual(self.get(port=7081)['status'], 404, 'range 2 ipv4') + + self.route_match({"source": "::2-::3"}) + self.assertEqual(self.get(sock_type='ipv6')['status'], 404, 'range 3') + self.assertEqual(self.get(port=7081)['status'], 404, 'range 3 ipv4') + + self.route_match({"source": "::1-::2"}) + self.assertEqual(self.get(sock_type='ipv6')['status'], 200, 'range 4') + self.assertEqual(self.get(port=7081)['status'], 404, 'range 4 ipv4') + + self.route_match({"source": "::0-::2"}) + self.assertEqual(self.get(sock_type='ipv6')['status'], 200, 'range 5') + self.assertEqual(self.get(port=7081)['status'], 404, 'range 5 ipv4') + + self.route_match({"source": "::0-::1"}) + self.assertEqual(self.get(sock_type='ipv6')['status'], 200, 'range 6') + self.assertEqual(self.get(port=7081)['status'], 404, 'range 6 ipv4') + + def test_routes_source_cidr(self): self.assertIn( 'success', - self.route( + self.conf( { - "match": {"cookies": {"blah": ["test", "blah"]}}, - "action": {"pass": "applications/empty"}, - } + "*:7080": {"pass": "routes"}, + "[::1]:7081": {"pass": "routes"}, + }, + 'listeners', ), - 'match cookies multiple rules configure', + 'source listeners configure', ) - self.assertEqual( - self.get()['status'], 404, 'match cookies multiple rules' - ) + def get_ipv6(): + return self.get(sock_type='ipv6', port=7081) - self.assertEqual( - self.get( - headers={ - 'Host': 'localhost', - 'Cookie': 'blah=test', - 'Connection': 'close', - } - )['status'], - 200, - 'match cookies multiple rules 2', - ) + self.route_match({"source": "127.0.0.1/32"}) + self.assertEqual(self.get()['status'], 200, '32') + self.assertEqual(get_ipv6()['status'], 404, '32 ipv6') - self.assertEqual( - self.get( - headers={ - 'Host': 'localhost', - 'Cookie': 'blah=blah', - 'Connection': 'close', - } - )['status'], - 200, - 'match cookies multiple rules 3', - ) + self.route_match({"source": "127.0.0.0/32"}) + self.assertEqual(self.get()['status'], 404, '32 2') + self.assertEqual(get_ipv6()['status'], 404, '32 2 ipv6') - self.assertEqual( - self.get( - headers={ - 'Host': 'localhost', - 'Cookie': ['blah=blah', 'blah=test', 'blah=blah'], - 'Connection': 'close', - } - )['status'], - 200, - 'match cookies multiple rules 4', - ) + self.route_match({"source": "127.0.0.0/31"}) + self.assertEqual(self.get()['status'], 200, '31') + self.assertEqual(get_ipv6()['status'], 404, '31 ipv6') - self.assertEqual( - self.get( - headers={ - 'Host': 'localhost', - 'Cookie': ['blah=blah; blah=test', 'blah=blah'], - 'Connection': 'close', - } - )['status'], - 200, - 'match cookies multiple rules 5', - ) + self.route_match({"source": "0.0.0.0/1"}) + self.assertEqual(self.get()['status'], 200, '1') + self.assertEqual(get_ipv6()['status'], 404, '1 ipv6') - self.assertEqual( - self.get( - headers={ - 'Host': 'localhost', - 'Cookie': ['blah=blah', 'blah'], # invalid cookie - 'Connection': 'close', - } - )['status'], - 200, - 'match cookies multiple rules 6', - ) + self.route_match({"source": "0.0.0.0/0"}) + self.assertEqual(self.get()['status'], 200, '0') + self.assertEqual(get_ipv6()['status'], 404, '0 ipv6') - def test_routes_match_cookies_array(self): + def test_routes_source_cidr_ipv6(self): self.assertIn( 'success', - self.route( + self.conf( { - "match": { - "cookies": [ - {"var1": "val1*"}, - {"var2": "val2"}, - {"var3": ["foo", "bar"]}, - {"var1": "bar", "var4": "foo"}, - ] - }, - "action": {"pass": "applications/empty"}, - } + "[::1]:7080": {"pass": "routes"}, + "127.0.0.1:7081": {"pass": "routes"}, + }, + 'listeners', ), - 'match cookies array configure', + 'source listeners configure', ) - self.assertEqual(self.get()['status'], 404, 'match cookies array') - self.assertEqual( - self.get( - headers={ - 'Host': 'localhost', - 'Cookie': 'var1=val123', - 'Connection': 'close', - }, - )['status'], - 200, - 'match cookies array 2', - ) - self.assertEqual( - self.get( - headers={ - 'Host': 'localhost', - 'Cookie': 'var2=val2', - 'Connection': 'close', - }, - )['status'], - 200, - 'match cookies array 3', - ) - self.assertEqual( - self.get( - headers={ - 'Host': 'localhost', - 'Cookie': 'var3=bar', - 'Connection': 'close', - }, - )['status'], - 200, - 'match cookies array 4', - ) - self.assertEqual( - self.get( - headers={ - 'Host': 'localhost', - 'Cookie': 'var3=bar;', - 'Connection': 'close', - }, - )['status'], - 200, - 'match cookies array 5', - ) - self.assertEqual( - self.get( - headers={ - 'Host': 'localhost', - 'Cookie': 'var1=bar', - 'Connection': 'close', - }, - )['status'], - 404, - 'match cookies array 6', - ) - self.assertEqual( - self.get( - headers={ - 'Host': 'localhost', - 'Cookie': 'var1=bar; var4=foo;', - 'Connection': 'close', - }, - )['status'], - 200, - 'match cookies array 7', - ) - self.assertEqual( - self.get( - headers={ - 'Host': 'localhost', - 'Cookie': ['var1=bar', 'var4=foo'], - 'Connection': 'close', - }, - )['status'], - 200, - 'match cookies array 8', - ) + self.route_match({"source": "::1/128"}) + self.assertEqual(self.get(sock_type='ipv6')['status'], 200, '128') + self.assertEqual(self.get(port=7081)['status'], 404, '128 ipv4') + + self.route_match({"source": "::0/128"}) + self.assertEqual(self.get(sock_type='ipv6')['status'], 404, '128 2') + self.assertEqual(self.get(port=7081)['status'], 404, '128 ipv4') + + self.route_match({"source": "::0/127"}) + self.assertEqual(self.get(sock_type='ipv6')['status'], 200, '127') + self.assertEqual(self.get(port=7081)['status'], 404, '127 ipv4') + + self.route_match({"source": "::0/32"}) + self.assertEqual(self.get(sock_type='ipv6')['status'], 200, '32') + self.assertEqual(self.get(port=7081)['status'], 404, '32 ipv4') + + self.route_match({"source": "::0/1"}) + self.assertEqual(self.get(sock_type='ipv6')['status'], 200, '1') + self.assertEqual(self.get(port=7081)['status'], 404, '1 ipv4') + + self.route_match({"source": "::/0"}) + self.assertEqual(self.get(sock_type='ipv6')['status'], 200, '0') + self.assertEqual(self.get(port=7081)['status'], 404, '0 ipv4') + + def test_routes_source_unix(self): + addr = self.testdir + '/sock' self.assertIn( 'success', - self.conf_delete('routes/0/match/cookies/1'), - 'match cookies array configure 2', + self.conf({"unix:" + addr: {"pass": "routes"}}, 'listeners'), + 'source listeners configure', ) + self.route_match({"source": "!0.0.0.0/0"}) self.assertEqual( - self.get( - headers={ - 'Host': 'localhost', - 'Cookie': 'var2=val2', - 'Connection': 'close', - }, - )['status'], - 404, - 'match cookies array 9', + self.get(sock_type='unix', addr=addr)['status'], 200, 'unix ipv4' ) + + self.route_match({"source": "!::/0"}) self.assertEqual( - self.get( - headers={ - 'Host': 'localhost', - 'Cookie': 'var3=foo', - 'Connection': 'close', - }, - )['status'], - 200, - 'match cookies array 10', + self.get(sock_type='unix', addr=addr)['status'], 200, 'unix ipv6' ) - def test_routes_match_scheme(self): - self.assertIn( - 'success', - self.route( - { - "match": {"scheme": "http"}, - "action": {"pass": "applications/empty"}, - } - ), - 'match scheme http configure', - ) - self.assertIn( - 'success', - self.route( - { - "match": {"scheme": "https"}, - "action": {"pass": "applications/empty"}, - } - ), - 'match scheme https configure', + def test_routes_match_source(self): + self.route_match({"source": "::"}) + self.route_match( + { + "source": [ + "127.0.0.1", + "192.168.0.10:8080", + "192.168.0.11:8080-8090", + ] + } ) - self.assertIn( - 'success', - self.route( - { - "match": {"scheme": "HtTp"}, - "action": {"pass": "applications/empty"}, - } - ), - 'match scheme http case insensitive configure', + self.route_match( + { + "source": [ + "10.0.0.0/8", + "10.0.0.0/7:1000", + "10.0.0.0/32:8080-8090", + ] + } ) - self.assertIn( - 'success', - self.route( - { - "match": {"scheme": "HtTpS"}, - "action": {"pass": "applications/empty"}, - } - ), - 'match scheme https case insensitive configure', + self.route_match( + { + "source": [ + "10.0.0.0-10.0.0.1", + "10.0.0.0-11.0.0.0:1000", + "127.0.0.0-127.0.0.255:8080-8090", + ] + } ) - - def test_routes_match_scheme_invalid(self): - self.assertIn( - 'error', - self.route( - { - "match": {"scheme": ["http"]}, - "action": {"pass": "applications/empty"}, - } - ), - 'scheme invalid type no arrays allowed', + self.route_match( + {"source": ["2001::", "[2002::]:8000", "[2003::]:8080-8090"]} ) - self.assertIn( - 'error', - self.route( - { - "match": {"scheme": "ftp"}, - "action": {"pass": "applications/empty"}, - } - ), - 'scheme invalid protocol 1', + self.route_match( + { + "source": [ + "2001::-200f:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "[fe08::-feff::]:8000", + "[fff0::-fff0::10]:8080-8090", + ] + } ) - self.assertIn( - 'error', - self.route( - { - "match": {"scheme": "ws"}, - "action": {"pass": "applications/empty"}, - } - ), - 'scheme invalid protocol 2', + self.route_match( + { + "source": [ + "2001::/16", + "[0ff::/64]:8000", + "[fff0:abcd:ffff:ffff:ffff::/128]:8080-8090", + ] + } ) + self.route_match({"source": "*:0-65535"}) + self.assertEqual(self.get()['status'], 200, 'source any') + + def test_routes_match_source_invalid(self): + self.route_match_invalid({"source": "127"}) + self.route_match_invalid({"source": "256.0.0.1"}) + self.route_match_invalid({"source": "127.0.0."}) + self.route_match_invalid({"source": "127.0.0.1:"}) + self.route_match_invalid({"source": "127.0.0.1/"}) + self.route_match_invalid({"source": "11.0.0.0/33"}) + self.route_match_invalid({"source": "11.0.0.0/65536"}) + self.route_match_invalid({"source": "11.0.0.0-10.0.0.0"}) + self.route_match_invalid({"source": "11.0.0.0:3000-2000"}) + self.route_match_invalid({"source": ["11.0.0.0:3000-2000"]}) + self.route_match_invalid({"source": "[2001::]:3000-2000"}) + self.route_match_invalid({"source": "2001::-2000::"}) + self.route_match_invalid({"source": "2001::/129"}) + self.route_match_invalid({"source": "::FFFFF"}) + self.route_match_invalid({"source": "[::1]:"}) + self.route_match_invalid({"source": "*:"}) + self.route_match_invalid({"source": "*:1-a"}) + self.route_match_invalid({"source": "*:65536"}) + + def test_routes_match_destination(self): self.assertIn( - 'error', - self.route( - { - "match": {"scheme": "*"}, - "action": {"pass": "applications/empty"}, - } + 'success', + self.conf( + {"*:7080": {"pass": "routes"}, "*:7081": {"pass": "routes"}}, + 'listeners', ), - 'scheme invalid no wildcard allowed', + 'listeners configure', ) + + self.route_match({"destination": "*:7080"}) + self.assertEqual(self.get()['status'], 200, 'dest') + self.assertEqual(self.get(port=7081)['status'], 404, 'dest 2') + + self.route_match({"destination": ["127.0.0.1:7080"]}) + self.assertEqual(self.get()['status'], 200, 'dest 3') + self.assertEqual(self.get(port=7081)['status'], 404, 'dest 4') + + self.route_match({"destination": "!*:7080"}) + self.assertEqual(self.get()['status'], 404, 'dest neg') + self.assertEqual(self.get(port=7081)['status'], 200, 'dest neg 2') + + def test_routes_match_destination_proxy(self): self.assertIn( - 'error', - self.route( + 'success', + self.conf( { - "match": {"scheme": ""}, - "action": {"pass": "applications/empty"}, + "listeners": { + "*:7080": {"pass": "routes/first"}, + "*:7081": {"pass": "routes/second"}, + }, + "routes": { + "first": [ + {"action": {"proxy": "http://127.0.0.1:7081"}} + ], + "second": [ + { + "match": {"destination": ["127.0.0.1:7081"]}, + "action": {"pass": "applications/empty"}, + } + ], + }, + "applications": { + "empty": { + "type": "python", + "processes": {"spare": 0}, + "path": self.current_dir + "/python/empty", + "working_directory": self.current_dir + + "/python/empty", + "module": "wsgi", + } + }, } ), - 'scheme invalid empty', + 'proxy configure', ) + self.assertEqual(self.get()['status'], 200, 'proxy') + if __name__ == '__main__': TestRouting.main() diff --git a/test/test_routing_tls.py b/test/test_routing_tls.py index 3df2bc82..c6648095 100644 --- a/test/test_routing_tls.py +++ b/test/test_routing_tls.py @@ -48,10 +48,8 @@ class TestRoutingTLS(TestApplicationTLS): 'scheme configure', ) - self.assertEqual(self.get()['status'], 200, 'scheme http') - self.assertEqual( - self.get_ssl(port=7081)['status'], 204, 'scheme https' - ) + self.assertEqual(self.get()['status'], 200, 'http') + self.assertEqual(self.get_ssl(port=7081)['status'], 204, 'https') if __name__ == '__main__': diff --git a/test/test_ruby_application.py b/test/test_ruby_application.py index bbb252d7..83a71f96 100644 --- a/test/test_ruby_application.py +++ b/test/test_ruby_application.py @@ -285,7 +285,7 @@ class TestRubyApplication(TestApplicationRuby): def test_ruby_application_body_empty(self): self.load('body_empty') - self.assertEqual(self.get()['body'], '0\r\n\r\n', 'body empty') + self.assertEqual(self.get()['body'], '', 'body empty') def test_ruby_application_body_array(self): self.load('body_array') diff --git a/test/unit/applications/lang/go.py b/test/unit/applications/lang/go.py index 18345828..7212a95c 100644 --- a/test/unit/applications/lang/go.py +++ b/test/unit/applications/lang/go.py @@ -23,7 +23,7 @@ class TestApplicationGo(TestApplicationProto): os.mkdir(self.testdir + '/go') env = os.environ.copy() - env['GOPATH'] = self.pardir + '/go' + env['GOPATH'] = self.pardir + '/build/go' try: process = Popen( @@ -44,7 +44,7 @@ class TestApplicationGo(TestApplicationProto): return process - def load(self, script, name='app'): + def load(self, script, name='app', **kwargs): self.prepare_env(script, name) self._load_conf( @@ -60,5 +60,6 @@ class TestApplicationGo(TestApplicationProto): "executable": self.testdir + "/go/" + name, } }, - } + }, + **kwargs ) diff --git a/test/unit/applications/lang/java.py b/test/unit/applications/lang/java.py index bcf87f59..a370d96b 100644 --- a/test/unit/applications/lang/java.py +++ b/test/unit/applications/lang/java.py @@ -6,7 +6,7 @@ from unit.applications.proto import TestApplicationProto class TestApplicationJava(TestApplicationProto): - def load(self, script, name='app'): + def load(self, script, name='app', **kwargs): app_path = self.testdir + '/java' web_inf_path = app_path + '/WEB-INF/' classes_path = web_inf_path + 'classes/' @@ -82,5 +82,6 @@ class TestApplicationJava(TestApplicationProto): "webapp": app_path, } }, - } + }, + **kwargs ) diff --git a/test/unit/applications/lang/node.py b/test/unit/applications/lang/node.py index 3cc72669..d818298f 100644 --- a/test/unit/applications/lang/node.py +++ b/test/unit/applications/lang/node.py @@ -15,20 +15,22 @@ class TestApplicationNode(TestApplicationProto): return unit if not complete_check else unit.complete() - def load(self, script, name='app.js'): + def load(self, script, name='app.js', **kwargs): # copy application shutil.copytree( self.current_dir + '/node/' + script, self.testdir + '/node' ) - # link modules + # copy modules - os.symlink( + shutil.copytree( self.pardir + '/node/node_modules', self.testdir + '/node/node_modules', ) + self.public_dir(self.testdir + '/node') + self._load_conf( { "listeners": {"*:7080": {"pass": "applications/" + script}}, @@ -40,5 +42,6 @@ class TestApplicationNode(TestApplicationProto): "executable": name, } }, - } + }, + **kwargs ) diff --git a/test/unit/applications/lang/perl.py b/test/unit/applications/lang/perl.py index 79df2cfa..d32aca33 100644 --- a/test/unit/applications/lang/perl.py +++ b/test/unit/applications/lang/perl.py @@ -4,7 +4,7 @@ from unit.applications.proto import TestApplicationProto class TestApplicationPerl(TestApplicationProto): application_type = "perl" - def load(self, script, name='psgi.pl'): + def load(self, script, name='psgi.pl', **kwargs): script_path = self.current_dir + '/perl/' + script self._load_conf( @@ -18,5 +18,6 @@ class TestApplicationPerl(TestApplicationProto): "script": script_path + '/' + name, } }, - } + }, + **kwargs ) diff --git a/test/unit/applications/lang/php.py b/test/unit/applications/lang/php.py index 9c54368d..6b1677e6 100644 --- a/test/unit/applications/lang/php.py +++ b/test/unit/applications/lang/php.py @@ -4,7 +4,7 @@ from unit.applications.proto import TestApplicationProto class TestApplicationPHP(TestApplicationProto): application_type = "php" - def load(self, script, name='index.php'): + def load(self, script, name='index.php', **kwargs): script_path = self.current_dir + '/php/' + script self._load_conf( @@ -19,5 +19,6 @@ class TestApplicationPHP(TestApplicationProto): "index": name, } }, - } + }, + **kwargs ) diff --git a/test/unit/applications/lang/python.py b/test/unit/applications/lang/python.py index ded76cb6..fdda024a 100644 --- a/test/unit/applications/lang/python.py +++ b/test/unit/applications/lang/python.py @@ -4,7 +4,7 @@ from unit.applications.proto import TestApplicationProto class TestApplicationPython(TestApplicationProto): application_type = "python" - def load(self, script, name=None): + def load(self, script, name=None, **kwargs): if name is None: name = script @@ -22,5 +22,6 @@ class TestApplicationPython(TestApplicationProto): "module": "wsgi", } }, - } + }, + **kwargs ) diff --git a/test/unit/applications/lang/ruby.py b/test/unit/applications/lang/ruby.py index d30735ad..8c8acecc 100644 --- a/test/unit/applications/lang/ruby.py +++ b/test/unit/applications/lang/ruby.py @@ -4,7 +4,7 @@ from unit.applications.proto import TestApplicationProto class TestApplicationRuby(TestApplicationProto): application_type = "ruby" - def load(self, script, name='config.ru'): + def load(self, script, name='config.ru', **kwargs): script_path = self.current_dir + '/ruby/' + script self._load_conf( @@ -18,5 +18,6 @@ class TestApplicationRuby(TestApplicationProto): "script": script_path + '/' + name, } }, - } + }, + **kwargs ) diff --git a/test/unit/applications/proto.py b/test/unit/applications/proto.py index 4105473f..ae1af354 100644 --- a/test/unit/applications/proto.py +++ b/test/unit/applications/proto.py @@ -25,7 +25,19 @@ class TestApplicationProto(TestControl): return found - def _load_conf(self, conf): + def _load_conf(self, conf, **kwargs): + if 'applications' in conf: + for app in conf['applications'].keys(): + app_conf = conf['applications'][app] + if 'user' in kwargs: + app_conf['user'] = kwargs['user'] + + if 'group' in kwargs: + app_conf['group'] = kwargs['group'] + + if 'isolation' in kwargs: + app_conf['isolation'] = kwargs['isolation'] + self.assertIn( 'success', self.conf(conf), 'load application configuration' ) diff --git a/test/unit/feature/isolation.py b/test/unit/feature/isolation.py index 9b06ab3c..3f474993 100644 --- a/test/unit/feature/isolation.py +++ b/test/unit/feature/isolation.py @@ -82,6 +82,3 @@ class TestFeatureIsolation(TestApplicationProto): data = int(os.readlink(nspath)[len(nstype) + 2 : -1]) return data - - def parsejson(self, data): - return json.loads(data.split('\n')[1]) diff --git a/test/unit/http.py b/test/unit/http.py index c7e3e36d..839e91a2 100644 --- a/test/unit/http.py +++ b/test/unit/http.py @@ -1,5 +1,6 @@ import re import time +import json import socket import select from unit.main import TestUnit @@ -86,23 +87,24 @@ class TestHTTP(TestUnit): sock.sendall(req) + encoding = 'utf-8' if 'encoding' not in kwargs else kwargs['encoding'] + if TestUnit.detailed: print('>>>') try: - print(req.decode('utf-8', 'ignore')) + print(req.decode(encoding, 'ignore')) except UnicodeEncodeError: print(req) resp = '' if 'no_recv' not in kwargs: - enc = 'utf-8' if 'encoding' not in kwargs else kwargs['encoding'] read_timeout = ( 30 if 'read_timeout' not in kwargs else kwargs['read_timeout'] ) resp = self.recvall( sock, read_timeout=read_timeout, buff_size=read_buffer_size - ).decode(enc) + ).decode(encoding) if TestUnit.detailed: print('<<<') @@ -114,6 +116,15 @@ class TestHTTP(TestUnit): if 'raw_resp' not in kwargs: resp = self._resp_to_dict(resp) + headers = resp.get('headers') + if headers and headers.get('Transfer-Encoding') == 'chunked': + resp['body'] = self._parse_chunked_body(resp['body']).decode( + encoding + ) + + if 'json' in kwargs: + resp = self._parse_json(resp) + if 'start' not in kwargs: sock.close() return resp @@ -151,7 +162,7 @@ class TestHTTP(TestUnit): return data def _resp_to_dict(self, resp): - m = re.search('(.*?\x0d\x0a?)\x0d\x0a?(.*)', resp, re.M | re.S) + m = re.search(r'(.*?\x0d\x0a?)\x0d\x0a?(.*)', resp, re.M | re.S) if not m: return {} @@ -162,12 +173,12 @@ class TestHTTP(TestUnit): headers_lines = p.findall(headers_text) status = re.search( - '^HTTP\/\d\.\d\s(\d+)|$', headers_lines.pop(0) + r'^HTTP\/\d\.\d\s(\d+)|$', headers_lines.pop(0) ).group(1) headers = {} for line in headers_lines: - m = re.search('(.*)\:\s(.*)', line) + m = re.search(r'(.*)\:\s(.*)', line) if m.group(1) not in headers: headers[m.group(1)] = m.group(2) @@ -180,6 +191,65 @@ class TestHTTP(TestUnit): return {'status': int(status), 'headers': headers, 'body': body} + def _parse_chunked_body(self, raw_body): + if isinstance(raw_body, str): + raw_body = bytes(raw_body.encode()) + + crlf = b'\r\n' + chunks = raw_body.split(crlf) + + if len(chunks) < 3: + self.fail('Invalid chunked body') + + if chunks.pop() != b'': + self.fail('No CRLF at the end of the body') + + try: + last_size = int(chunks[-2], 16) + except: + self.fail('Invalid zero size chunk') + + if last_size != 0 or chunks[-1] != b'': + self.fail('Incomplete body') + + body = b'' + while len(chunks) >= 2: + try: + size = int(chunks.pop(0), 16) + except: + self.fail('Invalid chunk size %s' % str(size)) + + if size == 0: + self.assertEqual(len(chunks), 1, 'last zero size') + break + + temp_body = crlf.join(chunks) + + body += temp_body[:size] + + temp_body = temp_body[size + len(crlf) :] + + chunks = temp_body.split(crlf) + + return body + + def _parse_json(self, resp): + headers = resp['headers'] + + self.assertIn('Content-Type', headers, 'Content-Type header set') + self.assertEqual( + headers['Content-Type'], + 'application/json', + 'Content-Type header is application/json', + ) + + resp['body'] = json.loads(resp['body']) + + return resp + + def getjson(self, **kwargs): + return self.get(json=True, **kwargs) + def waitforsocket(self, port): ret = False diff --git a/test/unit/main.py b/test/unit/main.py index 094fdb0e..ea6afd7f 100644 --- a/test/unit/main.py +++ b/test/unit/main.py @@ -1,6 +1,7 @@ import os import re import sys +import stat import time import fcntl import shutil @@ -20,6 +21,9 @@ class TestUnit(unittest.TestCase): pardir = os.path.abspath( os.path.join(os.path.dirname(__file__), os.pardir, os.pardir) ) + is_su = os.geteuid() == 0 + uid = os.geteuid() + gid = os.getegid() architecture = platform.architecture()[0] system = platform.system() maxDiff = None @@ -188,13 +192,19 @@ class TestUnit(unittest.TestCase): self.stop_processes() def _run(self): - self.unitd = self.pardir + '/build/unitd' + build_dir = self.pardir + '/build' + self.unitd = build_dir + '/unitd' if not os.path.isfile(self.unitd): exit("Could not find unit") self.testdir = tempfile.mkdtemp(prefix='unit-test-') + self.public_dir(self.testdir) + + if oct(stat.S_IMODE(os.stat(build_dir).st_mode)) != '0o777': + self.public_dir(build_dir) + os.mkdir(self.testdir + '/state') print() @@ -328,6 +338,15 @@ class TestUnit(unittest.TestCase): return ret + def public_dir(self, path): + os.chmod(path, 0o777) + + for root, dirs, files in os.walk(path): + for d in dirs: + os.chmod(os.path.join(root, d), 0o777) + for f in files: + os.chmod(os.path.join(root, f), 0o777) + @staticmethod def _parse_args(): parser = argparse.ArgumentParser(add_help=False) |