summaryrefslogtreecommitdiffhomepage
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/python/delayed/wsgi.py1
-rw-r--r--test/python/log_body/wsgi.py2
-rw-r--r--test/python/upstreams/0/wsgi.py8
-rw-r--r--test/python/upstreams/1/wsgi.py8
-rw-r--r--test/python/upstreams/2/wsgi.py8
-rw-r--r--test/test_configuration.py80
-rw-r--r--test/test_go_application.py10
-rw-r--r--test/test_java_application.py10
-rw-r--r--test/test_java_websockets.py28
-rw-r--r--test/test_node_application.py8
-rw-r--r--test/test_node_websockets.py28
-rw-r--r--test/test_perl_application.py10
-rw-r--r--test/test_php_application.py10
-rw-r--r--test/test_php_basic.py56
-rw-r--r--test/test_python_application.py48
-rw-r--r--test/test_python_basic.py69
-rw-r--r--test/test_python_procman.py173
-rw-r--r--test/test_return.py198
-rw-r--r--test/test_routing.py161
-rw-r--r--test/test_routing_tls.py26
-rw-r--r--test/test_ruby_application.py10
-rw-r--r--test/test_share_fallback.py165
-rw-r--r--test/test_tls.py5
-rw-r--r--test/test_upstreams_rr.py282
-rw-r--r--test/test_usr1.py3
-rw-r--r--test/unit/applications/websockets.py20
-rw-r--r--test/unit/http.py51
-rw-r--r--test/unit/main.py175
28 files changed, 887 insertions, 766 deletions
diff --git a/test/python/delayed/wsgi.py b/test/python/delayed/wsgi.py
index d25e2765..3eb5a6f8 100644
--- a/test/python/delayed/wsgi.py
+++ b/test/python/delayed/wsgi.py
@@ -11,6 +11,7 @@ def application(environ, start_response):
write = start_response('200', [('Content-Length', str(len(body)))])
if not body:
+ time.sleep(delay)
return []
step = int(len(body) / parts)
diff --git a/test/python/log_body/wsgi.py b/test/python/log_body/wsgi.py
index 9dcb1b0c..0ec07a68 100644
--- a/test/python/log_body/wsgi.py
+++ b/test/python/log_body/wsgi.py
@@ -2,7 +2,7 @@ def application(environ, start_response):
content_length = int(environ.get('CONTENT_LENGTH', 0))
body = bytes(environ['wsgi.input'].read(content_length))
- environ['wsgi.errors'].write(body)
+ environ['wsgi.errors'].write(body.decode())
environ['wsgi.errors'].flush()
start_response('200', [('Content-Length', '0')])
diff --git a/test/python/upstreams/0/wsgi.py b/test/python/upstreams/0/wsgi.py
deleted file mode 100644
index 2c88979b..00000000
--- a/test/python/upstreams/0/wsgi.py
+++ /dev/null
@@ -1,8 +0,0 @@
-import time
-
-def application(env, start_response):
- delay = int(env.get('HTTP_X_DELAY', 0))
-
- start_response('200', [('Content-Length', '0'), ('X-Upstream', '0')])
- time.sleep(delay)
- return []
diff --git a/test/python/upstreams/1/wsgi.py b/test/python/upstreams/1/wsgi.py
deleted file mode 100644
index 5077bdb1..00000000
--- a/test/python/upstreams/1/wsgi.py
+++ /dev/null
@@ -1,8 +0,0 @@
-import time
-
-def application(env, start_response):
- delay = int(env.get('HTTP_X_DELAY', 0))
-
- start_response('200', [('Content-Length', '0'), ('X-Upstream', '1')])
- time.sleep(delay)
- return []
diff --git a/test/python/upstreams/2/wsgi.py b/test/python/upstreams/2/wsgi.py
deleted file mode 100644
index bb0ce797..00000000
--- a/test/python/upstreams/2/wsgi.py
+++ /dev/null
@@ -1,8 +0,0 @@
-import time
-
-def application(env, start_response):
- delay = int(env.get('HTTP_X_DELAY', 0))
-
- start_response('200', [('Content-Length', '0'), ('X-Upstream', '2')])
- time.sleep(delay)
- return []
diff --git a/test/test_configuration.py b/test/test_configuration.py
index 186e037d..daba874b 100644
--- a/test/test_configuration.py
+++ b/test/test_configuration.py
@@ -83,6 +83,86 @@ class TestConfiguration(TestControl):
'unicode number',
)
+ def test_json_utf8_bom(self):
+ self.assertIn(
+ 'success',
+ self.conf(
+ b"""\xEF\xBB\xBF
+ {
+ "app": {
+ "type": "python",
+ "processes": {"spare": 0},
+ "path": "/app",
+ "module": "wsgi"
+ }
+ }
+ """,
+ 'applications',
+ ),
+ 'UTF-8 BOM',
+ )
+
+ def test_json_comment_single_line(self):
+ self.assertIn(
+ 'success',
+ self.conf(
+ b"""
+ // this is bridge
+ {
+ "//app": {
+ "type": "python", // end line
+ "processes": {"spare": 0},
+ // inside of block
+ "path": "/app",
+ "module": "wsgi"
+ }
+ // double //
+ }
+ // end of json \xEF\t
+ """,
+ 'applications',
+ ),
+ 'single line comments',
+ )
+
+ def test_json_comment_multi_line(self):
+ self.assertIn(
+ 'success',
+ self.conf(
+ b"""
+ /* this is bridge */
+ {
+ "/*app": {
+ /**
+ * multiple lines
+ **/
+ "type": "python",
+ "processes": /* inline */ {"spare": 0},
+ "path": "/app",
+ "module": "wsgi"
+ /*
+ // end of block */
+ }
+ /* blah * / blah /* blah */
+ }
+ /* end of json \xEF\t\b */
+ """,
+ 'applications',
+ ),
+ 'multi line comments',
+ )
+
+ def test_json_comment_invalid(self):
+ self.assertIn('error', self.conf(b'/{}', 'applications'), 'slash')
+ self.assertIn('error', self.conf(b'//{}', 'applications'), 'comment')
+ self.assertIn('error', self.conf(b'{} /', 'applications'), 'slash end')
+ self.assertIn(
+ 'error', self.conf(b'/*{}', 'applications'), 'slash star'
+ )
+ self.assertIn(
+ 'error', self.conf(b'{} /*', 'applications'), 'slash star end'
+ )
+
def test_applications_open_brace(self):
self.assertIn('error', self.conf('{', 'applications'), 'open brace')
diff --git a/test/test_go_application.py b/test/test_go_application.py
index 42429be7..c9d4ba77 100644
--- a/test/test_go_application.py
+++ b/test/test_go_application.py
@@ -89,6 +89,7 @@ class TestGoApplication(TestApplicationGo):
self.assertEqual(self.get()['status'], 200, 'init')
+ body = '0123456789' * 500
(resp, sock) = self.post(
headers={
'Host': 'localhost',
@@ -96,12 +97,13 @@ class TestGoApplication(TestApplicationGo):
'Content-Type': 'text/html',
},
start=True,
- body='0123456789' * 500,
+ body=body,
read_timeout=1,
)
- self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1')
+ self.assertEqual(resp['body'], body, 'keep-alive 1')
+ body = '0123456789'
resp = self.post(
headers={
'Host': 'localhost',
@@ -109,10 +111,10 @@ class TestGoApplication(TestApplicationGo):
'Connection': 'close',
},
sock=sock,
- body='0123456789',
+ body=body,
)
- self.assertEqual(resp['body'], '0123456789', 'keep-alive 2')
+ self.assertEqual(resp['body'], body, 'keep-alive 2')
def test_go_application_cookies(self):
self.load('cookies')
diff --git a/test/test_java_application.py b/test/test_java_application.py
index 9d873d6b..7bd351a4 100644
--- a/test/test_java_application.py
+++ b/test/test_java_application.py
@@ -1085,6 +1085,7 @@ class TestJavaApplication(TestApplicationJava):
self.assertEqual(self.post()['status'], 200, 'init')
+ body = '0123456789' * 500
(resp, sock) = self.post(
headers={
'Connection': 'keep-alive',
@@ -1092,12 +1093,13 @@ class TestJavaApplication(TestApplicationJava):
'Host': 'localhost',
},
start=True,
- body='0123456789' * 500,
+ body=body,
read_timeout=1,
)
- self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1')
+ self.assertEqual(resp['body'], body, 'keep-alive 1')
+ body = '0123456789'
resp = self.post(
headers={
'Connection': 'close',
@@ -1105,10 +1107,10 @@ class TestJavaApplication(TestApplicationJava):
'Host': 'localhost',
},
sock=sock,
- body='0123456789',
+ body=body,
)
- self.assertEqual(resp['body'], '0123456789', 'keep-alive 2')
+ self.assertEqual(resp['body'], body, 'keep-alive 2')
def test_java_application_http_10(self):
self.load('empty')
diff --git a/test/test_java_websockets.py b/test/test_java_websockets.py
index d75ee3a6..7ea04620 100644
--- a/test/test_java_websockets.py
+++ b/test/test_java_websockets.py
@@ -22,11 +22,11 @@ class TestJavaWebsockets(TestApplicationJava):
)
self.skip_alerts.extend(
- [r'last message send failed', r'socket close\(\d+\) failed']
+ [r'socket close\(\d+\) failed']
)
def close_connection(self, sock):
- self.assertEqual(self.recvall(sock, read_timeout=1), b'', 'empty sock')
+ self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc')
self.ws.frame_write(sock, self.ws.OP_CLOSE, self.ws.serialize_close())
@@ -441,12 +441,12 @@ class TestJavaWebsockets(TestApplicationJava):
_, sock, _ = self.ws.upgrade()
self.ws.frame_write(sock, self.ws.OP_PONG, '')
- self.assertEqual(self.recvall(sock, read_timeout=1), b'', '2_7')
+ self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '2_7')
# 2_8
self.ws.frame_write(sock, self.ws.OP_PONG, 'unsolicited pong payload')
- self.assertEqual(self.recvall(sock, read_timeout=1), b'', '2_8')
+ self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '2_8')
# 2_9
@@ -512,7 +512,7 @@ class TestJavaWebsockets(TestApplicationJava):
self.check_close(sock, 1002, no_close=True)
- self.assertEqual(self.recvall(sock, read_timeout=1), b'', 'empty 3_2')
+ self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty 3_2')
sock.close()
# 3_3
@@ -530,7 +530,7 @@ class TestJavaWebsockets(TestApplicationJava):
self.check_close(sock, 1002, no_close=True)
- self.assertEqual(self.recvall(sock, read_timeout=1), b'', 'empty 3_3')
+ self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty 3_3')
sock.close()
# 3_4
@@ -548,7 +548,7 @@ class TestJavaWebsockets(TestApplicationJava):
self.check_close(sock, 1002, no_close=True)
- self.assertEqual(self.recvall(sock, read_timeout=1), b'', 'empty 3_4')
+ self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty 3_4')
sock.close()
# 3_5
@@ -734,7 +734,7 @@ class TestJavaWebsockets(TestApplicationJava):
# 5_4
self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False)
- self.assertEqual(self.recvall(sock, read_timeout=1), b'', '5_4')
+ self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '5_4')
self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=True)
frame = self.ws.frame_read(sock)
@@ -771,7 +771,7 @@ class TestJavaWebsockets(TestApplicationJava):
ping_payload = 'ping payload'
self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False)
- self.assertEqual(self.recvall(sock, read_timeout=1), b'', '5_7')
+ self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '5_7')
self.ws.frame_write(sock, self.ws.OP_PING, ping_payload)
@@ -955,7 +955,7 @@ class TestJavaWebsockets(TestApplicationJava):
frame = self.ws.frame_read(sock)
self.check_frame(frame, True, self.ws.OP_PONG, 'pongme 2!')
- self.assertEqual(self.recvall(sock, read_timeout=1), b'', '5_20')
+ self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '5_20')
self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment5')
self.check_frame(
@@ -1088,7 +1088,7 @@ class TestJavaWebsockets(TestApplicationJava):
self.check_close(sock, no_close=True)
self.ws.frame_write(sock, self.ws.OP_PING, '')
- self.assertEqual(self.recvall(sock, read_timeout=1), b'', 'empty sock')
+ self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc')
sock.close()
@@ -1100,7 +1100,7 @@ class TestJavaWebsockets(TestApplicationJava):
self.check_close(sock, no_close=True)
self.ws.frame_write(sock, self.ws.OP_TEXT, payload)
- self.assertEqual(self.recvall(sock, read_timeout=1), b'', 'empty sock')
+ self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc')
sock.close()
@@ -1113,7 +1113,7 @@ class TestJavaWebsockets(TestApplicationJava):
self.check_close(sock, no_close=True)
self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2')
- self.assertEqual(self.recvall(sock, read_timeout=1), b'', 'empty sock')
+ self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc')
sock.close()
@@ -1128,7 +1128,7 @@ class TestJavaWebsockets(TestApplicationJava):
self.recvall(sock, read_timeout=1)
self.ws.frame_write(sock, self.ws.OP_PING, '')
- self.assertEqual(self.recvall(sock, read_timeout=1), b'', 'empty sock')
+ self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc')
sock.close()
diff --git a/test/test_node_application.py b/test/test_node_application.py
index b80d17d3..174af15d 100644
--- a/test/test_node_application.py
+++ b/test/test_node_application.py
@@ -112,6 +112,7 @@ class TestNodeApplication(TestApplicationNode):
self.assertEqual(self.get()['status'], 200, 'init')
+ body = '0123456789' * 500
(resp, sock) = self.post(
headers={
'Host': 'localhost',
@@ -119,12 +120,13 @@ class TestNodeApplication(TestApplicationNode):
'Content-Type': 'text/html',
},
start=True,
- body='0123456789' * 500,
+ body=body,
read_timeout=1,
)
self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1')
+ body = '0123456789'
resp = self.post(
headers={
'Host': 'localhost',
@@ -132,10 +134,10 @@ class TestNodeApplication(TestApplicationNode):
'Content-Type': 'text/html',
},
sock=sock,
- body='0123456789',
+ body=body,
)
- self.assertEqual(resp['body'], '0123456789', 'keep-alive 2')
+ self.assertEqual(resp['body'], body, 'keep-alive 2')
def test_node_application_write_buffer(self):
self.load('write_buffer')
diff --git a/test/test_node_websockets.py b/test/test_node_websockets.py
index bb189552..4ce727db 100644
--- a/test/test_node_websockets.py
+++ b/test/test_node_websockets.py
@@ -22,11 +22,11 @@ class TestNodeWebsockets(TestApplicationNode):
)
self.skip_alerts.extend(
- [r'last message send failed', r'socket close\(\d+\) failed']
+ [r'socket close\(\d+\) failed']
)
def close_connection(self, sock):
- self.assertEqual(self.recvall(sock, read_timeout=1), b'', 'empty sock')
+ self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc')
self.ws.frame_write(sock, self.ws.OP_CLOSE, self.ws.serialize_close())
@@ -460,12 +460,12 @@ class TestNodeWebsockets(TestApplicationNode):
_, sock, _ = self.ws.upgrade()
self.ws.frame_write(sock, self.ws.OP_PONG, '')
- self.assertEqual(self.recvall(sock, read_timeout=1), b'', '2_7')
+ self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '2_7')
# 2_8
self.ws.frame_write(sock, self.ws.OP_PONG, 'unsolicited pong payload')
- self.assertEqual(self.recvall(sock, read_timeout=1), b'', '2_8')
+ self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '2_8')
# 2_9
@@ -531,7 +531,7 @@ class TestNodeWebsockets(TestApplicationNode):
self.check_close(sock, 1002, no_close=True)
- self.assertEqual(self.recvall(sock, read_timeout=1), b'', 'empty 3_2')
+ self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty 3_2')
sock.close()
# 3_3
@@ -549,7 +549,7 @@ class TestNodeWebsockets(TestApplicationNode):
self.check_close(sock, 1002, no_close=True)
- self.assertEqual(self.recvall(sock, read_timeout=1), b'', 'empty 3_3')
+ self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty 3_3')
sock.close()
# 3_4
@@ -567,7 +567,7 @@ class TestNodeWebsockets(TestApplicationNode):
self.check_close(sock, 1002, no_close=True)
- self.assertEqual(self.recvall(sock, read_timeout=1), b'', 'empty 3_4')
+ self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty 3_4')
sock.close()
# 3_5
@@ -753,7 +753,7 @@ class TestNodeWebsockets(TestApplicationNode):
# 5_4
self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False)
- self.assertEqual(self.recvall(sock, read_timeout=1), b'', '5_4')
+ self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '5_4')
self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=True)
frame = self.ws.frame_read(sock)
@@ -790,7 +790,7 @@ class TestNodeWebsockets(TestApplicationNode):
ping_payload = 'ping payload'
self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False)
- self.assertEqual(self.recvall(sock, read_timeout=1), b'', '5_7')
+ self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '5_7')
self.ws.frame_write(sock, self.ws.OP_PING, ping_payload)
@@ -974,7 +974,7 @@ class TestNodeWebsockets(TestApplicationNode):
frame = self.ws.frame_read(sock)
self.check_frame(frame, True, self.ws.OP_PONG, 'pongme 2!')
- self.assertEqual(self.recvall(sock, read_timeout=1), b'', '5_20')
+ self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '5_20')
self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment5')
self.check_frame(
@@ -1107,7 +1107,7 @@ class TestNodeWebsockets(TestApplicationNode):
self.check_close(sock, no_close=True)
self.ws.frame_write(sock, self.ws.OP_PING, '')
- self.assertEqual(self.recvall(sock, read_timeout=1), b'', 'empty sock')
+ self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc')
sock.close()
@@ -1119,7 +1119,7 @@ class TestNodeWebsockets(TestApplicationNode):
self.check_close(sock, no_close=True)
self.ws.frame_write(sock, self.ws.OP_TEXT, payload)
- self.assertEqual(self.recvall(sock, read_timeout=1), b'', 'empty sock')
+ self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc')
sock.close()
@@ -1132,7 +1132,7 @@ class TestNodeWebsockets(TestApplicationNode):
self.check_close(sock, no_close=True)
self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2')
- self.assertEqual(self.recvall(sock, read_timeout=1), b'', 'empty sock')
+ self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc')
sock.close()
@@ -1147,7 +1147,7 @@ class TestNodeWebsockets(TestApplicationNode):
self.recvall(sock, read_timeout=1)
self.ws.frame_write(sock, self.ws.OP_PING, '')
- self.assertEqual(self.recvall(sock, read_timeout=1), b'', 'empty sock')
+ self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc')
sock.close()
diff --git a/test/test_perl_application.py b/test/test_perl_application.py
index a4bac623..cc4eb915 100644
--- a/test/test_perl_application.py
+++ b/test/test_perl_application.py
@@ -197,6 +197,7 @@ class TestPerlApplication(TestApplicationPerl):
self.assertEqual(self.get()['status'], 200, 'init')
+ body = '0123456789' * 500
(resp, sock) = self.post(
headers={
'Host': 'localhost',
@@ -204,12 +205,13 @@ class TestPerlApplication(TestApplicationPerl):
'Content-Type': 'text/html',
},
start=True,
- body='0123456789' * 500,
+ body=body,
read_timeout=1,
)
- self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1')
+ self.assertEqual(resp['body'], body, 'keep-alive 1')
+ body = '0123456789'
resp = self.post(
headers={
'Host': 'localhost',
@@ -217,10 +219,10 @@ class TestPerlApplication(TestApplicationPerl):
'Content-Type': 'text/html',
},
sock=sock,
- body='0123456789',
+ body=body,
)
- self.assertEqual(resp['body'], '0123456789', 'keep-alive 2')
+ self.assertEqual(resp['body'], body, 'keep-alive 2')
def test_perl_body_io_fake(self):
self.load('body_io_fake')
diff --git a/test/test_php_application.py b/test/test_php_application.py
index c3645a99..48e1e815 100644
--- a/test/test_php_application.py
+++ b/test/test_php_application.py
@@ -183,6 +183,7 @@ class TestPHPApplication(TestApplicationPHP):
self.assertEqual(self.get()['status'], 200, 'init')
+ body = '0123456789' * 500
(resp, sock) = self.post(
headers={
'Host': 'localhost',
@@ -190,12 +191,13 @@ class TestPHPApplication(TestApplicationPHP):
'Content-Type': 'text/html',
},
start=True,
- body='0123456789' * 500,
+ body=body,
read_timeout=1,
)
- self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1')
+ self.assertEqual(resp['body'], body, 'keep-alive 1')
+ body = '0123456789'
resp = self.post(
headers={
'Host': 'localhost',
@@ -203,10 +205,10 @@ class TestPHPApplication(TestApplicationPHP):
'Content-Type': 'text/html',
},
sock=sock,
- body='0123456789',
+ body=body,
)
- self.assertEqual(resp['body'], '0123456789', 'keep-alive 2')
+ self.assertEqual(resp['body'], body, 'keep-alive 2')
def test_php_application_conditional(self):
self.load('conditional')
diff --git a/test/test_php_basic.py b/test/test_php_basic.py
index 7ecff1b2..5fde3e00 100644
--- a/test/test_php_basic.py
+++ b/test/test_php_basic.py
@@ -37,9 +37,6 @@ class TestPHPBasic(TestControl):
'applications',
)
- def test_php_get_applications_prefix(self):
- self.conf(self.conf_app, 'applications')
-
self.assertEqual(
self.conf_get('applications'),
{
@@ -53,9 +50,6 @@ class TestPHPBasic(TestControl):
'applications prefix',
)
- def test_php_get_applications_prefix_2(self):
- self.conf(self.conf_app, 'applications')
-
self.assertEqual(
self.conf_get('applications/app'),
{
@@ -67,9 +61,6 @@ class TestPHPBasic(TestControl):
'applications prefix 2',
)
- def test_php_get_applications_prefix_3(self):
- self.conf(self.conf_app, 'applications')
-
self.assertEqual(self.conf_get('applications/app/type'), 'php', 'type')
self.assertEqual(
self.conf_get('applications/app/processes/spare'),
@@ -86,18 +77,12 @@ class TestPHPBasic(TestControl):
'listeners',
)
- def test_php_get_listeners_prefix(self):
- self.conf(self.conf_basic)
-
self.assertEqual(
self.conf_get('listeners'),
{"*:7080": {"pass": "applications/app"}},
'listeners prefix',
)
- def test_php_get_listeners_prefix_2(self):
- self.conf(self.conf_basic)
-
self.assertEqual(
self.conf_get('listeners/*:7080'),
{"pass": "applications/app"},
@@ -147,49 +132,24 @@ class TestPHPBasic(TestControl):
def test_php_delete(self):
self.conf(self.conf_basic)
- self.assertIn(
- 'error',
- self.conf_delete('applications/app'),
- 'delete app before listener',
- )
- self.assertIn(
- 'success', self.conf_delete('listeners/*:7080'), 'delete listener'
- )
- self.assertIn(
- 'success',
- self.conf_delete('applications/app'),
- 'delete app after listener',
- )
- self.assertIn(
- 'error', self.conf_delete('applications/app'), 'delete app again'
- )
+ self.assertIn('error', self.conf_delete('applications/app'))
+ self.assertIn('success', self.conf_delete('listeners/*:7080'))
+ self.assertIn('success', self.conf_delete('applications/app'))
+ self.assertIn('error', self.conf_delete('applications/app'))
def test_php_delete_blocks(self):
self.conf(self.conf_basic)
- self.assertIn(
- 'success',
- self.conf_delete('listeners'),
- 'listeners delete',
- )
-
- self.assertIn(
- 'success',
- self.conf_delete('applications'),
- 'applications delete',
- )
-
- self.assertIn(
- 'success',
- self.conf(self.conf_app, 'applications'),
- 'listeners restore',
- )
+ self.assertIn('success', self.conf_delete('listeners'))
+ self.assertIn('success', self.conf_delete('applications'))
+ self.assertIn('success', self.conf(self.conf_app, 'applications'))
self.assertIn(
'success',
self.conf({"*:7081": {"pass": "applications/app"}}, 'listeners'),
'applications restore',
)
+
if __name__ == '__main__':
TestPHPBasic.main()
diff --git a/test/test_python_application.py b/test/test_python_application.py
index 460cc804..8d435b48 100644
--- a/test/test_python_application.py
+++ b/test/test_python_application.py
@@ -187,6 +187,7 @@ class TestPythonApplication(TestApplicationPython):
self.assertEqual(self.get()['status'], 200, 'init')
+ body = '0123456789' * 500
(resp, sock) = self.post(
headers={
'Host': 'localhost',
@@ -194,12 +195,13 @@ class TestPythonApplication(TestApplicationPython):
'Content-Type': 'text/html',
},
start=True,
- body='0123456789' * 500,
+ body=body,
read_timeout=1,
)
- self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1')
+ self.assertEqual(resp['body'], body, 'keep-alive 1')
+ body = '0123456789'
resp = self.post(
headers={
'Host': 'localhost',
@@ -207,10 +209,10 @@ class TestPythonApplication(TestApplicationPython):
'Content-Type': 'text/html',
},
sock=sock,
- body='0123456789',
+ body=body,
)
- self.assertEqual(resp['body'], '0123456789', 'keep-alive 2')
+ self.assertEqual(resp['body'], body, 'keep-alive 2')
def test_python_keepalive_reconfigure(self):
self.skip_alerts.extend(
@@ -340,14 +342,16 @@ class TestPythonApplication(TestApplicationPython):
self.assertEqual(self.get()['status'], 200, 'init')
- (resp, sock) = self.http(
+ (_, sock) = self.http(
b"""GET / HTTP/1.1
""",
start=True,
raw=True,
- read_timeout=5,
+ no_recv=True,
)
+ self.assertEqual(self.get()['status'], 200)
+
self.assertIn(
'success',
self.conf({"listeners": {}, "applications": {}}),
@@ -378,6 +382,38 @@ Connection: close
self.wait_for_record(r'At exit called\.'), 'atexit'
)
+ def test_python_process_switch(self):
+ self.load('delayed')
+
+ self.assertIn(
+ 'success',
+ self.conf('2', 'applications/delayed/processes'),
+ 'configure 2 processes',
+ )
+
+ self.get(headers={
+ 'Host': 'localhost',
+ 'Content-Length': '0',
+ 'X-Delay': '5',
+ 'Connection': 'close',
+ }, no_recv=True)
+
+ headers_delay_1 = {
+ 'Connection': 'close',
+ 'Host': 'localhost',
+ 'Content-Length': '0',
+ 'X-Delay': '1',
+ }
+
+ self.get(headers=headers_delay_1, no_recv=True)
+
+ time.sleep(0.5)
+
+ for _ in range(10):
+ self.get(headers=headers_delay_1, no_recv=True)
+
+ self.get(headers=headers_delay_1)
+
@unittest.skip('not yet')
def test_python_application_start_response_exit(self):
self.load('start_response_exit')
diff --git a/test/test_python_basic.py b/test/test_python_basic.py
index 67a5f548..3233fca2 100644
--- a/test/test_python_basic.py
+++ b/test/test_python_basic.py
@@ -19,17 +19,9 @@ class TestPythonBasic(TestControl):
}
def test_python_get_empty(self):
- self.assertEqual(
- self.conf_get(), {'listeners': {}, 'applications': {}}, 'empty'
- )
-
- def test_python_get_prefix_listeners(self):
- self.assertEqual(self.conf_get('listeners'), {}, 'listeners prefix')
-
- def test_python_get_prefix_applications(self):
- self.assertEqual(
- self.conf_get('applications'), {}, 'applications prefix'
- )
+ self.assertEqual(self.conf_get(), {'listeners': {}, 'applications': {}})
+ self.assertEqual(self.conf_get('listeners'), {})
+ self.assertEqual(self.conf_get('applications'), {})
def test_python_get_applications(self):
self.conf(self.conf_app, 'applications')
@@ -50,9 +42,6 @@ class TestPythonBasic(TestControl):
'applications',
)
- def test_python_get_applications_prefix(self):
- self.conf(self.conf_app, 'applications')
-
self.assertEqual(
self.conf_get('applications'),
{
@@ -66,9 +55,6 @@ class TestPythonBasic(TestControl):
'applications prefix',
)
- def test_python_get_applications_prefix_2(self):
- self.conf(self.conf_app, 'applications')
-
self.assertEqual(
self.conf_get('applications/app'),
{
@@ -80,9 +66,6 @@ class TestPythonBasic(TestControl):
'applications prefix 2',
)
- def test_python_get_applications_prefix_3(self):
- self.conf(self.conf_app, 'applications')
-
self.assertEqual(
self.conf_get('applications/app/type'), 'python', 'type'
)
@@ -99,18 +82,12 @@ class TestPythonBasic(TestControl):
'listeners',
)
- def test_python_get_listeners_prefix(self):
- self.conf(self.conf_basic)
-
self.assertEqual(
self.conf_get('listeners'),
{"*:7080": {"pass": "applications/app"}},
'listeners prefix',
)
- def test_python_get_listeners_prefix_2(self):
- self.conf(self.conf_basic)
-
self.assertEqual(
self.conf_get('listeners/*:7080'),
{"pass": "applications/app"},
@@ -160,44 +137,18 @@ class TestPythonBasic(TestControl):
def test_python_delete(self):
self.conf(self.conf_basic)
- self.assertIn(
- 'error',
- self.conf_delete('applications/app'),
- 'delete app before listener',
- )
- self.assertIn(
- 'success', self.conf_delete('listeners/*:7080'), 'delete listener'
- )
- self.assertIn(
- 'success',
- self.conf_delete('applications/app'),
- 'delete app after listener',
- )
- self.assertIn(
- 'error', self.conf_delete('applications/app'), 'delete app again'
- )
+ self.assertIn('error', self.conf_delete('applications/app'))
+ self.assertIn('success', self.conf_delete('listeners/*:7080'))
+ self.assertIn('success', self.conf_delete('applications/app'))
+ self.assertIn('error', self.conf_delete('applications/app'))
def test_python_delete_blocks(self):
self.conf(self.conf_basic)
- self.assertIn(
- 'success',
- self.conf_delete('listeners'),
- 'listeners delete',
- )
-
- self.assertIn(
- 'success',
- self.conf_delete('applications'),
- 'applications delete',
- )
-
- self.assertIn(
- 'success',
- self.conf(self.conf_app, 'applications'),
- 'listeners restore',
- )
+ self.assertIn('success', self.conf_delete('listeners'))
+ self.assertIn('success', self.conf_delete('applications'))
+ self.assertIn('success', self.conf(self.conf_app, 'applications'))
self.assertIn(
'success',
self.conf({"*:7081": {"pass": "applications/app"}}, 'listeners'),
diff --git a/test/test_python_procman.py b/test/test_python_procman.py
index 52d8cacb..a2e6126c 100644
--- a/test/test_python_procman.py
+++ b/test/test_python_procman.py
@@ -8,6 +8,13 @@ from unit.applications.lang.python import TestApplicationPython
class TestPythonProcman(TestApplicationPython):
prerequisites = {'modules': ['python']}
+ def setUp(self):
+ super().setUp()
+
+ self.app_name = "app-" + self.testdir.split('/')[-1]
+ self.app_proc = 'applications/' + self.app_name + '/processes'
+ self.load('empty', self.app_name)
+
def pids_for_process(self):
time.sleep(0.2)
@@ -19,103 +26,20 @@ class TestPythonProcman(TestApplicationPython):
return pids
- def setUp(self):
- super().setUp()
-
- self.app_name = "app-" + self.testdir.split('/')[-1]
- self.load('empty', self.app_name)
-
- def test_python_processes_access(self):
- self.conf('1', 'applications/' + self.app_name + '/processes')
-
- self.assertIn(
- 'error',
- self.conf_get('/applications/' + self.app_name + '/processes/max'),
- 'max no access',
- )
- self.assertIn(
- 'error',
- self.conf_get(
- '/applications/' + self.app_name + '/processes/spare'
- ),
- 'spare no access',
- )
- self.assertIn(
- 'error',
- self.conf_get(
- '/applications/' + self.app_name + '/processes/idle_timeout'
- ),
- 'idle_timeout no access',
- )
-
- def test_python_processes_spare_negative(self):
- self.assertIn(
- 'error',
- self.conf(
- {"spare": -1}, 'applications/' + self.app_name + '/processes'
- ),
- 'negative spare',
- )
-
- def test_python_processes_max_negative(self):
- self.assertIn(
- 'error',
- self.conf(
- {"max": -1}, 'applications/' + self.app_name + '/processes'
- ),
- 'negative max',
- )
-
- def test_python_processes_idle_timeout_negative(self):
- self.assertIn(
- 'error',
- self.conf(
- {"idle_timeout": -1},
- 'applications/' + self.app_name + '/processes',
- ),
- 'negative idle_timeout',
- )
-
- def test_python_processes_spare_gt_max_default(self):
- self.assertIn(
- 'error',
- self.conf(
- {"spare": 2}, 'applications/' + self.app_name + '/processes'
- ),
- 'spare greater than max default',
- )
-
- def test_python_processes_spare_gt_max(self):
- self.assertIn(
- 'error',
- self.conf(
- {"spare": 2, "max": 1, "idle_timeout": 1},
- '/applications/' + self.app_name + '/processes',
- ),
- 'spare greater than max',
- )
+ def conf_proc(self, conf, path=None):
+ if path is None:
+ path = self.app_proc
- def test_python_processes_max_zero(self):
- self.assertIn(
- 'error',
- self.conf(
- {"spare": 0, "max": 0, "idle_timeout": 1},
- 'applications/' + self.app_name + '/processes',
- ),
- 'max 0',
- )
+ self.assertIn('success', self.conf(conf, path), 'configure processes')
def test_python_processes_idle_timeout_zero(self):
- self.conf(
- {"spare": 0, "max": 2, "idle_timeout": 0},
- 'applications/' + self.app_name + '/processes',
- )
+ self.conf_proc({"spare": 0, "max": 2, "idle_timeout": 0})
self.get()
self.assertEqual(len(self.pids_for_process()), 0, 'idle timeout 0')
def test_python_prefork(self):
- self.conf('2', 'applications/' + self.app_name + '/processes')
+ self.conf_proc('2')
pids = self.pids_for_process()
self.assertEqual(len(pids), 2, 'prefork 2')
@@ -123,7 +47,7 @@ class TestPythonProcman(TestApplicationPython):
self.get()
self.assertSetEqual(self.pids_for_process(), pids, 'prefork still 2')
- self.conf('4', 'applications/' + self.app_name + '/processes')
+ self.conf_proc('4')
pids = self.pids_for_process()
self.assertEqual(len(pids), 4, 'prefork 4')
@@ -135,21 +59,16 @@ class TestPythonProcman(TestApplicationPython):
@unittest.skip('not yet')
def test_python_prefork_same_processes(self):
- self.conf('2', 'applications/' + self.app_name + '/processes')
-
+ self.conf_proc('2')
pids = self.pids_for_process()
- self.conf('4', 'applications/' + self.app_name + '/processes')
-
+ self.conf_proc('4')
pids_new = self.pids_for_process()
self.assertTrue(pids.issubset(pids_new), 'prefork same processes')
def test_python_ondemand(self):
- self.conf(
- {"spare": 0, "max": 8, "idle_timeout": 1},
- 'applications/' + self.app_name + '/processes',
- )
+ self.conf_proc({"spare": 0, "max": 8, "idle_timeout": 1})
self.assertEqual(len(self.pids_for_process()), 0, 'on-demand 0')
@@ -169,10 +88,7 @@ class TestPythonProcman(TestApplicationPython):
self.stop_all()
def test_python_scale_updown(self):
- self.conf(
- {"spare": 2, "max": 8, "idle_timeout": 1},
- 'applications/' + self.app_name + '/processes',
- )
+ self.conf_proc({"spare": 2, "max": 8, "idle_timeout": 1})
pids = self.pids_for_process()
self.assertEqual(len(pids), 2, 'updown 2')
@@ -200,10 +116,7 @@ class TestPythonProcman(TestApplicationPython):
self.stop_all()
def test_python_reconfigure(self):
- self.conf(
- {"spare": 2, "max": 6, "idle_timeout": 1},
- 'applications/' + self.app_name + '/processes',
- )
+ self.conf_proc({"spare": 2, "max": 6, "idle_timeout": 1})
pids = self.pids_for_process()
self.assertEqual(len(pids), 2, 'reconf 2')
@@ -213,7 +126,7 @@ class TestPythonProcman(TestApplicationPython):
self.assertEqual(len(pids_new), 3, 'reconf 3')
self.assertTrue(pids.issubset(pids_new), 'reconf 3 only 1 new')
- self.conf('6', 'applications/' + self.app_name + '/processes/spare')
+ self.conf_proc('6', self.app_proc + '/spare')
pids = self.pids_for_process()
self.assertEqual(len(pids), 6, 'reconf 6')
@@ -224,10 +137,7 @@ class TestPythonProcman(TestApplicationPython):
self.stop_all()
def test_python_idle_timeout(self):
- self.conf(
- {"spare": 0, "max": 6, "idle_timeout": 2},
- 'applications/' + self.app_name + '/processes',
- )
+ self.conf_proc({"spare": 0, "max": 6, "idle_timeout": 2})
self.get()
pids = self.pids_for_process()
@@ -250,10 +160,7 @@ class TestPythonProcman(TestApplicationPython):
self.assertEqual(len(self.pids_for_process()), 0, 'idle timed out')
def test_python_processes_connection_keepalive(self):
- self.conf(
- {"spare": 0, "max": 6, "idle_timeout": 2},
- 'applications/' + self.app_name + '/processes',
- )
+ self.conf_proc({"spare": 0, "max": 6, "idle_timeout": 2})
(resp, sock) = self.get(
headers={'Host': 'localhost', 'Connection': 'keep-alive'},
@@ -272,6 +179,42 @@ class TestPythonProcman(TestApplicationPython):
sock.close()
+ def test_python_processes_access(self):
+ self.conf_proc('1')
+
+ path = '/' + self.app_proc
+ self.assertIn('error', self.conf_get(path + '/max'))
+ self.assertIn('error', self.conf_get(path + '/spare'))
+ self.assertIn('error', self.conf_get(path + '/idle_timeout'))
+
+ def test_python_processes_invalid(self):
+ self.assertIn(
+ 'error', self.conf({"spare": -1}, self.app_proc), 'negative spare',
+ )
+ self.assertIn(
+ 'error', self.conf({"max": -1}, self.app_proc), 'negative max',
+ )
+ self.assertIn(
+ 'error',
+ self.conf({"idle_timeout": -1}, self.app_proc),
+ 'negative idle_timeout',
+ )
+ self.assertIn(
+ 'error',
+ self.conf({"spare": 2}, self.app_proc),
+ 'spare gt max default',
+ )
+ self.assertIn(
+ 'error',
+ self.conf({"spare": 2, "max": 1}, self.app_proc),
+ 'spare gt max',
+ )
+ self.assertIn(
+ 'error',
+ self.conf({"spare": 0, "max": 0}, self.app_proc),
+ 'max zero',
+ )
+
def stop_all(self):
self.conf({"listeners": {}, "applications": {}})
diff --git a/test/test_return.py b/test/test_return.py
new file mode 100644
index 00000000..fcb51745
--- /dev/null
+++ b/test/test_return.py
@@ -0,0 +1,198 @@
+import re
+import unittest
+from unit.applications.proto import TestApplicationProto
+
+
+class TestReturn(TestApplicationProto):
+ prerequisites = {}
+
+ def setUp(self):
+ super().setUp()
+
+ self._load_conf(
+ {
+ "listeners": {"*:7080": {"pass": "routes"}},
+ "routes": [{"action": {"return": 200}}],
+ "applications": {},
+ }
+ )
+
+ def get_resps_sc(self, req=10):
+ to_send = b"""GET / HTTP/1.1
+Host: localhost
+
+""" * (
+ req - 1
+ )
+
+ to_send += b"""GET / HTTP/1.1
+Host: localhost
+Connection: close
+
+"""
+
+ return self.http(to_send, raw_resp=True, raw=True)
+
+ def test_return(self):
+ resp = self.get()
+ self.assertEqual(resp['status'], 200)
+ self.assertIn('Server', resp['headers'])
+ self.assertIn('Date', resp['headers'])
+ self.assertEqual(resp['headers']['Content-Length'], '0')
+ self.assertEqual(resp['headers']['Connection'], 'close')
+ self.assertEqual(resp['body'], '', 'body')
+
+ resp = self.post(body='blah')
+ self.assertEqual(resp['status'], 200)
+ self.assertEqual(resp['body'], '', 'body')
+
+ resp = self.get_resps_sc()
+ self.assertEqual(len(re.findall('200 OK', resp)), 10)
+ self.assertEqual(len(re.findall('Connection:', resp)), 1)
+ self.assertEqual(len(re.findall('Connection: close', resp)), 1)
+
+ resp = self.get(http_10=True)
+ self.assertEqual(resp['status'], 200)
+ self.assertIn('Server', resp['headers'])
+ self.assertIn('Date', resp['headers'])
+ self.assertEqual(resp['headers']['Content-Length'], '0')
+ self.assertNotIn('Connection', resp['headers'])
+ self.assertEqual(resp['body'], '', 'body')
+
+ def test_return_update(self):
+ self.assertIn('success', self.conf('0', 'routes/0/action/return'))
+
+ resp = self.get()
+ self.assertEqual(resp['status'], 0)
+ self.assertEqual(resp['body'], '')
+
+ self.assertIn('success', self.conf('404', 'routes/0/action/return'))
+
+ resp = self.get()
+ self.assertEqual(resp['status'], 404)
+ self.assertNotEqual(resp['body'], '')
+
+ self.assertIn('success', self.conf('598', 'routes/0/action/return'))
+
+ resp = self.get()
+ self.assertEqual(resp['status'], 598)
+ self.assertNotEqual(resp['body'], '')
+
+ self.assertIn('success', self.conf('999', 'routes/0/action/return'))
+
+ resp = self.get()
+ self.assertEqual(resp['status'], 999)
+ self.assertEqual(resp['body'], '')
+
+ def test_return_location(self):
+ reserved = ":/?#[]@!$&'()*+,;="
+ unreserved = ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+ "0123456789-._~")
+ unsafe = " \"%<>\\^`{|}"
+ unsafe_enc = "%20%22%25%3C%3E%5C%5E%60%7B%7C%7D"
+
+ def check_location(location, expect=None):
+ if expect is None:
+ expect = location
+
+ self.assertIn(
+ 'success',
+ self.conf(
+ {"return": 301, "location": location}, 'routes/0/action'
+ ),
+ 'configure location'
+ )
+
+ self.assertEqual(self.get()['headers']['Location'], expect)
+
+ # FAIL: can't specify empty header value.
+ # check_location("")
+
+ check_location(reserved)
+
+ # After first "?" all other "?" encoded.
+ check_location("/?" + reserved, "/?:/%3F#[]@!$&'()*+,;=")
+ check_location("???", "?%3F%3F")
+
+ # After first "#" all other "?" or "#" encoded.
+ check_location("/#" + reserved, "/#:/%3F%23[]@!$&'()*+,;=")
+ check_location("##?#?", "#%23%3F%23%3F")
+
+ # After first "?" next "#" not encoded.
+ check_location("/?#" + reserved, "/?#:/%3F%23[]@!$&'()*+,;=")
+ check_location("??##", "?%3F#%23")
+ check_location("/?##?", "/?#%23%3F")
+
+ # Unreserved never encoded.
+ check_location(unreserved)
+ check_location("/" + unreserved + "?" + unreserved + "#" + unreserved)
+
+ # Unsafe always encoded.
+ check_location(unsafe, unsafe_enc)
+ check_location("?" + unsafe, "?" + unsafe_enc)
+ check_location("#" + unsafe, "#" + unsafe_enc)
+
+ # %00-%20 and %7F-%FF always encoded.
+ check_location(u"\u0000\u0018\u001F\u0020\u0021", "%00%18%1F%20!")
+ check_location(u"\u007F\u0080н\u20BD", "%7F%C2%80%D0%BD%E2%82%BD")
+
+ # Encoded string detection. If at least one char need to be encoded
+ # then whole string will be encoded.
+ check_location("%20")
+ check_location("/%20?%20#%20")
+ check_location(" %20", "%20%2520")
+ check_location("%20 ", "%2520%20")
+ check_location("/%20?%20#%20 ", "/%2520?%2520#%2520%20")
+
+ def test_return_location_edit(self):
+ self.assertIn(
+ 'success',
+ self.conf(
+ {"return": 302, "location": "blah"}, 'routes/0/action'
+ ),
+ 'configure init location'
+ )
+ self.assertEqual(self.get()['headers']['Location'], 'blah')
+
+ self.assertIn(
+ 'success',
+ self.conf_delete('routes/0/action/location'),
+ 'location delete'
+ )
+ self.assertNotIn('Location', self.get()['headers'])
+
+ self.assertIn(
+ 'success',
+ self.conf('"blah"', 'routes/0/action/location'),
+ 'location restore'
+ )
+ self.assertEqual(self.get()['headers']['Location'], 'blah')
+
+ self.assertIn(
+ 'error',
+ self.conf_post('"blah"', 'routes/0/action/location'),
+ 'location method not allowed'
+ )
+ self.assertEqual(self.get()['headers']['Location'], 'blah')
+
+ def test_return_invalid(self):
+ def check_error(conf):
+ self.assertIn('error', self.conf(conf, 'routes/0/action'))
+
+ check_error({"return": "200"})
+ check_error({"return": []})
+ check_error({"return": 80.1})
+ check_error({"return": 1000})
+ check_error({"return": -1})
+ check_error({"return": 200, "share": "/blah"})
+
+ self.assertIn(
+ 'error', self.conf('001', 'routes/0/action/return'), 'leading zero'
+ )
+
+ check_error({"return": 301, "location": 0})
+ check_error({"return": 301, "location": []})
+
+
+if __name__ == '__main__':
+ TestReturn.main()
diff --git a/test/test_routing.py b/test/test_routing.py
index 950923d6..ad793662 100644
--- a/test/test_routing.py
+++ b/test/test_routing.py
@@ -16,27 +16,10 @@ class TestRouting(TestApplicationProto):
"routes": [
{
"match": {"method": "GET"},
- "action": {"pass": "applications/empty"},
+ "action": {"return": 200},
}
],
- "applications": {
- "empty": {
- "type": "python",
- "processes": {"spare": 0},
- "path": self.current_dir + '/python/empty',
- "working_directory": self.current_dir
- + '/python/empty',
- "module": "wsgi",
- },
- "mirror": {
- "type": "python",
- "processes": {"spare": 0},
- "path": self.current_dir + '/python/mirror',
- "working_directory": self.current_dir
- + '/python/mirror',
- "module": "wsgi",
- },
- },
+ "applications": {},
}
),
'routing configure',
@@ -48,18 +31,14 @@ class TestRouting(TestApplicationProto):
def route_match(self, match):
self.assertIn(
'success',
- self.route(
- {"match": match, "action": {"pass": "applications/empty"}}
- ),
+ self.route({"match": match, "action": {"return": 200}}),
'route match configure',
)
def route_match_invalid(self, match):
self.assertIn(
'error',
- self.route(
- {"match": match, "action": {"pass": "applications/empty"}}
- ),
+ self.route({"match": match, "action": {"return": 200}}),
'route match configure invalid',
)
@@ -233,24 +212,7 @@ class TestRouting(TestApplicationProto):
{
"listeners": {"*:7080": {"pass": "routes/main"}},
"routes": {"main": []},
- "applications": {
- "empty": {
- "type": "python",
- "processes": {"spare": 0},
- "path": self.current_dir + '/python/empty',
- "working_directory": self.current_dir
- + '/python/empty',
- "module": "wsgi",
- },
- "mirror": {
- "type": "python",
- "processes": {"spare": 0},
- "path": self.current_dir + '/python/mirror',
- "working_directory": self.current_dir
- + '/python/mirror',
- "module": "wsgi",
- },
- },
+ "applications": {},
}
),
'route empty configure',
@@ -272,7 +234,7 @@ class TestRouting(TestApplicationProto):
def test_routes_route_match_absent(self):
self.assertIn(
'success',
- self.conf([{"action": {"pass": "applications/empty"}}], 'routes'),
+ self.conf([{"action": {"return": 200}}], 'routes'),
'route match absent configure',
)
@@ -349,14 +311,8 @@ class TestRouting(TestApplicationProto):
'success',
self.conf(
[
- {
- "match": {"method": "GET"},
- "action": {"pass": "applications/empty"},
- },
- {
- "match": {"method": "POST"},
- "action": {"pass": "applications/mirror"},
- },
+ {"match": {"method": "GET"}, "action": {"return": 200}},
+ {"match": {"method": "POST"}, "action": {"return": 201}},
],
'routes',
),
@@ -364,18 +320,7 @@ class TestRouting(TestApplicationProto):
)
self.assertEqual(self.get()['status'], 200, 'rules two match first')
- self.assertEqual(
- self.post(
- headers={
- 'Host': 'localhost',
- 'Content-Type': 'text/html',
- 'Connection': 'close',
- },
- body='X',
- )['status'],
- 200,
- 'rules two match second',
- )
+ self.assertEqual(self.post()['status'], 201, 'rules two match second')
def test_routes_two(self):
self.assertIn(
@@ -393,20 +338,11 @@ class TestRouting(TestApplicationProto):
"second": [
{
"match": {"host": "localhost"},
- "action": {"pass": "applications/empty"},
+ "action": {"return": 200},
}
],
},
- "applications": {
- "empty": {
- "type": "python",
- "processes": {"spare": 0},
- "path": self.current_dir + '/python/empty',
- "working_directory": self.current_dir
- + '/python/empty',
- "module": "wsgi",
- }
- },
+ "applications": {},
}
),
'routes two configure',
@@ -556,7 +492,7 @@ class TestRouting(TestApplicationProto):
self.assertIn(
'success',
- self.conf([{"action": {"pass": "applications/empty"}}], 'routes'),
+ self.conf([{"action": {"return": 200}}], 'routes'),
'redefine 2',
)
self.assertEqual(self.get()['status'], 200, 'redefine request 2')
@@ -569,19 +505,8 @@ class TestRouting(TestApplicationProto):
self.conf(
{
"listeners": {"*:7080": {"pass": "routes/main"}},
- "routes": {
- "main": [{"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",
- }
- },
+ "routes": {"main": [{"action": {"return": 200}}]},
+ "applications": {},
}
),
'redefine 4',
@@ -595,25 +520,19 @@ class TestRouting(TestApplicationProto):
self.assertIn(
'success',
- self.conf_post(
- {"action": {"pass": "applications/empty"}}, 'routes/main'
- ),
+ self.conf_post({"action": {"return": 200}}, 'routes/main'),
'redefine 6',
)
self.assertEqual(self.get()['status'], 200, 'redefine request 6')
self.assertIn(
'error',
- self.conf(
- {"action": {"pass": "applications/empty"}}, 'routes/main/2'
- ),
+ self.conf({"action": {"return": 200}}, 'routes/main/2'),
'redefine 7',
)
self.assertIn(
'success',
- self.conf(
- {"action": {"pass": "applications/empty"}}, 'routes/main/1'
- ),
+ self.conf({"action": {"return": 201}}, 'routes/main/1'),
'redefine 8',
)
@@ -631,10 +550,7 @@ class TestRouting(TestApplicationProto):
self.assertIn(
'success',
self.conf_post(
- {
- "match": {"method": "POST"},
- "action": {"pass": "applications/empty"},
- },
+ {"match": {"method": "POST"}, "action": {"return": 200}},
'routes',
),
'routes edit configure 2',
@@ -654,9 +570,7 @@ class TestRouting(TestApplicationProto):
self.assertEqual(self.post()['status'], 200, 'routes edit POST 2')
self.assertIn(
- 'success',
- self.conf_delete('routes/0'),
- 'routes edit configure 3',
+ 'success', self.conf_delete('routes/0'), 'routes edit configure 3',
)
self.assertEqual(self.get()['status'], 404, 'routes edit GET 3')
@@ -682,9 +596,7 @@ class TestRouting(TestApplicationProto):
self.assertEqual(self.post()['status'], 200, 'routes edit POST 4')
self.assertIn(
- 'success',
- self.conf_delete('routes/0'),
- 'routes edit configure 5',
+ 'success', self.conf_delete('routes/0'), 'routes edit configure 5',
)
self.assertEqual(self.get()['status'], 404, 'routes edit GET 5')
@@ -693,10 +605,7 @@ class TestRouting(TestApplicationProto):
self.assertIn(
'success',
self.conf_post(
- {
- "match": {"method": "POST"},
- "action": {"pass": "applications/empty"},
- },
+ {"match": {"method": "POST"}, "action": {"return": 200}},
'routes',
),
'routes edit configure 6',
@@ -710,19 +619,8 @@ class TestRouting(TestApplicationProto):
self.conf(
{
"listeners": {"*:7080": {"pass": "routes/main"}},
- "routes": {
- "main": [{"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",
- }
- },
+ "routes": {"main": [{"action": {"return": 200}}]},
+ "applications": {},
}
),
'route edit configure 7',
@@ -1838,20 +1736,11 @@ class TestRouting(TestApplicationProto):
"second": [
{
"match": {"destination": ["127.0.0.1:7081"]},
- "action": {"pass": "applications/empty"},
+ "action": {"return": 200},
}
],
},
- "applications": {
- "empty": {
- "type": "python",
- "processes": {"spare": 0},
- "path": self.current_dir + "/python/empty",
- "working_directory": self.current_dir
- + "/python/empty",
- "module": "wsgi",
- }
- },
+ "applications": {},
}
),
'proxy configure',
diff --git a/test/test_routing_tls.py b/test/test_routing_tls.py
index c6648095..36bd9057 100644
--- a/test/test_routing_tls.py
+++ b/test/test_routing_tls.py
@@ -2,9 +2,9 @@ from unit.applications.tls import TestApplicationTLS
class TestRoutingTLS(TestApplicationTLS):
- prerequisites = {'modules': ['python', 'openssl']}
+ prerequisites = {'modules': ['openssl']}
- def test_routes_match_scheme(self):
+ def test_routes_match_scheme_tls(self):
self.certificate()
self.assertIn(
@@ -21,35 +21,21 @@ class TestRoutingTLS(TestApplicationTLS):
"routes": [
{
"match": {"scheme": "http"},
- "action": {"pass": "applications/empty"},
+ "action": {"return": 200},
},
{
"match": {"scheme": "https"},
- "action": {"pass": "applications/204_no_content"},
+ "action": {"return": 201},
},
],
- "applications": {
- "empty": {
- "type": "python",
- "processes": {"spare": 0},
- "path": self.current_dir + "/python/empty",
- "module": "wsgi",
- },
- "204_no_content": {
- "type": "python",
- "processes": {"spare": 0},
- "path": self.current_dir
- + "/python/204_no_content",
- "module": "wsgi",
- },
- },
+ "applications": {},
}
),
'scheme configure',
)
self.assertEqual(self.get()['status'], 200, 'http')
- self.assertEqual(self.get_ssl(port=7081)['status'], 204, 'https')
+ self.assertEqual(self.get_ssl(port=7081)['status'], 201, 'https')
if __name__ == '__main__':
diff --git a/test/test_ruby_application.py b/test/test_ruby_application.py
index 83a71f96..bdaabe51 100644
--- a/test/test_ruby_application.py
+++ b/test/test_ruby_application.py
@@ -322,6 +322,7 @@ class TestRubyApplication(TestApplicationRuby):
self.assertEqual(self.get()['status'], 200, 'init')
+ body = '0123456789' * 500
(resp, sock) = self.post(
headers={
'Host': 'localhost',
@@ -329,12 +330,13 @@ class TestRubyApplication(TestApplicationRuby):
'Content-Type': 'text/html',
},
start=True,
- body='0123456789' * 500,
+ body=body,
read_timeout=1,
)
- self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1')
+ self.assertEqual(resp['body'], body, 'keep-alive 1')
+ body = '0123456789'
resp = self.post(
headers={
'Host': 'localhost',
@@ -342,10 +344,10 @@ class TestRubyApplication(TestApplicationRuby):
'Content-Type': 'text/html',
},
sock=sock,
- body='0123456789',
+ body=body,
)
- self.assertEqual(resp['body'], '0123456789', 'keep-alive 2')
+ self.assertEqual(resp['body'], body, 'keep-alive 2')
def test_ruby_application_constants(self):
self.load('constants')
diff --git a/test/test_share_fallback.py b/test/test_share_fallback.py
index 8c45793e..c51e43ee 100644
--- a/test/test_share_fallback.py
+++ b/test/test_share_fallback.py
@@ -20,19 +20,10 @@ class TestStatic(TestApplicationProto):
{
"listeners": {
"*:7080": {"pass": "routes"},
- "*:7081": {"pass": "applications/empty"},
+ "*:7081": {"pass": "routes"},
},
"routes": [{"action": {"share": self.testdir + "/assets"}}],
- "applications": {
- "empty": {
- "type": "python",
- "processes": {"spare": 0},
- "path": self.current_dir + "/python/empty",
- "working_directory": self.current_dir
- + "/python/empty",
- "module": "wsgi",
- }
- },
+ "applications": {},
}
)
@@ -41,37 +32,22 @@ class TestStatic(TestApplicationProto):
super().tearDown()
+ def action_update(self, conf):
+ self.assertIn('success', self.conf(conf, 'routes/0/action'))
+
def test_fallback(self):
- self.assertIn(
- 'success',
- self.conf({"share": "/blah"}, 'routes/0/action'),
- 'configure bad path no fallback',
- )
+ self.action_update({"share": "/blah"})
self.assertEqual(self.get()['status'], 404, 'bad path no fallback')
- self.assertIn(
- 'success',
- self.conf(
- {"share": "/blah", "fallback": {"pass": "applications/empty"}},
- 'routes/0/action',
- ),
- 'configure bad path fallback',
- )
+ self.action_update({"share": "/blah", "fallback": {"return": 200}})
+
resp = self.get()
self.assertEqual(resp['status'], 200, 'bad path fallback status')
self.assertEqual(resp['body'], '', 'bad path fallback')
def test_fallback_valid_path(self):
- self.assertIn(
- 'success',
- self.conf(
- {
- "share": self.testdir + "/assets",
- "fallback": {"pass": "applications/empty"},
- },
- 'routes/0/action',
- ),
- 'configure fallback',
+ self.action_update(
+ {"share": self.testdir + "/assets", "fallback": {"return": 200}}
)
resp = self.get()
self.assertEqual(resp['status'], 200, 'fallback status')
@@ -90,36 +66,28 @@ class TestStatic(TestApplicationProto):
)
def test_fallback_nested(self):
- self.assertIn(
- 'success',
- self.conf(
- {
- "share": "/blah",
- "fallback": {
- "share": "/blah/blah",
- "fallback": {"pass": "applications/empty"},
- },
+ self.action_update(
+ {
+ "share": "/blah",
+ "fallback": {
+ "share": "/blah/blah",
+ "fallback": {"return": 200},
},
- 'routes/0/action',
- ),
- 'configure fallback nested',
+ }
)
+
resp = self.get()
self.assertEqual(resp['status'], 200, 'fallback nested status')
self.assertEqual(resp['body'], '', 'fallback nested')
def test_fallback_share(self):
- self.assertIn(
- 'success',
- self.conf(
- {
- "share": "/blah",
- "fallback": {"share": self.testdir + "/assets"},
- },
- 'routes/0/action',
- ),
- 'configure fallback share',
+ self.action_update(
+ {
+ "share": "/blah",
+ "fallback": {"share": self.testdir + "/assets"},
+ }
)
+
resp = self.get()
self.assertEqual(resp['status'], 200, 'fallback share status')
self.assertEqual(resp['body'], '0123456789', 'fallback share')
@@ -136,76 +104,51 @@ class TestStatic(TestApplicationProto):
self.assertIn(
'success',
self.conf(
- {
- "share": "/blah",
- "fallback": {"proxy": "http://127.0.0.1:7081"},
- },
- 'routes/0/action',
+ [
+ {
+ "match": {"destination": "*:7081"},
+ "action": {"return": 200},
+ },
+ {
+ "action": {
+ "share": "/blah",
+ "fallback": {"proxy": "http://127.0.0.1:7081"},
+ }
+ },
+ ],
+ 'routes',
),
- 'configure fallback proxy',
+ 'configure fallback proxy route',
)
+
resp = self.get()
self.assertEqual(resp['status'], 200, 'fallback proxy status')
self.assertEqual(resp['body'], '', 'fallback proxy')
@unittest.skip('not yet')
def test_fallback_proxy_cycle(self):
- self.assertIn(
- 'success',
- self.conf(
- {
- "share": "/blah",
- "fallback": {"proxy": "http://127.0.0.1:7080"},
- },
- 'routes/0/action',
- ),
- 'configure fallback cycle',
+ self.action_update(
+ {
+ "share": "/blah",
+ "fallback": {"proxy": "http://127.0.0.1:7080"},
+ }
)
self.assertNotEqual(self.get()['status'], 200, 'fallback cycle')
- self.assertIn(
- 'success', self.conf_delete('listeners/*:7081'), 'delete listener'
- )
+ self.assertIn('success', self.conf_delete('listeners/*:7081'))
self.assertNotEqual(self.get()['status'], 200, 'fallback cycle 2')
def test_fallback_invalid(self):
- self.assertIn(
- 'error',
- self.conf({"share": "/blah", "fallback": {}}, 'routes/0/action'),
- 'configure fallback empty',
- )
- self.assertIn(
- 'error',
- self.conf({"share": "/blah", "fallback": ""}, 'routes/0/action'),
- 'configure fallback not object',
- )
- self.assertIn(
- 'error',
- self.conf(
- {
- "proxy": "http://127.0.0.1:7081",
- "fallback": {"share": "/blah"},
- },
- 'routes/0/action',
- ),
- 'configure fallback proxy invalid',
- )
- self.assertIn(
- 'error',
- self.conf(
- {
- "pass": "applications/empty",
- "fallback": {"share": "/blah"},
- },
- 'routes/0/action',
- ),
- 'configure fallback pass invalid',
- )
- self.assertIn(
- 'error',
- self.conf({"fallback": {"share": "/blah"}}, 'routes/0/action'),
- 'configure fallback only',
+ def check_error(conf):
+ self.assertIn('error', self.conf(conf, 'routes/0/action'))
+
+ check_error({"share": "/blah", "fallback": {}})
+ check_error({"share": "/blah", "fallback": ""})
+ check_error({"return": 200, "fallback": {"share": "/blah"}})
+ check_error(
+ {"proxy": "http://127.0.0.1:7081", "fallback": {"share": "/blah"}}
)
+ check_error({"fallback": {"share": "/blah"}})
if __name__ == '__main__':
diff --git a/test/test_tls.py b/test/test_tls.py
index 475e9919..d9dcf237 100644
--- a/test/test_tls.py
+++ b/test/test_tls.py
@@ -521,7 +521,6 @@ basicConstraints = critical,CA:TRUE"""
)
def test_tls_application_respawn(self):
- self.skip_alerts.append(r'process \d+ exited on signal 9')
self.load('mirror')
self.certificate()
@@ -530,7 +529,7 @@ basicConstraints = critical,CA:TRUE"""
self.add_tls(application='mirror')
- (resp, sock) = self.post_ssl(
+ (_, sock) = self.post_ssl(
headers={
'Host': 'localhost',
'Connection': 'keep-alive',
@@ -545,6 +544,8 @@ basicConstraints = critical,CA:TRUE"""
subprocess.call(['kill', '-9', app_id])
+ self.skip_alerts.append(r'process %s exited on signal 9' % app_id)
+
self.wait_for_record(
re.compile(
' (?!' + app_id + '#)(\d+)#\d+ "mirror" application started'
diff --git a/test/test_upstreams_rr.py b/test/test_upstreams_rr.py
index 2bc2d90a..7045318a 100644
--- a/test/test_upstreams_rr.py
+++ b/test/test_upstreams_rr.py
@@ -16,10 +16,10 @@ class TestUpstreamsRR(TestApplicationPython):
{
"listeners": {
"*:7080": {"pass": "upstreams/one"},
- "*:7081": {"pass": "applications/ups_0"},
- "*:7082": {"pass": "applications/ups_1"},
- "*:7083": {"pass": "applications/ups_2"},
"*:7090": {"pass": "upstreams/two"},
+ "*:7081": {"pass": "routes/one"},
+ "*:7082": {"pass": "routes/two"},
+ "*:7083": {"pass": "routes/three"},
},
"upstreams": {
"one": {
@@ -35,32 +35,12 @@ class TestUpstreamsRR(TestApplicationPython):
},
},
},
- "applications": {
- "ups_0": {
- "type": "python",
- "processes": {"spare": 0},
- "path": self.current_dir + "/python/upstreams/0",
- "working_directory": self.current_dir
- + "/python/upstreams/0",
- "module": "wsgi",
- },
- "ups_1": {
- "type": "python",
- "processes": {"spare": 0},
- "path": self.current_dir + "/python/upstreams/1",
- "working_directory": self.current_dir
- + "/python/upstreams/1",
- "module": "wsgi",
- },
- "ups_2": {
- "type": "python",
- "processes": {"spare": 0},
- "path": self.current_dir + "/python/upstreams/2",
- "working_directory": self.current_dir
- + "/python/upstreams/2",
- "module": "wsgi",
- },
+ "routes": {
+ "one": [{"action": {"return": 200}}],
+ "two": [{"action": {"return": 201}}],
+ "three": [{"action": {"return": 202}}],
},
+ "applications": {},
},
),
'upstreams initial configuration',
@@ -70,15 +50,17 @@ class TestUpstreamsRR(TestApplicationPython):
def get_resps(self, req=100, port=7080):
resps = [0]
+
for _ in range(req):
- headers = self.get(port=port)['headers']
- if 'X-Upstream' in headers:
- ups = int(headers['X-Upstream'])
+ status = self.get(port=port)['status']
+ if 200 > status or status > 209:
+ continue
- if ups > len(resps) - 1:
- resps.extend([0] * (ups - len(resps) + 1))
+ ups = status % 10
+ if ups > len(resps) - 1:
+ resps.extend([0] * (ups - len(resps) + 1))
- resps[ups] += 1
+ resps[ups] += 1
return resps
@@ -97,16 +79,19 @@ Connection: close
"""
resp = self.http(to_send, raw_resp=True, raw=True, port=port)
- ups = re.findall('X-Upstream: (\d+)', resp)
- resps = [0] * (int(max(ups)) + 1)
+ status = re.findall(r'HTTP\/\d\.\d\s(\d\d\d)', resp)
+ status = list(filter(lambda x: x[:2] == '20', status))
+ ups = list(map(lambda x: int(x[-1]), status))
+ resps = [0] * (max(ups) + 1)
for i in range(len(ups)):
- resps[int(ups[i])] += 1
+ resps[ups[i]] += 1
return resps
def test_upstreams_rr_no_weight(self):
resps = self.get_resps()
+ self.assertEqual(sum(resps), 100, 'no weight sum')
self.assertLessEqual(
abs(resps[0] - resps[1]), self.cpu_count, 'no weight'
)
@@ -127,6 +112,7 @@ Connection: close
)
resps = self.get_resps()
+ self.assertEqual(sum(resps), 100, 'no weight 3 sum')
self.assertLessEqual(
abs(resps[0] - resps[1]), self.cpu_count, 'no weight 3'
)
@@ -138,6 +124,7 @@ Connection: close
)
resps = self.get_resps()
+ self.assertEqual(sum(resps), 100, 'no weight 4 sum')
self.assertLessEqual(
max(resps) - min(resps), self.cpu_count, 'no weight 4'
)
@@ -193,6 +180,67 @@ Connection: close
self.assertEqual(resps[0], 60, 'weight 2 0')
self.assertEqual(resps[2], 40, 'weight 2 1')
+ def test_upstreams_rr_weight_rational(self):
+ def set_weights(w1, w2):
+ self.assertIn(
+ 'success',
+ self.conf(
+ {
+ "127.0.0.1:7081": {"weight": w1},
+ "127.0.0.1:7082": {"weight": w2},
+ },
+ 'upstreams/one/servers',
+ ),
+ 'configure weights',
+ )
+
+ def check_reqs(w1, w2, reqs=10):
+ resps = self.get_resps_sc(req=reqs)
+ self.assertEqual(resps[0], reqs * w1 / (w1 + w2), 'weight 1')
+ self.assertEqual(resps[1], reqs * w2 / (w1 + w2), 'weight 2')
+
+ def check_weights(w1, w2):
+ set_weights(w1, w2)
+ check_reqs(w1, w2)
+
+ check_weights(0, 1)
+ check_weights(0, 999999.0123456)
+ check_weights(1, 9)
+ check_weights(100000, 900000)
+ check_weights(1, .25)
+ check_weights(1, 0.25)
+ check_weights(0.2, .8)
+ check_weights(1, 1.5)
+ check_weights(1e-3, 1E-3)
+ check_weights(1e-20, 1e-20)
+ check_weights(1e4, 1e4)
+ check_weights(1000000, 1000000)
+
+ set_weights(0.25, 0.25)
+ self.assertIn(
+ 'success',
+ self.conf_delete('upstreams/one/servers/127.0.0.1:7081/weight'),
+ 'delete weight',
+ )
+ check_reqs(1, 0.25)
+
+ self.assertIn(
+ 'success',
+ self.conf(
+ {
+ "127.0.0.1:7081": {"weight": 0.1},
+ "127.0.0.1:7082": {"weight": 1},
+ "127.0.0.1:7083": {"weight": 0.9},
+ },
+ 'upstreams/one/servers',
+ ),
+ 'configure weights',
+ )
+ resps = self.get_resps_sc(req=20)
+ self.assertEqual(resps[0], 1, 'weight 3 1')
+ self.assertEqual(resps[1], 10, 'weight 3 2')
+ self.assertEqual(resps[2], 9, 'weight 3 3')
+
def test_upstreams_rr_independent(self):
def sum_resps(*args):
sum = [0] * len(args[0])
@@ -234,33 +282,71 @@ Connection: close
r_one = sum_resps(r_one, self.get_resps(req=10))
r_two = sum_resps(r_two, self.get_resps(req=10, port=7090))
+
+ self.assertEqual(sum(r_one), 100, 'dep one mix sum')
self.assertLessEqual(
abs(r_one[0] - r_one[1]), self.cpu_count, 'dep one mix'
)
+ self.assertEqual(sum(r_two), 100, 'dep two mix sum')
self.assertLessEqual(
abs(r_two[0] - r_two[1]), self.cpu_count, 'dep two mix'
)
def test_upstreams_rr_delay(self):
- headers_delay_1 = {
- 'Connection': 'close',
- 'Host': 'localhost',
- 'Content-Length': '0',
- 'X-Delay': '1',
- }
- headers_no_delay = {
- 'Connection': 'close',
- 'Host': 'localhost',
- 'Content-Length': '0',
- }
+ self.assertIn(
+ 'success',
+ self.conf(
+ {
+ "listeners": {
+ "*:7080": {"pass": "upstreams/one"},
+ "*:7081": {"pass": "routes"},
+ "*:7082": {"pass": "routes"},
+ },
+ "upstreams": {
+ "one": {
+ "servers": {
+ "127.0.0.1:7081": {},
+ "127.0.0.1:7082": {},
+ },
+ },
+ },
+ "routes": [
+ {
+ "match": {"destination": "*:7081"},
+ "action": {"pass": "applications/delayed"},
+ },
+ {
+ "match": {"destination": "*:7082"},
+ "action": {"return": 201},
+ },
+ ],
+ "applications": {
+ "delayed": {
+ "type": "python",
+ "processes": {"spare": 0},
+ "path": self.current_dir + "/python/delayed",
+ "working_directory": self.current_dir
+ + "/python/delayed",
+ "module": "wsgi",
+ }
+ },
+ },
+ ),
+ 'upstreams initial configuration',
+ )
req = 50
socks = []
for i in range(req):
- headers = headers_delay_1 if i % 5 == 0 else headers_no_delay
+ delay = 1 if i % 5 == 0 else 0
_, sock = self.get(
- headers=headers,
+ headers={
+ 'Host': 'localhost',
+ 'Content-Length': '0',
+ 'X-Delay': str(delay),
+ 'Connection': 'close',
+ },
start=True,
no_recv=True,
)
@@ -271,12 +357,12 @@ Connection: close
resp = self.recvall(socks[i]).decode()
socks[i].close()
- m = re.search('X-Upstream: (\d+)', resp)
+ m = re.search('HTTP/1.1 20(\d)', resp)
+ self.assertIsNotNone(m, 'status')
resps[int(m.group(1))] += 1
- self.assertLessEqual(
- abs(resps[0] - resps[1]), self.cpu_count, 'dep two mix'
- )
+ self.assertEqual(sum(resps), req, 'delay sum')
+ self.assertLessEqual(abs(resps[0] - resps[1]), self.cpu_count, 'delay')
def test_upstreams_rr_active_req(self):
conns = 5
@@ -303,7 +389,7 @@ Connection: close
# Send one more request and read response to make sure that previous
# requests had enough time to reach server.
- self.assertEqual(self.get()['status'], 200)
+ self.assertEqual(self.get()['body'], '')
self.assertIn(
'success',
@@ -327,13 +413,17 @@ Connection: close
)
for i in range(conns):
- resp = self.recvall(socks[i]).decode()
- socks[i].close()
-
- self.assertRegex(resp, r'X-Upstream', 'active req GET')
+ self.assertEqual(
+ self.http(b'', sock=socks[i], raw=True)['body'],
+ '',
+ 'active req GET',
+ )
- resp = self.http(b"""0123456789""", sock=socks2[i], raw=True)
- self.assertEqual(resp['status'], 200, 'active req POST')
+ self.assertEqual(
+ self.http(b"""0123456789""", sock=socks2[i], raw=True)['body'],
+ '',
+ 'active req POST',
+ )
def test_upstreams_rr_bad_server(self):
self.assertIn(
@@ -356,14 +446,11 @@ Connection: close
def test_upstreams_rr_post(self):
resps = [0, 0]
for _ in range(50):
- resps[
- int(self.post(body='0123456789')['headers']['X-Upstream'])
- ] += 1
- resps[int(self.get()['headers']['X-Upstream'])] += 1
+ resps[self.get()['status'] % 10] += 1
+ resps[self.post(body='0123456789')['status'] % 10] += 1
- self.assertLessEqual(
- abs(resps[0] - resps[1]), self.cpu_count, 'post'
- )
+ self.assertEqual(sum(resps), 100, 'post sum')
+ self.assertLessEqual(abs(resps[0] - resps[1]), self.cpu_count, 'post')
def test_upstreams_rr_unix(self):
addr_0 = self.testdir + '/sock_0'
@@ -374,8 +461,8 @@ Connection: close
self.conf(
{
"*:7080": {"pass": "upstreams/one"},
- "unix:" + addr_0: {"pass": "applications/ups_0"},
- "unix:" + addr_1: {"pass": "applications/ups_1"},
+ "unix:" + addr_0: {"pass": "routes/one"},
+ "unix:" + addr_1: {"pass": "routes/two"},
},
'listeners',
),
@@ -385,7 +472,7 @@ Connection: close
self.assertIn(
'success',
self.conf(
- {"unix:" + addr_0: {}, "unix:" + addr_1: {},},
+ {"unix:" + addr_0: {}, "unix:" + addr_1: {}},
'upstreams/one/servers',
),
'configure servers unix',
@@ -402,8 +489,8 @@ Connection: close
self.conf(
{
"*:7080": {"pass": "upstreams/one"},
- "[::1]:7081": {"pass": "applications/ups_0"},
- "[::1]:7082": {"pass": "applications/ups_1"},
+ "[::1]:7081": {"pass": "routes/one"},
+ "[::1]:7082": {"pass": "routes/two"},
},
'listeners',
),
@@ -413,7 +500,7 @@ Connection: close
self.assertIn(
'success',
self.conf(
- {"[::1]:7081": {}, "[::1]:7082": {},}, 'upstreams/one/servers'
+ {"[::1]:7081": {}, "[::1]:7082": {}}, 'upstreams/one/servers'
),
'configure servers ipv6',
)
@@ -429,9 +516,29 @@ Connection: close
self.conf({}, 'upstreams/one/servers'),
'configure servers empty',
)
-
self.assertEqual(self.get()['status'], 502, 'servers empty')
+ self.assertIn(
+ 'success',
+ self.conf(
+ {"127.0.0.1:7081": {"weight": 0}}, 'upstreams/one/servers'
+ ),
+ 'configure servers empty one',
+ )
+ self.assertEqual(self.get()['status'], 502, 'servers empty one')
+ self.assertIn(
+ 'success',
+ self.conf(
+ {
+ "127.0.0.1:7081": {"weight": 0},
+ "127.0.0.1:7082": {"weight": 0},
+ },
+ 'upstreams/one/servers',
+ ),
+ 'configure servers empty two',
+ )
+ self.assertEqual(self.get()['status'], 502, 'servers empty two')
+
def test_upstreams_rr_invalid(self):
self.assertIn(
'error', self.conf({}, 'upstreams'), 'upstreams empty',
@@ -449,16 +556,21 @@ Connection: close
self.conf({}, 'upstreams/one/servers/127.0.0.1:7081/blah'),
'invalid server option',
)
- self.assertIn(
- 'error',
- self.conf({}, 'upstreams/one/servers/127.0.0.1:7081/weight'),
- 'invalid weight option',
- )
- self.assertIn(
- 'error',
- self.conf('-1', 'upstreams/one/servers/127.0.0.1:7081/weight'),
- 'invalid negative weight',
- )
+
+ def check_weight(w):
+ self.assertIn(
+ 'error',
+ self.conf(w, 'upstreams/one/servers/127.0.0.1:7081/weight'),
+ 'invalid weight option',
+ )
+ check_weight({})
+ check_weight('-1')
+ check_weight('1.')
+ check_weight('1.1.')
+ check_weight('.')
+ check_weight('.01234567890123')
+ check_weight('1000001')
+ check_weight('2e6')
if __name__ == '__main__':
diff --git a/test/test_usr1.py b/test/test_usr1.py
index 2b4f394b..155303ea 100644
--- a/test/test_usr1.py
+++ b/test/test_usr1.py
@@ -51,12 +51,11 @@ class TestUSR1(TestApplicationPython):
self.search_in_log(r'/usr1', log_new), 'rename new 2'
)
- @unittest.skip('not yet')
def test_usr1_unit_log(self):
self.load('log_body')
log_new = 'new.log'
- log_path = self.testdir + '/' + 'unit.log'
+ log_path = self.testdir + '/unit.log'
log_path_new = self.testdir + '/' + log_new
os.rename(log_path, log_path_new)
diff --git a/test/unit/applications/websockets.py b/test/unit/applications/websockets.py
index ef16f433..fc15e8e4 100644
--- a/test/unit/applications/websockets.py
+++ b/test/unit/applications/websockets.py
@@ -52,7 +52,11 @@ class TestApplicationWebsocket(TestApplicationProto):
)
resp = ''
- while select.select([sock], [], [], 30)[0]:
+ while True:
+ rlist = select.select([sock], [], [], 60)[0]
+ if not rlist:
+ self.fail('Can\'t read response from server.')
+
resp += sock.recv(4096).decode()
if (
@@ -70,10 +74,18 @@ class TestApplicationWebsocket(TestApplicationProto):
def serialize_close(self, code=1000, reason=''):
return struct.pack('!H', code) + reason.encode('utf-8')
- def frame_read(self, sock, read_timeout=30):
+ def frame_read(self, sock, read_timeout=60):
def recv_bytes(sock, bytes):
data = b''
- while select.select([sock], [], [], read_timeout)[0]:
+ while True:
+ rlist = select.select([sock], [], [], read_timeout)[0]
+ if not rlist:
+ # For all current cases if the "read_timeout" was changed
+ # than test do not expect to get a response from server.
+ if read_timeout == 60:
+ self.fail('Can\'t read response from server.')
+ break
+
data += sock.recv(bytes - len(data))
if len(data) == bytes:
@@ -221,7 +233,7 @@ class TestApplicationWebsocket(TestApplicationProto):
op_code = self.OP_CONT
pos = end
- def message_read(self, sock, read_timeout=10):
+ def message_read(self, sock, read_timeout=60):
frame = self.frame_read(sock, read_timeout=read_timeout)
while not frame['fin']:
diff --git a/test/unit/http.py b/test/unit/http.py
index 47fb48f1..13384dc8 100644
--- a/test/unit/http.py
+++ b/test/unit/http.py
@@ -17,11 +17,6 @@ class TestHTTP(TestUnit):
port = 7080 if 'port' not in kwargs else kwargs['port']
url = '/' if 'url' not in kwargs else kwargs['url']
http = 'HTTP/1.0' if 'http_10' in kwargs else 'HTTP/1.1'
- read_buffer_size = (
- 4096
- if 'read_buffer_size' not in kwargs
- else kwargs['read_buffer_size']
- )
headers = (
{'Host': 'localhost', 'Connection': 'close'}
@@ -60,7 +55,7 @@ class TestHTTP(TestUnit):
sock.connect(connect_args)
except ConnectionRefusedError:
sock.close()
- return None
+ self.fail('Client can\'t connect to the server.')
else:
sock = kwargs['sock']
@@ -101,12 +96,15 @@ class TestHTTP(TestUnit):
resp = ''
if 'no_recv' not in kwargs:
- 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(encoding)
+ recvall_kwargs = {}
+
+ if 'read_timeout' in kwargs:
+ recvall_kwargs['read_timeout'] = kwargs['read_timeout']
+
+ if 'read_buffer_size' in kwargs:
+ recvall_kwargs['buff_size'] = kwargs['read_buffer_size']
+
+ resp = self.recvall(sock, **recvall_kwargs).decode(encoding)
self.log_in(resp)
@@ -174,9 +172,26 @@ class TestHTTP(TestUnit):
def put(self, **kwargs):
return self.http('PUT', **kwargs)
- def recvall(self, sock, read_timeout=30, buff_size=4096):
+ def recvall(self, sock, **kwargs):
+ timeout_default = 60
+
+ timeout = (
+ timeout_default
+ if 'read_timeout' not in kwargs
+ else kwargs['read_timeout']
+ )
+ buff_size = 4096 if 'buff_size' not in kwargs else kwargs['buff_size']
+
data = b''
- while select.select([sock], [], [], read_timeout)[0]:
+ while True:
+ rlist = select.select([sock], [], [], timeout)[0]
+ if not rlist:
+ # For all current cases if the "read_timeout" was changed
+ # than test do not expect to get a response from server.
+ if timeout == timeout_default:
+ self.fail('Can\'t read response from server.')
+ break
+
try:
part = sock.recv(buff_size)
except:
@@ -264,12 +279,8 @@ class TestHTTP(TestUnit):
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',
- )
+ self.assertIn('Content-Type', headers)
+ self.assertEqual(headers['Content-Type'], 'application/json')
resp['body'] = json.loads(resp['body'])
diff --git a/test/unit/main.py b/test/unit/main.py
index 69234dcc..4507f71a 100644
--- a/test/unit/main.py
+++ b/test/unit/main.py
@@ -4,6 +4,7 @@ import sys
import stat
import time
import fcntl
+import atexit
import shutil
import signal
import argparse
@@ -151,48 +152,6 @@ class TestUnit(unittest.TestCase):
def setUp(self):
self._run()
- def tearDown(self):
- self.stop()
-
- # detect errors and failures for current test
-
- def list2reason(exc_list):
- if exc_list and exc_list[-1][0] is self:
- return exc_list[-1][1]
-
- if hasattr(self, '_outcome'):
- result = self.defaultTestResult()
- self._feedErrorsToResult(result, self._outcome.errors)
- else:
- result = getattr(
- self, '_outcomeForDoCleanups', self._resultForDoCleanups
- )
-
- success = not list2reason(result.errors) and not list2reason(
- result.failures
- )
-
- # check unit.log for alerts
-
- unit_log = self.testdir + '/unit.log'
-
- with open(unit_log, 'r', encoding='utf-8', errors='ignore') as f:
- self._check_alerts(f.read())
-
- # remove unit.log
-
- if not TestUnit.save_log and success:
- shutil.rmtree(self.testdir)
-
- else:
- self._print_log()
-
- def stop(self):
- if self._started:
- self._stop()
-
- self.stop_processes()
-
def _run(self):
build_dir = self.pardir + '/build'
self.unitd = build_dir + '/unitd'
@@ -224,62 +183,81 @@ class TestUnit(unittest.TestCase):
stderr=log,
)
+ atexit.register(self.stop)
+
if not self.waitforfiles(self.testdir + '/control.unit.sock'):
exit("Could not start unit")
- self._started = True
-
self.skip_alerts = [
r'read signalfd\(4\) failed',
- r'last message send failed',
r'sendmsg.+failed',
r'recvmsg.+failed',
]
self.skip_sanitizer = False
- def _stop(self):
- with self._p as p:
- p.send_signal(signal.SIGQUIT)
+ def tearDown(self):
+ stop_errs = self.stop()
- try:
- retcode = p.wait(15)
- if retcode:
- self.fail(
- "Child process terminated with code " + str(retcode)
- )
- except:
- self.fail("Could not terminate unit")
- p.kill()
+ # detect errors and failures for current test
- self._started = False
+ def list2reason(exc_list):
+ if exc_list and exc_list[-1][0] is self:
+ return exc_list[-1][1]
- def _check_alerts(self, log):
- found = False
+ if hasattr(self, '_outcome'):
+ result = self.defaultTestResult()
+ self._feedErrorsToResult(result, self._outcome.errors)
+ else:
+ result = getattr(
+ self, '_outcomeForDoCleanups', self._resultForDoCleanups
+ )
- alerts = re.findall('.+\[alert\].+', log)
+ success = not list2reason(result.errors) and not list2reason(
+ result.failures
+ )
- if alerts:
- print('All alerts/sanitizer errors found in log:')
- [print(alert) for alert in alerts]
- found = True
+ # check unit.log for alerts
- if self.skip_alerts:
- for skip in self.skip_alerts:
- alerts = [al for al in alerts if re.search(skip, al) is None]
+ unit_log = self.testdir + '/unit.log'
- if alerts:
- self._print_log(log)
- self.assertFalse(alerts, 'alert(s)')
+ with open(unit_log, 'r', encoding='utf-8', errors='ignore') as f:
+ self._check_alerts(f.read())
- if not self.skip_sanitizer:
- sanitizer_errors = re.findall('.+Sanitizer.+', log)
+ # remove unit.log
- if sanitizer_errors:
- self._print_log(log)
- self.assertFalse(sanitizer_errors, 'sanitizer error(s)')
+ if not TestUnit.save_log and success:
+ shutil.rmtree(self.testdir)
- if found:
- print('skipped.')
+ else:
+ self._print_log()
+
+ self.assertListEqual(stop_errs, [None, None], 'stop errors')
+
+ def stop(self):
+ errors = []
+
+ errors.append(self._stop())
+
+ errors.append(self.stop_processes())
+
+ atexit.unregister(self.stop)
+
+ return errors
+
+ def _stop(self):
+ if self._p.poll() is not None:
+ return
+
+ with self._p as p:
+ p.send_signal(signal.SIGQUIT)
+
+ try:
+ retcode = p.wait(15)
+ if retcode:
+ return 'Child process terminated with code ' + str(retcode)
+ except:
+ p.kill()
+ return 'Could not terminate unit'
def run_process(self, target, *args):
if not hasattr(self, '_processes'):
@@ -294,12 +272,17 @@ class TestUnit(unittest.TestCase):
if not hasattr(self, '_processes'):
return
+ fail = False
for process in self._processes:
- process.terminate()
- process.join(timeout=5)
-
if process.is_alive():
- self.fail('Fail to stop process')
+ process.terminate()
+ process.join(timeout=15)
+
+ if process.is_alive():
+ fail = True
+
+ if fail:
+ return 'Fail to stop process'
def waitforfiles(self, *files):
for i in range(50):
@@ -329,6 +312,34 @@ class TestUnit(unittest.TestCase):
for f in files:
os.chmod(os.path.join(root, f), 0o777)
+ def _check_alerts(self, log):
+ found = False
+
+ alerts = re.findall('.+\[alert\].+', log)
+
+ if alerts:
+ print('All alerts/sanitizer errors found in log:')
+ [print(alert) for alert in alerts]
+ found = True
+
+ if self.skip_alerts:
+ for skip in self.skip_alerts:
+ alerts = [al for al in alerts if re.search(skip, al) is None]
+
+ if alerts:
+ self._print_log(log)
+ self.assertFalse(alerts, 'alert(s)')
+
+ if not self.skip_sanitizer:
+ sanitizer_errors = re.findall('.+Sanitizer.+', log)
+
+ if sanitizer_errors:
+ self._print_log(log)
+ self.assertFalse(sanitizer_errors, 'sanitizer error(s)')
+
+ if found:
+ print('skipped.')
+
@staticmethod
def _parse_args():
parser = argparse.ArgumentParser(add_help=False)