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:
Andrei Zeliankou
2023-06-12 14:16:59 +01:00
parent a3b9b49cfb
commit ce2405ec3d
79 changed files with 524 additions and 548 deletions

View 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,
)

View File

@@ -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

View 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()

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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