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 re
import shutil import shutil
import signal import signal
import socket
import stat import stat
import subprocess import subprocess
import sys import sys
import tempfile import tempfile
import time import time
from multiprocessing import Process
import pytest import pytest
@@ -45,6 +47,7 @@ def pytest_addoption(parser):
unit_instance = {} unit_instance = {}
_processes = []
option = None option = None
@@ -66,6 +69,10 @@ def pytest_configure(config):
fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, 0) fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, 0)
def skip_alert(*alerts):
option.skip_alerts.extend(alerts)
def pytest_generate_tests(metafunc): def pytest_generate_tests(metafunc):
cls = metafunc.cls cls = metafunc.cls
if not hasattr(cls, 'application_type'): if not hasattr(cls, 'application_type'):
@@ -127,7 +134,7 @@ def pytest_sessionstart(session):
break break
if m is None: if m is None:
_print_log() _print_log(log)
exit("Unit is writing log too long") exit("Unit is writing log too long")
# discover available modules from unit.log # discover available modules from unit.log
@@ -154,8 +161,26 @@ def pytest_sessionstart(session):
unit_stop() 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 = [ option.skip_alerts = [
r'read signalfd\(4\) failed', r'read signalfd\(4\) failed',
r'sendmsg.+failed', r'sendmsg.+failed',
@@ -163,6 +188,40 @@ def setup_method(self):
] ]
option.skip_sanitizer = False 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(): def unit_run():
global unit_instance global unit_instance
build_dir = option.current_dir + '/build' build_dir = option.current_dir + '/build'
@@ -204,14 +263,6 @@ def unit_run():
_print_log() _print_log()
exit('Could not start unit') 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['temp_dir'] = temp_dir
unit_instance['log'] = temp_dir + '/unit.log' unit_instance['log'] = temp_dir + '/unit.log'
unit_instance['control_sock'] = temp_dir + '/control.unit.sock' unit_instance['control_sock'] = temp_dir + '/control.unit.sock'
@@ -236,8 +287,6 @@ def unit_stop():
p.kill() p.kill()
return 'Could not terminate unit' return 'Could not terminate unit'
shutil.rmtree(unit_instance['temp_dir'])
def public_dir(path): def public_dir(path):
os.chmod(path, 0o777) os.chmod(path, 0o777)
@@ -267,11 +316,14 @@ def waitforfiles(*files):
return ret 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 found = False
alerts = re.findall(r'.+\[alert\].+', log) alerts = re.findall(r'.+\[alert\].+', log)
@@ -286,23 +338,22 @@ def _check_alerts(log):
alerts = [al for al in alerts if re.search(skip, al) is None] alerts = [al for al in alerts if re.search(skip, al) is None]
if alerts: if alerts:
_print_log(data=log) _print_log(log)
assert not alerts, 'alert(s)' assert not alerts, 'alert(s)'
if not option.skip_sanitizer: if not option.skip_sanitizer:
sanitizer_errors = re.findall('.+Sanitizer.+', log) sanitizer_errors = re.findall('.+Sanitizer.+', log)
if sanitizer_errors: if sanitizer_errors:
_print_log(data=log) _print_log(log)
assert not sanitizer_errors, 'sanitizer error(s)' assert not sanitizer_errors, 'sanitizer error(s)'
if found: if found:
print('skipped.') print('skipped.')
def _print_log(path=None, data=None): def _print_log(data=None):
if path is None: path = unit_instance['log']
path = unit_instance['log']
print('Path to unit.log:\n' + path + '\n') print('Path to unit.log:\n' + path + '\n')
@@ -317,6 +368,52 @@ def _print_log(path=None, data=None):
sys.stdout.write(data) 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 @pytest.fixture
def is_unsafe(request): def is_unsafe(request):
return request.config.getoption("--unsafe") return request.config.getoption("--unsafe")

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -6,6 +6,7 @@ import time
import pytest import pytest
from conftest import option from conftest import option
from conftest import unit_stop
from unit.applications.lang.php import TestApplicationPHP from unit.applications.lang.php import TestApplicationPHP
class TestPHPApplication(TestApplicationPHP): class TestPHPApplication(TestApplicationPHP):
@@ -444,7 +445,7 @@ class TestPHPApplication(TestApplicationPHP):
r'012345', self.get()['body'] r'012345', self.get()['body']
), 'disable_classes before' ), 'disable_classes before'
def test_php_application_error_log(self): def test_php_application_error_log(self, temp_dir):
self.load('error_log') self.load('error_log')
assert self.get()['status'] == 200, 'status' assert self.get()['status'] == 200, 'status'
@@ -453,13 +454,13 @@ class TestPHPApplication(TestApplicationPHP):
assert self.get()['status'] == 200, 'status 2' 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' 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' 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()) errs = re.findall(pattern, f.read())
assert len(errs) == 2, 'error_log count' assert len(errs) == 2, 'error_log count'
@@ -507,12 +508,12 @@ class TestPHPApplication(TestApplicationPHP):
assert resp['status'] == 200, 'status' assert resp['status'] == 200, 'status'
assert resp['body'] != '', 'body not empty' 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') self.load('phpinfo')
assert self.get(url='/index.wrong')['status'] != 200, 'status' assert self.get(url='/index.wrong')['status'] != 200, 'status'
new_root = self.temp_dir + "/php" new_root = temp_dir + "/php"
os.mkdir(new_root) os.mkdir(new_root)
shutil.copy(option.test_dir + '/php/phpinfo/index.wrong', new_root) shutil.copy(option.test_dir + '/php/phpinfo/index.wrong', new_root)

View File

@@ -1,6 +1,10 @@
import shutil
import pytest import pytest
from conftest import option from conftest import option
from conftest import unit_run
from conftest import unit_stop
from unit.applications.lang.php import TestApplicationPHP from unit.applications.lang.php import TestApplicationPHP
from unit.feature.isolation import TestFeatureIsolation from unit.feature.isolation import TestFeatureIsolation
@@ -8,18 +12,22 @@ from unit.feature.isolation import TestFeatureIsolation
class TestPHPIsolation(TestApplicationPHP): class TestPHPIsolation(TestApplicationPHP):
prerequisites = {'modules': {'php': 'any'}, 'features': ['isolation']} prerequisites = {'modules': {'php': 'any'}, 'features': ['isolation']}
isolation = TestFeatureIsolation()
@classmethod @classmethod
def setup_class(cls, complete_check=True): 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): 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: if 'mnt' not in isolation_features:
pytest.skip('requires mnt ns') pytest.skip('requires mnt ns')
@@ -48,7 +56,7 @@ class TestPHPIsolation(TestApplicationPHP):
assert self.get()['status'] == 200, 'empty rootfs' assert self.get()['status'] == 200, 'empty rootfs'
def test_php_isolation_rootfs_extensions(self, is_su): 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 not is_su:
if 'user' not in isolation_features: if 'user' not in isolation_features:

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,10 @@
import shutil
import pytest import pytest
from conftest import option from conftest import option
from conftest import unit_run
from conftest import unit_stop
from unit.applications.lang.ruby import TestApplicationRuby from unit.applications.lang.ruby import TestApplicationRuby
from unit.feature.isolation import TestFeatureIsolation from unit.feature.isolation import TestFeatureIsolation
@@ -9,18 +12,22 @@ from unit.feature.isolation import TestFeatureIsolation
class TestRubyIsolation(TestApplicationRuby): class TestRubyIsolation(TestApplicationRuby):
prerequisites = {'modules': {'ruby': 'any'}, 'features': ['isolation']} prerequisites = {'modules': {'ruby': 'any'}, 'features': ['isolation']}
isolation = TestFeatureIsolation()
@classmethod @classmethod
def setup_class(cls, complete_check=True): 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): 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: if 'mnt' not in isolation_features:
pytest.skip('requires mnt ns') pytest.skip('requires mnt ns')

View File

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

View File

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

View File

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

View File

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

View File

@@ -9,8 +9,6 @@ class TestUpstreamsRR(TestApplicationPython):
prerequisites = {'modules': {'python': 'any'}} prerequisites = {'modules': {'python': 'any'}}
def setup_method(self): def setup_method(self):
super().setup_method()
assert 'success' in self.conf( assert 'success' in self.conf(
{ {
"listeners": { "listeners": {
@@ -391,9 +389,9 @@ Connection: close
assert sum(resps) == 100, 'post sum' assert sum(resps) == 100, 'post sum'
assert abs(resps[0] - resps[1]) <= self.cpu_count, 'post' assert abs(resps[0] - resps[1]) <= self.cpu_count, 'post'
def test_upstreams_rr_unix(self): def test_upstreams_rr_unix(self, temp_dir):
addr_0 = self.temp_dir + '/sock_0' addr_0 = temp_dir + '/sock_0'
addr_1 = self.temp_dir + '/sock_1' addr_1 = temp_dir + '/sock_1'
assert 'success' in self.conf( assert 'success' in self.conf(
{ {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -14,7 +14,7 @@ class TestApplicationProto(TestControl):
return time.mktime(time.strptime(date, template)) return time.mktime(time.strptime(date, template))
def search_in_log(self, pattern, name='unit.log'): 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()) return re.search(pattern, f.read())
def wait_for_record(self, pattern, name='unit.log'): def wait_for_record(self, pattern, name='unit.log'):

View File

@@ -8,8 +8,6 @@ from unit.applications.proto import TestApplicationProto
class TestApplicationTLS(TestApplicationProto): class TestApplicationTLS(TestApplicationProto):
def setup_method(self): def setup_method(self):
super().setup_method()
self.context = ssl.create_default_context() self.context = ssl.create_default_context()
self.context.check_hostname = False self.context.check_hostname = False
self.context.verify_mode = ssl.CERT_NONE self.context.verify_mode = ssl.CERT_NONE
@@ -24,9 +22,9 @@ class TestApplicationTLS(TestApplicationProto):
'-x509', '-x509',
'-new', '-new',
'-subj', '/CN=' + name + '/', '-subj', '/CN=' + name + '/',
'-config', self.temp_dir + '/openssl.conf', '-config', option.temp_dir + '/openssl.conf',
'-out', self.temp_dir + '/' + name + '.crt', '-out', option.temp_dir + '/' + name + '.crt',
'-keyout', self.temp_dir + '/' + name + '.key', '-keyout', option.temp_dir + '/' + name + '.key',
], ],
stderr=subprocess.STDOUT, stderr=subprocess.STDOUT,
) )
@@ -38,8 +36,8 @@ class TestApplicationTLS(TestApplicationProto):
if key is None: if key is None:
key = crt key = crt
key_path = self.temp_dir + '/' + key + '.key' key_path = option.temp_dir + '/' + key + '.key'
crt_path = self.temp_dir + '/' + crt + '.crt' crt_path = option.temp_dir + '/' + crt + '.crt'
with open(key_path, 'rb') as k, open(crt_path, 'rb') as c: with open(key_path, 'rb') as k, open(crt_path, 'rb') as c:
return self.conf(k.read() + c.read(), '/certificates/' + crt) return self.conf(k.read() + c.read(), '/certificates/' + crt)
@@ -66,7 +64,7 @@ class TestApplicationTLS(TestApplicationProto):
return ssl.get_server_certificate(addr, ssl_version=ssl_version) return ssl.get_server_certificate(addr, ssl_version=ssl_version)
def openssl_conf(self): def openssl_conf(self):
conf_path = self.temp_dir + '/openssl.conf' conf_path = option.temp_dir + '/openssl.conf'
if os.path.exists(conf_path): if os.path.exists(conf_path):
return return

View File

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

View File

@@ -21,6 +21,16 @@ class TestFeatureIsolation(TestApplicationProto):
if 'go' in available['modules']: if 'go' in available['modules']:
module = TestApplicationGo() 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']: elif 'java' in available['modules']:
module = TestApplicationJava() module = TestApplicationJava()
@@ -32,16 +42,6 @@ class TestFeatureIsolation(TestApplicationProto):
module = TestApplicationPerl() module = TestApplicationPerl()
app = 'body_empty' 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: if not module:
return return

View File

@@ -5,7 +5,6 @@ import os
import re import re
import select import select
import socket import socket
import time
import pytest import pytest
from conftest import option from conftest import option
@@ -283,23 +282,6 @@ class TestHTTP(TestUnit):
def getjson(self, **kwargs): def getjson(self, **kwargs):
return self.get(json=True, **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): def form_encode(self, fields):
is_multipart = False 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 import pytest
from conftest import _check_alerts
from conftest import _print_log
from conftest import option from conftest import option
from conftest import public_dir
from conftest import waitforfiles
class TestUnit(): class TestUnit():
@classmethod @classmethod
def setup_class(cls, complete_check=True): def setup_class(cls, complete_check=True):
cls.available = option.available def check():
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):
missed = [] missed = []
# check modules # check modules
if 'modules' in prerequisites: if 'modules' in cls.prerequisites:
available_modules = list(available['modules'].keys()) available_modules = list(option.available['modules'].keys())
for module in prerequisites['modules']: for module in cls.prerequisites['modules']:
if module in available_modules: if module in available_modules:
continue continue
@@ -60,10 +24,10 @@ class TestUnit():
# check features # check features
if 'features' in prerequisites: if 'features' in cls.prerequisites:
available_features = list(available['features'].keys()) available_features = list(option.available['features'].keys())
for feature in prerequisites['features']: for feature in cls.prerequisites['features']:
if feature in available_features: if feature in available_features:
continue continue
@@ -72,132 +36,7 @@ class TestUnit():
if missed: if missed:
pytest.skip(', '.join(missed) + ' feature(s) not supported') 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: if complete_check:
complete() check()
else: else:
unit.complete = complete return check
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'