Tests: prerequisites checking reworked.
Prerequisites check moved to the module level to simplify class structure. Discovery and prerequisites checks functions moved to the separate files. Introduced "require" fixture to provide per-test requirements check.
This commit is contained in:
63
test/unit/check/check_prerequisites.py
Normal file
63
test/unit/check/check_prerequisites.py
Normal file
@@ -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,
|
||||
)
|
||||
@@ -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
|
||||
|
||||
47
test/unit/check/discover_available.py
Normal file
47
test/unit/check/discover_available.py
Normal file
@@ -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()
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user