diff options
Diffstat (limited to 'test/unit')
-rw-r--r-- | test/unit/applications/proto.py | 3 | ||||
-rw-r--r-- | test/unit/check/check_prerequisites.py | 63 | ||||
-rw-r--r-- | test/unit/check/chroot.py | 40 | ||||
-rw-r--r-- | test/unit/check/discover_available.py | 47 | ||||
-rw-r--r-- | test/unit/check/go.py | 3 | ||||
-rw-r--r-- | test/unit/check/isolation.py | 16 | ||||
-rw-r--r-- | test/unit/check/njs.py | 3 | ||||
-rw-r--r-- | test/unit/check/node.py | 10 | ||||
-rw-r--r-- | test/unit/check/regex.py | 5 | ||||
-rw-r--r-- | test/unit/check/tls.py | 5 | ||||
-rw-r--r-- | test/unit/check/unix_abstract.py | 30 | ||||
-rw-r--r-- | test/unit/log.py | 24 | ||||
-rw-r--r-- | test/unit/option.py | 1 |
13 files changed, 185 insertions, 65 deletions
diff --git a/test/unit/applications/proto.py b/test/unit/applications/proto.py index 00ea44b2..354c31af 100644 --- a/test/unit/applications/proto.py +++ b/test/unit/applications/proto.py @@ -1,9 +1,6 @@ import os -import re -import time from unit.control import TestControl -from unit.log import Log from unit.option import option diff --git a/test/unit/check/check_prerequisites.py b/test/unit/check/check_prerequisites.py new file mode 100644 index 00000000..44c3f10f --- /dev/null +++ b/test/unit/check/check_prerequisites.py @@ -0,0 +1,63 @@ +import pytest +from unit.option import option + + +def check_prerequisites(prerequisites): + if 'privileged_user' in prerequisites: + if prerequisites['privileged_user'] and not option.is_privileged: + pytest.skip( + 'privileged user required', + allow_module_level=True, + ) + elif not prerequisites['privileged_user'] and option.is_privileged: + pytest.skip( + 'unprivileged user required', + allow_module_level=True, + ) + + missed = [] + + # check modules + + if 'modules' in prerequisites: + available = option.available['modules'] + + for module in prerequisites['modules']: + if module in available and available[module]: + continue + + missed.append(module) + + if missed: + pytest.skip( + f'Unit has no {", ".join(missed)} module(s)', + allow_module_level=True, + ) + + # check features + + if 'features' in prerequisites: + available = option.available['features'] + require = prerequisites['features'] + + for feature in require: + avail_feature = available[feature] + + if feature in available and avail_feature: + if isinstance(require[feature], list) and isinstance( + avail_feature, dict + ): + avail_keys = avail_feature.keys() + + for key in require[feature]: + if key not in avail_keys: + missed.append(f'{feature}/{key}') + continue + + missed.append(feature) + + if missed: + pytest.skip( + f'{", ".join(missed)} feature(s) not supported', + allow_module_level=True, + ) diff --git a/test/unit/check/chroot.py b/test/unit/check/chroot.py index 1b7aae90..ac5a91d0 100644 --- a/test/unit/check/chroot.py +++ b/test/unit/check/chroot.py @@ -7,26 +7,24 @@ http = TestHTTP() def check_chroot(): - available = option.available - - resp = http.put( - url='/config', - sock_type='unix', - addr=f'{option.temp_dir}/control.unit.sock', - body=json.dumps( - { - "listeners": {"*:7080": {"pass": "routes"}}, - "routes": [ - { - "action": { - "share": option.temp_dir, - "chroot": option.temp_dir, + return ( + 'success' + in http.put( + url='/config', + sock_type='unix', + addr=f'{option.temp_dir}/control.unit.sock', + body=json.dumps( + { + "listeners": {"*:7080": {"pass": "routes"}}, + "routes": [ + { + "action": { + "share": option.temp_dir, + "chroot": option.temp_dir, + } } - } - ], - } - ), + ], + } + ), + )['body'] ) - - if 'success' in resp['body']: - available['features']['chroot'] = True diff --git a/test/unit/check/discover_available.py b/test/unit/check/discover_available.py new file mode 100644 index 00000000..0942581b --- /dev/null +++ b/test/unit/check/discover_available.py @@ -0,0 +1,47 @@ +import subprocess +import sys + +from unit.check.chroot import check_chroot +from unit.check.go import check_go +from unit.check.isolation import check_isolation +from unit.check.njs import check_njs +from unit.check.node import check_node +from unit.check.regex import check_regex +from unit.check.tls import check_openssl +from unit.check.unix_abstract import check_unix_abstract +from unit.log import Log +from unit.option import option + + +def discover_available(unit): + output_version = subprocess.check_output( + [unit['unitd'], '--version'], stderr=subprocess.STDOUT + ).decode() + + # wait for controller start + + if Log.wait_for_record(r'controller started') is None: + Log.print_log() + sys.exit("controller didn't start") + + # discover modules from log file + + for module in Log.findall(r'module: ([a-zA-Z]+) (.*) ".*"$'): + versions = option.available['modules'].setdefault(module[0], []) + if module[1] not in versions: + versions.append(module[1]) + + # discover modules using check + + option.available['modules']['go'] = check_go() + option.available['modules']['njs'] = check_njs(output_version) + option.available['modules']['node'] = check_node() + option.available['modules']['openssl'] = check_openssl(output_version) + option.available['modules']['regex'] = check_regex(output_version) + + # Discover features using check. Features should be discovered after + # modules since some features can require modules. + + option.available['features']['chroot'] = check_chroot() + option.available['features']['isolation'] = check_isolation() + option.available['features']['unix_abstract'] = check_unix_abstract() diff --git a/test/unit/check/go.py b/test/unit/check/go.py index 09ae641d..469bef1d 100644 --- a/test/unit/check/go.py +++ b/test/unit/check/go.py @@ -2,5 +2,4 @@ from unit.applications.lang.go import TestApplicationGo def check_go(): - if TestApplicationGo.prepare_env('empty') is not None: - return True + return TestApplicationGo.prepare_env('empty') is not None diff --git a/test/unit/check/isolation.py b/test/unit/check/isolation.py index 829d956b..aaa9b166 100644 --- a/test/unit/check/isolation.py +++ b/test/unit/check/isolation.py @@ -127,7 +127,7 @@ def check_isolation(): } else: - return + return False resp = http.put( url='/config', @@ -137,23 +137,23 @@ def check_isolation(): ) if 'success' not in resp['body']: - return + return False userns = getns('user') if not userns: - return + return False - available['features']['isolation'] = {'user': userns} + isolation = {'user': userns} unp_clone_path = '/proc/sys/kernel/unprivileged_userns_clone' if os.path.exists(unp_clone_path): with open(unp_clone_path, 'r') as f: if str(f.read()).rstrip() == '1': - available['features']['isolation'][ - 'unprivileged_userns_clone' - ] = True + isolation['unprivileged_userns_clone'] = True for ns in allns: ns_value = getns(ns) if ns_value: - available['features']['isolation'][ns] = ns_value + isolation[ns] = ns_value + + return isolation diff --git a/test/unit/check/njs.py b/test/unit/check/njs.py index 433473a1..363a1b62 100644 --- a/test/unit/check/njs.py +++ b/test/unit/check/njs.py @@ -2,5 +2,4 @@ import re def check_njs(output_version): - if re.search('--njs', output_version): - return True + return re.search('--njs', output_version) diff --git a/test/unit/check/node.py b/test/unit/check/node.py index dd59e7a4..6a3d581f 100644 --- a/test/unit/check/node.py +++ b/test/unit/check/node.py @@ -1,10 +1,12 @@ import os import subprocess +from unit.option import option -def check_node(current_dir): - if not os.path.exists(f'{current_dir}/node/node_modules'): - return None + +def check_node(): + if not os.path.exists(f'{option.current_dir}/node/node_modules'): + return False try: v_bytes = subprocess.check_output(['/usr/bin/env', 'node', '-v']) @@ -12,4 +14,4 @@ def check_node(current_dir): return [str(v_bytes, 'utf-8').lstrip('v').rstrip()] except subprocess.CalledProcessError: - return None + return False diff --git a/test/unit/check/regex.py b/test/unit/check/regex.py index 51cf966b..83e93f2d 100644 --- a/test/unit/check/regex.py +++ b/test/unit/check/regex.py @@ -2,7 +2,4 @@ import re def check_regex(output_version): - if re.search('--no-regex', output_version): - return False - - return True + return not re.search('--no-regex', output_version) diff --git a/test/unit/check/tls.py b/test/unit/check/tls.py index 53ce5ffc..9cc2a5f9 100644 --- a/test/unit/check/tls.py +++ b/test/unit/check/tls.py @@ -6,7 +6,6 @@ def check_openssl(output_version): try: subprocess.check_output(['which', 'openssl']) except subprocess.CalledProcessError: - return None + return False - if re.search('--openssl', output_version): - return True + return re.search('--openssl', output_version) diff --git a/test/unit/check/unix_abstract.py b/test/unit/check/unix_abstract.py index aadde43a..780e0212 100644 --- a/test/unit/check/unix_abstract.py +++ b/test/unit/check/unix_abstract.py @@ -7,19 +7,19 @@ http = TestHTTP() def check_unix_abstract(): - available = option.available - - resp = http.put( - url='/config', - sock_type='unix', - addr=f'{option.temp_dir}/control.unit.sock', - body=json.dumps( - { - "listeners": {"unix:@sock": {"pass": "routes"}}, - "routes": [], - } - ), + return ( + 'success' + in http.put( + url='/config', + sock_type='unix', + addr=f'{option.temp_dir}/control.unit.sock', + body=json.dumps( + { + "listeners": { + f'unix:@{option.temp_dir}/sock': {"pass": "routes"} + }, + "routes": [], + } + ), + )['body'] ) - - if 'success' in resp['body']: - available['features']['unix_abstract'] = True diff --git a/test/unit/log.py b/test/unit/log.py index c98054d5..7d7e355a 100644 --- a/test/unit/log.py +++ b/test/unit/log.py @@ -1,6 +1,7 @@ import os import re import sys +import time from unit.option import option @@ -25,7 +26,7 @@ class Log: @print_log_on_assert def check_alerts(log=None): if log is None: - log = Log.read(encoding='utf-8') + log = Log.read() found = False alerts = re.findall(r'.+\[alert\].+', log) @@ -52,11 +53,15 @@ class Log: print('skipped.') @staticmethod + def findall(pattern, name=UNIT_LOG, flags=re.M): + return re.findall(pattern, Log.read(name), flags) + + @staticmethod def get_path(name=UNIT_LOG): return f'{option.temp_dir}/{name}' @staticmethod - def open(name=UNIT_LOG, encoding=None): + def open(name=UNIT_LOG, encoding='utf-8'): file = open(Log.get_path(name), 'r', encoding=encoding, errors='ignore') file.seek(Log.pos.get(name, 0)) @@ -71,7 +76,7 @@ class Log: sys.stdout.flush() if log is None: - log = Log.read(encoding='utf-8') + log = Log.read() sys.stdout.write(log) @@ -93,3 +98,16 @@ class Log: pos = Log.pos.get(UNIT_LOG, 0) Log.pos[UNIT_LOG] = Log.pos.get(name, 0) Log.pos[name] = pos + + @staticmethod + def wait_for_record(pattern, name=UNIT_LOG, wait=150, flags=re.M): + with Log.open(name) as file: + for _ in range(wait): + found = re.search(pattern, file.read(), flags) + + if found is not None: + break + + time.sleep(0.1) + + return found diff --git a/test/unit/option.py b/test/unit/option.py index e00a043a..6bd0c836 100644 --- a/test/unit/option.py +++ b/test/unit/option.py @@ -4,6 +4,7 @@ import platform class Options: _options = { 'architecture': platform.architecture()[0], + 'available': {'modules': {}, 'features': {}}, 'is_privileged': os.geteuid() == 0, 'skip_alerts': [], 'skip_sanitizer': False, |