Tests: fixed unit.log print.

This commit is contained in:
Andrei Zeliankou
2020-10-19 22:25:29 +01:00
parent d8628a43d0
commit 54837759f3
44 changed files with 427 additions and 488 deletions

View File

@@ -4,11 +4,13 @@ import platform
import re
import shutil
import signal
import socket
import stat
import subprocess
import sys
import tempfile
import time
from multiprocessing import Process
import pytest
@@ -45,6 +47,7 @@ def pytest_addoption(parser):
unit_instance = {}
_processes = []
option = None
@@ -66,6 +69,10 @@ def pytest_configure(config):
fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, 0)
def skip_alert(*alerts):
option.skip_alerts.extend(alerts)
def pytest_generate_tests(metafunc):
cls = metafunc.cls
if not hasattr(cls, 'application_type'):
@@ -127,7 +134,7 @@ def pytest_sessionstart(session):
break
if m is None:
_print_log()
_print_log(log)
exit("Unit is writing log too long")
# discover available modules from unit.log
@@ -154,8 +161,26 @@ def pytest_sessionstart(session):
unit_stop()
shutil.rmtree(unit_instance['temp_dir'])
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
# execute all other hooks to obtain the report object
outcome = yield
rep = outcome.get_result()
# set a report attribute for each phase of a call, which can
# be "setup", "call", "teardown"
setattr(item, "rep_" + rep.when, rep)
@pytest.fixture(autouse=True)
def run(request):
unit = unit_run()
option.temp_dir = unit['temp_dir']
def setup_method(self):
option.skip_alerts = [
r'read signalfd\(4\) failed',
r'sendmsg.+failed',
@@ -163,6 +188,40 @@ def setup_method(self):
]
option.skip_sanitizer = False
yield
# stop unit
error = unit_stop()
if error:
_print_log()
assert error is None, 'stop unit'
# stop all processes
error = stop_processes()
if error:
_print_log()
assert error is None, 'stop unit'
# check unit.log for alerts
_check_alerts()
# print unit.log in case of error
if request.node.rep_call.failed:
_print_log()
# remove unit.log
if not option.save_log:
shutil.rmtree(unit['temp_dir'])
def unit_run():
global unit_instance
build_dir = option.current_dir + '/build'
@@ -204,14 +263,6 @@ def unit_run():
_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'
@@ -236,8 +287,6 @@ def unit_stop():
p.kill()
return 'Could not terminate unit'
shutil.rmtree(unit_instance['temp_dir'])
def public_dir(path):
os.chmod(path, 0o777)
@@ -267,11 +316,14 @@ def waitforfiles(*files):
return ret
def skip_alert(*alerts):
option.skip_alerts.extend(alerts)
def _check_alerts(path=None):
if path is None:
path = unit_instance['log']
with open(path, 'r', encoding='utf-8', errors='ignore') as f:
log = f.read()
def _check_alerts(log):
found = False
alerts = re.findall(r'.+\[alert\].+', log)
@@ -286,22 +338,21 @@ def _check_alerts(log):
alerts = [al for al in alerts if re.search(skip, al) is None]
if alerts:
_print_log(data=log)
_print_log(log)
assert not alerts, 'alert(s)'
if not option.skip_sanitizer:
sanitizer_errors = re.findall('.+Sanitizer.+', log)
if sanitizer_errors:
_print_log(data=log)
_print_log(log)
assert not sanitizer_errors, 'sanitizer error(s)'
if found:
print('skipped.')
def _print_log(path=None, data=None):
if path is None:
def _print_log(data=None):
path = unit_instance['log']
print('Path to unit.log:\n' + path + '\n')
@@ -317,6 +368,52 @@ def _print_log(path=None, data=None):
sys.stdout.write(data)
def run_process(target, *args):
global _processes
process = Process(target=target, args=args)
process.start()
_processes.append(process)
def stop_processes():
if not _processes:
return
fail = False
for process in _processes:
if process.is_alive():
process.terminate()
process.join(timeout=15)
if process.is_alive():
fail = True
if fail:
return 'Fail to stop process(es)'
def waitforsocket(port):
ret = False
for i in range(50):
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('127.0.0.1', port))
ret = True
break
except:
sock.close()
time.sleep(0.1)
sock.close()
assert ret, 'socket connected'
@pytest.fixture
def temp_dir(request):
return unit_instance['temp_dir']
@pytest.fixture
def is_unsafe(request):
return request.config.getoption("--unsafe")

View File

@@ -1,3 +1,3 @@
[pytest]
addopts = -rs -vvv
addopts = -vvv -s --detailed --print_log
python_functions = test_*

View File

@@ -2,6 +2,8 @@ import time
import pytest
from conftest import option
from conftest import unit_stop
from unit.applications.lang.python import TestApplicationPython
@@ -12,7 +14,7 @@ class TestAccessLog(TestApplicationPython):
super().load(script)
assert 'success' in self.conf(
'"' + self.temp_dir + '/access.log"', 'access_log'
'"' + option.temp_dir + '/access.log"', 'access_log'
), 'access_log configure'
def wait_for_record(self, pattern, name='access.log'):
@@ -48,7 +50,7 @@ class TestAccessLog(TestApplicationPython):
body='0123456789',
)
self.stop()
unit_stop()
assert (
self.wait_for_record(r'"POST / HTTP/1.1" 200 10') is not None
@@ -76,7 +78,7 @@ Connection: close
raw=True,
)
self.stop()
unit_stop()
assert (
self.wait_for_record(r'"GET / HTTP/1.1" 200 0 "Referer-1" "-"')
@@ -98,7 +100,7 @@ Connection: close
self.get(sock_type='ipv6')
self.stop()
unit_stop()
assert (
self.wait_for_record(
@@ -110,7 +112,7 @@ Connection: close
def test_access_log_unix(self):
self.load('empty')
addr = self.temp_dir + '/sock'
addr = option.temp_dir + '/sock'
self.conf(
{"unix:" + addr: {"pass": "applications/empty"}}, 'listeners'
@@ -118,7 +120,7 @@ Connection: close
self.get(sock_type='unix', addr=addr)
self.stop()
unit_stop()
assert (
self.wait_for_record(
@@ -138,7 +140,7 @@ Connection: close
}
)
self.stop()
unit_stop()
assert (
self.wait_for_record(r'"GET / HTTP/1.1" 200 0 "referer-value" "-"')
@@ -156,7 +158,7 @@ Connection: close
}
)
self.stop()
unit_stop()
assert (
self.wait_for_record(
@@ -170,7 +172,7 @@ Connection: close
self.get(http_10=True)
self.stop()
unit_stop()
assert (
self.wait_for_record(r'"GET / HTTP/1.0" 200 0 "-" "-"') is not None
@@ -185,7 +187,7 @@ Connection: close
time.sleep(1)
self.stop()
unit_stop()
assert (
self.wait_for_record(r'"GE" 400 0 "-" "-"') is not None
@@ -198,7 +200,7 @@ Connection: close
self.http(b"""GET /\n""", raw=True)
self.stop()
unit_stop()
assert (
self.wait_for_record(r'"GET /" 400 \d+ "-" "-"') is not None
@@ -213,7 +215,7 @@ Connection: close
time.sleep(1)
self.stop()
unit_stop()
assert (
self.wait_for_record(r'"GET /" 400 0 "-" "-"') is not None
@@ -228,7 +230,7 @@ Connection: close
time.sleep(1)
self.stop()
unit_stop()
assert (
self.wait_for_record(r'"GET / HTTP/1.1" 400 0 "-" "-"') is not None
@@ -242,7 +244,7 @@ Connection: close
self.get(headers={'Connection': 'close'})
self.stop()
unit_stop()
assert (
self.wait_for_record(r'"GET / HTTP/1.1" 400 \d+ "-" "-"')
@@ -254,7 +256,7 @@ Connection: close
self.get(url='/?blah&var=val')
self.stop()
unit_stop()
assert (
self.wait_for_record(
@@ -270,20 +272,20 @@ Connection: close
self.get(url='/delete')
self.stop()
unit_stop()
assert self.search_in_log(r'/delete', 'access.log') is None, 'delete'
def test_access_log_change(self):
def test_access_log_change(self, temp_dir):
self.load('empty')
self.get()
self.conf('"' + self.temp_dir + '/new.log"', 'access_log')
self.conf('"' + option.temp_dir + '/new.log"', 'access_log')
self.get()
self.stop()
unit_stop()
assert (
self.wait_for_record(r'"GET / HTTP/1.1" 200 0 "-" "-"', 'new.log')

View File

@@ -4,6 +4,7 @@ from distutils.version import LooseVersion
import pytest
from conftest import option
from conftest import skip_alert
from unit.applications.lang.python import TestApplicationPython
@@ -14,7 +15,7 @@ class TestASGIApplication(TestApplicationPython):
load_module = 'asgi'
def findall(self, pattern):
with open(self.temp_dir + '/unit.log', 'r', errors='ignore') as f:
with open(option.temp_dir + '/unit.log', 'r', errors='ignore') as f:
return re.findall(pattern, f.read())
def test_asgi_application_variables(self):

View File

@@ -5,6 +5,7 @@ import pytest
from conftest import option
from conftest import public_dir
from conftest import unit_stop
from unit.applications.lang.python import TestApplicationPython
@@ -34,7 +35,7 @@ class TestASGILifespan(TestApplicationPython):
assert self.get()['status'] == 204
self.stop()
unit_stop()
is_startup = os.path.isfile(startup_path)
is_shutdown = os.path.isfile(shutdown_path)

View File

@@ -18,8 +18,6 @@ class TestASGIWebsockets(TestApplicationPython):
ws = TestApplicationWebsocket()
def setup_method(self):
super().setup_method()
assert 'success' in self.conf(
{'http': {'websocket': {'keepalive_interval': 0}}}, 'settings'
), 'clear keepalive_interval'

View File

@@ -1,9 +1,13 @@
import grp
import os
import pwd
import shutil
import pytest
from conftest import option
from conftest import unit_run
from conftest import unit_stop
from unit.applications.lang.go import TestApplicationGo
from unit.feature.isolation import TestFeatureIsolation
@@ -14,11 +18,17 @@ class TestGoIsolation(TestApplicationGo):
@classmethod
def setup_class(cls, complete_check=True):
unit = super().setup_class(complete_check=False)
check = super().setup_class(complete_check=False)
TestFeatureIsolation().check(cls.available, unit.temp_dir)
unit = unit_run()
option.temp_dir = unit['temp_dir']
return unit if not complete_check else unit.complete()
TestFeatureIsolation().check(option.available, unit['temp_dir'])
assert unit_stop() is None
shutil.rmtree(unit['temp_dir'])
return check if not complete_check else check()
def unpriv_creds(self):
nobody_uid = pwd.getpwnam('nobody').pw_uid
@@ -33,14 +43,14 @@ class TestGoIsolation(TestApplicationGo):
return (nobody_uid, nogroup_gid, nogroup)
def isolation_key(self, key):
return key in self.available['features']['isolation'].keys()
return key in option.available['features']['isolation'].keys()
def test_isolation_values(self):
self.load('ns_inspect')
obj = self.getjson()['body']
for ns, ns_value in self.available['features']['isolation'].items():
for ns, ns_value in option.available['features']['isolation'].items():
if ns.upper() in obj['NS']:
assert obj['NS'][ns.upper()] == ns_value, '%s match' % ns
@@ -198,7 +208,7 @@ class TestGoIsolation(TestApplicationGo):
obj = self.getjson()['body']
# all but user and mnt
allns = list(self.available['features']['isolation'].keys())
allns = list(option.available['features']['isolation'].keys())
allns.remove('user')
allns.remove('mnt')
@@ -206,7 +216,7 @@ class TestGoIsolation(TestApplicationGo):
if ns.upper() in obj['NS']:
assert (
obj['NS'][ns.upper()]
== self.available['features']['isolation'][ns]
== option.available['features']['isolation'][ns]
), ('%s match' % ns)
assert obj['NS']['MNT'] != self.isolation.getns('mnt'), 'mnt set'
@@ -230,7 +240,7 @@ class TestGoIsolation(TestApplicationGo):
def test_isolation_namespace_false(self):
self.load('ns_inspect')
allns = list(self.available['features']['isolation'].keys())
allns = list(option.available['features']['isolation'].keys())
remove_list = ['unprivileged_userns_clone', 'ipc', 'cgroup']
allns = [ns for ns in allns if ns not in remove_list]
@@ -256,10 +266,10 @@ class TestGoIsolation(TestApplicationGo):
if ns.upper() in obj['NS']:
assert (
obj['NS'][ns.upper()]
== self.available['features']['isolation'][ns]
== option.available['features']['isolation'][ns]
), ('%s match' % ns)
def test_go_isolation_rootfs_container(self):
def test_go_isolation_rootfs_container(self, temp_dir):
if not self.isolation_key('unprivileged_userns_clone'):
pytest.skip('unprivileged clone is not available')
@@ -268,7 +278,7 @@ class TestGoIsolation(TestApplicationGo):
isolation = {
'namespaces': {'mount': True, 'credential': True},
'rootfs': self.temp_dir,
'rootfs': temp_dir,
}
self.load('ns_inspect', isolation=isolation)
@@ -280,7 +290,7 @@ class TestGoIsolation(TestApplicationGo):
obj = self.getjson(url='/?file=/bin/sh')['body']
assert obj['FileExists'] == False, 'file should not exists'
def test_go_isolation_rootfs_container_priv(self, is_su):
def test_go_isolation_rootfs_container_priv(self, is_su, temp_dir):
if not is_su:
pytest.skip('requires root')
@@ -289,7 +299,7 @@ class TestGoIsolation(TestApplicationGo):
isolation = {
'namespaces': {'mount': True},
'rootfs': self.temp_dir,
'rootfs': temp_dir,
}
self.load('ns_inspect', isolation=isolation)
@@ -301,7 +311,7 @@ class TestGoIsolation(TestApplicationGo):
obj = self.getjson(url='/?file=/bin/sh')['body']
assert obj['FileExists'] == False, 'file should not exists'
def test_go_isolation_rootfs_default_tmpfs(self):
def test_go_isolation_rootfs_default_tmpfs(self, temp_dir):
if not self.isolation_key('unprivileged_userns_clone'):
pytest.skip('unprivileged clone is not available')
@@ -310,7 +320,7 @@ class TestGoIsolation(TestApplicationGo):
isolation = {
'namespaces': {'mount': True, 'credential': True},
'rootfs': self.temp_dir,
'rootfs': temp_dir,
}
self.load('ns_inspect', isolation=isolation)

View File

@@ -8,7 +8,7 @@ from unit.applications.lang.go import TestApplicationGo
class TestGoIsolationRootfs(TestApplicationGo):
prerequisites = {'modules': {'go': 'all'}}
def test_go_isolation_rootfs_chroot(self, is_su):
def test_go_isolation_rootfs_chroot(self, is_su, temp_dir):
if not is_su:
pytest.skip('requires root')
@@ -16,7 +16,7 @@ class TestGoIsolationRootfs(TestApplicationGo):
pytest.skip('chroot tests not supported on OSX')
isolation = {
'rootfs': self.temp_dir,
'rootfs': temp_dir,
}
self.load('ns_inspect', isolation=isolation)

View File

@@ -11,7 +11,7 @@ from unit.applications.lang.java import TestApplicationJava
class TestJavaApplication(TestApplicationJava):
prerequisites = {'modules': {'java': 'all'}}
def test_java_conf_error(self):
def test_java_conf_error(self, temp_dir):
skip_alert(
r'realpath.*failed',
r'failed to apply new conf',
@@ -25,18 +25,18 @@ class TestJavaApplication(TestApplicationJava):
"type": "java",
"processes": 1,
"working_directory": option.test_dir + "/java/empty",
"webapp": self.temp_dir + "/java",
"unit_jars": self.temp_dir + "/no_such_dir",
"webapp": temp_dir + "/java",
"unit_jars": temp_dir + "/no_such_dir",
}
},
}
), 'conf error'
def test_java_war(self):
def test_java_war(self, temp_dir):
self.load('empty_war')
assert 'success' in self.conf(
'"' + self.temp_dir + '/java/empty.war"',
'"' + temp_dir + '/java/empty.war"',
'/config/applications/empty_war/webapp',
), 'configure war'
@@ -969,11 +969,11 @@ class TestJavaApplication(TestApplicationJava):
), 'set date header'
assert headers['X-Get-Date'] == date, 'get date header'
def test_java_application_multipart(self):
def test_java_application_multipart(self, temp_dir):
self.load('multipart')
reldst = '/uploads'
fulldst = self.temp_dir + reldst
fulldst = temp_dir + reldst
os.mkdir(fulldst)
public_dir(fulldst)

View File

@@ -11,14 +11,12 @@ class TestJavaIsolationRootfs(TestApplicationJava):
prerequisites = {'modules': {'java': 'all'}}
def setup_method(self, is_su):
super().setup_method()
if not is_su:
return
os.makedirs(self.temp_dir + '/jars')
os.makedirs(self.temp_dir + '/tmp')
os.chmod(self.temp_dir + '/tmp', 0o777)
os.makedirs(option.temp_dir + '/jars')
os.makedirs(option.temp_dir + '/tmp')
os.chmod(option.temp_dir + '/tmp', 0o777)
try:
process = subprocess.Popen(
@@ -26,7 +24,7 @@ class TestJavaIsolationRootfs(TestApplicationJava):
"mount",
"--bind",
option.current_dir + "/build",
self.temp_dir + "/jars",
option.temp_dir + "/jars",
],
stderr=subprocess.STDOUT,
)
@@ -42,7 +40,7 @@ class TestJavaIsolationRootfs(TestApplicationJava):
try:
process = subprocess.Popen(
["umount", "--lazy", self.temp_dir + "/jars"],
["umount", "--lazy", option.temp_dir + "/jars"],
stderr=subprocess.STDOUT,
)
@@ -51,15 +49,12 @@ class TestJavaIsolationRootfs(TestApplicationJava):
except:
pytest.fail('Cann\'t run mount process.')
# super teardown must happen after unmount to avoid deletion of /build
super().teardown_method()
def test_java_isolation_rootfs_chroot_war(self, is_su):
def test_java_isolation_rootfs_chroot_war(self, is_su, temp_dir):
if not is_su:
pytest.skip('require root')
isolation = {
'rootfs': self.temp_dir,
'rootfs': temp_dir,
}
self.load('empty_war', isolation=isolation)

View File

@@ -15,8 +15,6 @@ class TestJavaWebsockets(TestApplicationJava):
ws = TestApplicationWebsocket()
def setup_method(self):
super().setup_method()
assert 'success' in self.conf(
{'http': {'websocket': {'keepalive_interval': 0}}}, 'settings'
), 'clear keepalive_interval'

View File

@@ -139,11 +139,11 @@ class TestNodeApplication(TestApplicationNode):
assert self.get()['body'] == 'buffer', 'write buffer'
def test_node_application_write_callback(self):
def test_node_application_write_callback(self, temp_dir):
self.load('write_callback')
assert self.get()['body'] == 'helloworld', 'write callback order'
assert waitforfiles(self.temp_dir + '/node/callback'), 'write callback'
assert waitforfiles(temp_dir + '/node/callback'), 'write callback'
def test_node_application_write_before_write_head(self):
self.load('write_before_write_head')
@@ -222,7 +222,7 @@ class TestNodeApplication(TestApplicationNode):
assert 'X-Header' not in headers, 'insensitive'
assert 'X-header' not in headers, 'insensitive 2'
def test_node_application_promise_handler(self):
def test_node_application_promise_handler(self, temp_dir):
self.load('promise_handler')
assert (
@@ -236,7 +236,7 @@ class TestNodeApplication(TestApplicationNode):
)['status']
== 200
), 'promise handler request'
assert waitforfiles(self.temp_dir + '/node/callback'), 'promise handler'
assert waitforfiles(temp_dir + '/node/callback'), 'promise handler'
def test_node_application_promise_handler_write_after_end(self):
self.load('promise_handler')
@@ -254,7 +254,7 @@ class TestNodeApplication(TestApplicationNode):
== 200
), 'promise handler request write after end'
def test_node_application_promise_end(self):
def test_node_application_promise_end(self, temp_dir):
self.load('promise_end')
assert (
@@ -268,9 +268,9 @@ class TestNodeApplication(TestApplicationNode):
)['status']
== 200
), 'promise end request'
assert waitforfiles(self.temp_dir + '/node/callback'), 'promise end'
assert waitforfiles(temp_dir + '/node/callback'), 'promise end'
def test_node_application_promise_multiple_calls(self):
def test_node_application_promise_multiple_calls(self, temp_dir):
self.load('promise_handler')
self.post(
@@ -283,7 +283,7 @@ class TestNodeApplication(TestApplicationNode):
)
assert waitforfiles(
self.temp_dir + '/node/callback1'
temp_dir + '/node/callback1'
), 'promise first call'
self.post(
@@ -296,7 +296,7 @@ class TestNodeApplication(TestApplicationNode):
)
assert waitforfiles(
self.temp_dir + '/node/callback2'
temp_dir + '/node/callback2'
), 'promise second call'
@pytest.mark.skip('not yet')

View File

@@ -15,8 +15,6 @@ class TestNodeWebsockets(TestApplicationNode):
ws = TestApplicationWebsocket()
def setup_method(self):
super().setup_method()
assert 'success' in self.conf(
{'http': {'websocket': {'keepalive_interval': 0}}}, 'settings'
), 'clear keepalive_interval'

View File

@@ -3,6 +3,7 @@ import re
import pytest
from conftest import skip_alert
from conftest import unit_stop
from unit.applications.lang.perl import TestApplicationPerl
@@ -119,7 +120,7 @@ class TestPerlApplication(TestApplicationPerl):
assert self.get()['body'] == '1', 'errors result'
self.stop()
unit_stop()
assert (
self.wait_for_record(r'\[error\].+Error in application')

View File

@@ -6,6 +6,7 @@ import time
import pytest
from conftest import option
from conftest import unit_stop
from unit.applications.lang.php import TestApplicationPHP
class TestPHPApplication(TestApplicationPHP):
@@ -444,7 +445,7 @@ class TestPHPApplication(TestApplicationPHP):
r'012345', self.get()['body']
), 'disable_classes before'
def test_php_application_error_log(self):
def test_php_application_error_log(self, temp_dir):
self.load('error_log')
assert self.get()['status'] == 200, 'status'
@@ -453,13 +454,13 @@ class TestPHPApplication(TestApplicationPHP):
assert self.get()['status'] == 200, 'status 2'
self.stop()
unit_stop()
pattern = r'\d{4}\/\d\d\/\d\d\s\d\d:.+\[notice\].+Error in application'
assert self.wait_for_record(pattern) is not None, 'errors print'
with open(self.temp_dir + '/unit.log', 'r', errors='ignore') as f:
with open(temp_dir + '/unit.log', 'r', errors='ignore') as f:
errs = re.findall(pattern, f.read())
assert len(errs) == 2, 'error_log count'
@@ -507,12 +508,12 @@ class TestPHPApplication(TestApplicationPHP):
assert resp['status'] == 200, 'status'
assert resp['body'] != '', 'body not empty'
def test_php_application_extension_check(self):
def test_php_application_extension_check(self, temp_dir):
self.load('phpinfo')
assert self.get(url='/index.wrong')['status'] != 200, 'status'
new_root = self.temp_dir + "/php"
new_root = temp_dir + "/php"
os.mkdir(new_root)
shutil.copy(option.test_dir + '/php/phpinfo/index.wrong', new_root)

View File

@@ -1,6 +1,10 @@
import shutil
import pytest
from conftest import option
from conftest import unit_run
from conftest import unit_stop
from unit.applications.lang.php import TestApplicationPHP
from unit.feature.isolation import TestFeatureIsolation
@@ -8,18 +12,22 @@ from unit.feature.isolation import TestFeatureIsolation
class TestPHPIsolation(TestApplicationPHP):
prerequisites = {'modules': {'php': 'any'}, 'features': ['isolation']}
isolation = TestFeatureIsolation()
@classmethod
def setup_class(cls, complete_check=True):
unit = super().setup_class(complete_check=False)
check = super().setup_class(complete_check=False)
TestFeatureIsolation().check(cls.available, unit.temp_dir)
unit = unit_run()
option.temp_dir = unit['temp_dir']
return unit if not complete_check else unit.complete()
TestFeatureIsolation().check(option.available, unit['temp_dir'])
assert unit_stop() is None
shutil.rmtree(unit['temp_dir'])
return check if not complete_check else check()
def test_php_isolation_rootfs(self, is_su):
isolation_features = self.available['features']['isolation'].keys()
isolation_features = option.available['features']['isolation'].keys()
if 'mnt' not in isolation_features:
pytest.skip('requires mnt ns')
@@ -48,7 +56,7 @@ class TestPHPIsolation(TestApplicationPHP):
assert self.get()['status'] == 200, 'empty rootfs'
def test_php_isolation_rootfs_extensions(self, is_su):
isolation_features = self.available['features']['isolation'].keys()
isolation_features = option.available['features']['isolation'].keys()
if not is_su:
if 'user' not in isolation_features:

View File

@@ -5,7 +5,9 @@ import time
import pytest
from conftest import option
from conftest import run_process
from conftest import skip_alert
from conftest import waitforsocket
from unit.applications.lang.python import TestApplicationPython
@@ -60,10 +62,8 @@ Content-Length: 10
return self.post(*args, http_10=True, **kwargs)
def setup_method(self):
super().setup_method()
self.run_process(self.run_server, self.SERVER_PORT)
self.waitforsocket(self.SERVER_PORT)
run_process(self.run_server, self.SERVER_PORT)
waitforsocket(self.SERVER_PORT)
assert 'success' in self.conf(
{
@@ -346,8 +346,8 @@ Content-Length: 10
assert self.get_http10()['status'] == 200, 'status'
def test_proxy_unix(self):
addr = self.temp_dir + '/sock'
def test_proxy_unix(self, temp_dir):
addr = temp_dir + '/sock'
assert 'success' in self.conf(
{

View File

@@ -3,6 +3,9 @@ import select
import socket
import time
from conftest import option
from conftest import run_process
from conftest import waitforsocket
from unit.applications.lang.python import TestApplicationPython
@@ -82,10 +85,8 @@ class TestProxyChunked(TestApplicationPython):
return self.get(*args, http_10=True, **kwargs)
def setup_method(self):
super().setup_method()
self.run_process(self.run_server, self.SERVER_PORT, self.temp_dir)
self.waitforsocket(self.SERVER_PORT)
run_process(self.run_server, self.SERVER_PORT, option.temp_dir)
waitforsocket(self.SERVER_PORT)
assert 'success' in self.conf(
{

View File

@@ -5,7 +5,9 @@ import time
import pytest
from conftest import option
from conftest import skip_alert
from conftest import unit_stop
from unit.applications.lang.python import TestApplicationPython
@@ -13,7 +15,7 @@ class TestPythonApplication(TestApplicationPython):
prerequisites = {'modules': {'python': 'all'}}
def findall(self, pattern):
with open(self.temp_dir + '/unit.log', 'r', errors='ignore') as f:
with open(option.temp_dir + '/unit.log', 'r', errors='ignore') as f:
return re.findall(pattern, f.read())
def test_python_application_variables(self):
@@ -156,7 +158,7 @@ custom-header: BLAH
self.conf({"listeners": {}, "applications": {}})
self.stop()
unit_stop()
assert (
self.wait_for_record(r'RuntimeError') is not None
@@ -344,7 +346,7 @@ Connection: close
self.conf({"listeners": {}, "applications": {}})
self.stop()
unit_stop()
assert self.wait_for_record(r'At exit called\.') is not None, 'atexit'
@@ -507,7 +509,7 @@ last line: 987654321
self.get()
self.stop()
unit_stop()
assert (
self.wait_for_record(r'\[error\].+Error in application\.')
@@ -550,7 +552,7 @@ last line: 987654321
self.get()
self.stop()
unit_stop()
assert self.wait_for_record(r'Close called\.') is not None, 'close'
@@ -559,7 +561,7 @@ last line: 987654321
self.get()
self.stop()
unit_stop()
assert (
self.wait_for_record(r'Close called\.') is not None
@@ -570,7 +572,7 @@ last line: 987654321
self.get()
self.stop()
unit_stop()
assert (
self.wait_for_record(

View File

@@ -1,5 +1,10 @@
import shutil
import pytest
from conftest import option
from conftest import unit_run
from conftest import unit_stop
from unit.applications.lang.python import TestApplicationPython
from unit.feature.isolation import TestFeatureIsolation
@@ -7,18 +12,22 @@ from unit.feature.isolation import TestFeatureIsolation
class TestPythonIsolation(TestApplicationPython):
prerequisites = {'modules': {'python': 'any'}, 'features': ['isolation']}
isolation = TestFeatureIsolation()
@classmethod
def setup_class(cls, complete_check=True):
unit = super().setup_class(complete_check=False)
check = super().setup_class(complete_check=False)
TestFeatureIsolation().check(cls.available, unit.temp_dir)
unit = unit_run()
option.temp_dir = unit['temp_dir']
return unit if not complete_check else unit.complete()
TestFeatureIsolation().check(option.available, unit['temp_dir'])
def test_python_isolation_rootfs(self, is_su):
isolation_features = self.available['features']['isolation'].keys()
assert unit_stop() is None
shutil.rmtree(unit['temp_dir'])
return check if not complete_check else check()
def test_python_isolation_rootfs(self, is_su, temp_dir):
isolation_features = option.available['features']['isolation'].keys()
if 'mnt' not in isolation_features:
pytest.skip('requires mnt ns')
@@ -32,7 +41,7 @@ class TestPythonIsolation(TestApplicationPython):
isolation = {
'namespaces': {'credential': not is_su, 'mount': True},
'rootfs': self.temp_dir,
'rootfs': temp_dir,
}
self.load('empty', isolation=isolation)
@@ -42,7 +51,7 @@ class TestPythonIsolation(TestApplicationPython):
self.load('ns_inspect', isolation=isolation)
assert (
self.getjson(url='/?path=' + self.temp_dir)['body']['FileExists']
self.getjson(url='/?path=' + temp_dir)['body']['FileExists']
== False
), 'temp_dir does not exists in rootfs'
@@ -66,8 +75,8 @@ class TestPythonIsolation(TestApplicationPython):
ret['body']['FileExists'] == True
), 'application exists in rootfs'
def test_python_isolation_rootfs_no_language_deps(self, is_su):
isolation_features = self.available['features']['isolation'].keys()
def test_python_isolation_rootfs_no_language_deps(self, is_su, temp_dir):
isolation_features = option.available['features']['isolation'].keys()
if 'mnt' not in isolation_features:
pytest.skip('requires mnt ns')
@@ -81,7 +90,7 @@ class TestPythonIsolation(TestApplicationPython):
isolation = {
'namespaces': {'credential': not is_su, 'mount': True},
'rootfs': self.temp_dir,
'rootfs': temp_dir,
'automount': {'language_deps': False}
}

View File

@@ -7,12 +7,12 @@ from unit.feature.isolation import TestFeatureIsolation
class TestPythonIsolation(TestApplicationPython):
prerequisites = {'modules': {'python': 'any'}}
def test_python_isolation_chroot(self, is_su):
def test_python_isolation_chroot(self, is_su, temp_dir):
if not is_su:
pytest.skip('requires root')
isolation = {
'rootfs': self.temp_dir,
'rootfs': temp_dir,
}
self.load('empty', isolation=isolation)
@@ -22,7 +22,7 @@ class TestPythonIsolation(TestApplicationPython):
self.load('ns_inspect', isolation=isolation)
assert (
self.getjson(url='/?path=' + self.temp_dir)['body']['FileExists']
self.getjson(url='/?path=' + temp_dir)['body']['FileExists']
== False
), 'temp_dir does not exists in rootfs'

View File

@@ -4,6 +4,7 @@ import time
import pytest
from conftest import option
from unit.applications.lang.python import TestApplicationPython
@@ -11,9 +12,7 @@ class TestPythonProcman(TestApplicationPython):
prerequisites = {'modules': {'python': 'any'}}
def setup_method(self):
super().setup_method()
self.app_name = "app-" + self.temp_dir.split('/')[-1]
self.app_name = "app-" + option.temp_dir.split('/')[-1]
self.app_proc = 'applications/' + self.app_name + '/processes'
self.load('empty', self.app_name)

View File

@@ -2,6 +2,7 @@ import re
import subprocess
import time
from conftest import option
from conftest import skip_alert
from unit.applications.lang.python import TestApplicationPython
@@ -13,9 +14,7 @@ class TestRespawn(TestApplicationPython):
PATTERN_CONTROLLER = 'unit: controller'
def setup_method(self):
super().setup_method()
self.app_name = "app-" + self.temp_dir.split('/')[-1]
self.app_name = "app-" + option.temp_dir.split('/')[-1]
self.load('empty', self.app_name)

View File

@@ -7,8 +7,6 @@ class TestReturn(TestApplicationProto):
prerequisites = {}
def setup_method(self):
super().setup_method()
self._load_conf(
{
"listeners": {"*:7080": {"pass": "routes"}},

View File

@@ -10,8 +10,6 @@ class TestRouting(TestApplicationProto):
prerequisites = {'modules': {'python': 'any'}}
def setup_method(self):
super().setup_method()
assert 'success' in self.conf(
{
"listeners": {"*:7080": {"pass": "routes"}},
@@ -417,7 +415,7 @@ class TestRouting(TestApplicationProto):
[{"action": {"pass": "upstreams/blah"}}], 'routes'
), 'route pass upstreams invalid'
def test_routes_action_unique(self):
def test_routes_action_unique(self, temp_dir):
assert 'success' in self.conf(
{
"listeners": {
@@ -437,7 +435,7 @@ class TestRouting(TestApplicationProto):
)
assert 'error' in self.conf(
{"proxy": "http://127.0.0.1:7081", "share": self.temp_dir},
{"proxy": "http://127.0.0.1:7081", "share": temp_dir},
'routes/0/action',
), 'proxy share'
assert 'error' in self.conf(
@@ -445,7 +443,7 @@ class TestRouting(TestApplicationProto):
'routes/0/action',
), 'proxy pass'
assert 'error' in self.conf(
{"share": self.temp_dir, "pass": "applications/app"},
{"share": temp_dir, "pass": "applications/app"},
'routes/0/action',
), 'share pass'
@@ -1665,8 +1663,8 @@ class TestRouting(TestApplicationProto):
assert self.get(sock_type='ipv6')['status'] == 200, '0'
assert self.get(port=7081)['status'] == 404, '0 ipv4'
def test_routes_source_unix(self):
addr = self.temp_dir + '/sock'
def test_routes_source_unix(self, temp_dir):
addr = temp_dir + '/sock'
assert 'success' in self.conf(
{"unix:" + addr: {"pass": "routes"}}, 'listeners'

View File

@@ -3,6 +3,7 @@ import re
import pytest
from conftest import skip_alert
from conftest import unit_stop
from unit.applications.lang.ruby import TestApplicationRuby
@@ -175,7 +176,7 @@ class TestRubyApplication(TestApplicationRuby):
self.get()
self.stop()
unit_stop()
assert (
self.wait_for_record(r'\[error\].+Error in application')
@@ -187,7 +188,7 @@ class TestRubyApplication(TestApplicationRuby):
self.get()
self.stop()
unit_stop()
assert (
self.wait_for_record(r'\[error\].+1234567890') is not None
@@ -198,7 +199,7 @@ class TestRubyApplication(TestApplicationRuby):
self.get()
self.stop()
unit_stop()
assert (
self.wait_for_record(r'\[error\].+Error in application')
@@ -215,7 +216,7 @@ class TestRubyApplication(TestApplicationRuby):
self.get()
self.stop()
unit_stop()
assert (
self.wait_for_record(r'\[error\].+1234567890') is not None
@@ -228,7 +229,7 @@ class TestRubyApplication(TestApplicationRuby):
self.conf({"listeners": {}, "applications": {}})
self.stop()
unit_stop()
assert (
self.wait_for_record(r'\[error\].+At exit called\.') is not None
@@ -289,7 +290,7 @@ class TestRubyApplication(TestApplicationRuby):
assert self.get()['status'] == 500, 'body each error status'
self.stop()
unit_stop()
assert (
self.wait_for_record(r'\[error\].+Failed to run ruby script')

View File

@@ -1,7 +1,10 @@
import shutil
import pytest
from conftest import option
from conftest import unit_run
from conftest import unit_stop
from unit.applications.lang.ruby import TestApplicationRuby
from unit.feature.isolation import TestFeatureIsolation
@@ -9,18 +12,22 @@ from unit.feature.isolation import TestFeatureIsolation
class TestRubyIsolation(TestApplicationRuby):
prerequisites = {'modules': {'ruby': 'any'}, 'features': ['isolation']}
isolation = TestFeatureIsolation()
@classmethod
def setup_class(cls, complete_check=True):
unit = super().setup_class(complete_check=False)
check = super().setup_class(complete_check=False)
TestFeatureIsolation().check(cls.available, unit.temp_dir)
unit = unit_run()
option.temp_dir = unit['temp_dir']
return unit if not complete_check else unit.complete()
TestFeatureIsolation().check(option.available, unit['temp_dir'])
assert unit_stop() is None
shutil.rmtree(unit['temp_dir'])
return check if not complete_check else check()
def test_ruby_isolation_rootfs(self, is_su):
isolation_features = self.available['features']['isolation'].keys()
isolation_features = option.available['features']['isolation'].keys()
if 'mnt' not in isolation_features:
pytest.skip('requires mnt ns')

View File

@@ -146,14 +146,14 @@ Connection: close
assert resp['status'] == 200, 'status body read timeout update'
def test_settings_send_timeout(self):
def test_settings_send_timeout(self, temp_dir):
self.load('mirror')
data_len = 1048576
self.conf({'http': {'send_timeout': 1}}, 'settings')
addr = self.temp_dir + '/sock'
addr = temp_dir + '/sock'
self.conf({"unix:" + addr: {'application': 'mirror'}}, 'listeners')

View File

@@ -1,5 +1,6 @@
import os
from conftest import option
from conftest import skip_alert
from unit.applications.proto import TestApplicationProto
@@ -8,14 +9,12 @@ class TestStatic(TestApplicationProto):
prerequisites = {}
def setup_method(self):
super().setup_method()
os.makedirs(self.temp_dir + '/assets/dir')
with open(self.temp_dir + '/assets/index.html', 'w') as index:
os.makedirs(option.temp_dir + '/assets/dir')
with open(option.temp_dir + '/assets/index.html', 'w') as index:
index.write('0123456789')
os.makedirs(self.temp_dir + '/assets/403')
os.chmod(self.temp_dir + '/assets/403', 0o000)
os.makedirs(option.temp_dir + '/assets/403')
os.chmod(option.temp_dir + '/assets/403', 0o000)
self._load_conf(
{
@@ -23,15 +22,13 @@ class TestStatic(TestApplicationProto):
"*:7080": {"pass": "routes"},
"*:7081": {"pass": "routes"},
},
"routes": [{"action": {"share": self.temp_dir + "/assets"}}],
"routes": [{"action": {"share": option.temp_dir + "/assets"}}],
"applications": {},
}
)
def teardown_method(self):
os.chmod(self.temp_dir + '/assets/403', 0o777)
super().teardown_method()
os.chmod(option.temp_dir + '/assets/403', 0o777)
def action_update(self, conf):
assert 'success' in self.conf(conf, 'routes/0/action')
@@ -46,9 +43,9 @@ class TestStatic(TestApplicationProto):
assert resp['status'] == 200, 'bad path fallback status'
assert resp['body'] == '', 'bad path fallback'
def test_fallback_valid_path(self):
def test_fallback_valid_path(self, temp_dir):
self.action_update(
{"share": self.temp_dir + "/assets", "fallback": {"return": 200}}
{"share": temp_dir + "/assets", "fallback": {"return": 200}}
)
resp = self.get()
assert resp['status'] == 200, 'fallback status'
@@ -79,11 +76,11 @@ class TestStatic(TestApplicationProto):
assert resp['status'] == 200, 'fallback nested status'
assert resp['body'] == '', 'fallback nested'
def test_fallback_share(self):
def test_fallback_share(self, temp_dir):
self.action_update(
{
"share": "/blah",
"fallback": {"share": self.temp_dir + "/assets"},
"fallback": {"share": temp_dir + "/assets"},
}
)

View File

@@ -3,6 +3,7 @@ import socket
import pytest
from conftest import option
from conftest import waitforfiles
from unit.applications.proto import TestApplicationProto
@@ -11,13 +12,13 @@ class TestStatic(TestApplicationProto):
prerequisites = {}
def setup_method(self):
super().setup_method()
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'
os.makedirs(option.temp_dir + '/assets/dir')
with open(option.temp_dir + '/assets/index.html', 'w') as index, open(
option.temp_dir + '/assets/README', 'w'
) as readme, open(
option.temp_dir + '/assets/log.log', 'w'
) as log, open(
option.temp_dir + '/assets/dir/file', 'w'
) as file:
index.write('0123456789')
readme.write('readme')
@@ -27,7 +28,7 @@ class TestStatic(TestApplicationProto):
self._load_conf(
{
"listeners": {"*:7080": {"pass": "routes"}},
"routes": [{"action": {"share": self.temp_dir + "/assets"}}],
"routes": [{"action": {"share": option.temp_dir + "/assets"}}],
"settings": {
"http": {
"static": {
@@ -54,9 +55,9 @@ class TestStatic(TestApplicationProto):
resp['headers']['Content-Type'] == 'text/html'
), 'index not found 2 Content-Type'
def test_static_large_file(self):
def test_static_large_file(self, temp_dir):
file_size = 32 * 1024 * 1024
with open(self.temp_dir + '/assets/large', 'wb') as f:
with open(temp_dir + '/assets/large', 'wb') as f:
f.seek(file_size - 1)
f.write(b'\0')
@@ -65,14 +66,14 @@ class TestStatic(TestApplicationProto):
== file_size
), 'large file'
def test_static_etag(self):
def test_static_etag(self, temp_dir):
etag = self.get(url='/')['headers']['ETag']
etag_2 = self.get(url='/README')['headers']['ETag']
assert etag != etag_2, 'different ETag'
assert etag == self.get(url='/')['headers']['ETag'], 'same ETag'
with open(self.temp_dir + '/assets/index.html', 'w') as f:
with open(temp_dir + '/assets/index.html', 'w') as f:
f.write('blah')
assert etag != self.get(url='/')['headers']['ETag'], 'new ETag'
@@ -83,22 +84,22 @@ class TestStatic(TestApplicationProto):
assert resp['headers']['Location'] == '/dir/', 'redirect Location'
assert 'Content-Type' not in resp['headers'], 'redirect Content-Type'
def test_static_space_in_name(self):
def test_static_space_in_name(self, temp_dir):
os.rename(
self.temp_dir + '/assets/dir/file',
self.temp_dir + '/assets/dir/fi le',
temp_dir + '/assets/dir/file',
temp_dir + '/assets/dir/fi le',
)
assert waitforfiles(self.temp_dir + '/assets/dir/fi le')
assert waitforfiles(temp_dir + '/assets/dir/fi le')
assert self.get(url='/dir/fi le')['body'] == 'blah', 'file name'
os.rename(self.temp_dir + '/assets/dir', self.temp_dir + '/assets/di r')
assert waitforfiles(self.temp_dir + '/assets/di r/fi le')
os.rename(temp_dir + '/assets/dir', temp_dir + '/assets/di r')
assert waitforfiles(temp_dir + '/assets/di r/fi le')
assert self.get(url='/di r/fi le')['body'] == 'blah', 'dir name'
os.rename(
self.temp_dir + '/assets/di r', self.temp_dir + '/assets/ di r '
temp_dir + '/assets/di r', temp_dir + '/assets/ di r '
)
assert waitforfiles(self.temp_dir + '/assets/ di r /fi le')
assert waitforfiles(temp_dir + '/assets/ di r /fi le')
assert (
self.get(url='/ di r /fi le')['body'] == 'blah'
), 'dir name enclosing'
@@ -121,16 +122,16 @@ class TestStatic(TestApplicationProto):
), 'encoded 2'
os.rename(
self.temp_dir + '/assets/ di r /fi le',
self.temp_dir + '/assets/ di r / fi le ',
temp_dir + '/assets/ di r /fi le',
temp_dir + '/assets/ di r / fi le ',
)
assert waitforfiles(self.temp_dir + '/assets/ di r / fi le ')
assert waitforfiles(temp_dir + '/assets/ di r / fi le ')
assert (
self.get(url='/%20di%20r%20/%20fi%20le%20')['body'] == 'blah'
), 'file name enclosing'
try:
open(self.temp_dir + 'а', 'a').close()
open(temp_dir + 'а', 'a').close()
utf8 = True
except:
@@ -138,38 +139,38 @@ class TestStatic(TestApplicationProto):
if utf8:
os.rename(
self.temp_dir + '/assets/ di r / fi le ',
self.temp_dir + '/assets/ di r /фа йл',
temp_dir + '/assets/ di r / fi le ',
temp_dir + '/assets/ di r /фа йл',
)
assert waitforfiles(self.temp_dir + '/assets/ di r /фа йл')
assert waitforfiles(temp_dir + '/assets/ di r /фа йл')
assert (
self.get(url='/ di r /фа йл')['body'] == 'blah'
), 'file name 2'
os.rename(
self.temp_dir + '/assets/ di r ',
self.temp_dir + '/assets/ди ректория',
temp_dir + '/assets/ di r ',
temp_dir + '/assets/ди ректория',
)
assert waitforfiles(self.temp_dir + '/assets/ди ректория/фа йл')
assert waitforfiles(temp_dir + '/assets/ди ректория/фа йл')
assert (
self.get(url='/ди ректория/фа йл')['body'] == 'blah'
), 'dir name 2'
def test_static_unix_socket(self):
def test_static_unix_socket(self, temp_dir):
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.bind(self.temp_dir + '/assets/unix_socket')
sock.bind(temp_dir + '/assets/unix_socket')
assert self.get(url='/unix_socket')['status'] == 404, 'socket'
sock.close()
def test_static_unix_fifo(self):
os.mkfifo(self.temp_dir + '/assets/fifo')
def test_static_unix_fifo(self, temp_dir):
os.mkfifo(temp_dir + '/assets/fifo')
assert self.get(url='/fifo')['status'] == 404, 'fifo'
def test_static_symlink(self):
os.symlink(self.temp_dir + '/assets/dir', self.temp_dir + '/assets/link')
def test_static_symlink(self, temp_dir):
os.symlink(temp_dir + '/assets/dir', temp_dir + '/assets/link')
assert self.get(url='/dir')['status'] == 301, 'dir'
assert self.get(url='/dir/file')['status'] == 200, 'file'
@@ -312,7 +313,7 @@ class TestStatic(TestApplicationProto):
), 'mime_types same extensions case insensitive'
@pytest.mark.skip('not yet')
def test_static_mime_types_invalid(self):
def test_static_mime_types_invalid(self, temp_dir):
assert 'error' in self.http(
b"""PUT /config/settings/http/static/mime_types/%0%00% HTTP/1.1\r
Host: localhost\r
@@ -323,5 +324,5 @@ Content-Length: 6\r
raw_resp=True,
raw=True,
sock_type='unix',
addr=self.temp_dir + '/control.unit.sock',
addr=temp_dir + '/control.unit.sock',
), 'mime_types invalid'

View File

@@ -5,6 +5,7 @@ import subprocess
import pytest
from conftest import option
from conftest import skip_alert
from unit.applications.tls import TestApplicationTLS
@@ -13,7 +14,7 @@ class TestTLS(TestApplicationTLS):
prerequisites = {'modules': {'python': 'any', 'openssl': 'any'}}
def findall(self, pattern):
with open(self.temp_dir + '/unit.log', 'r', errors='ignore') as f:
with open(option.temp_dir + '/unit.log', 'r', errors='ignore') as f:
return re.findall(pattern, f.read())
def openssl_date_to_sec_epoch(self, date):
@@ -134,7 +135,7 @@ class TestTLS(TestApplicationTLS):
self.conf_get('/certificates/default/key') == 'RSA (2048 bits)'
), 'certificate key rsa'
def test_tls_certificate_key_ec(self):
def test_tls_certificate_key_ec(self, temp_dir):
self.load('empty')
self.openssl_conf()
@@ -146,7 +147,7 @@ class TestTLS(TestApplicationTLS):
'-noout',
'-genkey',
'-out',
self.temp_dir + '/ec.key',
temp_dir + '/ec.key',
'-name',
'prime256v1',
],
@@ -162,11 +163,11 @@ class TestTLS(TestApplicationTLS):
'-subj',
'/CN=ec/',
'-config',
self.temp_dir + '/openssl.conf',
temp_dir + '/openssl.conf',
'-key',
self.temp_dir + '/ec.key',
temp_dir + '/ec.key',
'-out',
self.temp_dir + '/ec.crt',
temp_dir + '/ec.crt',
],
stderr=subprocess.STDOUT,
)
@@ -208,7 +209,7 @@ class TestTLS(TestApplicationTLS):
== 2592000
), 'certificate validity until'
def test_tls_certificate_chain(self):
def test_tls_certificate_chain(self, temp_dir):
self.load('empty')
self.certificate('root', False)
@@ -221,11 +222,11 @@ class TestTLS(TestApplicationTLS):
'-subj',
'/CN=int/',
'-config',
self.temp_dir + '/openssl.conf',
temp_dir + '/openssl.conf',
'-out',
self.temp_dir + '/int.csr',
temp_dir + '/int.csr',
'-keyout',
self.temp_dir + '/int.key',
temp_dir + '/int.key',
],
stderr=subprocess.STDOUT,
)
@@ -238,16 +239,16 @@ class TestTLS(TestApplicationTLS):
'-subj',
'/CN=end/',
'-config',
self.temp_dir + '/openssl.conf',
temp_dir + '/openssl.conf',
'-out',
self.temp_dir + '/end.csr',
temp_dir + '/end.csr',
'-keyout',
self.temp_dir + '/end.key',
temp_dir + '/end.key',
],
stderr=subprocess.STDOUT,
)
with open(self.temp_dir + '/ca.conf', 'w') as f:
with open(temp_dir + '/ca.conf', 'w') as f:
f.write(
"""[ ca ]
default_ca = myca
@@ -267,16 +268,16 @@ commonName = supplied
[ myca_extensions ]
basicConstraints = critical,CA:TRUE"""
% {
'dir': self.temp_dir,
'database': self.temp_dir + '/certindex',
'certserial': self.temp_dir + '/certserial',
'dir': temp_dir,
'database': temp_dir + '/certindex',
'certserial': temp_dir + '/certserial',
}
)
with open(self.temp_dir + '/certserial', 'w') as f:
with open(temp_dir + '/certserial', 'w') as f:
f.write('1000')
with open(self.temp_dir + '/certindex', 'w') as f:
with open(temp_dir + '/certindex', 'w') as f:
f.write('')
subprocess.call(
@@ -287,15 +288,15 @@ basicConstraints = critical,CA:TRUE"""
'-subj',
'/CN=int/',
'-config',
self.temp_dir + '/ca.conf',
temp_dir + '/ca.conf',
'-keyfile',
self.temp_dir + '/root.key',
temp_dir + '/root.key',
'-cert',
self.temp_dir + '/root.crt',
temp_dir + '/root.crt',
'-in',
self.temp_dir + '/int.csr',
temp_dir + '/int.csr',
'-out',
self.temp_dir + '/int.crt',
temp_dir + '/int.crt',
],
stderr=subprocess.STDOUT,
)
@@ -308,22 +309,22 @@ basicConstraints = critical,CA:TRUE"""
'-subj',
'/CN=end/',
'-config',
self.temp_dir + '/ca.conf',
temp_dir + '/ca.conf',
'-keyfile',
self.temp_dir + '/int.key',
temp_dir + '/int.key',
'-cert',
self.temp_dir + '/int.crt',
temp_dir + '/int.crt',
'-in',
self.temp_dir + '/end.csr',
temp_dir + '/end.csr',
'-out',
self.temp_dir + '/end.crt',
temp_dir + '/end.crt',
],
stderr=subprocess.STDOUT,
)
crt_path = self.temp_dir + '/end-int.crt'
end_path = self.temp_dir + '/end.crt'
int_path = self.temp_dir + '/int.crt'
crt_path = temp_dir + '/end-int.crt'
end_path = temp_dir + '/end.crt'
int_path = temp_dir + '/int.crt'
with open(crt_path, 'wb') as crt, open(end_path, 'rb') as end, open(
int_path, 'rb'
@@ -333,7 +334,7 @@ basicConstraints = critical,CA:TRUE"""
self.context = ssl.create_default_context()
self.context.check_hostname = False
self.context.verify_mode = ssl.CERT_REQUIRED
self.context.load_verify_locations(self.temp_dir + '/root.crt')
self.context.load_verify_locations(temp_dir + '/root.crt')
# incomplete chain

View File

@@ -9,8 +9,6 @@ class TestUpstreamsRR(TestApplicationPython):
prerequisites = {'modules': {'python': 'any'}}
def setup_method(self):
super().setup_method()
assert 'success' in self.conf(
{
"listeners": {
@@ -391,9 +389,9 @@ Connection: close
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.temp_dir + '/sock_0'
addr_1 = self.temp_dir + '/sock_1'
def test_upstreams_rr_unix(self, temp_dir):
addr_0 = temp_dir + '/sock_0'
addr_1 = temp_dir + '/sock_1'
assert 'success' in self.conf(
{

View File

@@ -1,6 +1,7 @@
import os
from subprocess import call
from conftest import unit_stop
from conftest import waitforfiles
from unit.applications.lang.python import TestApplicationPython
@@ -8,12 +9,12 @@ from unit.applications.lang.python import TestApplicationPython
class TestUSR1(TestApplicationPython):
prerequisites = {'modules': {'python': 'any'}}
def test_usr1_access_log(self):
def test_usr1_access_log(self, temp_dir):
self.load('empty')
log = 'access.log'
log_new = 'new.log'
log_path = self.temp_dir + '/' + log
log_path = temp_dir + '/' + log
assert 'success' in self.conf(
'"' + log_path + '"', 'access_log'
@@ -21,7 +22,7 @@ class TestUSR1(TestApplicationPython):
assert waitforfiles(log_path), 'open'
os.rename(log_path, self.temp_dir + '/' + log_new)
os.rename(log_path, temp_dir + '/' + log_new)
assert self.get()['status'] == 200
@@ -31,7 +32,7 @@ class TestUSR1(TestApplicationPython):
), 'rename new'
assert not os.path.isfile(log_path), 'rename old'
with open(self.temp_dir + '/unit.pid', 'r') as f:
with open(temp_dir + '/unit.pid', 'r') as f:
pid = f.read().rstrip()
call(['kill', '-s', 'USR1', pid])
@@ -40,7 +41,7 @@ class TestUSR1(TestApplicationPython):
assert self.get(url='/usr1')['status'] == 200
self.stop()
unit_stop()
assert (
self.wait_for_record(r'"GET /usr1 HTTP/1.1" 200 0 "-" "-"', log)
@@ -48,12 +49,12 @@ class TestUSR1(TestApplicationPython):
), 'reopen 2'
assert self.search_in_log(r'/usr1', log_new) is None, 'rename new 2'
def test_usr1_unit_log(self):
def test_usr1_unit_log(self, temp_dir):
self.load('log_body')
log_new = 'new.log'
log_path = self.temp_dir + '/unit.log'
log_path_new = self.temp_dir + '/' + log_new
log_path = temp_dir + '/unit.log'
log_path_new = temp_dir + '/' + log_new
os.rename(log_path, log_path_new)
@@ -63,7 +64,7 @@ class TestUSR1(TestApplicationPython):
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.temp_dir + '/unit.pid', 'r') as f:
with open(temp_dir + '/unit.pid', 'r') as f:
pid = f.read().rstrip()
call(['kill', '-s', 'USR1', pid])
@@ -73,7 +74,7 @@ class TestUSR1(TestApplicationPython):
body = 'body_for_a_log_unit'
assert self.post(body=body)['status'] == 200
self.stop()
unit_stop()
assert self.wait_for_record(body) is not None, 'rename new'
assert self.search_in_log(body, log_new) is None, 'rename new 2'

View File

@@ -5,8 +5,6 @@ class TestVariables(TestApplicationProto):
prerequisites = {}
def setup_method(self):
super().setup_method()
assert 'success' in self.conf(
{
"listeners": {"*:7080": {"pass": "routes/$method"}},

View File

@@ -7,8 +7,8 @@ from unit.applications.proto import TestApplicationProto
class TestApplicationGo(TestApplicationProto):
def prepare_env(self, script, name, static=False):
if not os.path.exists(self.temp_dir + '/go'):
os.mkdir(self.temp_dir + '/go')
if not os.path.exists(option.temp_dir + '/go'):
os.mkdir(option.temp_dir + '/go')
env = os.environ.copy()
env['GOPATH'] = option.current_dir + '/build/go'
@@ -22,7 +22,7 @@ class TestApplicationGo(TestApplicationProto):
'-ldflags',
'-extldflags "-static"',
'-o',
self.temp_dir + '/go/' + name,
option.temp_dir + '/go/' + name,
option.test_dir + '/go/' + script + '/' + name + '.go',
]
else:
@@ -30,7 +30,7 @@ class TestApplicationGo(TestApplicationProto):
'go',
'build',
'-o',
self.temp_dir + '/go/' + name,
option.temp_dir + '/go/' + name,
option.test_dir + '/go/' + script + '/' + name + '.go',
]
@@ -47,7 +47,7 @@ class TestApplicationGo(TestApplicationProto):
static_build = False
wdir = option.test_dir + "/go/" + script
executable = self.temp_dir + "/go/" + name
executable = option.temp_dir + "/go/" + name
if 'isolation' in kwargs and 'rootfs' in kwargs['isolation']:
wdir = "/go/"

View File

@@ -10,7 +10,7 @@ from unit.applications.proto import TestApplicationProto
class TestApplicationJava(TestApplicationProto):
def load(self, script, name='app', **kwargs):
app_path = self.temp_dir + '/java'
app_path = option.temp_dir + '/java'
web_inf_path = app_path + '/WEB-INF/'
classes_path = web_inf_path + 'classes/'
script_path = option.test_dir + '/java/' + script + '/'

View File

@@ -11,17 +11,17 @@ class TestApplicationNode(TestApplicationProto):
# copy application
shutil.copytree(
option.test_dir + '/node/' + script, self.temp_dir + '/node'
option.test_dir + '/node/' + script, option.temp_dir + '/node'
)
# copy modules
shutil.copytree(
option.current_dir + '/node/node_modules',
self.temp_dir + '/node/node_modules',
option.temp_dir + '/node/node_modules',
)
public_dir(self.temp_dir + '/node')
public_dir(option.temp_dir + '/node')
self._load_conf(
{
@@ -32,7 +32,7 @@ class TestApplicationNode(TestApplicationProto):
script: {
"type": "external",
"processes": {"spare": 0},
"working_directory": self.temp_dir + '/node',
"working_directory": option.temp_dir + '/node',
"executable": name,
}
},

View File

@@ -12,7 +12,6 @@ class TestApplicationPython(TestApplicationProto):
load_module = "wsgi"
def load(self, script, name=None, module=None, **kwargs):
print()
if name is None:
name = script

View File

@@ -14,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.temp_dir + '/' + name, 'r', errors='ignore') as f:
with open(option.temp_dir + '/' + name, 'r', errors='ignore') as f:
return re.search(pattern, f.read())
def wait_for_record(self, pattern, name='unit.log'):

View File

@@ -8,8 +8,6 @@ from unit.applications.proto import TestApplicationProto
class TestApplicationTLS(TestApplicationProto):
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
@@ -24,9 +22,9 @@ class TestApplicationTLS(TestApplicationProto):
'-x509',
'-new',
'-subj', '/CN=' + name + '/',
'-config', self.temp_dir + '/openssl.conf',
'-out', self.temp_dir + '/' + name + '.crt',
'-keyout', self.temp_dir + '/' + name + '.key',
'-config', option.temp_dir + '/openssl.conf',
'-out', option.temp_dir + '/' + name + '.crt',
'-keyout', option.temp_dir + '/' + name + '.key',
],
stderr=subprocess.STDOUT,
)
@@ -38,8 +36,8 @@ class TestApplicationTLS(TestApplicationProto):
if key is None:
key = crt
key_path = self.temp_dir + '/' + key + '.key'
crt_path = self.temp_dir + '/' + crt + '.crt'
key_path = option.temp_dir + '/' + key + '.key'
crt_path = option.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)
@@ -66,7 +64,7 @@ class TestApplicationTLS(TestApplicationProto):
return ssl.get_server_certificate(addr, ssl_version=ssl_version)
def openssl_conf(self):
conf_path = self.temp_dir + '/openssl.conf'
conf_path = option.temp_dir + '/openssl.conf'
if os.path.exists(conf_path):
return

View File

@@ -1,5 +1,6 @@
import json
from conftest import option
from unit.http import TestHTTP
@@ -53,7 +54,7 @@ class TestControl(TestHTTP):
args = {
'url': url,
'sock_type': 'unix',
'addr': self.temp_dir + '/control.unit.sock',
'addr': option.temp_dir + '/control.unit.sock',
}
if conf is not None:

View File

@@ -21,6 +21,16 @@ class TestFeatureIsolation(TestApplicationProto):
if 'go' in available['modules']:
module = TestApplicationGo()
elif 'python' in available['modules']:
module = TestApplicationPython()
elif 'php' in available['modules']:
module = TestApplicationPHP()
app = 'phpinfo'
elif 'ruby' in available['modules']:
module = TestApplicationRuby()
elif 'java' in available['modules']:
module = TestApplicationJava()
@@ -32,16 +42,6 @@ class TestFeatureIsolation(TestApplicationProto):
module = TestApplicationPerl()
app = 'body_empty'
elif 'php' in available['modules']:
module = TestApplicationPHP()
app = 'phpinfo'
elif 'python' in available['modules']:
module = TestApplicationPython()
elif 'ruby' in available['modules']:
module = TestApplicationRuby()
if not module:
return

View File

@@ -5,7 +5,6 @@ import os
import re
import select
import socket
import time
import pytest
from conftest import option
@@ -283,23 +282,6 @@ class TestHTTP(TestUnit):
def getjson(self, **kwargs):
return self.get(json=True, **kwargs)
def waitforsocket(self, port):
ret = False
for i in range(50):
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('127.0.0.1', port))
ret = True
break
except:
sock.close()
time.sleep(0.1)
sock.close()
assert ret, 'socket connected'
def form_encode(self, fields):
is_multipart = False

View File

@@ -1,55 +1,19 @@
import atexit
import os
import re
import shutil
import signal
import stat
import subprocess
import tempfile
import time
from multiprocessing import Process
import pytest
from conftest import _check_alerts
from conftest import _print_log
from conftest import option
from conftest import public_dir
from conftest import waitforfiles
class TestUnit():
@classmethod
def setup_class(cls, complete_check=True):
cls.available = option.available
unit = TestUnit()
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(path=unit.temp_dir + '/unit.log')
exit("Unit is writing log too long")
def check(available, prerequisites):
def check():
missed = []
# check modules
if 'modules' in prerequisites:
available_modules = list(available['modules'].keys())
if 'modules' in cls.prerequisites:
available_modules = list(option.available['modules'].keys())
for module in prerequisites['modules']:
for module in cls.prerequisites['modules']:
if module in available_modules:
continue
@@ -60,10 +24,10 @@ class TestUnit():
# check features
if 'features' in prerequisites:
available_features = list(available['features'].keys())
if 'features' in cls.prerequisites:
available_features = list(option.available['features'].keys())
for feature in prerequisites['features']:
for feature in cls.prerequisites['features']:
if feature in available_features:
continue
@@ -72,132 +36,7 @@ class TestUnit():
if missed:
pytest.skip(', '.join(missed) + ' feature(s) not supported')
def destroy():
unit.stop()
_check_alerts(log)
shutil.rmtree(unit.temp_dir)
def complete():
destroy()
check(cls.available, cls.prerequisites)
if complete_check:
complete()
check()
else:
unit.complete = complete
return unit
def setup_method(self):
self._run()
def _run(self):
build_dir = option.current_dir + '/build'
self.unitd = build_dir + '/unitd'
if not os.path.isfile(self.unitd):
exit("Could not find unit")
self.temp_dir = tempfile.mkdtemp(prefix='unit-test-')
public_dir(self.temp_dir)
if oct(stat.S_IMODE(os.stat(build_dir).st_mode)) != '0o777':
public_dir(build_dir)
os.mkdir(self.temp_dir + '/state')
with open(self.temp_dir + '/unit.log', 'w') as log:
self._p = subprocess.Popen(
[
self.unitd,
'--no-daemon',
'--modules', build_dir,
'--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 waitforfiles(self.temp_dir + '/control.unit.sock'):
_print_log(path=self.temp_dir + '/unit.log')
exit("Could not start unit")
self._started = True
def teardown_method(self):
self.stop()
# check unit.log for alerts
unit_log = self.temp_dir + '/unit.log'
with open(unit_log, 'r', encoding='utf-8', errors='ignore') as f:
_check_alerts(f.read())
# remove unit.log
if not option.save_log:
shutil.rmtree(self.temp_dir)
else:
_print_log(path=self.temp_dir)
assert self.stop_errors == [None, None], 'stop errors'
def stop(self):
if not self._started:
return
self.stop_errors = []
self.stop_errors.append(self._stop())
self.stop_errors.append(self.stop_processes())
atexit.unregister(self.stop)
self._started = False
def _stop(self):
if self._p.poll() is not None:
return
with self._p as p:
p.send_signal(signal.SIGQUIT)
try:
retcode = p.wait(15)
if retcode:
return 'Child process terminated with code ' + str(retcode)
except:
p.kill()
return 'Could not terminate unit'
def run_process(self, target, *args):
if not hasattr(self, '_processes'):
self._processes = []
process = Process(target=target, args=args)
process.start()
self._processes.append(process)
def stop_processes(self):
if not hasattr(self, '_processes'):
return
fail = False
for process in self._processes:
if process.is_alive():
process.terminate()
process.join(timeout=15)
if process.is_alive():
fail = True
if fail:
return 'Fail to stop process'
return check