Tests: get rid of classes in test files.
Class usage came from the unittest framework and it was always redundant after migration to the pytest. This commit removes classes from files containing tests to make them more readable and understandable.
This commit is contained in:
parent
c6d05191a0
commit
c183bd8749
84 changed files with 17455 additions and 16814 deletions
|
@ -15,7 +15,7 @@ from multiprocessing import Process
|
|||
import pytest
|
||||
from unit.check.discover_available import discover_available
|
||||
from unit.check.check_prerequisites import check_prerequisites
|
||||
from unit.http import TestHTTP
|
||||
from unit.http import HTTP1
|
||||
from unit.log import Log
|
||||
from unit.log import print_log_on_assert
|
||||
from unit.option import option
|
||||
|
@ -82,7 +82,7 @@ _fds_info = {
|
|||
'skip': False,
|
||||
},
|
||||
}
|
||||
http = TestHTTP()
|
||||
http = HTTP1()
|
||||
is_findmnt = check_findmnt()
|
||||
|
||||
|
||||
|
@ -113,15 +113,16 @@ def pytest_configure(config):
|
|||
|
||||
|
||||
def pytest_generate_tests(metafunc):
|
||||
cls = metafunc.cls
|
||||
module = metafunc.module
|
||||
if (
|
||||
not hasattr(cls, 'application_type')
|
||||
or cls.application_type == None
|
||||
or cls.application_type == 'external'
|
||||
not hasattr(module, 'client')
|
||||
or not hasattr(module.client, 'application_type')
|
||||
or module.client.application_type is None
|
||||
or module.client.application_type == 'external'
|
||||
):
|
||||
return
|
||||
|
||||
type = cls.application_type
|
||||
app_type = module.client.application_type
|
||||
|
||||
def generate_tests(versions):
|
||||
if not versions:
|
||||
|
@ -133,7 +134,7 @@ def pytest_generate_tests(metafunc):
|
|||
for version in versions:
|
||||
option.generated_tests[
|
||||
f'{metafunc.function.__name__} [{version}]'
|
||||
] = f'{type} {version}'
|
||||
] = f'{app_type} {version}'
|
||||
|
||||
# take available module from option and generate tests for each version
|
||||
|
||||
|
@ -149,7 +150,7 @@ def pytest_generate_tests(metafunc):
|
|||
elif version == 'any':
|
||||
option.generated_tests[
|
||||
metafunc.function.__name__
|
||||
] = f'{type} {available_versions[0]}'
|
||||
] = f'{app_type} {available_versions[0]}'
|
||||
elif callable(version):
|
||||
generate_tests(list(filter(version, available_versions)))
|
||||
|
||||
|
|
|
@ -1,22 +1,24 @@
|
|||
import time
|
||||
|
||||
import pytest
|
||||
from unit.applications.lang.python import TestApplicationPython
|
||||
from unit.applications.lang.python import ApplicationPython
|
||||
from unit.option import option
|
||||
|
||||
prerequisites = {'modules': {'python': 'any'}}
|
||||
|
||||
client = ApplicationPython()
|
||||
|
||||
class TestAccessLog(TestApplicationPython):
|
||||
def load(self, script):
|
||||
super().load(script)
|
||||
|
||||
assert 'success' in self.conf(
|
||||
def load(script):
|
||||
client.load(script)
|
||||
|
||||
assert 'success' in client.conf(
|
||||
f'"{option.temp_dir}/access.log"', 'access_log'
|
||||
), 'access_log configure'
|
||||
|
||||
def set_format(self, format):
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def set_format(format):
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
'path': f'{option.temp_dir}/access.log',
|
||||
'format': format,
|
||||
|
@ -24,12 +26,13 @@ class TestAccessLog(TestApplicationPython):
|
|||
'access_log',
|
||||
), 'access_log format'
|
||||
|
||||
def test_access_log_keepalive(self, wait_for_record):
|
||||
self.load('mirror')
|
||||
|
||||
assert self.get()['status'] == 200, 'init'
|
||||
def test_access_log_keepalive(wait_for_record):
|
||||
load('mirror')
|
||||
|
||||
(_, sock) = self.post(
|
||||
assert client.get()['status'] == 200, 'init'
|
||||
|
||||
(_, sock) = client.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Connection': 'keep-alive',
|
||||
|
@ -40,21 +43,20 @@ class TestAccessLog(TestApplicationPython):
|
|||
)
|
||||
|
||||
assert (
|
||||
wait_for_record(r'"POST / HTTP/1.1" 200 5', 'access.log')
|
||||
is not None
|
||||
wait_for_record(r'"POST / HTTP/1.1" 200 5', 'access.log') is not None
|
||||
), 'keepalive 1'
|
||||
|
||||
_ = self.post(sock=sock, body='0123456789')
|
||||
_ = client.post(sock=sock, body='0123456789')
|
||||
|
||||
assert (
|
||||
wait_for_record(r'"POST / HTTP/1.1" 200 10', 'access.log')
|
||||
is not None
|
||||
wait_for_record(r'"POST / HTTP/1.1" 200 10', 'access.log') is not None
|
||||
), 'keepalive 2'
|
||||
|
||||
def test_access_log_pipeline(self, wait_for_record):
|
||||
self.load('empty')
|
||||
|
||||
self.http(
|
||||
def test_access_log_pipeline(wait_for_record):
|
||||
load('empty')
|
||||
|
||||
client.http(
|
||||
b"""GET / HTTP/1.1
|
||||
Host: localhost
|
||||
Referer: Referer-1
|
||||
|
@ -74,32 +76,27 @@ Connection: close
|
|||
)
|
||||
|
||||
assert (
|
||||
wait_for_record(
|
||||
r'"GET / HTTP/1.1" 200 0 "Referer-1" "-"', 'access.log'
|
||||
)
|
||||
wait_for_record(r'"GET / HTTP/1.1" 200 0 "Referer-1" "-"', 'access.log')
|
||||
is not None
|
||||
), 'pipeline 1'
|
||||
assert (
|
||||
wait_for_record(
|
||||
r'"GET / HTTP/1.1" 200 0 "Referer-2" "-"', 'access.log'
|
||||
)
|
||||
wait_for_record(r'"GET / HTTP/1.1" 200 0 "Referer-2" "-"', 'access.log')
|
||||
is not None
|
||||
), 'pipeline 2'
|
||||
assert (
|
||||
wait_for_record(
|
||||
r'"GET / HTTP/1.1" 200 0 "Referer-3" "-"', 'access.log'
|
||||
)
|
||||
wait_for_record(r'"GET / HTTP/1.1" 200 0 "Referer-3" "-"', 'access.log')
|
||||
is not None
|
||||
), 'pipeline 3'
|
||||
|
||||
def test_access_log_ipv6(self, wait_for_record):
|
||||
self.load('empty')
|
||||
|
||||
assert 'success' in self.conf(
|
||||
def test_access_log_ipv6(wait_for_record):
|
||||
load('empty')
|
||||
|
||||
assert 'success' in client.conf(
|
||||
{"[::1]:7080": {"pass": "applications/empty"}}, 'listeners'
|
||||
)
|
||||
|
||||
self.get(sock_type='ipv6')
|
||||
client.get(sock_type='ipv6')
|
||||
|
||||
assert (
|
||||
wait_for_record(
|
||||
|
@ -108,16 +105,17 @@ Connection: close
|
|||
is not None
|
||||
), 'ipv6'
|
||||
|
||||
def test_access_log_unix(self, temp_dir, wait_for_record):
|
||||
self.load('empty')
|
||||
|
||||
def test_access_log_unix(temp_dir, wait_for_record):
|
||||
load('empty')
|
||||
|
||||
addr = f'{temp_dir}/sock'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{f'unix:{addr}': {"pass": "applications/empty"}}, 'listeners'
|
||||
)
|
||||
|
||||
self.get(sock_type='unix', addr=addr)
|
||||
client.get(sock_type='unix', addr=addr)
|
||||
|
||||
assert (
|
||||
wait_for_record(
|
||||
|
@ -126,10 +124,11 @@ Connection: close
|
|||
is not None
|
||||
), 'unix'
|
||||
|
||||
def test_access_log_referer(self, wait_for_record):
|
||||
self.load('empty')
|
||||
|
||||
self.get(
|
||||
def test_access_log_referer(wait_for_record):
|
||||
load('empty')
|
||||
|
||||
client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Referer': 'referer-value',
|
||||
|
@ -144,10 +143,11 @@ Connection: close
|
|||
is not None
|
||||
), 'referer'
|
||||
|
||||
def test_access_log_user_agent(self, wait_for_record):
|
||||
self.load('empty')
|
||||
|
||||
self.get(
|
||||
def test_access_log_user_agent(wait_for_record):
|
||||
load('empty')
|
||||
|
||||
client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'User-Agent': 'user-agent-value',
|
||||
|
@ -162,22 +162,24 @@ Connection: close
|
|||
is not None
|
||||
), 'user agent'
|
||||
|
||||
def test_access_log_http10(self, wait_for_record):
|
||||
self.load('empty')
|
||||
|
||||
self.get(http_10=True)
|
||||
def test_access_log_http10(wait_for_record):
|
||||
load('empty')
|
||||
|
||||
client.get(http_10=True)
|
||||
|
||||
assert (
|
||||
wait_for_record(r'"GET / HTTP/1.0" 200 0 "-" "-"', 'access.log')
|
||||
is not None
|
||||
), 'http 1.0'
|
||||
|
||||
def test_access_log_partial(self, wait_for_record):
|
||||
self.load('empty')
|
||||
|
||||
assert self.post()['status'] == 200, 'init'
|
||||
def test_access_log_partial(wait_for_record):
|
||||
load('empty')
|
||||
|
||||
_ = self.http(b"""GE""", raw=True, read_timeout=1)
|
||||
assert client.post()['status'] == 200, 'init'
|
||||
|
||||
_ = client.http(b"""GE""", raw=True, read_timeout=1)
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
|
@ -185,23 +187,25 @@ Connection: close
|
|||
wait_for_record(r'"-" 400 0 "-" "-"', 'access.log') is not None
|
||||
), 'partial'
|
||||
|
||||
def test_access_log_partial_2(self, wait_for_record):
|
||||
self.load('empty')
|
||||
|
||||
assert self.post()['status'] == 200, 'init'
|
||||
def test_access_log_partial_2(wait_for_record):
|
||||
load('empty')
|
||||
|
||||
self.http(b"""GET /\n""", raw=True)
|
||||
assert client.post()['status'] == 200, 'init'
|
||||
|
||||
client.http(b"""GET /\n""", raw=True)
|
||||
|
||||
assert (
|
||||
wait_for_record(r'"-" 400 \d+ "-" "-"', 'access.log') is not None
|
||||
), 'partial 2'
|
||||
|
||||
def test_access_log_partial_3(self, wait_for_record):
|
||||
self.load('empty')
|
||||
|
||||
assert self.post()['status'] == 200, 'init'
|
||||
def test_access_log_partial_3(wait_for_record):
|
||||
load('empty')
|
||||
|
||||
_ = self.http(b"""GET / HTTP/1.1""", raw=True, read_timeout=1)
|
||||
assert client.post()['status'] == 200, 'init'
|
||||
|
||||
_ = client.http(b"""GET / HTTP/1.1""", raw=True, read_timeout=1)
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
|
@ -209,12 +213,13 @@ Connection: close
|
|||
wait_for_record(r'"-" 400 0 "-" "-"', 'access.log') is not None
|
||||
), 'partial 3'
|
||||
|
||||
def test_access_log_partial_4(self, wait_for_record):
|
||||
self.load('empty')
|
||||
|
||||
assert self.post()['status'] == 200, 'init'
|
||||
def test_access_log_partial_4(wait_for_record):
|
||||
load('empty')
|
||||
|
||||
_ = self.http(b"""GET / HTTP/1.1\n""", raw=True, read_timeout=1)
|
||||
assert client.post()['status'] == 200, 'init'
|
||||
|
||||
_ = client.http(b"""GET / HTTP/1.1\n""", raw=True, read_timeout=1)
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
|
@ -222,23 +227,25 @@ Connection: close
|
|||
wait_for_record(r'"-" 400 0 "-" "-"', 'access.log') is not None
|
||||
), 'partial 4'
|
||||
|
||||
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_access_log_partial_5(self, wait_for_record):
|
||||
self.load('empty')
|
||||
def test_access_log_partial_5(wait_for_record):
|
||||
load('empty')
|
||||
|
||||
assert self.post()['status'] == 200, 'init'
|
||||
assert client.post()['status'] == 200, 'init'
|
||||
|
||||
self.get(headers={'Connection': 'close'})
|
||||
client.get(headers={'Connection': 'close'})
|
||||
|
||||
assert (
|
||||
wait_for_record(r'"GET / HTTP/1.1" 400 \d+ "-" "-"', 'access.log')
|
||||
is not None
|
||||
), 'partial 5'
|
||||
|
||||
def test_access_log_get_parameters(self, wait_for_record):
|
||||
self.load('empty')
|
||||
|
||||
self.get(url='/?blah&var=val')
|
||||
def test_access_log_get_parameters(wait_for_record):
|
||||
load('empty')
|
||||
|
||||
client.get(url='/?blah&var=val')
|
||||
|
||||
assert (
|
||||
wait_for_record(
|
||||
|
@ -247,63 +254,68 @@ Connection: close
|
|||
is not None
|
||||
), 'get parameters'
|
||||
|
||||
def test_access_log_delete(self, search_in_file):
|
||||
self.load('empty')
|
||||
|
||||
assert 'success' in self.conf_delete('access_log')
|
||||
def test_access_log_delete(search_in_file):
|
||||
load('empty')
|
||||
|
||||
self.get(url='/delete')
|
||||
assert 'success' in client.conf_delete('access_log')
|
||||
|
||||
client.get(url='/delete')
|
||||
|
||||
assert search_in_file(r'/delete', 'access.log') is None, 'delete'
|
||||
|
||||
def test_access_log_change(self, temp_dir, wait_for_record):
|
||||
self.load('empty')
|
||||
|
||||
self.get()
|
||||
def test_access_log_change(temp_dir, wait_for_record):
|
||||
load('empty')
|
||||
|
||||
assert 'success' in self.conf(f'"{temp_dir}/new.log"', 'access_log')
|
||||
client.get()
|
||||
|
||||
self.get()
|
||||
assert 'success' in client.conf(f'"{temp_dir}/new.log"', 'access_log')
|
||||
|
||||
client.get()
|
||||
|
||||
assert (
|
||||
wait_for_record(r'"GET / HTTP/1.1" 200 0 "-" "-"', 'new.log')
|
||||
is not None
|
||||
), 'change'
|
||||
|
||||
def test_access_log_format(self, wait_for_record):
|
||||
self.load('empty')
|
||||
|
||||
def test_access_log_format(wait_for_record):
|
||||
load('empty')
|
||||
|
||||
def check_format(format, expect, url='/'):
|
||||
self.set_format(format)
|
||||
set_format(format)
|
||||
|
||||
assert self.get(url=url)['status'] == 200
|
||||
assert client.get(url=url)['status'] == 200
|
||||
assert wait_for_record(expect, 'access.log') is not None, 'found'
|
||||
|
||||
format = 'BLAH\t0123456789'
|
||||
check_format(format, format)
|
||||
check_format('$uri $status $uri $status', '/ 200 / 200')
|
||||
|
||||
def test_access_log_variables(self, wait_for_record):
|
||||
self.load('mirror')
|
||||
|
||||
def test_access_log_variables(wait_for_record):
|
||||
load('mirror')
|
||||
|
||||
# $body_bytes_sent
|
||||
|
||||
self.set_format('$uri $body_bytes_sent')
|
||||
set_format('$uri $body_bytes_sent')
|
||||
body = '0123456789' * 50
|
||||
self.post(url='/bbs', body=body, read_timeout=1)
|
||||
client.post(url='/bbs', body=body, read_timeout=1)
|
||||
assert (
|
||||
wait_for_record(fr'^\/bbs {len(body)}$', 'access.log') is not None
|
||||
), '$body_bytes_sent'
|
||||
|
||||
def test_access_log_incorrect(self, temp_dir, skip_alert):
|
||||
|
||||
def test_access_log_incorrect(temp_dir, skip_alert):
|
||||
skip_alert(r'failed to apply new conf')
|
||||
|
||||
assert 'error' in self.conf(
|
||||
assert 'error' in client.conf(
|
||||
f'{temp_dir}/blah/access.log',
|
||||
'access_log/path',
|
||||
), 'access_log path incorrect'
|
||||
|
||||
assert 'error' in self.conf(
|
||||
assert 'error' in client.conf(
|
||||
{
|
||||
'path': f'{temp_dir}/access.log',
|
||||
'format': '$remote_add',
|
||||
|
|
|
@ -3,22 +3,21 @@ import time
|
|||
|
||||
import pytest
|
||||
from packaging import version
|
||||
from unit.applications.lang.python import TestApplicationPython
|
||||
from unit.applications.lang.python import ApplicationPython
|
||||
|
||||
prerequisites = {
|
||||
'modules': {'python': lambda v: version.parse(v) >= version.parse('3.5')}
|
||||
}
|
||||
|
||||
client = ApplicationPython(load_module='asgi')
|
||||
|
||||
class TestASGIApplication(TestApplicationPython):
|
||||
load_module = 'asgi'
|
||||
|
||||
def test_asgi_application_variables(self, date_to_sec_epoch, sec_epoch):
|
||||
self.load('variables')
|
||||
def test_asgi_application_variables(date_to_sec_epoch, sec_epoch):
|
||||
client.load('variables')
|
||||
|
||||
body = 'Test body string.'
|
||||
|
||||
resp = self.http(
|
||||
resp = client.http(
|
||||
f"""POST / HTTP/1.1
|
||||
Host: localhost
|
||||
Content-Length: {len(body)}
|
||||
|
@ -56,42 +55,46 @@ custom-header: BLAH
|
|||
}, 'headers'
|
||||
assert resp['body'] == body, 'body'
|
||||
|
||||
def test_asgi_application_ipv6(self):
|
||||
self.load('empty')
|
||||
|
||||
assert 'success' in self.conf(
|
||||
def test_asgi_application_ipv6():
|
||||
client.load('empty')
|
||||
|
||||
assert 'success' in client.conf(
|
||||
{"[::1]:7080": {"pass": "applications/empty"}}, 'listeners'
|
||||
)
|
||||
|
||||
assert self.get(sock_type='ipv6')['status'] == 200
|
||||
assert client.get(sock_type='ipv6')['status'] == 200
|
||||
|
||||
def test_asgi_application_unix(self, temp_dir):
|
||||
self.load('empty')
|
||||
|
||||
def test_asgi_application_unix(temp_dir):
|
||||
client.load('empty')
|
||||
|
||||
addr = f'{temp_dir}/sock'
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{f"unix:{addr}": {"pass": "applications/empty"}}, 'listeners'
|
||||
)
|
||||
|
||||
assert self.get(sock_type='unix', addr=addr)['status'] == 200
|
||||
assert client.get(sock_type='unix', addr=addr)['status'] == 200
|
||||
|
||||
def test_asgi_application_query_string(self):
|
||||
self.load('query_string')
|
||||
|
||||
resp = self.get(url='/?var1=val1&var2=val2')
|
||||
def test_asgi_application_query_string():
|
||||
client.load('query_string')
|
||||
|
||||
resp = client.get(url='/?var1=val1&var2=val2')
|
||||
|
||||
assert (
|
||||
resp['headers']['query-string'] == 'var1=val1&var2=val2'
|
||||
), 'query-string header'
|
||||
|
||||
def test_asgi_application_prefix(self):
|
||||
self.load('prefix', prefix='/api/rest')
|
||||
|
||||
def test_asgi_application_prefix():
|
||||
client.load('prefix', prefix='/api/rest')
|
||||
|
||||
def set_prefix(prefix):
|
||||
self.conf(f'"{prefix}"', 'applications/prefix/prefix')
|
||||
client.conf(f'"{prefix}"', 'applications/prefix/prefix')
|
||||
|
||||
def check_prefix(url, prefix):
|
||||
resp = self.get(url=url)
|
||||
resp = client.get(url=url)
|
||||
assert resp['status'] == 200
|
||||
assert resp['headers']['prefix'] == prefix
|
||||
|
||||
|
@ -121,98 +124,106 @@ custom-header: BLAH
|
|||
check_prefix('/', 'NULL')
|
||||
check_prefix('/app', 'NULL')
|
||||
|
||||
def test_asgi_application_query_string_space(self):
|
||||
self.load('query_string')
|
||||
|
||||
resp = self.get(url='/ ?var1=val1&var2=val2')
|
||||
def test_asgi_application_query_string_space():
|
||||
client.load('query_string')
|
||||
|
||||
resp = client.get(url='/ ?var1=val1&var2=val2')
|
||||
assert (
|
||||
resp['headers']['query-string'] == 'var1=val1&var2=val2'
|
||||
), 'query-string space'
|
||||
|
||||
resp = self.get(url='/ %20?var1=val1&var2=val2')
|
||||
resp = client.get(url='/ %20?var1=val1&var2=val2')
|
||||
assert (
|
||||
resp['headers']['query-string'] == 'var1=val1&var2=val2'
|
||||
), 'query-string space 2'
|
||||
|
||||
resp = self.get(url='/ %20 ?var1=val1&var2=val2')
|
||||
resp = client.get(url='/ %20 ?var1=val1&var2=val2')
|
||||
assert (
|
||||
resp['headers']['query-string'] == 'var1=val1&var2=val2'
|
||||
), 'query-string space 3'
|
||||
|
||||
resp = self.get(url='/blah %20 blah? var1= val1 & var2=val2')
|
||||
resp = client.get(url='/blah %20 blah? var1= val1 & var2=val2')
|
||||
assert (
|
||||
resp['headers']['query-string'] == ' var1= val1 & var2=val2'
|
||||
), 'query-string space 4'
|
||||
|
||||
def test_asgi_application_query_string_empty(self):
|
||||
self.load('query_string')
|
||||
|
||||
resp = self.get(url='/?')
|
||||
def test_asgi_application_query_string_empty():
|
||||
client.load('query_string')
|
||||
|
||||
resp = client.get(url='/?')
|
||||
|
||||
assert resp['status'] == 200, 'query string empty status'
|
||||
assert resp['headers']['query-string'] == '', 'query string empty'
|
||||
|
||||
def test_asgi_application_query_string_absent(self):
|
||||
self.load('query_string')
|
||||
|
||||
resp = self.get()
|
||||
def test_asgi_application_query_string_absent():
|
||||
client.load('query_string')
|
||||
|
||||
resp = client.get()
|
||||
|
||||
assert resp['status'] == 200, 'query string absent status'
|
||||
assert resp['headers']['query-string'] == '', 'query string absent'
|
||||
|
||||
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_asgi_application_server_port(self):
|
||||
self.load('server_port')
|
||||
def test_asgi_application_server_port():
|
||||
client.load('server_port')
|
||||
|
||||
assert (
|
||||
self.get()['headers']['Server-Port'] == '7080'
|
||||
client.get()['headers']['Server-Port'] == '7080'
|
||||
), 'Server-Port header'
|
||||
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_asgi_application_working_directory_invalid(self):
|
||||
self.load('empty')
|
||||
|
||||
assert 'success' in self.conf(
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_asgi_application_working_directory_invalid():
|
||||
client.load('empty')
|
||||
|
||||
assert 'success' in client.conf(
|
||||
'"/blah"', 'applications/empty/working_directory'
|
||||
), 'configure invalid working_directory'
|
||||
|
||||
assert self.get()['status'] == 500, 'status'
|
||||
assert client.get()['status'] == 500, 'status'
|
||||
|
||||
def test_asgi_application_204_transfer_encoding(self):
|
||||
self.load('204_no_content')
|
||||
|
||||
def test_asgi_application_204_transfer_encoding():
|
||||
client.load('204_no_content')
|
||||
|
||||
assert (
|
||||
'Transfer-Encoding' not in self.get()['headers']
|
||||
'Transfer-Encoding' not in client.get()['headers']
|
||||
), '204 header transfer encoding'
|
||||
|
||||
def test_asgi_application_shm_ack_handle(self):
|
||||
|
||||
def test_asgi_application_shm_ack_handle():
|
||||
# Minimum possible limit
|
||||
shm_limit = 10 * 1024 * 1024
|
||||
|
||||
self.load('mirror', limits={"shm": shm_limit})
|
||||
client.load('mirror', limits={"shm": shm_limit})
|
||||
|
||||
# Should exceed shm_limit
|
||||
max_body_size = 12 * 1024 * 1024
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
f'{{"http":{{"max_body_size": {max_body_size} }}}}',
|
||||
'settings',
|
||||
)
|
||||
|
||||
assert self.get()['status'] == 200, 'init'
|
||||
assert client.get()['status'] == 200, 'init'
|
||||
|
||||
body = '0123456789AB' * 1024 * 1024 # 12 Mb
|
||||
resp = self.post(body=body, read_buffer_size=1024 * 1024)
|
||||
resp = client.post(body=body, read_buffer_size=1024 * 1024)
|
||||
|
||||
assert resp['body'] == body, 'keep-alive 1'
|
||||
|
||||
def test_asgi_keepalive_body(self):
|
||||
self.load('mirror')
|
||||
|
||||
assert self.get()['status'] == 200, 'init'
|
||||
def test_asgi_keepalive_body():
|
||||
client.load('mirror')
|
||||
|
||||
assert client.get()['status'] == 200, 'init'
|
||||
|
||||
body = '0123456789' * 500
|
||||
(resp, sock) = self.post(
|
||||
(resp, sock) = client.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Connection': 'keep-alive',
|
||||
|
@ -225,21 +236,22 @@ custom-header: BLAH
|
|||
assert resp['body'] == body, 'keep-alive 1'
|
||||
|
||||
body = '0123456789'
|
||||
resp = self.post(sock=sock, body=body)
|
||||
resp = client.post(sock=sock, body=body)
|
||||
|
||||
assert resp['body'] == body, 'keep-alive 2'
|
||||
|
||||
def test_asgi_keepalive_reconfigure(self):
|
||||
self.load('mirror')
|
||||
|
||||
assert self.get()['status'] == 200, 'init'
|
||||
def test_asgi_keepalive_reconfigure():
|
||||
client.load('mirror')
|
||||
|
||||
assert client.get()['status'] == 200, 'init'
|
||||
|
||||
body = '0123456789'
|
||||
conns = 3
|
||||
socks = []
|
||||
|
||||
for i in range(conns):
|
||||
(resp, sock) = self.post(
|
||||
(resp, sock) = client.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Connection': 'keep-alive',
|
||||
|
@ -251,12 +263,12 @@ custom-header: BLAH
|
|||
|
||||
assert resp['body'] == body, 'keep-alive open'
|
||||
|
||||
self.load('mirror', processes=i + 1)
|
||||
client.load('mirror', processes=i + 1)
|
||||
|
||||
socks.append(sock)
|
||||
|
||||
for i in range(conns):
|
||||
(resp, sock) = self.post(
|
||||
(resp, sock) = client.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Connection': 'keep-alive',
|
||||
|
@ -269,23 +281,24 @@ custom-header: BLAH
|
|||
|
||||
assert resp['body'] == body, 'keep-alive request'
|
||||
|
||||
self.load('mirror', processes=i + 1)
|
||||
client.load('mirror', processes=i + 1)
|
||||
|
||||
for i in range(conns):
|
||||
resp = self.post(sock=socks[i], body=body)
|
||||
resp = client.post(sock=socks[i], body=body)
|
||||
|
||||
assert resp['body'] == body, 'keep-alive close'
|
||||
|
||||
self.load('mirror', processes=i + 1)
|
||||
client.load('mirror', processes=i + 1)
|
||||
|
||||
def test_asgi_keepalive_reconfigure_2(self):
|
||||
self.load('mirror')
|
||||
|
||||
assert self.get()['status'] == 200, 'init'
|
||||
def test_asgi_keepalive_reconfigure_2():
|
||||
client.load('mirror')
|
||||
|
||||
assert client.get()['status'] == 200, 'init'
|
||||
|
||||
body = '0123456789'
|
||||
|
||||
(resp, sock) = self.post(
|
||||
(resp, sock) = client.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Connection': 'keep-alive',
|
||||
|
@ -297,42 +310,43 @@ custom-header: BLAH
|
|||
|
||||
assert resp['body'] == body, 'reconfigure 2 keep-alive 1'
|
||||
|
||||
self.load('empty')
|
||||
client.load('empty')
|
||||
|
||||
assert self.get()['status'] == 200, 'init'
|
||||
assert client.get()['status'] == 200, 'init'
|
||||
|
||||
(resp, sock) = self.post(start=True, sock=sock, body=body)
|
||||
(resp, sock) = client.post(start=True, sock=sock, body=body)
|
||||
|
||||
assert resp['status'] == 200, 'reconfigure 2 keep-alive 2'
|
||||
assert resp['body'] == '', 'reconfigure 2 keep-alive 2 body'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{"listeners": {}, "applications": {}}
|
||||
), 'reconfigure 2 clear configuration'
|
||||
|
||||
resp = self.get(sock=sock)
|
||||
resp = client.get(sock=sock)
|
||||
|
||||
assert resp == {}, 'reconfigure 2 keep-alive 3'
|
||||
|
||||
def test_asgi_keepalive_reconfigure_3(self):
|
||||
self.load('empty')
|
||||
|
||||
assert self.get()['status'] == 200, 'init'
|
||||
def test_asgi_keepalive_reconfigure_3():
|
||||
client.load('empty')
|
||||
|
||||
sock = self.http(
|
||||
assert client.get()['status'] == 200, 'init'
|
||||
|
||||
sock = client.http(
|
||||
b"""GET / HTTP/1.1
|
||||
""",
|
||||
raw=True,
|
||||
no_recv=True,
|
||||
)
|
||||
|
||||
assert self.get()['status'] == 200
|
||||
assert client.get()['status'] == 200
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{"listeners": {}, "applications": {}}
|
||||
), 'reconfigure 3 clear configuration'
|
||||
|
||||
resp = self.http(
|
||||
resp = client.http(
|
||||
b"""Host: localhost
|
||||
Connection: close
|
||||
|
||||
|
@ -343,10 +357,11 @@ Connection: close
|
|||
|
||||
assert resp['status'] == 200, 'reconfigure 3'
|
||||
|
||||
def test_asgi_process_switch(self):
|
||||
self.load('delayed', processes=2)
|
||||
|
||||
self.get(
|
||||
def test_asgi_process_switch():
|
||||
client.load('delayed', processes=2)
|
||||
|
||||
client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Content-Length': '0',
|
||||
|
@ -363,43 +378,46 @@ Connection: close
|
|||
'X-Delay': '1',
|
||||
}
|
||||
|
||||
self.get(headers=headers_delay_1, no_recv=True)
|
||||
client.get(headers=headers_delay_1, no_recv=True)
|
||||
|
||||
time.sleep(0.5)
|
||||
|
||||
for _ in range(10):
|
||||
self.get(headers=headers_delay_1, no_recv=True)
|
||||
client.get(headers=headers_delay_1, no_recv=True)
|
||||
|
||||
self.get(headers=headers_delay_1)
|
||||
client.get(headers=headers_delay_1)
|
||||
|
||||
def test_asgi_application_loading_error(self, skip_alert):
|
||||
|
||||
def test_asgi_application_loading_error(skip_alert):
|
||||
skip_alert(r'Python failed to import module "blah"')
|
||||
|
||||
self.load('empty', module="blah")
|
||||
client.load('empty', module="blah")
|
||||
|
||||
assert self.get()['status'] == 503, 'loading error'
|
||||
assert client.get()['status'] == 503, 'loading error'
|
||||
|
||||
def test_asgi_application_threading(self, wait_for_record):
|
||||
|
||||
def test_asgi_application_threading(wait_for_record):
|
||||
"""wait_for_record() timeouts after 5s while every thread works at
|
||||
least 3s. So without releasing GIL test should fail.
|
||||
"""
|
||||
|
||||
self.load('threading')
|
||||
client.load('threading')
|
||||
|
||||
for _ in range(10):
|
||||
self.get(no_recv=True)
|
||||
client.get(no_recv=True)
|
||||
|
||||
assert (
|
||||
wait_for_record(r'\(5\) Thread: 100', wait=50) is not None
|
||||
), 'last thread finished'
|
||||
|
||||
def test_asgi_application_threads(self):
|
||||
self.load('threads', threads=2)
|
||||
|
||||
def test_asgi_application_threads():
|
||||
client.load('threads', threads=2)
|
||||
|
||||
socks = []
|
||||
|
||||
for _ in range(2):
|
||||
sock = self.get(
|
||||
sock = client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Delay': '3',
|
||||
|
@ -415,11 +433,11 @@ Connection: close
|
|||
threads = set()
|
||||
|
||||
for sock in socks:
|
||||
resp = self.recvall(sock).decode('utf-8')
|
||||
resp = client.recvall(sock).decode('utf-8')
|
||||
|
||||
self.log_in(resp)
|
||||
client.log_in(resp)
|
||||
|
||||
resp = self._resp_to_dict(resp)
|
||||
resp = client._resp_to_dict(resp)
|
||||
|
||||
assert resp['status'] == 200, 'status'
|
||||
|
||||
|
@ -429,10 +447,11 @@ Connection: close
|
|||
|
||||
assert len(socks) == len(threads), 'threads differs'
|
||||
|
||||
def test_asgi_application_legacy(self):
|
||||
self.load('legacy')
|
||||
|
||||
resp = self.get(
|
||||
def test_asgi_application_legacy():
|
||||
client.load('legacy')
|
||||
|
||||
resp = client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Content-Length': '0',
|
||||
|
@ -442,10 +461,11 @@ Connection: close
|
|||
|
||||
assert resp['status'] == 200, 'status'
|
||||
|
||||
def test_asgi_application_legacy_force(self):
|
||||
self.load('legacy_force', protocol='asgi')
|
||||
|
||||
resp = self.get(
|
||||
def test_asgi_application_legacy_force():
|
||||
client.load('legacy_force', protocol='asgi')
|
||||
|
||||
resp = client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Content-Length': '0',
|
||||
|
|
|
@ -1,22 +1,21 @@
|
|||
from packaging import version
|
||||
from unit.applications.lang.python import TestApplicationPython
|
||||
from unit.applications.lang.python import ApplicationPython
|
||||
|
||||
prerequisites = {
|
||||
'modules': {'python': lambda v: version.parse(v) >= version.parse('3.5')},
|
||||
'features': {'unix_abstract': True},
|
||||
}
|
||||
|
||||
client = ApplicationPython(load_module='asgi')
|
||||
|
||||
class TestASGIApplicationUnixAbstract(TestApplicationPython):
|
||||
load_module = 'asgi'
|
||||
|
||||
def test_asgi_application_unix_abstract(self):
|
||||
self.load('empty')
|
||||
def test_asgi_application_unix_abstract():
|
||||
client.load('empty')
|
||||
|
||||
addr = '\0sock'
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{f"unix:@{addr[1:]}": {"pass": "applications/empty"}},
|
||||
'listeners',
|
||||
)
|
||||
|
||||
assert self.get(sock_type='unix', addr=addr)['status'] == 200
|
||||
assert client.get(sock_type='unix', addr=addr)['status'] == 200
|
||||
|
|
|
@ -2,28 +2,17 @@ import os
|
|||
|
||||
from conftest import unit_stop
|
||||
from packaging import version
|
||||
from unit.applications.lang.python import TestApplicationPython
|
||||
from unit.applications.lang.python import ApplicationPython
|
||||
from unit.option import option
|
||||
|
||||
prerequisites = {
|
||||
'modules': {'python': lambda v: version.parse(v) >= version.parse('3.5')}
|
||||
}
|
||||
|
||||
client = ApplicationPython(load_module='asgi')
|
||||
|
||||
class TestASGILifespan(TestApplicationPython):
|
||||
load_module = 'asgi'
|
||||
|
||||
def setup_cookies(self, prefix):
|
||||
base_dir = f'{option.test_dir}/python/lifespan/empty'
|
||||
|
||||
os.chmod(base_dir, 0o777)
|
||||
|
||||
for name in ['startup', 'shutdown', 'version']:
|
||||
path = f'{option.test_dir}/python/lifespan/empty/{prefix}{name}'
|
||||
open(path, 'a').close()
|
||||
os.chmod(path, 0o777)
|
||||
|
||||
def assert_cookies(self, prefix):
|
||||
def assert_cookies(prefix):
|
||||
for name in ['startup', 'shutdown']:
|
||||
path = f'{option.test_dir}/python/lifespan/empty/{prefix}{name}'
|
||||
exists = os.path.isfile(path)
|
||||
|
@ -41,21 +30,34 @@ class TestASGILifespan(TestApplicationPython):
|
|||
|
||||
assert version == '3.0 2.0', 'version'
|
||||
|
||||
def test_asgi_lifespan(self):
|
||||
self.load('lifespan/empty')
|
||||
|
||||
self.setup_cookies('')
|
||||
def setup_cookies(prefix):
|
||||
base_dir = f'{option.test_dir}/python/lifespan/empty'
|
||||
|
||||
assert self.get()['status'] == 204
|
||||
os.chmod(base_dir, 0o777)
|
||||
|
||||
for name in ['startup', 'shutdown', 'version']:
|
||||
path = f'{option.test_dir}/python/lifespan/empty/{prefix}{name}'
|
||||
open(path, 'a').close()
|
||||
os.chmod(path, 0o777)
|
||||
|
||||
|
||||
def test_asgi_lifespan():
|
||||
client.load('lifespan/empty')
|
||||
|
||||
setup_cookies('')
|
||||
|
||||
assert client.get()['status'] == 204
|
||||
|
||||
unit_stop()
|
||||
|
||||
self.assert_cookies('')
|
||||
assert_cookies('')
|
||||
|
||||
def test_asgi_lifespan_targets(self):
|
||||
|
||||
def test_asgi_lifespan_targets():
|
||||
path = f'{option.test_dir}/python/lifespan/empty'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "routes"}},
|
||||
"routes": [
|
||||
|
@ -70,7 +72,7 @@ class TestASGILifespan(TestApplicationPython):
|
|||
],
|
||||
"applications": {
|
||||
"targets": {
|
||||
"type": self.get_application_type(),
|
||||
"type": client.get_application_type(),
|
||||
"processes": {"spare": 0},
|
||||
"working_directory": path,
|
||||
"path": path,
|
||||
|
@ -86,38 +88,40 @@ class TestASGILifespan(TestApplicationPython):
|
|||
}
|
||||
)
|
||||
|
||||
self.setup_cookies('')
|
||||
self.setup_cookies('app2_')
|
||||
setup_cookies('')
|
||||
setup_cookies('app2_')
|
||||
|
||||
assert self.get(url="/1")['status'] == 204
|
||||
assert self.get(url="/2")['status'] == 204
|
||||
assert client.get(url="/1")['status'] == 204
|
||||
assert client.get(url="/2")['status'] == 204
|
||||
|
||||
unit_stop()
|
||||
|
||||
self.assert_cookies('')
|
||||
self.assert_cookies('app2_')
|
||||
assert_cookies('')
|
||||
assert_cookies('app2_')
|
||||
|
||||
def test_asgi_lifespan_failed(self, wait_for_record):
|
||||
self.load('lifespan/failed')
|
||||
|
||||
assert self.get()['status'] == 503
|
||||
def test_asgi_lifespan_failed(wait_for_record):
|
||||
client.load('lifespan/failed')
|
||||
|
||||
assert client.get()['status'] == 503
|
||||
|
||||
assert (
|
||||
wait_for_record(r'\[error\].*Application startup failed')
|
||||
is not None
|
||||
wait_for_record(r'\[error\].*Application startup failed') is not None
|
||||
), 'error message'
|
||||
assert wait_for_record(r'Exception blah') is not None, 'exception'
|
||||
|
||||
def test_asgi_lifespan_error(self, wait_for_record):
|
||||
self.load('lifespan/error')
|
||||
|
||||
self.get()
|
||||
def test_asgi_lifespan_error(wait_for_record):
|
||||
client.load('lifespan/error')
|
||||
|
||||
client.get()
|
||||
|
||||
assert wait_for_record(r'Exception blah') is not None, 'exception'
|
||||
|
||||
def test_asgi_lifespan_error_auto(self, wait_for_record):
|
||||
self.load('lifespan/error_auto')
|
||||
|
||||
self.get()
|
||||
def test_asgi_lifespan_error_auto(wait_for_record):
|
||||
client.load('lifespan/error_auto')
|
||||
|
||||
client.get()
|
||||
|
||||
assert wait_for_record(r'AssertionError') is not None, 'assertion'
|
||||
|
|
|
@ -1,21 +1,20 @@
|
|||
import pytest
|
||||
from packaging import version
|
||||
from unit.applications.lang.python import TestApplicationPython
|
||||
from unit.applications.lang.python import ApplicationPython
|
||||
from unit.option import option
|
||||
|
||||
prerequisites = {
|
||||
'modules': {'python': lambda v: version.parse(v) >= version.parse('3.5')}
|
||||
}
|
||||
|
||||
client = ApplicationPython(load_module='asgi')
|
||||
|
||||
class TestASGITargets(TestApplicationPython):
|
||||
load_module = 'asgi'
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_method_fixture(self):
|
||||
def setup_method_fixture():
|
||||
path = f'{option.test_dir}/python/targets/'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "routes"}},
|
||||
"routes": [
|
||||
|
@ -30,7 +29,7 @@ class TestASGITargets(TestApplicationPython):
|
|||
],
|
||||
"applications": {
|
||||
"targets": {
|
||||
"type": self.get_application_type(),
|
||||
"type": client.get_application_type(),
|
||||
"processes": {"spare": 0},
|
||||
"working_directory": path,
|
||||
"path": path,
|
||||
|
@ -50,49 +49,55 @@ class TestASGITargets(TestApplicationPython):
|
|||
}
|
||||
)
|
||||
|
||||
def conf_targets(self, targets):
|
||||
assert 'success' in self.conf(targets, 'applications/targets/targets')
|
||||
|
||||
def test_asgi_targets(self):
|
||||
assert self.get(url='/1')['status'] == 200
|
||||
assert self.get(url='/2')['status'] == 201
|
||||
def conf_targets(targets):
|
||||
assert 'success' in client.conf(targets, 'applications/targets/targets')
|
||||
|
||||
def test_asgi_targets_legacy(self):
|
||||
self.conf_targets(
|
||||
|
||||
def test_asgi_targets():
|
||||
assert client.get(url='/1')['status'] == 200
|
||||
assert client.get(url='/2')['status'] == 201
|
||||
|
||||
|
||||
def test_asgi_targets_legacy():
|
||||
conf_targets(
|
||||
{
|
||||
"1": {"module": "asgi", "callable": "legacy_application_200"},
|
||||
"2": {"module": "asgi", "callable": "legacy_application_201"},
|
||||
}
|
||||
)
|
||||
|
||||
assert self.get(url='/1')['status'] == 200
|
||||
assert self.get(url='/2')['status'] == 201
|
||||
assert client.get(url='/1')['status'] == 200
|
||||
assert client.get(url='/2')['status'] == 201
|
||||
|
||||
def test_asgi_targets_mix(self):
|
||||
self.conf_targets(
|
||||
|
||||
def test_asgi_targets_mix():
|
||||
conf_targets(
|
||||
{
|
||||
"1": {"module": "asgi", "callable": "application_200"},
|
||||
"2": {"module": "asgi", "callable": "legacy_application_201"},
|
||||
}
|
||||
)
|
||||
|
||||
assert self.get(url='/1')['status'] == 200
|
||||
assert self.get(url='/2')['status'] == 201
|
||||
assert client.get(url='/1')['status'] == 200
|
||||
assert client.get(url='/2')['status'] == 201
|
||||
|
||||
def test_asgi_targets_broken(self, skip_alert):
|
||||
|
||||
def test_asgi_targets_broken(skip_alert):
|
||||
skip_alert(r'Python failed to get "blah" from module')
|
||||
|
||||
self.conf_targets(
|
||||
conf_targets(
|
||||
{
|
||||
"1": {"module": "asgi", "callable": "application_200"},
|
||||
"2": {"module": "asgi", "callable": "blah"},
|
||||
}
|
||||
)
|
||||
|
||||
assert self.get(url='/1')['status'] != 200
|
||||
assert client.get(url='/1')['status'] != 200
|
||||
|
||||
def test_asgi_targets_prefix(self):
|
||||
self.conf_targets(
|
||||
|
||||
def test_asgi_targets_prefix():
|
||||
conf_targets(
|
||||
{
|
||||
"1": {
|
||||
"module": "asgi",
|
||||
|
@ -106,7 +111,7 @@ class TestASGITargets(TestApplicationPython):
|
|||
},
|
||||
}
|
||||
)
|
||||
self.conf(
|
||||
client.conf(
|
||||
[
|
||||
{
|
||||
"match": {"uri": "/1*"},
|
||||
|
@ -121,7 +126,7 @@ class TestASGITargets(TestApplicationPython):
|
|||
)
|
||||
|
||||
def check_prefix(url, prefix):
|
||||
resp = self.get(url=url)
|
||||
resp = client.get(url=url)
|
||||
assert resp['status'] == 200
|
||||
assert resp['headers']['prefix'] == prefix
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,17 +1,19 @@
|
|||
import pytest
|
||||
from unit.applications.lang.python import TestApplicationPython
|
||||
from unit.applications.lang.python import ApplicationPython
|
||||
from unit.option import option
|
||||
|
||||
prerequisites = {'modules': {'python': 'any'}}
|
||||
|
||||
client = ApplicationPython()
|
||||
|
||||
|
||||
class TestClientIP(TestApplicationPython):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_method_fixture(self):
|
||||
self.load('client_ip')
|
||||
def setup_method_fixture():
|
||||
client.load('client_ip')
|
||||
|
||||
def client_ip(self, options):
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def client_ip(options):
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"127.0.0.1:7081": {
|
||||
"client_ip": options,
|
||||
|
@ -29,7 +31,8 @@ class TestClientIP(TestApplicationPython):
|
|||
'listeners',
|
||||
), 'listeners configure'
|
||||
|
||||
def get_xff(self, xff, sock_type='ipv4'):
|
||||
|
||||
def get_xff(xff, sock_type='ipv4'):
|
||||
address = {
|
||||
'ipv4': ('127.0.0.1', 7081),
|
||||
'ipv6': ('::1', 7082),
|
||||
|
@ -37,58 +40,57 @@ class TestClientIP(TestApplicationPython):
|
|||
}
|
||||
(addr, port) = address[sock_type]
|
||||
|
||||
return self.get(
|
||||
return client.get(
|
||||
sock_type=sock_type,
|
||||
addr=addr,
|
||||
port=port,
|
||||
headers={'Connection': 'close', 'X-Forwarded-For': xff},
|
||||
)['body']
|
||||
|
||||
def test_client_ip_single_ip(self):
|
||||
self.client_ip(
|
||||
{'header': 'X-Forwarded-For', 'source': '123.123.123.123'}
|
||||
)
|
||||
|
||||
assert self.get(port=7081)['body'] == '127.0.0.1', 'ipv4 default'
|
||||
def test_client_ip_single_ip():
|
||||
client_ip({'header': 'X-Forwarded-For', 'source': '123.123.123.123'})
|
||||
|
||||
assert client.get(port=7081)['body'] == '127.0.0.1', 'ipv4 default'
|
||||
assert (
|
||||
self.get(sock_type='ipv6', port=7082)['body'] == '::1'
|
||||
client.get(sock_type='ipv6', port=7082)['body'] == '::1'
|
||||
), 'ipv6 default'
|
||||
assert self.get_xff('1.1.1.1') == '127.0.0.1', 'bad source'
|
||||
assert self.get_xff('blah') == '127.0.0.1', 'bad header'
|
||||
assert self.get_xff('1.1.1.1', 'ipv6') == '::1', 'bad source ipv6'
|
||||
assert get_xff('1.1.1.1') == '127.0.0.1', 'bad source'
|
||||
assert get_xff('blah') == '127.0.0.1', 'bad header'
|
||||
assert get_xff('1.1.1.1', 'ipv6') == '::1', 'bad source ipv6'
|
||||
|
||||
self.client_ip({'header': 'X-Forwarded-For', 'source': '127.0.0.1'})
|
||||
client_ip({'header': 'X-Forwarded-For', 'source': '127.0.0.1'})
|
||||
|
||||
assert self.get(port=7081)['body'] == '127.0.0.1', 'ipv4 default 2'
|
||||
assert client.get(port=7081)['body'] == '127.0.0.1', 'ipv4 default 2'
|
||||
assert (
|
||||
self.get(sock_type='ipv6', port=7082)['body'] == '::1'
|
||||
client.get(sock_type='ipv6', port=7082)['body'] == '::1'
|
||||
), 'ipv6 default 2'
|
||||
assert self.get_xff('1.1.1.1') == '1.1.1.1', 'replace'
|
||||
assert self.get_xff('blah') == '127.0.0.1', 'bad header 2'
|
||||
assert self.get_xff('1.1.1.1', 'ipv6') == '::1', 'bad source ipv6 2'
|
||||
assert get_xff('1.1.1.1') == '1.1.1.1', 'replace'
|
||||
assert get_xff('blah') == '127.0.0.1', 'bad header 2'
|
||||
assert get_xff('1.1.1.1', 'ipv6') == '::1', 'bad source ipv6 2'
|
||||
|
||||
self.client_ip({'header': 'X-Forwarded-For', 'source': '!127.0.0.1'})
|
||||
client_ip({'header': 'X-Forwarded-For', 'source': '!127.0.0.1'})
|
||||
|
||||
assert self.get_xff('1.1.1.1') == '127.0.0.1', 'bad source 3'
|
||||
assert self.get_xff('1.1.1.1', 'ipv6') == '1.1.1.1', 'replace 2'
|
||||
assert get_xff('1.1.1.1') == '127.0.0.1', 'bad source 3'
|
||||
assert get_xff('1.1.1.1', 'ipv6') == '1.1.1.1', 'replace 2'
|
||||
|
||||
def test_client_ip_ipv4(self):
|
||||
self.client_ip({'header': 'X-Forwarded-For', 'source': '127.0.0.1'})
|
||||
|
||||
def test_client_ip_ipv4():
|
||||
client_ip({'header': 'X-Forwarded-For', 'source': '127.0.0.1'})
|
||||
|
||||
assert get_xff('8.8.8.8, 84.23.23.11') == '84.23.23.11', 'xff replace'
|
||||
assert (
|
||||
self.get_xff('8.8.8.8, 84.23.23.11') == '84.23.23.11'
|
||||
), 'xff replace'
|
||||
assert (
|
||||
self.get_xff('8.8.8.8, 84.23.23.11, 127.0.0.1') == '127.0.0.1'
|
||||
get_xff('8.8.8.8, 84.23.23.11, 127.0.0.1') == '127.0.0.1'
|
||||
), 'xff replace 2'
|
||||
assert (
|
||||
self.get_xff(['8.8.8.8', '127.0.0.1, 10.0.1.1']) == '10.0.1.1'
|
||||
get_xff(['8.8.8.8', '127.0.0.1, 10.0.1.1']) == '10.0.1.1'
|
||||
), 'xff replace multi'
|
||||
|
||||
def test_client_ip_ipv6(self):
|
||||
self.client_ip({'header': 'X-Forwarded-For', 'source': '::1'})
|
||||
|
||||
assert self.get_xff('1.1.1.1') == '127.0.0.1', 'bad source ipv4'
|
||||
def test_client_ip_ipv6():
|
||||
client_ip({'header': 'X-Forwarded-For', 'source': '::1'})
|
||||
|
||||
assert get_xff('1.1.1.1') == '127.0.0.1', 'bad source ipv4'
|
||||
|
||||
for ip in [
|
||||
'f607:7403:1e4b:6c66:33b2:843f:2517:da27',
|
||||
|
@ -96,22 +98,24 @@ class TestClientIP(TestApplicationPython):
|
|||
'2001::3c4d:15:1a2f:1a2b',
|
||||
'::11.22.33.44',
|
||||
]:
|
||||
assert self.get_xff(ip, 'ipv6') == ip, 'replace'
|
||||
assert get_xff(ip, 'ipv6') == ip, 'replace'
|
||||
|
||||
def test_client_ip_unix(self):
|
||||
self.client_ip({'header': 'X-Forwarded-For', 'source': 'unix'})
|
||||
|
||||
assert self.get_xff('1.1.1.1') == '127.0.0.1', 'bad source ipv4'
|
||||
assert self.get_xff('1.1.1.1', 'ipv6') == '::1', 'bad source ipv6'
|
||||
def test_client_ip_unix():
|
||||
client_ip({'header': 'X-Forwarded-For', 'source': 'unix'})
|
||||
|
||||
assert get_xff('1.1.1.1') == '127.0.0.1', 'bad source ipv4'
|
||||
assert get_xff('1.1.1.1', 'ipv6') == '::1', 'bad source ipv6'
|
||||
|
||||
for ip in [
|
||||
'1.1.1.1',
|
||||
'::11.22.33.44',
|
||||
]:
|
||||
assert self.get_xff(ip, 'unix') == ip, 'replace'
|
||||
assert get_xff(ip, 'unix') == ip, 'replace'
|
||||
|
||||
def test_client_ip_recursive(self):
|
||||
self.client_ip(
|
||||
|
||||
def test_client_ip_recursive():
|
||||
client_ip(
|
||||
{
|
||||
'header': 'X-Forwarded-For',
|
||||
'recursive': True,
|
||||
|
@ -119,42 +123,41 @@ class TestClientIP(TestApplicationPython):
|
|||
}
|
||||
)
|
||||
|
||||
assert self.get_xff('1.1.1.1') == '1.1.1.1', 'xff chain'
|
||||
assert self.get_xff('1.1.1.1, 10.5.2.1') == '1.1.1.1', 'xff chain 2'
|
||||
assert get_xff('1.1.1.1') == '1.1.1.1', 'xff chain'
|
||||
assert get_xff('1.1.1.1, 10.5.2.1') == '1.1.1.1', 'xff chain 2'
|
||||
assert get_xff('8.8.8.8, 1.1.1.1, 10.5.2.1') == '1.1.1.1', 'xff chain 3'
|
||||
assert (
|
||||
self.get_xff('8.8.8.8, 1.1.1.1, 10.5.2.1') == '1.1.1.1'
|
||||
), 'xff chain 3'
|
||||
assert (
|
||||
self.get_xff('10.50.0.17, 10.5.2.1, 10.5.2.1') == '10.50.0.17'
|
||||
get_xff('10.50.0.17, 10.5.2.1, 10.5.2.1') == '10.50.0.17'
|
||||
), 'xff chain 4'
|
||||
assert (
|
||||
self.get_xff(['8.8.8.8', '1.1.1.1, 127.0.0.1']) == '1.1.1.1'
|
||||
get_xff(['8.8.8.8', '1.1.1.1, 127.0.0.1']) == '1.1.1.1'
|
||||
), 'xff replace multi'
|
||||
assert (
|
||||
self.get_xff(['8.8.8.8', '1.1.1.1, 127.0.0.1', '10.5.2.1'])
|
||||
== '1.1.1.1'
|
||||
get_xff(['8.8.8.8', '1.1.1.1, 127.0.0.1', '10.5.2.1']) == '1.1.1.1'
|
||||
), 'xff replace multi 2'
|
||||
assert (
|
||||
self.get_xff(['10.5.2.1', '10.50.0.17, 1.1.1.1', '10.5.2.1'])
|
||||
== '1.1.1.1'
|
||||
get_xff(['10.5.2.1', '10.50.0.17, 1.1.1.1', '10.5.2.1']) == '1.1.1.1'
|
||||
), 'xff replace multi 3'
|
||||
assert (
|
||||
self.get_xff('8.8.8.8, 2001:db8:3c4d:15::1a2f:1a2b, 127.0.0.1')
|
||||
get_xff('8.8.8.8, 2001:db8:3c4d:15::1a2f:1a2b, 127.0.0.1')
|
||||
== '2001:db8:3c4d:15::1a2f:1a2b'
|
||||
), 'xff chain ipv6'
|
||||
|
||||
def test_client_ip_case_insensitive(self):
|
||||
self.client_ip({'header': 'x-forwarded-for', 'source': '127.0.0.1'})
|
||||
|
||||
assert self.get_xff('1.1.1.1') == '1.1.1.1', 'case insensitive'
|
||||
def test_client_ip_case_insensitive():
|
||||
client_ip({'header': 'x-forwarded-for', 'source': '127.0.0.1'})
|
||||
|
||||
def test_client_ip_empty_source(self):
|
||||
self.client_ip({'header': 'X-Forwarded-For', 'source': []})
|
||||
assert get_xff('1.1.1.1') == '1.1.1.1', 'case insensitive'
|
||||
|
||||
assert self.get_xff('1.1.1.1') == '127.0.0.1', 'empty source'
|
||||
|
||||
def test_client_ip_invalid(self):
|
||||
assert 'error' in self.conf(
|
||||
def test_client_ip_empty_source():
|
||||
client_ip({'header': 'X-Forwarded-For', 'source': []})
|
||||
|
||||
assert get_xff('1.1.1.1') == '127.0.0.1', 'empty source'
|
||||
|
||||
|
||||
def test_client_ip_invalid():
|
||||
assert 'error' in client.conf(
|
||||
{
|
||||
"127.0.0.1:7081": {
|
||||
"client_ip": {"source": '127.0.0.1'},
|
||||
|
@ -165,7 +168,7 @@ class TestClientIP(TestApplicationPython):
|
|||
), 'invalid header'
|
||||
|
||||
def check_invalid_source(source):
|
||||
assert 'error' in self.conf(
|
||||
assert 'error' in client.conf(
|
||||
{
|
||||
"127.0.0.1:7081": {
|
||||
"client_ip": {
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
import socket
|
||||
|
||||
import pytest
|
||||
from unit.control import TestControl
|
||||
from unit.control import Control
|
||||
|
||||
prerequisites = {'modules': {'python': 'any'}}
|
||||
|
||||
client = Control()
|
||||
|
||||
class TestConfiguration(TestControl):
|
||||
def try_addr(self, addr):
|
||||
return self.conf(
|
||||
|
||||
def try_addr(addr):
|
||||
return client.conf(
|
||||
{
|
||||
"listeners": {addr: {"pass": "routes"}},
|
||||
"routes": [{"action": {"return": 200}}],
|
||||
|
@ -16,14 +17,17 @@ class TestConfiguration(TestControl):
|
|||
}
|
||||
)
|
||||
|
||||
def test_json_empty(self):
|
||||
assert 'error' in self.conf(''), 'empty'
|
||||
|
||||
def test_json_leading_zero(self):
|
||||
assert 'error' in self.conf('00'), 'leading zero'
|
||||
def test_json_empty():
|
||||
assert 'error' in client.conf(''), 'empty'
|
||||
|
||||
def test_json_unicode(self):
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def test_json_leading_zero():
|
||||
assert 'error' in client.conf('00'), 'leading zero'
|
||||
|
||||
|
||||
def test_json_unicode():
|
||||
assert 'success' in client.conf(
|
||||
"""
|
||||
{
|
||||
"ap\u0070": {
|
||||
|
@ -37,7 +41,7 @@ class TestConfiguration(TestControl):
|
|||
'applications',
|
||||
), 'unicode'
|
||||
|
||||
assert self.conf_get('applications') == {
|
||||
assert client.conf_get('applications') == {
|
||||
"app": {
|
||||
"type": "python",
|
||||
"processes": {"spare": 0},
|
||||
|
@ -46,8 +50,9 @@ class TestConfiguration(TestControl):
|
|||
}
|
||||
}, 'unicode get'
|
||||
|
||||
def test_json_unicode_2(self):
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def test_json_unicode_2():
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"приложение": {
|
||||
"type": "python",
|
||||
|
@ -59,10 +64,11 @@ class TestConfiguration(TestControl):
|
|||
'applications',
|
||||
), 'unicode 2'
|
||||
|
||||
assert 'приложение' in self.conf_get('applications'), 'unicode 2 get'
|
||||
assert 'приложение' in client.conf_get('applications')
|
||||
|
||||
def test_json_unicode_number(self):
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def test_json_unicode_number():
|
||||
assert 'success' in client.conf(
|
||||
"""
|
||||
{
|
||||
"app": {
|
||||
|
@ -76,8 +82,9 @@ class TestConfiguration(TestControl):
|
|||
'applications',
|
||||
), 'unicode number'
|
||||
|
||||
def test_json_utf8_bom(self):
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def test_json_utf8_bom():
|
||||
assert 'success' in client.conf(
|
||||
b"""\xEF\xBB\xBF
|
||||
{
|
||||
"app": {
|
||||
|
@ -91,8 +98,9 @@ class TestConfiguration(TestControl):
|
|||
'applications',
|
||||
), 'UTF-8 BOM'
|
||||
|
||||
def test_json_comment_single_line(self):
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def test_json_comment_single_line():
|
||||
assert 'success' in client.conf(
|
||||
b"""
|
||||
// this is bridge
|
||||
{
|
||||
|
@ -110,8 +118,9 @@ class TestConfiguration(TestControl):
|
|||
'applications',
|
||||
), 'single line comments'
|
||||
|
||||
def test_json_comment_multi_line(self):
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def test_json_comment_multi_line():
|
||||
assert 'success' in client.conf(
|
||||
b"""
|
||||
/* this is bridge */
|
||||
{
|
||||
|
@ -133,27 +142,32 @@ class TestConfiguration(TestControl):
|
|||
'applications',
|
||||
), 'multi line comments'
|
||||
|
||||
def test_json_comment_invalid(self):
|
||||
assert 'error' in self.conf(b'/{}', 'applications'), 'slash'
|
||||
assert 'error' in self.conf(b'//{}', 'applications'), 'comment'
|
||||
assert 'error' in self.conf(b'{} /', 'applications'), 'slash end'
|
||||
assert 'error' in self.conf(b'/*{}', 'applications'), 'slash star'
|
||||
assert 'error' in self.conf(b'{} /*', 'applications'), 'slash star end'
|
||||
|
||||
def test_applications_open_brace(self):
|
||||
assert 'error' in self.conf('{', 'applications'), 'open brace'
|
||||
def test_json_comment_invalid():
|
||||
assert 'error' in client.conf(b'/{}', 'applications'), 'slash'
|
||||
assert 'error' in client.conf(b'//{}', 'applications'), 'comment'
|
||||
assert 'error' in client.conf(b'{} /', 'applications'), 'slash end'
|
||||
assert 'error' in client.conf(b'/*{}', 'applications'), 'slash star'
|
||||
assert 'error' in client.conf(b'{} /*', 'applications'), 'slash star end'
|
||||
|
||||
|
||||
def test_applications_open_brace():
|
||||
assert 'error' in client.conf('{', 'applications'), 'open brace'
|
||||
|
||||
|
||||
def test_applications_string():
|
||||
assert 'error' in client.conf('"{}"', 'applications'), 'string'
|
||||
|
||||
def test_applications_string(self):
|
||||
assert 'error' in self.conf('"{}"', 'applications'), 'string'
|
||||
|
||||
@pytest.mark.skip('not yet, unsafe')
|
||||
def test_applications_type_only(self):
|
||||
assert 'error' in self.conf(
|
||||
def test_applications_type_only():
|
||||
assert 'error' in client.conf(
|
||||
{"app": {"type": "python"}}, 'applications'
|
||||
), 'type only'
|
||||
|
||||
def test_applications_miss_quote(self):
|
||||
assert 'error' in self.conf(
|
||||
|
||||
def test_applications_miss_quote():
|
||||
assert 'error' in client.conf(
|
||||
"""
|
||||
{
|
||||
app": {
|
||||
|
@ -167,8 +181,9 @@ class TestConfiguration(TestControl):
|
|||
'applications',
|
||||
), 'miss quote'
|
||||
|
||||
def test_applications_miss_colon(self):
|
||||
assert 'error' in self.conf(
|
||||
|
||||
def test_applications_miss_colon():
|
||||
assert 'error' in client.conf(
|
||||
"""
|
||||
{
|
||||
"app" {
|
||||
|
@ -182,8 +197,9 @@ class TestConfiguration(TestControl):
|
|||
'applications',
|
||||
), 'miss colon'
|
||||
|
||||
def test_applications_miss_comma(self):
|
||||
assert 'error' in self.conf(
|
||||
|
||||
def test_applications_miss_comma():
|
||||
assert 'error' in client.conf(
|
||||
"""
|
||||
{
|
||||
"app": {
|
||||
|
@ -197,13 +213,13 @@ class TestConfiguration(TestControl):
|
|||
'applications',
|
||||
), 'miss comma'
|
||||
|
||||
def test_applications_skip_spaces(self):
|
||||
assert 'success' in self.conf(
|
||||
b'{ \n\r\t}', 'applications'
|
||||
), 'skip spaces'
|
||||
|
||||
def test_applications_relative_path(self):
|
||||
assert 'success' in self.conf(
|
||||
def test_applications_skip_spaces():
|
||||
assert 'success' in client.conf(b'{ \n\r\t}', 'applications'), 'skip spaces'
|
||||
|
||||
|
||||
def test_applications_relative_path():
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"app": {
|
||||
"type": "python",
|
||||
|
@ -215,55 +231,58 @@ class TestConfiguration(TestControl):
|
|||
'applications',
|
||||
), 'relative path'
|
||||
|
||||
@pytest.mark.skip('not yet, unsafe')
|
||||
def test_listeners_empty(self):
|
||||
assert 'error' in self.conf(
|
||||
{"*:7080": {}}, 'listeners'
|
||||
), 'listener empty'
|
||||
|
||||
def test_listeners_no_app(self):
|
||||
assert 'error' in self.conf(
|
||||
@pytest.mark.skip('not yet, unsafe')
|
||||
def test_listeners_empty():
|
||||
assert 'error' in client.conf({"*:7080": {}}, 'listeners'), 'listener empty'
|
||||
|
||||
|
||||
def test_listeners_no_app():
|
||||
assert 'error' in client.conf(
|
||||
{"*:7080": {"pass": "applications/app"}}, 'listeners'
|
||||
), 'listeners no app'
|
||||
|
||||
def test_listeners_unix_abstract(self, system):
|
||||
|
||||
def test_listeners_unix_abstract(system):
|
||||
if system != 'Linux':
|
||||
assert 'error' in self.try_addr("unix:@sock"), 'abstract at'
|
||||
assert 'error' in try_addr("unix:@sock"), 'abstract at'
|
||||
|
||||
pytest.skip('not yet')
|
||||
|
||||
assert 'error' in self.try_addr("unix:\0soc"), 'abstract \0'
|
||||
assert 'error' in self.try_addr("unix:\u0000soc"), 'abstract \0 unicode'
|
||||
assert 'error' in try_addr("unix:\0soc"), 'abstract \0'
|
||||
assert 'error' in try_addr("unix:\u0000soc"), 'abstract \0 unicode'
|
||||
|
||||
def test_listeners_addr(self):
|
||||
assert 'success' in self.try_addr("*:7080"), 'wildcard'
|
||||
assert 'success' in self.try_addr("127.0.0.1:7081"), 'explicit'
|
||||
assert 'success' in self.try_addr("[::1]:7082"), 'explicit ipv6'
|
||||
|
||||
def test_listeners_addr_error(self):
|
||||
assert 'error' in self.try_addr("127.0.0.1"), 'no port'
|
||||
def test_listeners_addr():
|
||||
assert 'success' in try_addr("*:7080"), 'wildcard'
|
||||
assert 'success' in try_addr("127.0.0.1:7081"), 'explicit'
|
||||
assert 'success' in try_addr("[::1]:7082"), 'explicit ipv6'
|
||||
|
||||
def test_listeners_addr_error_2(self, skip_alert):
|
||||
|
||||
def test_listeners_addr_error():
|
||||
assert 'error' in try_addr("127.0.0.1"), 'no port'
|
||||
|
||||
|
||||
def test_listeners_addr_error_2(skip_alert):
|
||||
skip_alert(r'bind.*failed', r'failed to apply new conf')
|
||||
|
||||
assert 'error' in self.try_addr(
|
||||
"[f607:7403:1e4b:6c66:33b2:843f:2517:da27]:7080"
|
||||
)
|
||||
assert 'error' in try_addr("[f607:7403:1e4b:6c66:33b2:843f:2517:da27]:7080")
|
||||
|
||||
def test_listeners_port_release(self):
|
||||
|
||||
def test_listeners_port_release():
|
||||
for _ in range(10):
|
||||
fail = False
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
|
||||
self.conf(
|
||||
client.conf(
|
||||
{
|
||||
"listeners": {"127.0.0.1:7080": {"pass": "routes"}},
|
||||
"routes": [],
|
||||
}
|
||||
)
|
||||
|
||||
resp = self.conf({"listeners": {}, "applications": {}})
|
||||
resp = client.conf({"listeners": {}, "applications": {}})
|
||||
|
||||
try:
|
||||
s.bind(('127.0.0.1', 7080))
|
||||
|
@ -277,10 +296,11 @@ class TestConfiguration(TestControl):
|
|||
|
||||
assert 'success' in resp, 'port release'
|
||||
|
||||
def test_json_application_name_large(self):
|
||||
|
||||
def test_json_application_name_large():
|
||||
name = "X" * 1024 * 1024
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": f"applications/{name}"}},
|
||||
"applications": {
|
||||
|
@ -294,8 +314,9 @@ class TestConfiguration(TestControl):
|
|||
}
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_json_application_many(self):
|
||||
def test_json_application_many():
|
||||
apps = 999
|
||||
|
||||
conf = {
|
||||
|
@ -314,9 +335,10 @@ class TestConfiguration(TestControl):
|
|||
},
|
||||
}
|
||||
|
||||
assert 'success' in self.conf(conf)
|
||||
assert 'success' in client.conf(conf)
|
||||
|
||||
def test_json_application_python_prefix(self):
|
||||
|
||||
def test_json_application_python_prefix():
|
||||
conf = {
|
||||
"applications": {
|
||||
"sub-app": {
|
||||
|
@ -336,9 +358,10 @@ class TestConfiguration(TestControl):
|
|||
],
|
||||
}
|
||||
|
||||
assert 'success' in self.conf(conf)
|
||||
assert 'success' in client.conf(conf)
|
||||
|
||||
def test_json_application_prefix_target(self):
|
||||
|
||||
def test_json_application_prefix_target():
|
||||
conf = {
|
||||
"applications": {
|
||||
"sub-app": {
|
||||
|
@ -368,9 +391,10 @@ class TestConfiguration(TestControl):
|
|||
],
|
||||
}
|
||||
|
||||
assert 'success' in self.conf(conf)
|
||||
assert 'success' in client.conf(conf)
|
||||
|
||||
def test_json_application_invalid_python_prefix(self):
|
||||
|
||||
def test_json_application_invalid_python_prefix():
|
||||
conf = {
|
||||
"applications": {
|
||||
"sub-app": {
|
||||
|
@ -384,9 +408,10 @@ class TestConfiguration(TestControl):
|
|||
"listeners": {"*:7080": {"pass": "applications/sub-app"}},
|
||||
}
|
||||
|
||||
assert 'error' in self.conf(conf)
|
||||
assert 'error' in client.conf(conf)
|
||||
|
||||
def test_json_application_empty_python_prefix(self):
|
||||
|
||||
def test_json_application_empty_python_prefix():
|
||||
conf = {
|
||||
"applications": {
|
||||
"sub-app": {
|
||||
|
@ -400,9 +425,10 @@ class TestConfiguration(TestControl):
|
|||
"listeners": {"*:7080": {"pass": "applications/sub-app"}},
|
||||
}
|
||||
|
||||
assert 'error' in self.conf(conf)
|
||||
assert 'error' in client.conf(conf)
|
||||
|
||||
def test_json_application_many2(self):
|
||||
|
||||
def test_json_application_many2():
|
||||
conf = {
|
||||
"applications": {
|
||||
f"app-{a}": {
|
||||
|
@ -418,14 +444,15 @@ class TestConfiguration(TestControl):
|
|||
"listeners": {"*:7080": {"pass": "applications/app-1"}},
|
||||
}
|
||||
|
||||
assert 'success' in self.conf(conf)
|
||||
assert 'success' in client.conf(conf)
|
||||
|
||||
def test_unprivileged_user_error(self, require, skip_alert):
|
||||
|
||||
def test_unprivileged_user_error(require, skip_alert):
|
||||
require({'privileged_user': False})
|
||||
|
||||
skip_alert(r'cannot set user "root"', r'failed to apply new conf')
|
||||
|
||||
assert 'error' in self.conf(
|
||||
assert 'error' in client.conf(
|
||||
{
|
||||
"app": {
|
||||
"type": "external",
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
import pytest
|
||||
from unit.applications.lang.python import TestApplicationPython
|
||||
from unit.applications.lang.python import ApplicationPython
|
||||
|
||||
prerequisites = {'modules': {'python': 'any'}}
|
||||
|
||||
client = ApplicationPython()
|
||||
|
||||
|
||||
class TestForwardedHeader(TestApplicationPython):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_method_fixture(self):
|
||||
self.load('forwarded_header')
|
||||
def setup_method_fixture():
|
||||
client.load('forwarded_header')
|
||||
|
||||
def forwarded_header(self, forwarded):
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def forwarded_header(forwarded):
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"127.0.0.1:7081": {
|
||||
"forwarded": forwarded,
|
||||
|
@ -24,7 +26,8 @@ class TestForwardedHeader(TestApplicationPython):
|
|||
'listeners',
|
||||
), 'listeners configure'
|
||||
|
||||
def get_fwd(self, sock_type='ipv4', xff=None, xfp=None):
|
||||
|
||||
def get_fwd(sock_type='ipv4', xff=None, xfp=None):
|
||||
port = 7081 if sock_type == 'ipv4' else 7082
|
||||
|
||||
headers = {'Connection': 'close'}
|
||||
|
@ -35,18 +38,21 @@ class TestForwardedHeader(TestApplicationPython):
|
|||
if xfp is not None:
|
||||
headers['X-Forwarded-Proto'] = xfp
|
||||
|
||||
return self.get(sock_type=sock_type, port=port, headers=headers)[
|
||||
return client.get(sock_type=sock_type, port=port, headers=headers)[
|
||||
'headers'
|
||||
]
|
||||
|
||||
def get_addr(self, *args, **kwargs):
|
||||
return self.get_fwd(*args, **kwargs)['Remote-Addr']
|
||||
|
||||
def get_scheme(self, *args, **kwargs):
|
||||
return self.get_fwd(*args, **kwargs)['Url-Scheme']
|
||||
def get_addr(*args, **kwargs):
|
||||
return get_fwd(*args, **kwargs)['Remote-Addr']
|
||||
|
||||
def test_forwarded_header_single_ip(self):
|
||||
self.forwarded_header(
|
||||
|
||||
def get_scheme(*args, **kwargs):
|
||||
return get_fwd(*args, **kwargs)['Url-Scheme']
|
||||
|
||||
|
||||
def test_forwarded_header_single_ip():
|
||||
forwarded_header(
|
||||
{
|
||||
'client_ip': 'X-Forwarded-For',
|
||||
'protocol': 'X-Forwarded-Proto',
|
||||
|
@ -54,23 +60,23 @@ class TestForwardedHeader(TestApplicationPython):
|
|||
}
|
||||
)
|
||||
|
||||
resp = self.get_fwd(xff='1.1.1.1', xfp='https')
|
||||
resp = get_fwd(xff='1.1.1.1', xfp='https')
|
||||
assert resp['Remote-Addr'] == '127.0.0.1', 'both headers addr'
|
||||
assert resp['Url-Scheme'] == 'http', 'both headers proto'
|
||||
|
||||
assert self.get_addr() == '127.0.0.1', 'ipv4 default addr'
|
||||
assert self.get_addr('ipv6') == '::1', 'ipv6 default addr'
|
||||
assert self.get_addr(xff='1.1.1.1') == '127.0.0.1', 'bad source'
|
||||
assert self.get_addr(xff='blah') == '127.0.0.1', 'bad xff'
|
||||
assert self.get_addr('ipv6', '1.1.1.1') == '::1', 'bad source ipv6'
|
||||
assert get_addr() == '127.0.0.1', 'ipv4 default addr'
|
||||
assert get_addr('ipv6') == '::1', 'ipv6 default addr'
|
||||
assert get_addr(xff='1.1.1.1') == '127.0.0.1', 'bad source'
|
||||
assert get_addr(xff='blah') == '127.0.0.1', 'bad xff'
|
||||
assert get_addr('ipv6', '1.1.1.1') == '::1', 'bad source ipv6'
|
||||
|
||||
assert self.get_scheme() == 'http', 'ipv4 default proto'
|
||||
assert self.get_scheme('ipv6') == 'http', 'ipv6 default proto'
|
||||
assert self.get_scheme(xfp='https') == 'http', 'bad proto'
|
||||
assert self.get_scheme(xfp='blah') == 'http', 'bad xfp'
|
||||
assert self.get_scheme('ipv6', xfp='https') == 'http', 'bad proto ipv6'
|
||||
assert get_scheme() == 'http', 'ipv4 default proto'
|
||||
assert get_scheme('ipv6') == 'http', 'ipv6 default proto'
|
||||
assert get_scheme(xfp='https') == 'http', 'bad proto'
|
||||
assert get_scheme(xfp='blah') == 'http', 'bad xfp'
|
||||
assert get_scheme('ipv6', xfp='https') == 'http', 'bad proto ipv6'
|
||||
|
||||
self.forwarded_header(
|
||||
forwarded_header(
|
||||
{
|
||||
'client_ip': 'X-Forwarded-For',
|
||||
'protocol': 'X-Forwarded-Proto',
|
||||
|
@ -78,24 +84,22 @@ class TestForwardedHeader(TestApplicationPython):
|
|||
}
|
||||
)
|
||||
|
||||
resp = self.get_fwd(xff='1.1.1.1', xfp='https')
|
||||
resp = get_fwd(xff='1.1.1.1', xfp='https')
|
||||
assert resp['Remote-Addr'] == '1.1.1.1', 'both headers addr 2'
|
||||
assert resp['Url-Scheme'] == 'https', 'both headers proto 2'
|
||||
|
||||
assert self.get_addr() == '127.0.0.1', 'ipv4 default addr 2'
|
||||
assert self.get_addr('ipv6') == '::1', 'ipv6 default addr 2'
|
||||
assert self.get_addr(xff='1.1.1.1') == '1.1.1.1', 'xff replace'
|
||||
assert self.get_addr('ipv6', '1.1.1.1') == '::1', 'bad source ipv6 2'
|
||||
assert get_addr() == '127.0.0.1', 'ipv4 default addr 2'
|
||||
assert get_addr('ipv6') == '::1', 'ipv6 default addr 2'
|
||||
assert get_addr(xff='1.1.1.1') == '1.1.1.1', 'xff replace'
|
||||
assert get_addr('ipv6', '1.1.1.1') == '::1', 'bad source ipv6 2'
|
||||
|
||||
assert self.get_scheme() == 'http', 'ipv4 default proto 2'
|
||||
assert self.get_scheme('ipv6') == 'http', 'ipv6 default proto 2'
|
||||
assert self.get_scheme(xfp='https') == 'https', 'xfp replace'
|
||||
assert self.get_scheme(xfp='on') == 'https', 'xfp replace 2'
|
||||
assert (
|
||||
self.get_scheme('ipv6', xfp='https') == 'http'
|
||||
), 'bad proto ipv6 2'
|
||||
assert get_scheme() == 'http', 'ipv4 default proto 2'
|
||||
assert get_scheme('ipv6') == 'http', 'ipv6 default proto 2'
|
||||
assert get_scheme(xfp='https') == 'https', 'xfp replace'
|
||||
assert get_scheme(xfp='on') == 'https', 'xfp replace 2'
|
||||
assert get_scheme('ipv6', xfp='https') == 'http', 'bad proto ipv6 2'
|
||||
|
||||
self.forwarded_header(
|
||||
forwarded_header(
|
||||
{
|
||||
'client_ip': 'X-Forwarded-For',
|
||||
'protocol': 'X-Forwarded-Proto',
|
||||
|
@ -103,13 +107,14 @@ class TestForwardedHeader(TestApplicationPython):
|
|||
}
|
||||
)
|
||||
|
||||
assert self.get_addr(xff='1.1.1.1') == '127.0.0.1', 'bad source 3'
|
||||
assert self.get_addr('ipv6', '1.1.1.1') == '1.1.1.1', 'xff replace 2'
|
||||
assert self.get_scheme(xfp='https') == 'http', 'bad proto 2'
|
||||
assert self.get_scheme('ipv6', xfp='https') == 'https', 'xfp replace 3'
|
||||
assert get_addr(xff='1.1.1.1') == '127.0.0.1', 'bad source 3'
|
||||
assert get_addr('ipv6', '1.1.1.1') == '1.1.1.1', 'xff replace 2'
|
||||
assert get_scheme(xfp='https') == 'http', 'bad proto 2'
|
||||
assert get_scheme('ipv6', xfp='https') == 'https', 'xfp replace 3'
|
||||
|
||||
def test_forwarded_header_ipv4(self):
|
||||
self.forwarded_header(
|
||||
|
||||
def test_forwarded_header_ipv4():
|
||||
forwarded_header(
|
||||
{
|
||||
'client_ip': 'X-Forwarded-For',
|
||||
'protocol': 'X-Forwarded-Proto',
|
||||
|
@ -117,26 +122,23 @@ class TestForwardedHeader(TestApplicationPython):
|
|||
}
|
||||
)
|
||||
|
||||
assert get_addr(xff='8.8.8.8, 84.23.23.11') == '84.23.23.11', 'xff replace'
|
||||
assert (
|
||||
self.get_addr(xff='8.8.8.8, 84.23.23.11') == '84.23.23.11'
|
||||
), 'xff replace'
|
||||
assert (
|
||||
self.get_addr(xff='8.8.8.8, 84.23.23.11, 127.0.0.1') == '127.0.0.1'
|
||||
get_addr(xff='8.8.8.8, 84.23.23.11, 127.0.0.1') == '127.0.0.1'
|
||||
), 'xff replace 2'
|
||||
assert (
|
||||
self.get_addr(xff=['8.8.8.8', '127.0.0.1, 10.0.1.1']) == '10.0.1.1'
|
||||
get_addr(xff=['8.8.8.8', '127.0.0.1, 10.0.1.1']) == '10.0.1.1'
|
||||
), 'xff replace multi'
|
||||
|
||||
assert self.get_scheme(xfp='http, https') == 'http', 'xfp replace'
|
||||
assert get_scheme(xfp='http, https') == 'http', 'xfp replace'
|
||||
assert get_scheme(xfp='http, https, http') == 'http', 'xfp replace 2'
|
||||
assert (
|
||||
self.get_scheme(xfp='http, https, http') == 'http'
|
||||
), 'xfp replace 2'
|
||||
assert (
|
||||
self.get_scheme(xfp=['http, https', 'http', 'https']) == 'http'
|
||||
get_scheme(xfp=['http, https', 'http', 'https']) == 'http'
|
||||
), 'xfp replace multi'
|
||||
|
||||
def test_forwarded_header_ipv6(self):
|
||||
self.forwarded_header(
|
||||
|
||||
def test_forwarded_header_ipv6():
|
||||
forwarded_header(
|
||||
{
|
||||
'client_ip': 'X-Forwarded-For',
|
||||
'protocol': 'X-Forwarded-Proto',
|
||||
|
@ -144,7 +146,7 @@ class TestForwardedHeader(TestApplicationPython):
|
|||
}
|
||||
)
|
||||
|
||||
assert self.get_addr(xff='1.1.1.1') == '127.0.0.1', 'bad source ipv4'
|
||||
assert get_addr(xff='1.1.1.1') == '127.0.0.1', 'bad source ipv4'
|
||||
|
||||
for ip in [
|
||||
'f607:7403:1e4b:6c66:33b2:843f:2517:da27',
|
||||
|
@ -152,15 +154,16 @@ class TestForwardedHeader(TestApplicationPython):
|
|||
'2001::3c4d:15:1a2f:1a2b',
|
||||
'::11.22.33.44',
|
||||
]:
|
||||
assert self.get_addr('ipv6', ip) == ip, 'replace'
|
||||
assert get_addr('ipv6', ip) == ip, 'replace'
|
||||
|
||||
assert self.get_scheme(xfp='https') == 'http', 'bad source ipv4'
|
||||
assert get_scheme(xfp='https') == 'http', 'bad source ipv4'
|
||||
|
||||
for proto in ['http', 'https']:
|
||||
assert self.get_scheme('ipv6', xfp=proto) == proto, 'replace'
|
||||
assert get_scheme('ipv6', xfp=proto) == proto, 'replace'
|
||||
|
||||
def test_forwarded_header_recursive(self):
|
||||
self.forwarded_header(
|
||||
|
||||
def test_forwarded_header_recursive():
|
||||
forwarded_header(
|
||||
{
|
||||
'client_ip': 'X-Forwarded-For',
|
||||
'recursive': True,
|
||||
|
@ -168,34 +171,32 @@ class TestForwardedHeader(TestApplicationPython):
|
|||
}
|
||||
)
|
||||
|
||||
assert self.get_addr(xff='1.1.1.1') == '1.1.1.1', 'xff chain'
|
||||
assert get_addr(xff='1.1.1.1') == '1.1.1.1', 'xff chain'
|
||||
assert get_addr(xff='1.1.1.1, 10.5.2.1') == '1.1.1.1', 'xff chain 2'
|
||||
assert (
|
||||
self.get_addr(xff='1.1.1.1, 10.5.2.1') == '1.1.1.1'
|
||||
), 'xff chain 2'
|
||||
assert (
|
||||
self.get_addr(xff='8.8.8.8, 1.1.1.1, 10.5.2.1') == '1.1.1.1'
|
||||
get_addr(xff='8.8.8.8, 1.1.1.1, 10.5.2.1') == '1.1.1.1'
|
||||
), 'xff chain 3'
|
||||
assert (
|
||||
self.get_addr(xff='10.50.0.17, 10.5.2.1, 10.5.2.1') == '10.50.0.17'
|
||||
get_addr(xff='10.50.0.17, 10.5.2.1, 10.5.2.1') == '10.50.0.17'
|
||||
), 'xff chain 4'
|
||||
assert (
|
||||
self.get_addr(xff=['8.8.8.8', '1.1.1.1, 127.0.0.1']) == '1.1.1.1'
|
||||
get_addr(xff=['8.8.8.8', '1.1.1.1, 127.0.0.1']) == '1.1.1.1'
|
||||
), 'xff replace multi'
|
||||
assert (
|
||||
self.get_addr(xff=['8.8.8.8', '1.1.1.1, 127.0.0.1', '10.5.2.1'])
|
||||
== '1.1.1.1'
|
||||
get_addr(xff=['8.8.8.8', '1.1.1.1, 127.0.0.1', '10.5.2.1']) == '1.1.1.1'
|
||||
), 'xff replace multi 2'
|
||||
assert (
|
||||
self.get_addr(xff=['10.5.2.1', '10.50.0.17, 1.1.1.1', '10.5.2.1'])
|
||||
get_addr(xff=['10.5.2.1', '10.50.0.17, 1.1.1.1', '10.5.2.1'])
|
||||
== '1.1.1.1'
|
||||
), 'xff replace multi 3'
|
||||
assert (
|
||||
self.get_addr(xff='8.8.8.8, 2001:db8:3c4d:15::1a2f:1a2b, 127.0.0.1')
|
||||
get_addr(xff='8.8.8.8, 2001:db8:3c4d:15::1a2f:1a2b, 127.0.0.1')
|
||||
== '2001:db8:3c4d:15::1a2f:1a2b'
|
||||
), 'xff chain ipv6'
|
||||
|
||||
def test_forwarded_header_case_insensitive(self):
|
||||
self.forwarded_header(
|
||||
|
||||
def test_forwarded_header_case_insensitive():
|
||||
forwarded_header(
|
||||
{
|
||||
'client_ip': 'x-forwarded-for',
|
||||
'protocol': 'x-forwarded-proto',
|
||||
|
@ -203,17 +204,18 @@ class TestForwardedHeader(TestApplicationPython):
|
|||
}
|
||||
)
|
||||
|
||||
assert self.get_addr() == '127.0.0.1', 'ipv4 default addr'
|
||||
assert self.get_addr('ipv6') == '::1', 'ipv6 default addr'
|
||||
assert self.get_addr(xff='1.1.1.1') == '1.1.1.1', 'replace'
|
||||
assert get_addr() == '127.0.0.1', 'ipv4 default addr'
|
||||
assert get_addr('ipv6') == '::1', 'ipv6 default addr'
|
||||
assert get_addr(xff='1.1.1.1') == '1.1.1.1', 'replace'
|
||||
|
||||
assert self.get_scheme() == 'http', 'ipv4 default proto'
|
||||
assert self.get_scheme('ipv6') == 'http', 'ipv6 default proto'
|
||||
assert self.get_scheme(xfp='https') == 'https', 'replace 1'
|
||||
assert self.get_scheme(xfp='oN') == 'https', 'replace 2'
|
||||
assert get_scheme() == 'http', 'ipv4 default proto'
|
||||
assert get_scheme('ipv6') == 'http', 'ipv6 default proto'
|
||||
assert get_scheme(xfp='https') == 'https', 'replace 1'
|
||||
assert get_scheme(xfp='oN') == 'https', 'replace 2'
|
||||
|
||||
def test_forwarded_header_source_empty(self):
|
||||
self.forwarded_header(
|
||||
|
||||
def test_forwarded_header_source_empty():
|
||||
forwarded_header(
|
||||
{
|
||||
'client_ip': 'X-Forwarded-For',
|
||||
'protocol': 'X-Forwarded-Proto',
|
||||
|
@ -221,11 +223,12 @@ class TestForwardedHeader(TestApplicationPython):
|
|||
}
|
||||
)
|
||||
|
||||
assert self.get_addr(xff='1.1.1.1') == '127.0.0.1', 'empty source xff'
|
||||
assert self.get_scheme(xfp='https') == 'http', 'empty source xfp'
|
||||
assert get_addr(xff='1.1.1.1') == '127.0.0.1', 'empty source xff'
|
||||
assert get_scheme(xfp='https') == 'http', 'empty source xfp'
|
||||
|
||||
def test_forwarded_header_source_range(self):
|
||||
self.forwarded_header(
|
||||
|
||||
def test_forwarded_header_source_range():
|
||||
forwarded_header(
|
||||
{
|
||||
'client_ip': 'X-Forwarded-For',
|
||||
'protocol': 'X-Forwarded-Proto',
|
||||
|
@ -233,11 +236,12 @@ class TestForwardedHeader(TestApplicationPython):
|
|||
}
|
||||
)
|
||||
|
||||
assert self.get_addr(xff='1.1.1.1') == '1.1.1.1', 'source range'
|
||||
assert self.get_addr('ipv6', '1.1.1.1') == '::1', 'source range 2'
|
||||
assert get_addr(xff='1.1.1.1') == '1.1.1.1', 'source range'
|
||||
assert get_addr('ipv6', '1.1.1.1') == '::1', 'source range 2'
|
||||
|
||||
def test_forwarded_header_invalid(self):
|
||||
assert 'error' in self.conf(
|
||||
|
||||
def test_forwarded_header_invalid():
|
||||
assert 'error' in client.conf(
|
||||
{
|
||||
"127.0.0.1:7081": {
|
||||
"forwarded": {"source": '127.0.0.1'},
|
||||
|
@ -248,7 +252,7 @@ class TestForwardedHeader(TestApplicationPython):
|
|||
), 'invalid forward'
|
||||
|
||||
def check_invalid_source(source):
|
||||
assert 'error' in self.conf(
|
||||
assert 'error' in client.conf(
|
||||
{
|
||||
"127.0.0.1:7081": {
|
||||
"forwarded": {
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
import re
|
||||
|
||||
import pytest
|
||||
from unit.applications.lang.go import TestApplicationGo
|
||||
from unit.applications.lang.go import ApplicationGo
|
||||
|
||||
prerequisites = {'modules': {'go': 'all'}}
|
||||
|
||||
client = ApplicationGo()
|
||||
|
||||
class TestGoApplication(TestApplicationGo):
|
||||
def test_go_application_variables(self, date_to_sec_epoch, sec_epoch):
|
||||
self.load('variables')
|
||||
|
||||
def test_go_application_variables(date_to_sec_epoch, sec_epoch):
|
||||
client.load('variables')
|
||||
|
||||
body = 'Test body string.'
|
||||
|
||||
resp = self.post(
|
||||
resp = client.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Content-Type': 'text/html',
|
||||
|
@ -45,18 +45,20 @@ class TestGoApplication(TestApplicationGo):
|
|||
}, 'headers'
|
||||
assert resp['body'] == body, 'body'
|
||||
|
||||
def test_go_application_get_variables(self):
|
||||
self.load('get_variables')
|
||||
|
||||
resp = self.get(url='/?var1=val1&var2=&var3')
|
||||
def test_go_application_get_variables():
|
||||
client.load('get_variables')
|
||||
|
||||
resp = client.get(url='/?var1=val1&var2=&var3')
|
||||
assert resp['headers']['X-Var-1'] == 'val1', 'GET variables'
|
||||
assert resp['headers']['X-Var-2'] == '', 'GET variables 2'
|
||||
assert resp['headers']['X-Var-3'] == '', 'GET variables 3'
|
||||
|
||||
def test_go_application_post_variables(self):
|
||||
self.load('post_variables')
|
||||
|
||||
resp = self.post(
|
||||
def test_go_application_post_variables():
|
||||
client.load('post_variables')
|
||||
|
||||
resp = client.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
|
@ -69,23 +71,23 @@ class TestGoApplication(TestApplicationGo):
|
|||
assert resp['headers']['X-Var-2'] == '', 'POST variables 2'
|
||||
assert resp['headers']['X-Var-3'] == '', 'POST variables 3'
|
||||
|
||||
def test_go_application_404(self):
|
||||
self.load('404')
|
||||
|
||||
resp = self.get()
|
||||
def test_go_application_404():
|
||||
client.load('404')
|
||||
|
||||
resp = client.get()
|
||||
|
||||
assert resp['status'] == 404, '404 status'
|
||||
assert re.search(
|
||||
r'<title>404 Not Found</title>', resp['body']
|
||||
), '404 body'
|
||||
assert re.search(r'<title>404 Not Found</title>', resp['body']), '404 body'
|
||||
|
||||
def test_go_keepalive_body(self):
|
||||
self.load('mirror')
|
||||
|
||||
assert self.get()['status'] == 200, 'init'
|
||||
def test_go_keepalive_body():
|
||||
client.load('mirror')
|
||||
|
||||
assert client.get()['status'] == 200, 'init'
|
||||
|
||||
body = '0123456789' * 500
|
||||
(resp, sock) = self.post(
|
||||
(resp, sock) = client.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Connection': 'keep-alive',
|
||||
|
@ -98,13 +100,14 @@ class TestGoApplication(TestApplicationGo):
|
|||
assert resp['body'] == body, 'keep-alive 1'
|
||||
|
||||
body = '0123456789'
|
||||
resp = self.post(sock=sock, body=body)
|
||||
resp = client.post(sock=sock, body=body)
|
||||
assert resp['body'] == body, 'keep-alive 2'
|
||||
|
||||
def test_go_application_cookies(self):
|
||||
self.load('cookies')
|
||||
|
||||
resp = self.get(
|
||||
def test_go_application_cookies():
|
||||
client.load('cookies')
|
||||
|
||||
resp = client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Cookie': 'var1=val1; var2=val2',
|
||||
|
@ -115,47 +118,51 @@ class TestGoApplication(TestApplicationGo):
|
|||
assert resp['headers']['X-Cookie-1'] == 'val1', 'cookie 1'
|
||||
assert resp['headers']['X-Cookie-2'] == 'val2', 'cookie 2'
|
||||
|
||||
def test_go_application_command_line_arguments_type(self):
|
||||
self.load('command_line_arguments')
|
||||
|
||||
assert 'error' in self.conf(
|
||||
def test_go_application_command_line_arguments_type():
|
||||
client.load('command_line_arguments')
|
||||
|
||||
assert 'error' in client.conf(
|
||||
'' "a b c", 'applications/command_line_arguments/arguments'
|
||||
), 'arguments type'
|
||||
|
||||
def test_go_application_command_line_arguments_0(self):
|
||||
self.load('command_line_arguments')
|
||||
|
||||
assert self.get()['headers']['X-Arg-0'] == self.conf_get(
|
||||
def test_go_application_command_line_arguments_0():
|
||||
client.load('command_line_arguments')
|
||||
|
||||
assert client.get()['headers']['X-Arg-0'] == client.conf_get(
|
||||
'applications/command_line_arguments/executable'
|
||||
), 'argument 0'
|
||||
|
||||
def test_go_application_command_line_arguments(self):
|
||||
self.load('command_line_arguments')
|
||||
|
||||
def test_go_application_command_line_arguments():
|
||||
client.load('command_line_arguments')
|
||||
|
||||
arg1 = '--cc=gcc-7.2.0'
|
||||
arg2 = "--cc-opt='-O0 -DNXT_DEBUG_MEMORY=1 -fsanitize=address'"
|
||||
arg3 = '--debug'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
f'["{arg1}", "{arg2}", "{arg3}"]',
|
||||
'applications/command_line_arguments/arguments',
|
||||
)
|
||||
|
||||
assert self.get()['body'] == f'{arg1},{arg2},{arg3}', 'arguments'
|
||||
assert client.get()['body'] == f'{arg1},{arg2},{arg3}', 'arguments'
|
||||
|
||||
def test_go_application_command_line_arguments_change(self):
|
||||
self.load('command_line_arguments')
|
||||
|
||||
def test_go_application_command_line_arguments_change():
|
||||
client.load('command_line_arguments')
|
||||
|
||||
args_path = 'applications/command_line_arguments/arguments'
|
||||
|
||||
assert 'success' in self.conf('["0", "a", "$", ""]', args_path)
|
||||
assert 'success' in client.conf('["0", "a", "$", ""]', args_path)
|
||||
|
||||
assert self.get()['body'] == '0,a,$,', 'arguments'
|
||||
assert client.get()['body'] == '0,a,$,', 'arguments'
|
||||
|
||||
assert 'success' in self.conf('["-1", "b", "%"]', args_path)
|
||||
assert 'success' in client.conf('["-1", "b", "%"]', args_path)
|
||||
|
||||
assert self.get()['body'] == '-1,b,%', 'arguments change'
|
||||
assert client.get()['body'] == '-1,b,%', 'arguments change'
|
||||
|
||||
assert 'success' in self.conf('[]', args_path)
|
||||
assert 'success' in client.conf('[]', args_path)
|
||||
|
||||
assert self.get()['headers']['Content-Length'] == '0', 'arguments empty'
|
||||
assert client.get()['headers']['Content-Length'] == '0', 'arguments empty'
|
||||
|
|
|
@ -3,15 +3,16 @@ import os
|
|||
import pwd
|
||||
|
||||
import pytest
|
||||
from unit.applications.lang.go import TestApplicationGo
|
||||
from unit.applications.lang.go import ApplicationGo
|
||||
from unit.option import option
|
||||
from unit.utils import getns
|
||||
|
||||
prerequisites = {'modules': {'go': 'any'}, 'features': {'isolation': True}}
|
||||
|
||||
client = ApplicationGo()
|
||||
|
||||
class TestGoIsolation(TestApplicationGo):
|
||||
def unpriv_creds(self):
|
||||
|
||||
def unpriv_creds():
|
||||
nobody_uid = pwd.getpwnam('nobody').pw_uid
|
||||
|
||||
try:
|
||||
|
@ -23,16 +24,18 @@ class TestGoIsolation(TestApplicationGo):
|
|||
|
||||
return (nobody_uid, nogroup_gid, nogroup)
|
||||
|
||||
def test_isolation_values(self):
|
||||
self.load('ns_inspect')
|
||||
|
||||
obj = self.getjson()['body']
|
||||
def test_isolation_values():
|
||||
client.load('ns_inspect')
|
||||
|
||||
obj = client.getjson()['body']
|
||||
|
||||
for ns, ns_value in option.available['features']['isolation'].items():
|
||||
if ns.upper() in obj['NS']:
|
||||
assert obj['NS'][ns.upper()] == ns_value, f'{ns} match'
|
||||
|
||||
def test_isolation_unpriv_user(self, require):
|
||||
|
||||
def test_isolation_unpriv_user(require):
|
||||
require(
|
||||
{
|
||||
'privileged_user': False,
|
||||
|
@ -40,46 +43,46 @@ class TestGoIsolation(TestApplicationGo):
|
|||
}
|
||||
)
|
||||
|
||||
self.load('ns_inspect')
|
||||
obj = self.getjson()['body']
|
||||
client.load('ns_inspect')
|
||||
obj = client.getjson()['body']
|
||||
|
||||
assert obj['UID'] == os.geteuid(), 'uid match'
|
||||
assert obj['GID'] == os.getegid(), 'gid match'
|
||||
|
||||
self.load('ns_inspect', isolation={'namespaces': {'credential': True}})
|
||||
client.load('ns_inspect', isolation={'namespaces': {'credential': True}})
|
||||
|
||||
obj = self.getjson()['body']
|
||||
obj = client.getjson()['body']
|
||||
|
||||
nobody_uid, nogroup_gid, nogroup = self.unpriv_creds()
|
||||
nobody_uid, nogroup_gid, nogroup = unpriv_creds()
|
||||
|
||||
# unprivileged unit map itself to nobody in the container by default
|
||||
assert obj['UID'] == nobody_uid, 'uid of nobody'
|
||||
assert obj['GID'] == nogroup_gid, f'gid of {nogroup}'
|
||||
|
||||
self.load(
|
||||
client.load(
|
||||
'ns_inspect',
|
||||
user='root',
|
||||
isolation={'namespaces': {'credential': True}},
|
||||
)
|
||||
|
||||
obj = self.getjson()['body']
|
||||
obj = client.getjson()['body']
|
||||
|
||||
assert obj['UID'] == 0, 'uid match user=root'
|
||||
assert obj['GID'] == 0, 'gid match user=root'
|
||||
|
||||
self.load(
|
||||
client.load(
|
||||
'ns_inspect',
|
||||
user='root',
|
||||
group=nogroup,
|
||||
isolation={'namespaces': {'credential': True}},
|
||||
)
|
||||
|
||||
obj = self.getjson()['body']
|
||||
obj = client.getjson()['body']
|
||||
|
||||
assert obj['UID'] == 0, 'uid match user=root group=nogroup'
|
||||
assert obj['GID'] == nogroup_gid, 'gid match user=root group=nogroup'
|
||||
|
||||
self.load(
|
||||
client.load(
|
||||
'ns_inspect',
|
||||
user='root',
|
||||
group='root',
|
||||
|
@ -90,55 +93,56 @@ class TestGoIsolation(TestApplicationGo):
|
|||
},
|
||||
)
|
||||
|
||||
obj = self.getjson()['body']
|
||||
obj = client.getjson()['body']
|
||||
|
||||
assert obj['UID'] == 0, 'uid match uidmap'
|
||||
assert obj['GID'] == 0, 'gid match gidmap'
|
||||
|
||||
def test_isolation_priv_user(self, require):
|
||||
|
||||
def test_isolation_priv_user(require):
|
||||
require({'privileged_user': True})
|
||||
|
||||
self.load('ns_inspect')
|
||||
client.load('ns_inspect')
|
||||
|
||||
nobody_uid, nogroup_gid, nogroup = self.unpriv_creds()
|
||||
nobody_uid, nogroup_gid, nogroup = unpriv_creds()
|
||||
|
||||
obj = self.getjson()['body']
|
||||
obj = client.getjson()['body']
|
||||
|
||||
assert obj['UID'] == nobody_uid, 'uid match'
|
||||
assert obj['GID'] == nogroup_gid, 'gid match'
|
||||
|
||||
self.load('ns_inspect', isolation={'namespaces': {'credential': True}})
|
||||
client.load('ns_inspect', isolation={'namespaces': {'credential': True}})
|
||||
|
||||
obj = self.getjson()['body']
|
||||
obj = client.getjson()['body']
|
||||
|
||||
# privileged unit map app creds in the container by default
|
||||
assert obj['UID'] == nobody_uid, 'uid nobody'
|
||||
assert obj['GID'] == nogroup_gid, 'gid nobody'
|
||||
|
||||
self.load(
|
||||
client.load(
|
||||
'ns_inspect',
|
||||
user='root',
|
||||
isolation={'namespaces': {'credential': True}},
|
||||
)
|
||||
|
||||
obj = self.getjson()['body']
|
||||
obj = client.getjson()['body']
|
||||
|
||||
assert obj['UID'] == 0, 'uid nobody user=root'
|
||||
assert obj['GID'] == 0, 'gid nobody user=root'
|
||||
|
||||
self.load(
|
||||
client.load(
|
||||
'ns_inspect',
|
||||
user='root',
|
||||
group=nogroup,
|
||||
isolation={'namespaces': {'credential': True}},
|
||||
)
|
||||
|
||||
obj = self.getjson()['body']
|
||||
obj = client.getjson()['body']
|
||||
|
||||
assert obj['UID'] == 0, 'uid match user=root group=nogroup'
|
||||
assert obj['GID'] == nogroup_gid, 'gid match user=root group=nogroup'
|
||||
|
||||
self.load(
|
||||
client.load(
|
||||
'ns_inspect',
|
||||
user='root',
|
||||
group='root',
|
||||
|
@ -149,13 +153,13 @@ class TestGoIsolation(TestApplicationGo):
|
|||
},
|
||||
)
|
||||
|
||||
obj = self.getjson()['body']
|
||||
obj = client.getjson()['body']
|
||||
|
||||
assert obj['UID'] == 0, 'uid match uidmap user=root'
|
||||
assert obj['GID'] == 0, 'gid match gidmap user=root'
|
||||
|
||||
# map 65535 uids
|
||||
self.load(
|
||||
client.load(
|
||||
'ns_inspect',
|
||||
user='nobody',
|
||||
isolation={
|
||||
|
@ -164,24 +168,25 @@ class TestGoIsolation(TestApplicationGo):
|
|||
},
|
||||
)
|
||||
|
||||
obj = self.getjson()['body']
|
||||
obj = client.getjson()['body']
|
||||
|
||||
assert obj['UID'] == nobody_uid, 'uid match uidmap user=nobody'
|
||||
assert obj['GID'] == nogroup_gid, 'gid match uidmap user=nobody'
|
||||
|
||||
def test_isolation_mnt(self, require):
|
||||
|
||||
def test_isolation_mnt(require):
|
||||
require(
|
||||
{
|
||||
'features': {'isolation': ['unprivileged_userns_clone', 'mnt']},
|
||||
}
|
||||
)
|
||||
|
||||
self.load(
|
||||
client.load(
|
||||
'ns_inspect',
|
||||
isolation={'namespaces': {'mount': True, 'credential': True}},
|
||||
)
|
||||
|
||||
obj = self.getjson()['body']
|
||||
obj = client.getjson()['body']
|
||||
|
||||
# all but user and mnt
|
||||
allns = list(option.available['features']['isolation'].keys())
|
||||
|
@ -198,7 +203,8 @@ class TestGoIsolation(TestApplicationGo):
|
|||
assert obj['NS']['MNT'] != getns('mnt'), 'mnt set'
|
||||
assert obj['NS']['USER'] != getns('user'), 'user set'
|
||||
|
||||
def test_isolation_pid(self, is_su, require):
|
||||
|
||||
def test_isolation_pid(is_su, require):
|
||||
require({'features': {'isolation': ['pid']}})
|
||||
|
||||
if not is_su:
|
||||
|
@ -220,14 +226,15 @@ class TestGoIsolation(TestApplicationGo):
|
|||
isolation['namespaces']['mount'] = True
|
||||
isolation['namespaces']['credential'] = True
|
||||
|
||||
self.load('ns_inspect', isolation=isolation)
|
||||
client.load('ns_inspect', isolation=isolation)
|
||||
|
||||
obj = self.getjson()['body']
|
||||
obj = client.getjson()['body']
|
||||
|
||||
assert obj['PID'] == 2, 'pid of container is 2'
|
||||
|
||||
def test_isolation_namespace_false(self):
|
||||
self.load('ns_inspect')
|
||||
|
||||
def test_isolation_namespace_false():
|
||||
client.load('ns_inspect')
|
||||
allns = list(option.available['features']['isolation'].keys())
|
||||
|
||||
remove_list = ['unprivileged_userns_clone', 'ipc', 'cgroup']
|
||||
|
@ -246,9 +253,9 @@ class TestGoIsolation(TestApplicationGo):
|
|||
else:
|
||||
namespaces[ns] = False
|
||||
|
||||
self.load('ns_inspect', isolation={'namespaces': namespaces})
|
||||
client.load('ns_inspect', isolation={'namespaces': namespaces})
|
||||
|
||||
obj = self.getjson()['body']
|
||||
obj = client.getjson()['body']
|
||||
|
||||
for ns in allns:
|
||||
if ns.upper() in obj['NS']:
|
||||
|
@ -257,7 +264,8 @@ class TestGoIsolation(TestApplicationGo):
|
|||
== option.available['features']['isolation'][ns]
|
||||
), f'{ns} match'
|
||||
|
||||
def test_go_isolation_rootfs_container(self, is_su, require, temp_dir):
|
||||
|
||||
def test_go_isolation_rootfs_container(is_su, require, temp_dir):
|
||||
if not is_su:
|
||||
require(
|
||||
{
|
||||
|
@ -281,16 +289,17 @@ class TestGoIsolation(TestApplicationGo):
|
|||
'pid': True,
|
||||
}
|
||||
|
||||
self.load('ns_inspect', isolation=isolation)
|
||||
client.load('ns_inspect', isolation=isolation)
|
||||
|
||||
obj = self.getjson(url='/?file=/go/app')['body']
|
||||
obj = client.getjson(url='/?file=/go/app')['body']
|
||||
|
||||
assert obj['FileExists'], 'app relative to rootfs'
|
||||
|
||||
obj = self.getjson(url='/?file=/bin/sh')['body']
|
||||
obj = client.getjson(url='/?file=/bin/sh')['body']
|
||||
assert not obj['FileExists'], 'file should not exists'
|
||||
|
||||
def test_go_isolation_rootfs_container_priv(self, require, temp_dir):
|
||||
|
||||
def test_go_isolation_rootfs_container_priv(require, temp_dir):
|
||||
require({'privileged_user': True, 'features': {'isolation': ['mnt']}})
|
||||
|
||||
isolation = {
|
||||
|
@ -298,18 +307,17 @@ class TestGoIsolation(TestApplicationGo):
|
|||
'rootfs': temp_dir,
|
||||
}
|
||||
|
||||
self.load('ns_inspect', isolation=isolation)
|
||||
client.load('ns_inspect', isolation=isolation)
|
||||
|
||||
obj = self.getjson(url='/?file=/go/app')['body']
|
||||
obj = client.getjson(url='/?file=/go/app')['body']
|
||||
|
||||
assert obj['FileExists'], 'app relative to rootfs'
|
||||
|
||||
obj = self.getjson(url='/?file=/bin/sh')['body']
|
||||
obj = client.getjson(url='/?file=/bin/sh')['body']
|
||||
assert not obj['FileExists'], 'file should not exists'
|
||||
|
||||
def test_go_isolation_rootfs_automount_tmpfs(
|
||||
self, is_su, require, temp_dir
|
||||
):
|
||||
|
||||
def test_go_isolation_rootfs_automount_tmpfs(is_su, require, temp_dir):
|
||||
try:
|
||||
open("/proc/self/mountinfo")
|
||||
except:
|
||||
|
@ -340,9 +348,9 @@ class TestGoIsolation(TestApplicationGo):
|
|||
|
||||
isolation['automount'] = {'tmpfs': False}
|
||||
|
||||
self.load('ns_inspect', isolation=isolation)
|
||||
client.load('ns_inspect', isolation=isolation)
|
||||
|
||||
obj = self.getjson(url='/?mounts=true')['body']
|
||||
obj = client.getjson(url='/?mounts=true')['body']
|
||||
|
||||
assert (
|
||||
"/ /tmp" not in obj['Mounts'] and "tmpfs" not in obj['Mounts']
|
||||
|
@ -350,9 +358,9 @@ class TestGoIsolation(TestApplicationGo):
|
|||
|
||||
isolation['automount'] = {'tmpfs': True}
|
||||
|
||||
self.load('ns_inspect', isolation=isolation)
|
||||
client.load('ns_inspect', isolation=isolation)
|
||||
|
||||
obj = self.getjson(url='/?mounts=true')['body']
|
||||
obj = client.getjson(url='/?mounts=true')['body']
|
||||
|
||||
assert (
|
||||
"/ /tmp" in obj['Mounts'] and "tmpfs" in obj['Mounts']
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import pytest
|
||||
from unit.applications.lang.go import TestApplicationGo
|
||||
from unit.applications.lang.go import ApplicationGo
|
||||
|
||||
prerequisites = {
|
||||
'modules': {'go': 'all'},
|
||||
|
@ -7,16 +6,14 @@ prerequisites = {
|
|||
'privileged_user': True,
|
||||
}
|
||||
|
||||
client = ApplicationGo()
|
||||
|
||||
class TestGoIsolationRootfs(TestApplicationGo):
|
||||
def test_go_isolation_rootfs_chroot(self, temp_dir):
|
||||
isolation = {'rootfs': temp_dir}
|
||||
|
||||
self.load('ns_inspect', isolation=isolation)
|
||||
|
||||
obj = self.getjson(url='/?file=/go/app')['body']
|
||||
def test_go_isolation_rootfs_chroot(temp_dir):
|
||||
client.load('ns_inspect', isolation={'rootfs': temp_dir})
|
||||
|
||||
obj = client.getjson(url='/?file=/go/app')['body']
|
||||
assert obj['FileExists'], 'app relative to rootfs'
|
||||
|
||||
obj = self.getjson(url='/?file=/bin/sh')['body']
|
||||
obj = client.getjson(url='/?file=/bin/sh')['body']
|
||||
assert not obj['FileExists'], 'file should not exists'
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
import pytest
|
||||
from unit.applications.lang.python import TestApplicationPython
|
||||
from unit.applications.lang.python import ApplicationPython
|
||||
|
||||
prerequisites = {'modules': {'python': 'any'}}
|
||||
|
||||
client = ApplicationPython()
|
||||
|
||||
class TestHTTPHeader(TestApplicationPython):
|
||||
def test_http_header_value_leading_sp(self):
|
||||
self.load('custom_header')
|
||||
|
||||
resp = self.get(
|
||||
def test_http_header_value_leading_sp():
|
||||
client.load('custom_header')
|
||||
|
||||
resp = client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Custom-Header': ' ,',
|
||||
|
@ -21,10 +22,11 @@ class TestHTTPHeader(TestApplicationPython):
|
|||
resp['headers']['Custom-Header'] == ','
|
||||
), 'value leading sp custom header'
|
||||
|
||||
def test_http_header_value_leading_htab(self):
|
||||
self.load('custom_header')
|
||||
|
||||
resp = self.get(
|
||||
def test_http_header_value_leading_htab():
|
||||
client.load('custom_header')
|
||||
|
||||
resp = client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Custom-Header': '\t,',
|
||||
|
@ -37,10 +39,11 @@ class TestHTTPHeader(TestApplicationPython):
|
|||
resp['headers']['Custom-Header'] == ','
|
||||
), 'value leading htab custom header'
|
||||
|
||||
def test_http_header_value_trailing_sp(self):
|
||||
self.load('custom_header')
|
||||
|
||||
resp = self.get(
|
||||
def test_http_header_value_trailing_sp():
|
||||
client.load('custom_header')
|
||||
|
||||
resp = client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Custom-Header': ', ',
|
||||
|
@ -53,10 +56,11 @@ class TestHTTPHeader(TestApplicationPython):
|
|||
resp['headers']['Custom-Header'] == ','
|
||||
), 'value trailing sp custom header'
|
||||
|
||||
def test_http_header_value_trailing_htab(self):
|
||||
self.load('custom_header')
|
||||
|
||||
resp = self.get(
|
||||
def test_http_header_value_trailing_htab():
|
||||
client.load('custom_header')
|
||||
|
||||
resp = client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Custom-Header': ',\t',
|
||||
|
@ -69,10 +73,11 @@ class TestHTTPHeader(TestApplicationPython):
|
|||
resp['headers']['Custom-Header'] == ','
|
||||
), 'value trailing htab custom header'
|
||||
|
||||
def test_http_header_value_both_sp(self):
|
||||
self.load('custom_header')
|
||||
|
||||
resp = self.get(
|
||||
def test_http_header_value_both_sp():
|
||||
client.load('custom_header')
|
||||
|
||||
resp = client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Custom-Header': ' , ',
|
||||
|
@ -85,10 +90,11 @@ class TestHTTPHeader(TestApplicationPython):
|
|||
resp['headers']['Custom-Header'] == ','
|
||||
), 'value both sp custom header'
|
||||
|
||||
def test_http_header_value_both_htab(self):
|
||||
self.load('custom_header')
|
||||
|
||||
resp = self.get(
|
||||
def test_http_header_value_both_htab():
|
||||
client.load('custom_header')
|
||||
|
||||
resp = client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Custom-Header': '\t,\t',
|
||||
|
@ -101,10 +107,11 @@ class TestHTTPHeader(TestApplicationPython):
|
|||
resp['headers']['Custom-Header'] == ','
|
||||
), 'value both htab custom header'
|
||||
|
||||
def test_http_header_value_chars(self):
|
||||
self.load('custom_header')
|
||||
|
||||
resp = self.get(
|
||||
def test_http_header_value_chars():
|
||||
client.load('custom_header')
|
||||
|
||||
resp = client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Custom-Header': r"(),/:;<=>?@[\]{}\t !#$%&'*+-.^_`|~",
|
||||
|
@ -118,10 +125,11 @@ class TestHTTPHeader(TestApplicationPython):
|
|||
== r"(),/:;<=>?@[\]{}\t !#$%&'*+-.^_`|~"
|
||||
), 'value chars custom header'
|
||||
|
||||
def test_http_header_value_chars_edge(self):
|
||||
self.load('custom_header')
|
||||
|
||||
resp = self.http(
|
||||
def test_http_header_value_chars_edge():
|
||||
client.load('custom_header')
|
||||
|
||||
resp = client.http(
|
||||
b"""GET / HTTP/1.1
|
||||
Host: localhost
|
||||
Custom-Header: \x20\xFF
|
||||
|
@ -135,10 +143,11 @@ Connection: close
|
|||
assert resp['status'] == 200, 'value chars edge status'
|
||||
assert resp['headers']['Custom-Header'] == '\xFF', 'value chars edge'
|
||||
|
||||
def test_http_header_value_chars_below(self):
|
||||
self.load('custom_header')
|
||||
|
||||
resp = self.http(
|
||||
def test_http_header_value_chars_below():
|
||||
client.load('custom_header')
|
||||
|
||||
resp = client.http(
|
||||
b"""GET / HTTP/1.1
|
||||
Host: localhost
|
||||
Custom-Header: \x1F
|
||||
|
@ -150,11 +159,12 @@ Connection: close
|
|||
|
||||
assert resp['status'] == 400, 'value chars below'
|
||||
|
||||
def test_http_header_field_leading_sp(self):
|
||||
self.load('empty')
|
||||
|
||||
def test_http_header_field_leading_sp():
|
||||
client.load('empty')
|
||||
|
||||
assert (
|
||||
self.get(
|
||||
client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
' Custom-Header': 'blah',
|
||||
|
@ -164,11 +174,12 @@ Connection: close
|
|||
== 400
|
||||
), 'field leading sp'
|
||||
|
||||
def test_http_header_field_leading_htab(self):
|
||||
self.load('empty')
|
||||
|
||||
def test_http_header_field_leading_htab():
|
||||
client.load('empty')
|
||||
|
||||
assert (
|
||||
self.get(
|
||||
client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'\tCustom-Header': 'blah',
|
||||
|
@ -178,11 +189,12 @@ Connection: close
|
|||
== 400
|
||||
), 'field leading htab'
|
||||
|
||||
def test_http_header_field_trailing_sp(self):
|
||||
self.load('empty')
|
||||
|
||||
def test_http_header_field_trailing_sp():
|
||||
client.load('empty')
|
||||
|
||||
assert (
|
||||
self.get(
|
||||
client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Custom-Header ': 'blah',
|
||||
|
@ -192,11 +204,12 @@ Connection: close
|
|||
== 400
|
||||
), 'field trailing sp'
|
||||
|
||||
def test_http_header_field_trailing_htab(self):
|
||||
self.load('empty')
|
||||
|
||||
def test_http_header_field_trailing_htab():
|
||||
client.load('empty')
|
||||
|
||||
assert (
|
||||
self.get(
|
||||
client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Custom-Header\t': 'blah',
|
||||
|
@ -206,11 +219,12 @@ Connection: close
|
|||
== 400
|
||||
), 'field trailing htab'
|
||||
|
||||
def test_http_header_content_length_big(self):
|
||||
self.load('empty')
|
||||
|
||||
def test_http_header_content_length_big():
|
||||
client.load('empty')
|
||||
|
||||
assert (
|
||||
self.post(
|
||||
client.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Content-Length': str(2**64),
|
||||
|
@ -221,11 +235,12 @@ Connection: close
|
|||
== 400
|
||||
), 'Content-Length big'
|
||||
|
||||
def test_http_header_content_length_negative(self):
|
||||
self.load('empty')
|
||||
|
||||
def test_http_header_content_length_negative():
|
||||
client.load('empty')
|
||||
|
||||
assert (
|
||||
self.post(
|
||||
client.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Content-Length': '-100',
|
||||
|
@ -236,11 +251,12 @@ Connection: close
|
|||
== 400
|
||||
), 'Content-Length negative'
|
||||
|
||||
def test_http_header_content_length_text(self):
|
||||
self.load('empty')
|
||||
|
||||
def test_http_header_content_length_text():
|
||||
client.load('empty')
|
||||
|
||||
assert (
|
||||
self.post(
|
||||
client.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Content-Length': 'blah',
|
||||
|
@ -251,11 +267,12 @@ Connection: close
|
|||
== 400
|
||||
), 'Content-Length text'
|
||||
|
||||
def test_http_header_content_length_multiple_values(self):
|
||||
self.load('empty')
|
||||
|
||||
def test_http_header_content_length_multiple_values():
|
||||
client.load('empty')
|
||||
|
||||
assert (
|
||||
self.post(
|
||||
client.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Content-Length': '41, 42',
|
||||
|
@ -266,11 +283,12 @@ Connection: close
|
|||
== 400
|
||||
), 'Content-Length multiple value'
|
||||
|
||||
def test_http_header_content_length_multiple_fields(self):
|
||||
self.load('empty')
|
||||
|
||||
def test_http_header_content_length_multiple_fields():
|
||||
client.load('empty')
|
||||
|
||||
assert (
|
||||
self.post(
|
||||
client.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Content-Length': ['41', '42'],
|
||||
|
@ -281,36 +299,40 @@ Connection: close
|
|||
== 400
|
||||
), 'Content-Length multiple fields'
|
||||
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_http_header_host_absent(self):
|
||||
self.load('host')
|
||||
|
||||
resp = self.get(headers={'Connection': 'close'})
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_http_header_host_absent():
|
||||
client.load('host')
|
||||
|
||||
resp = client.get(headers={'Connection': 'close'})
|
||||
|
||||
assert resp['status'] == 400, 'Host absent status'
|
||||
|
||||
def test_http_header_host_empty(self):
|
||||
self.load('host')
|
||||
|
||||
resp = self.get(headers={'Host': '', 'Connection': 'close'})
|
||||
def test_http_header_host_empty():
|
||||
client.load('host')
|
||||
|
||||
resp = client.get(headers={'Host': '', 'Connection': 'close'})
|
||||
|
||||
assert resp['status'] == 200, 'Host empty status'
|
||||
assert resp['headers']['X-Server-Name'] != '', 'Host empty SERVER_NAME'
|
||||
|
||||
def test_http_header_host_big(self):
|
||||
self.load('empty')
|
||||
|
||||
def test_http_header_host_big():
|
||||
client.load('empty')
|
||||
|
||||
assert (
|
||||
self.get(headers={'Host': 'X' * 10000, 'Connection': 'close'})[
|
||||
client.get(headers={'Host': 'X' * 10000, 'Connection': 'close'})[
|
||||
'status'
|
||||
]
|
||||
== 431
|
||||
), 'Host big'
|
||||
|
||||
def test_http_header_host_port(self):
|
||||
self.load('host')
|
||||
|
||||
resp = self.get(
|
||||
def test_http_header_host_port():
|
||||
client.load('host')
|
||||
|
||||
resp = client.get(
|
||||
headers={'Host': 'exmaple.com:7080', 'Connection': 'close'}
|
||||
)
|
||||
|
||||
|
@ -322,10 +344,11 @@ Connection: close
|
|||
resp['headers']['X-Http-Host'] == 'exmaple.com:7080'
|
||||
), 'Host port HTTP_HOST'
|
||||
|
||||
def test_http_header_host_port_empty(self):
|
||||
self.load('host')
|
||||
|
||||
resp = self.get(headers={'Host': 'exmaple.com:', 'Connection': 'close'})
|
||||
def test_http_header_host_port_empty():
|
||||
client.load('host')
|
||||
|
||||
resp = client.get(headers={'Host': 'exmaple.com:', 'Connection': 'close'})
|
||||
|
||||
assert resp['status'] == 200, 'Host port empty status'
|
||||
assert (
|
||||
|
@ -335,20 +358,22 @@ Connection: close
|
|||
resp['headers']['X-Http-Host'] == 'exmaple.com:'
|
||||
), 'Host port empty HTTP_HOST'
|
||||
|
||||
def test_http_header_host_literal(self):
|
||||
self.load('host')
|
||||
|
||||
resp = self.get(headers={'Host': '127.0.0.1', 'Connection': 'close'})
|
||||
def test_http_header_host_literal():
|
||||
client.load('host')
|
||||
|
||||
resp = client.get(headers={'Host': '127.0.0.1', 'Connection': 'close'})
|
||||
|
||||
assert resp['status'] == 200, 'Host literal status'
|
||||
assert (
|
||||
resp['headers']['X-Server-Name'] == '127.0.0.1'
|
||||
), 'Host literal SERVER_NAME'
|
||||
|
||||
def test_http_header_host_literal_ipv6(self):
|
||||
self.load('host')
|
||||
|
||||
resp = self.get(headers={'Host': '[::1]:7080', 'Connection': 'close'})
|
||||
def test_http_header_host_literal_ipv6():
|
||||
client.load('host')
|
||||
|
||||
resp = client.get(headers={'Host': '[::1]:7080', 'Connection': 'close'})
|
||||
|
||||
assert resp['status'] == 200, 'Host literal ipv6 status'
|
||||
assert (
|
||||
|
@ -358,10 +383,11 @@ Connection: close
|
|||
resp['headers']['X-Http-Host'] == '[::1]:7080'
|
||||
), 'Host literal ipv6 HTTP_HOST'
|
||||
|
||||
def test_http_header_host_trailing_period(self):
|
||||
self.load('host')
|
||||
|
||||
resp = self.get(headers={'Host': '127.0.0.1.', 'Connection': 'close'})
|
||||
def test_http_header_host_trailing_period():
|
||||
client.load('host')
|
||||
|
||||
resp = client.get(headers={'Host': '127.0.0.1.', 'Connection': 'close'})
|
||||
|
||||
assert resp['status'] == 200, 'Host trailing period status'
|
||||
assert (
|
||||
|
@ -371,10 +397,11 @@ Connection: close
|
|||
resp['headers']['X-Http-Host'] == '127.0.0.1.'
|
||||
), 'Host trailing period HTTP_HOST'
|
||||
|
||||
def test_http_header_host_trailing_period_2(self):
|
||||
self.load('host')
|
||||
|
||||
resp = self.get(headers={'Host': 'EXAMPLE.COM.', 'Connection': 'close'})
|
||||
def test_http_header_host_trailing_period_2():
|
||||
client.load('host')
|
||||
|
||||
resp = client.get(headers={'Host': 'EXAMPLE.COM.', 'Connection': 'close'})
|
||||
|
||||
assert resp['status'] == 200, 'Host trailing period 2 status'
|
||||
assert (
|
||||
|
@ -384,41 +411,45 @@ Connection: close
|
|||
resp['headers']['X-Http-Host'] == 'EXAMPLE.COM.'
|
||||
), 'Host trailing period 2 HTTP_HOST'
|
||||
|
||||
def test_http_header_host_case_insensitive(self):
|
||||
self.load('host')
|
||||
|
||||
resp = self.get(headers={'Host': 'EXAMPLE.COM', 'Connection': 'close'})
|
||||
def test_http_header_host_case_insensitive():
|
||||
client.load('host')
|
||||
|
||||
resp = client.get(headers={'Host': 'EXAMPLE.COM', 'Connection': 'close'})
|
||||
|
||||
assert resp['status'] == 200, 'Host case insensitive'
|
||||
assert (
|
||||
resp['headers']['X-Server-Name'] == 'example.com'
|
||||
), 'Host case insensitive SERVER_NAME'
|
||||
|
||||
def test_http_header_host_double_dot(self):
|
||||
self.load('empty')
|
||||
|
||||
def test_http_header_host_double_dot():
|
||||
client.load('empty')
|
||||
|
||||
assert (
|
||||
self.get(headers={'Host': '127.0.0..1', 'Connection': 'close'})[
|
||||
client.get(headers={'Host': '127.0.0..1', 'Connection': 'close'})[
|
||||
'status'
|
||||
]
|
||||
== 400
|
||||
), 'Host double dot'
|
||||
|
||||
def test_http_header_host_slash(self):
|
||||
self.load('empty')
|
||||
|
||||
def test_http_header_host_slash():
|
||||
client.load('empty')
|
||||
|
||||
assert (
|
||||
self.get(headers={'Host': '/localhost', 'Connection': 'close'})[
|
||||
client.get(headers={'Host': '/localhost', 'Connection': 'close'})[
|
||||
'status'
|
||||
]
|
||||
== 400
|
||||
), 'Host slash'
|
||||
|
||||
def test_http_header_host_multiple_fields(self):
|
||||
self.load('empty')
|
||||
|
||||
def test_http_header_host_multiple_fields():
|
||||
client.load('empty')
|
||||
|
||||
assert (
|
||||
self.get(
|
||||
client.get(
|
||||
headers={
|
||||
'Host': ['localhost', 'example.com'],
|
||||
'Connection': 'close',
|
||||
|
@ -427,11 +458,12 @@ Connection: close
|
|||
== 400
|
||||
), 'Host multiple fields'
|
||||
|
||||
def test_http_discard_unsafe_fields(self):
|
||||
self.load('header_fields')
|
||||
|
||||
def test_http_discard_unsafe_fields():
|
||||
client.load('header_fields')
|
||||
|
||||
def check_status(header):
|
||||
resp = self.get(
|
||||
resp = client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
header: 'blah',
|
||||
|
@ -448,7 +480,7 @@ Connection: close
|
|||
resp = check_status("Custom_Header")
|
||||
assert 'CUSTOM' not in resp['headers']['All-Headers']
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{'http': {'discard_unsafe_fields': False}},
|
||||
'settings',
|
||||
)
|
||||
|
@ -456,7 +488,7 @@ Connection: close
|
|||
resp = check_status("!#$%&'*+.^`|~Custom_Header")
|
||||
assert 'CUSTOM' in resp['headers']['All-Headers']
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{'http': {'discard_unsafe_fields': True}},
|
||||
'settings',
|
||||
)
|
||||
|
|
|
@ -3,26 +3,27 @@ import os
|
|||
import re
|
||||
import time
|
||||
|
||||
from unit.applications.lang.java import TestApplicationJava
|
||||
from unit.applications.lang.java import ApplicationJava
|
||||
from unit.option import option
|
||||
from unit.utils import public_dir
|
||||
|
||||
prerequisites = {'modules': {'java': 'all'}}
|
||||
|
||||
client = ApplicationJava()
|
||||
|
||||
class TestJavaApplication(TestApplicationJava):
|
||||
def test_java_conf_error(self, temp_dir, skip_alert):
|
||||
|
||||
def test_java_conf_error(temp_dir, skip_alert):
|
||||
skip_alert(
|
||||
r'realpath.*failed',
|
||||
r'failed to apply new conf',
|
||||
r'application setup failed',
|
||||
)
|
||||
assert 'error' in self.conf(
|
||||
assert 'error' in client.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "applications/app"}},
|
||||
"applications": {
|
||||
"app": {
|
||||
"type": self.get_application_type(),
|
||||
"type": client.get_application_type(),
|
||||
"processes": 1,
|
||||
"working_directory": f"{option.test_dir}/java/empty",
|
||||
"webapp": f"{temp_dir}/java",
|
||||
|
@ -32,20 +33,22 @@ class TestJavaApplication(TestApplicationJava):
|
|||
}
|
||||
), 'conf error'
|
||||
|
||||
def test_java_war(self, temp_dir):
|
||||
self.load('empty_war')
|
||||
|
||||
assert 'success' in self.conf(
|
||||
def test_java_war(temp_dir):
|
||||
client.load('empty_war')
|
||||
|
||||
assert 'success' in client.conf(
|
||||
f'"{temp_dir}/java/empty.war"',
|
||||
'/config/applications/empty_war/webapp',
|
||||
), 'configure war'
|
||||
|
||||
assert self.get()['status'] == 200, 'war'
|
||||
assert client.get()['status'] == 200, 'war'
|
||||
|
||||
def test_java_application_cookies(self):
|
||||
self.load('cookies')
|
||||
|
||||
headers = self.get(
|
||||
def test_java_application_cookies():
|
||||
client.load('cookies')
|
||||
|
||||
headers = client.get(
|
||||
headers={
|
||||
'Cookie': 'var1=val1; var2=val2',
|
||||
'Host': 'localhost',
|
||||
|
@ -56,29 +59,29 @@ class TestJavaApplication(TestApplicationJava):
|
|||
assert headers['X-Cookie-1'] == 'val1', 'cookie 1'
|
||||
assert headers['X-Cookie-2'] == 'val2', 'cookie 2'
|
||||
|
||||
def test_java_application_filter(self):
|
||||
self.load('filter')
|
||||
|
||||
headers = self.get()['headers']
|
||||
def test_java_application_filter():
|
||||
client.load('filter')
|
||||
|
||||
headers = client.get()['headers']
|
||||
|
||||
assert headers['X-Filter-Before'] == '1', 'filter before'
|
||||
assert headers['X-Filter-After'] == '1', 'filter after'
|
||||
|
||||
assert (
|
||||
self.get(url='/test')['headers']['X-Filter-After'] == '0'
|
||||
client.get(url='/test')['headers']['X-Filter-After'] == '0'
|
||||
), 'filter after 2'
|
||||
|
||||
def test_java_application_get_variables(self):
|
||||
self.load('get_params')
|
||||
|
||||
def test_java_application_get_variables():
|
||||
client.load('get_params')
|
||||
|
||||
def check_header(header, expect):
|
||||
values = header.split(' ')[:-1]
|
||||
assert len(values) == len(expect)
|
||||
assert set(values) == set(expect)
|
||||
|
||||
headers = self.get(url='/?var1=val1&var2=&var4=val4&var4=foo')[
|
||||
'headers'
|
||||
]
|
||||
headers = client.get(url='/?var1=val1&var2=&var4=val4&var4=foo')['headers']
|
||||
|
||||
assert headers['X-Var-1'] == 'val1', 'GET variables'
|
||||
assert headers['X-Var-2'] == 'true', 'GET variables 2'
|
||||
|
@ -90,10 +93,11 @@ class TestJavaApplication(TestApplicationJava):
|
|||
headers['X-Param-Map'], ['var2=', 'var1=val1', 'var4=val4,foo']
|
||||
)
|
||||
|
||||
def test_java_application_post_variables(self):
|
||||
self.load('post_params')
|
||||
|
||||
headers = self.post(
|
||||
def test_java_application_post_variables():
|
||||
client.load('post_params')
|
||||
|
||||
headers = client.post(
|
||||
headers={
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'Host': 'localhost',
|
||||
|
@ -106,16 +110,17 @@ class TestJavaApplication(TestApplicationJava):
|
|||
assert headers['X-Var-2'] == 'true', 'POST variables 2'
|
||||
assert headers['X-Var-3'] == 'false', 'POST variables 3'
|
||||
|
||||
def test_java_application_session(self):
|
||||
self.load('session')
|
||||
|
||||
headers = self.get(url='/?var1=val1')['headers']
|
||||
def test_java_application_session():
|
||||
client.load('session')
|
||||
|
||||
headers = client.get(url='/?var1=val1')['headers']
|
||||
session_id = headers['X-Session-Id']
|
||||
|
||||
assert headers['X-Var-1'] == 'null', 'variable empty'
|
||||
assert headers['X-Session-New'] == 'true', 'session create'
|
||||
|
||||
headers = self.get(
|
||||
headers = client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Cookie': f'JSESSIONID={session_id}',
|
||||
|
@ -128,12 +133,11 @@ class TestJavaApplication(TestApplicationJava):
|
|||
assert headers['X-Session-New'] == 'false', 'session resume'
|
||||
assert session_id == headers['X-Session-Id'], 'session same id'
|
||||
|
||||
def test_java_application_session_active(
|
||||
self, date_to_sec_epoch, sec_epoch
|
||||
):
|
||||
self.load('session_inactive')
|
||||
|
||||
resp = self.get(
|
||||
def test_java_application_session_active(date_to_sec_epoch, sec_epoch):
|
||||
client.load('session_inactive')
|
||||
|
||||
resp = client.get(
|
||||
headers={
|
||||
'X-Interval': '4',
|
||||
'Host': 'localhost',
|
||||
|
@ -154,7 +158,7 @@ class TestJavaApplication(TestApplicationJava):
|
|||
|
||||
time.sleep(1)
|
||||
|
||||
resp = self.get(
|
||||
resp = client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Cookie': f'JSESSIONID={session_id}',
|
||||
|
@ -168,7 +172,7 @@ class TestJavaApplication(TestApplicationJava):
|
|||
|
||||
time.sleep(1)
|
||||
|
||||
resp = self.get(
|
||||
resp = client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Cookie': f'JSESSIONID={session_id}',
|
||||
|
@ -180,7 +184,7 @@ class TestJavaApplication(TestApplicationJava):
|
|||
|
||||
time.sleep(2)
|
||||
|
||||
resp = self.get(
|
||||
resp = client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Cookie': f'JSESSIONID={session_id}',
|
||||
|
@ -190,10 +194,11 @@ class TestJavaApplication(TestApplicationJava):
|
|||
|
||||
assert resp['headers']['X-Session-Id'] == session_id, 'session active 3'
|
||||
|
||||
def test_java_application_session_inactive(self):
|
||||
self.load('session_inactive')
|
||||
|
||||
resp = self.get(
|
||||
def test_java_application_session_inactive():
|
||||
client.load('session_inactive')
|
||||
|
||||
resp = client.get(
|
||||
headers={
|
||||
'X-Interval': '1',
|
||||
'Host': 'localhost',
|
||||
|
@ -204,7 +209,7 @@ class TestJavaApplication(TestApplicationJava):
|
|||
|
||||
time.sleep(3)
|
||||
|
||||
resp = self.get(
|
||||
resp = client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Cookie': f'JSESSIONID={session_id}',
|
||||
|
@ -214,13 +219,14 @@ class TestJavaApplication(TestApplicationJava):
|
|||
|
||||
assert resp['headers']['X-Session-Id'] != session_id, 'session inactive'
|
||||
|
||||
def test_java_application_session_invalidate(self):
|
||||
self.load('session_invalidate')
|
||||
|
||||
resp = self.get()
|
||||
def test_java_application_session_invalidate():
|
||||
client.load('session_invalidate')
|
||||
|
||||
resp = client.get()
|
||||
session_id = resp['headers']['X-Session-Id']
|
||||
|
||||
resp = self.get(
|
||||
resp = client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Cookie': f'JSESSIONID={session_id}',
|
||||
|
@ -228,20 +234,19 @@ class TestJavaApplication(TestApplicationJava):
|
|||
}
|
||||
)
|
||||
|
||||
assert (
|
||||
resp['headers']['X-Session-Id'] != session_id
|
||||
), 'session invalidate'
|
||||
assert resp['headers']['X-Session-Id'] != session_id, 'session invalidate'
|
||||
|
||||
def test_java_application_session_listeners(self):
|
||||
self.load('session_listeners')
|
||||
|
||||
headers = self.get(url='/test?var1=val1')['headers']
|
||||
def test_java_application_session_listeners():
|
||||
client.load('session_listeners')
|
||||
|
||||
headers = client.get(url='/test?var1=val1')['headers']
|
||||
session_id = headers['X-Session-Id']
|
||||
|
||||
assert headers['X-Session-Created'] == session_id, 'session create'
|
||||
assert headers['X-Attr-Added'] == 'var1=val1', 'attribute add'
|
||||
|
||||
headers = self.get(
|
||||
headers = client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Cookie': f'JSESSIONID={session_id}',
|
||||
|
@ -253,7 +258,7 @@ class TestJavaApplication(TestApplicationJava):
|
|||
assert session_id == headers['X-Session-Id'], 'session same id'
|
||||
assert headers['X-Attr-Replaced'] == 'var1=val1', 'attribute replace'
|
||||
|
||||
headers = self.get(
|
||||
headers = client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Cookie': f'JSESSIONID={session_id}',
|
||||
|
@ -265,109 +270,102 @@ class TestJavaApplication(TestApplicationJava):
|
|||
assert session_id == headers['X-Session-Id'], 'session same id'
|
||||
assert headers['X-Attr-Removed'] == 'var1=val2', 'attribute remove'
|
||||
|
||||
def test_java_application_jsp(self):
|
||||
self.load('jsp')
|
||||
|
||||
headers = self.get(url='/index.jsp')['headers']
|
||||
def test_java_application_jsp():
|
||||
client.load('jsp')
|
||||
|
||||
headers = client.get(url='/index.jsp')['headers']
|
||||
|
||||
assert headers['X-Unit-JSP'] == 'ok', 'JSP Ok header'
|
||||
|
||||
def test_java_application_url_pattern(self):
|
||||
self.load('url_pattern')
|
||||
|
||||
headers = self.get(url='/foo/bar/index.html')['headers']
|
||||
def test_java_application_url_pattern():
|
||||
client.load('url_pattern')
|
||||
|
||||
headers = client.get(url='/foo/bar/index.html')['headers']
|
||||
|
||||
assert headers['X-Id'] == 'servlet1', '#1 Servlet1 request'
|
||||
assert (
|
||||
headers['X-Request-URI'] == '/foo/bar/index.html'
|
||||
), '#1 request URI'
|
||||
assert headers['X-Request-URI'] == '/foo/bar/index.html', '#1 request URI'
|
||||
assert headers['X-Servlet-Path'] == '/foo/bar', '#1 servlet path'
|
||||
assert headers['X-Path-Info'] == '/index.html', '#1 path info'
|
||||
|
||||
headers = self.get(url='/foo/bar/index.bop')['headers']
|
||||
headers = client.get(url='/foo/bar/index.bop')['headers']
|
||||
|
||||
assert headers['X-Id'] == 'servlet1', '#2 Servlet1 request'
|
||||
assert (
|
||||
headers['X-Request-URI'] == '/foo/bar/index.bop'
|
||||
), '#2 request URI'
|
||||
assert headers['X-Request-URI'] == '/foo/bar/index.bop', '#2 request URI'
|
||||
assert headers['X-Servlet-Path'] == '/foo/bar', '#2 servlet path'
|
||||
assert headers['X-Path-Info'] == '/index.bop', '#2 path info'
|
||||
|
||||
headers = self.get(url='/baz')['headers']
|
||||
headers = client.get(url='/baz')['headers']
|
||||
|
||||
assert headers['X-Id'] == 'servlet2', '#3 Servlet2 request'
|
||||
assert headers['X-Request-URI'] == '/baz', '#3 request URI'
|
||||
assert headers['X-Servlet-Path'] == '/baz', '#3 servlet path'
|
||||
assert headers['X-Path-Info'] == 'null', '#3 path info'
|
||||
|
||||
headers = self.get(url='/baz/index.html')['headers']
|
||||
headers = client.get(url='/baz/index.html')['headers']
|
||||
|
||||
assert headers['X-Id'] == 'servlet2', '#4 Servlet2 request'
|
||||
assert headers['X-Request-URI'] == '/baz/index.html', '#4 request URI'
|
||||
assert headers['X-Servlet-Path'] == '/baz', '#4 servlet path'
|
||||
assert headers['X-Path-Info'] == '/index.html', '#4 path info'
|
||||
|
||||
headers = self.get(url='/catalog')['headers']
|
||||
headers = client.get(url='/catalog')['headers']
|
||||
|
||||
assert headers['X-Id'] == 'servlet3', '#5 Servlet3 request'
|
||||
assert headers['X-Request-URI'] == '/catalog', '#5 request URI'
|
||||
assert headers['X-Servlet-Path'] == '/catalog', '#5 servlet path'
|
||||
assert headers['X-Path-Info'] == 'null', '#5 path info'
|
||||
|
||||
headers = self.get(url='/catalog/index.html')['headers']
|
||||
headers = client.get(url='/catalog/index.html')['headers']
|
||||
|
||||
assert headers['X-Id'] == 'default', '#6 default request'
|
||||
assert (
|
||||
headers['X-Request-URI'] == '/catalog/index.html'
|
||||
), '#6 request URI'
|
||||
assert (
|
||||
headers['X-Servlet-Path'] == '/catalog/index.html'
|
||||
), '#6 servlet path'
|
||||
assert headers['X-Request-URI'] == '/catalog/index.html', '#6 request URI'
|
||||
assert headers['X-Servlet-Path'] == '/catalog/index.html', '#6 servlet path'
|
||||
assert headers['X-Path-Info'] == 'null', '#6 path info'
|
||||
|
||||
headers = self.get(url='/catalog/racecar.bop')['headers']
|
||||
headers = client.get(url='/catalog/racecar.bop')['headers']
|
||||
|
||||
assert headers['X-Id'] == 'servlet4', '#7 servlet4 request'
|
||||
assert (
|
||||
headers['X-Request-URI'] == '/catalog/racecar.bop'
|
||||
), '#7 request URI'
|
||||
assert headers['X-Request-URI'] == '/catalog/racecar.bop', '#7 request URI'
|
||||
assert (
|
||||
headers['X-Servlet-Path'] == '/catalog/racecar.bop'
|
||||
), '#7 servlet path'
|
||||
assert headers['X-Path-Info'] == 'null', '#7 path info'
|
||||
|
||||
headers = self.get(url='/index.bop')['headers']
|
||||
headers = client.get(url='/index.bop')['headers']
|
||||
|
||||
assert headers['X-Id'] == 'servlet4', '#8 servlet4 request'
|
||||
assert headers['X-Request-URI'] == '/index.bop', '#8 request URI'
|
||||
assert headers['X-Servlet-Path'] == '/index.bop', '#8 servlet path'
|
||||
assert headers['X-Path-Info'] == 'null', '#8 path info'
|
||||
|
||||
headers = self.get(url='/foo/baz')['headers']
|
||||
headers = client.get(url='/foo/baz')['headers']
|
||||
|
||||
assert headers['X-Id'] == 'servlet0', '#9 servlet0 request'
|
||||
assert headers['X-Request-URI'] == '/foo/baz', '#9 request URI'
|
||||
assert headers['X-Servlet-Path'] == '/foo', '#9 servlet path'
|
||||
assert headers['X-Path-Info'] == '/baz', '#9 path info'
|
||||
|
||||
headers = self.get()['headers']
|
||||
headers = client.get()['headers']
|
||||
|
||||
assert headers['X-Id'] == 'default', '#10 default request'
|
||||
assert headers['X-Request-URI'] == '/', '#10 request URI'
|
||||
assert headers['X-Servlet-Path'] == '/', '#10 servlet path'
|
||||
assert headers['X-Path-Info'] == 'null', '#10 path info'
|
||||
|
||||
headers = self.get(url='/index.bop/')['headers']
|
||||
headers = client.get(url='/index.bop/')['headers']
|
||||
|
||||
assert headers['X-Id'] == 'default', '#11 default request'
|
||||
assert headers['X-Request-URI'] == '/index.bop/', '#11 request URI'
|
||||
assert headers['X-Servlet-Path'] == '/index.bop/', '#11 servlet path'
|
||||
assert headers['X-Path-Info'] == 'null', '#11 path info'
|
||||
|
||||
def test_java_application_header(self):
|
||||
self.load('header')
|
||||
|
||||
headers = self.get()['headers']
|
||||
def test_java_application_header():
|
||||
client.load('header')
|
||||
|
||||
headers = client.get()['headers']
|
||||
|
||||
assert headers['X-Set-Utf8-Value'] == '????', 'set Utf8 header value'
|
||||
assert headers['X-Set-Utf8-Name-???'] == 'x', 'set Utf8 header name'
|
||||
|
@ -377,10 +375,11 @@ class TestJavaApplication(TestApplicationJava):
|
|||
assert 'X-Set-Test1' not in headers, 'set null header'
|
||||
assert headers['X-Set-Test2'] == '', 'set empty header'
|
||||
|
||||
def test_java_application_content_type(self):
|
||||
self.load('content_type')
|
||||
|
||||
headers = self.get(url='/1')['headers']
|
||||
def test_java_application_content_type():
|
||||
client.load('content_type')
|
||||
|
||||
headers = client.get(url='/1')['headers']
|
||||
|
||||
assert (
|
||||
headers['Content-Type'] == 'text/plain;charset=utf-8'
|
||||
|
@ -390,7 +389,7 @@ class TestJavaApplication(TestApplicationJava):
|
|||
), '#1 response Content-Type'
|
||||
assert headers['X-Character-Encoding'] == 'utf-8', '#1 response charset'
|
||||
|
||||
headers = self.get(url='/2')['headers']
|
||||
headers = client.get(url='/2')['headers']
|
||||
|
||||
assert (
|
||||
headers['Content-Type'] == 'text/plain;charset=iso-8859-1'
|
||||
|
@ -402,7 +401,7 @@ class TestJavaApplication(TestApplicationJava):
|
|||
headers['X-Character-Encoding'] == 'iso-8859-1'
|
||||
), '#2 response charset'
|
||||
|
||||
headers = self.get(url='/3')['headers']
|
||||
headers = client.get(url='/3')['headers']
|
||||
|
||||
assert (
|
||||
headers['Content-Type'] == 'text/plain;charset=windows-1251'
|
||||
|
@ -414,7 +413,7 @@ class TestJavaApplication(TestApplicationJava):
|
|||
headers['X-Character-Encoding'] == 'windows-1251'
|
||||
), '#3 response charset'
|
||||
|
||||
headers = self.get(url='/4')['headers']
|
||||
headers = client.get(url='/4')['headers']
|
||||
|
||||
assert (
|
||||
headers['Content-Type'] == 'text/plain;charset=windows-1251'
|
||||
|
@ -426,7 +425,7 @@ class TestJavaApplication(TestApplicationJava):
|
|||
headers['X-Character-Encoding'] == 'windows-1251'
|
||||
), '#4 response charset'
|
||||
|
||||
headers = self.get(url='/5')['headers']
|
||||
headers = client.get(url='/5')['headers']
|
||||
|
||||
assert (
|
||||
headers['Content-Type'] == 'text/plain;charset=iso-8859-1'
|
||||
|
@ -438,13 +437,13 @@ class TestJavaApplication(TestApplicationJava):
|
|||
headers['X-Character-Encoding'] == 'iso-8859-1'
|
||||
), '#5 response charset'
|
||||
|
||||
headers = self.get(url='/6')['headers']
|
||||
headers = client.get(url='/6')['headers']
|
||||
|
||||
assert 'Content-Type' not in headers, '#6 no Content-Type header'
|
||||
assert 'X-Content-Type' not in headers, '#6 no response Content-Type'
|
||||
assert headers['X-Character-Encoding'] == 'utf-8', '#6 response charset'
|
||||
|
||||
headers = self.get(url='/7')['headers']
|
||||
headers = client.get(url='/7')['headers']
|
||||
|
||||
assert (
|
||||
headers['Content-Type'] == 'text/plain;charset=utf-8'
|
||||
|
@ -454,7 +453,7 @@ class TestJavaApplication(TestApplicationJava):
|
|||
), '#7 response Content-Type'
|
||||
assert headers['X-Character-Encoding'] == 'utf-8', '#7 response charset'
|
||||
|
||||
headers = self.get(url='/8')['headers']
|
||||
headers = client.get(url='/8')['headers']
|
||||
|
||||
assert (
|
||||
headers['Content-Type'] == 'text/html;charset=utf-8'
|
||||
|
@ -464,47 +463,45 @@ class TestJavaApplication(TestApplicationJava):
|
|||
), '#8 response Content-Type'
|
||||
assert headers['X-Character-Encoding'] == 'utf-8', '#8 response charset'
|
||||
|
||||
def test_java_application_welcome_files(self):
|
||||
self.load('welcome_files')
|
||||
|
||||
headers = self.get()['headers']
|
||||
def test_java_application_welcome_files():
|
||||
client.load('welcome_files')
|
||||
|
||||
resp = self.get(url='/dir1')
|
||||
headers = client.get()['headers']
|
||||
|
||||
resp = client.get(url='/dir1')
|
||||
|
||||
assert resp['status'] == 302, 'dir redirect expected'
|
||||
|
||||
resp = self.get(url='/dir1/')
|
||||
resp = client.get(url='/dir1/')
|
||||
|
||||
assert 'This is index.txt.' in resp['body'], 'dir1 index body'
|
||||
assert resp['headers']['X-TXT-Filter'] == '1', 'TXT Filter header'
|
||||
|
||||
headers = self.get(url='/dir2/')['headers']
|
||||
headers = client.get(url='/dir2/')['headers']
|
||||
|
||||
assert headers['X-Unit-JSP'] == 'ok', 'JSP Ok header'
|
||||
assert headers['X-JSP-Filter'] == '1', 'JSP Filter header'
|
||||
|
||||
headers = self.get(url='/dir3/')['headers']
|
||||
headers = client.get(url='/dir3/')['headers']
|
||||
|
||||
assert (
|
||||
headers['X-App-Servlet'] == '1'
|
||||
), 'URL pattern overrides welcome file'
|
||||
assert headers['X-App-Servlet'] == '1', 'URL pattern overrides welcome file'
|
||||
|
||||
headers = self.get(url='/dir4/')['headers']
|
||||
headers = client.get(url='/dir4/')['headers']
|
||||
|
||||
assert (
|
||||
'X-App-Servlet' not in headers
|
||||
), 'Static welcome file served first'
|
||||
assert 'X-App-Servlet' not in headers, 'Static welcome file served first'
|
||||
|
||||
headers = self.get(url='/dir5/')['headers']
|
||||
headers = client.get(url='/dir5/')['headers']
|
||||
|
||||
assert (
|
||||
headers['X-App-Servlet'] == '1'
|
||||
), 'Servlet for welcome file served when no static file found'
|
||||
|
||||
def test_java_application_request_listeners(self):
|
||||
self.load('request_listeners')
|
||||
|
||||
headers = self.get(url='/test1')['headers']
|
||||
def test_java_application_request_listeners():
|
||||
client.load('request_listeners')
|
||||
|
||||
headers = client.get(url='/test1')['headers']
|
||||
|
||||
assert (
|
||||
headers['X-Request-Initialized'] == '/test1'
|
||||
|
@ -514,57 +511,48 @@ class TestJavaApplication(TestApplicationJava):
|
|||
assert headers['X-Attr-Removed'] == '', 'attribute removed event'
|
||||
assert headers['X-Attr-Replaced'] == '', 'attribute replaced event'
|
||||
|
||||
headers = self.get(url='/test2?var1=1')['headers']
|
||||
headers = client.get(url='/test2?var1=1')['headers']
|
||||
|
||||
assert (
|
||||
headers['X-Request-Initialized'] == '/test2'
|
||||
), 'request initialized event'
|
||||
assert (
|
||||
headers['X-Request-Destroyed'] == '/test1'
|
||||
), 'request destroyed event'
|
||||
assert headers['X-Request-Destroyed'] == '/test1', 'request destroyed event'
|
||||
assert headers['X-Attr-Added'] == 'var=1;', 'attribute added event'
|
||||
assert headers['X-Attr-Removed'] == 'var=1;', 'attribute removed event'
|
||||
assert headers['X-Attr-Replaced'] == '', 'attribute replaced event'
|
||||
|
||||
headers = self.get(url='/test3?var1=1&var2=2')['headers']
|
||||
headers = client.get(url='/test3?var1=1&var2=2')['headers']
|
||||
|
||||
assert (
|
||||
headers['X-Request-Initialized'] == '/test3'
|
||||
), 'request initialized event'
|
||||
assert (
|
||||
headers['X-Request-Destroyed'] == '/test2'
|
||||
), 'request destroyed event'
|
||||
assert headers['X-Request-Destroyed'] == '/test2', 'request destroyed event'
|
||||
assert headers['X-Attr-Added'] == 'var=1;', 'attribute added event'
|
||||
assert headers['X-Attr-Removed'] == 'var=2;', 'attribute removed event'
|
||||
assert (
|
||||
headers['X-Attr-Replaced'] == 'var=1;'
|
||||
), 'attribute replaced event'
|
||||
assert headers['X-Attr-Replaced'] == 'var=1;', 'attribute replaced event'
|
||||
|
||||
headers = self.get(url='/test4?var1=1&var2=2&var3=3')['headers']
|
||||
headers = client.get(url='/test4?var1=1&var2=2&var3=3')['headers']
|
||||
|
||||
assert (
|
||||
headers['X-Request-Initialized'] == '/test4'
|
||||
), 'request initialized event'
|
||||
assert (
|
||||
headers['X-Request-Destroyed'] == '/test3'
|
||||
), 'request destroyed event'
|
||||
assert headers['X-Request-Destroyed'] == '/test3', 'request destroyed event'
|
||||
assert headers['X-Attr-Added'] == 'var=1;', 'attribute added event'
|
||||
assert headers['X-Attr-Removed'] == '', 'attribute removed event'
|
||||
assert (
|
||||
headers['X-Attr-Replaced'] == 'var=1;var=2;'
|
||||
), 'attribute replaced event'
|
||||
|
||||
def test_java_application_request_uri_forward(self):
|
||||
self.load('forward')
|
||||
|
||||
resp = self.get(
|
||||
def test_java_application_request_uri_forward():
|
||||
client.load('forward')
|
||||
|
||||
resp = client.get(
|
||||
url='/fwd?uri=%2Fdata%2Ftest%3Furi%3Dnew_uri%26a%3D2%26b%3D3&a=1&c=4'
|
||||
)
|
||||
headers = resp['headers']
|
||||
|
||||
assert (
|
||||
headers['X-REQUEST-Id'] == 'fwd'
|
||||
), 'initial request servlet mapping'
|
||||
assert headers['X-REQUEST-Id'] == 'fwd', 'initial request servlet mapping'
|
||||
assert (
|
||||
headers['X-Forward-To'] == '/data/test?uri=new_uri&a=2&b=3'
|
||||
), 'forwarding triggered'
|
||||
|
@ -574,9 +562,7 @@ class TestJavaApplication(TestApplicationJava):
|
|||
assert headers['X-REQUEST-Param-a'] == '1', 'original a parameter'
|
||||
assert headers['X-REQUEST-Param-c'] == '4', 'original c parameter'
|
||||
|
||||
assert (
|
||||
headers['X-FORWARD-Id'] == 'data'
|
||||
), 'forward request servlet mapping'
|
||||
assert headers['X-FORWARD-Id'] == 'data', 'forward request servlet mapping'
|
||||
assert (
|
||||
headers['X-FORWARD-Request-URI'] == '/data/test'
|
||||
), 'forward request uri'
|
||||
|
@ -624,27 +610,22 @@ class TestJavaApplication(TestApplicationJava):
|
|||
'After forwarding' not in resp['body']
|
||||
), 'cannot add data after forward() call'
|
||||
|
||||
def test_java_application_named_dispatcher_forward(self):
|
||||
self.load('forward')
|
||||
|
||||
resp = self.get(url='/fwd?disp=name&uri=data')
|
||||
def test_java_application_named_dispatcher_forward():
|
||||
client.load('forward')
|
||||
|
||||
resp = client.get(url='/fwd?disp=name&uri=data')
|
||||
headers = resp['headers']
|
||||
|
||||
assert (
|
||||
headers['X-REQUEST-Id'] == 'fwd'
|
||||
), 'initial request servlet mapping'
|
||||
assert headers['X-REQUEST-Id'] == 'fwd', 'initial request servlet mapping'
|
||||
assert headers['X-Forward-To'] == 'data', 'forwarding triggered'
|
||||
|
||||
assert (
|
||||
headers['X-FORWARD-Id'] == 'data'
|
||||
), 'forward request servlet mapping'
|
||||
assert headers['X-FORWARD-Id'] == 'data', 'forward request servlet mapping'
|
||||
assert headers['X-FORWARD-Request-URI'] == '/fwd', 'forward request uri'
|
||||
assert (
|
||||
headers['X-FORWARD-Servlet-Path'] == '/fwd'
|
||||
), 'forward request servlet path'
|
||||
assert (
|
||||
headers['X-FORWARD-Path-Info'] == 'null'
|
||||
), 'forward request path info'
|
||||
assert headers['X-FORWARD-Path-Info'] == 'null', 'forward request path info'
|
||||
assert (
|
||||
headers['X-FORWARD-Query-String'] == 'disp=name&uri=data'
|
||||
), 'forward request query string'
|
||||
|
@ -675,16 +656,15 @@ class TestJavaApplication(TestApplicationJava):
|
|||
'After forwarding' not in resp['body']
|
||||
), 'cannot add data after forward() call'
|
||||
|
||||
def test_java_application_request_uri_include(self):
|
||||
self.load('include')
|
||||
|
||||
resp = self.get(url='/inc?uri=/data/test')
|
||||
def test_java_application_request_uri_include():
|
||||
client.load('include')
|
||||
|
||||
resp = client.get(url='/inc?uri=/data/test')
|
||||
headers = resp['headers']
|
||||
body = resp['body']
|
||||
|
||||
assert (
|
||||
headers['X-REQUEST-Id'] == 'inc'
|
||||
), 'initial request servlet mapping'
|
||||
assert headers['X-REQUEST-Id'] == 'inc', 'initial request servlet mapping'
|
||||
assert headers['X-Include'] == '/data/test', 'including triggered'
|
||||
|
||||
assert (
|
||||
|
@ -707,24 +687,21 @@ class TestJavaApplication(TestApplicationJava):
|
|||
'javax.servlet.include.query_string: null' in body
|
||||
), 'include request query'
|
||||
|
||||
assert (
|
||||
'Before include' in body
|
||||
), 'preserve data added before include() call'
|
||||
assert 'Before include' in body, 'preserve data added before include() call'
|
||||
assert (
|
||||
headers['X-After-Include'] == 'you-should-see-this'
|
||||
), 'add headers after include() call'
|
||||
assert 'After include' in body, 'add data after include() call'
|
||||
|
||||
def test_java_application_named_dispatcher_include(self):
|
||||
self.load('include')
|
||||
|
||||
resp = self.get(url='/inc?disp=name&uri=data')
|
||||
def test_java_application_named_dispatcher_include():
|
||||
client.load('include')
|
||||
|
||||
resp = client.get(url='/inc?disp=name&uri=data')
|
||||
headers = resp['headers']
|
||||
body = resp['body']
|
||||
|
||||
assert (
|
||||
headers['X-REQUEST-Id'] == 'inc'
|
||||
), 'initial request servlet mapping'
|
||||
assert headers['X-REQUEST-Id'] == 'inc', 'initial request servlet mapping'
|
||||
assert headers['X-Include'] == 'data', 'including triggered'
|
||||
|
||||
assert (
|
||||
|
@ -747,18 +724,17 @@ class TestJavaApplication(TestApplicationJava):
|
|||
'javax.servlet.include.query_string: null' in body
|
||||
), 'include request query'
|
||||
|
||||
assert (
|
||||
'Before include' in body
|
||||
), 'preserve data added before include() call'
|
||||
assert 'Before include' in body, 'preserve data added before include() call'
|
||||
assert (
|
||||
headers['X-After-Include'] == 'you-should-see-this'
|
||||
), 'add headers after include() call'
|
||||
assert 'After include' in body, 'add data after include() call'
|
||||
|
||||
def test_java_application_path_translation(self):
|
||||
self.load('path_translation')
|
||||
|
||||
headers = self.get(url='/pt/test?path=/')['headers']
|
||||
def test_java_application_path_translation():
|
||||
client.load('path_translation')
|
||||
|
||||
headers = client.get(url='/pt/test?path=/')['headers']
|
||||
|
||||
assert headers['X-Servlet-Path'] == '/pt', 'matched servlet path'
|
||||
assert headers['X-Path-Info'] == '/test', 'the rest of the path'
|
||||
|
@ -773,7 +749,7 @@ class TestJavaApplication(TestApplicationJava):
|
|||
headers['X-Resource-As-Stream'] == 'null'
|
||||
), 'no resource stream for root path'
|
||||
|
||||
headers = self.get(url='/test?path=/none')['headers']
|
||||
headers = client.get(url='/test?path=/none')['headers']
|
||||
|
||||
assert headers['X-Servlet-Path'] == '/test', 'matched whole path'
|
||||
assert (
|
||||
|
@ -786,39 +762,44 @@ class TestJavaApplication(TestApplicationJava):
|
|||
assert headers['X-Resource-Paths'] == 'null', 'no resource found'
|
||||
assert headers['X-Resource-As-Stream'] == 'null', 'no resource stream'
|
||||
|
||||
def test_java_application_query_string(self):
|
||||
self.load('query_string')
|
||||
|
||||
def test_java_application_query_string():
|
||||
client.load('query_string')
|
||||
|
||||
assert (
|
||||
self.get(url='/?a=b')['headers']['X-Query-String'] == 'a=b'
|
||||
client.get(url='/?a=b')['headers']['X-Query-String'] == 'a=b'
|
||||
), 'query string'
|
||||
|
||||
def test_java_application_query_empty(self):
|
||||
self.load('query_string')
|
||||
|
||||
def test_java_application_query_empty():
|
||||
client.load('query_string')
|
||||
|
||||
assert (
|
||||
self.get(url='/?')['headers']['X-Query-String'] == ''
|
||||
client.get(url='/?')['headers']['X-Query-String'] == ''
|
||||
), 'query string empty'
|
||||
|
||||
def test_java_application_query_absent(self):
|
||||
self.load('query_string')
|
||||
|
||||
def test_java_application_query_absent():
|
||||
client.load('query_string')
|
||||
|
||||
assert (
|
||||
self.get()['headers']['X-Query-String'] == 'null'
|
||||
client.get()['headers']['X-Query-String'] == 'null'
|
||||
), 'query string absent'
|
||||
|
||||
def test_java_application_empty(self):
|
||||
self.load('empty')
|
||||
|
||||
assert self.get()['status'] == 200, 'empty'
|
||||
def test_java_application_empty():
|
||||
client.load('empty')
|
||||
|
||||
def test_java_application_keepalive_body(self):
|
||||
self.load('mirror')
|
||||
assert client.get()['status'] == 200, 'empty'
|
||||
|
||||
assert self.post()['status'] == 200, 'init'
|
||||
|
||||
def test_java_application_keepalive_body():
|
||||
client.load('mirror')
|
||||
|
||||
assert client.post()['status'] == 200, 'init'
|
||||
|
||||
body = '0123456789' * 500
|
||||
(resp, sock) = self.post(
|
||||
(resp, sock) = client.post(
|
||||
headers={
|
||||
'Connection': 'keep-alive',
|
||||
'Content-Type': 'text/html',
|
||||
|
@ -832,7 +813,7 @@ class TestJavaApplication(TestApplicationJava):
|
|||
assert resp['body'] == body, 'keep-alive 1'
|
||||
|
||||
body = '0123456789'
|
||||
resp = self.post(
|
||||
resp = client.post(
|
||||
headers={
|
||||
'Connection': 'close',
|
||||
'Content-Type': 'text/html',
|
||||
|
@ -844,21 +825,24 @@ class TestJavaApplication(TestApplicationJava):
|
|||
|
||||
assert resp['body'] == body, 'keep-alive 2'
|
||||
|
||||
def test_java_application_http_10(self):
|
||||
self.load('empty')
|
||||
|
||||
assert self.get(http_10=True)['status'] == 200, 'HTTP 1.0'
|
||||
def test_java_application_http_10():
|
||||
client.load('empty')
|
||||
|
||||
def test_java_application_no_method(self):
|
||||
self.load('empty')
|
||||
assert client.get(http_10=True)['status'] == 200, 'HTTP 1.0'
|
||||
|
||||
assert self.post()['status'] == 405, 'no method'
|
||||
|
||||
def test_java_application_get_header(self):
|
||||
self.load('get_header')
|
||||
def test_java_application_no_method():
|
||||
client.load('empty')
|
||||
|
||||
assert client.post()['status'] == 405, 'no method'
|
||||
|
||||
|
||||
def test_java_application_get_header():
|
||||
client.load('get_header')
|
||||
|
||||
assert (
|
||||
self.get(
|
||||
client.get(
|
||||
headers={
|
||||
'X-Header': 'blah',
|
||||
'Content-Type': 'text/html',
|
||||
|
@ -869,15 +853,17 @@ class TestJavaApplication(TestApplicationJava):
|
|||
== 'blah'
|
||||
), 'get header'
|
||||
|
||||
def test_java_application_get_header_empty(self):
|
||||
self.load('get_header')
|
||||
|
||||
assert 'X-Reply' not in self.get()['headers'], 'get header empty'
|
||||
def test_java_application_get_header_empty():
|
||||
client.load('get_header')
|
||||
|
||||
def test_java_application_get_headers(self):
|
||||
self.load('get_headers')
|
||||
assert 'X-Reply' not in client.get()['headers'], 'get header empty'
|
||||
|
||||
headers = self.get(
|
||||
|
||||
def test_java_application_get_headers():
|
||||
client.load('get_headers')
|
||||
|
||||
headers = client.get(
|
||||
headers={
|
||||
'X-Header': ['blah', 'blah'],
|
||||
'Content-Type': 'text/html',
|
||||
|
@ -889,15 +875,17 @@ class TestJavaApplication(TestApplicationJava):
|
|||
assert headers['X-Reply-0'] == 'blah', 'get headers'
|
||||
assert headers['X-Reply-1'] == 'blah', 'get headers 2'
|
||||
|
||||
def test_java_application_get_headers_empty(self):
|
||||
self.load('get_headers')
|
||||
|
||||
assert 'X-Reply-0' not in self.get()['headers'], 'get headers empty'
|
||||
def test_java_application_get_headers_empty():
|
||||
client.load('get_headers')
|
||||
|
||||
def test_java_application_get_header_names(self):
|
||||
self.load('get_header_names')
|
||||
assert 'X-Reply-0' not in client.get()['headers'], 'get headers empty'
|
||||
|
||||
headers = self.get()['headers']
|
||||
|
||||
def test_java_application_get_header_names():
|
||||
client.load('get_header_names')
|
||||
|
||||
headers = client.get()['headers']
|
||||
|
||||
assert re.search(
|
||||
r'(?:Host|Connection)', headers['X-Reply-0']
|
||||
|
@ -909,10 +897,11 @@ class TestJavaApplication(TestApplicationJava):
|
|||
headers['X-Reply-0'] != headers['X-Reply-1']
|
||||
), 'get header names not equal'
|
||||
|
||||
def test_java_application_header_int(self):
|
||||
self.load('header_int')
|
||||
|
||||
headers = self.get(
|
||||
def test_java_application_header_int():
|
||||
client.load('header_int')
|
||||
|
||||
headers = client.get(
|
||||
headers={
|
||||
'X-Header': '2',
|
||||
'Content-Type': 'text/html',
|
||||
|
@ -924,12 +913,13 @@ class TestJavaApplication(TestApplicationJava):
|
|||
assert headers['X-Set-Int'] == '1', 'set int header'
|
||||
assert headers['X-Get-Int'] == '2', 'get int header'
|
||||
|
||||
def test_java_application_header_date(self):
|
||||
self.load('header_date')
|
||||
|
||||
def test_java_application_header_date():
|
||||
client.load('header_date')
|
||||
|
||||
date = 'Fri, 15 Mar 2019 14:45:34 GMT'
|
||||
|
||||
headers = self.get(
|
||||
headers = client.get(
|
||||
headers={
|
||||
'X-Header': date,
|
||||
'Content-Type': 'text/html',
|
||||
|
@ -943,8 +933,9 @@ class TestJavaApplication(TestApplicationJava):
|
|||
), 'set date header'
|
||||
assert headers['X-Get-Date'] == date, 'get date header'
|
||||
|
||||
def test_java_application_multipart(self, search_in_file, temp_dir):
|
||||
self.load('multipart')
|
||||
|
||||
def test_java_application_multipart(search_in_file, temp_dir):
|
||||
client.load('multipart')
|
||||
|
||||
reldst = '/uploads'
|
||||
fulldst = f'{temp_dir}{reldst}'
|
||||
|
@ -961,13 +952,13 @@ class TestJavaApplication(TestApplicationJava):
|
|||
'upload': 'Upload',
|
||||
}
|
||||
|
||||
encoded, content_type = self.multipart_encode(fields)
|
||||
encoded, content_type = client.multipart_encode(fields)
|
||||
|
||||
preamble = 'Preamble. Should be ignored.'
|
||||
epilogue = 'Epilogue. Should be ignored.'
|
||||
body = "%s\r\n%s\r\n%s" % (preamble, encoded.decode(), epilogue)
|
||||
body = f'{preamble}\r\n{encoded.decode()}\r\n{epilogue}'
|
||||
|
||||
resp = self.post(
|
||||
resp = client.post(
|
||||
headers={
|
||||
'Content-Type': content_type,
|
||||
'Host': 'localhost',
|
||||
|
@ -979,23 +970,22 @@ class TestJavaApplication(TestApplicationJava):
|
|||
assert resp['status'] == 200, 'multipart status'
|
||||
assert re.search(r'sample\.txt created', resp['body']), 'multipart body'
|
||||
assert (
|
||||
search_in_file(
|
||||
r'^Data from sample file$', name=f'{reldst}/sample.txt'
|
||||
)
|
||||
search_in_file(r'^Data from sample file$', name=f'{reldst}/sample.txt')
|
||||
is not None
|
||||
), 'file created'
|
||||
|
||||
def test_java_application_threads(self):
|
||||
self.load('threads')
|
||||
|
||||
assert 'success' in self.conf(
|
||||
def test_java_application_threads():
|
||||
client.load('threads')
|
||||
|
||||
assert 'success' in client.conf(
|
||||
'4', 'applications/threads/threads'
|
||||
), 'configure 4 threads'
|
||||
|
||||
socks = []
|
||||
|
||||
for _ in range(4):
|
||||
sock = self.get(
|
||||
sock = client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Delay': '2',
|
||||
|
@ -1011,11 +1001,11 @@ class TestJavaApplication(TestApplicationJava):
|
|||
threads = set()
|
||||
|
||||
for sock in socks:
|
||||
resp = self.recvall(sock).decode('utf-8')
|
||||
resp = client.recvall(sock).decode('utf-8')
|
||||
|
||||
self.log_in(resp)
|
||||
client.log_in(resp)
|
||||
|
||||
resp = self._resp_to_dict(resp)
|
||||
resp = client._resp_to_dict(resp)
|
||||
|
||||
assert resp['status'] == 200, 'status'
|
||||
|
||||
|
|
|
@ -2,15 +2,16 @@ import os
|
|||
import subprocess
|
||||
|
||||
import pytest
|
||||
from unit.applications.lang.java import TestApplicationJava
|
||||
from unit.applications.lang.java import ApplicationJava
|
||||
from unit.option import option
|
||||
|
||||
prerequisites = {'modules': {'java': 'all'}, 'privileged_user': True}
|
||||
|
||||
client = ApplicationJava()
|
||||
|
||||
|
||||
class TestJavaIsolationRootfs(TestApplicationJava):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_method_fixture(self, temp_dir):
|
||||
def setup_method_fixture(temp_dir):
|
||||
os.makedirs(f'{temp_dir}/jars')
|
||||
os.makedirs(f'{temp_dir}/tmp')
|
||||
os.chmod(f'{temp_dir}/tmp', 0o777)
|
||||
|
@ -32,7 +33,8 @@ class TestJavaIsolationRootfs(TestApplicationJava):
|
|||
except subprocess.CalledProcessError:
|
||||
pytest.fail("Can't run mount process.")
|
||||
|
||||
def teardown_method(self):
|
||||
yield
|
||||
|
||||
try:
|
||||
subprocess.run(
|
||||
["umount", "--lazy", f"{option.temp_dir}/jars"],
|
||||
|
@ -45,21 +47,20 @@ class TestJavaIsolationRootfs(TestApplicationJava):
|
|||
except subprocess.CalledProcessError:
|
||||
pytest.fail("Can't run umount process.")
|
||||
|
||||
def test_java_isolation_rootfs_chroot_war(self, temp_dir):
|
||||
isolation = {'rootfs': temp_dir}
|
||||
|
||||
self.load('empty_war', isolation=isolation)
|
||||
def test_java_isolation_rootfs_chroot_war(temp_dir):
|
||||
client.load('empty_war', isolation={'rootfs': temp_dir})
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
'"/"',
|
||||
'/config/applications/empty_war/working_directory',
|
||||
)
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
'"/jars"', 'applications/empty_war/unit_jars'
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
'"/java/empty.war"', 'applications/empty_war/webapp'
|
||||
)
|
||||
|
||||
assert self.get()['status'] == 200, 'war'
|
||||
assert client.get()['status'] == 200, 'war'
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,92 +1,101 @@
|
|||
import os
|
||||
|
||||
import pytest
|
||||
from unit.applications.proto import TestApplicationProto
|
||||
from unit.applications.proto import ApplicationProto
|
||||
from unit.option import option
|
||||
from unit.utils import waitforfiles
|
||||
|
||||
prerequisites = {'modules': {'njs': 'any'}}
|
||||
|
||||
client = ApplicationProto()
|
||||
|
||||
|
||||
class TestNJS(TestApplicationProto):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_method_fixture(self, temp_dir):
|
||||
assert 'success' in self.conf(
|
||||
def setup_method_fixture(temp_dir):
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "routes"}},
|
||||
"routes": [{"action": {"share": f"{temp_dir}/assets$uri"}}],
|
||||
}
|
||||
)
|
||||
|
||||
def create_files(self, *files):
|
||||
|
||||
def create_files(*files):
|
||||
assets_dir = f'{option.temp_dir}/assets/'
|
||||
os.makedirs(assets_dir)
|
||||
|
||||
[open(assets_dir + f, 'a') for f in files]
|
||||
waitforfiles(*[assets_dir + f for f in files])
|
||||
|
||||
def set_share(self, share):
|
||||
assert 'success' in self.conf(share, 'routes/0/action/share')
|
||||
|
||||
def check_expression(self, expression, url='/'):
|
||||
self.set_share(f'"`{option.temp_dir}/assets{expression}`"')
|
||||
assert self.get(url=url)['status'] == 200
|
||||
def set_share(share):
|
||||
assert 'success' in client.conf(share, 'routes/0/action/share')
|
||||
|
||||
def test_njs_template_string(self, temp_dir):
|
||||
self.create_files('str', '`string`', '`backtick', 'l1\nl2')
|
||||
|
||||
self.check_expression('/str')
|
||||
self.check_expression('/\\\\`backtick')
|
||||
self.check_expression('/l1\\nl2')
|
||||
def check_expression(expression, url='/'):
|
||||
set_share(f'"`{option.temp_dir}/assets{expression}`"')
|
||||
assert client.get(url=url)['status'] == 200
|
||||
|
||||
self.set_share(f'"{temp_dir}/assets/`string`"')
|
||||
assert self.get()['status'] == 200
|
||||
|
||||
def test_njs_template_expression(self):
|
||||
self.create_files('str', 'localhost')
|
||||
def test_njs_template_string(temp_dir):
|
||||
create_files('str', '`string`', '`backtick', 'l1\nl2')
|
||||
|
||||
self.check_expression('${uri}', '/str')
|
||||
self.check_expression('${uri}${host}')
|
||||
self.check_expression('${uri + host}')
|
||||
self.check_expression('${uri + `${host}`}')
|
||||
check_expression('/str')
|
||||
check_expression('/\\\\`backtick')
|
||||
check_expression('/l1\\nl2')
|
||||
|
||||
def test_njs_iteration(self):
|
||||
self.create_files('Connection,Host', 'close,localhost')
|
||||
set_share(f'"{temp_dir}/assets/`string`"')
|
||||
assert client.get()['status'] == 200
|
||||
|
||||
self.check_expression('/${Object.keys(headers).sort().join()}')
|
||||
self.check_expression('/${Object.values(headers).sort().join()}')
|
||||
|
||||
def test_njs_variables(self, temp_dir):
|
||||
self.create_files('str', 'localhost', '127.0.0.1')
|
||||
def test_njs_template_expression():
|
||||
create_files('str', 'localhost')
|
||||
|
||||
self.check_expression('/${host}')
|
||||
self.check_expression('/${remoteAddr}')
|
||||
self.check_expression('/${headers.Host}')
|
||||
check_expression('${uri}', '/str')
|
||||
check_expression('${uri}${host}')
|
||||
check_expression('${uri + host}')
|
||||
check_expression('${uri + `${host}`}')
|
||||
|
||||
self.set_share(f'"`{temp_dir}/assets/${{cookies.foo}}`"')
|
||||
|
||||
def test_njs_iteration():
|
||||
create_files('Connection,Host', 'close,localhost')
|
||||
|
||||
check_expression('/${Object.keys(headers).sort().join()}')
|
||||
check_expression('/${Object.values(headers).sort().join()}')
|
||||
|
||||
|
||||
def test_njs_variables(temp_dir):
|
||||
create_files('str', 'localhost', '127.0.0.1')
|
||||
|
||||
check_expression('/${host}')
|
||||
check_expression('/${remoteAddr}')
|
||||
check_expression('/${headers.Host}')
|
||||
|
||||
set_share(f'"`{temp_dir}/assets/${{cookies.foo}}`"')
|
||||
assert (
|
||||
self.get(headers={'Cookie': 'foo=str', 'Connection': 'close'})[
|
||||
client.get(headers={'Cookie': 'foo=str', 'Connection': 'close'})[
|
||||
'status'
|
||||
]
|
||||
== 200
|
||||
), 'cookies'
|
||||
|
||||
self.set_share(f'"`{temp_dir}/assets/${{args.foo}}`"')
|
||||
assert self.get(url='/?foo=str')['status'] == 200, 'args'
|
||||
set_share(f'"`{temp_dir}/assets/${{args.foo}}`"')
|
||||
assert client.get(url='/?foo=str')['status'] == 200, 'args'
|
||||
|
||||
def test_njs_invalid(self, skip_alert):
|
||||
|
||||
def test_njs_invalid(skip_alert):
|
||||
skip_alert(r'js exception:')
|
||||
|
||||
def check_invalid(template):
|
||||
assert 'error' in self.conf(template, 'routes/0/action/share')
|
||||
assert 'error' in client.conf(template, 'routes/0/action/share')
|
||||
|
||||
check_invalid('"`a"')
|
||||
check_invalid('"`a``"')
|
||||
check_invalid('"`a`/"')
|
||||
|
||||
def check_invalid_resolve(template):
|
||||
assert 'success' in self.conf(template, 'routes/0/action/share')
|
||||
assert self.get()['status'] == 500
|
||||
assert 'success' in client.conf(template, 'routes/0/action/share')
|
||||
assert client.get()['status'] == 500
|
||||
|
||||
check_invalid_resolve('"`${a}`"')
|
||||
check_invalid_resolve('"`${uri.a.a}`"')
|
||||
|
|
|
@ -1,24 +1,26 @@
|
|||
from unit.applications.proto import TestApplicationProto
|
||||
from unit.applications.proto import ApplicationProto
|
||||
from unit.option import option
|
||||
|
||||
prerequisites = {'modules': {'njs': 'any'}}
|
||||
|
||||
client = ApplicationProto()
|
||||
|
||||
class TestNJSModules(TestApplicationProto):
|
||||
def njs_script_load(self, module, name=None, expect='success'):
|
||||
|
||||
def njs_script_load(module, name=None, expect='success'):
|
||||
if name is None:
|
||||
name = module
|
||||
|
||||
with open(f'{option.test_dir}/njs/{module}/script.js', 'rb') as s:
|
||||
assert expect in self.conf(s.read(), f'/js_modules/{name}')
|
||||
with open(f'{option.test_dir}/njs/{module}/script.js', 'rb') as script:
|
||||
assert expect in client.conf(script.read(), f'/js_modules/{name}')
|
||||
|
||||
def test_njs_modules(self):
|
||||
self.njs_script_load('next')
|
||||
|
||||
assert 'export' in self.conf_get('/js_modules/next')
|
||||
assert 'error' in self.conf_post('"blah"', '/js_modules/next')
|
||||
def test_njs_modules():
|
||||
njs_script_load('next')
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'export' in client.conf_get('/js_modules/next')
|
||||
assert 'error' in client.conf_post('"blah"', '/js_modules/next')
|
||||
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"settings": {"js_module": "next"},
|
||||
"listeners": {"*:7080": {"pass": "routes/first"}},
|
||||
|
@ -28,41 +30,42 @@ class TestNJSModules(TestApplicationProto):
|
|||
},
|
||||
}
|
||||
)
|
||||
assert self.get()['status'] == 200, 'string'
|
||||
assert client.get()['status'] == 200, 'string'
|
||||
|
||||
assert 'success' in self.conf({"js_module": ["next"]}, 'settings')
|
||||
assert self.get()['status'] == 200, 'array'
|
||||
assert 'success' in client.conf({"js_module": ["next"]}, 'settings')
|
||||
assert client.get()['status'] == 200, 'array'
|
||||
|
||||
# add one more value to array
|
||||
|
||||
assert len(self.conf_get('/js_modules').keys()) == 1
|
||||
assert len(client.conf_get('/js_modules').keys()) == 1
|
||||
|
||||
self.njs_script_load('next', 'next_2')
|
||||
njs_script_load('next', 'next_2')
|
||||
|
||||
assert len(self.conf_get('/js_modules').keys()) == 2
|
||||
assert len(client.conf_get('/js_modules').keys()) == 2
|
||||
|
||||
assert 'success' in self.conf_post('"next_2"', 'settings/js_module')
|
||||
assert self.get()['status'] == 200, 'array len 2'
|
||||
assert 'success' in client.conf_post('"next_2"', 'settings/js_module')
|
||||
assert client.get()['status'] == 200, 'array len 2'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
'"`routes/${next_2.route()}`"', 'routes/first/0/action/pass'
|
||||
)
|
||||
assert self.get()['status'] == 200, 'array new'
|
||||
assert client.get()['status'] == 200, 'array new'
|
||||
|
||||
# can't update exsisting script
|
||||
|
||||
self.njs_script_load('global_this', 'next', expect='error')
|
||||
njs_script_load('global_this', 'next', expect='error')
|
||||
|
||||
# delete modules
|
||||
|
||||
assert 'error' in self.conf_delete('/js_modules/next_2')
|
||||
assert 'success' in self.conf_delete('settings/js_module')
|
||||
assert 'success' in self.conf_delete('/js_modules/next_2')
|
||||
assert 'error' in client.conf_delete('/js_modules/next_2')
|
||||
assert 'success' in client.conf_delete('settings/js_module')
|
||||
assert 'success' in client.conf_delete('/js_modules/next_2')
|
||||
|
||||
def test_njs_modules_import(self):
|
||||
self.njs_script_load('import_from')
|
||||
|
||||
assert 'success' in self.conf(
|
||||
def test_njs_modules_import():
|
||||
njs_script_load('import_from')
|
||||
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"settings": {"js_module": "import_from"},
|
||||
"listeners": {"*:7080": {"pass": "routes/first"}},
|
||||
|
@ -74,12 +77,13 @@ class TestNJSModules(TestApplicationProto):
|
|||
},
|
||||
}
|
||||
)
|
||||
assert self.get()['status'] == 200
|
||||
assert client.get()['status'] == 200
|
||||
|
||||
def test_njs_modules_this(self):
|
||||
self.njs_script_load('global_this')
|
||||
|
||||
assert 'success' in self.conf(
|
||||
def test_njs_modules_this():
|
||||
njs_script_load('global_this')
|
||||
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"settings": {"js_module": "global_this"},
|
||||
"listeners": {"*:7080": {"pass": "routes/first"}},
|
||||
|
@ -91,9 +95,10 @@ class TestNJSModules(TestApplicationProto):
|
|||
},
|
||||
}
|
||||
)
|
||||
assert self.get()['status'] == 200
|
||||
assert client.get()['status'] == 200
|
||||
|
||||
def test_njs_modules_invalid(self, skip_alert):
|
||||
|
||||
def test_njs_modules_invalid(skip_alert):
|
||||
skip_alert(r'.*JS compile module.*failed.*')
|
||||
|
||||
self.njs_script_load('invalid', expect='error')
|
||||
njs_script_load('invalid', expect='error')
|
||||
|
|
|
@ -1,45 +1,51 @@
|
|||
import re
|
||||
|
||||
import pytest
|
||||
from unit.applications.lang.node import TestApplicationNode
|
||||
from unit.applications.lang.node import ApplicationNode
|
||||
from unit.utils import waitforfiles
|
||||
|
||||
prerequisites = {'modules': {'node': 'all'}}
|
||||
|
||||
client = ApplicationNode()
|
||||
|
||||
class TestNodeApplication(TestApplicationNode):
|
||||
def assert_basic_application(self):
|
||||
resp = self.get()
|
||||
|
||||
def assert_basic_application():
|
||||
resp = client.get()
|
||||
assert resp['headers']['Content-Type'] == 'text/plain', 'basic header'
|
||||
assert resp['body'] == 'Hello World\n', 'basic body'
|
||||
|
||||
def test_node_application_basic(self):
|
||||
self.load('basic')
|
||||
|
||||
self.assert_basic_application()
|
||||
def test_node_application_basic():
|
||||
client.load('basic')
|
||||
|
||||
def test_node_application_loader_unit_http(self):
|
||||
self.load('loader/unit_http')
|
||||
assert_basic_application()
|
||||
|
||||
self.assert_basic_application()
|
||||
|
||||
def test_node_application_loader_transitive_dependency(self):
|
||||
self.load('loader/transitive_dependency')
|
||||
def test_node_application_loader_unit_http():
|
||||
client.load('loader/unit_http')
|
||||
|
||||
self.assert_basic_application()
|
||||
assert_basic_application()
|
||||
|
||||
def test_node_application_seq(self):
|
||||
self.load('basic')
|
||||
|
||||
assert self.get()['status'] == 200, 'seq'
|
||||
assert self.get()['status'] == 200, 'seq 2'
|
||||
def test_node_application_loader_transitive_dependency():
|
||||
client.load('loader/transitive_dependency')
|
||||
|
||||
def test_node_application_variables(self, date_to_sec_epoch, sec_epoch):
|
||||
self.load('variables')
|
||||
assert_basic_application()
|
||||
|
||||
|
||||
def test_node_application_seq():
|
||||
client.load('basic')
|
||||
|
||||
assert client.get()['status'] == 200, 'seq'
|
||||
assert client.get()['status'] == 200, 'seq 2'
|
||||
|
||||
|
||||
def test_node_application_variables(date_to_sec_epoch, sec_epoch):
|
||||
client.load('variables')
|
||||
|
||||
body = 'Test body string.'
|
||||
|
||||
resp = self.post(
|
||||
resp = client.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Content-Type': 'text/html',
|
||||
|
@ -78,18 +84,20 @@ class TestNodeApplication(TestApplicationNode):
|
|||
}, 'headers'
|
||||
assert resp['body'] == body, 'body'
|
||||
|
||||
def test_node_application_get_variables(self):
|
||||
self.load('get_variables')
|
||||
|
||||
resp = self.get(url='/?var1=val1&var2=&var3')
|
||||
def test_node_application_get_variables():
|
||||
client.load('get_variables')
|
||||
|
||||
resp = client.get(url='/?var1=val1&var2=&var3')
|
||||
assert resp['headers']['X-Var-1'] == 'val1', 'GET variables'
|
||||
assert resp['headers']['X-Var-2'] == '', 'GET variables 2'
|
||||
assert resp['headers']['X-Var-3'] == '', 'GET variables 3'
|
||||
|
||||
def test_node_application_post_variables(self):
|
||||
self.load('post_variables')
|
||||
|
||||
resp = self.post(
|
||||
def test_node_application_post_variables():
|
||||
client.load('post_variables')
|
||||
|
||||
resp = client.post(
|
||||
headers={
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'Host': 'localhost',
|
||||
|
@ -102,23 +110,23 @@ class TestNodeApplication(TestApplicationNode):
|
|||
assert resp['headers']['X-Var-2'] == '', 'POST variables 2'
|
||||
assert resp['headers']['X-Var-3'] == '', 'POST variables 3'
|
||||
|
||||
def test_node_application_404(self):
|
||||
self.load('404')
|
||||
|
||||
resp = self.get()
|
||||
def test_node_application_404():
|
||||
client.load('404')
|
||||
|
||||
resp = client.get()
|
||||
|
||||
assert resp['status'] == 404, '404 status'
|
||||
assert re.search(
|
||||
r'<title>404 Not Found</title>', resp['body']
|
||||
), '404 body'
|
||||
assert re.search(r'<title>404 Not Found</title>', resp['body']), '404 body'
|
||||
|
||||
def test_node_keepalive_body(self):
|
||||
self.load('mirror')
|
||||
|
||||
assert self.get()['status'] == 200, 'init'
|
||||
def test_node_keepalive_body():
|
||||
client.load('mirror')
|
||||
|
||||
assert client.get()['status'] == 200, 'init'
|
||||
|
||||
body = '0123456789' * 500
|
||||
(resp, sock) = self.post(
|
||||
(resp, sock) = client.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Connection': 'keep-alive',
|
||||
|
@ -131,41 +139,47 @@ class TestNodeApplication(TestApplicationNode):
|
|||
assert resp['body'] == '0123456789' * 500, 'keep-alive 1'
|
||||
|
||||
body = '0123456789'
|
||||
resp = self.post(sock=sock, body=body)
|
||||
resp = client.post(sock=sock, body=body)
|
||||
|
||||
assert resp['body'] == body, 'keep-alive 2'
|
||||
|
||||
def test_node_application_write_buffer(self):
|
||||
self.load('write_buffer')
|
||||
|
||||
assert self.get()['body'] == 'buffer', 'write buffer'
|
||||
def test_node_application_write_buffer():
|
||||
client.load('write_buffer')
|
||||
|
||||
def test_node_application_write_callback(self, temp_dir):
|
||||
self.load('write_callback')
|
||||
assert client.get()['body'] == 'buffer', 'write buffer'
|
||||
|
||||
assert self.get()['body'] == 'helloworld', 'write callback order'
|
||||
|
||||
def test_node_application_write_callback(temp_dir):
|
||||
client.load('write_callback')
|
||||
|
||||
assert client.get()['body'] == 'helloworld', 'write callback order'
|
||||
assert waitforfiles(f'{temp_dir}/node/callback'), 'write callback'
|
||||
|
||||
def test_node_application_write_before_write_head(self):
|
||||
self.load('write_before_write_head')
|
||||
|
||||
assert self.get()['status'] == 200, 'write before writeHead'
|
||||
def test_node_application_write_before_write_head():
|
||||
client.load('write_before_write_head')
|
||||
|
||||
def test_node_application_double_end(self):
|
||||
self.load('double_end')
|
||||
assert client.get()['status'] == 200, 'write before writeHead'
|
||||
|
||||
assert self.get()['status'] == 200, 'double end'
|
||||
assert self.get()['status'] == 200, 'double end 2'
|
||||
|
||||
def test_node_application_write_return(self):
|
||||
self.load('write_return')
|
||||
def test_node_application_double_end():
|
||||
client.load('double_end')
|
||||
|
||||
assert self.get()['body'] == 'bodytrue', 'write return'
|
||||
assert client.get()['status'] == 200, 'double end'
|
||||
assert client.get()['status'] == 200, 'double end 2'
|
||||
|
||||
def test_node_application_remove_header(self):
|
||||
self.load('remove_header')
|
||||
|
||||
resp = self.get(
|
||||
def test_node_application_write_return():
|
||||
client.load('write_return')
|
||||
|
||||
assert client.get()['body'] == 'bodytrue', 'write return'
|
||||
|
||||
|
||||
def test_node_application_remove_header():
|
||||
client.load('remove_header')
|
||||
|
||||
resp = client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Remove': 'X-Header',
|
||||
|
@ -176,11 +190,12 @@ class TestNodeApplication(TestApplicationNode):
|
|||
assert resp['headers']['Has-Header'] == 'false', 'has header'
|
||||
assert not ('X-Header' in resp['headers']), 'remove header'
|
||||
|
||||
def test_node_application_remove_header_nonexisting(self):
|
||||
self.load('remove_header')
|
||||
|
||||
def test_node_application_remove_header_nonexisting():
|
||||
client.load('remove_header')
|
||||
|
||||
assert (
|
||||
self.get(
|
||||
client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Remove': 'blah',
|
||||
|
@ -190,44 +205,50 @@ class TestNodeApplication(TestApplicationNode):
|
|||
== 'true'
|
||||
), 'remove header nonexisting'
|
||||
|
||||
def test_node_application_update_header(self):
|
||||
self.load('update_header')
|
||||
|
||||
assert self.get()['headers']['X-Header'] == 'new', 'update header'
|
||||
def test_node_application_update_header():
|
||||
client.load('update_header')
|
||||
|
||||
def test_node_application_set_header_array(self):
|
||||
self.load('set_header_array')
|
||||
assert client.get()['headers']['X-Header'] == 'new', 'update header'
|
||||
|
||||
assert self.get()['headers']['Set-Cookie'] == [
|
||||
|
||||
def test_node_application_set_header_array():
|
||||
client.load('set_header_array')
|
||||
|
||||
assert client.get()['headers']['Set-Cookie'] == [
|
||||
'tc=one,two,three',
|
||||
'tc=four,five,six',
|
||||
], 'set header array'
|
||||
|
||||
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_node_application_status_message(self):
|
||||
self.load('status_message')
|
||||
def test_node_application_status_message():
|
||||
client.load('status_message')
|
||||
|
||||
assert re.search(r'200 blah', self.get(raw_resp=True)), 'status message'
|
||||
assert re.search(r'200 blah', client.get(raw_resp=True)), 'status message'
|
||||
|
||||
def test_node_application_get_header_type(self):
|
||||
self.load('get_header_type')
|
||||
|
||||
assert self.get()['headers']['X-Type'] == 'number', 'get header type'
|
||||
def test_node_application_get_header_type():
|
||||
client.load('get_header_type')
|
||||
|
||||
def test_node_application_header_name_case(self):
|
||||
self.load('header_name_case')
|
||||
assert client.get()['headers']['X-Type'] == 'number', 'get header type'
|
||||
|
||||
headers = self.get()['headers']
|
||||
|
||||
def test_node_application_header_name_case():
|
||||
client.load('header_name_case')
|
||||
|
||||
headers = client.get()['headers']
|
||||
|
||||
assert headers['X-HEADER'] == '3', 'header value'
|
||||
assert 'X-Header' not in headers, 'insensitive'
|
||||
assert 'X-header' not in headers, 'insensitive 2'
|
||||
|
||||
def test_node_application_promise_handler_write_after_end(self):
|
||||
self.load('promise_handler')
|
||||
|
||||
def test_node_application_promise_handler_write_after_end():
|
||||
client.load('promise_handler')
|
||||
|
||||
assert (
|
||||
self.post(
|
||||
client.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Content-Type': 'text/html',
|
||||
|
@ -239,11 +260,12 @@ class TestNodeApplication(TestApplicationNode):
|
|||
== 200
|
||||
), 'promise handler request write after end'
|
||||
|
||||
def test_node_application_promise_end(self, temp_dir):
|
||||
self.load('promise_end')
|
||||
|
||||
def test_node_application_promise_end(temp_dir):
|
||||
client.load('promise_end')
|
||||
|
||||
assert (
|
||||
self.post(
|
||||
client.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Content-Type': 'text/html',
|
||||
|
@ -255,30 +277,34 @@ class TestNodeApplication(TestApplicationNode):
|
|||
), 'promise end request'
|
||||
assert waitforfiles(f'{temp_dir}/node/callback'), 'promise end'
|
||||
|
||||
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_node_application_header_name_valid(self):
|
||||
self.load('header_name_valid')
|
||||
def test_node_application_header_name_valid():
|
||||
client.load('header_name_valid')
|
||||
|
||||
assert 'status' not in self.get(), 'header name valid'
|
||||
assert 'status' not in client.get(), 'header name valid'
|
||||
|
||||
def test_node_application_header_value_object(self):
|
||||
self.load('header_value_object')
|
||||
|
||||
assert 'X-Header' in self.get()['headers'], 'header value object'
|
||||
def test_node_application_header_value_object():
|
||||
client.load('header_value_object')
|
||||
|
||||
def test_node_application_get_header_names(self):
|
||||
self.load('get_header_names')
|
||||
assert 'X-Header' in client.get()['headers'], 'header value object'
|
||||
|
||||
assert self.get()['headers']['X-Names'] == [
|
||||
|
||||
def test_node_application_get_header_names():
|
||||
client.load('get_header_names')
|
||||
|
||||
assert client.get()['headers']['X-Names'] == [
|
||||
'date',
|
||||
'x-header',
|
||||
], 'get header names'
|
||||
|
||||
def test_node_application_has_header(self):
|
||||
self.load('has_header')
|
||||
|
||||
def test_node_application_has_header():
|
||||
client.load('has_header')
|
||||
|
||||
assert (
|
||||
self.get(
|
||||
client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Header': 'length',
|
||||
|
@ -289,7 +315,7 @@ class TestNodeApplication(TestApplicationNode):
|
|||
), 'has header length'
|
||||
|
||||
assert (
|
||||
self.get(
|
||||
client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Header': 'Date',
|
||||
|
@ -299,7 +325,8 @@ class TestNodeApplication(TestApplicationNode):
|
|||
== 'false'
|
||||
), 'has header date'
|
||||
|
||||
def test_node_application_write_multiple(self):
|
||||
self.load('write_multiple')
|
||||
|
||||
assert self.get()['body'] == 'writewrite2end', 'write multiple'
|
||||
def test_node_application_write_multiple():
|
||||
client.load('write_multiple')
|
||||
|
||||
assert client.get()['body'] == 'writewrite2end', 'write multiple'
|
||||
|
|
|
@ -1,45 +1,47 @@
|
|||
from packaging import version
|
||||
from unit.applications.lang.node import TestApplicationNode
|
||||
from unit.applications.websockets import TestApplicationWebsocket
|
||||
from unit.applications.lang.node import ApplicationNode
|
||||
from unit.applications.websockets import ApplicationWebsocket
|
||||
|
||||
prerequisites = {
|
||||
'modules': {'node': lambda v: version.parse(v) >= version.parse('14.16.0')}
|
||||
}
|
||||
|
||||
client = ApplicationNode(es_modules=True)
|
||||
ws = ApplicationWebsocket()
|
||||
|
||||
class TestNodeESModules(TestApplicationNode):
|
||||
es_modules = True
|
||||
ws = TestApplicationWebsocket()
|
||||
|
||||
def assert_basic_application(self):
|
||||
resp = self.get()
|
||||
def assert_basic_application():
|
||||
resp = client.get()
|
||||
assert resp['headers']['Content-Type'] == 'text/plain', 'basic header'
|
||||
assert resp['body'] == 'Hello World\n', 'basic body'
|
||||
|
||||
def test_node_es_modules_loader_http(self):
|
||||
self.load('loader/es_modules_http', name="app.mjs")
|
||||
|
||||
self.assert_basic_application()
|
||||
def test_node_es_modules_loader_http():
|
||||
client.load('loader/es_modules_http', name="app.mjs")
|
||||
|
||||
def test_node_es_modules_loader_http_indirect(self):
|
||||
self.load('loader/es_modules_http_indirect', name="app.js")
|
||||
assert_basic_application()
|
||||
|
||||
self.assert_basic_application()
|
||||
|
||||
def test_node_es_modules_loader_websockets(self):
|
||||
self.load('loader/es_modules_websocket', name="app.mjs")
|
||||
def test_node_es_modules_loader_http_indirect():
|
||||
client.load('loader/es_modules_http_indirect', name="app.js")
|
||||
|
||||
assert_basic_application()
|
||||
|
||||
|
||||
def test_node_es_modules_loader_websockets():
|
||||
client.load('loader/es_modules_websocket', name="app.mjs")
|
||||
|
||||
message = 'blah'
|
||||
|
||||
_, sock, _ = self.ws.upgrade()
|
||||
_, sock, _ = ws.upgrade()
|
||||
|
||||
self.ws.frame_write(sock, self.ws.OP_TEXT, message)
|
||||
frame = self.ws.frame_read(sock)
|
||||
ws.frame_write(sock, ws.OP_TEXT, message)
|
||||
frame = ws.frame_read(sock)
|
||||
|
||||
assert message == frame['data'].decode('utf-8'), 'mirror'
|
||||
|
||||
self.ws.frame_write(sock, self.ws.OP_TEXT, message)
|
||||
frame = self.ws.frame_read(sock)
|
||||
ws.frame_write(sock, ws.OP_TEXT, message)
|
||||
frame = ws.frame_read(sock)
|
||||
|
||||
assert message == frame['data'].decode('utf-8'), 'mirror 2'
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,18 +1,19 @@
|
|||
import re
|
||||
|
||||
import pytest
|
||||
from unit.applications.lang.perl import TestApplicationPerl
|
||||
from unit.applications.lang.perl import ApplicationPerl
|
||||
|
||||
prerequisites = {'modules': {'perl': 'all'}}
|
||||
|
||||
client = ApplicationPerl()
|
||||
|
||||
class TestPerlApplication(TestApplicationPerl):
|
||||
def test_perl_application(self, date_to_sec_epoch, sec_epoch):
|
||||
self.load('variables')
|
||||
|
||||
def test_perl_application(date_to_sec_epoch, sec_epoch):
|
||||
client.load('variables')
|
||||
|
||||
body = 'Test body string.'
|
||||
|
||||
resp = self.post(
|
||||
resp = client.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Content-Type': 'text/html',
|
||||
|
@ -53,149 +54,170 @@ class TestPerlApplication(TestApplicationPerl):
|
|||
}, 'headers'
|
||||
assert resp['body'] == body, 'body'
|
||||
|
||||
def test_perl_application_query_string(self):
|
||||
self.load('query_string')
|
||||
|
||||
resp = self.get(url='/?var1=val1&var2=val2')
|
||||
def test_perl_application_query_string():
|
||||
client.load('query_string')
|
||||
|
||||
resp = client.get(url='/?var1=val1&var2=val2')
|
||||
|
||||
assert (
|
||||
resp['headers']['Query-String'] == 'var1=val1&var2=val2'
|
||||
), 'Query-String header'
|
||||
|
||||
def test_perl_application_query_string_empty(self):
|
||||
self.load('query_string')
|
||||
|
||||
resp = self.get(url='/?')
|
||||
def test_perl_application_query_string_empty():
|
||||
client.load('query_string')
|
||||
|
||||
resp = client.get(url='/?')
|
||||
|
||||
assert resp['status'] == 200, 'query string empty status'
|
||||
assert resp['headers']['Query-String'] == '', 'query string empty'
|
||||
|
||||
def test_perl_application_query_string_absent(self):
|
||||
self.load('query_string')
|
||||
|
||||
resp = self.get()
|
||||
def test_perl_application_query_string_absent():
|
||||
client.load('query_string')
|
||||
|
||||
resp = client.get()
|
||||
|
||||
assert resp['status'] == 200, 'query string absent status'
|
||||
assert resp['headers']['Query-String'] == '', 'query string absent'
|
||||
|
||||
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_perl_application_server_port(self):
|
||||
self.load('server_port')
|
||||
def test_perl_application_server_port():
|
||||
client.load('server_port')
|
||||
|
||||
assert (
|
||||
self.get()['headers']['Server-Port'] == '7080'
|
||||
client.get()['headers']['Server-Port'] == '7080'
|
||||
), 'Server-Port header'
|
||||
|
||||
def test_perl_application_input_read_empty(self):
|
||||
self.load('input_read_empty')
|
||||
|
||||
assert self.get()['body'] == '', 'read empty'
|
||||
def test_perl_application_input_read_empty():
|
||||
client.load('input_read_empty')
|
||||
|
||||
def test_perl_application_input_read_parts(self):
|
||||
self.load('input_read_parts')
|
||||
assert client.get()['body'] == '', 'read empty'
|
||||
|
||||
|
||||
def test_perl_application_input_read_parts():
|
||||
client.load('input_read_parts')
|
||||
|
||||
assert (
|
||||
self.post(body='0123456789')['body'] == '0123456789'
|
||||
client.post(body='0123456789')['body'] == '0123456789'
|
||||
), 'input read parts'
|
||||
|
||||
def test_perl_application_input_buffered_read(self):
|
||||
self.load('input_buffered_read')
|
||||
|
||||
assert self.post(body='012345')['body'] == '012345', 'buffered read #1'
|
||||
def test_perl_application_input_buffered_read():
|
||||
client.load('input_buffered_read')
|
||||
|
||||
assert client.post(body='012345')['body'] == '012345', 'buffered read #1'
|
||||
assert (
|
||||
self.post(body='9876543210')['body'] == '9876543210'
|
||||
client.post(body='9876543210')['body'] == '9876543210'
|
||||
), 'buffered read #2'
|
||||
|
||||
def test_perl_application_input_close(self):
|
||||
self.load('input_close')
|
||||
|
||||
assert self.post(body='012345')['body'] == '012345', 'input close #1'
|
||||
def test_perl_application_input_close():
|
||||
client.load('input_close')
|
||||
|
||||
assert client.post(body='012345')['body'] == '012345', 'input close #1'
|
||||
assert (
|
||||
self.post(body='9876543210')['body'] == '9876543210'
|
||||
client.post(body='9876543210')['body'] == '9876543210'
|
||||
), 'input close #2'
|
||||
|
||||
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_perl_application_input_read_offset(self):
|
||||
self.load('input_read_offset')
|
||||
def test_perl_application_input_read_offset():
|
||||
client.load('input_read_offset')
|
||||
|
||||
assert self.post(body='0123456789')['body'] == '4567', 'read offset'
|
||||
assert client.post(body='0123456789')['body'] == '4567', 'read offset'
|
||||
|
||||
def test_perl_application_input_copy(self):
|
||||
self.load('input_copy')
|
||||
|
||||
def test_perl_application_input_copy():
|
||||
client.load('input_copy')
|
||||
|
||||
body = '0123456789'
|
||||
assert self.post(body=body)['body'] == body, 'input copy'
|
||||
assert client.post(body=body)['body'] == body, 'input copy'
|
||||
|
||||
def test_perl_application_errors_print(self, wait_for_record):
|
||||
self.load('errors_print')
|
||||
|
||||
assert self.get()['body'] == '1', 'errors result'
|
||||
def test_perl_application_errors_print(wait_for_record):
|
||||
client.load('errors_print')
|
||||
|
||||
assert client.get()['body'] == '1', 'errors result'
|
||||
|
||||
assert (
|
||||
wait_for_record(r'\[error\].+Error in application') is not None
|
||||
), 'errors print'
|
||||
|
||||
def test_perl_application_header_equal_names(self):
|
||||
self.load('header_equal_names')
|
||||
|
||||
assert self.get()['headers']['Set-Cookie'] == [
|
||||
def test_perl_application_header_equal_names():
|
||||
client.load('header_equal_names')
|
||||
|
||||
assert client.get()['headers']['Set-Cookie'] == [
|
||||
'tc=one,two,three',
|
||||
'tc=four,five,six',
|
||||
], 'header equal names'
|
||||
|
||||
def test_perl_application_header_pairs(self):
|
||||
self.load('header_pairs')
|
||||
|
||||
assert self.get()['headers']['blah'] == 'blah', 'header pairs'
|
||||
def test_perl_application_header_pairs():
|
||||
client.load('header_pairs')
|
||||
|
||||
def test_perl_application_body_empty(self):
|
||||
self.load('body_empty')
|
||||
assert client.get()['headers']['blah'] == 'blah', 'header pairs'
|
||||
|
||||
assert self.get()['body'] == '', 'body empty'
|
||||
|
||||
def test_perl_application_body_array(self):
|
||||
self.load('body_array')
|
||||
def test_perl_application_body_empty():
|
||||
client.load('body_empty')
|
||||
|
||||
assert self.get()['body'] == '0123456789', 'body array'
|
||||
assert client.get()['body'] == '', 'body empty'
|
||||
|
||||
def test_perl_application_body_large(self):
|
||||
self.load('variables')
|
||||
|
||||
def test_perl_application_body_array():
|
||||
client.load('body_array')
|
||||
|
||||
assert client.get()['body'] == '0123456789', 'body array'
|
||||
|
||||
|
||||
def test_perl_application_body_large():
|
||||
client.load('variables')
|
||||
|
||||
body = '0123456789' * 1000
|
||||
|
||||
resp = self.post(body=body)['body']
|
||||
resp = client.post(body=body)['body']
|
||||
|
||||
assert resp == body, 'body large'
|
||||
|
||||
def test_perl_application_body_io_empty(self):
|
||||
self.load('body_io_empty')
|
||||
|
||||
assert self.get()['status'] == 200, 'body io empty'
|
||||
def test_perl_application_body_io_empty():
|
||||
client.load('body_io_empty')
|
||||
|
||||
def test_perl_application_body_io_file(self):
|
||||
self.load('body_io_file')
|
||||
assert client.get()['status'] == 200, 'body io empty'
|
||||
|
||||
assert self.get()['body'] == 'body\n', 'body io file'
|
||||
|
||||
def test_perl_streaming_body_multiple_responses(self):
|
||||
self.load('streaming_body_multiple_responses')
|
||||
def test_perl_application_body_io_file():
|
||||
client.load('body_io_file')
|
||||
|
||||
assert client.get()['body'] == 'body\n', 'body io file'
|
||||
|
||||
|
||||
def test_perl_streaming_body_multiple_responses():
|
||||
client.load('streaming_body_multiple_responses')
|
||||
|
||||
assert client.get()['status'] == 200
|
||||
|
||||
assert self.get()['status'] == 200
|
||||
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_perl_application_syntax_error(self, skip_alert):
|
||||
def test_perl_application_syntax_error(skip_alert):
|
||||
skip_alert(r'PSGI: Failed to parse script')
|
||||
self.load('syntax_error')
|
||||
client.load('syntax_error')
|
||||
|
||||
assert self.get()['status'] == 500, 'syntax error'
|
||||
assert client.get()['status'] == 500, 'syntax error'
|
||||
|
||||
def test_perl_keepalive_body(self):
|
||||
self.load('variables')
|
||||
|
||||
assert self.get()['status'] == 200, 'init'
|
||||
def test_perl_keepalive_body():
|
||||
client.load('variables')
|
||||
|
||||
assert client.get()['status'] == 200, 'init'
|
||||
|
||||
body = '0123456789' * 500
|
||||
(resp, sock) = self.post(
|
||||
(resp, sock) = client.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Connection': 'keep-alive',
|
||||
|
@ -209,7 +231,7 @@ class TestPerlApplication(TestApplicationPerl):
|
|||
assert resp['body'] == body, 'keep-alive 1'
|
||||
|
||||
body = '0123456789'
|
||||
resp = self.post(
|
||||
resp = client.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Connection': 'close',
|
||||
|
@ -221,10 +243,11 @@ class TestPerlApplication(TestApplicationPerl):
|
|||
|
||||
assert resp['body'] == body, 'keep-alive 2'
|
||||
|
||||
def test_perl_body_io_fake(self, wait_for_record):
|
||||
self.load('body_io_fake')
|
||||
|
||||
assert self.get()['body'] == '21', 'body io fake'
|
||||
def test_perl_body_io_fake(wait_for_record):
|
||||
client.load('body_io_fake')
|
||||
|
||||
assert client.get()['body'] == '21', 'body io fake'
|
||||
|
||||
assert (
|
||||
wait_for_record(r'\[error\].+IOFake getline\(\) \$\/ is \d+')
|
||||
|
@ -235,33 +258,36 @@ class TestPerlApplication(TestApplicationPerl):
|
|||
wait_for_record(r'\[error\].+IOFake close\(\) called') is not None
|
||||
), 'body io fake close'
|
||||
|
||||
def test_perl_delayed_response(self):
|
||||
self.load('delayed_response')
|
||||
|
||||
resp = self.get()
|
||||
def test_perl_delayed_response():
|
||||
client.load('delayed_response')
|
||||
|
||||
resp = client.get()
|
||||
|
||||
assert resp['status'] == 200, 'status'
|
||||
assert resp['body'] == 'Hello World!', 'body'
|
||||
|
||||
def test_perl_streaming_body(self):
|
||||
self.load('streaming_body')
|
||||
|
||||
resp = self.get()
|
||||
def test_perl_streaming_body():
|
||||
client.load('streaming_body')
|
||||
|
||||
resp = client.get()
|
||||
|
||||
assert resp['status'] == 200, 'status'
|
||||
assert resp['body'] == 'Hello World!', 'body'
|
||||
|
||||
def test_perl_application_threads(self):
|
||||
self.load('threads')
|
||||
|
||||
assert 'success' in self.conf(
|
||||
def test_perl_application_threads():
|
||||
client.load('threads')
|
||||
|
||||
assert 'success' in client.conf(
|
||||
'4', 'applications/threads/threads'
|
||||
), 'configure 4 threads'
|
||||
|
||||
socks = []
|
||||
|
||||
for _ in range(4):
|
||||
sock = self.get(
|
||||
sock = client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Delay': '2',
|
||||
|
@ -275,11 +301,11 @@ class TestPerlApplication(TestApplicationPerl):
|
|||
threads = set()
|
||||
|
||||
for sock in socks:
|
||||
resp = self.recvall(sock).decode('utf-8')
|
||||
resp = client.recvall(sock).decode('utf-8')
|
||||
|
||||
self.log_in(resp)
|
||||
client.log_in(resp)
|
||||
|
||||
resp = self._resp_to_dict(resp)
|
||||
resp = client._resp_to_dict(resp)
|
||||
|
||||
assert resp['status'] == 200, 'status'
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,9 +1,9 @@
|
|||
from unit.control import TestControl
|
||||
from unit.control import Control
|
||||
|
||||
prerequisites = {'modules': {'php': 'any'}}
|
||||
|
||||
client = Control()
|
||||
|
||||
class TestPHPBasic(TestControl):
|
||||
conf_app = {
|
||||
"app": {
|
||||
"type": "php",
|
||||
|
@ -18,10 +18,11 @@ class TestPHPBasic(TestControl):
|
|||
"applications": conf_app,
|
||||
}
|
||||
|
||||
def test_php_get_applications(self):
|
||||
assert 'success' in self.conf(self.conf_app, 'applications')
|
||||
|
||||
conf = self.conf_get()
|
||||
def test_php_get_applications():
|
||||
assert 'success' in client.conf(conf_app, 'applications')
|
||||
|
||||
conf = client.conf_get()
|
||||
|
||||
assert conf['listeners'] == {}, 'listeners'
|
||||
assert conf['applications'] == {
|
||||
|
@ -33,7 +34,7 @@ class TestPHPBasic(TestControl):
|
|||
}
|
||||
}, 'applications'
|
||||
|
||||
assert self.conf_get('applications') == {
|
||||
assert client.conf_get('applications') == {
|
||||
"app": {
|
||||
"type": "php",
|
||||
"processes": {"spare": 0},
|
||||
|
@ -42,82 +43,88 @@ class TestPHPBasic(TestControl):
|
|||
}
|
||||
}, 'applications prefix'
|
||||
|
||||
assert self.conf_get('applications/app') == {
|
||||
assert client.conf_get('applications/app') == {
|
||||
"type": "php",
|
||||
"processes": {"spare": 0},
|
||||
"root": "/app",
|
||||
"index": "index.php",
|
||||
}, 'applications prefix 2'
|
||||
|
||||
assert self.conf_get('applications/app/type') == 'php', 'type'
|
||||
assert client.conf_get('applications/app/type') == 'php', 'type'
|
||||
assert (
|
||||
self.conf_get('applications/app/processes/spare') == 0
|
||||
client.conf_get('applications/app/processes/spare') == 0
|
||||
), 'spare processes'
|
||||
|
||||
def test_php_get_listeners(self):
|
||||
assert 'success' in self.conf(self.conf_basic)
|
||||
|
||||
assert self.conf_get()['listeners'] == {
|
||||
def test_php_get_listeners():
|
||||
assert 'success' in client.conf(conf_basic)
|
||||
|
||||
assert client.conf_get()['listeners'] == {
|
||||
"*:7080": {"pass": "applications/app"}
|
||||
}, 'listeners'
|
||||
|
||||
assert self.conf_get('listeners') == {
|
||||
assert client.conf_get('listeners') == {
|
||||
"*:7080": {"pass": "applications/app"}
|
||||
}, 'listeners prefix'
|
||||
|
||||
assert self.conf_get('listeners/*:7080') == {
|
||||
assert client.conf_get('listeners/*:7080') == {
|
||||
"pass": "applications/app"
|
||||
}, 'listeners prefix 2'
|
||||
|
||||
def test_php_change_listener(self):
|
||||
assert 'success' in self.conf(self.conf_basic)
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def test_php_change_listener():
|
||||
assert 'success' in client.conf(conf_basic)
|
||||
assert 'success' in client.conf(
|
||||
{"*:7081": {"pass": "applications/app"}}, 'listeners'
|
||||
)
|
||||
|
||||
assert self.conf_get('listeners') == {
|
||||
assert client.conf_get('listeners') == {
|
||||
"*:7081": {"pass": "applications/app"}
|
||||
}, 'change listener'
|
||||
|
||||
def test_php_add_listener(self):
|
||||
assert 'success' in self.conf(self.conf_basic)
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def test_php_add_listener():
|
||||
assert 'success' in client.conf(conf_basic)
|
||||
assert 'success' in client.conf(
|
||||
{"pass": "applications/app"}, 'listeners/*:7082'
|
||||
)
|
||||
|
||||
assert self.conf_get('listeners') == {
|
||||
assert client.conf_get('listeners') == {
|
||||
"*:7080": {"pass": "applications/app"},
|
||||
"*:7082": {"pass": "applications/app"},
|
||||
}, 'add listener'
|
||||
|
||||
def test_php_change_application(self):
|
||||
assert 'success' in self.conf(self.conf_basic)
|
||||
|
||||
assert 'success' in self.conf('30', 'applications/app/processes/max')
|
||||
def test_php_change_application():
|
||||
assert 'success' in client.conf(conf_basic)
|
||||
|
||||
assert 'success' in client.conf('30', 'applications/app/processes/max')
|
||||
assert (
|
||||
self.conf_get('applications/app/processes/max') == 30
|
||||
client.conf_get('applications/app/processes/max') == 30
|
||||
), 'change application max'
|
||||
|
||||
assert 'success' in self.conf('"/www"', 'applications/app/root')
|
||||
assert 'success' in client.conf('"/www"', 'applications/app/root')
|
||||
assert (
|
||||
self.conf_get('applications/app/root') == '/www'
|
||||
client.conf_get('applications/app/root') == '/www'
|
||||
), 'change application root'
|
||||
|
||||
def test_php_delete(self):
|
||||
assert 'success' in self.conf(self.conf_basic)
|
||||
|
||||
assert 'error' in self.conf_delete('applications/app')
|
||||
assert 'success' in self.conf_delete('listeners/*:7080')
|
||||
assert 'success' in self.conf_delete('applications/app')
|
||||
assert 'error' in self.conf_delete('applications/app')
|
||||
def test_php_delete():
|
||||
assert 'success' in client.conf(conf_basic)
|
||||
|
||||
def test_php_delete_blocks(self):
|
||||
assert 'success' in self.conf(self.conf_basic)
|
||||
assert 'error' in client.conf_delete('applications/app')
|
||||
assert 'success' in client.conf_delete('listeners/*:7080')
|
||||
assert 'success' in client.conf_delete('applications/app')
|
||||
assert 'error' in client.conf_delete('applications/app')
|
||||
|
||||
assert 'success' in self.conf_delete('listeners')
|
||||
assert 'success' in self.conf_delete('applications')
|
||||
|
||||
assert 'success' in self.conf(self.conf_app, 'applications')
|
||||
assert 'success' in self.conf(
|
||||
def test_php_delete_blocks():
|
||||
assert 'success' in client.conf(conf_basic)
|
||||
|
||||
assert 'success' in client.conf_delete('listeners')
|
||||
assert 'success' in client.conf_delete('applications')
|
||||
|
||||
assert 'success' in client.conf(conf_app, 'applications')
|
||||
assert 'success' in client.conf(
|
||||
{"*:7081": {"pass": "applications/app"}}, 'listeners'
|
||||
), 'applications restore'
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
from unit.applications.lang.php import TestApplicationPHP
|
||||
from unit.applications.lang.php import ApplicationPHP
|
||||
|
||||
prerequisites = {'modules': {'php': 'any'}, 'features': {'isolation': True}}
|
||||
|
||||
client = ApplicationPHP()
|
||||
|
||||
class TestPHPIsolation(TestApplicationPHP):
|
||||
def test_php_isolation_rootfs(self, is_su, require, temp_dir):
|
||||
|
||||
def test_php_isolation_rootfs(is_su, require, temp_dir):
|
||||
isolation = {'rootfs': temp_dir}
|
||||
|
||||
if not is_su:
|
||||
|
@ -27,18 +28,19 @@ class TestPHPIsolation(TestApplicationPHP):
|
|||
'pid': True,
|
||||
}
|
||||
|
||||
self.load('phpinfo', isolation=isolation)
|
||||
client.load('phpinfo', isolation=isolation)
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
'"/app/php/phpinfo"', 'applications/phpinfo/root'
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
'"/app/php/phpinfo"', 'applications/phpinfo/working_directory'
|
||||
)
|
||||
|
||||
assert self.get()['status'] == 200, 'empty rootfs'
|
||||
assert client.get()['status'] == 200, 'empty rootfs'
|
||||
|
||||
def test_php_isolation_rootfs_extensions(self, is_su, require, temp_dir):
|
||||
|
||||
def test_php_isolation_rootfs_extensions(is_su, require, temp_dir):
|
||||
isolation = {'rootfs': temp_dir}
|
||||
|
||||
if not is_su:
|
||||
|
@ -61,23 +63,23 @@ class TestPHPIsolation(TestApplicationPHP):
|
|||
'pid': True,
|
||||
}
|
||||
|
||||
self.load('list-extensions', isolation=isolation)
|
||||
client.load('list-extensions', isolation=isolation)
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
'"/app/php/list-extensions"', 'applications/list-extensions/root'
|
||||
)
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{'file': '/php/list-extensions/php.ini'},
|
||||
'applications/list-extensions/options',
|
||||
)
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
'"/app/php/list-extensions"',
|
||||
'applications/list-extensions/working_directory',
|
||||
)
|
||||
|
||||
extensions = self.getjson()['body']
|
||||
extensions = client.getjson()['body']
|
||||
|
||||
assert 'json' in extensions, 'json in extensions list'
|
||||
assert 'unit' in extensions, 'unit in extensions list'
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
from unit.applications.lang.php import TestApplicationPHP
|
||||
from unit.applications.lang.php import ApplicationPHP
|
||||
from unit.option import option
|
||||
|
||||
prerequisites = {'modules': {'php': 'any'}}
|
||||
|
||||
client = ApplicationPHP()
|
||||
|
||||
class TestPHPTargets(TestApplicationPHP):
|
||||
def test_php_application_targets(self):
|
||||
|
||||
def test_php_application_targets():
|
||||
targets_dir = f"{option.test_dir}/php/targets"
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "routes"}},
|
||||
"routes": [
|
||||
|
@ -23,7 +24,7 @@ class TestPHPTargets(TestApplicationPHP):
|
|||
],
|
||||
"applications": {
|
||||
"targets": {
|
||||
"type": self.get_application_type(),
|
||||
"type": client.get_application_type(),
|
||||
"processes": {"spare": 0},
|
||||
"targets": {
|
||||
"1": {
|
||||
|
@ -44,31 +45,30 @@ class TestPHPTargets(TestApplicationPHP):
|
|||
}
|
||||
)
|
||||
|
||||
assert self.get(url='/1')['body'] == '1'
|
||||
assert self.get(url='/2')['body'] == '2'
|
||||
assert self.get(url='/blah')['status'] == 404
|
||||
assert self.get(url='/')['body'] == 'index'
|
||||
assert self.get(url='/1.php?test=test.php/')['body'] == '1'
|
||||
assert client.get(url='/1')['body'] == '1'
|
||||
assert client.get(url='/2')['body'] == '2'
|
||||
assert client.get(url='/blah')['status'] == 404
|
||||
assert client.get(url='/')['body'] == 'index'
|
||||
assert client.get(url='/1.php?test=test.php/')['body'] == '1'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
"\"1.php\"", 'applications/targets/targets/default/index'
|
||||
), 'change targets index'
|
||||
assert self.get(url='/')['body'] == '1'
|
||||
assert client.get(url='/')['body'] == '1'
|
||||
|
||||
assert 'success' in self.conf_delete(
|
||||
assert 'success' in client.conf_delete(
|
||||
'applications/targets/targets/default/index'
|
||||
), 'remove targets index'
|
||||
assert self.get(url='/')['body'] == 'index'
|
||||
assert client.get(url='/')['body'] == 'index'
|
||||
|
||||
def test_php_application_targets_error(self):
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def test_php_application_targets_error():
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"*:7080": {"pass": "applications/targets/default"}
|
||||
},
|
||||
"listeners": {"*:7080": {"pass": "applications/targets/default"}},
|
||||
"applications": {
|
||||
"targets": {
|
||||
"type": self.get_application_type(),
|
||||
"type": client.get_application_type(),
|
||||
"processes": {"spare": 0},
|
||||
"targets": {
|
||||
"default": {
|
||||
|
@ -80,21 +80,21 @@ class TestPHPTargets(TestApplicationPHP):
|
|||
},
|
||||
}
|
||||
), 'initial configuration'
|
||||
assert self.get()['status'] == 200
|
||||
assert client.get()['status'] == 200
|
||||
|
||||
assert 'error' in self.conf(
|
||||
assert 'error' in client.conf(
|
||||
{"pass": "applications/targets/blah"}, 'listeners/*:7080'
|
||||
), 'invalid targets pass'
|
||||
assert 'error' in self.conf(
|
||||
assert 'error' in client.conf(
|
||||
f'"{option.test_dir}/php/targets"',
|
||||
'applications/targets/root',
|
||||
), 'invalid root'
|
||||
assert 'error' in self.conf(
|
||||
assert 'error' in client.conf(
|
||||
'"index.php"', 'applications/targets/index'
|
||||
), 'invalid index'
|
||||
assert 'error' in self.conf(
|
||||
assert 'error' in client.conf(
|
||||
'"index.php"', 'applications/targets/script'
|
||||
), 'invalid script'
|
||||
assert 'error' in self.conf_delete(
|
||||
assert 'error' in client.conf_delete(
|
||||
'applications/targets/default/root'
|
||||
), 'root remove'
|
||||
|
|
|
@ -4,23 +4,23 @@ import time
|
|||
|
||||
import pytest
|
||||
from conftest import run_process
|
||||
from unit.applications.lang.python import TestApplicationPython
|
||||
from unit.applications.lang.python import ApplicationPython
|
||||
from unit.option import option
|
||||
from unit.utils import waitforsocket
|
||||
|
||||
prerequisites = {'modules': {'python': 'any'}}
|
||||
|
||||
|
||||
class TestProxy(TestApplicationPython):
|
||||
client = ApplicationPython()
|
||||
SERVER_PORT = 7999
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_method_fixture(self):
|
||||
run_process(self.run_server, self.SERVER_PORT)
|
||||
waitforsocket(self.SERVER_PORT)
|
||||
def setup_method_fixture():
|
||||
run_process(run_server, SERVER_PORT)
|
||||
waitforsocket(SERVER_PORT)
|
||||
|
||||
python_dir = f'{option.test_dir}/python'
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"*:7080": {"pass": "routes"},
|
||||
|
@ -29,21 +29,21 @@ class TestProxy(TestApplicationPython):
|
|||
"routes": [{"action": {"proxy": "http://127.0.0.1:7081"}}],
|
||||
"applications": {
|
||||
"mirror": {
|
||||
"type": self.get_application_type(),
|
||||
"type": client.get_application_type(),
|
||||
"processes": {"spare": 0},
|
||||
"path": f'{python_dir}/mirror',
|
||||
"working_directory": f'{python_dir}/mirror',
|
||||
"module": "wsgi",
|
||||
},
|
||||
"custom_header": {
|
||||
"type": self.get_application_type(),
|
||||
"type": client.get_application_type(),
|
||||
"processes": {"spare": 0},
|
||||
"path": f'{python_dir}/custom_header',
|
||||
"working_directory": f'{python_dir}/custom_header',
|
||||
"module": "wsgi",
|
||||
},
|
||||
"delayed": {
|
||||
"type": self.get_application_type(),
|
||||
"type": client.get_application_type(),
|
||||
"processes": {"spare": 0},
|
||||
"path": f'{python_dir}/delayed',
|
||||
"working_directory": f'{python_dir}/delayed',
|
||||
|
@ -53,7 +53,7 @@ class TestProxy(TestApplicationPython):
|
|||
}
|
||||
), 'proxy initial configuration'
|
||||
|
||||
@staticmethod
|
||||
|
||||
def run_server(server_port):
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
|
@ -92,18 +92,22 @@ Content-Length: 10
|
|||
|
||||
connection.close()
|
||||
|
||||
def get_http10(self, *args, **kwargs):
|
||||
return self.get(*args, http_10=True, **kwargs)
|
||||
|
||||
def post_http10(self, *args, **kwargs):
|
||||
return self.post(*args, http_10=True, **kwargs)
|
||||
def get_http10(*args, **kwargs):
|
||||
return client.get(*args, http_10=True, **kwargs)
|
||||
|
||||
def test_proxy_http10(self):
|
||||
|
||||
def post_http10(*args, **kwargs):
|
||||
return client.post(*args, http_10=True, **kwargs)
|
||||
|
||||
|
||||
def test_proxy_http10():
|
||||
for _ in range(10):
|
||||
assert self.get_http10()['status'] == 200, 'status'
|
||||
assert get_http10()['status'] == 200, 'status'
|
||||
|
||||
def test_proxy_chain(self):
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def test_proxy_chain():
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"*:7080": {"pass": "routes/first"},
|
||||
|
@ -122,7 +126,7 @@ Content-Length: 10
|
|||
},
|
||||
"applications": {
|
||||
"mirror": {
|
||||
"type": self.get_application_type(),
|
||||
"type": client.get_application_type(),
|
||||
"processes": {"spare": 0},
|
||||
"path": f'{option.test_dir}/python/mirror',
|
||||
"working_directory": f'{option.test_dir}/python/mirror',
|
||||
|
@ -132,60 +136,62 @@ Content-Length: 10
|
|||
}
|
||||
), 'proxy chain configuration'
|
||||
|
||||
assert self.get_http10()['status'] == 200, 'status'
|
||||
assert get_http10()['status'] == 200, 'status'
|
||||
|
||||
def test_proxy_body(self):
|
||||
|
||||
def test_proxy_body():
|
||||
payload = '0123456789'
|
||||
for _ in range(10):
|
||||
resp = self.post_http10(body=payload)
|
||||
resp = post_http10(body=payload)
|
||||
|
||||
assert resp['status'] == 200, 'status'
|
||||
assert resp['body'] == payload, 'body'
|
||||
|
||||
payload = 'X' * 4096
|
||||
for _ in range(10):
|
||||
resp = self.post_http10(body=payload)
|
||||
resp = post_http10(body=payload)
|
||||
|
||||
assert resp['status'] == 200, 'status'
|
||||
assert resp['body'] == payload, 'body'
|
||||
|
||||
payload = 'X' * 4097
|
||||
for _ in range(10):
|
||||
resp = self.post_http10(body=payload)
|
||||
resp = post_http10(body=payload)
|
||||
|
||||
assert resp['status'] == 200, 'status'
|
||||
assert resp['body'] == payload, 'body'
|
||||
|
||||
payload = 'X' * 4096 * 256
|
||||
for _ in range(10):
|
||||
resp = self.post_http10(body=payload, read_buffer_size=4096 * 128)
|
||||
resp = post_http10(body=payload, read_buffer_size=4096 * 128)
|
||||
|
||||
assert resp['status'] == 200, 'status'
|
||||
assert resp['body'] == payload, 'body'
|
||||
|
||||
payload = 'X' * 4096 * 257
|
||||
for _ in range(10):
|
||||
resp = self.post_http10(body=payload, read_buffer_size=4096 * 128)
|
||||
resp = post_http10(body=payload, read_buffer_size=4096 * 128)
|
||||
|
||||
assert resp['status'] == 200, 'status'
|
||||
assert resp['body'] == payload, 'body'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{'http': {'max_body_size': 32 * 1024 * 1024}}, 'settings'
|
||||
)
|
||||
|
||||
payload = '0123456789abcdef' * 32 * 64 * 1024
|
||||
resp = self.post_http10(body=payload, read_buffer_size=1024 * 1024)
|
||||
resp = post_http10(body=payload, read_buffer_size=1024 * 1024)
|
||||
assert resp['status'] == 200, 'status'
|
||||
assert resp['body'] == payload, 'body'
|
||||
|
||||
def test_proxy_parallel(self):
|
||||
|
||||
def test_proxy_parallel():
|
||||
payload = 'X' * 4096 * 257
|
||||
buff_size = 4096 * 258
|
||||
|
||||
socks = []
|
||||
for i in range(10):
|
||||
sock = self.post_http10(
|
||||
sock = post_http10(
|
||||
body=f'{payload}{i}',
|
||||
no_recv=True,
|
||||
read_buffer_size=buff_size,
|
||||
|
@ -193,22 +199,23 @@ Content-Length: 10
|
|||
socks.append(sock)
|
||||
|
||||
for i in range(10):
|
||||
resp = self.recvall(socks[i], buff_size=buff_size).decode()
|
||||
resp = client.recvall(socks[i], buff_size=buff_size).decode()
|
||||
socks[i].close()
|
||||
|
||||
resp = self._resp_to_dict(resp)
|
||||
resp = client._resp_to_dict(resp)
|
||||
|
||||
assert resp['status'] == 200, 'status'
|
||||
assert resp['body'] == f'{payload}{i}', 'body'
|
||||
|
||||
def test_proxy_header(self):
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def test_proxy_header():
|
||||
assert 'success' in client.conf(
|
||||
{"pass": "applications/custom_header"}, 'listeners/*:7081'
|
||||
), 'custom_header configure'
|
||||
|
||||
header_value = 'blah'
|
||||
assert (
|
||||
self.get_http10(
|
||||
get_http10(
|
||||
headers={'Host': 'localhost', 'Custom-Header': header_value}
|
||||
)['headers']['Custom-Header']
|
||||
== header_value
|
||||
|
@ -216,7 +223,7 @@ Content-Length: 10
|
|||
|
||||
header_value = r"(),/:;<=>?@[\]{}\t !#$%&'*+-.^_`|~"
|
||||
assert (
|
||||
self.get_http10(
|
||||
get_http10(
|
||||
headers={'Host': 'localhost', 'Custom-Header': header_value}
|
||||
)['headers']['Custom-Header']
|
||||
== header_value
|
||||
|
@ -224,7 +231,7 @@ Content-Length: 10
|
|||
|
||||
header_value = 'X' * 4096
|
||||
assert (
|
||||
self.get_http10(
|
||||
get_http10(
|
||||
headers={'Host': 'localhost', 'Custom-Header': header_value}
|
||||
)['headers']['Custom-Header']
|
||||
== header_value
|
||||
|
@ -232,7 +239,7 @@ Content-Length: 10
|
|||
|
||||
header_value = 'X' * 8191
|
||||
assert (
|
||||
self.get_http10(
|
||||
get_http10(
|
||||
headers={'Host': 'localhost', 'Custom-Header': header_value}
|
||||
)['headers']['Custom-Header']
|
||||
== header_value
|
||||
|
@ -240,14 +247,15 @@ Content-Length: 10
|
|||
|
||||
header_value = 'X' * 8192
|
||||
assert (
|
||||
self.get_http10(
|
||||
get_http10(
|
||||
headers={'Host': 'localhost', 'Custom-Header': header_value}
|
||||
)['status']
|
||||
== 431
|
||||
), 'custom header 5'
|
||||
|
||||
def test_proxy_fragmented(self):
|
||||
sock = self.http(b"""GET / HTT""", raw=True, no_recv=True)
|
||||
|
||||
def test_proxy_fragmented():
|
||||
sock = client.http(b"""GET / HTT""", raw=True, no_recv=True)
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
|
@ -257,13 +265,12 @@ Content-Length: 10
|
|||
|
||||
sock.sendall("t\r\n\r\n".encode())
|
||||
|
||||
assert re.search(
|
||||
'200 OK', self.recvall(sock).decode()
|
||||
), 'fragmented send'
|
||||
assert re.search('200 OK', client.recvall(sock).decode()), 'fragmented send'
|
||||
sock.close()
|
||||
|
||||
def test_proxy_fragmented_close(self):
|
||||
sock = self.http(b"""GET / HTT""", raw=True, no_recv=True)
|
||||
|
||||
def test_proxy_fragmented_close():
|
||||
sock = client.http(b"""GET / HTT""", raw=True, no_recv=True)
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
|
@ -271,8 +278,9 @@ Content-Length: 10
|
|||
|
||||
sock.close()
|
||||
|
||||
def test_proxy_fragmented_body(self):
|
||||
sock = self.http(b"""GET / HTT""", raw=True, no_recv=True)
|
||||
|
||||
def test_proxy_fragmented_body():
|
||||
sock = client.http(b"""GET / HTT""", raw=True, no_recv=True)
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
|
@ -292,14 +300,15 @@ Content-Length: 10
|
|||
|
||||
sock.sendall(("X" * 10000).encode())
|
||||
|
||||
resp = self._resp_to_dict(self.recvall(sock).decode())
|
||||
resp = client._resp_to_dict(client.recvall(sock).decode())
|
||||
sock.close()
|
||||
|
||||
assert resp['status'] == 200, 'status'
|
||||
assert resp['body'] == "X" * 30000, 'body'
|
||||
|
||||
def test_proxy_fragmented_body_close(self):
|
||||
sock = self.http(b"""GET / HTT""", raw=True, no_recv=True)
|
||||
|
||||
def test_proxy_fragmented_body_close():
|
||||
sock = client.http(b"""GET / HTT""", raw=True, no_recv=True)
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
|
@ -313,15 +322,17 @@ Content-Length: 10
|
|||
|
||||
sock.close()
|
||||
|
||||
def test_proxy_nowhere(self):
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def test_proxy_nowhere():
|
||||
assert 'success' in client.conf(
|
||||
[{"action": {"proxy": "http://127.0.0.1:7082"}}], 'routes'
|
||||
), 'proxy path changed'
|
||||
|
||||
assert self.get_http10()['status'] == 502, 'status'
|
||||
assert get_http10()['status'] == 502, 'status'
|
||||
|
||||
def test_proxy_ipv6(self):
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def test_proxy_ipv6():
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"*:7080": {"pass": "routes"},
|
||||
"[::1]:7081": {'application': 'mirror'},
|
||||
|
@ -329,16 +340,17 @@ Content-Length: 10
|
|||
'listeners',
|
||||
), 'add ipv6 listener configure'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
[{"action": {"proxy": "http://[::1]:7081"}}], 'routes'
|
||||
), 'proxy ipv6 configure'
|
||||
|
||||
assert self.get_http10()['status'] == 200, 'status'
|
||||
assert get_http10()['status'] == 200, 'status'
|
||||
|
||||
def test_proxy_unix(self, temp_dir):
|
||||
|
||||
def test_proxy_unix(temp_dir):
|
||||
addr = f'{temp_dir}/sock'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"*:7080": {"pass": "routes"},
|
||||
f'unix:{addr}': {'application': 'mirror'},
|
||||
|
@ -346,19 +358,20 @@ Content-Length: 10
|
|||
'listeners',
|
||||
), 'add unix listener configure'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
[{"action": {"proxy": f'http://unix:{addr}'}}], 'routes'
|
||||
), 'proxy unix configure'
|
||||
|
||||
assert self.get_http10()['status'] == 200, 'status'
|
||||
assert get_http10()['status'] == 200, 'status'
|
||||
|
||||
def test_proxy_delayed(self):
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def test_proxy_delayed():
|
||||
assert 'success' in client.conf(
|
||||
{"pass": "applications/delayed"}, 'listeners/*:7081'
|
||||
), 'delayed configure'
|
||||
|
||||
body = '0123456789' * 1000
|
||||
resp = self.post_http10(
|
||||
resp = post_http10(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Content-Length': str(len(body)),
|
||||
|
@ -371,7 +384,7 @@ Content-Length: 10
|
|||
assert resp['status'] == 200, 'status'
|
||||
assert resp['body'] == body, 'body'
|
||||
|
||||
resp = self.post_http10(
|
||||
resp = post_http10(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Content-Length': str(len(body)),
|
||||
|
@ -384,12 +397,13 @@ Content-Length: 10
|
|||
assert resp['status'] == 200, 'status'
|
||||
assert resp['body'] == body, 'body'
|
||||
|
||||
def test_proxy_delayed_close(self):
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def test_proxy_delayed_close():
|
||||
assert 'success' in client.conf(
|
||||
{"pass": "applications/delayed"}, 'listeners/*:7081'
|
||||
), 'delayed configure'
|
||||
|
||||
sock = self.post_http10(
|
||||
sock = post_http10(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Content-Length': '10000',
|
||||
|
@ -403,7 +417,7 @@ Content-Length: 10
|
|||
assert re.search('200 OK', sock.recv(100).decode()), 'first'
|
||||
sock.close()
|
||||
|
||||
sock = self.post_http10(
|
||||
sock = post_http10(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Content-Length': '10000',
|
||||
|
@ -417,31 +431,33 @@ Content-Length: 10
|
|||
assert re.search('200 OK', sock.recv(100).decode()), 'second'
|
||||
sock.close()
|
||||
|
||||
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_proxy_content_length(self):
|
||||
assert 'success' in self.conf(
|
||||
[{"action": {"proxy": f'http://127.0.0.1:{self.SERVER_PORT}'}}],
|
||||
def test_proxy_content_length():
|
||||
assert 'success' in client.conf(
|
||||
[{"action": {"proxy": f'http://127.0.0.1:{SERVER_PORT}'}}],
|
||||
'routes',
|
||||
), 'proxy backend configure'
|
||||
|
||||
resp = self.get_http10()
|
||||
resp = get_http10()
|
||||
assert len(resp['body']) == 0, 'body lt Content-Length 0'
|
||||
|
||||
resp = self.get_http10(headers={'Host': 'localhost', 'X-Len': '5'})
|
||||
resp = get_http10(headers={'Host': 'localhost', 'X-Len': '5'})
|
||||
assert len(resp['body']) == 5, 'body lt Content-Length 5'
|
||||
|
||||
resp = self.get_http10(headers={'Host': 'localhost', 'X-Len': '9'})
|
||||
resp = get_http10(headers={'Host': 'localhost', 'X-Len': '9'})
|
||||
assert len(resp['body']) == 9, 'body lt Content-Length 9'
|
||||
|
||||
resp = self.get_http10(headers={'Host': 'localhost', 'X-Len': '11'})
|
||||
resp = get_http10(headers={'Host': 'localhost', 'X-Len': '11'})
|
||||
assert len(resp['body']) == 10, 'body gt Content-Length 11'
|
||||
|
||||
resp = self.get_http10(headers={'Host': 'localhost', 'X-Len': '15'})
|
||||
resp = get_http10(headers={'Host': 'localhost', 'X-Len': '15'})
|
||||
assert len(resp['body']) == 10, 'body gt Content-Length 15'
|
||||
|
||||
def test_proxy_invalid(self):
|
||||
|
||||
def test_proxy_invalid():
|
||||
def check_proxy(proxy):
|
||||
assert 'error' in self.conf(
|
||||
assert 'error' in client.conf(
|
||||
[{"action": {"proxy": proxy}}], 'routes'
|
||||
), 'proxy invalid'
|
||||
|
||||
|
@ -459,14 +475,15 @@ Content-Length: 10
|
|||
check_proxy('http://[:]:7080')
|
||||
check_proxy('http://[::7080')
|
||||
|
||||
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_proxy_loop(self, skip_alert):
|
||||
def test_proxy_loop(skip_alert):
|
||||
skip_alert(
|
||||
r'socket.*failed',
|
||||
r'accept.*failed',
|
||||
r'new connections are not accepted',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"*:7080": {"pass": "routes"},
|
||||
|
@ -476,7 +493,7 @@ Content-Length: 10
|
|||
"routes": [{"action": {"proxy": "http://127.0.0.1:7082"}}],
|
||||
"applications": {
|
||||
"mirror": {
|
||||
"type": self.get_application_type(),
|
||||
"type": client.get_application_type(),
|
||||
"processes": {"spare": 0},
|
||||
"path": f'{option.test_dir}/python/mirror',
|
||||
"working_directory": f'{option.test_dir}/python/mirror',
|
||||
|
@ -486,5 +503,5 @@ Content-Length: 10
|
|||
}
|
||||
)
|
||||
|
||||
self.get_http10(no_recv=True)
|
||||
self.get_http10(read_timeout=1)
|
||||
get_http10(no_recv=True)
|
||||
get_http10(read_timeout=1)
|
||||
|
|
|
@ -5,36 +5,32 @@ import time
|
|||
|
||||
import pytest
|
||||
from conftest import run_process
|
||||
from unit.applications.lang.python import TestApplicationPython
|
||||
from unit.applications.lang.python import ApplicationPython
|
||||
from unit.utils import waitforsocket
|
||||
|
||||
prerequisites = {'modules': {'python': 'any'}}
|
||||
|
||||
|
||||
class TestProxyChunked(TestApplicationPython):
|
||||
client = ApplicationPython()
|
||||
SERVER_PORT = 7999
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_method_fixture(self):
|
||||
run_process(self.run_server, self.SERVER_PORT)
|
||||
waitforsocket(self.SERVER_PORT)
|
||||
|
||||
assert 'success' in self.conf(
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_method_fixture():
|
||||
run_process(run_server, SERVER_PORT)
|
||||
waitforsocket(SERVER_PORT)
|
||||
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"*:7080": {"pass": "routes"},
|
||||
},
|
||||
"routes": [
|
||||
{
|
||||
"action": {
|
||||
"proxy": f'http://127.0.0.1:{self.SERVER_PORT}'
|
||||
}
|
||||
}
|
||||
{"action": {"proxy": f'http://127.0.0.1:{SERVER_PORT}'}}
|
||||
],
|
||||
}
|
||||
), 'proxy initial configuration'
|
||||
|
||||
@staticmethod
|
||||
|
||||
def run_server(server_port):
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
|
@ -93,7 +89,8 @@ class TestProxyChunked(TestApplicationPython):
|
|||
|
||||
connection.close()
|
||||
|
||||
def chunks(self, chunks):
|
||||
|
||||
def chunks(chunks):
|
||||
body = '\r\n\r\n'
|
||||
|
||||
for l, c in chunks:
|
||||
|
@ -101,47 +98,44 @@ class TestProxyChunked(TestApplicationPython):
|
|||
|
||||
return f'{body}0\r\n\r\n'
|
||||
|
||||
def get_http10(self, *args, **kwargs):
|
||||
return self.get(*args, http_10=True, **kwargs)
|
||||
|
||||
def test_proxy_chunked(self):
|
||||
def get_http10(*args, **kwargs):
|
||||
return client.get(*args, http_10=True, **kwargs)
|
||||
|
||||
|
||||
def test_proxy_chunked():
|
||||
for _ in range(10):
|
||||
assert self.get_http10(body='\r\n\r\n0\r\n\r\n')['status'] == 200
|
||||
assert get_http10(body='\r\n\r\n0\r\n\r\n')['status'] == 200
|
||||
|
||||
def test_proxy_chunked_body(self):
|
||||
|
||||
def test_proxy_chunked_body():
|
||||
part = '0123456789abcdef'
|
||||
|
||||
assert (
|
||||
self.get_http10(body=self.chunks([('1000', f'{part} X 256')]))[
|
||||
'body'
|
||||
]
|
||||
get_http10(body=chunks([('1000', f'{part} X 256')]))['body']
|
||||
== part * 256
|
||||
)
|
||||
assert (
|
||||
self.get_http10(body=self.chunks([('100000', f'{part} X 65536')]))[
|
||||
'body'
|
||||
]
|
||||
get_http10(body=chunks([('100000', f'{part} X 65536')]))['body']
|
||||
== part * 65536
|
||||
)
|
||||
assert (
|
||||
self.get_http10(
|
||||
body=self.chunks([('1000000', f'{part} X 1048576')]),
|
||||
get_http10(
|
||||
body=chunks([('1000000', f'{part} X 1048576')]),
|
||||
read_buffer_size=4096 * 4096,
|
||||
)['body']
|
||||
== part * 1048576
|
||||
)
|
||||
|
||||
assert (
|
||||
self.get_http10(
|
||||
body=self.chunks(
|
||||
[('1000', f'{part} X 256'), ('1000', f'{part} X 256')]
|
||||
)
|
||||
get_http10(
|
||||
body=chunks([('1000', f'{part} X 256'), ('1000', f'{part} X 256')])
|
||||
)['body']
|
||||
== part * 256 * 2
|
||||
)
|
||||
assert (
|
||||
self.get_http10(
|
||||
body=self.chunks(
|
||||
get_http10(
|
||||
body=chunks(
|
||||
[
|
||||
('100000', f'{part} X 65536'),
|
||||
('100000', f'{part} X 65536'),
|
||||
|
@ -151,8 +145,8 @@ class TestProxyChunked(TestApplicationPython):
|
|||
== part * 65536 * 2
|
||||
)
|
||||
assert (
|
||||
self.get_http10(
|
||||
body=self.chunks(
|
||||
get_http10(
|
||||
body=chunks(
|
||||
[
|
||||
('1000000', f'{part} X 1048576'),
|
||||
('1000000', f'{part} X 1048576'),
|
||||
|
@ -163,34 +157,35 @@ class TestProxyChunked(TestApplicationPython):
|
|||
== part * 1048576 * 2
|
||||
)
|
||||
|
||||
def test_proxy_chunked_fragmented(self):
|
||||
|
||||
def test_proxy_chunked_fragmented():
|
||||
part = '0123456789abcdef'
|
||||
|
||||
assert (
|
||||
self.get_http10(
|
||||
body=self.chunks([('1', hex(i % 16)[2:]) for i in range(4096)]),
|
||||
get_http10(
|
||||
body=chunks([('1', hex(i % 16)[2:]) for i in range(4096)]),
|
||||
)['body']
|
||||
== part * 256
|
||||
)
|
||||
|
||||
def test_proxy_chunked_send(self):
|
||||
assert self.get_http10(body='\r\n\r\n@0@\r\n\r\n')['status'] == 200
|
||||
|
||||
def test_proxy_chunked_send():
|
||||
assert get_http10(body='\r\n\r\n@0@\r\n\r\n')['status'] == 200
|
||||
assert (
|
||||
self.get_http10(
|
||||
body='\r@\n\r\n2\r@\na@b\r\n2\r\ncd@\r\n0\r@\n\r\n'
|
||||
)['body']
|
||||
get_http10(body='\r@\n\r\n2\r@\na@b\r\n2\r\ncd@\r\n0\r@\n\r\n')['body']
|
||||
== 'abcd'
|
||||
)
|
||||
assert (
|
||||
self.get_http10(
|
||||
body='\r\n\r\n2\r#\na#b\r\n##2\r\n#cd\r\n0\r\n#\r#\n'
|
||||
)['body']
|
||||
get_http10(body='\r\n\r\n2\r#\na#b\r\n##2\r\n#cd\r\n0\r\n#\r#\n')[
|
||||
'body'
|
||||
]
|
||||
== 'abcd'
|
||||
)
|
||||
|
||||
def test_proxy_chunked_invalid(self):
|
||||
|
||||
def test_proxy_chunked_invalid():
|
||||
def check_invalid(body):
|
||||
assert self.get_http10(body=body)['status'] != 200
|
||||
assert get_http10(body=body)['status'] != 200
|
||||
|
||||
check_invalid('\r\n\r0')
|
||||
check_invalid('\r\n\r\n\r0')
|
||||
|
@ -201,26 +196,21 @@ class TestProxyChunked(TestApplicationPython):
|
|||
check_invalid('\r\n\r\nH\r\nXX\r\n0\r\n\r\n')
|
||||
check_invalid('\r\n\r\n0\r\nX')
|
||||
|
||||
resp = self.get_http10(body='\r\n\r\n65#\r\nA X 100')
|
||||
resp = get_http10(body='\r\n\r\n65#\r\nA X 100')
|
||||
assert resp['status'] == 200, 'incomplete chunk status'
|
||||
assert resp['body'][-5:] != '0\r\n\r\n', 'incomplete chunk'
|
||||
|
||||
resp = self.get_http10(body='\r\n\r\n64#\r\nA X 100')
|
||||
resp = get_http10(body='\r\n\r\n64#\r\nA X 100')
|
||||
assert resp['status'] == 200, 'no zero chunk status'
|
||||
assert resp['body'][-5:] != '0\r\n\r\n', 'no zero chunk'
|
||||
|
||||
assert get_http10(body='\r\n\r\n80000000\r\nA X 100')['status'] == 200
|
||||
assert (
|
||||
self.get_http10(body='\r\n\r\n80000000\r\nA X 100')['status'] == 200
|
||||
)
|
||||
assert (
|
||||
self.get_http10(body='\r\n\r\n10000000000000000\r\nA X 100')[
|
||||
'status'
|
||||
]
|
||||
== 502
|
||||
get_http10(body='\r\n\r\n10000000000000000\r\nA X 100')['status'] == 502
|
||||
)
|
||||
assert (
|
||||
len(
|
||||
self.get_http10(
|
||||
get_http10(
|
||||
body='\r\n\r\n1000000\r\nA X 1048576\r\n1000000\r\nA X 100',
|
||||
read_buffer_size=4096 * 4096,
|
||||
)['body']
|
||||
|
@ -229,7 +219,7 @@ class TestProxyChunked(TestApplicationPython):
|
|||
)
|
||||
assert (
|
||||
len(
|
||||
self.get_http10(
|
||||
get_http10(
|
||||
body='\r\n\r\n1000000\r\nA X 1048576\r\nXXX\r\nA X 100',
|
||||
read_buffer_size=4096 * 4096,
|
||||
)['body']
|
||||
|
|
|
@ -8,18 +8,19 @@ import venv
|
|||
|
||||
import pytest
|
||||
from packaging import version
|
||||
from unit.applications.lang.python import TestApplicationPython
|
||||
from unit.applications.lang.python import ApplicationPython
|
||||
|
||||
prerequisites = {'modules': {'python': 'all'}}
|
||||
|
||||
client = ApplicationPython()
|
||||
|
||||
class TestPythonApplication(TestApplicationPython):
|
||||
def test_python_application_variables(self, date_to_sec_epoch, sec_epoch):
|
||||
self.load('variables')
|
||||
|
||||
def test_python_application_variables(date_to_sec_epoch, sec_epoch):
|
||||
client.load('variables')
|
||||
|
||||
body = 'Test body string.'
|
||||
|
||||
resp = self.http(
|
||||
resp = client.http(
|
||||
f"""POST / HTTP/1.1
|
||||
Host: localhost
|
||||
Content-Length: {len(body)}
|
||||
|
@ -62,46 +63,49 @@ custom-header: BLAH
|
|||
}, 'headers'
|
||||
assert resp['body'] == body, 'body'
|
||||
|
||||
def test_python_application_query_string(self):
|
||||
self.load('query_string')
|
||||
|
||||
resp = self.get(url='/?var1=val1&var2=val2')
|
||||
def test_python_application_query_string():
|
||||
client.load('query_string')
|
||||
|
||||
resp = client.get(url='/?var1=val1&var2=val2')
|
||||
|
||||
assert (
|
||||
resp['headers']['Query-String'] == 'var1=val1&var2=val2'
|
||||
), 'Query-String header'
|
||||
|
||||
def test_python_application_query_string_space(self):
|
||||
self.load('query_string')
|
||||
|
||||
resp = self.get(url='/ ?var1=val1&var2=val2')
|
||||
def test_python_application_query_string_space():
|
||||
client.load('query_string')
|
||||
|
||||
resp = client.get(url='/ ?var1=val1&var2=val2')
|
||||
assert (
|
||||
resp['headers']['Query-String'] == 'var1=val1&var2=val2'
|
||||
), 'Query-String space'
|
||||
|
||||
resp = self.get(url='/ %20?var1=val1&var2=val2')
|
||||
resp = client.get(url='/ %20?var1=val1&var2=val2')
|
||||
assert (
|
||||
resp['headers']['Query-String'] == 'var1=val1&var2=val2'
|
||||
), 'Query-String space 2'
|
||||
|
||||
resp = self.get(url='/ %20 ?var1=val1&var2=val2')
|
||||
resp = client.get(url='/ %20 ?var1=val1&var2=val2')
|
||||
assert (
|
||||
resp['headers']['Query-String'] == 'var1=val1&var2=val2'
|
||||
), 'Query-String space 3'
|
||||
|
||||
resp = self.get(url='/blah %20 blah? var1= val1 & var2=val2')
|
||||
resp = client.get(url='/blah %20 blah? var1= val1 & var2=val2')
|
||||
assert (
|
||||
resp['headers']['Query-String'] == ' var1= val1 & var2=val2'
|
||||
), 'Query-String space 4'
|
||||
|
||||
def test_python_application_prefix(self):
|
||||
self.load('prefix', prefix='/api/rest')
|
||||
|
||||
def test_python_application_prefix():
|
||||
client.load('prefix', prefix='/api/rest')
|
||||
|
||||
def set_prefix(prefix):
|
||||
self.conf(f'"{prefix}"', 'applications/prefix/prefix')
|
||||
client.conf(f'"{prefix}"', 'applications/prefix/prefix')
|
||||
|
||||
def check_prefix(url, script_name, path_info):
|
||||
resp = self.get(url=url)
|
||||
resp = client.get(url=url)
|
||||
assert resp['status'] == 200
|
||||
assert resp['headers']['Script-Name'] == script_name
|
||||
assert resp['headers']['Path-Info'] == path_info
|
||||
|
@ -132,66 +136,73 @@ custom-header: BLAH
|
|||
check_prefix('/', 'NULL', '/')
|
||||
check_prefix('/app', 'NULL', '/app')
|
||||
|
||||
def test_python_application_query_string_empty(self):
|
||||
self.load('query_string')
|
||||
|
||||
resp = self.get(url='/?')
|
||||
def test_python_application_query_string_empty():
|
||||
client.load('query_string')
|
||||
|
||||
resp = client.get(url='/?')
|
||||
|
||||
assert resp['status'] == 200, 'query string empty status'
|
||||
assert resp['headers']['Query-String'] == '', 'query string empty'
|
||||
|
||||
def test_python_application_query_string_absent(self):
|
||||
self.load('query_string')
|
||||
|
||||
resp = self.get()
|
||||
def test_python_application_query_string_absent():
|
||||
client.load('query_string')
|
||||
|
||||
resp = client.get()
|
||||
|
||||
assert resp['status'] == 200, 'query string absent status'
|
||||
assert resp['headers']['Query-String'] == '', 'query string absent'
|
||||
|
||||
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_python_application_server_port(self):
|
||||
self.load('server_port')
|
||||
def test_python_application_server_port():
|
||||
client.load('server_port')
|
||||
|
||||
assert (
|
||||
self.get()['headers']['Server-Port'] == '7080'
|
||||
client.get()['headers']['Server-Port'] == '7080'
|
||||
), 'Server-Port header'
|
||||
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_python_application_working_directory_invalid(self):
|
||||
self.load('empty')
|
||||
|
||||
assert 'success' in self.conf(
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_python_application_working_directory_invalid():
|
||||
client.load('empty')
|
||||
|
||||
assert 'success' in client.conf(
|
||||
'"/blah"', 'applications/empty/working_directory'
|
||||
), 'configure invalid working_directory'
|
||||
|
||||
assert self.get()['status'] == 500, 'status'
|
||||
assert client.get()['status'] == 500, 'status'
|
||||
|
||||
def test_python_application_204_transfer_encoding(self):
|
||||
self.load('204_no_content')
|
||||
|
||||
def test_python_application_204_transfer_encoding():
|
||||
client.load('204_no_content')
|
||||
|
||||
assert (
|
||||
'Transfer-Encoding' not in self.get()['headers']
|
||||
'Transfer-Encoding' not in client.get()['headers']
|
||||
), '204 header transfer encoding'
|
||||
|
||||
def test_python_application_ctx_iter_atexit(self, wait_for_record):
|
||||
self.load('ctx_iter_atexit')
|
||||
|
||||
resp = self.post(body='0123456789')
|
||||
def test_python_application_ctx_iter_atexit(wait_for_record):
|
||||
client.load('ctx_iter_atexit')
|
||||
|
||||
resp = client.post(body='0123456789')
|
||||
|
||||
assert resp['status'] == 200, 'ctx iter status'
|
||||
assert resp['body'] == '0123456789', 'ctx iter body'
|
||||
|
||||
assert 'success' in self.conf({"listeners": {}, "applications": {}})
|
||||
assert 'success' in client.conf({"listeners": {}, "applications": {}})
|
||||
|
||||
assert wait_for_record(r'RuntimeError') is not None, 'ctx iter atexit'
|
||||
|
||||
def test_python_keepalive_body(self):
|
||||
self.load('mirror')
|
||||
|
||||
assert self.get()['status'] == 200, 'init'
|
||||
def test_python_keepalive_body():
|
||||
client.load('mirror')
|
||||
|
||||
assert client.get()['status'] == 200, 'init'
|
||||
|
||||
body = '0123456789' * 500
|
||||
(resp, sock) = self.post(
|
||||
(resp, sock) = client.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Connection': 'keep-alive',
|
||||
|
@ -204,21 +215,22 @@ custom-header: BLAH
|
|||
assert resp['body'] == body, 'keep-alive 1'
|
||||
|
||||
body = '0123456789'
|
||||
resp = self.post(sock=sock, body=body)
|
||||
resp = client.post(sock=sock, body=body)
|
||||
|
||||
assert resp['body'] == body, 'keep-alive 2'
|
||||
|
||||
def test_python_keepalive_reconfigure(self):
|
||||
self.load('mirror')
|
||||
|
||||
assert self.get()['status'] == 200, 'init'
|
||||
def test_python_keepalive_reconfigure():
|
||||
client.load('mirror')
|
||||
|
||||
assert client.get()['status'] == 200, 'init'
|
||||
|
||||
body = '0123456789'
|
||||
conns = 3
|
||||
socks = []
|
||||
|
||||
for i in range(conns):
|
||||
(resp, sock) = self.post(
|
||||
(resp, sock) = client.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Connection': 'keep-alive',
|
||||
|
@ -230,12 +242,12 @@ custom-header: BLAH
|
|||
|
||||
assert resp['body'] == body, 'keep-alive open'
|
||||
|
||||
self.load('mirror', processes=i + 1)
|
||||
client.load('mirror', processes=i + 1)
|
||||
|
||||
socks.append(sock)
|
||||
|
||||
for i in range(conns):
|
||||
(resp, sock) = self.post(
|
||||
(resp, sock) = client.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Connection': 'keep-alive',
|
||||
|
@ -248,23 +260,24 @@ custom-header: BLAH
|
|||
|
||||
assert resp['body'] == body, 'keep-alive request'
|
||||
|
||||
self.load('mirror', processes=i + 1)
|
||||
client.load('mirror', processes=i + 1)
|
||||
|
||||
for i in range(conns):
|
||||
resp = self.post(sock=socks[i], body=body)
|
||||
resp = client.post(sock=socks[i], body=body)
|
||||
|
||||
assert resp['body'] == body, 'keep-alive close'
|
||||
|
||||
self.load('mirror', processes=i + 1)
|
||||
client.load('mirror', processes=i + 1)
|
||||
|
||||
def test_python_keepalive_reconfigure_2(self):
|
||||
self.load('mirror')
|
||||
|
||||
assert self.get()['status'] == 200, 'init'
|
||||
def test_python_keepalive_reconfigure_2():
|
||||
client.load('mirror')
|
||||
|
||||
assert client.get()['status'] == 200, 'init'
|
||||
|
||||
body = '0123456789'
|
||||
|
||||
(resp, sock) = self.post(
|
||||
(resp, sock) = client.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Connection': 'keep-alive',
|
||||
|
@ -276,36 +289,38 @@ custom-header: BLAH
|
|||
|
||||
assert resp['body'] == body, 'reconfigure 2 keep-alive 1'
|
||||
|
||||
self.load('empty')
|
||||
client.load('empty')
|
||||
|
||||
assert self.get()['status'] == 200, 'init'
|
||||
assert client.get()['status'] == 200, 'init'
|
||||
|
||||
(resp, sock) = self.post(start=True, sock=sock, body=body)
|
||||
(resp, sock) = client.post(start=True, sock=sock, body=body)
|
||||
|
||||
assert resp['status'] == 200, 'reconfigure 2 keep-alive 2'
|
||||
assert resp['body'] == '', 'reconfigure 2 keep-alive 2 body'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{"listeners": {}, "applications": {}}
|
||||
), 'reconfigure 2 clear configuration'
|
||||
|
||||
resp = self.get(sock=sock)
|
||||
resp = client.get(sock=sock)
|
||||
|
||||
assert resp == {}, 'reconfigure 2 keep-alive 3'
|
||||
|
||||
def test_python_atexit(self, wait_for_record):
|
||||
self.load('atexit')
|
||||
|
||||
self.get()
|
||||
def test_python_atexit(wait_for_record):
|
||||
client.load('atexit')
|
||||
|
||||
assert 'success' in self.conf({"listeners": {}, "applications": {}})
|
||||
client.get()
|
||||
|
||||
assert 'success' in client.conf({"listeners": {}, "applications": {}})
|
||||
|
||||
assert wait_for_record(r'At exit called\.') is not None, 'atexit'
|
||||
|
||||
def test_python_process_switch(self):
|
||||
self.load('delayed', processes=2)
|
||||
|
||||
self.get(
|
||||
def test_python_process_switch():
|
||||
client.load('delayed', processes=2)
|
||||
|
||||
client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Content-Length': '0',
|
||||
|
@ -322,72 +337,78 @@ custom-header: BLAH
|
|||
'X-Delay': '1',
|
||||
}
|
||||
|
||||
self.get(headers=headers_delay_1, no_recv=True)
|
||||
client.get(headers=headers_delay_1, no_recv=True)
|
||||
|
||||
time.sleep(0.5)
|
||||
|
||||
for _ in range(10):
|
||||
self.get(headers=headers_delay_1, no_recv=True)
|
||||
client.get(headers=headers_delay_1, no_recv=True)
|
||||
|
||||
client.get(headers=headers_delay_1)
|
||||
|
||||
self.get(headers=headers_delay_1)
|
||||
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_python_application_start_response_exit(self):
|
||||
self.load('start_response_exit')
|
||||
def test_python_application_start_response_exit():
|
||||
client.load('start_response_exit')
|
||||
|
||||
assert self.get()['status'] == 500, 'start response exit'
|
||||
assert client.get()['status'] == 500, 'start response exit'
|
||||
|
||||
def test_python_application_input_iter(self):
|
||||
self.load('input_iter')
|
||||
|
||||
def test_python_application_input_iter():
|
||||
client.load('input_iter')
|
||||
|
||||
body = '''0123456789
|
||||
next line
|
||||
|
||||
last line'''
|
||||
|
||||
resp = self.post(body=body)
|
||||
resp = client.post(body=body)
|
||||
assert resp['body'] == body, 'input iter'
|
||||
assert resp['headers']['X-Lines-Count'] == '4', 'input iter lines'
|
||||
|
||||
def test_python_application_input_readline(self):
|
||||
self.load('input_readline')
|
||||
|
||||
def test_python_application_input_readline():
|
||||
client.load('input_readline')
|
||||
|
||||
body = '''0123456789
|
||||
next line
|
||||
|
||||
last line'''
|
||||
|
||||
resp = self.post(body=body)
|
||||
resp = client.post(body=body)
|
||||
assert resp['body'] == body, 'input readline'
|
||||
assert resp['headers']['X-Lines-Count'] == '4', 'input readline lines'
|
||||
|
||||
def test_python_application_input_readline_size(self):
|
||||
self.load('input_readline_size')
|
||||
|
||||
def test_python_application_input_readline_size():
|
||||
client.load('input_readline_size')
|
||||
|
||||
body = '''0123456789
|
||||
next line
|
||||
|
||||
last line'''
|
||||
|
||||
assert self.post(body=body)['body'] == body, 'input readline size'
|
||||
assert client.post(body=body)['body'] == body, 'input readline size'
|
||||
assert (
|
||||
self.post(body='0123')['body'] == '0123'
|
||||
client.post(body='0123')['body'] == '0123'
|
||||
), 'input readline size less'
|
||||
|
||||
def test_python_application_input_readlines(self):
|
||||
self.load('input_readlines')
|
||||
|
||||
def test_python_application_input_readlines():
|
||||
client.load('input_readlines')
|
||||
|
||||
body = '''0123456789
|
||||
next line
|
||||
|
||||
last line'''
|
||||
|
||||
resp = self.post(body=body)
|
||||
resp = client.post(body=body)
|
||||
assert resp['body'] == body, 'input readlines'
|
||||
assert resp['headers']['X-Lines-Count'] == '4', 'input readlines lines'
|
||||
|
||||
def test_python_application_input_readlines_huge(self):
|
||||
self.load('input_readlines')
|
||||
|
||||
def test_python_application_input_readlines_huge():
|
||||
client.load('input_readlines')
|
||||
|
||||
body = (
|
||||
'''0123456789 abcdefghi
|
||||
|
@ -399,15 +420,16 @@ last line: 987654321
|
|||
)
|
||||
|
||||
assert (
|
||||
self.post(body=body, read_buffer_size=16384)['body'] == body
|
||||
client.post(body=body, read_buffer_size=16384)['body'] == body
|
||||
), 'input readlines huge'
|
||||
|
||||
def test_python_application_input_read_length(self):
|
||||
self.load('input_read_length')
|
||||
|
||||
def test_python_application_input_read_length():
|
||||
client.load('input_read_length')
|
||||
|
||||
body = '0123456789'
|
||||
|
||||
resp = self.post(
|
||||
resp = client.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Input-Length': '5',
|
||||
|
@ -418,7 +440,7 @@ last line: 987654321
|
|||
|
||||
assert resp['body'] == body[:5], 'input read length lt body'
|
||||
|
||||
resp = self.post(
|
||||
resp = client.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Input-Length': '15',
|
||||
|
@ -429,7 +451,7 @@ last line: 987654321
|
|||
|
||||
assert resp['body'] == body, 'input read length gt body'
|
||||
|
||||
resp = self.post(
|
||||
resp = client.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Input-Length': '0',
|
||||
|
@ -440,7 +462,7 @@ last line: 987654321
|
|||
|
||||
assert resp['body'] == '', 'input read length zero'
|
||||
|
||||
resp = self.post(
|
||||
resp = client.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Input-Length': '-1',
|
||||
|
@ -451,63 +473,72 @@ last line: 987654321
|
|||
|
||||
assert resp['body'] == body, 'input read length negative'
|
||||
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_python_application_errors_write(self, wait_for_record):
|
||||
self.load('errors_write')
|
||||
|
||||
self.get()
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_python_application_errors_write(wait_for_record):
|
||||
client.load('errors_write')
|
||||
|
||||
client.get()
|
||||
|
||||
assert (
|
||||
wait_for_record(r'\[error\].+Error in application\.') is not None
|
||||
), 'errors write'
|
||||
|
||||
def test_python_application_body_array(self):
|
||||
self.load('body_array')
|
||||
|
||||
assert self.get()['body'] == '0123456789', 'body array'
|
||||
def test_python_application_body_array():
|
||||
client.load('body_array')
|
||||
|
||||
def test_python_application_body_io(self):
|
||||
self.load('body_io')
|
||||
assert client.get()['body'] == '0123456789', 'body array'
|
||||
|
||||
assert self.get()['body'] == '0123456789', 'body io'
|
||||
|
||||
def test_python_application_body_io_file(self):
|
||||
self.load('body_io_file')
|
||||
def test_python_application_body_io():
|
||||
client.load('body_io')
|
||||
|
||||
assert client.get()['body'] == '0123456789', 'body io'
|
||||
|
||||
|
||||
def test_python_application_body_io_file():
|
||||
client.load('body_io_file')
|
||||
|
||||
assert client.get()['body'] == 'body\n', 'body io file'
|
||||
|
||||
assert self.get()['body'] == 'body\n', 'body io file'
|
||||
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_python_application_syntax_error(self, skip_alert):
|
||||
def test_python_application_syntax_error(skip_alert):
|
||||
skip_alert(r'Python failed to import module "wsgi"')
|
||||
self.load('syntax_error')
|
||||
client.load('syntax_error')
|
||||
|
||||
assert self.get()['status'] == 500, 'syntax error'
|
||||
assert client.get()['status'] == 500, 'syntax error'
|
||||
|
||||
def test_python_application_loading_error(self, skip_alert):
|
||||
|
||||
def test_python_application_loading_error(skip_alert):
|
||||
skip_alert(r'Python failed to import module "blah"')
|
||||
|
||||
self.load('empty', module="blah")
|
||||
client.load('empty', module="blah")
|
||||
|
||||
assert self.get()['status'] == 503, 'loading error'
|
||||
assert client.get()['status'] == 503, 'loading error'
|
||||
|
||||
def test_python_application_close(self, wait_for_record):
|
||||
self.load('close')
|
||||
|
||||
self.get()
|
||||
def test_python_application_close(wait_for_record):
|
||||
client.load('close')
|
||||
|
||||
client.get()
|
||||
|
||||
assert wait_for_record(r'Close called\.') is not None, 'close'
|
||||
|
||||
def test_python_application_close_error(self, wait_for_record):
|
||||
self.load('close_error')
|
||||
|
||||
self.get()
|
||||
def test_python_application_close_error(wait_for_record):
|
||||
client.load('close_error')
|
||||
|
||||
client.get()
|
||||
|
||||
assert wait_for_record(r'Close called\.') is not None, 'close error'
|
||||
|
||||
def test_python_application_not_iterable(self, wait_for_record):
|
||||
self.load('not_iterable')
|
||||
|
||||
self.get()
|
||||
def test_python_application_not_iterable(wait_for_record):
|
||||
client.load('not_iterable')
|
||||
|
||||
client.get()
|
||||
|
||||
assert (
|
||||
wait_for_record(
|
||||
|
@ -516,13 +547,15 @@ last line: 987654321
|
|||
is not None
|
||||
), 'not iterable'
|
||||
|
||||
def test_python_application_write(self):
|
||||
self.load('write')
|
||||
|
||||
assert self.get()['body'] == '0123456789', 'write'
|
||||
def test_python_application_write():
|
||||
client.load('write')
|
||||
|
||||
def test_python_application_encoding(self):
|
||||
self.load('encoding')
|
||||
assert client.get()['body'] == '0123456789', 'write'
|
||||
|
||||
|
||||
def test_python_application_encoding():
|
||||
client.load('encoding')
|
||||
|
||||
try:
|
||||
locales = (
|
||||
|
@ -557,19 +590,18 @@ last line: 987654321
|
|||
str.upper().replace('-', '').replace('_', '')
|
||||
|
||||
for loc in matches:
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{"LC_CTYPE": loc, "LC_ALL": ""},
|
||||
'/config/applications/encoding/environment',
|
||||
)
|
||||
resp = self.get()
|
||||
resp = client.get()
|
||||
assert resp['status'] == 200, 'status'
|
||||
assert unify(resp['headers']['X-Encoding']) == unify(
|
||||
loc.split('.')[-1]
|
||||
)
|
||||
assert unify(resp['headers']['X-Encoding']) == unify(loc.split('.')[-1])
|
||||
|
||||
def test_python_application_unicode(self, temp_dir):
|
||||
|
||||
def test_python_application_unicode(temp_dir):
|
||||
try:
|
||||
app_type = self.get_application_type()
|
||||
app_type = client.get_application_type()
|
||||
v = version.Version(app_type.split()[-1])
|
||||
if v.major != 3:
|
||||
raise version.InvalidVersion
|
||||
|
@ -580,13 +612,13 @@ last line: 987654321
|
|||
venv_path = f'{temp_dir}/venv'
|
||||
venv.create(venv_path)
|
||||
|
||||
self.load('unicode')
|
||||
assert 'success' in self.conf(
|
||||
client.load('unicode')
|
||||
assert 'success' in client.conf(
|
||||
f'"{venv_path}"',
|
||||
'/config/applications/unicode/home',
|
||||
)
|
||||
assert (
|
||||
self.get(
|
||||
client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Temp-dir': temp_dir,
|
||||
|
@ -596,26 +628,28 @@ last line: 987654321
|
|||
== 200
|
||||
)
|
||||
|
||||
def test_python_application_threading(self, wait_for_record):
|
||||
|
||||
def test_python_application_threading(wait_for_record):
|
||||
"""wait_for_record() timeouts after 5s while every thread works at
|
||||
least 3s. So without releasing GIL test should fail.
|
||||
"""
|
||||
|
||||
self.load('threading')
|
||||
client.load('threading')
|
||||
|
||||
for _ in range(10):
|
||||
self.get(no_recv=True)
|
||||
client.get(no_recv=True)
|
||||
|
||||
assert (
|
||||
wait_for_record(r'\(5\) Thread: 100', wait=50) is not None
|
||||
), 'last thread finished'
|
||||
|
||||
def test_python_application_iter_exception(self, findall, wait_for_record):
|
||||
self.load('iter_exception')
|
||||
|
||||
def test_python_application_iter_exception(findall, wait_for_record):
|
||||
client.load('iter_exception')
|
||||
|
||||
# Default request doesn't lead to the exception.
|
||||
|
||||
resp = self.get(
|
||||
resp = client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Skip': '9',
|
||||
|
@ -628,7 +662,7 @@ last line: 987654321
|
|||
|
||||
# Exception before start_response().
|
||||
|
||||
assert self.get()['status'] == 503, 'error'
|
||||
assert client.get()['status'] == 503, 'error'
|
||||
|
||||
assert wait_for_record(r'Traceback') is not None, 'traceback'
|
||||
assert (
|
||||
|
@ -639,7 +673,7 @@ last line: 987654321
|
|||
# Exception after start_response(), before first write().
|
||||
|
||||
assert (
|
||||
self.get(
|
||||
client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Skip': '1',
|
||||
|
@ -650,14 +684,13 @@ last line: 987654321
|
|||
), 'error 2'
|
||||
|
||||
assert (
|
||||
wait_for_record(r"raise Exception\('second exception'\)")
|
||||
is not None
|
||||
wait_for_record(r"raise Exception\('second exception'\)") is not None
|
||||
), 'exception raise second'
|
||||
assert len(findall(r'Traceback')) == 2, 'traceback count 2'
|
||||
|
||||
# Exception after first write(), before first __next__().
|
||||
|
||||
_, sock = self.get(
|
||||
_, sock = client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Skip': '2',
|
||||
|
@ -671,12 +704,12 @@ last line: 987654321
|
|||
), 'exception raise third'
|
||||
assert len(findall(r'Traceback')) == 3, 'traceback count 3'
|
||||
|
||||
assert self.get(sock=sock) == {}, 'closed connection'
|
||||
assert client.get(sock=sock) == {}, 'closed connection'
|
||||
|
||||
# Exception after first write(), before first __next__(),
|
||||
# chunked (incomplete body).
|
||||
|
||||
resp = self.get(
|
||||
resp = client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Skip': '2',
|
||||
|
@ -691,7 +724,7 @@ last line: 987654321
|
|||
|
||||
# Exception in __next__().
|
||||
|
||||
_, sock = self.get(
|
||||
_, sock = client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Skip': '3',
|
||||
|
@ -705,11 +738,11 @@ last line: 987654321
|
|||
), 'exception raise next'
|
||||
assert len(findall(r'Traceback')) == 5, 'traceback count 5'
|
||||
|
||||
assert self.get(sock=sock) == {}, 'closed connection 2'
|
||||
assert client.get(sock=sock) == {}, 'closed connection 2'
|
||||
|
||||
# Exception in __next__(), chunked (incomplete body).
|
||||
|
||||
resp = self.get(
|
||||
resp = client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Skip': '3',
|
||||
|
@ -725,7 +758,7 @@ last line: 987654321
|
|||
# Exception before start_response() and in close().
|
||||
|
||||
assert (
|
||||
self.get(
|
||||
client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Not-Skip-Close': '1',
|
||||
|
@ -740,7 +773,8 @@ last line: 987654321
|
|||
), 'exception raise close'
|
||||
assert len(findall(r'Traceback')) == 8, 'traceback count 8'
|
||||
|
||||
def test_python_user_group(self, require):
|
||||
|
||||
def test_python_user_group(require):
|
||||
require({'privileged_user': True})
|
||||
|
||||
nobody_uid = pwd.getpwnam('nobody').pw_uid
|
||||
|
@ -753,33 +787,33 @@ last line: 987654321
|
|||
group = 'nogroup'
|
||||
group_id = grp.getgrnam(group).gr_gid
|
||||
|
||||
self.load('user_group')
|
||||
client.load('user_group')
|
||||
|
||||
obj = self.getjson()['body']
|
||||
obj = client.getjson()['body']
|
||||
assert obj['UID'] == nobody_uid, 'nobody uid'
|
||||
assert obj['GID'] == group_id, 'nobody gid'
|
||||
|
||||
self.load('user_group', user='nobody')
|
||||
client.load('user_group', user='nobody')
|
||||
|
||||
obj = self.getjson()['body']
|
||||
obj = client.getjson()['body']
|
||||
assert obj['UID'] == nobody_uid, 'nobody uid user=nobody'
|
||||
assert obj['GID'] == group_id, 'nobody gid user=nobody'
|
||||
|
||||
self.load('user_group', user='nobody', group=group)
|
||||
client.load('user_group', user='nobody', group=group)
|
||||
|
||||
obj = self.getjson()['body']
|
||||
obj = client.getjson()['body']
|
||||
assert obj['UID'] == nobody_uid, f'nobody uid user=nobody group={group}'
|
||||
assert obj['GID'] == group_id, f'nobody gid user=nobody group={group}'
|
||||
|
||||
self.load('user_group', group=group)
|
||||
client.load('user_group', group=group)
|
||||
|
||||
obj = self.getjson()['body']
|
||||
obj = client.getjson()['body']
|
||||
assert obj['UID'] == nobody_uid, f'nobody uid group={group}'
|
||||
assert obj['GID'] == group_id, f'nobody gid group={group}'
|
||||
|
||||
self.load('user_group', user='root')
|
||||
client.load('user_group', user='root')
|
||||
|
||||
obj = self.getjson()['body']
|
||||
obj = client.getjson()['body']
|
||||
assert obj['UID'] == 0, 'root uid user=root'
|
||||
assert obj['GID'] == 0, 'root gid user=root'
|
||||
|
||||
|
@ -792,48 +826,50 @@ last line: 987654321
|
|||
group = False
|
||||
|
||||
if group:
|
||||
self.load('user_group', user='root', group='root')
|
||||
client.load('user_group', user='root', group='root')
|
||||
|
||||
obj = self.getjson()['body']
|
||||
obj = client.getjson()['body']
|
||||
assert obj['UID'] == 0, 'root uid user=root group=root'
|
||||
assert obj['GID'] == 0, 'root gid user=root group=root'
|
||||
|
||||
self.load('user_group', group='root')
|
||||
client.load('user_group', group='root')
|
||||
|
||||
obj = self.getjson()['body']
|
||||
obj = client.getjson()['body']
|
||||
assert obj['UID'] == nobody_uid, 'root uid group=root'
|
||||
assert obj['GID'] == 0, 'root gid group=root'
|
||||
|
||||
def test_python_application_callable(self, skip_alert):
|
||||
|
||||
def test_python_application_callable(skip_alert):
|
||||
skip_alert(r'Python failed to get "blah" from module')
|
||||
self.load('callable')
|
||||
client.load('callable')
|
||||
|
||||
assert self.get()['status'] == 204, 'default application response'
|
||||
assert client.get()['status'] == 204, 'default application response'
|
||||
|
||||
self.load('callable', callable="app")
|
||||
client.load('callable', callable="app")
|
||||
|
||||
assert self.get()['status'] == 200, 'callable response'
|
||||
assert client.get()['status'] == 200, 'callable response'
|
||||
|
||||
self.load('callable', callable="blah")
|
||||
client.load('callable', callable="blah")
|
||||
|
||||
assert self.get()['status'] not in [200, 204], 'callable response inv'
|
||||
assert client.get()['status'] not in [200, 204], 'callable response inv'
|
||||
|
||||
def test_python_application_path(self):
|
||||
self.load('path')
|
||||
|
||||
def test_python_application_path():
|
||||
client.load('path')
|
||||
|
||||
def set_path(path):
|
||||
assert 'success' in self.conf(path, 'applications/path/path')
|
||||
assert 'success' in client.conf(path, 'applications/path/path')
|
||||
|
||||
def get_path():
|
||||
return self.get()['body'].split(os.pathsep)
|
||||
return client.get()['body'].split(os.pathsep)
|
||||
|
||||
default_path = self.conf_get('/config/applications/path/path')
|
||||
assert 'success' in self.conf(
|
||||
default_path = client.conf_get('/config/applications/path/path')
|
||||
assert 'success' in client.conf(
|
||||
{"PYTHONPATH": default_path},
|
||||
'/config/applications/path/environment',
|
||||
)
|
||||
|
||||
self.conf_delete('/config/applications/path/path')
|
||||
client.conf_delete('/config/applications/path/path')
|
||||
sys_path = get_path()
|
||||
|
||||
set_path('"/blah"')
|
||||
|
@ -849,22 +885,24 @@ last line: 987654321
|
|||
*sys_path,
|
||||
] == get_path(), 'check path array'
|
||||
|
||||
def test_python_application_path_invalid(self):
|
||||
self.load('path')
|
||||
|
||||
def test_python_application_path_invalid():
|
||||
client.load('path')
|
||||
|
||||
def check_path(path):
|
||||
assert 'error' in self.conf(path, 'applications/path/path')
|
||||
assert 'error' in client.conf(path, 'applications/path/path')
|
||||
|
||||
check_path('{}')
|
||||
check_path('["/blah", []]')
|
||||
|
||||
def test_python_application_threads(self):
|
||||
self.load('threads', threads=4)
|
||||
|
||||
def test_python_application_threads():
|
||||
client.load('threads', threads=4)
|
||||
|
||||
socks = []
|
||||
|
||||
for _ in range(4):
|
||||
sock = self.get(
|
||||
sock = client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Delay': '2',
|
||||
|
@ -878,11 +916,11 @@ last line: 987654321
|
|||
threads = set()
|
||||
|
||||
for sock in socks:
|
||||
resp = self.recvall(sock).decode('utf-8')
|
||||
resp = client.recvall(sock).decode('utf-8')
|
||||
|
||||
self.log_in(resp)
|
||||
client.log_in(resp)
|
||||
|
||||
resp = self._resp_to_dict(resp)
|
||||
resp = client._resp_to_dict(resp)
|
||||
|
||||
assert resp['status'] == 200, 'status'
|
||||
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
from unit.control import TestControl
|
||||
from unit.control import Control
|
||||
|
||||
prerequisites = {'modules': {'python': 'any'}}
|
||||
|
||||
|
||||
class TestPythonBasic(TestControl):
|
||||
client = Control()
|
||||
|
||||
conf_app = {
|
||||
"app": {
|
||||
|
@ -19,15 +18,17 @@ class TestPythonBasic(TestControl):
|
|||
"applications": conf_app,
|
||||
}
|
||||
|
||||
def test_python_get_empty(self):
|
||||
assert self.conf_get() == {'listeners': {}, 'applications': {}}
|
||||
assert self.conf_get('listeners') == {}
|
||||
assert self.conf_get('applications') == {}
|
||||
|
||||
def test_python_get_applications(self):
|
||||
self.conf(self.conf_app, 'applications')
|
||||
def test_python_get_empty():
|
||||
assert client.conf_get() == {'listeners': {}, 'applications': {}}
|
||||
assert client.conf_get('listeners') == {}
|
||||
assert client.conf_get('applications') == {}
|
||||
|
||||
conf = self.conf_get()
|
||||
|
||||
def test_python_get_applications():
|
||||
client.conf(conf_app, 'applications')
|
||||
|
||||
conf = client.conf_get()
|
||||
|
||||
assert conf['listeners'] == {}, 'listeners'
|
||||
assert conf['applications'] == {
|
||||
|
@ -39,7 +40,7 @@ class TestPythonBasic(TestControl):
|
|||
}
|
||||
}, 'applications'
|
||||
|
||||
assert self.conf_get('applications') == {
|
||||
assert client.conf_get('applications') == {
|
||||
"app": {
|
||||
"type": "python",
|
||||
"processes": {"spare": 0},
|
||||
|
@ -48,80 +49,86 @@ class TestPythonBasic(TestControl):
|
|||
}
|
||||
}, 'applications prefix'
|
||||
|
||||
assert self.conf_get('applications/app') == {
|
||||
assert client.conf_get('applications/app') == {
|
||||
"type": "python",
|
||||
"processes": {"spare": 0},
|
||||
"path": "/app",
|
||||
"module": "wsgi",
|
||||
}, 'applications prefix 2'
|
||||
|
||||
assert self.conf_get('applications/app/type') == 'python', 'type'
|
||||
assert self.conf_get('applications/app/processes/spare') == 0, 'spare'
|
||||
assert client.conf_get('applications/app/type') == 'python', 'type'
|
||||
assert client.conf_get('applications/app/processes/spare') == 0, 'spare'
|
||||
|
||||
def test_python_get_listeners(self):
|
||||
assert 'success' in self.conf(self.conf_basic)
|
||||
|
||||
assert self.conf_get()['listeners'] == {
|
||||
def test_python_get_listeners():
|
||||
assert 'success' in client.conf(conf_basic)
|
||||
|
||||
assert client.conf_get()['listeners'] == {
|
||||
"*:7080": {"pass": "applications/app"}
|
||||
}, 'listeners'
|
||||
|
||||
assert self.conf_get('listeners') == {
|
||||
assert client.conf_get('listeners') == {
|
||||
"*:7080": {"pass": "applications/app"}
|
||||
}, 'listeners prefix'
|
||||
|
||||
assert self.conf_get('listeners/*:7080') == {
|
||||
assert client.conf_get('listeners/*:7080') == {
|
||||
"pass": "applications/app"
|
||||
}, 'listeners prefix 2'
|
||||
|
||||
def test_python_change_listener(self):
|
||||
assert 'success' in self.conf(self.conf_basic)
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def test_python_change_listener():
|
||||
assert 'success' in client.conf(conf_basic)
|
||||
assert 'success' in client.conf(
|
||||
{"*:7081": {"pass": "applications/app"}}, 'listeners'
|
||||
)
|
||||
|
||||
assert self.conf_get('listeners') == {
|
||||
assert client.conf_get('listeners') == {
|
||||
"*:7081": {"pass": "applications/app"}
|
||||
}, 'change listener'
|
||||
|
||||
def test_python_add_listener(self):
|
||||
assert 'success' in self.conf(self.conf_basic)
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def test_python_add_listener():
|
||||
assert 'success' in client.conf(conf_basic)
|
||||
assert 'success' in client.conf(
|
||||
{"pass": "applications/app"}, 'listeners/*:7082'
|
||||
)
|
||||
|
||||
assert self.conf_get('listeners') == {
|
||||
assert client.conf_get('listeners') == {
|
||||
"*:7080": {"pass": "applications/app"},
|
||||
"*:7082": {"pass": "applications/app"},
|
||||
}, 'add listener'
|
||||
|
||||
def test_python_change_application(self):
|
||||
assert 'success' in self.conf(self.conf_basic)
|
||||
|
||||
assert 'success' in self.conf('30', 'applications/app/processes/max')
|
||||
def test_python_change_application():
|
||||
assert 'success' in client.conf(conf_basic)
|
||||
|
||||
assert 'success' in client.conf('30', 'applications/app/processes/max')
|
||||
assert (
|
||||
self.conf_get('applications/app/processes/max') == 30
|
||||
client.conf_get('applications/app/processes/max') == 30
|
||||
), 'change application max'
|
||||
|
||||
assert 'success' in self.conf('"/www"', 'applications/app/path')
|
||||
assert 'success' in client.conf('"/www"', 'applications/app/path')
|
||||
assert (
|
||||
self.conf_get('applications/app/path') == '/www'
|
||||
client.conf_get('applications/app/path') == '/www'
|
||||
), 'change application path'
|
||||
|
||||
def test_python_delete(self):
|
||||
assert 'success' in self.conf(self.conf_basic)
|
||||
|
||||
assert 'error' in self.conf_delete('applications/app')
|
||||
assert 'success' in self.conf_delete('listeners/*:7080')
|
||||
assert 'success' in self.conf_delete('applications/app')
|
||||
assert 'error' in self.conf_delete('applications/app')
|
||||
def test_python_delete():
|
||||
assert 'success' in client.conf(conf_basic)
|
||||
|
||||
def test_python_delete_blocks(self):
|
||||
assert 'success' in self.conf(self.conf_basic)
|
||||
assert 'error' in client.conf_delete('applications/app')
|
||||
assert 'success' in client.conf_delete('listeners/*:7080')
|
||||
assert 'success' in client.conf_delete('applications/app')
|
||||
assert 'error' in client.conf_delete('applications/app')
|
||||
|
||||
assert 'success' in self.conf_delete('listeners')
|
||||
assert 'success' in self.conf_delete('applications')
|
||||
|
||||
assert 'success' in self.conf(self.conf_app, 'applications')
|
||||
assert 'success' in self.conf(
|
||||
def test_python_delete_blocks():
|
||||
assert 'success' in client.conf(conf_basic)
|
||||
|
||||
assert 'success' in client.conf_delete('listeners')
|
||||
assert 'success' in client.conf_delete('applications')
|
||||
|
||||
assert 'success' in client.conf(conf_app, 'applications')
|
||||
assert 'success' in client.conf(
|
||||
{"*:7081": {"pass": "applications/app"}}, 'listeners'
|
||||
), 'applications restore'
|
||||
|
|
|
@ -1,37 +1,41 @@
|
|||
from unit.applications.lang.python import TestApplicationPython
|
||||
from unit.applications.lang.python import ApplicationPython
|
||||
|
||||
prerequisites = {'modules': {'python': 'any'}}
|
||||
|
||||
client = ApplicationPython()
|
||||
|
||||
class TestPythonEnvironment(TestApplicationPython):
|
||||
def test_python_environment_name_null(self):
|
||||
self.load('environment')
|
||||
|
||||
assert 'error' in self.conf(
|
||||
def test_python_environment_name_null():
|
||||
client.load('environment')
|
||||
|
||||
assert 'error' in client.conf(
|
||||
{"va\0r": "val1"}, 'applications/environment/environment'
|
||||
), 'name null'
|
||||
|
||||
def test_python_environment_name_equals(self):
|
||||
self.load('environment')
|
||||
|
||||
assert 'error' in self.conf(
|
||||
def test_python_environment_name_equals():
|
||||
client.load('environment')
|
||||
|
||||
assert 'error' in client.conf(
|
||||
{"var=": "val1"}, 'applications/environment/environment'
|
||||
), 'name equals'
|
||||
|
||||
def test_python_environment_value_null(self):
|
||||
self.load('environment')
|
||||
|
||||
assert 'error' in self.conf(
|
||||
def test_python_environment_value_null():
|
||||
client.load('environment')
|
||||
|
||||
assert 'error' in client.conf(
|
||||
{"var": "\0val"}, 'applications/environment/environment'
|
||||
), 'value null'
|
||||
|
||||
def test_python_environment_update(self):
|
||||
self.load('environment')
|
||||
|
||||
self.conf({"var": "val1"}, 'applications/environment/environment')
|
||||
def test_python_environment_update():
|
||||
client.load('environment')
|
||||
|
||||
client.conf({"var": "val1"}, 'applications/environment/environment')
|
||||
|
||||
assert (
|
||||
self.get(
|
||||
client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Variables': 'var',
|
||||
|
@ -41,10 +45,10 @@ class TestPythonEnvironment(TestApplicationPython):
|
|||
== 'val1'
|
||||
), 'set'
|
||||
|
||||
self.conf({"var": "val2"}, 'applications/environment/environment')
|
||||
client.conf({"var": "val2"}, 'applications/environment/environment')
|
||||
|
||||
assert (
|
||||
self.get(
|
||||
client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Variables': 'var',
|
||||
|
@ -54,13 +58,14 @@ class TestPythonEnvironment(TestApplicationPython):
|
|||
== 'val2'
|
||||
), 'update'
|
||||
|
||||
def test_python_environment_replace(self):
|
||||
self.load('environment')
|
||||
|
||||
self.conf({"var1": "val1"}, 'applications/environment/environment')
|
||||
def test_python_environment_replace():
|
||||
client.load('environment')
|
||||
|
||||
client.conf({"var1": "val1"}, 'applications/environment/environment')
|
||||
|
||||
assert (
|
||||
self.get(
|
||||
client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Variables': 'var1',
|
||||
|
@ -70,10 +75,10 @@ class TestPythonEnvironment(TestApplicationPython):
|
|||
== 'val1'
|
||||
), 'set'
|
||||
|
||||
self.conf({"var2": "val2"}, 'applications/environment/environment')
|
||||
client.conf({"var2": "val2"}, 'applications/environment/environment')
|
||||
|
||||
assert (
|
||||
self.get(
|
||||
client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Variables': 'var1,var2',
|
||||
|
@ -83,16 +88,17 @@ class TestPythonEnvironment(TestApplicationPython):
|
|||
== 'val2'
|
||||
), 'replace'
|
||||
|
||||
def test_python_environment_clear(self):
|
||||
self.load('environment')
|
||||
|
||||
self.conf(
|
||||
def test_python_environment_clear():
|
||||
client.load('environment')
|
||||
|
||||
client.conf(
|
||||
{"var1": "val1", "var2": "val2"},
|
||||
'applications/environment/environment',
|
||||
)
|
||||
|
||||
assert (
|
||||
self.get(
|
||||
client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Variables': 'var1,var2',
|
||||
|
@ -102,10 +108,10 @@ class TestPythonEnvironment(TestApplicationPython):
|
|||
== 'val1,val2'
|
||||
), 'set'
|
||||
|
||||
self.conf({}, 'applications/environment/environment')
|
||||
client.conf({}, 'applications/environment/environment')
|
||||
|
||||
assert (
|
||||
self.get(
|
||||
client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Variables': 'var1,var2',
|
||||
|
@ -115,10 +121,11 @@ class TestPythonEnvironment(TestApplicationPython):
|
|||
== ''
|
||||
), 'clear'
|
||||
|
||||
def test_python_environment_replace_default(self):
|
||||
self.load('environment')
|
||||
|
||||
home_default = self.get(
|
||||
def test_python_environment_replace_default():
|
||||
client.load('environment')
|
||||
|
||||
home_default = client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Variables': 'HOME',
|
||||
|
@ -128,10 +135,10 @@ class TestPythonEnvironment(TestApplicationPython):
|
|||
|
||||
assert len(home_default) > 1, 'get default'
|
||||
|
||||
self.conf({"HOME": "/"}, 'applications/environment/environment')
|
||||
client.conf({"HOME": "/"}, 'applications/environment/environment')
|
||||
|
||||
assert (
|
||||
self.get(
|
||||
client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Variables': 'HOME',
|
||||
|
@ -141,10 +148,10 @@ class TestPythonEnvironment(TestApplicationPython):
|
|||
== '/'
|
||||
), 'replace default'
|
||||
|
||||
self.conf({}, 'applications/environment/environment')
|
||||
client.conf({}, 'applications/environment/environment')
|
||||
|
||||
assert (
|
||||
self.get(
|
||||
client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Variables': 'HOME',
|
||||
|
|
|
@ -4,7 +4,7 @@ import subprocess
|
|||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from unit.applications.lang.python import TestApplicationPython
|
||||
from unit.applications.lang.python import ApplicationPython
|
||||
from unit.option import option
|
||||
from unit.utils import findmnt
|
||||
from unit.utils import waitformount
|
||||
|
@ -12,16 +12,15 @@ from unit.utils import waitforunmount
|
|||
|
||||
prerequisites = {'modules': {'python': 'any'}, 'features': {'isolation': True}}
|
||||
|
||||
client = ApplicationPython()
|
||||
|
||||
class TestPythonIsolation(TestApplicationPython):
|
||||
def get_cgroup(self, app_name):
|
||||
|
||||
def get_cgroup(app_name):
|
||||
output = subprocess.check_output(
|
||||
['ps', 'ax', '-o', 'pid', '-o', 'cmd']
|
||||
).decode()
|
||||
|
||||
pid = re.search(
|
||||
fr'(\d+)\s*unit: "{app_name}" application', output
|
||||
).group(1)
|
||||
pid = re.search(fr'(\d+)\s*unit: "{app_name}" application', output).group(1)
|
||||
|
||||
cgroup = f'/proc/{pid}/cgroup'
|
||||
|
||||
|
@ -31,7 +30,8 @@ class TestPythonIsolation(TestApplicationPython):
|
|||
with open(cgroup, 'r') as f:
|
||||
return f.read().rstrip()
|
||||
|
||||
def test_python_isolation_rootfs(self, is_su, require, temp_dir):
|
||||
|
||||
def test_python_isolation_rootfs(is_su, require, temp_dir):
|
||||
isolation = {'rootfs': temp_dir}
|
||||
|
||||
if not is_su:
|
||||
|
@ -54,101 +54,101 @@ class TestPythonIsolation(TestApplicationPython):
|
|||
'pid': True,
|
||||
}
|
||||
|
||||
self.load('ns_inspect', isolation=isolation)
|
||||
client.load('ns_inspect', isolation=isolation)
|
||||
|
||||
assert not (
|
||||
self.getjson(url=f'/?path={temp_dir}')['body']['FileExists']
|
||||
client.getjson(url=f'/?path={temp_dir}')['body']['FileExists']
|
||||
), 'temp_dir does not exists in rootfs'
|
||||
|
||||
assert self.getjson(url='/?path=/proc/self')['body'][
|
||||
assert client.getjson(url='/?path=/proc/self')['body'][
|
||||
'FileExists'
|
||||
], 'no /proc/self'
|
||||
|
||||
assert not (
|
||||
self.getjson(url='/?path=/dev/pts')['body']['FileExists']
|
||||
client.getjson(url='/?path=/dev/pts')['body']['FileExists']
|
||||
), 'no /dev/pts'
|
||||
|
||||
assert not (
|
||||
self.getjson(url='/?path=/sys/kernel')['body']['FileExists']
|
||||
client.getjson(url='/?path=/sys/kernel')['body']['FileExists']
|
||||
), 'no /sys/kernel'
|
||||
|
||||
ret = self.getjson(url='/?path=/app/python/ns_inspect')
|
||||
ret = client.getjson(url='/?path=/app/python/ns_inspect')
|
||||
|
||||
assert ret['body']['FileExists'], 'application exists in rootfs'
|
||||
|
||||
def test_python_isolation_rootfs_no_language_deps(self, require, temp_dir):
|
||||
|
||||
def test_python_isolation_rootfs_no_language_deps(require, temp_dir):
|
||||
require({'privileged_user': True})
|
||||
|
||||
isolation = {'rootfs': temp_dir, 'automount': {'language_deps': False}}
|
||||
self.load('empty', isolation=isolation)
|
||||
client.load('empty', isolation=isolation)
|
||||
|
||||
python_path = f'{temp_dir}/usr'
|
||||
|
||||
assert findmnt().find(python_path) == -1
|
||||
assert self.get()['status'] != 200, 'disabled language_deps'
|
||||
assert client.get()['status'] != 200, 'disabled language_deps'
|
||||
assert findmnt().find(python_path) == -1
|
||||
|
||||
isolation['automount']['language_deps'] = True
|
||||
|
||||
self.load('empty', isolation=isolation)
|
||||
client.load('empty', isolation=isolation)
|
||||
|
||||
assert findmnt().find(python_path) == -1
|
||||
assert self.get()['status'] == 200, 'enabled language_deps'
|
||||
assert client.get()['status'] == 200, 'enabled language_deps'
|
||||
assert waitformount(python_path), 'language_deps mount'
|
||||
|
||||
self.conf({"listeners": {}, "applications": {}})
|
||||
client.conf({"listeners": {}, "applications": {}})
|
||||
|
||||
assert waitforunmount(python_path), 'language_deps unmount'
|
||||
|
||||
def test_python_isolation_procfs(self, require, temp_dir):
|
||||
|
||||
def test_python_isolation_procfs(require, temp_dir):
|
||||
require({'privileged_user': True})
|
||||
|
||||
isolation = {'rootfs': temp_dir, 'automount': {'procfs': False}}
|
||||
|
||||
self.load('ns_inspect', isolation=isolation)
|
||||
client.load('ns_inspect', isolation=isolation)
|
||||
|
||||
assert not (
|
||||
self.getjson(url='/?path=/proc/self')['body']['FileExists']
|
||||
client.getjson(url='/?path=/proc/self')['body']['FileExists']
|
||||
), 'no /proc/self'
|
||||
|
||||
isolation['automount']['procfs'] = True
|
||||
|
||||
self.load('ns_inspect', isolation=isolation)
|
||||
client.load('ns_inspect', isolation=isolation)
|
||||
|
||||
assert self.getjson(url='/?path=/proc/self')['body'][
|
||||
assert client.getjson(url='/?path=/proc/self')['body'][
|
||||
'FileExists'
|
||||
], '/proc/self'
|
||||
|
||||
def test_python_isolation_cgroup(self, require):
|
||||
require(
|
||||
{'privileged_user': True, 'features': {'isolation': ['cgroup']}}
|
||||
)
|
||||
|
||||
def test_python_isolation_cgroup(require):
|
||||
require({'privileged_user': True, 'features': {'isolation': ['cgroup']}})
|
||||
|
||||
def set_cgroup_path(path):
|
||||
isolation = {'cgroup': {'path': path}}
|
||||
self.load('empty', processes=1, isolation=isolation)
|
||||
client.load('empty', processes=1, isolation=isolation)
|
||||
|
||||
set_cgroup_path('scope/python')
|
||||
|
||||
cgroup_rel = Path(self.get_cgroup('empty'))
|
||||
cgroup_rel = Path(get_cgroup('empty'))
|
||||
assert cgroup_rel.parts[-2:] == ('scope', 'python'), 'cgroup rel'
|
||||
|
||||
set_cgroup_path('/scope2/python')
|
||||
|
||||
cgroup_abs = Path(self.get_cgroup('empty'))
|
||||
cgroup_abs = Path(get_cgroup('empty'))
|
||||
assert cgroup_abs.parts[-2:] == ('scope2', 'python'), 'cgroup abs'
|
||||
|
||||
assert len(cgroup_rel.parts) >= len(cgroup_abs.parts)
|
||||
|
||||
def test_python_isolation_cgroup_two(self, require):
|
||||
require(
|
||||
{'privileged_user': True, 'features': {'isolation': ['cgroup']}}
|
||||
)
|
||||
|
||||
def test_python_isolation_cgroup_two(require):
|
||||
require({'privileged_user': True, 'features': {'isolation': ['cgroup']}})
|
||||
|
||||
def set_two_cgroup_path(path, path2):
|
||||
script_path = f'{option.test_dir}/python/empty'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"*:7080": {"pass": "applications/one"},
|
||||
|
@ -180,19 +180,18 @@ class TestPythonIsolation(TestApplicationPython):
|
|||
)
|
||||
|
||||
set_two_cgroup_path('/scope/python', '/scope/python')
|
||||
assert self.get_cgroup('one') == self.get_cgroup('two')
|
||||
assert get_cgroup('one') == get_cgroup('two')
|
||||
|
||||
set_two_cgroup_path('/scope/python', '/scope2/python')
|
||||
assert self.get_cgroup('one') != self.get_cgroup('two')
|
||||
assert get_cgroup('one') != get_cgroup('two')
|
||||
|
||||
def test_python_isolation_cgroup_invalid(self, require):
|
||||
require(
|
||||
{'privileged_user': True, 'features': {'isolation': ['cgroup']}}
|
||||
)
|
||||
|
||||
def test_python_isolation_cgroup_invalid(require):
|
||||
require({'privileged_user': True, 'features': {'isolation': ['cgroup']}})
|
||||
|
||||
def check_invalid(path):
|
||||
script_path = f'{option.test_dir}/python/empty'
|
||||
assert 'error' in self.conf(
|
||||
assert 'error' in client.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "applications/empty"}},
|
||||
"applications": {
|
||||
|
|
|
@ -1,30 +1,29 @@
|
|||
from unit.applications.lang.python import TestApplicationPython
|
||||
from unit.applications.lang.python import ApplicationPython
|
||||
|
||||
prerequisites = {'modules': {'python': 'any'}, 'privileged_user': True}
|
||||
|
||||
client = ApplicationPython()
|
||||
|
||||
class TestPythonIsolation(TestApplicationPython):
|
||||
def test_python_isolation_chroot(self, temp_dir):
|
||||
isolation = {'rootfs': temp_dir}
|
||||
|
||||
self.load('ns_inspect', isolation=isolation)
|
||||
def test_python_isolation_chroot(temp_dir):
|
||||
client.load('ns_inspect', isolation={'rootfs': temp_dir})
|
||||
|
||||
assert not (
|
||||
self.getjson(url=f'/?path={temp_dir}')['body']['FileExists']
|
||||
client.getjson(url=f'/?path={temp_dir}')['body']['FileExists']
|
||||
), 'temp_dir does not exists in rootfs'
|
||||
|
||||
assert self.getjson(url='/?path=/proc/self')['body'][
|
||||
assert client.getjson(url='/?path=/proc/self')['body'][
|
||||
'FileExists'
|
||||
], 'no /proc/self'
|
||||
|
||||
assert not (
|
||||
self.getjson(url='/?path=/dev/pts')['body']['FileExists']
|
||||
client.getjson(url='/?path=/dev/pts')['body']['FileExists']
|
||||
), 'no /dev/pts'
|
||||
|
||||
assert not (
|
||||
self.getjson(url='/?path=/sys/kernel')['body']['FileExists']
|
||||
client.getjson(url='/?path=/sys/kernel')['body']['FileExists']
|
||||
), 'no /sys/kernel'
|
||||
|
||||
ret = self.getjson(url='/?path=/app/python/ns_inspect')
|
||||
ret = client.getjson(url='/?path=/app/python/ns_inspect')
|
||||
|
||||
assert ret['body']['FileExists'], 'application exists in rootfs'
|
||||
|
|
|
@ -4,282 +4,299 @@ import subprocess
|
|||
import time
|
||||
|
||||
import pytest
|
||||
from unit.applications.lang.python import TestApplicationPython
|
||||
from unit.applications.lang.python import ApplicationPython
|
||||
from unit.option import option
|
||||
|
||||
prerequisites = {'modules': {'python': 'any'}}
|
||||
|
||||
client = ApplicationPython()
|
||||
|
||||
|
||||
class TestPythonProcman(TestApplicationPython):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_method_fixture(self, temp_dir):
|
||||
self.app_name = f'app-{temp_dir.split("/")[-1]}'
|
||||
self.app_proc = f'applications/{self.app_name}/processes'
|
||||
self.load('empty', self.app_name)
|
||||
def setup_method_fixture(temp_dir):
|
||||
client.app_name = f'app-{temp_dir.split("/")[-1]}'
|
||||
client.app_proc = f'applications/{client.app_name}/processes'
|
||||
client.load('empty', client.app_name)
|
||||
|
||||
def pids_for_process(self):
|
||||
|
||||
def pids_for_process():
|
||||
time.sleep(0.2)
|
||||
|
||||
output = subprocess.check_output(['ps', 'ax'])
|
||||
|
||||
pids = set()
|
||||
for m in re.findall(
|
||||
fr'.*unit: "{self.app_name}" application', output.decode()
|
||||
fr'.*unit: "{client.app_name}" application', output.decode()
|
||||
):
|
||||
pids.add(re.search(r'^\s*(\d+)', m).group(1))
|
||||
|
||||
return pids
|
||||
|
||||
def conf_proc(self, conf, path=None):
|
||||
if path is None:
|
||||
path = self.app_proc
|
||||
|
||||
assert 'success' in self.conf(conf, path), 'configure processes'
|
||||
def conf_proc(conf, path=None):
|
||||
if path is None:
|
||||
path = client.app_proc
|
||||
|
||||
assert 'success' in client.conf(conf, path), 'configure processes'
|
||||
|
||||
|
||||
def stop_all():
|
||||
assert 'success' in client.conf({"listeners": {}, "applications": {}})
|
||||
|
||||
assert len(pids_for_process()) == 0, 'stop all'
|
||||
|
||||
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_python_processes_idle_timeout_zero(self):
|
||||
self.conf_proc({"spare": 0, "max": 2, "idle_timeout": 0})
|
||||
def test_python_processes_idle_timeout_zero():
|
||||
conf_proc({"spare": 0, "max": 2, "idle_timeout": 0})
|
||||
|
||||
self.get()
|
||||
assert len(self.pids_for_process()) == 0, 'idle timeout 0'
|
||||
client.get()
|
||||
assert len(pids_for_process()) == 0, 'idle timeout 0'
|
||||
|
||||
def test_python_prefork(self):
|
||||
self.conf_proc('2')
|
||||
|
||||
pids = self.pids_for_process()
|
||||
def test_python_prefork():
|
||||
conf_proc('2')
|
||||
|
||||
pids = pids_for_process()
|
||||
assert len(pids) == 2, 'prefork 2'
|
||||
|
||||
self.get()
|
||||
assert self.pids_for_process() == pids, 'prefork still 2'
|
||||
client.get()
|
||||
assert pids_for_process() == pids, 'prefork still 2'
|
||||
|
||||
self.conf_proc('4')
|
||||
conf_proc('4')
|
||||
|
||||
pids = self.pids_for_process()
|
||||
pids = pids_for_process()
|
||||
assert len(pids) == 4, 'prefork 4'
|
||||
|
||||
self.get()
|
||||
assert self.pids_for_process() == pids, 'prefork still 4'
|
||||
client.get()
|
||||
assert pids_for_process() == pids, 'prefork still 4'
|
||||
|
||||
stop_all()
|
||||
|
||||
self.stop_all()
|
||||
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_python_prefork_same_processes(self):
|
||||
self.conf_proc('2')
|
||||
pids = self.pids_for_process()
|
||||
def test_python_prefork_same_processes():
|
||||
conf_proc('2')
|
||||
pids = pids_for_process()
|
||||
|
||||
self.conf_proc('4')
|
||||
pids_new = self.pids_for_process()
|
||||
conf_proc('4')
|
||||
pids_new = pids_for_process()
|
||||
|
||||
assert pids.issubset(pids_new), 'prefork same processes'
|
||||
|
||||
def test_python_ondemand(self):
|
||||
self.conf_proc({"spare": 0, "max": 8, "idle_timeout": 1})
|
||||
|
||||
assert len(self.pids_for_process()) == 0, 'on-demand 0'
|
||||
def test_python_ondemand():
|
||||
conf_proc({"spare": 0, "max": 8, "idle_timeout": 1})
|
||||
|
||||
self.get()
|
||||
pids = self.pids_for_process()
|
||||
assert len(pids_for_process()) == 0, 'on-demand 0'
|
||||
|
||||
client.get()
|
||||
pids = pids_for_process()
|
||||
assert len(pids) == 1, 'on-demand 1'
|
||||
|
||||
self.get()
|
||||
assert self.pids_for_process() == pids, 'on-demand still 1'
|
||||
client.get()
|
||||
assert pids_for_process() == pids, 'on-demand still 1'
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
assert len(self.pids_for_process()) == 0, 'on-demand stop idle'
|
||||
assert len(pids_for_process()) == 0, 'on-demand stop idle'
|
||||
|
||||
self.stop_all()
|
||||
stop_all()
|
||||
|
||||
def test_python_scale_updown(self):
|
||||
self.conf_proc({"spare": 2, "max": 8, "idle_timeout": 1})
|
||||
|
||||
pids = self.pids_for_process()
|
||||
def test_python_scale_updown():
|
||||
conf_proc({"spare": 2, "max": 8, "idle_timeout": 1})
|
||||
|
||||
pids = pids_for_process()
|
||||
assert len(pids) == 2, 'updown 2'
|
||||
|
||||
self.get()
|
||||
pids_new = self.pids_for_process()
|
||||
client.get()
|
||||
pids_new = pids_for_process()
|
||||
assert len(pids_new) == 3, 'updown 3'
|
||||
assert pids.issubset(pids_new), 'updown 3 only 1 new'
|
||||
|
||||
self.get()
|
||||
assert self.pids_for_process() == pids_new, 'updown still 3'
|
||||
client.get()
|
||||
assert pids_for_process() == pids_new, 'updown still 3'
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
pids = self.pids_for_process()
|
||||
pids = pids_for_process()
|
||||
assert len(pids) == 2, 'updown stop idle'
|
||||
|
||||
self.get()
|
||||
pids_new = self.pids_for_process()
|
||||
client.get()
|
||||
pids_new = pids_for_process()
|
||||
assert len(pids_new) == 3, 'updown again 3'
|
||||
assert pids.issubset(pids_new), 'updown again 3 only 1 new'
|
||||
|
||||
self.stop_all()
|
||||
stop_all()
|
||||
|
||||
def test_python_reconfigure(self):
|
||||
self.conf_proc({"spare": 2, "max": 6, "idle_timeout": 1})
|
||||
|
||||
pids = self.pids_for_process()
|
||||
def test_python_reconfigure():
|
||||
conf_proc({"spare": 2, "max": 6, "idle_timeout": 1})
|
||||
|
||||
pids = pids_for_process()
|
||||
assert len(pids) == 2, 'reconf 2'
|
||||
|
||||
self.get()
|
||||
pids_new = self.pids_for_process()
|
||||
client.get()
|
||||
pids_new = pids_for_process()
|
||||
assert len(pids_new) == 3, 'reconf 3'
|
||||
assert pids.issubset(pids_new), 'reconf 3 only 1 new'
|
||||
|
||||
self.conf_proc('6', f'{self.app_proc}/spare')
|
||||
conf_proc('6', f'{client.app_proc}/spare')
|
||||
|
||||
pids = self.pids_for_process()
|
||||
pids = pids_for_process()
|
||||
assert len(pids) == 6, 'reconf 6'
|
||||
|
||||
self.get()
|
||||
assert self.pids_for_process() == pids, 'reconf still 6'
|
||||
client.get()
|
||||
assert pids_for_process() == pids, 'reconf still 6'
|
||||
|
||||
self.stop_all()
|
||||
stop_all()
|
||||
|
||||
def test_python_idle_timeout(self):
|
||||
self.conf_proc({"spare": 0, "max": 6, "idle_timeout": 2})
|
||||
|
||||
self.get()
|
||||
pids = self.pids_for_process()
|
||||
def test_python_idle_timeout():
|
||||
conf_proc({"spare": 0, "max": 6, "idle_timeout": 2})
|
||||
|
||||
client.get()
|
||||
pids = pids_for_process()
|
||||
assert len(pids) == 1, 'idle timeout 1'
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
self.get()
|
||||
client.get()
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
pids_new = self.pids_for_process()
|
||||
pids_new = pids_for_process()
|
||||
assert len(pids_new) == 1, 'idle timeout still 1'
|
||||
assert self.pids_for_process() == pids, 'idle timeout still 1 same pid'
|
||||
assert pids_for_process() == pids, 'idle timeout still 1 same pid'
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
assert len(self.pids_for_process()) == 0, 'idle timed out'
|
||||
assert len(pids_for_process()) == 0, 'idle timed out'
|
||||
|
||||
def test_python_processes_connection_keepalive(self):
|
||||
self.conf_proc({"spare": 0, "max": 6, "idle_timeout": 2})
|
||||
|
||||
(_, sock) = self.get(
|
||||
def test_python_processes_connection_keepalive():
|
||||
conf_proc({"spare": 0, "max": 6, "idle_timeout": 2})
|
||||
|
||||
(_, sock) = client.get(
|
||||
headers={'Host': 'localhost', 'Connection': 'keep-alive'},
|
||||
start=True,
|
||||
read_timeout=1,
|
||||
)
|
||||
assert len(self.pids_for_process()) == 1, 'keepalive connection 1'
|
||||
assert len(pids_for_process()) == 1, 'keepalive connection 1'
|
||||
|
||||
time.sleep(2)
|
||||
|
||||
assert len(self.pids_for_process()) == 0, 'keepalive connection 0'
|
||||
assert len(pids_for_process()) == 0, 'keepalive connection 0'
|
||||
|
||||
sock.close()
|
||||
|
||||
def test_python_processes_access(self):
|
||||
self.conf_proc('1')
|
||||
|
||||
path = f'/{self.app_proc}'
|
||||
assert 'error' in self.conf_get(f'{path}/max')
|
||||
assert 'error' in self.conf_get(f'{path}/spare')
|
||||
assert 'error' in self.conf_get(f'{path}/idle_timeout')
|
||||
def test_python_processes_access():
|
||||
conf_proc('1')
|
||||
|
||||
def test_python_processes_invalid(self):
|
||||
assert 'error' in self.conf(
|
||||
{"spare": -1}, self.app_proc
|
||||
path = f'/{client.app_proc}'
|
||||
assert 'error' in client.conf_get(f'{path}/max')
|
||||
assert 'error' in client.conf_get(f'{path}/spare')
|
||||
assert 'error' in client.conf_get(f'{path}/idle_timeout')
|
||||
|
||||
|
||||
def test_python_processes_invalid():
|
||||
assert 'error' in client.conf(
|
||||
{"spare": -1}, client.app_proc
|
||||
), 'negative spare'
|
||||
assert 'error' in self.conf({"max": -1}, self.app_proc), 'negative max'
|
||||
assert 'error' in self.conf(
|
||||
{"idle_timeout": -1}, self.app_proc
|
||||
assert 'error' in client.conf({"max": -1}, client.app_proc), 'negative max'
|
||||
assert 'error' in client.conf(
|
||||
{"idle_timeout": -1}, client.app_proc
|
||||
), 'negative idle_timeout'
|
||||
assert 'error' in self.conf(
|
||||
{"spare": 2}, self.app_proc
|
||||
assert 'error' in client.conf(
|
||||
{"spare": 2}, client.app_proc
|
||||
), 'spare gt max default'
|
||||
assert 'error' in self.conf(
|
||||
{"spare": 2, "max": 1}, self.app_proc
|
||||
assert 'error' in client.conf(
|
||||
{"spare": 2, "max": 1}, client.app_proc
|
||||
), 'spare gt max'
|
||||
assert 'error' in self.conf(
|
||||
{"spare": 0, "max": 0}, self.app_proc
|
||||
assert 'error' in client.conf(
|
||||
{"spare": 0, "max": 0}, client.app_proc
|
||||
), 'max zero'
|
||||
|
||||
def stop_all(self):
|
||||
assert 'success' in self.conf({"listeners": {}, "applications": {}})
|
||||
|
||||
assert len(self.pids_for_process()) == 0, 'stop all'
|
||||
|
||||
def test_python_restart(self, temp_dir):
|
||||
def test_python_restart(temp_dir):
|
||||
shutil.copyfile(
|
||||
f'{option.test_dir}/python/restart/v1.py', f'{temp_dir}/wsgi.py'
|
||||
)
|
||||
|
||||
self.load(
|
||||
client.load(
|
||||
temp_dir,
|
||||
name=self.app_name,
|
||||
name=client.app_name,
|
||||
processes=1,
|
||||
environment={'PYTHONDONTWRITEBYTECODE': '1'},
|
||||
)
|
||||
|
||||
b = self.get()['body']
|
||||
b = client.get()['body']
|
||||
assert b == "v1", 'process started'
|
||||
|
||||
shutil.copyfile(
|
||||
f'{option.test_dir}/python/restart/v2.py', f'{temp_dir}/wsgi.py'
|
||||
)
|
||||
|
||||
b = self.get()['body']
|
||||
b = client.get()['body']
|
||||
assert b == "v1", 'still old process'
|
||||
|
||||
assert 'success' in self.conf_get(
|
||||
f'/control/applications/{self.app_name}/restart'
|
||||
assert 'success' in client.conf_get(
|
||||
f'/control/applications/{client.app_name}/restart'
|
||||
), 'restart processes'
|
||||
|
||||
b = self.get()['body']
|
||||
b = client.get()['body']
|
||||
assert b == "v2", 'new process started'
|
||||
|
||||
assert 'error' in self.conf_get(
|
||||
assert 'error' in client.conf_get(
|
||||
'/control/applications/blah/restart'
|
||||
), 'application incorrect'
|
||||
|
||||
assert 'error' in self.conf_delete(
|
||||
f'/control/applications/{self.app_name}/restart'
|
||||
assert 'error' in client.conf_delete(
|
||||
f'/control/applications/{client.app_name}/restart'
|
||||
), 'method incorrect'
|
||||
|
||||
def test_python_restart_multi(self):
|
||||
self.conf_proc('2')
|
||||
|
||||
pids = self.pids_for_process()
|
||||
def test_python_restart_multi():
|
||||
conf_proc('2')
|
||||
|
||||
pids = pids_for_process()
|
||||
assert len(pids) == 2, 'restart 2 started'
|
||||
|
||||
assert 'success' in self.conf_get(
|
||||
f'/control/applications/{self.app_name}/restart'
|
||||
assert 'success' in client.conf_get(
|
||||
f'/control/applications/{client.app_name}/restart'
|
||||
), 'restart processes'
|
||||
|
||||
new_pids = self.pids_for_process()
|
||||
new_pids = pids_for_process()
|
||||
assert len(new_pids) == 2, 'restart still 2'
|
||||
|
||||
assert len(new_pids.intersection(pids)) == 0, 'restart all new'
|
||||
|
||||
def test_python_restart_longstart(self):
|
||||
self.load(
|
||||
|
||||
def test_python_restart_longstart():
|
||||
client.load(
|
||||
'restart',
|
||||
name=self.app_name,
|
||||
name=client.app_name,
|
||||
module="longstart",
|
||||
processes={"spare": 1, "max": 2, "idle_timeout": 5},
|
||||
)
|
||||
|
||||
assert len(self.pids_for_process()) == 1, 'longstarts == 1'
|
||||
assert len(pids_for_process()) == 1, 'longstarts == 1'
|
||||
|
||||
self.get()
|
||||
client.get()
|
||||
|
||||
pids = self.pids_for_process()
|
||||
pids = pids_for_process()
|
||||
assert len(pids) == 2, 'longstarts == 2'
|
||||
|
||||
assert 'success' in self.conf_get(
|
||||
f'/control/applications/{self.app_name}/restart'
|
||||
assert 'success' in client.conf_get(
|
||||
f'/control/applications/{client.app_name}/restart'
|
||||
), 'restart processes'
|
||||
|
||||
# wait for longstarted app
|
||||
time.sleep(2)
|
||||
|
||||
new_pids = self.pids_for_process()
|
||||
new_pids = pids_for_process()
|
||||
assert len(new_pids) == 1, 'restart 1'
|
||||
|
||||
assert len(new_pids.intersection(pids)) == 0, 'restart all new'
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
from unit.applications.lang.python import TestApplicationPython
|
||||
from unit.applications.lang.python import ApplicationPython
|
||||
from unit.option import option
|
||||
|
||||
prerequisites = {'modules': {'python': 'all'}}
|
||||
|
||||
client = ApplicationPython()
|
||||
|
||||
class TestPythonTargets(TestApplicationPython):
|
||||
def test_python_targets(self):
|
||||
|
||||
def test_python_targets():
|
||||
python_dir = f'{option.test_dir}/python'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "routes"}},
|
||||
"routes": [
|
||||
|
@ -23,7 +24,7 @@ class TestPythonTargets(TestApplicationPython):
|
|||
],
|
||||
"applications": {
|
||||
"targets": {
|
||||
"type": self.get_application_type(),
|
||||
"type": client.get_application_type(),
|
||||
"working_directory": f'{python_dir}/targets/',
|
||||
"path": f'{python_dir}/targets/',
|
||||
"targets": {
|
||||
|
@ -41,18 +42,19 @@ class TestPythonTargets(TestApplicationPython):
|
|||
}
|
||||
)
|
||||
|
||||
resp = self.get(url='/1')
|
||||
resp = client.get(url='/1')
|
||||
assert resp['status'] == 200
|
||||
assert resp['body'] == '1'
|
||||
|
||||
resp = self.get(url='/2')
|
||||
resp = client.get(url='/2')
|
||||
assert resp['status'] == 200
|
||||
assert resp['body'] == '2'
|
||||
|
||||
def test_python_targets_prefix(self):
|
||||
|
||||
def test_python_targets_prefix():
|
||||
python_dir = f'{option.test_dir}/python'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "routes"}},
|
||||
"routes": [
|
||||
|
@ -89,7 +91,7 @@ class TestPythonTargets(TestApplicationPython):
|
|||
)
|
||||
|
||||
def check_prefix(url, body):
|
||||
resp = self.get(url=url)
|
||||
resp = client.get(url=url)
|
||||
assert resp['status'] == 200
|
||||
assert resp['body'] == body
|
||||
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import time
|
||||
|
||||
import pytest
|
||||
from unit.applications.proto import TestApplicationProto
|
||||
from unit.applications.proto import ApplicationProto
|
||||
|
||||
client = ApplicationProto()
|
||||
|
||||
|
||||
class TestReconfigure(TestApplicationProto):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_method_fixture(self):
|
||||
assert 'success' in self.conf(
|
||||
def setup_method_fixture():
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "routes"}},
|
||||
"routes": [{"action": {"return": 200}}],
|
||||
|
@ -15,20 +16,22 @@ class TestReconfigure(TestApplicationProto):
|
|||
}
|
||||
)
|
||||
|
||||
def clear_conf(self):
|
||||
assert 'success' in self.conf({"listeners": {}, "applications": {}})
|
||||
|
||||
def test_reconfigure(self):
|
||||
sock = self.http(
|
||||
def clear_conf():
|
||||
assert 'success' in client.conf({"listeners": {}, "applications": {}})
|
||||
|
||||
|
||||
def test_reconfigure():
|
||||
sock = client.http(
|
||||
b"""GET / HTTP/1.1
|
||||
""",
|
||||
raw=True,
|
||||
no_recv=True,
|
||||
)
|
||||
|
||||
self.clear_conf()
|
||||
clear_conf()
|
||||
|
||||
resp = self.http(
|
||||
resp = client.http(
|
||||
b"""Host: localhost
|
||||
Connection: close
|
||||
|
||||
|
@ -38,13 +41,14 @@ Connection: close
|
|||
)
|
||||
assert resp['status'] == 200, 'finish request'
|
||||
|
||||
def test_reconfigure_2(self):
|
||||
sock = self.http(b'', raw=True, no_recv=True)
|
||||
|
||||
def test_reconfigure_2():
|
||||
sock = client.http(b'', raw=True, no_recv=True)
|
||||
|
||||
# Waiting for connection completion.
|
||||
# Delay should be more than TCP_DEFER_ACCEPT.
|
||||
time.sleep(1.5)
|
||||
|
||||
self.clear_conf()
|
||||
clear_conf()
|
||||
|
||||
assert self.get(sock=sock)['status'] == 408, 'request timeout'
|
||||
assert client.get(sock=sock)['status'] == 408, 'request timeout'
|
||||
|
|
|
@ -3,20 +3,21 @@ import ssl
|
|||
import time
|
||||
|
||||
import pytest
|
||||
from unit.applications.tls import TestApplicationTLS
|
||||
from unit.applications.tls import ApplicationTLS
|
||||
|
||||
prerequisites = {'modules': {'openssl': 'any'}}
|
||||
|
||||
client = ApplicationTLS()
|
||||
|
||||
|
||||
class TestReconfigureTLS(TestApplicationTLS):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_method_fixture(self):
|
||||
def setup_method_fixture():
|
||||
if 'HAS_TLSv1_2' not in dir(ssl) or not ssl.HAS_TLSv1_2:
|
||||
pytest.skip('OpenSSL too old')
|
||||
|
||||
self.certificate()
|
||||
client.certificate()
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"*:7080": {
|
||||
|
@ -29,7 +30,8 @@ class TestReconfigureTLS(TestApplicationTLS):
|
|||
}
|
||||
), 'load application configuration'
|
||||
|
||||
def create_socket(self):
|
||||
|
||||
def create_socket():
|
||||
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
||||
ctx.check_hostname = False
|
||||
ctx.verify_mode = ssl.CERT_NONE
|
||||
|
@ -42,50 +44,54 @@ class TestReconfigureTLS(TestApplicationTLS):
|
|||
|
||||
return ssl_sock
|
||||
|
||||
def clear_conf(self):
|
||||
assert 'success' in self.conf({"listeners": {}, "applications": {}})
|
||||
|
||||
def clear_conf():
|
||||
assert 'success' in client.conf({"listeners": {}, "applications": {}})
|
||||
|
||||
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_reconfigure_tls_switch(self):
|
||||
assert 'success' in self.conf_delete('listeners/*:7080/tls')
|
||||
def test_reconfigure_tls_switch():
|
||||
assert 'success' in client.conf_delete('listeners/*:7080/tls')
|
||||
|
||||
(_, sock) = self.get(
|
||||
(_, sock) = client.get(
|
||||
headers={'Host': 'localhost', 'Connection': 'keep-alive'},
|
||||
start=True,
|
||||
read_timeout=1,
|
||||
)
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{"pass": "routes", "tls": {"certificate": "default"}},
|
||||
'listeners/*:7080',
|
||||
)
|
||||
|
||||
assert self.get(sock=sock)['status'] == 200, 'reconfigure'
|
||||
assert self.get_ssl()['status'] == 200, 'reconfigure tls'
|
||||
assert client.get(sock=sock)['status'] == 200, 'reconfigure'
|
||||
assert client.get_ssl()['status'] == 200, 'reconfigure tls'
|
||||
|
||||
def test_reconfigure_tls(self):
|
||||
ssl_sock = self.create_socket()
|
||||
|
||||
def test_reconfigure_tls():
|
||||
ssl_sock = create_socket()
|
||||
|
||||
ssl_sock.sendall("""GET / HTTP/1.1\r\n""".encode())
|
||||
|
||||
self.clear_conf()
|
||||
clear_conf()
|
||||
|
||||
ssl_sock.sendall(
|
||||
"""Host: localhost\r\nConnection: close\r\n\r\n""".encode()
|
||||
)
|
||||
|
||||
assert (
|
||||
self.recvall(ssl_sock).decode().startswith('HTTP/1.1 200 OK')
|
||||
client.recvall(ssl_sock).decode().startswith('HTTP/1.1 200 OK')
|
||||
), 'finish request'
|
||||
|
||||
def test_reconfigure_tls_2(self):
|
||||
ssl_sock = self.create_socket()
|
||||
|
||||
def test_reconfigure_tls_2():
|
||||
ssl_sock = create_socket()
|
||||
|
||||
# Waiting for connection completion.
|
||||
# Delay should be more than TCP_DEFER_ACCEPT.
|
||||
time.sleep(1.5)
|
||||
|
||||
self.clear_conf()
|
||||
clear_conf()
|
||||
|
||||
try:
|
||||
ssl_sock.do_handshake()
|
||||
|
@ -96,10 +102,11 @@ class TestReconfigureTLS(TestApplicationTLS):
|
|||
if not success:
|
||||
pytest.fail('Connection is not closed.')
|
||||
|
||||
def test_reconfigure_tls_3(self):
|
||||
ssl_sock = self.create_socket()
|
||||
|
||||
def test_reconfigure_tls_3():
|
||||
ssl_sock = create_socket()
|
||||
ssl_sock.do_handshake()
|
||||
|
||||
self.clear_conf()
|
||||
clear_conf()
|
||||
|
||||
assert self.get(sock=ssl_sock)['status'] == 408, 'request timeout'
|
||||
assert client.get(sock=ssl_sock)['status'] == 408, 'request timeout'
|
||||
|
|
|
@ -3,36 +3,40 @@ import subprocess
|
|||
import time
|
||||
|
||||
import pytest
|
||||
from unit.applications.lang.python import TestApplicationPython
|
||||
from unit.applications.lang.python import ApplicationPython
|
||||
|
||||
prerequisites = {'modules': {'python': 'any'}}
|
||||
|
||||
client = ApplicationPython()
|
||||
|
||||
class TestRespawn(TestApplicationPython):
|
||||
PATTERN_ROUTER = 'unit: router'
|
||||
PATTERN_CONTROLLER = 'unit: controller'
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_method_fixture(self, temp_dir):
|
||||
self.app_name = f'app-{temp_dir.split("/")[-1]}'
|
||||
def setup_method_fixture(temp_dir):
|
||||
client.app_name = f'app-{temp_dir.split("/")[-1]}'
|
||||
|
||||
self.load('empty', self.app_name)
|
||||
client.load('empty', client.app_name)
|
||||
|
||||
assert 'success' in self.conf(
|
||||
'1', f'applications/{self.app_name}/processes'
|
||||
assert 'success' in client.conf(
|
||||
'1', f'applications/{client.app_name}/processes'
|
||||
)
|
||||
|
||||
def pid_by_name(self, name, ppid):
|
||||
|
||||
def pid_by_name(name, ppid):
|
||||
output = subprocess.check_output(['ps', 'ax', '-O', 'ppid']).decode()
|
||||
m = re.search(fr'\s*(\d+)\s*{ppid}.*{name}', output)
|
||||
return None if m is None else m.group(1)
|
||||
|
||||
def kill_pids(self, *pids):
|
||||
|
||||
def kill_pids(*pids):
|
||||
subprocess.call(['kill', '-9', *pids])
|
||||
|
||||
def wait_for_process(self, process, unit_pid):
|
||||
|
||||
def wait_for_process(process, unit_pid):
|
||||
for _ in range(50):
|
||||
found = self.pid_by_name(process, unit_pid)
|
||||
found = pid_by_name(process, unit_pid)
|
||||
|
||||
if found is not None:
|
||||
break
|
||||
|
@ -41,12 +45,14 @@ class TestRespawn(TestApplicationPython):
|
|||
|
||||
return found
|
||||
|
||||
def find_proc(self, name, ppid, ps_output):
|
||||
|
||||
def find_proc(name, ppid, ps_output):
|
||||
return re.findall(fr'{ppid}.*{name}', ps_output)
|
||||
|
||||
def smoke_test(self, unit_pid):
|
||||
|
||||
def smoke_test(unit_pid):
|
||||
for _ in range(10):
|
||||
r = self.conf('1', f'applications/{self.app_name}/processes')
|
||||
r = client.conf('1', f'applications/{client.app_name}/processes')
|
||||
|
||||
if 'success' in r:
|
||||
break
|
||||
|
@ -54,48 +60,49 @@ class TestRespawn(TestApplicationPython):
|
|||
time.sleep(0.1)
|
||||
|
||||
assert 'success' in r
|
||||
assert self.get()['status'] == 200
|
||||
assert client.get()['status'] == 200
|
||||
|
||||
# Check if the only one router, controller,
|
||||
# and application processes running.
|
||||
|
||||
out = subprocess.check_output(['ps', 'ax', '-O', 'ppid']).decode()
|
||||
assert len(self.find_proc(self.PATTERN_ROUTER, unit_pid, out)) == 1
|
||||
assert len(self.find_proc(self.PATTERN_CONTROLLER, unit_pid, out)) == 1
|
||||
assert len(self.find_proc(self.app_name, unit_pid, out)) == 1
|
||||
assert len(find_proc(PATTERN_ROUTER, unit_pid, out)) == 1
|
||||
assert len(find_proc(PATTERN_CONTROLLER, unit_pid, out)) == 1
|
||||
assert len(find_proc(client.app_name, unit_pid, out)) == 1
|
||||
|
||||
def test_respawn_router(self, skip_alert, unit_pid, skip_fds_check):
|
||||
|
||||
def test_respawn_router(skip_alert, unit_pid, skip_fds_check):
|
||||
skip_fds_check(router=True)
|
||||
pid = self.pid_by_name(self.PATTERN_ROUTER, unit_pid)
|
||||
pid = pid_by_name(PATTERN_ROUTER, unit_pid)
|
||||
|
||||
self.kill_pids(pid)
|
||||
kill_pids(pid)
|
||||
skip_alert(fr'process {pid} exited on signal 9')
|
||||
|
||||
assert self.wait_for_process(self.PATTERN_ROUTER, unit_pid) is not None
|
||||
assert wait_for_process(PATTERN_ROUTER, unit_pid) is not None
|
||||
|
||||
self.smoke_test(unit_pid)
|
||||
smoke_test(unit_pid)
|
||||
|
||||
def test_respawn_controller(self, skip_alert, unit_pid, skip_fds_check):
|
||||
|
||||
def test_respawn_controller(skip_alert, unit_pid, skip_fds_check):
|
||||
skip_fds_check(controller=True)
|
||||
pid = self.pid_by_name(self.PATTERN_CONTROLLER, unit_pid)
|
||||
pid = pid_by_name(PATTERN_CONTROLLER, unit_pid)
|
||||
|
||||
self.kill_pids(pid)
|
||||
kill_pids(pid)
|
||||
skip_alert(fr'process {pid} exited on signal 9')
|
||||
|
||||
assert (
|
||||
self.wait_for_process(self.PATTERN_CONTROLLER, unit_pid) is not None
|
||||
)
|
||||
assert wait_for_process(PATTERN_CONTROLLER, unit_pid) is not None
|
||||
|
||||
assert self.get()['status'] == 200
|
||||
assert client.get()['status'] == 200
|
||||
|
||||
self.smoke_test(unit_pid)
|
||||
smoke_test(unit_pid)
|
||||
|
||||
def test_respawn_application(self, skip_alert, unit_pid):
|
||||
pid = self.pid_by_name(self.app_name, unit_pid)
|
||||
|
||||
self.kill_pids(pid)
|
||||
def test_respawn_application(skip_alert, unit_pid):
|
||||
pid = pid_by_name(client.app_name, unit_pid)
|
||||
|
||||
kill_pids(pid)
|
||||
skip_alert(fr'process {pid} exited on signal 9')
|
||||
|
||||
assert self.wait_for_process(self.app_name, unit_pid) is not None
|
||||
assert wait_for_process(client.app_name, unit_pid) is not None
|
||||
|
||||
self.smoke_test(unit_pid)
|
||||
smoke_test(unit_pid)
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import re
|
||||
|
||||
import pytest
|
||||
from unit.applications.proto import TestApplicationProto
|
||||
from unit.applications.proto import ApplicationProto
|
||||
|
||||
client = ApplicationProto()
|
||||
|
||||
|
||||
class TestReturn(TestApplicationProto):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_method_fixture(self):
|
||||
self._load_conf(
|
||||
def setup_method_fixture():
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "routes"}},
|
||||
"routes": [{"action": {"return": 200}}],
|
||||
|
@ -15,7 +16,8 @@ class TestReturn(TestApplicationProto):
|
|||
}
|
||||
)
|
||||
|
||||
def get_resps_sc(self, req=10):
|
||||
|
||||
def get_resps_sc(req=10):
|
||||
to_send = b"""GET / HTTP/1.1
|
||||
Host: localhost
|
||||
|
||||
|
@ -29,10 +31,11 @@ Connection: close
|
|||
|
||||
"""
|
||||
|
||||
return self.http(to_send, raw_resp=True, raw=True)
|
||||
return client.http(to_send, raw_resp=True, raw=True)
|
||||
|
||||
def test_return(self):
|
||||
resp = self.get()
|
||||
|
||||
def test_return():
|
||||
resp = client.get()
|
||||
assert resp['status'] == 200
|
||||
assert 'Server' in resp['headers']
|
||||
assert 'Date' in resp['headers']
|
||||
|
@ -40,16 +43,16 @@ Connection: close
|
|||
assert resp['headers']['Connection'] == 'close'
|
||||
assert resp['body'] == '', 'body'
|
||||
|
||||
resp = self.post(body='blah')
|
||||
resp = client.post(body='blah')
|
||||
assert resp['status'] == 200
|
||||
assert resp['body'] == '', 'body'
|
||||
|
||||
resp = self.get_resps_sc()
|
||||
resp = get_resps_sc()
|
||||
assert len(re.findall('200 OK', resp)) == 10
|
||||
assert len(re.findall('Connection:', resp)) == 1
|
||||
assert len(re.findall('Connection: close', resp)) == 1
|
||||
|
||||
resp = self.get(http_10=True)
|
||||
resp = client.get(http_10=True)
|
||||
assert resp['status'] == 200
|
||||
assert 'Server' in resp['headers']
|
||||
assert 'Date' in resp['headers']
|
||||
|
@ -57,36 +60,37 @@ Connection: close
|
|||
assert 'Connection' not in resp['headers']
|
||||
assert resp['body'] == '', 'body'
|
||||
|
||||
def test_return_update(self):
|
||||
assert 'success' in self.conf('0', 'routes/0/action/return')
|
||||
|
||||
resp = self.get()
|
||||
def test_return_update():
|
||||
assert 'success' in client.conf('0', 'routes/0/action/return')
|
||||
|
||||
resp = client.get()
|
||||
assert resp['status'] == 0
|
||||
assert resp['body'] == ''
|
||||
|
||||
assert 'success' in self.conf('404', 'routes/0/action/return')
|
||||
assert 'success' in client.conf('404', 'routes/0/action/return')
|
||||
|
||||
resp = self.get()
|
||||
resp = client.get()
|
||||
assert resp['status'] == 404
|
||||
assert resp['body'] != ''
|
||||
|
||||
assert 'success' in self.conf('598', 'routes/0/action/return')
|
||||
assert 'success' in client.conf('598', 'routes/0/action/return')
|
||||
|
||||
resp = self.get()
|
||||
resp = client.get()
|
||||
assert resp['status'] == 598
|
||||
assert resp['body'] != ''
|
||||
|
||||
assert 'success' in self.conf('999', 'routes/0/action/return')
|
||||
assert 'success' in client.conf('999', 'routes/0/action/return')
|
||||
|
||||
resp = self.get()
|
||||
resp = client.get()
|
||||
assert resp['status'] == 999
|
||||
assert resp['body'] == ''
|
||||
|
||||
def test_return_location(self):
|
||||
|
||||
def test_return_location():
|
||||
reserved = ":/?#[]@!&'()*+,;="
|
||||
unreserved = (
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789-._~"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" "0123456789-._~"
|
||||
)
|
||||
unsafe = " \"%<>\\^`{|}"
|
||||
unsafe_enc = "%20%22%25%3C%3E%5C%5E%60%7B%7C%7D"
|
||||
|
@ -95,11 +99,11 @@ Connection: close
|
|||
if expect is None:
|
||||
expect = location
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{"return": 301, "location": location}, 'routes/0/action'
|
||||
), 'configure location'
|
||||
|
||||
assert self.get()['headers']['Location'] == expect
|
||||
assert client.get()['headers']['Location'] == expect
|
||||
|
||||
# FAIL: can't specify empty header value.
|
||||
# check_location("")
|
||||
|
@ -140,62 +144,64 @@ Connection: close
|
|||
check_location("%20 ", "%2520%20")
|
||||
check_location("/%20?%20#%20 ", "/%2520?%2520#%2520%20")
|
||||
|
||||
def test_return_location_edit(self):
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def test_return_location_edit():
|
||||
assert 'success' in client.conf(
|
||||
{"return": 302, "location": "blah"}, 'routes/0/action'
|
||||
), 'configure init location'
|
||||
assert self.get()['headers']['Location'] == 'blah'
|
||||
assert client.get()['headers']['Location'] == 'blah'
|
||||
|
||||
assert 'success' in self.conf_delete(
|
||||
assert 'success' in client.conf_delete(
|
||||
'routes/0/action/location'
|
||||
), 'location delete'
|
||||
assert 'Location' not in self.get()['headers']
|
||||
assert 'Location' not in client.get()['headers']
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
'"blah"', 'routes/0/action/location'
|
||||
), 'location restore'
|
||||
assert self.get()['headers']['Location'] == 'blah'
|
||||
assert client.get()['headers']['Location'] == 'blah'
|
||||
|
||||
assert 'error' in self.conf_post(
|
||||
assert 'error' in client.conf_post(
|
||||
'"blah"', 'routes/0/action/location'
|
||||
), 'location method not allowed'
|
||||
assert self.get()['headers']['Location'] == 'blah'
|
||||
assert client.get()['headers']['Location'] == 'blah'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
'"https://${host}${uri}"', 'routes/0/action/location'
|
||||
), 'location with variables'
|
||||
assert self.get()['headers']['Location'] == 'https://localhost/'
|
||||
assert client.get()['headers']['Location'] == 'https://localhost/'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
'"/#$host"', 'routes/0/action/location'
|
||||
), 'location with encoding and a variable'
|
||||
assert self.get()['headers']['Location'] == '/#localhost'
|
||||
assert client.get()['headers']['Location'] == '/#localhost'
|
||||
|
||||
assert (
|
||||
self.get(headers={"Host": "#foo?bar", "Connection": "close"})[
|
||||
client.get(headers={"Host": "#foo?bar", "Connection": "close"})[
|
||||
'headers'
|
||||
]['Location']
|
||||
== "/#%23foo%3Fbar"
|
||||
), 'location with a variable with encoding'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
'""', 'routes/0/action/location'
|
||||
), 'location empty'
|
||||
assert self.get()['headers']['Location'] == ''
|
||||
assert client.get()['headers']['Location'] == ''
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
'"${host}"', 'routes/0/action/location'
|
||||
), 'location empty with variable'
|
||||
assert (
|
||||
self.get(headers={"Host": "", "Connection": "close"})['headers'][
|
||||
client.get(headers={"Host": "", "Connection": "close"})['headers'][
|
||||
'Location'
|
||||
]
|
||||
== ""
|
||||
), 'location with empty variable'
|
||||
|
||||
def test_return_invalid(self):
|
||||
|
||||
def test_return_invalid():
|
||||
def check_error(conf):
|
||||
assert 'error' in self.conf(conf, 'routes/0/action')
|
||||
assert 'error' in client.conf(conf, 'routes/0/action')
|
||||
|
||||
check_error({"return": "200"})
|
||||
check_error({"return": []})
|
||||
|
@ -206,7 +212,7 @@ Connection: close
|
|||
check_error({"return": 200, "location": "$hos"})
|
||||
check_error({"return": 200, "location": "$hostblah"})
|
||||
|
||||
assert 'error' in self.conf(
|
||||
assert 'error' in client.conf(
|
||||
'001', 'routes/0/action/return'
|
||||
), 'leading zero'
|
||||
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import os
|
||||
|
||||
import pytest
|
||||
from unit.applications.proto import TestApplicationProto
|
||||
from unit.applications.proto import ApplicationProto
|
||||
|
||||
client = ApplicationProto()
|
||||
|
||||
|
||||
class TestRewrite(TestApplicationProto):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_method_fixture(self):
|
||||
assert 'success' in self.conf(
|
||||
def setup_method_fixture():
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "routes"}},
|
||||
"routes": [
|
||||
|
@ -22,8 +23,9 @@ class TestRewrite(TestApplicationProto):
|
|||
},
|
||||
), 'set initial configuration'
|
||||
|
||||
def set_rewrite(self, rewrite, uri):
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def set_rewrite(rewrite, uri):
|
||||
assert 'success' in client.conf(
|
||||
[
|
||||
{
|
||||
"match": {"uri": "/"},
|
||||
|
@ -34,24 +36,27 @@ class TestRewrite(TestApplicationProto):
|
|||
'routes',
|
||||
)
|
||||
|
||||
def test_rewrite(self, findall, wait_for_record):
|
||||
assert self.get()['status'] == 200
|
||||
|
||||
def test_rewrite(findall, wait_for_record):
|
||||
assert client.get()['status'] == 200
|
||||
assert wait_for_record(rf'\[notice\].*"routes/1" selected') is not None
|
||||
assert len(findall(rf'\[notice\].*URI rewritten to "/new"')) == 1
|
||||
assert len(findall(rf'\[notice\].*URI rewritten')) == 1
|
||||
|
||||
self.set_rewrite("", "")
|
||||
assert self.get()['status'] == 200
|
||||
set_rewrite("", "")
|
||||
assert client.get()['status'] == 200
|
||||
|
||||
def test_rewrite_variable(self):
|
||||
self.set_rewrite("/$host", "/localhost")
|
||||
assert self.get()['status'] == 200
|
||||
|
||||
self.set_rewrite("${uri}a", "/a")
|
||||
assert self.get()['status'] == 200
|
||||
def test_rewrite_variable():
|
||||
set_rewrite("/$host", "/localhost")
|
||||
assert client.get()['status'] == 200
|
||||
|
||||
def test_rewrite_encoded(self):
|
||||
assert 'success' in self.conf(
|
||||
set_rewrite("${uri}a", "/a")
|
||||
assert client.get()['status'] == 200
|
||||
|
||||
|
||||
def test_rewrite_encoded():
|
||||
assert 'success' in client.conf(
|
||||
[
|
||||
{
|
||||
"match": {"uri": "/f"},
|
||||
|
@ -61,9 +66,9 @@ class TestRewrite(TestApplicationProto):
|
|||
],
|
||||
'routes',
|
||||
)
|
||||
assert self.get(url='/%66')['status'] == 200
|
||||
assert client.get(url='/%66')['status'] == 200
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
[
|
||||
{
|
||||
"match": {"uri": "/f"},
|
||||
|
@ -76,10 +81,11 @@ class TestRewrite(TestApplicationProto):
|
|||
],
|
||||
'routes',
|
||||
)
|
||||
assert self.get(url='/%66')['status'] == 200
|
||||
assert client.get(url='/%66')['status'] == 200
|
||||
|
||||
def test_rewrite_arguments(self):
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def test_rewrite_arguments():
|
||||
assert 'success' in client.conf(
|
||||
[
|
||||
{
|
||||
"match": {"uri": "/foo", "arguments": {"arg": "val"}},
|
||||
|
@ -92,17 +98,19 @@ class TestRewrite(TestApplicationProto):
|
|||
],
|
||||
'routes',
|
||||
)
|
||||
assert self.get(url='/foo?arg=val')['status'] == 200
|
||||
assert client.get(url='/foo?arg=val')['status'] == 200
|
||||
|
||||
def test_rewrite_njs(self, require):
|
||||
|
||||
def test_rewrite_njs(require):
|
||||
require({'modules': {'njs': 'any'}})
|
||||
|
||||
self.set_rewrite("`/${host}`", "/localhost")
|
||||
assert self.get()['status'] == 200
|
||||
set_rewrite("`/${host}`", "/localhost")
|
||||
assert client.get()['status'] == 200
|
||||
|
||||
def test_rewrite_location(self):
|
||||
|
||||
def test_rewrite_location():
|
||||
def check_location(rewrite, expect):
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "routes"}},
|
||||
"routes": [
|
||||
|
@ -116,12 +124,13 @@ class TestRewrite(TestApplicationProto):
|
|||
],
|
||||
}
|
||||
)
|
||||
assert self.get()['headers']['Location'] == expect
|
||||
assert client.get()['headers']['Location'] == expect
|
||||
|
||||
check_location('/new', '/new')
|
||||
check_location('${request_uri}new', '/new')
|
||||
|
||||
def test_rewrite_share(self, temp_dir):
|
||||
|
||||
def test_rewrite_share(temp_dir):
|
||||
os.makedirs(f'{temp_dir}/dir')
|
||||
os.makedirs(f'{temp_dir}/foo')
|
||||
|
||||
|
@ -130,7 +139,7 @@ class TestRewrite(TestApplicationProto):
|
|||
|
||||
# same action block
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "routes"}},
|
||||
"routes": [
|
||||
|
@ -144,14 +153,14 @@ class TestRewrite(TestApplicationProto):
|
|||
}
|
||||
)
|
||||
|
||||
resp = self.get()
|
||||
resp = client.get()
|
||||
assert resp['status'] == 301, 'redirect status'
|
||||
assert resp['headers']['Location'] == '/dir/', 'redirect Location'
|
||||
|
||||
# request_uri
|
||||
|
||||
index_path = f'{temp_dir}${{request_uri}}/index.html'
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "routes"}},
|
||||
"routes": [
|
||||
|
@ -167,11 +176,11 @@ class TestRewrite(TestApplicationProto):
|
|||
}
|
||||
)
|
||||
|
||||
assert self.get(url='/foo')['body'] == 'fooindex'
|
||||
assert client.get(url='/foo')['body'] == 'fooindex'
|
||||
|
||||
# different action block
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "routes"}},
|
||||
"routes": [
|
||||
|
@ -190,15 +199,16 @@ class TestRewrite(TestApplicationProto):
|
|||
],
|
||||
}
|
||||
)
|
||||
resp = self.get(url='/foo')
|
||||
resp = client.get(url='/foo')
|
||||
assert resp['status'] == 301, 'redirect status 2'
|
||||
assert resp['headers']['Location'] == '/foodir/', 'redirect Location 2'
|
||||
|
||||
def test_rewrite_invalid(self, skip_alert):
|
||||
|
||||
def test_rewrite_invalid(skip_alert):
|
||||
skip_alert(r'failed to apply new conf')
|
||||
|
||||
def check_rewrite(rewrite):
|
||||
assert 'error' in self.conf(
|
||||
assert 'error' in client.conf(
|
||||
[
|
||||
{
|
||||
"match": {"uri": "/"},
|
||||
|
|
1941
test/test_routing.py
1941
test/test_routing.py
File diff suppressed because it is too large
Load diff
|
@ -1,13 +1,14 @@
|
|||
from unit.applications.tls import TestApplicationTLS
|
||||
from unit.applications.tls import ApplicationTLS
|
||||
|
||||
prerequisites = {'modules': {'openssl': 'any'}}
|
||||
|
||||
client = ApplicationTLS()
|
||||
|
||||
class TestRoutingTLS(TestApplicationTLS):
|
||||
def test_routes_match_scheme_tls(self):
|
||||
self.certificate()
|
||||
|
||||
assert 'success' in self.conf(
|
||||
def test_routes_match_scheme_tls():
|
||||
client.certificate()
|
||||
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"*:7080": {"pass": "routes"},
|
||||
|
@ -24,5 +25,5 @@ class TestRoutingTLS(TestApplicationTLS):
|
|||
}
|
||||
), 'scheme configure'
|
||||
|
||||
assert self.get()['status'] == 200, 'http'
|
||||
assert self.get_ssl(port=7081)['status'] == 201, 'https'
|
||||
assert client.get()['status'] == 200, 'http'
|
||||
assert client.get_ssl(port=7081)['status'] == 201, 'https'
|
||||
|
|
|
@ -2,18 +2,19 @@ import re
|
|||
import subprocess
|
||||
|
||||
import pytest
|
||||
from unit.applications.lang.ruby import TestApplicationRuby
|
||||
from unit.applications.lang.ruby import ApplicationRuby
|
||||
|
||||
prerequisites = {'modules': {'ruby': 'all'}}
|
||||
|
||||
client = ApplicationRuby()
|
||||
|
||||
class TestRubyApplication(TestApplicationRuby):
|
||||
def test_ruby_application(self, date_to_sec_epoch, sec_epoch):
|
||||
self.load('variables')
|
||||
|
||||
def test_ruby_application(date_to_sec_epoch, sec_epoch):
|
||||
client.load('variables')
|
||||
|
||||
body = 'Test body string.'
|
||||
|
||||
resp = self.post(
|
||||
resp = client.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Content-Type': 'text/html',
|
||||
|
@ -56,170 +57,192 @@ class TestRubyApplication(TestApplicationRuby):
|
|||
}, 'headers'
|
||||
assert resp['body'] == body, 'body'
|
||||
|
||||
def test_ruby_application_query_string(self):
|
||||
self.load('query_string')
|
||||
|
||||
resp = self.get(url='/?var1=val1&var2=val2')
|
||||
def test_ruby_application_query_string():
|
||||
client.load('query_string')
|
||||
|
||||
resp = client.get(url='/?var1=val1&var2=val2')
|
||||
|
||||
assert (
|
||||
resp['headers']['Query-String'] == 'var1=val1&var2=val2'
|
||||
), 'Query-String header'
|
||||
|
||||
def test_ruby_application_query_string_empty(self):
|
||||
self.load('query_string')
|
||||
|
||||
resp = self.get(url='/?')
|
||||
def test_ruby_application_query_string_empty():
|
||||
client.load('query_string')
|
||||
|
||||
resp = client.get(url='/?')
|
||||
|
||||
assert resp['status'] == 200, 'query string empty status'
|
||||
assert resp['headers']['Query-String'] == '', 'query string empty'
|
||||
|
||||
def test_ruby_application_query_string_absent(self):
|
||||
self.load('query_string')
|
||||
|
||||
resp = self.get()
|
||||
def test_ruby_application_query_string_absent():
|
||||
client.load('query_string')
|
||||
|
||||
resp = client.get()
|
||||
|
||||
assert resp['status'] == 200, 'query string absent status'
|
||||
assert resp['headers']['Query-String'] == '', 'query string absent'
|
||||
|
||||
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_ruby_application_server_port(self):
|
||||
self.load('server_port')
|
||||
def test_ruby_application_server_port():
|
||||
client.load('server_port')
|
||||
|
||||
assert (
|
||||
self.get()['headers']['Server-Port'] == '7080'
|
||||
client.get()['headers']['Server-Port'] == '7080'
|
||||
), 'Server-Port header'
|
||||
|
||||
def test_ruby_application_status_int(self):
|
||||
self.load('status_int')
|
||||
|
||||
assert self.get()['status'] == 200, 'status int'
|
||||
def test_ruby_application_status_int():
|
||||
client.load('status_int')
|
||||
|
||||
def test_ruby_application_input_read_empty(self):
|
||||
self.load('input_read_empty')
|
||||
assert client.get()['status'] == 200, 'status int'
|
||||
|
||||
assert self.get()['body'] == '', 'read empty'
|
||||
|
||||
def test_ruby_application_input_read_parts(self):
|
||||
self.load('input_read_parts')
|
||||
def test_ruby_application_input_read_empty():
|
||||
client.load('input_read_empty')
|
||||
|
||||
assert client.get()['body'] == '', 'read empty'
|
||||
|
||||
|
||||
def test_ruby_application_input_read_parts():
|
||||
client.load('input_read_parts')
|
||||
|
||||
assert (
|
||||
self.post(body='0123456789')['body'] == '012345678'
|
||||
client.post(body='0123456789')['body'] == '012345678'
|
||||
), 'input read parts'
|
||||
|
||||
def test_ruby_application_input_read_buffer(self):
|
||||
self.load('input_read_buffer')
|
||||
|
||||
def test_ruby_application_input_read_buffer():
|
||||
client.load('input_read_buffer')
|
||||
|
||||
assert (
|
||||
self.post(body='0123456789')['body'] == '0123456789'
|
||||
client.post(body='0123456789')['body'] == '0123456789'
|
||||
), 'input read buffer'
|
||||
|
||||
def test_ruby_application_input_read_buffer_not_empty(self):
|
||||
self.load('input_read_buffer_not_empty')
|
||||
|
||||
def test_ruby_application_input_read_buffer_not_empty():
|
||||
client.load('input_read_buffer_not_empty')
|
||||
|
||||
assert (
|
||||
self.post(body='0123456789')['body'] == '0123456789'
|
||||
client.post(body='0123456789')['body'] == '0123456789'
|
||||
), 'input read buffer not empty'
|
||||
|
||||
def test_ruby_application_input_gets(self):
|
||||
self.load('input_gets')
|
||||
|
||||
def test_ruby_application_input_gets():
|
||||
client.load('input_gets')
|
||||
|
||||
body = '0123456789'
|
||||
|
||||
assert self.post(body=body)['body'] == body, 'input gets'
|
||||
assert client.post(body=body)['body'] == body, 'input gets'
|
||||
|
||||
def test_ruby_application_input_gets_2(self):
|
||||
self.load('input_gets')
|
||||
|
||||
def test_ruby_application_input_gets_2():
|
||||
client.load('input_gets')
|
||||
|
||||
assert (
|
||||
self.post(body='01234\n56789\n')['body'] == '01234\n'
|
||||
client.post(body='01234\n56789\n')['body'] == '01234\n'
|
||||
), 'input gets 2'
|
||||
|
||||
def test_ruby_application_input_gets_all(self):
|
||||
self.load('input_gets_all')
|
||||
|
||||
def test_ruby_application_input_gets_all():
|
||||
client.load('input_gets_all')
|
||||
|
||||
body = '\n01234\n56789\n\n'
|
||||
|
||||
assert self.post(body=body)['body'] == body, 'input gets all'
|
||||
assert client.post(body=body)['body'] == body, 'input gets all'
|
||||
|
||||
def test_ruby_application_input_each(self):
|
||||
self.load('input_each')
|
||||
|
||||
def test_ruby_application_input_each():
|
||||
client.load('input_each')
|
||||
|
||||
body = '\n01234\n56789\n\n'
|
||||
|
||||
assert self.post(body=body)['body'] == body, 'input each'
|
||||
assert client.post(body=body)['body'] == body, 'input each'
|
||||
|
||||
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_ruby_application_input_rewind(self):
|
||||
self.load('input_rewind')
|
||||
def test_ruby_application_input_rewind():
|
||||
client.load('input_rewind')
|
||||
|
||||
body = '0123456789'
|
||||
|
||||
assert self.post(body=body)['body'] == body, 'input rewind'
|
||||
assert client.post(body=body)['body'] == body, 'input rewind'
|
||||
|
||||
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_ruby_application_syntax_error(self, skip_alert):
|
||||
def test_ruby_application_syntax_error(skip_alert):
|
||||
skip_alert(
|
||||
r'Failed to parse rack script',
|
||||
r'syntax error',
|
||||
r'new_from_string',
|
||||
r'parse_file',
|
||||
)
|
||||
self.load('syntax_error')
|
||||
client.load('syntax_error')
|
||||
|
||||
assert self.get()['status'] == 500, 'syntax error'
|
||||
assert client.get()['status'] == 500, 'syntax error'
|
||||
|
||||
def test_ruby_application_errors_puts(self, wait_for_record):
|
||||
self.load('errors_puts')
|
||||
|
||||
assert self.get()['status'] == 200
|
||||
def test_ruby_application_errors_puts(wait_for_record):
|
||||
client.load('errors_puts')
|
||||
|
||||
assert client.get()['status'] == 200
|
||||
|
||||
assert (
|
||||
wait_for_record(r'\[error\].+Error in application') is not None
|
||||
), 'errors puts'
|
||||
|
||||
def test_ruby_application_errors_puts_int(self, wait_for_record):
|
||||
self.load('errors_puts_int')
|
||||
|
||||
assert self.get()['status'] == 200
|
||||
def test_ruby_application_errors_puts_int(wait_for_record):
|
||||
client.load('errors_puts_int')
|
||||
|
||||
assert client.get()['status'] == 200
|
||||
|
||||
assert (
|
||||
wait_for_record(r'\[error\].+1234567890') is not None
|
||||
), 'errors puts int'
|
||||
|
||||
def test_ruby_application_errors_write(self, wait_for_record):
|
||||
self.load('errors_write')
|
||||
|
||||
assert self.get()['status'] == 200
|
||||
def test_ruby_application_errors_write(wait_for_record):
|
||||
client.load('errors_write')
|
||||
|
||||
assert client.get()['status'] == 200
|
||||
assert (
|
||||
wait_for_record(r'\[error\].+Error in application') is not None
|
||||
), 'errors write'
|
||||
|
||||
def test_ruby_application_errors_write_to_s_custom(self):
|
||||
self.load('errors_write_to_s_custom')
|
||||
|
||||
assert self.get()['status'] == 200, 'errors write to_s custom'
|
||||
def test_ruby_application_errors_write_to_s_custom():
|
||||
client.load('errors_write_to_s_custom')
|
||||
|
||||
def test_ruby_application_errors_write_int(self, wait_for_record):
|
||||
self.load('errors_write_int')
|
||||
assert client.get()['status'] == 200, 'errors write to_s custom'
|
||||
|
||||
assert self.get()['status'] == 200
|
||||
|
||||
def test_ruby_application_errors_write_int(wait_for_record):
|
||||
client.load('errors_write_int')
|
||||
|
||||
assert client.get()['status'] == 200
|
||||
assert (
|
||||
wait_for_record(r'\[error\].+1234567890') is not None
|
||||
), 'errors write int'
|
||||
|
||||
def test_ruby_application_at_exit(self, wait_for_record):
|
||||
self.load('at_exit')
|
||||
|
||||
assert self.get()['status'] == 200
|
||||
def test_ruby_application_at_exit(wait_for_record):
|
||||
client.load('at_exit')
|
||||
|
||||
assert 'success' in self.conf({"listeners": {}, "applications": {}})
|
||||
assert client.get()['status'] == 200
|
||||
|
||||
assert 'success' in client.conf({"listeners": {}, "applications": {}})
|
||||
|
||||
assert (
|
||||
wait_for_record(r'\[error\].+At exit called\.') is not None
|
||||
), 'at exit'
|
||||
|
||||
def test_ruby_application_encoding(self):
|
||||
self.load('encoding')
|
||||
|
||||
def test_ruby_application_encoding():
|
||||
client.load('encoding')
|
||||
|
||||
try:
|
||||
locales = (
|
||||
|
@ -236,11 +259,7 @@ class TestRubyApplication(TestApplicationRuby):
|
|||
|
||||
def get_locale(pattern):
|
||||
return next(
|
||||
(
|
||||
l
|
||||
for l in locales
|
||||
if re.match(pattern, l.upper()) is not None
|
||||
),
|
||||
(l for l in locales if re.match(pattern, l.upper()) is not None),
|
||||
None,
|
||||
)
|
||||
|
||||
|
@ -248,18 +267,16 @@ class TestRubyApplication(TestApplicationRuby):
|
|||
iso88591 = get_locale(r'.*ISO[-_]?8859[-_]?1')
|
||||
|
||||
def check_locale(enc):
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{"LC_CTYPE": enc, "LC_ALL": ""},
|
||||
'/config/applications/encoding/environment',
|
||||
)
|
||||
|
||||
resp = self.get()
|
||||
resp = client.get()
|
||||
assert resp['status'] == 200, 'status'
|
||||
|
||||
enc_default = re.sub(r'[-_]', '', resp['headers']['X-Enc']).upper()
|
||||
assert (
|
||||
enc_default == re.sub(r'[-_]', '', enc.split('.')[-1]).upper()
|
||||
)
|
||||
assert enc_default == re.sub(r'[-_]', '', enc.split('.')[-1]).upper()
|
||||
|
||||
if utf8:
|
||||
check_locale(utf8)
|
||||
|
@ -270,10 +287,11 @@ class TestRubyApplication(TestApplicationRuby):
|
|||
if not utf8 and not iso88591:
|
||||
pytest.skip('no available locales')
|
||||
|
||||
def test_ruby_application_header_custom(self):
|
||||
self.load('header_custom')
|
||||
|
||||
resp = self.post(body="\ntc=one,two\ntc=three,four,\n\n")
|
||||
def test_ruby_application_header_custom():
|
||||
client.load('header_custom')
|
||||
|
||||
resp = client.post(body="\ntc=one,two\ntc=three,four,\n\n")
|
||||
|
||||
assert resp['headers']['Custom-Header'] == [
|
||||
'',
|
||||
|
@ -283,64 +301,73 @@ class TestRubyApplication(TestApplicationRuby):
|
|||
'',
|
||||
], 'header custom'
|
||||
|
||||
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_ruby_application_header_custom_non_printable(self):
|
||||
self.load('header_custom')
|
||||
def test_ruby_application_header_custom_non_printable():
|
||||
client.load('header_custom')
|
||||
|
||||
assert (
|
||||
self.post(body='\b')['status'] == 500
|
||||
client.post(body='\b')['status'] == 500
|
||||
), 'header custom non printable'
|
||||
|
||||
def test_ruby_application_header_status(self):
|
||||
self.load('header_status')
|
||||
|
||||
assert self.get()['status'] == 200, 'header status'
|
||||
def test_ruby_application_header_status():
|
||||
client.load('header_status')
|
||||
|
||||
assert client.get()['status'] == 200, 'header status'
|
||||
|
||||
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_ruby_application_header_rack(self):
|
||||
self.load('header_rack')
|
||||
def test_ruby_application_header_rack():
|
||||
client.load('header_rack')
|
||||
|
||||
assert self.get()['status'] == 500, 'header rack'
|
||||
assert client.get()['status'] == 500, 'header rack'
|
||||
|
||||
def test_ruby_application_body_empty(self):
|
||||
self.load('body_empty')
|
||||
|
||||
assert self.get()['body'] == '', 'body empty'
|
||||
def test_ruby_application_body_empty():
|
||||
client.load('body_empty')
|
||||
|
||||
def test_ruby_application_body_array(self):
|
||||
self.load('body_array')
|
||||
assert client.get()['body'] == '', 'body empty'
|
||||
|
||||
assert self.get()['body'] == '0123456789', 'body array'
|
||||
|
||||
def test_ruby_application_body_large(self):
|
||||
self.load('mirror')
|
||||
def test_ruby_application_body_array():
|
||||
client.load('body_array')
|
||||
|
||||
assert client.get()['body'] == '0123456789', 'body array'
|
||||
|
||||
|
||||
def test_ruby_application_body_large():
|
||||
client.load('mirror')
|
||||
|
||||
body = '0123456789' * 1000
|
||||
|
||||
assert self.post(body=body)['body'] == body, 'body large'
|
||||
assert client.post(body=body)['body'] == body, 'body large'
|
||||
|
||||
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_ruby_application_body_each_error(self, wait_for_record):
|
||||
self.load('body_each_error')
|
||||
def test_ruby_application_body_each_error(wait_for_record):
|
||||
client.load('body_each_error')
|
||||
|
||||
assert self.get()['status'] == 500, 'body each error status'
|
||||
assert client.get()['status'] == 500, 'body each error status'
|
||||
|
||||
assert (
|
||||
wait_for_record(r'\[error\].+Failed to run ruby script') is not None
|
||||
), 'body each error'
|
||||
|
||||
def test_ruby_application_body_file(self):
|
||||
self.load('body_file')
|
||||
|
||||
assert self.get()['body'] == 'body\n', 'body file'
|
||||
def test_ruby_application_body_file():
|
||||
client.load('body_file')
|
||||
|
||||
def test_ruby_keepalive_body(self):
|
||||
self.load('mirror')
|
||||
assert client.get()['body'] == 'body\n', 'body file'
|
||||
|
||||
assert self.get()['status'] == 200, 'init'
|
||||
|
||||
def test_ruby_keepalive_body():
|
||||
client.load('mirror')
|
||||
|
||||
assert client.get()['status'] == 200, 'init'
|
||||
|
||||
body = '0123456789' * 500
|
||||
(resp, sock) = self.post(
|
||||
(resp, sock) = client.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Connection': 'keep-alive',
|
||||
|
@ -353,14 +380,15 @@ class TestRubyApplication(TestApplicationRuby):
|
|||
assert resp['body'] == body, 'keep-alive 1'
|
||||
|
||||
body = '0123456789'
|
||||
resp = self.post(sock=sock, body=body)
|
||||
resp = client.post(sock=sock, body=body)
|
||||
|
||||
assert resp['body'] == body, 'keep-alive 2'
|
||||
|
||||
def test_ruby_application_constants(self):
|
||||
self.load('constants')
|
||||
|
||||
resp = self.get()
|
||||
def test_ruby_application_constants():
|
||||
client.load('constants')
|
||||
|
||||
resp = client.get()
|
||||
|
||||
assert resp['status'] == 200, 'status'
|
||||
|
||||
|
@ -375,17 +403,18 @@ class TestRubyApplication(TestApplicationRuby):
|
|||
assert len(headers['X-Revision']) > 0, 'RUBY_REVISION'
|
||||
assert len(headers['X-Version']) > 0, 'RUBY_VERSION'
|
||||
|
||||
def test_ruby_application_threads(self):
|
||||
self.load('threads')
|
||||
|
||||
assert 'success' in self.conf(
|
||||
def test_ruby_application_threads():
|
||||
client.load('threads')
|
||||
|
||||
assert 'success' in client.conf(
|
||||
'4', 'applications/threads/threads'
|
||||
), 'configure 4 threads'
|
||||
|
||||
socks = []
|
||||
|
||||
for _ in range(4):
|
||||
sock = self.get(
|
||||
sock = client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Delay': '2',
|
||||
|
@ -399,11 +428,11 @@ class TestRubyApplication(TestApplicationRuby):
|
|||
threads = set()
|
||||
|
||||
for sock in socks:
|
||||
resp = self.recvall(sock).decode('utf-8')
|
||||
resp = client.recvall(sock).decode('utf-8')
|
||||
|
||||
self.log_in(resp)
|
||||
client.log_in(resp)
|
||||
|
||||
resp = self._resp_to_dict(resp)
|
||||
resp = client._resp_to_dict(resp)
|
||||
|
||||
assert resp['status'] == 200, 'status'
|
||||
|
||||
|
|
|
@ -1,94 +1,99 @@
|
|||
from unit.applications.lang.ruby import TestApplicationRuby
|
||||
from unit.applications.lang.ruby import ApplicationRuby
|
||||
from unit.option import option
|
||||
from unit.utils import waitforglob
|
||||
|
||||
prerequisites = {'modules': {'ruby': 'all'}}
|
||||
|
||||
client = ApplicationRuby()
|
||||
|
||||
class TestRubyHooks(TestApplicationRuby):
|
||||
def _wait_cookie(self, pattern, count):
|
||||
return waitforglob(
|
||||
f'{option.temp_dir}/ruby/hooks/cookie_{pattern}', count
|
||||
)
|
||||
|
||||
def test_ruby_hooks_eval(self):
|
||||
def wait_cookie(pattern, count):
|
||||
return waitforglob(f'{option.temp_dir}/ruby/hooks/cookie_{pattern}', count)
|
||||
|
||||
|
||||
def test_ruby_hooks_eval():
|
||||
processes = 2
|
||||
|
||||
self.load('hooks', processes=processes, hooks='eval.rb')
|
||||
client.load('hooks', processes=processes, hooks='eval.rb')
|
||||
|
||||
hooked = self._wait_cookie('eval.*', processes)
|
||||
hooked = wait_cookie('eval.*', processes)
|
||||
|
||||
assert hooked, 'hooks evaluated'
|
||||
|
||||
def test_ruby_hooks_on_worker_boot(self):
|
||||
|
||||
def test_ruby_hooks_on_worker_boot():
|
||||
processes = 2
|
||||
|
||||
self.load('hooks', processes=processes, hooks='on_worker_boot.rb')
|
||||
client.load('hooks', processes=processes, hooks='on_worker_boot.rb')
|
||||
|
||||
hooked = self._wait_cookie('worker_boot.*', processes)
|
||||
hooked = wait_cookie('worker_boot.*', processes)
|
||||
|
||||
assert hooked, 'on_worker_boot called'
|
||||
|
||||
def test_ruby_hooks_on_worker_shutdown(self):
|
||||
|
||||
def test_ruby_hooks_on_worker_shutdown():
|
||||
processes = 2
|
||||
|
||||
self.load('hooks', processes=processes, hooks='on_worker_shutdown.rb')
|
||||
client.load('hooks', processes=processes, hooks='on_worker_shutdown.rb')
|
||||
|
||||
assert self.get()['status'] == 200, 'app response'
|
||||
assert client.get()['status'] == 200, 'app response'
|
||||
|
||||
self.load('empty')
|
||||
client.load('empty')
|
||||
|
||||
hooked = self._wait_cookie('worker_shutdown.*', processes)
|
||||
hooked = wait_cookie('worker_shutdown.*', processes)
|
||||
|
||||
assert hooked, 'on_worker_shutdown called'
|
||||
|
||||
def test_ruby_hooks_on_thread_boot(self):
|
||||
|
||||
def test_ruby_hooks_on_thread_boot():
|
||||
processes = 1
|
||||
threads = 2
|
||||
|
||||
self.load(
|
||||
client.load(
|
||||
'hooks',
|
||||
processes=processes,
|
||||
threads=threads,
|
||||
hooks='on_thread_boot.rb',
|
||||
)
|
||||
|
||||
hooked = self._wait_cookie('thread_boot.*', processes * threads)
|
||||
hooked = wait_cookie('thread_boot.*', processes * threads)
|
||||
|
||||
assert hooked, 'on_thread_boot called'
|
||||
|
||||
def test_ruby_hooks_on_thread_shutdown(self):
|
||||
|
||||
def test_ruby_hooks_on_thread_shutdown():
|
||||
processes = 1
|
||||
threads = 2
|
||||
|
||||
self.load(
|
||||
client.load(
|
||||
'hooks',
|
||||
processes=processes,
|
||||
threads=threads,
|
||||
hooks='on_thread_shutdown.rb',
|
||||
)
|
||||
|
||||
assert self.get()['status'] == 200, 'app response'
|
||||
assert client.get()['status'] == 200, 'app response'
|
||||
|
||||
self.load('empty')
|
||||
client.load('empty')
|
||||
|
||||
hooked = self._wait_cookie('thread_shutdown.*', processes * threads)
|
||||
hooked = wait_cookie('thread_shutdown.*', processes * threads)
|
||||
|
||||
assert hooked, 'on_thread_shutdown called'
|
||||
|
||||
def test_ruby_hooks_multiple(self):
|
||||
|
||||
def test_ruby_hooks_multiple():
|
||||
processes = 1
|
||||
threads = 1
|
||||
|
||||
self.load(
|
||||
client.load(
|
||||
'hooks',
|
||||
processes=processes,
|
||||
threads=threads,
|
||||
hooks='multiple.rb',
|
||||
)
|
||||
|
||||
hooked = self._wait_cookie('worker_boot.*', processes)
|
||||
hooked = wait_cookie('worker_boot.*', processes)
|
||||
assert hooked, 'on_worker_boot called'
|
||||
|
||||
hooked = self._wait_cookie('thread_boot.*', threads)
|
||||
hooked = wait_cookie('thread_boot.*', threads)
|
||||
assert hooked, 'on_thread_boot called'
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
from unit.applications.lang.ruby import TestApplicationRuby
|
||||
from unit.applications.lang.ruby import ApplicationRuby
|
||||
|
||||
prerequisites = {'modules': {'ruby': 'any'}, 'features': {'isolation': True}}
|
||||
|
||||
client = ApplicationRuby()
|
||||
|
||||
class TestRubyIsolation(TestApplicationRuby):
|
||||
def test_ruby_isolation_rootfs(self, is_su, require, temp_dir):
|
||||
|
||||
def test_ruby_isolation_rootfs(is_su, require, temp_dir):
|
||||
isolation = {'rootfs': temp_dir}
|
||||
|
||||
if not is_su:
|
||||
|
@ -27,16 +28,16 @@ class TestRubyIsolation(TestApplicationRuby):
|
|||
'pid': True,
|
||||
}
|
||||
|
||||
self.load('status_int', isolation=isolation)
|
||||
client.load('status_int', isolation=isolation)
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
'"/ruby/status_int/config.ru"',
|
||||
'applications/status_int/script',
|
||||
)
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
'"/ruby/status_int"',
|
||||
'applications/status_int/working_directory',
|
||||
)
|
||||
|
||||
assert self.get()['status'] == 200, 'status int'
|
||||
assert client.get()['status'] == 200, 'status int'
|
||||
|
|
|
@ -4,13 +4,14 @@ import subprocess
|
|||
import time
|
||||
|
||||
import pytest
|
||||
from unit.applications.lang.python import TestApplicationPython
|
||||
from unit.applications.lang.python import ApplicationPython
|
||||
|
||||
prerequisites = {'modules': {'python': 'any'}}
|
||||
|
||||
client = ApplicationPython()
|
||||
|
||||
class TestSettings(TestApplicationPython):
|
||||
def sysctl(self):
|
||||
|
||||
def sysctl():
|
||||
try:
|
||||
out = subprocess.check_output(
|
||||
['sysctl', '-a'], stderr=subprocess.STDOUT
|
||||
|
@ -20,18 +21,19 @@ class TestSettings(TestApplicationPython):
|
|||
|
||||
return out
|
||||
|
||||
def test_settings_large_header_buffer_size(self):
|
||||
self.load('empty')
|
||||
|
||||
def test_settings_large_header_buffer_size():
|
||||
client.load('empty')
|
||||
|
||||
def set_buffer_size(size):
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{'http': {'large_header_buffer_size': size}},
|
||||
'settings',
|
||||
)
|
||||
|
||||
def header_value(size, expect=200):
|
||||
headers = {'Host': 'a' * (size - 1), 'Connection': 'close'}
|
||||
assert self.get(headers=headers)['status'] == expect
|
||||
assert client.get(headers=headers)['status'] == expect
|
||||
|
||||
set_buffer_size(4096)
|
||||
header_value(4096)
|
||||
|
@ -41,11 +43,12 @@ class TestSettings(TestApplicationPython):
|
|||
header_value(16384)
|
||||
header_value(16385, 431)
|
||||
|
||||
def test_settings_large_header_buffers(self):
|
||||
self.load('empty')
|
||||
|
||||
def test_settings_large_header_buffers():
|
||||
client.load('empty')
|
||||
|
||||
def set_buffers(buffers):
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{'http': {'large_header_buffers': buffers}},
|
||||
'settings',
|
||||
)
|
||||
|
@ -56,7 +59,7 @@ class TestSettings(TestApplicationPython):
|
|||
for i in range(headers_num):
|
||||
headers[f'Custom-header-{i}'] = 'a' * 8000
|
||||
|
||||
assert self.get(headers=headers)['status'] == expect
|
||||
assert client.get(headers=headers)['status'] == expect
|
||||
|
||||
set_buffers(1)
|
||||
big_headers(1)
|
||||
|
@ -70,36 +73,39 @@ class TestSettings(TestApplicationPython):
|
|||
big_headers(8)
|
||||
big_headers(9, 431)
|
||||
|
||||
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_settings_large_header_buffer_invalid(self):
|
||||
def test_settings_large_header_buffer_invalid():
|
||||
def check_error(conf):
|
||||
assert 'error' in self.conf({'http': conf}, 'settings')
|
||||
assert 'error' in client.conf({'http': conf}, 'settings')
|
||||
|
||||
check_error({'large_header_buffer_size': -1})
|
||||
check_error({'large_header_buffer_size': 0})
|
||||
check_error({'large_header_buffers': -1})
|
||||
check_error({'large_header_buffers': 0})
|
||||
|
||||
def test_settings_server_version(self):
|
||||
self.load('empty')
|
||||
|
||||
assert self.get()['headers']['Server'].startswith('Unit/')
|
||||
def test_settings_server_version():
|
||||
client.load('empty')
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert client.get()['headers']['Server'].startswith('Unit/')
|
||||
|
||||
assert 'success' in client.conf(
|
||||
{"http": {"server_version": False}}, 'settings'
|
||||
), 'remove version'
|
||||
assert self.get()['headers']['Server'] == 'Unit'
|
||||
assert client.get()['headers']['Server'] == 'Unit'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{"http": {"server_version": True}}, 'settings'
|
||||
), 'add version'
|
||||
assert self.get()['headers']['Server'].startswith('Unit/')
|
||||
assert client.get()['headers']['Server'].startswith('Unit/')
|
||||
|
||||
def test_settings_header_read_timeout(self):
|
||||
self.load('empty')
|
||||
|
||||
def test_settings_header_read_timeout():
|
||||
client.load('empty')
|
||||
|
||||
def req():
|
||||
(_, sock) = self.http(
|
||||
(_, sock) = client.http(
|
||||
b"""GET / HTTP/1.1
|
||||
""",
|
||||
start=True,
|
||||
|
@ -109,7 +115,7 @@ class TestSettings(TestApplicationPython):
|
|||
|
||||
time.sleep(3)
|
||||
|
||||
return self.http(
|
||||
return client.http(
|
||||
b"""Host: localhost
|
||||
Connection: close
|
||||
|
||||
|
@ -118,24 +124,25 @@ Connection: close
|
|||
raw=True,
|
||||
)
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{'http': {'header_read_timeout': 2}}, 'settings'
|
||||
)
|
||||
assert req()['status'] == 408, 'status header read timeout'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{'http': {'header_read_timeout': 7}}, 'settings'
|
||||
)
|
||||
assert req()['status'] == 200, 'status header read timeout 2'
|
||||
|
||||
def test_settings_header_read_timeout_update(self):
|
||||
self.load('empty')
|
||||
|
||||
assert 'success' in self.conf(
|
||||
def test_settings_header_read_timeout_update():
|
||||
client.load('empty')
|
||||
|
||||
assert 'success' in client.conf(
|
||||
{'http': {'header_read_timeout': 4}}, 'settings'
|
||||
)
|
||||
|
||||
sock = self.http(
|
||||
sock = client.http(
|
||||
b"""GET / HTTP/1.1
|
||||
""",
|
||||
raw=True,
|
||||
|
@ -144,7 +151,7 @@ Connection: close
|
|||
|
||||
time.sleep(2)
|
||||
|
||||
sock = self.http(
|
||||
sock = client.http(
|
||||
b"""Host: localhost
|
||||
""",
|
||||
sock=sock,
|
||||
|
@ -154,7 +161,7 @@ Connection: close
|
|||
|
||||
time.sleep(2)
|
||||
|
||||
(resp, sock) = self.http(
|
||||
(resp, sock) = client.http(
|
||||
b"""X-Blah: blah
|
||||
""",
|
||||
start=True,
|
||||
|
@ -169,7 +176,7 @@ Connection: close
|
|||
else:
|
||||
time.sleep(2)
|
||||
|
||||
resp = self.http(
|
||||
resp = client.http(
|
||||
b"""Connection: close
|
||||
|
||||
""",
|
||||
|
@ -179,11 +186,12 @@ Connection: close
|
|||
|
||||
assert resp['status'] == 408, 'status header read timeout update'
|
||||
|
||||
def test_settings_body_read_timeout(self):
|
||||
self.load('empty')
|
||||
|
||||
def test_settings_body_read_timeout():
|
||||
client.load('empty')
|
||||
|
||||
def req():
|
||||
(_, sock) = self.http(
|
||||
(_, sock) = client.http(
|
||||
b"""POST / HTTP/1.1
|
||||
Host: localhost
|
||||
Content-Length: 10
|
||||
|
@ -198,26 +206,27 @@ Connection: close
|
|||
|
||||
time.sleep(3)
|
||||
|
||||
return self.http(b"""0123456789""", sock=sock, raw=True)
|
||||
return client.http(b"""0123456789""", sock=sock, raw=True)
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{'http': {'body_read_timeout': 2}}, 'settings'
|
||||
)
|
||||
assert req()['status'] == 408, 'status body read timeout'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{'http': {'body_read_timeout': 7}}, 'settings'
|
||||
)
|
||||
assert req()['status'] == 200, 'status body read timeout 2'
|
||||
|
||||
def test_settings_body_read_timeout_update(self):
|
||||
self.load('empty')
|
||||
|
||||
assert 'success' in self.conf(
|
||||
def test_settings_body_read_timeout_update():
|
||||
client.load('empty')
|
||||
|
||||
assert 'success' in client.conf(
|
||||
{'http': {'body_read_timeout': 4}}, 'settings'
|
||||
)
|
||||
|
||||
(resp, sock) = self.http(
|
||||
(resp, sock) = client.http(
|
||||
b"""POST / HTTP/1.1
|
||||
Host: localhost
|
||||
Content-Length: 10
|
||||
|
@ -231,24 +240,25 @@ Connection: close
|
|||
|
||||
time.sleep(2)
|
||||
|
||||
(resp, sock) = self.http(
|
||||
(resp, sock) = client.http(
|
||||
b"""012""", start=True, sock=sock, read_timeout=1, raw=True
|
||||
)
|
||||
|
||||
time.sleep(2)
|
||||
|
||||
(resp, sock) = self.http(
|
||||
(resp, sock) = client.http(
|
||||
b"""345""", start=True, sock=sock, read_timeout=1, raw=True
|
||||
)
|
||||
|
||||
time.sleep(2)
|
||||
|
||||
resp = self.http(b"""6789""", sock=sock, raw=True)
|
||||
resp = client.http(b"""6789""", sock=sock, raw=True)
|
||||
|
||||
assert resp['status'] == 200, 'status body read timeout update'
|
||||
|
||||
def test_settings_send_timeout(self, temp_dir):
|
||||
self.load('body_generate')
|
||||
|
||||
def test_settings_send_timeout(temp_dir):
|
||||
client.load('body_generate')
|
||||
|
||||
def req(addr, data_len):
|
||||
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
|
@ -267,43 +277,42 @@ Connection: close
|
|||
|
||||
time.sleep(3)
|
||||
|
||||
data += self.recvall(sock).decode()
|
||||
data += client.recvall(sock).decode()
|
||||
|
||||
sock.close()
|
||||
|
||||
return data
|
||||
|
||||
sysctl_out = self.sysctl()
|
||||
values = re.findall(
|
||||
r'net.core.[rw]mem_(?:max|default).*?(\d+)', sysctl_out
|
||||
)
|
||||
sysctl_out = sysctl()
|
||||
values = re.findall(r'net.core.[rw]mem_(?:max|default).*?(\d+)', sysctl_out)
|
||||
values = [int(v) for v in values]
|
||||
|
||||
data_len = 1048576 if len(values) == 0 else 10 * max(values)
|
||||
|
||||
addr = f'{temp_dir}/sock'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{f'unix:{addr}': {'application': 'body_generate'}}, 'listeners'
|
||||
)
|
||||
|
||||
assert 'success' in self.conf({'http': {'send_timeout': 1}}, 'settings')
|
||||
assert 'success' in client.conf({'http': {'send_timeout': 1}}, 'settings')
|
||||
|
||||
data = req(addr, data_len)
|
||||
assert re.search(r'200 OK', data), 'send timeout status'
|
||||
assert len(data) < data_len, 'send timeout data '
|
||||
|
||||
self.conf({'http': {'send_timeout': 7}}, 'settings')
|
||||
client.conf({'http': {'send_timeout': 7}}, 'settings')
|
||||
|
||||
data = req(addr, data_len)
|
||||
assert re.search(r'200 OK', data), 'send timeout status 2'
|
||||
assert len(data) > data_len, 'send timeout data 2'
|
||||
|
||||
def test_settings_idle_timeout(self):
|
||||
self.load('empty')
|
||||
|
||||
def test_settings_idle_timeout():
|
||||
client.load('empty')
|
||||
|
||||
def req():
|
||||
(_, sock) = self.get(
|
||||
(_, sock) = client.get(
|
||||
headers={'Host': 'localhost', 'Connection': 'keep-alive'},
|
||||
start=True,
|
||||
read_timeout=1,
|
||||
|
@ -311,81 +320,84 @@ Connection: close
|
|||
|
||||
time.sleep(3)
|
||||
|
||||
return self.get(sock=sock)
|
||||
return client.get(sock=sock)
|
||||
|
||||
assert self.get()['status'] == 200, 'init'
|
||||
assert client.get()['status'] == 200, 'init'
|
||||
|
||||
assert 'success' in self.conf({'http': {'idle_timeout': 2}}, 'settings')
|
||||
assert 'success' in client.conf({'http': {'idle_timeout': 2}}, 'settings')
|
||||
assert req()['status'] == 408, 'status idle timeout'
|
||||
|
||||
assert 'success' in self.conf({'http': {'idle_timeout': 7}}, 'settings')
|
||||
assert 'success' in client.conf({'http': {'idle_timeout': 7}}, 'settings')
|
||||
assert req()['status'] == 200, 'status idle timeout 2'
|
||||
|
||||
def test_settings_idle_timeout_2(self):
|
||||
self.load('empty')
|
||||
|
||||
def test_settings_idle_timeout_2():
|
||||
client.load('empty')
|
||||
|
||||
def req():
|
||||
sock = self.http(b'', raw=True, no_recv=True)
|
||||
sock = client.http(b'', raw=True, no_recv=True)
|
||||
|
||||
time.sleep(3)
|
||||
|
||||
return self.get(sock=sock)
|
||||
return client.get(sock=sock)
|
||||
|
||||
assert self.get()['status'] == 200, 'init'
|
||||
assert client.get()['status'] == 200, 'init'
|
||||
|
||||
assert 'success' in self.conf({'http': {'idle_timeout': 1}}, 'settings')
|
||||
assert 'success' in client.conf({'http': {'idle_timeout': 1}}, 'settings')
|
||||
assert req()['status'] == 408, 'status idle timeout'
|
||||
|
||||
assert 'success' in self.conf({'http': {'idle_timeout': 7}}, 'settings')
|
||||
assert 'success' in client.conf({'http': {'idle_timeout': 7}}, 'settings')
|
||||
assert req()['status'] == 200, 'status idle timeout 2'
|
||||
|
||||
def test_settings_max_body_size(self):
|
||||
self.load('empty')
|
||||
|
||||
assert 'success' in self.conf(
|
||||
{'http': {'max_body_size': 5}}, 'settings'
|
||||
)
|
||||
def test_settings_max_body_size():
|
||||
client.load('empty')
|
||||
|
||||
assert self.post(body='01234')['status'] == 200, 'status size'
|
||||
assert self.post(body='012345')['status'] == 413, 'status size max'
|
||||
assert 'success' in client.conf({'http': {'max_body_size': 5}}, 'settings')
|
||||
|
||||
def test_settings_max_body_size_large(self):
|
||||
self.load('mirror')
|
||||
assert client.post(body='01234')['status'] == 200, 'status size'
|
||||
assert client.post(body='012345')['status'] == 413, 'status size max'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def test_settings_max_body_size_large():
|
||||
client.load('mirror')
|
||||
|
||||
assert 'success' in client.conf(
|
||||
{'http': {'max_body_size': 32 * 1024 * 1024}}, 'settings'
|
||||
)
|
||||
|
||||
body = '0123456789abcdef' * 4 * 64 * 1024
|
||||
resp = self.post(body=body, read_buffer_size=1024 * 1024)
|
||||
resp = client.post(body=body, read_buffer_size=1024 * 1024)
|
||||
assert resp['status'] == 200, 'status size 4'
|
||||
assert resp['body'] == body, 'status body 4'
|
||||
|
||||
body = '0123456789abcdef' * 8 * 64 * 1024
|
||||
resp = self.post(body=body, read_buffer_size=1024 * 1024)
|
||||
resp = client.post(body=body, read_buffer_size=1024 * 1024)
|
||||
assert resp['status'] == 200, 'status size 8'
|
||||
assert resp['body'] == body, 'status body 8'
|
||||
|
||||
body = '0123456789abcdef' * 16 * 64 * 1024
|
||||
resp = self.post(body=body, read_buffer_size=1024 * 1024)
|
||||
resp = client.post(body=body, read_buffer_size=1024 * 1024)
|
||||
assert resp['status'] == 200, 'status size 16'
|
||||
assert resp['body'] == body, 'status body 16'
|
||||
|
||||
body = '0123456789abcdef' * 32 * 64 * 1024
|
||||
resp = self.post(body=body, read_buffer_size=1024 * 1024)
|
||||
resp = client.post(body=body, read_buffer_size=1024 * 1024)
|
||||
assert resp['status'] == 200, 'status size 32'
|
||||
assert resp['body'] == body, 'status body 32'
|
||||
|
||||
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_settings_negative_value(self):
|
||||
assert 'error' in self.conf(
|
||||
def test_settings_negative_value():
|
||||
assert 'error' in client.conf(
|
||||
{'http': {'max_body_size': -1}}, 'settings'
|
||||
), 'settings negative value'
|
||||
|
||||
def test_settings_body_buffer_size(self):
|
||||
self.load('mirror')
|
||||
|
||||
assert 'success' in self.conf(
|
||||
def test_settings_body_buffer_size():
|
||||
client.load('mirror')
|
||||
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
'http': {
|
||||
'max_body_size': 64 * 1024 * 1024,
|
||||
|
@ -396,30 +408,31 @@ Connection: close
|
|||
)
|
||||
|
||||
body = '0123456789abcdef'
|
||||
resp = self.post(body=body)
|
||||
resp = client.post(body=body)
|
||||
assert bool(resp), 'response from application'
|
||||
assert resp['status'] == 200, 'status'
|
||||
assert resp['body'] == body, 'body'
|
||||
|
||||
body = '0123456789abcdef' * 1024 * 1024
|
||||
resp = self.post(body=body, read_buffer_size=1024 * 1024)
|
||||
resp = client.post(body=body, read_buffer_size=1024 * 1024)
|
||||
assert bool(resp), 'response from application 2'
|
||||
assert resp['status'] == 200, 'status 2'
|
||||
assert resp['body'] == body, 'body 2'
|
||||
|
||||
body = '0123456789abcdef' * 2 * 1024 * 1024
|
||||
resp = self.post(body=body, read_buffer_size=1024 * 1024)
|
||||
resp = client.post(body=body, read_buffer_size=1024 * 1024)
|
||||
assert bool(resp), 'response from application 3'
|
||||
assert resp['status'] == 200, 'status 3'
|
||||
assert resp['body'] == body, 'body 3'
|
||||
|
||||
body = '0123456789abcdef' * 3 * 1024 * 1024
|
||||
resp = self.post(body=body, read_buffer_size=1024 * 1024)
|
||||
resp = client.post(body=body, read_buffer_size=1024 * 1024)
|
||||
assert bool(resp), 'response from application 4'
|
||||
assert resp['status'] == 200, 'status 4'
|
||||
assert resp['body'] == body, 'body 4'
|
||||
|
||||
def test_settings_log_route(self, findall, search_in_file, wait_for_record):
|
||||
|
||||
def test_settings_log_route(findall, search_in_file, wait_for_record):
|
||||
def count_fallbacks():
|
||||
return len(findall(r'"fallback" taken'))
|
||||
|
||||
|
@ -439,13 +452,13 @@ Connection: close
|
|||
return rf'\[info\].*"{route}" discarded'
|
||||
|
||||
def wait_for_request_log(status, uri, route):
|
||||
assert self.get(url=uri)['status'] == status
|
||||
assert client.get(url=uri)['status'] == status
|
||||
assert wait_for_record(template_req_line(uri)) is not None
|
||||
assert wait_for_record(template_selected(route)) is not None
|
||||
|
||||
# routes array
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "routes"}},
|
||||
"routes": [
|
||||
|
@ -472,7 +485,7 @@ Connection: close
|
|||
|
||||
# routes object
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "routes/main"}},
|
||||
"routes": {
|
||||
|
@ -501,7 +514,7 @@ Connection: close
|
|||
|
||||
# routes sequence
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "routes/first"}},
|
||||
"routes": {
|
||||
|
@ -526,7 +539,7 @@ Connection: close
|
|||
|
||||
# fallback
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "routes/fall"}},
|
||||
"routes": {
|
||||
|
@ -553,15 +566,15 @@ Connection: close
|
|||
assert count_fallbacks() == 1
|
||||
check_record(template_selected('routes/fall/0'))
|
||||
|
||||
assert self.head()['status'] == 200
|
||||
assert client.head()['status'] == 200
|
||||
assert count_fallbacks() == 2
|
||||
|
||||
# disable log
|
||||
|
||||
assert 'success' in self.conf({"log_route": False}, 'settings/http')
|
||||
assert 'success' in client.conf({"log_route": False}, 'settings/http')
|
||||
|
||||
url = '/disable_logging'
|
||||
assert self.get(url=url)['status'] == 200
|
||||
assert client.get(url=url)['status'] == 200
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
|
|
|
@ -2,13 +2,15 @@ import os
|
|||
import socket
|
||||
|
||||
import pytest
|
||||
from unit.applications.proto import TestApplicationProto
|
||||
from unit.applications.proto import ApplicationProto
|
||||
from unit.utils import waitforfiles
|
||||
|
||||
|
||||
class TestStatic(TestApplicationProto):
|
||||
client = ApplicationProto()
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_method_fixture(self, temp_dir):
|
||||
def setup_method_fixture(temp_dir):
|
||||
os.makedirs(f'{temp_dir}/assets/dir')
|
||||
assets_dir = f'{temp_dir}/assets'
|
||||
|
||||
|
@ -22,57 +24,58 @@ class TestStatic(TestApplicationProto):
|
|||
log.write('[debug]')
|
||||
file.write('blah')
|
||||
|
||||
self._load_conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "routes"}},
|
||||
"routes": [{"action": {"share": f'{assets_dir}$uri'}}],
|
||||
"settings": {
|
||||
"http": {
|
||||
"static": {
|
||||
"mime_types": {"text/plain": [".log", "README"]}
|
||||
}
|
||||
"static": {"mime_types": {"text/plain": [".log", "README"]}}
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
def test_static_index(self, temp_dir):
|
||||
|
||||
def test_static_index(temp_dir):
|
||||
def set_index(index):
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{"share": f'{temp_dir}/assets$uri', "index": index},
|
||||
'routes/0/action',
|
||||
), 'configure index'
|
||||
|
||||
set_index('README')
|
||||
assert self.get()['body'] == 'readme', 'index'
|
||||
assert client.get()['body'] == 'readme', 'index'
|
||||
|
||||
self.conf_delete('routes/0/action/index')
|
||||
assert self.get()['body'] == '0123456789', 'delete index'
|
||||
client.conf_delete('routes/0/action/index')
|
||||
assert client.get()['body'] == '0123456789', 'delete index'
|
||||
|
||||
set_index('')
|
||||
assert self.get()['status'] == 404, 'index empty'
|
||||
assert client.get()['status'] == 404, 'index empty'
|
||||
|
||||
def test_static_index_default(self):
|
||||
assert self.get(url='/index.html')['body'] == '0123456789', 'index'
|
||||
assert self.get(url='/')['body'] == '0123456789', 'index 2'
|
||||
assert self.get(url='//')['body'] == '0123456789', 'index 3'
|
||||
assert self.get(url='/.')['body'] == '0123456789', 'index 4'
|
||||
assert self.get(url='/./')['body'] == '0123456789', 'index 5'
|
||||
assert self.get(url='/?blah')['body'] == '0123456789', 'index vars'
|
||||
assert self.get(url='/#blah')['body'] == '0123456789', 'index anchor'
|
||||
assert self.get(url='/dir/')['status'] == 404, 'index not found'
|
||||
|
||||
resp = self.get(url='/index.html/')
|
||||
def test_static_index_default():
|
||||
assert client.get(url='/index.html')['body'] == '0123456789', 'index'
|
||||
assert client.get(url='/')['body'] == '0123456789', 'index 2'
|
||||
assert client.get(url='//')['body'] == '0123456789', 'index 3'
|
||||
assert client.get(url='/.')['body'] == '0123456789', 'index 4'
|
||||
assert client.get(url='/./')['body'] == '0123456789', 'index 5'
|
||||
assert client.get(url='/?blah')['body'] == '0123456789', 'index vars'
|
||||
assert client.get(url='/#blah')['body'] == '0123456789', 'index anchor'
|
||||
assert client.get(url='/dir/')['status'] == 404, 'index not found'
|
||||
|
||||
resp = client.get(url='/index.html/')
|
||||
assert resp['status'] == 404, 'index not found 2 status'
|
||||
assert (
|
||||
resp['headers']['Content-Type'] == 'text/html'
|
||||
), 'index not found 2 Content-Type'
|
||||
|
||||
def test_static_index_invalid(self, skip_alert, temp_dir):
|
||||
|
||||
def test_static_index_invalid(skip_alert, temp_dir):
|
||||
skip_alert(r'failed to apply new conf')
|
||||
|
||||
def check_index(index):
|
||||
assert 'error' in self.conf(
|
||||
assert 'error' in client.conf(
|
||||
{"share": f'{temp_dir}/assets$uri', "index": index},
|
||||
'routes/0/action',
|
||||
)
|
||||
|
@ -80,36 +83,40 @@ class TestStatic(TestApplicationProto):
|
|||
check_index({})
|
||||
check_index(['index.html', '$blah'])
|
||||
|
||||
def test_static_large_file(self, temp_dir):
|
||||
|
||||
def test_static_large_file(temp_dir):
|
||||
file_size = 32 * 1024 * 1024
|
||||
with open(f'{temp_dir}/assets/large', 'wb') as f:
|
||||
f.seek(file_size - 1)
|
||||
f.write(b'\0')
|
||||
|
||||
assert (
|
||||
len(self.get(url='/large', read_buffer_size=1024 * 1024)['body'])
|
||||
len(client.get(url='/large', read_buffer_size=1024 * 1024)['body'])
|
||||
== file_size
|
||||
), 'large file'
|
||||
|
||||
def test_static_etag(self, temp_dir):
|
||||
etag = self.get(url='/')['headers']['ETag']
|
||||
etag_2 = self.get(url='/README')['headers']['ETag']
|
||||
|
||||
def test_static_etag(temp_dir):
|
||||
etag = client.get(url='/')['headers']['ETag']
|
||||
etag_2 = client.get(url='/README')['headers']['ETag']
|
||||
|
||||
assert etag != etag_2, 'different ETag'
|
||||
assert etag == self.get(url='/')['headers']['ETag'], 'same ETag'
|
||||
assert etag == client.get(url='/')['headers']['ETag'], 'same ETag'
|
||||
|
||||
with open(f'{temp_dir}/assets/index.html', 'w') as f:
|
||||
f.write('blah')
|
||||
|
||||
assert etag != self.get(url='/')['headers']['ETag'], 'new ETag'
|
||||
assert etag != client.get(url='/')['headers']['ETag'], 'new ETag'
|
||||
|
||||
def test_static_redirect(self):
|
||||
resp = self.get(url='/dir')
|
||||
|
||||
def test_static_redirect():
|
||||
resp = client.get(url='/dir')
|
||||
assert resp['status'] == 301, 'redirect status'
|
||||
assert resp['headers']['Location'] == '/dir/', 'redirect Location'
|
||||
assert 'Content-Type' not in resp['headers'], 'redirect Content-Type'
|
||||
|
||||
def test_static_space_in_name(self, temp_dir):
|
||||
|
||||
def test_static_space_in_name(temp_dir):
|
||||
assets_dir = f'{temp_dir}/assets'
|
||||
|
||||
os.rename(
|
||||
|
@ -117,30 +124,28 @@ class TestStatic(TestApplicationProto):
|
|||
f'{assets_dir}/dir/fi le',
|
||||
)
|
||||
assert waitforfiles(f'{assets_dir}/dir/fi le')
|
||||
assert self.get(url='/dir/fi le')['body'] == 'blah', 'file name'
|
||||
assert client.get(url='/dir/fi le')['body'] == 'blah', 'file name'
|
||||
|
||||
os.rename(f'{assets_dir}/dir', f'{assets_dir}/di r')
|
||||
assert waitforfiles(f'{assets_dir}/di r/fi le')
|
||||
assert self.get(url='/di r/fi le')['body'] == 'blah', 'dir name'
|
||||
assert client.get(url='/di r/fi le')['body'] == 'blah', 'dir name'
|
||||
|
||||
os.rename(f'{assets_dir}/di r', f'{assets_dir}/ di r ')
|
||||
assert waitforfiles(f'{assets_dir}/ di r /fi le')
|
||||
assert (
|
||||
self.get(url='/ di r /fi le')['body'] == 'blah'
|
||||
client.get(url='/ di r /fi le')['body'] == 'blah'
|
||||
), 'dir name enclosing'
|
||||
|
||||
assert (
|
||||
self.get(url='/%20di%20r%20/fi le')['body'] == 'blah'
|
||||
client.get(url='/%20di%20r%20/fi le')['body'] == 'blah'
|
||||
), 'dir encoded'
|
||||
assert client.get(url='/ di r %2Ffi le')['body'] == 'blah', 'slash encoded'
|
||||
assert client.get(url='/ di r /fi%20le')['body'] == 'blah', 'file encoded'
|
||||
assert (
|
||||
self.get(url='/ di r %2Ffi le')['body'] == 'blah'
|
||||
), 'slash encoded'
|
||||
assert self.get(url='/ di r /fi%20le')['body'] == 'blah', 'file encoded'
|
||||
assert (
|
||||
self.get(url='/%20di%20r%20%2Ffi%20le')['body'] == 'blah'
|
||||
client.get(url='/%20di%20r%20%2Ffi%20le')['body'] == 'blah'
|
||||
), 'encoded'
|
||||
assert (
|
||||
self.get(url='/%20%64%69%20%72%20%2F%66%69%20%6C%65')['body']
|
||||
client.get(url='/%20%64%69%20%72%20%2F%66%69%20%6C%65')['body']
|
||||
== 'blah'
|
||||
), 'encoded 2'
|
||||
|
||||
|
@ -150,7 +155,7 @@ class TestStatic(TestApplicationProto):
|
|||
)
|
||||
assert waitforfiles(f'{assets_dir}/ di r / fi le ')
|
||||
assert (
|
||||
self.get(url='/%20di%20r%20/%20fi%20le%20')['body'] == 'blah'
|
||||
client.get(url='/%20di%20r%20/%20fi%20le%20')['body'] == 'blah'
|
||||
), 'file name enclosing'
|
||||
|
||||
try:
|
||||
|
@ -169,9 +174,7 @@ class TestStatic(TestApplicationProto):
|
|||
f'{assets_dir}/ di r /фа йл',
|
||||
)
|
||||
assert waitforfiles(f'{assets_dir}/ di r /фа йл')
|
||||
assert (
|
||||
self.get(url='/ di r /фа йл')['body'] == 'blah'
|
||||
), 'file name 2'
|
||||
assert client.get(url='/ di r /фа йл')['body'] == 'blah'
|
||||
|
||||
os.rename(
|
||||
f'{assets_dir}/ di r ',
|
||||
|
@ -179,43 +182,48 @@ class TestStatic(TestApplicationProto):
|
|||
)
|
||||
assert waitforfiles(f'{assets_dir}/ди ректория/фа йл')
|
||||
assert (
|
||||
self.get(url='/ди ректория/фа йл')['body'] == 'blah'
|
||||
client.get(url='/ди ректория/фа йл')['body'] == 'blah'
|
||||
), 'dir name 2'
|
||||
|
||||
def test_static_unix_socket(self, temp_dir):
|
||||
|
||||
def test_static_unix_socket(temp_dir):
|
||||
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
sock.bind(f'{temp_dir}/assets/unix_socket')
|
||||
|
||||
assert self.get(url='/unix_socket')['status'] == 404, 'socket'
|
||||
assert client.get(url='/unix_socket')['status'] == 404, 'socket'
|
||||
|
||||
sock.close()
|
||||
|
||||
def test_static_unix_fifo(self, temp_dir):
|
||||
|
||||
def test_static_unix_fifo(temp_dir):
|
||||
os.mkfifo(f'{temp_dir}/assets/fifo')
|
||||
|
||||
assert self.get(url='/fifo')['status'] == 404, 'fifo'
|
||||
assert client.get(url='/fifo')['status'] == 404, 'fifo'
|
||||
|
||||
def test_static_method(self):
|
||||
resp = self.head()
|
||||
|
||||
def test_static_method():
|
||||
resp = client.head()
|
||||
assert resp['status'] == 200, 'HEAD status'
|
||||
assert resp['body'] == '', 'HEAD empty body'
|
||||
|
||||
assert self.delete()['status'] == 405, 'DELETE'
|
||||
assert self.post()['status'] == 405, 'POST'
|
||||
assert self.put()['status'] == 405, 'PUT'
|
||||
assert client.delete()['status'] == 405, 'DELETE'
|
||||
assert client.post()['status'] == 405, 'POST'
|
||||
assert client.put()['status'] == 405, 'PUT'
|
||||
|
||||
def test_static_path(self):
|
||||
assert self.get(url='/dir/../dir/file')['status'] == 200, 'relative'
|
||||
|
||||
assert self.get(url='./')['status'] == 400, 'path invalid'
|
||||
assert self.get(url='../')['status'] == 400, 'path invalid 2'
|
||||
assert self.get(url='/..')['status'] == 400, 'path invalid 3'
|
||||
assert self.get(url='../assets/')['status'] == 400, 'path invalid 4'
|
||||
assert self.get(url='/../assets/')['status'] == 400, 'path invalid 5'
|
||||
def test_static_path():
|
||||
assert client.get(url='/dir/../dir/file')['status'] == 200, 'relative'
|
||||
|
||||
def test_static_two_clients(self):
|
||||
sock = self.get(no_recv=True)
|
||||
sock2 = self.get(no_recv=True)
|
||||
assert client.get(url='./')['status'] == 400, 'path invalid'
|
||||
assert client.get(url='../')['status'] == 400, 'path invalid 2'
|
||||
assert client.get(url='/..')['status'] == 400, 'path invalid 3'
|
||||
assert client.get(url='../assets/')['status'] == 400, 'path invalid 4'
|
||||
assert client.get(url='/../assets/')['status'] == 400, 'path invalid 5'
|
||||
|
||||
|
||||
def test_static_two_clients():
|
||||
sock = client.get(no_recv=True)
|
||||
sock2 = client.get(no_recv=True)
|
||||
|
||||
assert sock.recv(1) == b'H', 'client 1'
|
||||
assert sock2.recv(1) == b'H', 'client 2'
|
||||
|
@ -225,8 +233,9 @@ class TestStatic(TestApplicationProto):
|
|||
sock.close()
|
||||
sock2.close()
|
||||
|
||||
def test_static_mime_types(self):
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def test_static_mime_types():
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"text/x-code/x-blah/x-blah": "readme",
|
||||
"text/plain": [".html", ".log", "file"],
|
||||
|
@ -235,31 +244,32 @@ class TestStatic(TestApplicationProto):
|
|||
), 'configure mime_types'
|
||||
|
||||
assert (
|
||||
self.get(url='/README')['headers']['Content-Type']
|
||||
client.get(url='/README')['headers']['Content-Type']
|
||||
== 'text/x-code/x-blah/x-blah'
|
||||
), 'mime_types string case insensitive'
|
||||
assert (
|
||||
self.get(url='/index.html')['headers']['Content-Type']
|
||||
== 'text/plain'
|
||||
client.get(url='/index.html')['headers']['Content-Type'] == 'text/plain'
|
||||
), 'mime_types html'
|
||||
assert (
|
||||
self.get(url='/')['headers']['Content-Type'] == 'text/plain'
|
||||
client.get(url='/')['headers']['Content-Type'] == 'text/plain'
|
||||
), 'mime_types index default'
|
||||
assert (
|
||||
self.get(url='/dir/file')['headers']['Content-Type'] == 'text/plain'
|
||||
client.get(url='/dir/file')['headers']['Content-Type'] == 'text/plain'
|
||||
), 'mime_types file in dir'
|
||||
|
||||
def test_static_mime_types_partial_match(self):
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def test_static_mime_types_partial_match():
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"text/x-blah": ["ile", "fil", "f", "e", ".file"],
|
||||
},
|
||||
'settings/http/static/mime_types',
|
||||
), 'configure mime_types'
|
||||
assert 'Content-Type' not in self.get(url='/dir/file'), 'partial match'
|
||||
assert 'Content-Type' not in client.get(url='/dir/file'), 'partial match'
|
||||
|
||||
def test_static_mime_types_reconfigure(self):
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def test_static_mime_types_reconfigure():
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"text/x-code": "readme",
|
||||
"text/plain": [".html", ".log", "file"],
|
||||
|
@ -267,64 +277,67 @@ class TestStatic(TestApplicationProto):
|
|||
'settings/http/static/mime_types',
|
||||
), 'configure mime_types'
|
||||
|
||||
assert self.conf_get('settings/http/static/mime_types') == {
|
||||
assert client.conf_get('settings/http/static/mime_types') == {
|
||||
'text/x-code': 'readme',
|
||||
'text/plain': ['.html', '.log', 'file'],
|
||||
}, 'mime_types get'
|
||||
assert (
|
||||
self.conf_get('settings/http/static/mime_types/text%2Fx-code')
|
||||
client.conf_get('settings/http/static/mime_types/text%2Fx-code')
|
||||
== 'readme'
|
||||
), 'mime_types get string'
|
||||
assert self.conf_get(
|
||||
'settings/http/static/mime_types/text%2Fplain'
|
||||
) == ['.html', '.log', 'file'], 'mime_types get array'
|
||||
assert client.conf_get('settings/http/static/mime_types/text%2Fplain') == [
|
||||
'.html',
|
||||
'.log',
|
||||
'file',
|
||||
], 'mime_types get array'
|
||||
assert (
|
||||
self.conf_get('settings/http/static/mime_types/text%2Fplain/1')
|
||||
client.conf_get('settings/http/static/mime_types/text%2Fplain/1')
|
||||
== '.log'
|
||||
), 'mime_types get array element'
|
||||
|
||||
assert 'success' in self.conf_delete(
|
||||
assert 'success' in client.conf_delete(
|
||||
'settings/http/static/mime_types/text%2Fplain/2'
|
||||
), 'mime_types remove array element'
|
||||
assert (
|
||||
'Content-Type' not in self.get(url='/dir/file')['headers']
|
||||
'Content-Type' not in client.get(url='/dir/file')['headers']
|
||||
), 'mime_types removed'
|
||||
|
||||
assert 'success' in self.conf_post(
|
||||
assert 'success' in client.conf_post(
|
||||
'"file"', 'settings/http/static/mime_types/text%2Fplain'
|
||||
), 'mime_types add array element'
|
||||
assert (
|
||||
self.get(url='/dir/file')['headers']['Content-Type'] == 'text/plain'
|
||||
client.get(url='/dir/file')['headers']['Content-Type'] == 'text/plain'
|
||||
), 'mime_types reverted'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
'"file"', 'settings/http/static/mime_types/text%2Fplain'
|
||||
), 'configure mime_types update'
|
||||
assert (
|
||||
self.get(url='/dir/file')['headers']['Content-Type'] == 'text/plain'
|
||||
client.get(url='/dir/file')['headers']['Content-Type'] == 'text/plain'
|
||||
), 'mime_types updated'
|
||||
assert (
|
||||
'Content-Type' not in self.get(url='/log.log')['headers']
|
||||
'Content-Type' not in client.get(url='/log.log')['headers']
|
||||
), 'mime_types updated 2'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
'".log"', 'settings/http/static/mime_types/text%2Fblahblahblah'
|
||||
), 'configure mime_types create'
|
||||
assert (
|
||||
self.get(url='/log.log')['headers']['Content-Type']
|
||||
client.get(url='/log.log')['headers']['Content-Type']
|
||||
== 'text/blahblahblah'
|
||||
), 'mime_types create'
|
||||
|
||||
def test_static_mime_types_correct(self):
|
||||
assert 'error' in self.conf(
|
||||
|
||||
def test_static_mime_types_correct():
|
||||
assert 'error' in client.conf(
|
||||
{"text/x-code": "readme", "text/plain": "readme"},
|
||||
'settings/http/static/mime_types',
|
||||
), 'mime_types same extensions'
|
||||
assert 'error' in self.conf(
|
||||
assert 'error' in client.conf(
|
||||
{"text/x-code": [".h", ".c"], "text/plain": ".c"},
|
||||
'settings/http/static/mime_types',
|
||||
), 'mime_types same extensions array'
|
||||
assert 'error' in self.conf(
|
||||
assert 'error' in client.conf(
|
||||
{
|
||||
"text/x-code": [".h", ".c", "readme"],
|
||||
"text/plain": "README",
|
||||
|
@ -332,9 +345,10 @@ class TestStatic(TestApplicationProto):
|
|||
'settings/http/static/mime_types',
|
||||
), 'mime_types same extensions case insensitive'
|
||||
|
||||
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_static_mime_types_invalid(self, temp_dir):
|
||||
assert 'error' in self.http(
|
||||
def test_static_mime_types_invalid(temp_dir):
|
||||
assert 'error' in client.http(
|
||||
b"""PUT /config/settings/http/static/mime_types/%0%00% HTTP/1.1\r
|
||||
Host: localhost\r
|
||||
Connection: close\r
|
||||
|
|
|
@ -2,148 +2,162 @@ import os
|
|||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from unit.applications.proto import TestApplicationProto
|
||||
from unit.applications.proto import ApplicationProto
|
||||
from unit.option import option
|
||||
|
||||
prerequisites = {'features': {'chroot': True}}
|
||||
|
||||
client = ApplicationProto()
|
||||
|
||||
|
||||
class TestStaticChroot(TestApplicationProto):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_method_fixture(self, temp_dir):
|
||||
def setup_method_fixture(temp_dir):
|
||||
os.makedirs(f'{temp_dir}/assets/dir')
|
||||
Path(f'{temp_dir}/assets/index.html').write_text('0123456789')
|
||||
Path(f'{temp_dir}/assets/dir/file').write_text('blah')
|
||||
|
||||
self.test_path = f'/{os.path.relpath(Path(__file__))}'
|
||||
client.test_path = f'/{os.path.relpath(Path(__file__))}'
|
||||
|
||||
self._load_conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "routes"}},
|
||||
"routes": [{"action": {"share": f'{temp_dir}/assets$uri'}}],
|
||||
}
|
||||
)
|
||||
|
||||
def update_action(self, chroot, share=f'{option.temp_dir}/assets$uri'):
|
||||
return self.conf(
|
||||
|
||||
def update_action(chroot, share=f'{option.temp_dir}/assets$uri'):
|
||||
return client.conf(
|
||||
{'chroot': chroot, 'share': share},
|
||||
'routes/0/action',
|
||||
)
|
||||
|
||||
def get_custom(self, uri, host):
|
||||
return self.get(url=uri, headers={'Host': host, 'Connection': 'close'})[
|
||||
|
||||
def get_custom(uri, host):
|
||||
return client.get(url=uri, headers={'Host': host, 'Connection': 'close'})[
|
||||
'status'
|
||||
]
|
||||
|
||||
def test_static_chroot(self, temp_dir):
|
||||
assert self.get(url='/dir/file')['status'] == 200, 'default chroot'
|
||||
assert self.get(url='/index.html')['status'] == 200, 'default chroot 2'
|
||||
|
||||
assert 'success' in self.update_action(f'{temp_dir}/assets/dir')
|
||||
def test_static_chroot(temp_dir):
|
||||
assert client.get(url='/dir/file')['status'] == 200, 'default chroot'
|
||||
assert client.get(url='/index.html')['status'] == 200, 'default chroot 2'
|
||||
|
||||
assert self.get(url='/dir/file')['status'] == 200, 'chroot'
|
||||
assert self.get(url='/index.html')['status'] == 403, 'chroot 403 2'
|
||||
assert self.get(url='/file')['status'] == 403, 'chroot 403'
|
||||
assert 'success' in update_action(f'{temp_dir}/assets/dir')
|
||||
|
||||
def test_share_chroot_array(self, temp_dir):
|
||||
assert 'success' in self.update_action(
|
||||
assert client.get(url='/dir/file')['status'] == 200, 'chroot'
|
||||
assert client.get(url='/index.html')['status'] == 403, 'chroot 403 2'
|
||||
assert client.get(url='/file')['status'] == 403, 'chroot 403'
|
||||
|
||||
|
||||
def test_share_chroot_array(temp_dir):
|
||||
assert 'success' in update_action(
|
||||
f'{temp_dir}/assets/dir', ["/blah", f'{temp_dir}/assets$uri']
|
||||
)
|
||||
assert self.get(url='/dir/file')['status'] == 200, 'share array'
|
||||
assert client.get(url='/dir/file')['status'] == 200, 'share array'
|
||||
|
||||
assert 'success' in self.update_action(
|
||||
assert 'success' in update_action(
|
||||
f'{temp_dir}/assets/$host',
|
||||
['/blah', f'{temp_dir}/assets$uri'],
|
||||
)
|
||||
assert self.get_custom('/dir/file', 'dir') == 200, 'array variable'
|
||||
assert get_custom('/dir/file', 'dir') == 200, 'array variable'
|
||||
|
||||
assert 'success' in self.update_action(
|
||||
assert 'success' in update_action(
|
||||
f'{temp_dir}/assets/dir', ['/blah', '/blah2']
|
||||
)
|
||||
assert self.get()['status'] != 200, 'share array bad'
|
||||
assert client.get()['status'] != 200, 'share array bad'
|
||||
|
||||
def test_static_chroot_permission(self, require, temp_dir):
|
||||
|
||||
def test_static_chroot_permission(require, temp_dir):
|
||||
require({'privileged_user': False})
|
||||
|
||||
os.chmod(f'{temp_dir}/assets/dir', 0o100)
|
||||
|
||||
assert 'success' in self.update_action(
|
||||
assert 'success' in update_action(
|
||||
f'{temp_dir}/assets/dir'
|
||||
), 'configure chroot'
|
||||
|
||||
assert self.get(url='/dir/file')['status'] == 200, 'chroot'
|
||||
assert client.get(url='/dir/file')['status'] == 200, 'chroot'
|
||||
|
||||
def test_static_chroot_empty(self):
|
||||
assert 'success' in self.update_action('')
|
||||
assert self.get(url='/dir/file')['status'] == 200, 'empty absolute'
|
||||
|
||||
assert 'success' in self.update_action("", ".$uri")
|
||||
assert self.get(url=self.test_path)['status'] == 200, 'empty relative'
|
||||
def test_static_chroot_empty():
|
||||
assert 'success' in update_action('')
|
||||
assert client.get(url='/dir/file')['status'] == 200, 'empty absolute'
|
||||
|
||||
def test_static_chroot_relative(self, require):
|
||||
assert 'success' in update_action("", ".$uri")
|
||||
assert client.get(url=client.test_path)['status'] == 200, 'empty relative'
|
||||
|
||||
|
||||
def test_static_chroot_relative(require):
|
||||
require({'privileged_user': False})
|
||||
|
||||
assert 'success' in self.update_action('.')
|
||||
assert self.get(url='/dir/file')['status'] == 403, 'relative chroot'
|
||||
assert 'success' in update_action('.')
|
||||
assert client.get(url='/dir/file')['status'] == 403, 'relative chroot'
|
||||
|
||||
assert 'success' in self.conf({"share": ".$uri"}, 'routes/0/action')
|
||||
assert self.get(url=self.test_path)['status'] == 200, 'relative share'
|
||||
assert 'success' in client.conf({"share": ".$uri"}, 'routes/0/action')
|
||||
assert client.get(url=client.test_path)['status'] == 200, 'relative share'
|
||||
|
||||
assert 'success' in self.update_action(".", ".$uri")
|
||||
assert self.get(url=self.test_path)['status'] == 200, 'relative'
|
||||
assert 'success' in update_action(".", ".$uri")
|
||||
assert client.get(url=client.test_path)['status'] == 200, 'relative'
|
||||
|
||||
def test_static_chroot_variables(self, temp_dir):
|
||||
assert 'success' in self.update_action(f'{temp_dir}/assets/$host')
|
||||
assert self.get_custom('/dir/file', 'dir') == 200
|
||||
|
||||
assert 'success' in self.update_action(f'{temp_dir}/assets/${{host}}')
|
||||
assert self.get_custom('/dir/file', 'dir') == 200
|
||||
def test_static_chroot_variables(temp_dir):
|
||||
assert 'success' in update_action(f'{temp_dir}/assets/$host')
|
||||
assert get_custom('/dir/file', 'dir') == 200
|
||||
|
||||
def test_static_chroot_variables_buildin_start(self, temp_dir):
|
||||
assert 'success' in self.update_action(
|
||||
assert 'success' in update_action(f'{temp_dir}/assets/${{host}}')
|
||||
assert get_custom('/dir/file', 'dir') == 200
|
||||
|
||||
|
||||
def test_static_chroot_variables_buildin_start(temp_dir):
|
||||
assert 'success' in update_action(
|
||||
'$uri/assets/dir',
|
||||
f'{temp_dir}/assets/dir/$host',
|
||||
)
|
||||
assert self.get_custom(temp_dir, 'file') == 200
|
||||
assert get_custom(temp_dir, 'file') == 200
|
||||
|
||||
def test_static_chroot_variables_buildin_mid(self, temp_dir):
|
||||
assert 'success' in self.update_action(f'{temp_dir}/$host/dir')
|
||||
assert self.get_custom('/dir/file', 'assets') == 200
|
||||
|
||||
def test_static_chroot_variables_buildin_end(self, temp_dir):
|
||||
assert 'success' in self.update_action(f'{temp_dir}/assets/$host')
|
||||
assert self.get_custom('/dir/file', 'dir') == 200
|
||||
def test_static_chroot_variables_buildin_mid(temp_dir):
|
||||
assert 'success' in update_action(f'{temp_dir}/$host/dir')
|
||||
assert get_custom('/dir/file', 'assets') == 200
|
||||
|
||||
def test_static_chroot_slash(self, temp_dir):
|
||||
assert 'success' in self.update_action(f'{temp_dir}/assets/dir/')
|
||||
assert self.get(url='/dir/file')['status'] == 200, 'slash end'
|
||||
assert self.get(url='/dirxfile')['status'] == 403, 'slash end bad'
|
||||
|
||||
assert 'success' in self.update_action(f'{temp_dir}/assets/dir')
|
||||
assert self.get(url='/dir/file')['status'] == 200, 'no slash end'
|
||||
def test_static_chroot_variables_buildin_end(temp_dir):
|
||||
assert 'success' in update_action(f'{temp_dir}/assets/$host')
|
||||
assert get_custom('/dir/file', 'dir') == 200
|
||||
|
||||
assert 'success' in self.update_action(f'{temp_dir}/assets/dir/')
|
||||
assert self.get(url='/dir/file')['status'] == 200, 'slash end 2'
|
||||
assert self.get(url='/dirxfile')['status'] == 403, 'slash end 2 bad'
|
||||
|
||||
assert 'success' in self.update_action(
|
||||
def test_static_chroot_slash(temp_dir):
|
||||
assert 'success' in update_action(f'{temp_dir}/assets/dir/')
|
||||
assert client.get(url='/dir/file')['status'] == 200, 'slash end'
|
||||
assert client.get(url='/dirxfile')['status'] == 403, 'slash end bad'
|
||||
|
||||
assert 'success' in update_action(f'{temp_dir}/assets/dir')
|
||||
assert client.get(url='/dir/file')['status'] == 200, 'no slash end'
|
||||
|
||||
assert 'success' in update_action(f'{temp_dir}/assets/dir/')
|
||||
assert client.get(url='/dir/file')['status'] == 200, 'slash end 2'
|
||||
assert client.get(url='/dirxfile')['status'] == 403, 'slash end 2 bad'
|
||||
|
||||
assert 'success' in update_action(
|
||||
f'{temp_dir}//assets////dir///', f'{temp_dir}///assets/////$uri'
|
||||
)
|
||||
assert self.get(url='/dir/file')['status'] == 200, 'multiple slashes'
|
||||
assert client.get(url='/dir/file')['status'] == 200, 'multiple slashes'
|
||||
|
||||
def test_static_chroot_invalid(self, temp_dir):
|
||||
assert 'error' in self.conf(
|
||||
|
||||
def test_static_chroot_invalid(temp_dir):
|
||||
assert 'error' in client.conf(
|
||||
{"share": temp_dir, "chroot": True},
|
||||
'routes/0/action',
|
||||
), 'configure chroot error'
|
||||
assert 'error' in self.conf(
|
||||
assert 'error' in client.conf(
|
||||
{"share": temp_dir, "symlinks": "True"},
|
||||
'routes/0/action',
|
||||
), 'configure symlink error'
|
||||
assert 'error' in self.conf(
|
||||
assert 'error' in client.conf(
|
||||
{"share": temp_dir, "mount": "True"},
|
||||
'routes/0/action',
|
||||
), 'configure mount error'
|
||||
|
||||
assert 'error' in self.update_action(f'{temp_dir}/assets/d$r$uri')
|
||||
assert 'error' in self.update_action(f'{temp_dir}/assets/$$uri')
|
||||
assert 'error' in update_action(f'{temp_dir}/assets/d$r$uri')
|
||||
assert 'error' in update_action(f'{temp_dir}/assets/$$uri')
|
||||
|
|
|
@ -2,12 +2,13 @@ import os
|
|||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from unit.applications.proto import TestApplicationProto
|
||||
from unit.applications.proto import ApplicationProto
|
||||
|
||||
client = ApplicationProto()
|
||||
|
||||
|
||||
class TestStaticFallback(TestApplicationProto):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_method_fixture(self, temp_dir):
|
||||
def setup_method_fixture(temp_dir):
|
||||
assets_dir = f'{temp_dir}/assets'
|
||||
os.makedirs(f'{assets_dir}/dir')
|
||||
Path(f'{assets_dir}/index.html').write_text('0123456789')
|
||||
|
@ -15,7 +16,7 @@ class TestStaticFallback(TestApplicationProto):
|
|||
os.makedirs(f'{assets_dir}/403')
|
||||
os.chmod(f'{assets_dir}/403', 0o000)
|
||||
|
||||
self._load_conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"*:7080": {"pass": "routes"},
|
||||
|
@ -33,39 +34,43 @@ class TestStaticFallback(TestApplicationProto):
|
|||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
def action_update(self, conf):
|
||||
assert 'success' in self.conf(conf, 'routes/0/action')
|
||||
|
||||
def test_static_fallback(self):
|
||||
self.action_update({"share": "/blah"})
|
||||
assert self.get()['status'] == 404, 'bad path no fallback'
|
||||
def action_update(conf):
|
||||
assert 'success' in client.conf(conf, 'routes/0/action')
|
||||
|
||||
self.action_update({"share": "/blah", "fallback": {"return": 200}})
|
||||
|
||||
resp = self.get()
|
||||
def test_static_fallback():
|
||||
action_update({"share": "/blah"})
|
||||
assert client.get()['status'] == 404, 'bad path no fallback'
|
||||
|
||||
action_update({"share": "/blah", "fallback": {"return": 200}})
|
||||
|
||||
resp = client.get()
|
||||
assert resp['status'] == 200, 'bad path fallback status'
|
||||
assert resp['body'] == '', 'bad path fallback'
|
||||
|
||||
def test_static_fallback_valid_path(self, temp_dir):
|
||||
self.action_update(
|
||||
|
||||
def test_static_fallback_valid_path(temp_dir):
|
||||
action_update(
|
||||
{"share": f"{temp_dir}/assets$uri", "fallback": {"return": 200}}
|
||||
)
|
||||
resp = self.get()
|
||||
resp = client.get()
|
||||
assert resp['status'] == 200, 'fallback status'
|
||||
assert resp['body'] == '0123456789', 'fallback'
|
||||
|
||||
resp = self.get(url='/403/')
|
||||
resp = client.get(url='/403/')
|
||||
assert resp['status'] == 200, 'fallback status 403'
|
||||
assert resp['body'] == '', 'fallback 403'
|
||||
|
||||
resp = self.post()
|
||||
resp = client.post()
|
||||
assert resp['status'] == 200, 'fallback status 405'
|
||||
assert resp['body'] == '', 'fallback 405'
|
||||
|
||||
assert self.get(url='/dir')['status'] == 301, 'fallback status 301'
|
||||
assert client.get(url='/dir')['status'] == 301, 'fallback status 301'
|
||||
|
||||
def test_static_fallback_nested(self):
|
||||
self.action_update(
|
||||
|
||||
def test_static_fallback_nested():
|
||||
action_update(
|
||||
{
|
||||
"share": "/blah",
|
||||
"fallback": {
|
||||
|
@ -75,32 +80,32 @@ class TestStaticFallback(TestApplicationProto):
|
|||
}
|
||||
)
|
||||
|
||||
resp = self.get()
|
||||
resp = client.get()
|
||||
assert resp['status'] == 200, 'fallback nested status'
|
||||
assert resp['body'] == '', 'fallback nested'
|
||||
|
||||
def test_static_fallback_share(self, temp_dir):
|
||||
self.action_update(
|
||||
|
||||
def test_static_fallback_share(temp_dir):
|
||||
action_update(
|
||||
{
|
||||
"share": "/blah",
|
||||
"fallback": {"share": f"{temp_dir}/assets$uri"},
|
||||
}
|
||||
)
|
||||
|
||||
resp = self.get()
|
||||
resp = client.get()
|
||||
assert resp['status'] == 200, 'fallback share status'
|
||||
assert resp['body'] == '0123456789', 'fallback share'
|
||||
|
||||
resp = self.head()
|
||||
resp = client.head()
|
||||
assert resp['status'] == 200, 'fallback share status HEAD'
|
||||
assert resp['body'] == '', 'fallback share HEAD'
|
||||
|
||||
assert (
|
||||
self.get(url='/dir')['status'] == 301
|
||||
), 'fallback share status 301'
|
||||
assert client.get(url='/dir')['status'] == 301, 'fallback share status 301'
|
||||
|
||||
def test_static_fallback_proxy(self):
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def test_static_fallback_proxy():
|
||||
assert 'success' in client.conf(
|
||||
[
|
||||
{
|
||||
"match": {"destination": "*:7081"},
|
||||
|
@ -116,12 +121,13 @@ class TestStaticFallback(TestApplicationProto):
|
|||
'routes',
|
||||
), 'configure fallback proxy route'
|
||||
|
||||
resp = self.get()
|
||||
resp = client.get()
|
||||
assert resp['status'] == 200, 'fallback proxy status'
|
||||
assert resp['body'] == '', 'fallback proxy'
|
||||
|
||||
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_static_fallback_proxy_loop(self, skip_alert):
|
||||
def test_static_fallback_proxy_loop(skip_alert):
|
||||
skip_alert(
|
||||
r'open.*/blah/index.html.*failed',
|
||||
r'accept.*failed',
|
||||
|
@ -129,17 +135,18 @@ class TestStaticFallback(TestApplicationProto):
|
|||
r'new connections are not accepted',
|
||||
)
|
||||
|
||||
self.action_update(
|
||||
action_update(
|
||||
{"share": "/blah", "fallback": {"proxy": "http://127.0.0.1:7080"}}
|
||||
)
|
||||
self.get(no_recv=True)
|
||||
client.get(no_recv=True)
|
||||
|
||||
assert 'success' in self.conf_delete('listeners/*:7081')
|
||||
self.get(read_timeout=1)
|
||||
assert 'success' in client.conf_delete('listeners/*:7081')
|
||||
client.get(read_timeout=1)
|
||||
|
||||
def test_static_fallback_invalid(self):
|
||||
|
||||
def test_static_fallback_invalid():
|
||||
def check_error(conf):
|
||||
assert 'error' in self.conf(conf, 'routes/0/action')
|
||||
assert 'error' in client.conf(conf, 'routes/0/action')
|
||||
|
||||
check_error({"share": "/blah", "fallback": {}})
|
||||
check_error({"share": "/blah", "fallback": ""})
|
||||
|
|
|
@ -3,14 +3,15 @@ import subprocess
|
|||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from unit.applications.proto import TestApplicationProto
|
||||
from unit.applications.proto import ApplicationProto
|
||||
|
||||
prerequisites = {'features': {'chroot': True}, 'privileged_user': True}
|
||||
|
||||
client = ApplicationProto()
|
||||
|
||||
|
||||
class TestStaticMount(TestApplicationProto):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_method_fixture(self, temp_dir):
|
||||
def setup_method_fixture(temp_dir):
|
||||
os.makedirs(f'{temp_dir}/assets/dir/mount')
|
||||
os.makedirs(f'{temp_dir}/assets/dir/dir')
|
||||
os.makedirs(f'{temp_dir}/assets/mount')
|
||||
|
@ -35,7 +36,7 @@ class TestStaticMount(TestApplicationProto):
|
|||
except subprocess.CalledProcessError:
|
||||
pytest.fail("Can't run mount process.")
|
||||
|
||||
self._load_conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "routes"}},
|
||||
"routes": [{"action": {"share": f'{temp_dir}/assets/dir$uri'}}],
|
||||
|
@ -56,35 +57,37 @@ class TestStaticMount(TestApplicationProto):
|
|||
except subprocess.CalledProcessError:
|
||||
pytest.fail("Can't run umount process.")
|
||||
|
||||
def test_static_mount(self, temp_dir, skip_alert):
|
||||
|
||||
def test_static_mount(temp_dir, skip_alert):
|
||||
skip_alert(r'opening.*failed')
|
||||
|
||||
resp = self.get(url='/mount/')
|
||||
resp = client.get(url='/mount/')
|
||||
assert resp['status'] == 200
|
||||
assert resp['body'] == 'mount'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{"share": f'{temp_dir}/assets/dir$uri', "traverse_mounts": False},
|
||||
'routes/0/action',
|
||||
), 'configure mount disable'
|
||||
|
||||
assert self.get(url='/mount/')['status'] == 403
|
||||
assert client.get(url='/mount/')['status'] == 403
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{"share": f'{temp_dir}/assets/dir$uri', "traverse_mounts": True},
|
||||
'routes/0/action',
|
||||
), 'configure mount enable'
|
||||
|
||||
resp = self.get(url='/mount/')
|
||||
resp = client.get(url='/mount/')
|
||||
assert resp['status'] == 200
|
||||
assert resp['body'] == 'mount'
|
||||
|
||||
def test_static_mount_two_blocks(self, temp_dir, skip_alert):
|
||||
|
||||
def test_static_mount_two_blocks(temp_dir, skip_alert):
|
||||
skip_alert(r'opening.*failed')
|
||||
|
||||
os.symlink(f'{temp_dir}/assets/dir', f'{temp_dir}/assets/link')
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
[
|
||||
{
|
||||
"match": {"method": "HEAD"},
|
||||
|
@ -104,13 +107,14 @@ class TestStaticMount(TestApplicationProto):
|
|||
'routes',
|
||||
), 'configure two options'
|
||||
|
||||
assert self.get(url='/mount/')['status'] == 200, 'block enabled'
|
||||
assert self.head(url='/mount/')['status'] == 403, 'block disabled'
|
||||
assert client.get(url='/mount/')['status'] == 200, 'block enabled'
|
||||
assert client.head(url='/mount/')['status'] == 403, 'block disabled'
|
||||
|
||||
def test_static_mount_chroot(self, temp_dir, skip_alert):
|
||||
|
||||
def test_static_mount_chroot(temp_dir, skip_alert):
|
||||
skip_alert(r'opening.*failed')
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"share": f'{temp_dir}/assets/dir$uri',
|
||||
"chroot": f'{temp_dir}/assets',
|
||||
|
@ -118,9 +122,9 @@ class TestStaticMount(TestApplicationProto):
|
|||
'routes/0/action',
|
||||
), 'configure chroot mount default'
|
||||
|
||||
assert self.get(url='/mount/')['status'] == 200, 'chroot'
|
||||
assert client.get(url='/mount/')['status'] == 200, 'chroot'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"share": f'{temp_dir}/assets/dir$uri',
|
||||
"chroot": f'{temp_dir}/assets',
|
||||
|
@ -129,4 +133,4 @@ class TestStaticMount(TestApplicationProto):
|
|||
'routes/0/action',
|
||||
), 'configure chroot mount disable'
|
||||
|
||||
assert self.get(url='/mount/')['status'] == 403, 'chroot mount'
|
||||
assert client.get(url='/mount/')['status'] == 403, 'chroot mount'
|
||||
|
|
|
@ -2,19 +2,20 @@ import os
|
|||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from unit.applications.proto import TestApplicationProto
|
||||
from unit.applications.proto import ApplicationProto
|
||||
|
||||
client = ApplicationProto()
|
||||
|
||||
|
||||
class TestStaticShare(TestApplicationProto):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_method_fixture(self, temp_dir):
|
||||
def setup_method_fixture(temp_dir):
|
||||
os.makedirs(f'{temp_dir}/assets/dir')
|
||||
os.makedirs(f'{temp_dir}/assets/dir2')
|
||||
|
||||
Path(f'{temp_dir}/assets/dir/file').write_text('1')
|
||||
Path(f'{temp_dir}/assets/dir2/file2').write_text('2')
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "routes"}},
|
||||
"routes": [{"action": {"share": f'{temp_dir}/assets$uri'}}],
|
||||
|
@ -22,19 +23,21 @@ class TestStaticShare(TestApplicationProto):
|
|||
}
|
||||
)
|
||||
|
||||
def action_update(self, conf):
|
||||
assert 'success' in self.conf(conf, 'routes/0/action')
|
||||
|
||||
def test_share_array(self, temp_dir):
|
||||
assert self.get(url='/dir/file')['body'] == '1'
|
||||
assert self.get(url='/dir2/file2')['body'] == '2'
|
||||
def action_update(conf):
|
||||
assert 'success' in client.conf(conf, 'routes/0/action')
|
||||
|
||||
self.action_update({"share": [f'{temp_dir}/assets/dir$uri']})
|
||||
|
||||
assert self.get(url='/file')['body'] == '1'
|
||||
assert self.get(url='/file2')['status'] == 404
|
||||
def test_share_array(temp_dir):
|
||||
assert client.get(url='/dir/file')['body'] == '1'
|
||||
assert client.get(url='/dir2/file2')['body'] == '2'
|
||||
|
||||
self.action_update(
|
||||
action_update({"share": [f'{temp_dir}/assets/dir$uri']})
|
||||
|
||||
assert client.get(url='/file')['body'] == '1'
|
||||
assert client.get(url='/file2')['status'] == 404
|
||||
|
||||
action_update(
|
||||
{
|
||||
"share": [
|
||||
f'{temp_dir}/assets/dir$uri',
|
||||
|
@ -43,10 +46,10 @@ class TestStaticShare(TestApplicationProto):
|
|||
}
|
||||
)
|
||||
|
||||
assert self.get(url='/file')['body'] == '1'
|
||||
assert self.get(url='/file2')['body'] == '2'
|
||||
assert client.get(url='/file')['body'] == '1'
|
||||
assert client.get(url='/file2')['body'] == '2'
|
||||
|
||||
self.action_update(
|
||||
action_update(
|
||||
{
|
||||
"share": [
|
||||
f'{temp_dir}/assets/dir2$uri',
|
||||
|
@ -55,16 +58,16 @@ class TestStaticShare(TestApplicationProto):
|
|||
}
|
||||
)
|
||||
|
||||
assert self.get(url='/file')['status'] == 404
|
||||
assert self.get(url='/file2')['body'] == '2'
|
||||
assert client.get(url='/file')['status'] == 404
|
||||
assert client.get(url='/file2')['body'] == '2'
|
||||
|
||||
def test_share_array_fallback(self):
|
||||
self.action_update(
|
||||
{"share": ["/blah", "/blah2"], "fallback": {"return": 201}}
|
||||
)
|
||||
|
||||
assert self.get()['status'] == 201
|
||||
def test_share_array_fallback():
|
||||
action_update({"share": ["/blah", "/blah2"], "fallback": {"return": 201}})
|
||||
|
||||
def test_share_array_invalid(self):
|
||||
assert 'error' in self.conf({"share": []}, 'routes/0/action')
|
||||
assert 'error' in self.conf({"share": {}}, 'routes/0/action')
|
||||
assert client.get()['status'] == 201
|
||||
|
||||
|
||||
def test_share_array_invalid():
|
||||
assert 'error' in client.conf({"share": []}, 'routes/0/action')
|
||||
assert 'error' in client.conf({"share": {}}, 'routes/0/action')
|
||||
|
|
|
@ -2,55 +2,58 @@ import os
|
|||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from unit.applications.proto import TestApplicationProto
|
||||
from unit.applications.proto import ApplicationProto
|
||||
|
||||
prerequisites = {'features': {'chroot': True}}
|
||||
|
||||
client = ApplicationProto()
|
||||
|
||||
|
||||
class TestStaticSymlink(TestApplicationProto):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_method_fixture(self, temp_dir):
|
||||
def setup_method_fixture(temp_dir):
|
||||
os.makedirs(f'{temp_dir}/assets/dir/dir')
|
||||
Path(f'{temp_dir}/assets/index.html').write_text('0123456789')
|
||||
Path(f'{temp_dir}/assets/dir/file').write_text('blah')
|
||||
|
||||
self._load_conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "routes"}},
|
||||
"routes": [{"action": {"share": f'{temp_dir}/assets$uri'}}],
|
||||
}
|
||||
)
|
||||
|
||||
def test_static_symlink(self, temp_dir, skip_alert):
|
||||
|
||||
def test_static_symlink(temp_dir, skip_alert):
|
||||
skip_alert(r'opening.*failed')
|
||||
|
||||
os.symlink(f'{temp_dir}/assets/dir', f'{temp_dir}/assets/link')
|
||||
|
||||
assert self.get(url='/dir')['status'] == 301, 'dir'
|
||||
assert self.get(url='/dir/file')['status'] == 200, 'file'
|
||||
assert self.get(url='/link')['status'] == 301, 'symlink dir'
|
||||
assert self.get(url='/link/file')['status'] == 200, 'symlink file'
|
||||
assert client.get(url='/dir')['status'] == 301, 'dir'
|
||||
assert client.get(url='/dir/file')['status'] == 200, 'file'
|
||||
assert client.get(url='/link')['status'] == 301, 'symlink dir'
|
||||
assert client.get(url='/link/file')['status'] == 200, 'symlink file'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{"share": f'{temp_dir}/assets$uri', "follow_symlinks": False},
|
||||
'routes/0/action',
|
||||
), 'configure symlink disable'
|
||||
|
||||
assert self.get(url='/link/file')['status'] == 403, 'symlink disabled'
|
||||
assert client.get(url='/link/file')['status'] == 403, 'symlink disabled'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{"share": f'{temp_dir}/assets$uri', "follow_symlinks": True},
|
||||
'routes/0/action',
|
||||
), 'configure symlink enable'
|
||||
|
||||
assert self.get(url='/link/file')['status'] == 200, 'symlink enabled'
|
||||
assert client.get(url='/link/file')['status'] == 200, 'symlink enabled'
|
||||
|
||||
def test_static_symlink_two_blocks(self, temp_dir, skip_alert):
|
||||
|
||||
def test_static_symlink_two_blocks(temp_dir, skip_alert):
|
||||
skip_alert(r'opening.*failed')
|
||||
|
||||
os.symlink(f'{temp_dir}/assets/dir', f'{temp_dir}/assets/link')
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
[
|
||||
{
|
||||
"match": {"method": "HEAD"},
|
||||
|
@ -70,19 +73,18 @@ class TestStaticSymlink(TestApplicationProto):
|
|||
'routes',
|
||||
), 'configure two options'
|
||||
|
||||
assert self.get(url='/link/file')['status'] == 200, 'block enabled'
|
||||
assert self.head(url='/link/file')['status'] == 403, 'block disabled'
|
||||
assert client.get(url='/link/file')['status'] == 200, 'block enabled'
|
||||
assert client.head(url='/link/file')['status'] == 403, 'block disabled'
|
||||
|
||||
def test_static_symlink_chroot(self, temp_dir, skip_alert):
|
||||
|
||||
def test_static_symlink_chroot(temp_dir, skip_alert):
|
||||
skip_alert(r'opening.*failed')
|
||||
|
||||
os.symlink(
|
||||
f'{temp_dir}/assets/dir/file', f'{temp_dir}/assets/dir/dir/link'
|
||||
)
|
||||
os.symlink(f'{temp_dir}/assets/dir/file', f'{temp_dir}/assets/dir/dir/link')
|
||||
|
||||
assert self.get(url='/dir/dir/link')['status'] == 200, 'default chroot'
|
||||
assert client.get(url='/dir/dir/link')['status'] == 200, 'default chroot'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"share": f'{temp_dir}/assets$uri',
|
||||
"chroot": f'{temp_dir}/assets/dir/dir',
|
||||
|
@ -90,4 +92,4 @@ class TestStaticSymlink(TestApplicationProto):
|
|||
'routes/0/action',
|
||||
), 'configure chroot'
|
||||
|
||||
assert self.get(url='/dir/dir/link')['status'] == 404, 'chroot'
|
||||
assert client.get(url='/dir/dir/link')['status'] == 404, 'chroot'
|
||||
|
|
|
@ -1,19 +1,20 @@
|
|||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from unit.applications.proto import TestApplicationProto
|
||||
from unit.applications.proto import ApplicationProto
|
||||
|
||||
client = ApplicationProto()
|
||||
|
||||
|
||||
class TestStaticTypes(TestApplicationProto):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_method_fixture(self, temp_dir):
|
||||
def setup_method_fixture(temp_dir):
|
||||
Path(f'{temp_dir}/assets').mkdir()
|
||||
for ext in ['.xml', '.mp4', '.php', '', '.txt', '.html', '.png']:
|
||||
Path(f'{temp_dir}/assets/file{ext}').write_text(ext)
|
||||
|
||||
Path(f'{temp_dir}/assets/index.html').write_text('index')
|
||||
|
||||
self._load_conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"*:7080": {"pass": "routes"},
|
||||
|
@ -24,101 +25,103 @@ class TestStaticTypes(TestApplicationProto):
|
|||
}
|
||||
)
|
||||
|
||||
def action_update(self, conf):
|
||||
assert 'success' in self.conf(conf, 'routes/0/action')
|
||||
|
||||
def check_body(self, http_url, body):
|
||||
resp = self.get(url=http_url)
|
||||
def action_update(conf):
|
||||
assert 'success' in client.conf(conf, 'routes/0/action')
|
||||
|
||||
|
||||
def check_body(http_url, body):
|
||||
resp = client.get(url=http_url)
|
||||
assert resp['status'] == 200, 'status'
|
||||
assert resp['body'] == body, 'body'
|
||||
|
||||
def test_static_types_basic(self, temp_dir):
|
||||
self.action_update({"share": f'{temp_dir}/assets$uri'})
|
||||
self.check_body('/index.html', 'index')
|
||||
self.check_body('/file.xml', '.xml')
|
||||
|
||||
self.action_update(
|
||||
def test_static_types_basic(temp_dir):
|
||||
action_update({"share": f'{temp_dir}/assets$uri'})
|
||||
check_body('/index.html', 'index')
|
||||
check_body('/file.xml', '.xml')
|
||||
|
||||
action_update(
|
||||
{"share": f'{temp_dir}/assets$uri', "types": "application/xml"}
|
||||
)
|
||||
self.check_body('/file.xml', '.xml')
|
||||
check_body('/file.xml', '.xml')
|
||||
|
||||
self.action_update(
|
||||
action_update(
|
||||
{"share": f'{temp_dir}/assets$uri', "types": ["application/xml"]}
|
||||
)
|
||||
self.check_body('/file.xml', '.xml')
|
||||
check_body('/file.xml', '.xml')
|
||||
|
||||
self.action_update({"share": f'{temp_dir}/assets$uri', "types": [""]})
|
||||
assert self.get(url='/file.xml')['status'] == 403, 'no mtype'
|
||||
action_update({"share": f'{temp_dir}/assets$uri', "types": [""]})
|
||||
assert client.get(url='/file.xml')['status'] == 403, 'no mtype'
|
||||
|
||||
def test_static_types_wildcard(self, temp_dir):
|
||||
self.action_update(
|
||||
|
||||
def test_static_types_wildcard(temp_dir):
|
||||
action_update(
|
||||
{"share": f'{temp_dir}/assets$uri', "types": ["application/*"]}
|
||||
)
|
||||
self.check_body('/file.xml', '.xml')
|
||||
assert self.get(url='/file.mp4')['status'] == 403, 'app * mtype mp4'
|
||||
check_body('/file.xml', '.xml')
|
||||
assert client.get(url='/file.mp4')['status'] == 403, 'app * mtype mp4'
|
||||
|
||||
self.action_update(
|
||||
{"share": f'{temp_dir}/assets$uri', "types": ["video/*"]}
|
||||
)
|
||||
assert self.get(url='/file.xml')['status'] == 403, 'video * mtype xml'
|
||||
self.check_body('/file.mp4', '.mp4')
|
||||
action_update({"share": f'{temp_dir}/assets$uri', "types": ["video/*"]})
|
||||
assert client.get(url='/file.xml')['status'] == 403, 'video * mtype xml'
|
||||
check_body('/file.mp4', '.mp4')
|
||||
|
||||
def test_static_types_negation(self, temp_dir):
|
||||
self.action_update(
|
||||
|
||||
def test_static_types_negation(temp_dir):
|
||||
action_update(
|
||||
{"share": f'{temp_dir}/assets$uri', "types": ["!application/xml"]}
|
||||
)
|
||||
assert self.get(url='/file.xml')['status'] == 403, 'forbidden negation'
|
||||
self.check_body('/file.mp4', '.mp4')
|
||||
assert client.get(url='/file.xml')['status'] == 403, 'forbidden negation'
|
||||
check_body('/file.mp4', '.mp4')
|
||||
|
||||
# sorting negation
|
||||
self.action_update(
|
||||
action_update(
|
||||
{
|
||||
"share": f'{temp_dir}/assets$uri',
|
||||
"types": ["!video/*", "image/png", "!image/jpg"],
|
||||
}
|
||||
)
|
||||
assert self.get(url='/file.mp4')['status'] == 403, 'negation sort mp4'
|
||||
self.check_body('/file.png', '.png')
|
||||
assert self.get(url='/file.jpg')['status'] == 403, 'negation sort jpg'
|
||||
assert client.get(url='/file.mp4')['status'] == 403, 'negation sort mp4'
|
||||
check_body('/file.png', '.png')
|
||||
assert client.get(url='/file.jpg')['status'] == 403, 'negation sort jpg'
|
||||
|
||||
def test_static_types_regex(self, temp_dir):
|
||||
self.action_update(
|
||||
|
||||
def test_static_types_regex(temp_dir):
|
||||
action_update(
|
||||
{
|
||||
"share": f'{temp_dir}/assets$uri',
|
||||
"types": ["~text/(html|plain)"],
|
||||
}
|
||||
)
|
||||
assert self.get(url='/file.php')['status'] == 403, 'regex fail'
|
||||
self.check_body('/file.html', '.html')
|
||||
self.check_body('/file.txt', '.txt')
|
||||
assert client.get(url='/file.php')['status'] == 403, 'regex fail'
|
||||
check_body('/file.html', '.html')
|
||||
check_body('/file.txt', '.txt')
|
||||
|
||||
def test_static_types_case(self, temp_dir):
|
||||
self.action_update(
|
||||
|
||||
def test_static_types_case(temp_dir):
|
||||
action_update(
|
||||
{"share": f'{temp_dir}/assets$uri', "types": ["!APpliCaTiOn/xMl"]}
|
||||
)
|
||||
self.check_body('/file.mp4', '.mp4')
|
||||
check_body('/file.mp4', '.mp4')
|
||||
assert (
|
||||
self.get(url='/file.xml')['status'] == 403
|
||||
client.get(url='/file.xml')['status'] == 403
|
||||
), 'mixed case xml negation'
|
||||
|
||||
self.action_update(
|
||||
{"share": f'{temp_dir}/assets$uri', "types": ["vIdEo/mp4"]}
|
||||
)
|
||||
assert self.get(url='/file.mp4')['status'] == 200, 'mixed case'
|
||||
action_update({"share": f'{temp_dir}/assets$uri', "types": ["vIdEo/mp4"]})
|
||||
assert client.get(url='/file.mp4')['status'] == 200, 'mixed case'
|
||||
assert (
|
||||
self.get(url='/file.xml')['status'] == 403
|
||||
client.get(url='/file.xml')['status'] == 403
|
||||
), 'mixed case video negation'
|
||||
|
||||
self.action_update(
|
||||
{"share": f'{temp_dir}/assets$uri', "types": ["vIdEo/*"]}
|
||||
)
|
||||
self.check_body('/file.mp4', '.mp4')
|
||||
action_update({"share": f'{temp_dir}/assets$uri', "types": ["vIdEo/*"]})
|
||||
check_body('/file.mp4', '.mp4')
|
||||
assert (
|
||||
self.get(url='/file.xml')['status'] == 403
|
||||
client.get(url='/file.xml')['status'] == 403
|
||||
), 'mixed case video * negation'
|
||||
|
||||
def test_static_types_fallback(self, temp_dir):
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def test_static_types_fallback(temp_dir):
|
||||
assert 'success' in client.conf(
|
||||
[
|
||||
{
|
||||
"match": {"destination": "*:7081"},
|
||||
|
@ -135,36 +138,36 @@ class TestStaticTypes(TestApplicationProto):
|
|||
'routes',
|
||||
), 'configure fallback proxy route'
|
||||
|
||||
self.check_body('/file.php', '')
|
||||
self.check_body('/file.mp4', '.mp4')
|
||||
check_body('/file.php', '')
|
||||
check_body('/file.mp4', '.mp4')
|
||||
|
||||
def test_static_types_index(self, temp_dir):
|
||||
self.action_update(
|
||||
|
||||
def test_static_types_index(temp_dir):
|
||||
action_update(
|
||||
{"share": f'{temp_dir}/assets$uri', "types": "application/xml"}
|
||||
)
|
||||
self.check_body('/', 'index')
|
||||
self.check_body('/file.xml', '.xml')
|
||||
assert self.get(url='/index.html')['status'] == 403, 'forbidden mtype'
|
||||
assert self.get(url='/file.mp4')['status'] == 403, 'forbidden mtype'
|
||||
check_body('/', 'index')
|
||||
check_body('/file.xml', '.xml')
|
||||
assert client.get(url='/index.html')['status'] == 403, 'forbidden mtype'
|
||||
assert client.get(url='/file.mp4')['status'] == 403, 'forbidden mtype'
|
||||
|
||||
def test_static_types_custom_mime(self, temp_dir):
|
||||
self._load_conf(
|
||||
|
||||
def test_static_types_custom_mime(temp_dir):
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "routes"}},
|
||||
"routes": [{"action": {"share": f'{temp_dir}/assets$uri'}}],
|
||||
"applications": {},
|
||||
"settings": {
|
||||
"http": {
|
||||
"static": {"mime_types": {"test/mime-type": ["file"]}}
|
||||
}
|
||||
"http": {"static": {"mime_types": {"test/mime-type": ["file"]}}}
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
self.action_update({"share": f'{temp_dir}/assets$uri', "types": [""]})
|
||||
assert self.get(url='/file')['status'] == 403, 'forbidden custom mime'
|
||||
action_update({"share": f'{temp_dir}/assets$uri', "types": [""]})
|
||||
assert client.get(url='/file')['status'] == 403, 'forbidden custom mime'
|
||||
|
||||
self.action_update(
|
||||
action_update(
|
||||
{"share": f'{temp_dir}/assets$uri', "types": ["test/mime-type"]}
|
||||
)
|
||||
self.check_body('/file', '')
|
||||
check_body('/file', '')
|
||||
|
|
|
@ -2,51 +2,53 @@ import os
|
|||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from unit.applications.proto import TestApplicationProto
|
||||
from unit.applications.proto import ApplicationProto
|
||||
|
||||
client = ApplicationProto()
|
||||
|
||||
|
||||
class TestStaticVariables(TestApplicationProto):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_method_fixture(self, temp_dir):
|
||||
def setup_method_fixture(temp_dir):
|
||||
os.makedirs(f'{temp_dir}/assets/dir')
|
||||
os.makedirs(f'{temp_dir}/assets/d$r')
|
||||
Path(f'{temp_dir}/assets/index.html').write_text('0123456789')
|
||||
Path(f'{temp_dir}/assets/dir/file').write_text('file')
|
||||
Path(f'{temp_dir}/assets/d$r/file').write_text('d$r')
|
||||
|
||||
self._load_conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "routes"}},
|
||||
"routes": [{"action": {"share": f'{temp_dir}/assets$uri'}}],
|
||||
}
|
||||
)
|
||||
|
||||
def update_share(self, share):
|
||||
|
||||
def update_share(share):
|
||||
if isinstance(share, list):
|
||||
return self.conf(share, 'routes/0/action/share')
|
||||
return client.conf(share, 'routes/0/action/share')
|
||||
|
||||
return self.conf(f'"{share}"', 'routes/0/action/share')
|
||||
return client.conf(f'"{share}"', 'routes/0/action/share')
|
||||
|
||||
def test_static_variables(self, temp_dir):
|
||||
assert self.get(url='/index.html')['status'] == 200
|
||||
assert self.get(url='/d$r/file')['status'] == 200
|
||||
|
||||
assert 'success' in self.update_share('$uri')
|
||||
assert self.get(url=f'{temp_dir}/assets/index.html')['status'] == 200
|
||||
def test_static_variables(temp_dir):
|
||||
assert client.get(url='/index.html')['status'] == 200
|
||||
assert client.get(url='/d$r/file')['status'] == 200
|
||||
|
||||
assert 'success' in self.update_share(f'{temp_dir}/assets${{uri}}')
|
||||
assert self.get(url='/index.html')['status'] == 200
|
||||
assert 'success' in update_share('$uri')
|
||||
assert client.get(url=f'{temp_dir}/assets/index.html')['status'] == 200
|
||||
|
||||
def test_static_variables_array(self, temp_dir):
|
||||
assert 'success' in self.update_share(
|
||||
[f'{temp_dir}/assets$uri', '$uri']
|
||||
)
|
||||
assert 'success' in update_share(f'{temp_dir}/assets${{uri}}')
|
||||
assert client.get(url='/index.html')['status'] == 200
|
||||
|
||||
assert self.get(url='/dir/file')['status'] == 200
|
||||
assert self.get(url=f'{temp_dir}/assets/index.html')['status'] == 200
|
||||
assert self.get(url='/blah')['status'] == 404
|
||||
|
||||
assert 'success' in self.conf(
|
||||
def test_static_variables_array(temp_dir):
|
||||
assert 'success' in update_share([f'{temp_dir}/assets$uri', '$uri'])
|
||||
|
||||
assert client.get(url='/dir/file')['status'] == 200
|
||||
assert client.get(url=f'{temp_dir}/assets/index.html')['status'] == 200
|
||||
assert client.get(url='/blah')['status'] == 404
|
||||
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"share": [f'{temp_dir}/assets$uri', '$uri'],
|
||||
"fallback": {"return": 201},
|
||||
|
@ -54,24 +56,28 @@ class TestStaticVariables(TestApplicationProto):
|
|||
'routes/0/action',
|
||||
)
|
||||
|
||||
assert self.get(url='/dir/file')['status'] == 200
|
||||
assert self.get(url=f'{temp_dir}/assets/index.html')['status'] == 200
|
||||
assert self.get(url='/dir/blah')['status'] == 201
|
||||
assert client.get(url='/dir/file')['status'] == 200
|
||||
assert client.get(url=f'{temp_dir}/assets/index.html')['status'] == 200
|
||||
assert client.get(url='/dir/blah')['status'] == 201
|
||||
|
||||
def test_static_variables_buildin_start(self, temp_dir):
|
||||
assert 'success' in self.update_share('$uri/assets/index.html')
|
||||
assert self.get(url=temp_dir)['status'] == 200
|
||||
|
||||
def test_static_variables_buildin_mid(self, temp_dir):
|
||||
assert 'success' in self.update_share(f'{temp_dir}$uri/index.html')
|
||||
assert self.get(url='/assets')['status'] == 200
|
||||
def test_static_variables_buildin_start(temp_dir):
|
||||
assert 'success' in update_share('$uri/assets/index.html')
|
||||
assert client.get(url=temp_dir)['status'] == 200
|
||||
|
||||
def test_static_variables_buildin_end(self):
|
||||
assert self.get(url='/index.html')['status'] == 200
|
||||
|
||||
def test_static_variables_invalid(self, temp_dir):
|
||||
assert 'error' in self.update_share(f'{temp_dir}/assets/d$r$uri')
|
||||
assert 'error' in self.update_share(f'{temp_dir}/assets/$$uri')
|
||||
assert 'error' in self.update_share(
|
||||
def test_static_variables_buildin_mid(temp_dir):
|
||||
assert 'success' in update_share(f'{temp_dir}$uri/index.html')
|
||||
assert client.get(url='/assets')['status'] == 200
|
||||
|
||||
|
||||
def test_static_variables_buildin_end():
|
||||
assert client.get(url='/index.html')['status'] == 200
|
||||
|
||||
|
||||
def test_static_variables_invalid(temp_dir):
|
||||
assert 'error' in update_share(f'{temp_dir}/assets/d$r$uri')
|
||||
assert 'error' in update_share(f'{temp_dir}/assets/$$uri')
|
||||
assert 'error' in update_share(
|
||||
[f'{temp_dir}/assets$uri', f'{temp_dir}/assets/dir', '$$uri']
|
||||
)
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
import time
|
||||
|
||||
from unit.applications.lang.python import TestApplicationPython
|
||||
from unit.applications.lang.python import ApplicationPython
|
||||
from unit.option import option
|
||||
from unit.status import Status
|
||||
|
||||
prerequisites = {'modules': {'python': 'any'}}
|
||||
|
||||
client = ApplicationPython()
|
||||
|
||||
class TestStatus(TestApplicationPython):
|
||||
def check_connections(self, accepted, active, idle, closed):
|
||||
|
||||
def check_connections(accepted, active, idle, closed):
|
||||
assert Status.get('/connections') == {
|
||||
'accepted': accepted,
|
||||
'active': active,
|
||||
|
@ -16,23 +17,26 @@ class TestStatus(TestApplicationPython):
|
|||
'closed': closed,
|
||||
}
|
||||
|
||||
def app_default(self, name="empty", module="wsgi"):
|
||||
|
||||
def app_default(name="empty", module="wsgi"):
|
||||
name_dir = f'{option.test_dir}/python/{name}'
|
||||
return {
|
||||
"type": self.get_application_type(),
|
||||
"type": client.get_application_type(),
|
||||
"processes": {"spare": 0},
|
||||
"path": name_dir,
|
||||
"working_directory": name_dir,
|
||||
"module": module,
|
||||
}
|
||||
|
||||
def test_status(self):
|
||||
assert 'error' in self.conf_delete('/status'), 'DELETE method'
|
||||
|
||||
def test_status_requests(self, skip_alert):
|
||||
def test_status():
|
||||
assert 'error' in client.conf_delete('/status'), 'DELETE method'
|
||||
|
||||
|
||||
def test_status_requests(skip_alert):
|
||||
skip_alert(r'Python failed to import module "blah"')
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"*:7080": {"pass": "routes"},
|
||||
|
@ -41,9 +45,9 @@ class TestStatus(TestApplicationPython):
|
|||
},
|
||||
"routes": [{"action": {"return": 200}}],
|
||||
"applications": {
|
||||
"empty": self.app_default(),
|
||||
"empty": app_default(),
|
||||
"blah": {
|
||||
"type": self.get_application_type(),
|
||||
"type": client.get_application_type(),
|
||||
"processes": {"spare": 0},
|
||||
"module": "blah",
|
||||
},
|
||||
|
@ -53,22 +57,22 @@ class TestStatus(TestApplicationPython):
|
|||
|
||||
Status.init()
|
||||
|
||||
assert self.get()['status'] == 200
|
||||
assert client.get()['status'] == 200
|
||||
assert Status.get('/requests/total') == 1, '2xx'
|
||||
|
||||
assert self.get(port=7081)['status'] == 200
|
||||
assert client.get(port=7081)['status'] == 200
|
||||
assert Status.get('/requests/total') == 2, '2xx app'
|
||||
|
||||
assert (
|
||||
self.get(headers={'Host': '/', 'Connection': 'close'})['status']
|
||||
client.get(headers={'Host': '/', 'Connection': 'close'})['status']
|
||||
== 400
|
||||
)
|
||||
assert Status.get('/requests/total') == 3, '4xx'
|
||||
|
||||
assert self.get(port=7082)['status'] == 503
|
||||
assert client.get(port=7082)['status'] == 503
|
||||
assert Status.get('/requests/total') == 4, '5xx'
|
||||
|
||||
self.http(
|
||||
client.http(
|
||||
b"""GET / HTTP/1.1
|
||||
Host: localhost
|
||||
|
||||
|
@ -81,7 +85,7 @@ Connection: close
|
|||
)
|
||||
assert Status.get('/requests/total') == 6, 'pipeline'
|
||||
|
||||
sock = self.get(port=7081, no_recv=True)
|
||||
sock = client.get(port=7081, no_recv=True)
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
|
@ -89,8 +93,9 @@ Connection: close
|
|||
|
||||
sock.close()
|
||||
|
||||
def test_status_connections(self):
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def test_status_connections():
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"*:7080": {"pass": "routes"},
|
||||
|
@ -98,7 +103,7 @@ Connection: close
|
|||
},
|
||||
"routes": [{"action": {"return": 200}}],
|
||||
"applications": {
|
||||
"delayed": self.app_default("delayed"),
|
||||
"delayed": app_default("delayed"),
|
||||
},
|
||||
},
|
||||
)
|
||||
|
@ -107,25 +112,25 @@ Connection: close
|
|||
|
||||
# accepted, closed
|
||||
|
||||
assert self.get()['status'] == 200
|
||||
self.check_connections(1, 0, 0, 1)
|
||||
assert client.get()['status'] == 200
|
||||
check_connections(1, 0, 0, 1)
|
||||
|
||||
# idle
|
||||
|
||||
(_, sock) = self.get(
|
||||
(_, sock) = client.get(
|
||||
headers={'Host': 'localhost', 'Connection': 'keep-alive'},
|
||||
start=True,
|
||||
read_timeout=1,
|
||||
)
|
||||
|
||||
self.check_connections(2, 0, 1, 1)
|
||||
check_connections(2, 0, 1, 1)
|
||||
|
||||
self.get(sock=sock)
|
||||
self.check_connections(2, 0, 0, 2)
|
||||
client.get(sock=sock)
|
||||
check_connections(2, 0, 0, 2)
|
||||
|
||||
# active
|
||||
|
||||
(_, sock) = self.get(
|
||||
(_, sock) = client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Delay': '2',
|
||||
|
@ -135,14 +140,15 @@ Connection: close
|
|||
start=True,
|
||||
read_timeout=1,
|
||||
)
|
||||
self.check_connections(3, 1, 0, 2)
|
||||
check_connections(3, 1, 0, 2)
|
||||
|
||||
self.get(sock=sock)
|
||||
self.check_connections(3, 0, 0, 3)
|
||||
client.get(sock=sock)
|
||||
check_connections(3, 0, 0, 3)
|
||||
|
||||
def test_status_applications(self):
|
||||
|
||||
def test_status_applications():
|
||||
def check_applications(expert):
|
||||
apps = list(self.conf_get('/status/applications').keys()).sort()
|
||||
apps = list(client.conf_get('/status/applications').keys()).sort()
|
||||
assert apps == expert.sort()
|
||||
|
||||
def check_application(name, running, starting, idle, active):
|
||||
|
@ -155,7 +161,7 @@ Connection: close
|
|||
'requests': {'active': active},
|
||||
}
|
||||
|
||||
self.load('delayed')
|
||||
client.load('delayed')
|
||||
Status.init()
|
||||
|
||||
check_applications(['delayed'])
|
||||
|
@ -163,15 +169,15 @@ Connection: close
|
|||
|
||||
# idle
|
||||
|
||||
assert self.get()['status'] == 200
|
||||
assert client.get()['status'] == 200
|
||||
check_application('delayed', 1, 0, 1, 0)
|
||||
|
||||
assert 'success' in self.conf('4', 'applications/delayed/processes')
|
||||
assert 'success' in client.conf('4', 'applications/delayed/processes')
|
||||
check_application('delayed', 4, 0, 4, 0)
|
||||
|
||||
# active
|
||||
|
||||
(_, sock) = self.get(
|
||||
(_, sock) = client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Delay': '2',
|
||||
|
@ -185,7 +191,7 @@ Connection: close
|
|||
|
||||
# starting
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"*:7080": {"pass": "applications/restart"},
|
||||
|
@ -193,8 +199,8 @@ Connection: close
|
|||
},
|
||||
"routes": [],
|
||||
"applications": {
|
||||
"restart": self.app_default("restart", "longstart"),
|
||||
"delayed": self.app_default("delayed"),
|
||||
"restart": app_default("restart", "longstart"),
|
||||
"delayed": app_default("delayed"),
|
||||
},
|
||||
},
|
||||
)
|
||||
|
@ -204,13 +210,14 @@ Connection: close
|
|||
check_application('restart', 0, 0, 0, 0)
|
||||
check_application('delayed', 0, 0, 0, 0)
|
||||
|
||||
self.get(read_timeout=1)
|
||||
client.get(read_timeout=1)
|
||||
|
||||
check_application('restart', 0, 1, 0, 1)
|
||||
check_application('delayed', 0, 0, 0, 0)
|
||||
|
||||
def test_status_proxy(self):
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def test_status_proxy():
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"*:7080": {"pass": "routes"},
|
||||
|
@ -223,13 +230,13 @@ Connection: close
|
|||
}
|
||||
],
|
||||
"applications": {
|
||||
"empty": self.app_default(),
|
||||
"empty": app_default(),
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
Status.init()
|
||||
|
||||
assert self.get()['status'] == 200
|
||||
self.check_connections(2, 0, 0, 2)
|
||||
assert client.get()['status'] == 200
|
||||
check_connections(2, 0, 0, 2)
|
||||
assert Status.get('/requests/total') == 2, 'proxy'
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
from unit.applications.tls import TestApplicationTLS
|
||||
from unit.applications.tls import ApplicationTLS
|
||||
from unit.status import Status
|
||||
|
||||
prerequisites = {'modules': {'openssl': 'any'}}
|
||||
|
||||
client = ApplicationTLS()
|
||||
|
||||
class TestStatusTLS(TestApplicationTLS):
|
||||
def test_status_tls_requests(self):
|
||||
self.certificate()
|
||||
|
||||
assert 'success' in self.conf(
|
||||
def test_status_tls_requests():
|
||||
client.certificate()
|
||||
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"*:7080": {"pass": "routes"},
|
||||
|
@ -24,7 +25,7 @@ class TestStatusTLS(TestApplicationTLS):
|
|||
|
||||
Status.init()
|
||||
|
||||
assert self.get()['status'] == 200
|
||||
assert self.get_ssl(port=7081)['status'] == 200
|
||||
assert client.get()['status'] == 200
|
||||
assert client.get_ssl(port=7081)['status'] == 200
|
||||
|
||||
assert Status.get('/requests/total') == 2
|
||||
|
|
441
test/test_tls.py
441
test/test_tls.py
|
@ -4,15 +4,16 @@ import subprocess
|
|||
import time
|
||||
|
||||
import pytest
|
||||
from unit.applications.tls import TestApplicationTLS
|
||||
from unit.applications.tls import ApplicationTLS
|
||||
from unit.option import option
|
||||
|
||||
prerequisites = {'modules': {'python': 'any', 'openssl': 'any'}}
|
||||
|
||||
client = ApplicationTLS()
|
||||
|
||||
class TestTLS(TestApplicationTLS):
|
||||
def add_tls(self, application='empty', cert='default', port=7080):
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def add_tls(application='empty', cert='default', port=7080):
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"pass": f"applications/{application}",
|
||||
"tls": {"certificate": cert},
|
||||
|
@ -20,32 +21,38 @@ class TestTLS(TestApplicationTLS):
|
|||
f'listeners/*:{port}',
|
||||
)
|
||||
|
||||
def remove_tls(self, application='empty', port=7080):
|
||||
assert 'success' in self.conf(
|
||||
{"pass": f"applications/{application}"}, f'listeners/*:{port}'
|
||||
)
|
||||
|
||||
def req(self, name='localhost', subject=None):
|
||||
subj = subject if subject is not None else f'/CN={name}/'
|
||||
|
||||
def ca(cert='root', out='localhost'):
|
||||
subprocess.check_output(
|
||||
[
|
||||
'openssl',
|
||||
'req',
|
||||
'-new',
|
||||
'-subj',
|
||||
subj,
|
||||
'ca',
|
||||
'-batch',
|
||||
'-config',
|
||||
f'{option.temp_dir}/openssl.conf',
|
||||
f'{option.temp_dir}/ca.conf',
|
||||
'-keyfile',
|
||||
f'{option.temp_dir}/{cert}.key',
|
||||
'-cert',
|
||||
f'{option.temp_dir}/{cert}.crt',
|
||||
'-in',
|
||||
f'{option.temp_dir}/{out}.csr',
|
||||
'-out',
|
||||
f'{option.temp_dir}/{name}.csr',
|
||||
'-keyout',
|
||||
f'{option.temp_dir}/{name}.key',
|
||||
f'{option.temp_dir}/{out}.crt',
|
||||
],
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
|
||||
def generate_ca_conf(self):
|
||||
|
||||
def context_cert_req(cert='root'):
|
||||
context = ssl.create_default_context()
|
||||
context.check_hostname = False
|
||||
context.verify_mode = ssl.CERT_REQUIRED
|
||||
context.load_verify_locations(f'{option.temp_dir}/{cert}.crt')
|
||||
|
||||
return context
|
||||
|
||||
|
||||
def generate_ca_conf():
|
||||
with open(f'{option.temp_dir}/ca.conf', 'w') as f:
|
||||
f.write(
|
||||
f"""[ ca ]
|
||||
|
@ -77,141 +84,152 @@ basicConstraints = critical,CA:TRUE"""
|
|||
with open(f'{option.temp_dir}/certindex.attr', 'w') as f:
|
||||
f.write('')
|
||||
|
||||
def ca(self, cert='root', out='localhost'):
|
||||
|
||||
def remove_tls(application='empty', port=7080):
|
||||
assert 'success' in client.conf(
|
||||
{"pass": f"applications/{application}"}, f'listeners/*:{port}'
|
||||
)
|
||||
|
||||
|
||||
def req(name='localhost', subject=None):
|
||||
subj = subject if subject is not None else f'/CN={name}/'
|
||||
|
||||
subprocess.check_output(
|
||||
[
|
||||
'openssl',
|
||||
'ca',
|
||||
'-batch',
|
||||
'req',
|
||||
'-new',
|
||||
'-subj',
|
||||
subj,
|
||||
'-config',
|
||||
f'{option.temp_dir}/ca.conf',
|
||||
'-keyfile',
|
||||
f'{option.temp_dir}/{cert}.key',
|
||||
'-cert',
|
||||
f'{option.temp_dir}/{cert}.crt',
|
||||
'-in',
|
||||
f'{option.temp_dir}/{out}.csr',
|
||||
f'{option.temp_dir}/openssl.conf',
|
||||
'-out',
|
||||
f'{option.temp_dir}/{out}.crt',
|
||||
f'{option.temp_dir}/{name}.csr',
|
||||
'-keyout',
|
||||
f'{option.temp_dir}/{name}.key',
|
||||
],
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
|
||||
def set_certificate_req_context(self, cert='root'):
|
||||
self.context = ssl.create_default_context()
|
||||
self.context.check_hostname = False
|
||||
self.context.verify_mode = ssl.CERT_REQUIRED
|
||||
self.context.load_verify_locations(f'{option.temp_dir}/{cert}.crt')
|
||||
|
||||
def test_tls_listener_option_add(self):
|
||||
self.load('empty')
|
||||
def test_tls_listener_option_add():
|
||||
client.load('empty')
|
||||
|
||||
self.certificate()
|
||||
client.certificate()
|
||||
|
||||
self.add_tls()
|
||||
add_tls()
|
||||
|
||||
assert self.get_ssl()['status'] == 200, 'add listener option'
|
||||
assert client.get_ssl()['status'] == 200, 'add listener option'
|
||||
|
||||
def test_tls_listener_option_remove(self):
|
||||
self.load('empty')
|
||||
|
||||
self.certificate()
|
||||
def test_tls_listener_option_remove():
|
||||
client.load('empty')
|
||||
|
||||
self.add_tls()
|
||||
client.certificate()
|
||||
|
||||
self.get_ssl()
|
||||
add_tls()
|
||||
|
||||
self.remove_tls()
|
||||
client.get_ssl()
|
||||
|
||||
assert self.get()['status'] == 200, 'remove listener option'
|
||||
remove_tls()
|
||||
|
||||
def test_tls_certificate_remove(self):
|
||||
self.load('empty')
|
||||
assert client.get()['status'] == 200, 'remove listener option'
|
||||
|
||||
self.certificate()
|
||||
|
||||
assert 'success' in self.conf_delete(
|
||||
def test_tls_certificate_remove():
|
||||
client.load('empty')
|
||||
|
||||
client.certificate()
|
||||
|
||||
assert 'success' in client.conf_delete(
|
||||
'/certificates/default'
|
||||
), 'remove certificate'
|
||||
|
||||
def test_tls_certificate_remove_used(self):
|
||||
self.load('empty')
|
||||
|
||||
self.certificate()
|
||||
def test_tls_certificate_remove_used():
|
||||
client.load('empty')
|
||||
|
||||
self.add_tls()
|
||||
client.certificate()
|
||||
|
||||
assert 'error' in self.conf_delete(
|
||||
add_tls()
|
||||
|
||||
assert 'error' in client.conf_delete(
|
||||
'/certificates/default'
|
||||
), 'remove certificate'
|
||||
|
||||
def test_tls_certificate_remove_nonexisting(self):
|
||||
self.load('empty')
|
||||
|
||||
self.certificate()
|
||||
def test_tls_certificate_remove_nonexisting():
|
||||
client.load('empty')
|
||||
|
||||
self.add_tls()
|
||||
client.certificate()
|
||||
|
||||
assert 'error' in self.conf_delete(
|
||||
add_tls()
|
||||
|
||||
assert 'error' in client.conf_delete(
|
||||
'/certificates/blah'
|
||||
), 'remove nonexistings certificate'
|
||||
|
||||
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_tls_certificate_update(self):
|
||||
self.load('empty')
|
||||
def test_tls_certificate_update():
|
||||
client.load('empty')
|
||||
|
||||
self.certificate()
|
||||
client.certificate()
|
||||
|
||||
self.add_tls()
|
||||
add_tls()
|
||||
|
||||
cert_old = ssl.get_server_certificate(('127.0.0.1', 7080))
|
||||
|
||||
self.certificate()
|
||||
client.certificate()
|
||||
|
||||
assert cert_old != ssl.get_server_certificate(
|
||||
('127.0.0.1', 7080)
|
||||
), 'update certificate'
|
||||
|
||||
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_tls_certificate_key_incorrect(self):
|
||||
self.load('empty')
|
||||
def test_tls_certificate_key_incorrect():
|
||||
client.load('empty')
|
||||
|
||||
self.certificate('first', False)
|
||||
self.certificate('second', False)
|
||||
client.certificate('first', False)
|
||||
client.certificate('second', False)
|
||||
|
||||
assert 'error' in self.certificate_load(
|
||||
assert 'error' in client.certificate_load(
|
||||
'first', 'second'
|
||||
), 'key incorrect'
|
||||
|
||||
def test_tls_certificate_change(self):
|
||||
self.load('empty')
|
||||
|
||||
self.certificate()
|
||||
self.certificate('new')
|
||||
def test_tls_certificate_change():
|
||||
client.load('empty')
|
||||
|
||||
self.add_tls()
|
||||
client.certificate()
|
||||
client.certificate('new')
|
||||
|
||||
add_tls()
|
||||
|
||||
cert_old = ssl.get_server_certificate(('127.0.0.1', 7080))
|
||||
|
||||
self.add_tls(cert='new')
|
||||
add_tls(cert='new')
|
||||
|
||||
assert cert_old != ssl.get_server_certificate(
|
||||
('127.0.0.1', 7080)
|
||||
), 'change certificate'
|
||||
|
||||
def test_tls_certificate_key_rsa(self):
|
||||
self.load('empty')
|
||||
|
||||
self.certificate()
|
||||
def test_tls_certificate_key_rsa():
|
||||
client.load('empty')
|
||||
|
||||
client.certificate()
|
||||
|
||||
assert (
|
||||
self.conf_get('/certificates/default/key') == 'RSA (2048 bits)'
|
||||
client.conf_get('/certificates/default/key') == 'RSA (2048 bits)'
|
||||
), 'certificate key rsa'
|
||||
|
||||
def test_tls_certificate_key_ec(self, temp_dir):
|
||||
self.load('empty')
|
||||
|
||||
self.openssl_conf()
|
||||
def test_tls_certificate_key_ec(temp_dir):
|
||||
client.load('empty')
|
||||
|
||||
client.openssl_conf()
|
||||
|
||||
subprocess.check_output(
|
||||
[
|
||||
|
@ -245,19 +263,20 @@ basicConstraints = critical,CA:TRUE"""
|
|||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
|
||||
self.certificate_load('ec')
|
||||
client.certificate_load('ec')
|
||||
|
||||
assert (
|
||||
self.conf_get('/certificates/ec/key') == 'ECDH'
|
||||
client.conf_get('/certificates/ec/key') == 'ECDH'
|
||||
), 'certificate key ec'
|
||||
|
||||
def test_tls_certificate_chain_options(self, date_to_sec_epoch, sec_epoch):
|
||||
self.load('empty')
|
||||
|
||||
def test_tls_certificate_chain_options(date_to_sec_epoch, sec_epoch):
|
||||
client.load('empty')
|
||||
date_format = '%b %d %X %Y %Z'
|
||||
|
||||
self.certificate()
|
||||
client.certificate()
|
||||
|
||||
chain = self.conf_get('/certificates/default/chain')
|
||||
chain = client.conf_get('/certificates/default/chain')
|
||||
|
||||
assert len(chain) == 1, 'certificate chain length'
|
||||
|
||||
|
@ -283,18 +302,19 @@ basicConstraints = critical,CA:TRUE"""
|
|||
== 2592000
|
||||
), 'certificate validity until'
|
||||
|
||||
def test_tls_certificate_chain(self, temp_dir):
|
||||
self.load('empty')
|
||||
|
||||
self.certificate('root', False)
|
||||
def test_tls_certificate_chain(temp_dir):
|
||||
client.load('empty')
|
||||
|
||||
self.req('int')
|
||||
self.req('end')
|
||||
client.certificate('root', False)
|
||||
|
||||
self.generate_ca_conf()
|
||||
req('int')
|
||||
req('end')
|
||||
|
||||
self.ca(cert='root', out='int')
|
||||
self.ca(cert='int', out='end')
|
||||
generate_ca_conf()
|
||||
|
||||
ca(cert='root', out='int')
|
||||
ca(cert='int', out='end')
|
||||
|
||||
crt_path = f'{temp_dir}/end-int.crt'
|
||||
end_path = f'{temp_dir}/end.crt'
|
||||
|
@ -305,15 +325,13 @@ basicConstraints = critical,CA:TRUE"""
|
|||
) as int:
|
||||
crt.write(end.read() + int.read())
|
||||
|
||||
self.set_certificate_req_context()
|
||||
|
||||
# incomplete chain
|
||||
|
||||
assert 'success' in self.certificate_load(
|
||||
assert 'success' in client.certificate_load(
|
||||
'end', 'end'
|
||||
), 'certificate chain end upload'
|
||||
|
||||
chain = self.conf_get('/certificates/end/chain')
|
||||
chain = client.conf_get('/certificates/end/chain')
|
||||
assert len(chain) == 1, 'certificate chain end length'
|
||||
assert (
|
||||
chain[0]['subject']['common_name'] == 'end'
|
||||
|
@ -322,10 +340,11 @@ basicConstraints = critical,CA:TRUE"""
|
|||
chain[0]['issuer']['common_name'] == 'int'
|
||||
), 'certificate chain end issuer common name'
|
||||
|
||||
self.add_tls(cert='end')
|
||||
add_tls(cert='end')
|
||||
|
||||
ctx_cert_req = context_cert_req()
|
||||
try:
|
||||
resp = self.get_ssl()
|
||||
resp = client.get_ssl(context=ctx_cert_req)
|
||||
except ssl.SSLError:
|
||||
resp = None
|
||||
|
||||
|
@ -333,11 +352,11 @@ basicConstraints = critical,CA:TRUE"""
|
|||
|
||||
# intermediate
|
||||
|
||||
assert 'success' in self.certificate_load(
|
||||
assert 'success' in client.certificate_load(
|
||||
'int', 'int'
|
||||
), 'certificate chain int upload'
|
||||
|
||||
chain = self.conf_get('/certificates/int/chain')
|
||||
chain = client.conf_get('/certificates/int/chain')
|
||||
assert len(chain) == 1, 'certificate chain int length'
|
||||
assert (
|
||||
chain[0]['subject']['common_name'] == 'int'
|
||||
|
@ -346,17 +365,17 @@ basicConstraints = critical,CA:TRUE"""
|
|||
chain[0]['issuer']['common_name'] == 'root'
|
||||
), 'certificate chain int issuer common name'
|
||||
|
||||
self.add_tls(cert='int')
|
||||
add_tls(cert='int')
|
||||
|
||||
assert self.get_ssl()['status'] == 200, 'certificate chain intermediate'
|
||||
assert client.get_ssl()['status'] == 200, 'certificate chain intermediate'
|
||||
|
||||
# intermediate server
|
||||
|
||||
assert 'success' in self.certificate_load(
|
||||
assert 'success' in client.certificate_load(
|
||||
'end-int', 'end'
|
||||
), 'certificate chain end-int upload'
|
||||
|
||||
chain = self.conf_get('/certificates/end-int/chain')
|
||||
chain = client.conf_get('/certificates/end-int/chain')
|
||||
assert len(chain) == 2, 'certificate chain end-int length'
|
||||
assert (
|
||||
chain[0]['subject']['common_name'] == 'end'
|
||||
|
@ -371,35 +390,36 @@ basicConstraints = critical,CA:TRUE"""
|
|||
chain[1]['issuer']['common_name'] == 'root'
|
||||
), 'certificate chain end-int end issuer common name'
|
||||
|
||||
self.add_tls(cert='end-int')
|
||||
add_tls(cert='end-int')
|
||||
|
||||
assert (
|
||||
self.get_ssl()['status'] == 200
|
||||
client.get_ssl(context=ctx_cert_req)['status'] == 200
|
||||
), 'certificate chain intermediate server'
|
||||
|
||||
def test_tls_certificate_chain_long(self, temp_dir):
|
||||
self.load('empty')
|
||||
|
||||
self.generate_ca_conf()
|
||||
def test_tls_certificate_chain_long(temp_dir):
|
||||
client.load('empty')
|
||||
|
||||
generate_ca_conf()
|
||||
|
||||
# Minimum chain length is 3.
|
||||
chain_length = 10
|
||||
|
||||
for i in range(chain_length):
|
||||
if i == 0:
|
||||
self.certificate('root', False)
|
||||
client.certificate('root', False)
|
||||
elif i == chain_length - 1:
|
||||
self.req('end')
|
||||
req('end')
|
||||
else:
|
||||
self.req(f'int{i}')
|
||||
req(f'int{i}')
|
||||
|
||||
for i in range(chain_length - 1):
|
||||
if i == 0:
|
||||
self.ca(cert='root', out='int1')
|
||||
ca(cert='root', out='int1')
|
||||
elif i == chain_length - 2:
|
||||
self.ca(cert=f'int{(chain_length - 2)}', out='end')
|
||||
ca(cert=f'int{(chain_length - 2)}', out='end')
|
||||
else:
|
||||
self.ca(cert=f'int{i}', out=f'int{(i + 1)}')
|
||||
ca(cert=f'int{i}', out=f'int{(i + 1)}')
|
||||
|
||||
for i in range(chain_length - 1, 0, -1):
|
||||
path = (
|
||||
|
@ -411,90 +431,88 @@ basicConstraints = critical,CA:TRUE"""
|
|||
with open(f'{temp_dir}/all.crt', 'a') as chain, open(path) as cert:
|
||||
chain.write(cert.read())
|
||||
|
||||
self.set_certificate_req_context()
|
||||
|
||||
assert 'success' in self.certificate_load(
|
||||
assert 'success' in client.certificate_load(
|
||||
'all', 'end'
|
||||
), 'certificate chain upload'
|
||||
|
||||
chain = self.conf_get('/certificates/all/chain')
|
||||
chain = client.conf_get('/certificates/all/chain')
|
||||
assert len(chain) == chain_length - 1, 'certificate chain length'
|
||||
|
||||
self.add_tls(cert='all')
|
||||
add_tls(cert='all')
|
||||
|
||||
assert self.get_ssl()['status'] == 200, 'certificate chain long'
|
||||
assert (
|
||||
client.get_ssl(context=context_cert_req())['status'] == 200
|
||||
), 'certificate chain long'
|
||||
|
||||
def test_tls_certificate_empty_cn(self):
|
||||
self.certificate('root', False)
|
||||
|
||||
self.req(subject='/')
|
||||
def test_tls_certificate_empty_cn():
|
||||
client.certificate('root', False)
|
||||
|
||||
self.generate_ca_conf()
|
||||
self.ca()
|
||||
req(subject='/')
|
||||
|
||||
self.set_certificate_req_context()
|
||||
generate_ca_conf()
|
||||
ca()
|
||||
|
||||
assert 'success' in self.certificate_load('localhost', 'localhost')
|
||||
assert 'success' in client.certificate_load('localhost', 'localhost')
|
||||
|
||||
cert = self.conf_get('/certificates/localhost')
|
||||
cert = client.conf_get('/certificates/localhost')
|
||||
assert cert['chain'][0]['subject'] == {}, 'empty subject'
|
||||
assert cert['chain'][0]['issuer']['common_name'] == 'root', 'issuer'
|
||||
|
||||
def test_tls_certificate_empty_cn_san(self):
|
||||
self.certificate('root', False)
|
||||
|
||||
self.openssl_conf(
|
||||
def test_tls_certificate_empty_cn_san():
|
||||
client.certificate('root', False)
|
||||
|
||||
client.openssl_conf(
|
||||
rewrite=True, alt_names=["example.com", "www.example.net"]
|
||||
)
|
||||
|
||||
self.req(subject='/')
|
||||
req(subject='/')
|
||||
|
||||
self.generate_ca_conf()
|
||||
self.ca()
|
||||
generate_ca_conf()
|
||||
ca()
|
||||
|
||||
self.set_certificate_req_context()
|
||||
assert 'success' in client.certificate_load('localhost', 'localhost')
|
||||
|
||||
assert 'success' in self.certificate_load('localhost', 'localhost')
|
||||
|
||||
cert = self.conf_get('/certificates/localhost')
|
||||
cert = client.conf_get('/certificates/localhost')
|
||||
assert cert['chain'][0]['subject'] == {
|
||||
'alt_names': ['example.com', 'www.example.net']
|
||||
}, 'subject alt_names'
|
||||
assert cert['chain'][0]['issuer']['common_name'] == 'root', 'issuer'
|
||||
|
||||
def test_tls_certificate_empty_cn_san_ip(self):
|
||||
self.certificate('root', False)
|
||||
|
||||
self.openssl_conf(
|
||||
def test_tls_certificate_empty_cn_san_ip():
|
||||
client.certificate('root', False)
|
||||
|
||||
client.openssl_conf(
|
||||
rewrite=True,
|
||||
alt_names=['example.com', 'www.example.net', 'IP|10.0.0.1'],
|
||||
)
|
||||
|
||||
self.req(subject='/')
|
||||
req(subject='/')
|
||||
|
||||
self.generate_ca_conf()
|
||||
self.ca()
|
||||
generate_ca_conf()
|
||||
ca()
|
||||
|
||||
self.set_certificate_req_context()
|
||||
assert 'success' in client.certificate_load('localhost', 'localhost')
|
||||
|
||||
assert 'success' in self.certificate_load('localhost', 'localhost')
|
||||
|
||||
cert = self.conf_get('/certificates/localhost')
|
||||
cert = client.conf_get('/certificates/localhost')
|
||||
assert cert['chain'][0]['subject'] == {
|
||||
'alt_names': ['example.com', 'www.example.net']
|
||||
}, 'subject alt_names'
|
||||
assert cert['chain'][0]['issuer']['common_name'] == 'root', 'issuer'
|
||||
|
||||
def test_tls_keepalive(self):
|
||||
self.load('mirror')
|
||||
|
||||
assert self.get()['status'] == 200, 'init'
|
||||
def test_tls_keepalive():
|
||||
client.load('mirror')
|
||||
|
||||
self.certificate()
|
||||
assert client.get()['status'] == 200, 'init'
|
||||
|
||||
self.add_tls(application='mirror')
|
||||
client.certificate()
|
||||
|
||||
(resp, sock) = self.post_ssl(
|
||||
add_tls(application='mirror')
|
||||
|
||||
(resp, sock) = client.post_ssl(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Connection': 'keep-alive',
|
||||
|
@ -506,7 +524,7 @@ basicConstraints = critical,CA:TRUE"""
|
|||
|
||||
assert resp['body'] == '0123456789', 'keepalive 1'
|
||||
|
||||
resp = self.post_ssl(
|
||||
resp = client.post_ssl(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Connection': 'close',
|
||||
|
@ -517,10 +535,11 @@ basicConstraints = critical,CA:TRUE"""
|
|||
|
||||
assert resp['body'] == '0123456789', 'keepalive 2'
|
||||
|
||||
def test_tls_no_close_notify(self):
|
||||
self.certificate()
|
||||
|
||||
assert 'success' in self.conf(
|
||||
def test_tls_no_close_notify():
|
||||
client.certificate()
|
||||
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"*:7080": {
|
||||
|
@ -533,35 +552,36 @@ basicConstraints = critical,CA:TRUE"""
|
|||
}
|
||||
), 'load application configuration'
|
||||
|
||||
(_, sock) = self.get_ssl(start=True)
|
||||
(_, sock) = client.get_ssl(start=True)
|
||||
|
||||
time.sleep(5)
|
||||
|
||||
sock.close()
|
||||
|
||||
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_tls_keepalive_certificate_remove(self):
|
||||
self.load('empty')
|
||||
def test_tls_keepalive_certificate_remove():
|
||||
client.load('empty')
|
||||
|
||||
assert self.get()['status'] == 200, 'init'
|
||||
assert client.get()['status'] == 200, 'init'
|
||||
|
||||
self.certificate()
|
||||
client.certificate()
|
||||
|
||||
self.add_tls()
|
||||
add_tls()
|
||||
|
||||
(resp, sock) = self.get_ssl(
|
||||
(resp, sock) = client.get_ssl(
|
||||
headers={'Host': 'localhost', 'Connection': 'keep-alive'},
|
||||
start=True,
|
||||
read_timeout=1,
|
||||
)
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{"pass": "applications/empty"}, 'listeners/*:7080'
|
||||
)
|
||||
assert 'success' in self.conf_delete('/certificates/default')
|
||||
assert 'success' in client.conf_delete('/certificates/default')
|
||||
|
||||
try:
|
||||
resp = self.get_ssl(sock=sock)
|
||||
resp = client.get_ssl(sock=sock)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
raise
|
||||
|
@ -571,28 +591,28 @@ basicConstraints = critical,CA:TRUE"""
|
|||
|
||||
assert resp is None, 'keepalive remove certificate'
|
||||
|
||||
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_tls_certificates_remove_all(self):
|
||||
self.load('empty')
|
||||
def test_tls_certificates_remove_all():
|
||||
client.load('empty')
|
||||
|
||||
self.certificate()
|
||||
client.certificate()
|
||||
|
||||
assert 'success' in self.conf_delete(
|
||||
assert 'success' in client.conf_delete(
|
||||
'/certificates'
|
||||
), 'remove all certificates'
|
||||
|
||||
def test_tls_application_respawn(
|
||||
self, findall, skip_alert, wait_for_record
|
||||
):
|
||||
self.load('mirror')
|
||||
|
||||
self.certificate()
|
||||
def test_tls_application_respawn(findall, skip_alert, wait_for_record):
|
||||
client.load('mirror')
|
||||
|
||||
assert 'success' in self.conf('1', 'applications/mirror/processes')
|
||||
client.certificate()
|
||||
|
||||
self.add_tls(application='mirror')
|
||||
assert 'success' in client.conf('1', 'applications/mirror/processes')
|
||||
|
||||
(_, sock) = self.post_ssl(
|
||||
add_tls(application='mirror')
|
||||
|
||||
(_, sock) = client.post_ssl(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Connection': 'keep-alive',
|
||||
|
@ -608,20 +628,19 @@ basicConstraints = critical,CA:TRUE"""
|
|||
|
||||
skip_alert(fr'process {app_id} exited on signal 9')
|
||||
|
||||
wait_for_record(
|
||||
fr' (?!{app_id}#)(\d+)#\d+ "mirror" application started'
|
||||
)
|
||||
wait_for_record(fr' (?!{app_id}#)(\d+)#\d+ "mirror" application started')
|
||||
|
||||
resp = self.post_ssl(sock=sock, body='0123456789')
|
||||
resp = client.post_ssl(sock=sock, body='0123456789')
|
||||
|
||||
assert resp['status'] == 200, 'application respawn status'
|
||||
assert resp['body'] == '0123456789', 'application respawn body'
|
||||
|
||||
def test_tls_url_scheme(self):
|
||||
self.load('variables')
|
||||
|
||||
def test_tls_url_scheme():
|
||||
client.load('variables')
|
||||
|
||||
assert (
|
||||
self.post(
|
||||
client.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Content-Type': 'text/html',
|
||||
|
@ -632,12 +651,12 @@ basicConstraints = critical,CA:TRUE"""
|
|||
== 'http'
|
||||
), 'url scheme http'
|
||||
|
||||
self.certificate()
|
||||
client.certificate()
|
||||
|
||||
self.add_tls(application='variables')
|
||||
add_tls(application='variables')
|
||||
|
||||
assert (
|
||||
self.post_ssl(
|
||||
client.post_ssl(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Content-Type': 'text/html',
|
||||
|
@ -648,17 +667,18 @@ basicConstraints = critical,CA:TRUE"""
|
|||
== 'https'
|
||||
), 'url scheme https'
|
||||
|
||||
def test_tls_big_upload(self):
|
||||
self.load('upload')
|
||||
|
||||
self.certificate()
|
||||
def test_tls_big_upload():
|
||||
client.load('upload')
|
||||
|
||||
self.add_tls(application='upload')
|
||||
client.certificate()
|
||||
|
||||
add_tls(application='upload')
|
||||
|
||||
filename = 'test.txt'
|
||||
data = '0123456789' * 9000
|
||||
|
||||
res = self.post_ssl(
|
||||
res = client.post_ssl(
|
||||
body={
|
||||
'file': {
|
||||
'filename': filename,
|
||||
|
@ -670,14 +690,15 @@ basicConstraints = critical,CA:TRUE"""
|
|||
assert res['status'] == 200, 'status ok'
|
||||
assert res['body'] == f'{filename}{data}'
|
||||
|
||||
def test_tls_multi_listener(self):
|
||||
self.load('empty')
|
||||
|
||||
self.certificate()
|
||||
def test_tls_multi_listener():
|
||||
client.load('empty')
|
||||
|
||||
self.add_tls()
|
||||
self.add_tls(port=7081)
|
||||
client.certificate()
|
||||
|
||||
assert self.get_ssl()['status'] == 200, 'listener #1'
|
||||
add_tls()
|
||||
add_tls(port=7081)
|
||||
|
||||
assert self.get_ssl(port=7081)['status'] == 200, 'listener #2'
|
||||
assert client.get_ssl()['status'] == 200, 'listener #1'
|
||||
|
||||
assert client.get_ssl(port=7081)['status'] == 200, 'listener #2'
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
import ssl
|
||||
|
||||
import pytest
|
||||
from unit.applications.tls import TestApplicationTLS
|
||||
from unit.applications.tls import ApplicationTLS
|
||||
|
||||
prerequisites = {'modules': {'openssl': 'any'}}
|
||||
|
||||
client = ApplicationTLS()
|
||||
|
||||
|
||||
class TestTLSConfCommand(TestApplicationTLS):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_method_fixture(self):
|
||||
self.certificate()
|
||||
def setup_method_fixture():
|
||||
client.certificate()
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"*:7080": {
|
||||
|
@ -24,10 +25,11 @@ class TestTLSConfCommand(TestApplicationTLS):
|
|||
}
|
||||
), 'load application configuration'
|
||||
|
||||
def test_tls_conf_command(self):
|
||||
|
||||
def test_tls_conf_command():
|
||||
def check_no_connection():
|
||||
try:
|
||||
self.get_ssl()
|
||||
client.get_ssl()
|
||||
pytest.fail('Unexpected connection.')
|
||||
|
||||
except (ssl.SSLError, ConnectionRefusedError):
|
||||
|
@ -35,7 +37,7 @@ class TestTLSConfCommand(TestApplicationTLS):
|
|||
|
||||
# Set one conf_commands (disable protocol).
|
||||
|
||||
(_, sock) = self.get_ssl(start=True)
|
||||
(_, sock) = client.get_ssl(start=True)
|
||||
|
||||
shared_ciphers = sock.shared_ciphers()
|
||||
protocols = list(set(c[1] for c in shared_ciphers))
|
||||
|
@ -44,7 +46,7 @@ class TestTLSConfCommand(TestApplicationTLS):
|
|||
if '/' in protocol:
|
||||
pytest.skip('Complex protocol format.')
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"certificate": "default",
|
||||
"conf_commands": {"protocol": f'-{protocol}'},
|
||||
|
@ -55,7 +57,7 @@ class TestTLSConfCommand(TestApplicationTLS):
|
|||
sock.close()
|
||||
|
||||
if len(protocols) > 1:
|
||||
(_, sock) = self.get_ssl(start=True)
|
||||
(_, sock) = client.get_ssl(start=True)
|
||||
|
||||
cipher = sock.cipher()
|
||||
assert cipher[1] != protocol, 'new protocol used'
|
||||
|
@ -70,7 +72,7 @@ class TestTLSConfCommand(TestApplicationTLS):
|
|||
|
||||
# Set two conf_commands (disable protocol and cipher).
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"certificate": "default",
|
||||
"conf_commands": {
|
||||
|
@ -82,7 +84,7 @@ class TestTLSConfCommand(TestApplicationTLS):
|
|||
), 'cipher disabled'
|
||||
|
||||
if len(ciphers) > 1:
|
||||
(_, sock) = self.get_ssl(start=True)
|
||||
(_, sock) = client.get_ssl(start=True)
|
||||
|
||||
cipher_new = sock.cipher()
|
||||
assert cipher_new[1] == cipher[1], 'previous protocol used'
|
||||
|
@ -93,11 +95,12 @@ class TestTLSConfCommand(TestApplicationTLS):
|
|||
else:
|
||||
check_no_connection()
|
||||
|
||||
def test_tls_conf_command_invalid(self, skip_alert):
|
||||
|
||||
def test_tls_conf_command_invalid(skip_alert):
|
||||
skip_alert(r'SSL_CONF_cmd', r'failed to apply new conf')
|
||||
|
||||
def check_conf_commands(conf_commands):
|
||||
assert 'error' in self.conf(
|
||||
assert 'error' in client.conf(
|
||||
{"certificate": "default", "conf_commands": conf_commands},
|
||||
'listeners/*:7080/tls',
|
||||
), 'ivalid conf_commands'
|
||||
|
|
|
@ -12,17 +12,18 @@ from OpenSSL.SSL import (
|
|||
Connection,
|
||||
_lib,
|
||||
)
|
||||
from unit.applications.tls import TestApplicationTLS
|
||||
from unit.applications.tls import ApplicationTLS
|
||||
|
||||
prerequisites = {'modules': {'openssl': 'any'}}
|
||||
|
||||
client = ApplicationTLS()
|
||||
|
||||
|
||||
class TestTLSSession(TestApplicationTLS):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_method_fixture(self):
|
||||
self.certificate()
|
||||
def setup_method_fixture():
|
||||
client.certificate()
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"*:7080": {
|
||||
|
@ -35,7 +36,8 @@ class TestTLSSession(TestApplicationTLS):
|
|||
}
|
||||
), 'load application configuration'
|
||||
|
||||
def add_session(self, cache_size=None, timeout=None):
|
||||
|
||||
def add_session(cache_size=None, timeout=None):
|
||||
session = {}
|
||||
|
||||
if cache_size is not None:
|
||||
|
@ -43,9 +45,10 @@ class TestTLSSession(TestApplicationTLS):
|
|||
if timeout is not None:
|
||||
session['timeout'] = timeout
|
||||
|
||||
return self.conf(session, 'listeners/*:7080/tls/session')
|
||||
return client.conf(session, 'listeners/*:7080/tls/session')
|
||||
|
||||
def connect(self, ctx=None, session=None):
|
||||
|
||||
def connect(ctx=None, session=None):
|
||||
sock = socket.create_connection(('127.0.0.1', 7080))
|
||||
|
||||
if ctx is None:
|
||||
|
@ -53,74 +56,77 @@ class TestTLSSession(TestApplicationTLS):
|
|||
ctx.set_session_cache_mode(SESS_CACHE_CLIENT)
|
||||
ctx.set_options(OP_NO_TICKET)
|
||||
|
||||
client = Connection(ctx, sock)
|
||||
client.set_connect_state()
|
||||
conn = Connection(ctx, sock)
|
||||
conn.set_connect_state()
|
||||
|
||||
if session is not None:
|
||||
client.set_session(session)
|
||||
conn.set_session(session)
|
||||
|
||||
client.do_handshake()
|
||||
client.shutdown()
|
||||
conn.do_handshake()
|
||||
conn.shutdown()
|
||||
|
||||
return (
|
||||
client,
|
||||
client.get_session(),
|
||||
conn,
|
||||
conn.get_session(),
|
||||
ctx,
|
||||
_lib.SSL_session_reused(client._ssl),
|
||||
_lib.SSL_session_reused(conn._ssl),
|
||||
)
|
||||
|
||||
def test_tls_session(self):
|
||||
_, sess, ctx, reused = self.connect()
|
||||
|
||||
def test_tls_session():
|
||||
_, sess, ctx, reused = connect()
|
||||
assert not reused, 'new connection'
|
||||
|
||||
_, _, _, reused = self.connect(ctx, sess)
|
||||
_, _, _, reused = connect(ctx, sess)
|
||||
assert not reused, 'no cache'
|
||||
|
||||
assert 'success' in self.add_session(cache_size=2)
|
||||
assert 'success' in add_session(cache_size=2)
|
||||
|
||||
_, sess, ctx, reused = self.connect()
|
||||
_, sess, ctx, reused = connect()
|
||||
assert not reused, 'new connection cache'
|
||||
|
||||
_, _, _, reused = self.connect(ctx, sess)
|
||||
_, _, _, reused = connect(ctx, sess)
|
||||
assert reused, 'cache'
|
||||
|
||||
_, _, _, reused = self.connect(ctx, sess)
|
||||
_, _, _, reused = connect(ctx, sess)
|
||||
assert reused, 'cache 2'
|
||||
|
||||
# check that at least one session of four is not reused
|
||||
|
||||
clients = [self.connect() for _ in range(4)]
|
||||
assert True not in [c[-1] for c in clients], 'cache small all new'
|
||||
conns = [connect() for _ in range(4)]
|
||||
assert True not in [c[-1] for c in conns], 'cache small all new'
|
||||
|
||||
clients_again = [self.connect(c[2], c[1]) for c in clients]
|
||||
assert False in [c[-1] for c in clients_again], 'cache small no reuse'
|
||||
conns_again = [connect(c[2], c[1]) for c in conns]
|
||||
assert False in [c[-1] for c in conns_again], 'cache small no reuse'
|
||||
|
||||
# all four sessions are reused
|
||||
|
||||
assert 'success' in self.add_session(cache_size=8)
|
||||
assert 'success' in add_session(cache_size=8)
|
||||
|
||||
clients = [self.connect() for _ in range(4)]
|
||||
assert True not in [c[-1] for c in clients], 'cache big all new'
|
||||
conns = [connect() for _ in range(4)]
|
||||
assert True not in [c[-1] for c in conns], 'cache big all new'
|
||||
|
||||
clients_again = [self.connect(c[2], c[1]) for c in clients]
|
||||
assert False not in [c[-1] for c in clients_again], 'cache big reuse'
|
||||
conns_again = [connect(c[2], c[1]) for c in conns]
|
||||
assert False not in [c[-1] for c in conns_again], 'cache big reuse'
|
||||
|
||||
def test_tls_session_timeout(self):
|
||||
assert 'success' in self.add_session(cache_size=5, timeout=1)
|
||||
|
||||
_, sess, ctx, reused = self.connect()
|
||||
def test_tls_session_timeout():
|
||||
assert 'success' in add_session(cache_size=5, timeout=1)
|
||||
|
||||
_, sess, ctx, reused = connect()
|
||||
assert not reused, 'new connection'
|
||||
|
||||
_, _, _, reused = self.connect(ctx, sess)
|
||||
_, _, _, reused = connect(ctx, sess)
|
||||
assert reused, 'no timeout'
|
||||
|
||||
time.sleep(3)
|
||||
|
||||
_, _, _, reused = self.connect(ctx, sess)
|
||||
_, _, _, reused = connect(ctx, sess)
|
||||
assert not reused, 'timeout'
|
||||
|
||||
def test_tls_session_invalid(self):
|
||||
assert 'error' in self.add_session(cache_size=-1)
|
||||
assert 'error' in self.add_session(cache_size={})
|
||||
assert 'error' in self.add_session(timeout=-1)
|
||||
assert 'error' in self.add_session(timeout={})
|
||||
|
||||
def test_tls_session_invalid():
|
||||
assert 'error' in add_session(cache_size=-1)
|
||||
assert 'error' in add_session(cache_size={})
|
||||
assert 'error' in add_session(timeout=-1)
|
||||
assert 'error' in add_session(timeout={})
|
||||
|
|
|
@ -2,16 +2,17 @@ import ssl
|
|||
import subprocess
|
||||
|
||||
import pytest
|
||||
from unit.applications.tls import TestApplicationTLS
|
||||
from unit.applications.tls import ApplicationTLS
|
||||
from unit.option import option
|
||||
|
||||
prerequisites = {'modules': {'openssl': 'any'}}
|
||||
|
||||
client = ApplicationTLS()
|
||||
|
||||
|
||||
class TestTLSSNI(TestApplicationTLS):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_method_fixture(self):
|
||||
self._load_conf(
|
||||
def setup_method_fixture():
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "routes"}},
|
||||
"routes": [{"action": {"return": 200}}],
|
||||
|
@ -19,16 +20,90 @@ class TestTLSSNI(TestApplicationTLS):
|
|||
}
|
||||
)
|
||||
|
||||
def add_tls(self, cert='default'):
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def add_tls(cert='default'):
|
||||
assert 'success' in client.conf(
|
||||
{"pass": "routes", "tls": {"certificate": cert}},
|
||||
'listeners/*:7080',
|
||||
)
|
||||
|
||||
def remove_tls(self):
|
||||
assert 'success' in self.conf({"pass": "routes"}, 'listeners/*:7080')
|
||||
|
||||
def generate_ca_conf(self):
|
||||
def check_cert(host, expect, ctx):
|
||||
resp, sock = client.get_ssl(
|
||||
headers={
|
||||
'Host': host,
|
||||
'Content-Length': '0',
|
||||
'Connection': 'close',
|
||||
},
|
||||
start=True,
|
||||
context=ctx,
|
||||
)
|
||||
|
||||
assert resp['status'] == 200
|
||||
assert sock.getpeercert()['subject'][0][0][1] == expect
|
||||
|
||||
|
||||
def config_bundles(bundles):
|
||||
client.certificate('root', False)
|
||||
|
||||
for b in bundles:
|
||||
client.openssl_conf(rewrite=True, alt_names=bundles[b]['alt_names'])
|
||||
subj = f'/CN={bundles[b]["subj"]}/' if 'subj' in bundles[b] else '/'
|
||||
|
||||
subprocess.check_output(
|
||||
[
|
||||
'openssl',
|
||||
'req',
|
||||
'-new',
|
||||
'-subj',
|
||||
subj,
|
||||
'-config',
|
||||
f'{option.temp_dir}/openssl.conf',
|
||||
'-out',
|
||||
f'{option.temp_dir}/{b}.csr',
|
||||
'-keyout',
|
||||
f'{option.temp_dir}/{b}.key',
|
||||
],
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
|
||||
generate_ca_conf()
|
||||
|
||||
for b in bundles:
|
||||
subj = f'/CN={bundles[b]["subj"]}/' if 'subj' in bundles[b] else '/'
|
||||
|
||||
subprocess.check_output(
|
||||
[
|
||||
'openssl',
|
||||
'ca',
|
||||
'-batch',
|
||||
'-subj',
|
||||
subj,
|
||||
'-config',
|
||||
f'{option.temp_dir}/ca.conf',
|
||||
'-keyfile',
|
||||
f'{option.temp_dir}/root.key',
|
||||
'-cert',
|
||||
f'{option.temp_dir}/root.crt',
|
||||
'-in',
|
||||
f'{option.temp_dir}/{b}.csr',
|
||||
'-out',
|
||||
f'{option.temp_dir}/{b}.crt',
|
||||
],
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
|
||||
load_certs(bundles)
|
||||
|
||||
context = ssl.create_default_context()
|
||||
context.check_hostname = False
|
||||
context.verify_mode = ssl.CERT_REQUIRED
|
||||
context.load_verify_locations(f'{option.temp_dir}/root.crt')
|
||||
|
||||
return context
|
||||
|
||||
|
||||
def generate_ca_conf():
|
||||
with open(f'{option.temp_dir}/ca.conf', 'w') as f:
|
||||
f.write(
|
||||
f"""[ ca ]
|
||||
|
@ -57,83 +132,19 @@ basicConstraints = critical,CA:TRUE"""
|
|||
with open(f'{option.temp_dir}/certindex', 'w') as f:
|
||||
f.write('')
|
||||
|
||||
def config_bundles(self, bundles):
|
||||
self.certificate('root', False)
|
||||
|
||||
for b in bundles:
|
||||
self.openssl_conf(rewrite=True, alt_names=bundles[b]['alt_names'])
|
||||
subj = f'/CN={bundles[b]["subj"]}/' if 'subj' in bundles[b] else '/'
|
||||
|
||||
subprocess.check_output(
|
||||
[
|
||||
'openssl',
|
||||
'req',
|
||||
'-new',
|
||||
'-subj',
|
||||
subj,
|
||||
'-config',
|
||||
f'{option.temp_dir}/openssl.conf',
|
||||
'-out',
|
||||
f'{option.temp_dir}/{b}.csr',
|
||||
'-keyout',
|
||||
f'{option.temp_dir}/{b}.key',
|
||||
],
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
|
||||
self.generate_ca_conf()
|
||||
|
||||
for b in bundles:
|
||||
subj = f'/CN={bundles[b]["subj"]}/' if 'subj' in bundles[b] else '/'
|
||||
|
||||
subprocess.check_output(
|
||||
[
|
||||
'openssl',
|
||||
'ca',
|
||||
'-batch',
|
||||
'-subj',
|
||||
subj,
|
||||
'-config',
|
||||
f'{option.temp_dir}/ca.conf',
|
||||
'-keyfile',
|
||||
f'{option.temp_dir}/root.key',
|
||||
'-cert',
|
||||
f'{option.temp_dir}/root.crt',
|
||||
'-in',
|
||||
f'{option.temp_dir}/{b}.csr',
|
||||
'-out',
|
||||
f'{option.temp_dir}/{b}.crt',
|
||||
],
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
|
||||
self.context = ssl.create_default_context()
|
||||
self.context.check_hostname = False
|
||||
self.context.verify_mode = ssl.CERT_REQUIRED
|
||||
self.context.load_verify_locations(f'{option.temp_dir}/root.crt')
|
||||
|
||||
self.load_certs(bundles)
|
||||
|
||||
def load_certs(self, bundles):
|
||||
def load_certs(bundles):
|
||||
for bname, bvalue in bundles.items():
|
||||
assert 'success' in self.certificate_load(
|
||||
assert 'success' in client.certificate_load(
|
||||
bname, bname
|
||||
), f'certificate {bvalue["subj"]} upload'
|
||||
|
||||
def check_cert(self, host, expect):
|
||||
resp, sock = self.get_ssl(
|
||||
headers={
|
||||
'Host': host,
|
||||
'Content-Length': '0',
|
||||
'Connection': 'close',
|
||||
},
|
||||
start=True,
|
||||
)
|
||||
|
||||
assert resp['status'] == 200
|
||||
assert sock.getpeercert()['subject'][0][0][1] == expect
|
||||
def remove_tls():
|
||||
assert 'success' in client.conf({"pass": "routes"}, 'listeners/*:7080')
|
||||
|
||||
def test_tls_sni(self):
|
||||
|
||||
def test_tls_sni():
|
||||
bundles = {
|
||||
"default": {"subj": "default", "alt_names": ["default"]},
|
||||
"localhost.com": {
|
||||
|
@ -145,14 +156,15 @@ basicConstraints = critical,CA:TRUE"""
|
|||
"alt_names": ["alt1.example.com", "alt2.example.com"],
|
||||
},
|
||||
}
|
||||
self.config_bundles(bundles)
|
||||
self.add_tls(["default", "localhost.com", "example.com"])
|
||||
ctx = config_bundles(bundles)
|
||||
add_tls(["default", "localhost.com", "example.com"])
|
||||
|
||||
self.check_cert('alt1.localhost.com', bundles['localhost.com']['subj'])
|
||||
self.check_cert('alt2.example.com', bundles['example.com']['subj'])
|
||||
self.check_cert('blah', bundles['default']['subj'])
|
||||
check_cert('alt1.localhost.com', bundles['localhost.com']['subj'], ctx)
|
||||
check_cert('alt2.example.com', bundles['example.com']['subj'], ctx)
|
||||
check_cert('blah', bundles['default']['subj'], ctx)
|
||||
|
||||
def test_tls_sni_no_hostname(self):
|
||||
|
||||
def test_tls_sni_no_hostname():
|
||||
bundles = {
|
||||
"localhost.com": {"subj": "localhost.com", "alt_names": []},
|
||||
"example.com": {
|
||||
|
@ -160,12 +172,13 @@ basicConstraints = critical,CA:TRUE"""
|
|||
"alt_names": ["example.com"],
|
||||
},
|
||||
}
|
||||
self.config_bundles(bundles)
|
||||
self.add_tls(["localhost.com", "example.com"])
|
||||
ctx = config_bundles(bundles)
|
||||
add_tls(["localhost.com", "example.com"])
|
||||
|
||||
resp, sock = self.get_ssl(
|
||||
resp, sock = client.get_ssl(
|
||||
headers={'Content-Length': '0', 'Connection': 'close'},
|
||||
start=True,
|
||||
context=ctx,
|
||||
)
|
||||
assert resp['status'] == 200
|
||||
assert (
|
||||
|
@ -173,7 +186,8 @@ basicConstraints = critical,CA:TRUE"""
|
|||
== bundles['localhost.com']['subj']
|
||||
)
|
||||
|
||||
def test_tls_sni_upper_case(self):
|
||||
|
||||
def test_tls_sni_upper_case():
|
||||
bundles = {
|
||||
"localhost.com": {"subj": "LOCALHOST.COM", "alt_names": []},
|
||||
"example.com": {
|
||||
|
@ -181,29 +195,31 @@ basicConstraints = critical,CA:TRUE"""
|
|||
"alt_names": ["ALT1.EXAMPLE.COM", "*.ALT2.EXAMPLE.COM"],
|
||||
},
|
||||
}
|
||||
self.config_bundles(bundles)
|
||||
self.add_tls(["localhost.com", "example.com"])
|
||||
ctx = config_bundles(bundles)
|
||||
add_tls(["localhost.com", "example.com"])
|
||||
|
||||
self.check_cert('localhost.com', bundles['localhost.com']['subj'])
|
||||
self.check_cert('LOCALHOST.COM', bundles['localhost.com']['subj'])
|
||||
self.check_cert('EXAMPLE.COM', bundles['localhost.com']['subj'])
|
||||
self.check_cert('ALT1.EXAMPLE.COM', bundles['example.com']['subj'])
|
||||
self.check_cert('WWW.ALT2.EXAMPLE.COM', bundles['example.com']['subj'])
|
||||
check_cert('localhost.com', bundles['localhost.com']['subj'], ctx)
|
||||
check_cert('LOCALHOST.COM', bundles['localhost.com']['subj'], ctx)
|
||||
check_cert('EXAMPLE.COM', bundles['localhost.com']['subj'], ctx)
|
||||
check_cert('ALT1.EXAMPLE.COM', bundles['example.com']['subj'], ctx)
|
||||
check_cert('WWW.ALT2.EXAMPLE.COM', bundles['example.com']['subj'], ctx)
|
||||
|
||||
def test_tls_sni_only_bundle(self):
|
||||
|
||||
def test_tls_sni_only_bundle():
|
||||
bundles = {
|
||||
"localhost.com": {
|
||||
"subj": "localhost.com",
|
||||
"alt_names": ["alt1.localhost.com", "alt2.localhost.com"],
|
||||
}
|
||||
}
|
||||
self.config_bundles(bundles)
|
||||
self.add_tls(["localhost.com"])
|
||||
ctx = config_bundles(bundles)
|
||||
add_tls(["localhost.com"])
|
||||
|
||||
self.check_cert('domain.com', bundles['localhost.com']['subj'])
|
||||
self.check_cert('alt1.domain.com', bundles['localhost.com']['subj'])
|
||||
check_cert('domain.com', bundles['localhost.com']['subj'], ctx)
|
||||
check_cert('alt1.domain.com', bundles['localhost.com']['subj'], ctx)
|
||||
|
||||
def test_tls_sni_wildcard(self):
|
||||
|
||||
def test_tls_sni_wildcard():
|
||||
bundles = {
|
||||
"localhost.com": {"subj": "localhost.com", "alt_names": []},
|
||||
"example.com": {
|
||||
|
@ -211,62 +227,67 @@ basicConstraints = critical,CA:TRUE"""
|
|||
"alt_names": ["*.example.com", "*.alt.example.com"],
|
||||
},
|
||||
}
|
||||
self.config_bundles(bundles)
|
||||
self.add_tls(["localhost.com", "example.com"])
|
||||
ctx = config_bundles(bundles)
|
||||
add_tls(["localhost.com", "example.com"])
|
||||
|
||||
self.check_cert('example.com', bundles['localhost.com']['subj'])
|
||||
self.check_cert('www.example.com', bundles['example.com']['subj'])
|
||||
self.check_cert('alt.example.com', bundles['example.com']['subj'])
|
||||
self.check_cert('www.alt.example.com', bundles['example.com']['subj'])
|
||||
self.check_cert('www.alt.example.ru', bundles['localhost.com']['subj'])
|
||||
check_cert('example.com', bundles['localhost.com']['subj'], ctx)
|
||||
check_cert('www.example.com', bundles['example.com']['subj'], ctx)
|
||||
check_cert('alt.example.com', bundles['example.com']['subj'], ctx)
|
||||
check_cert('www.alt.example.com', bundles['example.com']['subj'], ctx)
|
||||
check_cert('www.alt.example.ru', bundles['localhost.com']['subj'], ctx)
|
||||
|
||||
def test_tls_sni_duplicated_bundle(self):
|
||||
|
||||
def test_tls_sni_duplicated_bundle():
|
||||
bundles = {
|
||||
"localhost.com": {
|
||||
"subj": "localhost.com",
|
||||
"alt_names": ["localhost.com", "alt2.localhost.com"],
|
||||
}
|
||||
}
|
||||
self.config_bundles(bundles)
|
||||
self.add_tls(["localhost.com", "localhost.com"])
|
||||
ctx = config_bundles(bundles)
|
||||
add_tls(["localhost.com", "localhost.com"])
|
||||
|
||||
self.check_cert('localhost.com', bundles['localhost.com']['subj'])
|
||||
self.check_cert('alt2.localhost.com', bundles['localhost.com']['subj'])
|
||||
check_cert('localhost.com', bundles['localhost.com']['subj'], ctx)
|
||||
check_cert('alt2.localhost.com', bundles['localhost.com']['subj'], ctx)
|
||||
|
||||
def test_tls_sni_same_alt(self):
|
||||
|
||||
def test_tls_sni_same_alt():
|
||||
bundles = {
|
||||
"localhost": {"subj": "subj1", "alt_names": "same.altname.com"},
|
||||
"example": {"subj": "subj2", "alt_names": "same.altname.com"},
|
||||
}
|
||||
self.config_bundles(bundles)
|
||||
self.add_tls(["localhost", "example"])
|
||||
ctx = config_bundles(bundles)
|
||||
add_tls(["localhost", "example"])
|
||||
|
||||
self.check_cert('localhost', bundles['localhost']['subj'])
|
||||
self.check_cert('example', bundles['localhost']['subj'])
|
||||
check_cert('localhost', bundles['localhost']['subj'], ctx)
|
||||
check_cert('example', bundles['localhost']['subj'], ctx)
|
||||
|
||||
def test_tls_sni_empty_cn(self):
|
||||
|
||||
def test_tls_sni_empty_cn():
|
||||
bundles = {"localhost": {"alt_names": ["alt.localhost.com"]}}
|
||||
self.config_bundles(bundles)
|
||||
self.add_tls(["localhost"])
|
||||
ctx = config_bundles(bundles)
|
||||
add_tls(["localhost"])
|
||||
|
||||
resp, sock = self.get_ssl(
|
||||
resp, sock = client.get_ssl(
|
||||
headers={
|
||||
'Host': 'domain.com',
|
||||
'Content-Length': '0',
|
||||
'Connection': 'close',
|
||||
},
|
||||
start=True,
|
||||
context=ctx,
|
||||
)
|
||||
|
||||
assert resp['status'] == 200
|
||||
assert sock.getpeercert()['subjectAltName'][0][1] == 'alt.localhost.com'
|
||||
|
||||
def test_tls_sni_invalid(self):
|
||||
self.config_bundles({"localhost": {"subj": "subj1", "alt_names": ''}})
|
||||
self.add_tls(["localhost"])
|
||||
|
||||
def test_tls_sni_invalid():
|
||||
_ = config_bundles({"localhost": {"subj": "subj1", "alt_names": ''}})
|
||||
add_tls(["localhost"])
|
||||
|
||||
def check_certificate(cert):
|
||||
assert 'error' in self.conf(
|
||||
assert 'error' in client.conf(
|
||||
{"pass": "routes", "tls": {"certificate": cert}},
|
||||
'listeners/*:7080',
|
||||
)
|
||||
|
|
|
@ -9,20 +9,21 @@ from OpenSSL.SSL import (
|
|||
Connection,
|
||||
_lib,
|
||||
)
|
||||
from unit.applications.tls import TestApplicationTLS
|
||||
from unit.applications.tls import ApplicationTLS
|
||||
|
||||
prerequisites = {'modules': {'openssl': 'any'}}
|
||||
|
||||
client = ApplicationTLS()
|
||||
|
||||
class TestTLSTicket(TestApplicationTLS):
|
||||
ticket = 'U1oDTh11mMxODuw12gS0EXX1E/PkZG13cJNQ6m5+6BGlfPTjNlIEw7PSVU3X1gTE'
|
||||
ticket2 = '5AV0DSYIYbZWZQB7fCnTHZmMxtotb/aXjam+n2XS79lTvX3Tq9xGqpC8XKNEF2lt'
|
||||
ticket80 = '6Pfil8lv/k8zf8MndPpfXaO5EAV6dhME6zs6CfUyq2yziynQwSywtKQMqHGnJ2HR\
|
||||
TICKET = 'U1oDTh11mMxODuw12gS0EXX1E/PkZG13cJNQ6m5+6BGlfPTjNlIEw7PSVU3X1gTE'
|
||||
TICKET2 = '5AV0DSYIYbZWZQB7fCnTHZmMxtotb/aXjam+n2XS79lTvX3Tq9xGqpC8XKNEF2lt'
|
||||
TICKET80 = '6Pfil8lv/k8zf8MndPpfXaO5EAV6dhME6zs6CfUyq2yziynQwSywtKQMqHGnJ2HR\
|
||||
49TZXi/Y4/8RSIO7QPsU51/HLR1gWIMhVM2m9yh93Bw='
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_method_fixture(self):
|
||||
self.certificate()
|
||||
def setup_method_fixture():
|
||||
client.certificate()
|
||||
|
||||
listener_conf = {
|
||||
"pass": "routes",
|
||||
|
@ -32,7 +33,7 @@ class TestTLSTicket(TestApplicationTLS):
|
|||
},
|
||||
}
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"*:7080": listener_conf,
|
||||
|
@ -44,151 +45,158 @@ class TestTLSTicket(TestApplicationTLS):
|
|||
}
|
||||
), 'load application configuration'
|
||||
|
||||
def set_tickets(self, tickets=True, port=7080):
|
||||
assert 'success' in self.conf(
|
||||
{"cache_size": 0, "tickets": tickets},
|
||||
f'listeners/*:{port}/tls/session',
|
||||
)
|
||||
|
||||
def connect(self, ctx=None, session=None, port=7080):
|
||||
def connect(ctx=None, session=None, port=7080):
|
||||
sock = socket.create_connection(('127.0.0.1', port))
|
||||
|
||||
if ctx is None:
|
||||
ctx = Context(TLSv1_2_METHOD)
|
||||
|
||||
client = Connection(ctx, sock)
|
||||
client.set_connect_state()
|
||||
conn = Connection(ctx, sock)
|
||||
conn.set_connect_state()
|
||||
|
||||
if session is not None:
|
||||
client.set_session(session)
|
||||
conn.set_session(session)
|
||||
|
||||
client.do_handshake()
|
||||
client.shutdown()
|
||||
conn.do_handshake()
|
||||
conn.shutdown()
|
||||
|
||||
return (
|
||||
client.get_session(),
|
||||
conn.get_session(),
|
||||
ctx,
|
||||
_lib.SSL_session_reused(client._ssl),
|
||||
_lib.SSL_session_reused(conn._ssl),
|
||||
)
|
||||
|
||||
def has_ticket(self, sess):
|
||||
|
||||
def has_ticket(sess):
|
||||
return _lib.SSL_SESSION_has_ticket(sess._session)
|
||||
|
||||
|
||||
def set_tickets(tickets=True, port=7080):
|
||||
assert 'success' in client.conf(
|
||||
{"cache_size": 0, "tickets": tickets},
|
||||
f'listeners/*:{port}/tls/session',
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
not hasattr(_lib, 'SSL_SESSION_has_ticket'),
|
||||
reason='ticket check is not supported',
|
||||
)
|
||||
def test_tls_ticket(self):
|
||||
sess, ctx, reused = self.connect()
|
||||
assert self.has_ticket(sess), 'tickets True'
|
||||
def test_tls_ticket():
|
||||
sess, ctx, reused = connect()
|
||||
assert has_ticket(sess), 'tickets True'
|
||||
assert not reused, 'tickets True not reused'
|
||||
|
||||
sess, ctx, reused = self.connect(ctx, sess)
|
||||
assert self.has_ticket(sess), 'tickets True reconnect'
|
||||
sess, ctx, reused = connect(ctx, sess)
|
||||
assert has_ticket(sess), 'tickets True reconnect'
|
||||
assert reused, 'tickets True reused'
|
||||
|
||||
self.set_tickets(tickets=False)
|
||||
set_tickets(tickets=False)
|
||||
|
||||
sess, _, _ = self.connect()
|
||||
assert not self.has_ticket(sess), 'tickets False'
|
||||
sess, _, _ = connect()
|
||||
assert not has_ticket(sess), 'tickets False'
|
||||
|
||||
assert 'success' in self.conf_delete(
|
||||
assert 'success' in client.conf_delete(
|
||||
'listeners/*:7080/tls/session/tickets'
|
||||
), 'tickets default configure'
|
||||
|
||||
sess, _, _ = self.connect()
|
||||
assert not self.has_ticket(sess), 'tickets default (false)'
|
||||
sess, _, _ = connect()
|
||||
assert not has_ticket(sess), 'tickets default (false)'
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
not hasattr(_lib, 'SSL_SESSION_has_ticket'),
|
||||
reason='ticket check is not supported',
|
||||
)
|
||||
def test_tls_ticket_string(self):
|
||||
self.set_tickets(self.ticket)
|
||||
sess, ctx, _ = self.connect()
|
||||
assert self.has_ticket(sess), 'tickets string'
|
||||
def test_tls_ticket_string():
|
||||
set_tickets(TICKET)
|
||||
sess, ctx, _ = connect()
|
||||
assert has_ticket(sess), 'tickets string'
|
||||
|
||||
sess2, _, reused = self.connect(ctx, sess)
|
||||
assert self.has_ticket(sess2), 'tickets string reconnect'
|
||||
sess2, _, reused = connect(ctx, sess)
|
||||
assert has_ticket(sess2), 'tickets string reconnect'
|
||||
assert reused, 'tickets string reused'
|
||||
|
||||
sess2, _, reused = self.connect(ctx, sess, port=7081)
|
||||
assert self.has_ticket(sess2), 'connect True'
|
||||
sess2, _, reused = connect(ctx, sess, port=7081)
|
||||
assert has_ticket(sess2), 'connect True'
|
||||
assert not reused, 'connect True not reused'
|
||||
|
||||
self.set_tickets(self.ticket2, port=7081)
|
||||
set_tickets(TICKET2, port=7081)
|
||||
|
||||
sess2, _, reused = self.connect(ctx, sess, port=7081)
|
||||
assert self.has_ticket(sess2), 'wrong ticket'
|
||||
sess2, _, reused = connect(ctx, sess, port=7081)
|
||||
assert has_ticket(sess2), 'wrong ticket'
|
||||
assert not reused, 'wrong ticket not reused'
|
||||
|
||||
self.set_tickets(self.ticket80)
|
||||
set_tickets(TICKET80)
|
||||
|
||||
sess, ctx, _ = self.connect()
|
||||
assert self.has_ticket(sess), 'tickets string 80'
|
||||
sess, ctx, _ = connect()
|
||||
assert has_ticket(sess), 'tickets string 80'
|
||||
|
||||
sess2, _, reused = self.connect(ctx, sess)
|
||||
assert self.has_ticket(sess2), 'tickets string 80 reconnect'
|
||||
sess2, _, reused = connect(ctx, sess)
|
||||
assert has_ticket(sess2), 'tickets string 80 reconnect'
|
||||
assert reused, 'tickets string 80 reused'
|
||||
|
||||
sess2, _, reused = self.connect(ctx, sess, port=7081)
|
||||
assert self.has_ticket(sess2), 'wrong ticket 80'
|
||||
sess2, _, reused = connect(ctx, sess, port=7081)
|
||||
assert has_ticket(sess2), 'wrong ticket 80'
|
||||
assert not reused, 'wrong ticket 80 not reused'
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
not hasattr(_lib, 'SSL_SESSION_has_ticket'),
|
||||
reason='ticket check is not supported',
|
||||
)
|
||||
def test_tls_ticket_array(self):
|
||||
self.set_tickets([])
|
||||
def test_tls_ticket_array():
|
||||
set_tickets([])
|
||||
|
||||
sess, ctx, _ = self.connect()
|
||||
assert not self.has_ticket(sess), 'tickets array empty'
|
||||
sess, ctx, _ = connect()
|
||||
assert not has_ticket(sess), 'tickets array empty'
|
||||
|
||||
self.set_tickets([self.ticket, self.ticket2])
|
||||
self.set_tickets(self.ticket, port=7081)
|
||||
self.set_tickets(self.ticket2, port=7082)
|
||||
set_tickets([TICKET, TICKET2])
|
||||
set_tickets(TICKET, port=7081)
|
||||
set_tickets(TICKET2, port=7082)
|
||||
|
||||
sess, ctx, _ = self.connect()
|
||||
_, _, reused = self.connect(ctx, sess, port=7081)
|
||||
sess, ctx, _ = connect()
|
||||
_, _, reused = connect(ctx, sess, port=7081)
|
||||
assert not reused, 'not last ticket'
|
||||
_, _, reused = self.connect(ctx, sess, port=7082)
|
||||
_, _, reused = connect(ctx, sess, port=7082)
|
||||
assert reused, 'last ticket'
|
||||
|
||||
sess, ctx, _ = self.connect(port=7081)
|
||||
_, _, reused = self.connect(ctx, sess)
|
||||
sess, ctx, _ = connect(port=7081)
|
||||
_, _, reused = connect(ctx, sess)
|
||||
assert reused, 'first ticket'
|
||||
|
||||
sess, ctx, _ = self.connect(port=7082)
|
||||
_, _, reused = self.connect(ctx, sess)
|
||||
sess, ctx, _ = connect(port=7082)
|
||||
_, _, reused = connect(ctx, sess)
|
||||
assert reused, 'second ticket'
|
||||
|
||||
assert 'success' in self.conf_delete(
|
||||
assert 'success' in client.conf_delete(
|
||||
'listeners/*:7080/tls/session/tickets/0'
|
||||
), 'removed first ticket'
|
||||
assert 'success' in self.conf_post(
|
||||
f'"{self.ticket}"', 'listeners/*:7080/tls/session/tickets'
|
||||
assert 'success' in client.conf_post(
|
||||
f'"{TICKET}"', 'listeners/*:7080/tls/session/tickets'
|
||||
), 'add new ticket to the end of array'
|
||||
|
||||
sess, ctx, _ = self.connect()
|
||||
_, _, reused = self.connect(ctx, sess, port=7082)
|
||||
sess, ctx, _ = connect()
|
||||
_, _, reused = connect(ctx, sess, port=7082)
|
||||
assert not reused, 'not last ticket 2'
|
||||
_, _, reused = self.connect(ctx, sess, port=7081)
|
||||
_, _, reused = connect(ctx, sess, port=7081)
|
||||
assert reused, 'last ticket 2'
|
||||
|
||||
def test_tls_ticket_invalid(self):
|
||||
|
||||
def test_tls_ticket_invalid():
|
||||
def check_tickets(tickets):
|
||||
assert 'error' in self.conf(
|
||||
assert 'error' in client.conf(
|
||||
{"tickets": tickets},
|
||||
'listeners/*:7080/tls/session',
|
||||
)
|
||||
|
||||
check_tickets({})
|
||||
check_tickets('!?&^' * 16)
|
||||
check_tickets(f'{self.ticket[:-2]}!{self.ticket[3:]}')
|
||||
check_tickets(self.ticket[:-1])
|
||||
check_tickets(f'{self.ticket}b')
|
||||
check_tickets(f'{self.ticket}blah')
|
||||
check_tickets([True, self.ticket, self.ticket2])
|
||||
check_tickets([self.ticket, 'blah', self.ticket2])
|
||||
check_tickets([self.ticket, self.ticket2, []])
|
||||
check_tickets(f'{TICKET[:-2]}!{TICKET[3:]}')
|
||||
check_tickets(TICKET[:-1])
|
||||
check_tickets(f'{TICKET}b')
|
||||
check_tickets(f'{TICKET}blah')
|
||||
check_tickets([True, TICKET, TICKET2])
|
||||
check_tickets([TICKET, 'blah', TICKET2])
|
||||
check_tickets([TICKET, TICKET2, []])
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from unit.applications.lang.python import TestApplicationPython
|
||||
from unit.applications.lang.python import ApplicationPython
|
||||
from unit.option import option
|
||||
|
||||
prerequisites = {
|
||||
|
@ -6,17 +6,16 @@ prerequisites = {
|
|||
'features': {'unix_abstract': True},
|
||||
}
|
||||
|
||||
client = ApplicationPython()
|
||||
|
||||
class TestUnixAbstract(TestApplicationPython):
|
||||
def test_unix_abstract_source(self):
|
||||
|
||||
def test_unix_abstract_source():
|
||||
addr = '\0sock'
|
||||
|
||||
def source(source):
|
||||
assert 'success' in self.conf(
|
||||
f'"{source}"', 'routes/0/match/source'
|
||||
)
|
||||
assert 'success' in client.conf(f'"{source}"', 'routes/0/match/source')
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"127.0.0.1:7080": {"pass": "routes"},
|
||||
|
@ -32,20 +31,17 @@ class TestUnixAbstract(TestApplicationPython):
|
|||
}
|
||||
)
|
||||
|
||||
assert (
|
||||
self.get(sock_type='unix', addr=addr)['status'] == 200
|
||||
), 'neg ipv4'
|
||||
assert client.get(sock_type='unix', addr=addr)['status'] == 200, 'neg ipv4'
|
||||
|
||||
source("!::/0")
|
||||
assert (
|
||||
self.get(sock_type='unix', addr=addr)['status'] == 200
|
||||
), 'neg ipv6'
|
||||
assert client.get(sock_type='unix', addr=addr)['status'] == 200, 'neg ipv6'
|
||||
|
||||
source("unix")
|
||||
assert self.get()['status'] == 404, 'ipv4'
|
||||
assert self.get(sock_type='unix', addr=addr)['status'] == 200, 'unix'
|
||||
assert client.get()['status'] == 404, 'ipv4'
|
||||
assert client.get(sock_type='unix', addr=addr)['status'] == 200, 'unix'
|
||||
|
||||
def test_unix_abstract_client_ip(self):
|
||||
|
||||
def test_unix_abstract_client_ip():
|
||||
def get_xff(xff, sock_type='ipv4'):
|
||||
address = {
|
||||
'ipv4': ('127.0.0.1', 7080),
|
||||
|
@ -54,7 +50,7 @@ class TestUnixAbstract(TestApplicationPython):
|
|||
}
|
||||
(addr, port) = address[sock_type]
|
||||
|
||||
return self.get(
|
||||
return client.get(
|
||||
sock_type=sock_type,
|
||||
addr=addr,
|
||||
port=port,
|
||||
|
@ -62,7 +58,7 @@ class TestUnixAbstract(TestApplicationPython):
|
|||
)['body']
|
||||
|
||||
client_ip_dir = f"{option.test_dir}/python/client_ip"
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"127.0.0.1:7080": {
|
||||
|
@ -89,7 +85,7 @@ class TestUnixAbstract(TestApplicationPython):
|
|||
},
|
||||
"applications": {
|
||||
"client_ip": {
|
||||
"type": self.get_application_type(),
|
||||
"type": client.get_application_type(),
|
||||
"processes": {"spare": 0},
|
||||
"path": client_ip_dir,
|
||||
"working_directory": client_ip_dir,
|
||||
|
|
|
@ -2,16 +2,17 @@ import os
|
|||
import re
|
||||
|
||||
import pytest
|
||||
from unit.applications.lang.python import TestApplicationPython
|
||||
from unit.applications.lang.python import ApplicationPython
|
||||
from unit.option import option
|
||||
|
||||
prerequisites = {'modules': {'python': 'any'}}
|
||||
|
||||
client = ApplicationPython()
|
||||
|
||||
|
||||
class TestUpstreamsRR(TestApplicationPython):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_method_fixture(self):
|
||||
assert 'success' in self.conf(
|
||||
def setup_method_fixture():
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"*:7080": {"pass": "upstreams/one"},
|
||||
|
@ -43,13 +44,14 @@ class TestUpstreamsRR(TestApplicationPython):
|
|||
},
|
||||
), 'upstreams initial configuration'
|
||||
|
||||
self.cpu_count = os.cpu_count()
|
||||
client.cpu_count = os.cpu_count()
|
||||
|
||||
def get_resps(self, req=100, port=7080):
|
||||
|
||||
def get_resps(req=100, port=7080):
|
||||
resps = [0]
|
||||
|
||||
for _ in range(req):
|
||||
status = self.get(port=port)['status']
|
||||
status = client.get(port=port)['status']
|
||||
if 200 > status or status > 209:
|
||||
continue
|
||||
|
||||
|
@ -61,7 +63,8 @@ class TestUpstreamsRR(TestApplicationPython):
|
|||
|
||||
return resps
|
||||
|
||||
def get_resps_sc(self, req=100, port=7080):
|
||||
|
||||
def get_resps_sc(req=100, port=7080):
|
||||
to_send = b"""GET / HTTP/1.1
|
||||
Host: localhost
|
||||
|
||||
|
@ -75,75 +78,77 @@ Connection: close
|
|||
|
||||
"""
|
||||
|
||||
resp = self.http(to_send, raw_resp=True, raw=True, port=port)
|
||||
resp = client.http(to_send, raw_resp=True, raw=True, port=port)
|
||||
status = re.findall(r'HTTP\/\d\.\d\s(\d\d\d)', resp)
|
||||
status = list(filter(lambda x: x[:2] == '20', status))
|
||||
ups = list(map(lambda x: int(x[-1]), status))
|
||||
|
||||
resps = [0] * (max(ups) + 1)
|
||||
for i in range(len(ups)):
|
||||
resps[ups[i]] += 1
|
||||
for _, up in enumerate(ups):
|
||||
resps[up] += 1
|
||||
|
||||
return resps
|
||||
|
||||
def test_upstreams_rr_no_weight(self):
|
||||
resps = self.get_resps()
|
||||
assert sum(resps) == 100, 'no weight sum'
|
||||
assert abs(resps[0] - resps[1]) <= self.cpu_count, 'no weight'
|
||||
|
||||
assert 'success' in self.conf_delete(
|
||||
def test_upstreams_rr_no_weight():
|
||||
resps = get_resps()
|
||||
assert sum(resps) == 100, 'no weight sum'
|
||||
assert abs(resps[0] - resps[1]) <= client.cpu_count, 'no weight'
|
||||
|
||||
assert 'success' in client.conf_delete(
|
||||
'upstreams/one/servers/127.0.0.1:7081'
|
||||
), 'no weight server remove'
|
||||
|
||||
resps = self.get_resps(req=50)
|
||||
resps = get_resps(req=50)
|
||||
assert resps[1] == 50, 'no weight 2'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{}, 'upstreams/one/servers/127.0.0.1:7081'
|
||||
), 'no weight server revert'
|
||||
|
||||
resps = self.get_resps()
|
||||
resps = get_resps()
|
||||
assert sum(resps) == 100, 'no weight 3 sum'
|
||||
assert abs(resps[0] - resps[1]) <= self.cpu_count, 'no weight 3'
|
||||
assert abs(resps[0] - resps[1]) <= client.cpu_count, 'no weight 3'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{}, 'upstreams/one/servers/127.0.0.1:7083'
|
||||
), 'no weight server new'
|
||||
|
||||
resps = self.get_resps()
|
||||
resps = get_resps()
|
||||
assert sum(resps) == 100, 'no weight 4 sum'
|
||||
assert max(resps) - min(resps) <= self.cpu_count, 'no weight 4'
|
||||
assert max(resps) - min(resps) <= client.cpu_count, 'no weight 4'
|
||||
|
||||
resps = self.get_resps_sc(req=30)
|
||||
resps = get_resps_sc(req=30)
|
||||
assert resps[0] == 10, 'no weight 4 0'
|
||||
assert resps[1] == 10, 'no weight 4 1'
|
||||
assert resps[2] == 10, 'no weight 4 2'
|
||||
|
||||
def test_upstreams_rr_weight(self):
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def test_upstreams_rr_weight():
|
||||
assert 'success' in client.conf(
|
||||
{"weight": 3}, 'upstreams/one/servers/127.0.0.1:7081'
|
||||
), 'configure weight'
|
||||
|
||||
resps = self.get_resps_sc()
|
||||
resps = get_resps_sc()
|
||||
assert resps[0] == 75, 'weight 3 0'
|
||||
assert resps[1] == 25, 'weight 3 1'
|
||||
|
||||
assert 'success' in self.conf_delete(
|
||||
assert 'success' in client.conf_delete(
|
||||
'upstreams/one/servers/127.0.0.1:7081/weight'
|
||||
), 'configure weight remove'
|
||||
resps = self.get_resps_sc(req=10)
|
||||
resps = get_resps_sc(req=10)
|
||||
assert resps[0] == 5, 'weight 0 0'
|
||||
assert resps[1] == 5, 'weight 0 1'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
'1', 'upstreams/one/servers/127.0.0.1:7081/weight'
|
||||
), 'configure weight 1'
|
||||
|
||||
resps = self.get_resps_sc()
|
||||
resps = get_resps_sc()
|
||||
assert resps[0] == 50, 'weight 1 0'
|
||||
assert resps[1] == 50, 'weight 1 1'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"127.0.0.1:7081": {"weight": 3},
|
||||
"127.0.0.1:7083": {"weight": 2},
|
||||
|
@ -151,13 +156,14 @@ Connection: close
|
|||
'upstreams/one/servers',
|
||||
), 'configure weight 2'
|
||||
|
||||
resps = self.get_resps_sc()
|
||||
resps = get_resps_sc()
|
||||
assert resps[0] == 60, 'weight 2 0'
|
||||
assert resps[2] == 40, 'weight 2 1'
|
||||
|
||||
def test_upstreams_rr_weight_rational(self):
|
||||
|
||||
def test_upstreams_rr_weight_rational():
|
||||
def set_weights(w1, w2):
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"127.0.0.1:7081": {"weight": w1},
|
||||
"127.0.0.1:7082": {"weight": w2},
|
||||
|
@ -166,7 +172,7 @@ Connection: close
|
|||
), 'configure weights'
|
||||
|
||||
def check_reqs(w1, w2, reqs=10):
|
||||
resps = self.get_resps_sc(req=reqs)
|
||||
resps = get_resps_sc(req=reqs)
|
||||
assert resps[0] == reqs * w1 / (w1 + w2), 'weight 1'
|
||||
assert resps[1] == reqs * w2 / (w1 + w2), 'weight 2'
|
||||
|
||||
|
@ -188,12 +194,12 @@ Connection: close
|
|||
check_weights(1000000, 1000000)
|
||||
|
||||
set_weights(0.25, 0.25)
|
||||
assert 'success' in self.conf_delete(
|
||||
assert 'success' in client.conf_delete(
|
||||
'upstreams/one/servers/127.0.0.1:7081/weight'
|
||||
), 'delete weight'
|
||||
check_reqs(1, 0.25)
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"127.0.0.1:7081": {"weight": 0.1},
|
||||
"127.0.0.1:7082": {"weight": 1},
|
||||
|
@ -201,56 +207,58 @@ Connection: close
|
|||
},
|
||||
'upstreams/one/servers',
|
||||
), 'configure weights'
|
||||
resps = self.get_resps_sc(req=20)
|
||||
resps = get_resps_sc(req=20)
|
||||
assert resps[0] == 1, 'weight 3 1'
|
||||
assert resps[1] == 10, 'weight 3 2'
|
||||
assert resps[2] == 9, 'weight 3 3'
|
||||
|
||||
def test_upstreams_rr_independent(self):
|
||||
|
||||
def test_upstreams_rr_independent():
|
||||
def sum_resps(*args):
|
||||
sum = [0] * len(args[0])
|
||||
sum_r = [0] * len(args[0])
|
||||
for arg in args:
|
||||
sum = [x + y for x, y in zip(sum, arg)]
|
||||
sum_r = [x + y for x, y in zip(sum_r, arg)]
|
||||
|
||||
return sum
|
||||
return sum_r
|
||||
|
||||
resps = self.get_resps_sc(req=30, port=7090)
|
||||
resps = get_resps_sc(req=30, port=7090)
|
||||
assert resps[0] == 15, 'dep two before 0'
|
||||
assert resps[1] == 15, 'dep two before 1'
|
||||
|
||||
resps = self.get_resps_sc(req=30)
|
||||
resps = get_resps_sc(req=30)
|
||||
assert resps[0] == 15, 'dep one before 0'
|
||||
assert resps[1] == 15, 'dep one before 1'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
'2', 'upstreams/two/servers/127.0.0.1:7081/weight'
|
||||
), 'configure dep weight'
|
||||
|
||||
resps = self.get_resps_sc(req=30, port=7090)
|
||||
resps = get_resps_sc(req=30, port=7090)
|
||||
assert resps[0] == 20, 'dep two 0'
|
||||
assert resps[1] == 10, 'dep two 1'
|
||||
|
||||
resps = self.get_resps_sc(req=30)
|
||||
resps = get_resps_sc(req=30)
|
||||
assert resps[0] == 15, 'dep one 0'
|
||||
assert resps[1] == 15, 'dep one 1'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
'1', 'upstreams/two/servers/127.0.0.1:7081/weight'
|
||||
), 'configure dep weight 1'
|
||||
|
||||
r_one, r_two = [0, 0], [0, 0]
|
||||
for _ in range(10):
|
||||
r_one = sum_resps(r_one, self.get_resps(req=10))
|
||||
r_two = sum_resps(r_two, self.get_resps(req=10, port=7090))
|
||||
r_one = sum_resps(r_one, get_resps(req=10))
|
||||
r_two = sum_resps(r_two, get_resps(req=10, port=7090))
|
||||
|
||||
assert sum(r_one) == 100, 'dep one mix sum'
|
||||
assert abs(r_one[0] - r_one[1]) <= self.cpu_count, 'dep one mix'
|
||||
assert abs(r_one[0] - r_one[1]) <= client.cpu_count, 'dep one mix'
|
||||
assert sum(r_two) == 100, 'dep two mix sum'
|
||||
assert abs(r_two[0] - r_two[1]) <= self.cpu_count, 'dep two mix'
|
||||
assert abs(r_two[0] - r_two[1]) <= client.cpu_count, 'dep two mix'
|
||||
|
||||
def test_upstreams_rr_delay(self):
|
||||
|
||||
def test_upstreams_rr_delay():
|
||||
delayed_dir = f'{option.test_dir}/python/delayed'
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"*:7080": {"pass": "upstreams/one"},
|
||||
|
@ -277,7 +285,7 @@ Connection: close
|
|||
],
|
||||
"applications": {
|
||||
"delayed": {
|
||||
"type": self.get_application_type(),
|
||||
"type": client.get_application_type(),
|
||||
"processes": {"spare": 0},
|
||||
"path": delayed_dir,
|
||||
"working_directory": delayed_dir,
|
||||
|
@ -292,7 +300,7 @@ Connection: close
|
|||
socks = []
|
||||
for i in range(req):
|
||||
delay = 1 if i % 5 == 0 else 0
|
||||
sock = self.get(
|
||||
sock = client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Content-Length': '0',
|
||||
|
@ -305,7 +313,7 @@ Connection: close
|
|||
|
||||
resps = [0, 0]
|
||||
for i in range(req):
|
||||
resp = self.recvall(socks[i]).decode()
|
||||
resp = client.recvall(socks[i]).decode()
|
||||
socks[i].close()
|
||||
|
||||
m = re.search(r'HTTP/1.1 20(\d)', resp)
|
||||
|
@ -313,18 +321,19 @@ Connection: close
|
|||
resps[int(m.group(1))] += 1
|
||||
|
||||
assert sum(resps) == req, 'delay sum'
|
||||
assert abs(resps[0] - resps[1]) <= self.cpu_count, 'delay'
|
||||
assert abs(resps[0] - resps[1]) <= client.cpu_count, 'delay'
|
||||
|
||||
def test_upstreams_rr_active_req(self):
|
||||
|
||||
def test_upstreams_rr_active_req():
|
||||
conns = 5
|
||||
socks = []
|
||||
socks2 = []
|
||||
|
||||
for _ in range(conns):
|
||||
sock = self.get(no_recv=True)
|
||||
sock = client.get(no_recv=True)
|
||||
socks.append(sock)
|
||||
|
||||
sock2 = self.http(
|
||||
sock2 = client.http(
|
||||
b"""POST / HTTP/1.1
|
||||
Host: localhost
|
||||
Content-Length: 10
|
||||
|
@ -339,62 +348,66 @@ Connection: close
|
|||
# Send one more request and read response to make sure that previous
|
||||
# requests had enough time to reach server.
|
||||
|
||||
assert self.get()['body'] == ''
|
||||
assert client.get()['body'] == ''
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{"127.0.0.1:7083": {"weight": 2}},
|
||||
'upstreams/one/servers',
|
||||
), 'active req new server'
|
||||
assert 'success' in self.conf_delete(
|
||||
assert 'success' in client.conf_delete(
|
||||
'upstreams/one/servers/127.0.0.1:7083'
|
||||
), 'active req server remove'
|
||||
assert 'success' in self.conf_delete(
|
||||
assert 'success' in client.conf_delete(
|
||||
'listeners/*:7080'
|
||||
), 'delete listener'
|
||||
assert 'success' in self.conf_delete(
|
||||
assert 'success' in client.conf_delete(
|
||||
'upstreams/one'
|
||||
), 'active req upstream remove'
|
||||
|
||||
for i in range(conns):
|
||||
assert (
|
||||
self.http(b'', sock=socks[i], raw=True)['body'] == ''
|
||||
client.http(b'', sock=socks[i], raw=True)['body'] == ''
|
||||
), 'active req GET'
|
||||
|
||||
assert (
|
||||
self.http(b"""0123456789""", sock=socks2[i], raw=True)['body']
|
||||
client.http(b"""0123456789""", sock=socks2[i], raw=True)['body']
|
||||
== ''
|
||||
), 'active req POST'
|
||||
|
||||
def test_upstreams_rr_bad_server(self):
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def test_upstreams_rr_bad_server():
|
||||
assert 'success' in client.conf(
|
||||
{"weight": 1}, 'upstreams/one/servers/127.0.0.1:7084'
|
||||
), 'configure bad server'
|
||||
|
||||
resps = self.get_resps_sc(req=30)
|
||||
resps = get_resps_sc(req=30)
|
||||
assert resps[0] == 10, 'bad server 0'
|
||||
assert resps[1] == 10, 'bad server 1'
|
||||
assert sum(resps) == 20, 'bad server sum'
|
||||
|
||||
def test_upstreams_rr_pipeline(self):
|
||||
resps = self.get_resps_sc()
|
||||
|
||||
def test_upstreams_rr_pipeline():
|
||||
resps = get_resps_sc()
|
||||
|
||||
assert resps[0] == 50, 'pipeline 0'
|
||||
assert resps[1] == 50, 'pipeline 1'
|
||||
|
||||
def test_upstreams_rr_post(self):
|
||||
|
||||
def test_upstreams_rr_post():
|
||||
resps = [0, 0]
|
||||
for _ in range(50):
|
||||
resps[self.get()['status'] % 10] += 1
|
||||
resps[self.post(body='0123456789')['status'] % 10] += 1
|
||||
resps[client.get()['status'] % 10] += 1
|
||||
resps[client.post(body='0123456789')['status'] % 10] += 1
|
||||
|
||||
assert sum(resps) == 100, 'post sum'
|
||||
assert abs(resps[0] - resps[1]) <= self.cpu_count, 'post'
|
||||
assert abs(resps[0] - resps[1]) <= client.cpu_count, 'post'
|
||||
|
||||
def test_upstreams_rr_unix(self, temp_dir):
|
||||
|
||||
def test_upstreams_rr_unix(temp_dir):
|
||||
addr_0 = f'{temp_dir}/sock_0'
|
||||
addr_1 = f'{temp_dir}/sock_1'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"*:7080": {"pass": "upstreams/one"},
|
||||
f"unix:{addr_0}": {"pass": "routes/one"},
|
||||
|
@ -403,18 +416,19 @@ Connection: close
|
|||
'listeners',
|
||||
), 'configure listeners unix'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{f"unix:{addr_0}": {}, f"unix:{addr_1}": {}},
|
||||
'upstreams/one/servers',
|
||||
), 'configure servers unix'
|
||||
|
||||
resps = self.get_resps_sc()
|
||||
resps = get_resps_sc()
|
||||
|
||||
assert resps[0] == 50, 'unix 0'
|
||||
assert resps[1] == 50, 'unix 1'
|
||||
|
||||
def test_upstreams_rr_ipv6(self):
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def test_upstreams_rr_ipv6():
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"*:7080": {"pass": "upstreams/one"},
|
||||
"[::1]:7081": {"pass": "routes/one"},
|
||||
|
@ -423,48 +437,48 @@ Connection: close
|
|||
'listeners',
|
||||
), 'configure listeners ipv6'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{"[::1]:7081": {}, "[::1]:7082": {}}, 'upstreams/one/servers'
|
||||
), 'configure servers ipv6'
|
||||
|
||||
resps = self.get_resps_sc()
|
||||
resps = get_resps_sc()
|
||||
|
||||
assert resps[0] == 50, 'ipv6 0'
|
||||
assert resps[1] == 50, 'ipv6 1'
|
||||
|
||||
def test_upstreams_rr_servers_empty(self):
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def test_upstreams_rr_servers_empty():
|
||||
assert 'success' in client.conf(
|
||||
{}, 'upstreams/one/servers'
|
||||
), 'configure servers empty'
|
||||
assert self.get()['status'] == 502, 'servers empty'
|
||||
assert client.get()['status'] == 502, 'servers empty'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{"127.0.0.1:7081": {"weight": 0}}, 'upstreams/one/servers'
|
||||
), 'configure servers empty one'
|
||||
assert self.get()['status'] == 502, 'servers empty one'
|
||||
assert 'success' in self.conf(
|
||||
assert client.get()['status'] == 502, 'servers empty one'
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"127.0.0.1:7081": {"weight": 0},
|
||||
"127.0.0.1:7082": {"weight": 0},
|
||||
},
|
||||
'upstreams/one/servers',
|
||||
), 'configure servers empty two'
|
||||
assert self.get()['status'] == 502, 'servers empty two'
|
||||
assert client.get()['status'] == 502, 'servers empty two'
|
||||
|
||||
def test_upstreams_rr_invalid(self):
|
||||
assert 'error' in self.conf({}, 'upstreams'), 'upstreams empty'
|
||||
assert 'error' in self.conf(
|
||||
{}, 'upstreams/one'
|
||||
), 'named upstreams empty'
|
||||
assert 'error' in self.conf(
|
||||
|
||||
def test_upstreams_rr_invalid():
|
||||
assert 'error' in client.conf({}, 'upstreams'), 'upstreams empty'
|
||||
assert 'error' in client.conf({}, 'upstreams/one'), 'named upstreams empty'
|
||||
assert 'error' in client.conf(
|
||||
{}, 'upstreams/one/servers/127.0.0.1'
|
||||
), 'invalid address'
|
||||
assert 'error' in self.conf(
|
||||
assert 'error' in client.conf(
|
||||
{}, 'upstreams/one/servers/127.0.0.1:7081/blah'
|
||||
), 'invalid server option'
|
||||
|
||||
def check_weight(w):
|
||||
assert 'error' in self.conf(
|
||||
assert 'error' in client.conf(
|
||||
w, 'upstreams/one/servers/127.0.0.1:7081/weight'
|
||||
), 'invalid weight option'
|
||||
|
||||
|
|
|
@ -1,24 +1,23 @@
|
|||
import os
|
||||
import signal
|
||||
|
||||
from unit.applications.lang.python import TestApplicationPython
|
||||
from unit.applications.lang.python import ApplicationPython
|
||||
from unit.log import Log
|
||||
from unit.utils import waitforfiles
|
||||
|
||||
prerequisites = {'modules': {'python': 'any'}}
|
||||
|
||||
client = ApplicationPython()
|
||||
|
||||
class TestUSR1(TestApplicationPython):
|
||||
def test_usr1_access_log(
|
||||
self, search_in_file, temp_dir, unit_pid, wait_for_record
|
||||
):
|
||||
self.load('empty')
|
||||
|
||||
def test_usr1_access_log(search_in_file, temp_dir, unit_pid, wait_for_record):
|
||||
client.load('empty')
|
||||
|
||||
log = 'access.log'
|
||||
log_new = 'new.log'
|
||||
log_path = f'{temp_dir}/{log}'
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
f'"{log_path}"', 'access_log'
|
||||
), 'access log configure'
|
||||
|
||||
|
@ -26,11 +25,10 @@ class TestUSR1(TestApplicationPython):
|
|||
|
||||
os.rename(log_path, f'{temp_dir}/{log_new}')
|
||||
|
||||
assert self.get()['status'] == 200
|
||||
assert client.get()['status'] == 200
|
||||
|
||||
assert (
|
||||
wait_for_record(r'"GET / HTTP/1.1" 200 0 "-" "-"', log_new)
|
||||
is not None
|
||||
wait_for_record(r'"GET / HTTP/1.1" 200 0 "-" "-"', log_new) is not None
|
||||
), 'rename new'
|
||||
assert not os.path.isfile(log_path), 'rename old'
|
||||
|
||||
|
@ -38,18 +36,16 @@ class TestUSR1(TestApplicationPython):
|
|||
|
||||
assert waitforfiles(log_path), 'reopen'
|
||||
|
||||
assert self.get(url='/usr1')['status'] == 200
|
||||
assert client.get(url='/usr1')['status'] == 200
|
||||
|
||||
assert (
|
||||
wait_for_record(r'"GET /usr1 HTTP/1.1" 200 0 "-" "-"', log)
|
||||
is not None
|
||||
wait_for_record(r'"GET /usr1 HTTP/1.1" 200 0 "-" "-"', log) is not None
|
||||
), 'reopen 2'
|
||||
assert search_in_file(r'/usr1', log_new) is None, 'rename new 2'
|
||||
|
||||
def test_usr1_unit_log(
|
||||
self, search_in_file, temp_dir, unit_pid, wait_for_record
|
||||
):
|
||||
self.load('log_body')
|
||||
|
||||
def test_usr1_unit_log(search_in_file, temp_dir, unit_pid, wait_for_record):
|
||||
client.load('log_body')
|
||||
|
||||
log_new = 'new.log'
|
||||
log_path = f'{temp_dir}/unit.log'
|
||||
|
@ -61,7 +57,7 @@ class TestUSR1(TestApplicationPython):
|
|||
|
||||
try:
|
||||
body = 'body_for_a_log_new\n'
|
||||
assert self.post(body=body)['status'] == 200
|
||||
assert client.post(body=body)['status'] == 200
|
||||
|
||||
assert wait_for_record(body, log_new) is not None, 'rename new'
|
||||
assert not os.path.isfile(log_path), 'rename old'
|
||||
|
@ -71,7 +67,7 @@ class TestUSR1(TestApplicationPython):
|
|||
assert waitforfiles(log_path), 'reopen'
|
||||
|
||||
body = 'body_for_a_log_unit\n'
|
||||
assert self.post(body=body)['status'] == 200
|
||||
assert client.post(body=body)['status'] == 200
|
||||
|
||||
assert wait_for_record(body) is not None, 'rename new'
|
||||
assert search_in_file(body, log_new) is None, 'rename new 2'
|
||||
|
|
|
@ -2,22 +2,24 @@ import re
|
|||
import time
|
||||
|
||||
import pytest
|
||||
from unit.applications.proto import TestApplicationProto
|
||||
from unit.applications.proto import ApplicationProto
|
||||
from unit.option import option
|
||||
|
||||
client = ApplicationProto()
|
||||
|
||||
|
||||
class TestVariables(TestApplicationProto):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_method_fixture(self):
|
||||
assert 'success' in self.conf(
|
||||
def setup_method_fixture():
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "routes"}},
|
||||
"routes": [{"action": {"return": 200}}],
|
||||
},
|
||||
), 'configure routes'
|
||||
|
||||
def set_format(self, format):
|
||||
assert 'success' in self.conf(
|
||||
|
||||
def set_format(format):
|
||||
assert 'success' in client.conf(
|
||||
{
|
||||
'path': f'{option.temp_dir}/access.log',
|
||||
'format': format,
|
||||
|
@ -25,15 +27,16 @@ class TestVariables(TestApplicationProto):
|
|||
'access_log',
|
||||
), 'access_log format'
|
||||
|
||||
def test_variables_dollar(self):
|
||||
assert 'success' in self.conf("301", 'routes/0/action/return')
|
||||
|
||||
def test_variables_dollar():
|
||||
assert 'success' in client.conf("301", 'routes/0/action/return')
|
||||
|
||||
def check_dollar(location, expect):
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
f'"{location}"',
|
||||
'routes/0/action/location',
|
||||
)
|
||||
assert self.get()['headers']['Location'] == expect
|
||||
assert client.get()['headers']['Location'] == expect
|
||||
|
||||
check_dollar(
|
||||
'https://${host}${uri}path${dollar}dollar',
|
||||
|
@ -41,17 +44,18 @@ class TestVariables(TestApplicationProto):
|
|||
)
|
||||
check_dollar('path$dollar${dollar}', 'path$$')
|
||||
|
||||
def test_variables_request_time(self, wait_for_record):
|
||||
self.set_format('$uri $request_time')
|
||||
|
||||
sock = self.http(b'', raw=True, no_recv=True)
|
||||
def test_variables_request_time(wait_for_record):
|
||||
set_format('$uri $request_time')
|
||||
|
||||
sock = client.http(b'', raw=True, no_recv=True)
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
assert self.get(url='/r_time_1', sock=sock)['status'] == 200
|
||||
assert client.get(url='/r_time_1', sock=sock)['status'] == 200
|
||||
assert wait_for_record(r'\/r_time_1 0\.\d{3}', 'access.log') is not None
|
||||
|
||||
sock = self.http(
|
||||
sock = client.http(
|
||||
b"""G""",
|
||||
no_recv=True,
|
||||
raw=True,
|
||||
|
@ -59,7 +63,7 @@ class TestVariables(TestApplicationProto):
|
|||
|
||||
time.sleep(2)
|
||||
|
||||
self.http(
|
||||
client.http(
|
||||
b"""ET /r_time_2 HTTP/1.1
|
||||
Host: localhost
|
||||
Connection: close
|
||||
|
@ -68,32 +72,31 @@ Connection: close
|
|||
sock=sock,
|
||||
raw=True,
|
||||
)
|
||||
assert (
|
||||
wait_for_record(r'\/r_time_2 [1-9]\.\d{3}', 'access.log')
|
||||
is not None
|
||||
)
|
||||
assert wait_for_record(r'\/r_time_2 [1-9]\.\d{3}', 'access.log') is not None
|
||||
|
||||
def test_variables_method(self, search_in_file, wait_for_record):
|
||||
self.set_format('$method')
|
||||
|
||||
def test_variables_method(search_in_file, wait_for_record):
|
||||
set_format('$method')
|
||||
|
||||
reg = r'^GET$'
|
||||
assert search_in_file(reg, 'access.log') is None
|
||||
assert self.get()['status'] == 200
|
||||
assert client.get()['status'] == 200
|
||||
assert wait_for_record(reg, 'access.log') is not None, 'method GET'
|
||||
|
||||
reg = r'^POST$'
|
||||
assert search_in_file(reg, 'access.log') is None
|
||||
assert self.post()['status'] == 200
|
||||
assert client.post()['status'] == 200
|
||||
assert wait_for_record(reg, 'access.log') is not None, 'method POST'
|
||||
|
||||
def test_variables_request_uri(self, search_in_file, wait_for_record):
|
||||
self.set_format('$request_uri')
|
||||
|
||||
def test_variables_request_uri(search_in_file, wait_for_record):
|
||||
set_format('$request_uri')
|
||||
|
||||
def check_request_uri(req_uri):
|
||||
reg = fr'^{re.escape(req_uri)}$'
|
||||
|
||||
assert search_in_file(reg, 'access.log') is None
|
||||
assert self.get(url=req_uri)['status'] == 200
|
||||
assert client.get(url=req_uri)['status'] == 200
|
||||
assert wait_for_record(reg, 'access.log') is not None
|
||||
|
||||
check_request_uri('/3')
|
||||
|
@ -101,15 +104,16 @@ Connection: close
|
|||
check_request_uri('/4%2A')
|
||||
check_request_uri('/9?q#a')
|
||||
|
||||
def test_variables_uri(self, search_in_file, wait_for_record):
|
||||
self.set_format('$uri')
|
||||
|
||||
def test_variables_uri(search_in_file, wait_for_record):
|
||||
set_format('$uri')
|
||||
|
||||
def check_uri(uri, expect=None):
|
||||
expect = uri if expect is None else expect
|
||||
reg = fr'^{re.escape(expect)}$'
|
||||
|
||||
assert search_in_file(reg, 'access.log') is None
|
||||
assert self.get(url=uri)['status'] == 200
|
||||
assert client.get(url=uri)['status'] == 200
|
||||
assert wait_for_record(reg, 'access.log') is not None
|
||||
|
||||
check_uri('/3')
|
||||
|
@ -117,8 +121,9 @@ Connection: close
|
|||
check_uri('/5%2A', '/5*')
|
||||
check_uri('/9?q#a', '/9')
|
||||
|
||||
def test_variables_host(self, search_in_file, wait_for_record):
|
||||
self.set_format('$host')
|
||||
|
||||
def test_variables_host(search_in_file, wait_for_record):
|
||||
set_format('$host')
|
||||
|
||||
def check_host(host, expect=None):
|
||||
expect = host if expect is None else expect
|
||||
|
@ -126,9 +131,7 @@ Connection: close
|
|||
|
||||
assert search_in_file(reg, 'access.log') is None
|
||||
assert (
|
||||
self.get(headers={'Host': host, 'Connection': 'close'})[
|
||||
'status'
|
||||
]
|
||||
client.get(headers={'Host': host, 'Connection': 'close'})['status']
|
||||
== 200
|
||||
)
|
||||
assert wait_for_record(reg, 'access.log') is not None
|
||||
|
@ -139,34 +142,32 @@ Connection: close
|
|||
check_host('.localhost')
|
||||
check_host('www.localhost')
|
||||
|
||||
def test_variables_remote_addr(self, search_in_file, wait_for_record):
|
||||
self.set_format('$remote_addr')
|
||||
|
||||
assert self.get()['status'] == 200
|
||||
def test_variables_remote_addr(search_in_file, wait_for_record):
|
||||
set_format('$remote_addr')
|
||||
|
||||
assert client.get()['status'] == 200
|
||||
assert wait_for_record(r'^127\.0\.0\.1$', 'access.log') is not None
|
||||
|
||||
assert 'success' in self.conf(
|
||||
assert 'success' in client.conf(
|
||||
{"[::1]:7080": {"pass": "routes"}}, 'listeners'
|
||||
)
|
||||
|
||||
reg = r'^::1$'
|
||||
assert search_in_file(reg, 'access.log') is None
|
||||
assert self.get(sock_type='ipv6')['status'] == 200
|
||||
assert client.get(sock_type='ipv6')['status'] == 200
|
||||
assert wait_for_record(reg, 'access.log') is not None
|
||||
|
||||
|
||||
def test_variables_time_local(
|
||||
self, date_to_sec_epoch, search_in_file, wait_for_record
|
||||
date_to_sec_epoch, search_in_file, wait_for_record
|
||||
):
|
||||
self.set_format('$uri $time_local $uri')
|
||||
set_format('$uri $time_local $uri')
|
||||
|
||||
assert search_in_file(r'/time_local', 'access.log') is None
|
||||
assert self.get(url='/time_local')['status'] == 200
|
||||
assert (
|
||||
wait_for_record(r'/time_local', 'access.log') is not None
|
||||
), 'time log'
|
||||
date = search_in_file(
|
||||
r'^\/time_local (.*) \/time_local$', 'access.log'
|
||||
)[1]
|
||||
assert client.get(url='/time_local')['status'] == 200
|
||||
assert wait_for_record(r'/time_local', 'access.log') is not None, 'time log'
|
||||
date = search_in_file(r'^\/time_local (.*) \/time_local$', 'access.log')[1]
|
||||
assert (
|
||||
abs(
|
||||
date_to_sec_epoch(date, '%d/%b/%Y:%X %z')
|
||||
|
@ -175,33 +176,36 @@ Connection: close
|
|||
< 5
|
||||
), '$time_local'
|
||||
|
||||
def test_variables_request_line(self, search_in_file, wait_for_record):
|
||||
self.set_format('$request_line')
|
||||
|
||||
def test_variables_request_line(search_in_file, wait_for_record):
|
||||
set_format('$request_line')
|
||||
|
||||
reg = r'^GET \/r_line HTTP\/1\.1$'
|
||||
assert search_in_file(reg, 'access.log') is None
|
||||
assert self.get(url='/r_line')['status'] == 200
|
||||
assert client.get(url='/r_line')['status'] == 200
|
||||
assert wait_for_record(reg, 'access.log') is not None
|
||||
|
||||
def test_variables_status(self, search_in_file, wait_for_record):
|
||||
self.set_format('$status')
|
||||
|
||||
assert 'success' in self.conf("418", 'routes/0/action/return')
|
||||
def test_variables_status(search_in_file, wait_for_record):
|
||||
set_format('$status')
|
||||
|
||||
assert 'success' in client.conf("418", 'routes/0/action/return')
|
||||
|
||||
reg = r'^418$'
|
||||
assert search_in_file(reg, 'access.log') is None
|
||||
assert self.get()['status'] == 418
|
||||
assert client.get()['status'] == 418
|
||||
assert wait_for_record(reg, 'access.log') is not None
|
||||
|
||||
def test_variables_header_referer(self, search_in_file, wait_for_record):
|
||||
self.set_format('$method $header_referer')
|
||||
|
||||
def test_variables_header_referer(search_in_file, wait_for_record):
|
||||
set_format('$method $header_referer')
|
||||
|
||||
def check_referer(referer):
|
||||
reg = fr'^GET {re.escape(referer)}$'
|
||||
|
||||
assert search_in_file(reg, 'access.log') is None
|
||||
assert (
|
||||
self.get(
|
||||
client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Connection': 'close',
|
||||
|
@ -216,15 +220,16 @@ Connection: close
|
|||
check_referer('')
|
||||
check_referer('no')
|
||||
|
||||
def test_variables_header_user_agent(self, search_in_file, wait_for_record):
|
||||
self.set_format('$method $header_user_agent')
|
||||
|
||||
def test_variables_header_user_agent(search_in_file, wait_for_record):
|
||||
set_format('$method $header_user_agent')
|
||||
|
||||
def check_user_agent(user_agent):
|
||||
reg = fr'^GET {re.escape(user_agent)}$'
|
||||
|
||||
assert search_in_file(reg, 'access.log') is None
|
||||
assert (
|
||||
self.get(
|
||||
client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Connection': 'close',
|
||||
|
@ -239,31 +244,33 @@ Connection: close
|
|||
check_user_agent('')
|
||||
check_user_agent('no')
|
||||
|
||||
def test_variables_many(self, search_in_file, wait_for_record):
|
||||
|
||||
def test_variables_many(search_in_file, wait_for_record):
|
||||
def check_vars(uri, expect):
|
||||
reg = fr'^{re.escape(expect)}$'
|
||||
|
||||
assert search_in_file(reg, 'access.log') is None
|
||||
assert self.get(url=uri)['status'] == 200
|
||||
assert client.get(url=uri)['status'] == 200
|
||||
assert wait_for_record(reg, 'access.log') is not None
|
||||
|
||||
self.set_format('$uri$method')
|
||||
set_format('$uri$method')
|
||||
check_vars('/1', '/1GET')
|
||||
|
||||
self.set_format('${uri}${method}')
|
||||
set_format('${uri}${method}')
|
||||
check_vars('/2', '/2GET')
|
||||
|
||||
self.set_format('${uri}$method')
|
||||
set_format('${uri}$method')
|
||||
check_vars('/3', '/3GET')
|
||||
|
||||
self.set_format('$method$method')
|
||||
set_format('$method$method')
|
||||
check_vars('/', 'GETGET')
|
||||
|
||||
def test_variables_dynamic(self, wait_for_record):
|
||||
self.set_format('$header_foo$cookie_foo$arg_foo')
|
||||
|
||||
def test_variables_dynamic(wait_for_record):
|
||||
set_format('$header_foo$cookie_foo$arg_foo')
|
||||
|
||||
assert (
|
||||
self.get(
|
||||
client.get(
|
||||
url='/?foo=h',
|
||||
headers={'Foo': 'b', 'Cookie': 'foo=la', 'Connection': 'close'},
|
||||
)['status']
|
||||
|
@ -271,20 +278,21 @@ Connection: close
|
|||
)
|
||||
assert wait_for_record(r'^blah$', 'access.log') is not None
|
||||
|
||||
def test_variables_dynamic_arguments(self, search_in_file, wait_for_record):
|
||||
|
||||
def test_variables_dynamic_arguments(search_in_file, wait_for_record):
|
||||
def check_arg(url, expect=None):
|
||||
expect = url if expect is None else expect
|
||||
reg = fr'^{re.escape(expect)}$'
|
||||
|
||||
assert search_in_file(reg, 'access.log') is None
|
||||
assert self.get(url=url)['status'] == 200
|
||||
assert client.get(url=url)['status'] == 200
|
||||
assert wait_for_record(reg, 'access.log') is not None
|
||||
|
||||
def check_no_arg(url):
|
||||
assert self.get(url=url)['status'] == 200
|
||||
assert client.get(url=url)['status'] == 200
|
||||
assert search_in_file(r'^0$', 'access.log') is None
|
||||
|
||||
self.set_format('$arg_foo_bar')
|
||||
set_format('$arg_foo_bar')
|
||||
check_arg('/?foo_bar=1', '1')
|
||||
check_arg('/?foo_b%61r=2', '2')
|
||||
check_arg('/?bar&foo_bar=3&foo', '3')
|
||||
|
@ -295,50 +303,50 @@ Connection: close
|
|||
check_no_arg('/?foo-bar=0')
|
||||
check_no_arg('/?foo_bar=0&foo_bar=l')
|
||||
|
||||
self.set_format('$arg_foo_b%61r')
|
||||
set_format('$arg_foo_b%61r')
|
||||
check_no_arg('/?foo_b=0')
|
||||
check_no_arg('/?foo_bar=0')
|
||||
|
||||
self.set_format('$arg_f!~')
|
||||
set_format('$arg_f!~')
|
||||
check_no_arg('/?f=0')
|
||||
check_no_arg('/?f!~=0')
|
||||
|
||||
def test_variables_dynamic_headers(self, search_in_file, wait_for_record):
|
||||
|
||||
def test_variables_dynamic_headers(search_in_file, wait_for_record):
|
||||
def check_header(header, value):
|
||||
reg = fr'^{value}$'
|
||||
|
||||
assert search_in_file(reg, 'access.log') is None
|
||||
assert (
|
||||
self.get(headers={header: value, 'Connection': 'close'})[
|
||||
'status'
|
||||
]
|
||||
client.get(headers={header: value, 'Connection': 'close'})['status']
|
||||
== 200
|
||||
)
|
||||
assert wait_for_record(reg, 'access.log') is not None
|
||||
|
||||
def check_no_header(header):
|
||||
assert (
|
||||
self.get(headers={header: '0', 'Connection': 'close'})['status']
|
||||
client.get(headers={header: '0', 'Connection': 'close'})['status']
|
||||
== 200
|
||||
)
|
||||
assert search_in_file(r'^0$', 'access.log') is None
|
||||
|
||||
self.set_format('$header_foo_bar')
|
||||
set_format('$header_foo_bar')
|
||||
check_header('foo-bar', '1')
|
||||
check_header('Foo-Bar', '2')
|
||||
check_no_header('foo_bar')
|
||||
check_no_header('foobar')
|
||||
|
||||
self.set_format('$header_Foo_Bar')
|
||||
set_format('$header_Foo_Bar')
|
||||
check_header('Foo-Bar', '4')
|
||||
check_header('foo-bar', '5')
|
||||
check_no_header('foo_bar')
|
||||
check_no_header('foobar')
|
||||
|
||||
def test_variables_dynamic_cookies(self, search_in_file, wait_for_record):
|
||||
|
||||
def test_variables_dynamic_cookies(search_in_file, wait_for_record):
|
||||
def check_no_cookie(cookie):
|
||||
assert (
|
||||
self.get(
|
||||
client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Cookie': cookie,
|
||||
|
@ -349,12 +357,12 @@ Connection: close
|
|||
)
|
||||
assert search_in_file(r'^0$', 'access.log') is None
|
||||
|
||||
self.set_format('$cookie_foo_bar')
|
||||
set_format('$cookie_foo_bar')
|
||||
|
||||
reg = r'^1$'
|
||||
assert search_in_file(reg, 'access.log') is None
|
||||
assert (
|
||||
self.get(
|
||||
client.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Cookie': 'foo_bar=1',
|
||||
|
@ -368,9 +376,10 @@ Connection: close
|
|||
check_no_cookie('fOo_bar=0')
|
||||
check_no_cookie('foo_bar=')
|
||||
|
||||
def test_variables_invalid(self, temp_dir):
|
||||
|
||||
def test_variables_invalid(temp_dir):
|
||||
def check_variables(format):
|
||||
assert 'error' in self.conf(
|
||||
assert 'error' in client.conf(
|
||||
{
|
||||
'path': f'{temp_dir}/access.log',
|
||||
'format': format,
|
||||
|
|
|
@ -2,11 +2,11 @@ import os
|
|||
import shutil
|
||||
import subprocess
|
||||
|
||||
from unit.applications.proto import TestApplicationProto
|
||||
from unit.applications.proto import ApplicationProto
|
||||
from unit.option import option
|
||||
|
||||
|
||||
class TestApplicationGo(TestApplicationProto):
|
||||
class ApplicationGo(ApplicationProto):
|
||||
@staticmethod
|
||||
def prepare_env(script, name='app', static=False):
|
||||
try:
|
||||
|
@ -88,7 +88,7 @@ replace unit.nginx.org/go => {replace_path}
|
|||
executable = f"/go/{name}"
|
||||
static_build = True
|
||||
|
||||
TestApplicationGo.prepare_env(script, name, static=static_build)
|
||||
ApplicationGo.prepare_env(script, name, static=static_build)
|
||||
|
||||
conf = {
|
||||
"listeners": {"*:7080": {"pass": f"applications/{script}"}},
|
||||
|
|
|
@ -4,12 +4,13 @@ import shutil
|
|||
import subprocess
|
||||
|
||||
import pytest
|
||||
from unit.applications.proto import TestApplicationProto
|
||||
from unit.applications.proto import ApplicationProto
|
||||
from unit.option import option
|
||||
|
||||
|
||||
class TestApplicationJava(TestApplicationProto):
|
||||
application_type = "java"
|
||||
class ApplicationJava(ApplicationProto):
|
||||
def __init__(self, application_type='java'):
|
||||
self.application_type = application_type
|
||||
|
||||
def prepare_env(self, script):
|
||||
app_path = f'{option.temp_dir}/java'
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
import shutil
|
||||
from urllib.parse import quote
|
||||
|
||||
from unit.applications.proto import TestApplicationProto
|
||||
from unit.applications.proto import ApplicationProto
|
||||
from unit.option import option
|
||||
from unit.utils import public_dir
|
||||
|
||||
|
||||
class TestApplicationNode(TestApplicationProto):
|
||||
application_type = "node"
|
||||
es_modules = False
|
||||
class ApplicationNode(ApplicationProto):
|
||||
def __init__(self, application_type='node', es_modules=False):
|
||||
self.application_type = application_type
|
||||
self.es_modules = es_modules
|
||||
|
||||
def prepare_env(self, script):
|
||||
# copy application
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
from unit.applications.proto import TestApplicationProto
|
||||
from unit.applications.proto import ApplicationProto
|
||||
from unit.option import option
|
||||
|
||||
|
||||
class TestApplicationPerl(TestApplicationProto):
|
||||
application_type = "perl"
|
||||
class ApplicationPerl(ApplicationProto):
|
||||
def __init__(self, application_type='perl'):
|
||||
self.application_type = application_type
|
||||
|
||||
def load(self, script, name='psgi.pl', **kwargs):
|
||||
script_path = f'{option.test_dir}/perl/{script}'
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import os
|
||||
import shutil
|
||||
|
||||
from unit.applications.proto import TestApplicationProto
|
||||
from unit.applications.proto import ApplicationProto
|
||||
from unit.option import option
|
||||
|
||||
|
||||
class TestApplicationPHP(TestApplicationProto):
|
||||
application_type = "php"
|
||||
class ApplicationPHP(ApplicationProto):
|
||||
def __init__(self, application_type='php'):
|
||||
self.application_type = application_type
|
||||
|
||||
def load(self, script, index='index.php', **kwargs):
|
||||
script_path = f'{option.test_dir}/php/{script}'
|
||||
|
|
|
@ -2,13 +2,14 @@ import os
|
|||
import shutil
|
||||
from urllib.parse import quote
|
||||
|
||||
from unit.applications.proto import TestApplicationProto
|
||||
from unit.applications.proto import ApplicationProto
|
||||
from unit.option import option
|
||||
|
||||
|
||||
class TestApplicationPython(TestApplicationProto):
|
||||
application_type = "python"
|
||||
load_module = "wsgi"
|
||||
class ApplicationPython(ApplicationProto):
|
||||
def __init__(self, application_type='python', load_module='wsgi'):
|
||||
self.application_type = application_type
|
||||
self.load_module = load_module
|
||||
|
||||
def load(self, script, name=None, module=None, **kwargs):
|
||||
if name is None:
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import shutil
|
||||
|
||||
from unit.applications.proto import TestApplicationProto
|
||||
from unit.applications.proto import ApplicationProto
|
||||
from unit.option import option
|
||||
from unit.utils import public_dir
|
||||
|
||||
|
||||
class TestApplicationRuby(TestApplicationProto):
|
||||
application_type = "ruby"
|
||||
class ApplicationRuby(ApplicationProto):
|
||||
def __init__(self, application_type='ruby'):
|
||||
self.application_type = application_type
|
||||
|
||||
def prepare_env(self, script):
|
||||
shutil.copytree(
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import os
|
||||
|
||||
from unit.control import TestControl
|
||||
from unit.control import Control
|
||||
from unit.option import option
|
||||
|
||||
|
||||
class TestApplicationProto(TestControl):
|
||||
class ApplicationProto(Control):
|
||||
application_type = None
|
||||
|
||||
def get_application_type(self):
|
||||
|
|
|
@ -2,15 +2,15 @@ import os
|
|||
import ssl
|
||||
import subprocess
|
||||
|
||||
from unit.applications.proto import TestApplicationProto
|
||||
from unit.applications.proto import ApplicationProto
|
||||
from unit.option import option
|
||||
|
||||
|
||||
class TestApplicationTLS(TestApplicationProto):
|
||||
def setup_method(self):
|
||||
self.context = ssl.create_default_context()
|
||||
self.context.check_hostname = False
|
||||
self.context.verify_mode = ssl.CERT_NONE
|
||||
class ApplicationTLS(ApplicationProto):
|
||||
def __init__(self):
|
||||
self._default_context = ssl.create_default_context()
|
||||
self._default_context.check_hostname = False
|
||||
self._default_context.verify_mode = ssl.CERT_NONE
|
||||
|
||||
def certificate(self, name='default', load=True):
|
||||
self.openssl_conf()
|
||||
|
@ -47,10 +47,12 @@ class TestApplicationTLS(TestApplicationProto):
|
|||
return self.conf(k.read() + c.read(), f'/certificates/{crt}')
|
||||
|
||||
def get_ssl(self, **kwargs):
|
||||
return self.get(wrapper=self.context.wrap_socket, **kwargs)
|
||||
context = kwargs.get('context', self._default_context)
|
||||
return self.get(wrapper=context.wrap_socket, **kwargs)
|
||||
|
||||
def post_ssl(self, **kwargs):
|
||||
return self.post(wrapper=self.context.wrap_socket, **kwargs)
|
||||
context = kwargs.get('context', self._default_context)
|
||||
return self.post(wrapper=context.wrap_socket, **kwargs)
|
||||
|
||||
def openssl_conf(self, rewrite=False, alt_names=None):
|
||||
alt_names = alt_names or []
|
||||
|
|
|
@ -6,12 +6,12 @@ import select
|
|||
import struct
|
||||
|
||||
import pytest
|
||||
from unit.applications.proto import TestApplicationProto
|
||||
from unit.applications.proto import ApplicationProto
|
||||
|
||||
GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
|
||||
|
||||
|
||||
class TestApplicationWebsocket(TestApplicationProto):
|
||||
class ApplicationWebsocket(ApplicationProto):
|
||||
|
||||
OP_CONT = 0x00
|
||||
OP_TEXT = 0x01
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import json
|
||||
|
||||
from unit.http import TestHTTP
|
||||
from unit.http import HTTP1
|
||||
from unit.option import option
|
||||
|
||||
http = TestHTTP()
|
||||
http = HTTP1()
|
||||
|
||||
|
||||
def check_chroot():
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from unit.applications.lang.go import TestApplicationGo
|
||||
from unit.applications.lang.go import ApplicationGo
|
||||
|
||||
|
||||
def check_go():
|
||||
return TestApplicationGo.prepare_env('empty') is not None
|
||||
return ApplicationGo.prepare_env('empty') is not None
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
import json
|
||||
import os
|
||||
|
||||
from unit.applications.lang.go import TestApplicationGo
|
||||
from unit.applications.lang.java import TestApplicationJava
|
||||
from unit.applications.lang.node import TestApplicationNode
|
||||
from unit.applications.lang.ruby import TestApplicationRuby
|
||||
from unit.http import TestHTTP
|
||||
from unit.applications.lang.go import ApplicationGo
|
||||
from unit.applications.lang.java import ApplicationJava
|
||||
from unit.applications.lang.node import ApplicationNode
|
||||
from unit.applications.lang.ruby import ApplicationRuby
|
||||
from unit.http import HTTP1
|
||||
from unit.option import option
|
||||
from unit.utils import getns
|
||||
|
||||
allns = ['pid', 'mnt', 'ipc', 'uts', 'cgroup', 'net']
|
||||
http = TestHTTP()
|
||||
http = HTTP1()
|
||||
|
||||
|
||||
def check_isolation():
|
||||
|
@ -18,7 +18,7 @@ def check_isolation():
|
|||
|
||||
conf = ''
|
||||
if 'go' in available['modules']:
|
||||
TestApplicationGo().prepare_env('empty', 'app')
|
||||
ApplicationGo().prepare_env('empty', 'app')
|
||||
|
||||
conf = {
|
||||
"listeners": {"*:7080": {"pass": "applications/empty"}},
|
||||
|
@ -64,7 +64,7 @@ def check_isolation():
|
|||
}
|
||||
|
||||
elif 'ruby' in available['modules']:
|
||||
TestApplicationRuby().prepare_env('empty')
|
||||
ApplicationRuby().prepare_env('empty')
|
||||
|
||||
conf = {
|
||||
"listeners": {"*:7080": {"pass": "applications/empty"}},
|
||||
|
@ -80,7 +80,7 @@ def check_isolation():
|
|||
}
|
||||
|
||||
elif 'java' in available['modules']:
|
||||
TestApplicationJava().prepare_env('empty')
|
||||
ApplicationJava().prepare_env('empty')
|
||||
|
||||
conf = {
|
||||
"listeners": {"*:7080": {"pass": "applications/empty"}},
|
||||
|
@ -97,7 +97,7 @@ def check_isolation():
|
|||
}
|
||||
|
||||
elif 'node' in available['modules']:
|
||||
TestApplicationNode().prepare_env('basic')
|
||||
ApplicationNode().prepare_env('basic')
|
||||
|
||||
conf = {
|
||||
"listeners": {"*:7080": {"pass": "applications/basic"}},
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import json
|
||||
|
||||
from unit.http import TestHTTP
|
||||
from unit.http import HTTP1
|
||||
from unit.option import option
|
||||
|
||||
http = TestHTTP()
|
||||
http = HTTP1()
|
||||
|
||||
|
||||
def check_unix_abstract():
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import json
|
||||
|
||||
from unit.http import TestHTTP
|
||||
from unit.http import HTTP1
|
||||
from unit.option import option
|
||||
|
||||
|
||||
|
@ -29,7 +29,7 @@ def args_handler(conf_func):
|
|||
return args_wrapper
|
||||
|
||||
|
||||
class TestControl(TestHTTP):
|
||||
class Control(HTTP1):
|
||||
@args_handler
|
||||
def conf(self, conf, url):
|
||||
return self.put(**self._get_args(url, conf))['body']
|
||||
|
|
|
@ -10,7 +10,7 @@ import pytest
|
|||
from unit.option import option
|
||||
|
||||
|
||||
class TestHTTP:
|
||||
class HTTP1:
|
||||
def http(self, start_str, **kwargs):
|
||||
sock_type = kwargs.get('sock_type', 'ipv4')
|
||||
port = kwargs.get('port', 7080)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import os
|
||||
import platform
|
||||
|
||||
|
||||
class Options:
|
||||
_options = {
|
||||
'architecture': platform.architecture()[0],
|
||||
|
@ -8,7 +9,7 @@ class Options:
|
|||
'is_privileged': os.geteuid() == 0,
|
||||
'skip_alerts': [],
|
||||
'skip_sanitizer': False,
|
||||
'system': platform.system()
|
||||
'system': platform.system(),
|
||||
}
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
from unit.control import TestControl
|
||||
from unit.control import Control
|
||||
|
||||
|
||||
class Status:
|
||||
_status = None
|
||||
control = TestControl()
|
||||
control = Control()
|
||||
|
||||
def _check_zeros():
|
||||
assert Status.control.conf_get('/status') == {
|
||||
|
|
Loading…
Reference in a new issue