diff options
44 files changed, 427 insertions, 488 deletions
diff --git a/test/conftest.py b/test/conftest.py index b62264ca..0b9adf69 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -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,23 +338,22 @@ 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: - path = unit_instance['log'] +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") diff --git a/test/pytest.ini b/test/pytest.ini index c672788a..0c3a330c 100644 --- a/test/pytest.ini +++ b/test/pytest.ini @@ -1,3 +1,3 @@ [pytest] -addopts = -rs -vvv +addopts = -vvv -s --detailed --print_log python_functions = test_* diff --git a/test/test_access_log.py b/test/test_access_log.py index eaba82ab..511ce6c5 100644 --- a/test/test_access_log.py +++ b/test/test_access_log.py @@ -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') diff --git a/test/test_asgi_application.py b/test/test_asgi_application.py index 948d9823..1a654ebf 100644 --- a/test/test_asgi_application.py +++ b/test/test_asgi_application.py @@ -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): diff --git a/test/test_asgi_lifespan.py b/test/test_asgi_lifespan.py index c37a1aae..3f29c7e7 100644 --- a/test/test_asgi_lifespan.py +++ b/test/test_asgi_lifespan.py @@ -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) diff --git a/test/test_asgi_websockets.py b/test/test_asgi_websockets.py index ab49b130..54984526 100644 --- a/test/test_asgi_websockets.py +++ b/test/test_asgi_websockets.py @@ -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' diff --git a/test/test_go_isolation.py b/test/test_go_isolation.py index 1e7243f6..9a84aa25 100644 --- a/test/test_go_isolation.py +++ b/test/test_go_isolation.py @@ -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) diff --git a/test/test_go_isolation_rootfs.py b/test/test_go_isolation_rootfs.py index d8e177b1..1cc59c67 100644 --- a/test/test_go_isolation_rootfs.py +++ b/test/test_go_isolation_rootfs.py @@ -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) diff --git a/test/test_java_application.py b/test/test_java_application.py index afcdf651..efafa6a1 100644 --- a/test/test_java_application.py +++ b/test/test_java_application.py @@ -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) diff --git a/test/test_java_isolation_rootfs.py b/test/test_java_isolation_rootfs.py index f0f04df1..4f9e9834 100644 --- a/test/test_java_isolation_rootfs.py +++ b/test/test_java_isolation_rootfs.py @@ -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) diff --git a/test/test_java_websockets.py b/test/test_java_websockets.py index 7e6d82e8..7586d4aa 100644 --- a/test/test_java_websockets.py +++ b/test/test_java_websockets.py @@ -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' diff --git a/test/test_node_application.py b/test/test_node_application.py index a0b882f3..c8c3a444 100644 --- a/test/test_node_application.py +++ b/test/test_node_application.py @@ -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') diff --git a/test/test_node_websockets.py b/test/test_node_websockets.py index 6a6b7f2d..7b65b5c1 100644 --- a/test/test_node_websockets.py +++ b/test/test_node_websockets.py @@ -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' diff --git a/test/test_perl_application.py b/test/test_perl_application.py index 78e32a43..acd76626 100644 --- a/test/test_perl_application.py +++ b/test/test_perl_application.py @@ -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') diff --git a/test/test_php_application.py b/test/test_php_application.py index 063d3e0c..f1a9e293 100644 --- a/test/test_php_application.py +++ b/test/test_php_application.py @@ -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) diff --git a/test/test_php_isolation.py b/test/test_php_isolation.py index 8ab3419a..ac6942c6 100644 --- a/test/test_php_isolation.py +++ b/test/test_php_isolation.py @@ -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) + + unit = unit_run() + option.temp_dir = unit['temp_dir'] + + TestFeatureIsolation().check(option.available, unit['temp_dir']) - TestFeatureIsolation().check(cls.available, unit.temp_dir) + assert unit_stop() is None + shutil.rmtree(unit['temp_dir']) - return unit if not complete_check else unit.complete() + 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: diff --git a/test/test_proxy.py b/test/test_proxy.py index d02c96a7..be3e93fd 100644 --- a/test/test_proxy.py +++ b/test/test_proxy.py @@ -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( { diff --git a/test/test_proxy_chunked.py b/test/test_proxy_chunked.py index 26023617..ae2228fa 100644 --- a/test/test_proxy_chunked.py +++ b/test/test_proxy_chunked.py @@ -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( { diff --git a/test/test_python_application.py b/test/test_python_application.py index 3e27a24c..6ea9f4ff 100644 --- a/test/test_python_application.py +++ b/test/test_python_application.py @@ -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( diff --git a/test/test_python_isolation.py b/test/test_python_isolation.py index ac678103..34abd1df 100644 --- a/test/test_python_isolation.py +++ b/test/test_python_isolation.py @@ -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) + + unit = unit_run() + option.temp_dir = unit['temp_dir'] + + TestFeatureIsolation().check(option.available, unit['temp_dir']) - TestFeatureIsolation().check(cls.available, unit.temp_dir) + assert unit_stop() is None + shutil.rmtree(unit['temp_dir']) - return unit if not complete_check else unit.complete() + return check if not complete_check else check() - def test_python_isolation_rootfs(self, is_su): - isolation_features = self.available['features']['isolation'].keys() + 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} } diff --git a/test/test_python_isolation_chroot.py b/test/test_python_isolation_chroot.py index 315fee9f..6d178b2e 100644 --- a/test/test_python_isolation_chroot.py +++ b/test/test_python_isolation_chroot.py @@ -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' diff --git a/test/test_python_procman.py b/test/test_python_procman.py index 8eccae3e..ff914fc8 100644 --- a/test/test_python_procman.py +++ b/test/test_python_procman.py @@ -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) diff --git a/test/test_respawn.py b/test/test_respawn.py index 18b9d535..09a806d4 100644 --- a/test/test_respawn.py +++ b/test/test_respawn.py @@ -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) diff --git a/test/test_return.py b/test/test_return.py index 64050022..2f7b7ae4 100644 --- a/test/test_return.py +++ b/test/test_return.py @@ -7,8 +7,6 @@ class TestReturn(TestApplicationProto): prerequisites = {} def setup_method(self): - super().setup_method() - self._load_conf( { "listeners": {"*:7080": {"pass": "routes"}}, diff --git a/test/test_routing.py b/test/test_routing.py index 2b528435..9e0f52dc 100644 --- a/test/test_routing.py +++ b/test/test_routing.py @@ -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' diff --git a/test/test_ruby_application.py b/test/test_ruby_application.py index f84935f8..b765f390 100644 --- a/test/test_ruby_application.py +++ b/test/test_ruby_application.py @@ -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') diff --git a/test/test_ruby_isolation.py b/test/test_ruby_isolation.py index 13ca0e16..bf934540 100644 --- a/test/test_ruby_isolation.py +++ b/test/test_ruby_isolation.py @@ -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) + + unit = unit_run() + option.temp_dir = unit['temp_dir'] + + TestFeatureIsolation().check(option.available, unit['temp_dir']) - TestFeatureIsolation().check(cls.available, unit.temp_dir) + assert unit_stop() is None + shutil.rmtree(unit['temp_dir']) - return unit if not complete_check else unit.complete() + 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') diff --git a/test/test_settings.py b/test/test_settings.py index b0af6b04..30aa2bff 100644 --- a/test/test_settings.py +++ b/test/test_settings.py @@ -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') diff --git a/test/test_share_fallback.py b/test/test_share_fallback.py index 391d0836..462da9de 100644 --- a/test/test_share_fallback.py +++ b/test/test_share_fallback.py @@ -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"}, } ) diff --git a/test/test_static.py b/test/test_static.py index 0b82b4e8..de8b71cc 100644 --- a/test/test_static.py +++ b/test/test_static.py @@ -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' diff --git a/test/test_tls.py b/test/test_tls.py index 518a834c..7be426b1 100644 --- a/test/test_tls.py +++ b/test/test_tls.py @@ -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 diff --git a/test/test_upstreams_rr.py b/test/test_upstreams_rr.py index 2ecf1d9a..c20d6054 100644 --- a/test/test_upstreams_rr.py +++ b/test/test_upstreams_rr.py @@ -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( { diff --git a/test/test_usr1.py b/test/test_usr1.py index 2e48c18f..3e44e4c5 100644 --- a/test/test_usr1.py +++ b/test/test_usr1.py @@ -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' diff --git a/test/test_variables.py b/test/test_variables.py index c458b636..bbb8f769 100644 --- a/test/test_variables.py +++ b/test/test_variables.py @@ -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"}}, diff --git a/test/unit/applications/lang/go.py b/test/unit/applications/lang/go.py index 7715bd6c..518cd017 100644 --- a/test/unit/applications/lang/go.py +++ b/test/unit/applications/lang/go.py @@ -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/" diff --git a/test/unit/applications/lang/java.py b/test/unit/applications/lang/java.py index 01cbfa0b..a034d9a4 100644 --- a/test/unit/applications/lang/java.py +++ b/test/unit/applications/lang/java.py @@ -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 + '/' diff --git a/test/unit/applications/lang/node.py b/test/unit/applications/lang/node.py index 877fc461..4aa9eb1c 100644 --- a/test/unit/applications/lang/node.py +++ b/test/unit/applications/lang/node.py @@ -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, } }, diff --git a/test/unit/applications/lang/python.py b/test/unit/applications/lang/python.py index 47b95dac..a4a27bb9 100644 --- a/test/unit/applications/lang/python.py +++ b/test/unit/applications/lang/python.py @@ -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 diff --git a/test/unit/applications/proto.py b/test/unit/applications/proto.py index 2f748c21..9a0361d5 100644 --- a/test/unit/applications/proto.py +++ b/test/unit/applications/proto.py @@ -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'): diff --git a/test/unit/applications/tls.py b/test/unit/applications/tls.py index fdf681ae..fb1b112c 100644 --- a/test/unit/applications/tls.py +++ b/test/unit/applications/tls.py @@ -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 diff --git a/test/unit/control.py b/test/unit/control.py index 6fd350f4..f05aa827 100644 --- a/test/unit/control.py +++ b/test/unit/control.py @@ -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: diff --git a/test/unit/feature/isolation.py b/test/unit/feature/isolation.py index c6f6f3c0..235177ab 100644 --- a/test/unit/feature/isolation.py +++ b/test/unit/feature/isolation.py @@ -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 diff --git a/test/unit/http.py b/test/unit/http.py index 7845f9a8..5f073439 100644 --- a/test/unit/http.py +++ b/test/unit/http.py @@ -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 diff --git a/test/unit/main.py b/test/unit/main.py index d5940995..488b3f4d 100644 --- a/test/unit/main.py +++ b/test/unit/main.py @@ -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() - 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) + check() 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 |