Tests: migrated to the pytest.
This commit is contained in:
parent
77ecb6ab49
commit
d5e9159340
55 changed files with 4717 additions and 6262 deletions
|
@ -299,7 +299,7 @@ test: unit modules
|
|||
test -h debuild/unit-$(VERSION)/debian/build-unit/build/$${soname} || \
|
||||
ln -fs `pwd`/$${so} debuild/unit-$(VERSION)/debian/build-unit/build/$${soname} ; \
|
||||
done ; \
|
||||
( cd debuild/unit-$(VERSION)/debian/build-unit && ./test/run.py ) ; \
|
||||
( cd debuild/unit-$(VERSION)/debian/build-unit && env python3 -m pytest ) ; \
|
||||
}
|
||||
|
||||
test-debug: unit modules
|
||||
|
@ -310,7 +310,7 @@ test-debug: unit modules
|
|||
test -h debuild/unit-$(VERSION)/debian/build-unit-debug/build/$${soname} || \
|
||||
ln -fs `pwd`/$${so} debuild/unit-$(VERSION)/debian/build-unit-debug/build/$${soname} ; \
|
||||
done ; \
|
||||
( cd debuild/unit-$(VERSION)/debian/build-unit-debug && ./test/run.py ) ; \
|
||||
( cd debuild/unit-$(VERSION)/debian/build-unit-debug && env python3 -m pytest ) ; \
|
||||
}
|
||||
|
||||
clean:
|
||||
|
|
|
@ -274,7 +274,7 @@ test: unit modules
|
|||
test -h rpmbuild/BUILD/unit-$(VERSION)/build-nodebug/$${soname} || \
|
||||
ln -fs `pwd`/$${so} rpmbuild/BUILD/unit-$(VERSION)/build-nodebug/$${soname} ; \
|
||||
done ; \
|
||||
( cd rpmbuild/BUILD/unit-$(VERSION) && rm -f build && ln -s build-nodebug build && ./test/run.py ) ; \
|
||||
( cd rpmbuild/BUILD/unit-$(VERSION) && rm -f build && ln -s build-nodebug build && env python3 -m pytest ) ; \
|
||||
}
|
||||
|
||||
test-debug: unit modules
|
||||
|
@ -285,7 +285,7 @@ test-debug: unit modules
|
|||
test -h rpmbuild/BUILD/unit-$(VERSION)/build-debug/$${soname} || \
|
||||
ln -fs `pwd`/$${so} rpmbuild/BUILD/unit-$(VERSION)/build-debug/$${soname} ; \
|
||||
done ; \
|
||||
( cd rpmbuild/BUILD/unit-$(VERSION) && rm -f build && ln -s build-debug build && ./test/run.py ) ; \
|
||||
( cd rpmbuild/BUILD/unit-$(VERSION) && rm -f build && ln -s build-debug build && env python3 -m pytest ) ; \
|
||||
}
|
||||
|
||||
clean:
|
||||
|
|
299
test/conftest.py
Normal file
299
test/conftest.py
Normal file
|
@ -0,0 +1,299 @@
|
|||
import fcntl
|
||||
import os
|
||||
import platform
|
||||
import pytest
|
||||
import signal
|
||||
import stat
|
||||
import subprocess
|
||||
import sys
|
||||
import re
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
|
||||
def pytest_addoption(parser):
|
||||
parser.addoption(
|
||||
"--detailed",
|
||||
default=False,
|
||||
action="store_true",
|
||||
help="Detailed output for tests",
|
||||
)
|
||||
parser.addoption(
|
||||
"--print_log",
|
||||
default=False,
|
||||
action="store_true",
|
||||
help="Print unit.log to stdout in case of errors",
|
||||
)
|
||||
parser.addoption(
|
||||
"--save_log",
|
||||
default=False,
|
||||
action="store_true",
|
||||
help="Save unit.log after the test execution",
|
||||
)
|
||||
parser.addoption(
|
||||
"--unsafe",
|
||||
default=False,
|
||||
action="store_true",
|
||||
help="Run unsafe tests",
|
||||
)
|
||||
|
||||
|
||||
unit_instance = {}
|
||||
option = None
|
||||
|
||||
|
||||
def pytest_configure(config):
|
||||
global option
|
||||
option = config.option
|
||||
|
||||
option.generated_tests = {}
|
||||
option.current_dir = os.path.abspath(
|
||||
os.path.join(os.path.dirname(__file__), os.pardir)
|
||||
)
|
||||
option.test_dir = option.current_dir + '/test'
|
||||
option.architecture = platform.architecture()[0]
|
||||
option.system = platform.system()
|
||||
|
||||
# set stdout to non-blocking
|
||||
|
||||
if option.detailed or option.print_log:
|
||||
fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, 0)
|
||||
|
||||
|
||||
def pytest_generate_tests(metafunc):
|
||||
cls = metafunc.cls
|
||||
if not hasattr(cls, 'application_type'):
|
||||
return
|
||||
|
||||
type = cls.application_type
|
||||
|
||||
# take available module from option and generate tests for each version
|
||||
|
||||
for module in cls.prerequisites['modules']:
|
||||
if module in option.available['modules']:
|
||||
prereq_version = cls.prerequisites['modules'][module]
|
||||
available_versions = option.available['modules'][module]
|
||||
|
||||
if prereq_version == 'all':
|
||||
metafunc.fixturenames.append('tmp_ct')
|
||||
metafunc.parametrize('tmp_ct', range(len(available_versions)))
|
||||
|
||||
for i in range(len(available_versions)):
|
||||
version = available_versions[i]
|
||||
option.generated_tests[
|
||||
metafunc.function.__name__ + '[{}]'.format(i)
|
||||
] = (type + ' ' + version)
|
||||
elif prereq_version == 'any':
|
||||
option.generated_tests[metafunc.function.__name__] = (
|
||||
type + ' ' + available_versions[0]
|
||||
)
|
||||
else:
|
||||
for version in available_versions:
|
||||
if version.startswith(prereq_version):
|
||||
option.generated_tests[metafunc.function.__name__] = (
|
||||
type + ' ' + version
|
||||
)
|
||||
|
||||
|
||||
def pytest_sessionstart(session):
|
||||
option.available = {'modules': {}, 'features': {}}
|
||||
|
||||
unit = unit_run()
|
||||
|
||||
# read unit.log
|
||||
|
||||
for i in range(50):
|
||||
with open(unit['temp_dir'] + '/unit.log', 'r') as f:
|
||||
log = f.read()
|
||||
m = re.search('controller started', log)
|
||||
|
||||
if m is None:
|
||||
time.sleep(0.1)
|
||||
else:
|
||||
break
|
||||
|
||||
if m is None:
|
||||
_print_log()
|
||||
exit("Unit is writing log too long")
|
||||
|
||||
# discover available modules from unit.log
|
||||
|
||||
for module in re.findall(r'module: ([a-zA-Z]+) (.*) ".*"$', log, re.M):
|
||||
if module[0] not in option.available['modules']:
|
||||
option.available['modules'][module[0]] = [module[1]]
|
||||
else:
|
||||
option.available['modules'][module[0]].append(module[1])
|
||||
|
||||
unit_stop()
|
||||
|
||||
|
||||
def setup_method(self):
|
||||
option.skip_alerts = [
|
||||
r'read signalfd\(4\) failed',
|
||||
r'sendmsg.+failed',
|
||||
r'recvmsg.+failed',
|
||||
]
|
||||
option.skip_sanitizer = False
|
||||
|
||||
def unit_run():
|
||||
global unit_instance
|
||||
build_dir = option.current_dir + '/build'
|
||||
unitd = build_dir + '/unitd'
|
||||
|
||||
if not os.path.isfile(unitd):
|
||||
exit('Could not find unit')
|
||||
|
||||
temp_dir = tempfile.mkdtemp(prefix='unit-test-')
|
||||
public_dir(temp_dir)
|
||||
|
||||
if oct(stat.S_IMODE(os.stat(build_dir).st_mode)) != '0o777':
|
||||
public_dir(build_dir)
|
||||
|
||||
os.mkdir(temp_dir + '/state')
|
||||
|
||||
with open(temp_dir + '/unit.log', 'w') as log:
|
||||
unit_instance['process'] = subprocess.Popen(
|
||||
[
|
||||
unitd,
|
||||
'--no-daemon',
|
||||
'--modules',
|
||||
build_dir,
|
||||
'--state',
|
||||
temp_dir + '/state',
|
||||
'--pid',
|
||||
temp_dir + '/unit.pid',
|
||||
'--log',
|
||||
temp_dir + '/unit.log',
|
||||
'--control',
|
||||
'unix:' + temp_dir + '/control.unit.sock',
|
||||
'--tmp',
|
||||
temp_dir,
|
||||
],
|
||||
stderr=log,
|
||||
)
|
||||
|
||||
if not waitforfiles(temp_dir + '/control.unit.sock'):
|
||||
_print_log()
|
||||
exit('Could not start unit')
|
||||
|
||||
# dumb (TODO: remove)
|
||||
option.skip_alerts = [
|
||||
r'read signalfd\(4\) failed',
|
||||
r'sendmsg.+failed',
|
||||
r'recvmsg.+failed',
|
||||
]
|
||||
option.skip_sanitizer = False
|
||||
|
||||
unit_instance['temp_dir'] = temp_dir
|
||||
unit_instance['log'] = temp_dir + '/unit.log'
|
||||
unit_instance['control_sock'] = temp_dir + '/control.unit.sock'
|
||||
unit_instance['unitd'] = unitd
|
||||
|
||||
return unit_instance
|
||||
|
||||
|
||||
def unit_stop():
|
||||
p = unit_instance['process']
|
||||
|
||||
if p.poll() is not None:
|
||||
return
|
||||
|
||||
p.send_signal(signal.SIGQUIT)
|
||||
|
||||
try:
|
||||
retcode = p.wait(15)
|
||||
if retcode:
|
||||
return 'Child process terminated with code ' + str(retcode)
|
||||
except:
|
||||
p.kill()
|
||||
return 'Could not terminate unit'
|
||||
|
||||
|
||||
def public_dir(path):
|
||||
os.chmod(path, 0o777)
|
||||
|
||||
for root, dirs, files in os.walk(path):
|
||||
for d in dirs:
|
||||
os.chmod(os.path.join(root, d), 0o777)
|
||||
for f in files:
|
||||
os.chmod(os.path.join(root, f), 0o777)
|
||||
|
||||
def waitforfiles(*files):
|
||||
for i in range(50):
|
||||
wait = False
|
||||
ret = False
|
||||
|
||||
for f in files:
|
||||
if not os.path.exists(f):
|
||||
wait = True
|
||||
break
|
||||
|
||||
if wait:
|
||||
time.sleep(0.1)
|
||||
|
||||
else:
|
||||
ret = True
|
||||
break
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def skip_alert(*alerts):
|
||||
option.skip_alerts.extend(alerts)
|
||||
|
||||
|
||||
def _check_alerts(log):
|
||||
found = False
|
||||
|
||||
alerts = re.findall(r'.+\[alert\].+', log)
|
||||
|
||||
if alerts:
|
||||
print('All alerts/sanitizer errors found in log:')
|
||||
[print(alert) for alert in alerts]
|
||||
found = True
|
||||
|
||||
if option.skip_alerts:
|
||||
for skip in option.skip_alerts:
|
||||
alerts = [al for al in alerts if re.search(skip, al) is None]
|
||||
|
||||
if alerts:
|
||||
_print_log(log)
|
||||
assert not alerts, 'alert(s)'
|
||||
|
||||
if not option.skip_sanitizer:
|
||||
sanitizer_errors = re.findall('.+Sanitizer.+', log)
|
||||
|
||||
if sanitizer_errors:
|
||||
_print_log(log)
|
||||
assert not sanitizer_errors, 'sanitizer error(s)'
|
||||
|
||||
if found:
|
||||
print('skipped.')
|
||||
|
||||
|
||||
def _print_log(data=None):
|
||||
unit_log = unit_instance['log']
|
||||
|
||||
print('Path to unit.log:\n' + unit_log + '\n')
|
||||
|
||||
if option.print_log:
|
||||
os.set_blocking(sys.stdout.fileno(), True)
|
||||
sys.stdout.flush()
|
||||
|
||||
if data is None:
|
||||
with open(unit_log, 'r', encoding='utf-8', errors='ignore') as f:
|
||||
shutil.copyfileobj(f, sys.stdout)
|
||||
else:
|
||||
sys.stdout.write(data)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def is_unsafe(request):
|
||||
return request.config.getoption("--unsafe")
|
||||
|
||||
@pytest.fixture
|
||||
def is_su(request):
|
||||
return os.geteuid() == 0
|
||||
|
||||
def pytest_sessionfinish(session):
|
||||
unit_stop()
|
19
test/run.py
19
test/run.py
|
@ -1,19 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
if __name__ == '__main__':
|
||||
loader = unittest.TestLoader()
|
||||
suite = unittest.TestSuite()
|
||||
|
||||
this_dir = os.path.dirname(__file__)
|
||||
tests = loader.discover(start_dir=this_dir)
|
||||
suite.addTests(tests)
|
||||
|
||||
runner = unittest.TextTestRunner(stream=sys.stdout, verbosity=3)
|
||||
result = runner.run(suite)
|
||||
|
||||
ret = not (len(result.failures) == len(result.errors) == 0)
|
||||
|
||||
sys.exit(ret)
|
|
@ -1,5 +1,5 @@
|
|||
import pytest
|
||||
import time
|
||||
import unittest
|
||||
|
||||
from unit.applications.lang.python import TestApplicationPython
|
||||
|
||||
|
@ -10,11 +10,9 @@ class TestAccessLog(TestApplicationPython):
|
|||
def load(self, script):
|
||||
super().load(script)
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf('"' + self.testdir + '/access.log"', 'access_log'),
|
||||
'access_log configure',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
'"' + self.temp_dir + '/access.log"', 'access_log'
|
||||
), 'access_log configure'
|
||||
|
||||
def wait_for_record(self, pattern, name='access.log'):
|
||||
return super().wait_for_record(pattern, name)
|
||||
|
@ -22,7 +20,7 @@ class TestAccessLog(TestApplicationPython):
|
|||
def test_access_log_keepalive(self):
|
||||
self.load('mirror')
|
||||
|
||||
self.assertEqual(self.get()['status'], 200, 'init')
|
||||
assert self.get()['status'] == 200, 'init'
|
||||
|
||||
(resp, sock) = self.post(
|
||||
headers={
|
||||
|
@ -35,9 +33,9 @@ class TestAccessLog(TestApplicationPython):
|
|||
read_timeout=1,
|
||||
)
|
||||
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(r'"POST / HTTP/1.1" 200 5'), 'keepalive 1'
|
||||
)
|
||||
assert (
|
||||
self.wait_for_record(r'"POST / HTTP/1.1" 200 5') is not None
|
||||
), 'keepalive 1'
|
||||
|
||||
resp = self.post(
|
||||
headers={
|
||||
|
@ -51,9 +49,9 @@ class TestAccessLog(TestApplicationPython):
|
|||
|
||||
self.stop()
|
||||
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(r'"POST / HTTP/1.1" 200 10'), 'keepalive 2'
|
||||
)
|
||||
assert (
|
||||
self.wait_for_record(r'"POST / HTTP/1.1" 200 10') is not None
|
||||
), 'keepalive 2'
|
||||
|
||||
def test_access_log_pipeline(self):
|
||||
self.load('empty')
|
||||
|
@ -79,18 +77,18 @@ Connection: close
|
|||
|
||||
self.stop()
|
||||
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(r'"GET / HTTP/1.1" 200 0 "Referer-1" "-"'),
|
||||
'pipeline 1',
|
||||
)
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(r'"GET / HTTP/1.1" 200 0 "Referer-2" "-"'),
|
||||
'pipeline 2',
|
||||
)
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(r'"GET / HTTP/1.1" 200 0 "Referer-3" "-"'),
|
||||
'pipeline 3',
|
||||
)
|
||||
assert (
|
||||
self.wait_for_record(r'"GET / HTTP/1.1" 200 0 "Referer-1" "-"')
|
||||
is not None
|
||||
), 'pipeline 1'
|
||||
assert (
|
||||
self.wait_for_record(r'"GET / HTTP/1.1" 200 0 "Referer-2" "-"')
|
||||
is not None
|
||||
), 'pipeline 2'
|
||||
assert (
|
||||
self.wait_for_record(r'"GET / HTTP/1.1" 200 0 "Referer-3" "-"')
|
||||
is not None
|
||||
), 'pipeline 3'
|
||||
|
||||
def test_access_log_ipv6(self):
|
||||
self.load('empty')
|
||||
|
@ -101,17 +99,17 @@ Connection: close
|
|||
|
||||
self.stop()
|
||||
|
||||
self.assertIsNotNone(
|
||||
assert (
|
||||
self.wait_for_record(
|
||||
r'::1 - - \[.+\] "GET / HTTP/1.1" 200 0 "-" "-"'
|
||||
),
|
||||
'ipv6',
|
||||
)
|
||||
)
|
||||
is not None
|
||||
), 'ipv6'
|
||||
|
||||
def test_access_log_unix(self):
|
||||
self.load('empty')
|
||||
|
||||
addr = self.testdir + '/sock'
|
||||
addr = self.temp_dir + '/sock'
|
||||
|
||||
self.conf(
|
||||
{"unix:" + addr: {"pass": "applications/empty"}}, 'listeners'
|
||||
|
@ -121,12 +119,12 @@ Connection: close
|
|||
|
||||
self.stop()
|
||||
|
||||
self.assertIsNotNone(
|
||||
assert (
|
||||
self.wait_for_record(
|
||||
r'unix: - - \[.+\] "GET / HTTP/1.1" 200 0 "-" "-"'
|
||||
),
|
||||
'unix',
|
||||
)
|
||||
)
|
||||
is not None
|
||||
), 'unix'
|
||||
|
||||
def test_access_log_referer(self):
|
||||
self.load('empty')
|
||||
|
@ -141,12 +139,10 @@ Connection: close
|
|||
|
||||
self.stop()
|
||||
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(
|
||||
r'"GET / HTTP/1.1" 200 0 "referer-value" "-"'
|
||||
),
|
||||
'referer',
|
||||
)
|
||||
assert (
|
||||
self.wait_for_record(r'"GET / HTTP/1.1" 200 0 "referer-value" "-"')
|
||||
is not None
|
||||
), 'referer'
|
||||
|
||||
def test_access_log_user_agent(self):
|
||||
self.load('empty')
|
||||
|
@ -161,12 +157,12 @@ Connection: close
|
|||
|
||||
self.stop()
|
||||
|
||||
self.assertIsNotNone(
|
||||
assert (
|
||||
self.wait_for_record(
|
||||
r'"GET / HTTP/1.1" 200 0 "-" "user-agent-value"'
|
||||
),
|
||||
'user agent',
|
||||
)
|
||||
)
|
||||
is not None
|
||||
), 'user agent'
|
||||
|
||||
def test_access_log_http10(self):
|
||||
self.load('empty')
|
||||
|
@ -175,14 +171,14 @@ Connection: close
|
|||
|
||||
self.stop()
|
||||
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(r'"GET / HTTP/1.0" 200 0 "-" "-"'), 'http 1.0'
|
||||
)
|
||||
assert (
|
||||
self.wait_for_record(r'"GET / HTTP/1.0" 200 0 "-" "-"') is not None
|
||||
), 'http 1.0'
|
||||
|
||||
def test_access_log_partial(self):
|
||||
self.load('empty')
|
||||
|
||||
self.assertEqual(self.post()['status'], 200, 'init')
|
||||
assert self.post()['status'] == 200, 'init'
|
||||
|
||||
resp = self.http(b"""GE""", raw=True, read_timeout=1)
|
||||
|
||||
|
@ -190,27 +186,27 @@ Connection: close
|
|||
|
||||
self.stop()
|
||||
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(r'"GE" 400 0 "-" "-"'), 'partial'
|
||||
)
|
||||
assert (
|
||||
self.wait_for_record(r'"GE" 400 0 "-" "-"') is not None
|
||||
), 'partial'
|
||||
|
||||
def test_access_log_partial_2(self):
|
||||
self.load('empty')
|
||||
|
||||
self.assertEqual(self.post()['status'], 200, 'init')
|
||||
assert self.post()['status'] == 200, 'init'
|
||||
|
||||
self.http(b"""GET /\n""", raw=True)
|
||||
|
||||
self.stop()
|
||||
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(r'"GET /" 400 \d+ "-" "-"'), 'partial 2'
|
||||
)
|
||||
assert (
|
||||
self.wait_for_record(r'"GET /" 400 \d+ "-" "-"') is not None
|
||||
), 'partial 2'
|
||||
|
||||
def test_access_log_partial_3(self):
|
||||
self.load('empty')
|
||||
|
||||
self.assertEqual(self.post()['status'], 200, 'init')
|
||||
assert self.post()['status'] == 200, 'init'
|
||||
|
||||
resp = self.http(b"""GET / HTTP/1.1""", raw=True, read_timeout=1)
|
||||
|
||||
|
@ -218,14 +214,14 @@ Connection: close
|
|||
|
||||
self.stop()
|
||||
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(r'"GET /" 400 0 "-" "-"'), 'partial 3'
|
||||
)
|
||||
assert (
|
||||
self.wait_for_record(r'"GET /" 400 0 "-" "-"') is not None
|
||||
), 'partial 3'
|
||||
|
||||
def test_access_log_partial_4(self):
|
||||
self.load('empty')
|
||||
|
||||
self.assertEqual(self.post()['status'], 200, 'init')
|
||||
assert self.post()['status'] == 200, 'init'
|
||||
|
||||
resp = self.http(b"""GET / HTTP/1.1\n""", raw=True, read_timeout=1)
|
||||
|
||||
|
@ -233,25 +229,24 @@ Connection: close
|
|||
|
||||
self.stop()
|
||||
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(r'"GET / HTTP/1.1" 400 0 "-" "-"'),
|
||||
'partial 4',
|
||||
)
|
||||
assert (
|
||||
self.wait_for_record(r'"GET / HTTP/1.1" 400 0 "-" "-"') is not None
|
||||
), 'partial 4'
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_access_log_partial_5(self):
|
||||
self.load('empty')
|
||||
|
||||
self.assertEqual(self.post()['status'], 200, 'init')
|
||||
assert self.post()['status'] == 200, 'init'
|
||||
|
||||
self.get(headers={'Connection': 'close'})
|
||||
|
||||
self.stop()
|
||||
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(r'"GET / HTTP/1.1" 400 \d+ "-" "-"'),
|
||||
'partial 5',
|
||||
)
|
||||
assert (
|
||||
self.wait_for_record(r'"GET / HTTP/1.1" 400 \d+ "-" "-"')
|
||||
is not None
|
||||
), 'partial 5'
|
||||
|
||||
def test_access_log_get_parameters(self):
|
||||
self.load('empty')
|
||||
|
@ -260,12 +255,12 @@ Connection: close
|
|||
|
||||
self.stop()
|
||||
|
||||
self.assertIsNotNone(
|
||||
assert (
|
||||
self.wait_for_record(
|
||||
r'"GET /\?blah&var=val HTTP/1.1" 200 0 "-" "-"'
|
||||
),
|
||||
'get parameters',
|
||||
)
|
||||
)
|
||||
is not None
|
||||
), 'get parameters'
|
||||
|
||||
def test_access_log_delete(self):
|
||||
self.load('empty')
|
||||
|
@ -276,25 +271,20 @@ Connection: close
|
|||
|
||||
self.stop()
|
||||
|
||||
self.assertIsNone(
|
||||
self.search_in_log(r'/delete', 'access.log'), 'delete'
|
||||
)
|
||||
assert self.search_in_log(r'/delete', 'access.log') is None, 'delete'
|
||||
|
||||
def test_access_log_change(self):
|
||||
self.load('empty')
|
||||
|
||||
self.get()
|
||||
|
||||
self.conf('"' + self.testdir + '/new.log"', 'access_log')
|
||||
self.conf('"' + self.temp_dir + '/new.log"', 'access_log')
|
||||
|
||||
self.get()
|
||||
|
||||
self.stop()
|
||||
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(r'"GET / HTTP/1.1" 200 0 "-" "-"', 'new.log'),
|
||||
'change',
|
||||
)
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestAccessLog.main()
|
||||
assert (
|
||||
self.wait_for_record(r'"GET / HTTP/1.1" 200 0 "-" "-"', 'new.log')
|
||||
is not None
|
||||
), 'change'
|
||||
|
|
|
@ -1,22 +1,21 @@
|
|||
import unittest
|
||||
import pytest
|
||||
|
||||
from unit.control import TestControl
|
||||
from conftest import skip_alert
|
||||
|
||||
|
||||
class TestConfiguration(TestControl):
|
||||
prerequisites = {'modules': {'python': 'any'}}
|
||||
|
||||
def test_json_empty(self):
|
||||
self.assertIn('error', self.conf(''), 'empty')
|
||||
assert 'error' in self.conf(''), 'empty'
|
||||
|
||||
def test_json_leading_zero(self):
|
||||
self.assertIn('error', self.conf('00'), 'leading zero')
|
||||
assert 'error' in self.conf('00'), 'leading zero'
|
||||
|
||||
def test_json_unicode(self):
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
b"""
|
||||
assert 'success' in self.conf(
|
||||
b"""
|
||||
{
|
||||
"ap\u0070": {
|
||||
"type": "\u0070ython",
|
||||
|
@ -26,50 +25,36 @@ class TestConfiguration(TestControl):
|
|||
}
|
||||
}
|
||||
""",
|
||||
'applications',
|
||||
),
|
||||
'unicode',
|
||||
)
|
||||
'applications',
|
||||
), 'unicode'
|
||||
|
||||
self.assertDictEqual(
|
||||
self.conf_get('applications'),
|
||||
assert self.conf_get('applications') == {
|
||||
"app": {
|
||||
"type": "python",
|
||||
"processes": {"spare": 0},
|
||||
"path": "/app",
|
||||
"module": "wsgi",
|
||||
}
|
||||
}, 'unicode get'
|
||||
|
||||
def test_json_unicode_2(self):
|
||||
assert 'success' in self.conf(
|
||||
{
|
||||
"app": {
|
||||
"приложение": {
|
||||
"type": "python",
|
||||
"processes": {"spare": 0},
|
||||
"path": "/app",
|
||||
"module": "wsgi",
|
||||
}
|
||||
},
|
||||
'unicode get',
|
||||
)
|
||||
'applications',
|
||||
), 'unicode 2'
|
||||
|
||||
def test_json_unicode_2(self):
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{
|
||||
"приложение": {
|
||||
"type": "python",
|
||||
"processes": {"spare": 0},
|
||||
"path": "/app",
|
||||
"module": "wsgi",
|
||||
}
|
||||
},
|
||||
'applications',
|
||||
),
|
||||
'unicode 2',
|
||||
)
|
||||
|
||||
self.assertIn(
|
||||
'приложение', self.conf_get('applications'), 'unicode 2 get'
|
||||
)
|
||||
assert 'приложение' in self.conf_get('applications'), 'unicode 2 get'
|
||||
|
||||
def test_json_unicode_number(self):
|
||||
self.assertIn(
|
||||
'error',
|
||||
self.conf(
|
||||
b"""
|
||||
assert 'error' in self.conf(
|
||||
b"""
|
||||
{
|
||||
"app": {
|
||||
"type": "python",
|
||||
|
@ -79,16 +64,12 @@ class TestConfiguration(TestControl):
|
|||
}
|
||||
}
|
||||
""",
|
||||
'applications',
|
||||
),
|
||||
'unicode number',
|
||||
)
|
||||
'applications',
|
||||
), 'unicode number'
|
||||
|
||||
def test_json_utf8_bom(self):
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
b"""\xEF\xBB\xBF
|
||||
assert 'success' in self.conf(
|
||||
b"""\xEF\xBB\xBF
|
||||
{
|
||||
"app": {
|
||||
"type": "python",
|
||||
|
@ -98,16 +79,12 @@ class TestConfiguration(TestControl):
|
|||
}
|
||||
}
|
||||
""",
|
||||
'applications',
|
||||
),
|
||||
'UTF-8 BOM',
|
||||
)
|
||||
'applications',
|
||||
), 'UTF-8 BOM'
|
||||
|
||||
def test_json_comment_single_line(self):
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
b"""
|
||||
assert 'success' in self.conf(
|
||||
b"""
|
||||
// this is bridge
|
||||
{
|
||||
"//app": {
|
||||
|
@ -121,16 +98,12 @@ class TestConfiguration(TestControl):
|
|||
}
|
||||
// end of json \xEF\t
|
||||
""",
|
||||
'applications',
|
||||
),
|
||||
'single line comments',
|
||||
)
|
||||
'applications',
|
||||
), 'single line comments'
|
||||
|
||||
def test_json_comment_multi_line(self):
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
b"""
|
||||
assert 'success' in self.conf(
|
||||
b"""
|
||||
/* this is bridge */
|
||||
{
|
||||
"/*app": {
|
||||
|
@ -148,41 +121,31 @@ class TestConfiguration(TestControl):
|
|||
}
|
||||
/* end of json \xEF\t\b */
|
||||
""",
|
||||
'applications',
|
||||
),
|
||||
'multi line comments',
|
||||
)
|
||||
'applications',
|
||||
), 'multi line comments'
|
||||
|
||||
def test_json_comment_invalid(self):
|
||||
self.assertIn('error', self.conf(b'/{}', 'applications'), 'slash')
|
||||
self.assertIn('error', self.conf(b'//{}', 'applications'), 'comment')
|
||||
self.assertIn('error', self.conf(b'{} /', 'applications'), 'slash end')
|
||||
self.assertIn(
|
||||
'error', self.conf(b'/*{}', 'applications'), 'slash star'
|
||||
)
|
||||
self.assertIn(
|
||||
'error', self.conf(b'{} /*', 'applications'), 'slash star end'
|
||||
)
|
||||
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):
|
||||
self.assertIn('error', self.conf('{', 'applications'), 'open brace')
|
||||
assert 'error' in self.conf('{', 'applications'), 'open brace'
|
||||
|
||||
def test_applications_string(self):
|
||||
self.assertIn('error', self.conf('"{}"', 'applications'), 'string')
|
||||
assert 'error' in self.conf('"{}"', 'applications'), 'string'
|
||||
|
||||
@unittest.skip('not yet, unsafe')
|
||||
@pytest.mark.skip('not yet, unsafe')
|
||||
def test_applications_type_only(self):
|
||||
self.assertIn(
|
||||
'error',
|
||||
self.conf({"app": {"type": "python"}}, 'applications'),
|
||||
'type only',
|
||||
)
|
||||
assert 'error' in self.conf(
|
||||
{"app": {"type": "python"}}, 'applications'
|
||||
), 'type only'
|
||||
|
||||
def test_applications_miss_quote(self):
|
||||
self.assertIn(
|
||||
'error',
|
||||
self.conf(
|
||||
"""
|
||||
assert 'error' in self.conf(
|
||||
"""
|
||||
{
|
||||
app": {
|
||||
"type": "python",
|
||||
|
@ -192,16 +155,12 @@ class TestConfiguration(TestControl):
|
|||
}
|
||||
}
|
||||
""",
|
||||
'applications',
|
||||
),
|
||||
'miss quote',
|
||||
)
|
||||
'applications',
|
||||
), 'miss quote'
|
||||
|
||||
def test_applications_miss_colon(self):
|
||||
self.assertIn(
|
||||
'error',
|
||||
self.conf(
|
||||
"""
|
||||
assert 'error' in self.conf(
|
||||
"""
|
||||
{
|
||||
"app" {
|
||||
"type": "python",
|
||||
|
@ -211,16 +170,12 @@ class TestConfiguration(TestControl):
|
|||
}
|
||||
}
|
||||
""",
|
||||
'applications',
|
||||
),
|
||||
'miss colon',
|
||||
)
|
||||
'applications',
|
||||
), 'miss colon'
|
||||
|
||||
def test_applications_miss_comma(self):
|
||||
self.assertIn(
|
||||
'error',
|
||||
self.conf(
|
||||
"""
|
||||
assert 'error' in self.conf(
|
||||
"""
|
||||
{
|
||||
"app": {
|
||||
"type": "python"
|
||||
|
@ -230,144 +185,117 @@ class TestConfiguration(TestControl):
|
|||
}
|
||||
}
|
||||
""",
|
||||
'applications',
|
||||
),
|
||||
'miss comma',
|
||||
)
|
||||
'applications',
|
||||
), 'miss comma'
|
||||
|
||||
def test_applications_skip_spaces(self):
|
||||
self.assertIn(
|
||||
'success', self.conf(b'{ \n\r\t}', 'applications'), 'skip spaces'
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
b'{ \n\r\t}', 'applications'
|
||||
), 'skip spaces'
|
||||
|
||||
def test_applications_relative_path(self):
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{
|
||||
assert 'success' in self.conf(
|
||||
{
|
||||
"app": {
|
||||
"type": "python",
|
||||
"processes": {"spare": 0},
|
||||
"path": "../app",
|
||||
"module": "wsgi",
|
||||
}
|
||||
},
|
||||
'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(
|
||||
{"*:7080": {"pass": "applications/app"}}, 'listeners'
|
||||
), 'listeners no app'
|
||||
|
||||
def test_listeners_wildcard(self):
|
||||
assert 'success' in self.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "applications/app"}},
|
||||
"applications": {
|
||||
"app": {
|
||||
"type": "python",
|
||||
"processes": {"spare": 0},
|
||||
"path": "../app",
|
||||
"path": "/app",
|
||||
"module": "wsgi",
|
||||
}
|
||||
},
|
||||
'applications',
|
||||
),
|
||||
'relative path',
|
||||
)
|
||||
|
||||
@unittest.skip('not yet, unsafe')
|
||||
def test_listeners_empty(self):
|
||||
self.assertIn(
|
||||
'error', self.conf({"*:7080": {}}, 'listeners'), 'listener empty'
|
||||
)
|
||||
|
||||
def test_listeners_no_app(self):
|
||||
self.assertIn(
|
||||
'error',
|
||||
self.conf({"*:7080": {"pass": "applications/app"}}, 'listeners'),
|
||||
'listeners no app',
|
||||
)
|
||||
|
||||
def test_listeners_wildcard(self):
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "applications/app"}},
|
||||
"applications": {
|
||||
"app": {
|
||||
"type": "python",
|
||||
"processes": {"spare": 0},
|
||||
"path": "/app",
|
||||
"module": "wsgi",
|
||||
}
|
||||
},
|
||||
}
|
||||
),
|
||||
'listeners wildcard',
|
||||
)
|
||||
}
|
||||
), 'listeners wildcard'
|
||||
|
||||
def test_listeners_explicit(self):
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{
|
||||
"listeners": {"127.0.0.1:7080": {"pass": "applications/app"}},
|
||||
"applications": {
|
||||
"app": {
|
||||
"type": "python",
|
||||
"processes": {"spare": 0},
|
||||
"path": "/app",
|
||||
"module": "wsgi",
|
||||
}
|
||||
},
|
||||
}
|
||||
),
|
||||
'explicit',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{
|
||||
"listeners": {"127.0.0.1:7080": {"pass": "applications/app"}},
|
||||
"applications": {
|
||||
"app": {
|
||||
"type": "python",
|
||||
"processes": {"spare": 0},
|
||||
"path": "/app",
|
||||
"module": "wsgi",
|
||||
}
|
||||
},
|
||||
}
|
||||
), 'explicit'
|
||||
|
||||
def test_listeners_explicit_ipv6(self):
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{
|
||||
"listeners": {"[::1]:7080": {"pass": "applications/app"}},
|
||||
"applications": {
|
||||
"app": {
|
||||
"type": "python",
|
||||
"processes": {"spare": 0},
|
||||
"path": "/app",
|
||||
"module": "wsgi",
|
||||
}
|
||||
},
|
||||
}
|
||||
),
|
||||
'explicit ipv6',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{
|
||||
"listeners": {"[::1]:7080": {"pass": "applications/app"}},
|
||||
"applications": {
|
||||
"app": {
|
||||
"type": "python",
|
||||
"processes": {"spare": 0},
|
||||
"path": "/app",
|
||||
"module": "wsgi",
|
||||
}
|
||||
},
|
||||
}
|
||||
), 'explicit ipv6'
|
||||
|
||||
@unittest.skip('not yet, unsafe')
|
||||
@pytest.mark.skip('not yet, unsafe')
|
||||
def test_listeners_no_port(self):
|
||||
self.assertIn(
|
||||
'error',
|
||||
self.conf(
|
||||
{
|
||||
"listeners": {"127.0.0.1": {"pass": "applications/app"}},
|
||||
"applications": {
|
||||
"app": {
|
||||
"type": "python",
|
||||
"processes": {"spare": 0},
|
||||
"path": "/app",
|
||||
"module": "wsgi",
|
||||
}
|
||||
},
|
||||
}
|
||||
),
|
||||
'no port',
|
||||
)
|
||||
assert 'error' in self.conf(
|
||||
{
|
||||
"listeners": {"127.0.0.1": {"pass": "applications/app"}},
|
||||
"applications": {
|
||||
"app": {
|
||||
"type": "python",
|
||||
"processes": {"spare": 0},
|
||||
"path": "/app",
|
||||
"module": "wsgi",
|
||||
}
|
||||
},
|
||||
}
|
||||
), 'no port'
|
||||
|
||||
def test_json_application_name_large(self):
|
||||
name = "X" * 1024 * 1024
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "applications/" + name}},
|
||||
"applications": {
|
||||
name: {
|
||||
"type": "python",
|
||||
"processes": {"spare": 0},
|
||||
"path": "/app",
|
||||
"module": "wsgi",
|
||||
}
|
||||
},
|
||||
}
|
||||
),
|
||||
assert 'success' in self.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "applications/" + name}},
|
||||
"applications": {
|
||||
name: {
|
||||
"type": "python",
|
||||
"processes": {"spare": 0},
|
||||
"path": "/app",
|
||||
"module": "wsgi",
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_json_application_many(self):
|
||||
apps = 999
|
||||
|
||||
|
@ -388,7 +316,7 @@ class TestConfiguration(TestControl):
|
|||
},
|
||||
}
|
||||
|
||||
self.assertIn('success', self.conf(conf))
|
||||
assert 'success' in self.conf(conf)
|
||||
|
||||
def test_json_application_many2(self):
|
||||
conf = {
|
||||
|
@ -407,35 +335,21 @@ class TestConfiguration(TestControl):
|
|||
"listeners": {"*:7080": {"pass": "applications/app-1"}},
|
||||
}
|
||||
|
||||
self.assertIn('success', self.conf(conf))
|
||||
assert 'success' in self.conf(conf)
|
||||
|
||||
def test_unprivileged_user_error(self):
|
||||
self.skip_alerts.extend(
|
||||
[
|
||||
r'cannot set user "root"',
|
||||
r'failed to apply new conf',
|
||||
]
|
||||
)
|
||||
if self.is_su:
|
||||
print('unprivileged tests, skip this')
|
||||
raise unittest.SkipTest()
|
||||
def test_unprivileged_user_error(self, is_su):
|
||||
skip_alert(r'cannot set user "root"', r'failed to apply new conf')
|
||||
if is_su:
|
||||
pytest.skip('unprivileged tests')
|
||||
|
||||
self.assertIn(
|
||||
'error',
|
||||
self.conf(
|
||||
{
|
||||
"app": {
|
||||
"type": "external",
|
||||
"processes": 1,
|
||||
"executable": "/app",
|
||||
"user": "root",
|
||||
}
|
||||
},
|
||||
'applications',
|
||||
),
|
||||
'setting user',
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestConfiguration.main()
|
||||
assert 'error' in self.conf(
|
||||
{
|
||||
"app": {
|
||||
"type": "external",
|
||||
"processes": 1,
|
||||
"executable": "/app",
|
||||
"user": "root",
|
||||
}
|
||||
},
|
||||
'applications',
|
||||
), 'setting user'
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from unit.applications.lang.go import TestApplicationGo
|
||||
import re
|
||||
|
||||
|
||||
class TestGoApplication(TestApplicationGo):
|
||||
|
@ -19,44 +20,38 @@ class TestGoApplication(TestApplicationGo):
|
|||
body=body,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'status')
|
||||
assert resp['status'] == 200, 'status'
|
||||
headers = resp['headers']
|
||||
header_server = headers.pop('Server')
|
||||
self.assertRegex(header_server, r'Unit/[\d\.]+', 'server header')
|
||||
assert re.search(r'Unit/[\d\.]+', header_server), 'server header'
|
||||
|
||||
date = headers.pop('Date')
|
||||
self.assertEqual(date[-4:], ' GMT', 'date header timezone')
|
||||
self.assertLess(
|
||||
abs(self.date_to_sec_epoch(date) - self.sec_epoch()),
|
||||
5,
|
||||
'date header',
|
||||
)
|
||||
assert date[-4:] == ' GMT', 'date header timezone'
|
||||
assert (
|
||||
abs(self.date_to_sec_epoch(date) - self.sec_epoch()) < 5
|
||||
), 'date header'
|
||||
|
||||
self.assertDictEqual(
|
||||
headers,
|
||||
{
|
||||
'Content-Length': str(len(body)),
|
||||
'Content-Type': 'text/html',
|
||||
'Request-Method': 'POST',
|
||||
'Request-Uri': '/',
|
||||
'Http-Host': 'localhost',
|
||||
'Server-Protocol': 'HTTP/1.1',
|
||||
'Server-Protocol-Major': '1',
|
||||
'Server-Protocol-Minor': '1',
|
||||
'Custom-Header': 'blah',
|
||||
'Connection': 'close',
|
||||
},
|
||||
'headers',
|
||||
)
|
||||
self.assertEqual(resp['body'], body, 'body')
|
||||
assert headers == {
|
||||
'Content-Length': str(len(body)),
|
||||
'Content-Type': 'text/html',
|
||||
'Request-Method': 'POST',
|
||||
'Request-Uri': '/',
|
||||
'Http-Host': 'localhost',
|
||||
'Server-Protocol': 'HTTP/1.1',
|
||||
'Server-Protocol-Major': '1',
|
||||
'Server-Protocol-Minor': '1',
|
||||
'Custom-Header': 'blah',
|
||||
'Connection': 'close',
|
||||
}, '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')
|
||||
self.assertEqual(resp['headers']['X-Var-1'], 'val1', 'GET variables')
|
||||
self.assertEqual(resp['headers']['X-Var-2'], '', 'GET variables 2')
|
||||
self.assertEqual(resp['headers']['X-Var-3'], '', 'GET variables 3')
|
||||
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')
|
||||
|
@ -70,24 +65,24 @@ class TestGoApplication(TestApplicationGo):
|
|||
body='var1=val1&var2=&var3',
|
||||
)
|
||||
|
||||
self.assertEqual(resp['headers']['X-Var-1'], 'val1', 'POST variables')
|
||||
self.assertEqual(resp['headers']['X-Var-2'], '', 'POST variables 2')
|
||||
self.assertEqual(resp['headers']['X-Var-3'], '', 'POST variables 3')
|
||||
assert resp['headers']['X-Var-1'] == 'val1', 'POST variables'
|
||||
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()
|
||||
|
||||
self.assertEqual(resp['status'], 404, '404 status')
|
||||
self.assertRegex(
|
||||
resp['body'], r'<title>404 Not Found</title>', '404 body'
|
||||
)
|
||||
assert resp['status'] == 404, '404 status'
|
||||
assert re.search(
|
||||
r'<title>404 Not Found</title>', resp['body']
|
||||
), '404 body'
|
||||
|
||||
def test_go_keepalive_body(self):
|
||||
self.load('mirror')
|
||||
|
||||
self.assertEqual(self.get()['status'], 200, 'init')
|
||||
assert self.get()['status'] == 200, 'init'
|
||||
|
||||
body = '0123456789' * 500
|
||||
(resp, sock) = self.post(
|
||||
|
@ -101,7 +96,7 @@ class TestGoApplication(TestApplicationGo):
|
|||
read_timeout=1,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['body'], body, 'keep-alive 1')
|
||||
assert resp['body'] == body, 'keep-alive 1'
|
||||
|
||||
body = '0123456789'
|
||||
resp = self.post(
|
||||
|
@ -114,7 +109,7 @@ class TestGoApplication(TestApplicationGo):
|
|||
body=body,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['body'], body, 'keep-alive 2')
|
||||
assert resp['body'] == body, 'keep-alive 2'
|
||||
|
||||
def test_go_application_cookies(self):
|
||||
self.load('cookies')
|
||||
|
@ -127,28 +122,24 @@ class TestGoApplication(TestApplicationGo):
|
|||
}
|
||||
)
|
||||
|
||||
self.assertEqual(resp['headers']['X-Cookie-1'], 'val1', 'cookie 1')
|
||||
self.assertEqual(resp['headers']['X-Cookie-2'], 'val2', 'cookie 2')
|
||||
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')
|
||||
|
||||
self.assertIn(
|
||||
'error',
|
||||
assert 'error' in \
|
||||
self.conf(
|
||||
'' "a b c", 'applications/command_line_arguments/arguments'
|
||||
),
|
||||
'arguments type',
|
||||
)
|
||||
), \
|
||||
'arguments type'
|
||||
|
||||
def test_go_application_command_line_arguments_0(self):
|
||||
self.load('command_line_arguments')
|
||||
|
||||
self.assertEqual(
|
||||
self.get()['headers']['X-Arg-0'],
|
||||
self.conf_get('applications/command_line_arguments/executable'),
|
||||
'argument 0',
|
||||
)
|
||||
assert self.get()['headers']['X-Arg-0'] == self.conf_get(
|
||||
'applications/command_line_arguments/executable'
|
||||
), 'argument 0'
|
||||
|
||||
def test_go_application_command_line_arguments(self):
|
||||
self.load('command_line_arguments')
|
||||
|
@ -162,9 +153,9 @@ class TestGoApplication(TestApplicationGo):
|
|||
'applications/command_line_arguments/arguments',
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
self.get()['body'], arg1 + ',' + arg2 + ',' + arg3, 'arguments'
|
||||
)
|
||||
assert (
|
||||
self.get()['body'] == arg1 + ',' + arg2 + ',' + arg3
|
||||
), 'arguments'
|
||||
|
||||
def test_go_application_command_line_arguments_change(self):
|
||||
self.load('command_line_arguments')
|
||||
|
@ -173,18 +164,14 @@ class TestGoApplication(TestApplicationGo):
|
|||
|
||||
self.conf('["0", "a", "$", ""]', args_path)
|
||||
|
||||
self.assertEqual(self.get()['body'], '0,a,$,', 'arguments')
|
||||
assert self.get()['body'] == '0,a,$,', 'arguments'
|
||||
|
||||
self.conf('["-1", "b", "%"]', args_path)
|
||||
|
||||
self.assertEqual(self.get()['body'], '-1,b,%', 'arguments change')
|
||||
assert self.get()['body'] == '-1,b,%', 'arguments change'
|
||||
|
||||
self.conf('[]', args_path)
|
||||
|
||||
self.assertEqual(
|
||||
self.get()['headers']['Content-Length'], '0', 'arguments empty'
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestGoApplication.main()
|
||||
assert (
|
||||
self.get()['headers']['Content-Length'] == '0'
|
||||
), 'arguments empty'
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
import grp
|
||||
import os
|
||||
import pwd
|
||||
import unittest
|
||||
import pytest
|
||||
|
||||
from unit.applications.lang.go import TestApplicationGo
|
||||
from unit.feature.isolation import TestFeatureIsolation
|
||||
|
||||
|
||||
class TestGoIsolation(TestApplicationGo):
|
||||
prerequisites = {'modules': {'go': 'any'}, 'features': ['isolation']}
|
||||
|
||||
isolation = TestFeatureIsolation()
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls, complete_check=True):
|
||||
unit = super().setUpClass(complete_check=False)
|
||||
def setup_class(cls, complete_check=True):
|
||||
unit = super().setup_class(complete_check=False)
|
||||
|
||||
TestFeatureIsolation().check(cls.available, unit.testdir)
|
||||
TestFeatureIsolation().check(cls.available, unit.temp_dir)
|
||||
|
||||
return unit if not complete_check else unit.complete()
|
||||
|
||||
|
@ -41,24 +41,20 @@ class TestGoIsolation(TestApplicationGo):
|
|||
|
||||
for ns, ns_value in self.available['features']['isolation'].items():
|
||||
if ns.upper() in obj['NS']:
|
||||
self.assertEqual(
|
||||
obj['NS'][ns.upper()], ns_value, '%s match' % ns
|
||||
)
|
||||
assert obj['NS'][ns.upper()] == ns_value, '%s match' % ns
|
||||
|
||||
def test_isolation_unpriv_user(self):
|
||||
def test_isolation_unpriv_user(self, is_su):
|
||||
if not self.isolation_key('unprivileged_userns_clone'):
|
||||
print('unprivileged clone is not available')
|
||||
raise unittest.SkipTest()
|
||||
pytest.skip('unprivileged clone is not available')
|
||||
|
||||
if self.is_su:
|
||||
print('privileged tests, skip this')
|
||||
raise unittest.SkipTest()
|
||||
if is_su:
|
||||
pytest.skip('privileged tests, skip this')
|
||||
|
||||
self.load('ns_inspect')
|
||||
obj = self.getjson()['body']
|
||||
|
||||
self.assertEqual(obj['UID'], self.uid, 'uid match')
|
||||
self.assertEqual(obj['GID'], self.gid, 'gid match')
|
||||
assert obj['UID'] == os.geteuid(), 'uid match'
|
||||
assert obj['GID'] == os.getegid(), 'gid match'
|
||||
|
||||
self.load('ns_inspect', isolation={'namespaces': {'credential': True}})
|
||||
|
||||
|
@ -67,8 +63,8 @@ class TestGoIsolation(TestApplicationGo):
|
|||
nobody_uid, nogroup_gid, nogroup = self.unpriv_creds()
|
||||
|
||||
# unprivileged unit map itself to nobody in the container by default
|
||||
self.assertEqual(obj['UID'], nobody_uid, 'uid of nobody')
|
||||
self.assertEqual(obj['GID'], nogroup_gid, 'gid of %s' % nogroup)
|
||||
assert obj['UID'] == nobody_uid, 'uid of nobody'
|
||||
assert obj['GID'] == nogroup_gid, 'gid of %s' % nogroup
|
||||
|
||||
self.load(
|
||||
'ns_inspect',
|
||||
|
@ -78,8 +74,8 @@ class TestGoIsolation(TestApplicationGo):
|
|||
|
||||
obj = self.getjson()['body']
|
||||
|
||||
self.assertEqual(obj['UID'], 0, 'uid match user=root')
|
||||
self.assertEqual(obj['GID'], 0, 'gid match user=root')
|
||||
assert obj['UID'] == 0, 'uid match user=root'
|
||||
assert obj['GID'] == 0, 'gid match user=root'
|
||||
|
||||
self.load(
|
||||
'ns_inspect',
|
||||
|
@ -90,10 +86,8 @@ class TestGoIsolation(TestApplicationGo):
|
|||
|
||||
obj = self.getjson()['body']
|
||||
|
||||
self.assertEqual(obj['UID'], 0, 'uid match user=root group=nogroup')
|
||||
self.assertEqual(
|
||||
obj['GID'], nogroup_gid, 'gid match user=root group=nogroup'
|
||||
)
|
||||
assert obj['UID'] == 0, 'uid match user=root group=nogroup'
|
||||
assert obj['GID'] == nogroup_gid, 'gid match user=root group=nogroup'
|
||||
|
||||
self.load(
|
||||
'ns_inspect',
|
||||
|
@ -101,20 +95,19 @@ class TestGoIsolation(TestApplicationGo):
|
|||
group='root',
|
||||
isolation={
|
||||
'namespaces': {'credential': True},
|
||||
'uidmap': [{'container': 0, 'host': self.uid, 'size': 1}],
|
||||
'gidmap': [{'container': 0, 'host': self.gid, 'size': 1}],
|
||||
'uidmap': [{'container': 0, 'host': os.geteuid(), 'size': 1}],
|
||||
'gidmap': [{'container': 0, 'host': os.getegid(), 'size': 1}],
|
||||
},
|
||||
)
|
||||
|
||||
obj = self.getjson()['body']
|
||||
|
||||
self.assertEqual(obj['UID'], 0, 'uid match uidmap')
|
||||
self.assertEqual(obj['GID'], 0, 'gid match gidmap')
|
||||
assert obj['UID'] == 0, 'uid match uidmap'
|
||||
assert obj['GID'] == 0, 'gid match gidmap'
|
||||
|
||||
def test_isolation_priv_user(self):
|
||||
if not self.is_su:
|
||||
print('unprivileged tests, skip this')
|
||||
raise unittest.SkipTest()
|
||||
def test_isolation_priv_user(self, is_su):
|
||||
if not is_su:
|
||||
pytest.skip('unprivileged tests, skip this')
|
||||
|
||||
self.load('ns_inspect')
|
||||
|
||||
|
@ -122,16 +115,16 @@ class TestGoIsolation(TestApplicationGo):
|
|||
|
||||
obj = self.getjson()['body']
|
||||
|
||||
self.assertEqual(obj['UID'], nobody_uid, 'uid match')
|
||||
self.assertEqual(obj['GID'], nogroup_gid, 'gid match')
|
||||
assert obj['UID'] == nobody_uid, 'uid match'
|
||||
assert obj['GID'] == nogroup_gid, 'gid match'
|
||||
|
||||
self.load('ns_inspect', isolation={'namespaces': {'credential': True}})
|
||||
|
||||
obj = self.getjson()['body']
|
||||
|
||||
# privileged unit map app creds in the container by default
|
||||
self.assertEqual(obj['UID'], nobody_uid, 'uid nobody')
|
||||
self.assertEqual(obj['GID'], nogroup_gid, 'gid nobody')
|
||||
assert obj['UID'] == nobody_uid, 'uid nobody'
|
||||
assert obj['GID'] == nogroup_gid, 'gid nobody'
|
||||
|
||||
self.load(
|
||||
'ns_inspect',
|
||||
|
@ -141,8 +134,8 @@ class TestGoIsolation(TestApplicationGo):
|
|||
|
||||
obj = self.getjson()['body']
|
||||
|
||||
self.assertEqual(obj['UID'], 0, 'uid nobody user=root')
|
||||
self.assertEqual(obj['GID'], 0, 'gid nobody user=root')
|
||||
assert obj['UID'] == 0, 'uid nobody user=root'
|
||||
assert obj['GID'] == 0, 'gid nobody user=root'
|
||||
|
||||
self.load(
|
||||
'ns_inspect',
|
||||
|
@ -153,10 +146,8 @@ class TestGoIsolation(TestApplicationGo):
|
|||
|
||||
obj = self.getjson()['body']
|
||||
|
||||
self.assertEqual(obj['UID'], 0, 'uid match user=root group=nogroup')
|
||||
self.assertEqual(
|
||||
obj['GID'], nogroup_gid, 'gid match user=root group=nogroup'
|
||||
)
|
||||
assert obj['UID'] == 0, 'uid match user=root group=nogroup'
|
||||
assert obj['GID'] == nogroup_gid, 'gid match user=root group=nogroup'
|
||||
|
||||
self.load(
|
||||
'ns_inspect',
|
||||
|
@ -171,8 +162,8 @@ class TestGoIsolation(TestApplicationGo):
|
|||
|
||||
obj = self.getjson()['body']
|
||||
|
||||
self.assertEqual(obj['UID'], 0, 'uid match uidmap user=root')
|
||||
self.assertEqual(obj['GID'], 0, 'gid match gidmap user=root')
|
||||
assert obj['UID'] == 0, 'uid match uidmap user=root'
|
||||
assert obj['GID'] == 0, 'gid match gidmap user=root'
|
||||
|
||||
# map 65535 uids
|
||||
self.load(
|
||||
|
@ -188,21 +179,15 @@ class TestGoIsolation(TestApplicationGo):
|
|||
|
||||
obj = self.getjson()['body']
|
||||
|
||||
self.assertEqual(
|
||||
obj['UID'], nobody_uid, 'uid match uidmap user=nobody'
|
||||
)
|
||||
self.assertEqual(
|
||||
obj['GID'], nogroup_gid, 'gid match uidmap user=nobody'
|
||||
)
|
||||
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):
|
||||
if not self.isolation_key('mnt'):
|
||||
print('mnt namespace is not supported')
|
||||
raise unittest.SkipTest()
|
||||
pytest.skip('mnt namespace is not supported')
|
||||
|
||||
if not self.isolation_key('unprivileged_userns_clone'):
|
||||
print('unprivileged clone is not available')
|
||||
raise unittest.SkipTest()
|
||||
pytest.skip('unprivileged clone is not available')
|
||||
|
||||
self.load(
|
||||
'ns_inspect',
|
||||
|
@ -218,27 +203,20 @@ class TestGoIsolation(TestApplicationGo):
|
|||
|
||||
for ns in allns:
|
||||
if ns.upper() in obj['NS']:
|
||||
self.assertEqual(
|
||||
obj['NS'][ns.upper()],
|
||||
self.available['features']['isolation'][ns],
|
||||
'%s match' % ns,
|
||||
)
|
||||
assert (
|
||||
obj['NS'][ns.upper()]
|
||||
== self.available['features']['isolation'][ns]
|
||||
), ('%s match' % ns)
|
||||
|
||||
self.assertNotEqual(
|
||||
obj['NS']['MNT'], self.isolation.getns('mnt'), 'mnt set'
|
||||
)
|
||||
self.assertNotEqual(
|
||||
obj['NS']['USER'], self.isolation.getns('user'), 'user set'
|
||||
)
|
||||
assert obj['NS']['MNT'] != self.isolation.getns('mnt'), 'mnt set'
|
||||
assert obj['NS']['USER'] != self.isolation.getns('user'), 'user set'
|
||||
|
||||
def test_isolation_pid(self):
|
||||
def test_isolation_pid(self, is_su):
|
||||
if not self.isolation_key('pid'):
|
||||
print('pid namespace is not supported')
|
||||
raise unittest.SkipTest()
|
||||
pytest.skip('pid namespace is not supported')
|
||||
|
||||
if not (self.is_su or self.isolation_key('unprivileged_userns_clone')):
|
||||
print('requires root or unprivileged_userns_clone')
|
||||
raise unittest.SkipTest()
|
||||
if not (is_su or self.isolation_key('unprivileged_userns_clone')):
|
||||
pytest.skip('requires root or unprivileged_userns_clone')
|
||||
|
||||
self.load(
|
||||
'ns_inspect',
|
||||
|
@ -247,7 +225,7 @@ class TestGoIsolation(TestApplicationGo):
|
|||
|
||||
obj = self.getjson()['body']
|
||||
|
||||
self.assertEqual(obj['PID'], 1, 'pid of container is 1')
|
||||
assert obj['PID'] == 1, 'pid of container is 1'
|
||||
|
||||
def test_isolation_namespace_false(self):
|
||||
self.load('ns_inspect')
|
||||
|
@ -275,78 +253,67 @@ class TestGoIsolation(TestApplicationGo):
|
|||
|
||||
for ns in allns:
|
||||
if ns.upper() in obj['NS']:
|
||||
self.assertEqual(
|
||||
obj['NS'][ns.upper()],
|
||||
self.available['features']['isolation'][ns],
|
||||
'%s match' % ns,
|
||||
)
|
||||
assert (
|
||||
obj['NS'][ns.upper()]
|
||||
== self.available['features']['isolation'][ns]
|
||||
), ('%s match' % ns)
|
||||
|
||||
def test_go_isolation_rootfs_container(self):
|
||||
if not self.isolation_key('unprivileged_userns_clone'):
|
||||
print('unprivileged clone is not available')
|
||||
raise unittest.SkipTest()
|
||||
pytest.skip('unprivileged clone is not available')
|
||||
|
||||
if not self.isolation_key('mnt'):
|
||||
print('mnt namespace is not supported')
|
||||
raise unittest.SkipTest()
|
||||
pytest.skip('mnt namespace is not supported')
|
||||
|
||||
isolation = {
|
||||
'namespaces': {'mount': True, 'credential': True},
|
||||
'rootfs': self.testdir,
|
||||
'rootfs': self.temp_dir,
|
||||
}
|
||||
|
||||
self.load('ns_inspect', isolation=isolation)
|
||||
|
||||
obj = self.getjson(url='/?file=/go/app')['body']
|
||||
|
||||
self.assertEqual(obj['FileExists'], True, 'app relative to rootfs')
|
||||
assert obj['FileExists'] == True, 'app relative to rootfs'
|
||||
|
||||
obj = self.getjson(url='/?file=/bin/sh')['body']
|
||||
self.assertEqual(obj['FileExists'], False, 'file should not exists')
|
||||
assert obj['FileExists'] == False, 'file should not exists'
|
||||
|
||||
def test_go_isolation_rootfs_container_priv(self):
|
||||
if not self.is_su:
|
||||
print("requires root")
|
||||
raise unittest.SkipTest()
|
||||
def test_go_isolation_rootfs_container_priv(self, is_su):
|
||||
if not is_su:
|
||||
pytest.skip('requires root')
|
||||
|
||||
if not self.isolation_key('mnt'):
|
||||
print('mnt namespace is not supported')
|
||||
raise unittest.SkipTest()
|
||||
pytest.skip('mnt namespace is not supported')
|
||||
|
||||
isolation = {
|
||||
'namespaces': {'mount': True},
|
||||
'rootfs': self.testdir,
|
||||
'rootfs': self.temp_dir,
|
||||
}
|
||||
|
||||
self.load('ns_inspect', isolation=isolation)
|
||||
|
||||
obj = self.getjson(url='/?file=/go/app')['body']
|
||||
|
||||
self.assertEqual(obj['FileExists'], True, 'app relative to rootfs')
|
||||
assert obj['FileExists'] == True, 'app relative to rootfs'
|
||||
|
||||
obj = self.getjson(url='/?file=/bin/sh')['body']
|
||||
self.assertEqual(obj['FileExists'], False, 'file should not exists')
|
||||
assert obj['FileExists'] == False, 'file should not exists'
|
||||
|
||||
def test_go_isolation_rootfs_default_tmpfs(self):
|
||||
if not self.isolation_key('unprivileged_userns_clone'):
|
||||
print('unprivileged clone is not available')
|
||||
raise unittest.SkipTest()
|
||||
pytest.skip('unprivileged clone is not available')
|
||||
|
||||
if not self.isolation_key('mnt'):
|
||||
print('mnt namespace is not supported')
|
||||
raise unittest.SkipTest()
|
||||
pytest.skip('mnt namespace is not supported')
|
||||
|
||||
isolation = {
|
||||
'namespaces': {'mount': True, 'credential': True},
|
||||
'rootfs': self.testdir,
|
||||
'rootfs': self.temp_dir,
|
||||
}
|
||||
|
||||
self.load('ns_inspect', isolation=isolation)
|
||||
|
||||
obj = self.getjson(url='/?file=/tmp')['body']
|
||||
|
||||
self.assertEqual(obj['FileExists'], True, 'app has /tmp')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestGoIsolation.main()
|
||||
assert obj['FileExists'] == True, 'app has /tmp'
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import os
|
||||
import unittest
|
||||
import pytest
|
||||
|
||||
from unit.applications.lang.go import TestApplicationGo
|
||||
|
||||
|
@ -7,28 +7,22 @@ from unit.applications.lang.go import TestApplicationGo
|
|||
class TestGoIsolationRootfs(TestApplicationGo):
|
||||
prerequisites = {'modules': {'go': 'all'}}
|
||||
|
||||
def test_go_isolation_rootfs_chroot(self):
|
||||
if not self.is_su:
|
||||
print("requires root")
|
||||
raise unittest.SkipTest()
|
||||
def test_go_isolation_rootfs_chroot(self, is_su):
|
||||
if not is_su:
|
||||
pytest.skip('requires root')
|
||||
|
||||
if os.uname().sysname == 'Darwin':
|
||||
print('chroot tests not supported on OSX')
|
||||
raise unittest.SkipTest()
|
||||
pytest.skip('chroot tests not supported on OSX')
|
||||
|
||||
isolation = {
|
||||
'rootfs': self.testdir,
|
||||
'rootfs': self.temp_dir,
|
||||
}
|
||||
|
||||
self.load('ns_inspect', isolation=isolation)
|
||||
|
||||
obj = self.getjson(url='/?file=/go/app')['body']
|
||||
|
||||
self.assertEqual(obj['FileExists'], True, 'app relative to rootfs')
|
||||
assert obj['FileExists'] == True, 'app relative to rootfs'
|
||||
|
||||
obj = self.getjson(url='/?file=/bin/sh')['body']
|
||||
self.assertEqual(obj['FileExists'], False, 'file should not exists')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestGoIsolationRootfs.main()
|
||||
assert obj['FileExists'] == False, 'file should not exists'
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import unittest
|
||||
import pytest
|
||||
|
||||
from unit.applications.lang.python import TestApplicationPython
|
||||
|
||||
|
@ -17,12 +17,10 @@ class TestHTTPHeader(TestApplicationPython):
|
|||
}
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'value leading sp status')
|
||||
self.assertEqual(
|
||||
resp['headers']['Custom-Header'],
|
||||
',',
|
||||
'value leading sp custom header',
|
||||
)
|
||||
assert resp['status'] == 200, 'value leading sp status'
|
||||
assert (
|
||||
resp['headers']['Custom-Header'] == ','
|
||||
), 'value leading sp custom header'
|
||||
|
||||
def test_http_header_value_leading_htab(self):
|
||||
self.load('custom_header')
|
||||
|
@ -35,12 +33,10 @@ class TestHTTPHeader(TestApplicationPython):
|
|||
}
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'value leading htab status')
|
||||
self.assertEqual(
|
||||
resp['headers']['Custom-Header'],
|
||||
',',
|
||||
'value leading htab custom header',
|
||||
)
|
||||
assert resp['status'] == 200, 'value leading htab status'
|
||||
assert (
|
||||
resp['headers']['Custom-Header'] == ','
|
||||
), 'value leading htab custom header'
|
||||
|
||||
def test_http_header_value_trailing_sp(self):
|
||||
self.load('custom_header')
|
||||
|
@ -53,12 +49,10 @@ class TestHTTPHeader(TestApplicationPython):
|
|||
}
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'value trailing sp status')
|
||||
self.assertEqual(
|
||||
resp['headers']['Custom-Header'],
|
||||
',',
|
||||
'value trailing sp custom header',
|
||||
)
|
||||
assert resp['status'] == 200, 'value trailing sp status'
|
||||
assert (
|
||||
resp['headers']['Custom-Header'] == ','
|
||||
), 'value trailing sp custom header'
|
||||
|
||||
def test_http_header_value_trailing_htab(self):
|
||||
self.load('custom_header')
|
||||
|
@ -71,12 +65,10 @@ class TestHTTPHeader(TestApplicationPython):
|
|||
}
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'value trailing htab status')
|
||||
self.assertEqual(
|
||||
resp['headers']['Custom-Header'],
|
||||
',',
|
||||
'value trailing htab custom header',
|
||||
)
|
||||
assert resp['status'] == 200, 'value trailing htab status'
|
||||
assert (
|
||||
resp['headers']['Custom-Header'] == ','
|
||||
), 'value trailing htab custom header'
|
||||
|
||||
def test_http_header_value_both_sp(self):
|
||||
self.load('custom_header')
|
||||
|
@ -89,12 +81,10 @@ class TestHTTPHeader(TestApplicationPython):
|
|||
}
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'value both sp status')
|
||||
self.assertEqual(
|
||||
resp['headers']['Custom-Header'],
|
||||
',',
|
||||
'value both sp custom header',
|
||||
)
|
||||
assert resp['status'] == 200, 'value both sp status'
|
||||
assert (
|
||||
resp['headers']['Custom-Header'] == ','
|
||||
), 'value both sp custom header'
|
||||
|
||||
def test_http_header_value_both_htab(self):
|
||||
self.load('custom_header')
|
||||
|
@ -107,12 +97,10 @@ class TestHTTPHeader(TestApplicationPython):
|
|||
}
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'value both htab status')
|
||||
self.assertEqual(
|
||||
resp['headers']['Custom-Header'],
|
||||
',',
|
||||
'value both htab custom header',
|
||||
)
|
||||
assert resp['status'] == 200, 'value both htab status'
|
||||
assert (
|
||||
resp['headers']['Custom-Header'] == ','
|
||||
), 'value both htab custom header'
|
||||
|
||||
def test_http_header_value_chars(self):
|
||||
self.load('custom_header')
|
||||
|
@ -125,12 +113,11 @@ class TestHTTPHeader(TestApplicationPython):
|
|||
}
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'value chars status')
|
||||
self.assertEqual(
|
||||
resp['headers']['Custom-Header'],
|
||||
'(),/:;<=>?@[\]{}\t !#$%&\'*+-.^_`|~',
|
||||
'value chars custom header',
|
||||
)
|
||||
assert resp['status'] == 200, 'value chars status'
|
||||
assert (
|
||||
resp['headers']['Custom-Header']
|
||||
== '(),/:;<=>?@[\]{}\t !#$%&\'*+-.^_`|~'
|
||||
), 'value chars custom header'
|
||||
|
||||
def test_http_header_value_chars_edge(self):
|
||||
self.load('custom_header')
|
||||
|
@ -146,10 +133,8 @@ Connection: close
|
|||
encoding='latin1',
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'value chars edge status')
|
||||
self.assertEqual(
|
||||
resp['headers']['Custom-Header'], '\xFF', 'value chars edge'
|
||||
)
|
||||
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')
|
||||
|
@ -164,7 +149,7 @@ Connection: close
|
|||
raw=True,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 400, 'value chars below')
|
||||
assert resp['status'] == 400, 'value chars below'
|
||||
|
||||
def test_http_header_field_leading_sp(self):
|
||||
self.load('empty')
|
||||
|
@ -177,7 +162,7 @@ Connection: close
|
|||
}
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 400, 'field leading sp')
|
||||
assert resp['status'] == 400, 'field leading sp'
|
||||
|
||||
def test_http_header_field_leading_htab(self):
|
||||
self.load('empty')
|
||||
|
@ -190,7 +175,7 @@ Connection: close
|
|||
}
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 400, 'field leading htab')
|
||||
assert resp['status'] == 400, 'field leading htab'
|
||||
|
||||
def test_http_header_field_trailing_sp(self):
|
||||
self.load('empty')
|
||||
|
@ -203,7 +188,7 @@ Connection: close
|
|||
}
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 400, 'field trailing sp')
|
||||
assert resp['status'] == 400, 'field trailing sp'
|
||||
|
||||
def test_http_header_field_trailing_htab(self):
|
||||
self.load('empty')
|
||||
|
@ -216,12 +201,12 @@ Connection: close
|
|||
}
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 400, 'field trailing htab')
|
||||
assert resp['status'] == 400, 'field trailing htab'
|
||||
|
||||
def test_http_header_content_length_big(self):
|
||||
self.load('empty')
|
||||
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
|
@ -229,15 +214,14 @@ Connection: close
|
|||
'Connection': 'close',
|
||||
},
|
||||
body='X' * 1000,
|
||||
)['status'],
|
||||
400,
|
||||
'Content-Length big',
|
||||
)
|
||||
)['status']
|
||||
== 400
|
||||
), 'Content-Length big'
|
||||
|
||||
def test_http_header_content_length_negative(self):
|
||||
self.load('empty')
|
||||
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
|
@ -245,15 +229,14 @@ Connection: close
|
|||
'Connection': 'close',
|
||||
},
|
||||
body='X' * 1000,
|
||||
)['status'],
|
||||
400,
|
||||
'Content-Length negative',
|
||||
)
|
||||
)['status']
|
||||
== 400
|
||||
), 'Content-Length negative'
|
||||
|
||||
def test_http_header_content_length_text(self):
|
||||
self.load('empty')
|
||||
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
|
@ -261,15 +244,14 @@ Connection: close
|
|||
'Connection': 'close',
|
||||
},
|
||||
body='X' * 1000,
|
||||
)['status'],
|
||||
400,
|
||||
'Content-Length text',
|
||||
)
|
||||
)['status']
|
||||
== 400
|
||||
), 'Content-Length text'
|
||||
|
||||
def test_http_header_content_length_multiple_values(self):
|
||||
self.load('empty')
|
||||
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
|
@ -277,15 +259,14 @@ Connection: close
|
|||
'Connection': 'close',
|
||||
},
|
||||
body='X' * 1000,
|
||||
)['status'],
|
||||
400,
|
||||
'Content-Length multiple value',
|
||||
)
|
||||
)['status']
|
||||
== 400
|
||||
), 'Content-Length multiple value'
|
||||
|
||||
def test_http_header_content_length_multiple_fields(self):
|
||||
self.load('empty')
|
||||
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
|
@ -293,39 +274,35 @@ Connection: close
|
|||
'Connection': 'close',
|
||||
},
|
||||
body='X' * 1000,
|
||||
)['status'],
|
||||
400,
|
||||
'Content-Length multiple fields',
|
||||
)
|
||||
)['status']
|
||||
== 400
|
||||
), 'Content-Length multiple fields'
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_http_header_host_absent(self):
|
||||
self.load('host')
|
||||
|
||||
resp = self.get(headers={'Connection': 'close'})
|
||||
|
||||
self.assertEqual(resp['status'], 400, 'Host absent status')
|
||||
assert resp['status'] == 400, 'Host absent status'
|
||||
|
||||
def test_http_header_host_empty(self):
|
||||
self.load('host')
|
||||
|
||||
resp = self.get(headers={'Host': '', 'Connection': 'close'})
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'Host empty status')
|
||||
self.assertNotEqual(
|
||||
resp['headers']['X-Server-Name'], '', 'Host empty SERVER_NAME'
|
||||
)
|
||||
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')
|
||||
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.get(headers={'Host': 'X' * 10000, 'Connection': 'close'})[
|
||||
'status'
|
||||
],
|
||||
431,
|
||||
'Host big',
|
||||
)
|
||||
]
|
||||
== 431
|
||||
), 'Host big'
|
||||
|
||||
def test_http_header_host_port(self):
|
||||
self.load('host')
|
||||
|
@ -334,17 +311,13 @@ Connection: close
|
|||
headers={'Host': 'exmaple.com:7080', 'Connection': 'close'}
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'Host port status')
|
||||
self.assertEqual(
|
||||
resp['headers']['X-Server-Name'],
|
||||
'exmaple.com',
|
||||
'Host port SERVER_NAME',
|
||||
)
|
||||
self.assertEqual(
|
||||
resp['headers']['X-Http-Host'],
|
||||
'exmaple.com:7080',
|
||||
'Host port HTTP_HOST',
|
||||
)
|
||||
assert resp['status'] == 200, 'Host port status'
|
||||
assert (
|
||||
resp['headers']['X-Server-Name'] == 'exmaple.com'
|
||||
), 'Host port SERVER_NAME'
|
||||
assert (
|
||||
resp['headers']['X-Http-Host'] == 'exmaple.com:7080'
|
||||
), 'Host port HTTP_HOST'
|
||||
|
||||
def test_http_header_host_port_empty(self):
|
||||
self.load('host')
|
||||
|
@ -353,63 +326,49 @@ Connection: close
|
|||
headers={'Host': 'exmaple.com:', 'Connection': 'close'}
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'Host port empty status')
|
||||
self.assertEqual(
|
||||
resp['headers']['X-Server-Name'],
|
||||
'exmaple.com',
|
||||
'Host port empty SERVER_NAME',
|
||||
)
|
||||
self.assertEqual(
|
||||
resp['headers']['X-Http-Host'],
|
||||
'exmaple.com:',
|
||||
'Host port empty HTTP_HOST',
|
||||
)
|
||||
assert resp['status'] == 200, 'Host port empty status'
|
||||
assert (
|
||||
resp['headers']['X-Server-Name'] == 'exmaple.com'
|
||||
), 'Host port empty SERVER_NAME'
|
||||
assert (
|
||||
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'})
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'Host literal status')
|
||||
self.assertEqual(
|
||||
resp['headers']['X-Server-Name'],
|
||||
'127.0.0.1',
|
||||
'Host literal SERVER_NAME',
|
||||
)
|
||||
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'})
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'Host literal ipv6 status')
|
||||
self.assertEqual(
|
||||
resp['headers']['X-Server-Name'],
|
||||
'[::1]',
|
||||
'Host literal ipv6 SERVER_NAME',
|
||||
)
|
||||
self.assertEqual(
|
||||
resp['headers']['X-Http-Host'],
|
||||
'[::1]:7080',
|
||||
'Host literal ipv6 HTTP_HOST',
|
||||
)
|
||||
assert resp['status'] == 200, 'Host literal ipv6 status'
|
||||
assert (
|
||||
resp['headers']['X-Server-Name'] == '[::1]'
|
||||
), 'Host literal ipv6 SERVER_NAME'
|
||||
assert (
|
||||
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'})
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'Host trailing period status')
|
||||
self.assertEqual(
|
||||
resp['headers']['X-Server-Name'],
|
||||
'127.0.0.1',
|
||||
'Host trailing period SERVER_NAME',
|
||||
)
|
||||
self.assertEqual(
|
||||
resp['headers']['X-Http-Host'],
|
||||
'127.0.0.1.',
|
||||
'Host trailing period HTTP_HOST',
|
||||
)
|
||||
assert resp['status'] == 200, 'Host trailing period status'
|
||||
assert (
|
||||
resp['headers']['X-Server-Name'] == '127.0.0.1'
|
||||
), 'Host trailing period SERVER_NAME'
|
||||
assert (
|
||||
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')
|
||||
|
@ -418,66 +377,53 @@ Connection: close
|
|||
headers={'Host': 'EXAMPLE.COM.', 'Connection': 'close'}
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'Host trailing period 2 status')
|
||||
self.assertEqual(
|
||||
resp['headers']['X-Server-Name'],
|
||||
'example.com',
|
||||
'Host trailing period 2 SERVER_NAME',
|
||||
)
|
||||
self.assertEqual(
|
||||
resp['headers']['X-Http-Host'],
|
||||
'EXAMPLE.COM.',
|
||||
'Host trailing period 2 HTTP_HOST',
|
||||
)
|
||||
assert resp['status'] == 200, 'Host trailing period 2 status'
|
||||
assert (
|
||||
resp['headers']['X-Server-Name'] == 'example.com'
|
||||
), 'Host trailing period 2 SERVER_NAME'
|
||||
assert (
|
||||
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'})
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'Host case insensitive')
|
||||
self.assertEqual(
|
||||
resp['headers']['X-Server-Name'],
|
||||
'example.com',
|
||||
'Host case insensitive SERVER_NAME',
|
||||
)
|
||||
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')
|
||||
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.get(headers={'Host': '127.0.0..1', 'Connection': 'close'})[
|
||||
'status'
|
||||
],
|
||||
400,
|
||||
'Host double dot',
|
||||
)
|
||||
]
|
||||
== 400
|
||||
), 'Host double dot'
|
||||
|
||||
def test_http_header_host_slash(self):
|
||||
self.load('empty')
|
||||
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.get(headers={'Host': '/localhost', 'Connection': 'close'})[
|
||||
'status'
|
||||
],
|
||||
400,
|
||||
'Host slash',
|
||||
)
|
||||
]
|
||||
== 400
|
||||
), 'Host slash'
|
||||
|
||||
def test_http_header_host_multiple_fields(self):
|
||||
self.load('empty')
|
||||
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.get(
|
||||
headers={
|
||||
'Host': ['localhost', 'example.com'],
|
||||
'Connection': 'close',
|
||||
}
|
||||
)['status'],
|
||||
400,
|
||||
'Host multiple fields',
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestHTTPHeader.main()
|
||||
)['status']
|
||||
== 400
|
||||
), 'Host multiple fields'
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
|||
import os
|
||||
import subprocess
|
||||
import unittest
|
||||
import pytest
|
||||
|
||||
from unit.applications.lang.java import TestApplicationJava
|
||||
|
||||
|
@ -8,15 +8,15 @@ from unit.applications.lang.java import TestApplicationJava
|
|||
class TestJavaIsolationRootfs(TestApplicationJava):
|
||||
prerequisites = {'modules': {'java': 'all'}}
|
||||
|
||||
def setUp(self):
|
||||
if not self.is_su:
|
||||
def setup_method(self, is_su):
|
||||
super().setup_method()
|
||||
|
||||
if not is_su:
|
||||
return
|
||||
|
||||
super().setUp()
|
||||
|
||||
os.makedirs(self.testdir + '/jars')
|
||||
os.makedirs(self.testdir + '/tmp')
|
||||
os.chmod(self.testdir + '/tmp', 0o777)
|
||||
os.makedirs(self.temp_dir + '/jars')
|
||||
os.makedirs(self.temp_dir + '/tmp')
|
||||
os.chmod(self.temp_dir + '/tmp', 0o777)
|
||||
|
||||
try:
|
||||
process = subprocess.Popen(
|
||||
|
@ -24,7 +24,7 @@ class TestJavaIsolationRootfs(TestApplicationJava):
|
|||
"mount",
|
||||
"--bind",
|
||||
self.pardir + "/build",
|
||||
self.testdir + "/jars",
|
||||
self.temp_dir + "/jars",
|
||||
],
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
|
@ -32,54 +32,45 @@ class TestJavaIsolationRootfs(TestApplicationJava):
|
|||
process.communicate()
|
||||
|
||||
except:
|
||||
self.fail('Cann\'t run mount process.')
|
||||
pytest.fail('Cann\'t run mount process.')
|
||||
|
||||
def tearDown(self):
|
||||
if not self.is_su:
|
||||
def teardown_method(self, is_su):
|
||||
if not is_su:
|
||||
return
|
||||
|
||||
try:
|
||||
process = subprocess.Popen(
|
||||
["umount", "--lazy", self.testdir + "/jars"],
|
||||
["umount", "--lazy", self.temp_dir + "/jars"],
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
|
||||
process.communicate()
|
||||
|
||||
except:
|
||||
self.fail('Cann\'t run mount process.')
|
||||
pytest.fail('Cann\'t run mount process.')
|
||||
|
||||
# super teardown must happen after unmount to avoid deletion of /build
|
||||
super().tearDown()
|
||||
super().teardown_method()
|
||||
|
||||
def test_java_isolation_rootfs_chroot_war(self):
|
||||
if not self.is_su:
|
||||
print('require root')
|
||||
raise unittest.SkipTest()
|
||||
def test_java_isolation_rootfs_chroot_war(self, is_su):
|
||||
if not is_su:
|
||||
pytest.skip('require root')
|
||||
|
||||
isolation = {
|
||||
'rootfs': self.testdir,
|
||||
'rootfs': self.temp_dir,
|
||||
}
|
||||
|
||||
self.load('empty_war', isolation=isolation)
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
'"/"', '/config/applications/empty_war/working_directory',
|
||||
),
|
||||
assert 'success' in self.conf(
|
||||
'"/"', '/config/applications/empty_war/working_directory',
|
||||
)
|
||||
|
||||
self.assertIn(
|
||||
'success', self.conf('"/jars"', 'applications/empty_war/unit_jars')
|
||||
assert 'success' in self.conf(
|
||||
'"/jars"', 'applications/empty_war/unit_jars'
|
||||
)
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf('"/java/empty.war"', 'applications/empty_war/webapp'),
|
||||
assert 'success' in self.conf(
|
||||
'"/java/empty.war"', 'applications/empty_war/webapp'
|
||||
)
|
||||
|
||||
self.assertEqual(self.get()['status'], 200, 'war')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestJavaIsolationRootfs.main()
|
||||
assert self.get()['status'] == 200, 'war'
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import pytest
|
||||
import struct
|
||||
import time
|
||||
import unittest
|
||||
|
||||
from unit.applications.lang.java import TestApplicationJava
|
||||
from unit.applications.websockets import TestApplicationWebsocket
|
||||
from conftest import option, skip_alert
|
||||
|
||||
|
||||
class TestJavaWebsockets(TestApplicationJava):
|
||||
|
@ -11,23 +12,17 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
|
||||
ws = TestApplicationWebsocket()
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
def setup_method(self):
|
||||
super().setup_method()
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{'http': {'websocket': {'keepalive_interval': 0}}}, 'settings'
|
||||
),
|
||||
'clear keepalive_interval',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{'http': {'websocket': {'keepalive_interval': 0}}}, 'settings'
|
||||
), 'clear keepalive_interval'
|
||||
|
||||
self.skip_alerts.extend(
|
||||
[r'socket close\(\d+\) failed']
|
||||
)
|
||||
skip_alert(r'socket close\(\d+\) failed')
|
||||
|
||||
def close_connection(self, sock):
|
||||
self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc')
|
||||
assert self.recvall(sock, read_timeout=0.1) == b'', 'empty soc'
|
||||
|
||||
self.ws.frame_write(sock, self.ws.OP_CLOSE, self.ws.serialize_close())
|
||||
|
||||
|
@ -36,9 +31,9 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
def check_close(self, sock, code=1000, no_close=False):
|
||||
frame = self.ws.frame_read(sock)
|
||||
|
||||
self.assertEqual(frame['fin'], True, 'close fin')
|
||||
self.assertEqual(frame['opcode'], self.ws.OP_CLOSE, 'close opcode')
|
||||
self.assertEqual(frame['code'], code, 'close code')
|
||||
assert frame['fin'] == True, 'close fin'
|
||||
assert frame['opcode'] == self.ws.OP_CLOSE, 'close opcode'
|
||||
assert frame['code'] == code, 'close code'
|
||||
|
||||
if not no_close:
|
||||
sock.close()
|
||||
|
@ -49,9 +44,9 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
else:
|
||||
data = frame['data'].decode('utf-8')
|
||||
|
||||
self.assertEqual(frame['fin'], fin, 'fin')
|
||||
self.assertEqual(frame['opcode'], opcode, 'opcode')
|
||||
self.assertEqual(data, payload, 'payload')
|
||||
assert frame['fin'] == fin, 'fin'
|
||||
assert frame['opcode'] == opcode, 'opcode'
|
||||
assert data == payload, 'payload'
|
||||
|
||||
def test_java_websockets_handshake(self):
|
||||
self.load('websockets_mirror')
|
||||
|
@ -59,14 +54,12 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
resp, sock, key = self.ws.upgrade()
|
||||
sock.close()
|
||||
|
||||
self.assertEqual(resp['status'], 101, 'status')
|
||||
self.assertEqual(resp['headers']['Upgrade'], 'websocket', 'upgrade')
|
||||
self.assertEqual(
|
||||
resp['headers']['Connection'], 'Upgrade', 'connection'
|
||||
)
|
||||
self.assertEqual(
|
||||
resp['headers']['Sec-WebSocket-Accept'], self.ws.accept(key), 'key'
|
||||
)
|
||||
assert resp['status'] == 101, 'status'
|
||||
assert resp['headers']['Upgrade'] == 'websocket', 'upgrade'
|
||||
assert resp['headers']['Connection'] == 'Upgrade', 'connection'
|
||||
assert resp['headers']['Sec-WebSocket-Accept'] == self.ws.accept(
|
||||
key
|
||||
), 'key'
|
||||
|
||||
def test_java_websockets_mirror(self):
|
||||
self.load('websockets_mirror')
|
||||
|
@ -78,12 +71,12 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
self.ws.frame_write(sock, self.ws.OP_TEXT, message)
|
||||
frame = self.ws.frame_read(sock)
|
||||
|
||||
self.assertEqual(message, frame['data'].decode('utf-8'), 'mirror')
|
||||
assert message == frame['data'].decode('utf-8'), 'mirror'
|
||||
|
||||
self.ws.frame_write(sock, self.ws.OP_TEXT, message)
|
||||
frame = self.ws.frame_read(sock)
|
||||
|
||||
self.assertEqual(message, frame['data'].decode('utf-8'), 'mirror 2')
|
||||
assert message == frame['data'].decode('utf-8'), 'mirror 2'
|
||||
|
||||
sock.close()
|
||||
|
||||
|
@ -98,8 +91,8 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
|
||||
frame = self.ws.frame_read(sock)
|
||||
|
||||
self.assertEqual(frame['opcode'], self.ws.OP_CLOSE, 'no mask opcode')
|
||||
self.assertEqual(frame['code'], 1002, 'no mask close code')
|
||||
assert frame['opcode'] == self.ws.OP_CLOSE, 'no mask opcode'
|
||||
assert frame['code'] == 1002, 'no mask close code'
|
||||
|
||||
sock.close()
|
||||
|
||||
|
@ -116,11 +109,9 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
|
||||
frame = self.ws.frame_read(sock)
|
||||
|
||||
self.assertEqual(
|
||||
message + ' ' + message,
|
||||
frame['data'].decode('utf-8'),
|
||||
'mirror framing',
|
||||
)
|
||||
assert message + ' ' + message == frame['data'].decode(
|
||||
'utf-8'
|
||||
), 'mirror framing'
|
||||
|
||||
sock.close()
|
||||
|
||||
|
@ -136,20 +127,16 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
frame = self.ws.frame_read(sock)
|
||||
|
||||
frame.pop('data')
|
||||
self.assertDictEqual(
|
||||
frame,
|
||||
{
|
||||
'fin': True,
|
||||
'rsv1': False,
|
||||
'rsv2': False,
|
||||
'rsv3': False,
|
||||
'opcode': self.ws.OP_CLOSE,
|
||||
'mask': 0,
|
||||
'code': 1002,
|
||||
'reason': 'Fragmented control frame',
|
||||
},
|
||||
'close frame',
|
||||
)
|
||||
assert frame == {
|
||||
'fin': True,
|
||||
'rsv1': False,
|
||||
'rsv2': False,
|
||||
'rsv3': False,
|
||||
'opcode': self.ws.OP_CLOSE,
|
||||
'mask': 0,
|
||||
'code': 1002,
|
||||
'reason': 'Fragmented control frame',
|
||||
}, 'close frame'
|
||||
|
||||
sock.close()
|
||||
|
||||
|
@ -168,13 +155,13 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
frame1 = self.ws.frame_read(sock1)
|
||||
frame2 = self.ws.frame_read(sock2)
|
||||
|
||||
self.assertEqual(message1, frame1['data'].decode('utf-8'), 'client 1')
|
||||
self.assertEqual(message2, frame2['data'].decode('utf-8'), 'client 2')
|
||||
assert message1 == frame1['data'].decode('utf-8'), 'client 1'
|
||||
assert message2 == frame2['data'].decode('utf-8'), 'client 2'
|
||||
|
||||
sock1.close()
|
||||
sock2.close()
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_java_websockets_handshake_upgrade_absent(
|
||||
self
|
||||
): # FAIL https://tools.ietf.org/html/rfc6455#section-4.2.1
|
||||
|
@ -190,7 +177,7 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
},
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 400, 'upgrade absent')
|
||||
assert resp['status'] == 400, 'upgrade absent'
|
||||
|
||||
def test_java_websockets_handshake_case_insensitive(self):
|
||||
self.load('websockets_mirror')
|
||||
|
@ -207,9 +194,9 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
)
|
||||
sock.close()
|
||||
|
||||
self.assertEqual(resp['status'], 101, 'status')
|
||||
assert resp['status'] == 101, 'status'
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_java_websockets_handshake_connection_absent(self): # FAIL
|
||||
self.load('websockets_mirror')
|
||||
|
||||
|
@ -223,7 +210,7 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
},
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 400, 'status')
|
||||
assert resp['status'] == 400, 'status'
|
||||
|
||||
def test_java_websockets_handshake_version_absent(self):
|
||||
self.load('websockets_mirror')
|
||||
|
@ -238,9 +225,9 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
},
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 426, 'status')
|
||||
assert resp['status'] == 426, 'status'
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_java_websockets_handshake_key_invalid(self):
|
||||
self.load('websockets_mirror')
|
||||
|
||||
|
@ -255,7 +242,7 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
},
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 400, 'key length')
|
||||
assert resp['status'] == 400, 'key length'
|
||||
|
||||
key = self.ws.key()
|
||||
resp = self.get(
|
||||
|
@ -269,9 +256,7 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
},
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
resp['status'], 400, 'key double'
|
||||
) # FAIL https://tools.ietf.org/html/rfc6455#section-11.3.1
|
||||
assert resp['status'] == 400, 'key double' # FAIL https://tools.ietf.org/html/rfc6455#section-11.3.1
|
||||
|
||||
def test_java_websockets_handshake_method_invalid(self):
|
||||
self.load('websockets_mirror')
|
||||
|
@ -287,7 +272,7 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
},
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 400, 'status')
|
||||
assert resp['status'] == 400, 'status'
|
||||
|
||||
def test_java_websockets_handshake_http_10(self):
|
||||
self.load('websockets_mirror')
|
||||
|
@ -304,7 +289,7 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
http_10=True,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 400, 'status')
|
||||
assert resp['status'] == 400, 'status'
|
||||
|
||||
def test_java_websockets_handshake_uri_invalid(self):
|
||||
self.load('websockets_mirror')
|
||||
|
@ -321,7 +306,7 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
url='!',
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 400, 'status')
|
||||
assert resp['status'] == 400, 'status'
|
||||
|
||||
def test_java_websockets_protocol_absent(self):
|
||||
self.load('websockets_mirror')
|
||||
|
@ -338,14 +323,12 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
)
|
||||
sock.close()
|
||||
|
||||
self.assertEqual(resp['status'], 101, 'status')
|
||||
self.assertEqual(resp['headers']['Upgrade'], 'websocket', 'upgrade')
|
||||
self.assertEqual(
|
||||
resp['headers']['Connection'], 'Upgrade', 'connection'
|
||||
)
|
||||
self.assertEqual(
|
||||
resp['headers']['Sec-WebSocket-Accept'], self.ws.accept(key), 'key'
|
||||
)
|
||||
assert resp['status'] == 101, 'status'
|
||||
assert resp['headers']['Upgrade'] == 'websocket', 'upgrade'
|
||||
assert resp['headers']['Connection'] == 'Upgrade', 'connection'
|
||||
assert resp['headers']['Sec-WebSocket-Accept'] == self.ws.accept(
|
||||
key
|
||||
), 'key'
|
||||
|
||||
# autobahn-testsuite
|
||||
#
|
||||
|
@ -442,12 +425,12 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
_, sock, _ = self.ws.upgrade()
|
||||
|
||||
self.ws.frame_write(sock, self.ws.OP_PONG, '')
|
||||
self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '2_7')
|
||||
assert self.recvall(sock, read_timeout=0.1) == b'', '2_7'
|
||||
|
||||
# 2_8
|
||||
|
||||
self.ws.frame_write(sock, self.ws.OP_PONG, 'unsolicited pong payload')
|
||||
self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '2_8')
|
||||
assert self.recvall(sock, read_timeout=0.1) == b'', '2_8'
|
||||
|
||||
# 2_9
|
||||
|
||||
|
@ -487,7 +470,7 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
|
||||
self.close_connection(sock)
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_java_websockets_3_1__3_7(self):
|
||||
self.load('websockets_mirror')
|
||||
|
||||
|
@ -513,7 +496,7 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
|
||||
self.check_close(sock, 1002, no_close=True)
|
||||
|
||||
self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty 3_2')
|
||||
assert self.recvall(sock, read_timeout=0.1) == b'', 'empty 3_2'
|
||||
sock.close()
|
||||
|
||||
# 3_3
|
||||
|
@ -531,7 +514,7 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
|
||||
self.check_close(sock, 1002, no_close=True)
|
||||
|
||||
self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty 3_3')
|
||||
assert self.recvall(sock, read_timeout=0.1) == b'', 'empty 3_3'
|
||||
sock.close()
|
||||
|
||||
# 3_4
|
||||
|
@ -549,7 +532,7 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
|
||||
self.check_close(sock, 1002, no_close=True)
|
||||
|
||||
self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty 3_4')
|
||||
assert self.recvall(sock, read_timeout=0.1) == b'', 'empty 3_4'
|
||||
sock.close()
|
||||
|
||||
# 3_5
|
||||
|
@ -735,7 +718,7 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
# 5_4
|
||||
|
||||
self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False)
|
||||
self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '5_4')
|
||||
assert self.recvall(sock, read_timeout=0.1) == b'', '5_4'
|
||||
self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=True)
|
||||
|
||||
frame = self.ws.frame_read(sock)
|
||||
|
@ -772,7 +755,7 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
ping_payload = 'ping payload'
|
||||
|
||||
self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False)
|
||||
self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '5_7')
|
||||
assert self.recvall(sock, read_timeout=0.1) == b'', '5_7'
|
||||
|
||||
self.ws.frame_write(sock, self.ws.OP_PING, ping_payload)
|
||||
|
||||
|
@ -956,7 +939,7 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
frame = self.ws.frame_read(sock)
|
||||
self.check_frame(frame, True, self.ws.OP_PONG, 'pongme 2!')
|
||||
|
||||
self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '5_20')
|
||||
assert self.recvall(sock, read_timeout=0.1) == b'', '5_20'
|
||||
self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment5')
|
||||
|
||||
self.check_frame(
|
||||
|
@ -1089,7 +1072,7 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
self.check_close(sock, no_close=True)
|
||||
|
||||
self.ws.frame_write(sock, self.ws.OP_PING, '')
|
||||
self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc')
|
||||
assert self.recvall(sock, read_timeout=0.1) == b'', 'empty soc'
|
||||
|
||||
sock.close()
|
||||
|
||||
|
@ -1101,7 +1084,7 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
self.check_close(sock, no_close=True)
|
||||
|
||||
self.ws.frame_write(sock, self.ws.OP_TEXT, payload)
|
||||
self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc')
|
||||
assert self.recvall(sock, read_timeout=0.1) == b'', 'empty soc'
|
||||
|
||||
sock.close()
|
||||
|
||||
|
@ -1114,7 +1097,7 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
self.check_close(sock, no_close=True)
|
||||
|
||||
self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2')
|
||||
self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc')
|
||||
assert self.recvall(sock, read_timeout=0.1) == b'', 'empty soc'
|
||||
|
||||
sock.close()
|
||||
|
||||
|
@ -1129,7 +1112,7 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
self.recvall(sock, read_timeout=1)
|
||||
|
||||
self.ws.frame_write(sock, self.ws.OP_PING, '')
|
||||
self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc')
|
||||
assert self.recvall(sock, read_timeout=0.1) == b'', 'empty soc'
|
||||
|
||||
sock.close()
|
||||
|
||||
|
@ -1249,27 +1232,23 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
self.ws.frame_write(sock, self.ws.OP_CLOSE, payload)
|
||||
self.check_close(sock, 1002)
|
||||
|
||||
def test_java_websockets_9_1_1__9_6_6(self):
|
||||
if not self.unsafe:
|
||||
self.skipTest("unsafe, long run")
|
||||
def test_java_websockets_9_1_1__9_6_6(self, is_unsafe):
|
||||
if not is_unsafe:
|
||||
pytest.skip('unsafe, long run')
|
||||
|
||||
self.load('websockets_mirror')
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{
|
||||
'http': {
|
||||
'websocket': {
|
||||
'max_frame_size': 33554432,
|
||||
'keepalive_interval': 0,
|
||||
}
|
||||
assert 'success' in self.conf(
|
||||
{
|
||||
'http': {
|
||||
'websocket': {
|
||||
'max_frame_size': 33554432,
|
||||
'keepalive_interval': 0,
|
||||
}
|
||||
},
|
||||
'settings',
|
||||
),
|
||||
'increase max_frame_size and keepalive_interval',
|
||||
)
|
||||
}
|
||||
},
|
||||
'settings',
|
||||
), 'increase max_frame_size and keepalive_interval'
|
||||
|
||||
_, sock, _ = self.ws.upgrade()
|
||||
|
||||
|
@ -1310,7 +1289,7 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
check_payload(op_binary, 8 * 2 ** 20) # 9_2_5
|
||||
check_payload(op_binary, 16 * 2 ** 20) # 9_2_6
|
||||
|
||||
if self.system != 'Darwin' and self.system != 'FreeBSD':
|
||||
if option.system != 'Darwin' and option.system != 'FreeBSD':
|
||||
check_message(op_text, 64) # 9_3_1
|
||||
check_message(op_text, 256) # 9_3_2
|
||||
check_message(op_text, 2 ** 10) # 9_3_3
|
||||
|
@ -1366,13 +1345,9 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
def test_java_websockets_max_frame_size(self):
|
||||
self.load('websockets_mirror')
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{'http': {'websocket': {'max_frame_size': 100}}}, 'settings'
|
||||
),
|
||||
'configure max_frame_size',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{'http': {'websocket': {'max_frame_size': 100}}}, 'settings'
|
||||
), 'configure max_frame_size'
|
||||
|
||||
_, sock, _ = self.ws.upgrade()
|
||||
|
||||
|
@ -1392,13 +1367,9 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
def test_java_websockets_read_timeout(self):
|
||||
self.load('websockets_mirror')
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{'http': {'websocket': {'read_timeout': 5}}}, 'settings'
|
||||
),
|
||||
'configure read_timeout',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{'http': {'websocket': {'read_timeout': 5}}}, 'settings'
|
||||
), 'configure read_timeout'
|
||||
|
||||
_, sock, _ = self.ws.upgrade()
|
||||
|
||||
|
@ -1412,13 +1383,9 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
def test_java_websockets_keepalive_interval(self):
|
||||
self.load('websockets_mirror')
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{'http': {'websocket': {'keepalive_interval': 5}}}, 'settings'
|
||||
),
|
||||
'configure keepalive_interval',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{'http': {'websocket': {'keepalive_interval': 5}}}, 'settings'
|
||||
), 'configure keepalive_interval'
|
||||
|
||||
_, sock, _ = self.ws.upgrade()
|
||||
|
||||
|
@ -1431,7 +1398,3 @@ class TestJavaWebsockets(TestApplicationJava):
|
|||
self.check_frame(frame, True, self.ws.OP_PING, '') # PING frame
|
||||
|
||||
sock.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestJavaWebsockets.main()
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import unittest
|
||||
import pytest
|
||||
import re
|
||||
|
||||
from unit.applications.lang.node import TestApplicationNode
|
||||
from conftest import waitforfiles
|
||||
|
||||
|
||||
class TestNodeApplication(TestApplicationNode):
|
||||
|
@ -10,16 +12,14 @@ class TestNodeApplication(TestApplicationNode):
|
|||
self.load('basic')
|
||||
|
||||
resp = self.get()
|
||||
self.assertEqual(
|
||||
resp['headers']['Content-Type'], 'text/plain', 'basic header'
|
||||
)
|
||||
self.assertEqual(resp['body'], 'Hello World\n', 'basic body')
|
||||
assert resp['headers']['Content-Type'] == 'text/plain', 'basic header'
|
||||
assert resp['body'] == 'Hello World\n', 'basic body'
|
||||
|
||||
def test_node_application_seq(self):
|
||||
self.load('basic')
|
||||
|
||||
self.assertEqual(self.get()['status'], 200, 'seq')
|
||||
self.assertEqual(self.get()['status'], 200, 'seq 2')
|
||||
assert self.get()['status'] == 200, 'seq'
|
||||
assert self.get()['status'] == 200, 'seq 2'
|
||||
|
||||
def test_node_application_variables(self):
|
||||
self.load('variables')
|
||||
|
@ -36,51 +36,44 @@ class TestNodeApplication(TestApplicationNode):
|
|||
body=body,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'status')
|
||||
assert resp['status'] == 200, 'status'
|
||||
headers = resp['headers']
|
||||
header_server = headers.pop('Server')
|
||||
self.assertRegex(header_server, r'Unit/[\d\.]+', 'server header')
|
||||
assert re.search(r'Unit/[\d\.]+', header_server), 'server header'
|
||||
|
||||
date = headers.pop('Date')
|
||||
self.assertEqual(date[-4:], ' GMT', 'date header timezone')
|
||||
self.assertLess(
|
||||
abs(self.date_to_sec_epoch(date) - self.sec_epoch()),
|
||||
5,
|
||||
'date header',
|
||||
)
|
||||
assert date[-4:] == ' GMT', 'date header timezone'
|
||||
assert (
|
||||
abs(self.date_to_sec_epoch(date) - self.sec_epoch()) < 5
|
||||
), 'date header'
|
||||
|
||||
raw_headers = headers.pop('Request-Raw-Headers')
|
||||
self.assertRegex(
|
||||
raw_headers,
|
||||
assert re.search(
|
||||
r'^(?:Host|localhost|Content-Type|'
|
||||
'text\/html|Custom-Header|blah|Content-Length|17|Connection|'
|
||||
'close|,)+$',
|
||||
'raw headers',
|
||||
)
|
||||
raw_headers,
|
||||
), 'raw headers'
|
||||
|
||||
self.assertDictEqual(
|
||||
headers,
|
||||
{
|
||||
'Connection': 'close',
|
||||
'Content-Length': str(len(body)),
|
||||
'Content-Type': 'text/html',
|
||||
'Request-Method': 'POST',
|
||||
'Request-Uri': '/',
|
||||
'Http-Host': 'localhost',
|
||||
'Server-Protocol': 'HTTP/1.1',
|
||||
'Custom-Header': 'blah',
|
||||
},
|
||||
'headers',
|
||||
)
|
||||
self.assertEqual(resp['body'], body, 'body')
|
||||
assert headers == {
|
||||
'Connection': 'close',
|
||||
'Content-Length': str(len(body)),
|
||||
'Content-Type': 'text/html',
|
||||
'Request-Method': 'POST',
|
||||
'Request-Uri': '/',
|
||||
'Http-Host': 'localhost',
|
||||
'Server-Protocol': 'HTTP/1.1',
|
||||
'Custom-Header': 'blah',
|
||||
}, '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')
|
||||
self.assertEqual(resp['headers']['X-Var-1'], 'val1', 'GET variables')
|
||||
self.assertEqual(resp['headers']['X-Var-2'], '', 'GET variables 2')
|
||||
self.assertEqual(resp['headers']['X-Var-3'], '', 'GET variables 3')
|
||||
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')
|
||||
|
@ -94,24 +87,24 @@ class TestNodeApplication(TestApplicationNode):
|
|||
body='var1=val1&var2=&var3',
|
||||
)
|
||||
|
||||
self.assertEqual(resp['headers']['X-Var-1'], 'val1', 'POST variables')
|
||||
self.assertEqual(resp['headers']['X-Var-2'], '', 'POST variables 2')
|
||||
self.assertEqual(resp['headers']['X-Var-3'], '', 'POST variables 3')
|
||||
assert resp['headers']['X-Var-1'] == 'val1', 'POST variables'
|
||||
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()
|
||||
|
||||
self.assertEqual(resp['status'], 404, '404 status')
|
||||
self.assertRegex(
|
||||
resp['body'], r'<title>404 Not Found</title>', '404 body'
|
||||
)
|
||||
assert resp['status'] == 404, '404 status'
|
||||
assert re.search(
|
||||
r'<title>404 Not Found</title>', resp['body']
|
||||
), '404 body'
|
||||
|
||||
def test_node_keepalive_body(self):
|
||||
self.load('mirror')
|
||||
|
||||
self.assertEqual(self.get()['status'], 200, 'init')
|
||||
assert self.get()['status'] == 200, 'init'
|
||||
|
||||
body = '0123456789' * 500
|
||||
(resp, sock) = self.post(
|
||||
|
@ -125,7 +118,7 @@ class TestNodeApplication(TestApplicationNode):
|
|||
read_timeout=1,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1')
|
||||
assert resp['body'] == '0123456789' * 500, 'keep-alive 1'
|
||||
|
||||
body = '0123456789'
|
||||
resp = self.post(
|
||||
|
@ -138,47 +131,34 @@ class TestNodeApplication(TestApplicationNode):
|
|||
body=body,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['body'], body, 'keep-alive 2')
|
||||
assert resp['body'] == body, 'keep-alive 2'
|
||||
|
||||
def test_node_application_write_buffer(self):
|
||||
self.load('write_buffer')
|
||||
|
||||
self.assertEqual(
|
||||
self.get()['body'], 'buffer', 'write buffer'
|
||||
)
|
||||
assert self.get()['body'] == 'buffer', 'write buffer'
|
||||
|
||||
def test_node_application_write_callback(self):
|
||||
self.load('write_callback')
|
||||
|
||||
self.assertEqual(
|
||||
self.get()['body'],
|
||||
'helloworld',
|
||||
'write callback order',
|
||||
)
|
||||
self.assertTrue(
|
||||
self.waitforfiles(self.testdir + '/node/callback'),
|
||||
'write callback',
|
||||
)
|
||||
assert self.get()['body'] == 'helloworld', 'write callback order'
|
||||
assert waitforfiles(self.temp_dir + '/node/callback'), 'write callback'
|
||||
|
||||
def test_node_application_write_before_write_head(self):
|
||||
self.load('write_before_write_head')
|
||||
|
||||
self.assertEqual(self.get()['status'], 200, 'write before writeHead')
|
||||
assert self.get()['status'] == 200, 'write before writeHead'
|
||||
|
||||
def test_node_application_double_end(self):
|
||||
self.load('double_end')
|
||||
|
||||
self.assertEqual(self.get()['status'], 200, 'double end')
|
||||
self.assertEqual(self.get()['status'], 200, 'double end 2')
|
||||
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')
|
||||
|
||||
self.assertEqual(
|
||||
self.get()['body'],
|
||||
'bodytrue',
|
||||
'write return',
|
||||
)
|
||||
assert self.get()['body'] == 'bodytrue', 'write return'
|
||||
|
||||
def test_node_application_remove_header(self):
|
||||
self.load('remove_header')
|
||||
|
@ -190,69 +170,61 @@ class TestNodeApplication(TestApplicationNode):
|
|||
'Connection': 'close',
|
||||
}
|
||||
)
|
||||
self.assertEqual(resp['headers']['Was-Header'], 'true', 'was header')
|
||||
self.assertEqual(resp['headers']['Has-Header'], 'false', 'has header')
|
||||
self.assertFalse('X-Header' in resp['headers'], 'remove header')
|
||||
assert resp['headers']['Was-Header'] == 'true', 'was header'
|
||||
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')
|
||||
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Remove': 'blah',
|
||||
'Connection': 'close',
|
||||
}
|
||||
)['headers']['Has-Header'],
|
||||
'true',
|
||||
'remove header nonexisting',
|
||||
)
|
||||
)['headers']['Has-Header']
|
||||
== 'true'
|
||||
), 'remove header nonexisting'
|
||||
|
||||
def test_node_application_update_header(self):
|
||||
self.load('update_header')
|
||||
|
||||
self.assertEqual(
|
||||
self.get()['headers']['X-Header'], 'new', 'update header'
|
||||
)
|
||||
assert self.get()['headers']['X-Header'] == 'new', 'update header'
|
||||
|
||||
def test_node_application_set_header_array(self):
|
||||
self.load('set_header_array')
|
||||
|
||||
self.assertListEqual(
|
||||
self.get()['headers']['Set-Cookie'],
|
||||
['tc=one,two,three', 'tc=four,five,six'],
|
||||
'set header array',
|
||||
)
|
||||
assert self.get()['headers']['Set-Cookie'] == [
|
||||
'tc=one,two,three',
|
||||
'tc=four,five,six',
|
||||
], 'set header array'
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_node_application_status_message(self):
|
||||
self.load('status_message')
|
||||
|
||||
self.assertRegex(
|
||||
self.get(raw_resp=True), r'200 blah', 'status message'
|
||||
)
|
||||
assert re.search(r'200 blah', self.get(raw_resp=True)), 'status message'
|
||||
|
||||
def test_node_application_get_header_type(self):
|
||||
self.load('get_header_type')
|
||||
|
||||
self.assertEqual(
|
||||
self.get()['headers']['X-Type'], 'number', 'get header type'
|
||||
)
|
||||
assert self.get()['headers']['X-Type'] == 'number', 'get header type'
|
||||
|
||||
def test_node_application_header_name_case(self):
|
||||
self.load('header_name_case')
|
||||
|
||||
headers = self.get()['headers']
|
||||
|
||||
self.assertEqual(headers['X-HEADER'], '3', 'header value')
|
||||
self.assertNotIn('X-Header', headers, 'insensitive')
|
||||
self.assertNotIn('X-header', headers, 'insensitive 2')
|
||||
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(self):
|
||||
self.load('promise_handler')
|
||||
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
|
@ -260,19 +232,15 @@ class TestNodeApplication(TestApplicationNode):
|
|||
'Connection': 'close',
|
||||
},
|
||||
body='callback',
|
||||
)['status'],
|
||||
200,
|
||||
'promise handler request',
|
||||
)
|
||||
self.assertTrue(
|
||||
self.waitforfiles(self.testdir + '/node/callback'),
|
||||
'promise handler',
|
||||
)
|
||||
)['status']
|
||||
== 200
|
||||
), 'promise handler request'
|
||||
assert waitforfiles(self.temp_dir + '/node/callback'), 'promise handler'
|
||||
|
||||
def test_node_application_promise_handler_write_after_end(self):
|
||||
self.load('promise_handler')
|
||||
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
|
@ -281,15 +249,14 @@ class TestNodeApplication(TestApplicationNode):
|
|||
'Connection': 'close',
|
||||
},
|
||||
body='callback',
|
||||
)['status'],
|
||||
200,
|
||||
'promise handler request write after end',
|
||||
)
|
||||
)['status']
|
||||
== 200
|
||||
), 'promise handler request write after end'
|
||||
|
||||
def test_node_application_promise_end(self):
|
||||
self.load('promise_end')
|
||||
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
|
@ -297,13 +264,10 @@ class TestNodeApplication(TestApplicationNode):
|
|||
'Connection': 'close',
|
||||
},
|
||||
body='end',
|
||||
)['status'],
|
||||
200,
|
||||
'promise end request',
|
||||
)
|
||||
self.assertTrue(
|
||||
self.waitforfiles(self.testdir + '/node/callback'), 'promise end'
|
||||
)
|
||||
)['status']
|
||||
== 200
|
||||
), 'promise end request'
|
||||
assert waitforfiles(self.temp_dir + '/node/callback'), 'promise end'
|
||||
|
||||
def test_node_application_promise_multiple_calls(self):
|
||||
self.load('promise_handler')
|
||||
|
@ -317,10 +281,9 @@ class TestNodeApplication(TestApplicationNode):
|
|||
body='callback1',
|
||||
)
|
||||
|
||||
self.assertTrue(
|
||||
self.waitforfiles(self.testdir + '/node/callback1'),
|
||||
'promise first call',
|
||||
)
|
||||
assert waitforfiles(
|
||||
self.temp_dir + '/node/callback1'
|
||||
), 'promise first call'
|
||||
|
||||
self.post(
|
||||
headers={
|
||||
|
@ -331,65 +294,55 @@ class TestNodeApplication(TestApplicationNode):
|
|||
body='callback2',
|
||||
)
|
||||
|
||||
self.assertTrue(
|
||||
self.waitforfiles(self.testdir + '/node/callback2'),
|
||||
'promise second call',
|
||||
)
|
||||
assert waitforfiles(
|
||||
self.temp_dir + '/node/callback2'
|
||||
), 'promise second call'
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_node_application_header_name_valid(self):
|
||||
self.load('header_name_valid')
|
||||
|
||||
self.assertNotIn('status', self.get(), 'header name valid')
|
||||
assert 'status' not in self.get(), 'header name valid'
|
||||
|
||||
def test_node_application_header_value_object(self):
|
||||
self.load('header_value_object')
|
||||
|
||||
self.assertIn('X-Header', self.get()['headers'], 'header value object')
|
||||
assert 'X-Header' in self.get()['headers'], 'header value object'
|
||||
|
||||
def test_node_application_get_header_names(self):
|
||||
self.load('get_header_names')
|
||||
|
||||
self.assertListEqual(
|
||||
self.get()['headers']['X-Names'],
|
||||
['date', 'x-header'],
|
||||
'get header names',
|
||||
)
|
||||
assert self.get()['headers']['X-Names'] == [
|
||||
'date',
|
||||
'x-header',
|
||||
], 'get header names'
|
||||
|
||||
def test_node_application_has_header(self):
|
||||
self.load('has_header')
|
||||
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Header': 'length',
|
||||
'Connection': 'close',
|
||||
}
|
||||
)['headers']['X-Has-Header'],
|
||||
'false',
|
||||
'has header length',
|
||||
)
|
||||
)['headers']['X-Has-Header']
|
||||
== 'false'
|
||||
), 'has header length'
|
||||
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Header': 'Date',
|
||||
'Connection': 'close',
|
||||
}
|
||||
)['headers']['X-Has-Header'],
|
||||
'false',
|
||||
'has header date',
|
||||
)
|
||||
)['headers']['X-Has-Header']
|
||||
== 'false'
|
||||
), 'has header date'
|
||||
|
||||
def test_node_application_write_multiple(self):
|
||||
self.load('write_multiple')
|
||||
|
||||
self.assertEqual(
|
||||
self.get()['body'], 'writewrite2end', 'write multiple'
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestNodeApplication.main()
|
||||
assert self.get()['body'] == 'writewrite2end', 'write multiple'
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import pytest
|
||||
import struct
|
||||
import time
|
||||
import unittest
|
||||
|
||||
from unit.applications.lang.node import TestApplicationNode
|
||||
from unit.applications.websockets import TestApplicationWebsocket
|
||||
from conftest import option, skip_alert
|
||||
|
||||
|
||||
class TestNodeWebsockets(TestApplicationNode):
|
||||
|
@ -11,23 +12,17 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
|
||||
ws = TestApplicationWebsocket()
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
def setup_method(self):
|
||||
super().setup_method()
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{'http': {'websocket': {'keepalive_interval': 0}}}, 'settings'
|
||||
),
|
||||
'clear keepalive_interval',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{'http': {'websocket': {'keepalive_interval': 0}}}, 'settings'
|
||||
), 'clear keepalive_interval'
|
||||
|
||||
self.skip_alerts.extend(
|
||||
[r'socket close\(\d+\) failed']
|
||||
)
|
||||
skip_alert(r'socket close\(\d+\) failed')
|
||||
|
||||
def close_connection(self, sock):
|
||||
self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc')
|
||||
assert self.recvall(sock, read_timeout=0.1) == b'', 'empty soc'
|
||||
|
||||
self.ws.frame_write(sock, self.ws.OP_CLOSE, self.ws.serialize_close())
|
||||
|
||||
|
@ -36,9 +31,9 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
def check_close(self, sock, code=1000, no_close=False):
|
||||
frame = self.ws.frame_read(sock)
|
||||
|
||||
self.assertEqual(frame['fin'], True, 'close fin')
|
||||
self.assertEqual(frame['opcode'], self.ws.OP_CLOSE, 'close opcode')
|
||||
self.assertEqual(frame['code'], code, 'close code')
|
||||
assert frame['fin'] == True, 'close fin'
|
||||
assert frame['opcode'] == self.ws.OP_CLOSE, 'close opcode'
|
||||
assert frame['code'] == code, 'close code'
|
||||
|
||||
if not no_close:
|
||||
sock.close()
|
||||
|
@ -49,9 +44,9 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
else:
|
||||
data = frame['data'].decode('utf-8')
|
||||
|
||||
self.assertEqual(frame['fin'], fin, 'fin')
|
||||
self.assertEqual(frame['opcode'], opcode, 'opcode')
|
||||
self.assertEqual(data, payload, 'payload')
|
||||
assert frame['fin'] == fin, 'fin'
|
||||
assert frame['opcode'] == opcode, 'opcode'
|
||||
assert data == payload, 'payload'
|
||||
|
||||
def test_node_websockets_handshake(self):
|
||||
self.load('websockets/mirror')
|
||||
|
@ -59,14 +54,12 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
resp, sock, key = self.ws.upgrade()
|
||||
sock.close()
|
||||
|
||||
self.assertEqual(resp['status'], 101, 'status')
|
||||
self.assertEqual(resp['headers']['Upgrade'], 'websocket', 'upgrade')
|
||||
self.assertEqual(
|
||||
resp['headers']['Connection'], 'Upgrade', 'connection'
|
||||
)
|
||||
self.assertEqual(
|
||||
resp['headers']['Sec-WebSocket-Accept'], self.ws.accept(key), 'key'
|
||||
)
|
||||
assert resp['status'] == 101, 'status'
|
||||
assert resp['headers']['Upgrade'] == 'websocket', 'upgrade'
|
||||
assert resp['headers']['Connection'] == 'Upgrade', 'connection'
|
||||
assert resp['headers']['Sec-WebSocket-Accept'] == self.ws.accept(
|
||||
key
|
||||
), 'key'
|
||||
|
||||
def test_node_websockets_mirror(self):
|
||||
self.load('websockets/mirror')
|
||||
|
@ -78,12 +71,12 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
self.ws.frame_write(sock, self.ws.OP_TEXT, message)
|
||||
frame = self.ws.frame_read(sock)
|
||||
|
||||
self.assertEqual(message, frame['data'].decode('utf-8'), 'mirror')
|
||||
assert message == frame['data'].decode('utf-8'), 'mirror'
|
||||
|
||||
self.ws.frame_write(sock, self.ws.OP_TEXT, message)
|
||||
frame = self.ws.frame_read(sock)
|
||||
|
||||
self.assertEqual(message, frame['data'].decode('utf-8'), 'mirror 2')
|
||||
assert message == frame['data'].decode('utf-8'), 'mirror 2'
|
||||
|
||||
sock.close()
|
||||
|
||||
|
@ -98,8 +91,8 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
|
||||
frame = self.ws.frame_read(sock)
|
||||
|
||||
self.assertEqual(frame['opcode'], self.ws.OP_CLOSE, 'no mask opcode')
|
||||
self.assertEqual(frame['code'], 1002, 'no mask close code')
|
||||
assert frame['opcode'] == self.ws.OP_CLOSE, 'no mask opcode'
|
||||
assert frame['code'] == 1002, 'no mask close code'
|
||||
|
||||
sock.close()
|
||||
|
||||
|
@ -116,11 +109,9 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
|
||||
frame = self.ws.frame_read(sock)
|
||||
|
||||
self.assertEqual(
|
||||
message + ' ' + message,
|
||||
frame['data'].decode('utf-8'),
|
||||
'mirror framing',
|
||||
)
|
||||
assert message + ' ' + message == frame['data'].decode(
|
||||
'utf-8'
|
||||
), 'mirror framing'
|
||||
|
||||
sock.close()
|
||||
|
||||
|
@ -136,20 +127,16 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
frame = self.ws.frame_read(sock)
|
||||
|
||||
frame.pop('data')
|
||||
self.assertDictEqual(
|
||||
frame,
|
||||
{
|
||||
'fin': True,
|
||||
'rsv1': False,
|
||||
'rsv2': False,
|
||||
'rsv3': False,
|
||||
'opcode': self.ws.OP_CLOSE,
|
||||
'mask': 0,
|
||||
'code': 1002,
|
||||
'reason': 'Fragmented control frame',
|
||||
},
|
||||
'close frame',
|
||||
)
|
||||
assert frame == {
|
||||
'fin': True,
|
||||
'rsv1': False,
|
||||
'rsv2': False,
|
||||
'rsv3': False,
|
||||
'opcode': self.ws.OP_CLOSE,
|
||||
'mask': 0,
|
||||
'code': 1002,
|
||||
'reason': 'Fragmented control frame',
|
||||
}, 'close frame'
|
||||
|
||||
sock.close()
|
||||
|
||||
|
@ -168,7 +155,7 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
frame = self.ws.frame_read(sock)
|
||||
data += frame['data'].decode('utf-8')
|
||||
|
||||
self.assertEqual(message, data, 'large')
|
||||
assert message == data, 'large'
|
||||
|
||||
sock.close()
|
||||
|
||||
|
@ -187,13 +174,13 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
frame1 = self.ws.frame_read(sock1)
|
||||
frame2 = self.ws.frame_read(sock2)
|
||||
|
||||
self.assertEqual(message1, frame1['data'].decode('utf-8'), 'client 1')
|
||||
self.assertEqual(message2, frame2['data'].decode('utf-8'), 'client 2')
|
||||
assert message1 == frame1['data'].decode('utf-8'), 'client 1'
|
||||
assert message2 == frame2['data'].decode('utf-8'), 'client 2'
|
||||
|
||||
sock1.close()
|
||||
sock2.close()
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_node_websockets_handshake_upgrade_absent(
|
||||
self
|
||||
): # FAIL https://tools.ietf.org/html/rfc6455#section-4.2.1
|
||||
|
@ -209,7 +196,7 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
},
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 400, 'upgrade absent')
|
||||
assert resp['status'] == 400, 'upgrade absent'
|
||||
|
||||
def test_node_websockets_handshake_case_insensitive(self):
|
||||
self.load('websockets/mirror')
|
||||
|
@ -226,9 +213,9 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
)
|
||||
sock.close()
|
||||
|
||||
self.assertEqual(resp['status'], 101, 'status')
|
||||
assert resp['status'] == 101, 'status'
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_node_websockets_handshake_connection_absent(self): # FAIL
|
||||
self.load('websockets/mirror')
|
||||
|
||||
|
@ -242,7 +229,7 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
},
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 400, 'status')
|
||||
assert resp['status'] == 400, 'status'
|
||||
|
||||
def test_node_websockets_handshake_version_absent(self):
|
||||
self.load('websockets/mirror')
|
||||
|
@ -257,9 +244,9 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
},
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 426, 'status')
|
||||
assert resp['status'] == 426, 'status'
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_node_websockets_handshake_key_invalid(self):
|
||||
self.load('websockets/mirror')
|
||||
|
||||
|
@ -274,7 +261,7 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
},
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 400, 'key length')
|
||||
assert resp['status'] == 400, 'key length'
|
||||
|
||||
key = self.ws.key()
|
||||
resp = self.get(
|
||||
|
@ -288,9 +275,7 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
},
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
resp['status'], 400, 'key double'
|
||||
) # FAIL https://tools.ietf.org/html/rfc6455#section-11.3.1
|
||||
assert resp['status'] == 400, 'key double' # FAIL https://tools.ietf.org/html/rfc6455#section-11.3.1
|
||||
|
||||
def test_node_websockets_handshake_method_invalid(self):
|
||||
self.load('websockets/mirror')
|
||||
|
@ -306,7 +291,7 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
},
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 400, 'status')
|
||||
assert resp['status'] == 400, 'status'
|
||||
|
||||
def test_node_websockets_handshake_http_10(self):
|
||||
self.load('websockets/mirror')
|
||||
|
@ -323,7 +308,7 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
http_10=True,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 400, 'status')
|
||||
assert resp['status'] == 400, 'status'
|
||||
|
||||
def test_node_websockets_handshake_uri_invalid(self):
|
||||
self.load('websockets/mirror')
|
||||
|
@ -340,7 +325,7 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
url='!',
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 400, 'status')
|
||||
assert resp['status'] == 400, 'status'
|
||||
|
||||
def test_node_websockets_protocol_absent(self):
|
||||
self.load('websockets/mirror')
|
||||
|
@ -357,14 +342,12 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
)
|
||||
sock.close()
|
||||
|
||||
self.assertEqual(resp['status'], 101, 'status')
|
||||
self.assertEqual(resp['headers']['Upgrade'], 'websocket', 'upgrade')
|
||||
self.assertEqual(
|
||||
resp['headers']['Connection'], 'Upgrade', 'connection'
|
||||
)
|
||||
self.assertEqual(
|
||||
resp['headers']['Sec-WebSocket-Accept'], self.ws.accept(key), 'key'
|
||||
)
|
||||
assert resp['status'] == 101, 'status'
|
||||
assert resp['headers']['Upgrade'] == 'websocket', 'upgrade'
|
||||
assert resp['headers']['Connection'] == 'Upgrade', 'connection'
|
||||
assert resp['headers']['Sec-WebSocket-Accept'] == self.ws.accept(
|
||||
key
|
||||
), 'key'
|
||||
|
||||
# autobahn-testsuite
|
||||
#
|
||||
|
@ -461,12 +444,12 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
_, sock, _ = self.ws.upgrade()
|
||||
|
||||
self.ws.frame_write(sock, self.ws.OP_PONG, '')
|
||||
self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '2_7')
|
||||
assert self.recvall(sock, read_timeout=0.1) == b'', '2_7'
|
||||
|
||||
# 2_8
|
||||
|
||||
self.ws.frame_write(sock, self.ws.OP_PONG, 'unsolicited pong payload')
|
||||
self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '2_8')
|
||||
assert self.recvall(sock, read_timeout=0.1) == b'', '2_8'
|
||||
|
||||
# 2_9
|
||||
|
||||
|
@ -506,7 +489,7 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
|
||||
self.close_connection(sock)
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_node_websockets_3_1__3_7(self):
|
||||
self.load('websockets/mirror')
|
||||
|
||||
|
@ -532,7 +515,7 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
|
||||
self.check_close(sock, 1002, no_close=True)
|
||||
|
||||
self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty 3_2')
|
||||
assert self.recvall(sock, read_timeout=0.1) == b'', 'empty 3_2'
|
||||
sock.close()
|
||||
|
||||
# 3_3
|
||||
|
@ -550,7 +533,7 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
|
||||
self.check_close(sock, 1002, no_close=True)
|
||||
|
||||
self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty 3_3')
|
||||
assert self.recvall(sock, read_timeout=0.1) == b'', 'empty 3_3'
|
||||
sock.close()
|
||||
|
||||
# 3_4
|
||||
|
@ -568,7 +551,7 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
|
||||
self.check_close(sock, 1002, no_close=True)
|
||||
|
||||
self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty 3_4')
|
||||
assert self.recvall(sock, read_timeout=0.1) == b'', 'empty 3_4'
|
||||
sock.close()
|
||||
|
||||
# 3_5
|
||||
|
@ -754,7 +737,7 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
# 5_4
|
||||
|
||||
self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False)
|
||||
self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '5_4')
|
||||
assert self.recvall(sock, read_timeout=0.1) == b'', '5_4'
|
||||
self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=True)
|
||||
|
||||
frame = self.ws.frame_read(sock)
|
||||
|
@ -791,7 +774,7 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
ping_payload = 'ping payload'
|
||||
|
||||
self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment1', fin=False)
|
||||
self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '5_7')
|
||||
assert self.recvall(sock, read_timeout=0.1) == b'', '5_7'
|
||||
|
||||
self.ws.frame_write(sock, self.ws.OP_PING, ping_payload)
|
||||
|
||||
|
@ -975,7 +958,7 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
frame = self.ws.frame_read(sock)
|
||||
self.check_frame(frame, True, self.ws.OP_PONG, 'pongme 2!')
|
||||
|
||||
self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', '5_20')
|
||||
assert self.recvall(sock, read_timeout=0.1) == b'', '5_20'
|
||||
self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment5')
|
||||
|
||||
self.check_frame(
|
||||
|
@ -1108,7 +1091,7 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
self.check_close(sock, no_close=True)
|
||||
|
||||
self.ws.frame_write(sock, self.ws.OP_PING, '')
|
||||
self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc')
|
||||
assert self.recvall(sock, read_timeout=0.1) == b'', 'empty soc'
|
||||
|
||||
sock.close()
|
||||
|
||||
|
@ -1120,7 +1103,7 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
self.check_close(sock, no_close=True)
|
||||
|
||||
self.ws.frame_write(sock, self.ws.OP_TEXT, payload)
|
||||
self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc')
|
||||
assert self.recvall(sock, read_timeout=0.1) == b'', 'empty soc'
|
||||
|
||||
sock.close()
|
||||
|
||||
|
@ -1133,7 +1116,7 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
self.check_close(sock, no_close=True)
|
||||
|
||||
self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2')
|
||||
self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc')
|
||||
assert self.recvall(sock, read_timeout=0.1) == b'', 'empty soc'
|
||||
|
||||
sock.close()
|
||||
|
||||
|
@ -1148,7 +1131,7 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
self.recvall(sock, read_timeout=1)
|
||||
|
||||
self.ws.frame_write(sock, self.ws.OP_PING, '')
|
||||
self.assertEqual(self.recvall(sock, read_timeout=0.1), b'', 'empty soc')
|
||||
assert self.recvall(sock, read_timeout=0.1) == b'', 'empty soc'
|
||||
|
||||
sock.close()
|
||||
|
||||
|
@ -1268,27 +1251,23 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
self.ws.frame_write(sock, self.ws.OP_CLOSE, payload)
|
||||
self.check_close(sock, 1002)
|
||||
|
||||
def test_node_websockets_9_1_1__9_6_6(self):
|
||||
if not self.unsafe:
|
||||
self.skipTest("unsafe, long run")
|
||||
def test_node_websockets_9_1_1__9_6_6(self, is_unsafe):
|
||||
if not is_unsafe:
|
||||
pytest.skip('unsafe, long run')
|
||||
|
||||
self.load('websockets/mirror')
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{
|
||||
'http': {
|
||||
'websocket': {
|
||||
'max_frame_size': 33554432,
|
||||
'keepalive_interval': 0,
|
||||
}
|
||||
assert 'success' in self.conf(
|
||||
{
|
||||
'http': {
|
||||
'websocket': {
|
||||
'max_frame_size': 33554432,
|
||||
'keepalive_interval': 0,
|
||||
}
|
||||
},
|
||||
'settings',
|
||||
),
|
||||
'increase max_frame_size and keepalive_interval',
|
||||
)
|
||||
}
|
||||
},
|
||||
'settings',
|
||||
), 'increase max_frame_size and keepalive_interval'
|
||||
|
||||
_, sock, _ = self.ws.upgrade()
|
||||
|
||||
|
@ -1329,7 +1308,7 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
check_payload(op_binary, 8 * 2 ** 20) # 9_2_5
|
||||
check_payload(op_binary, 16 * 2 ** 20) # 9_2_6
|
||||
|
||||
if self.system != 'Darwin' and self.system != 'FreeBSD':
|
||||
if option.system != 'Darwin' and option.system != 'FreeBSD':
|
||||
check_message(op_text, 64) # 9_3_1
|
||||
check_message(op_text, 256) # 9_3_2
|
||||
check_message(op_text, 2 ** 10) # 9_3_3
|
||||
|
@ -1385,13 +1364,9 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
def test_node_websockets_max_frame_size(self):
|
||||
self.load('websockets/mirror')
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{'http': {'websocket': {'max_frame_size': 100}}}, 'settings'
|
||||
),
|
||||
'configure max_frame_size',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{'http': {'websocket': {'max_frame_size': 100}}}, 'settings'
|
||||
), 'configure max_frame_size'
|
||||
|
||||
_, sock, _ = self.ws.upgrade()
|
||||
|
||||
|
@ -1411,13 +1386,9 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
def test_node_websockets_read_timeout(self):
|
||||
self.load('websockets/mirror')
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{'http': {'websocket': {'read_timeout': 5}}}, 'settings'
|
||||
),
|
||||
'configure read_timeout',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{'http': {'websocket': {'read_timeout': 5}}}, 'settings'
|
||||
), 'configure read_timeout'
|
||||
|
||||
_, sock, _ = self.ws.upgrade()
|
||||
|
||||
|
@ -1431,13 +1402,9 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
def test_node_websockets_keepalive_interval(self):
|
||||
self.load('websockets/mirror')
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{'http': {'websocket': {'keepalive_interval': 5}}}, 'settings'
|
||||
),
|
||||
'configure keepalive_interval',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{'http': {'websocket': {'keepalive_interval': 5}}}, 'settings'
|
||||
), 'configure keepalive_interval'
|
||||
|
||||
_, sock, _ = self.ws.upgrade()
|
||||
|
||||
|
@ -1450,7 +1417,3 @@ class TestNodeWebsockets(TestApplicationNode):
|
|||
self.check_frame(frame, True, self.ws.OP_PING, '') # PING frame
|
||||
|
||||
sock.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestNodeWebsockets.main()
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import unittest
|
||||
import pytest
|
||||
import re
|
||||
|
||||
from unit.applications.lang.perl import TestApplicationPerl
|
||||
from conftest import skip_alert
|
||||
|
||||
|
||||
class TestPerlApplication(TestApplicationPerl):
|
||||
|
@ -21,149 +23,130 @@ class TestPerlApplication(TestApplicationPerl):
|
|||
body=body,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'status')
|
||||
assert resp['status'] == 200, 'status'
|
||||
headers = resp['headers']
|
||||
header_server = headers.pop('Server')
|
||||
self.assertRegex(header_server, r'Unit/[\d\.]+', 'server header')
|
||||
self.assertEqual(
|
||||
headers.pop('Server-Software'),
|
||||
header_server,
|
||||
'server software header',
|
||||
)
|
||||
assert re.search(r'Unit/[\d\.]+', header_server), 'server header'
|
||||
assert (
|
||||
headers.pop('Server-Software') == header_server
|
||||
), 'server software header'
|
||||
|
||||
date = headers.pop('Date')
|
||||
self.assertEqual(date[-4:], ' GMT', 'date header timezone')
|
||||
self.assertLess(
|
||||
abs(self.date_to_sec_epoch(date) - self.sec_epoch()),
|
||||
5,
|
||||
'date header',
|
||||
)
|
||||
assert date[-4:] == ' GMT', 'date header timezone'
|
||||
assert (
|
||||
abs(self.date_to_sec_epoch(date) - self.sec_epoch()) < 5
|
||||
), 'date header'
|
||||
|
||||
self.assertDictEqual(
|
||||
headers,
|
||||
{
|
||||
'Connection': 'close',
|
||||
'Content-Length': str(len(body)),
|
||||
'Content-Type': 'text/html',
|
||||
'Request-Method': 'POST',
|
||||
'Request-Uri': '/',
|
||||
'Http-Host': 'localhost',
|
||||
'Server-Protocol': 'HTTP/1.1',
|
||||
'Custom-Header': 'blah',
|
||||
'Psgi-Version': '11',
|
||||
'Psgi-Url-Scheme': 'http',
|
||||
'Psgi-Multithread': '',
|
||||
'Psgi-Multiprocess': '1',
|
||||
'Psgi-Run-Once': '',
|
||||
'Psgi-Nonblocking': '',
|
||||
'Psgi-Streaming': '1',
|
||||
},
|
||||
'headers',
|
||||
)
|
||||
self.assertEqual(resp['body'], body, 'body')
|
||||
assert headers == {
|
||||
'Connection': 'close',
|
||||
'Content-Length': str(len(body)),
|
||||
'Content-Type': 'text/html',
|
||||
'Request-Method': 'POST',
|
||||
'Request-Uri': '/',
|
||||
'Http-Host': 'localhost',
|
||||
'Server-Protocol': 'HTTP/1.1',
|
||||
'Custom-Header': 'blah',
|
||||
'Psgi-Version': '11',
|
||||
'Psgi-Url-Scheme': 'http',
|
||||
'Psgi-Multithread': '',
|
||||
'Psgi-Multiprocess': '1',
|
||||
'Psgi-Run-Once': '',
|
||||
'Psgi-Nonblocking': '',
|
||||
'Psgi-Streaming': '1',
|
||||
}, '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')
|
||||
|
||||
self.assertEqual(
|
||||
resp['headers']['Query-String'],
|
||||
'var1=val1&var2=val2',
|
||||
'Query-String header',
|
||||
)
|
||||
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='/?')
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'query string empty status')
|
||||
self.assertEqual(
|
||||
resp['headers']['Query-String'], '', 'query string empty'
|
||||
)
|
||||
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()
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'query string absent status')
|
||||
self.assertEqual(
|
||||
resp['headers']['Query-String'], '', 'query string absent'
|
||||
)
|
||||
assert resp['status'] == 200, 'query string absent status'
|
||||
assert resp['headers']['Query-String'] == '', 'query string absent'
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_perl_application_server_port(self):
|
||||
self.load('server_port')
|
||||
|
||||
self.assertEqual(
|
||||
self.get()['headers']['Server-Port'], '7080', 'Server-Port header'
|
||||
)
|
||||
assert (
|
||||
self.get()['headers']['Server-Port'] == '7080'
|
||||
), 'Server-Port header'
|
||||
|
||||
def test_perl_application_input_read_empty(self):
|
||||
self.load('input_read_empty')
|
||||
|
||||
self.assertEqual(self.get()['body'], '', 'read empty')
|
||||
assert self.get()['body'] == '', 'read empty'
|
||||
|
||||
def test_perl_application_input_read_parts(self):
|
||||
self.load('input_read_parts')
|
||||
|
||||
self.assertEqual(
|
||||
self.post(body='0123456789')['body'],
|
||||
'0123456789',
|
||||
'input read parts',
|
||||
)
|
||||
assert (
|
||||
self.post(body='0123456789')['body'] == '0123456789'
|
||||
), 'input read parts'
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_perl_application_input_read_offset(self):
|
||||
self.load('input_read_offset')
|
||||
|
||||
self.assertEqual(
|
||||
self.post(body='0123456789')['body'], '4567', 'read offset'
|
||||
)
|
||||
assert self.post(body='0123456789')['body'] == '4567', 'read offset'
|
||||
|
||||
def test_perl_application_input_copy(self):
|
||||
self.load('input_copy')
|
||||
|
||||
body = '0123456789'
|
||||
self.assertEqual(self.post(body=body)['body'], body, 'input copy')
|
||||
assert self.post(body=body)['body'] == body, 'input copy'
|
||||
|
||||
def test_perl_application_errors_print(self):
|
||||
self.load('errors_print')
|
||||
|
||||
self.assertEqual(self.get()['body'], '1', 'errors result')
|
||||
assert self.get()['body'] == '1', 'errors result'
|
||||
|
||||
self.stop()
|
||||
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(r'\[error\].+Error in application'),
|
||||
'errors print',
|
||||
)
|
||||
assert (
|
||||
self.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')
|
||||
|
||||
self.assertListEqual(
|
||||
self.get()['headers']['Set-Cookie'],
|
||||
['tc=one,two,three', 'tc=four,five,six'],
|
||||
'header equal names',
|
||||
)
|
||||
assert self.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')
|
||||
|
||||
self.assertEqual(self.get()['headers']['blah'], 'blah', 'header pairs')
|
||||
assert self.get()['headers']['blah'] == 'blah', 'header pairs'
|
||||
|
||||
def test_perl_application_body_empty(self):
|
||||
self.load('body_empty')
|
||||
|
||||
self.assertEqual(self.get()['body'], '', 'body empty')
|
||||
assert self.get()['body'] == '', 'body empty'
|
||||
|
||||
def test_perl_application_body_array(self):
|
||||
self.load('body_array')
|
||||
|
||||
self.assertEqual(self.get()['body'], '0123456789', 'body array')
|
||||
assert self.get()['body'] == '0123456789', 'body array'
|
||||
|
||||
def test_perl_application_body_large(self):
|
||||
self.load('variables')
|
||||
|
@ -172,31 +155,29 @@ class TestPerlApplication(TestApplicationPerl):
|
|||
|
||||
resp = self.post(body=body)['body']
|
||||
|
||||
self.assertEqual(resp, body, 'body large')
|
||||
assert resp == body, 'body large'
|
||||
|
||||
def test_perl_application_body_io_empty(self):
|
||||
self.load('body_io_empty')
|
||||
|
||||
self.assertEqual(self.get()['status'], 200, 'body io empty')
|
||||
assert self.get()['status'] == 200, 'body io empty'
|
||||
|
||||
def test_perl_application_body_io_file(self):
|
||||
self.load('body_io_file')
|
||||
|
||||
self.assertEqual(self.get()['body'], 'body\n', 'body io file')
|
||||
assert self.get()['body'] == 'body\n', 'body io file'
|
||||
|
||||
@unittest.skip('not yet, unsafe')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_perl_application_syntax_error(self):
|
||||
self.skip_alerts.extend(
|
||||
[r'PSGI: Failed to parse script']
|
||||
)
|
||||
skip_alert(r'PSGI: Failed to parse script')
|
||||
self.load('syntax_error')
|
||||
|
||||
self.assertEqual(self.get()['status'], 500, 'syntax error')
|
||||
assert self.get()['status'] == 500, 'syntax error'
|
||||
|
||||
def test_perl_keepalive_body(self):
|
||||
self.load('variables')
|
||||
|
||||
self.assertEqual(self.get()['status'], 200, 'init')
|
||||
assert self.get()['status'] == 200, 'init'
|
||||
|
||||
body = '0123456789' * 500
|
||||
(resp, sock) = self.post(
|
||||
|
@ -210,7 +191,7 @@ class TestPerlApplication(TestApplicationPerl):
|
|||
read_timeout=1,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['body'], body, 'keep-alive 1')
|
||||
assert resp['body'] == body, 'keep-alive 1'
|
||||
|
||||
body = '0123456789'
|
||||
resp = self.post(
|
||||
|
@ -223,39 +204,35 @@ class TestPerlApplication(TestApplicationPerl):
|
|||
body=body,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['body'], body, 'keep-alive 2')
|
||||
assert resp['body'] == body, 'keep-alive 2'
|
||||
|
||||
def test_perl_body_io_fake(self):
|
||||
self.load('body_io_fake')
|
||||
|
||||
self.assertEqual(self.get()['body'], '21', 'body io fake')
|
||||
assert self.get()['body'] == '21', 'body io fake'
|
||||
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(r'\[error\].+IOFake getline\(\) \$\/ is \d+'),
|
||||
'body io fake $/ value',
|
||||
)
|
||||
assert (
|
||||
self.wait_for_record(r'\[error\].+IOFake getline\(\) \$\/ is \d+')
|
||||
is not None
|
||||
), 'body io fake $/ value'
|
||||
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(r'\[error\].+IOFake close\(\) called'),
|
||||
'body io fake close',
|
||||
)
|
||||
assert (
|
||||
self.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()
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'status')
|
||||
self.assertEqual(resp['body'], 'Hello World!', 'body')
|
||||
assert resp['status'] == 200, 'status'
|
||||
assert resp['body'] == 'Hello World!', 'body'
|
||||
|
||||
def test_perl_streaming_body(self):
|
||||
self.load('streaming_body')
|
||||
|
||||
resp = self.get()
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'status')
|
||||
self.assertEqual(resp['body'], 'Hello World!', 'body')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestPerlApplication.main()
|
||||
assert resp['status'] == 200, 'status'
|
||||
assert resp['body'] == 'Hello World!', 'body'
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import os
|
||||
import pytest
|
||||
import re
|
||||
import shutil
|
||||
import time
|
||||
import unittest
|
||||
|
||||
from unit.applications.lang.php import TestApplicationPHP
|
||||
from conftest import option
|
||||
|
||||
class TestPHPApplication(TestApplicationPHP):
|
||||
prerequisites = {'modules': {'php': 'all'}}
|
||||
|
@ -12,30 +13,21 @@ class TestPHPApplication(TestApplicationPHP):
|
|||
def before_disable_functions(self):
|
||||
body = self.get()['body']
|
||||
|
||||
self.assertRegex(body, r'time: \d+', 'disable_functions before time')
|
||||
self.assertRegex(body, r'exec: \/\w+', 'disable_functions before exec')
|
||||
assert re.search(r'time: \d+', body), 'disable_functions before time'
|
||||
assert re.search(r'exec: \/\w+', body), 'disable_functions before exec'
|
||||
|
||||
def set_opcache(self, app, val):
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{
|
||||
"admin": {
|
||||
"opcache.enable": val,
|
||||
"opcache.enable_cli": val,
|
||||
},
|
||||
},
|
||||
'applications/' + app + '/options',
|
||||
),
|
||||
assert 'success' in self.conf(
|
||||
{"admin": {"opcache.enable": val, "opcache.enable_cli": val,},},
|
||||
'applications/' + app + '/options',
|
||||
)
|
||||
|
||||
opcache = self.get()['headers']['X-OPcache']
|
||||
|
||||
if not opcache or opcache == '-1':
|
||||
print('opcache is not supported')
|
||||
raise unittest.SkipTest()
|
||||
pytest.skip('opcache is not supported')
|
||||
|
||||
self.assertEqual(opcache, val, 'opcache value')
|
||||
assert opcache == val, 'opcache value'
|
||||
|
||||
def test_php_application_variables(self):
|
||||
self.load('variables')
|
||||
|
@ -50,140 +42,122 @@ class TestPHPApplication(TestApplicationPHP):
|
|||
'Connection': 'close',
|
||||
},
|
||||
body=body,
|
||||
url='/index.php/blah?var=val'
|
||||
url='/index.php/blah?var=val',
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'status')
|
||||
assert resp['status'] == 200, 'status'
|
||||
headers = resp['headers']
|
||||
header_server = headers.pop('Server')
|
||||
self.assertRegex(header_server, r'Unit/[\d\.]+', 'server header')
|
||||
self.assertEqual(
|
||||
headers.pop('Server-Software'),
|
||||
header_server,
|
||||
'server software header',
|
||||
)
|
||||
assert re.search(r'Unit/[\d\.]+', header_server), 'server header'
|
||||
assert (
|
||||
headers.pop('Server-Software') == header_server
|
||||
), 'server software header'
|
||||
|
||||
date = headers.pop('Date')
|
||||
self.assertEqual(date[-4:], ' GMT', 'date header timezone')
|
||||
self.assertLess(
|
||||
abs(self.date_to_sec_epoch(date) - self.sec_epoch()),
|
||||
5,
|
||||
'date header',
|
||||
)
|
||||
assert date[-4:] == ' GMT', 'date header timezone'
|
||||
assert (
|
||||
abs(self.date_to_sec_epoch(date) - self.sec_epoch()) < 5
|
||||
), 'date header'
|
||||
|
||||
if 'X-Powered-By' in headers:
|
||||
headers.pop('X-Powered-By')
|
||||
|
||||
headers.pop('Content-type')
|
||||
self.assertDictEqual(
|
||||
headers,
|
||||
{
|
||||
'Connection': 'close',
|
||||
'Content-Length': str(len(body)),
|
||||
'Request-Method': 'POST',
|
||||
'Path-Info': '/blah',
|
||||
'Request-Uri': '/index.php/blah?var=val',
|
||||
'Http-Host': 'localhost',
|
||||
'Server-Protocol': 'HTTP/1.1',
|
||||
'Custom-Header': 'blah',
|
||||
},
|
||||
'headers',
|
||||
)
|
||||
self.assertEqual(resp['body'], body, 'body')
|
||||
assert headers == {
|
||||
'Connection': 'close',
|
||||
'Content-Length': str(len(body)),
|
||||
'Request-Method': 'POST',
|
||||
'Path-Info': '/blah',
|
||||
'Request-Uri': '/index.php/blah?var=val',
|
||||
'Http-Host': 'localhost',
|
||||
'Server-Protocol': 'HTTP/1.1',
|
||||
'Custom-Header': 'blah',
|
||||
}, 'headers'
|
||||
assert resp['body'] == body, 'body'
|
||||
|
||||
def test_php_application_query_string(self):
|
||||
self.load('query_string')
|
||||
|
||||
resp = self.get(url='/?var1=val1&var2=val2')
|
||||
|
||||
self.assertEqual(
|
||||
resp['headers']['Query-String'],
|
||||
'var1=val1&var2=val2',
|
||||
'query string',
|
||||
)
|
||||
assert (
|
||||
resp['headers']['Query-String'] == 'var1=val1&var2=val2'
|
||||
), 'query string'
|
||||
|
||||
def test_php_application_query_string_empty(self):
|
||||
self.load('query_string')
|
||||
|
||||
resp = self.get(url='/?')
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'query string empty status')
|
||||
self.assertEqual(
|
||||
resp['headers']['Query-String'], '', 'query string empty'
|
||||
)
|
||||
assert resp['status'] == 200, 'query string empty status'
|
||||
assert resp['headers']['Query-String'] == '', 'query string empty'
|
||||
|
||||
def test_php_application_query_string_absent(self):
|
||||
self.load('query_string')
|
||||
|
||||
resp = self.get()
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'query string absent status')
|
||||
self.assertEqual(
|
||||
resp['headers']['Query-String'], '', 'query string absent'
|
||||
)
|
||||
assert resp['status'] == 200, 'query string absent status'
|
||||
assert resp['headers']['Query-String'] == '', 'query string absent'
|
||||
|
||||
def test_php_application_phpinfo(self):
|
||||
self.load('phpinfo')
|
||||
|
||||
resp = self.get()
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'status')
|
||||
self.assertNotEqual(resp['body'], '', 'body not empty')
|
||||
assert resp['status'] == 200, 'status'
|
||||
assert resp['body'] != '', 'body not empty'
|
||||
|
||||
def test_php_application_header_status(self):
|
||||
self.load('header')
|
||||
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Connection': 'close',
|
||||
'X-Header': 'HTTP/1.1 404 Not Found',
|
||||
}
|
||||
)['status'],
|
||||
404,
|
||||
'status',
|
||||
)
|
||||
)['status']
|
||||
== 404
|
||||
), 'status'
|
||||
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Connection': 'close',
|
||||
'X-Header': 'http/1.1 404 Not Found',
|
||||
}
|
||||
)['status'],
|
||||
404,
|
||||
'status case insensitive',
|
||||
)
|
||||
)['status']
|
||||
== 404
|
||||
), 'status case insensitive'
|
||||
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Connection': 'close',
|
||||
'X-Header': 'HTTP/ 404 Not Found',
|
||||
}
|
||||
)['status'],
|
||||
404,
|
||||
'status version empty',
|
||||
)
|
||||
|
||||
)['status']
|
||||
== 404
|
||||
), 'status version empty'
|
||||
|
||||
def test_php_application_404(self):
|
||||
self.load('404')
|
||||
|
||||
resp = self.get()
|
||||
|
||||
self.assertEqual(resp['status'], 404, '404 status')
|
||||
self.assertRegex(
|
||||
resp['body'], r'<title>404 Not Found</title>', '404 body'
|
||||
)
|
||||
assert resp['status'] == 404, '404 status'
|
||||
assert re.search(
|
||||
r'<title>404 Not Found</title>', resp['body']
|
||||
), '404 body'
|
||||
|
||||
def test_php_application_keepalive_body(self):
|
||||
self.load('mirror')
|
||||
|
||||
self.assertEqual(self.get()['status'], 200, 'init')
|
||||
assert self.get()['status'] == 200, 'init'
|
||||
|
||||
body = '0123456789' * 500
|
||||
(resp, sock) = self.post(
|
||||
|
@ -197,7 +171,7 @@ class TestPHPApplication(TestApplicationPHP):
|
|||
read_timeout=1,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['body'], body, 'keep-alive 1')
|
||||
assert resp['body'] == body, 'keep-alive 1'
|
||||
|
||||
body = '0123456789'
|
||||
resp = self.post(
|
||||
|
@ -210,22 +184,22 @@ class TestPHPApplication(TestApplicationPHP):
|
|||
body=body,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['body'], body, 'keep-alive 2')
|
||||
assert resp['body'] == body, 'keep-alive 2'
|
||||
|
||||
def test_php_application_conditional(self):
|
||||
self.load('conditional')
|
||||
|
||||
self.assertRegex(self.get()['body'], r'True', 'conditional true')
|
||||
self.assertRegex(self.post()['body'], r'False', 'conditional false')
|
||||
assert re.search(r'True', self.get()['body']), 'conditional true'
|
||||
assert re.search(r'False', self.post()['body']), 'conditional false'
|
||||
|
||||
def test_php_application_get_variables(self):
|
||||
self.load('get_variables')
|
||||
|
||||
resp = self.get(url='/?var1=val1&var2=&var3')
|
||||
self.assertEqual(resp['headers']['X-Var-1'], 'val1', 'GET variables')
|
||||
self.assertEqual(resp['headers']['X-Var-2'], '1', 'GET variables 2')
|
||||
self.assertEqual(resp['headers']['X-Var-3'], '1', 'GET variables 3')
|
||||
self.assertEqual(resp['headers']['X-Var-4'], '', 'GET variables 4')
|
||||
assert resp['headers']['X-Var-1'] == 'val1', 'GET variables'
|
||||
assert resp['headers']['X-Var-2'] == '1', 'GET variables 2'
|
||||
assert resp['headers']['X-Var-3'] == '1', 'GET variables 3'
|
||||
assert resp['headers']['X-Var-4'] == '', 'GET variables 4'
|
||||
|
||||
def test_php_application_post_variables(self):
|
||||
self.load('post_variables')
|
||||
|
@ -238,9 +212,9 @@ class TestPHPApplication(TestApplicationPHP):
|
|||
},
|
||||
body='var1=val1&var2=',
|
||||
)
|
||||
self.assertEqual(resp['headers']['X-Var-1'], 'val1', 'POST variables')
|
||||
self.assertEqual(resp['headers']['X-Var-2'], '1', 'POST variables 2')
|
||||
self.assertEqual(resp['headers']['X-Var-3'], '', 'POST variables 3')
|
||||
assert resp['headers']['X-Var-1'] == 'val1', 'POST variables'
|
||||
assert resp['headers']['X-Var-2'] == '1', 'POST variables 2'
|
||||
assert resp['headers']['X-Var-3'] == '', 'POST variables 3'
|
||||
|
||||
def test_php_application_cookies(self):
|
||||
self.load('cookies')
|
||||
|
@ -253,41 +227,32 @@ class TestPHPApplication(TestApplicationPHP):
|
|||
}
|
||||
)
|
||||
|
||||
self.assertEqual(resp['headers']['X-Cookie-1'], 'val', 'cookie')
|
||||
self.assertEqual(resp['headers']['X-Cookie-2'], 'val2', 'cookie')
|
||||
assert resp['headers']['X-Cookie-1'] == 'val', 'cookie'
|
||||
assert resp['headers']['X-Cookie-2'] == 'val2', 'cookie'
|
||||
|
||||
def test_php_application_ini_precision(self):
|
||||
self.load('ini_precision')
|
||||
|
||||
self.assertNotEqual(
|
||||
self.get()['headers']['X-Precision'], '4', 'ini value default'
|
||||
)
|
||||
assert self.get()['headers']['X-Precision'] != '4', 'ini value default'
|
||||
|
||||
self.conf(
|
||||
{"file": "ini/php.ini"}, 'applications/ini_precision/options'
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
self.get()['headers']['X-File'],
|
||||
self.current_dir + '/php/ini_precision/ini/php.ini',
|
||||
'ini file',
|
||||
)
|
||||
self.assertEqual(
|
||||
self.get()['headers']['X-Precision'], '4', 'ini value'
|
||||
)
|
||||
assert (
|
||||
self.get()['headers']['X-File']
|
||||
== option.test_dir + '/php/ini_precision/ini/php.ini'
|
||||
), 'ini file'
|
||||
assert self.get()['headers']['X-Precision'] == '4', 'ini value'
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_php_application_ini_admin_user(self):
|
||||
self.load('ini_precision')
|
||||
|
||||
self.assertIn(
|
||||
'error',
|
||||
self.conf(
|
||||
{"user": {"precision": "4"}, "admin": {"precision": "5"}},
|
||||
'applications/ini_precision/options',
|
||||
),
|
||||
'ini admin user',
|
||||
)
|
||||
assert 'error' in self.conf(
|
||||
{"user": {"precision": "4"}, "admin": {"precision": "5"}},
|
||||
'applications/ini_precision/options',
|
||||
), 'ini admin user'
|
||||
|
||||
def test_php_application_ini_admin(self):
|
||||
self.load('ini_precision')
|
||||
|
@ -297,9 +262,7 @@ class TestPHPApplication(TestApplicationPHP):
|
|||
'applications/ini_precision/options',
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
self.get()['headers']['X-Precision'], '5', 'ini value admin'
|
||||
)
|
||||
assert self.get()['headers']['X-Precision'] == '5', 'ini value admin'
|
||||
|
||||
def test_php_application_ini_user(self):
|
||||
self.load('ini_precision')
|
||||
|
@ -309,9 +272,7 @@ class TestPHPApplication(TestApplicationPHP):
|
|||
'applications/ini_precision/options',
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
self.get()['headers']['X-Precision'], '5', 'ini value user'
|
||||
)
|
||||
assert self.get()['headers']['X-Precision'] == '5', 'ini value user'
|
||||
|
||||
def test_php_application_ini_user_2(self):
|
||||
self.load('ini_precision')
|
||||
|
@ -320,17 +281,13 @@ class TestPHPApplication(TestApplicationPHP):
|
|||
{"file": "ini/php.ini"}, 'applications/ini_precision/options'
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
self.get()['headers']['X-Precision'], '4', 'ini user file'
|
||||
)
|
||||
assert self.get()['headers']['X-Precision'] == '4', 'ini user file'
|
||||
|
||||
self.conf(
|
||||
{"precision": "5"}, 'applications/ini_precision/options/user'
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
self.get()['headers']['X-Precision'], '5', 'ini value user'
|
||||
)
|
||||
assert self.get()['headers']['X-Precision'] == '5', 'ini value user'
|
||||
|
||||
def test_php_application_ini_set_admin(self):
|
||||
self.load('ini_precision')
|
||||
|
@ -339,11 +296,9 @@ class TestPHPApplication(TestApplicationPHP):
|
|||
{"admin": {"precision": "5"}}, 'applications/ini_precision/options'
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
self.get(url='/?precision=6')['headers']['X-Precision'],
|
||||
'5',
|
||||
'ini set admin',
|
||||
)
|
||||
assert (
|
||||
self.get(url='/?precision=6')['headers']['X-Precision'] == '5'
|
||||
), 'ini set admin'
|
||||
|
||||
def test_php_application_ini_set_user(self):
|
||||
self.load('ini_precision')
|
||||
|
@ -352,11 +307,9 @@ class TestPHPApplication(TestApplicationPHP):
|
|||
{"user": {"precision": "5"}}, 'applications/ini_precision/options'
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
self.get(url='/?precision=6')['headers']['X-Precision'],
|
||||
'6',
|
||||
'ini set user',
|
||||
)
|
||||
assert (
|
||||
self.get(url='/?precision=6')['headers']['X-Precision'] == '6'
|
||||
), 'ini set user'
|
||||
|
||||
def test_php_application_ini_repeat(self):
|
||||
self.load('ini_precision')
|
||||
|
@ -365,13 +318,9 @@ class TestPHPApplication(TestApplicationPHP):
|
|||
{"user": {"precision": "5"}}, 'applications/ini_precision/options'
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
self.get()['headers']['X-Precision'], '5', 'ini value'
|
||||
)
|
||||
assert self.get()['headers']['X-Precision'] == '5', 'ini value'
|
||||
|
||||
self.assertEqual(
|
||||
self.get()['headers']['X-Precision'], '5', 'ini value repeat'
|
||||
)
|
||||
assert self.get()['headers']['X-Precision'] == '5', 'ini value repeat'
|
||||
|
||||
def test_php_application_disable_functions_exec(self):
|
||||
self.load('time_exec')
|
||||
|
@ -385,8 +334,8 @@ class TestPHPApplication(TestApplicationPHP):
|
|||
|
||||
body = self.get()['body']
|
||||
|
||||
self.assertRegex(body, r'time: \d+', 'disable_functions time')
|
||||
self.assertNotRegex(body, r'exec: \/\w+', 'disable_functions exec')
|
||||
assert re.search(r'time: \d+', body), 'disable_functions time'
|
||||
assert not re.search(r'exec: \/\w+', body), 'disable_functions exec'
|
||||
|
||||
def test_php_application_disable_functions_comma(self):
|
||||
self.load('time_exec')
|
||||
|
@ -400,10 +349,12 @@ class TestPHPApplication(TestApplicationPHP):
|
|||
|
||||
body = self.get()['body']
|
||||
|
||||
self.assertNotRegex(body, r'time: \d+', 'disable_functions comma time')
|
||||
self.assertNotRegex(
|
||||
body, r'exec: \/\w+', 'disable_functions comma exec'
|
||||
)
|
||||
assert not re.search(
|
||||
r'time: \d+', body
|
||||
), 'disable_functions comma time'
|
||||
assert not re.search(
|
||||
r'exec: \/\w+', body
|
||||
), 'disable_functions comma exec'
|
||||
|
||||
def test_php_application_disable_functions_space(self):
|
||||
self.load('time_exec')
|
||||
|
@ -417,10 +368,12 @@ class TestPHPApplication(TestApplicationPHP):
|
|||
|
||||
body = self.get()['body']
|
||||
|
||||
self.assertNotRegex(body, r'time: \d+', 'disable_functions space time')
|
||||
self.assertNotRegex(
|
||||
body, r'exec: \/\w+', 'disable_functions space exec'
|
||||
)
|
||||
assert not re.search(
|
||||
r'time: \d+', body
|
||||
), 'disable_functions space time'
|
||||
assert not re.search(
|
||||
r'exec: \/\w+', body
|
||||
), 'disable_functions space exec'
|
||||
|
||||
def test_php_application_disable_functions_user(self):
|
||||
self.load('time_exec')
|
||||
|
@ -434,10 +387,10 @@ class TestPHPApplication(TestApplicationPHP):
|
|||
|
||||
body = self.get()['body']
|
||||
|
||||
self.assertRegex(body, r'time: \d+', 'disable_functions user time')
|
||||
self.assertNotRegex(
|
||||
body, r'exec: \/\w+', 'disable_functions user exec'
|
||||
)
|
||||
assert re.search(r'time: \d+', body), 'disable_functions user time'
|
||||
assert not re.search(
|
||||
r'exec: \/\w+', body
|
||||
), 'disable_functions user exec'
|
||||
|
||||
def test_php_application_disable_functions_nonexistent(self):
|
||||
self.load('time_exec')
|
||||
|
@ -451,187 +404,165 @@ class TestPHPApplication(TestApplicationPHP):
|
|||
|
||||
body = self.get()['body']
|
||||
|
||||
self.assertRegex(
|
||||
body, r'time: \d+', 'disable_functions nonexistent time'
|
||||
)
|
||||
self.assertRegex(
|
||||
body, r'exec: \/\w+', 'disable_functions nonexistent exec'
|
||||
)
|
||||
assert re.search(
|
||||
r'time: \d+', body
|
||||
), 'disable_functions nonexistent time'
|
||||
assert re.search(
|
||||
r'exec: \/\w+', body
|
||||
), 'disable_functions nonexistent exec'
|
||||
|
||||
def test_php_application_disable_classes(self):
|
||||
self.load('date_time')
|
||||
|
||||
self.assertRegex(
|
||||
self.get()['body'], r'012345', 'disable_classes before'
|
||||
)
|
||||
assert re.search(
|
||||
r'012345', self.get()['body']
|
||||
), 'disable_classes before'
|
||||
|
||||
self.conf(
|
||||
{"admin": {"disable_classes": "DateTime"}},
|
||||
'applications/date_time/options',
|
||||
)
|
||||
|
||||
self.assertNotRegex(
|
||||
self.get()['body'], r'012345', 'disable_classes before'
|
||||
)
|
||||
assert not re.search(
|
||||
r'012345', self.get()['body']
|
||||
), 'disable_classes before'
|
||||
|
||||
def test_php_application_disable_classes_user(self):
|
||||
self.load('date_time')
|
||||
|
||||
self.assertRegex(
|
||||
self.get()['body'], r'012345', 'disable_classes before'
|
||||
)
|
||||
assert re.search(
|
||||
r'012345', self.get()['body']
|
||||
), 'disable_classes before'
|
||||
|
||||
self.conf(
|
||||
{"user": {"disable_classes": "DateTime"}},
|
||||
'applications/date_time/options',
|
||||
)
|
||||
|
||||
self.assertNotRegex(
|
||||
self.get()['body'], r'012345', 'disable_classes before'
|
||||
)
|
||||
assert not re.search(
|
||||
r'012345', self.get()['body']
|
||||
), 'disable_classes before'
|
||||
|
||||
def test_php_application_error_log(self):
|
||||
self.load('error_log')
|
||||
|
||||
self.assertEqual(self.get()['status'], 200, 'status')
|
||||
assert self.get()['status'] == 200, 'status'
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
self.assertEqual(self.get()['status'], 200, 'status 2')
|
||||
assert self.get()['status'] == 200, 'status 2'
|
||||
|
||||
self.stop()
|
||||
|
||||
pattern = r'\d{4}\/\d\d\/\d\d\s\d\d:.+\[notice\].+Error in application'
|
||||
|
||||
self.assertIsNotNone(self.wait_for_record(pattern), 'errors print')
|
||||
assert self.wait_for_record(pattern) is not None, 'errors print'
|
||||
|
||||
with open(self.testdir + '/unit.log', 'r', errors='ignore') as f:
|
||||
with open(self.temp_dir + '/unit.log', 'r', errors='ignore') as f:
|
||||
errs = re.findall(pattern, f.read())
|
||||
|
||||
self.assertEqual(len(errs), 2, 'error_log count')
|
||||
assert len(errs) == 2, 'error_log count'
|
||||
|
||||
date = errs[0].split('[')[0]
|
||||
date2 = errs[1].split('[')[0]
|
||||
self.assertNotEqual(date, date2, 'date diff')
|
||||
assert date != date2, 'date diff'
|
||||
|
||||
def test_php_application_script(self):
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "applications/script"}},
|
||||
"applications": {
|
||||
"script": {
|
||||
"type": "php",
|
||||
"processes": {"spare": 0},
|
||||
"root": self.current_dir + "/php/script",
|
||||
"script": "phpinfo.php",
|
||||
}
|
||||
},
|
||||
}
|
||||
),
|
||||
'configure script',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "applications/script"}},
|
||||
"applications": {
|
||||
"script": {
|
||||
"type": "php",
|
||||
"processes": {"spare": 0},
|
||||
"root": option.test_dir + "/php/script",
|
||||
"script": "phpinfo.php",
|
||||
}
|
||||
},
|
||||
}
|
||||
), 'configure script'
|
||||
|
||||
resp = self.get()
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'status')
|
||||
self.assertNotEqual(resp['body'], '', 'body not empty')
|
||||
assert resp['status'] == 200, 'status'
|
||||
assert resp['body'] != '', 'body not empty'
|
||||
|
||||
def test_php_application_index_default(self):
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "applications/phpinfo"}},
|
||||
"applications": {
|
||||
"phpinfo": {
|
||||
"type": "php",
|
||||
"processes": {"spare": 0},
|
||||
"root": self.current_dir + "/php/phpinfo",
|
||||
}
|
||||
},
|
||||
}
|
||||
),
|
||||
'configure index default',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "applications/phpinfo"}},
|
||||
"applications": {
|
||||
"phpinfo": {
|
||||
"type": "php",
|
||||
"processes": {"spare": 0},
|
||||
"root": option.test_dir + "/php/phpinfo",
|
||||
}
|
||||
},
|
||||
}
|
||||
), 'configure index default'
|
||||
|
||||
resp = self.get()
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'status')
|
||||
self.assertNotEqual(resp['body'], '', 'body not empty')
|
||||
assert resp['status'] == 200, 'status'
|
||||
assert resp['body'] != '', 'body not empty'
|
||||
|
||||
def test_php_application_extension_check(self):
|
||||
self.load('phpinfo')
|
||||
|
||||
self.assertNotEqual(
|
||||
self.get(url='/index.wrong')['status'], 200, 'status'
|
||||
)
|
||||
assert self.get(url='/index.wrong')['status'] != 200, 'status'
|
||||
|
||||
new_root = self.testdir + "/php"
|
||||
new_root = self.temp_dir + "/php"
|
||||
os.mkdir(new_root)
|
||||
shutil.copy(self.current_dir + '/php/phpinfo/index.wrong', new_root)
|
||||
shutil.copy(option.test_dir + '/php/phpinfo/index.wrong', new_root)
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "applications/phpinfo"}},
|
||||
"applications": {
|
||||
"phpinfo": {
|
||||
"type": "php",
|
||||
"processes": {"spare": 0},
|
||||
"root": new_root,
|
||||
"working_directory": new_root,
|
||||
}
|
||||
},
|
||||
}
|
||||
),
|
||||
'configure new root',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "applications/phpinfo"}},
|
||||
"applications": {
|
||||
"phpinfo": {
|
||||
"type": "php",
|
||||
"processes": {"spare": 0},
|
||||
"root": new_root,
|
||||
"working_directory": new_root,
|
||||
}
|
||||
},
|
||||
}
|
||||
), 'configure new root'
|
||||
|
||||
resp = self.get()
|
||||
self.assertNotEqual(
|
||||
str(resp['status']) + resp['body'], '200', 'status new root'
|
||||
)
|
||||
assert str(resp['status']) + resp['body'] != '200', 'status new root'
|
||||
|
||||
def run_php_application_cwd_root_tests(self):
|
||||
self.assertIn(
|
||||
'success', self.conf_delete('applications/cwd/working_directory')
|
||||
assert 'success' in self.conf_delete(
|
||||
'applications/cwd/working_directory'
|
||||
)
|
||||
|
||||
script_cwd = self.current_dir + '/php/cwd'
|
||||
script_cwd = option.test_dir + '/php/cwd'
|
||||
|
||||
resp = self.get()
|
||||
self.assertEqual(resp['status'], 200, 'status ok')
|
||||
self.assertEqual(resp['body'], script_cwd, 'default cwd')
|
||||
assert resp['status'] == 200, 'status ok'
|
||||
assert resp['body'] == script_cwd, 'default cwd'
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
'"' + self.current_dir + '"',
|
||||
'applications/cwd/working_directory',
|
||||
),
|
||||
assert 'success' in self.conf(
|
||||
'"' + option.test_dir + '"', 'applications/cwd/working_directory',
|
||||
)
|
||||
|
||||
resp = self.get()
|
||||
self.assertEqual(resp['status'], 200, 'status ok')
|
||||
self.assertEqual(resp['body'], script_cwd, 'wdir cwd')
|
||||
assert resp['status'] == 200, 'status ok'
|
||||
assert resp['body'] == script_cwd, 'wdir cwd'
|
||||
|
||||
resp = self.get(url='/?chdir=/')
|
||||
self.assertEqual(resp['status'], 200, 'status ok')
|
||||
self.assertEqual(resp['body'], '/', 'cwd after chdir')
|
||||
assert resp['status'] == 200, 'status ok'
|
||||
assert resp['body'] == '/', 'cwd after chdir'
|
||||
|
||||
# cwd must be restored
|
||||
|
||||
resp = self.get()
|
||||
self.assertEqual(resp['status'], 200, 'status ok')
|
||||
self.assertEqual(resp['body'], script_cwd, 'cwd restored')
|
||||
assert resp['status'] == 200, 'status ok'
|
||||
assert resp['body'] == script_cwd, 'cwd restored'
|
||||
|
||||
resp = self.get(url='/subdir/')
|
||||
self.assertEqual(
|
||||
resp['body'], script_cwd + '/subdir', 'cwd subdir',
|
||||
)
|
||||
assert resp['body'] == script_cwd + '/subdir', 'cwd subdir'
|
||||
|
||||
def test_php_application_cwd_root(self):
|
||||
self.load('cwd')
|
||||
|
@ -650,26 +581,20 @@ class TestPHPApplication(TestApplicationPHP):
|
|||
def run_php_application_cwd_script_tests(self):
|
||||
self.load('cwd')
|
||||
|
||||
script_cwd = self.current_dir + '/php/cwd'
|
||||
script_cwd = option.test_dir + '/php/cwd'
|
||||
|
||||
self.assertIn(
|
||||
'success', self.conf_delete('applications/cwd/working_directory')
|
||||
assert 'success' in self.conf_delete(
|
||||
'applications/cwd/working_directory'
|
||||
)
|
||||
|
||||
self.assertIn(
|
||||
'success', self.conf('"index.php"', 'applications/cwd/script')
|
||||
)
|
||||
assert 'success' in self.conf('"index.php"', 'applications/cwd/script')
|
||||
|
||||
self.assertEqual(
|
||||
self.get()['body'], script_cwd, 'default cwd',
|
||||
)
|
||||
assert self.get()['body'] == script_cwd, 'default cwd'
|
||||
|
||||
self.assertEqual(
|
||||
self.get(url='/?chdir=/')['body'], '/', 'cwd after chdir',
|
||||
)
|
||||
assert self.get(url='/?chdir=/')['body'] == '/', 'cwd after chdir'
|
||||
|
||||
# cwd must be restored
|
||||
self.assertEqual(self.get()['body'], script_cwd, 'cwd restored')
|
||||
assert self.get()['body'] == script_cwd, 'cwd restored'
|
||||
|
||||
def test_php_application_cwd_script(self):
|
||||
self.load('cwd')
|
||||
|
@ -688,14 +613,10 @@ class TestPHPApplication(TestApplicationPHP):
|
|||
def test_php_application_path_relative(self):
|
||||
self.load('open')
|
||||
|
||||
self.assertEqual(self.get()['body'], 'test', 'relative path')
|
||||
assert self.get()['body'] == 'test', 'relative path'
|
||||
|
||||
self.assertNotEqual(
|
||||
self.get(url='/?chdir=/')['body'], 'test', 'relative path w/ chdir'
|
||||
)
|
||||
assert (
|
||||
self.get(url='/?chdir=/')['body'] != 'test'
|
||||
), 'relative path w/ chdir'
|
||||
|
||||
self.assertEqual(self.get()['body'], 'test', 'relative path 2')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestPHPApplication.main()
|
||||
assert self.get()['body'] == 'test', 'relative path 2'
|
||||
|
|
|
@ -23,133 +23,97 @@ class TestPHPBasic(TestControl):
|
|||
|
||||
conf = self.conf_get()
|
||||
|
||||
self.assertEqual(conf['listeners'], {}, 'listeners')
|
||||
self.assertEqual(
|
||||
conf['applications'],
|
||||
{
|
||||
"app": {
|
||||
"type": "php",
|
||||
"processes": {"spare": 0},
|
||||
"root": "/app",
|
||||
"index": "index.php",
|
||||
}
|
||||
},
|
||||
'applications',
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
self.conf_get('applications'),
|
||||
{
|
||||
"app": {
|
||||
"type": "php",
|
||||
"processes": {"spare": 0},
|
||||
"root": "/app",
|
||||
"index": "index.php",
|
||||
}
|
||||
},
|
||||
'applications prefix',
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
self.conf_get('applications/app'),
|
||||
{
|
||||
assert conf['listeners'] == {}, 'listeners'
|
||||
assert conf['applications'] == {
|
||||
"app": {
|
||||
"type": "php",
|
||||
"processes": {"spare": 0},
|
||||
"root": "/app",
|
||||
"index": "index.php",
|
||||
},
|
||||
'applications prefix 2',
|
||||
)
|
||||
}
|
||||
}, 'applications'
|
||||
|
||||
self.assertEqual(self.conf_get('applications/app/type'), 'php', 'type')
|
||||
self.assertEqual(
|
||||
self.conf_get('applications/app/processes/spare'),
|
||||
0,
|
||||
'spare processes',
|
||||
)
|
||||
assert self.conf_get('applications') == {
|
||||
"app": {
|
||||
"type": "php",
|
||||
"processes": {"spare": 0},
|
||||
"root": "/app",
|
||||
"index": "index.php",
|
||||
}
|
||||
}, 'applications prefix'
|
||||
|
||||
assert self.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 (
|
||||
self.conf_get('applications/app/processes/spare') == 0
|
||||
), 'spare processes'
|
||||
|
||||
def test_php_get_listeners(self):
|
||||
self.conf(self.conf_basic)
|
||||
|
||||
self.assertEqual(
|
||||
self.conf_get()['listeners'],
|
||||
{"*:7080": {"pass": "applications/app"}},
|
||||
'listeners',
|
||||
)
|
||||
assert self.conf_get()['listeners'] == {
|
||||
"*:7080": {"pass": "applications/app"}
|
||||
}, 'listeners'
|
||||
|
||||
self.assertEqual(
|
||||
self.conf_get('listeners'),
|
||||
{"*:7080": {"pass": "applications/app"}},
|
||||
'listeners prefix',
|
||||
)
|
||||
assert self.conf_get('listeners') == {
|
||||
"*:7080": {"pass": "applications/app"}
|
||||
}, 'listeners prefix'
|
||||
|
||||
self.assertEqual(
|
||||
self.conf_get('listeners/*:7080'),
|
||||
{"pass": "applications/app"},
|
||||
'listeners prefix 2',
|
||||
)
|
||||
assert self.conf_get('listeners/*:7080') == {
|
||||
"pass": "applications/app"
|
||||
}, 'listeners prefix 2'
|
||||
|
||||
def test_php_change_listener(self):
|
||||
self.conf(self.conf_basic)
|
||||
self.conf({"*:7081": {"pass": "applications/app"}}, 'listeners')
|
||||
|
||||
self.assertEqual(
|
||||
self.conf_get('listeners'),
|
||||
{"*:7081": {"pass": "applications/app"}},
|
||||
'change listener',
|
||||
)
|
||||
assert self.conf_get('listeners') == {
|
||||
"*:7081": {"pass": "applications/app"}
|
||||
}, 'change listener'
|
||||
|
||||
def test_php_add_listener(self):
|
||||
self.conf(self.conf_basic)
|
||||
self.conf({"pass": "applications/app"}, 'listeners/*:7082')
|
||||
|
||||
self.assertEqual(
|
||||
self.conf_get('listeners'),
|
||||
{
|
||||
"*:7080": {"pass": "applications/app"},
|
||||
"*:7082": {"pass": "applications/app"},
|
||||
},
|
||||
'add listener',
|
||||
)
|
||||
assert self.conf_get('listeners') == {
|
||||
"*:7080": {"pass": "applications/app"},
|
||||
"*:7082": {"pass": "applications/app"},
|
||||
}, 'add listener'
|
||||
|
||||
def test_php_change_application(self):
|
||||
self.conf(self.conf_basic)
|
||||
|
||||
self.conf('30', 'applications/app/processes/max')
|
||||
self.assertEqual(
|
||||
self.conf_get('applications/app/processes/max'),
|
||||
30,
|
||||
'change application max',
|
||||
)
|
||||
assert (
|
||||
self.conf_get('applications/app/processes/max') == 30
|
||||
), 'change application max'
|
||||
|
||||
self.conf('"/www"', 'applications/app/root')
|
||||
self.assertEqual(
|
||||
self.conf_get('applications/app/root'),
|
||||
'/www',
|
||||
'change application root',
|
||||
)
|
||||
assert (
|
||||
self.conf_get('applications/app/root') == '/www'
|
||||
), 'change application root'
|
||||
|
||||
def test_php_delete(self):
|
||||
self.conf(self.conf_basic)
|
||||
|
||||
self.assertIn('error', self.conf_delete('applications/app'))
|
||||
self.assertIn('success', self.conf_delete('listeners/*:7080'))
|
||||
self.assertIn('success', self.conf_delete('applications/app'))
|
||||
self.assertIn('error', self.conf_delete('applications/app'))
|
||||
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_blocks(self):
|
||||
self.conf(self.conf_basic)
|
||||
|
||||
self.assertIn('success', self.conf_delete('listeners'))
|
||||
self.assertIn('success', self.conf_delete('applications'))
|
||||
assert 'success' in self.conf_delete('listeners')
|
||||
assert 'success' in self.conf_delete('applications')
|
||||
|
||||
self.assertIn('success', self.conf(self.conf_app, 'applications'))
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf({"*:7081": {"pass": "applications/app"}}, 'listeners'),
|
||||
'applications restore',
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestPHPBasic.main()
|
||||
assert 'success' in self.conf(self.conf_app, 'applications')
|
||||
assert 'success' in self.conf(
|
||||
{"*:7081": {"pass": "applications/app"}}, 'listeners'
|
||||
), 'applications restore'
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import unittest
|
||||
import pytest
|
||||
|
||||
from unit.applications.lang.php import TestApplicationPHP
|
||||
from unit.feature.isolation import TestFeatureIsolation
|
||||
from conftest import option
|
||||
|
||||
|
||||
class TestPHPIsolation(TestApplicationPHP):
|
||||
|
@ -10,171 +11,128 @@ class TestPHPIsolation(TestApplicationPHP):
|
|||
isolation = TestFeatureIsolation()
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls, complete_check=True):
|
||||
unit = super().setUpClass(complete_check=False)
|
||||
def setup_class(cls, complete_check=True):
|
||||
unit = super().setup_class(complete_check=False)
|
||||
|
||||
TestFeatureIsolation().check(cls.available, unit.testdir)
|
||||
TestFeatureIsolation().check(cls.available, unit.temp_dir)
|
||||
|
||||
return unit if not complete_check else unit.complete()
|
||||
|
||||
def test_php_isolation_rootfs(self):
|
||||
def test_php_isolation_rootfs(self, is_su):
|
||||
isolation_features = self.available['features']['isolation'].keys()
|
||||
|
||||
if 'mnt' not in isolation_features:
|
||||
print('requires mnt ns')
|
||||
raise unittest.SkipTest()
|
||||
pytest.skip('requires mnt ns')
|
||||
|
||||
if not self.is_su:
|
||||
if not is_su:
|
||||
if 'user' not in isolation_features:
|
||||
print('requires unprivileged userns or root')
|
||||
raise unittest.SkipTest()
|
||||
pytest.skip('requires unprivileged userns or root')
|
||||
|
||||
if not 'unprivileged_userns_clone' in isolation_features:
|
||||
print('requires unprivileged userns or root')
|
||||
raise unittest.SkipTest()
|
||||
pytest.skip('requires unprivileged userns or root')
|
||||
|
||||
isolation = {
|
||||
'namespaces': {'credential': not self.is_su, 'mount': True},
|
||||
'rootfs': self.current_dir,
|
||||
'namespaces': {'credential': not is_su, 'mount': True},
|
||||
'rootfs': option.test_dir,
|
||||
}
|
||||
|
||||
self.load('phpinfo', isolation=isolation)
|
||||
|
||||
self.assertIn(
|
||||
'success', self.conf('"/php/phpinfo"', 'applications/phpinfo/root')
|
||||
assert 'success' in self.conf(
|
||||
'"/php/phpinfo"', 'applications/phpinfo/root'
|
||||
)
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
'"/php/phpinfo"', 'applications/phpinfo/working_directory'
|
||||
),
|
||||
assert 'success' in self.conf(
|
||||
'"/php/phpinfo"', 'applications/phpinfo/working_directory'
|
||||
)
|
||||
|
||||
self.assertEqual(self.get()['status'], 200, 'empty rootfs')
|
||||
assert self.get()['status'] == 200, 'empty rootfs'
|
||||
|
||||
def test_php_isolation_rootfs_extensions(self):
|
||||
def test_php_isolation_rootfs_extensions(self, is_su):
|
||||
isolation_features = self.available['features']['isolation'].keys()
|
||||
|
||||
if not self.is_su:
|
||||
if not is_su:
|
||||
if 'user' not in isolation_features:
|
||||
print('requires unprivileged userns or root')
|
||||
raise unittest.SkipTest()
|
||||
pytest.skip('requires unprivileged userns or root')
|
||||
|
||||
if not 'unprivileged_userns_clone' in isolation_features:
|
||||
print('requires unprivileged userns or root')
|
||||
raise unittest.SkipTest()
|
||||
pytest.skip('requires unprivileged userns or root')
|
||||
|
||||
if 'mnt' not in isolation_features:
|
||||
print('requires mnt ns')
|
||||
raise unittest.SkipTest()
|
||||
pytest.skip('requires mnt ns')
|
||||
|
||||
isolation = {
|
||||
'rootfs': self.current_dir,
|
||||
'namespaces': {
|
||||
'credential': not self.is_su,
|
||||
'mount': not self.is_su,
|
||||
},
|
||||
'rootfs': option.test_dir,
|
||||
'namespaces': {'credential': not is_su, 'mount': not is_su},
|
||||
}
|
||||
|
||||
self.load('list-extensions', isolation=isolation)
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
'"/php/list-extensions"', 'applications/list-extensions/root'
|
||||
),
|
||||
assert 'success' in self.conf(
|
||||
'"/php/list-extensions"', 'applications/list-extensions/root'
|
||||
)
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{'file': '/php/list-extensions/php.ini'},
|
||||
'applications/list-extensions/options',
|
||||
),
|
||||
assert 'success' in self.conf(
|
||||
{'file': '/php/list-extensions/php.ini'},
|
||||
'applications/list-extensions/options',
|
||||
)
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
'"/php/list-extensions"',
|
||||
'applications/list-extensions/working_directory',
|
||||
),
|
||||
assert 'success' in self.conf(
|
||||
'"/php/list-extensions"',
|
||||
'applications/list-extensions/working_directory',
|
||||
)
|
||||
|
||||
extensions = self.getjson()['body']
|
||||
|
||||
self.assertIn('json', extensions, 'json in extensions list')
|
||||
self.assertIn('unit', extensions, 'unit in extensions list')
|
||||
assert 'json' in extensions, 'json in extensions list'
|
||||
assert 'unit' in extensions, 'unit in extensions list'
|
||||
|
||||
|
||||
def test_php_isolation_rootfs_no_language_libs(self):
|
||||
def test_php_isolation_rootfs_no_language_libs(self, is_su):
|
||||
isolation_features = self.available['features']['isolation'].keys()
|
||||
|
||||
if not self.is_su:
|
||||
if not is_su:
|
||||
if 'user' not in isolation_features:
|
||||
print('requires unprivileged userns or root')
|
||||
raise unittest.SkipTest()
|
||||
pytest.skip('requires unprivileged userns or root')
|
||||
|
||||
if not 'unprivileged_userns_clone' in isolation_features:
|
||||
print('requires unprivileged userns or root')
|
||||
raise unittest.SkipTest()
|
||||
pytest.skip('requires unprivileged userns or root')
|
||||
|
||||
if 'mnt' not in isolation_features:
|
||||
print('requires mnt ns')
|
||||
raise unittest.SkipTest()
|
||||
pytest.skip('requires mnt ns')
|
||||
|
||||
isolation = {
|
||||
'rootfs': self.current_dir,
|
||||
'rootfs': option.test_dir,
|
||||
'automount': {'language_deps': False},
|
||||
'namespaces': {
|
||||
'credential': not self.is_su,
|
||||
'mount': not self.is_su,
|
||||
},
|
||||
'namespaces': {'credential': not is_su, 'mount': not is_su},
|
||||
}
|
||||
|
||||
self.load('list-extensions', isolation=isolation)
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
'"/php/list-extensions"', 'applications/list-extensions/root'
|
||||
),
|
||||
assert 'success' in self.conf(
|
||||
'"/php/list-extensions"', 'applications/list-extensions/root'
|
||||
)
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{'file': '/php/list-extensions/php.ini'},
|
||||
'applications/list-extensions/options',
|
||||
),
|
||||
assert 'success' in self.conf(
|
||||
{'file': '/php/list-extensions/php.ini'},
|
||||
'applications/list-extensions/options',
|
||||
)
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
'"/php/list-extensions"',
|
||||
'applications/list-extensions/working_directory',
|
||||
),
|
||||
assert 'success' in self.conf(
|
||||
'"/php/list-extensions"',
|
||||
'applications/list-extensions/working_directory',
|
||||
)
|
||||
|
||||
extensions = self.getjson()['body']
|
||||
|
||||
self.assertIn('unit', extensions, 'unit in extensions list')
|
||||
self.assertNotIn('json', extensions, 'json not in extensions list')
|
||||
assert 'unit' in extensions, 'unit in extensions list'
|
||||
assert 'json' not in extensions, 'json not in extensions list'
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{'language_deps': True},
|
||||
'applications/list-extensions/isolation/automount',
|
||||
),
|
||||
assert 'success' in self.conf(
|
||||
{'language_deps': True},
|
||||
'applications/list-extensions/isolation/automount',
|
||||
)
|
||||
|
||||
extensions = self.getjson()['body']
|
||||
|
||||
self.assertIn('unit', extensions, 'unit in extensions list 2')
|
||||
self.assertIn('json', extensions, 'json in extensions list 2')
|
||||
assert 'unit' in extensions, 'unit in extensions list 2'
|
||||
assert 'json' in extensions, 'json in extensions list 2'
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestPHPIsolation.main()
|
||||
|
|
|
@ -1,128 +1,98 @@
|
|||
from unit.applications.lang.php import TestApplicationPHP
|
||||
from conftest import option
|
||||
|
||||
|
||||
class TestPHPTargets(TestApplicationPHP):
|
||||
prerequisites = {'modules': {'php': 'any'}}
|
||||
|
||||
def test_php_application_targets(self):
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "routes"}},
|
||||
"routes": [
|
||||
{
|
||||
"match": {"uri": "/1"},
|
||||
"action": {"pass": "applications/targets/1"},
|
||||
},
|
||||
{
|
||||
"match": {"uri": "/2"},
|
||||
"action": {"pass": "applications/targets/2"},
|
||||
},
|
||||
{"action": {"pass": "applications/targets/default"}},
|
||||
],
|
||||
"applications": {
|
||||
"targets": {
|
||||
"type": "php",
|
||||
"processes": {"spare": 0},
|
||||
"targets": {
|
||||
"1": {
|
||||
"script": "1.php",
|
||||
"root": self.current_dir + "/php/targets",
|
||||
},
|
||||
"2": {
|
||||
"script": "2.php",
|
||||
"root": self.current_dir
|
||||
+ "/php/targets/2",
|
||||
},
|
||||
"default": {
|
||||
"index": "index.php",
|
||||
"root": self.current_dir + "/php/targets",
|
||||
},
|
||||
},
|
||||
}
|
||||
assert 'success' in self.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "routes"}},
|
||||
"routes": [
|
||||
{
|
||||
"match": {"uri": "/1"},
|
||||
"action": {"pass": "applications/targets/1"},
|
||||
},
|
||||
}
|
||||
),
|
||||
{
|
||||
"match": {"uri": "/2"},
|
||||
"action": {"pass": "applications/targets/2"},
|
||||
},
|
||||
{"action": {"pass": "applications/targets/default"}},
|
||||
],
|
||||
"applications": {
|
||||
"targets": {
|
||||
"type": "php",
|
||||
"processes": {"spare": 0},
|
||||
"targets": {
|
||||
"1": {
|
||||
"script": "1.php",
|
||||
"root": option.test_dir + "/php/targets",
|
||||
},
|
||||
"2": {
|
||||
"script": "2.php",
|
||||
"root": option.test_dir + "/php/targets/2",
|
||||
},
|
||||
"default": {
|
||||
"index": "index.php",
|
||||
"root": option.test_dir + "/php/targets",
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
self.assertEqual(self.get(url='/1')['body'], '1')
|
||||
self.assertEqual(self.get(url='/2')['body'], '2')
|
||||
self.assertEqual(self.get(url='/blah')['status'], 503) # TODO 404
|
||||
self.assertEqual(self.get(url='/')['body'], 'index')
|
||||
assert self.get(url='/1')['body'] == '1'
|
||||
assert self.get(url='/2')['body'] == '2'
|
||||
assert self.get(url='/blah')['status'] == 503 # TODO 404
|
||||
assert self.get(url='/')['body'] == 'index'
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
"\"1.php\"", 'applications/targets/targets/default/index'
|
||||
),
|
||||
'change targets index',
|
||||
)
|
||||
self.assertEqual(self.get(url='/')['body'], '1')
|
||||
assert 'success' in self.conf(
|
||||
"\"1.php\"", 'applications/targets/targets/default/index'
|
||||
), 'change targets index'
|
||||
assert self.get(url='/')['body'] == '1'
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf_delete('applications/targets/targets/default/index'),
|
||||
'remove targets index',
|
||||
)
|
||||
self.assertEqual(self.get(url='/')['body'], 'index')
|
||||
assert 'success' in self.conf_delete(
|
||||
'applications/targets/targets/default/index'
|
||||
), 'remove targets index'
|
||||
assert self.get(url='/')['body'] == 'index'
|
||||
|
||||
def test_php_application_targets_error(self):
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"*:7080": {"pass": "applications/targets/default"}
|
||||
},
|
||||
"applications": {
|
||||
assert 'success' in self.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"*:7080": {"pass": "applications/targets/default"}
|
||||
},
|
||||
"applications": {
|
||||
"targets": {
|
||||
"type": "php",
|
||||
"processes": {"spare": 0},
|
||||
"targets": {
|
||||
"type": "php",
|
||||
"processes": {"spare": 0},
|
||||
"targets": {
|
||||
"default": {
|
||||
"index": "index.php",
|
||||
"root": self.current_dir + "/php/targets",
|
||||
},
|
||||
"default": {
|
||||
"index": "index.php",
|
||||
"root": option.test_dir + "/php/targets",
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
),
|
||||
'initial configuration',
|
||||
)
|
||||
self.assertEqual(self.get()['status'], 200)
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
), 'initial configuration'
|
||||
assert self.get()['status'] == 200
|
||||
|
||||
self.assertIn(
|
||||
'error',
|
||||
self.conf(
|
||||
{"pass": "applications/targets/blah"}, 'listeners/*:7080'
|
||||
),
|
||||
'invalid targets pass',
|
||||
)
|
||||
self.assertIn(
|
||||
'error',
|
||||
self.conf(
|
||||
'"' + self.current_dir + '/php/targets\"',
|
||||
'applications/targets/root',
|
||||
),
|
||||
'invalid root',
|
||||
)
|
||||
self.assertIn(
|
||||
'error',
|
||||
self.conf('"index.php"', 'applications/targets/index'),
|
||||
'invalid index',
|
||||
)
|
||||
self.assertIn(
|
||||
'error',
|
||||
self.conf('"index.php"', 'applications/targets/script'),
|
||||
'invalid script',
|
||||
)
|
||||
self.assertIn(
|
||||
'error',
|
||||
self.conf_delete('applications/targets/default/root'),
|
||||
'root remove',
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestPHPTargets.main()
|
||||
assert 'error' in self.conf(
|
||||
{"pass": "applications/targets/blah"}, 'listeners/*:7080'
|
||||
), 'invalid targets pass'
|
||||
assert 'error' in self.conf(
|
||||
'"' + option.test_dir + '/php/targets\"',
|
||||
'applications/targets/root',
|
||||
), 'invalid root'
|
||||
assert 'error' in self.conf(
|
||||
'"index.php"', 'applications/targets/index'
|
||||
), 'invalid index'
|
||||
assert 'error' in self.conf(
|
||||
'"index.php"', 'applications/targets/script'
|
||||
), 'invalid script'
|
||||
assert 'error' in self.conf_delete(
|
||||
'applications/targets/default/root'
|
||||
), 'root remove'
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import pytest
|
||||
import re
|
||||
import socket
|
||||
import time
|
||||
import unittest
|
||||
|
||||
from unit.applications.lang.python import TestApplicationPython
|
||||
from conftest import option, skip_alert
|
||||
|
||||
|
||||
class TestProxy(TestApplicationPython):
|
||||
|
@ -42,7 +43,7 @@ Content-Length: 10
|
|||
|
||||
to_send = req
|
||||
|
||||
m = re.search('X-Len: (\d+)', data)
|
||||
m = re.search(r'X-Len: (\d+)', data)
|
||||
if m:
|
||||
to_send += b'X' * int(m.group(1))
|
||||
|
||||
|
@ -56,145 +57,127 @@ Content-Length: 10
|
|||
def post_http10(self, *args, **kwargs):
|
||||
return self.post(*args, http_10=True, **kwargs)
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
def setup_method(self):
|
||||
super().setup_method()
|
||||
|
||||
self.run_process(self.run_server, self.SERVER_PORT)
|
||||
self.waitforsocket(self.SERVER_PORT)
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"*:7080": {"pass": "routes"},
|
||||
"*:7081": {"pass": "applications/mirror"},
|
||||
assert 'success' in self.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"*:7080": {"pass": "routes"},
|
||||
"*:7081": {"pass": "applications/mirror"},
|
||||
},
|
||||
"routes": [{"action": {"proxy": "http://127.0.0.1:7081"}}],
|
||||
"applications": {
|
||||
"mirror": {
|
||||
"type": "python",
|
||||
"processes": {"spare": 0},
|
||||
"path": option.test_dir + "/python/mirror",
|
||||
"working_directory": option.test_dir
|
||||
+ "/python/mirror",
|
||||
"module": "wsgi",
|
||||
},
|
||||
"routes": [{"action": {"proxy": "http://127.0.0.1:7081"}}],
|
||||
"applications": {
|
||||
"mirror": {
|
||||
"type": "python",
|
||||
"processes": {"spare": 0},
|
||||
"path": self.current_dir + "/python/mirror",
|
||||
"working_directory": self.current_dir
|
||||
+ "/python/mirror",
|
||||
"module": "wsgi",
|
||||
},
|
||||
"custom_header": {
|
||||
"type": "python",
|
||||
"processes": {"spare": 0},
|
||||
"path": self.current_dir + "/python/custom_header",
|
||||
"working_directory": self.current_dir
|
||||
+ "/python/custom_header",
|
||||
"module": "wsgi",
|
||||
},
|
||||
"delayed": {
|
||||
"type": "python",
|
||||
"processes": {"spare": 0},
|
||||
"path": self.current_dir + "/python/delayed",
|
||||
"working_directory": self.current_dir
|
||||
+ "/python/delayed",
|
||||
"module": "wsgi",
|
||||
},
|
||||
"custom_header": {
|
||||
"type": "python",
|
||||
"processes": {"spare": 0},
|
||||
"path": option.test_dir + "/python/custom_header",
|
||||
"working_directory": option.test_dir
|
||||
+ "/python/custom_header",
|
||||
"module": "wsgi",
|
||||
},
|
||||
}
|
||||
),
|
||||
'proxy initial configuration',
|
||||
)
|
||||
"delayed": {
|
||||
"type": "python",
|
||||
"processes": {"spare": 0},
|
||||
"path": option.test_dir + "/python/delayed",
|
||||
"working_directory": option.test_dir
|
||||
+ "/python/delayed",
|
||||
"module": "wsgi",
|
||||
},
|
||||
},
|
||||
}
|
||||
), 'proxy initial configuration'
|
||||
|
||||
def test_proxy_http10(self):
|
||||
for _ in range(10):
|
||||
self.assertEqual(self.get_http10()['status'], 200, 'status')
|
||||
assert self.get_http10()['status'] == 200, 'status'
|
||||
|
||||
def test_proxy_chain(self):
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"*:7080": {"pass": "routes/first"},
|
||||
"*:7081": {"pass": "routes/second"},
|
||||
"*:7082": {"pass": "routes/third"},
|
||||
"*:7083": {"pass": "routes/fourth"},
|
||||
"*:7084": {"pass": "routes/fifth"},
|
||||
"*:7085": {"pass": "applications/mirror"},
|
||||
},
|
||||
"routes": {
|
||||
"first": [
|
||||
{"action": {"proxy": "http://127.0.0.1:7081"}}
|
||||
],
|
||||
"second": [
|
||||
{"action": {"proxy": "http://127.0.0.1:7082"}}
|
||||
],
|
||||
"third": [
|
||||
{"action": {"proxy": "http://127.0.0.1:7083"}}
|
||||
],
|
||||
"fourth": [
|
||||
{"action": {"proxy": "http://127.0.0.1:7084"}}
|
||||
],
|
||||
"fifth": [
|
||||
{"action": {"proxy": "http://127.0.0.1:7085"}}
|
||||
],
|
||||
},
|
||||
"applications": {
|
||||
"mirror": {
|
||||
"type": "python",
|
||||
"processes": {"spare": 0},
|
||||
"path": self.current_dir + "/python/mirror",
|
||||
"working_directory": self.current_dir
|
||||
+ "/python/mirror",
|
||||
"module": "wsgi",
|
||||
}
|
||||
},
|
||||
}
|
||||
),
|
||||
'proxy chain configuration',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"*:7080": {"pass": "routes/first"},
|
||||
"*:7081": {"pass": "routes/second"},
|
||||
"*:7082": {"pass": "routes/third"},
|
||||
"*:7083": {"pass": "routes/fourth"},
|
||||
"*:7084": {"pass": "routes/fifth"},
|
||||
"*:7085": {"pass": "applications/mirror"},
|
||||
},
|
||||
"routes": {
|
||||
"first": [{"action": {"proxy": "http://127.0.0.1:7081"}}],
|
||||
"second": [{"action": {"proxy": "http://127.0.0.1:7082"}}],
|
||||
"third": [{"action": {"proxy": "http://127.0.0.1:7083"}}],
|
||||
"fourth": [{"action": {"proxy": "http://127.0.0.1:7084"}}],
|
||||
"fifth": [{"action": {"proxy": "http://127.0.0.1:7085"}}],
|
||||
},
|
||||
"applications": {
|
||||
"mirror": {
|
||||
"type": "python",
|
||||
"processes": {"spare": 0},
|
||||
"path": option.test_dir + "/python/mirror",
|
||||
"working_directory": option.test_dir
|
||||
+ "/python/mirror",
|
||||
"module": "wsgi",
|
||||
}
|
||||
},
|
||||
}
|
||||
), 'proxy chain configuration'
|
||||
|
||||
self.assertEqual(self.get_http10()['status'], 200, 'status')
|
||||
assert self.get_http10()['status'] == 200, 'status'
|
||||
|
||||
def test_proxy_body(self):
|
||||
payload = '0123456789'
|
||||
for _ in range(10):
|
||||
resp = self.post_http10(body=payload)
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'status')
|
||||
self.assertEqual(resp['body'], payload, 'body')
|
||||
assert resp['status'] == 200, 'status'
|
||||
assert resp['body'] == payload, 'body'
|
||||
|
||||
payload = 'X' * 4096
|
||||
for _ in range(10):
|
||||
resp = self.post_http10(body=payload)
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'status')
|
||||
self.assertEqual(resp['body'], payload, 'body')
|
||||
assert resp['status'] == 200, 'status'
|
||||
assert resp['body'] == payload, 'body'
|
||||
|
||||
payload = 'X' * 4097
|
||||
for _ in range(10):
|
||||
resp = self.post_http10(body=payload)
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'status')
|
||||
self.assertEqual(resp['body'], payload, 'body')
|
||||
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)
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'status')
|
||||
self.assertEqual(resp['body'], payload, 'body')
|
||||
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)
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'status')
|
||||
self.assertEqual(resp['body'], payload, 'body')
|
||||
assert resp['status'] == 200, 'status'
|
||||
assert resp['body'] == payload, 'body'
|
||||
|
||||
self.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)
|
||||
self.assertEqual(resp['status'], 200, 'status')
|
||||
self.assertEqual(resp['body'], payload, 'body')
|
||||
assert resp['status'] == 200, 'status'
|
||||
assert resp['body'] == payload, 'body'
|
||||
|
||||
def test_proxy_parallel(self):
|
||||
payload = 'X' * 4096 * 257
|
||||
|
@ -216,62 +199,53 @@ Content-Length: 10
|
|||
|
||||
resp = self._resp_to_dict(resp)
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'status')
|
||||
self.assertEqual(resp['body'], payload + str(i), 'body')
|
||||
assert resp['status'] == 200, 'status'
|
||||
assert resp['body'] == payload + str(i), 'body'
|
||||
|
||||
def test_proxy_header(self):
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{"pass": "applications/custom_header"}, 'listeners/*:7081'
|
||||
),
|
||||
'custom_header configure',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{"pass": "applications/custom_header"}, 'listeners/*:7081'
|
||||
), 'custom_header configure'
|
||||
|
||||
header_value = 'blah'
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.get_http10(
|
||||
headers={'Host': 'localhost', 'Custom-Header': header_value}
|
||||
)['headers']['Custom-Header'],
|
||||
header_value,
|
||||
'custom header',
|
||||
)
|
||||
)['headers']['Custom-Header']
|
||||
== header_value
|
||||
), 'custom header'
|
||||
|
||||
header_value = '(),/:;<=>?@[\]{}\t !#$%&\'*+-.^_`|~'
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.get_http10(
|
||||
headers={'Host': 'localhost', 'Custom-Header': header_value}
|
||||
)['headers']['Custom-Header'],
|
||||
header_value,
|
||||
'custom header 2',
|
||||
)
|
||||
)['headers']['Custom-Header']
|
||||
== header_value
|
||||
), 'custom header 2'
|
||||
|
||||
header_value = 'X' * 4096
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.get_http10(
|
||||
headers={'Host': 'localhost', 'Custom-Header': header_value}
|
||||
)['headers']['Custom-Header'],
|
||||
header_value,
|
||||
'custom header 3',
|
||||
)
|
||||
)['headers']['Custom-Header']
|
||||
== header_value
|
||||
), 'custom header 3'
|
||||
|
||||
header_value = 'X' * 8191
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.get_http10(
|
||||
headers={'Host': 'localhost', 'Custom-Header': header_value}
|
||||
)['headers']['Custom-Header'],
|
||||
header_value,
|
||||
'custom header 4',
|
||||
)
|
||||
)['headers']['Custom-Header']
|
||||
== header_value
|
||||
), 'custom header 4'
|
||||
|
||||
header_value = 'X' * 8192
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.get_http10(
|
||||
headers={'Host': 'localhost', 'Custom-Header': header_value}
|
||||
)['status'],
|
||||
431,
|
||||
'custom header 5',
|
||||
)
|
||||
)['status']
|
||||
== 431
|
||||
), 'custom header 5'
|
||||
|
||||
def test_proxy_fragmented(self):
|
||||
_, sock = self.http(
|
||||
|
@ -286,9 +260,9 @@ Content-Length: 10
|
|||
|
||||
sock.sendall("t\r\n\r\n".encode())
|
||||
|
||||
self.assertRegex(
|
||||
self.recvall(sock).decode(), '200 OK', 'fragmented send'
|
||||
)
|
||||
assert re.search(
|
||||
'200 OK', self.recvall(sock).decode()
|
||||
), 'fragmented send'
|
||||
sock.close()
|
||||
|
||||
def test_proxy_fragmented_close(self):
|
||||
|
@ -328,8 +302,8 @@ Content-Length: 10
|
|||
resp = self._resp_to_dict(self.recvall(sock).decode())
|
||||
sock.close()
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'status')
|
||||
self.assertEqual(resp['body'], "X" * 30000, 'body')
|
||||
assert resp['status'] == 200, 'status'
|
||||
assert resp['body'] == "X" * 30000, 'body'
|
||||
|
||||
def test_proxy_fragmented_body_close(self):
|
||||
_, sock = self.http(
|
||||
|
@ -349,70 +323,48 @@ Content-Length: 10
|
|||
sock.close()
|
||||
|
||||
def test_proxy_nowhere(self):
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
[{"action": {"proxy": "http://127.0.0.1:7082"}}], 'routes'
|
||||
),
|
||||
'proxy path changed',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
[{"action": {"proxy": "http://127.0.0.1:7082"}}], 'routes'
|
||||
), 'proxy path changed'
|
||||
|
||||
self.assertEqual(self.get_http10()['status'], 502, 'status')
|
||||
assert self.get_http10()['status'] == 502, 'status'
|
||||
|
||||
def test_proxy_ipv6(self):
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{
|
||||
"*:7080": {"pass": "routes"},
|
||||
"[::1]:7081": {'application': 'mirror'},
|
||||
},
|
||||
'listeners',
|
||||
),
|
||||
'add ipv6 listener configure',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{
|
||||
"*:7080": {"pass": "routes"},
|
||||
"[::1]:7081": {'application': 'mirror'},
|
||||
},
|
||||
'listeners',
|
||||
), 'add ipv6 listener configure'
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf([{"action": {"proxy": "http://[::1]:7081"}}], 'routes'),
|
||||
'proxy ipv6 configure',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
[{"action": {"proxy": "http://[::1]:7081"}}], 'routes'
|
||||
), 'proxy ipv6 configure'
|
||||
|
||||
self.assertEqual(self.get_http10()['status'], 200, 'status')
|
||||
assert self.get_http10()['status'] == 200, 'status'
|
||||
|
||||
def test_proxy_unix(self):
|
||||
addr = self.testdir + '/sock'
|
||||
addr = self.temp_dir + '/sock'
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{
|
||||
"*:7080": {"pass": "routes"},
|
||||
"unix:" + addr: {'application': 'mirror'},
|
||||
},
|
||||
'listeners',
|
||||
),
|
||||
'add unix listener configure',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{
|
||||
"*:7080": {"pass": "routes"},
|
||||
"unix:" + addr: {'application': 'mirror'},
|
||||
},
|
||||
'listeners',
|
||||
), 'add unix listener configure'
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
[{"action": {"proxy": 'http://unix:' + addr}}], 'routes'
|
||||
),
|
||||
'proxy unix configure',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
[{"action": {"proxy": 'http://unix:' + addr}}], 'routes'
|
||||
), 'proxy unix configure'
|
||||
|
||||
self.assertEqual(self.get_http10()['status'], 200, 'status')
|
||||
assert self.get_http10()['status'] == 200, 'status'
|
||||
|
||||
def test_proxy_delayed(self):
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{"pass": "applications/delayed"}, 'listeners/*:7081'
|
||||
),
|
||||
'delayed configure',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{"pass": "applications/delayed"}, 'listeners/*:7081'
|
||||
), 'delayed configure'
|
||||
|
||||
body = '0123456789' * 1000
|
||||
resp = self.post_http10(
|
||||
|
@ -426,8 +378,8 @@ Content-Length: 10
|
|||
body=body,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'status')
|
||||
self.assertEqual(resp['body'], body, 'body')
|
||||
assert resp['status'] == 200, 'status'
|
||||
assert resp['body'] == body, 'body'
|
||||
|
||||
resp = self.post_http10(
|
||||
headers={
|
||||
|
@ -440,17 +392,13 @@ Content-Length: 10
|
|||
body=body,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'status')
|
||||
self.assertEqual(resp['body'], body, 'body')
|
||||
assert resp['status'] == 200, 'status'
|
||||
assert resp['body'] == body, 'body'
|
||||
|
||||
def test_proxy_delayed_close(self):
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{"pass": "applications/delayed"}, 'listeners/*:7081'
|
||||
),
|
||||
'delayed configure',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{"pass": "applications/delayed"}, 'listeners/*:7081'
|
||||
), 'delayed configure'
|
||||
|
||||
_, sock = self.post_http10(
|
||||
headers={
|
||||
|
@ -465,9 +413,7 @@ Content-Length: 10
|
|||
no_recv=True,
|
||||
)
|
||||
|
||||
self.assertRegex(
|
||||
sock.recv(100).decode(), '200 OK', 'first'
|
||||
)
|
||||
assert re.search('200 OK', sock.recv(100).decode()), 'first'
|
||||
sock.close()
|
||||
|
||||
_, sock = self.post_http10(
|
||||
|
@ -483,51 +429,42 @@ Content-Length: 10
|
|||
no_recv=True,
|
||||
)
|
||||
|
||||
self.assertRegex(
|
||||
sock.recv(100).decode(), '200 OK', 'second'
|
||||
)
|
||||
assert re.search('200 OK', sock.recv(100).decode()), 'second'
|
||||
sock.close()
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_proxy_content_length(self):
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
[
|
||||
{
|
||||
"action": {
|
||||
"proxy": "http://127.0.0.1:"
|
||||
+ str(self.SERVER_PORT)
|
||||
}
|
||||
assert 'success' in self.conf(
|
||||
[
|
||||
{
|
||||
"action": {
|
||||
"proxy": "http://127.0.0.1:" + str(self.SERVER_PORT)
|
||||
}
|
||||
],
|
||||
'routes',
|
||||
),
|
||||
'proxy backend configure',
|
||||
)
|
||||
}
|
||||
],
|
||||
'routes',
|
||||
), 'proxy backend configure'
|
||||
|
||||
resp = self.get_http10()
|
||||
self.assertEqual(len(resp['body']), 0, 'body lt Content-Length 0')
|
||||
assert len(resp['body']) == 0, 'body lt Content-Length 0'
|
||||
|
||||
resp = self.get_http10(headers={'Host': 'localhost', 'X-Len': '5'})
|
||||
self.assertEqual(len(resp['body']), 5, 'body lt Content-Length 5')
|
||||
assert len(resp['body']) == 5, 'body lt Content-Length 5'
|
||||
|
||||
resp = self.get_http10(headers={'Host': 'localhost', 'X-Len': '9'})
|
||||
self.assertEqual(len(resp['body']), 9, 'body lt Content-Length 9')
|
||||
assert len(resp['body']) == 9, 'body lt Content-Length 9'
|
||||
|
||||
resp = self.get_http10(headers={'Host': 'localhost', 'X-Len': '11'})
|
||||
self.assertEqual(len(resp['body']), 10, 'body gt Content-Length 11')
|
||||
assert len(resp['body']) == 10, 'body gt Content-Length 11'
|
||||
|
||||
resp = self.get_http10(headers={'Host': 'localhost', 'X-Len': '15'})
|
||||
self.assertEqual(len(resp['body']), 10, 'body gt Content-Length 15')
|
||||
assert len(resp['body']) == 10, 'body gt Content-Length 15'
|
||||
|
||||
def test_proxy_invalid(self):
|
||||
def check_proxy(proxy):
|
||||
self.assertIn(
|
||||
'error',
|
||||
self.conf([{"action": {"proxy": proxy}}], 'routes'),
|
||||
'proxy invalid',
|
||||
)
|
||||
assert 'error' in \
|
||||
self.conf([{"action": {"proxy": proxy}}], 'routes'), \
|
||||
'proxy invalid'
|
||||
|
||||
check_proxy('blah')
|
||||
check_proxy('/blah')
|
||||
|
@ -544,12 +481,10 @@ Content-Length: 10
|
|||
check_proxy('http://[::7080')
|
||||
|
||||
def test_proxy_loop(self):
|
||||
self.skip_alerts.extend(
|
||||
[
|
||||
r'socket.*failed',
|
||||
r'accept.*failed',
|
||||
r'new connections are not accepted',
|
||||
]
|
||||
skip_alert(
|
||||
r'socket.*failed',
|
||||
r'accept.*failed',
|
||||
r'new connections are not accepted',
|
||||
)
|
||||
self.conf(
|
||||
{
|
||||
|
@ -563,9 +498,8 @@ Content-Length: 10
|
|||
"mirror": {
|
||||
"type": "python",
|
||||
"processes": {"spare": 0},
|
||||
"path": self.current_dir + "/python/mirror",
|
||||
"working_directory": self.current_dir
|
||||
+ "/python/mirror",
|
||||
"path": option.test_dir + "/python/mirror",
|
||||
"working_directory": option.test_dir + "/python/mirror",
|
||||
"module": "wsgi",
|
||||
},
|
||||
},
|
||||
|
@ -574,6 +508,3 @@ Content-Length: 10
|
|||
|
||||
self.get_http10(no_recv=True)
|
||||
self.get_http10(read_timeout=1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestProxy.main()
|
||||
|
|
|
@ -12,7 +12,7 @@ class TestProxyChunked(TestApplicationPython):
|
|||
SERVER_PORT = 7999
|
||||
|
||||
@staticmethod
|
||||
def run_server(server_port, testdir):
|
||||
def run_server(server_port, temp_dir):
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
||||
|
@ -81,68 +81,62 @@ class TestProxyChunked(TestApplicationPython):
|
|||
def get_http10(self, *args, **kwargs):
|
||||
return self.get(*args, http_10=True, **kwargs)
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
def setup_method(self):
|
||||
super().setup_method()
|
||||
|
||||
self.run_process(self.run_server, self.SERVER_PORT, self.testdir)
|
||||
self.run_process(self.run_server, self.SERVER_PORT, self.temp_dir)
|
||||
self.waitforsocket(self.SERVER_PORT)
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "routes"},},
|
||||
"routes": [
|
||||
{
|
||||
"action": {
|
||||
"proxy": "http://127.0.0.1:"
|
||||
+ str(self.SERVER_PORT)
|
||||
}
|
||||
assert 'success' in self.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "routes"},},
|
||||
"routes": [
|
||||
{
|
||||
"action": {
|
||||
"proxy": "http://127.0.0.1:"
|
||||
+ str(self.SERVER_PORT)
|
||||
}
|
||||
],
|
||||
}
|
||||
),
|
||||
'proxy initial configuration',
|
||||
)
|
||||
}
|
||||
],
|
||||
}
|
||||
), 'proxy initial configuration'
|
||||
|
||||
def test_proxy_chunked(self):
|
||||
for _ in range(10):
|
||||
self.assertEqual(
|
||||
self.get_http10(body='\r\n\r\n0\r\n\r\n')['status'], 200
|
||||
)
|
||||
assert self.get_http10(body='\r\n\r\n0\r\n\r\n')['status'] == 200
|
||||
|
||||
def test_proxy_chunked_body(self):
|
||||
part = '0123456789abcdef'
|
||||
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.get_http10(body=self.chunks([('1000', part + ' X 256')]))[
|
||||
'body'
|
||||
],
|
||||
part * 256,
|
||||
]
|
||||
== part * 256
|
||||
)
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.get_http10(body=self.chunks([('100000', part + ' X 65536')]))[
|
||||
'body'
|
||||
],
|
||||
part * 65536,
|
||||
]
|
||||
== part * 65536
|
||||
)
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.get_http10(
|
||||
body=self.chunks([('1000000', part + ' X 1048576')]),
|
||||
read_buffer_size=4096 * 4096,
|
||||
)['body'],
|
||||
part * 1048576,
|
||||
)['body']
|
||||
== part * 1048576
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.get_http10(
|
||||
body=self.chunks(
|
||||
[('1000', part + ' X 256'), ('1000', part + ' X 256')]
|
||||
)
|
||||
)['body'],
|
||||
part * 256 * 2,
|
||||
)['body']
|
||||
== part * 256 * 2
|
||||
)
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.get_http10(
|
||||
body=self.chunks(
|
||||
[
|
||||
|
@ -150,10 +144,10 @@ class TestProxyChunked(TestApplicationPython):
|
|||
('100000', part + ' X 65536'),
|
||||
]
|
||||
)
|
||||
)['body'],
|
||||
part * 65536 * 2,
|
||||
)['body']
|
||||
== part * 65536 * 2
|
||||
)
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.get_http10(
|
||||
body=self.chunks(
|
||||
[
|
||||
|
@ -162,42 +156,40 @@ class TestProxyChunked(TestApplicationPython):
|
|||
]
|
||||
),
|
||||
read_buffer_size=4096 * 4096,
|
||||
)['body'],
|
||||
part * 1048576 * 2,
|
||||
)['body']
|
||||
== part * 1048576 * 2
|
||||
)
|
||||
|
||||
def test_proxy_chunked_fragmented(self):
|
||||
part = '0123456789abcdef'
|
||||
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.get_http10(
|
||||
body=self.chunks(
|
||||
[('1', hex(i % 16)[2:]) for i in range(4096)]
|
||||
),
|
||||
)['body'],
|
||||
part * 256,
|
||||
)['body']
|
||||
== part * 256
|
||||
)
|
||||
|
||||
def test_proxy_chunked_send(self):
|
||||
self.assertEqual(
|
||||
self.get_http10(body='\r\n\r\n@0@\r\n\r\n')['status'], 200
|
||||
)
|
||||
self.assertEqual(
|
||||
assert self.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'],
|
||||
'abcd',
|
||||
)['body']
|
||||
== 'abcd'
|
||||
)
|
||||
self.assertEqual(
|
||||
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'],
|
||||
'abcd',
|
||||
)['body']
|
||||
== 'abcd'
|
||||
)
|
||||
|
||||
def test_proxy_chunked_invalid(self):
|
||||
def check_invalid(body):
|
||||
self.assertNotEqual(self.get_http10(body=body)['status'], 200)
|
||||
assert self.get_http10(body=body)['status'] != 200
|
||||
|
||||
check_invalid('\r\n\r0')
|
||||
check_invalid('\r\n\r\n\r0')
|
||||
|
@ -209,41 +201,38 @@ class TestProxyChunked(TestApplicationPython):
|
|||
check_invalid('\r\n\r\n0\r\nX')
|
||||
|
||||
resp = self.get_http10(body='\r\n\r\n65#\r\nA X 100')
|
||||
self.assertEqual(resp['status'], 200, 'incomplete chunk status')
|
||||
self.assertNotEqual(resp['body'][-5:], '0\r\n\r\n', 'incomplete chunk')
|
||||
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')
|
||||
self.assertEqual(resp['status'], 200, 'no zero chunk status')
|
||||
self.assertNotEqual(resp['body'][-5:], '0\r\n\r\n', 'no zero chunk')
|
||||
assert resp['status'] == 200, 'no zero chunk status'
|
||||
assert resp['body'][-5:] != '0\r\n\r\n', 'no zero chunk'
|
||||
|
||||
self.assertEqual(
|
||||
self.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
|
||||
)
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.get_http10(body='\r\n\r\n10000000000000000\r\nA X 100')[
|
||||
'status'
|
||||
],
|
||||
502,
|
||||
]
|
||||
== 502
|
||||
)
|
||||
self.assertGreaterEqual(
|
||||
assert (
|
||||
len(
|
||||
self.get_http10(
|
||||
body='\r\n\r\n1000000\r\nA X 1048576\r\n1000000\r\nA X 100',
|
||||
read_buffer_size=4096 * 4096,
|
||||
)['body']
|
||||
),
|
||||
1048576,
|
||||
)
|
||||
>= 1048576
|
||||
)
|
||||
self.assertGreaterEqual(
|
||||
assert (
|
||||
len(
|
||||
self.get_http10(
|
||||
body='\r\n\r\n1000000\r\nA X 1048576\r\nXXX\r\nA X 100',
|
||||
read_buffer_size=4096 * 4096,
|
||||
)['body']
|
||||
),
|
||||
1048576,
|
||||
)
|
||||
>= 1048576
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestProxyChunked.main()
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
import grp
|
||||
import pytest
|
||||
import pwd
|
||||
import re
|
||||
import time
|
||||
import unittest
|
||||
|
||||
from unit.applications.lang.python import TestApplicationPython
|
||||
from conftest import skip_alert
|
||||
|
||||
|
||||
class TestPythonApplication(TestApplicationPython):
|
||||
prerequisites = {'modules': {'python': 'all'}}
|
||||
|
||||
def findall(self, pattern):
|
||||
with open(self.testdir + '/unit.log', 'r', errors='ignore') as f:
|
||||
with open(self.temp_dir + '/unit.log', 'r', errors='ignore') as f:
|
||||
return re.findall(pattern, f.read())
|
||||
|
||||
def test_python_application_variables(self):
|
||||
|
@ -29,135 +30,109 @@ class TestPythonApplication(TestApplicationPython):
|
|||
body=body,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'status')
|
||||
assert resp['status'] == 200, 'status'
|
||||
headers = resp['headers']
|
||||
header_server = headers.pop('Server')
|
||||
self.assertRegex(header_server, r'Unit/[\d\.]+', 'server header')
|
||||
self.assertEqual(
|
||||
headers.pop('Server-Software'),
|
||||
header_server,
|
||||
'server software header',
|
||||
)
|
||||
assert re.search(r'Unit/[\d\.]+', header_server), 'server header'
|
||||
assert (
|
||||
headers.pop('Server-Software') == header_server
|
||||
), 'server software header'
|
||||
|
||||
date = headers.pop('Date')
|
||||
self.assertEqual(date[-4:], ' GMT', 'date header timezone')
|
||||
self.assertLess(
|
||||
abs(self.date_to_sec_epoch(date) - self.sec_epoch()),
|
||||
5,
|
||||
'date header',
|
||||
)
|
||||
assert date[-4:] == ' GMT', 'date header timezone'
|
||||
assert (
|
||||
abs(self.date_to_sec_epoch(date) - self.sec_epoch()) < 5
|
||||
), 'date header'
|
||||
|
||||
self.assertDictEqual(
|
||||
headers,
|
||||
{
|
||||
'Connection': 'close',
|
||||
'Content-Length': str(len(body)),
|
||||
'Content-Type': 'text/html',
|
||||
'Request-Method': 'POST',
|
||||
'Request-Uri': '/',
|
||||
'Http-Host': 'localhost',
|
||||
'Server-Protocol': 'HTTP/1.1',
|
||||
'Custom-Header': 'blah',
|
||||
'Wsgi-Version': '(1, 0)',
|
||||
'Wsgi-Url-Scheme': 'http',
|
||||
'Wsgi-Multithread': 'False',
|
||||
'Wsgi-Multiprocess': 'True',
|
||||
'Wsgi-Run-Once': 'False',
|
||||
},
|
||||
'headers',
|
||||
)
|
||||
self.assertEqual(resp['body'], body, 'body')
|
||||
assert headers == {
|
||||
'Connection': 'close',
|
||||
'Content-Length': str(len(body)),
|
||||
'Content-Type': 'text/html',
|
||||
'Request-Method': 'POST',
|
||||
'Request-Uri': '/',
|
||||
'Http-Host': 'localhost',
|
||||
'Server-Protocol': 'HTTP/1.1',
|
||||
'Custom-Header': 'blah',
|
||||
'Wsgi-Version': '(1, 0)',
|
||||
'Wsgi-Url-Scheme': 'http',
|
||||
'Wsgi-Multithread': 'False',
|
||||
'Wsgi-Multiprocess': 'True',
|
||||
'Wsgi-Run-Once': 'False',
|
||||
}, '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')
|
||||
|
||||
self.assertEqual(
|
||||
resp['headers']['Query-String'],
|
||||
'var1=val1&var2=val2',
|
||||
'Query-String header',
|
||||
)
|
||||
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')
|
||||
self.assertEqual(
|
||||
resp['headers']['Query-String'],
|
||||
'var1=val1&var2=val2',
|
||||
'Query-String space',
|
||||
)
|
||||
assert (
|
||||
resp['headers']['Query-String'] == 'var1=val1&var2=val2'
|
||||
), 'Query-String space'
|
||||
|
||||
resp = self.get(url='/ %20?var1=val1&var2=val2')
|
||||
self.assertEqual(
|
||||
resp['headers']['Query-String'],
|
||||
'var1=val1&var2=val2',
|
||||
'Query-String space 2',
|
||||
)
|
||||
assert (
|
||||
resp['headers']['Query-String'] == 'var1=val1&var2=val2'
|
||||
), 'Query-String space 2'
|
||||
|
||||
resp = self.get(url='/ %20 ?var1=val1&var2=val2')
|
||||
self.assertEqual(
|
||||
resp['headers']['Query-String'],
|
||||
'var1=val1&var2=val2',
|
||||
'Query-String space 3',
|
||||
)
|
||||
assert (
|
||||
resp['headers']['Query-String'] == 'var1=val1&var2=val2'
|
||||
), 'Query-String space 3'
|
||||
|
||||
resp = self.get(url='/blah %20 blah? var1= val1 & var2=val2')
|
||||
self.assertEqual(
|
||||
resp['headers']['Query-String'],
|
||||
' var1= val1 & var2=val2',
|
||||
'Query-String space 4',
|
||||
)
|
||||
assert (
|
||||
resp['headers']['Query-String'] == ' var1= val1 & var2=val2'
|
||||
), 'Query-String space 4'
|
||||
|
||||
def test_python_application_query_string_empty(self):
|
||||
self.load('query_string')
|
||||
|
||||
resp = self.get(url='/?')
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'query string empty status')
|
||||
self.assertEqual(
|
||||
resp['headers']['Query-String'], '', 'query string empty'
|
||||
)
|
||||
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()
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'query string absent status')
|
||||
self.assertEqual(
|
||||
resp['headers']['Query-String'], '', 'query string absent'
|
||||
)
|
||||
assert resp['status'] == 200, 'query string absent status'
|
||||
assert resp['headers']['Query-String'] == '', 'query string absent'
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_python_application_server_port(self):
|
||||
self.load('server_port')
|
||||
|
||||
self.assertEqual(
|
||||
self.get()['headers']['Server-Port'], '7080', 'Server-Port header'
|
||||
)
|
||||
assert (
|
||||
self.get()['headers']['Server-Port'] == '7080'
|
||||
), 'Server-Port header'
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_python_application_working_directory_invalid(self):
|
||||
self.load('empty')
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf('"/blah"', 'applications/empty/working_directory'),
|
||||
'configure invalid working_directory',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
'"/blah"', 'applications/empty/working_directory'
|
||||
), 'configure invalid working_directory'
|
||||
|
||||
self.assertEqual(self.get()['status'], 500, 'status')
|
||||
assert self.get()['status'] == 500, 'status'
|
||||
|
||||
def test_python_application_204_transfer_encoding(self):
|
||||
self.load('204_no_content')
|
||||
|
||||
self.assertNotIn(
|
||||
'Transfer-Encoding',
|
||||
self.get()['headers'],
|
||||
'204 header transfer encoding',
|
||||
)
|
||||
assert (
|
||||
'Transfer-Encoding' not in self.get()['headers']
|
||||
), '204 header transfer encoding'
|
||||
|
||||
def test_python_application_ctx_iter_atexit(self):
|
||||
self.load('ctx_iter_atexit')
|
||||
|
@ -171,21 +146,21 @@ class TestPythonApplication(TestApplicationPython):
|
|||
body='0123456789',
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'ctx iter status')
|
||||
self.assertEqual(resp['body'], '0123456789', 'ctx iter body')
|
||||
assert resp['status'] == 200, 'ctx iter status'
|
||||
assert resp['body'] == '0123456789', 'ctx iter body'
|
||||
|
||||
self.conf({"listeners": {}, "applications": {}})
|
||||
|
||||
self.stop()
|
||||
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(r'RuntimeError'), 'ctx iter atexit'
|
||||
)
|
||||
assert (
|
||||
self.wait_for_record(r'RuntimeError') is not None
|
||||
), 'ctx iter atexit'
|
||||
|
||||
def test_python_keepalive_body(self):
|
||||
self.load('mirror')
|
||||
|
||||
self.assertEqual(self.get()['status'], 200, 'init')
|
||||
assert self.get()['status'] == 200, 'init'
|
||||
|
||||
body = '0123456789' * 500
|
||||
(resp, sock) = self.post(
|
||||
|
@ -199,7 +174,7 @@ class TestPythonApplication(TestApplicationPython):
|
|||
read_timeout=1,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['body'], body, 'keep-alive 1')
|
||||
assert resp['body'] == body, 'keep-alive 1'
|
||||
|
||||
body = '0123456789'
|
||||
resp = self.post(
|
||||
|
@ -212,19 +187,17 @@ class TestPythonApplication(TestApplicationPython):
|
|||
body=body,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['body'], body, 'keep-alive 2')
|
||||
assert resp['body'] == body, 'keep-alive 2'
|
||||
|
||||
def test_python_keepalive_reconfigure(self):
|
||||
self.skip_alerts.extend(
|
||||
[
|
||||
r'pthread_mutex.+failed',
|
||||
r'failed to apply',
|
||||
r'process \d+ exited on signal',
|
||||
]
|
||||
skip_alert(
|
||||
r'pthread_mutex.+failed',
|
||||
r'failed to apply',
|
||||
r'process \d+ exited on signal',
|
||||
)
|
||||
self.load('mirror')
|
||||
|
||||
self.assertEqual(self.get()['status'], 200, 'init')
|
||||
assert self.get()['status'] == 200, 'init'
|
||||
|
||||
body = '0123456789'
|
||||
conns = 3
|
||||
|
@ -242,12 +215,10 @@ class TestPythonApplication(TestApplicationPython):
|
|||
read_timeout=1,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['body'], body, 'keep-alive open')
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(str(i + 1), 'applications/mirror/processes'),
|
||||
'reconfigure',
|
||||
)
|
||||
assert resp['body'] == body, 'keep-alive open'
|
||||
assert 'success' in self.conf(
|
||||
str(i + 1), 'applications/mirror/processes'
|
||||
), 'reconfigure'
|
||||
|
||||
socks.append(sock)
|
||||
|
||||
|
@ -264,12 +235,10 @@ class TestPythonApplication(TestApplicationPython):
|
|||
read_timeout=1,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['body'], body, 'keep-alive request')
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(str(i + 1), 'applications/mirror/processes'),
|
||||
'reconfigure 2',
|
||||
)
|
||||
assert resp['body'] == body, 'keep-alive request'
|
||||
assert 'success' in self.conf(
|
||||
str(i + 1), 'applications/mirror/processes'
|
||||
), 'reconfigure 2'
|
||||
|
||||
for i in range(conns):
|
||||
resp = self.post(
|
||||
|
@ -282,17 +251,15 @@ class TestPythonApplication(TestApplicationPython):
|
|||
body=body,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['body'], body, 'keep-alive close')
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(str(i + 1), 'applications/mirror/processes'),
|
||||
'reconfigure 3',
|
||||
)
|
||||
assert resp['body'] == body, 'keep-alive close'
|
||||
assert 'success' in self.conf(
|
||||
str(i + 1), 'applications/mirror/processes'
|
||||
), 'reconfigure 3'
|
||||
|
||||
def test_python_keepalive_reconfigure_2(self):
|
||||
self.load('mirror')
|
||||
|
||||
self.assertEqual(self.get()['status'], 200, 'init')
|
||||
assert self.get()['status'] == 200, 'init'
|
||||
|
||||
body = '0123456789'
|
||||
|
||||
|
@ -307,11 +274,11 @@ class TestPythonApplication(TestApplicationPython):
|
|||
read_timeout=1,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['body'], body, 'reconfigure 2 keep-alive 1')
|
||||
assert resp['body'] == body, 'reconfigure 2 keep-alive 1'
|
||||
|
||||
self.load('empty')
|
||||
|
||||
self.assertEqual(self.get()['status'], 200, 'init')
|
||||
assert self.get()['status'] == 200, 'init'
|
||||
|
||||
(resp, sock) = self.post(
|
||||
headers={
|
||||
|
@ -324,23 +291,21 @@ class TestPythonApplication(TestApplicationPython):
|
|||
body=body,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'reconfigure 2 keep-alive 2')
|
||||
self.assertEqual(resp['body'], '', 'reconfigure 2 keep-alive 2 body')
|
||||
assert resp['status'] == 200, 'reconfigure 2 keep-alive 2'
|
||||
assert resp['body'] == '', 'reconfigure 2 keep-alive 2 body'
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf({"listeners": {}, "applications": {}}),
|
||||
'reconfigure 2 clear configuration',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{"listeners": {}, "applications": {}}
|
||||
), 'reconfigure 2 clear configuration'
|
||||
|
||||
resp = self.get(sock=sock)
|
||||
|
||||
self.assertEqual(resp, {}, 'reconfigure 2 keep-alive 3')
|
||||
assert resp == {}, 'reconfigure 2 keep-alive 3'
|
||||
|
||||
def test_python_keepalive_reconfigure_3(self):
|
||||
self.load('empty')
|
||||
|
||||
self.assertEqual(self.get()['status'], 200, 'init')
|
||||
assert self.get()['status'] == 200, 'init'
|
||||
|
||||
(_, sock) = self.http(
|
||||
b"""GET / HTTP/1.1
|
||||
|
@ -350,13 +315,11 @@ class TestPythonApplication(TestApplicationPython):
|
|||
no_recv=True,
|
||||
)
|
||||
|
||||
self.assertEqual(self.get()['status'], 200)
|
||||
assert self.get()['status'] == 200
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf({"listeners": {}, "applications": {}}),
|
||||
'reconfigure 3 clear configuration',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{"listeners": {}, "applications": {}}
|
||||
), 'reconfigure 3 clear configuration'
|
||||
|
||||
resp = self.http(
|
||||
b"""Host: localhost
|
||||
|
@ -367,7 +330,7 @@ Connection: close
|
|||
raw=True,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'reconfigure 3')
|
||||
assert resp['status'] == 200, 'reconfigure 3'
|
||||
|
||||
def test_python_atexit(self):
|
||||
self.load('atexit')
|
||||
|
@ -378,25 +341,24 @@ Connection: close
|
|||
|
||||
self.stop()
|
||||
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(r'At exit called\.'), 'atexit'
|
||||
)
|
||||
assert self.wait_for_record(r'At exit called\.') is not None, 'atexit'
|
||||
|
||||
def test_python_process_switch(self):
|
||||
self.load('delayed')
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf('2', 'applications/delayed/processes'),
|
||||
'configure 2 processes',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
'2', 'applications/delayed/processes'
|
||||
), 'configure 2 processes'
|
||||
|
||||
self.get(headers={
|
||||
'Host': 'localhost',
|
||||
'Content-Length': '0',
|
||||
'X-Delay': '5',
|
||||
'Connection': 'close',
|
||||
}, no_recv=True)
|
||||
self.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'Content-Length': '0',
|
||||
'X-Delay': '5',
|
||||
'Connection': 'close',
|
||||
},
|
||||
no_recv=True,
|
||||
)
|
||||
|
||||
headers_delay_1 = {
|
||||
'Connection': 'close',
|
||||
|
@ -414,11 +376,11 @@ Connection: close
|
|||
|
||||
self.get(headers=headers_delay_1)
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_python_application_start_response_exit(self):
|
||||
self.load('start_response_exit')
|
||||
|
||||
self.assertEqual(self.get()['status'], 500, 'start response exit')
|
||||
assert self.get()['status'] == 500, 'start response exit'
|
||||
|
||||
def test_python_application_input_iter(self):
|
||||
self.load('input_iter')
|
||||
|
@ -429,10 +391,8 @@ next line
|
|||
last line'''
|
||||
|
||||
resp = self.post(body=body)
|
||||
self.assertEqual(resp['body'], body, 'input iter')
|
||||
self.assertEqual(
|
||||
resp['headers']['X-Lines-Count'], '4', 'input iter lines'
|
||||
)
|
||||
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')
|
||||
|
@ -443,10 +403,8 @@ next line
|
|||
last line'''
|
||||
|
||||
resp = self.post(body=body)
|
||||
self.assertEqual(resp['body'], body, 'input readline')
|
||||
self.assertEqual(
|
||||
resp['headers']['X-Lines-Count'], '4', 'input readline lines'
|
||||
)
|
||||
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')
|
||||
|
@ -456,12 +414,10 @@ next line
|
|||
|
||||
last line'''
|
||||
|
||||
self.assertEqual(
|
||||
self.post(body=body)['body'], body, 'input readline size'
|
||||
)
|
||||
self.assertEqual(
|
||||
self.post(body='0123')['body'], '0123', 'input readline size less'
|
||||
)
|
||||
assert self.post(body=body)['body'] == body, 'input readline size'
|
||||
assert (
|
||||
self.post(body='0123')['body'] == '0123'
|
||||
), 'input readline size less'
|
||||
|
||||
def test_python_application_input_readlines(self):
|
||||
self.load('input_readlines')
|
||||
|
@ -472,10 +428,8 @@ next line
|
|||
last line'''
|
||||
|
||||
resp = self.post(body=body)
|
||||
self.assertEqual(resp['body'], body, 'input readlines')
|
||||
self.assertEqual(
|
||||
resp['headers']['X-Lines-Count'], '4', 'input readlines lines'
|
||||
)
|
||||
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')
|
||||
|
@ -489,11 +443,9 @@ last line: 987654321
|
|||
* 512
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
self.post(body=body, read_buffer_size=16384)['body'],
|
||||
body,
|
||||
'input readlines huge',
|
||||
)
|
||||
assert (
|
||||
self.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')
|
||||
|
@ -509,7 +461,7 @@ last line: 987654321
|
|||
body=body,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['body'], body[:5], 'input read length lt body')
|
||||
assert resp['body'] == body[:5], 'input read length lt body'
|
||||
|
||||
resp = self.post(
|
||||
headers={
|
||||
|
@ -520,7 +472,7 @@ last line: 987654321
|
|||
body=body,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['body'], body, 'input read length gt body')
|
||||
assert resp['body'] == body, 'input read length gt body'
|
||||
|
||||
resp = self.post(
|
||||
headers={
|
||||
|
@ -531,7 +483,7 @@ last line: 987654321
|
|||
body=body,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['body'], '', 'input read length zero')
|
||||
assert resp['body'] == '', 'input read length zero'
|
||||
|
||||
resp = self.post(
|
||||
headers={
|
||||
|
@ -542,9 +494,9 @@ last line: 987654321
|
|||
body=body,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['body'], body, 'input read length negative')
|
||||
assert resp['body'] == body, 'input read length negative'
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_python_application_errors_write(self):
|
||||
self.load('errors_write')
|
||||
|
||||
|
@ -552,43 +504,41 @@ last line: 987654321
|
|||
|
||||
self.stop()
|
||||
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(r'\[error\].+Error in application\.'),
|
||||
'errors write',
|
||||
)
|
||||
assert (
|
||||
self.wait_for_record(r'\[error\].+Error in application\.')
|
||||
is not None
|
||||
), 'errors write'
|
||||
|
||||
def test_python_application_body_array(self):
|
||||
self.load('body_array')
|
||||
|
||||
self.assertEqual(self.get()['body'], '0123456789', 'body array')
|
||||
assert self.get()['body'] == '0123456789', 'body array'
|
||||
|
||||
def test_python_application_body_io(self):
|
||||
self.load('body_io')
|
||||
|
||||
self.assertEqual(self.get()['body'], '0123456789', 'body io')
|
||||
assert self.get()['body'] == '0123456789', 'body io'
|
||||
|
||||
def test_python_application_body_io_file(self):
|
||||
self.load('body_io_file')
|
||||
|
||||
self.assertEqual(self.get()['body'], 'body\n', 'body io file')
|
||||
assert self.get()['body'] == 'body\n', 'body io file'
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_python_application_syntax_error(self):
|
||||
self.skip_alerts.append(r'Python failed to import module "wsgi"')
|
||||
skip_alert(r'Python failed to import module "wsgi"')
|
||||
self.load('syntax_error')
|
||||
|
||||
self.assertEqual(self.get()['status'], 500, 'syntax error')
|
||||
assert self.get()['status'] == 500, 'syntax error'
|
||||
|
||||
def test_python_application_loading_error(self):
|
||||
self.skip_alerts.append(r'Python failed to import module "blah"')
|
||||
skip_alert(r'Python failed to import module "blah"')
|
||||
|
||||
self.load('empty')
|
||||
|
||||
self.assertIn(
|
||||
'success', self.conf('"blah"', 'applications/empty/module'),
|
||||
)
|
||||
assert 'success' in self.conf('"blah"', 'applications/empty/module')
|
||||
|
||||
self.assertEqual(self.get()['status'], 503, 'loading error')
|
||||
assert self.get()['status'] == 503, 'loading error'
|
||||
|
||||
def test_python_application_close(self):
|
||||
self.load('close')
|
||||
|
@ -597,7 +547,7 @@ last line: 987654321
|
|||
|
||||
self.stop()
|
||||
|
||||
self.assertIsNotNone(self.wait_for_record(r'Close called\.'), 'close')
|
||||
assert self.wait_for_record(r'Close called\.') is not None, 'close'
|
||||
|
||||
def test_python_application_close_error(self):
|
||||
self.load('close_error')
|
||||
|
@ -606,9 +556,9 @@ last line: 987654321
|
|||
|
||||
self.stop()
|
||||
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(r'Close called\.'), 'close error'
|
||||
)
|
||||
assert (
|
||||
self.wait_for_record(r'Close called\.') is not None
|
||||
), 'close error'
|
||||
|
||||
def test_python_application_not_iterable(self):
|
||||
self.load('not_iterable')
|
||||
|
@ -617,17 +567,17 @@ last line: 987654321
|
|||
|
||||
self.stop()
|
||||
|
||||
self.assertIsNotNone(
|
||||
assert (
|
||||
self.wait_for_record(
|
||||
r'\[error\].+the application returned not an iterable object'
|
||||
),
|
||||
'not iterable',
|
||||
)
|
||||
)
|
||||
is not None
|
||||
), 'not iterable'
|
||||
|
||||
def test_python_application_write(self):
|
||||
self.load('write')
|
||||
|
||||
self.assertEqual(self.get()['body'], '0123456789', 'write')
|
||||
assert self.get()['body'] == '0123456789', 'write'
|
||||
|
||||
def test_python_application_threading(self):
|
||||
"""wait_for_record() timeouts after 5s while every thread works at
|
||||
|
@ -639,9 +589,9 @@ last line: 987654321
|
|||
for _ in range(10):
|
||||
self.get(no_recv=True)
|
||||
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(r'\(5\) Thread: 100'), 'last thread finished'
|
||||
)
|
||||
assert (
|
||||
self.wait_for_record(r'\(5\) Thread: 100') is not None
|
||||
), 'last thread finished'
|
||||
|
||||
def test_python_application_iter_exception(self):
|
||||
self.load('iter_exception')
|
||||
|
@ -656,43 +606,38 @@ last line: 987654321
|
|||
'Connection': 'close',
|
||||
}
|
||||
)
|
||||
self.assertEqual(resp['status'], 200, 'status')
|
||||
self.assertEqual(resp['body'], 'XXXXXXX', 'body')
|
||||
assert resp['status'] == 200, 'status'
|
||||
assert resp['body'] == 'XXXXXXX', 'body'
|
||||
|
||||
# Exception before start_response().
|
||||
|
||||
self.assertEqual(self.get()['status'], 503, 'error')
|
||||
assert self.get()['status'] == 503, 'error'
|
||||
|
||||
self.assertIsNotNone(self.wait_for_record(r'Traceback'), 'traceback')
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(r'raise Exception\(\'first exception\'\)'),
|
||||
'first exception raise',
|
||||
)
|
||||
self.assertEqual(
|
||||
len(self.findall(r'Traceback')), 1, 'traceback count 1'
|
||||
)
|
||||
assert self.wait_for_record(r'Traceback') is not None, 'traceback'
|
||||
assert (
|
||||
self.wait_for_record(r'raise Exception\(\'first exception\'\)')
|
||||
is not None
|
||||
), 'first exception raise'
|
||||
assert len(self.findall(r'Traceback')) == 1, 'traceback count 1'
|
||||
|
||||
# Exception after start_response(), before first write().
|
||||
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Skip': '1',
|
||||
'Connection': 'close',
|
||||
}
|
||||
)['status'],
|
||||
503,
|
||||
'error 2',
|
||||
)
|
||||
)['status']
|
||||
== 503
|
||||
), 'error 2'
|
||||
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(r'raise Exception\(\'second exception\'\)'),
|
||||
'exception raise second',
|
||||
)
|
||||
self.assertEqual(
|
||||
len(self.findall(r'Traceback')), 2, 'traceback count 2'
|
||||
)
|
||||
assert (
|
||||
self.wait_for_record(r'raise Exception\(\'second exception\'\)')
|
||||
is not None
|
||||
), 'exception raise second'
|
||||
assert len(self.findall(r'Traceback')) == 2, 'traceback count 2'
|
||||
|
||||
# Exception after first write(), before first __next__().
|
||||
|
||||
|
@ -705,15 +650,13 @@ last line: 987654321
|
|||
start=True,
|
||||
)
|
||||
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(r'raise Exception\(\'third exception\'\)'),
|
||||
'exception raise third',
|
||||
)
|
||||
self.assertEqual(
|
||||
len(self.findall(r'Traceback')), 3, 'traceback count 3'
|
||||
)
|
||||
assert (
|
||||
self.wait_for_record(r'raise Exception\(\'third exception\'\)')
|
||||
is not None
|
||||
), 'exception raise third'
|
||||
assert len(self.findall(r'Traceback')) == 3, 'traceback count 3'
|
||||
|
||||
self.assertDictEqual(self.get(sock=sock), {}, 'closed connection')
|
||||
assert self.get(sock=sock) == {}, 'closed connection'
|
||||
|
||||
# Exception after first write(), before first __next__(),
|
||||
# chunked (incomplete body).
|
||||
|
@ -725,13 +668,11 @@ last line: 987654321
|
|||
'X-Chunked': '1',
|
||||
'Connection': 'close',
|
||||
},
|
||||
raw_resp=True
|
||||
raw_resp=True,
|
||||
)
|
||||
if resp:
|
||||
self.assertNotEqual(resp[-5:], '0\r\n\r\n', 'incomplete body')
|
||||
self.assertEqual(
|
||||
len(self.findall(r'Traceback')), 4, 'traceback count 4'
|
||||
)
|
||||
assert resp[-5:] != '0\r\n\r\n', 'incomplete body'
|
||||
assert len(self.findall(r'Traceback')) == 4, 'traceback count 4'
|
||||
|
||||
# Exception in __next__().
|
||||
|
||||
|
@ -744,15 +685,13 @@ last line: 987654321
|
|||
start=True,
|
||||
)
|
||||
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(r'raise Exception\(\'next exception\'\)'),
|
||||
'exception raise next',
|
||||
)
|
||||
self.assertEqual(
|
||||
len(self.findall(r'Traceback')), 5, 'traceback count 5'
|
||||
)
|
||||
assert (
|
||||
self.wait_for_record(r'raise Exception\(\'next exception\'\)')
|
||||
is not None
|
||||
), 'exception raise next'
|
||||
assert len(self.findall(r'Traceback')) == 5, 'traceback count 5'
|
||||
|
||||
self.assertDictEqual(self.get(sock=sock), {}, 'closed connection 2')
|
||||
assert self.get(sock=sock) == {}, 'closed connection 2'
|
||||
|
||||
# Exception in __next__(), chunked (incomplete body).
|
||||
|
||||
|
@ -763,40 +702,34 @@ last line: 987654321
|
|||
'X-Chunked': '1',
|
||||
'Connection': 'close',
|
||||
},
|
||||
raw_resp=True
|
||||
raw_resp=True,
|
||||
)
|
||||
if resp:
|
||||
self.assertNotEqual(resp[-5:], '0\r\n\r\n', 'incomplete body 2')
|
||||
self.assertEqual(
|
||||
len(self.findall(r'Traceback')), 6, 'traceback count 6'
|
||||
)
|
||||
assert resp[-5:] != '0\r\n\r\n', 'incomplete body 2'
|
||||
assert len(self.findall(r'Traceback')) == 6, 'traceback count 6'
|
||||
|
||||
# Exception before start_response() and in close().
|
||||
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Not-Skip-Close': '1',
|
||||
'Connection': 'close',
|
||||
}
|
||||
)['status'],
|
||||
503,
|
||||
'error',
|
||||
)
|
||||
)['status']
|
||||
== 503
|
||||
), 'error'
|
||||
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(r'raise Exception\(\'close exception\'\)'),
|
||||
'exception raise close',
|
||||
)
|
||||
self.assertEqual(
|
||||
len(self.findall(r'Traceback')), 8, 'traceback count 8'
|
||||
)
|
||||
assert (
|
||||
self.wait_for_record(r'raise Exception\(\'close exception\'\)')
|
||||
is not None
|
||||
), 'exception raise close'
|
||||
assert len(self.findall(r'Traceback')) == 8, 'traceback count 8'
|
||||
|
||||
def test_python_user_group(self):
|
||||
if not self.is_su:
|
||||
print("requires root")
|
||||
raise unittest.SkipTest()
|
||||
def test_python_user_group(self, is_su):
|
||||
if not is_su:
|
||||
pytest.skip('requires root')
|
||||
|
||||
nobody_uid = pwd.getpwnam('nobody').pw_uid
|
||||
|
||||
|
@ -811,40 +744,38 @@ last line: 987654321
|
|||
self.load('user_group')
|
||||
|
||||
obj = self.getjson()['body']
|
||||
self.assertEqual(obj['UID'], nobody_uid, 'nobody uid')
|
||||
self.assertEqual(obj['GID'], group_id, 'nobody gid')
|
||||
assert obj['UID'] == nobody_uid, 'nobody uid'
|
||||
assert obj['GID'] == group_id, 'nobody gid'
|
||||
|
||||
self.load('user_group', user='nobody')
|
||||
|
||||
obj = self.getjson()['body']
|
||||
self.assertEqual(obj['UID'], nobody_uid, 'nobody uid user=nobody')
|
||||
self.assertEqual(obj['GID'], group_id, 'nobody gid user=nobody')
|
||||
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)
|
||||
|
||||
obj = self.getjson()['body']
|
||||
self.assertEqual(
|
||||
obj['UID'], nobody_uid, 'nobody uid user=nobody group=%s' % group
|
||||
assert obj['UID'] == nobody_uid, (
|
||||
'nobody uid user=nobody group=%s' % group
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
obj['GID'], group_id, 'nobody gid user=nobody group=%s' % group
|
||||
assert obj['GID'] == group_id, (
|
||||
'nobody gid user=nobody group=%s' % group
|
||||
)
|
||||
|
||||
self.load('user_group', group=group)
|
||||
|
||||
obj = self.getjson()['body']
|
||||
self.assertEqual(
|
||||
obj['UID'], nobody_uid, 'nobody uid group=%s' % group
|
||||
)
|
||||
assert obj['UID'] == nobody_uid, 'nobody uid group=%s' % group
|
||||
|
||||
self.assertEqual(obj['GID'], group_id, 'nobody gid group=%s' % group)
|
||||
assert obj['GID'] == group_id, 'nobody gid group=%s' % group
|
||||
|
||||
self.load('user_group', user='root')
|
||||
|
||||
obj = self.getjson()['body']
|
||||
self.assertEqual(obj['UID'], 0, 'root uid user=root')
|
||||
self.assertEqual(obj['GID'], 0, 'root gid user=root')
|
||||
assert obj['UID'] == 0, 'root uid user=root'
|
||||
assert obj['GID'] == 0, 'root gid user=root'
|
||||
|
||||
group = 'root'
|
||||
|
||||
|
@ -858,14 +789,11 @@ last line: 987654321
|
|||
self.load('user_group', user='root', group='root')
|
||||
|
||||
obj = self.getjson()['body']
|
||||
self.assertEqual(obj['UID'], 0, 'root uid user=root group=root')
|
||||
self.assertEqual(obj['GID'], 0, 'root gid user=root group=root')
|
||||
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')
|
||||
|
||||
obj = self.getjson()['body']
|
||||
self.assertEqual(obj['UID'], nobody_uid, 'root uid group=root')
|
||||
self.assertEqual(obj['GID'], 0, 'root gid group=root')
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestPythonApplication.main()
|
||||
assert obj['UID'] == nobody_uid, 'root uid group=root'
|
||||
assert obj['GID'] == 0, 'root gid group=root'
|
||||
|
|
|
@ -19,142 +19,104 @@ class TestPythonBasic(TestControl):
|
|||
}
|
||||
|
||||
def test_python_get_empty(self):
|
||||
self.assertEqual(self.conf_get(), {'listeners': {}, 'applications': {}})
|
||||
self.assertEqual(self.conf_get('listeners'), {})
|
||||
self.assertEqual(self.conf_get('applications'), {})
|
||||
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')
|
||||
|
||||
conf = self.conf_get()
|
||||
|
||||
self.assertEqual(conf['listeners'], {}, 'listeners')
|
||||
self.assertEqual(
|
||||
conf['applications'],
|
||||
{
|
||||
"app": {
|
||||
"type": "python",
|
||||
"processes": {"spare": 0},
|
||||
"path": "/app",
|
||||
"module": "wsgi",
|
||||
}
|
||||
},
|
||||
'applications',
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
self.conf_get('applications'),
|
||||
{
|
||||
"app": {
|
||||
"type": "python",
|
||||
"processes": {"spare": 0},
|
||||
"path": "/app",
|
||||
"module": "wsgi",
|
||||
}
|
||||
},
|
||||
'applications prefix',
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
self.conf_get('applications/app'),
|
||||
{
|
||||
assert conf['listeners'] == {}, 'listeners'
|
||||
assert conf['applications'] == {
|
||||
"app": {
|
||||
"type": "python",
|
||||
"processes": {"spare": 0},
|
||||
"path": "/app",
|
||||
"module": "wsgi",
|
||||
},
|
||||
'applications prefix 2',
|
||||
)
|
||||
}
|
||||
}, 'applications'
|
||||
|
||||
self.assertEqual(
|
||||
self.conf_get('applications/app/type'), 'python', 'type'
|
||||
)
|
||||
self.assertEqual(
|
||||
self.conf_get('applications/app/processes/spare'), 0, 'spare'
|
||||
)
|
||||
assert self.conf_get('applications') == {
|
||||
"app": {
|
||||
"type": "python",
|
||||
"processes": {"spare": 0},
|
||||
"path": "/app",
|
||||
"module": "wsgi",
|
||||
}
|
||||
}, 'applications prefix'
|
||||
|
||||
assert self.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'
|
||||
|
||||
def test_python_get_listeners(self):
|
||||
self.conf(self.conf_basic)
|
||||
|
||||
self.assertEqual(
|
||||
self.conf_get()['listeners'],
|
||||
{"*:7080": {"pass": "applications/app"}},
|
||||
'listeners',
|
||||
)
|
||||
assert self.conf_get()['listeners'] == {
|
||||
"*:7080": {"pass": "applications/app"}
|
||||
}, 'listeners'
|
||||
|
||||
self.assertEqual(
|
||||
self.conf_get('listeners'),
|
||||
{"*:7080": {"pass": "applications/app"}},
|
||||
'listeners prefix',
|
||||
)
|
||||
assert self.conf_get('listeners') == {
|
||||
"*:7080": {"pass": "applications/app"}
|
||||
}, 'listeners prefix'
|
||||
|
||||
self.assertEqual(
|
||||
self.conf_get('listeners/*:7080'),
|
||||
{"pass": "applications/app"},
|
||||
'listeners prefix 2',
|
||||
)
|
||||
assert self.conf_get('listeners/*:7080') == {
|
||||
"pass": "applications/app"
|
||||
}, 'listeners prefix 2'
|
||||
|
||||
def test_python_change_listener(self):
|
||||
self.conf(self.conf_basic)
|
||||
self.conf({"*:7081": {"pass": "applications/app"}}, 'listeners')
|
||||
|
||||
self.assertEqual(
|
||||
self.conf_get('listeners'),
|
||||
{"*:7081": {"pass": "applications/app"}},
|
||||
'change listener',
|
||||
)
|
||||
assert self.conf_get('listeners') == {
|
||||
"*:7081": {"pass": "applications/app"}
|
||||
}, 'change listener'
|
||||
|
||||
def test_python_add_listener(self):
|
||||
self.conf(self.conf_basic)
|
||||
self.conf({"pass": "applications/app"}, 'listeners/*:7082')
|
||||
|
||||
self.assertEqual(
|
||||
self.conf_get('listeners'),
|
||||
{
|
||||
"*:7080": {"pass": "applications/app"},
|
||||
"*:7082": {"pass": "applications/app"},
|
||||
},
|
||||
'add listener',
|
||||
)
|
||||
assert self.conf_get('listeners') == {
|
||||
"*:7080": {"pass": "applications/app"},
|
||||
"*:7082": {"pass": "applications/app"},
|
||||
}, 'add listener'
|
||||
|
||||
def test_python_change_application(self):
|
||||
self.conf(self.conf_basic)
|
||||
|
||||
self.conf('30', 'applications/app/processes/max')
|
||||
self.assertEqual(
|
||||
self.conf_get('applications/app/processes/max'),
|
||||
30,
|
||||
'change application max',
|
||||
)
|
||||
assert (
|
||||
self.conf_get('applications/app/processes/max') == 30
|
||||
), 'change application max'
|
||||
|
||||
self.conf('"/www"', 'applications/app/path')
|
||||
self.assertEqual(
|
||||
self.conf_get('applications/app/path'),
|
||||
'/www',
|
||||
'change application path',
|
||||
)
|
||||
assert (
|
||||
self.conf_get('applications/app/path') == '/www'
|
||||
), 'change application path'
|
||||
|
||||
def test_python_delete(self):
|
||||
self.conf(self.conf_basic)
|
||||
|
||||
self.assertIn('error', self.conf_delete('applications/app'))
|
||||
self.assertIn('success', self.conf_delete('listeners/*:7080'))
|
||||
self.assertIn('success', self.conf_delete('applications/app'))
|
||||
self.assertIn('error', self.conf_delete('applications/app'))
|
||||
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_blocks(self):
|
||||
self.conf(self.conf_basic)
|
||||
|
||||
self.assertIn('success', self.conf_delete('listeners'))
|
||||
self.assertIn('success', self.conf_delete('applications'))
|
||||
assert 'success' in self.conf_delete('listeners')
|
||||
assert 'success' in self.conf_delete('applications')
|
||||
|
||||
self.assertIn('success', self.conf(self.conf_app, 'applications'))
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf({"*:7081": {"pass": "applications/app"}}, 'listeners'),
|
||||
'applications restore',
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestPythonBasic.main()
|
||||
assert 'success' in self.conf(self.conf_app, 'applications')
|
||||
assert 'success' in self.conf(
|
||||
{"*:7081": {"pass": "applications/app"}}, 'listeners'
|
||||
), 'applications restore'
|
||||
|
|
|
@ -7,97 +7,81 @@ class TestPythonEnvironment(TestApplicationPython):
|
|||
def test_python_environment_name_null(self):
|
||||
self.load('environment')
|
||||
|
||||
self.assertIn(
|
||||
'error',
|
||||
self.conf(
|
||||
{"va\0r": "val1"}, 'applications/environment/environment'
|
||||
),
|
||||
'name null',
|
||||
)
|
||||
assert 'error' in self.conf(
|
||||
{"va\0r": "val1"}, 'applications/environment/environment'
|
||||
), 'name null'
|
||||
|
||||
def test_python_environment_name_equals(self):
|
||||
self.load('environment')
|
||||
|
||||
self.assertIn(
|
||||
'error',
|
||||
self.conf(
|
||||
{"var=": "val1"}, 'applications/environment/environment'
|
||||
),
|
||||
'name equals',
|
||||
)
|
||||
assert 'error' in self.conf(
|
||||
{"var=": "val1"}, 'applications/environment/environment'
|
||||
), 'name equals'
|
||||
|
||||
def test_python_environment_value_null(self):
|
||||
self.load('environment')
|
||||
|
||||
self.assertIn(
|
||||
'error',
|
||||
self.conf(
|
||||
{"var": "\0val"}, 'applications/environment/environment'
|
||||
),
|
||||
'value null',
|
||||
)
|
||||
assert 'error' in self.conf(
|
||||
{"var": "\0val"}, 'applications/environment/environment'
|
||||
), 'value null'
|
||||
|
||||
def test_python_environment_update(self):
|
||||
self.load('environment')
|
||||
|
||||
self.conf({"var": "val1"}, 'applications/environment/environment')
|
||||
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Variables': 'var',
|
||||
'Connection': 'close',
|
||||
}
|
||||
)['body'],
|
||||
'val1,',
|
||||
'set',
|
||||
)
|
||||
)['body']
|
||||
== 'val1,'
|
||||
), 'set'
|
||||
|
||||
self.conf({"var": "val2"}, 'applications/environment/environment')
|
||||
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Variables': 'var',
|
||||
'Connection': 'close',
|
||||
}
|
||||
)['body'],
|
||||
'val2,',
|
||||
'update',
|
||||
)
|
||||
)['body']
|
||||
== 'val2,'
|
||||
), 'update'
|
||||
|
||||
def test_python_environment_replace(self):
|
||||
self.load('environment')
|
||||
|
||||
self.conf({"var1": "val1"}, 'applications/environment/environment')
|
||||
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Variables': 'var1',
|
||||
'Connection': 'close',
|
||||
}
|
||||
)['body'],
|
||||
'val1,',
|
||||
'set',
|
||||
)
|
||||
)['body']
|
||||
== 'val1,'
|
||||
), 'set'
|
||||
|
||||
self.conf({"var2": "val2"}, 'applications/environment/environment')
|
||||
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Variables': 'var1,var2',
|
||||
'Connection': 'close',
|
||||
}
|
||||
)['body'],
|
||||
'val2,',
|
||||
'replace',
|
||||
)
|
||||
)['body']
|
||||
== 'val2,'
|
||||
), 'replace'
|
||||
|
||||
def test_python_environment_clear(self):
|
||||
self.load('environment')
|
||||
|
@ -107,31 +91,29 @@ class TestPythonEnvironment(TestApplicationPython):
|
|||
'applications/environment/environment',
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Variables': 'var1,var2',
|
||||
'Connection': 'close',
|
||||
}
|
||||
)['body'],
|
||||
'val1,val2,',
|
||||
'set',
|
||||
)
|
||||
)['body']
|
||||
== 'val1,val2,'
|
||||
), 'set'
|
||||
|
||||
self.conf({}, 'applications/environment/environment')
|
||||
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Variables': 'var1,var2',
|
||||
'Connection': 'close',
|
||||
}
|
||||
)['body'],
|
||||
'',
|
||||
'clear',
|
||||
)
|
||||
)['body']
|
||||
== ''
|
||||
), 'clear'
|
||||
|
||||
def test_python_environment_replace_default(self):
|
||||
self.load('environment')
|
||||
|
@ -144,36 +126,30 @@ class TestPythonEnvironment(TestApplicationPython):
|
|||
}
|
||||
)['body']
|
||||
|
||||
self.assertGreater(len(home_default), 1, 'get default')
|
||||
assert len(home_default) > 1, 'get default'
|
||||
|
||||
self.conf({"HOME": "/"}, 'applications/environment/environment')
|
||||
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Variables': 'HOME',
|
||||
'Connection': 'close',
|
||||
}
|
||||
)['body'],
|
||||
'/,',
|
||||
'replace default',
|
||||
)
|
||||
)['body']
|
||||
== '/,'
|
||||
), 'replace default'
|
||||
|
||||
self.conf({}, 'applications/environment/environment')
|
||||
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.get(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
'X-Variables': 'HOME',
|
||||
'Connection': 'close',
|
||||
}
|
||||
)['body'],
|
||||
home_default,
|
||||
'restore default',
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestPythonEnvironment.main()
|
||||
)['body']
|
||||
== home_default
|
||||
), 'restore default'
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import unittest
|
||||
import pytest
|
||||
|
||||
from unit.applications.lang.python import TestApplicationPython
|
||||
from unit.feature.isolation import TestFeatureIsolation
|
||||
|
@ -10,70 +10,58 @@ class TestPythonIsolation(TestApplicationPython):
|
|||
isolation = TestFeatureIsolation()
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls, complete_check=True):
|
||||
unit = super().setUpClass(complete_check=False)
|
||||
def setup_class(cls, complete_check=True):
|
||||
unit = super().setup_class(complete_check=False)
|
||||
|
||||
TestFeatureIsolation().check(cls.available, unit.testdir)
|
||||
TestFeatureIsolation().check(cls.available, unit.temp_dir)
|
||||
|
||||
return unit if not complete_check else unit.complete()
|
||||
|
||||
def test_python_isolation_rootfs(self):
|
||||
def test_python_isolation_rootfs(self, is_su):
|
||||
isolation_features = self.available['features']['isolation'].keys()
|
||||
|
||||
if 'mnt' not in isolation_features:
|
||||
print('requires mnt ns')
|
||||
raise unittest.SkipTest()
|
||||
pytest.skip('requires mnt ns')
|
||||
|
||||
if not self.is_su:
|
||||
if not is_su:
|
||||
if 'user' not in isolation_features:
|
||||
print('requires unprivileged userns or root')
|
||||
raise unittest.SkipTest()
|
||||
pytest.skip('requires unprivileged userns or root')
|
||||
|
||||
if not 'unprivileged_userns_clone' in isolation_features:
|
||||
print('requires unprivileged userns or root')
|
||||
raise unittest.SkipTest()
|
||||
pytest.skip('requires unprivileged userns or root')
|
||||
|
||||
isolation = {
|
||||
'namespaces': {'credential': not self.is_su, 'mount': True},
|
||||
'rootfs': self.testdir,
|
||||
'namespaces': {'credential': not is_su, 'mount': True},
|
||||
'rootfs': self.temp_dir,
|
||||
}
|
||||
|
||||
self.load('empty', isolation=isolation)
|
||||
|
||||
self.assertEqual(self.get()['status'], 200, 'python rootfs')
|
||||
assert self.get()['status'] == 200, 'python rootfs'
|
||||
|
||||
self.load('ns_inspect', isolation=isolation)
|
||||
|
||||
self.assertEqual(
|
||||
self.getjson(url='/?path=' + self.testdir)['body']['FileExists'],
|
||||
False,
|
||||
'testdir does not exists in rootfs',
|
||||
)
|
||||
assert (
|
||||
self.getjson(url='/?path=' + self.temp_dir)['body']['FileExists']
|
||||
== False
|
||||
), 'temp_dir does not exists in rootfs'
|
||||
|
||||
self.assertEqual(
|
||||
self.getjson(url='/?path=/proc/self')['body']['FileExists'],
|
||||
False,
|
||||
'no /proc/self',
|
||||
)
|
||||
assert (
|
||||
self.getjson(url='/?path=/proc/self')['body']['FileExists']
|
||||
== False
|
||||
), 'no /proc/self'
|
||||
|
||||
self.assertEqual(
|
||||
self.getjson(url='/?path=/dev/pts')['body']['FileExists'],
|
||||
False,
|
||||
'no /dev/pts',
|
||||
)
|
||||
assert (
|
||||
self.getjson(url='/?path=/dev/pts')['body']['FileExists'] == False
|
||||
), 'no /dev/pts'
|
||||
|
||||
self.assertEqual(
|
||||
self.getjson(url='/?path=/sys/kernel')['body']['FileExists'],
|
||||
False,
|
||||
'no /sys/kernel',
|
||||
)
|
||||
assert (
|
||||
self.getjson(url='/?path=/sys/kernel')['body']['FileExists']
|
||||
== False
|
||||
), 'no /sys/kernel'
|
||||
|
||||
ret = self.getjson(url='/?path=/app/python/ns_inspect')
|
||||
|
||||
self.assertEqual(
|
||||
ret['body']['FileExists'], True, 'application exists in rootfs',
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestPythonIsolation.main()
|
||||
assert (
|
||||
ret['body']['FileExists'] == True
|
||||
), 'application exists in rootfs'
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import unittest
|
||||
import pytest
|
||||
|
||||
from unit.applications.lang.python import TestApplicationPython
|
||||
from unit.feature.isolation import TestFeatureIsolation
|
||||
|
@ -7,51 +7,41 @@ from unit.feature.isolation import TestFeatureIsolation
|
|||
class TestPythonIsolation(TestApplicationPython):
|
||||
prerequisites = {'modules': {'python': 'any'}}
|
||||
|
||||
def test_python_isolation_chroot(self):
|
||||
if not self.is_su:
|
||||
print('requires root')
|
||||
raise unittest.SkipTest()
|
||||
def test_python_isolation_chroot(self, is_su):
|
||||
if not is_su:
|
||||
pytest.skip('requires root')
|
||||
|
||||
isolation = {
|
||||
'rootfs': self.testdir,
|
||||
'rootfs': self.temp_dir,
|
||||
}
|
||||
|
||||
self.load('empty', isolation=isolation)
|
||||
|
||||
self.assertEqual(self.get()['status'], 200, 'python chroot')
|
||||
assert self.get()['status'] == 200, 'python chroot'
|
||||
|
||||
self.load('ns_inspect', isolation=isolation)
|
||||
|
||||
self.assertEqual(
|
||||
self.getjson(url='/?path=' + self.testdir)['body']['FileExists'],
|
||||
False,
|
||||
'testdir does not exists in rootfs',
|
||||
)
|
||||
assert (
|
||||
self.getjson(url='/?path=' + self.temp_dir)['body']['FileExists']
|
||||
== False
|
||||
), 'temp_dir does not exists in rootfs'
|
||||
|
||||
self.assertEqual(
|
||||
self.getjson(url='/?path=/proc/self')['body']['FileExists'],
|
||||
False,
|
||||
'no /proc/self',
|
||||
)
|
||||
assert (
|
||||
self.getjson(url='/?path=/proc/self')['body']['FileExists']
|
||||
== False
|
||||
), 'no /proc/self'
|
||||
|
||||
self.assertEqual(
|
||||
self.getjson(url='/?path=/dev/pts')['body']['FileExists'],
|
||||
False,
|
||||
'no /dev/pts',
|
||||
)
|
||||
assert (
|
||||
self.getjson(url='/?path=/dev/pts')['body']['FileExists'] == False
|
||||
), 'no /dev/pts'
|
||||
|
||||
self.assertEqual(
|
||||
self.getjson(url='/?path=/sys/kernel')['body']['FileExists'],
|
||||
False,
|
||||
'no /sys/kernel',
|
||||
)
|
||||
assert (
|
||||
self.getjson(url='/?path=/sys/kernel')['body']['FileExists']
|
||||
== False
|
||||
), 'no /sys/kernel'
|
||||
|
||||
ret = self.getjson(url='/?path=/app/python/ns_inspect')
|
||||
|
||||
self.assertEqual(
|
||||
ret['body']['FileExists'], True, 'application exists in rootfs',
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestPythonIsolation.main()
|
||||
assert (
|
||||
ret['body']['FileExists'] == True
|
||||
), 'application exists in rootfs'
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import pytest
|
||||
import re
|
||||
import subprocess
|
||||
import time
|
||||
import unittest
|
||||
|
||||
from unit.applications.lang.python import TestApplicationPython
|
||||
|
||||
|
@ -9,10 +9,10 @@ from unit.applications.lang.python import TestApplicationPython
|
|||
class TestPythonProcman(TestApplicationPython):
|
||||
prerequisites = {'modules': {'python': 'any'}}
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
def setup_method(self):
|
||||
super().setup_method()
|
||||
|
||||
self.app_name = "app-" + self.testdir.split('/')[-1]
|
||||
self.app_name = "app-" + self.temp_dir.split('/')[-1]
|
||||
self.app_proc = 'applications/' + self.app_name + '/processes'
|
||||
self.load('empty', self.app_name)
|
||||
|
||||
|
@ -23,7 +23,7 @@ class TestPythonProcman(TestApplicationPython):
|
|||
|
||||
pids = set()
|
||||
for m in re.findall('.*' + self.app_name, output.decode()):
|
||||
pids.add(re.search('^\s*(\d+)', m).group(1))
|
||||
pids.add(re.search(r'^\s*(\d+)', m).group(1))
|
||||
|
||||
return pids
|
||||
|
||||
|
@ -31,35 +31,35 @@ class TestPythonProcman(TestApplicationPython):
|
|||
if path is None:
|
||||
path = self.app_proc
|
||||
|
||||
self.assertIn('success', self.conf(conf, path), 'configure processes')
|
||||
assert 'success' in self.conf(conf, path), 'configure processes'
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_python_processes_idle_timeout_zero(self):
|
||||
self.conf_proc({"spare": 0, "max": 2, "idle_timeout": 0})
|
||||
|
||||
self.get()
|
||||
self.assertEqual(len(self.pids_for_process()), 0, 'idle timeout 0')
|
||||
assert len(self.pids_for_process()) == 0, 'idle timeout 0'
|
||||
|
||||
def test_python_prefork(self):
|
||||
self.conf_proc('2')
|
||||
|
||||
pids = self.pids_for_process()
|
||||
self.assertEqual(len(pids), 2, 'prefork 2')
|
||||
assert len(pids) == 2, 'prefork 2'
|
||||
|
||||
self.get()
|
||||
self.assertSetEqual(self.pids_for_process(), pids, 'prefork still 2')
|
||||
assert self.pids_for_process() == pids, 'prefork still 2'
|
||||
|
||||
self.conf_proc('4')
|
||||
|
||||
pids = self.pids_for_process()
|
||||
self.assertEqual(len(pids), 4, 'prefork 4')
|
||||
assert len(pids) == 4, 'prefork 4'
|
||||
|
||||
self.get()
|
||||
self.assertSetEqual(self.pids_for_process(), pids, 'prefork still 4')
|
||||
assert self.pids_for_process() == pids, 'prefork still 4'
|
||||
|
||||
self.stop_all()
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_python_prefork_same_processes(self):
|
||||
self.conf_proc('2')
|
||||
pids = self.pids_for_process()
|
||||
|
@ -67,25 +67,23 @@ class TestPythonProcman(TestApplicationPython):
|
|||
self.conf_proc('4')
|
||||
pids_new = self.pids_for_process()
|
||||
|
||||
self.assertTrue(pids.issubset(pids_new), 'prefork same processes')
|
||||
assert pids.issubset(pids_new), 'prefork same processes'
|
||||
|
||||
def test_python_ondemand(self):
|
||||
self.conf_proc({"spare": 0, "max": 8, "idle_timeout": 1})
|
||||
|
||||
self.assertEqual(len(self.pids_for_process()), 0, 'on-demand 0')
|
||||
assert len(self.pids_for_process()) == 0, 'on-demand 0'
|
||||
|
||||
self.get()
|
||||
pids = self.pids_for_process()
|
||||
self.assertEqual(len(pids), 1, 'on-demand 1')
|
||||
assert len(pids) == 1, 'on-demand 1'
|
||||
|
||||
self.get()
|
||||
self.assertSetEqual(self.pids_for_process(), pids, 'on-demand still 1')
|
||||
assert self.pids_for_process() == pids, 'on-demand still 1'
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
self.assertEqual(
|
||||
len(self.pids_for_process()), 0, 'on-demand stop idle'
|
||||
)
|
||||
assert len(self.pids_for_process()) == 0, 'on-demand stop idle'
|
||||
|
||||
self.stop_all()
|
||||
|
||||
|
@ -93,27 +91,25 @@ class TestPythonProcman(TestApplicationPython):
|
|||
self.conf_proc({"spare": 2, "max": 8, "idle_timeout": 1})
|
||||
|
||||
pids = self.pids_for_process()
|
||||
self.assertEqual(len(pids), 2, 'updown 2')
|
||||
assert len(pids) == 2, 'updown 2'
|
||||
|
||||
self.get()
|
||||
pids_new = self.pids_for_process()
|
||||
self.assertEqual(len(pids_new), 3, 'updown 3')
|
||||
self.assertTrue(pids.issubset(pids_new), 'updown 3 only 1 new')
|
||||
assert len(pids_new) == 3, 'updown 3'
|
||||
assert pids.issubset(pids_new), 'updown 3 only 1 new'
|
||||
|
||||
self.get()
|
||||
self.assertSetEqual(
|
||||
self.pids_for_process(), pids_new, 'updown still 3'
|
||||
)
|
||||
assert self.pids_for_process() == pids_new, 'updown still 3'
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
pids = self.pids_for_process()
|
||||
self.assertEqual(len(pids), 2, 'updown stop idle')
|
||||
assert len(pids) == 2, 'updown stop idle'
|
||||
|
||||
self.get()
|
||||
pids_new = self.pids_for_process()
|
||||
self.assertEqual(len(pids_new), 3, 'updown again 3')
|
||||
self.assertTrue(pids.issubset(pids_new), 'updown again 3 only 1 new')
|
||||
assert len(pids_new) == 3, 'updown again 3'
|
||||
assert pids.issubset(pids_new), 'updown again 3 only 1 new'
|
||||
|
||||
self.stop_all()
|
||||
|
||||
|
@ -121,20 +117,20 @@ class TestPythonProcman(TestApplicationPython):
|
|||
self.conf_proc({"spare": 2, "max": 6, "idle_timeout": 1})
|
||||
|
||||
pids = self.pids_for_process()
|
||||
self.assertEqual(len(pids), 2, 'reconf 2')
|
||||
assert len(pids) == 2, 'reconf 2'
|
||||
|
||||
self.get()
|
||||
pids_new = self.pids_for_process()
|
||||
self.assertEqual(len(pids_new), 3, 'reconf 3')
|
||||
self.assertTrue(pids.issubset(pids_new), 'reconf 3 only 1 new')
|
||||
assert len(pids_new) == 3, 'reconf 3'
|
||||
assert pids.issubset(pids_new), 'reconf 3 only 1 new'
|
||||
|
||||
self.conf_proc('6', self.app_proc + '/spare')
|
||||
|
||||
pids = self.pids_for_process()
|
||||
self.assertEqual(len(pids), 6, 'reconf 6')
|
||||
assert len(pids) == 6, 'reconf 6'
|
||||
|
||||
self.get()
|
||||
self.assertSetEqual(self.pids_for_process(), pids, 'reconf still 6')
|
||||
assert self.pids_for_process() == pids, 'reconf still 6'
|
||||
|
||||
self.stop_all()
|
||||
|
||||
|
@ -143,7 +139,7 @@ class TestPythonProcman(TestApplicationPython):
|
|||
|
||||
self.get()
|
||||
pids = self.pids_for_process()
|
||||
self.assertEqual(len(pids), 1, 'idle timeout 1')
|
||||
assert len(pids) == 1, 'idle timeout 1'
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
|
@ -152,14 +148,12 @@ class TestPythonProcman(TestApplicationPython):
|
|||
time.sleep(1)
|
||||
|
||||
pids_new = self.pids_for_process()
|
||||
self.assertEqual(len(pids_new), 1, 'idle timeout still 1')
|
||||
self.assertSetEqual(
|
||||
self.pids_for_process(), pids, 'idle timeout still 1 same pid'
|
||||
)
|
||||
assert len(pids_new) == 1, 'idle timeout still 1'
|
||||
assert self.pids_for_process() == pids, 'idle timeout still 1 same pid'
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
self.assertEqual(len(self.pids_for_process()), 0, 'idle timed out')
|
||||
assert len(self.pids_for_process()) == 0, 'idle timed out'
|
||||
|
||||
def test_python_processes_connection_keepalive(self):
|
||||
self.conf_proc({"spare": 0, "max": 6, "idle_timeout": 2})
|
||||
|
@ -169,15 +163,11 @@ class TestPythonProcman(TestApplicationPython):
|
|||
start=True,
|
||||
read_timeout=1,
|
||||
)
|
||||
self.assertEqual(
|
||||
len(self.pids_for_process()), 1, 'keepalive connection 1'
|
||||
)
|
||||
assert len(self.pids_for_process()) == 1, 'keepalive connection 1'
|
||||
|
||||
time.sleep(2)
|
||||
|
||||
self.assertEqual(
|
||||
len(self.pids_for_process()), 0, 'keepalive connection 0'
|
||||
)
|
||||
assert len(self.pids_for_process()) == 0, 'keepalive connection 0'
|
||||
|
||||
sock.close()
|
||||
|
||||
|
@ -185,43 +175,29 @@ class TestPythonProcman(TestApplicationPython):
|
|||
self.conf_proc('1')
|
||||
|
||||
path = '/' + self.app_proc
|
||||
self.assertIn('error', self.conf_get(path + '/max'))
|
||||
self.assertIn('error', self.conf_get(path + '/spare'))
|
||||
self.assertIn('error', self.conf_get(path + '/idle_timeout'))
|
||||
assert 'error' in self.conf_get(path + '/max')
|
||||
assert 'error' in self.conf_get(path + '/spare')
|
||||
assert 'error' in self.conf_get(path + '/idle_timeout')
|
||||
|
||||
def test_python_processes_invalid(self):
|
||||
self.assertIn(
|
||||
'error', self.conf({"spare": -1}, self.app_proc), 'negative spare',
|
||||
)
|
||||
self.assertIn(
|
||||
'error', self.conf({"max": -1}, self.app_proc), 'negative max',
|
||||
)
|
||||
self.assertIn(
|
||||
'error',
|
||||
self.conf({"idle_timeout": -1}, self.app_proc),
|
||||
'negative idle_timeout',
|
||||
)
|
||||
self.assertIn(
|
||||
'error',
|
||||
self.conf({"spare": 2}, self.app_proc),
|
||||
'spare gt max default',
|
||||
)
|
||||
self.assertIn(
|
||||
'error',
|
||||
self.conf({"spare": 2, "max": 1}, self.app_proc),
|
||||
'spare gt max',
|
||||
)
|
||||
self.assertIn(
|
||||
'error',
|
||||
self.conf({"spare": 0, "max": 0}, self.app_proc),
|
||||
'max zero',
|
||||
)
|
||||
assert 'error' in self.conf(
|
||||
{"spare": -1}, self.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
|
||||
), 'negative idle_timeout'
|
||||
assert 'error' in self.conf(
|
||||
{"spare": 2}, self.app_proc
|
||||
), 'spare gt max default'
|
||||
assert 'error' in self.conf(
|
||||
{"spare": 2, "max": 1}, self.app_proc
|
||||
), 'spare gt max'
|
||||
assert 'error' in self.conf(
|
||||
{"spare": 0, "max": 0}, self.app_proc
|
||||
), 'max zero'
|
||||
|
||||
def stop_all(self):
|
||||
self.conf({"listeners": {}, "applications": {}})
|
||||
|
||||
self.assertEqual(len(self.pids_for_process()), 0, 'stop all')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestPythonProcman.main()
|
||||
assert len(self.pids_for_process()) == 0, 'stop all'
|
||||
|
|
|
@ -3,6 +3,7 @@ import subprocess
|
|||
import time
|
||||
|
||||
from unit.applications.lang.python import TestApplicationPython
|
||||
from conftest import skip_alert
|
||||
|
||||
|
||||
class TestRespawn(TestApplicationPython):
|
||||
|
@ -11,21 +12,20 @@ class TestRespawn(TestApplicationPython):
|
|||
PATTERN_ROUTER = 'unit: router'
|
||||
PATTERN_CONTROLLER = 'unit: controller'
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
def setup_method(self):
|
||||
super().setup_method()
|
||||
|
||||
self.app_name = "app-" + self.testdir.split('/')[-1]
|
||||
self.app_name = "app-" + self.temp_dir.split('/')[-1]
|
||||
|
||||
self.load('empty', self.app_name)
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf('1', 'applications/' + self.app_name + '/processes')
|
||||
assert 'success' in self.conf(
|
||||
'1', 'applications/' + self.app_name + '/processes'
|
||||
)
|
||||
|
||||
def pid_by_name(self, name):
|
||||
output = subprocess.check_output(['ps', 'ax']).decode()
|
||||
m = re.search('\s*(\d+).*' + name, output)
|
||||
m = re.search(r'\s*(\d+).*' + name, output)
|
||||
return m if m is None else m.group(1)
|
||||
|
||||
def kill_pids(self, *pids):
|
||||
|
@ -44,27 +44,26 @@ class TestRespawn(TestApplicationPython):
|
|||
|
||||
def smoke_test(self):
|
||||
for _ in range(5):
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf('1', 'applications/' + self.app_name + '/processes')
|
||||
assert 'success' in self.conf(
|
||||
'1', 'applications/' + self.app_name + '/processes'
|
||||
)
|
||||
self.assertEqual(self.get()['status'], 200)
|
||||
assert self.get()['status'] == 200
|
||||
|
||||
# Check if the only one router, controller,
|
||||
# and application processes running.
|
||||
|
||||
output = subprocess.check_output(['ps', 'ax']).decode()
|
||||
self.assertEqual(len(re.findall(self.PATTERN_ROUTER, output)), 1)
|
||||
self.assertEqual(len(re.findall(self.PATTERN_CONTROLLER, output)), 1)
|
||||
self.assertEqual(len(re.findall(self.app_name, output)), 1)
|
||||
assert len(re.findall(self.PATTERN_ROUTER, output)) == 1
|
||||
assert len(re.findall(self.PATTERN_CONTROLLER, output)) == 1
|
||||
assert len(re.findall(self.app_name, output)) == 1
|
||||
|
||||
def test_respawn_router(self):
|
||||
pid = self.pid_by_name(self.PATTERN_ROUTER)
|
||||
|
||||
self.kill_pids(pid)
|
||||
self.skip_alerts.append(r'process %s exited on signal 9' % pid)
|
||||
skip_alert(r'process %s exited on signal 9' % pid)
|
||||
|
||||
self.assertIsNotNone(self.wait_for_process(self.PATTERN_ROUTER))
|
||||
assert self.wait_for_process(self.PATTERN_ROUTER) is not None
|
||||
|
||||
self.smoke_test()
|
||||
|
||||
|
@ -72,11 +71,11 @@ class TestRespawn(TestApplicationPython):
|
|||
pid = self.pid_by_name(self.PATTERN_CONTROLLER)
|
||||
|
||||
self.kill_pids(pid)
|
||||
self.skip_alerts.append(r'process %s exited on signal 9' % pid)
|
||||
skip_alert(r'process %s exited on signal 9' % pid)
|
||||
|
||||
self.assertIsNotNone(self.wait_for_process(self.PATTERN_CONTROLLER))
|
||||
assert self.wait_for_process(self.PATTERN_CONTROLLER) is not None
|
||||
|
||||
self.assertEqual(self.get()['status'], 200)
|
||||
assert self.get()['status'] == 200
|
||||
|
||||
self.smoke_test()
|
||||
|
||||
|
@ -84,12 +83,8 @@ class TestRespawn(TestApplicationPython):
|
|||
pid = self.pid_by_name(self.app_name)
|
||||
|
||||
self.kill_pids(pid)
|
||||
self.skip_alerts.append(r'process %s exited on signal 9' % pid)
|
||||
skip_alert(r'process %s exited on signal 9' % pid)
|
||||
|
||||
self.assertIsNotNone(self.wait_for_process(self.app_name))
|
||||
assert self.wait_for_process(self.app_name) is not None
|
||||
|
||||
self.smoke_test()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestRespawn.main()
|
||||
|
|
|
@ -6,8 +6,8 @@ from unit.applications.proto import TestApplicationProto
|
|||
class TestReturn(TestApplicationProto):
|
||||
prerequisites = {}
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
def setup_method(self):
|
||||
super().setup_method()
|
||||
|
||||
self._load_conf(
|
||||
{
|
||||
|
@ -35,59 +35,61 @@ Connection: close
|
|||
|
||||
def test_return(self):
|
||||
resp = self.get()
|
||||
self.assertEqual(resp['status'], 200)
|
||||
self.assertIn('Server', resp['headers'])
|
||||
self.assertIn('Date', resp['headers'])
|
||||
self.assertEqual(resp['headers']['Content-Length'], '0')
|
||||
self.assertEqual(resp['headers']['Connection'], 'close')
|
||||
self.assertEqual(resp['body'], '', 'body')
|
||||
assert resp['status'] == 200
|
||||
assert 'Server' in resp['headers']
|
||||
assert 'Date' in resp['headers']
|
||||
assert resp['headers']['Content-Length'] == '0'
|
||||
assert resp['headers']['Connection'] == 'close'
|
||||
assert resp['body'] == '', 'body'
|
||||
|
||||
resp = self.post(body='blah')
|
||||
self.assertEqual(resp['status'], 200)
|
||||
self.assertEqual(resp['body'], '', 'body')
|
||||
assert resp['status'] == 200
|
||||
assert resp['body'] == '', 'body'
|
||||
|
||||
resp = self.get_resps_sc()
|
||||
self.assertEqual(len(re.findall('200 OK', resp)), 10)
|
||||
self.assertEqual(len(re.findall('Connection:', resp)), 1)
|
||||
self.assertEqual(len(re.findall('Connection: close', resp)), 1)
|
||||
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)
|
||||
self.assertEqual(resp['status'], 200)
|
||||
self.assertIn('Server', resp['headers'])
|
||||
self.assertIn('Date', resp['headers'])
|
||||
self.assertEqual(resp['headers']['Content-Length'], '0')
|
||||
self.assertNotIn('Connection', resp['headers'])
|
||||
self.assertEqual(resp['body'], '', 'body')
|
||||
assert resp['status'] == 200
|
||||
assert 'Server' in resp['headers']
|
||||
assert 'Date' in resp['headers']
|
||||
assert resp['headers']['Content-Length'] == '0'
|
||||
assert 'Connection' not in resp['headers']
|
||||
assert resp['body'] == '', 'body'
|
||||
|
||||
def test_return_update(self):
|
||||
self.assertIn('success', self.conf('0', 'routes/0/action/return'))
|
||||
assert 'success' in self.conf('0', 'routes/0/action/return')
|
||||
|
||||
resp = self.get()
|
||||
self.assertEqual(resp['status'], 0)
|
||||
self.assertEqual(resp['body'], '')
|
||||
assert resp['status'] == 0
|
||||
assert resp['body'] == ''
|
||||
|
||||
self.assertIn('success', self.conf('404', 'routes/0/action/return'))
|
||||
assert 'success' in self.conf('404', 'routes/0/action/return')
|
||||
|
||||
resp = self.get()
|
||||
self.assertEqual(resp['status'], 404)
|
||||
self.assertNotEqual(resp['body'], '')
|
||||
assert resp['status'] == 404
|
||||
assert resp['body'] != ''
|
||||
|
||||
self.assertIn('success', self.conf('598', 'routes/0/action/return'))
|
||||
assert 'success' in self.conf('598', 'routes/0/action/return')
|
||||
|
||||
resp = self.get()
|
||||
self.assertEqual(resp['status'], 598)
|
||||
self.assertNotEqual(resp['body'], '')
|
||||
assert resp['status'] == 598
|
||||
assert resp['body'] != ''
|
||||
|
||||
self.assertIn('success', self.conf('999', 'routes/0/action/return'))
|
||||
assert 'success' in self.conf('999', 'routes/0/action/return')
|
||||
|
||||
resp = self.get()
|
||||
self.assertEqual(resp['status'], 999)
|
||||
self.assertEqual(resp['body'], '')
|
||||
assert resp['status'] == 999
|
||||
assert resp['body'] == ''
|
||||
|
||||
def test_return_location(self):
|
||||
reserved = ":/?#[]@!$&'()*+,;="
|
||||
unreserved = ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789-._~")
|
||||
unreserved = (
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789-._~"
|
||||
)
|
||||
unsafe = " \"%<>\\^`{|}"
|
||||
unsafe_enc = "%20%22%25%3C%3E%5C%5E%60%7B%7C%7D"
|
||||
|
||||
|
@ -95,15 +97,11 @@ Connection: close
|
|||
if expect is None:
|
||||
expect = location
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{"return": 301, "location": location}, 'routes/0/action'
|
||||
),
|
||||
'configure location'
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{"return": 301, "location": location}, 'routes/0/action'
|
||||
), 'configure location'
|
||||
|
||||
self.assertEqual(self.get()['headers']['Location'], expect)
|
||||
assert self.get()['headers']['Location'] == expect
|
||||
|
||||
# FAIL: can't specify empty header value.
|
||||
# check_location("")
|
||||
|
@ -145,39 +143,29 @@ Connection: close
|
|||
check_location("/%20?%20#%20 ", "/%2520?%2520#%2520%20")
|
||||
|
||||
def test_return_location_edit(self):
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{"return": 302, "location": "blah"}, 'routes/0/action'
|
||||
),
|
||||
'configure init location'
|
||||
)
|
||||
self.assertEqual(self.get()['headers']['Location'], 'blah')
|
||||
assert 'success' in self.conf(
|
||||
{"return": 302, "location": "blah"}, 'routes/0/action'
|
||||
), 'configure init location'
|
||||
assert self.get()['headers']['Location'] == 'blah'
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf_delete('routes/0/action/location'),
|
||||
'location delete'
|
||||
)
|
||||
self.assertNotIn('Location', self.get()['headers'])
|
||||
assert 'success' in self.conf_delete(
|
||||
'routes/0/action/location'
|
||||
), 'location delete'
|
||||
assert 'Location' not in self.get()['headers']
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf('"blah"', 'routes/0/action/location'),
|
||||
'location restore'
|
||||
)
|
||||
self.assertEqual(self.get()['headers']['Location'], 'blah')
|
||||
assert 'success' in self.conf(
|
||||
'"blah"', 'routes/0/action/location'
|
||||
), 'location restore'
|
||||
assert self.get()['headers']['Location'] == 'blah'
|
||||
|
||||
self.assertIn(
|
||||
'error',
|
||||
self.conf_post('"blah"', 'routes/0/action/location'),
|
||||
'location method not allowed'
|
||||
)
|
||||
self.assertEqual(self.get()['headers']['Location'], 'blah')
|
||||
assert 'error' in self.conf_post(
|
||||
'"blah"', 'routes/0/action/location'
|
||||
), 'location method not allowed'
|
||||
assert self.get()['headers']['Location'] == 'blah'
|
||||
|
||||
def test_return_invalid(self):
|
||||
def check_error(conf):
|
||||
self.assertIn('error', self.conf(conf, 'routes/0/action'))
|
||||
assert 'error' in self.conf(conf, 'routes/0/action')
|
||||
|
||||
check_error({"return": "200"})
|
||||
check_error({"return": []})
|
||||
|
@ -186,13 +174,9 @@ Connection: close
|
|||
check_error({"return": -1})
|
||||
check_error({"return": 200, "share": "/blah"})
|
||||
|
||||
self.assertIn(
|
||||
'error', self.conf('001', 'routes/0/action/return'), 'leading zero'
|
||||
)
|
||||
assert 'error' in self.conf(
|
||||
'001', 'routes/0/action/return'
|
||||
), 'leading zero'
|
||||
|
||||
check_error({"return": 301, "location": 0})
|
||||
check_error({"return": 301, "location": []})
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestReturn.main()
|
||||
|
|
1825
test/test_routing.py
1825
test/test_routing.py
File diff suppressed because it is too large
Load diff
|
@ -7,36 +7,22 @@ class TestRoutingTLS(TestApplicationTLS):
|
|||
def test_routes_match_scheme_tls(self):
|
||||
self.certificate()
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"*:7080": {"pass": "routes"},
|
||||
"*:7081": {
|
||||
"pass": "routes",
|
||||
"tls": {"certificate": 'default'},
|
||||
},
|
||||
assert 'success' in self.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"*:7080": {"pass": "routes"},
|
||||
"*:7081": {
|
||||
"pass": "routes",
|
||||
"tls": {"certificate": 'default'},
|
||||
},
|
||||
"routes": [
|
||||
{
|
||||
"match": {"scheme": "http"},
|
||||
"action": {"return": 200},
|
||||
},
|
||||
{
|
||||
"match": {"scheme": "https"},
|
||||
"action": {"return": 201},
|
||||
},
|
||||
],
|
||||
"applications": {},
|
||||
}
|
||||
),
|
||||
'scheme configure',
|
||||
)
|
||||
},
|
||||
"routes": [
|
||||
{"match": {"scheme": "http"}, "action": {"return": 200}},
|
||||
{"match": {"scheme": "https"}, "action": {"return": 201}},
|
||||
],
|
||||
"applications": {},
|
||||
}
|
||||
), 'scheme configure'
|
||||
|
||||
self.assertEqual(self.get()['status'], 200, 'http')
|
||||
self.assertEqual(self.get_ssl(port=7081)['status'], 201, 'https')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestRoutingTLS.main()
|
||||
assert self.get()['status'] == 200, 'http'
|
||||
assert self.get_ssl(port=7081)['status'] == 201, 'https'
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import unittest
|
||||
import pytest
|
||||
import re
|
||||
|
||||
from unit.applications.lang.ruby import TestApplicationRuby
|
||||
from conftest import skip_alert
|
||||
|
||||
|
||||
class TestRubyApplication(TestApplicationRuby):
|
||||
|
@ -21,173 +23,151 @@ class TestRubyApplication(TestApplicationRuby):
|
|||
body=body,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'status')
|
||||
assert resp['status'] == 200, 'status'
|
||||
headers = resp['headers']
|
||||
header_server = headers.pop('Server')
|
||||
self.assertRegex(header_server, r'Unit/[\d\.]+', 'server header')
|
||||
self.assertEqual(
|
||||
headers.pop('Server-Software'),
|
||||
header_server,
|
||||
'server software header',
|
||||
)
|
||||
assert re.search(r'Unit/[\d\.]+', header_server), 'server header'
|
||||
assert (
|
||||
headers.pop('Server-Software') == header_server
|
||||
), 'server software header'
|
||||
|
||||
date = headers.pop('Date')
|
||||
self.assertEqual(date[-4:], ' GMT', 'date header timezone')
|
||||
self.assertLess(
|
||||
abs(self.date_to_sec_epoch(date) - self.sec_epoch()),
|
||||
5,
|
||||
'date header',
|
||||
)
|
||||
assert date[-4:] == ' GMT', 'date header timezone'
|
||||
assert (
|
||||
abs(self.date_to_sec_epoch(date) - self.sec_epoch()) < 5
|
||||
), 'date header'
|
||||
|
||||
self.assertDictEqual(
|
||||
headers,
|
||||
{
|
||||
'Connection': 'close',
|
||||
'Content-Length': str(len(body)),
|
||||
'Content-Type': 'text/html',
|
||||
'Request-Method': 'POST',
|
||||
'Request-Uri': '/',
|
||||
'Http-Host': 'localhost',
|
||||
'Server-Protocol': 'HTTP/1.1',
|
||||
'Custom-Header': 'blah',
|
||||
'Rack-Version': '13',
|
||||
'Rack-Url-Scheme': 'http',
|
||||
'Rack-Multithread': 'false',
|
||||
'Rack-Multiprocess': 'true',
|
||||
'Rack-Run-Once': 'false',
|
||||
'Rack-Hijack-Q': 'false',
|
||||
'Rack-Hijack': '',
|
||||
'Rack-Hijack-IO': '',
|
||||
},
|
||||
'headers',
|
||||
)
|
||||
self.assertEqual(resp['body'], body, 'body')
|
||||
assert headers == {
|
||||
'Connection': 'close',
|
||||
'Content-Length': str(len(body)),
|
||||
'Content-Type': 'text/html',
|
||||
'Request-Method': 'POST',
|
||||
'Request-Uri': '/',
|
||||
'Http-Host': 'localhost',
|
||||
'Server-Protocol': 'HTTP/1.1',
|
||||
'Custom-Header': 'blah',
|
||||
'Rack-Version': '13',
|
||||
'Rack-Url-Scheme': 'http',
|
||||
'Rack-Multithread': 'false',
|
||||
'Rack-Multiprocess': 'true',
|
||||
'Rack-Run-Once': 'false',
|
||||
'Rack-Hijack-Q': 'false',
|
||||
'Rack-Hijack': '',
|
||||
'Rack-Hijack-IO': '',
|
||||
}, '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')
|
||||
|
||||
self.assertEqual(
|
||||
resp['headers']['Query-String'],
|
||||
'var1=val1&var2=val2',
|
||||
'Query-String header',
|
||||
)
|
||||
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='/?')
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'query string empty status')
|
||||
self.assertEqual(
|
||||
resp['headers']['Query-String'], '', 'query string empty'
|
||||
)
|
||||
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()
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'query string absent status')
|
||||
self.assertEqual(
|
||||
resp['headers']['Query-String'], '', 'query string absent'
|
||||
)
|
||||
assert resp['status'] == 200, 'query string absent status'
|
||||
assert resp['headers']['Query-String'] == '', 'query string absent'
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_ruby_application_server_port(self):
|
||||
self.load('server_port')
|
||||
|
||||
self.assertEqual(
|
||||
self.get()['headers']['Server-Port'], '7080', 'Server-Port header'
|
||||
)
|
||||
assert (
|
||||
self.get()['headers']['Server-Port'] == '7080'
|
||||
), 'Server-Port header'
|
||||
|
||||
def test_ruby_application_status_int(self):
|
||||
self.load('status_int')
|
||||
|
||||
self.assertEqual(self.get()['status'], 200, 'status int')
|
||||
assert self.get()['status'] == 200, 'status int'
|
||||
|
||||
def test_ruby_application_input_read_empty(self):
|
||||
self.load('input_read_empty')
|
||||
|
||||
self.assertEqual(self.get()['body'], '', 'read empty')
|
||||
assert self.get()['body'] == '', 'read empty'
|
||||
|
||||
def test_ruby_application_input_read_parts(self):
|
||||
self.load('input_read_parts')
|
||||
|
||||
self.assertEqual(
|
||||
self.post(body='0123456789')['body'],
|
||||
'012345678',
|
||||
'input read parts',
|
||||
)
|
||||
assert (
|
||||
self.post(body='0123456789')['body'] == '012345678'
|
||||
), 'input read parts'
|
||||
|
||||
def test_ruby_application_input_read_buffer(self):
|
||||
self.load('input_read_buffer')
|
||||
|
||||
self.assertEqual(
|
||||
self.post(body='0123456789')['body'],
|
||||
'0123456789',
|
||||
'input read buffer',
|
||||
)
|
||||
assert (
|
||||
self.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')
|
||||
|
||||
self.assertEqual(
|
||||
self.post(body='0123456789')['body'],
|
||||
'0123456789',
|
||||
'input read buffer not empty',
|
||||
)
|
||||
assert (
|
||||
self.post(body='0123456789')['body'] == '0123456789'
|
||||
), 'input read buffer not empty'
|
||||
|
||||
def test_ruby_application_input_gets(self):
|
||||
self.load('input_gets')
|
||||
|
||||
body = '0123456789'
|
||||
|
||||
self.assertEqual(self.post(body=body)['body'], body, 'input gets')
|
||||
assert self.post(body=body)['body'] == body, 'input gets'
|
||||
|
||||
def test_ruby_application_input_gets_2(self):
|
||||
self.load('input_gets')
|
||||
|
||||
self.assertEqual(
|
||||
self.post(body='01234\n56789\n')['body'], '01234\n', 'input gets 2'
|
||||
)
|
||||
assert (
|
||||
self.post(body='01234\n56789\n')['body'] == '01234\n'
|
||||
), 'input gets 2'
|
||||
|
||||
def test_ruby_application_input_gets_all(self):
|
||||
self.load('input_gets_all')
|
||||
|
||||
body = '\n01234\n56789\n\n'
|
||||
|
||||
self.assertEqual(self.post(body=body)['body'], body, 'input gets all')
|
||||
assert self.post(body=body)['body'] == body, 'input gets all'
|
||||
|
||||
def test_ruby_application_input_each(self):
|
||||
self.load('input_each')
|
||||
|
||||
body = '\n01234\n56789\n\n'
|
||||
|
||||
self.assertEqual(self.post(body=body)['body'], body, 'input each')
|
||||
assert self.post(body=body)['body'] == body, 'input each'
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_ruby_application_input_rewind(self):
|
||||
self.load('input_rewind')
|
||||
|
||||
body = '0123456789'
|
||||
|
||||
self.assertEqual(self.post(body=body)['body'], body, 'input rewind')
|
||||
assert self.post(body=body)['body'] == body, 'input rewind'
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_ruby_application_syntax_error(self):
|
||||
self.skip_alerts.extend(
|
||||
[
|
||||
r'Failed to parse rack script',
|
||||
r'syntax error',
|
||||
r'new_from_string',
|
||||
r'parse_file',
|
||||
]
|
||||
skip_alert(
|
||||
r'Failed to parse rack script',
|
||||
r'syntax error',
|
||||
r'new_from_string',
|
||||
r'parse_file',
|
||||
)
|
||||
self.load('syntax_error')
|
||||
|
||||
self.assertEqual(self.get()['status'], 500, 'syntax error')
|
||||
assert self.get()['status'] == 500, 'syntax error'
|
||||
|
||||
def test_ruby_application_errors_puts(self):
|
||||
self.load('errors_puts')
|
||||
|
@ -196,10 +176,10 @@ class TestRubyApplication(TestApplicationRuby):
|
|||
|
||||
self.stop()
|
||||
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(r'\[error\].+Error in application'),
|
||||
'errors puts',
|
||||
)
|
||||
assert (
|
||||
self.wait_for_record(r'\[error\].+Error in application')
|
||||
is not None
|
||||
), 'errors puts'
|
||||
|
||||
def test_ruby_application_errors_puts_int(self):
|
||||
self.load('errors_puts_int')
|
||||
|
@ -208,9 +188,9 @@ class TestRubyApplication(TestApplicationRuby):
|
|||
|
||||
self.stop()
|
||||
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(r'\[error\].+1234567890'), 'errors puts int'
|
||||
)
|
||||
assert (
|
||||
self.wait_for_record(r'\[error\].+1234567890') is not None
|
||||
), 'errors puts int'
|
||||
|
||||
def test_ruby_application_errors_write(self):
|
||||
self.load('errors_write')
|
||||
|
@ -219,15 +199,15 @@ class TestRubyApplication(TestApplicationRuby):
|
|||
|
||||
self.stop()
|
||||
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(r'\[error\].+Error in application'),
|
||||
'errors write',
|
||||
)
|
||||
assert (
|
||||
self.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')
|
||||
|
||||
self.assertEqual(self.get()['status'], 200, 'errors write to_s custom')
|
||||
assert self.get()['status'] == 200, 'errors write to_s custom'
|
||||
|
||||
def test_ruby_application_errors_write_int(self):
|
||||
self.load('errors_write_int')
|
||||
|
@ -236,9 +216,9 @@ class TestRubyApplication(TestApplicationRuby):
|
|||
|
||||
self.stop()
|
||||
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(r'\[error\].+1234567890'), 'errors write int'
|
||||
)
|
||||
assert (
|
||||
self.wait_for_record(r'\[error\].+1234567890') is not None
|
||||
), 'errors write int'
|
||||
|
||||
def test_ruby_application_at_exit(self):
|
||||
self.load('at_exit')
|
||||
|
@ -249,79 +229,81 @@ class TestRubyApplication(TestApplicationRuby):
|
|||
|
||||
self.stop()
|
||||
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(r'\[error\].+At exit called\.'), 'at exit'
|
||||
)
|
||||
assert (
|
||||
self.wait_for_record(r'\[error\].+At exit called\.') is not None
|
||||
), 'at exit'
|
||||
|
||||
def test_ruby_application_header_custom(self):
|
||||
self.load('header_custom')
|
||||
|
||||
resp = self.post(body="\ntc=one,two\ntc=three,four,\n\n")
|
||||
|
||||
self.assertEqual(
|
||||
resp['headers']['Custom-Header'],
|
||||
['', 'tc=one,two', 'tc=three,four,', '', ''],
|
||||
'header custom',
|
||||
)
|
||||
assert resp['headers']['Custom-Header'] == [
|
||||
'',
|
||||
'tc=one,two',
|
||||
'tc=three,four,',
|
||||
'',
|
||||
'',
|
||||
], 'header custom'
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_ruby_application_header_custom_non_printable(self):
|
||||
self.load('header_custom')
|
||||
|
||||
self.assertEqual(
|
||||
self.post(body='\b')['status'], 500, 'header custom non printable'
|
||||
)
|
||||
assert (
|
||||
self.post(body='\b')['status'] == 500
|
||||
), 'header custom non printable'
|
||||
|
||||
def test_ruby_application_header_status(self):
|
||||
self.load('header_status')
|
||||
|
||||
self.assertEqual(self.get()['status'], 200, 'header status')
|
||||
assert self.get()['status'] == 200, 'header status'
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_ruby_application_header_rack(self):
|
||||
self.load('header_rack')
|
||||
|
||||
self.assertEqual(self.get()['status'], 500, 'header rack')
|
||||
assert self.get()['status'] == 500, 'header rack'
|
||||
|
||||
def test_ruby_application_body_empty(self):
|
||||
self.load('body_empty')
|
||||
|
||||
self.assertEqual(self.get()['body'], '', 'body empty')
|
||||
assert self.get()['body'] == '', 'body empty'
|
||||
|
||||
def test_ruby_application_body_array(self):
|
||||
self.load('body_array')
|
||||
|
||||
self.assertEqual(self.get()['body'], '0123456789', 'body array')
|
||||
assert self.get()['body'] == '0123456789', 'body array'
|
||||
|
||||
def test_ruby_application_body_large(self):
|
||||
self.load('mirror')
|
||||
|
||||
body = '0123456789' * 1000
|
||||
|
||||
self.assertEqual(self.post(body=body)['body'], body, 'body large')
|
||||
assert self.post(body=body)['body'] == body, 'body large'
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_ruby_application_body_each_error(self):
|
||||
self.load('body_each_error')
|
||||
|
||||
self.assertEqual(self.get()['status'], 500, 'body each error status')
|
||||
assert self.get()['status'] == 500, 'body each error status'
|
||||
|
||||
self.stop()
|
||||
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(r'\[error\].+Failed to run ruby script'),
|
||||
'body each error',
|
||||
)
|
||||
assert (
|
||||
self.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')
|
||||
|
||||
self.assertEqual(self.get()['body'], 'body\n', 'body file')
|
||||
assert self.get()['body'] == 'body\n', 'body file'
|
||||
|
||||
def test_ruby_keepalive_body(self):
|
||||
self.load('mirror')
|
||||
|
||||
self.assertEqual(self.get()['status'], 200, 'init')
|
||||
assert self.get()['status'] == 200, 'init'
|
||||
|
||||
body = '0123456789' * 500
|
||||
(resp, sock) = self.post(
|
||||
|
@ -335,7 +317,7 @@ class TestRubyApplication(TestApplicationRuby):
|
|||
read_timeout=1,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['body'], body, 'keep-alive 1')
|
||||
assert resp['body'] == body, 'keep-alive 1'
|
||||
|
||||
body = '0123456789'
|
||||
resp = self.post(
|
||||
|
@ -348,31 +330,22 @@ class TestRubyApplication(TestApplicationRuby):
|
|||
body=body,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['body'], body, 'keep-alive 2')
|
||||
assert resp['body'] == body, 'keep-alive 2'
|
||||
|
||||
def test_ruby_application_constants(self):
|
||||
self.load('constants')
|
||||
|
||||
resp = self.get()
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'status')
|
||||
assert resp['status'] == 200, 'status'
|
||||
|
||||
headers = resp['headers']
|
||||
self.assertGreater(len(headers['X-Copyright']), 0, 'RUBY_COPYRIGHT')
|
||||
self.assertGreater(
|
||||
len(headers['X-Description']), 0, 'RUBY_DESCRIPTION'
|
||||
)
|
||||
self.assertGreater(len(headers['X-Engine']), 0, 'RUBY_ENGINE')
|
||||
self.assertGreater(
|
||||
len(headers['X-Engine-Version']), 0, 'RUBY_ENGINE_VERSION'
|
||||
)
|
||||
self.assertGreater(len(headers['X-Patchlevel']), 0, 'RUBY_PATCHLEVEL')
|
||||
self.assertGreater(len(headers['X-Platform']), 0, 'RUBY_PLATFORM')
|
||||
self.assertGreater(
|
||||
len(headers['X-Release-Date']), 0, 'RUBY_RELEASE_DATE'
|
||||
)
|
||||
self.assertGreater(len(headers['X-Revision']), 0, 'RUBY_REVISION')
|
||||
self.assertGreater(len(headers['X-Version']), 0, 'RUBY_VERSION')
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestRubyApplication.main()
|
||||
assert len(headers['X-Copyright']) > 0, 'RUBY_COPYRIGHT'
|
||||
assert len(headers['X-Description']) > 0, 'RUBY_DESCRIPTION'
|
||||
assert len(headers['X-Engine']) > 0, 'RUBY_ENGINE'
|
||||
assert len(headers['X-Engine-Version']) > 0, 'RUBY_ENGINE_VERSION'
|
||||
assert len(headers['X-Patchlevel']) > 0, 'RUBY_PATCHLEVEL'
|
||||
assert len(headers['X-Platform']) > 0, 'RUBY_PLATFORM'
|
||||
assert len(headers['X-Release-Date']) > 0, 'RUBY_RELEASE_DATE'
|
||||
assert len(headers['X-Revision']) > 0, 'RUBY_REVISION'
|
||||
assert len(headers['X-Version']) > 0, 'RUBY_VERSION'
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import os
|
||||
import pytest
|
||||
import shutil
|
||||
import unittest
|
||||
|
||||
from unit.applications.lang.ruby import TestApplicationRuby
|
||||
from unit.feature.isolation import TestFeatureIsolation
|
||||
from conftest import option
|
||||
|
||||
|
||||
class TestRubyIsolation(TestApplicationRuby):
|
||||
|
@ -12,60 +13,45 @@ class TestRubyIsolation(TestApplicationRuby):
|
|||
isolation = TestFeatureIsolation()
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls, complete_check=True):
|
||||
unit = super().setUpClass(complete_check=False)
|
||||
def setup_class(cls, complete_check=True):
|
||||
unit = super().setup_class(complete_check=False)
|
||||
|
||||
TestFeatureIsolation().check(cls.available, unit.testdir)
|
||||
TestFeatureIsolation().check(cls.available, unit.temp_dir)
|
||||
|
||||
return unit if not complete_check else unit.complete()
|
||||
|
||||
def test_ruby_isolation_rootfs(self):
|
||||
def test_ruby_isolation_rootfs(self, is_su):
|
||||
isolation_features = self.available['features']['isolation'].keys()
|
||||
|
||||
if 'mnt' not in isolation_features:
|
||||
print('requires mnt ns')
|
||||
raise unittest.SkipTest()
|
||||
pytest.skip('requires mnt ns')
|
||||
|
||||
if not self.is_su:
|
||||
if not is_su:
|
||||
if 'user' not in isolation_features:
|
||||
print('requires unprivileged userns or root')
|
||||
raise unittest.SkipTest()
|
||||
pytest.skip('requires unprivileged userns or root')
|
||||
|
||||
if not 'unprivileged_userns_clone' in isolation_features:
|
||||
print('requires unprivileged userns or root')
|
||||
raise unittest.SkipTest()
|
||||
pytest.skip('requires unprivileged userns or root')
|
||||
|
||||
os.mkdir(self.testdir + '/ruby')
|
||||
os.mkdir(self.temp_dir + '/ruby')
|
||||
|
||||
shutil.copytree(
|
||||
self.current_dir + '/ruby/status_int',
|
||||
self.testdir + '/ruby/status_int',
|
||||
option.test_dir + '/ruby/status_int',
|
||||
self.temp_dir + '/ruby/status_int',
|
||||
)
|
||||
isolation = {
|
||||
'namespaces': {'credential': not self.is_su, 'mount': True},
|
||||
'rootfs': self.testdir,
|
||||
'namespaces': {'credential': not is_su, 'mount': True},
|
||||
'rootfs': self.temp_dir,
|
||||
}
|
||||
|
||||
self.load('status_int', isolation=isolation)
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
'"/ruby/status_int/config.ru"',
|
||||
'applications/status_int/script',
|
||||
),
|
||||
assert 'success' in self.conf(
|
||||
'"/ruby/status_int/config.ru"', 'applications/status_int/script',
|
||||
)
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
'"/ruby/status_int"',
|
||||
'applications/status_int/working_directory',
|
||||
),
|
||||
assert 'success' in self.conf(
|
||||
'"/ruby/status_int"', 'applications/status_int/working_directory',
|
||||
)
|
||||
|
||||
self.assertEqual(self.get()['status'], 200, 'status int')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestRubyIsolation.main()
|
||||
assert self.get()['status'] == 200, 'status int'
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import pytest
|
||||
import socket
|
||||
import time
|
||||
import unittest
|
||||
|
||||
from unit.applications.lang.python import TestApplicationPython
|
||||
import re
|
||||
|
||||
|
||||
class TestSettings(TestApplicationPython):
|
||||
|
@ -32,7 +33,7 @@ Connection: close
|
|||
raw=True,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 408, 'status header read timeout')
|
||||
assert resp['status'] == 408, 'status header read timeout'
|
||||
|
||||
def test_settings_header_read_timeout_update(self):
|
||||
self.load('empty')
|
||||
|
@ -83,9 +84,7 @@ Connection: close
|
|||
raw=True,
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
resp['status'], 408, 'status header read timeout update'
|
||||
)
|
||||
assert resp['status'] == 408, 'status header read timeout update'
|
||||
|
||||
def test_settings_body_read_timeout(self):
|
||||
self.load('empty')
|
||||
|
@ -109,7 +108,7 @@ Connection: close
|
|||
|
||||
resp = self.http(b"""0123456789""", sock=sock, raw=True)
|
||||
|
||||
self.assertEqual(resp['status'], 408, 'status body read timeout')
|
||||
assert resp['status'] == 408, 'status body read timeout'
|
||||
|
||||
def test_settings_body_read_timeout_update(self):
|
||||
self.load('empty')
|
||||
|
@ -144,9 +143,7 @@ Connection: close
|
|||
|
||||
resp = self.http(b"""6789""", sock=sock, raw=True)
|
||||
|
||||
self.assertEqual(
|
||||
resp['status'], 200, 'status body read timeout update'
|
||||
)
|
||||
assert resp['status'] == 200, 'status body read timeout update'
|
||||
|
||||
def test_settings_send_timeout(self):
|
||||
self.load('mirror')
|
||||
|
@ -155,7 +152,7 @@ Connection: close
|
|||
|
||||
self.conf({'http': {'send_timeout': 1}}, 'settings')
|
||||
|
||||
addr = self.testdir + '/sock'
|
||||
addr = self.temp_dir + '/sock'
|
||||
|
||||
self.conf({"unix:" + addr: {'application': 'mirror'}}, 'listeners')
|
||||
|
||||
|
@ -182,13 +179,13 @@ Connection: close
|
|||
|
||||
sock.close()
|
||||
|
||||
self.assertRegex(data, r'200 OK', 'status send timeout')
|
||||
self.assertLess(len(data), data_len, 'data send timeout')
|
||||
assert re.search(r'200 OK', data), 'status send timeout'
|
||||
assert len(data) < data_len, 'data send timeout'
|
||||
|
||||
def test_settings_idle_timeout(self):
|
||||
self.load('empty')
|
||||
|
||||
self.assertEqual(self.get()['status'], 200, 'init')
|
||||
assert self.get()['status'] == 200, 'init'
|
||||
|
||||
self.conf({'http': {'idle_timeout': 2}}, 'settings')
|
||||
|
||||
|
@ -204,17 +201,15 @@ Connection: close
|
|||
headers={'Host': 'localhost', 'Connection': 'close'}, sock=sock
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 408, 'status idle timeout')
|
||||
assert resp['status'] == 408, 'status idle timeout'
|
||||
|
||||
def test_settings_max_body_size(self):
|
||||
self.load('empty')
|
||||
|
||||
self.conf({'http': {'max_body_size': 5}}, 'settings')
|
||||
|
||||
self.assertEqual(self.post(body='01234')['status'], 200, 'status size')
|
||||
self.assertEqual(
|
||||
self.post(body='012345')['status'], 413, 'status size max'
|
||||
)
|
||||
assert self.post(body='01234')['status'] == 200, 'status size'
|
||||
assert self.post(body='012345')['status'] == 413, 'status size max'
|
||||
|
||||
def test_settings_max_body_size_large(self):
|
||||
self.load('mirror')
|
||||
|
@ -223,32 +218,26 @@ Connection: close
|
|||
|
||||
body = '0123456789abcdef' * 4 * 64 * 1024
|
||||
resp = self.post(body=body, read_buffer_size=1024 * 1024)
|
||||
self.assertEqual(resp['status'], 200, 'status size 4')
|
||||
self.assertEqual(resp['body'], body, 'status body 4')
|
||||
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)
|
||||
self.assertEqual(resp['status'], 200, 'status size 8')
|
||||
self.assertEqual(resp['body'], body, 'status body 8')
|
||||
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)
|
||||
self.assertEqual(resp['status'], 200, 'status size 16')
|
||||
self.assertEqual(resp['body'], body, 'status body 16')
|
||||
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)
|
||||
self.assertEqual(resp['status'], 200, 'status size 32')
|
||||
self.assertEqual(resp['body'], body, 'status body 32')
|
||||
assert resp['status'] == 200, 'status size 32'
|
||||
assert resp['body'] == body, 'status body 32'
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_settings_negative_value(self):
|
||||
self.assertIn(
|
||||
'error',
|
||||
self.conf({'http': {'max_body_size': -1}}, 'settings'),
|
||||
'settings negative value',
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestSettings.main()
|
||||
assert 'error' in self.conf(
|
||||
{'http': {'max_body_size': -1}}, 'settings'
|
||||
), 'settings negative value'
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
import os
|
||||
|
||||
from unit.applications.proto import TestApplicationProto
|
||||
from conftest import skip_alert
|
||||
|
||||
|
||||
class TestStatic(TestApplicationProto):
|
||||
prerequisites = {}
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
def setup_method(self):
|
||||
super().setup_method()
|
||||
|
||||
os.makedirs(self.testdir + '/assets/dir')
|
||||
with open(self.testdir + '/assets/index.html', 'w') as index:
|
||||
os.makedirs(self.temp_dir + '/assets/dir')
|
||||
with open(self.temp_dir + '/assets/index.html', 'w') as index:
|
||||
index.write('0123456789')
|
||||
|
||||
os.makedirs(self.testdir + '/assets/403')
|
||||
os.chmod(self.testdir + '/assets/403', 0o000)
|
||||
os.makedirs(self.temp_dir + '/assets/403')
|
||||
os.chmod(self.temp_dir + '/assets/403', 0o000)
|
||||
|
||||
self._load_conf(
|
||||
{
|
||||
|
@ -22,48 +23,46 @@ class TestStatic(TestApplicationProto):
|
|||
"*:7080": {"pass": "routes"},
|
||||
"*:7081": {"pass": "routes"},
|
||||
},
|
||||
"routes": [{"action": {"share": self.testdir + "/assets"}}],
|
||||
"routes": [{"action": {"share": self.temp_dir + "/assets"}}],
|
||||
"applications": {},
|
||||
}
|
||||
)
|
||||
|
||||
def tearDown(self):
|
||||
os.chmod(self.testdir + '/assets/403', 0o777)
|
||||
def teardown_method(self):
|
||||
os.chmod(self.temp_dir + '/assets/403', 0o777)
|
||||
|
||||
super().tearDown()
|
||||
super().teardown_method()
|
||||
|
||||
def action_update(self, conf):
|
||||
self.assertIn('success', self.conf(conf, 'routes/0/action'))
|
||||
assert 'success' in self.conf(conf, 'routes/0/action')
|
||||
|
||||
def test_fallback(self):
|
||||
self.action_update({"share": "/blah"})
|
||||
self.assertEqual(self.get()['status'], 404, 'bad path no fallback')
|
||||
assert self.get()['status'] == 404, 'bad path no fallback'
|
||||
|
||||
self.action_update({"share": "/blah", "fallback": {"return": 200}})
|
||||
|
||||
resp = self.get()
|
||||
self.assertEqual(resp['status'], 200, 'bad path fallback status')
|
||||
self.assertEqual(resp['body'], '', 'bad path fallback')
|
||||
assert resp['status'] == 200, 'bad path fallback status'
|
||||
assert resp['body'] == '', 'bad path fallback'
|
||||
|
||||
def test_fallback_valid_path(self):
|
||||
self.action_update(
|
||||
{"share": self.testdir + "/assets", "fallback": {"return": 200}}
|
||||
{"share": self.temp_dir + "/assets", "fallback": {"return": 200}}
|
||||
)
|
||||
resp = self.get()
|
||||
self.assertEqual(resp['status'], 200, 'fallback status')
|
||||
self.assertEqual(resp['body'], '0123456789', 'fallback')
|
||||
assert resp['status'] == 200, 'fallback status'
|
||||
assert resp['body'] == '0123456789', 'fallback'
|
||||
|
||||
resp = self.get(url='/403/')
|
||||
self.assertEqual(resp['status'], 200, 'fallback status 403')
|
||||
self.assertEqual(resp['body'], '', 'fallback 403')
|
||||
assert resp['status'] == 200, 'fallback status 403'
|
||||
assert resp['body'] == '', 'fallback 403'
|
||||
|
||||
resp = self.post()
|
||||
self.assertEqual(resp['status'], 200, 'fallback status 405')
|
||||
self.assertEqual(resp['body'], '', 'fallback 405')
|
||||
assert resp['status'] == 200, 'fallback status 405'
|
||||
assert resp['body'] == '', 'fallback 405'
|
||||
|
||||
self.assertEqual(
|
||||
self.get(url='/dir')['status'], 301, 'fallback status 301'
|
||||
)
|
||||
assert self.get(url='/dir')['status'] == 301, 'fallback status 301'
|
||||
|
||||
def test_fallback_nested(self):
|
||||
self.action_update(
|
||||
|
@ -77,62 +76,56 @@ class TestStatic(TestApplicationProto):
|
|||
)
|
||||
|
||||
resp = self.get()
|
||||
self.assertEqual(resp['status'], 200, 'fallback nested status')
|
||||
self.assertEqual(resp['body'], '', 'fallback nested')
|
||||
assert resp['status'] == 200, 'fallback nested status'
|
||||
assert resp['body'] == '', 'fallback nested'
|
||||
|
||||
def test_fallback_share(self):
|
||||
self.action_update(
|
||||
{
|
||||
"share": "/blah",
|
||||
"fallback": {"share": self.testdir + "/assets"},
|
||||
"fallback": {"share": self.temp_dir + "/assets"},
|
||||
}
|
||||
)
|
||||
|
||||
resp = self.get()
|
||||
self.assertEqual(resp['status'], 200, 'fallback share status')
|
||||
self.assertEqual(resp['body'], '0123456789', 'fallback share')
|
||||
assert resp['status'] == 200, 'fallback share status'
|
||||
assert resp['body'] == '0123456789', 'fallback share'
|
||||
|
||||
resp = self.head()
|
||||
self.assertEqual(resp['status'], 200, 'fallback share status HEAD')
|
||||
self.assertEqual(resp['body'], '', 'fallback share HEAD')
|
||||
assert resp['status'] == 200, 'fallback share status HEAD'
|
||||
assert resp['body'] == '', 'fallback share HEAD'
|
||||
|
||||
self.assertEqual(
|
||||
self.get(url='/dir')['status'], 301, 'fallback share status 301'
|
||||
)
|
||||
assert (
|
||||
self.get(url='/dir')['status'] == 301
|
||||
), 'fallback share status 301'
|
||||
|
||||
def test_fallback_proxy(self):
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
[
|
||||
{
|
||||
"match": {"destination": "*:7081"},
|
||||
"action": {"return": 200},
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"share": "/blah",
|
||||
"fallback": {"proxy": "http://127.0.0.1:7081"},
|
||||
}
|
||||
},
|
||||
],
|
||||
'routes',
|
||||
),
|
||||
'configure fallback proxy route',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
[
|
||||
{
|
||||
"match": {"destination": "*:7081"},
|
||||
"action": {"return": 200},
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"share": "/blah",
|
||||
"fallback": {"proxy": "http://127.0.0.1:7081"},
|
||||
}
|
||||
},
|
||||
],
|
||||
'routes',
|
||||
), 'configure fallback proxy route'
|
||||
|
||||
resp = self.get()
|
||||
self.assertEqual(resp['status'], 200, 'fallback proxy status')
|
||||
self.assertEqual(resp['body'], '', 'fallback proxy')
|
||||
assert resp['status'] == 200, 'fallback proxy status'
|
||||
assert resp['body'] == '', 'fallback proxy'
|
||||
|
||||
def test_fallback_proxy_loop(self):
|
||||
self.skip_alerts.extend(
|
||||
[
|
||||
r'open.*/blah/index.html.*failed',
|
||||
r'accept.*failed',
|
||||
r'socket.*failed',
|
||||
r'new connections are not accepted',
|
||||
]
|
||||
skip_alert(
|
||||
r'open.*/blah/index.html.*failed',
|
||||
r'accept.*failed',
|
||||
r'socket.*failed',
|
||||
r'new connections are not accepted',
|
||||
)
|
||||
|
||||
self.action_update(
|
||||
|
@ -140,12 +133,12 @@ class TestStatic(TestApplicationProto):
|
|||
)
|
||||
self.get(no_recv=True)
|
||||
|
||||
self.assertIn('success', self.conf_delete('listeners/*:7081'))
|
||||
assert 'success' in self.conf_delete('listeners/*:7081')
|
||||
self.get(read_timeout=1)
|
||||
|
||||
def test_fallback_invalid(self):
|
||||
def check_error(conf):
|
||||
self.assertIn('error', self.conf(conf, 'routes/0/action'))
|
||||
assert 'error' in self.conf(conf, 'routes/0/action')
|
||||
|
||||
check_error({"share": "/blah", "fallback": {}})
|
||||
check_error({"share": "/blah", "fallback": ""})
|
||||
|
@ -154,7 +147,3 @@ class TestStatic(TestApplicationProto):
|
|||
{"proxy": "http://127.0.0.1:7081", "fallback": {"share": "/blah"}}
|
||||
)
|
||||
check_error({"fallback": {"share": "/blah"}})
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestStatic.main()
|
||||
|
|
|
@ -1,21 +1,23 @@
|
|||
import os
|
||||
import pytest
|
||||
import socket
|
||||
import unittest
|
||||
|
||||
from unit.applications.proto import TestApplicationProto
|
||||
from conftest import waitforfiles
|
||||
|
||||
|
||||
class TestStatic(TestApplicationProto):
|
||||
prerequisites = {}
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
def setup_method(self):
|
||||
super().setup_method()
|
||||
|
||||
os.makedirs(self.testdir + '/assets/dir')
|
||||
with open(self.testdir + '/assets/index.html', 'w') as index, \
|
||||
open(self.testdir + '/assets/README', 'w') as readme, \
|
||||
open(self.testdir + '/assets/log.log', 'w') as log, \
|
||||
open(self.testdir + '/assets/dir/file', 'w') as file:
|
||||
os.makedirs(self.temp_dir + '/assets/dir')
|
||||
with open(self.temp_dir + '/assets/index.html', 'w') as index, open(
|
||||
self.temp_dir + '/assets/README', 'w'
|
||||
) as readme, open(self.temp_dir + '/assets/log.log', 'w') as log, open(
|
||||
self.temp_dir + '/assets/dir/file', 'w'
|
||||
) as file:
|
||||
index.write('0123456789')
|
||||
readme.write('readme')
|
||||
log.write('[debug]')
|
||||
|
@ -24,7 +26,7 @@ class TestStatic(TestApplicationProto):
|
|||
self._load_conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "routes"}},
|
||||
"routes": [{"action": {"share": self.testdir + "/assets"}}],
|
||||
"routes": [{"action": {"share": self.temp_dir + "/assets"}}],
|
||||
"settings": {
|
||||
"http": {
|
||||
"static": {
|
||||
|
@ -36,123 +38,95 @@ class TestStatic(TestApplicationProto):
|
|||
)
|
||||
|
||||
def test_static_index(self):
|
||||
self.assertEqual(
|
||||
self.get(url='/index.html')['body'], '0123456789', 'index'
|
||||
)
|
||||
self.assertEqual(self.get(url='/')['body'], '0123456789', 'index 2')
|
||||
self.assertEqual(self.get(url='//')['body'], '0123456789', 'index 3')
|
||||
self.assertEqual(self.get(url='/.')['body'], '0123456789', 'index 4')
|
||||
self.assertEqual(self.get(url='/./')['body'], '0123456789', 'index 5')
|
||||
self.assertEqual(
|
||||
self.get(url='/?blah')['body'], '0123456789', 'index vars'
|
||||
)
|
||||
self.assertEqual(
|
||||
self.get(url='/#blah')['body'], '0123456789', 'index anchor'
|
||||
)
|
||||
self.assertEqual(
|
||||
self.get(url='/dir/')['status'], 404, 'index not found'
|
||||
)
|
||||
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/')
|
||||
self.assertEqual(resp['status'], 404, 'index not found 2 status')
|
||||
self.assertEqual(
|
||||
resp['headers']['Content-Type'],
|
||||
'text/html',
|
||||
'index not found 2 Content-Type',
|
||||
)
|
||||
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_large_file(self):
|
||||
file_size = 32 * 1024 * 1024
|
||||
with open(self.testdir + '/assets/large', 'wb') as f:
|
||||
with open(self.temp_dir + '/assets/large', 'wb') as f:
|
||||
f.seek(file_size - 1)
|
||||
f.write(b'\0')
|
||||
|
||||
self.assertEqual(
|
||||
len(
|
||||
self.get(url='/large', read_buffer_size=1024 * 1024)['body']
|
||||
),
|
||||
file_size,
|
||||
'large file',
|
||||
)
|
||||
assert (
|
||||
len(self.get(url='/large', read_buffer_size=1024 * 1024)['body'])
|
||||
== file_size
|
||||
), 'large file'
|
||||
|
||||
def test_static_etag(self):
|
||||
etag = self.get(url='/')['headers']['ETag']
|
||||
etag_2 = self.get(url='/README')['headers']['ETag']
|
||||
|
||||
self.assertNotEqual(etag, etag_2, 'different ETag')
|
||||
self.assertEqual(
|
||||
etag, self.get(url='/')['headers']['ETag'], 'same ETag'
|
||||
)
|
||||
assert etag != etag_2, 'different ETag'
|
||||
assert etag == self.get(url='/')['headers']['ETag'], 'same ETag'
|
||||
|
||||
with open(self.testdir + '/assets/index.html', 'w') as f:
|
||||
with open(self.temp_dir + '/assets/index.html', 'w') as f:
|
||||
f.write('blah')
|
||||
|
||||
self.assertNotEqual(
|
||||
etag, self.get(url='/')['headers']['ETag'], 'new ETag'
|
||||
)
|
||||
assert etag != self.get(url='/')['headers']['ETag'], 'new ETag'
|
||||
|
||||
def test_static_redirect(self):
|
||||
resp = self.get(url='/dir')
|
||||
self.assertEqual(resp['status'], 301, 'redirect status')
|
||||
self.assertEqual(
|
||||
resp['headers']['Location'], '/dir/', 'redirect Location'
|
||||
)
|
||||
self.assertNotIn(
|
||||
'Content-Type', resp['headers'], 'redirect Content-Type'
|
||||
)
|
||||
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):
|
||||
os.rename(
|
||||
self.testdir + '/assets/dir/file',
|
||||
self.testdir + '/assets/dir/fi le',
|
||||
)
|
||||
self.waitforfiles(self.testdir + '/assets/dir/fi le')
|
||||
self.assertEqual(
|
||||
self.get(url='/dir/fi le')['body'], 'blah', 'file name'
|
||||
self.temp_dir + '/assets/dir/file',
|
||||
self.temp_dir + '/assets/dir/fi le',
|
||||
)
|
||||
assert waitforfiles(self.temp_dir + '/assets/dir/fi le')
|
||||
assert self.get(url='/dir/fi le')['body'] == 'blah', 'file name'
|
||||
|
||||
os.rename(self.testdir + '/assets/dir', self.testdir + '/assets/di r')
|
||||
self.waitforfiles(self.testdir + '/assets/di r/fi le')
|
||||
self.assertEqual(
|
||||
self.get(url='/di r/fi le')['body'], 'blah', 'dir name'
|
||||
)
|
||||
os.rename(self.temp_dir + '/assets/dir', self.temp_dir + '/assets/di r')
|
||||
assert waitforfiles(self.temp_dir + '/assets/di r/fi le')
|
||||
assert self.get(url='/di r/fi le')['body'] == 'blah', 'dir name'
|
||||
|
||||
os.rename(
|
||||
self.testdir + '/assets/di r', self.testdir + '/assets/ di r '
|
||||
)
|
||||
self.waitforfiles(self.testdir + '/assets/ di r /fi le')
|
||||
self.assertEqual(
|
||||
self.get(url='/ di r /fi le')['body'], 'blah', 'dir name enclosing'
|
||||
self.temp_dir + '/assets/di r', self.temp_dir + '/assets/ di r '
|
||||
)
|
||||
assert waitforfiles(self.temp_dir + '/assets/ di r /fi le')
|
||||
assert (
|
||||
self.get(url='/ di r /fi le')['body'] == 'blah'
|
||||
), 'dir name enclosing'
|
||||
|
||||
self.assertEqual(
|
||||
self.get(url='/%20di%20r%20/fi le')['body'], 'blah', 'dir encoded'
|
||||
)
|
||||
self.assertEqual(
|
||||
self.get(url='/ di r %2Ffi le')['body'], 'blah', 'slash encoded'
|
||||
)
|
||||
self.assertEqual(
|
||||
self.get(url='/ di r /fi%20le')['body'], 'blah', 'file encoded'
|
||||
)
|
||||
self.assertEqual(
|
||||
self.get(url='/%20di%20r%20%2Ffi%20le')['body'], 'blah', 'encoded'
|
||||
)
|
||||
self.assertEqual(
|
||||
self.get(url='/%20%64%69%20%72%20%2F%66%69%20%6C%65')['body'],
|
||||
'blah',
|
||||
'encoded 2',
|
||||
)
|
||||
assert (
|
||||
self.get(url='/%20di%20r%20/fi le')['body'] == 'blah'
|
||||
), 'dir 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'
|
||||
), 'encoded'
|
||||
assert (
|
||||
self.get(url='/%20%64%69%20%72%20%2F%66%69%20%6C%65')['body']
|
||||
== 'blah'
|
||||
), 'encoded 2'
|
||||
|
||||
os.rename(
|
||||
self.testdir + '/assets/ di r /fi le',
|
||||
self.testdir + '/assets/ di r / fi le ',
|
||||
)
|
||||
self.waitforfiles(self.testdir + '/assets/ di r / fi le ')
|
||||
self.assertEqual(
|
||||
self.get(url='/%20di%20r%20/%20fi%20le%20')['body'],
|
||||
'blah',
|
||||
'file name enclosing',
|
||||
self.temp_dir + '/assets/ di r /fi le',
|
||||
self.temp_dir + '/assets/ di r / fi le ',
|
||||
)
|
||||
assert waitforfiles(self.temp_dir + '/assets/ di r / fi le ')
|
||||
assert (
|
||||
self.get(url='/%20di%20r%20/%20fi%20le%20')['body'] == 'blah'
|
||||
), 'file name enclosing'
|
||||
|
||||
try:
|
||||
print('файл')
|
||||
|
@ -163,267 +137,190 @@ class TestStatic(TestApplicationProto):
|
|||
|
||||
if utf8:
|
||||
os.rename(
|
||||
self.testdir + '/assets/ di r / fi le ',
|
||||
self.testdir + '/assets/ di r /фа йл',
|
||||
)
|
||||
self.waitforfiles(self.testdir + '/assets/ di r /фа йл')
|
||||
self.assertEqual(
|
||||
self.get(url='/ di r /фа йл')['body'], 'blah', 'file name 2'
|
||||
self.temp_dir + '/assets/ di r / fi le ',
|
||||
self.temp_dir + '/assets/ di r /фа йл',
|
||||
)
|
||||
assert waitforfiles(self.temp_dir + '/assets/ di r /фа йл')
|
||||
assert (
|
||||
self.get(url='/ di r /фа йл')['body'] == 'blah'
|
||||
), 'file name 2'
|
||||
|
||||
os.rename(
|
||||
self.testdir + '/assets/ di r ',
|
||||
self.testdir + '/assets/ди ректория',
|
||||
)
|
||||
self.waitforfiles(self.testdir + '/assets/ди ректория/фа йл')
|
||||
self.assertEqual(
|
||||
self.get(url='/ди ректория/фа йл')['body'], 'blah', 'dir name 2'
|
||||
self.temp_dir + '/assets/ di r ',
|
||||
self.temp_dir + '/assets/ди ректория',
|
||||
)
|
||||
assert waitforfiles(self.temp_dir + '/assets/ди ректория/фа йл')
|
||||
assert (
|
||||
self.get(url='/ди ректория/фа йл')['body'] == 'blah'
|
||||
), 'dir name 2'
|
||||
|
||||
def test_static_unix_socket(self):
|
||||
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
sock.bind(self.testdir + '/assets/unix_socket')
|
||||
sock.bind(self.temp_dir + '/assets/unix_socket')
|
||||
|
||||
self.assertEqual(self.get(url='/unix_socket')['status'], 404, 'socket')
|
||||
assert self.get(url='/unix_socket')['status'] == 404, 'socket'
|
||||
|
||||
sock.close()
|
||||
|
||||
def test_static_unix_fifo(self):
|
||||
os.mkfifo(self.testdir + '/assets/fifo')
|
||||
os.mkfifo(self.temp_dir + '/assets/fifo')
|
||||
|
||||
self.assertEqual(self.get(url='/fifo')['status'], 404, 'fifo')
|
||||
assert self.get(url='/fifo')['status'] == 404, 'fifo'
|
||||
|
||||
def test_static_symlink(self):
|
||||
os.symlink(self.testdir + '/assets/dir', self.testdir + '/assets/link')
|
||||
os.symlink(self.temp_dir + '/assets/dir', self.temp_dir + '/assets/link')
|
||||
|
||||
self.assertEqual(self.get(url='/dir')['status'], 301, 'dir')
|
||||
self.assertEqual(self.get(url='/dir/file')['status'], 200, 'file')
|
||||
self.assertEqual(self.get(url='/link')['status'], 301, 'symlink dir')
|
||||
self.assertEqual(
|
||||
self.get(url='/link/file')['status'], 200, 'symlink file'
|
||||
)
|
||||
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'
|
||||
|
||||
def test_static_method(self):
|
||||
resp = self.head()
|
||||
self.assertEqual(resp['status'], 200, 'HEAD status')
|
||||
self.assertEqual(resp['body'], '', 'HEAD empty body')
|
||||
assert resp['status'] == 200, 'HEAD status'
|
||||
assert resp['body'] == '', 'HEAD empty body'
|
||||
|
||||
self.assertEqual(self.delete()['status'], 405, 'DELETE')
|
||||
self.assertEqual(self.post()['status'], 405, 'POST')
|
||||
self.assertEqual(self.put()['status'], 405, 'PUT')
|
||||
assert self.delete()['status'] == 405, 'DELETE'
|
||||
assert self.post()['status'] == 405, 'POST'
|
||||
assert self.put()['status'] == 405, 'PUT'
|
||||
|
||||
def test_static_path(self):
|
||||
self.assertEqual(
|
||||
self.get(url='/dir/../dir/file')['status'], 200, 'relative'
|
||||
)
|
||||
assert self.get(url='/dir/../dir/file')['status'] == 200, 'relative'
|
||||
|
||||
self.assertEqual(self.get(url='./')['status'], 400, 'path invalid')
|
||||
self.assertEqual(self.get(url='../')['status'], 400, 'path invalid 2')
|
||||
self.assertEqual(self.get(url='/..')['status'], 400, 'path invalid 3')
|
||||
self.assertEqual(
|
||||
self.get(url='../assets/')['status'], 400, 'path invalid 4'
|
||||
)
|
||||
self.assertEqual(
|
||||
self.get(url='/../assets/')['status'], 400, 'path invalid 5'
|
||||
)
|
||||
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_two_clients(self):
|
||||
_, sock = self.get(url='/', start=True, no_recv=True)
|
||||
_, sock2 = self.get(url='/', start=True, no_recv=True)
|
||||
|
||||
self.assertEqual(sock.recv(1), b'H', 'client 1')
|
||||
self.assertEqual(sock2.recv(1), b'H', 'client 2')
|
||||
self.assertEqual(sock.recv(1), b'T', 'client 1 again')
|
||||
self.assertEqual(sock2.recv(1), b'T', 'client 2 again')
|
||||
assert sock.recv(1) == b'H', 'client 1'
|
||||
assert sock2.recv(1) == b'H', 'client 2'
|
||||
assert sock.recv(1) == b'T', 'client 1 again'
|
||||
assert sock2.recv(1) == b'T', 'client 2 again'
|
||||
|
||||
sock.close()
|
||||
sock2.close()
|
||||
|
||||
def test_static_mime_types(self):
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{
|
||||
"text/x-code/x-blah/x-blah": "readme",
|
||||
"text/plain": [".html", ".log", "file"],
|
||||
},
|
||||
'settings/http/static/mime_types',
|
||||
),
|
||||
'configure mime_types',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{
|
||||
"text/x-code/x-blah/x-blah": "readme",
|
||||
"text/plain": [".html", ".log", "file"],
|
||||
},
|
||||
'settings/http/static/mime_types',
|
||||
), 'configure mime_types'
|
||||
|
||||
self.assertEqual(
|
||||
self.get(url='/README')['headers']['Content-Type'],
|
||||
'text/x-code/x-blah/x-blah',
|
||||
'mime_types string case insensitive',
|
||||
)
|
||||
self.assertEqual(
|
||||
self.get(url='/index.html')['headers']['Content-Type'],
|
||||
'text/plain',
|
||||
'mime_types html',
|
||||
)
|
||||
self.assertEqual(
|
||||
self.get(url='/')['headers']['Content-Type'],
|
||||
'text/plain',
|
||||
'mime_types index default',
|
||||
)
|
||||
self.assertEqual(
|
||||
self.get(url='/dir/file')['headers']['Content-Type'],
|
||||
'text/plain',
|
||||
'mime_types file in dir',
|
||||
)
|
||||
assert (
|
||||
self.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'
|
||||
), 'mime_types html'
|
||||
assert (
|
||||
self.get(url='/')['headers']['Content-Type'] == 'text/plain'
|
||||
), 'mime_types index default'
|
||||
assert (
|
||||
self.get(url='/dir/file')['headers']['Content-Type']
|
||||
== 'text/plain'
|
||||
), 'mime_types file in dir'
|
||||
|
||||
def test_static_mime_types_partial_match(self):
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{
|
||||
"text/x-blah": ["ile", "fil", "f", "e", ".file"],
|
||||
},
|
||||
'settings/http/static/mime_types',
|
||||
),
|
||||
'configure mime_types',
|
||||
)
|
||||
self.assertNotIn(
|
||||
'Content-Type', self.get(url='/dir/file'), 'partial match'
|
||||
)
|
||||
assert 'success' in self.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'
|
||||
|
||||
def test_static_mime_types_reconfigure(self):
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{
|
||||
"text/x-code": "readme",
|
||||
"text/plain": [".html", ".log", "file"],
|
||||
},
|
||||
'settings/http/static/mime_types',
|
||||
),
|
||||
'configure mime_types',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{
|
||||
"text/x-code": "readme",
|
||||
"text/plain": [".html", ".log", "file"],
|
||||
},
|
||||
'settings/http/static/mime_types',
|
||||
), 'configure mime_types'
|
||||
|
||||
self.assertEqual(
|
||||
self.conf_get('settings/http/static/mime_types'),
|
||||
{'text/x-code': 'readme', 'text/plain': ['.html', '.log', 'file']},
|
||||
'mime_types get',
|
||||
)
|
||||
self.assertEqual(
|
||||
self.conf_get('settings/http/static/mime_types/text%2Fx-code'),
|
||||
'readme',
|
||||
'mime_types get string',
|
||||
)
|
||||
self.assertEqual(
|
||||
self.conf_get('settings/http/static/mime_types/text%2Fplain'),
|
||||
['.html', '.log', 'file'],
|
||||
'mime_types get array',
|
||||
)
|
||||
self.assertEqual(
|
||||
self.conf_get('settings/http/static/mime_types/text%2Fplain/1'),
|
||||
'.log',
|
||||
'mime_types get array element',
|
||||
)
|
||||
assert self.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')
|
||||
== 'readme'
|
||||
), 'mime_types get string'
|
||||
assert self.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')
|
||||
== '.log'
|
||||
), 'mime_types get array element'
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf_delete('settings/http/static/mime_types/text%2Fplain/2'),
|
||||
'mime_types remove array element',
|
||||
)
|
||||
self.assertNotIn(
|
||||
'Content-Type',
|
||||
self.get(url='/dir/file')['headers'],
|
||||
'mime_types removed',
|
||||
)
|
||||
assert 'success' in self.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']
|
||||
), 'mime_types removed'
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf_post(
|
||||
'"file"', 'settings/http/static/mime_types/text%2Fplain'
|
||||
),
|
||||
'mime_types add array element',
|
||||
)
|
||||
self.assertEqual(
|
||||
self.get(url='/dir/file')['headers']['Content-Type'],
|
||||
'text/plain',
|
||||
'mime_types reverted',
|
||||
)
|
||||
assert 'success' in self.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'
|
||||
), 'mime_types reverted'
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
'"file"', 'settings/http/static/mime_types/text%2Fplain'
|
||||
),
|
||||
'configure mime_types update',
|
||||
)
|
||||
self.assertEqual(
|
||||
self.get(url='/dir/file')['headers']['Content-Type'],
|
||||
'text/plain',
|
||||
'mime_types updated',
|
||||
)
|
||||
self.assertNotIn(
|
||||
'Content-Type',
|
||||
self.get(url='/log.log')['headers'],
|
||||
'mime_types updated 2',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
'"file"', 'settings/http/static/mime_types/text%2Fplain'
|
||||
), 'configure mime_types update'
|
||||
assert (
|
||||
self.get(url='/dir/file')['headers']['Content-Type']
|
||||
== 'text/plain'
|
||||
), 'mime_types updated'
|
||||
assert (
|
||||
'Content-Type' not in self.get(url='/log.log')['headers']
|
||||
), 'mime_types updated 2'
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
'".log"', 'settings/http/static/mime_types/text%2Fblahblahblah'
|
||||
),
|
||||
'configure mime_types create',
|
||||
)
|
||||
self.assertEqual(
|
||||
self.get(url='/log.log')['headers']['Content-Type'],
|
||||
'text/blahblahblah',
|
||||
'mime_types create',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
'".log"', 'settings/http/static/mime_types/text%2Fblahblahblah'
|
||||
), 'configure mime_types create'
|
||||
assert (
|
||||
self.get(url='/log.log')['headers']['Content-Type']
|
||||
== 'text/blahblahblah'
|
||||
), 'mime_types create'
|
||||
|
||||
def test_static_mime_types_correct(self):
|
||||
self.assertIn(
|
||||
'error',
|
||||
self.conf(
|
||||
{"text/x-code": "readme", "text/plain": "readme"},
|
||||
'settings/http/static/mime_types',
|
||||
),
|
||||
'mime_types same extensions',
|
||||
)
|
||||
self.assertIn(
|
||||
'error',
|
||||
self.conf(
|
||||
{"text/x-code": [".h", ".c"], "text/plain": ".c"},
|
||||
'settings/http/static/mime_types',
|
||||
),
|
||||
'mime_types same extensions array',
|
||||
)
|
||||
self.assertIn(
|
||||
'error',
|
||||
self.conf(
|
||||
{
|
||||
"text/x-code": [".h", ".c", "readme"],
|
||||
"text/plain": "README",
|
||||
},
|
||||
'settings/http/static/mime_types',
|
||||
),
|
||||
'mime_types same extensions case insensitive',
|
||||
)
|
||||
assert 'error' in self.conf(
|
||||
{"text/x-code": "readme", "text/plain": "readme"},
|
||||
'settings/http/static/mime_types',
|
||||
), 'mime_types same extensions'
|
||||
assert 'error' in self.conf(
|
||||
{"text/x-code": [".h", ".c"], "text/plain": ".c"},
|
||||
'settings/http/static/mime_types',
|
||||
), 'mime_types same extensions array'
|
||||
assert 'error' in self.conf(
|
||||
{"text/x-code": [".h", ".c", "readme"], "text/plain": "README",},
|
||||
'settings/http/static/mime_types',
|
||||
), 'mime_types same extensions case insensitive'
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_static_mime_types_invalid(self):
|
||||
self.assertIn(
|
||||
'error',
|
||||
self.http(
|
||||
b"""PUT /config/settings/http/static/mime_types/%0%00% HTTP/1.1\r
|
||||
assert 'error' in self.http(
|
||||
b"""PUT /config/settings/http/static/mime_types/%0%00% HTTP/1.1\r
|
||||
Host: localhost\r
|
||||
Connection: close\r
|
||||
Content-Length: 6\r
|
||||
\r
|
||||
\"blah\"""",
|
||||
raw_resp=True,
|
||||
raw=True,
|
||||
sock_type='unix',
|
||||
addr=self.testdir + '/control.unit.sock',
|
||||
),
|
||||
'mime_types invalid',
|
||||
)
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestStatic.main()
|
||||
raw_resp=True,
|
||||
raw=True,
|
||||
sock_type='unix',
|
||||
addr=self.temp_dir + '/control.unit.sock',
|
||||
), 'mime_types invalid'
|
||||
|
|
398
test/test_tls.py
398
test/test_tls.py
|
@ -1,17 +1,18 @@
|
|||
import io
|
||||
import pytest
|
||||
import re
|
||||
import ssl
|
||||
import subprocess
|
||||
import unittest
|
||||
|
||||
from unit.applications.tls import TestApplicationTLS
|
||||
from conftest import skip_alert
|
||||
|
||||
|
||||
class TestTLS(TestApplicationTLS):
|
||||
prerequisites = {'modules': {'python': 'any', 'openssl': 'any'}}
|
||||
|
||||
def findall(self, pattern):
|
||||
with open(self.testdir + '/unit.log', 'r', errors='ignore') as f:
|
||||
with open(self.temp_dir + '/unit.log', 'r', errors='ignore') as f:
|
||||
return re.findall(pattern, f.read())
|
||||
|
||||
def openssl_date_to_sec_epoch(self, date):
|
||||
|
@ -38,7 +39,7 @@ class TestTLS(TestApplicationTLS):
|
|||
|
||||
self.add_tls()
|
||||
|
||||
self.assertEqual(self.get_ssl()['status'], 200, 'add listener option')
|
||||
assert self.get_ssl()['status'] == 200, 'add listener option'
|
||||
|
||||
def test_tls_listener_option_remove(self):
|
||||
self.load('empty')
|
||||
|
@ -51,18 +52,16 @@ class TestTLS(TestApplicationTLS):
|
|||
|
||||
self.remove_tls()
|
||||
|
||||
self.assertEqual(self.get()['status'], 200, 'remove listener option')
|
||||
assert self.get()['status'] == 200, 'remove listener option'
|
||||
|
||||
def test_tls_certificate_remove(self):
|
||||
self.load('empty')
|
||||
|
||||
self.certificate()
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf_delete('/certificates/default'),
|
||||
'remove certificate',
|
||||
)
|
||||
assert 'success' in self.conf_delete(
|
||||
'/certificates/default'
|
||||
), 'remove certificate'
|
||||
|
||||
def test_tls_certificate_remove_used(self):
|
||||
self.load('empty')
|
||||
|
@ -71,11 +70,9 @@ class TestTLS(TestApplicationTLS):
|
|||
|
||||
self.add_tls()
|
||||
|
||||
self.assertIn(
|
||||
'error',
|
||||
self.conf_delete('/certificates/default'),
|
||||
'remove certificate',
|
||||
)
|
||||
assert 'error' in self.conf_delete(
|
||||
'/certificates/default'
|
||||
), 'remove certificate'
|
||||
|
||||
def test_tls_certificate_remove_nonexisting(self):
|
||||
self.load('empty')
|
||||
|
@ -84,13 +81,11 @@ class TestTLS(TestApplicationTLS):
|
|||
|
||||
self.add_tls()
|
||||
|
||||
self.assertIn(
|
||||
'error',
|
||||
self.conf_delete('/certificates/blah'),
|
||||
'remove nonexistings certificate',
|
||||
)
|
||||
assert 'error' in self.conf_delete(
|
||||
'/certificates/blah'
|
||||
), 'remove nonexistings certificate'
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_tls_certificate_update(self):
|
||||
self.load('empty')
|
||||
|
||||
|
@ -102,20 +97,18 @@ class TestTLS(TestApplicationTLS):
|
|||
|
||||
self.certificate()
|
||||
|
||||
self.assertNotEqual(
|
||||
cert_old, self.get_server_certificate(), 'update certificate'
|
||||
)
|
||||
assert cert_old != self.get_server_certificate(), 'update certificate'
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_tls_certificate_key_incorrect(self):
|
||||
self.load('empty')
|
||||
|
||||
self.certificate('first', False)
|
||||
self.certificate('second', False)
|
||||
|
||||
self.assertIn(
|
||||
'error', self.certificate_load('first', 'second'), 'key incorrect'
|
||||
)
|
||||
assert 'error' in self.certificate_load(
|
||||
'first', 'second'
|
||||
), 'key incorrect'
|
||||
|
||||
def test_tls_certificate_change(self):
|
||||
self.load('empty')
|
||||
|
@ -129,20 +122,16 @@ class TestTLS(TestApplicationTLS):
|
|||
|
||||
self.add_tls(cert='new')
|
||||
|
||||
self.assertNotEqual(
|
||||
cert_old, self.get_server_certificate(), 'change certificate'
|
||||
)
|
||||
assert cert_old != self.get_server_certificate(), 'change certificate'
|
||||
|
||||
def test_tls_certificate_key_rsa(self):
|
||||
self.load('empty')
|
||||
|
||||
self.certificate()
|
||||
|
||||
self.assertEqual(
|
||||
self.conf_get('/certificates/default/key'),
|
||||
'RSA (2048 bits)',
|
||||
'certificate key rsa',
|
||||
)
|
||||
assert (
|
||||
self.conf_get('/certificates/default/key') == 'RSA (2048 bits)'
|
||||
), 'certificate key rsa'
|
||||
|
||||
def test_tls_certificate_key_ec(self):
|
||||
self.load('empty')
|
||||
|
@ -155,8 +144,10 @@ class TestTLS(TestApplicationTLS):
|
|||
'ecparam',
|
||||
'-noout',
|
||||
'-genkey',
|
||||
'-out', self.testdir + '/ec.key',
|
||||
'-name', 'prime256v1',
|
||||
'-out',
|
||||
self.temp_dir + '/ec.key',
|
||||
'-name',
|
||||
'prime256v1',
|
||||
],
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
|
@ -167,19 +158,23 @@ class TestTLS(TestApplicationTLS):
|
|||
'req',
|
||||
'-x509',
|
||||
'-new',
|
||||
'-subj', '/CN=ec/',
|
||||
'-config', self.testdir + '/openssl.conf',
|
||||
'-key', self.testdir + '/ec.key',
|
||||
'-out', self.testdir + '/ec.crt',
|
||||
'-subj',
|
||||
'/CN=ec/',
|
||||
'-config',
|
||||
self.temp_dir + '/openssl.conf',
|
||||
'-key',
|
||||
self.temp_dir + '/ec.key',
|
||||
'-out',
|
||||
self.temp_dir + '/ec.crt',
|
||||
],
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
|
||||
self.certificate_load('ec')
|
||||
|
||||
self.assertEqual(
|
||||
self.conf_get('/certificates/ec/key'), 'ECDH', 'certificate key ec'
|
||||
)
|
||||
assert (
|
||||
self.conf_get('/certificates/ec/key') == 'ECDH'
|
||||
), 'certificate key ec'
|
||||
|
||||
def test_tls_certificate_chain_options(self):
|
||||
self.load('empty')
|
||||
|
@ -188,35 +183,29 @@ class TestTLS(TestApplicationTLS):
|
|||
|
||||
chain = self.conf_get('/certificates/default/chain')
|
||||
|
||||
self.assertEqual(len(chain), 1, 'certificate chain length')
|
||||
assert len(chain) == 1, 'certificate chain length'
|
||||
|
||||
cert = chain[0]
|
||||
|
||||
self.assertEqual(
|
||||
cert['subject']['common_name'],
|
||||
'default',
|
||||
'certificate subject common name',
|
||||
)
|
||||
self.assertEqual(
|
||||
cert['issuer']['common_name'],
|
||||
'default',
|
||||
'certificate issuer common name',
|
||||
)
|
||||
assert (
|
||||
cert['subject']['common_name'] == 'default'
|
||||
), 'certificate subject common name'
|
||||
assert (
|
||||
cert['issuer']['common_name'] == 'default'
|
||||
), 'certificate issuer common name'
|
||||
|
||||
self.assertLess(
|
||||
assert (
|
||||
abs(
|
||||
self.sec_epoch()
|
||||
- self.openssl_date_to_sec_epoch(cert['validity']['since'])
|
||||
),
|
||||
5,
|
||||
'certificate validity since',
|
||||
)
|
||||
self.assertEqual(
|
||||
)
|
||||
< 5
|
||||
), 'certificate validity since'
|
||||
assert (
|
||||
self.openssl_date_to_sec_epoch(cert['validity']['until'])
|
||||
- self.openssl_date_to_sec_epoch(cert['validity']['since']),
|
||||
2592000,
|
||||
'certificate validity until',
|
||||
)
|
||||
- self.openssl_date_to_sec_epoch(cert['validity']['since'])
|
||||
== 2592000
|
||||
), 'certificate validity until'
|
||||
|
||||
def test_tls_certificate_chain(self):
|
||||
self.load('empty')
|
||||
|
@ -228,10 +217,14 @@ class TestTLS(TestApplicationTLS):
|
|||
'openssl',
|
||||
'req',
|
||||
'-new',
|
||||
'-subj', '/CN=int/',
|
||||
'-config', self.testdir + '/openssl.conf',
|
||||
'-out', self.testdir + '/int.csr',
|
||||
'-keyout', self.testdir + '/int.key',
|
||||
'-subj',
|
||||
'/CN=int/',
|
||||
'-config',
|
||||
self.temp_dir + '/openssl.conf',
|
||||
'-out',
|
||||
self.temp_dir + '/int.csr',
|
||||
'-keyout',
|
||||
self.temp_dir + '/int.key',
|
||||
],
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
|
@ -241,15 +234,19 @@ class TestTLS(TestApplicationTLS):
|
|||
'openssl',
|
||||
'req',
|
||||
'-new',
|
||||
'-subj', '/CN=end/',
|
||||
'-config', self.testdir + '/openssl.conf',
|
||||
'-out', self.testdir + '/end.csr',
|
||||
'-keyout', self.testdir + '/end.key',
|
||||
'-subj',
|
||||
'/CN=end/',
|
||||
'-config',
|
||||
self.temp_dir + '/openssl.conf',
|
||||
'-out',
|
||||
self.temp_dir + '/end.csr',
|
||||
'-keyout',
|
||||
self.temp_dir + '/end.key',
|
||||
],
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
|
||||
with open(self.testdir + '/ca.conf', 'w') as f:
|
||||
with open(self.temp_dir + '/ca.conf', 'w') as f:
|
||||
f.write(
|
||||
"""[ ca ]
|
||||
default_ca = myca
|
||||
|
@ -269,16 +266,16 @@ commonName = supplied
|
|||
[ myca_extensions ]
|
||||
basicConstraints = critical,CA:TRUE"""
|
||||
% {
|
||||
'dir': self.testdir,
|
||||
'database': self.testdir + '/certindex',
|
||||
'certserial': self.testdir + '/certserial',
|
||||
'dir': self.temp_dir,
|
||||
'database': self.temp_dir + '/certindex',
|
||||
'certserial': self.temp_dir + '/certserial',
|
||||
}
|
||||
)
|
||||
|
||||
with open(self.testdir + '/certserial', 'w') as f:
|
||||
with open(self.temp_dir + '/certserial', 'w') as f:
|
||||
f.write('1000')
|
||||
|
||||
with open(self.testdir + '/certindex', 'w') as f:
|
||||
with open(self.temp_dir + '/certindex', 'w') as f:
|
||||
f.write('')
|
||||
|
||||
subprocess.call(
|
||||
|
@ -286,12 +283,18 @@ basicConstraints = critical,CA:TRUE"""
|
|||
'openssl',
|
||||
'ca',
|
||||
'-batch',
|
||||
'-subj', '/CN=int/',
|
||||
'-config', self.testdir + '/ca.conf',
|
||||
'-keyfile', self.testdir + '/root.key',
|
||||
'-cert', self.testdir + '/root.crt',
|
||||
'-in', self.testdir + '/int.csr',
|
||||
'-out', self.testdir + '/int.crt',
|
||||
'-subj',
|
||||
'/CN=int/',
|
||||
'-config',
|
||||
self.temp_dir + '/ca.conf',
|
||||
'-keyfile',
|
||||
self.temp_dir + '/root.key',
|
||||
'-cert',
|
||||
self.temp_dir + '/root.crt',
|
||||
'-in',
|
||||
self.temp_dir + '/int.csr',
|
||||
'-out',
|
||||
self.temp_dir + '/int.crt',
|
||||
],
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
|
@ -301,50 +304,50 @@ basicConstraints = critical,CA:TRUE"""
|
|||
'openssl',
|
||||
'ca',
|
||||
'-batch',
|
||||
'-subj', '/CN=end/',
|
||||
'-config', self.testdir + '/ca.conf',
|
||||
'-keyfile', self.testdir + '/int.key',
|
||||
'-cert', self.testdir + '/int.crt',
|
||||
'-in', self.testdir + '/end.csr',
|
||||
'-out', self.testdir + '/end.crt',
|
||||
'-subj',
|
||||
'/CN=end/',
|
||||
'-config',
|
||||
self.temp_dir + '/ca.conf',
|
||||
'-keyfile',
|
||||
self.temp_dir + '/int.key',
|
||||
'-cert',
|
||||
self.temp_dir + '/int.crt',
|
||||
'-in',
|
||||
self.temp_dir + '/end.csr',
|
||||
'-out',
|
||||
self.temp_dir + '/end.crt',
|
||||
],
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
|
||||
crt_path = self.testdir + '/end-int.crt'
|
||||
end_path = self.testdir + '/end.crt'
|
||||
int_path = self.testdir + '/int.crt'
|
||||
crt_path = self.temp_dir + '/end-int.crt'
|
||||
end_path = self.temp_dir + '/end.crt'
|
||||
int_path = self.temp_dir + '/int.crt'
|
||||
|
||||
with open(crt_path, 'wb') as crt, \
|
||||
open(end_path, 'rb') as end, \
|
||||
open(int_path, 'rb') as int:
|
||||
with open(crt_path, 'wb') as crt, open(end_path, 'rb') as end, open(
|
||||
int_path, 'rb'
|
||||
) as int:
|
||||
crt.write(end.read() + int.read())
|
||||
|
||||
self.context = ssl.create_default_context()
|
||||
self.context.check_hostname = False
|
||||
self.context.verify_mode = ssl.CERT_REQUIRED
|
||||
self.context.load_verify_locations(self.testdir + '/root.crt')
|
||||
self.context.load_verify_locations(self.temp_dir + '/root.crt')
|
||||
|
||||
# incomplete chain
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.certificate_load('end', 'end'),
|
||||
'certificate chain end upload',
|
||||
)
|
||||
assert 'success' in self.certificate_load(
|
||||
'end', 'end'
|
||||
), 'certificate chain end upload'
|
||||
|
||||
chain = self.conf_get('/certificates/end/chain')
|
||||
self.assertEqual(len(chain), 1, 'certificate chain end length')
|
||||
self.assertEqual(
|
||||
chain[0]['subject']['common_name'],
|
||||
'end',
|
||||
'certificate chain end subject common name',
|
||||
)
|
||||
self.assertEqual(
|
||||
chain[0]['issuer']['common_name'],
|
||||
'int',
|
||||
'certificate chain end issuer common name',
|
||||
)
|
||||
assert len(chain) == 1, 'certificate chain end length'
|
||||
assert (
|
||||
chain[0]['subject']['common_name'] == 'end'
|
||||
), 'certificate chain end subject common name'
|
||||
assert (
|
||||
chain[0]['issuer']['common_name'] == 'int'
|
||||
), 'certificate chain end issuer common name'
|
||||
|
||||
self.add_tls(cert='end')
|
||||
|
||||
|
@ -353,79 +356,61 @@ basicConstraints = critical,CA:TRUE"""
|
|||
except ssl.SSLError:
|
||||
resp = None
|
||||
|
||||
self.assertEqual(resp, None, 'certificate chain incomplete chain')
|
||||
assert resp == None, 'certificate chain incomplete chain'
|
||||
|
||||
# intermediate
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.certificate_load('int', 'int'),
|
||||
'certificate chain int upload',
|
||||
)
|
||||
assert 'success' in self.certificate_load(
|
||||
'int', 'int'
|
||||
), 'certificate chain int upload'
|
||||
|
||||
chain = self.conf_get('/certificates/int/chain')
|
||||
self.assertEqual(len(chain), 1, 'certificate chain int length')
|
||||
self.assertEqual(
|
||||
chain[0]['subject']['common_name'],
|
||||
'int',
|
||||
'certificate chain int subject common name',
|
||||
)
|
||||
self.assertEqual(
|
||||
chain[0]['issuer']['common_name'],
|
||||
'root',
|
||||
'certificate chain int issuer common name',
|
||||
)
|
||||
assert len(chain) == 1, 'certificate chain int length'
|
||||
assert (
|
||||
chain[0]['subject']['common_name'] == 'int'
|
||||
), 'certificate chain int subject common name'
|
||||
assert (
|
||||
chain[0]['issuer']['common_name'] == 'root'
|
||||
), 'certificate chain int issuer common name'
|
||||
|
||||
self.add_tls(cert='int')
|
||||
|
||||
self.assertEqual(
|
||||
self.get_ssl()['status'], 200, 'certificate chain intermediate'
|
||||
)
|
||||
assert (
|
||||
self.get_ssl()['status'] == 200
|
||||
), 'certificate chain intermediate'
|
||||
|
||||
# intermediate server
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.certificate_load('end-int', 'end'),
|
||||
'certificate chain end-int upload',
|
||||
)
|
||||
assert 'success' in self.certificate_load(
|
||||
'end-int', 'end'
|
||||
), 'certificate chain end-int upload'
|
||||
|
||||
chain = self.conf_get('/certificates/end-int/chain')
|
||||
self.assertEqual(len(chain), 2, 'certificate chain end-int length')
|
||||
self.assertEqual(
|
||||
chain[0]['subject']['common_name'],
|
||||
'end',
|
||||
'certificate chain end-int int subject common name',
|
||||
)
|
||||
self.assertEqual(
|
||||
chain[0]['issuer']['common_name'],
|
||||
'int',
|
||||
'certificate chain end-int int issuer common name',
|
||||
)
|
||||
self.assertEqual(
|
||||
chain[1]['subject']['common_name'],
|
||||
'int',
|
||||
'certificate chain end-int end subject common name',
|
||||
)
|
||||
self.assertEqual(
|
||||
chain[1]['issuer']['common_name'],
|
||||
'root',
|
||||
'certificate chain end-int end issuer common name',
|
||||
)
|
||||
assert len(chain) == 2, 'certificate chain end-int length'
|
||||
assert (
|
||||
chain[0]['subject']['common_name'] == 'end'
|
||||
), 'certificate chain end-int int subject common name'
|
||||
assert (
|
||||
chain[0]['issuer']['common_name'] == 'int'
|
||||
), 'certificate chain end-int int issuer common name'
|
||||
assert (
|
||||
chain[1]['subject']['common_name'] == 'int'
|
||||
), 'certificate chain end-int end subject common name'
|
||||
assert (
|
||||
chain[1]['issuer']['common_name'] == 'root'
|
||||
), 'certificate chain end-int end issuer common name'
|
||||
|
||||
self.add_tls(cert='end-int')
|
||||
|
||||
self.assertEqual(
|
||||
self.get_ssl()['status'],
|
||||
200,
|
||||
'certificate chain intermediate server',
|
||||
)
|
||||
assert (
|
||||
self.get_ssl()['status'] == 200
|
||||
), 'certificate chain intermediate server'
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_tls_reconfigure(self):
|
||||
self.load('empty')
|
||||
|
||||
self.assertEqual(self.get()['status'], 200, 'init')
|
||||
assert self.get()['status'] == 200, 'init'
|
||||
|
||||
self.certificate()
|
||||
|
||||
|
@ -435,21 +420,17 @@ basicConstraints = critical,CA:TRUE"""
|
|||
read_timeout=1,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'initial status')
|
||||
assert resp['status'] == 200, 'initial status'
|
||||
|
||||
self.add_tls()
|
||||
|
||||
self.assertEqual(
|
||||
self.get(sock=sock)['status'], 200, 'reconfigure status'
|
||||
)
|
||||
self.assertEqual(
|
||||
self.get_ssl()['status'], 200, 'reconfigure tls status'
|
||||
)
|
||||
assert self.get(sock=sock)['status'] == 200, 'reconfigure status'
|
||||
assert self.get_ssl()['status'] == 200, 'reconfigure tls status'
|
||||
|
||||
def test_tls_keepalive(self):
|
||||
self.load('mirror')
|
||||
|
||||
self.assertEqual(self.get()['status'], 200, 'init')
|
||||
assert self.get()['status'] == 200, 'init'
|
||||
|
||||
self.certificate()
|
||||
|
||||
|
@ -466,7 +447,7 @@ basicConstraints = critical,CA:TRUE"""
|
|||
read_timeout=1,
|
||||
)
|
||||
|
||||
self.assertEqual(resp['body'], '0123456789', 'keepalive 1')
|
||||
assert resp['body'] == '0123456789', 'keepalive 1'
|
||||
|
||||
resp = self.post_ssl(
|
||||
headers={
|
||||
|
@ -478,13 +459,13 @@ basicConstraints = critical,CA:TRUE"""
|
|||
body='0123456789',
|
||||
)
|
||||
|
||||
self.assertEqual(resp['body'], '0123456789', 'keepalive 2')
|
||||
assert resp['body'] == '0123456789', 'keepalive 2'
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_tls_keepalive_certificate_remove(self):
|
||||
self.load('empty')
|
||||
|
||||
self.assertEqual(self.get()['status'], 200, 'init')
|
||||
assert self.get()['status'] == 200, 'init'
|
||||
|
||||
self.certificate()
|
||||
|
||||
|
@ -506,19 +487,17 @@ basicConstraints = critical,CA:TRUE"""
|
|||
except:
|
||||
resp = None
|
||||
|
||||
self.assertEqual(resp, None, 'keepalive remove certificate')
|
||||
assert resp == None, 'keepalive remove certificate'
|
||||
|
||||
@unittest.skip('not yet')
|
||||
@pytest.mark.skip('not yet')
|
||||
def test_tls_certificates_remove_all(self):
|
||||
self.load('empty')
|
||||
|
||||
self.certificate()
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf_delete('/certificates'),
|
||||
'remove all certificates',
|
||||
)
|
||||
assert 'success' in self.conf_delete(
|
||||
'/certificates'
|
||||
), 'remove all certificates'
|
||||
|
||||
def test_tls_application_respawn(self):
|
||||
self.load('mirror')
|
||||
|
@ -544,7 +523,7 @@ basicConstraints = critical,CA:TRUE"""
|
|||
|
||||
subprocess.call(['kill', '-9', app_id])
|
||||
|
||||
self.skip_alerts.append(r'process %s exited on signal 9' % app_id)
|
||||
skip_alert(r'process %s exited on signal 9' % app_id)
|
||||
|
||||
self.wait_for_record(
|
||||
re.compile(
|
||||
|
@ -562,15 +541,13 @@ basicConstraints = critical,CA:TRUE"""
|
|||
body='0123456789',
|
||||
)
|
||||
|
||||
self.assertEqual(resp['status'], 200, 'application respawn status')
|
||||
self.assertEqual(
|
||||
resp['body'], '0123456789', 'application respawn body'
|
||||
)
|
||||
assert resp['status'] == 200, 'application respawn status'
|
||||
assert resp['body'] == '0123456789', 'application respawn body'
|
||||
|
||||
def test_tls_url_scheme(self):
|
||||
self.load('variables')
|
||||
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.post(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
|
@ -578,16 +555,15 @@ basicConstraints = critical,CA:TRUE"""
|
|||
'Custom-Header': '',
|
||||
'Connection': 'close',
|
||||
}
|
||||
)['headers']['Wsgi-Url-Scheme'],
|
||||
'http',
|
||||
'url scheme http',
|
||||
)
|
||||
)['headers']['Wsgi-Url-Scheme']
|
||||
== 'http'
|
||||
), 'url scheme http'
|
||||
|
||||
self.certificate()
|
||||
|
||||
self.add_tls(application='variables')
|
||||
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.post_ssl(
|
||||
headers={
|
||||
'Host': 'localhost',
|
||||
|
@ -595,10 +571,9 @@ basicConstraints = critical,CA:TRUE"""
|
|||
'Custom-Header': '',
|
||||
'Connection': 'close',
|
||||
}
|
||||
)['headers']['Wsgi-Url-Scheme'],
|
||||
'https',
|
||||
'url scheme https',
|
||||
)
|
||||
)['headers']['Wsgi-Url-Scheme']
|
||||
== 'https'
|
||||
), 'url scheme https'
|
||||
|
||||
def test_tls_big_upload(self):
|
||||
self.load('upload')
|
||||
|
@ -610,15 +585,14 @@ basicConstraints = critical,CA:TRUE"""
|
|||
filename = 'test.txt'
|
||||
data = '0123456789' * 9000
|
||||
|
||||
res = self.post_ssl(body={
|
||||
'file': {
|
||||
'filename': filename,
|
||||
'type': 'text/plain',
|
||||
'data': io.StringIO(data),
|
||||
res = self.post_ssl(
|
||||
body={
|
||||
'file': {
|
||||
'filename': filename,
|
||||
'type': 'text/plain',
|
||||
'data': io.StringIO(data),
|
||||
}
|
||||
}
|
||||
})
|
||||
self.assertEqual(res['status'], 200, 'status ok')
|
||||
self.assertEqual(res['body'], filename + data)
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestTLS.main()
|
||||
)
|
||||
assert res['status'] == 200, 'status ok'
|
||||
assert res['body'] == filename + data
|
||||
|
|
|
@ -2,49 +2,46 @@ import os
|
|||
import re
|
||||
|
||||
from unit.applications.lang.python import TestApplicationPython
|
||||
from conftest import option
|
||||
|
||||
|
||||
class TestUpstreamsRR(TestApplicationPython):
|
||||
prerequisites = {'modules': {'python': 'any'}}
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
def setup_method(self):
|
||||
super().setup_method()
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"*:7080": {"pass": "upstreams/one"},
|
||||
"*:7090": {"pass": "upstreams/two"},
|
||||
"*:7081": {"pass": "routes/one"},
|
||||
"*:7082": {"pass": "routes/two"},
|
||||
"*:7083": {"pass": "routes/three"},
|
||||
},
|
||||
"upstreams": {
|
||||
"one": {
|
||||
"servers": {
|
||||
"127.0.0.1:7081": {},
|
||||
"127.0.0.1:7082": {},
|
||||
},
|
||||
},
|
||||
"two": {
|
||||
"servers": {
|
||||
"127.0.0.1:7081": {},
|
||||
"127.0.0.1:7082": {},
|
||||
},
|
||||
},
|
||||
},
|
||||
"routes": {
|
||||
"one": [{"action": {"return": 200}}],
|
||||
"two": [{"action": {"return": 201}}],
|
||||
"three": [{"action": {"return": 202}}],
|
||||
},
|
||||
"applications": {},
|
||||
assert 'success' in self.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"*:7080": {"pass": "upstreams/one"},
|
||||
"*:7090": {"pass": "upstreams/two"},
|
||||
"*:7081": {"pass": "routes/one"},
|
||||
"*:7082": {"pass": "routes/two"},
|
||||
"*:7083": {"pass": "routes/three"},
|
||||
},
|
||||
),
|
||||
'upstreams initial configuration',
|
||||
)
|
||||
"upstreams": {
|
||||
"one": {
|
||||
"servers": {
|
||||
"127.0.0.1:7081": {},
|
||||
"127.0.0.1:7082": {},
|
||||
},
|
||||
},
|
||||
"two": {
|
||||
"servers": {
|
||||
"127.0.0.1:7081": {},
|
||||
"127.0.0.1:7082": {},
|
||||
},
|
||||
},
|
||||
},
|
||||
"routes": {
|
||||
"one": [{"action": {"return": 200}}],
|
||||
"two": [{"action": {"return": 201}}],
|
||||
"three": [{"action": {"return": 202}}],
|
||||
},
|
||||
"applications": {},
|
||||
},
|
||||
), 'upstreams initial configuration'
|
||||
|
||||
self.cpu_count = os.cpu_count()
|
||||
|
||||
|
@ -91,113 +88,87 @@ Connection: close
|
|||
|
||||
def test_upstreams_rr_no_weight(self):
|
||||
resps = self.get_resps()
|
||||
self.assertEqual(sum(resps), 100, 'no weight sum')
|
||||
self.assertLessEqual(
|
||||
abs(resps[0] - resps[1]), self.cpu_count, 'no weight'
|
||||
)
|
||||
assert sum(resps) == 100, 'no weight sum'
|
||||
assert abs(resps[0] - resps[1]) <= self.cpu_count, 'no weight'
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf_delete('upstreams/one/servers/127.0.0.1:7081'),
|
||||
'no weight server remove',
|
||||
)
|
||||
assert 'success' in self.conf_delete(
|
||||
'upstreams/one/servers/127.0.0.1:7081'
|
||||
), 'no weight server remove'
|
||||
|
||||
resps = self.get_resps(req=50)
|
||||
self.assertEqual(resps[1], 50, 'no weight 2')
|
||||
assert resps[1] == 50, 'no weight 2'
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf({}, 'upstreams/one/servers/127.0.0.1:7081'),
|
||||
'no weight server revert',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{}, 'upstreams/one/servers/127.0.0.1:7081'
|
||||
), 'no weight server revert'
|
||||
|
||||
resps = self.get_resps()
|
||||
self.assertEqual(sum(resps), 100, 'no weight 3 sum')
|
||||
self.assertLessEqual(
|
||||
abs(resps[0] - resps[1]), self.cpu_count, 'no weight 3'
|
||||
)
|
||||
assert sum(resps) == 100, 'no weight 3 sum'
|
||||
assert abs(resps[0] - resps[1]) <= self.cpu_count, 'no weight 3'
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf({}, 'upstreams/one/servers/127.0.0.1:7083'),
|
||||
'no weight server new',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{}, 'upstreams/one/servers/127.0.0.1:7083'
|
||||
), 'no weight server new'
|
||||
|
||||
resps = self.get_resps()
|
||||
self.assertEqual(sum(resps), 100, 'no weight 4 sum')
|
||||
self.assertLessEqual(
|
||||
max(resps) - min(resps), self.cpu_count, 'no weight 4'
|
||||
)
|
||||
assert sum(resps) == 100, 'no weight 4 sum'
|
||||
assert max(resps) - min(resps) <= self.cpu_count, 'no weight 4'
|
||||
|
||||
resps = self.get_resps_sc(req=30)
|
||||
self.assertEqual(resps[0], 10, 'no weight 4 0')
|
||||
self.assertEqual(resps[1], 10, 'no weight 4 1')
|
||||
self.assertEqual(resps[2], 10, 'no weight 4 2')
|
||||
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):
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf({"weight": 3}, 'upstreams/one/servers/127.0.0.1:7081'),
|
||||
'configure weight',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{"weight": 3}, 'upstreams/one/servers/127.0.0.1:7081'
|
||||
), 'configure weight'
|
||||
|
||||
resps = self.get_resps_sc()
|
||||
self.assertEqual(resps[0], 75, 'weight 3 0')
|
||||
self.assertEqual(resps[1], 25, 'weight 3 1')
|
||||
assert resps[0] == 75, 'weight 3 0'
|
||||
assert resps[1] == 25, 'weight 3 1'
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf_delete('upstreams/one/servers/127.0.0.1:7081/weight'),
|
||||
'configure weight remove',
|
||||
)
|
||||
assert 'success' in self.conf_delete(
|
||||
'upstreams/one/servers/127.0.0.1:7081/weight'
|
||||
), 'configure weight remove'
|
||||
resps = self.get_resps_sc(req=10)
|
||||
self.assertEqual(resps[0], 5, 'weight 0 0')
|
||||
self.assertEqual(resps[1], 5, 'weight 0 1')
|
||||
assert resps[0] == 5, 'weight 0 0'
|
||||
assert resps[1] == 5, 'weight 0 1'
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf('1', 'upstreams/one/servers/127.0.0.1:7081/weight'),
|
||||
'configure weight 1',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
'1', 'upstreams/one/servers/127.0.0.1:7081/weight'
|
||||
), 'configure weight 1'
|
||||
|
||||
resps = self.get_resps_sc()
|
||||
self.assertEqual(resps[0], 50, 'weight 1 0')
|
||||
self.assertEqual(resps[1], 50, 'weight 1 1')
|
||||
assert resps[0] == 50, 'weight 1 0'
|
||||
assert resps[1] == 50, 'weight 1 1'
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{
|
||||
"127.0.0.1:7081": {"weight": 3},
|
||||
"127.0.0.1:7083": {"weight": 2},
|
||||
},
|
||||
'upstreams/one/servers',
|
||||
),
|
||||
'configure weight 2',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{
|
||||
"127.0.0.1:7081": {"weight": 3},
|
||||
"127.0.0.1:7083": {"weight": 2},
|
||||
},
|
||||
'upstreams/one/servers',
|
||||
), 'configure weight 2'
|
||||
|
||||
resps = self.get_resps_sc()
|
||||
self.assertEqual(resps[0], 60, 'weight 2 0')
|
||||
self.assertEqual(resps[2], 40, 'weight 2 1')
|
||||
assert resps[0] == 60, 'weight 2 0'
|
||||
assert resps[2] == 40, 'weight 2 1'
|
||||
|
||||
def test_upstreams_rr_weight_rational(self):
|
||||
def set_weights(w1, w2):
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{
|
||||
"127.0.0.1:7081": {"weight": w1},
|
||||
"127.0.0.1:7082": {"weight": w2},
|
||||
},
|
||||
'upstreams/one/servers',
|
||||
),
|
||||
'configure weights',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{
|
||||
"127.0.0.1:7081": {"weight": w1},
|
||||
"127.0.0.1:7082": {"weight": w2},
|
||||
},
|
||||
'upstreams/one/servers',
|
||||
), 'configure weights'
|
||||
|
||||
def check_reqs(w1, w2, reqs=10):
|
||||
resps = self.get_resps_sc(req=reqs)
|
||||
self.assertEqual(resps[0], reqs * w1 / (w1 + w2), 'weight 1')
|
||||
self.assertEqual(resps[1], reqs * w2 / (w1 + w2), 'weight 2')
|
||||
assert resps[0] == reqs * w1 / (w1 + w2), 'weight 1'
|
||||
assert resps[1] == reqs * w2 / (w1 + w2), 'weight 2'
|
||||
|
||||
def check_weights(w1, w2):
|
||||
set_weights(w1, w2)
|
||||
|
@ -207,39 +178,33 @@ Connection: close
|
|||
check_weights(0, 999999.0123456)
|
||||
check_weights(1, 9)
|
||||
check_weights(100000, 900000)
|
||||
check_weights(1, .25)
|
||||
check_weights(1, 0.25)
|
||||
check_weights(0.2, .8)
|
||||
check_weights(1, 0.25)
|
||||
check_weights(0.2, 0.8)
|
||||
check_weights(1, 1.5)
|
||||
check_weights(1e-3, 1E-3)
|
||||
check_weights(1e-3, 1e-3)
|
||||
check_weights(1e-20, 1e-20)
|
||||
check_weights(1e4, 1e4)
|
||||
check_weights(1000000, 1000000)
|
||||
|
||||
set_weights(0.25, 0.25)
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf_delete('upstreams/one/servers/127.0.0.1:7081/weight'),
|
||||
'delete weight',
|
||||
)
|
||||
assert 'success' in self.conf_delete(
|
||||
'upstreams/one/servers/127.0.0.1:7081/weight'
|
||||
), 'delete weight'
|
||||
check_reqs(1, 0.25)
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{
|
||||
"127.0.0.1:7081": {"weight": 0.1},
|
||||
"127.0.0.1:7082": {"weight": 1},
|
||||
"127.0.0.1:7083": {"weight": 0.9},
|
||||
},
|
||||
'upstreams/one/servers',
|
||||
),
|
||||
'configure weights',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{
|
||||
"127.0.0.1:7081": {"weight": 0.1},
|
||||
"127.0.0.1:7082": {"weight": 1},
|
||||
"127.0.0.1:7083": {"weight": 0.9},
|
||||
},
|
||||
'upstreams/one/servers',
|
||||
), 'configure weights'
|
||||
resps = self.get_resps_sc(req=20)
|
||||
self.assertEqual(resps[0], 1, 'weight 3 1')
|
||||
self.assertEqual(resps[1], 10, 'weight 3 2')
|
||||
self.assertEqual(resps[2], 9, 'weight 3 3')
|
||||
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 sum_resps(*args):
|
||||
|
@ -250,90 +215,77 @@ Connection: close
|
|||
return sum
|
||||
|
||||
resps = self.get_resps_sc(req=30, port=7090)
|
||||
self.assertEqual(resps[0], 15, 'dep two before 0')
|
||||
self.assertEqual(resps[1], 15, 'dep two before 1')
|
||||
assert resps[0] == 15, 'dep two before 0'
|
||||
assert resps[1] == 15, 'dep two before 1'
|
||||
|
||||
resps = self.get_resps_sc(req=30)
|
||||
self.assertEqual(resps[0], 15, 'dep one before 0')
|
||||
self.assertEqual(resps[1], 15, 'dep one before 1')
|
||||
assert resps[0] == 15, 'dep one before 0'
|
||||
assert resps[1] == 15, 'dep one before 1'
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf('2', 'upstreams/two/servers/127.0.0.1:7081/weight'),
|
||||
'configure dep weight',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
'2', 'upstreams/two/servers/127.0.0.1:7081/weight'
|
||||
), 'configure dep weight'
|
||||
|
||||
resps = self.get_resps_sc(req=30, port=7090)
|
||||
self.assertEqual(resps[0], 20, 'dep two 0')
|
||||
self.assertEqual(resps[1], 10, 'dep two 1')
|
||||
assert resps[0] == 20, 'dep two 0'
|
||||
assert resps[1] == 10, 'dep two 1'
|
||||
|
||||
resps = self.get_resps_sc(req=30)
|
||||
self.assertEqual(resps[0], 15, 'dep one 0')
|
||||
self.assertEqual(resps[1], 15, 'dep one 1')
|
||||
assert resps[0] == 15, 'dep one 0'
|
||||
assert resps[1] == 15, 'dep one 1'
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf('1', 'upstreams/two/servers/127.0.0.1:7081/weight'),
|
||||
'configure dep weight 1',
|
||||
)
|
||||
assert 'success' in self.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))
|
||||
|
||||
|
||||
self.assertEqual(sum(r_one), 100, 'dep one mix sum')
|
||||
self.assertLessEqual(
|
||||
abs(r_one[0] - r_one[1]), self.cpu_count, 'dep one mix'
|
||||
)
|
||||
self.assertEqual(sum(r_two), 100, 'dep two mix sum')
|
||||
self.assertLessEqual(
|
||||
abs(r_two[0] - r_two[1]), self.cpu_count, 'dep two mix'
|
||||
)
|
||||
assert sum(r_one) == 100, 'dep one mix sum'
|
||||
assert abs(r_one[0] - r_one[1]) <= self.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'
|
||||
|
||||
def test_upstreams_rr_delay(self):
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"*:7080": {"pass": "upstreams/one"},
|
||||
"*:7081": {"pass": "routes"},
|
||||
"*:7082": {"pass": "routes"},
|
||||
},
|
||||
"upstreams": {
|
||||
"one": {
|
||||
"servers": {
|
||||
"127.0.0.1:7081": {},
|
||||
"127.0.0.1:7082": {},
|
||||
},
|
||||
assert 'success' in self.conf(
|
||||
{
|
||||
"listeners": {
|
||||
"*:7080": {"pass": "upstreams/one"},
|
||||
"*:7081": {"pass": "routes"},
|
||||
"*:7082": {"pass": "routes"},
|
||||
},
|
||||
"upstreams": {
|
||||
"one": {
|
||||
"servers": {
|
||||
"127.0.0.1:7081": {},
|
||||
"127.0.0.1:7082": {},
|
||||
},
|
||||
},
|
||||
"routes": [
|
||||
{
|
||||
"match": {"destination": "*:7081"},
|
||||
"action": {"pass": "applications/delayed"},
|
||||
},
|
||||
{
|
||||
"match": {"destination": "*:7082"},
|
||||
"action": {"return": 201},
|
||||
},
|
||||
],
|
||||
"applications": {
|
||||
"delayed": {
|
||||
"type": "python",
|
||||
"processes": {"spare": 0},
|
||||
"path": self.current_dir + "/python/delayed",
|
||||
"working_directory": self.current_dir
|
||||
+ "/python/delayed",
|
||||
"module": "wsgi",
|
||||
}
|
||||
},
|
||||
},
|
||||
),
|
||||
'upstreams initial configuration',
|
||||
)
|
||||
"routes": [
|
||||
{
|
||||
"match": {"destination": "*:7081"},
|
||||
"action": {"pass": "applications/delayed"},
|
||||
},
|
||||
{
|
||||
"match": {"destination": "*:7082"},
|
||||
"action": {"return": 201},
|
||||
},
|
||||
],
|
||||
"applications": {
|
||||
"delayed": {
|
||||
"type": "python",
|
||||
"processes": {"spare": 0},
|
||||
"path": option.test_dir + "/python/delayed",
|
||||
"working_directory": option.test_dir
|
||||
+ "/python/delayed",
|
||||
"module": "wsgi",
|
||||
}
|
||||
},
|
||||
},
|
||||
), 'upstreams initial configuration'
|
||||
|
||||
req = 50
|
||||
|
||||
|
@ -357,12 +309,12 @@ Connection: close
|
|||
resp = self.recvall(socks[i]).decode()
|
||||
socks[i].close()
|
||||
|
||||
m = re.search('HTTP/1.1 20(\d)', resp)
|
||||
self.assertIsNotNone(m, 'status')
|
||||
m = re.search(r'HTTP/1.1 20(\d)', resp)
|
||||
assert m is not None, 'status'
|
||||
resps[int(m.group(1))] += 1
|
||||
|
||||
self.assertEqual(sum(resps), req, 'delay sum')
|
||||
self.assertLessEqual(abs(resps[0] - resps[1]), self.cpu_count, 'delay')
|
||||
assert sum(resps) == req, 'delay sum'
|
||||
assert abs(resps[0] - resps[1]) <= self.cpu_count, 'delay'
|
||||
|
||||
def test_upstreams_rr_active_req(self):
|
||||
conns = 5
|
||||
|
@ -389,59 +341,46 @@ Connection: close
|
|||
# Send one more request and read response to make sure that previous
|
||||
# requests had enough time to reach server.
|
||||
|
||||
self.assertEqual(self.get()['body'], '')
|
||||
assert self.get()['body'] == ''
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{"127.0.0.1:7083": {"weight": 2}}, 'upstreams/one/servers',
|
||||
),
|
||||
'active req new server',
|
||||
)
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf_delete('upstreams/one/servers/127.0.0.1:7083'),
|
||||
'active req server remove',
|
||||
)
|
||||
self.assertIn(
|
||||
'success', self.conf_delete('listeners/*:7080'), 'delete listener'
|
||||
)
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf_delete('upstreams/one'),
|
||||
'active req upstream remove',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{"127.0.0.1:7083": {"weight": 2}}, 'upstreams/one/servers',
|
||||
), 'active req new server'
|
||||
assert 'success' in self.conf_delete(
|
||||
'upstreams/one/servers/127.0.0.1:7083'
|
||||
), 'active req server remove'
|
||||
assert 'success' in self.conf_delete(
|
||||
'listeners/*:7080'
|
||||
), 'delete listener'
|
||||
assert 'success' in self.conf_delete(
|
||||
'upstreams/one'
|
||||
), 'active req upstream remove'
|
||||
|
||||
for i in range(conns):
|
||||
self.assertEqual(
|
||||
self.http(b'', sock=socks[i], raw=True)['body'],
|
||||
'',
|
||||
'active req GET',
|
||||
)
|
||||
assert (
|
||||
self.http(b'', sock=socks[i], raw=True)['body'] == ''
|
||||
), 'active req GET'
|
||||
|
||||
self.assertEqual(
|
||||
self.http(b"""0123456789""", sock=socks2[i], raw=True)['body'],
|
||||
'',
|
||||
'active req POST',
|
||||
)
|
||||
assert (
|
||||
self.http(b"""0123456789""", sock=socks2[i], raw=True)['body']
|
||||
== ''
|
||||
), 'active req POST'
|
||||
|
||||
def test_upstreams_rr_bad_server(self):
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf({"weight": 1}, 'upstreams/one/servers/127.0.0.1:7084'),
|
||||
'configure bad server',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{"weight": 1}, 'upstreams/one/servers/127.0.0.1:7084'
|
||||
), 'configure bad server'
|
||||
|
||||
resps = self.get_resps_sc(req=30)
|
||||
self.assertEqual(resps[0], 10, 'bad server 0')
|
||||
self.assertEqual(resps[1], 10, 'bad server 1')
|
||||
self.assertEqual(sum(resps), 20, 'bad server sum')
|
||||
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()
|
||||
|
||||
self.assertEqual(resps[0], 50, 'pipeline 0')
|
||||
self.assertEqual(resps[1], 50, 'pipeline 1')
|
||||
assert resps[0] == 50, 'pipeline 0'
|
||||
assert resps[1] == 50, 'pipeline 1'
|
||||
|
||||
def test_upstreams_rr_post(self):
|
||||
resps = [0, 0]
|
||||
|
@ -449,120 +388,87 @@ Connection: close
|
|||
resps[self.get()['status'] % 10] += 1
|
||||
resps[self.post(body='0123456789')['status'] % 10] += 1
|
||||
|
||||
self.assertEqual(sum(resps), 100, 'post sum')
|
||||
self.assertLessEqual(abs(resps[0] - resps[1]), self.cpu_count, 'post')
|
||||
assert sum(resps) == 100, 'post sum'
|
||||
assert abs(resps[0] - resps[1]) <= self.cpu_count, 'post'
|
||||
|
||||
def test_upstreams_rr_unix(self):
|
||||
addr_0 = self.testdir + '/sock_0'
|
||||
addr_1 = self.testdir + '/sock_1'
|
||||
addr_0 = self.temp_dir + '/sock_0'
|
||||
addr_1 = self.temp_dir + '/sock_1'
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{
|
||||
"*:7080": {"pass": "upstreams/one"},
|
||||
"unix:" + addr_0: {"pass": "routes/one"},
|
||||
"unix:" + addr_1: {"pass": "routes/two"},
|
||||
},
|
||||
'listeners',
|
||||
),
|
||||
'configure listeners unix',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{
|
||||
"*:7080": {"pass": "upstreams/one"},
|
||||
"unix:" + addr_0: {"pass": "routes/one"},
|
||||
"unix:" + addr_1: {"pass": "routes/two"},
|
||||
},
|
||||
'listeners',
|
||||
), 'configure listeners unix'
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{"unix:" + addr_0: {}, "unix:" + addr_1: {}},
|
||||
'upstreams/one/servers',
|
||||
),
|
||||
'configure servers unix',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{"unix:" + addr_0: {}, "unix:" + addr_1: {}},
|
||||
'upstreams/one/servers',
|
||||
), 'configure servers unix'
|
||||
|
||||
resps = self.get_resps_sc()
|
||||
|
||||
self.assertEqual(resps[0], 50, 'unix 0')
|
||||
self.assertEqual(resps[1], 50, 'unix 1')
|
||||
assert resps[0] == 50, 'unix 0'
|
||||
assert resps[1] == 50, 'unix 1'
|
||||
|
||||
def test_upstreams_rr_ipv6(self):
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{
|
||||
"*:7080": {"pass": "upstreams/one"},
|
||||
"[::1]:7081": {"pass": "routes/one"},
|
||||
"[::1]:7082": {"pass": "routes/two"},
|
||||
},
|
||||
'listeners',
|
||||
),
|
||||
'configure listeners ipv6',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{
|
||||
"*:7080": {"pass": "upstreams/one"},
|
||||
"[::1]:7081": {"pass": "routes/one"},
|
||||
"[::1]:7082": {"pass": "routes/two"},
|
||||
},
|
||||
'listeners',
|
||||
), 'configure listeners ipv6'
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{"[::1]:7081": {}, "[::1]:7082": {}}, 'upstreams/one/servers'
|
||||
),
|
||||
'configure servers ipv6',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
{"[::1]:7081": {}, "[::1]:7082": {}}, 'upstreams/one/servers'
|
||||
), 'configure servers ipv6'
|
||||
|
||||
resps = self.get_resps_sc()
|
||||
|
||||
self.assertEqual(resps[0], 50, 'ipv6 0')
|
||||
self.assertEqual(resps[1], 50, 'ipv6 1')
|
||||
assert resps[0] == 50, 'ipv6 0'
|
||||
assert resps[1] == 50, 'ipv6 1'
|
||||
|
||||
def test_upstreams_rr_servers_empty(self):
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf({}, 'upstreams/one/servers'),
|
||||
'configure servers empty',
|
||||
)
|
||||
self.assertEqual(self.get()['status'], 502, 'servers empty')
|
||||
assert 'success' in self.conf(
|
||||
{}, 'upstreams/one/servers'
|
||||
), 'configure servers empty'
|
||||
assert self.get()['status'] == 502, 'servers empty'
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{"127.0.0.1:7081": {"weight": 0}}, 'upstreams/one/servers'
|
||||
),
|
||||
'configure servers empty one',
|
||||
)
|
||||
self.assertEqual(self.get()['status'], 502, 'servers empty one')
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{
|
||||
"127.0.0.1:7081": {"weight": 0},
|
||||
"127.0.0.1:7082": {"weight": 0},
|
||||
},
|
||||
'upstreams/one/servers',
|
||||
),
|
||||
'configure servers empty two',
|
||||
)
|
||||
self.assertEqual(self.get()['status'], 502, 'servers empty two')
|
||||
assert 'success' in self.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(
|
||||
{
|
||||
"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'
|
||||
|
||||
def test_upstreams_rr_invalid(self):
|
||||
self.assertIn(
|
||||
'error', self.conf({}, 'upstreams'), 'upstreams empty',
|
||||
)
|
||||
self.assertIn(
|
||||
'error', self.conf({}, 'upstreams/one'), 'named upstreams empty',
|
||||
)
|
||||
self.assertIn(
|
||||
'error',
|
||||
self.conf({}, 'upstreams/one/servers/127.0.0.1'),
|
||||
'invalid address',
|
||||
)
|
||||
self.assertIn(
|
||||
'error',
|
||||
self.conf({}, 'upstreams/one/servers/127.0.0.1:7081/blah'),
|
||||
'invalid server option',
|
||||
)
|
||||
assert 'error' in self.conf({}, 'upstreams'), 'upstreams empty'
|
||||
assert 'error' in self.conf(
|
||||
{}, 'upstreams/one'
|
||||
), 'named upstreams empty'
|
||||
assert 'error' in self.conf(
|
||||
{}, 'upstreams/one/servers/127.0.0.1'
|
||||
), 'invalid address'
|
||||
assert 'error' in self.conf(
|
||||
{}, 'upstreams/one/servers/127.0.0.1:7081/blah'
|
||||
), 'invalid server option'
|
||||
|
||||
def check_weight(w):
|
||||
self.assertIn(
|
||||
'error',
|
||||
self.conf(w, 'upstreams/one/servers/127.0.0.1:7081/weight'),
|
||||
'invalid weight option',
|
||||
)
|
||||
assert 'error' in self.conf(
|
||||
w, 'upstreams/one/servers/127.0.0.1:7081/weight'
|
||||
), 'invalid weight option'
|
||||
|
||||
check_weight({})
|
||||
check_weight('-1')
|
||||
check_weight('1.')
|
||||
|
@ -571,7 +477,3 @@ Connection: close
|
|||
check_weight('.01234567890123')
|
||||
check_weight('1000001')
|
||||
check_weight('2e6')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestUpstreamsRR.main()
|
||||
|
|
|
@ -2,6 +2,7 @@ import os
|
|||
from subprocess import call
|
||||
|
||||
from unit.applications.lang.python import TestApplicationPython
|
||||
from conftest import waitforfiles
|
||||
|
||||
|
||||
class TestUSR1(TestApplicationPython):
|
||||
|
@ -12,83 +13,74 @@ class TestUSR1(TestApplicationPython):
|
|||
|
||||
log = 'access.log'
|
||||
log_new = 'new.log'
|
||||
log_path = self.testdir + '/' + log
|
||||
log_path = self.temp_dir + '/' + log
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf('"' + log_path + '"', 'access_log'),
|
||||
'access log configure',
|
||||
)
|
||||
assert 'success' in self.conf(
|
||||
'"' + log_path + '"', 'access_log'
|
||||
), 'access log configure'
|
||||
|
||||
self.assertTrue(self.waitforfiles(log_path), 'open')
|
||||
assert waitforfiles(log_path), 'open'
|
||||
|
||||
os.rename(log_path, self.testdir + '/' + log_new)
|
||||
os.rename(log_path, self.temp_dir + '/' + log_new)
|
||||
|
||||
self.assertEqual(self.get()['status'], 200)
|
||||
assert self.get()['status'] == 200
|
||||
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(r'"GET / HTTP/1.1" 200 0 "-" "-"', log_new),
|
||||
'rename new',
|
||||
)
|
||||
self.assertFalse(os.path.isfile(log_path), 'rename old')
|
||||
assert (
|
||||
self.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'
|
||||
|
||||
with open(self.testdir + '/unit.pid', 'r') as f:
|
||||
with open(self.temp_dir + '/unit.pid', 'r') as f:
|
||||
pid = f.read().rstrip()
|
||||
|
||||
call(['kill', '-s', 'USR1', pid])
|
||||
|
||||
self.assertTrue(self.waitforfiles(log_path), 'reopen')
|
||||
assert waitforfiles(log_path), 'reopen'
|
||||
|
||||
self.assertEqual(self.get(url='/usr1')['status'], 200)
|
||||
assert self.get(url='/usr1')['status'] == 200
|
||||
|
||||
self.stop()
|
||||
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(r'"GET /usr1 HTTP/1.1" 200 0 "-" "-"', log),
|
||||
'reopen 2',
|
||||
)
|
||||
self.assertIsNone(
|
||||
self.search_in_log(r'/usr1', log_new), 'rename new 2'
|
||||
)
|
||||
assert (
|
||||
self.wait_for_record(r'"GET /usr1 HTTP/1.1" 200 0 "-" "-"', log)
|
||||
is not None
|
||||
), 'reopen 2'
|
||||
assert self.search_in_log(r'/usr1', log_new) is None, 'rename new 2'
|
||||
|
||||
def test_usr1_unit_log(self):
|
||||
self.load('log_body')
|
||||
|
||||
log_new = 'new.log'
|
||||
log_path = self.testdir + '/unit.log'
|
||||
log_path_new = self.testdir + '/' + log_new
|
||||
log_path = self.temp_dir + '/unit.log'
|
||||
log_path_new = self.temp_dir + '/' + log_new
|
||||
|
||||
os.rename(log_path, log_path_new)
|
||||
|
||||
body = 'body_for_a_log_new'
|
||||
self.assertEqual(self.post(body=body)['status'], 200)
|
||||
assert self.post(body=body)['status'] == 200
|
||||
|
||||
self.assertIsNotNone(
|
||||
self.wait_for_record(body, log_new), 'rename new'
|
||||
)
|
||||
self.assertFalse(os.path.isfile(log_path), 'rename old')
|
||||
assert self.wait_for_record(body, log_new) is not None, 'rename new'
|
||||
assert not os.path.isfile(log_path), 'rename old'
|
||||
|
||||
with open(self.testdir + '/unit.pid', 'r') as f:
|
||||
with open(self.temp_dir + '/unit.pid', 'r') as f:
|
||||
pid = f.read().rstrip()
|
||||
|
||||
call(['kill', '-s', 'USR1', pid])
|
||||
|
||||
self.assertTrue(self.waitforfiles(log_path), 'reopen')
|
||||
assert waitforfiles(log_path), 'reopen'
|
||||
|
||||
body = 'body_for_a_log_unit'
|
||||
self.assertEqual(self.post(body=body)['status'], 200)
|
||||
assert self.post(body=body)['status'] == 200
|
||||
|
||||
self.stop()
|
||||
|
||||
self.assertIsNotNone(self.wait_for_record(body), 'rename new')
|
||||
self.assertIsNone(self.search_in_log(body, log_new), 'rename new 2')
|
||||
assert self.wait_for_record(body) is not None, 'rename new'
|
||||
assert self.search_in_log(body, log_new) is None, 'rename new 2'
|
||||
|
||||
# merge two log files into unit.log to check alerts
|
||||
|
||||
with open(log_path, 'w') as unit_log, \
|
||||
open(log_path_new, 'r') as unit_log_new:
|
||||
with open(log_path, 'w') as unit_log, open(
|
||||
log_path_new, 'r'
|
||||
) as unit_log_new:
|
||||
unit_log.write(unit_log_new.read())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestUSR1.main()
|
||||
|
|
|
@ -4,52 +4,48 @@ from unit.applications.proto import TestApplicationProto
|
|||
class TestVariables(TestApplicationProto):
|
||||
prerequisites = {}
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
def setup_method(self):
|
||||
super().setup_method()
|
||||
|
||||
self.assertIn(
|
||||
'success',
|
||||
self.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "routes/$method"}},
|
||||
"routes": {
|
||||
"GET": [{"action": {"return": 201}}],
|
||||
"POST": [{"action": {"return": 202}}],
|
||||
"3": [{"action": {"return": 203}}],
|
||||
"4*": [{"action": {"return": 204}}],
|
||||
"blahGET}": [{"action": {"return": 205}}],
|
||||
"5GET": [{"action": {"return": 206}}],
|
||||
"GETGET": [{"action": {"return": 207}}],
|
||||
"localhost": [{"action": {"return": 208}}],
|
||||
},
|
||||
assert 'success' in self.conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "routes/$method"}},
|
||||
"routes": {
|
||||
"GET": [{"action": {"return": 201}}],
|
||||
"POST": [{"action": {"return": 202}}],
|
||||
"3": [{"action": {"return": 203}}],
|
||||
"4*": [{"action": {"return": 204}}],
|
||||
"blahGET}": [{"action": {"return": 205}}],
|
||||
"5GET": [{"action": {"return": 206}}],
|
||||
"GETGET": [{"action": {"return": 207}}],
|
||||
"localhost": [{"action": {"return": 208}}],
|
||||
},
|
||||
),
|
||||
'configure routes',
|
||||
)
|
||||
},
|
||||
), 'configure routes'
|
||||
|
||||
def conf_routes(self, routes):
|
||||
self.assertIn('success', self.conf(routes, 'listeners/*:7080/pass'))
|
||||
assert 'success' in self.conf(routes, 'listeners/*:7080/pass')
|
||||
|
||||
def test_variables_method(self):
|
||||
self.assertEqual(self.get()['status'], 201, 'method GET')
|
||||
self.assertEqual(self.post()['status'], 202, 'method POST')
|
||||
assert self.get()['status'] == 201, 'method GET'
|
||||
assert self.post()['status'] == 202, 'method POST'
|
||||
|
||||
def test_variables_uri(self):
|
||||
self.conf_routes("\"routes$uri\"")
|
||||
|
||||
self.assertEqual(self.get(url='/3')['status'], 203, 'uri')
|
||||
self.assertEqual(self.get(url='/4*')['status'], 204, 'uri 2')
|
||||
self.assertEqual(self.get(url='/4%2A')['status'], 204, 'uri 3')
|
||||
assert self.get(url='/3')['status'] == 203, 'uri'
|
||||
assert self.get(url='/4*')['status'] == 204, 'uri 2'
|
||||
assert self.get(url='/4%2A')['status'] == 204, 'uri 3'
|
||||
|
||||
def test_variables_host(self):
|
||||
self.conf_routes("\"routes/$host\"")
|
||||
|
||||
def check_host(host, status=208):
|
||||
self.assertEqual(
|
||||
assert (
|
||||
self.get(headers={'Host': host, 'Connection': 'close'})[
|
||||
'status'
|
||||
],
|
||||
status,
|
||||
]
|
||||
== status
|
||||
)
|
||||
|
||||
check_host('localhost')
|
||||
|
@ -61,43 +57,41 @@ class TestVariables(TestApplicationProto):
|
|||
|
||||
def test_variables_many(self):
|
||||
self.conf_routes("\"routes$uri$method\"")
|
||||
self.assertEqual(self.get(url='/5')['status'], 206, 'many')
|
||||
assert self.get(url='/5')['status'] == 206, 'many'
|
||||
|
||||
self.conf_routes("\"routes${uri}${method}\"")
|
||||
self.assertEqual(self.get(url='/5')['status'], 206, 'many 2')
|
||||
assert self.get(url='/5')['status'] == 206, 'many 2'
|
||||
|
||||
self.conf_routes("\"routes${uri}$method\"")
|
||||
self.assertEqual(self.get(url='/5')['status'], 206, 'many 3')
|
||||
assert self.get(url='/5')['status'] == 206, 'many 3'
|
||||
|
||||
self.conf_routes("\"routes/$method$method\"")
|
||||
self.assertEqual(self.get()['status'], 207, 'many 4')
|
||||
assert self.get()['status'] == 207, 'many 4'
|
||||
|
||||
self.conf_routes("\"routes/$method$uri\"")
|
||||
self.assertEqual(self.get()['status'], 404, 'no route')
|
||||
self.assertEqual(self.get(url='/blah')['status'], 404, 'no route 2')
|
||||
assert self.get()['status'] == 404, 'no route'
|
||||
assert self.get(url='/blah')['status'] == 404, 'no route 2'
|
||||
|
||||
def test_variables_replace(self):
|
||||
self.assertEqual(self.get()['status'], 201)
|
||||
assert self.get()['status'] == 201
|
||||
|
||||
self.conf_routes("\"routes$uri\"")
|
||||
self.assertEqual(self.get(url='/3')['status'], 203)
|
||||
assert self.get(url='/3')['status'] == 203
|
||||
|
||||
self.conf_routes("\"routes/${method}\"")
|
||||
self.assertEqual(self.post()['status'], 202)
|
||||
assert self.post()['status'] == 202
|
||||
|
||||
self.conf_routes("\"routes${uri}\"")
|
||||
self.assertEqual(self.get(url='/4*')['status'], 204)
|
||||
assert self.get(url='/4*')['status'] == 204
|
||||
|
||||
self.conf_routes("\"routes/blah$method}\"")
|
||||
self.assertEqual(self.get()['status'], 205)
|
||||
assert self.get()['status'] == 205
|
||||
|
||||
def test_variables_invalid(self):
|
||||
def check_variables(routes):
|
||||
self.assertIn(
|
||||
'error',
|
||||
self.conf(routes, 'listeners/*:7080/pass'),
|
||||
'invalid variables',
|
||||
)
|
||||
assert 'error' in self.conf(
|
||||
routes, 'listeners/*:7080/pass'
|
||||
), 'invalid variables'
|
||||
|
||||
check_variables("\"routes$\"")
|
||||
check_variables("\"routes${\"")
|
||||
|
@ -106,6 +100,3 @@ class TestVariables(TestApplicationProto):
|
|||
check_variables("\"routes$uriblah\"")
|
||||
check_variables("\"routes${uri\"")
|
||||
check_variables("\"routes${{uri}\"")
|
||||
|
||||
if __name__ == '__main__':
|
||||
TestVariables.main()
|
||||
|
|
|
@ -2,17 +2,18 @@ import os
|
|||
import subprocess
|
||||
|
||||
from unit.applications.proto import TestApplicationProto
|
||||
from conftest import option
|
||||
|
||||
|
||||
class TestApplicationGo(TestApplicationProto):
|
||||
@classmethod
|
||||
def setUpClass(cls, complete_check=True):
|
||||
unit = super().setUpClass(complete_check=False)
|
||||
def setup_class(cls, complete_check=True):
|
||||
unit = super().setup_class(complete_check=False)
|
||||
|
||||
# check go module
|
||||
|
||||
go_app = TestApplicationGo()
|
||||
go_app.testdir = unit.testdir
|
||||
go_app.temp_dir = unit.temp_dir
|
||||
proc = go_app.prepare_env('empty', 'app')
|
||||
if proc and proc.returncode == 0:
|
||||
cls.available['modules']['go'] = []
|
||||
|
@ -20,8 +21,8 @@ class TestApplicationGo(TestApplicationProto):
|
|||
return unit if not complete_check else unit.complete()
|
||||
|
||||
def prepare_env(self, script, name, static=False):
|
||||
if not os.path.exists(self.testdir + '/go'):
|
||||
os.mkdir(self.testdir + '/go')
|
||||
if not os.path.exists(self.temp_dir + '/go'):
|
||||
os.mkdir(self.temp_dir + '/go')
|
||||
|
||||
env = os.environ.copy()
|
||||
env['GOPATH'] = self.pardir + '/build/go'
|
||||
|
@ -35,16 +36,16 @@ class TestApplicationGo(TestApplicationProto):
|
|||
'-ldflags',
|
||||
'-extldflags "-static"',
|
||||
'-o',
|
||||
self.testdir + '/go/' + name,
|
||||
self.current_dir + '/go/' + script + '/' + name + '.go',
|
||||
self.temp_dir + '/go/' + name,
|
||||
option.test_dir + '/go/' + script + '/' + name + '.go',
|
||||
]
|
||||
else:
|
||||
args = [
|
||||
'go',
|
||||
'build',
|
||||
'-o',
|
||||
self.testdir + '/go/' + name,
|
||||
self.current_dir + '/go/' + script + '/' + name + '.go',
|
||||
self.temp_dir + '/go/' + name,
|
||||
option.test_dir + '/go/' + script + '/' + name + '.go',
|
||||
]
|
||||
|
||||
try:
|
||||
|
@ -59,8 +60,8 @@ class TestApplicationGo(TestApplicationProto):
|
|||
def load(self, script, name='app', **kwargs):
|
||||
static_build = False
|
||||
|
||||
wdir = self.current_dir + "/go/" + script
|
||||
executable = self.testdir + "/go/" + name
|
||||
wdir = option.test_dir + "/go/" + script
|
||||
executable = self.temp_dir + "/go/" + name
|
||||
|
||||
if 'isolation' in kwargs and 'rootfs' in kwargs['isolation']:
|
||||
wdir = "/go/"
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
import glob
|
||||
import os
|
||||
import pytest
|
||||
import shutil
|
||||
import subprocess
|
||||
|
||||
from unit.applications.proto import TestApplicationProto
|
||||
from conftest import option
|
||||
|
||||
|
||||
class TestApplicationJava(TestApplicationProto):
|
||||
def load(self, script, name='app', **kwargs):
|
||||
app_path = self.testdir + '/java'
|
||||
app_path = self.temp_dir + '/java'
|
||||
web_inf_path = app_path + '/WEB-INF/'
|
||||
classes_path = web_inf_path + 'classes/'
|
||||
script_path = self.current_dir + '/java/' + script + '/'
|
||||
script_path = option.test_dir + '/java/' + script + '/'
|
||||
|
||||
if not os.path.isdir(app_path):
|
||||
os.makedirs(app_path)
|
||||
|
@ -54,7 +56,7 @@ class TestApplicationJava(TestApplicationProto):
|
|||
)
|
||||
|
||||
if not ws_jars:
|
||||
self.fail('websocket api jar not found.')
|
||||
pytest.fail('websocket api jar not found.')
|
||||
|
||||
javac = [
|
||||
'javac',
|
||||
|
@ -69,7 +71,7 @@ class TestApplicationJava(TestApplicationProto):
|
|||
process.communicate()
|
||||
|
||||
except:
|
||||
self.fail('Cann\'t run javac process.')
|
||||
pytest.fail('Cann\'t run javac process.')
|
||||
|
||||
self._load_conf(
|
||||
{
|
||||
|
|
|
@ -3,12 +3,13 @@ import shutil
|
|||
from urllib.parse import quote
|
||||
|
||||
from unit.applications.proto import TestApplicationProto
|
||||
from conftest import option, public_dir
|
||||
|
||||
|
||||
class TestApplicationNode(TestApplicationProto):
|
||||
@classmethod
|
||||
def setUpClass(cls, complete_check=True):
|
||||
unit = super().setUpClass(complete_check=False)
|
||||
def setup_class(cls, complete_check=True):
|
||||
unit = super().setup_class(complete_check=False)
|
||||
|
||||
# check node module
|
||||
|
||||
|
@ -21,17 +22,17 @@ class TestApplicationNode(TestApplicationProto):
|
|||
# copy application
|
||||
|
||||
shutil.copytree(
|
||||
self.current_dir + '/node/' + script, self.testdir + '/node'
|
||||
option.test_dir + '/node/' + script, self.temp_dir + '/node'
|
||||
)
|
||||
|
||||
# copy modules
|
||||
|
||||
shutil.copytree(
|
||||
self.pardir + '/node/node_modules',
|
||||
self.testdir + '/node/node_modules',
|
||||
self.temp_dir + '/node/node_modules',
|
||||
)
|
||||
|
||||
self.public_dir(self.testdir + '/node')
|
||||
public_dir(self.temp_dir + '/node')
|
||||
|
||||
self._load_conf(
|
||||
{
|
||||
|
@ -42,7 +43,7 @@ class TestApplicationNode(TestApplicationProto):
|
|||
script: {
|
||||
"type": "external",
|
||||
"processes": {"spare": 0},
|
||||
"working_directory": self.testdir + '/node',
|
||||
"working_directory": self.temp_dir + '/node',
|
||||
"executable": name,
|
||||
}
|
||||
},
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
from unit.applications.proto import TestApplicationProto
|
||||
from conftest import option
|
||||
|
||||
|
||||
class TestApplicationPerl(TestApplicationProto):
|
||||
application_type = "perl"
|
||||
|
||||
def load(self, script, name='psgi.pl', **kwargs):
|
||||
script_path = self.current_dir + '/perl/' + script
|
||||
script_path = option.test_dir + '/perl/' + script
|
||||
|
||||
self._load_conf(
|
||||
{
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
from unit.applications.proto import TestApplicationProto
|
||||
from conftest import option
|
||||
|
||||
|
||||
class TestApplicationPHP(TestApplicationProto):
|
||||
application_type = "php"
|
||||
|
||||
def load(self, script, index='index.php', **kwargs):
|
||||
script_path = self.current_dir + '/php/' + script
|
||||
script_path = option.test_dir + '/php/' + script
|
||||
|
||||
self._load_conf(
|
||||
{
|
||||
|
|
|
@ -1,20 +1,23 @@
|
|||
import os
|
||||
import shutil
|
||||
import pytest
|
||||
|
||||
from unit.applications.proto import TestApplicationProto
|
||||
from conftest import option
|
||||
|
||||
|
||||
class TestApplicationPython(TestApplicationProto):
|
||||
application_type = "python"
|
||||
|
||||
def load(self, script, name=None, **kwargs):
|
||||
print()
|
||||
if name is None:
|
||||
name = script
|
||||
|
||||
if script[0] == '/':
|
||||
script_path = script
|
||||
else:
|
||||
script_path = self.current_dir + '/python/' + script
|
||||
script_path = option.test_dir + '/python/' + script
|
||||
|
||||
if kwargs.get('isolation') and kwargs['isolation'].get('rootfs'):
|
||||
rootfs = kwargs['isolation']['rootfs']
|
||||
|
@ -27,12 +30,17 @@ class TestApplicationPython(TestApplicationProto):
|
|||
|
||||
script_path = '/app/python/' + name
|
||||
|
||||
appication_type = self.get_appication_type()
|
||||
|
||||
if appication_type is None:
|
||||
appication_type = self.application_type
|
||||
|
||||
self._load_conf(
|
||||
{
|
||||
"listeners": {"*:7080": {"pass": "applications/" + name}},
|
||||
"applications": {
|
||||
name: {
|
||||
"type": self.application_type,
|
||||
"type": appication_type,
|
||||
"processes": {"spare": 0},
|
||||
"path": script_path,
|
||||
"working_directory": script_path,
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
from unit.applications.proto import TestApplicationProto
|
||||
from conftest import option
|
||||
|
||||
|
||||
class TestApplicationRuby(TestApplicationProto):
|
||||
application_type = "ruby"
|
||||
|
||||
def load(self, script, name='config.ru', **kwargs):
|
||||
script_path = self.current_dir + '/ruby/' + script
|
||||
script_path = option.test_dir + '/ruby/' + script
|
||||
|
||||
self._load_conf(
|
||||
{
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import os
|
||||
import re
|
||||
import time
|
||||
|
||||
from unit.control import TestControl
|
||||
from conftest import option
|
||||
|
||||
|
||||
class TestApplicationProto(TestControl):
|
||||
|
@ -12,7 +14,7 @@ class TestApplicationProto(TestControl):
|
|||
return time.mktime(time.strptime(date, template))
|
||||
|
||||
def search_in_log(self, pattern, name='unit.log'):
|
||||
with open(self.testdir + '/' + name, 'r', errors='ignore') as f:
|
||||
with open(self.temp_dir + '/' + name, 'r', errors='ignore') as f:
|
||||
return re.search(pattern, f.read())
|
||||
|
||||
def wait_for_record(self, pattern, name='unit.log'):
|
||||
|
@ -26,6 +28,16 @@ class TestApplicationProto(TestControl):
|
|||
|
||||
return found
|
||||
|
||||
def get_appication_type(self):
|
||||
current_test = (
|
||||
os.environ.get('PYTEST_CURRENT_TEST').split(':')[-1].split(' ')[0]
|
||||
)
|
||||
|
||||
if current_test in option.generated_tests:
|
||||
return option.generated_tests[current_test]
|
||||
|
||||
return None
|
||||
|
||||
def _load_conf(self, conf, **kwargs):
|
||||
if 'applications' in conf:
|
||||
for app in conf['applications'].keys():
|
||||
|
@ -39,6 +51,4 @@ class TestApplicationProto(TestControl):
|
|||
if 'isolation' in kwargs:
|
||||
app_conf['isolation'] = kwargs['isolation']
|
||||
|
||||
self.assertIn(
|
||||
'success', self.conf(conf), 'load application configuration'
|
||||
)
|
||||
assert 'success' in self.conf(conf), 'load application configuration'
|
||||
|
|
|
@ -4,19 +4,20 @@ import ssl
|
|||
import subprocess
|
||||
|
||||
from unit.applications.proto import TestApplicationProto
|
||||
from conftest import option
|
||||
|
||||
|
||||
class TestApplicationTLS(TestApplicationProto):
|
||||
def __init__(self, test):
|
||||
super().__init__(test)
|
||||
def setup_method(self):
|
||||
super().setup_method()
|
||||
|
||||
self.context = ssl.create_default_context()
|
||||
self.context.check_hostname = False
|
||||
self.context.verify_mode = ssl.CERT_NONE
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls, complete_check=True):
|
||||
unit = super().setUpClass(complete_check=False)
|
||||
def setup_class(cls, complete_check=True):
|
||||
unit = super().setup_class(complete_check=False)
|
||||
|
||||
# check tls module
|
||||
|
||||
|
@ -45,9 +46,9 @@ class TestApplicationTLS(TestApplicationProto):
|
|||
'-x509',
|
||||
'-new',
|
||||
'-subj', '/CN=' + name + '/',
|
||||
'-config', self.testdir + '/openssl.conf',
|
||||
'-out', self.testdir + '/' + name + '.crt',
|
||||
'-keyout', self.testdir + '/' + name + '.key',
|
||||
'-config', self.temp_dir + '/openssl.conf',
|
||||
'-out', self.temp_dir + '/' + name + '.crt',
|
||||
'-keyout', self.temp_dir + '/' + name + '.key',
|
||||
],
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
|
@ -59,8 +60,8 @@ class TestApplicationTLS(TestApplicationProto):
|
|||
if key is None:
|
||||
key = crt
|
||||
|
||||
key_path = self.testdir + '/' + key + '.key'
|
||||
crt_path = self.testdir + '/' + crt + '.crt'
|
||||
key_path = self.temp_dir + '/' + key + '.key'
|
||||
crt_path = self.temp_dir + '/' + crt + '.crt'
|
||||
|
||||
with open(key_path, 'rb') as k, open(crt_path, 'rb') as c:
|
||||
return self.conf(k.read() + c.read(), '/certificates/' + crt)
|
||||
|
@ -87,7 +88,7 @@ class TestApplicationTLS(TestApplicationProto):
|
|||
return ssl.get_server_certificate(addr, ssl_version=ssl_version)
|
||||
|
||||
def openssl_conf(self):
|
||||
conf_path = self.testdir + '/openssl.conf'
|
||||
conf_path = self.temp_dir + '/openssl.conf'
|
||||
|
||||
if os.path.exists(conf_path):
|
||||
return
|
||||
|
@ -105,7 +106,7 @@ distinguished_name = req_distinguished_name
|
|||
if name is None:
|
||||
name = script
|
||||
|
||||
script_path = self.current_dir + '/python/' + script
|
||||
script_path = option.test_dir + '/python/' + script
|
||||
|
||||
self._load_conf(
|
||||
{
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import base64
|
||||
import hashlib
|
||||
import itertools
|
||||
import pytest
|
||||
import random
|
||||
import re
|
||||
import select
|
||||
|
@ -21,9 +22,6 @@ class TestApplicationWebsocket(TestApplicationProto):
|
|||
OP_PONG = 0x0A
|
||||
CLOSE_CODES = [1000, 1001, 1002, 1003, 1007, 1008, 1009, 1010, 1011]
|
||||
|
||||
def __init__(self, preinit=False):
|
||||
self.preinit = preinit
|
||||
|
||||
def key(self):
|
||||
raw_key = bytes(random.getrandbits(8) for _ in range(16))
|
||||
return base64.b64encode(raw_key).decode()
|
||||
|
@ -56,7 +54,7 @@ class TestApplicationWebsocket(TestApplicationProto):
|
|||
while True:
|
||||
rlist = select.select([sock], [], [], 60)[0]
|
||||
if not rlist:
|
||||
self.fail('Can\'t read response from server.')
|
||||
pytest.fail('Can\'t read response from server.')
|
||||
|
||||
resp += sock.recv(4096).decode()
|
||||
|
||||
|
@ -84,7 +82,7 @@ class TestApplicationWebsocket(TestApplicationProto):
|
|||
# For all current cases if the "read_timeout" was changed
|
||||
# than test do not expect to get a response from server.
|
||||
if read_timeout == 60:
|
||||
self.fail('Can\'t read response from server.')
|
||||
pytest.fail('Can\'t read response from server.')
|
||||
break
|
||||
|
||||
data += sock.recv(bytes - len(data))
|
||||
|
@ -130,19 +128,19 @@ class TestApplicationWebsocket(TestApplicationProto):
|
|||
code, = struct.unpack('!H', data[:2])
|
||||
reason = data[2:].decode('utf-8')
|
||||
if not (code in self.CLOSE_CODES or 3000 <= code < 5000):
|
||||
self.fail('Invalid status code')
|
||||
pytest.fail('Invalid status code')
|
||||
frame['code'] = code
|
||||
frame['reason'] = reason
|
||||
elif length == 0:
|
||||
frame['code'] = 1005
|
||||
frame['reason'] = ''
|
||||
else:
|
||||
self.fail('Close frame too short')
|
||||
pytest.fail('Close frame too short')
|
||||
|
||||
frame['data'] = data
|
||||
|
||||
if frame['mask']:
|
||||
self.fail('Received frame with mask')
|
||||
pytest.fail('Received frame with mask')
|
||||
|
||||
return frame
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ class TestControl(TestHTTP):
|
|||
args = {
|
||||
'url': url,
|
||||
'sock_type': 'unix',
|
||||
'addr': self.testdir + '/control.unit.sock',
|
||||
'addr': self.temp_dir + '/control.unit.sock',
|
||||
}
|
||||
|
||||
if conf is not None:
|
||||
|
|
|
@ -13,7 +13,7 @@ from unit.applications.proto import TestApplicationProto
|
|||
class TestFeatureIsolation(TestApplicationProto):
|
||||
allns = ['pid', 'mnt', 'ipc', 'uts', 'cgroup', 'net']
|
||||
|
||||
def check(self, available, testdir):
|
||||
def check(self, available, temp_dir):
|
||||
test_conf = {"namespaces": {"credential": True}}
|
||||
|
||||
module = ''
|
||||
|
@ -45,7 +45,7 @@ class TestFeatureIsolation(TestApplicationProto):
|
|||
if not module:
|
||||
return
|
||||
|
||||
module.testdir = testdir
|
||||
module.temp_dir = temp_dir
|
||||
module.load(app)
|
||||
|
||||
resp = module.conf(test_conf, 'applications/' + app + '/isolation')
|
||||
|
|
|
@ -2,12 +2,14 @@ import binascii
|
|||
import io
|
||||
import json
|
||||
import os
|
||||
import pytest
|
||||
import re
|
||||
import select
|
||||
import socket
|
||||
import time
|
||||
|
||||
from unit.main import TestUnit
|
||||
from conftest import option
|
||||
|
||||
|
||||
class TestHTTP(TestUnit):
|
||||
|
@ -56,7 +58,7 @@ class TestHTTP(TestUnit):
|
|||
sock.connect(connect_args)
|
||||
except ConnectionRefusedError:
|
||||
sock.close()
|
||||
self.fail('Client can\'t connect to the server.')
|
||||
pytest.fail('Client can\'t connect to the server.')
|
||||
|
||||
else:
|
||||
sock = kwargs['sock']
|
||||
|
@ -128,7 +130,7 @@ class TestHTTP(TestUnit):
|
|||
return (resp, sock)
|
||||
|
||||
def log_out(self, log, encoding):
|
||||
if TestUnit.detailed:
|
||||
if option.detailed:
|
||||
print('>>>')
|
||||
log = self.log_truncate(log)
|
||||
try:
|
||||
|
@ -137,7 +139,7 @@ class TestHTTP(TestUnit):
|
|||
print(log)
|
||||
|
||||
def log_in(self, log):
|
||||
if TestUnit.detailed:
|
||||
if option.detailed:
|
||||
print('<<<')
|
||||
log = self.log_truncate(log)
|
||||
try:
|
||||
|
@ -190,7 +192,7 @@ class TestHTTP(TestUnit):
|
|||
# For all current cases if the "read_timeout" was changed
|
||||
# than test do not expect to get a response from server.
|
||||
if timeout == timeout_default:
|
||||
self.fail('Can\'t read response from server.')
|
||||
pytest.fail('Can\'t read response from server.')
|
||||
break
|
||||
|
||||
try:
|
||||
|
@ -243,28 +245,28 @@ class TestHTTP(TestUnit):
|
|||
chunks = raw_body.split(crlf)
|
||||
|
||||
if len(chunks) < 3:
|
||||
self.fail('Invalid chunked body')
|
||||
pytest.fail('Invalid chunked body')
|
||||
|
||||
if chunks.pop() != b'':
|
||||
self.fail('No CRLF at the end of the body')
|
||||
pytest.fail('No CRLF at the end of the body')
|
||||
|
||||
try:
|
||||
last_size = int(chunks[-2], 16)
|
||||
except:
|
||||
self.fail('Invalid zero size chunk')
|
||||
pytest.fail('Invalid zero size chunk')
|
||||
|
||||
if last_size != 0 or chunks[-1] != b'':
|
||||
self.fail('Incomplete body')
|
||||
pytest.fail('Incomplete body')
|
||||
|
||||
body = b''
|
||||
while len(chunks) >= 2:
|
||||
try:
|
||||
size = int(chunks.pop(0), 16)
|
||||
except:
|
||||
self.fail('Invalid chunk size %s' % str(size))
|
||||
pytest.fail('Invalid chunk size %s' % str(size))
|
||||
|
||||
if size == 0:
|
||||
self.assertEqual(len(chunks), 1, 'last zero size')
|
||||
assert len(chunks) == 1, 'last zero size'
|
||||
break
|
||||
|
||||
temp_body = crlf.join(chunks)
|
||||
|
@ -280,8 +282,8 @@ class TestHTTP(TestUnit):
|
|||
def _parse_json(self, resp):
|
||||
headers = resp['headers']
|
||||
|
||||
self.assertIn('Content-Type', headers)
|
||||
self.assertEqual(headers['Content-Type'], 'application/json')
|
||||
assert 'Content-Type' in headers
|
||||
assert headers['Content-Type'] == 'application/json'
|
||||
|
||||
resp['body'] = json.loads(resp['body'])
|
||||
|
||||
|
@ -305,7 +307,7 @@ class TestHTTP(TestUnit):
|
|||
|
||||
sock.close()
|
||||
|
||||
self.assertTrue(ret, 'socket connected')
|
||||
assert ret, 'socket connected'
|
||||
|
||||
def form_encode(self, fields):
|
||||
is_multipart = False
|
||||
|
@ -345,7 +347,7 @@ class TestHTTP(TestUnit):
|
|||
datatype = value['type']
|
||||
|
||||
if not isinstance(value['data'], io.IOBase):
|
||||
self.fail('multipart encoding of file requires a stream.')
|
||||
pytest.fail('multipart encoding of file requires a stream.')
|
||||
|
||||
data = value['data'].read()
|
||||
|
||||
|
@ -353,7 +355,7 @@ class TestHTTP(TestUnit):
|
|||
data = value
|
||||
|
||||
else:
|
||||
self.fail('multipart requires a string or stream data')
|
||||
pytest.fail('multipart requires a string or stream data')
|
||||
|
||||
body += (
|
||||
"--%s\r\nContent-Disposition: form-data; name=\"%s\""
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import argparse
|
||||
import atexit
|
||||
import fcntl
|
||||
import os
|
||||
import platform
|
||||
import pytest
|
||||
import re
|
||||
import shutil
|
||||
import signal
|
||||
|
@ -11,80 +11,19 @@ import subprocess
|
|||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
import unittest
|
||||
from conftest import option, public_dir, waitforfiles, _check_alerts, _print_log
|
||||
from multiprocessing import Process
|
||||
|
||||
|
||||
class TestUnit(unittest.TestCase):
|
||||
class TestUnit():
|
||||
|
||||
current_dir = os.path.abspath(
|
||||
os.path.join(os.path.dirname(__file__), os.pardir)
|
||||
)
|
||||
pardir = os.path.abspath(
|
||||
os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)
|
||||
)
|
||||
is_su = os.geteuid() == 0
|
||||
uid = os.geteuid()
|
||||
gid = os.getegid()
|
||||
architecture = platform.architecture()[0]
|
||||
system = platform.system()
|
||||
maxDiff = None
|
||||
|
||||
detailed = False
|
||||
save_log = False
|
||||
print_log = False
|
||||
unsafe = False
|
||||
|
||||
def __init__(self, methodName='runTest'):
|
||||
super().__init__(methodName)
|
||||
|
||||
if re.match(r'.*\/run\.py$', sys.argv[0]):
|
||||
args, rest = TestUnit._parse_args()
|
||||
|
||||
TestUnit._set_args(args)
|
||||
|
||||
def run(self, result=None):
|
||||
if not hasattr(self, 'application_type'):
|
||||
return super().run(result)
|
||||
|
||||
# rerun test for each available module version
|
||||
|
||||
type = self.application_type
|
||||
for module in self.prerequisites['modules']:
|
||||
if module in self.available['modules']:
|
||||
prereq_version = self.prerequisites['modules'][module]
|
||||
available_versions = self.available['modules'][module]
|
||||
|
||||
if prereq_version == 'all':
|
||||
for version in available_versions:
|
||||
self.application_type = type + ' ' + version
|
||||
super().run(result)
|
||||
elif prereq_version == 'any':
|
||||
self.application_type = type + ' ' + available_versions[0]
|
||||
super().run(result)
|
||||
else:
|
||||
for version in available_versions:
|
||||
if version.startswith(prereq_version):
|
||||
self.application_type = type + ' ' + version
|
||||
super().run(result)
|
||||
|
||||
@classmethod
|
||||
def main(cls):
|
||||
args, rest = TestUnit._parse_args()
|
||||
|
||||
for i, arg in enumerate(rest):
|
||||
if arg[:5] == 'test_':
|
||||
rest[i] = cls.__name__ + '.' + arg
|
||||
|
||||
sys.argv = sys.argv[:1] + rest
|
||||
|
||||
TestUnit._set_args(args)
|
||||
|
||||
unittest.main()
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls, complete_check=True):
|
||||
cls.available = {'modules': {}, 'features': {}}
|
||||
def setup_class(cls, complete_check=True):
|
||||
cls.available = option.available
|
||||
unit = TestUnit()
|
||||
|
||||
unit._run()
|
||||
|
@ -92,7 +31,7 @@ class TestUnit(unittest.TestCase):
|
|||
# read unit.log
|
||||
|
||||
for i in range(50):
|
||||
with open(unit.testdir + '/unit.log', 'r') as f:
|
||||
with open(unit.temp_dir + '/unit.log', 'r') as f:
|
||||
log = f.read()
|
||||
m = re.search('controller started', log)
|
||||
|
||||
|
@ -102,7 +41,7 @@ class TestUnit(unittest.TestCase):
|
|||
break
|
||||
|
||||
if m is None:
|
||||
unit._print_log()
|
||||
_print_log()
|
||||
exit("Unit is writing log too long")
|
||||
|
||||
# discover available modules from unit.log
|
||||
|
@ -128,8 +67,7 @@ class TestUnit(unittest.TestCase):
|
|||
missed.append(module)
|
||||
|
||||
if missed:
|
||||
print('Unit has no ' + ', '.join(missed) + ' module(s)')
|
||||
raise unittest.SkipTest()
|
||||
pytest.skip('Unit has no ' + ', '.join(missed) + ' module(s)')
|
||||
|
||||
# check features
|
||||
|
||||
|
@ -143,13 +81,12 @@ class TestUnit(unittest.TestCase):
|
|||
missed.append(feature)
|
||||
|
||||
if missed:
|
||||
print(', '.join(missed) + ' feature(s) not supported')
|
||||
raise unittest.SkipTest()
|
||||
pytest.skip(', '.join(missed) + ' feature(s) not supported')
|
||||
|
||||
def destroy():
|
||||
unit.stop()
|
||||
unit._check_alerts(log)
|
||||
shutil.rmtree(unit.testdir)
|
||||
_check_alerts(log)
|
||||
shutil.rmtree(unit.temp_dir)
|
||||
|
||||
def complete():
|
||||
destroy()
|
||||
|
@ -161,7 +98,7 @@ class TestUnit(unittest.TestCase):
|
|||
unit.complete = complete
|
||||
return unit
|
||||
|
||||
def setUp(self):
|
||||
def setup_method(self):
|
||||
self._run()
|
||||
|
||||
def _run(self):
|
||||
|
@ -171,82 +108,56 @@ class TestUnit(unittest.TestCase):
|
|||
if not os.path.isfile(self.unitd):
|
||||
exit("Could not find unit")
|
||||
|
||||
self.testdir = tempfile.mkdtemp(prefix='unit-test-')
|
||||
self.temp_dir = tempfile.mkdtemp(prefix='unit-test-')
|
||||
|
||||
self.public_dir(self.testdir)
|
||||
public_dir(self.temp_dir)
|
||||
|
||||
if oct(stat.S_IMODE(os.stat(build_dir).st_mode)) != '0o777':
|
||||
self.public_dir(build_dir)
|
||||
public_dir(build_dir)
|
||||
|
||||
os.mkdir(self.testdir + '/state')
|
||||
os.mkdir(self.temp_dir + '/state')
|
||||
|
||||
with open(self.testdir + '/unit.log', 'w') as log:
|
||||
with open(self.temp_dir + '/unit.log', 'w') as log:
|
||||
self._p = subprocess.Popen(
|
||||
[
|
||||
self.unitd,
|
||||
'--no-daemon',
|
||||
'--modules', self.pardir + '/build',
|
||||
'--state', self.testdir + '/state',
|
||||
'--pid', self.testdir + '/unit.pid',
|
||||
'--log', self.testdir + '/unit.log',
|
||||
'--control', 'unix:' + self.testdir + '/control.unit.sock',
|
||||
'--tmp', self.testdir,
|
||||
'--state', self.temp_dir + '/state',
|
||||
'--pid', self.temp_dir + '/unit.pid',
|
||||
'--log', self.temp_dir + '/unit.log',
|
||||
'--control', 'unix:' + self.temp_dir + '/control.unit.sock',
|
||||
'--tmp', self.temp_dir,
|
||||
],
|
||||
stderr=log,
|
||||
)
|
||||
|
||||
atexit.register(self.stop)
|
||||
|
||||
if not self.waitforfiles(self.testdir + '/control.unit.sock'):
|
||||
self._print_log()
|
||||
if not waitforfiles(self.temp_dir + '/control.unit.sock'):
|
||||
_print_log()
|
||||
exit("Could not start unit")
|
||||
|
||||
self._started = True
|
||||
|
||||
self.skip_alerts = [
|
||||
r'read signalfd\(4\) failed',
|
||||
r'sendmsg.+failed',
|
||||
r'recvmsg.+failed',
|
||||
]
|
||||
self.skip_sanitizer = False
|
||||
|
||||
def tearDown(self):
|
||||
def teardown_method(self):
|
||||
self.stop()
|
||||
|
||||
# detect errors and failures for current test
|
||||
|
||||
def list2reason(exc_list):
|
||||
if exc_list and exc_list[-1][0] is self:
|
||||
return exc_list[-1][1]
|
||||
|
||||
if hasattr(self, '_outcome'):
|
||||
result = self.defaultTestResult()
|
||||
self._feedErrorsToResult(result, self._outcome.errors)
|
||||
else:
|
||||
result = getattr(
|
||||
self, '_outcomeForDoCleanups', self._resultForDoCleanups
|
||||
)
|
||||
|
||||
success = not list2reason(result.errors) and not list2reason(
|
||||
result.failures
|
||||
)
|
||||
|
||||
# check unit.log for alerts
|
||||
|
||||
unit_log = self.testdir + '/unit.log'
|
||||
unit_log = self.temp_dir + '/unit.log'
|
||||
|
||||
with open(unit_log, 'r', encoding='utf-8', errors='ignore') as f:
|
||||
self._check_alerts(f.read())
|
||||
_check_alerts(f.read())
|
||||
|
||||
# remove unit.log
|
||||
|
||||
if not TestUnit.save_log and success:
|
||||
shutil.rmtree(self.testdir)
|
||||
|
||||
if not option.save_log:
|
||||
shutil.rmtree(self.temp_dir)
|
||||
else:
|
||||
self._print_log()
|
||||
_print_log()
|
||||
|
||||
self.assertListEqual(self.stop_errors, [None, None], 'stop errors')
|
||||
assert self.stop_errors == [None, None], 'stop errors'
|
||||
|
||||
def stop(self):
|
||||
if not self._started:
|
||||
|
@ -301,121 +212,3 @@ class TestUnit(unittest.TestCase):
|
|||
|
||||
if fail:
|
||||
return 'Fail to stop process'
|
||||
|
||||
def waitforfiles(self, *files):
|
||||
for i in range(50):
|
||||
wait = False
|
||||
ret = False
|
||||
|
||||
for f in files:
|
||||
if not os.path.exists(f):
|
||||
wait = True
|
||||
break
|
||||
|
||||
if wait:
|
||||
time.sleep(0.1)
|
||||
|
||||
else:
|
||||
ret = True
|
||||
break
|
||||
|
||||
return ret
|
||||
|
||||
def public_dir(self, path):
|
||||
os.chmod(path, 0o777)
|
||||
|
||||
for root, dirs, files in os.walk(path):
|
||||
for d in dirs:
|
||||
os.chmod(os.path.join(root, d), 0o777)
|
||||
for f in files:
|
||||
os.chmod(os.path.join(root, f), 0o777)
|
||||
|
||||
def _check_alerts(self, log):
|
||||
found = False
|
||||
|
||||
alerts = re.findall('.+\[alert\].+', log)
|
||||
|
||||
if alerts:
|
||||
print('All alerts/sanitizer errors found in log:')
|
||||
[print(alert) for alert in alerts]
|
||||
found = True
|
||||
|
||||
if self.skip_alerts:
|
||||
for skip in self.skip_alerts:
|
||||
alerts = [al for al in alerts if re.search(skip, al) is None]
|
||||
|
||||
if alerts:
|
||||
self._print_log(log)
|
||||
self.assertFalse(alerts, 'alert(s)')
|
||||
|
||||
if not self.skip_sanitizer:
|
||||
sanitizer_errors = re.findall('.+Sanitizer.+', log)
|
||||
|
||||
if sanitizer_errors:
|
||||
self._print_log(log)
|
||||
self.assertFalse(sanitizer_errors, 'sanitizer error(s)')
|
||||
|
||||
if found:
|
||||
print('skipped.')
|
||||
|
||||
@staticmethod
|
||||
def _parse_args():
|
||||
parser = argparse.ArgumentParser(add_help=False)
|
||||
|
||||
parser.add_argument(
|
||||
'-d',
|
||||
'--detailed',
|
||||
dest='detailed',
|
||||
action='store_true',
|
||||
help='Detailed output for tests',
|
||||
)
|
||||
parser.add_argument(
|
||||
'-l',
|
||||
'--log',
|
||||
dest='save_log',
|
||||
action='store_true',
|
||||
help='Save unit.log after the test execution',
|
||||
)
|
||||
parser.add_argument(
|
||||
'-r',
|
||||
'--reprint_log',
|
||||
dest='print_log',
|
||||
action='store_true',
|
||||
help='Print unit.log to stdout in case of errors',
|
||||
)
|
||||
parser.add_argument(
|
||||
'-u',
|
||||
'--unsafe',
|
||||
dest='unsafe',
|
||||
action='store_true',
|
||||
help='Run unsafe tests',
|
||||
)
|
||||
|
||||
return parser.parse_known_args()
|
||||
|
||||
@staticmethod
|
||||
def _set_args(args):
|
||||
TestUnit.detailed = args.detailed
|
||||
TestUnit.save_log = args.save_log
|
||||
TestUnit.print_log = args.print_log
|
||||
TestUnit.unsafe = args.unsafe
|
||||
|
||||
# set stdout to non-blocking
|
||||
|
||||
if TestUnit.detailed or TestUnit.print_log:
|
||||
fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, 0)
|
||||
|
||||
def _print_log(self, data=None):
|
||||
path = self.testdir + '/unit.log'
|
||||
|
||||
print('Path to unit.log:\n' + path + '\n')
|
||||
|
||||
if TestUnit.print_log:
|
||||
os.set_blocking(sys.stdout.fileno(), True)
|
||||
sys.stdout.flush()
|
||||
|
||||
if data is None:
|
||||
with open(path, 'r', encoding='utf-8', errors='ignore') as f:
|
||||
shutil.copyfileobj(f, sys.stdout)
|
||||
else:
|
||||
sys.stdout.write(data)
|
||||
|
|
Loading…
Reference in a new issue