Tests: style.

This commit is contained in:
Andrey Zelenkov
2019-03-26 23:38:30 +03:00
parent 3d7a47c9ac
commit 281899fcef
18 changed files with 4091 additions and 2312 deletions

View File

@@ -5,8 +5,8 @@ from subprocess import call
import unittest import unittest
import unit import unit
class TestUnitAccessLog(unit.TestUnitApplicationPython):
class TestUnitAccessLog(unit.TestUnitApplicationPython):
def setUpClass(): def setUpClass():
unit.TestUnit().check_modules('python') unit.TestUnit().check_modules('python')
@@ -22,34 +22,45 @@ class TestUnitAccessLog(unit.TestUnitApplicationPython):
def test_access_log_keepalive(self): def test_access_log_keepalive(self):
self.load('mirror') self.load('mirror')
(resp, sock) = self.post(headers={ (resp, sock) = self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Connection': 'keep-alive', 'Connection': 'keep-alive',
'Content-Type': 'text/html' 'Content-Type': 'text/html',
}, start=True, body='01234') },
start=True,
body='01234',
)
time.sleep(0.2) time.sleep(0.2)
self.assertIsNotNone( self.assertIsNotNone(
self.search_in_log(r'"POST / HTTP/1.1" 200 5'), 'keepalive 1') self.search_in_log(r'"POST / HTTP/1.1" 200 5'), 'keepalive 1'
)
resp = self.post(headers={ resp = self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Connection': 'close', 'Connection': 'close',
'Content-Type': 'text/html' 'Content-Type': 'text/html',
}, sock=sock, body='0123456789') },
sock=sock,
body='0123456789',
)
time.sleep(0.2) time.sleep(0.2)
self.stop() self.stop()
self.assertIsNotNone( self.assertIsNotNone(
self.search_in_log(r'"POST / HTTP/1.1" 200 10'), 'keepalive 2') self.search_in_log(r'"POST / HTTP/1.1" 200 10'), 'keepalive 2'
)
def test_access_log_pipeline(self): def test_access_log_pipeline(self):
self.load('empty') self.load('empty')
self.http(b"""GET / HTTP/1.1 self.http(
b"""GET / HTTP/1.1
Host: localhost Host: localhost
Referer: Referer-1 Referer: Referer-1
@@ -62,7 +73,10 @@ Host: localhost
Referer: Referer-3 Referer: Referer-3
Connection: close Connection: close
""", raw_resp=True, raw=True) """,
raw_resp=True,
raw=True,
)
time.sleep(0.2) time.sleep(0.2)
@@ -70,22 +84,21 @@ Connection: close
self.assertIsNotNone( self.assertIsNotNone(
self.search_in_log(r'"GET / HTTP/1.1" 200 0 "Referer-1" "-"'), self.search_in_log(r'"GET / HTTP/1.1" 200 0 "Referer-1" "-"'),
'pipeline 1') 'pipeline 1',
)
self.assertIsNotNone( self.assertIsNotNone(
self.search_in_log(r'"GET / HTTP/1.1" 200 0 "Referer-2" "-"'), self.search_in_log(r'"GET / HTTP/1.1" 200 0 "Referer-2" "-"'),
'pipeline 2') 'pipeline 2',
)
self.assertIsNotNone( self.assertIsNotNone(
self.search_in_log(r'"GET / HTTP/1.1" 200 0 "Referer-3" "-"'), self.search_in_log(r'"GET / HTTP/1.1" 200 0 "Referer-3" "-"'),
'pipeline 3') 'pipeline 3',
)
def test_access_log_ipv6(self): def test_access_log_ipv6(self):
self.load('empty') self.load('empty')
self.conf({ self.conf({"[::1]:7080": {"application": "empty"}}, 'listeners')
"[::1]:7080": {
"application": "empty"
}
}, 'listeners')
self.get(sock_type='ipv6') self.get(sock_type='ipv6')
@@ -95,18 +108,17 @@ Connection: close
self.assertIsNotNone( self.assertIsNotNone(
self.search_in_log( self.search_in_log(
r'::1 - - \[.+\] "GET / HTTP/1.1" 200 0 "-" "-"'), 'ipv6') r'::1 - - \[.+\] "GET / HTTP/1.1" 200 0 "-" "-"'
),
'ipv6',
)
def test_access_log_unix(self): def test_access_log_unix(self):
self.load('empty') self.load('empty')
addr = self.testdir + '/sock' addr = self.testdir + '/sock'
self.conf({ self.conf({"unix:" + addr: {"application": "empty"}}, 'listeners')
"unix:" + addr: {
"application": "empty"
}
}, 'listeners')
self.get(sock_type='unix', addr=addr) self.get(sock_type='unix', addr=addr)
@@ -114,17 +126,23 @@ Connection: close
self.stop() self.stop()
self.assertIsNotNone(self.search_in_log( self.assertIsNotNone(
r'unix: - - \[.+\] "GET / HTTP/1.1" 200 0 "-" "-"'), 'unix') self.search_in_log(
r'unix: - - \[.+\] "GET / HTTP/1.1" 200 0 "-" "-"'
),
'unix',
)
def test_access_log_referer(self): def test_access_log_referer(self):
self.load('empty') self.load('empty')
self.get(headers={ self.get(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Referer': 'referer-value', 'Referer': 'referer-value',
'Connection': 'close' 'Connection': 'close',
}) }
)
time.sleep(0.2) time.sleep(0.2)
@@ -132,16 +150,19 @@ Connection: close
self.assertIsNotNone( self.assertIsNotNone(
self.search_in_log(r'"GET / HTTP/1.1" 200 0 "referer-value" "-"'), self.search_in_log(r'"GET / HTTP/1.1" 200 0 "referer-value" "-"'),
'referer') 'referer',
)
def test_access_log_user_agent(self): def test_access_log_user_agent(self):
self.load('empty') self.load('empty')
self.get(headers={ self.get(
headers={
'Host': 'localhost', 'Host': 'localhost',
'User-Agent': 'user-agent-value', 'User-Agent': 'user-agent-value',
'Connection': 'close' 'Connection': 'close',
}) }
)
time.sleep(0.2) time.sleep(0.2)
@@ -149,7 +170,10 @@ Connection: close
self.assertIsNotNone( self.assertIsNotNone(
self.search_in_log( self.search_in_log(
r'"GET / HTTP/1.1" 200 0 "-" "user-agent-value"'), 'user agent') r'"GET / HTTP/1.1" 200 0 "-" "user-agent-value"'
),
'user agent',
)
def test_access_log_http10(self): def test_access_log_http10(self):
self.load('empty') self.load('empty')
@@ -161,8 +185,8 @@ Connection: close
self.stop() self.stop()
self.assertIsNotNone( self.assertIsNotNone(
self.search_in_log( self.search_in_log(r'"GET / HTTP/1.0" 200 0 "-" "-"'), 'http 1.0'
r'"GET / HTTP/1.0" 200 0 "-" "-"'), 'http 1.0') )
def test_access_log_partial(self): def test_access_log_partial(self):
self.load('empty') self.load('empty')
@@ -174,7 +198,8 @@ Connection: close
self.stop() self.stop()
self.assertIsNotNone( self.assertIsNotNone(
self.search_in_log(r'"GE" 400 0 "-" "-"'), 'partial') self.search_in_log(r'"GE" 400 0 "-" "-"'), 'partial'
)
def test_access_log_partial_2(self): def test_access_log_partial_2(self):
self.load('empty') self.load('empty')
@@ -186,7 +211,8 @@ Connection: close
self.stop() self.stop()
self.assertIsNotNone( self.assertIsNotNone(
self.search_in_log(r'"GET /" 400 \d+ "-" "-"'), 'partial 2') self.search_in_log(r'"GET /" 400 \d+ "-" "-"'), 'partial 2'
)
def test_access_log_partial_3(self): def test_access_log_partial_3(self):
self.load('empty') self.load('empty')
@@ -198,7 +224,8 @@ Connection: close
self.stop() self.stop()
self.assertIsNotNone( self.assertIsNotNone(
self.search_in_log(r'"GET /" 400 0 "-" "-"'), 'partial 3') self.search_in_log(r'"GET /" 400 0 "-" "-"'), 'partial 3'
)
def test_access_log_partial_4(self): def test_access_log_partial_4(self):
self.load('empty') self.load('empty')
@@ -210,8 +237,8 @@ Connection: close
self.stop() self.stop()
self.assertIsNotNone( self.assertIsNotNone(
self.search_in_log(r'"GET / HTTP/1.1" 400 0 "-" "-"'), self.search_in_log(r'"GET / HTTP/1.1" 400 0 "-" "-"'), 'partial 4'
'partial 4') )
def test_access_log_partial_5(self): def test_access_log_partial_5(self):
self.load('empty') self.load('empty')
@@ -221,7 +248,8 @@ Connection: close
self.stop() self.stop()
self.assertIsNotNone( self.assertIsNotNone(
self.search_in_log(r'"GET / HTTP/1.1" 200 0 "-" "-"'), 'partial 5') self.search_in_log(r'"GET / HTTP/1.1" 200 0 "-" "-"'), 'partial 5'
)
def test_access_log_get_parameters(self): def test_access_log_get_parameters(self):
self.load('empty') self.load('empty')
@@ -234,8 +262,10 @@ Connection: close
self.assertIsNotNone( self.assertIsNotNone(
self.search_in_log( self.search_in_log(
r'"GET /\?blah&var=val HTTP/1.1" 200 0 "-" "-"'), r'"GET /\?blah&var=val HTTP/1.1" 200 0 "-" "-"'
'get parameters') ),
'get parameters',
)
def test_access_log_delete(self): def test_access_log_delete(self):
self.load('empty') self.load('empty')
@@ -265,7 +295,8 @@ Connection: close
self.assertIsNotNone( self.assertIsNotNone(
self.search_in_log(r'"GET / HTTP/1.1" 200 0 "-" "-"', 'new.log'), self.search_in_log(r'"GET / HTTP/1.1" 200 0 "-" "-"', 'new.log'),
'change') 'change',
)
def test_access_log_reopen(self): def test_access_log_reopen(self):
self.load('empty') self.load('empty')
@@ -284,7 +315,8 @@ Connection: close
self.assertIsNotNone( self.assertIsNotNone(
self.search_in_log(r'"GET / HTTP/1.1" 200 0 "-" "-"', 'new.log'), self.search_in_log(r'"GET / HTTP/1.1" 200 0 "-" "-"', 'new.log'),
'rename new') 'rename new',
)
self.assertFalse(os.path.isfile(log_path), 'rename old') self.assertFalse(os.path.isfile(log_path), 'rename old')
with open(self.testdir + '/unit.pid', 'r') as f: with open(self.testdir + '/unit.pid', 'r') as f:
@@ -299,10 +331,13 @@ Connection: close
time.sleep(0.2) time.sleep(0.2)
self.assertIsNone( self.assertIsNone(
self.search_in_log(r'/usr1', 'new.log'), 'rename new 2') self.search_in_log(r'/usr1', 'new.log'), 'rename new 2'
)
self.assertIsNotNone( self.assertIsNotNone(
self.search_in_log(r'"GET /usr1 HTTP/1.1" 200 0 "-" "-"'), self.search_in_log(r'"GET /usr1 HTTP/1.1" 200 0 "-" "-"'),
'reopen 2') 'reopen 2',
)
if __name__ == '__main__': if __name__ == '__main__':
TestUnitAccessLog.main() TestUnitAccessLog.main()

View File

@@ -1,8 +1,8 @@
import unittest import unittest
import unit import unit
class TestUnitConfiguration(unit.TestUnitControl):
class TestUnitConfiguration(unit.TestUnitControl):
def setUpClass(): def setUpClass():
unit.TestUnit().check_modules('python') unit.TestUnit().check_modules('python')
@@ -13,7 +13,10 @@ class TestUnitConfiguration(unit.TestUnitControl):
self.assertIn('error', self.conf('00'), 'leading zero') self.assertIn('error', self.conf('00'), 'leading zero')
def test_json_unicode(self): def test_json_unicode(self):
self.assertIn('success', self.conf(b""" self.assertIn(
'success',
self.conf(
b"""
{ {
"ap\u0070": { "ap\u0070": {
"type": "\u0070ython", "type": "\u0070ython",
@@ -22,32 +25,51 @@ class TestUnitConfiguration(unit.TestUnitControl):
"module": "wsgi" "module": "wsgi"
} }
} }
""", 'applications'), 'unicode') """,
'applications',
),
'unicode',
)
self.assertDictEqual(self.conf_get('applications'), { self.assertDictEqual(
self.conf_get('applications'),
{
"app": { "app": {
"type": "python", "type": "python",
"processes": { "spare": 0 }, "processes": {"spare": 0},
"path": "/app", "path": "/app",
"module": "wsgi" "module": "wsgi",
} }
}, 'unicode get') },
'unicode get',
)
def test_json_unicode_2(self): def test_json_unicode_2(self):
self.assertIn('success', self.conf({ self.assertIn(
'success',
self.conf(
{
"приложение": { "приложение": {
"type": "python", "type": "python",
"processes": { "spare": 0 }, "processes": {"spare": 0},
"path": "/app", "path": "/app",
"module": "wsgi" "module": "wsgi",
} }
}, 'applications'), 'unicode 2') },
'applications',
),
'unicode 2',
)
self.assertIn('приложение', self.conf_get('applications'), self.assertIn(
'unicode 2 get') 'приложение', self.conf_get('applications'), 'unicode 2 get'
)
def test_json_unicode_number(self): def test_json_unicode_number(self):
self.assertIn('error', self.conf(b""" self.assertIn(
'error',
self.conf(
b"""
{ {
"app": { "app": {
"type": "python", "type": "python",
@@ -56,7 +78,11 @@ class TestUnitConfiguration(unit.TestUnitControl):
"module": "wsgi" "module": "wsgi"
} }
} }
""", 'applications'), 'unicode number') """,
'applications',
),
'unicode number',
)
def test_applications_open_brace(self): def test_applications_open_brace(self):
self.assertIn('error', self.conf('{', 'applications'), 'open brace') self.assertIn('error', self.conf('{', 'applications'), 'open brace')
@@ -65,20 +91,25 @@ class TestUnitConfiguration(unit.TestUnitControl):
self.assertIn('error', self.conf('"{}"', 'applications'), 'string') self.assertIn('error', self.conf('"{}"', 'applications'), 'string')
def test_applications_type_only(self): def test_applications_type_only(self):
self.skip_alerts.extend([ self.skip_alerts.extend(
[
r'python module is empty', r'python module is empty',
r'failed to apply new conf', r'failed to apply new conf',
r'process \d+ exited on signal' r'process \d+ exited on signal',
]) ]
)
self.assertIn('error', self.conf({ self.assertIn(
"app": { 'error',
"type": "python" self.conf({"app": {"type": "python"}}, 'applications'),
} 'type only',
}, 'applications'), 'type only') )
def test_applications_miss_quote(self): def test_applications_miss_quote(self):
self.assertIn('error', self.conf(""" self.assertIn(
'error',
self.conf(
"""
{ {
app": { app": {
"type": "python", "type": "python",
@@ -87,10 +118,17 @@ class TestUnitConfiguration(unit.TestUnitControl):
"module": "wsgi" "module": "wsgi"
} }
} }
""", 'applications'), 'miss quote') """,
'applications',
),
'miss quote',
)
def test_applications_miss_colon(self): def test_applications_miss_colon(self):
self.assertIn('error', self.conf(""" self.assertIn(
'error',
self.conf(
"""
{ {
"app" { "app" {
"type": "python", "type": "python",
@@ -99,10 +137,17 @@ class TestUnitConfiguration(unit.TestUnitControl):
"module": "wsgi" "module": "wsgi"
} }
} }
""", 'applications'), 'miss colon') """,
'applications',
),
'miss colon',
)
def test_applications_miss_comma(self): def test_applications_miss_comma(self):
self.assertIn('error', self.conf(""" self.assertIn(
'error',
self.conf(
"""
{ {
"app": { "app": {
"type": "python" "type": "python"
@@ -111,181 +156,206 @@ class TestUnitConfiguration(unit.TestUnitControl):
"module": "wsgi" "module": "wsgi"
} }
} }
""", 'applications'), 'miss comma') """,
'applications',
),
'miss comma',
)
def test_applications_skip_spaces(self): def test_applications_skip_spaces(self):
self.assertIn('success', self.conf(b'{ \n\r\t}', 'applications'), self.assertIn(
'skip spaces') 'success', self.conf(b'{ \n\r\t}', 'applications'), 'skip spaces'
)
def test_applications_relative_path(self): def test_applications_relative_path(self):
self.assertIn('success', self.conf({ self.assertIn(
'success',
self.conf(
{
"app": { "app": {
"type": "python", "type": "python",
"processes": { "spare": 0 }, "processes": {"spare": 0},
"path": "../app", "path": "../app",
"module": "wsgi" "module": "wsgi",
} }
}, 'applications'), 'relative path') },
'applications',
),
'relative path',
)
@unittest.expectedFailure @unittest.expectedFailure
def test_listeners_empty(self): def test_listeners_empty(self):
self.skip_sanitizer = True self.skip_sanitizer = True
self.skip_alerts.extend([ self.skip_alerts.extend(
[
r'failed to apply previous configuration', r'failed to apply previous configuration',
r'process \d+ exited on signal' r'process \d+ exited on signal',
]) ]
)
self.assertIn('error', self.conf({"*:7080":{}}, 'listeners'), self.assertIn(
'listener empty') 'error', self.conf({"*:7080": {}}, 'listeners'), 'listener empty'
)
def test_listeners_no_app(self): def test_listeners_no_app(self):
self.assertIn('error', self.conf({"*:7080":{"application":"app"}}, self.assertIn(
'listeners'), 'listeners no app') 'error',
self.conf({"*:7080": {"application": "app"}}, 'listeners'),
'listeners no app',
)
def test_listeners_wildcard(self): def test_listeners_wildcard(self):
self.assertIn('success', self.conf({ self.assertIn(
"listeners": { 'success',
"*:7080": { self.conf(
"application":"app" {
} "listeners": {"*:7080": {"application": "app"}},
},
"applications": { "applications": {
"app": { "app": {
"type": "python", "type": "python",
"processes": { "spare": 0 }, "processes": {"spare": 0},
"path": "/app", "path": "/app",
"module": "wsgi" "module": "wsgi",
} }
},
} }
}), 'listeners wildcard') ),
'listeners wildcard',
)
def test_listeners_explicit(self): def test_listeners_explicit(self):
self.assertIn('success', self.conf({ self.assertIn(
"listeners": { 'success',
"127.0.0.1:7080": { self.conf(
"application":"app" {
} "listeners": {"127.0.0.1:7080": {"application": "app"}},
},
"applications": { "applications": {
"app": { "app": {
"type": "python", "type": "python",
"processes": { "spare": 0 }, "processes": {"spare": 0},
"path": "/app", "path": "/app",
"module": "wsgi" "module": "wsgi",
} }
},
} }
}), 'explicit') ),
'explicit',
)
def test_listeners_explicit_ipv6(self): def test_listeners_explicit_ipv6(self):
self.assertIn('success', self.conf({ self.assertIn(
"listeners": { 'success',
"[::1]:7080": { self.conf(
"application":"app" {
} "listeners": {"[::1]:7080": {"application": "app"}},
},
"applications": { "applications": {
"app": { "app": {
"type": "python", "type": "python",
"processes": { "spare": 0 }, "processes": {"spare": 0},
"path": "/app", "path": "/app",
"module": "wsgi" "module": "wsgi",
} }
},
} }
}), 'explicit ipv6') ),
'explicit ipv6',
)
def test_listeners_no_port(self): def test_listeners_no_port(self):
self.skip_alerts.extend([ self.skip_alerts.extend(
[
r'invalid listener "127\.0\.0\.1"', r'invalid listener "127\.0\.0\.1"',
r'failed to apply new conf', r'failed to apply new conf',
r'process \d+ exited on signal' r'process \d+ exited on signal',
]) ]
)
self.assertIn('error', self.conf({ self.assertIn(
"listeners": { 'error',
"127.0.0.1": { self.conf(
"application":"app" {
} "listeners": {"127.0.0.1": {"application": "app"}},
},
"applications": { "applications": {
"app": { "app": {
"type": "python", "type": "python",
"processes": { "spare": 0 }, "processes": {"spare": 0},
"path": "/app", "path": "/app",
"module": "wsgi" "module": "wsgi",
} }
},
} }
}), 'no port') ),
'no port',
)
def test_json_application_name_large(self): def test_json_application_name_large(self):
name = "X" * 1024 * 1024 name = "X" * 1024 * 1024
self.assertIn('success', self.conf({ self.assertIn(
"listeners": { 'success',
"*:7080": { self.conf(
"application": name {
} "listeners": {"*:7080": {"application": name}},
},
"applications": { "applications": {
name: { name: {
"type": "python", "type": "python",
"processes": { "spare": 0 }, "processes": {"spare": 0},
"path": "/app", "path": "/app",
"module": "wsgi" "module": "wsgi",
} }
},
} }
})) ),
)
@unittest.expectedFailure @unittest.expectedFailure
def test_json_application_many(self): def test_json_application_many(self):
self.skip_alerts.extend([ self.skip_alerts.extend(
r'eventfd.+failed', [r'eventfd.+failed', r'epoll.+failed', r'failed to apply']
r'epoll.+failed', )
r'failed to apply'
])
apps = 999 apps = 999
conf = { conf = {
"applications": "applications": {
{"app-" + str(a): { "app-"
+ str(a): {
"type": "python", "type": "python",
"processes": { "spare": 0 }, "processes": {"spare": 0},
"path": "/app", "path": "/app",
"module": "wsgi" "module": "wsgi",
} for a in range(apps) }
for a in range(apps)
}, },
"listeners": { "listeners": {
"*:" + str(7000 + a): { "*:" + str(7000 + a): {"application": "app-" + str(a)}
"application": "app-" + str(a) for a in range(apps)
} for a in range(apps) },
}
} }
self.assertIn('success', self.conf(conf)) self.assertIn('success', self.conf(conf))
def test_json_application_many2(self): def test_json_application_many2(self):
self.skip_alerts.extend([ self.skip_alerts.extend(
r'eventfd.+failed', [r'eventfd.+failed', r'epoll.+failed', r'failed to apply']
r'epoll.+failed', )
r'failed to apply'
])
conf = { conf = {
"applications": "applications": {
{"app-" + str(a): { "app-"
+ str(a): {
"type": "python", "type": "python",
"processes": { "spare": 0 }, "processes": {"spare": 0},
"path": "/app", "path": "/app",
"module": "wsgi" "module": "wsgi",
} for a in range(999) }
for a in range(999)
}, },
"listeners": { "listeners": {"*:7001": {"application": "app-1"}},
"*:7001": {
"application": "app-1"
}
}
} }
self.assertIn('success', self.conf(conf)) self.assertIn('success', self.conf(conf))
if __name__ == '__main__': if __name__ == '__main__':
TestUnitConfiguration.main() TestUnitConfiguration.main()

View File

@@ -1,8 +1,8 @@
import unittest import unittest
import unit import unit
class TestUnitGoApplication(unit.TestUnitApplicationGo):
class TestUnitGoApplication(unit.TestUnitApplicationGo):
def setUpClass(): def setUpClass():
unit.TestUnit().check_modules('go') unit.TestUnit().check_modules('go')
@@ -11,12 +11,15 @@ class TestUnitGoApplication(unit.TestUnitApplicationGo):
body = 'Test body string.' body = 'Test body string.'
resp = self.post(headers={ resp = self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Content-Type': 'text/html', 'Content-Type': 'text/html',
'Custom-Header': 'blah', 'Custom-Header': 'blah',
'Connection': 'close' 'Connection': 'close',
}, body=body) },
body=body,
)
self.assertEqual(resp['status'], 200, 'status') self.assertEqual(resp['status'], 200, 'status')
headers = resp['headers'] headers = resp['headers']
@@ -25,10 +28,15 @@ class TestUnitGoApplication(unit.TestUnitApplicationGo):
date = headers.pop('Date') date = headers.pop('Date')
self.assertEqual(date[-4:], ' GMT', 'date header timezone') self.assertEqual(date[-4:], ' GMT', 'date header timezone')
self.assertLess(abs(self.date_to_sec_epoch(date) - self.sec_epoch()), 5, self.assertLess(
'date header') abs(self.date_to_sec_epoch(date) - self.sec_epoch()),
5,
'date header',
)
self.assertDictEqual(headers, { self.assertDictEqual(
headers,
{
'Content-Length': str(len(body)), 'Content-Length': str(len(body)),
'Content-Type': 'text/html', 'Content-Type': 'text/html',
'Request-Method': 'POST', 'Request-Method': 'POST',
@@ -38,8 +46,10 @@ class TestUnitGoApplication(unit.TestUnitApplicationGo):
'Server-Protocol-Major': '1', 'Server-Protocol-Major': '1',
'Server-Protocol-Minor': '1', 'Server-Protocol-Minor': '1',
'Custom-Header': 'blah', 'Custom-Header': 'blah',
'Connection': 'close' 'Connection': 'close',
}, 'headers') },
'headers',
)
self.assertEqual(resp['body'], body, 'body') self.assertEqual(resp['body'], body, 'body')
def test_go_application_get_variables(self): def test_go_application_get_variables(self):
@@ -53,11 +63,14 @@ class TestUnitGoApplication(unit.TestUnitApplicationGo):
def test_go_application_post_variables(self): def test_go_application_post_variables(self):
self.load('post_variables') self.load('post_variables')
resp = self.post(headers={ resp = self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Content-Type': 'application/x-www-form-urlencoded', 'Content-Type': 'application/x-www-form-urlencoded',
'Connection': 'close' 'Connection': 'close',
}, body='var1=val1&var2=&var3') },
body='var1=val1&var2=&var3',
)
self.assertEqual(resp['headers']['X-Var-1'], 'val1', 'POST variables') self.assertEqual(resp['headers']['X-Var-1'], 'val1', 'POST variables')
self.assertEqual(resp['headers']['X-Var-2'], '', 'POST variables 2') self.assertEqual(resp['headers']['X-Var-2'], '', 'POST variables 2')
@@ -69,36 +82,47 @@ class TestUnitGoApplication(unit.TestUnitApplicationGo):
resp = self.get() resp = self.get()
self.assertEqual(resp['status'], 404, '404 status') self.assertEqual(resp['status'], 404, '404 status')
self.assertRegex(resp['body'], r'<title>404 Not Found</title>', self.assertRegex(
'404 body') resp['body'], r'<title>404 Not Found</title>', '404 body'
)
def test_go_keepalive_body(self): def test_go_keepalive_body(self):
self.load('mirror') self.load('mirror')
(resp, sock) = self.post(headers={ (resp, sock) = self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Connection': 'keep-alive', 'Connection': 'keep-alive',
'Content-Type': 'text/html' 'Content-Type': 'text/html',
}, start=True, body='0123456789' * 500) },
start=True,
body='0123456789' * 500,
)
self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1') self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1')
resp = self.post(headers={ resp = self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Content-Type': 'text/html', 'Content-Type': 'text/html',
'Connection': 'close' 'Connection': 'close',
}, sock=sock, body='0123456789') },
sock=sock,
body='0123456789',
)
self.assertEqual(resp['body'], '0123456789', 'keep-alive 2') self.assertEqual(resp['body'], '0123456789', 'keep-alive 2')
def test_go_application_cookies(self): def test_go_application_cookies(self):
self.load('cookies') self.load('cookies')
resp = self.get(headers={ resp = self.get(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Cookie': 'var1=val1; var2=val2', 'Cookie': 'var1=val1; var2=val2',
'Connection': 'close' 'Connection': 'close',
}) }
)
self.assertEqual(resp['headers']['X-Cookie-1'], 'val1', 'cookie 1') self.assertEqual(resp['headers']['X-Cookie-1'], 'val1', 'cookie 1')
self.assertEqual(resp['headers']['X-Cookie-2'], 'val2', 'cookie 2') self.assertEqual(resp['headers']['X-Cookie-2'], 'val2', 'cookie 2')
@@ -106,15 +130,22 @@ class TestUnitGoApplication(unit.TestUnitApplicationGo):
def test_go_application_command_line_arguments_type(self): def test_go_application_command_line_arguments_type(self):
self.load('command_line_arguments') self.load('command_line_arguments')
self.assertIn('error', self.conf(''"a b c", self.assertIn(
'applications/command_line_arguments/arguments'), 'arguments type') 'error',
self.conf(
'' "a b c", 'applications/command_line_arguments/arguments'
),
'arguments type',
)
def test_go_application_command_line_arguments_0(self): def test_go_application_command_line_arguments_0(self):
self.load('command_line_arguments') self.load('command_line_arguments')
self.assertEqual(self.get()['headers']['X-Arg-0'], self.assertEqual(
self.get()['headers']['X-Arg-0'],
self.conf_get('applications/command_line_arguments/executable'), self.conf_get('applications/command_line_arguments/executable'),
'argument 0') 'argument 0',
)
def test_go_application_command_line_arguments(self): def test_go_application_command_line_arguments(self):
self.load('command_line_arguments') self.load('command_line_arguments')
@@ -123,11 +154,14 @@ class TestUnitGoApplication(unit.TestUnitApplicationGo):
arg2 = '--cc-opt=\'-O0 -DNXT_DEBUG_MEMORY=1 -fsanitize=address\'' arg2 = '--cc-opt=\'-O0 -DNXT_DEBUG_MEMORY=1 -fsanitize=address\''
arg3 = '--debug' arg3 = '--debug'
self.conf('["' + arg1 + '", "' + arg2 + '", "' + arg3 + '"]', self.conf(
'applications/command_line_arguments/arguments') '["' + arg1 + '", "' + arg2 + '", "' + arg3 + '"]',
'applications/command_line_arguments/arguments',
)
self.assertEqual(self.get()['body'], arg1 + ',' + arg2 + ',' + arg3, self.assertEqual(
'arguments') self.get()['body'], arg1 + ',' + arg2 + ',' + arg3, 'arguments'
)
def test_go_application_command_line_arguments_change(self): def test_go_application_command_line_arguments_change(self):
self.load('command_line_arguments') self.load('command_line_arguments')
@@ -144,8 +178,10 @@ class TestUnitGoApplication(unit.TestUnitApplicationGo):
self.conf('[]', args_path) self.conf('[]', args_path)
self.assertEqual(self.get()['headers']['Content-Length'], '0', self.assertEqual(
'arguments empty') self.get()['headers']['Content-Length'], '0', 'arguments empty'
)
if __name__ == '__main__': if __name__ == '__main__':
TestUnitGoApplication.main() TestUnitGoApplication.main()

View File

@@ -1,216 +1,302 @@
import unittest import unittest
import unit import unit
class TestUnitHTTPHeader(unit.TestUnitApplicationPython):
class TestUnitHTTPHeader(unit.TestUnitApplicationPython):
def setUpClass(): def setUpClass():
unit.TestUnit().check_modules('python') unit.TestUnit().check_modules('python')
def test_http_header_value_leading_sp(self): def test_http_header_value_leading_sp(self):
self.load('custom_header') self.load('custom_header')
resp = self.get(headers={ resp = self.get(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Custom-Header': ' ,', 'Custom-Header': ' ,',
'Connection': 'close' 'Connection': 'close',
}) }
)
self.assertEqual(resp['status'], 200, 'value leading sp status') self.assertEqual(resp['status'], 200, 'value leading sp status')
self.assertEqual(resp['headers']['Custom-Header'], ',', self.assertEqual(
'value leading sp custom header') resp['headers']['Custom-Header'],
',',
'value leading sp custom header',
)
def test_http_header_value_leading_htab(self): def test_http_header_value_leading_htab(self):
self.load('custom_header') self.load('custom_header')
resp = self.get(headers={ resp = self.get(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Custom-Header': '\t,', 'Custom-Header': '\t,',
'Connection': 'close' 'Connection': 'close',
}) }
)
self.assertEqual(resp['status'], 200, 'value leading htab status') self.assertEqual(resp['status'], 200, 'value leading htab status')
self.assertEqual(resp['headers']['Custom-Header'], ',', self.assertEqual(
'value leading htab custom header') resp['headers']['Custom-Header'],
',',
'value leading htab custom header',
)
def test_http_header_value_trailing_sp(self): def test_http_header_value_trailing_sp(self):
self.load('custom_header') self.load('custom_header')
resp = self.get(headers={ resp = self.get(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Custom-Header': ', ', 'Custom-Header': ', ',
'Connection': 'close' 'Connection': 'close',
}) }
)
self.assertEqual(resp['status'], 200, 'value trailing sp status') self.assertEqual(resp['status'], 200, 'value trailing sp status')
self.assertEqual(resp['headers']['Custom-Header'], ',', self.assertEqual(
'value trailing sp custom header') resp['headers']['Custom-Header'],
',',
'value trailing sp custom header',
)
def test_http_header_value_trailing_htab(self): def test_http_header_value_trailing_htab(self):
self.load('custom_header') self.load('custom_header')
resp = self.get(headers={ resp = self.get(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Custom-Header': ',\t', 'Custom-Header': ',\t',
'Connection': 'close' 'Connection': 'close',
}) }
)
self.assertEqual(resp['status'], 200, 'value trailing htab status') self.assertEqual(resp['status'], 200, 'value trailing htab status')
self.assertEqual(resp['headers']['Custom-Header'], ',', self.assertEqual(
'value trailing htab custom header') resp['headers']['Custom-Header'],
',',
'value trailing htab custom header',
)
def test_http_header_value_both_sp(self): def test_http_header_value_both_sp(self):
self.load('custom_header') self.load('custom_header')
resp = self.get(headers={ resp = self.get(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Custom-Header': ' , ', 'Custom-Header': ' , ',
'Connection': 'close' 'Connection': 'close',
}) }
)
self.assertEqual(resp['status'], 200, 'value both sp status') self.assertEqual(resp['status'], 200, 'value both sp status')
self.assertEqual(resp['headers']['Custom-Header'], ',', self.assertEqual(
'value both sp custom header') resp['headers']['Custom-Header'],
',',
'value both sp custom header',
)
def test_http_header_value_both_htab(self): def test_http_header_value_both_htab(self):
self.load('custom_header') self.load('custom_header')
resp = self.get(headers={ resp = self.get(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Custom-Header': '\t,\t', 'Custom-Header': '\t,\t',
'Connection': 'close' 'Connection': 'close',
}) }
)
self.assertEqual(resp['status'], 200, 'value both htab status') self.assertEqual(resp['status'], 200, 'value both htab status')
self.assertEqual(resp['headers']['Custom-Header'], ',', self.assertEqual(
'value both htab custom header') resp['headers']['Custom-Header'],
',',
'value both htab custom header',
)
def test_http_header_value_chars(self): def test_http_header_value_chars(self):
self.load('custom_header') self.load('custom_header')
resp = self.get(headers={ resp = self.get(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Custom-Header': '(),/:;<=>?@[\]{}\t !#$%&\'*+-.^_`|~', 'Custom-Header': '(),/:;<=>?@[\]{}\t !#$%&\'*+-.^_`|~',
'Connection': 'close' 'Connection': 'close',
}) }
)
self.assertEqual(resp['status'], 200, 'value chars status') self.assertEqual(resp['status'], 200, 'value chars status')
self.assertEqual(resp['headers']['Custom-Header'], self.assertEqual(
'(),/:;<=>?@[\]{}\t !#$%&\'*+-.^_`|~', 'value chars custom header') resp['headers']['Custom-Header'],
'(),/:;<=>?@[\]{}\t !#$%&\'*+-.^_`|~',
'value chars custom header',
)
def test_http_header_value_chars_edge(self): def test_http_header_value_chars_edge(self):
self.load('custom_header') self.load('custom_header')
resp = self.http(b"""GET / HTTP/1.1 resp = self.http(
b"""GET / HTTP/1.1
Host: localhost Host: localhost
Custom-Header: \x20\xFF Custom-Header: \x20\xFF
Connection: close Connection: close
""", raw=True, encoding='latin1') """,
raw=True,
encoding='latin1',
)
self.assertEqual(resp['status'], 200, 'value chars edge status') self.assertEqual(resp['status'], 200, 'value chars edge status')
self.assertEqual(resp['headers']['Custom-Header'], '\xFF', self.assertEqual(
'value chars edge') resp['headers']['Custom-Header'], '\xFF', 'value chars edge'
)
def test_http_header_value_chars_below(self): def test_http_header_value_chars_below(self):
self.load('custom_header') self.load('custom_header')
resp = self.http(b"""GET / HTTP/1.1 resp = self.http(
b"""GET / HTTP/1.1
Host: localhost Host: localhost
Custom-Header: \x1F Custom-Header: \x1F
Connection: close Connection: close
""", raw=True) """,
raw=True,
)
self.assertEqual(resp['status'], 400, 'value chars below') self.assertEqual(resp['status'], 400, 'value chars below')
def test_http_header_field_leading_sp(self): def test_http_header_field_leading_sp(self):
self.load('empty') self.load('empty')
resp = self.get(headers={ resp = self.get(
headers={
'Host': 'localhost', 'Host': 'localhost',
' Custom-Header': 'blah', ' Custom-Header': 'blah',
'Connection': 'close' 'Connection': 'close',
}) }
)
self.assertEqual(resp['status'], 400, 'field leading sp') self.assertEqual(resp['status'], 400, 'field leading sp')
def test_http_header_field_leading_htab(self): def test_http_header_field_leading_htab(self):
self.load('empty') self.load('empty')
resp = self.get(headers={ resp = self.get(
headers={
'Host': 'localhost', 'Host': 'localhost',
'\tCustom-Header': 'blah', '\tCustom-Header': 'blah',
'Connection': 'close' 'Connection': 'close',
}) }
)
self.assertEqual(resp['status'], 400, 'field leading htab') self.assertEqual(resp['status'], 400, 'field leading htab')
def test_http_header_field_trailing_sp(self): def test_http_header_field_trailing_sp(self):
self.load('empty') self.load('empty')
resp = self.get(headers={ resp = self.get(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Custom-Header ': 'blah', 'Custom-Header ': 'blah',
'Connection': 'close' 'Connection': 'close',
}) }
)
self.assertEqual(resp['status'], 400, 'field trailing sp') self.assertEqual(resp['status'], 400, 'field trailing sp')
def test_http_header_field_trailing_htab(self): def test_http_header_field_trailing_htab(self):
self.load('empty') self.load('empty')
resp = self.get(headers={ resp = self.get(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Custom-Header\t': 'blah', 'Custom-Header\t': 'blah',
'Connection': 'close' 'Connection': 'close',
}) }
)
self.assertEqual(resp['status'], 400, 'field trailing htab') self.assertEqual(resp['status'], 400, 'field trailing htab')
def test_http_header_content_length_big(self): def test_http_header_content_length_big(self):
self.load('empty') self.load('empty')
self.assertEqual(self.post(headers={ self.assertEqual(
self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Content-Length': str(2 ** 64), 'Content-Length': str(2 ** 64),
'Connection': 'close' 'Connection': 'close',
}, body='X' * 1000)['status'], 400, 'Content-Length big') },
body='X' * 1000,
)['status'],
400,
'Content-Length big',
)
def test_http_header_content_length_negative(self): def test_http_header_content_length_negative(self):
self.load('empty') self.load('empty')
self.assertEqual(self.post(headers={ self.assertEqual(
self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Content-Length': '-100', 'Content-Length': '-100',
'Connection': 'close' 'Connection': 'close',
}, body='X' * 1000)['status'], 400, 'Content-Length negative') },
body='X' * 1000,
)['status'],
400,
'Content-Length negative',
)
def test_http_header_content_length_text(self): def test_http_header_content_length_text(self):
self.load('empty') self.load('empty')
self.assertEqual(self.post(headers={ self.assertEqual(
self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Content-Length': 'blah', 'Content-Length': 'blah',
'Connection': 'close' 'Connection': 'close',
}, body='X' * 1000)['status'], 400, 'Content-Length text') },
body='X' * 1000,
)['status'],
400,
'Content-Length text',
)
def test_http_header_content_length_multiple_values(self): def test_http_header_content_length_multiple_values(self):
self.load('empty') self.load('empty')
self.assertEqual(self.post(headers={ self.assertEqual(
self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Content-Length': '41, 42', 'Content-Length': '41, 42',
'Connection': 'close' 'Connection': 'close',
}, body='X' * 1000)['status'], 400, 'Content-Length multiple value') },
body='X' * 1000,
)['status'],
400,
'Content-Length multiple value',
)
def test_http_header_content_length_multiple_fields(self): def test_http_header_content_length_multiple_fields(self):
self.load('empty') self.load('empty')
self.assertEqual(self.post(headers={ self.assertEqual(
self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Content-Length': ['41', '42'], 'Content-Length': ['41', '42'],
'Connection': 'close' 'Connection': 'close',
}, body='X' * 1000)['status'], 400, 'Content-Length multiple fields') },
body='X' * 1000,
)['status'],
400,
'Content-Length multiple fields',
)
def test_http_header_host_absent(self): def test_http_header_host_absent(self):
self.load('host') self.load('host')
@@ -218,146 +304,182 @@ Connection: close
resp = self.get(headers={'Connection': 'close'}) resp = self.get(headers={'Connection': 'close'})
self.assertEqual(resp['status'], 200, 'Host absent status') self.assertEqual(resp['status'], 200, 'Host absent status')
self.assertNotEqual(resp['headers']['X-Server-Name'], '', self.assertNotEqual(
'Host absent SERVER_NAME') resp['headers']['X-Server-Name'], '', 'Host absent SERVER_NAME'
)
def test_http_header_host_empty(self): def test_http_header_host_empty(self):
self.load('host') self.load('host')
resp = self.get(headers={ resp = self.get(headers={'Host': '', 'Connection': 'close'})
'Host': '',
'Connection': 'close'
})
self.assertEqual(resp['status'], 200, 'Host empty status') self.assertEqual(resp['status'], 200, 'Host empty status')
self.assertNotEqual(resp['headers']['X-Server-Name'], '', self.assertNotEqual(
'Host empty SERVER_NAME') resp['headers']['X-Server-Name'], '', 'Host empty SERVER_NAME'
)
def test_http_header_host_big(self): def test_http_header_host_big(self):
self.load('empty') self.load('empty')
self.assertEqual(self.get(headers={ self.assertEqual(
'Host': 'X' * 10000, self.get(headers={'Host': 'X' * 10000, 'Connection': 'close'})[
'Connection': 'close' 'status'
})['status'], 431, 'Host big') ],
431,
'Host big',
)
def test_http_header_host_port(self): def test_http_header_host_port(self):
self.load('host') self.load('host')
resp = self.get(headers={ resp = self.get(
'Host': 'exmaple.com:7080', headers={'Host': 'exmaple.com:7080', 'Connection': 'close'}
'Connection': 'close' )
})
self.assertEqual(resp['status'], 200, 'Host port status') self.assertEqual(resp['status'], 200, 'Host port status')
self.assertEqual(resp['headers']['X-Server-Name'], 'exmaple.com', self.assertEqual(
'Host port SERVER_NAME') resp['headers']['X-Server-Name'],
self.assertEqual(resp['headers']['X-Http-Host'], 'exmaple.com:7080', 'exmaple.com',
'Host port HTTP_HOST') 'Host port SERVER_NAME',
)
self.assertEqual(
resp['headers']['X-Http-Host'],
'exmaple.com:7080',
'Host port HTTP_HOST',
)
def test_http_header_host_port_empty(self): def test_http_header_host_port_empty(self):
self.load('host') self.load('host')
resp = self.get(headers={ resp = self.get(
'Host': 'exmaple.com:', headers={'Host': 'exmaple.com:', 'Connection': 'close'}
'Connection': 'close' )
})
self.assertEqual(resp['status'], 200, 'Host port empty status') self.assertEqual(resp['status'], 200, 'Host port empty status')
self.assertEqual(resp['headers']['X-Server-Name'], 'exmaple.com', self.assertEqual(
'Host port empty SERVER_NAME') resp['headers']['X-Server-Name'],
self.assertEqual(resp['headers']['X-Http-Host'], 'exmaple.com:', 'exmaple.com',
'Host port empty HTTP_HOST') 'Host port empty SERVER_NAME',
)
self.assertEqual(
resp['headers']['X-Http-Host'],
'exmaple.com:',
'Host port empty HTTP_HOST',
)
def test_http_header_host_literal(self): def test_http_header_host_literal(self):
self.load('host') self.load('host')
resp = self.get(headers={ resp = self.get(headers={'Host': '127.0.0.1', 'Connection': 'close'})
'Host': '127.0.0.1',
'Connection': 'close'
})
self.assertEqual(resp['status'], 200, 'Host literal status') self.assertEqual(resp['status'], 200, 'Host literal status')
self.assertEqual(resp['headers']['X-Server-Name'], '127.0.0.1', self.assertEqual(
'Host literal SERVER_NAME') resp['headers']['X-Server-Name'],
'127.0.0.1',
'Host literal SERVER_NAME',
)
def test_http_header_host_literal_ipv6(self): def test_http_header_host_literal_ipv6(self):
self.load('host') self.load('host')
resp = self.get(headers={ resp = self.get(headers={'Host': '[::1]:7080', 'Connection': 'close'})
'Host': '[::1]:7080',
'Connection': 'close'
})
self.assertEqual(resp['status'], 200, 'Host literal ipv6 status') self.assertEqual(resp['status'], 200, 'Host literal ipv6 status')
self.assertEqual(resp['headers']['X-Server-Name'], '[::1]', self.assertEqual(
'Host literal ipv6 SERVER_NAME') resp['headers']['X-Server-Name'],
self.assertEqual(resp['headers']['X-Http-Host'], '[::1]:7080', '[::1]',
'Host literal ipv6 HTTP_HOST') 'Host literal ipv6 SERVER_NAME',
)
self.assertEqual(
resp['headers']['X-Http-Host'],
'[::1]:7080',
'Host literal ipv6 HTTP_HOST',
)
def test_http_header_host_trailing_period(self): def test_http_header_host_trailing_period(self):
self.load('host') self.load('host')
resp = self.get(headers={ resp = self.get(headers={'Host': '127.0.0.1.', 'Connection': 'close'})
'Host': '127.0.0.1.',
'Connection': 'close'
})
self.assertEqual(resp['status'], 200, 'Host trailing period status') self.assertEqual(resp['status'], 200, 'Host trailing period status')
self.assertEqual(resp['headers']['X-Server-Name'], '127.0.0.1', self.assertEqual(
'Host trailing period SERVER_NAME') resp['headers']['X-Server-Name'],
self.assertEqual(resp['headers']['X-Http-Host'], '127.0.0.1.', '127.0.0.1',
'Host trailing period HTTP_HOST') 'Host trailing period SERVER_NAME',
)
self.assertEqual(
resp['headers']['X-Http-Host'],
'127.0.0.1.',
'Host trailing period HTTP_HOST',
)
def test_http_header_host_trailing_period_2(self): def test_http_header_host_trailing_period_2(self):
self.load('host') self.load('host')
resp = self.get(headers={ resp = self.get(
'Host': 'EXAMPLE.COM.', headers={'Host': 'EXAMPLE.COM.', 'Connection': 'close'}
'Connection': 'close' )
})
self.assertEqual(resp['status'], 200, 'Host trailing period 2 status') self.assertEqual(resp['status'], 200, 'Host trailing period 2 status')
self.assertEqual(resp['headers']['X-Server-Name'], 'example.com', self.assertEqual(
'Host trailing period 2 SERVER_NAME') resp['headers']['X-Server-Name'],
self.assertEqual(resp['headers']['X-Http-Host'], 'EXAMPLE.COM.', 'example.com',
'Host trailing period 2 HTTP_HOST') 'Host trailing period 2 SERVER_NAME',
)
self.assertEqual(
resp['headers']['X-Http-Host'],
'EXAMPLE.COM.',
'Host trailing period 2 HTTP_HOST',
)
def test_http_header_host_case_insensitive(self): def test_http_header_host_case_insensitive(self):
self.load('host') self.load('host')
resp = self.get(headers={ resp = self.get(headers={'Host': 'EXAMPLE.COM', 'Connection': 'close'})
'Host': 'EXAMPLE.COM',
'Connection': 'close'
})
self.assertEqual(resp['status'], 200, 'Host case insensitive') self.assertEqual(resp['status'], 200, 'Host case insensitive')
self.assertEqual(resp['headers']['X-Server-Name'], 'example.com', self.assertEqual(
'Host case insensitive SERVER_NAME') resp['headers']['X-Server-Name'],
'example.com',
'Host case insensitive SERVER_NAME',
)
def test_http_header_host_double_dot(self): def test_http_header_host_double_dot(self):
self.load('empty') self.load('empty')
self.assertEqual(self.get(headers={ self.assertEqual(
'Host': '127.0.0..1', self.get(headers={'Host': '127.0.0..1', 'Connection': 'close'})[
'Connection': 'close' 'status'
})['status'], 400, 'Host double dot') ],
400,
'Host double dot',
)
def test_http_header_host_slash(self): def test_http_header_host_slash(self):
self.load('empty') self.load('empty')
self.assertEqual(self.get(headers={ self.assertEqual(
'Host': '/localhost', self.get(headers={'Host': '/localhost', 'Connection': 'close'})[
'Connection': 'close' 'status'
})['status'], 400, 'Host slash') ],
400,
'Host slash',
)
def test_http_header_host_multiple_fields(self): def test_http_header_host_multiple_fields(self):
self.load('empty') self.load('empty')
self.assertEqual(self.get(headers={ self.assertEqual(
self.get(
headers={
'Host': ['localhost', 'example.com'], 'Host': ['localhost', 'example.com'],
'Connection': 'close' 'Connection': 'close',
})['status'], 400, 'Host multiple fields') }
)['status'],
400,
'Host multiple fields',
)
if __name__ == '__main__': if __name__ == '__main__':
TestUnitHTTPHeader.main() TestUnitHTTPHeader.main()

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,8 @@
import unittest import unittest
import unit import unit
class TestUnitNodeApplication(unit.TestUnitApplicationNode):
class TestUnitNodeApplication(unit.TestUnitApplicationNode):
def setUpClass(): def setUpClass():
u = unit.TestUnit().check_modules('node') u = unit.TestUnit().check_modules('node')
@@ -10,8 +10,9 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode):
self.load('basic') self.load('basic')
resp = self.get() resp = self.get()
self.assertEqual(resp['headers']['Content-Type'], 'text/plain', self.assertEqual(
'basic header') resp['headers']['Content-Type'], 'text/plain', 'basic header'
)
self.assertEqual(resp['body'], 'Hello World\n', 'basic body') self.assertEqual(resp['body'], 'Hello World\n', 'basic body')
def test_node_application_seq(self): def test_node_application_seq(self):
@@ -25,12 +26,15 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode):
body = 'Test body string.' body = 'Test body string.'
resp = self.post(headers={ resp = self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Content-Type': 'text/html', 'Content-Type': 'text/html',
'Custom-Header': 'blah', 'Custom-Header': 'blah',
'Connection': 'close' 'Connection': 'close',
}, body=body) },
body=body,
)
self.assertEqual(resp['status'], 200, 'status') self.assertEqual(resp['status'], 200, 'status')
headers = resp['headers'] headers = resp['headers']
@@ -39,15 +43,24 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode):
date = headers.pop('Date') date = headers.pop('Date')
self.assertEqual(date[-4:], ' GMT', 'date header timezone') self.assertEqual(date[-4:], ' GMT', 'date header timezone')
self.assertLess(abs(self.date_to_sec_epoch(date) - self.sec_epoch()), 5, self.assertLess(
'date header') abs(self.date_to_sec_epoch(date) - self.sec_epoch()),
5,
'date header',
)
raw_headers = headers.pop('Request-Raw-Headers') raw_headers = headers.pop('Request-Raw-Headers')
self.assertRegex(raw_headers, r'^(?:Host|localhost|Content-Type|' \ self.assertRegex(
'text\/html|Custom-Header|blah|Content-Length|17|Connection|' \ raw_headers,
'close|,)+$', 'raw headers') r'^(?:Host|localhost|Content-Type|'
'text\/html|Custom-Header|blah|Content-Length|17|Connection|'
'close|,)+$',
'raw headers',
)
self.assertDictEqual(headers, { self.assertDictEqual(
headers,
{
'Connection': 'close', 'Connection': 'close',
'Content-Length': str(len(body)), 'Content-Length': str(len(body)),
'Content-Type': 'text/html', 'Content-Type': 'text/html',
@@ -55,8 +68,10 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode):
'Request-Uri': '/', 'Request-Uri': '/',
'Http-Host': 'localhost', 'Http-Host': 'localhost',
'Server-Protocol': 'HTTP/1.1', 'Server-Protocol': 'HTTP/1.1',
'Custom-Header': 'blah' 'Custom-Header': 'blah',
}, 'headers') },
'headers',
)
self.assertEqual(resp['body'], body, 'body') self.assertEqual(resp['body'], body, 'body')
def test_node_application_get_variables(self): def test_node_application_get_variables(self):
@@ -70,11 +85,14 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode):
def test_node_application_post_variables(self): def test_node_application_post_variables(self):
self.load('post_variables') self.load('post_variables')
resp = self.post(headers={ resp = self.post(
headers={
'Content-Type': 'application/x-www-form-urlencoded', 'Content-Type': 'application/x-www-form-urlencoded',
'Host': 'localhost', 'Host': 'localhost',
'Connection': 'close' 'Connection': 'close',
}, body='var1=val1&var2=&var3') },
body='var1=val1&var2=&var3',
)
self.assertEqual(resp['headers']['X-Var-1'], 'val1', 'POST variables') self.assertEqual(resp['headers']['X-Var-1'], 'val1', 'POST variables')
self.assertEqual(resp['headers']['X-Var-2'], '', 'POST variables 2') self.assertEqual(resp['headers']['X-Var-2'], '', 'POST variables 2')
@@ -86,41 +104,56 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode):
resp = self.get() resp = self.get()
self.assertEqual(resp['status'], 404, '404 status') self.assertEqual(resp['status'], 404, '404 status')
self.assertRegex(resp['body'], r'<title>404 Not Found</title>', self.assertRegex(
'404 body') resp['body'], r'<title>404 Not Found</title>', '404 body'
)
def test_node_keepalive_body(self): def test_node_keepalive_body(self):
self.load('mirror') self.load('mirror')
(resp, sock) = self.post(headers={ (resp, sock) = self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Connection': 'keep-alive', 'Connection': 'keep-alive',
'Content-Type': 'text/html' 'Content-Type': 'text/html',
}, start=True, body='0123456789' * 500) },
start=True,
body='0123456789' * 500,
)
self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1') self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1')
resp = self.post(headers={ resp = self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Connection': 'close', 'Connection': 'close',
'Content-Type': 'text/html' 'Content-Type': 'text/html',
}, sock=sock, body='0123456789') },
sock=sock,
body='0123456789',
)
self.assertEqual(resp['body'], '0123456789', 'keep-alive 2') self.assertEqual(resp['body'], '0123456789', 'keep-alive 2')
def test_node_application_write_buffer(self): def test_node_application_write_buffer(self):
self.load('write_buffer') self.load('write_buffer')
self.assertEqual(self.get()['body'], '6\r\nbuffer\r\n0\r\n\r\n', self.assertEqual(
'write buffer') self.get()['body'], '6\r\nbuffer\r\n0\r\n\r\n', 'write buffer'
)
def test_node_application_write_callback(self): def test_node_application_write_callback(self):
self.load('write_callback') self.load('write_callback')
self.assertEqual(self.get()['body'], self.assertEqual(
'5\r\nhello\r\n5\r\nworld\r\n0\r\n\r\n', 'write callback order') self.get()['body'],
self.assertTrue(self.waitforfiles(self.testdir + '/node/callback'), '5\r\nhello\r\n5\r\nworld\r\n0\r\n\r\n',
'write callback') 'write callback order',
)
self.assertTrue(
self.waitforfiles(self.testdir + '/node/callback'),
'write callback',
)
def test_node_application_write_before_write_head(self): def test_node_application_write_before_write_head(self):
self.load('write_before_write_head') self.load('write_before_write_head')
@@ -136,17 +169,22 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode):
def test_node_application_write_return(self): def test_node_application_write_return(self):
self.load('write_return') self.load('write_return')
self.assertEqual(self.get()['body'], self.assertEqual(
'4\r\nbody\r\n4\r\ntrue\r\n0\r\n\r\n', 'write return') self.get()['body'],
'4\r\nbody\r\n4\r\ntrue\r\n0\r\n\r\n',
'write return',
)
def test_node_application_remove_header(self): def test_node_application_remove_header(self):
self.load('remove_header') self.load('remove_header')
resp = self.get(headers={ resp = self.get(
headers={
'Host': 'localhost', 'Host': 'localhost',
'X-Remove': 'X-Header', 'X-Remove': 'X-Header',
'Connection': 'close' 'Connection': 'close',
}) }
)
self.assertEqual(resp['headers']['Was-Header'], 'true', 'was header') self.assertEqual(resp['headers']['Was-Header'], 'true', 'was header')
self.assertEqual(resp['headers']['Has-Header'], 'false', 'has header') self.assertEqual(resp['headers']['Has-Header'], 'false', 'has header')
self.assertFalse('X-Header' in resp['headers'], 'remove header') self.assertFalse('X-Header' in resp['headers'], 'remove header')
@@ -154,35 +192,48 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode):
def test_node_application_remove_header_nonexisting(self): def test_node_application_remove_header_nonexisting(self):
self.load('remove_header') self.load('remove_header')
self.assertEqual(self.get(headers={ self.assertEqual(
self.get(
headers={
'Host': 'localhost', 'Host': 'localhost',
'X-Remove': 'blah', 'X-Remove': 'blah',
'Connection': 'close' 'Connection': 'close',
})['headers']['Has-Header'], 'true', 'remove header nonexisting') }
)['headers']['Has-Header'],
'true',
'remove header nonexisting',
)
def test_node_application_update_header(self): def test_node_application_update_header(self):
self.load('update_header') self.load('update_header')
self.assertEqual(self.get()['headers']['X-Header'], 'new', self.assertEqual(
'update header') self.get()['headers']['X-Header'], 'new', 'update header'
)
def test_node_application_set_header_array(self): def test_node_application_set_header_array(self):
self.load('set_header_array') self.load('set_header_array')
self.assertListEqual(self.get()['headers']['Set-Cookie'], self.assertListEqual(
['tc=one,two,three', 'tc=four,five,six'], 'set header array') self.get()['headers']['Set-Cookie'],
['tc=one,two,three', 'tc=four,five,six'],
'set header array',
)
@unittest.expectedFailure @unittest.expectedFailure
def test_node_application_status_message(self): def test_node_application_status_message(self):
self.load('status_message') self.load('status_message')
self.assertRegex(self.get(raw_resp=True), r'200 blah', 'status message') self.assertRegex(
self.get(raw_resp=True), r'200 blah', 'status message'
)
def test_node_application_get_header_type(self): def test_node_application_get_header_type(self):
self.load('get_header_type') self.load('get_header_type')
self.assertEqual(self.get()['headers']['X-Type'], 'number', self.assertEqual(
'get header type') self.get()['headers']['X-Type'], 'number', 'get header type'
)
def test_node_application_header_name_case(self): def test_node_application_header_name_case(self):
self.load('header_name_case') self.load('header_name_case')
@@ -196,56 +247,89 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode):
def test_node_application_promise_handler(self): def test_node_application_promise_handler(self):
self.load('promise_handler') self.load('promise_handler')
self.assertEqual(self.post(headers={ self.assertEqual(
self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Content-Type': 'text/html', 'Content-Type': 'text/html',
'Connection': 'close' 'Connection': 'close',
}, body='callback')['status'], 200, 'promise handler request') },
self.assertTrue(self.waitforfiles(self.testdir + '/node/callback'), body='callback',
'promise handler') )['status'],
200,
'promise handler request',
)
self.assertTrue(
self.waitforfiles(self.testdir + '/node/callback'),
'promise handler',
)
def test_node_application_promise_handler_write_after_end(self): def test_node_application_promise_handler_write_after_end(self):
self.load('promise_handler') self.load('promise_handler')
self.assertEqual(self.post(headers={ self.assertEqual(
self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Content-Type': 'text/html', 'Content-Type': 'text/html',
'X-Write-Call': '1', 'X-Write-Call': '1',
'Connection': 'close' 'Connection': 'close',
}, body='callback')['status'], 200, },
'promise handler request write after end') body='callback',
)['status'],
200,
'promise handler request write after end',
)
def test_node_application_promise_end(self): def test_node_application_promise_end(self):
self.load('promise_end') self.load('promise_end')
self.assertEqual(self.post(headers={ self.assertEqual(
self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Content-Type': 'text/html', 'Content-Type': 'text/html',
'Connection': 'close' 'Connection': 'close',
}, body='end')['status'], 200, 'promise end request') },
self.assertTrue(self.waitforfiles(self.testdir + '/node/callback'), body='end',
'promise end') )['status'],
200,
'promise end request',
)
self.assertTrue(
self.waitforfiles(self.testdir + '/node/callback'), 'promise end'
)
def test_node_application_promise_multiple_calls(self): def test_node_application_promise_multiple_calls(self):
self.load('promise_handler') self.load('promise_handler')
self.post(headers={ self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Content-Type': 'text/html', 'Content-Type': 'text/html',
'Connection': 'close' 'Connection': 'close',
}, body='callback1') },
body='callback1',
)
self.assertTrue(self.waitforfiles(self.testdir + '/node/callback1'), self.assertTrue(
'promise first call') self.waitforfiles(self.testdir + '/node/callback1'),
'promise first call',
)
self.post(headers={ self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Content-Type': 'text/html', 'Content-Type': 'text/html',
'Connection': 'close' 'Connection': 'close',
}, body='callback2') },
body='callback2',
)
self.assertTrue(self.waitforfiles(self.testdir + '/node/callback2'), self.assertTrue(
'promise second call') self.waitforfiles(self.testdir + '/node/callback2'),
'promise second call',
)
@unittest.expectedFailure @unittest.expectedFailure
def test_node_application_header_name_valid(self): def test_node_application_header_name_valid(self):
@@ -261,28 +345,46 @@ class TestUnitNodeApplication(unit.TestUnitApplicationNode):
def test_node_application_get_header_names(self): def test_node_application_get_header_names(self):
self.load('get_header_names') self.load('get_header_names')
self.assertListEqual(self.get()['headers']['X-Names'], self.assertListEqual(
['date', 'x-header'], 'get header names') self.get()['headers']['X-Names'],
['date', 'x-header'],
'get header names',
)
def test_node_application_has_header(self): def test_node_application_has_header(self):
self.load('has_header') self.load('has_header')
self.assertEqual(self.get(headers={ self.assertEqual(
self.get(
headers={
'Host': 'localhost', 'Host': 'localhost',
'X-Header': 'length', 'X-Header': 'length',
'Connection': 'close' 'Connection': 'close',
})['headers']['X-Has-Header'], 'false', 'has header length') }
)['headers']['X-Has-Header'],
'false',
'has header length',
)
self.assertEqual(self.get(headers={ self.assertEqual(
self.get(
headers={
'Host': 'localhost', 'Host': 'localhost',
'X-Header': 'Date', 'X-Header': 'Date',
'Connection': 'close' 'Connection': 'close',
})['headers']['X-Has-Header'], 'false', 'has header date') }
)['headers']['X-Has-Header'],
'false',
'has header date',
)
def test_node_application_write_multiple(self): def test_node_application_write_multiple(self):
self.load('write_multiple') self.load('write_multiple')
self.assertEqual(self.get()['body'], 'writewrite2end', 'write multiple') self.assertEqual(
self.get()['body'], 'writewrite2end', 'write multiple'
)
if __name__ == '__main__': if __name__ == '__main__':
TestUnitNodeApplication.main() TestUnitNodeApplication.main()

View File

@@ -1,8 +1,8 @@
import unittest import unittest
import unit import unit
class TestUnitPerlApplication(unit.TestUnitApplicationPerl):
class TestUnitPerlApplication(unit.TestUnitApplicationPerl):
def setUpClass(): def setUpClass():
unit.TestUnit().check_modules('perl') unit.TestUnit().check_modules('perl')
@@ -11,26 +11,37 @@ class TestUnitPerlApplication(unit.TestUnitApplicationPerl):
body = 'Test body string.' body = 'Test body string.'
resp = self.post(headers={ resp = self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Content-Type': 'text/html', 'Content-Type': 'text/html',
'Custom-Header': 'blah', 'Custom-Header': 'blah',
'Connection': 'close' 'Connection': 'close',
}, body=body) },
body=body,
)
self.assertEqual(resp['status'], 200, 'status') self.assertEqual(resp['status'], 200, 'status')
headers = resp['headers'] headers = resp['headers']
header_server = headers.pop('Server') header_server = headers.pop('Server')
self.assertRegex(header_server, r'Unit/[\d\.]+', 'server header') self.assertRegex(header_server, r'Unit/[\d\.]+', 'server header')
self.assertEqual(headers.pop('Server-Software'), header_server, self.assertEqual(
'server software header') headers.pop('Server-Software'),
header_server,
'server software header',
)
date = headers.pop('Date') date = headers.pop('Date')
self.assertEqual(date[-4:], ' GMT', 'date header timezone') self.assertEqual(date[-4:], ' GMT', 'date header timezone')
self.assertLess(abs(self.date_to_sec_epoch(date) - self.sec_epoch()), 5, self.assertLess(
'date header') abs(self.date_to_sec_epoch(date) - self.sec_epoch()),
5,
'date header',
)
self.assertDictEqual(headers, { self.assertDictEqual(
headers,
{
'Connection': 'close', 'Connection': 'close',
'Content-Length': str(len(body)), 'Content-Length': str(len(body)),
'Content-Type': 'text/html', 'Content-Type': 'text/html',
@@ -45,8 +56,10 @@ class TestUnitPerlApplication(unit.TestUnitApplicationPerl):
'Psgi-Multiprocess': '1', 'Psgi-Multiprocess': '1',
'Psgi-Run-Once': '', 'Psgi-Run-Once': '',
'Psgi-Nonblocking': '', 'Psgi-Nonblocking': '',
'Psgi-Streaming': '1' 'Psgi-Streaming': '1',
}, 'headers') },
'headers',
)
self.assertEqual(resp['body'], body, 'body') self.assertEqual(resp['body'], body, 'body')
def test_perl_application_query_string(self): def test_perl_application_query_string(self):
@@ -54,8 +67,11 @@ class TestUnitPerlApplication(unit.TestUnitApplicationPerl):
resp = self.get(url='/?var1=val1&var2=val2') resp = self.get(url='/?var1=val1&var2=val2')
self.assertEqual(resp['headers']['Query-String'], 'var1=val1&var2=val2', self.assertEqual(
'Query-String header') resp['headers']['Query-String'],
'var1=val1&var2=val2',
'Query-String header',
)
def test_perl_application_query_string_empty(self): def test_perl_application_query_string_empty(self):
self.load('query_string') self.load('query_string')
@@ -63,8 +79,9 @@ class TestUnitPerlApplication(unit.TestUnitApplicationPerl):
resp = self.get(url='/?') resp = self.get(url='/?')
self.assertEqual(resp['status'], 200, 'query string empty status') self.assertEqual(resp['status'], 200, 'query string empty status')
self.assertEqual(resp['headers']['Query-String'], '', self.assertEqual(
'query string empty') resp['headers']['Query-String'], '', 'query string empty'
)
@unittest.expectedFailure @unittest.expectedFailure
def test_perl_application_query_string_absent(self): def test_perl_application_query_string_absent(self):
@@ -73,15 +90,17 @@ class TestUnitPerlApplication(unit.TestUnitApplicationPerl):
resp = self.get() resp = self.get()
self.assertEqual(resp['status'], 200, 'query string absent status') self.assertEqual(resp['status'], 200, 'query string absent status')
self.assertEqual(resp['headers']['Query-String'], '', self.assertEqual(
'query string absent') resp['headers']['Query-String'], '', 'query string absent'
)
@unittest.expectedFailure @unittest.expectedFailure
def test_perl_application_server_port(self): def test_perl_application_server_port(self):
self.load('server_port') self.load('server_port')
self.assertEqual(self.get()['headers']['Server-Port'], '7080', self.assertEqual(
'Server-Port header') self.get()['headers']['Server-Port'], '7080', 'Server-Port header'
)
def test_perl_application_input_read_empty(self): def test_perl_application_input_read_empty(self):
self.load('input_read_empty') self.load('input_read_empty')
@@ -91,15 +110,19 @@ class TestUnitPerlApplication(unit.TestUnitApplicationPerl):
def test_perl_application_input_read_parts(self): def test_perl_application_input_read_parts(self):
self.load('input_read_parts') self.load('input_read_parts')
self.assertEqual(self.post(body='0123456789')['body'], '0123456789', self.assertEqual(
'input read parts') self.post(body='0123456789')['body'],
'0123456789',
'input read parts',
)
@unittest.expectedFailure @unittest.expectedFailure
def test_perl_application_input_read_offset(self): def test_perl_application_input_read_offset(self):
self.load('input_read_offset') self.load('input_read_offset')
self.assertEqual(self.post(body='0123456789')['body'], '4567', self.assertEqual(
'read offset') self.post(body='0123456789')['body'], '4567', 'read offset'
)
def test_perl_application_input_copy(self): def test_perl_application_input_copy(self):
self.load('input_copy') self.load('input_copy')
@@ -116,13 +139,17 @@ class TestUnitPerlApplication(unit.TestUnitApplicationPerl):
self.assertIsNotNone( self.assertIsNotNone(
self.search_in_log(r'\[error\].+Error in application'), self.search_in_log(r'\[error\].+Error in application'),
'errors print') 'errors print',
)
def test_perl_application_header_equal_names(self): def test_perl_application_header_equal_names(self):
self.load('header_equal_names') self.load('header_equal_names')
self.assertListEqual(self.get()['headers']['Set-Cookie'], self.assertListEqual(
['tc=one,two,three', 'tc=four,five,six'], 'header equal names') self.get()['headers']['Set-Cookie'],
['tc=one,two,three', 'tc=four,five,six'],
'header equal names',
)
def test_perl_application_header_pairs(self): def test_perl_application_header_pairs(self):
self.load('header_pairs') self.load('header_pairs')
@@ -160,10 +187,9 @@ class TestUnitPerlApplication(unit.TestUnitApplicationPerl):
@unittest.expectedFailure @unittest.expectedFailure
def test_perl_application_syntax_error(self): def test_perl_application_syntax_error(self):
self.skip_alerts.extend([ self.skip_alerts.extend(
r'PSGI: Failed to parse script', [r'PSGI: Failed to parse script', r'process \d+ exited on signal']
r'process \d+ exited on signal' )
])
self.load('syntax_error') self.load('syntax_error')
self.assertEqual(self.get()['status'], 500, 'syntax error') self.assertEqual(self.get()['status'], 500, 'syntax error')
@@ -171,19 +197,27 @@ class TestUnitPerlApplication(unit.TestUnitApplicationPerl):
def test_perl_keepalive_body(self): def test_perl_keepalive_body(self):
self.load('variables') self.load('variables')
(resp, sock) = self.post(headers={ (resp, sock) = self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Connection': 'keep-alive', 'Connection': 'keep-alive',
'Content-Type': 'text/html' 'Content-Type': 'text/html',
}, start=True, body='0123456789' * 500) },
start=True,
body='0123456789' * 500,
)
self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1') self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1')
resp = self.post(headers={ resp = self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Connection': 'close', 'Connection': 'close',
'Content-Type': 'text/html' 'Content-Type': 'text/html',
}, sock=sock, body='0123456789') },
sock=sock,
body='0123456789',
)
self.assertEqual(resp['body'], '0123456789', 'keep-alive 2') self.assertEqual(resp['body'], '0123456789', 'keep-alive 2')
@@ -194,11 +228,13 @@ class TestUnitPerlApplication(unit.TestUnitApplicationPerl):
self.assertIsNotNone( self.assertIsNotNone(
self.search_in_log(r'\[error\].+IOFake getline\(\) \$\/ is \d+'), self.search_in_log(r'\[error\].+IOFake getline\(\) \$\/ is \d+'),
'body io fake $/ value') 'body io fake $/ value',
)
self.assertIsNotNone( self.assertIsNotNone(
self.search_in_log(r'\[error\].+IOFake close\(\) called'), self.search_in_log(r'\[error\].+IOFake close\(\) called'),
'body io fake close') 'body io fake close',
)
def test_perl_delayed_response(self): def test_perl_delayed_response(self):
self.load('delayed_response') self.load('delayed_response')
@@ -216,5 +252,6 @@ class TestUnitPerlApplication(unit.TestUnitApplicationPerl):
self.assertEqual(resp['status'], 200, 'status') self.assertEqual(resp['status'], 200, 'status')
self.assertEqual(resp['body'], 'Hello World!', 'body') self.assertEqual(resp['body'], 'Hello World!', 'body')
if __name__ == '__main__': if __name__ == '__main__':
TestUnitPerlApplication.main() TestUnitPerlApplication.main()

View File

@@ -2,8 +2,8 @@ import unittest
import unit import unit
import re import re
class TestUnitPHPApplication(unit.TestUnitApplicationPHP):
class TestUnitPHPApplication(unit.TestUnitApplicationPHP):
def setUpClass(): def setUpClass():
unit.TestUnit().check_modules('php') unit.TestUnit().check_modules('php')
@@ -18,38 +18,51 @@ class TestUnitPHPApplication(unit.TestUnitApplicationPHP):
body = 'Test body string.' body = 'Test body string.'
resp = self.post(headers={ resp = self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Content-Type': 'text/html', 'Content-Type': 'text/html',
'Custom-Header': 'blah', 'Custom-Header': 'blah',
'Connection': 'close' 'Connection': 'close',
}, body=body) },
body=body,
)
self.assertEqual(resp['status'], 200, 'status') self.assertEqual(resp['status'], 200, 'status')
headers = resp['headers'] headers = resp['headers']
header_server = headers.pop('Server') header_server = headers.pop('Server')
self.assertRegex(header_server, r'Unit/[\d\.]+', 'server header') self.assertRegex(header_server, r'Unit/[\d\.]+', 'server header')
self.assertEqual(headers.pop('Server-Software'), header_server, self.assertEqual(
'server software header') headers.pop('Server-Software'),
header_server,
'server software header',
)
date = headers.pop('Date') date = headers.pop('Date')
self.assertEqual(date[-4:], ' GMT', 'date header timezone') self.assertEqual(date[-4:], ' GMT', 'date header timezone')
self.assertLess(abs(self.date_to_sec_epoch(date) - self.sec_epoch()), 5, self.assertLess(
'date header') abs(self.date_to_sec_epoch(date) - self.sec_epoch()),
5,
'date header',
)
if 'X-Powered-By' in headers: if 'X-Powered-By' in headers:
headers.pop('X-Powered-By') headers.pop('X-Powered-By')
headers.pop('Content-type') headers.pop('Content-type')
self.assertDictEqual(headers, { self.assertDictEqual(
headers,
{
'Connection': 'close', 'Connection': 'close',
'Content-Length': str(len(body)), 'Content-Length': str(len(body)),
'Request-Method': 'POST', 'Request-Method': 'POST',
'Request-Uri': '/', 'Request-Uri': '/',
'Http-Host': 'localhost', 'Http-Host': 'localhost',
'Server-Protocol': 'HTTP/1.1', 'Server-Protocol': 'HTTP/1.1',
'Custom-Header': 'blah' 'Custom-Header': 'blah',
}, 'headers') },
'headers',
)
self.assertEqual(resp['body'], body, 'body') self.assertEqual(resp['body'], body, 'body')
def test_php_application_query_string(self): def test_php_application_query_string(self):
@@ -57,8 +70,11 @@ class TestUnitPHPApplication(unit.TestUnitApplicationPHP):
resp = self.get(url='/?var1=val1&var2=val2') resp = self.get(url='/?var1=val1&var2=val2')
self.assertEqual(resp['headers']['Query-String'], 'var1=val1&var2=val2', self.assertEqual(
'query string') resp['headers']['Query-String'],
'var1=val1&var2=val2',
'query string',
)
def test_php_application_query_string_empty(self): def test_php_application_query_string_empty(self):
self.load('query_string') self.load('query_string')
@@ -66,8 +82,9 @@ class TestUnitPHPApplication(unit.TestUnitApplicationPHP):
resp = self.get(url='/?') resp = self.get(url='/?')
self.assertEqual(resp['status'], 200, 'query string empty status') self.assertEqual(resp['status'], 200, 'query string empty status')
self.assertEqual(resp['headers']['Query-String'], '', self.assertEqual(
'query string empty') resp['headers']['Query-String'], '', 'query string empty'
)
@unittest.expectedFailure @unittest.expectedFailure
def test_php_application_query_string_absent(self): def test_php_application_query_string_absent(self):
@@ -76,8 +93,9 @@ class TestUnitPHPApplication(unit.TestUnitApplicationPHP):
resp = self.get() resp = self.get()
self.assertEqual(resp['status'], 200, 'query string absent status') self.assertEqual(resp['status'], 200, 'query string absent status')
self.assertEqual(resp['headers']['Query-String'], '', self.assertEqual(
'query string absent') resp['headers']['Query-String'], '', 'query string absent'
)
def test_php_application_phpinfo(self): def test_php_application_phpinfo(self):
self.load('phpinfo') self.load('phpinfo')
@@ -93,25 +111,34 @@ class TestUnitPHPApplication(unit.TestUnitApplicationPHP):
resp = self.get() resp = self.get()
self.assertEqual(resp['status'], 404, '404 status') self.assertEqual(resp['status'], 404, '404 status')
self.assertRegex(resp['body'], r'<title>404 Not Found</title>', self.assertRegex(
'404 body') resp['body'], r'<title>404 Not Found</title>', '404 body'
)
def test_php_application_keepalive_body(self): def test_php_application_keepalive_body(self):
self.load('mirror') self.load('mirror')
(resp, sock) = self.post(headers={ (resp, sock) = self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Connection': 'keep-alive', 'Connection': 'keep-alive',
'Content-Type': 'text/html' 'Content-Type': 'text/html',
}, start=True, body='0123456789' * 500) },
start=True,
body='0123456789' * 500,
)
self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1') self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1')
resp = self.post(headers={ resp = self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Connection': 'close', 'Connection': 'close',
'Content-Type': 'text/html' 'Content-Type': 'text/html',
}, sock=sock, body='0123456789') },
sock=sock,
body='0123456789',
)
self.assertEqual(resp['body'], '0123456789', 'keep-alive 2') self.assertEqual(resp['body'], '0123456789', 'keep-alive 2')
@@ -133,11 +160,14 @@ class TestUnitPHPApplication(unit.TestUnitApplicationPHP):
def test_php_application_post_variables(self): def test_php_application_post_variables(self):
self.load('post_variables') self.load('post_variables')
resp = self.post(headers={ resp = self.post(
headers={
'Content-Type': 'application/x-www-form-urlencoded', 'Content-Type': 'application/x-www-form-urlencoded',
'Host': 'localhost', 'Host': 'localhost',
'Connection': 'close' 'Connection': 'close',
}, body='var1=val1&var2=') },
body='var1=val1&var2=',
)
self.assertEqual(resp['headers']['X-Var-1'], 'val1', 'POST variables') self.assertEqual(resp['headers']['X-Var-1'], 'val1', 'POST variables')
self.assertEqual(resp['headers']['X-Var-2'], '1', 'POST variables 2') self.assertEqual(resp['headers']['X-Var-2'], '1', 'POST variables 2')
self.assertEqual(resp['headers']['X-Var-3'], '', 'POST variables 3') self.assertEqual(resp['headers']['X-Var-3'], '', 'POST variables 3')
@@ -145,11 +175,13 @@ class TestUnitPHPApplication(unit.TestUnitApplicationPHP):
def test_php_application_cookies(self): def test_php_application_cookies(self):
self.load('cookies') self.load('cookies')
resp = self.get(headers={ resp = self.get(
headers={
'Cookie': 'var=val; var2=val2', 'Cookie': 'var=val; var2=val2',
'Host': 'localhost', 'Host': 'localhost',
'Connection': 'close' 'Connection': 'close',
}) }
)
self.assertEqual(resp['headers']['X-Cookie-1'], 'val', 'cookie') self.assertEqual(resp['headers']['X-Cookie-1'], 'val', 'cookie')
self.assertEqual(resp['headers']['X-Cookie-2'], 'val2', 'cookie') self.assertEqual(resp['headers']['X-Cookie-2'], 'val2', 'cookie')
@@ -157,96 +189,129 @@ class TestUnitPHPApplication(unit.TestUnitApplicationPHP):
def test_php_application_ini_precision(self): def test_php_application_ini_precision(self):
self.load('ini_precision') self.load('ini_precision')
self.assertNotEqual(self.get()['headers']['X-Precision'], '4', self.assertNotEqual(
'ini value default') self.get()['headers']['X-Precision'], '4', 'ini value default'
)
self.conf({"file": "ini/php.ini"}, 'applications/ini_precision/options') self.conf(
{"file": "ini/php.ini"}, 'applications/ini_precision/options'
)
self.assertEqual(self.get()['headers']['X-File'], self.assertEqual(
self.current_dir + '/php/ini_precision/ini/php.ini', 'ini file') self.get()['headers']['X-File'],
self.assertEqual(self.get()['headers']['X-Precision'], '4', 'ini value') self.current_dir + '/php/ini_precision/ini/php.ini',
'ini file',
)
self.assertEqual(
self.get()['headers']['X-Precision'], '4', 'ini value'
)
@unittest.expectedFailure @unittest.expectedFailure
def test_php_application_ini_admin_user(self): def test_php_application_ini_admin_user(self):
self.load('ini_precision') self.load('ini_precision')
self.assertIn('error', self.conf({ self.assertIn(
"user": { "precision": "4" }, 'error',
"admin": { "precision": "5" } self.conf(
}, 'applications/ini_precision/options'), 'ini admin user') {"user": {"precision": "4"}, "admin": {"precision": "5"}},
'applications/ini_precision/options',
),
'ini admin user',
)
def test_php_application_ini_admin(self): def test_php_application_ini_admin(self):
self.load('ini_precision') self.load('ini_precision')
self.conf({ self.conf(
"file": "php.ini", {"file": "php.ini", "admin": {"precision": "5"}},
"admin": { "precision": "5" } 'applications/ini_precision/options',
}, 'applications/ini_precision/options') )
self.assertEqual(self.get()['headers']['X-Precision'], '5', self.assertEqual(
'ini value admin') self.get()['headers']['X-Precision'], '5', 'ini value admin'
)
def test_php_application_ini_user(self): def test_php_application_ini_user(self):
self.load('ini_precision') self.load('ini_precision')
self.conf({ self.conf(
"file": "php.ini", {"file": "php.ini", "user": {"precision": "5"}},
"user": { "precision": "5" } 'applications/ini_precision/options',
}, 'applications/ini_precision/options') )
self.assertEqual(self.get()['headers']['X-Precision'], '5', self.assertEqual(
'ini value user') self.get()['headers']['X-Precision'], '5', 'ini value user'
)
def test_php_application_ini_user_2(self): def test_php_application_ini_user_2(self):
self.load('ini_precision') self.load('ini_precision')
self.conf({"file": "ini/php.ini"}, 'applications/ini_precision/options') self.conf(
{"file": "ini/php.ini"}, 'applications/ini_precision/options'
)
self.assertEqual(self.get()['headers']['X-Precision'], '4', self.assertEqual(
'ini user file') self.get()['headers']['X-Precision'], '4', 'ini user file'
)
self.conf({ "precision": "5" }, self.conf(
'applications/ini_precision/options/user') {"precision": "5"}, 'applications/ini_precision/options/user'
)
self.assertEqual(self.get()['headers']['X-Precision'], '5', self.assertEqual(
'ini value user') self.get()['headers']['X-Precision'], '5', 'ini value user'
)
def test_php_application_ini_set_admin(self): def test_php_application_ini_set_admin(self):
self.load('ini_precision') self.load('ini_precision')
self.conf({"admin": { "precision": "5" }}, self.conf(
'applications/ini_precision/options') {"admin": {"precision": "5"}}, 'applications/ini_precision/options'
)
self.assertEqual(self.get(url='/?precision=6')['headers']['X-Precision'], self.assertEqual(
'5', 'ini set admin') self.get(url='/?precision=6')['headers']['X-Precision'],
'5',
'ini set admin',
)
def test_php_application_ini_set_user(self): def test_php_application_ini_set_user(self):
self.load('ini_precision') self.load('ini_precision')
self.conf({"user": { "precision": "5" }}, self.conf(
'applications/ini_precision/options') {"user": {"precision": "5"}}, 'applications/ini_precision/options'
)
self.assertEqual(self.get(url='/?precision=6')['headers']['X-Precision'], self.assertEqual(
'6', 'ini set user') self.get(url='/?precision=6')['headers']['X-Precision'],
'6',
'ini set user',
)
def test_php_application_ini_repeat(self): def test_php_application_ini_repeat(self):
self.load('ini_precision') self.load('ini_precision')
self.conf({"user": { "precision": "5" }}, self.conf(
'applications/ini_precision/options') {"user": {"precision": "5"}}, 'applications/ini_precision/options'
)
self.assertEqual(self.get()['headers']['X-Precision'], '5', 'ini value') self.assertEqual(
self.get()['headers']['X-Precision'], '5', 'ini value'
)
self.assertEqual(self.get()['headers']['X-Precision'], '5', self.assertEqual(
'ini value repeat') self.get()['headers']['X-Precision'], '5', 'ini value repeat'
)
def test_php_application_disable_functions_exec(self): def test_php_application_disable_functions_exec(self):
self.load('time_exec') self.load('time_exec')
self.before_disable_functions() self.before_disable_functions()
self.conf({"admin": { "disable_functions": "exec" }}, self.conf(
'applications/time_exec/options') {"admin": {"disable_functions": "exec"}},
'applications/time_exec/options',
)
body = self.get()['body'] body = self.get()['body']
@@ -258,80 +323,103 @@ class TestUnitPHPApplication(unit.TestUnitApplicationPHP):
self.before_disable_functions() self.before_disable_functions()
self.conf({"admin": { "disable_functions": "exec,time" }}, self.conf(
'applications/time_exec/options') {"admin": {"disable_functions": "exec,time"}},
'applications/time_exec/options',
)
body = self.get()['body'] body = self.get()['body']
self.assertNotRegex(body, r'time: \d+', 'disable_functions comma time') self.assertNotRegex(body, r'time: \d+', 'disable_functions comma time')
self.assertNotRegex(body, r'exec: \/\w+', self.assertNotRegex(
'disable_functions comma exec') body, r'exec: \/\w+', 'disable_functions comma exec'
)
def test_php_application_disable_functions_space(self): def test_php_application_disable_functions_space(self):
self.load('time_exec') self.load('time_exec')
self.before_disable_functions() self.before_disable_functions()
self.conf({"admin": { "disable_functions": "exec time" }}, self.conf(
'applications/time_exec/options') {"admin": {"disable_functions": "exec time"}},
'applications/time_exec/options',
)
body = self.get()['body'] body = self.get()['body']
self.assertNotRegex(body, r'time: \d+', 'disable_functions space time') self.assertNotRegex(body, r'time: \d+', 'disable_functions space time')
self.assertNotRegex(body, r'exec: \/\w+', self.assertNotRegex(
'disable_functions space exec') body, r'exec: \/\w+', 'disable_functions space exec'
)
def test_php_application_disable_functions_user(self): def test_php_application_disable_functions_user(self):
self.load('time_exec') self.load('time_exec')
self.before_disable_functions() self.before_disable_functions()
self.conf({"user": { "disable_functions": "exec" }}, self.conf(
'applications/time_exec/options') {"user": {"disable_functions": "exec"}},
'applications/time_exec/options',
)
body = self.get()['body'] body = self.get()['body']
self.assertRegex(body, r'time: \d+', 'disable_functions user time') self.assertRegex(body, r'time: \d+', 'disable_functions user time')
self.assertNotRegex(body, r'exec: \/\w+', 'disable_functions user exec') self.assertNotRegex(
body, r'exec: \/\w+', 'disable_functions user exec'
)
def test_php_application_disable_functions_nonexistent(self): def test_php_application_disable_functions_nonexistent(self):
self.load('time_exec') self.load('time_exec')
self.before_disable_functions() self.before_disable_functions()
self.conf({"admin": { "disable_functions": "blah" }}, self.conf(
'applications/time_exec/options') {"admin": {"disable_functions": "blah"}},
'applications/time_exec/options',
)
body = self.get()['body'] body = self.get()['body']
self.assertRegex(body, r'time: \d+', self.assertRegex(
'disable_functions nonexistent time') body, r'time: \d+', 'disable_functions nonexistent time'
self.assertRegex(body, r'exec: \/\w+', )
'disable_functions nonexistent exec') self.assertRegex(
body, r'exec: \/\w+', 'disable_functions nonexistent exec'
)
def test_php_application_disable_classes(self): def test_php_application_disable_classes(self):
self.load('date_time') self.load('date_time')
self.assertRegex(self.get()['body'], r'012345', self.assertRegex(
'disable_classes before') self.get()['body'], r'012345', 'disable_classes before'
)
self.conf({"admin": { "disable_classes": "DateTime" }}, self.conf(
'applications/date_time/options') {"admin": {"disable_classes": "DateTime"}},
'applications/date_time/options',
)
self.assertNotRegex(self.get()['body'], r'012345', self.assertNotRegex(
'disable_classes before') self.get()['body'], r'012345', 'disable_classes before'
)
def test_php_application_disable_classes_user(self): def test_php_application_disable_classes_user(self):
self.load('date_time') self.load('date_time')
self.assertRegex(self.get()['body'], r'012345', self.assertRegex(
'disable_classes before') self.get()['body'], r'012345', 'disable_classes before'
)
self.conf({"user": { "disable_classes": "DateTime" }}, self.conf(
'applications/date_time/options') {"user": {"disable_classes": "DateTime"}},
'applications/date_time/options',
)
self.assertNotRegex(
self.get()['body'], r'012345', 'disable_classes before'
)
self.assertNotRegex(self.get()['body'], r'012345',
'disable_classes before')
if __name__ == '__main__': if __name__ == '__main__':
TestUnitPHPApplication.main() TestUnitPHPApplication.main()

View File

@@ -1,27 +1,23 @@
import unittest import unittest
import unit import unit
class TestUnitPHPBasic(unit.TestUnitControl):
class TestUnitPHPBasic(unit.TestUnitControl):
def setUpClass(): def setUpClass():
unit.TestUnit().check_modules('php') unit.TestUnit().check_modules('php')
conf_app = { conf_app = {
"app": { "app": {
"type": "php", "type": "php",
"processes": { "spare": 0 }, "processes": {"spare": 0},
"root": "/app", "root": "/app",
"index": "index.php" "index": "index.php",
} }
} }
conf_basic = { conf_basic = {
"listeners": { "listeners": {"*:7080": {"application": "app"}},
"*:7080": { "applications": conf_app,
"application": "app"
}
},
"applications": conf_app
} }
def test_php_get_applications(self): def test_php_get_applications(self):
@@ -30,113 +26,146 @@ class TestUnitPHPBasic(unit.TestUnitControl):
conf = self.conf_get() conf = self.conf_get()
self.assertEqual(conf['listeners'], {}, 'listeners') self.assertEqual(conf['listeners'], {}, 'listeners')
self.assertEqual(conf['applications'], self.assertEqual(
conf['applications'],
{ {
"app": { "app": {
"type": "php", "type": "php",
"processes": { "spare": 0 }, "processes": {"spare": 0},
"root": "/app", "root": "/app",
"index": "index.php" "index": "index.php",
} }
}, },
'applications') 'applications',
)
def test_php_get_applications_prefix(self): def test_php_get_applications_prefix(self):
self.conf(self.conf_app, 'applications') self.conf(self.conf_app, 'applications')
self.assertEqual(self.conf_get('applications'), self.assertEqual(
self.conf_get('applications'),
{ {
"app": { "app": {
"type": "php", "type": "php",
"processes": { "spare": 0 }, "processes": {"spare": 0},
"root": "/app", "root": "/app",
"index": "index.php" "index": "index.php",
} }
}, },
'applications prefix') 'applications prefix',
)
def test_php_get_applications_prefix_2(self): def test_php_get_applications_prefix_2(self):
self.conf(self.conf_app, 'applications') self.conf(self.conf_app, 'applications')
self.assertEqual(self.conf_get('applications/app'), self.assertEqual(
self.conf_get('applications/app'),
{ {
"type": "php", "type": "php",
"processes": { "spare": 0 }, "processes": {"spare": 0},
"root": "/app", "root": "/app",
"index": "index.php" "index": "index.php",
}, },
'applications prefix 2') 'applications prefix 2',
)
def test_php_get_applications_prefix_3(self): def test_php_get_applications_prefix_3(self):
self.conf(self.conf_app, 'applications') self.conf(self.conf_app, 'applications')
self.assertEqual(self.conf_get('applications/app/type'), 'php', self.assertEqual(self.conf_get('applications/app/type'), 'php', 'type')
'type') self.assertEqual(
self.assertEqual(self.conf_get('applications/app/processes/spare'), 0, self.conf_get('applications/app/processes/spare'),
'spare processes') 0,
'spare processes',
)
def test_php_get_listeners(self): def test_php_get_listeners(self):
self.conf(self.conf_basic) self.conf(self.conf_basic)
self.assertEqual(self.conf_get()['listeners'], self.assertEqual(
{"*:7080":{"application":"app"}}, 'listeners') self.conf_get()['listeners'],
{"*:7080": {"application": "app"}},
'listeners',
)
def test_php_get_listeners_prefix(self): def test_php_get_listeners_prefix(self):
self.conf(self.conf_basic) self.conf(self.conf_basic)
self.assertEqual(self.conf_get('listeners'), self.assertEqual(
{"*:7080":{"application":"app"}}, 'listeners prefix') self.conf_get('listeners'),
{"*:7080": {"application": "app"}},
'listeners prefix',
)
def test_php_get_listeners_prefix_2(self): def test_php_get_listeners_prefix_2(self):
self.conf(self.conf_basic) self.conf(self.conf_basic)
self.assertEqual(self.conf_get('listeners/*:7080'), self.assertEqual(
{"application":"app"}, 'listeners prefix 2') self.conf_get('listeners/*:7080'),
{"application": "app"},
'listeners prefix 2',
)
def test_php_change_listener(self): def test_php_change_listener(self):
self.conf(self.conf_basic) self.conf(self.conf_basic)
self.conf({"*:7081":{"application":"app"}}, 'listeners') self.conf({"*:7081": {"application": "app"}}, 'listeners')
self.assertEqual(self.conf_get('listeners'), self.assertEqual(
{"*:7081": {"application":"app"}}, 'change listener') self.conf_get('listeners'),
{"*:7081": {"application": "app"}},
'change listener',
)
def test_php_add_listener(self): def test_php_add_listener(self):
self.conf(self.conf_basic) self.conf(self.conf_basic)
self.conf({"application":"app"}, 'listeners/*:7082') self.conf({"application": "app"}, 'listeners/*:7082')
self.assertEqual(self.conf_get('listeners'), self.assertEqual(
self.conf_get('listeners'),
{ {
"*:7080": { "*:7080": {"application": "app"},
"application": "app" "*:7082": {"application": "app"},
}, },
"*:7082": { 'add listener',
"application": "app" )
}
},
'add listener')
def test_php_change_application(self): def test_php_change_application(self):
self.conf(self.conf_basic) self.conf(self.conf_basic)
self.conf('30', 'applications/app/processes/max') self.conf('30', 'applications/app/processes/max')
self.assertEqual(self.conf_get('applications/app/processes/max'), 30, self.assertEqual(
'change application max') self.conf_get('applications/app/processes/max'),
30,
'change application max',
)
self.conf('"/www"', 'applications/app/root') self.conf('"/www"', 'applications/app/root')
self.assertEqual(self.conf_get('applications/app/root'), '/www', self.assertEqual(
'change application root') self.conf_get('applications/app/root'),
'/www',
'change application root',
)
def test_php_delete(self): def test_php_delete(self):
self.conf(self.conf_basic) self.conf(self.conf_basic)
self.assertIn('error', self.conf_delete('applications/app'), self.assertIn(
'delete app before listener') 'error',
self.assertIn('success', self.conf_delete('listeners/*:7080'), self.conf_delete('applications/app'),
'delete listener') 'delete app before listener',
self.assertIn('success', self.conf_delete('applications/app'), )
'delete app after listener') self.assertIn(
self.assertIn('error', self.conf_delete('applications/app'), 'success', self.conf_delete('listeners/*:7080'), 'delete listener'
'delete app again') )
self.assertIn(
'success',
self.conf_delete('applications/app'),
'delete app after listener',
)
self.assertIn(
'error', self.conf_delete('applications/app'), 'delete app again'
)
if __name__ == '__main__': if __name__ == '__main__':
TestUnitPHPBasic.main() TestUnitPHPBasic.main()

View File

@@ -2,8 +2,8 @@ import time
import unittest import unittest
import unit import unit
class TestUnitPythonApplication(unit.TestUnitApplicationPython):
class TestUnitPythonApplication(unit.TestUnitApplicationPython):
def setUpClass(): def setUpClass():
unit.TestUnit().check_modules('python') unit.TestUnit().check_modules('python')
@@ -12,26 +12,37 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython):
body = 'Test body string.' body = 'Test body string.'
resp = self.post(headers={ resp = self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Content-Type': 'text/html', 'Content-Type': 'text/html',
'Custom-Header': 'blah', 'Custom-Header': 'blah',
'Connection': 'close' 'Connection': 'close',
}, body=body) },
body=body,
)
self.assertEqual(resp['status'], 200, 'status') self.assertEqual(resp['status'], 200, 'status')
headers = resp['headers'] headers = resp['headers']
header_server = headers.pop('Server') header_server = headers.pop('Server')
self.assertRegex(header_server, r'Unit/[\d\.]+', 'server header') self.assertRegex(header_server, r'Unit/[\d\.]+', 'server header')
self.assertEqual(headers.pop('Server-Software'), header_server, self.assertEqual(
'server software header') headers.pop('Server-Software'),
header_server,
'server software header',
)
date = headers.pop('Date') date = headers.pop('Date')
self.assertEqual(date[-4:], ' GMT', 'date header timezone') self.assertEqual(date[-4:], ' GMT', 'date header timezone')
self.assertLess(abs(self.date_to_sec_epoch(date) - self.sec_epoch()), 5, self.assertLess(
'date header') abs(self.date_to_sec_epoch(date) - self.sec_epoch()),
5,
'date header',
)
self.assertDictEqual(headers, { self.assertDictEqual(
headers,
{
'Connection': 'close', 'Connection': 'close',
'Content-Length': str(len(body)), 'Content-Length': str(len(body)),
'Content-Type': 'text/html', 'Content-Type': 'text/html',
@@ -44,8 +55,10 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython):
'Wsgi-Url-Scheme': 'http', 'Wsgi-Url-Scheme': 'http',
'Wsgi-Multithread': 'False', 'Wsgi-Multithread': 'False',
'Wsgi-Multiprocess': 'True', 'Wsgi-Multiprocess': 'True',
'Wsgi-Run-Once': 'False' 'Wsgi-Run-Once': 'False',
}, 'headers') },
'headers',
)
self.assertEqual(resp['body'], body, 'body') self.assertEqual(resp['body'], body, 'body')
def test_python_application_query_string(self): def test_python_application_query_string(self):
@@ -53,8 +66,11 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython):
resp = self.get(url='/?var1=val1&var2=val2') resp = self.get(url='/?var1=val1&var2=val2')
self.assertEqual(resp['headers']['Query-String'], 'var1=val1&var2=val2', self.assertEqual(
'Query-String header') resp['headers']['Query-String'],
'var1=val1&var2=val2',
'Query-String header',
)
def test_python_application_query_string_empty(self): def test_python_application_query_string_empty(self):
self.load('query_string') self.load('query_string')
@@ -62,8 +78,9 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython):
resp = self.get(url='/?') resp = self.get(url='/?')
self.assertEqual(resp['status'], 200, 'query string empty status') self.assertEqual(resp['status'], 200, 'query string empty status')
self.assertEqual(resp['headers']['Query-String'], '', self.assertEqual(
'query string empty') resp['headers']['Query-String'], '', 'query string empty'
)
def test_python_application_query_string_absent(self): def test_python_application_query_string_absent(self):
self.load('query_string') self.load('query_string')
@@ -71,71 +88,87 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython):
resp = self.get() resp = self.get()
self.assertEqual(resp['status'], 200, 'query string absent status') self.assertEqual(resp['status'], 200, 'query string absent status')
self.assertEqual(resp['headers']['Query-String'], '', self.assertEqual(
'query string absent') resp['headers']['Query-String'], '', 'query string absent'
)
@unittest.expectedFailure @unittest.expectedFailure
def test_python_application_server_port(self): def test_python_application_server_port(self):
self.load('server_port') self.load('server_port')
self.assertEqual(self.get()['headers']['Server-Port'], '7080', self.assertEqual(
'Server-Port header') self.get()['headers']['Server-Port'], '7080', 'Server-Port header'
)
def test_python_application_204_transfer_encoding(self): def test_python_application_204_transfer_encoding(self):
self.load('204_no_content') self.load('204_no_content')
self.assertNotIn('Transfer-Encoding', self.get()['headers'], self.assertNotIn(
'204 header transfer encoding') 'Transfer-Encoding',
self.get()['headers'],
'204 header transfer encoding',
)
def test_python_application_ctx_iter_atexit(self): def test_python_application_ctx_iter_atexit(self):
self.load('ctx_iter_atexit') self.load('ctx_iter_atexit')
resp = self.post(headers={ resp = self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Connection': 'close', 'Connection': 'close',
'Content-Type': 'text/html' 'Content-Type': 'text/html',
}, body='0123456789') },
body='0123456789',
)
self.assertEqual(resp['status'], 200, 'ctx iter status') self.assertEqual(resp['status'], 200, 'ctx iter status')
self.assertEqual(resp['body'], '0123456789', 'ctx iter body') self.assertEqual(resp['body'], '0123456789', 'ctx iter body')
self.conf({ self.conf({"listeners": {}, "applications": {}})
"listeners": {},
"applications": {}
})
self.stop() self.stop()
time.sleep(0.2) time.sleep(0.2)
self.assertIsNotNone(self.search_in_log(r'RuntimeError'), self.assertIsNotNone(
'ctx iter atexit') self.search_in_log(r'RuntimeError'), 'ctx iter atexit'
)
def test_python_keepalive_body(self): def test_python_keepalive_body(self):
self.load('mirror') self.load('mirror')
(resp, sock) = self.post(headers={ (resp, sock) = self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Connection': 'keep-alive', 'Connection': 'keep-alive',
'Content-Type': 'text/html' 'Content-Type': 'text/html',
}, start=True, body='0123456789' * 500) },
start=True,
body='0123456789' * 500,
)
self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1') self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1')
resp = self.post(headers={ resp = self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Connection': 'close', 'Connection': 'close',
'Content-Type': 'text/html' 'Content-Type': 'text/html',
}, sock=sock, body='0123456789') },
sock=sock,
body='0123456789',
)
self.assertEqual(resp['body'], '0123456789', 'keep-alive 2') self.assertEqual(resp['body'], '0123456789', 'keep-alive 2')
def test_python_keepalive_reconfigure(self): def test_python_keepalive_reconfigure(self):
self.skip_alerts.extend([ self.skip_alerts.extend(
[
r'pthread_mutex.+failed', r'pthread_mutex.+failed',
r'failed to apply', r'failed to apply',
r'process \d+ exited on signal' r'process \d+ exited on signal',
]) ]
)
self.load('mirror') self.load('mirror')
body = '0123456789' body = '0123456789'
@@ -143,74 +176,109 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython):
socks = [] socks = []
for i in range(conns): for i in range(conns):
(resp, sock) = self.post(headers={ (resp, sock) = self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Connection': 'keep-alive', 'Connection': 'keep-alive',
'Content-Type': 'text/html' 'Content-Type': 'text/html',
}, start=True, body=body) },
start=True,
body=body,
)
self.assertEqual(resp['body'], body, 'keep-alive open') self.assertEqual(resp['body'], body, 'keep-alive open')
self.assertIn('success', self.conf({ self.assertIn(
"spare": i % 4, 'success',
"max": (i % 4) + 1 self.conf(
}, 'applications/mirror/processes'), 'reconfigure') str(i + 1),
'applications/mirror/processes',
),
'reconfigure',
)
socks.append(sock) socks.append(sock)
for i in range(conns): for i in range(conns):
(resp, sock) = self.post(headers={ (resp, sock) = self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Connection': 'keep-alive', 'Connection': 'keep-alive',
'Content-Type': 'text/html' 'Content-Type': 'text/html',
}, start=True, sock=socks[i], body=body) },
start=True,
sock=socks[i],
body=body,
)
self.assertEqual(resp['body'], body, 'keep-alive request') self.assertEqual(resp['body'], body, 'keep-alive request')
self.assertIn('success', self.conf({ self.assertIn(
"spare": i % 4, 'success',
"max": (i % 4) + 1 self.conf(
}, 'applications/mirror/processes'), 'reconfigure 2') str(i + 1),
'applications/mirror/processes',
),
'reconfigure 2',
)
for i in range(conns): for i in range(conns):
resp = self.post(headers={ resp = self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Connection': 'close', 'Connection': 'close',
'Content-Type': 'text/html' 'Content-Type': 'text/html',
}, sock=socks[i], body=body) },
sock=socks[i],
body=body,
)
self.assertEqual(resp['body'], body, 'keep-alive close') self.assertEqual(resp['body'], body, 'keep-alive close')
self.assertIn('success', self.conf({ self.assertIn(
"spare": i % 4, 'success',
"max": (i % 4) + 1 self.conf(
}, 'applications/mirror/processes'), 'reconfigure 3') str(i + 1),
'applications/mirror/processes',
),
'reconfigure 3',
)
def test_python_keepalive_reconfigure_2(self): def test_python_keepalive_reconfigure_2(self):
self.load('mirror') self.load('mirror')
body = '0123456789' body = '0123456789'
(resp, sock) = self.post(headers={ (resp, sock) = self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Connection': 'keep-alive', 'Connection': 'keep-alive',
'Content-Type': 'text/html' 'Content-Type': 'text/html',
}, start=True, body=body) },
start=True,
body=body,
)
self.assertEqual(resp['body'], body, 'reconfigure 2 keep-alive 1') self.assertEqual(resp['body'], body, 'reconfigure 2 keep-alive 1')
self.load('empty') self.load('empty')
(resp, sock) = self.post(headers={ (resp, sock) = self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Connection': 'close', 'Connection': 'close',
'Content-Type': 'text/html' 'Content-Type': 'text/html',
}, start=True, sock=sock, body=body) },
start=True,
sock=sock,
body=body,
)
self.assertEqual(resp['status'], 200, 'reconfigure 2 keep-alive 2') self.assertEqual(resp['status'], 200, 'reconfigure 2 keep-alive 2')
self.assertEqual(resp['body'], '', 'reconfigure 2 keep-alive 2 body') self.assertEqual(resp['body'], '', 'reconfigure 2 keep-alive 2 body')
self.assertIn('success', self.conf({ self.assertIn(
"listeners": {}, 'success',
"applications": {} self.conf({"listeners": {}, "applications": {}}),
}), 'reconfigure 2 clear configuration') 'reconfigure 2 clear configuration',
)
resp = self.get(sock=sock) resp = self.get(sock=sock)
@@ -219,18 +287,27 @@ class TestUnitPythonApplication(unit.TestUnitApplicationPython):
def test_python_keepalive_reconfigure_3(self): def test_python_keepalive_reconfigure_3(self):
self.load('empty') self.load('empty')
(resp, sock) = self.http(b"""GET / HTTP/1.1 (resp, sock) = self.http(
""", start=True, raw=True) b"""GET / HTTP/1.1
""",
start=True,
raw=True,
)
self.assertIn('success', self.conf({ self.assertIn(
"listeners": {}, 'success',
"applications": {} self.conf({"listeners": {}, "applications": {}}),
}), 'reconfigure 3 clear configuration') 'reconfigure 3 clear configuration',
)
resp = self.http(b"""Host: localhost resp = self.http(
b"""Host: localhost
Connection: close Connection: close
""", sock=sock, raw=True) """,
sock=sock,
raw=True,
)
self.assertEqual(resp['status'], 200, 'reconfigure 3') self.assertEqual(resp['status'], 200, 'reconfigure 3')
@@ -239,10 +316,7 @@ Connection: close
self.get() self.get()
self.conf({ self.conf({"listeners": {}, "applications": {}})
"listeners": {},
"applications": {}
})
self.stop() self.stop()
@@ -267,35 +341,47 @@ Connection: close
body = '0123456789' body = '0123456789'
resp = self.post(headers={ resp = self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Input-Length': '5', 'Input-Length': '5',
'Connection': 'close' 'Connection': 'close',
}, body=body) },
body=body,
)
self.assertEqual(resp['body'], body[:5], 'input read length lt body') self.assertEqual(resp['body'], body[:5], 'input read length lt body')
resp = self.post(headers={ resp = self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Input-Length': '15', 'Input-Length': '15',
'Connection': 'close' 'Connection': 'close',
}, body=body) },
body=body,
)
self.assertEqual(resp['body'], body, 'input read length gt body') self.assertEqual(resp['body'], body, 'input read length gt body')
resp = self.post(headers={ resp = self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Input-Length': '0', 'Input-Length': '0',
'Connection': 'close' 'Connection': 'close',
}, body=body) },
body=body,
)
self.assertEqual(resp['body'], '', 'input read length zero') self.assertEqual(resp['body'], '', 'input read length zero')
resp = self.post(headers={ resp = self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Input-Length': '-1', 'Input-Length': '-1',
'Connection': 'close' 'Connection': 'close',
}, body=body) },
body=body,
)
self.assertEqual(resp['body'], body, 'input read length negative') self.assertEqual(resp['body'], body, 'input read length negative')
@@ -309,7 +395,8 @@ Connection: close
self.assertIsNotNone( self.assertIsNotNone(
self.search_in_log(r'\[error\].+Error in application\.'), self.search_in_log(r'\[error\].+Error in application\.'),
'errors write') 'errors write',
)
def test_python_application_body_array(self): def test_python_application_body_array(self):
self.load('body_array') self.load('body_array')
@@ -349,8 +436,9 @@ Connection: close
self.stop() self.stop()
self.assertIsNotNone(self.search_in_log(r'Close called\.'), self.assertIsNotNone(
'close error') self.search_in_log(r'Close called\.'), 'close error'
)
def test_python_application_not_iterable(self): def test_python_application_not_iterable(self):
self.load('not_iterable') self.load('not_iterable')
@@ -359,14 +447,18 @@ Connection: close
self.stop() self.stop()
self.assertIsNotNone(self.search_in_log( self.assertIsNotNone(
r'\[error\].+the application returned not an iterable object'), self.search_in_log(
'not iterable') r'\[error\].+the application returned not an iterable object'
),
'not iterable',
)
def test_python_application_write(self): def test_python_application_write(self):
self.load('write') self.load('write')
self.assertEqual(self.get()['body'], '0123456789', 'write') self.assertEqual(self.get()['body'], '0123456789', 'write')
if __name__ == '__main__': if __name__ == '__main__':
TestUnitPythonApplication.main() TestUnitPythonApplication.main()

View File

@@ -1,38 +1,37 @@
import unittest import unittest
import unit import unit
class TestUnitPythonBasic(unit.TestUnitControl):
class TestUnitPythonBasic(unit.TestUnitControl):
def setUpClass(): def setUpClass():
unit.TestUnit().check_modules('python') unit.TestUnit().check_modules('python')
conf_app = { conf_app = {
"app": { "app": {
"type": "python", "type": "python",
"processes": { "spare": 0 }, "processes": {"spare": 0},
"path": "/app", "path": "/app",
"module": "wsgi" "module": "wsgi",
} }
} }
conf_basic = { conf_basic = {
"listeners": { "listeners": {"*:7080": {"application": "app"}},
"*:7080": { "applications": conf_app,
"application": "app"
}
},
"applications": conf_app
} }
def test_python_get_empty(self): def test_python_get_empty(self):
self.assertEqual(self.conf_get(), self.assertEqual(
{'listeners': {}, 'applications': {}}, 'empty') self.conf_get(), {'listeners': {}, 'applications': {}}, 'empty'
)
def test_python_get_prefix_listeners(self): def test_python_get_prefix_listeners(self):
self.assertEqual(self.conf_get('listeners'), {}, 'listeners prefix') self.assertEqual(self.conf_get('listeners'), {}, 'listeners prefix')
def test_python_get_prefix_applications(self): def test_python_get_prefix_applications(self):
self.assertEqual(self.conf_get('applications'), {}, 'applications prefix') self.assertEqual(
self.conf_get('applications'), {}, 'applications prefix'
)
def test_python_get_applications(self): def test_python_get_applications(self):
self.conf(self.conf_app, 'applications') self.conf(self.conf_app, 'applications')
@@ -40,113 +39,146 @@ class TestUnitPythonBasic(unit.TestUnitControl):
conf = self.conf_get() conf = self.conf_get()
self.assertEqual(conf['listeners'], {}, 'listeners') self.assertEqual(conf['listeners'], {}, 'listeners')
self.assertEqual(conf['applications'], self.assertEqual(
conf['applications'],
{ {
"app": { "app": {
"type": "python", "type": "python",
"processes": { "spare": 0 }, "processes": {"spare": 0},
"path": "/app", "path": "/app",
"module": "wsgi" "module": "wsgi",
} }
}, },
'applications') 'applications',
)
def test_python_get_applications_prefix(self): def test_python_get_applications_prefix(self):
self.conf(self.conf_app, 'applications') self.conf(self.conf_app, 'applications')
self.assertEqual(self.conf_get('applications'), self.assertEqual(
self.conf_get('applications'),
{ {
"app": { "app": {
"type": "python", "type": "python",
"processes": { "spare": 0 }, "processes": {"spare": 0},
"path": "/app", "path": "/app",
"module":"wsgi" "module": "wsgi",
} }
}, },
'applications prefix') 'applications prefix',
)
def test_python_get_applications_prefix_2(self): def test_python_get_applications_prefix_2(self):
self.conf(self.conf_app, 'applications') self.conf(self.conf_app, 'applications')
self.assertEqual(self.conf_get('applications/app'), self.assertEqual(
self.conf_get('applications/app'),
{ {
"type": "python", "type": "python",
"processes": { "spare": 0 }, "processes": {"spare": 0},
"path": "/app", "path": "/app",
"module": "wsgi" "module": "wsgi",
}, },
'applications prefix 2') 'applications prefix 2',
)
def test_python_get_applications_prefix_3(self): def test_python_get_applications_prefix_3(self):
self.conf(self.conf_app, 'applications') self.conf(self.conf_app, 'applications')
self.assertEqual(self.conf_get('applications/app/type'), 'python', self.assertEqual(
'type') self.conf_get('applications/app/type'), 'python', 'type'
self.assertEqual(self.conf_get('applications/app/processes/spare'), 0, )
'spare') self.assertEqual(
self.conf_get('applications/app/processes/spare'), 0, 'spare'
)
def test_python_get_listeners(self): def test_python_get_listeners(self):
self.conf(self.conf_basic) self.conf(self.conf_basic)
self.assertEqual(self.conf_get()['listeners'], self.assertEqual(
{"*:7080":{"application":"app"}}, 'listeners') self.conf_get()['listeners'],
{"*:7080": {"application": "app"}},
'listeners',
)
def test_python_get_listeners_prefix(self): def test_python_get_listeners_prefix(self):
self.conf(self.conf_basic) self.conf(self.conf_basic)
self.assertEqual(self.conf_get('listeners'), self.assertEqual(
{"*:7080":{"application":"app"}}, 'listeners prefix') self.conf_get('listeners'),
{"*:7080": {"application": "app"}},
'listeners prefix',
)
def test_python_get_listeners_prefix_2(self): def test_python_get_listeners_prefix_2(self):
self.conf(self.conf_basic) self.conf(self.conf_basic)
self.assertEqual(self.conf_get('listeners/*:7080'), self.assertEqual(
{"application":"app"}, 'listeners prefix 2') self.conf_get('listeners/*:7080'),
{"application": "app"},
'listeners prefix 2',
)
def test_python_change_listener(self): def test_python_change_listener(self):
self.conf(self.conf_basic) self.conf(self.conf_basic)
self.conf({"*:7081":{"application":"app"}}, 'listeners') self.conf({"*:7081": {"application": "app"}}, 'listeners')
self.assertEqual(self.conf_get('listeners'), self.assertEqual(
{"*:7081": {"application":"app"}}, 'change listener') self.conf_get('listeners'),
{"*:7081": {"application": "app"}},
'change listener',
)
def test_python_add_listener(self): def test_python_add_listener(self):
self.conf(self.conf_basic) self.conf(self.conf_basic)
self.conf({"application":"app"}, 'listeners/*:7082') self.conf({"application": "app"}, 'listeners/*:7082')
self.assertEqual(self.conf_get('listeners'), self.assertEqual(
self.conf_get('listeners'),
{ {
"*:7080": { "*:7080": {"application": "app"},
"application": "app" "*:7082": {"application": "app"},
}, },
"*:7082": { 'add listener',
"application": "app" )
}
},
'add listener')
def test_python_change_application(self): def test_python_change_application(self):
self.conf(self.conf_basic) self.conf(self.conf_basic)
self.conf('30', 'applications/app/processes/max') self.conf('30', 'applications/app/processes/max')
self.assertEqual(self.conf_get('applications/app/processes/max'), 30, self.assertEqual(
'change application max') self.conf_get('applications/app/processes/max'),
30,
'change application max',
)
self.conf('"/www"', 'applications/app/path') self.conf('"/www"', 'applications/app/path')
self.assertEqual(self.conf_get('applications/app/path'), '/www', self.assertEqual(
'change application path') self.conf_get('applications/app/path'),
'/www',
'change application path',
)
def test_python_delete(self): def test_python_delete(self):
self.conf(self.conf_basic) self.conf(self.conf_basic)
self.assertIn('error', self.conf_delete('applications/app'), self.assertIn(
'delete app before listener') 'error',
self.assertIn('success', self.conf_delete('listeners/*:7080'), self.conf_delete('applications/app'),
'delete listener') 'delete app before listener',
self.assertIn('success', self.conf_delete('applications/app'), )
'delete app after listener') self.assertIn(
self.assertIn('error', self.conf_delete('applications/app'), 'success', self.conf_delete('listeners/*:7080'), 'delete listener'
'delete app again') )
self.assertIn(
'success',
self.conf_delete('applications/app'),
'delete app after listener',
)
self.assertIn(
'error', self.conf_delete('applications/app'), 'delete app again'
)
if __name__ == '__main__': if __name__ == '__main__':
TestUnitPythonBasic.main() TestUnitPythonBasic.main()

View File

@@ -1,128 +1,181 @@
import unittest import unittest
import unit import unit
class TestUnitPythonEnvironment(unit.TestUnitApplicationPython):
class TestUnitPythonEnvironment(unit.TestUnitApplicationPython):
def setUpClass(): def setUpClass():
unit.TestUnit().check_modules('python') unit.TestUnit().check_modules('python')
def test_python_environment_name_null(self): def test_python_environment_name_null(self):
self.load('environment') self.load('environment')
self.assertIn('error', self.conf({ self.assertIn(
"va\0r": "val1" 'error',
}, 'applications/environment/environment'), 'name null') self.conf(
{"va\0r": "val1"}, 'applications/environment/environment'
),
'name null',
)
def test_python_environment_name_equals(self): def test_python_environment_name_equals(self):
self.load('environment') self.load('environment')
self.assertIn('error', self.conf({ self.assertIn(
"var=": "val1" 'error',
}, 'applications/environment/environment'), 'name equals') self.conf(
{"var=": "val1"}, 'applications/environment/environment'
),
'name equals',
)
def test_python_environment_value_null(self): def test_python_environment_value_null(self):
self.load('environment') self.load('environment')
self.assertIn('error', self.conf({ self.assertIn(
"var": "\0val" 'error',
}, 'applications/environment/environment'), 'value null') self.conf(
{"var": "\0val"}, 'applications/environment/environment'
),
'value null',
)
def test_python_environment_update(self): def test_python_environment_update(self):
self.load('environment') self.load('environment')
self.conf({ self.conf({"var": "val1"}, 'applications/environment/environment')
"var": "val1"
}, 'applications/environment/environment')
self.assertEqual(self.get(headers={ self.assertEqual(
self.get(
headers={
'Host': 'localhost', 'Host': 'localhost',
'X-Variables': 'var', 'X-Variables': 'var',
'Connection': 'close' 'Connection': 'close',
})['body'], 'val1,', 'set') }
)['body'],
'val1,',
'set',
)
self.conf({ self.conf({"var": "val2"}, 'applications/environment/environment')
"var": "val2"
}, 'applications/environment/environment')
self.assertEqual(self.get(headers={ self.assertEqual(
self.get(
headers={
'Host': 'localhost', 'Host': 'localhost',
'X-Variables': 'var', 'X-Variables': 'var',
'Connection': 'close' 'Connection': 'close',
})['body'], 'val2,', 'update') }
)['body'],
'val2,',
'update',
)
def test_python_environment_replace(self): def test_python_environment_replace(self):
self.load('environment') self.load('environment')
self.conf({ self.conf({"var1": "val1"}, 'applications/environment/environment')
"var1": "val1"
}, 'applications/environment/environment')
self.assertEqual(self.get(headers={ self.assertEqual(
self.get(
headers={
'Host': 'localhost', 'Host': 'localhost',
'X-Variables': 'var1', 'X-Variables': 'var1',
'Connection': 'close' 'Connection': 'close',
})['body'], 'val1,', 'set') }
)['body'],
'val1,',
'set',
)
self.conf({ self.conf({"var2": "val2"}, 'applications/environment/environment')
"var2": "val2"
}, 'applications/environment/environment')
self.assertEqual(self.get(headers={ self.assertEqual(
self.get(
headers={
'Host': 'localhost', 'Host': 'localhost',
'X-Variables': 'var1,var2', 'X-Variables': 'var1,var2',
'Connection': 'close' 'Connection': 'close',
})['body'], 'val2,', 'replace') }
)['body'],
'val2,',
'replace',
)
def test_python_environment_clear(self): def test_python_environment_clear(self):
self.load('environment') self.load('environment')
self.conf({ self.conf(
"var1": "val1", {"var1": "val1", "var2": "val2"},
"var2": "val2" 'applications/environment/environment',
}, 'applications/environment/environment') )
self.assertEqual(self.get(headers={ self.assertEqual(
self.get(
headers={
'Host': 'localhost', 'Host': 'localhost',
'X-Variables': 'var1,var2', 'X-Variables': 'var1,var2',
'Connection': 'close' 'Connection': 'close',
})['body'], 'val1,val2,', 'set') }
)['body'],
'val1,val2,',
'set',
)
self.conf({}, 'applications/environment/environment') self.conf({}, 'applications/environment/environment')
self.assertEqual(self.get(headers={ self.assertEqual(
self.get(
headers={
'Host': 'localhost', 'Host': 'localhost',
'X-Variables': 'var1,var2', 'X-Variables': 'var1,var2',
'Connection': 'close' 'Connection': 'close',
})['body'], '', 'clear') }
)['body'],
'',
'clear',
)
def test_python_environment_replace_default(self): def test_python_environment_replace_default(self):
self.load('environment') self.load('environment')
pwd_default = self.get(headers={ pwd_default = self.get(
headers={
'Host': 'localhost', 'Host': 'localhost',
'X-Variables': 'PWD', 'X-Variables': 'PWD',
'Connection': 'close' 'Connection': 'close',
})['body'] }
)['body']
self.assertGreater(len(pwd_default), 1, 'get default') self.assertGreater(len(pwd_default), 1, 'get default')
self.conf({ self.conf({"PWD": "new/pwd"}, 'applications/environment/environment')
"PWD": "new/pwd"
}, 'applications/environment/environment')
self.assertEqual(self.get(headers={ self.assertEqual(
self.get(
headers={
'Host': 'localhost', 'Host': 'localhost',
'X-Variables': 'PWD', 'X-Variables': 'PWD',
'Connection': 'close' 'Connection': 'close',
})['body'], 'new/pwd,', 'replace default') }
)['body'],
'new/pwd,',
'replace default',
)
self.conf({}, 'applications/environment/environment') self.conf({}, 'applications/environment/environment')
self.assertEqual(self.get(headers={ self.assertEqual(
self.get(
headers={
'Host': 'localhost', 'Host': 'localhost',
'X-Variables': 'PWD', 'X-Variables': 'PWD',
'Connection': 'close' 'Connection': 'close',
})['body'], pwd_default, 'restore default') }
)['body'],
pwd_default,
'restore default',
)
if __name__ == '__main__': if __name__ == '__main__':
TestUnitPythonEnvironment.main() TestUnitPythonEnvironment.main()

View File

@@ -4,8 +4,8 @@ import subprocess
import unittest import unittest
import unit import unit
class TestUnitPythonProcman(unit.TestUnitApplicationPython):
class TestUnitPythonProcman(unit.TestUnitApplicationPython):
def setUpClass(): def setUpClass():
unit.TestUnit().check_modules('python') unit.TestUnit().check_modules('python')
@@ -29,55 +29,88 @@ class TestUnitPythonProcman(unit.TestUnitApplicationPython):
def test_python_processes_access(self): def test_python_processes_access(self):
self.conf('1', 'applications/' + self.app_name + '/processes') self.conf('1', 'applications/' + self.app_name + '/processes')
self.assertIn('error', self.conf_get('/applications/' + self.app_name + self.assertIn(
'/processes/max'), 'max no access') 'error',
self.assertIn('error', self.conf_get('/applications/' + self.app_name + self.conf_get('/applications/' + self.app_name + '/processes/max'),
'/processes/spare'), 'spare no access') 'max no access',
self.assertIn('error', self.conf_get('/applications/' + self.app_name + )
'/processes/idle_timeout'), 'idle_timeout 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): def test_python_processes_spare_negative(self):
self.assertIn('error', self.conf({ self.assertIn(
"spare": -1 'error',
}, 'applications/' + self.app_name + '/processes'), 'negative spare') self.conf(
{"spare": -1}, 'applications/' + self.app_name + '/processes'
),
'negative spare',
)
def test_python_processes_max_negative(self): def test_python_processes_max_negative(self):
self.assertIn('error', self.conf({ self.assertIn(
"max": -1 'error',
}, 'applications/' + self.app_name + '/processes'), 'negative max') self.conf(
{"max": -1}, 'applications/' + self.app_name + '/processes'
),
'negative max',
)
def test_python_processes_idle_timeout_negative(self): def test_python_processes_idle_timeout_negative(self):
self.assertIn('error', self.conf({ self.assertIn(
"idle_timeout": -1 'error',
}, 'applications/' + self.app_name + '/processes'), self.conf(
'negative idle_timeout') {"idle_timeout": -1},
'applications/' + self.app_name + '/processes',
),
'negative idle_timeout',
)
def test_python_processes_spare_gt_max_default(self): def test_python_processes_spare_gt_max_default(self):
self.assertIn('error', self.conf({"spare": 2}, self.assertIn(
'applications/' + self.app_name + '/processes'), 'error',
'spare greater than max default') self.conf(
{"spare": 2}, 'applications/' + self.app_name + '/processes'
),
'spare greater than max default',
)
def test_python_processes_spare_gt_max(self): def test_python_processes_spare_gt_max(self):
self.assertIn('error', self.conf({ self.assertIn(
"spare": 2, 'error',
"max": 1, self.conf(
"idle_timeout": 1 {"spare": 2, "max": 1, "idle_timeout": 1},
}, '/applications/' + self.app_name + '/processes'), '/applications/' + self.app_name + '/processes',
'spare greater than max') ),
'spare greater than max',
)
def test_python_processes_max_zero(self): def test_python_processes_max_zero(self):
self.assertIn('error', self.conf({ self.assertIn(
"spare": 0, 'error',
"max": 0, self.conf(
"idle_timeout": 1 {"spare": 0, "max": 0, "idle_timeout": 1},
}, 'applications/' + self.app_name + '/processes'), 'max 0') 'applications/' + self.app_name + '/processes',
),
'max 0',
)
def test_python_processes_idle_timeout_zero(self): def test_python_processes_idle_timeout_zero(self):
self.conf({ self.conf(
"spare": 0, {"spare": 0, "max": 2, "idle_timeout": 0},
"max": 2, 'applications/' + self.app_name + '/processes',
"idle_timeout": 0 )
}, 'applications/' + self.app_name + '/processes')
self.get() self.get()
self.assertEqual(len(self.pids_for_process()), 0, 'idle timeout 0') self.assertEqual(len(self.pids_for_process()), 0, 'idle timeout 0')
@@ -114,11 +147,10 @@ class TestUnitPythonProcman(unit.TestUnitApplicationPython):
self.assertTrue(pids.issubset(pids_new), 'prefork same processes') self.assertTrue(pids.issubset(pids_new), 'prefork same processes')
def test_python_ondemand(self): def test_python_ondemand(self):
self.conf({ self.conf(
"spare": 0, {"spare": 0, "max": 8, "idle_timeout": 1},
"max": 8, 'applications/' + self.app_name + '/processes',
"idle_timeout": 1 )
}, 'applications/' + self.app_name + '/processes')
self.assertEqual(len(self.pids_for_process()), 0, 'on-demand 0') self.assertEqual(len(self.pids_for_process()), 0, 'on-demand 0')
@@ -131,16 +163,17 @@ class TestUnitPythonProcman(unit.TestUnitApplicationPython):
time.sleep(1) time.sleep(1)
self.assertEqual(len(self.pids_for_process()), 0, 'on-demand stop idle') self.assertEqual(
len(self.pids_for_process()), 0, 'on-demand stop idle'
)
self.stop_all() self.stop_all()
def test_python_scale_updown(self): def test_python_scale_updown(self):
self.conf({ self.conf(
"spare": 2, {"spare": 2, "max": 8, "idle_timeout": 1},
"max": 8, 'applications/' + self.app_name + '/processes',
"idle_timeout": 1 )
}, 'applications/' + self.app_name + '/processes')
pids = self.pids_for_process() pids = self.pids_for_process()
self.assertEqual(len(pids), 2, 'updown 2') self.assertEqual(len(pids), 2, 'updown 2')
@@ -151,7 +184,9 @@ class TestUnitPythonProcman(unit.TestUnitApplicationPython):
self.assertTrue(pids.issubset(pids_new), 'updown 3 only 1 new') self.assertTrue(pids.issubset(pids_new), 'updown 3 only 1 new')
self.get() self.get()
self.assertSetEqual(self.pids_for_process(), pids_new, 'updown still 3') self.assertSetEqual(
self.pids_for_process(), pids_new, 'updown still 3'
)
time.sleep(1) time.sleep(1)
@@ -166,11 +201,10 @@ class TestUnitPythonProcman(unit.TestUnitApplicationPython):
self.stop_all() self.stop_all()
def test_python_reconfigure(self): def test_python_reconfigure(self):
self.conf({ self.conf(
"spare": 2, {"spare": 2, "max": 6, "idle_timeout": 1},
"max": 6, 'applications/' + self.app_name + '/processes',
"idle_timeout": 1 )
}, 'applications/' + self.app_name + '/processes')
pids = self.pids_for_process() pids = self.pids_for_process()
self.assertEqual(len(pids), 2, 'reconf 2') self.assertEqual(len(pids), 2, 'reconf 2')
@@ -191,11 +225,10 @@ class TestUnitPythonProcman(unit.TestUnitApplicationPython):
self.stop_all() self.stop_all()
def test_python_idle_timeout(self): def test_python_idle_timeout(self):
self.conf({ self.conf(
"spare": 0, {"spare": 0, "max": 6, "idle_timeout": 2},
"max": 6, 'applications/' + self.app_name + '/processes',
"idle_timeout": 2 )
}, 'applications/' + self.app_name + '/processes')
self.get() self.get()
pids = self.pids_for_process() pids = self.pids_for_process()
@@ -209,40 +242,42 @@ class TestUnitPythonProcman(unit.TestUnitApplicationPython):
pids_new = self.pids_for_process() pids_new = self.pids_for_process()
self.assertEqual(len(pids_new), 1, 'idle timeout still 1') self.assertEqual(len(pids_new), 1, 'idle timeout still 1')
self.assertSetEqual(self.pids_for_process(), pids, self.assertSetEqual(
'idle timeout still 1 same pid') self.pids_for_process(), pids, 'idle timeout still 1 same pid'
)
time.sleep(1) time.sleep(1)
self.assertEqual(len(self.pids_for_process()), 0, 'idle timed out') self.assertEqual(len(self.pids_for_process()), 0, 'idle timed out')
def test_python_processes_connection_keepalive(self): def test_python_processes_connection_keepalive(self):
self.conf({ self.conf(
"spare": 0, {"spare": 0, "max": 6, "idle_timeout": 2},
"max": 6, 'applications/' + self.app_name + '/processes',
"idle_timeout": 2 )
}, 'applications/' + self.app_name + '/processes')
(resp, sock) = self.get(headers={ (resp, sock) = self.get(
'Host': 'localhost', headers={'Host': 'localhost', 'Connection': 'keep-alive'},
'Connection': 'keep-alive' start=True,
}, start=True, read_timeout=1) read_timeout=1,
self.assertEqual(len(self.pids_for_process()), 1, )
'keepalive connection 1') self.assertEqual(
len(self.pids_for_process()), 1, 'keepalive connection 1'
)
time.sleep(2) time.sleep(2)
self.assertEqual(len(self.pids_for_process()), 0, 'keepalive connection 0') self.assertEqual(
len(self.pids_for_process()), 0, 'keepalive connection 0'
)
sock.close() sock.close()
def stop_all(self): def stop_all(self):
self.conf({ self.conf({"listeners": {}, "applications": {}})
"listeners": {},
"applications": {}
})
self.assertEqual(len(self.pids_for_process()), 0, 'stop all') self.assertEqual(len(self.pids_for_process()), 0, 'stop all')
if __name__ == '__main__': if __name__ == '__main__':
TestUnitPythonProcman.main() TestUnitPythonProcman.main()

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,8 @@
import unittest import unittest
import unit import unit
class TestUnitRubyApplication(unit.TestUnitApplicationRuby):
class TestUnitRubyApplication(unit.TestUnitApplicationRuby):
def setUpClass(): def setUpClass():
unit.TestUnit().check_modules('ruby') unit.TestUnit().check_modules('ruby')
@@ -11,26 +11,37 @@ class TestUnitRubyApplication(unit.TestUnitApplicationRuby):
body = 'Test body string.' body = 'Test body string.'
resp = self.post(headers={ resp = self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Content-Type': 'text/html', 'Content-Type': 'text/html',
'Custom-Header': 'blah', 'Custom-Header': 'blah',
'Connection': 'close' 'Connection': 'close',
}, body=body) },
body=body,
)
self.assertEqual(resp['status'], 200, 'status') self.assertEqual(resp['status'], 200, 'status')
headers = resp['headers'] headers = resp['headers']
header_server = headers.pop('Server') header_server = headers.pop('Server')
self.assertRegex(header_server, r'Unit/[\d\.]+', 'server header') self.assertRegex(header_server, r'Unit/[\d\.]+', 'server header')
self.assertEqual(headers.pop('Server-Software'), header_server, self.assertEqual(
'server software header') headers.pop('Server-Software'),
header_server,
'server software header',
)
date = headers.pop('Date') date = headers.pop('Date')
self.assertEqual(date[-4:], ' GMT', 'date header timezone') self.assertEqual(date[-4:], ' GMT', 'date header timezone')
self.assertLess(abs(self.date_to_sec_epoch(date) - self.sec_epoch()), 5, self.assertLess(
'date header') abs(self.date_to_sec_epoch(date) - self.sec_epoch()),
5,
'date header',
)
self.assertDictEqual(headers, { self.assertDictEqual(
headers,
{
'Connection': 'close', 'Connection': 'close',
'Content-Length': str(len(body)), 'Content-Length': str(len(body)),
'Content-Type': 'text/html', 'Content-Type': 'text/html',
@@ -46,8 +57,10 @@ class TestUnitRubyApplication(unit.TestUnitApplicationRuby):
'Rack-Run-Once': 'false', 'Rack-Run-Once': 'false',
'Rack-Hijack-Q': 'false', 'Rack-Hijack-Q': 'false',
'Rack-Hijack': '', 'Rack-Hijack': '',
'Rack-Hijack-IO': '' 'Rack-Hijack-IO': '',
}, 'headers') },
'headers',
)
self.assertEqual(resp['body'], body, 'body') self.assertEqual(resp['body'], body, 'body')
def test_ruby_application_query_string(self): def test_ruby_application_query_string(self):
@@ -55,8 +68,11 @@ class TestUnitRubyApplication(unit.TestUnitApplicationRuby):
resp = self.get(url='/?var1=val1&var2=val2') resp = self.get(url='/?var1=val1&var2=val2')
self.assertEqual(resp['headers']['Query-String'], 'var1=val1&var2=val2', self.assertEqual(
'Query-String header') resp['headers']['Query-String'],
'var1=val1&var2=val2',
'Query-String header',
)
def test_ruby_application_query_string_empty(self): def test_ruby_application_query_string_empty(self):
self.load('query_string') self.load('query_string')
@@ -64,8 +80,9 @@ class TestUnitRubyApplication(unit.TestUnitApplicationRuby):
resp = self.get(url='/?') resp = self.get(url='/?')
self.assertEqual(resp['status'], 200, 'query string empty status') self.assertEqual(resp['status'], 200, 'query string empty status')
self.assertEqual(resp['headers']['Query-String'], '', self.assertEqual(
'query string empty') resp['headers']['Query-String'], '', 'query string empty'
)
@unittest.expectedFailure @unittest.expectedFailure
def test_ruby_application_query_string_absent(self): def test_ruby_application_query_string_absent(self):
@@ -74,15 +91,17 @@ class TestUnitRubyApplication(unit.TestUnitApplicationRuby):
resp = self.get() resp = self.get()
self.assertEqual(resp['status'], 200, 'query string absent status') self.assertEqual(resp['status'], 200, 'query string absent status')
self.assertEqual(resp['headers']['Query-String'], '', self.assertEqual(
'query string absent') resp['headers']['Query-String'], '', 'query string absent'
)
@unittest.expectedFailure @unittest.expectedFailure
def test_ruby_application_server_port(self): def test_ruby_application_server_port(self):
self.load('server_port') self.load('server_port')
self.assertEqual(self.get()['headers']['Server-Port'], '7080', self.assertEqual(
'Server-Port header') self.get()['headers']['Server-Port'], '7080', 'Server-Port header'
)
def test_ruby_application_status_int(self): def test_ruby_application_status_int(self):
self.load('status_int') self.load('status_int')
@@ -97,20 +116,29 @@ class TestUnitRubyApplication(unit.TestUnitApplicationRuby):
def test_ruby_application_input_read_parts(self): def test_ruby_application_input_read_parts(self):
self.load('input_read_parts') self.load('input_read_parts')
self.assertEqual(self.post(body='0123456789')['body'], '012345678', self.assertEqual(
'input read parts') self.post(body='0123456789')['body'],
'012345678',
'input read parts',
)
def test_ruby_application_input_read_buffer(self): def test_ruby_application_input_read_buffer(self):
self.load('input_read_buffer') self.load('input_read_buffer')
self.assertEqual(self.post(body='0123456789')['body'], '0123456789', self.assertEqual(
'input read buffer') self.post(body='0123456789')['body'],
'0123456789',
'input read buffer',
)
def test_ruby_application_input_read_buffer_not_empty(self): def test_ruby_application_input_read_buffer_not_empty(self):
self.load('input_read_buffer_not_empty') self.load('input_read_buffer_not_empty')
self.assertEqual(self.post(body='0123456789')['body'], '0123456789', self.assertEqual(
'input read buffer not empty') self.post(body='0123456789')['body'],
'0123456789',
'input read buffer not empty',
)
def test_ruby_application_input_gets(self): def test_ruby_application_input_gets(self):
self.load('input_gets') self.load('input_gets')
@@ -122,8 +150,9 @@ class TestUnitRubyApplication(unit.TestUnitApplicationRuby):
def test_ruby_application_input_gets_2(self): def test_ruby_application_input_gets_2(self):
self.load('input_gets') self.load('input_gets')
self.assertEqual(self.post(body='01234\n56789\n')['body'], '01234\n', self.assertEqual(
'input gets 2') self.post(body='01234\n56789\n')['body'], '01234\n', 'input gets 2'
)
def test_ruby_application_input_gets_all(self): def test_ruby_application_input_gets_all(self):
self.load('input_gets_all') self.load('input_gets_all')
@@ -149,12 +178,14 @@ class TestUnitRubyApplication(unit.TestUnitApplicationRuby):
@unittest.expectedFailure @unittest.expectedFailure
def test_ruby_application_syntax_error(self): def test_ruby_application_syntax_error(self):
self.skip_alerts.extend([ self.skip_alerts.extend(
[
r'Failed to parse rack script', r'Failed to parse rack script',
r'syntax error', r'syntax error',
r'new_from_string', r'new_from_string',
r'parse_file' r'parse_file',
]) ]
)
self.load('syntax_error') self.load('syntax_error')
self.assertEqual(self.get()['status'], 500, 'syntax error') self.assertEqual(self.get()['status'], 500, 'syntax error')
@@ -168,7 +199,8 @@ class TestUnitRubyApplication(unit.TestUnitApplicationRuby):
self.assertIsNotNone( self.assertIsNotNone(
self.search_in_log(r'\[error\].+Error in application'), self.search_in_log(r'\[error\].+Error in application'),
'errors puts') 'errors puts',
)
def test_ruby_application_errors_puts_int(self): def test_ruby_application_errors_puts_int(self):
self.load('errors_puts_int') self.load('errors_puts_int')
@@ -178,8 +210,8 @@ class TestUnitRubyApplication(unit.TestUnitApplicationRuby):
self.stop() self.stop()
self.assertIsNotNone( self.assertIsNotNone(
self.search_in_log(r'\[error\].+1234567890'), self.search_in_log(r'\[error\].+1234567890'), 'errors puts int'
'errors puts int') )
def test_ruby_application_errors_write(self): def test_ruby_application_errors_write(self):
self.load('errors_write') self.load('errors_write')
@@ -190,13 +222,13 @@ class TestUnitRubyApplication(unit.TestUnitApplicationRuby):
self.assertIsNotNone( self.assertIsNotNone(
self.search_in_log(r'\[error\].+Error in application'), self.search_in_log(r'\[error\].+Error in application'),
'errors write') 'errors write',
)
def test_ruby_application_errors_write_to_s_custom(self): def test_ruby_application_errors_write_to_s_custom(self):
self.load('errors_write_to_s_custom') self.load('errors_write_to_s_custom')
self.assertEqual(self.get()['status'], 200, self.assertEqual(self.get()['status'], 200, 'errors write to_s custom')
'errors write to_s custom')
def test_ruby_application_errors_write_int(self): def test_ruby_application_errors_write_int(self):
self.load('errors_write_int') self.load('errors_write_int')
@@ -206,38 +238,40 @@ class TestUnitRubyApplication(unit.TestUnitApplicationRuby):
self.stop() self.stop()
self.assertIsNotNone( self.assertIsNotNone(
self.search_in_log(r'\[error\].+1234567890'), self.search_in_log(r'\[error\].+1234567890'), 'errors write int'
'errors write int') )
def test_ruby_application_at_exit(self): def test_ruby_application_at_exit(self):
self.load('at_exit') self.load('at_exit')
self.get() self.get()
self.conf({ self.conf({"listeners": {}, "applications": {}})
"listeners": {},
"applications": {}
})
self.stop() self.stop()
self.assertIsNotNone( self.assertIsNotNone(
self.search_in_log(r'\[error\].+At exit called\.'), 'at exit') self.search_in_log(r'\[error\].+At exit called\.'), 'at exit'
)
def test_ruby_application_header_custom(self): def test_ruby_application_header_custom(self):
self.load('header_custom') self.load('header_custom')
resp = self.post(body="\ntc=one,two\ntc=three,four,\n\n") resp = self.post(body="\ntc=one,two\ntc=three,four,\n\n")
self.assertEqual(resp['headers']['Custom-Header'], self.assertEqual(
['', 'tc=one,two', 'tc=three,four,', '', ''], 'header custom') resp['headers']['Custom-Header'],
['', 'tc=one,two', 'tc=three,four,', '', ''],
'header custom',
)
@unittest.expectedFailure @unittest.expectedFailure
def test_ruby_application_header_custom_non_printable(self): def test_ruby_application_header_custom_non_printable(self):
self.load('header_custom') self.load('header_custom')
self.assertEqual(self.post(body='\b')['status'], 500, self.assertEqual(
'header custom non printable') self.post(body='\b')['status'], 500, 'header custom non printable'
)
def test_ruby_application_header_status(self): def test_ruby_application_header_status(self):
self.load('header_status') self.load('header_status')
@@ -277,7 +311,8 @@ class TestUnitRubyApplication(unit.TestUnitApplicationRuby):
self.assertIsNotNone( self.assertIsNotNone(
self.search_in_log(r'\[error\].+Failed to run ruby script'), self.search_in_log(r'\[error\].+Failed to run ruby script'),
'body each error') 'body each error',
)
def test_ruby_application_body_file(self): def test_ruby_application_body_file(self):
self.load('body_file') self.load('body_file')
@@ -287,21 +322,30 @@ class TestUnitRubyApplication(unit.TestUnitApplicationRuby):
def test_ruby_keepalive_body(self): def test_ruby_keepalive_body(self):
self.load('mirror') self.load('mirror')
(resp, sock) = self.post(headers={ (resp, sock) = self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Connection': 'keep-alive', 'Connection': 'keep-alive',
'Content-Type': 'text/html' 'Content-Type': 'text/html',
}, start=True, body='0123456789' * 500) },
start=True,
body='0123456789' * 500,
)
self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1') self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1')
resp = self.post(headers={ resp = self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Connection': 'close', 'Connection': 'close',
'Content-Type': 'text/html' 'Content-Type': 'text/html',
}, sock=sock, body='0123456789') },
sock=sock,
body='0123456789',
)
self.assertEqual(resp['body'], '0123456789', 'keep-alive 2') self.assertEqual(resp['body'], '0123456789', 'keep-alive 2')
if __name__ == '__main__': if __name__ == '__main__':
TestUnitRubyApplication.main() TestUnitRubyApplication.main()

View File

@@ -3,45 +3,73 @@ import socket
import unittest import unittest
import unit import unit
class TestUnitSettings(unit.TestUnitApplicationPython):
class TestUnitSettings(unit.TestUnitApplicationPython):
def setUpClass(): def setUpClass():
unit.TestUnit().check_modules('python') unit.TestUnit().check_modules('python')
def test_settings_header_read_timeout(self): def test_settings_header_read_timeout(self):
self.load('empty') self.load('empty')
self.conf({'http': { 'header_read_timeout': 2 }}, 'settings') self.conf({'http': {'header_read_timeout': 2}}, 'settings')
(resp, sock) = self.http(b"""GET / HTTP/1.1 (resp, sock) = self.http(
""", start=True, read_timeout=1, raw=True) b"""GET / HTTP/1.1
""",
start=True,
read_timeout=1,
raw=True,
)
time.sleep(3) time.sleep(3)
resp = self.http(b"""Host: localhost resp = self.http(
b"""Host: localhost
Connection: close Connection: close
""", sock=sock, raw=True) """,
sock=sock,
raw=True,
)
self.assertEqual(resp['status'], 408, 'status header read timeout') self.assertEqual(resp['status'], 408, 'status header read timeout')
def test_settings_header_read_timeout_update(self): def test_settings_header_read_timeout_update(self):
self.load('empty') self.load('empty')
self.conf({'http': { 'header_read_timeout': 4 }}, 'settings') self.conf({'http': {'header_read_timeout': 4}}, 'settings')
(resp, sock) = self.http(b"""GET / HTTP/1.1 (resp, sock) = self.http(
""", start=True, read_timeout=1, raw=True, no_recv=True) b"""GET / HTTP/1.1
""",
start=True,
read_timeout=1,
raw=True,
no_recv=True,
)
time.sleep(2) time.sleep(2)
(resp, sock) = self.http(b"""Host: localhost (resp, sock) = self.http(
""", start=True, sock=sock, read_timeout=1, raw=True, no_recv=True) b"""Host: localhost
""",
start=True,
sock=sock,
read_timeout=1,
raw=True,
no_recv=True,
)
time.sleep(2) time.sleep(2)
(resp, sock) = self.http(b"""X-Blah: blah (resp, sock) = self.http(
""", start=True, sock=sock, read_timeout=1, raw=True) b"""X-Blah: blah
""",
start=True,
sock=sock,
read_timeout=1,
raw=True,
)
if len(resp) != 0: if len(resp) != 0:
sock.close() sock.close()
@@ -49,24 +77,35 @@ Connection: close
else: else:
time.sleep(2) time.sleep(2)
resp = self.http(b"""Connection: close resp = self.http(
b"""Connection: close
""", sock=sock, raw=True) """,
sock=sock,
raw=True,
)
self.assertEqual(resp['status'], 408, self.assertEqual(
'status header read timeout update') resp['status'], 408, 'status header read timeout update'
)
def test_settings_body_read_timeout(self): def test_settings_body_read_timeout(self):
self.load('empty') self.load('empty')
self.conf({'http': { 'body_read_timeout': 2 }}, 'settings') self.conf({'http': {'body_read_timeout': 2}}, 'settings')
(resp, sock) = self.http(b"""POST / HTTP/1.1 (resp, sock) = self.http(
b"""POST / HTTP/1.1
Host: localhost Host: localhost
Content-Length: 10 Content-Length: 10
Connection: close Connection: close
""", start=True, raw_resp=True, read_timeout=1, raw=True) """,
start=True,
raw_resp=True,
read_timeout=1,
raw=True,
)
time.sleep(3) time.sleep(3)
@@ -77,37 +116,46 @@ Connection: close
def test_settings_body_read_timeout_update(self): def test_settings_body_read_timeout_update(self):
self.load('empty') self.load('empty')
self.conf({'http': { 'body_read_timeout': 4 }}, 'settings') self.conf({'http': {'body_read_timeout': 4}}, 'settings')
(resp, sock) = self.http(b"""POST / HTTP/1.1 (resp, sock) = self.http(
b"""POST / HTTP/1.1
Host: localhost Host: localhost
Content-Length: 10 Content-Length: 10
Connection: close Connection: close
""", start=True, read_timeout=1, raw=True) """,
start=True,
read_timeout=1,
raw=True,
)
time.sleep(2) time.sleep(2)
(resp, sock) = self.http(b"""012""", start=True, sock=sock, (resp, sock) = self.http(
read_timeout=1, raw=True) b"""012""", start=True, sock=sock, read_timeout=1, raw=True
)
time.sleep(2) time.sleep(2)
(resp, sock) = self.http(b"""345""", start=True, sock=sock, (resp, sock) = self.http(
read_timeout=1, raw=True) b"""345""", start=True, sock=sock, read_timeout=1, raw=True
)
time.sleep(2) time.sleep(2)
resp = self.http(b"""6789""", sock=sock, raw=True) resp = self.http(b"""6789""", sock=sock, raw=True)
self.assertEqual(resp['status'], 200, 'status body read timeout update') self.assertEqual(
resp['status'], 200, 'status body read timeout update'
)
def test_settings_send_timeout(self): def test_settings_send_timeout(self):
self.load('mirror') self.load('mirror')
data_len = 1048576 data_len = 1048576
self.conf({'http': { 'send_timeout': 1 }}, 'settings') self.conf({'http': {'send_timeout': 1}}, 'settings')
addr = self.testdir + '/sock' addr = self.testdir + '/sock'
@@ -122,7 +170,9 @@ Content-Type: text/html
Content-Length: %d Content-Length: %d
Connection: close Connection: close
""" % data_len + ('X' * data_len) """ % data_len + (
'X' * data_len
)
sock.sendall(req.encode()) sock.sendall(req.encode())
@@ -140,35 +190,40 @@ Connection: close
def test_settings_idle_timeout(self): def test_settings_idle_timeout(self):
self.load('empty') self.load('empty')
self.conf({'http': { 'idle_timeout': 2 }}, 'settings') self.conf({'http': {'idle_timeout': 2}}, 'settings')
(resp, sock) = self.get(headers={ (resp, sock) = self.get(
'Host': 'localhost', headers={'Host': 'localhost', 'Connection': 'keep-alive'},
'Connection': 'keep-alive' start=True,
}, start=True, read_timeout=1) read_timeout=1,
)
time.sleep(3) time.sleep(3)
resp = self.get(headers={ resp = self.get(
'Host': 'localhost', headers={'Host': 'localhost', 'Connection': 'close'}, sock=sock
'Connection': 'close' )
}, sock=sock)
self.assertEqual(resp['status'], 408, 'status idle timeout') self.assertEqual(resp['status'], 408, 'status idle timeout')
def test_settings_max_body_size(self): def test_settings_max_body_size(self):
self.load('empty') self.load('empty')
self.conf({'http': { 'max_body_size': 5 }}, 'settings') self.conf({'http': {'max_body_size': 5}}, 'settings')
self.assertEqual(self.post(body='01234')['status'], 200, 'status size') self.assertEqual(self.post(body='01234')['status'], 200, 'status size')
self.assertEqual(self.post(body='012345')['status'], 413, self.assertEqual(
'status size max') self.post(body='012345')['status'], 413, 'status size max'
)
@unittest.expectedFailure @unittest.expectedFailure
def test_settings_negative_value(self): def test_settings_negative_value(self):
self.assertIn('error', self.conf({'http': { 'max_body_size': -1 }}, self.assertIn(
'settings'), 'settings negative value') 'error',
self.conf({'http': {'max_body_size': -1}}, 'settings'),
'settings negative value',
)
if __name__ == '__main__': if __name__ == '__main__':
TestUnitSettings.main() TestUnitSettings.main()

View File

@@ -5,8 +5,8 @@ import subprocess
import unittest import unittest
import unit import unit
class TestUnitTLS(unit.TestUnitApplicationTLS):
class TestUnitTLS(unit.TestUnitApplicationTLS):
def setUpClass(): def setUpClass():
unit.TestUnit().check_modules('python', 'openssl') unit.TestUnit().check_modules('python', 'openssl')
@@ -26,17 +26,13 @@ class TestUnitTLS(unit.TestUnitApplicationTLS):
return self.date_to_sec_epoch(date, '%b %d %H:%M:%S %Y %Z') return self.date_to_sec_epoch(date, '%b %d %H:%M:%S %Y %Z')
def add_tls(self, application='empty', cert='default', port=7080): def add_tls(self, application='empty', cert='default', port=7080):
self.conf({ self.conf(
"application": application, {"application": application, "tls": {"certificate": cert}},
"tls": { 'listeners/*:' + str(port),
"certificate": cert )
}
}, 'listeners/*:' + str(port))
def remove_tls(self, application='empty', port=7080): def remove_tls(self, application='empty', port=7080):
self.conf({ self.conf({"application": application}, 'listeners/*:' + str(port))
"application": application
}, 'listeners/*:' + str(port))
def test_tls_listener_option_add(self): def test_tls_listener_option_add(self):
self.load('empty') self.load('empty')
@@ -65,8 +61,11 @@ class TestUnitTLS(unit.TestUnitApplicationTLS):
self.certificate() self.certificate()
self.assertIn('success', self.conf_delete('/certificates/default'), self.assertIn(
'remove certificate') 'success',
self.conf_delete('/certificates/default'),
'remove certificate',
)
def test_tls_certificate_remove_used(self): def test_tls_certificate_remove_used(self):
self.load('empty') self.load('empty')
@@ -75,8 +74,11 @@ class TestUnitTLS(unit.TestUnitApplicationTLS):
self.add_tls() self.add_tls()
self.assertIn('error', self.conf_delete('/certificates/default'), self.assertIn(
'remove certificate') 'error',
self.conf_delete('/certificates/default'),
'remove certificate',
)
def test_tls_certificate_remove_nonexisting(self): def test_tls_certificate_remove_nonexisting(self):
self.load('empty') self.load('empty')
@@ -85,8 +87,11 @@ class TestUnitTLS(unit.TestUnitApplicationTLS):
self.add_tls() self.add_tls()
self.assertIn('error', self.conf_delete('/certificates/blah'), self.assertIn(
'remove nonexistings certificate') 'error',
self.conf_delete('/certificates/blah'),
'remove nonexistings certificate',
)
@unittest.expectedFailure @unittest.expectedFailure
def test_tls_certificate_update(self): def test_tls_certificate_update(self):
@@ -100,8 +105,9 @@ class TestUnitTLS(unit.TestUnitApplicationTLS):
self.certificate() self.certificate()
self.assertNotEqual(cert_old, self.get_server_certificate(), self.assertNotEqual(
'update certificate') cert_old, self.get_server_certificate(), 'update certificate'
)
@unittest.expectedFailure @unittest.expectedFailure
def test_tls_certificate_key_incorrect(self): def test_tls_certificate_key_incorrect(self):
@@ -110,8 +116,9 @@ class TestUnitTLS(unit.TestUnitApplicationTLS):
self.certificate('first', False) self.certificate('first', False)
self.certificate('second', False) self.certificate('second', False)
self.assertIn('error', self.certificate_load('first', 'second'), self.assertIn(
'key incorrect') 'error', self.certificate_load('first', 'second'), 'key incorrect'
)
def test_tls_certificate_change(self): def test_tls_certificate_change(self):
self.load('empty') self.load('empty')
@@ -125,33 +132,53 @@ class TestUnitTLS(unit.TestUnitApplicationTLS):
self.add_tls(cert='new') self.add_tls(cert='new')
self.assertNotEqual(cert_old, self.get_server_certificate(), self.assertNotEqual(
'change certificate') cert_old, self.get_server_certificate(), 'change certificate'
)
def test_tls_certificate_key_rsa(self): def test_tls_certificate_key_rsa(self):
self.load('empty') self.load('empty')
self.certificate() self.certificate()
self.assertEqual(self.conf_get('/certificates/default/key'), self.assertEqual(
'RSA (1024 bits)', 'certificate key rsa') self.conf_get('/certificates/default/key'),
'RSA (1024 bits)',
'certificate key rsa',
)
def test_tls_certificate_key_ec(self): def test_tls_certificate_key_ec(self):
self.load('empty') self.load('empty')
subprocess.call(['openssl', 'ecparam', '-noout', '-genkey', subprocess.call(
[
'openssl',
'ecparam',
'-noout',
'-genkey',
'-out', self.testdir + '/ec.key', '-out', self.testdir + '/ec.key',
'-name', 'prime256v1']) '-name', 'prime256v1',
]
)
subprocess.call(['openssl', 'req', '-x509', '-new', subprocess.call(
[
'openssl',
'req',
'-x509',
'-new',
'-subj', '/CN=ec/',
'-config', self.testdir + '/openssl.conf', '-config', self.testdir + '/openssl.conf',
'-key', self.testdir + '/ec.key', '-subj', '/CN=ec/', '-key', self.testdir + '/ec.key',
'-out', self.testdir + '/ec.crt']) '-out', self.testdir + '/ec.crt',
]
)
self.certificate_load('ec') self.certificate_load('ec')
self.assertEqual(self.conf_get('/certificates/ec/key'), 'ECDH', self.assertEqual(
'certificate key ec') self.conf_get('/certificates/ec/key'), 'ECDH', 'certificate key ec'
)
def test_tls_certificate_chain_options(self): def test_tls_certificate_chain_options(self):
self.load('empty') self.load('empty')
@@ -164,36 +191,64 @@ class TestUnitTLS(unit.TestUnitApplicationTLS):
cert = chain[0] cert = chain[0]
self.assertEqual(cert['subject']['common_name'], 'default',
'certificate subject common name')
self.assertEqual(cert['issuer']['common_name'], 'default',
'certificate issuer common name')
self.assertLess(abs(self.sec_epoch() -
self.openssl_date_to_sec_epoch(cert['validity']['since'])), 5,
'certificate validity since')
self.assertEqual( self.assertEqual(
self.openssl_date_to_sec_epoch(cert['validity']['until']) - cert['subject']['common_name'],
self.openssl_date_to_sec_epoch(cert['validity']['since']), 2592000, 'default',
'certificate validity until') 'certificate subject common name',
)
self.assertEqual(
cert['issuer']['common_name'],
'default',
'certificate issuer common name',
)
self.assertLess(
abs(
self.sec_epoch()
- self.openssl_date_to_sec_epoch(cert['validity']['since'])
),
5,
'certificate validity since',
)
self.assertEqual(
self.openssl_date_to_sec_epoch(cert['validity']['until'])
- self.openssl_date_to_sec_epoch(cert['validity']['since']),
2592000,
'certificate validity until',
)
def test_tls_certificate_chain(self): def test_tls_certificate_chain(self):
self.load('empty') self.load('empty')
self.certificate('root', False) self.certificate('root', False)
subprocess.call(['openssl', 'req', '-new', '-config', subprocess.call(
self.testdir + '/openssl.conf', '-subj', '/CN=int/', [
'openssl',
'req',
'-new',
'-subj', '/CN=int/',
'-config', self.testdir + '/openssl.conf',
'-out', self.testdir + '/int.csr', '-out', self.testdir + '/int.csr',
'-keyout', self.testdir + '/int.key']) '-keyout', self.testdir + '/int.key',
]
)
subprocess.call(['openssl', 'req', '-new', '-config', subprocess.call(
self.testdir + '/openssl.conf', '-subj', '/CN=end/', [
'openssl',
'req',
'-new',
'-subj', '/CN=end/',
'-config', self.testdir + '/openssl.conf',
'-out', self.testdir + '/end.csr', '-out', self.testdir + '/end.csr',
'-keyout', self.testdir + '/end.key']) '-keyout', self.testdir + '/end.key',
]
)
with open(self.testdir + '/ca.conf', 'w') as f: with open(self.testdir + '/ca.conf', 'w') as f:
f.write("""[ ca ] f.write(
"""[ ca ]
default_ca = myca default_ca = myca
[ myca ] [ myca ]
@@ -209,11 +264,13 @@ x509_extensions = myca_extensions
commonName = supplied commonName = supplied
[ myca_extensions ] [ myca_extensions ]
basicConstraints = critical,CA:TRUE""" % { basicConstraints = critical,CA:TRUE"""
% {
'dir': self.testdir, 'dir': self.testdir,
'database': self.testdir + '/certindex', 'database': self.testdir + '/certindex',
'certserial': self.testdir + '/certserial' 'certserial': self.testdir + '/certserial',
}) }
)
with open(self.testdir + '/certserial', 'w') as f: with open(self.testdir + '/certserial', 'w') as f:
f.write('1000') f.write('1000')
@@ -221,25 +278,41 @@ basicConstraints = critical,CA:TRUE""" % {
with open(self.testdir + '/certindex', 'w') as f: with open(self.testdir + '/certindex', 'w') as f:
f.write('') f.write('')
subprocess.call(['openssl', 'ca', '-batch', subprocess.call(
[
'openssl',
'ca',
'-batch',
'-subj', '/CN=int/',
'-config', self.testdir + '/ca.conf', '-config', self.testdir + '/ca.conf',
'-keyfile', self.testdir + '/root.key', '-keyfile', self.testdir + '/root.key',
'-cert', self.testdir + '/root.crt', '-cert', self.testdir + '/root.crt',
'-subj', '/CN=int/',
'-in', self.testdir + '/int.csr', '-in', self.testdir + '/int.csr',
'-out', self.testdir + '/int.crt']) '-out', self.testdir + '/int.crt',
]
)
subprocess.call(['openssl', 'ca', '-batch', subprocess.call(
[
'openssl',
'ca',
'-batch',
'-subj', '/CN=end/',
'-config', self.testdir + '/ca.conf', '-config', self.testdir + '/ca.conf',
'-keyfile', self.testdir + '/int.key', '-keyfile', self.testdir + '/int.key',
'-cert', self.testdir + '/int.crt', '-cert', self.testdir + '/int.crt',
'-subj', '/CN=end/',
'-in', self.testdir + '/end.csr', '-in', self.testdir + '/end.csr',
'-out', self.testdir + '/end.crt']) '-out', self.testdir + '/end.crt',
]
)
with open(self.testdir + '/end-int.crt', 'wb') as crt, \ crt_path = self.testdir + '/end-int.crt'
open(self.testdir + '/end.crt', 'rb') as end, \ end_path = self.testdir + '/end.crt'
open(self.testdir + '/int.crt', 'rb') as int: int_path = self.testdir + '/int.crt'
with open(crt_path, 'wb') as crt, \
open(end_path, 'rb') as end, \
open(int_path, 'rb') as int:
crt.write(end.read() + int.read()) crt.write(end.read() + int.read())
self.context = ssl.create_default_context() self.context = ssl.create_default_context()
@@ -249,15 +322,24 @@ basicConstraints = critical,CA:TRUE""" % {
# incomplete chain # incomplete chain
self.assertIn('success', self.certificate_load('end', 'end'), self.assertIn(
'certificate chain end upload') 'success',
self.certificate_load('end', 'end'),
'certificate chain end upload',
)
chain = self.conf_get('/certificates/end/chain') chain = self.conf_get('/certificates/end/chain')
self.assertEqual(len(chain), 1, 'certificate chain end length') self.assertEqual(len(chain), 1, 'certificate chain end length')
self.assertEqual(chain[0]['subject']['common_name'], 'end', self.assertEqual(
'certificate chain end subject common name') chain[0]['subject']['common_name'],
self.assertEqual(chain[0]['issuer']['common_name'], 'int', 'end',
'certificate chain end issuer common name') 'certificate chain end subject common name',
)
self.assertEqual(
chain[0]['issuer']['common_name'],
'int',
'certificate chain end issuer common name',
)
self.add_tls(cert='end') self.add_tls(cert='end')
@@ -270,41 +352,69 @@ basicConstraints = critical,CA:TRUE""" % {
# intermediate # intermediate
self.assertIn('success', self.certificate_load('int', 'int'), self.assertIn(
'certificate chain int upload') 'success',
self.certificate_load('int', 'int'),
'certificate chain int upload',
)
chain = self.conf_get('/certificates/int/chain') chain = self.conf_get('/certificates/int/chain')
self.assertEqual(len(chain), 1, 'certificate chain int length') self.assertEqual(len(chain), 1, 'certificate chain int length')
self.assertEqual(chain[0]['subject']['common_name'], 'int', self.assertEqual(
'certificate chain int subject common name') chain[0]['subject']['common_name'],
self.assertEqual(chain[0]['issuer']['common_name'], 'root', 'int',
'certificate chain int issuer common name') 'certificate chain int subject common name',
)
self.assertEqual(
chain[0]['issuer']['common_name'],
'root',
'certificate chain int issuer common name',
)
self.add_tls(cert='int') self.add_tls(cert='int')
self.assertEqual(self.get_ssl()['status'], 200, self.assertEqual(
'certificate chain intermediate') self.get_ssl()['status'], 200, 'certificate chain intermediate'
)
# intermediate server # intermediate server
self.assertIn('success', self.certificate_load('end-int', 'end'), self.assertIn(
'certificate chain end-int upload') 'success',
self.certificate_load('end-int', 'end'),
'certificate chain end-int upload',
)
chain = self.conf_get('/certificates/end-int/chain') chain = self.conf_get('/certificates/end-int/chain')
self.assertEqual(len(chain), 2, 'certificate chain end-int length') self.assertEqual(len(chain), 2, 'certificate chain end-int length')
self.assertEqual(chain[0]['subject']['common_name'], 'end', self.assertEqual(
'certificate chain end-int int subject common name') chain[0]['subject']['common_name'],
self.assertEqual(chain[0]['issuer']['common_name'], 'int', 'end',
'certificate chain end-int int issuer common name') 'certificate chain end-int int subject common name',
self.assertEqual(chain[1]['subject']['common_name'], 'int', )
'certificate chain end-int end subject common name') self.assertEqual(
self.assertEqual(chain[1]['issuer']['common_name'], 'root', chain[0]['issuer']['common_name'],
'certificate chain end-int end issuer common name') 'int',
'certificate chain end-int int issuer common name',
)
self.assertEqual(
chain[1]['subject']['common_name'],
'int',
'certificate chain end-int end subject common name',
)
self.assertEqual(
chain[1]['issuer']['common_name'],
'root',
'certificate chain end-int end issuer common name',
)
self.add_tls(cert='end-int') self.add_tls(cert='end-int')
self.assertEqual(self.get_ssl()['status'], 200, self.assertEqual(
'certificate chain intermediate server') self.get_ssl()['status'],
200,
'certificate chain intermediate server',
)
@unittest.expectedFailure @unittest.expectedFailure
def test_tls_reconfigure(self): def test_tls_reconfigure(self):
@@ -312,19 +422,21 @@ basicConstraints = critical,CA:TRUE""" % {
self.certificate() self.certificate()
(resp, sock) = self.get(headers={ (resp, sock) = self.get(
'Host': 'localhost', headers={'Host': 'localhost', 'Connection': 'keep-alive'},
'Connection': 'keep-alive' start=True,
}, start=True) )
self.assertEqual(resp['status'], 200, 'initial status') self.assertEqual(resp['status'], 200, 'initial status')
self.add_tls() self.add_tls()
self.assertEqual(self.get(sock=sock)['status'], 200, self.assertEqual(
'reconfigure status') self.get(sock=sock)['status'], 200, 'reconfigure status'
self.assertEqual(self.get_ssl()['status'], 200, )
'reconfigure tls status') self.assertEqual(
self.get_ssl()['status'], 200, 'reconfigure tls status'
)
def test_tls_keepalive(self): def test_tls_keepalive(self):
self.load('mirror') self.load('mirror')
@@ -333,19 +445,27 @@ basicConstraints = critical,CA:TRUE""" % {
self.add_tls(application='mirror') self.add_tls(application='mirror')
(resp, sock) = self.post_ssl(headers={ (resp, sock) = self.post_ssl(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Connection': 'keep-alive', 'Connection': 'keep-alive',
'Content-Type': 'text/html' 'Content-Type': 'text/html',
}, start=True, body='0123456789') },
start=True,
body='0123456789',
)
self.assertEqual(resp['body'], '0123456789', 'keepalive 1') self.assertEqual(resp['body'], '0123456789', 'keepalive 1')
resp = self.post_ssl(headers={ resp = self.post_ssl(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Connection': 'close', 'Connection': 'close',
'Content-Type': 'text/html' 'Content-Type': 'text/html',
}, sock=sock, body='0123456789') },
sock=sock,
body='0123456789',
)
self.assertEqual(resp['body'], '0123456789', 'keepalive 2') self.assertEqual(resp['body'], '0123456789', 'keepalive 2')
@@ -357,21 +477,18 @@ basicConstraints = critical,CA:TRUE""" % {
self.add_tls() self.add_tls()
(resp, sock) = self.get_ssl(headers={ (resp, sock) = self.get_ssl(
'Host': 'localhost', headers={'Host': 'localhost', 'Connection': 'keep-alive'},
'Connection': 'keep-alive' start=True,
}, start=True) )
self.conf({ self.conf({"application": "empty"}, 'listeners/*:7080')
"application": "empty"
}, 'listeners/*:7080')
self.conf_delete('/certificates/default') self.conf_delete('/certificates/default')
try: try:
resp = self.get_ssl(headers={ resp = self.get_ssl(
'Host': 'localhost', headers={'Host': 'localhost', 'Connection': 'close'}, sock=sock
'Connection': 'close' )
}, sock=sock)
except: except:
resp = None resp = None
@@ -383,8 +500,11 @@ basicConstraints = critical,CA:TRUE""" % {
self.certificate() self.certificate()
self.assertIn('success', self.conf_delete('/certificates'), self.assertIn(
'remove all certificates') 'success',
self.conf_delete('/certificates'),
'remove all certificates',
)
def test_tls_application_respawn(self): def test_tls_application_respawn(self):
self.skip_alerts.append(r'process \d+ exited on signal 9') self.skip_alerts.append(r'process \d+ exited on signal 9')
@@ -396,48 +516,73 @@ basicConstraints = critical,CA:TRUE""" % {
self.add_tls(application='mirror') self.add_tls(application='mirror')
(resp, sock) = self.post_ssl(headers={ (resp, sock) = self.post_ssl(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Connection': 'keep-alive', 'Connection': 'keep-alive',
'Content-Type': 'text/html' 'Content-Type': 'text/html',
}, start=True, body='0123456789') },
start=True,
body='0123456789',
)
app_id = self.findall(r'(\d+)#\d+ "mirror" application started')[0] app_id = self.findall(r'(\d+)#\d+ "mirror" application started')[0]
subprocess.call(['kill', '-9', app_id]) subprocess.call(['kill', '-9', app_id])
self.wait_for_record(re.compile(' (?!' + app_id + self.wait_for_record(
'#)(\d+)#\d+ "mirror" application started')) re.compile(
' (?!' + app_id + '#)(\d+)#\d+ "mirror" application started'
)
)
resp = self.post_ssl(headers={ resp = self.post_ssl(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Connection': 'close', 'Connection': 'close',
'Content-Type': 'text/html' 'Content-Type': 'text/html',
}, sock=sock, body='0123456789') },
sock=sock,
body='0123456789',
)
self.assertEqual(resp['status'], 200, 'application respawn status') self.assertEqual(resp['status'], 200, 'application respawn status')
self.assertEqual(resp['body'], '0123456789', 'application respawn body') self.assertEqual(
resp['body'], '0123456789', 'application respawn body'
)
def test_tls_url_scheme(self): def test_tls_url_scheme(self):
self.load('variables') self.load('variables')
self.assertEqual(self.post(headers={ self.assertEqual(
self.post(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Content-Type': 'text/html', 'Content-Type': 'text/html',
'Custom-Header': '', 'Custom-Header': '',
'Connection': 'close' 'Connection': 'close',
})['headers']['Wsgi-Url-Scheme'], 'http', 'url scheme http') }
)['headers']['Wsgi-Url-Scheme'],
'http',
'url scheme http',
)
self.certificate() self.certificate()
self.add_tls(application='variables') self.add_tls(application='variables')
self.assertEqual(self.post_ssl(headers={ self.assertEqual(
self.post_ssl(
headers={
'Host': 'localhost', 'Host': 'localhost',
'Content-Type': 'text/html', 'Content-Type': 'text/html',
'Custom-Header': '', 'Custom-Header': '',
'Connection': 'close' 'Connection': 'close',
})['headers']['Wsgi-Url-Scheme'], 'https', 'url scheme https') }
)['headers']['Wsgi-Url-Scheme'],
'https',
'url scheme https',
)
if __name__ == '__main__': if __name__ == '__main__':
TestUnitTLS.main() TestUnitTLS.main()

View File

@@ -14,9 +14,12 @@ import unittest
import subprocess import subprocess
from multiprocessing import Process from multiprocessing import Process
class TestUnit(unittest.TestCase): class TestUnit(unittest.TestCase):
pardir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir)) pardir = os.path.abspath(
os.path.join(os.path.dirname(__file__), os.pardir)
)
architecture = platform.architecture()[0] architecture = platform.architecture()[0]
maxDiff = None maxDiff = None
@@ -61,16 +64,19 @@ class TestUnit(unittest.TestCase):
result = self.defaultTestResult() result = self.defaultTestResult()
self._feedErrorsToResult(result, self._outcome.errors) self._feedErrorsToResult(result, self._outcome.errors)
else: else:
result = getattr(self, '_outcomeForDoCleanups', result = getattr(
self._resultForDoCleanups) self, '_outcomeForDoCleanups', self._resultForDoCleanups
)
success = not list2reason(result.errors) \ success = not list2reason(result.errors) and not list2reason(
and not list2reason(result.failures) result.failures
)
# check unit.log for alerts # check unit.log for alerts
with open(self.testdir + '/unit.log', 'r', encoding='utf-8', unit_log = self.testdir + '/unit.log'
errors='ignore') as f:
with open(unit_log, 'r', encoding='utf-8', errors='ignore') as f:
self._check_alerts(f.read()) self._check_alerts(f.read())
# remove unit.log # remove unit.log
@@ -107,9 +113,16 @@ class TestUnit(unittest.TestCase):
env['GOPATH'] = self.pardir + '/go' env['GOPATH'] = self.pardir + '/go'
try: try:
process = subprocess.Popen(['go', 'build', '-o', process = subprocess.Popen(
[
'go',
'build',
'-o',
self.testdir + '/go/check_module', self.testdir + '/go/check_module',
current_dir + '/go/empty/app.go'], env=env) current_dir + '/go/empty/app.go',
],
env=env,
)
process.communicate() process.communicate()
m = module if process.returncode == 0 else None m = module if process.returncode == 0 else None
@@ -127,9 +140,10 @@ class TestUnit(unittest.TestCase):
try: try:
subprocess.check_output(['which', 'openssl']) subprocess.check_output(['which', 'openssl'])
output = subprocess.check_output([ output = subprocess.check_output(
self.pardir + '/build/unitd', '--version'], [self.pardir + '/build/unitd', '--version'],
stderr=subprocess.STDOUT) stderr=subprocess.STDOUT,
)
m = re.search('--openssl', output.decode()) m = re.search('--openssl', output.decode())
@@ -162,25 +176,35 @@ class TestUnit(unittest.TestCase):
print() print()
def _run_unit(): def _run_unit():
subprocess.call([self.pardir + '/build/unitd', subprocess.call(
[
self.pardir + '/build/unitd',
'--no-daemon', '--no-daemon',
'--modules', self.pardir + '/build', '--modules', self.pardir + '/build',
'--state', self.testdir + '/state', '--state', self.testdir + '/state',
'--pid', self.testdir + '/unit.pid', '--pid', self.testdir + '/unit.pid',
'--log', self.testdir + '/unit.log', '--log', self.testdir + '/unit.log',
'--control', 'unix:' + self.testdir + '/control.unit.sock']) '--control', 'unix:' + self.testdir + '/control.unit.sock',
]
)
self._p = Process(target=_run_unit) self._p = Process(target=_run_unit)
self._p.start() self._p.start()
if not self.waitforfiles(self.testdir + '/unit.pid', if not self.waitforfiles(
self.testdir + '/unit.log', self.testdir + '/control.unit.sock'): self.testdir + '/unit.pid',
self.testdir + '/unit.log',
self.testdir + '/control.unit.sock',
):
exit("Could not start unit") exit("Could not start unit")
self._started = True self._started = True
self.skip_alerts = [r'read signalfd\(4\) failed', r'sendmsg.+failed', self.skip_alerts = [
r'recvmsg.+failed'] r'read signalfd\(4\) failed',
r'sendmsg.+failed',
r'recvmsg.+failed',
]
self.skip_sanitizer = False self.skip_sanitizer = False
def _stop(self): def _stop(self):
@@ -264,10 +288,20 @@ class TestUnit(unittest.TestCase):
def _parse_args(): def _parse_args():
parser = argparse.ArgumentParser(add_help=False) parser = argparse.ArgumentParser(add_help=False)
parser.add_argument('-d', '--detailed', dest='detailed', parser.add_argument(
action='store_true', help='Detailed output for tests') '-d',
parser.add_argument('-l', '--log', dest='save_log', '--detailed',
action='store_true', help='Save unit.log after the test execution') dest='detailed',
action='store_true',
help='Detailed output for tests',
)
parser.add_argument(
'-l',
'--log',
dest='save_log',
action='store_true',
help='Save unit.log after the test execution',
)
return parser.parse_known_args() return parser.parse_known_args()
@@ -279,18 +313,21 @@ class TestUnit(unittest.TestCase):
def _print_path_to_log(self): def _print_path_to_log(self):
print('Path to unit.log:\n' + self.testdir + '/unit.log') print('Path to unit.log:\n' + self.testdir + '/unit.log')
class TestUnitHTTP(TestUnit):
class TestUnitHTTP(TestUnit):
def http(self, start_str, **kwargs): def http(self, start_str, **kwargs):
sock_type = 'ipv4' if 'sock_type' not in kwargs else kwargs['sock_type'] sock_type = (
'ipv4' if 'sock_type' not in kwargs else kwargs['sock_type']
)
port = 7080 if 'port' not in kwargs else kwargs['port'] port = 7080 if 'port' not in kwargs else kwargs['port']
url = '/' if 'url' not in kwargs else kwargs['url'] url = '/' if 'url' not in kwargs else kwargs['url']
http = 'HTTP/1.0' if 'http_10' in kwargs else 'HTTP/1.1' http = 'HTTP/1.0' if 'http_10' in kwargs else 'HTTP/1.1'
headers = ({ headers = (
'Host': 'localhost', {'Host': 'localhost', 'Connection': 'close'}
'Connection': 'close' if 'headers' not in kwargs
} if 'headers' not in kwargs else kwargs['headers']) else kwargs['headers']
)
body = b'' if 'body' not in kwargs else kwargs['body'] body = b'' if 'body' not in kwargs else kwargs['body']
crlf = '\r\n' crlf = '\r\n'
@@ -303,13 +340,16 @@ class TestUnitHTTP(TestUnit):
sock_types = { sock_types = {
'ipv4': socket.AF_INET, 'ipv4': socket.AF_INET,
'ipv6': socket.AF_INET6, 'ipv6': socket.AF_INET6,
'unix': socket.AF_UNIX 'unix': socket.AF_UNIX,
} }
if 'sock' not in kwargs: if 'sock' not in kwargs:
sock = socket.socket(sock_types[sock_type], socket.SOCK_STREAM) sock = socket.socket(sock_types[sock_type], socket.SOCK_STREAM)
if sock_type == sock_types['ipv4'] or sock_type == sock_types['ipv6']: if (
sock_type == sock_types['ipv4']
or sock_type == sock_types['ipv6']
):
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
if 'wrapper' in kwargs: if 'wrapper' in kwargs:
@@ -357,7 +397,9 @@ class TestUnitHTTP(TestUnit):
if 'no_recv' not in kwargs: if 'no_recv' not in kwargs:
enc = 'utf-8' if 'encoding' not in kwargs else kwargs['encoding'] enc = 'utf-8' if 'encoding' not in kwargs else kwargs['encoding']
read_timeout = 5 if 'read_timeout' not in kwargs else kwargs['read_timeout'] read_timeout = (
5 if 'read_timeout' not in kwargs else kwargs['read_timeout']
)
resp = self.recvall(sock, read_timeout=read_timeout).decode(enc) resp = self.recvall(sock, read_timeout=read_timeout).decode(enc)
if TestUnit.detailed: if TestUnit.detailed:
@@ -410,7 +452,9 @@ class TestUnitHTTP(TestUnit):
p = re.compile('(.*?)\x0d\x0a?', re.M | re.S) p = re.compile('(.*?)\x0d\x0a?', re.M | re.S)
headers_lines = p.findall(headers_text) headers_lines = p.findall(headers_text)
status = re.search('^HTTP\/\d\.\d\s(\d+)|$', headers_lines.pop(0)).group(1) status = re.search(
'^HTTP\/\d\.\d\s(\d+)|$', headers_lines.pop(0)
).group(1)
headers = {} headers = {}
for line in headers_lines: for line in headers_lines:
@@ -418,16 +462,15 @@ class TestUnitHTTP(TestUnit):
if m.group(1) not in headers: if m.group(1) not in headers:
headers[m.group(1)] = m.group(2) headers[m.group(1)] = m.group(2)
elif isinstance(headers[m.group(1)], list): elif isinstance(headers[m.group(1)], list):
headers[m.group(1)].append(m.group(2)) headers[m.group(1)].append(m.group(2))
else: else:
headers[m.group(1)] = [headers[m.group(1)], m.group(2)] headers[m.group(1)] = [headers[m.group(1)], m.group(2)]
return { return {'status': int(status), 'headers': headers, 'body': body}
'status': int(status),
'headers': headers,
'body': body
}
class TestUnitControl(TestUnitHTTP): class TestUnitControl(TestUnitHTTP):
@@ -441,32 +484,39 @@ class TestUnitControl(TestUnitHTTP):
if path[:1] != '/': if path[:1] != '/':
path = '/config/' + path path = '/config/' + path
return json.loads(self.put( return json.loads(
self.put(
url=path, url=path,
body=conf, body=conf,
sock_type='unix', sock_type='unix',
addr=self.testdir + '/control.unit.sock' addr=self.testdir + '/control.unit.sock',
)['body']) )['body']
)
def conf_get(self, path='/config'): def conf_get(self, path='/config'):
if path[:1] != '/': if path[:1] != '/':
path = '/config/' + path path = '/config/' + path
return json.loads(self.get( return json.loads(
self.get(
url=path, url=path,
sock_type='unix', sock_type='unix',
addr=self.testdir + '/control.unit.sock' addr=self.testdir + '/control.unit.sock',
)['body']) )['body']
)
def conf_delete(self, path='/config'): def conf_delete(self, path='/config'):
if path[:1] != '/': if path[:1] != '/':
path = '/config/' + path path = '/config/' + path
return json.loads(self.delete( return json.loads(
self.delete(
url=path, url=path,
sock_type='unix', sock_type='unix',
addr=self.testdir + '/control.unit.sock' addr=self.testdir + '/control.unit.sock',
)['body']) )['body']
)
class TestUnitApplicationProto(TestUnitControl): class TestUnitApplicationProto(TestUnitControl):
@@ -482,64 +532,68 @@ class TestUnitApplicationProto(TestUnitControl):
with open(self.testdir + '/unit.log', 'r', errors='ignore') as f: with open(self.testdir + '/unit.log', 'r', errors='ignore') as f:
return re.search(pattern, f.read()) return re.search(pattern, f.read())
class TestUnitApplicationPython(TestUnitApplicationProto): class TestUnitApplicationPython(TestUnitApplicationProto):
def load(self, script, name=None): def load(self, script, name=None):
if name is None: if name is None:
name = script name = script
self.conf({ script_path = self.current_dir + '/python/' + script
"listeners": {
"*:7080": { self.conf(
"application": name {
} "listeners": {"*:7080": {"application": name}},
},
"applications": { "applications": {
name: { name: {
"type": "python", "type": "python",
"processes": { "spare": 0 }, "processes": {"spare": 0},
"path": self.current_dir + '/python/' + script, "path": script_path,
"working_directory": self.current_dir + '/python/' + script, "working_directory": script_path,
"module": "wsgi" "module": "wsgi",
} }
},
} }
}) )
class TestUnitApplicationRuby(TestUnitApplicationProto): class TestUnitApplicationRuby(TestUnitApplicationProto):
def load(self, script, name='config.ru'): def load(self, script, name='config.ru'):
self.conf({ script_path = self.current_dir + '/ruby/' + script
"listeners": {
"*:7080": { self.conf(
"application": script {
} "listeners": {"*:7080": {"application": script}},
},
"applications": { "applications": {
script: { script: {
"type": "ruby", "type": "ruby",
"processes": { "spare": 0 }, "processes": {"spare": 0},
"working_directory": self.current_dir + '/ruby/' + script, "working_directory": script_path,
"script": self.current_dir + '/ruby/' + script + '/' + name "script": script_path + '/' + name,
} }
},
} }
}) )
class TestUnitApplicationPHP(TestUnitApplicationProto): class TestUnitApplicationPHP(TestUnitApplicationProto):
def load(self, script, name='index.php'): def load(self, script, name='index.php'):
self.conf({ script_path = self.current_dir + '/php/' + script
"listeners": {
"*:7080": { self.conf(
"application": script {
} "listeners": {"*:7080": {"application": script}},
},
"applications": { "applications": {
script: { script: {
"type": "php", "type": "php",
"processes": { "spare": 0 }, "processes": {"spare": 0},
"root": self.current_dir + '/php/' + script, "root": script_path,
"working_directory": self.current_dir + '/php/' + script, "working_directory": script_path,
"index": name "index": name,
} }
},
} }
}) )
class TestUnitApplicationGo(TestUnitApplicationProto): class TestUnitApplicationGo(TestUnitApplicationProto):
def load(self, script, name='app'): def load(self, script, name='app'):
@@ -547,58 +601,67 @@ class TestUnitApplicationGo(TestUnitApplicationProto):
if not os.path.isdir(self.testdir + '/go'): if not os.path.isdir(self.testdir + '/go'):
os.mkdir(self.testdir + '/go') os.mkdir(self.testdir + '/go')
go_app_path = self.current_dir + '/go/'
env = os.environ.copy() env = os.environ.copy()
env['GOPATH'] = self.pardir + '/go' env['GOPATH'] = self.pardir + '/go'
process = subprocess.Popen(['go', 'build', '-o', process = subprocess.Popen(
[
'go',
'build',
'-o',
self.testdir + '/go/' + name, self.testdir + '/go/' + name,
self.current_dir + '/go/' + script + '/' + name + '.go'], go_app_path + script + '/' + name + '.go',
env=env) ],
env=env,
)
process.communicate() process.communicate()
self.conf({ self.conf(
"listeners": { {
"*:7080": { "listeners": {"*:7080": {"application": script}},
"application": script
}
},
"applications": { "applications": {
script: { script: {
"type": "external", "type": "external",
"processes": { "spare": 0 }, "processes": {"spare": 0},
"working_directory": self.current_dir + '/go/' + script, "working_directory": go_app_path + script,
"executable": self.testdir + '/go/' + name "executable": self.testdir + '/go/' + name,
} }
},
} }
}) )
class TestUnitApplicationNode(TestUnitApplicationProto): class TestUnitApplicationNode(TestUnitApplicationProto):
def load(self, script, name='app.js'): def load(self, script, name='app.js'):
# copy application # copy application
shutil.copytree(self.current_dir + '/node/' + script, shutil.copytree(
self.testdir + '/node') self.current_dir + '/node/' + script, self.testdir + '/node'
)
# link modules # link modules
os.symlink(self.pardir + '/node/node_modules', os.symlink(
self.testdir + '/node/node_modules') self.pardir + '/node/node_modules',
self.testdir + '/node/node_modules',
)
self.conf({ self.conf(
"listeners": { {
"*:7080": { "listeners": {"*:7080": {"application": script}},
"application": script
}
},
"applications": { "applications": {
script: { script: {
"type": "external", "type": "external",
"processes": { "spare": 0 }, "processes": {"spare": 0},
"working_directory": self.testdir + '/node', "working_directory": self.testdir + '/node',
"executable": name "executable": name,
} }
},
} }
}) )
class TestUnitApplicationJava(TestUnitApplicationProto): class TestUnitApplicationJava(TestUnitApplicationProto):
def load(self, script, name='app'): def load(self, script, name='app'):
@@ -641,48 +704,53 @@ class TestUnitApplicationJava(TestUnitApplicationProto):
if not os.path.isdir(classes_path): if not os.path.isdir(classes_path):
os.makedirs(classes_path) os.makedirs(classes_path)
javac = ['javac', '-encoding', 'utf-8', '-d', classes_path, tomcat_jar = self.pardir + '/build/tomcat-servlet-api-9.0.13.jar'
'-classpath',
self.pardir + '/build/tomcat-servlet-api-9.0.13.jar'] javac = [
'javac',
'-encoding', 'utf-8',
'-d', classes_path,
'-classpath', tomcat_jar,
]
javac.extend(src) javac.extend(src)
process = subprocess.Popen(javac) process = subprocess.Popen(javac)
process.communicate() process.communicate()
self.conf({ self.conf(
"listeners": { {
"*:7080": { "listeners": {"*:7080": {"application": script}},
"application": script
}
},
"applications": { "applications": {
script: { script: {
"unit_jars": self.pardir + '/build', "unit_jars": self.pardir + '/build',
"type": "java", "type": "java",
"processes": { "spare": 0 }, "processes": {"spare": 0},
"working_directory": script_path, "working_directory": script_path,
"webapp": app_path "webapp": app_path,
} }
},
} }
}) )
class TestUnitApplicationPerl(TestUnitApplicationProto): class TestUnitApplicationPerl(TestUnitApplicationProto):
def load(self, script, name='psgi.pl'): def load(self, script, name='psgi.pl'):
self.conf({ script_path = self.current_dir + '/perl/' + script
"listeners": {
"*:7080": { self.conf(
"application": script {
} "listeners": {"*:7080": {"application": script}},
},
"applications": { "applications": {
script: { script: {
"type": "perl", "type": "perl",
"processes": { "spare": 0 }, "processes": {"spare": 0},
"working_directory": self.current_dir + '/perl/' + script, "working_directory": script_path,
"script": self.current_dir + '/perl/' + script + '/' + name "script": script_path + '/' + name,
} }
},
} }
}) )
class TestUnitApplicationTLS(TestUnitApplicationProto): class TestUnitApplicationTLS(TestUnitApplicationProto):
def __init__(self, test): def __init__(self, test):
@@ -693,10 +761,18 @@ class TestUnitApplicationTLS(TestUnitApplicationProto):
self.context.verify_mode = ssl.CERT_NONE self.context.verify_mode = ssl.CERT_NONE
def certificate(self, name='default', load=True): def certificate(self, name='default', load=True):
subprocess.call(['openssl', 'req', '-x509', '-new', '-config', subprocess.call(
self.testdir + '/openssl.conf', '-subj', '/CN=' + name + '/', [
'openssl',
'req',
'-x509',
'-new',
'-subj', '/CN=' + name + '/',
'-config', self.testdir + '/openssl.conf',
'-out', self.testdir + '/' + name + '.crt', '-out', self.testdir + '/' + name + '.crt',
'-keyout', self.testdir + '/' + name + '.key']) '-keyout', self.testdir + '/' + name + '.key',
]
)
if load: if load:
self.certificate_load(name) self.certificate_load(name)
@@ -705,17 +781,17 @@ class TestUnitApplicationTLS(TestUnitApplicationProto):
if key is None: if key is None:
key = crt key = crt
with open(self.testdir + '/' + key + '.key', 'rb') as k, \ key_path = self.testdir + '/' + key + '.key'
open(self.testdir + '/' + crt + '.crt', 'rb') as c: crt_path = self.testdir + '/' + crt + '.crt'
with open(key_path, 'rb') as k, open(crt_path, 'rb') as c:
return self.conf(k.read() + c.read(), '/certificates/' + crt) return self.conf(k.read() + c.read(), '/certificates/' + crt)
def get_ssl(self, **kwargs): def get_ssl(self, **kwargs):
return self.get(wrapper=self.context.wrap_socket, return self.get(wrapper=self.context.wrap_socket, **kwargs)
**kwargs)
def post_ssl(self, **kwargs): def post_ssl(self, **kwargs):
return self.post(wrapper=self.context.wrap_socket, return self.post(wrapper=self.context.wrap_socket, **kwargs)
**kwargs)
def get_server_certificate(self, addr=('127.0.0.1', 7080)): def get_server_certificate(self, addr=('127.0.0.1', 7080)):
@@ -739,25 +815,27 @@ class TestUnitApplicationTLS(TestUnitApplicationProto):
# create default openssl configuration # create default openssl configuration
with open(self.testdir + '/openssl.conf', 'w') as f: with open(self.testdir + '/openssl.conf', 'w') as f:
f.write("""[ req ] f.write(
"""[ req ]
default_bits = 1024 default_bits = 1024
encrypt_key = no encrypt_key = no
distinguished_name = req_distinguished_name distinguished_name = req_distinguished_name
[ req_distinguished_name ]""") [ req_distinguished_name ]"""
)
self.conf({ script_path = self.current_dir + '/python/' + script
"listeners": {
"*:7080": { self.conf(
"application": name {
} "listeners": {"*:7080": {"application": name}},
},
"applications": { "applications": {
name: { name: {
"type": "python", "type": "python",
"processes": { "spare": 0 }, "processes": {"spare": 0},
"path": self.current_dir + '/python/' + script, "path": script_path,
"working_directory": self.current_dir + '/python/' + script, "working_directory": script_path,
"module": "wsgi" "module": "wsgi",
} }
},
} }
}) )