Skip to content

Commit 79c9675

Browse files
committed
Simplify code in scs-compliance-check.py
Signed-off-by: Matthias Büchse <matthias.buechse@alasca.cloud>
1 parent 83622ab commit 79c9675

1 file changed

Lines changed: 37 additions & 77 deletions

File tree

Tests/scs-compliance-check.py

Lines changed: 37 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import getopt
2727
import datetime
2828
import subprocess
29-
from itertools import chain
3029
import logging
3130
import yaml
3231

@@ -60,7 +59,7 @@ def usage(file=sys.stdout):
6059
""", file=file)
6160

6261

63-
def run_check_tool(executable, args, env=None, cwd=None):
62+
def run_check_tool(executable, args, cwd=None):
6463
"""Run executable and return `CompletedProcess` instance"""
6564
if executable.startswith("http://") or executable.startswith("https://"):
6665
# TODO: When we start supporting this, consider security concerns
@@ -80,7 +79,7 @@ def run_check_tool(executable, args, env=None, cwd=None):
8079
exe.insert(0, sys.executable)
8180
return subprocess.run(
8281
exe, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
83-
encoding='UTF-8', check=False, env=env, cwd=cwd,
82+
encoding='UTF-8', check=False, cwd=cwd,
8483
)
8584

8685

@@ -153,34 +152,8 @@ def select_valid(versions: list) -> list:
153152
return [version for version in versions if version['_explicit_validity']]
154153

155154

156-
def invoke_check_tool(exe, args, env, cwd):
157-
"""run check tool and return invokation dict to use in the report"""
158-
try:
159-
compl = run_check_tool(exe, args, env, cwd)
160-
except Exception as e:
161-
invokation = {
162-
"rc": 127,
163-
"stdout": [],
164-
"stderr": [f"CRITICAL: {e!s}"],
165-
}
166-
else:
167-
invokation = {
168-
"rc": compl.returncode,
169-
"stdout": compl.stdout.splitlines(),
170-
"stderr": compl.stderr.splitlines(),
171-
}
172-
for signal in ('info', 'warning', 'error', 'critical'):
173-
invokation[signal] = len([
174-
line
175-
for line in chain(invokation["stderr"], invokation["stdout"])
176-
if line.lower().startswith(signal)
177-
])
178-
return invokation
179-
180-
181-
def compute_results(stdout, permissible_ids=()):
155+
def compute_results(stdout, results, permissible_ids=()):
182156
"""pick out test results from stdout lines"""
183-
result = {}
184157
for line in stdout:
185158
parts = line.rsplit(':', 1)
186159
if len(parts) != 2:
@@ -192,48 +165,40 @@ def compute_results(stdout, permissible_ids=()):
192165
if permissible_ids and testcase_id not in permissible_ids:
193166
logger.warning(f"ignoring invalid result id: {testcase_id}")
194167
continue
195-
result[testcase_id] = value
196-
return result
168+
results[testcase_id] = value
197169

198170

199171
class CheckRunner:
200-
def __init__(self, cwd, assignment, verbosity=0):
172+
def __init__(self, cwd, assignment, results, log, verbose=False):
201173
self.cwd = cwd
202174
self.assignment = assignment
203175
self.num_abort = 0
204-
self.num_error = 0
205-
self.verbosity = verbosity
176+
self.verbose = verbose
206177
self.spamminess = 0
178+
self.results = results
179+
self.log = log
207180

208-
def run(self, check, testcases=()):
209-
parameters = check.get('parameters', {})
210-
assignment = {'testcases': ' '.join(testcases), **self.assignment, **parameters}
181+
def run(self, check, testcases):
182+
assignment = {'testcases': ' '.join(testcases), **self.assignment}
211183
args = check.get('args', '').format(**assignment)
212-
env = {key: value.format(**assignment) for key, value in check.get('env', {}).items()}
213-
env_str = " ".join(f"{key}={value}" for key, value in env.items())
214-
cmd = f"{env_str} {check['executable']} {args}".strip()
184+
cmd = f"{check['executable']} {args}".strip()
215185
logger.debug(f"running {cmd!r}...")
216-
check_env = {**os.environ, **env}
217-
invocation = invoke_check_tool(check["executable"], args, check_env, self.cwd)
218-
invocation = {
219-
'id': str(uuid.uuid4()),
220-
'cmd': cmd,
221-
'results': compute_results(invocation['stdout'], permissible_ids=testcases),
222-
**invocation
223-
}
224-
if self.verbosity > 1 and invocation["stdout"]:
225-
print("\n".join(invocation["stdout"]))
226-
self.spamminess += 1
227-
# the following check used to be "> 0", but this is quite verbose...
228-
if invocation['rc'] or self.verbosity > 1 and invocation["stderr"]:
229-
print("\n".join(invocation["stderr"]))
186+
self.log.append(f"$ {cmd}")
187+
try:
188+
compl = run_check_tool(check["executable"], args, self.cwd)
189+
except Exception as e:
190+
err_log = f"CRITICAL: {e!s}"
191+
rc = 1
192+
else:
193+
compute_results(compl.stdout.splitlines(), self.results, permissible_ids=testcases)
194+
err_log = compl.stderr.strip()
195+
rc = compl.returncode
196+
self.num_abort += rc
197+
if rc or self.verbose and err_log:
198+
print(err_log, file=sys.stderr)
230199
self.spamminess += 1
231-
logger.debug(f".. rc {invocation['rc']}, {invocation['critical']} critical, {invocation['error']} error")
232-
self.num_abort += invocation["critical"]
233-
self.num_error += invocation["error"]
234-
# count failed testcases because they need not be reported redundantly on the error channel
235-
self.num_error += len([value for value in invocation['results'].values() if value < 0])
236-
return invocation
200+
logger.debug(f'.. rc {rc}')
201+
self.log.extend(err_log.splitlines())
237202

238203

239204
def print_report(testcase_lookup: dict, tc_ids: list, results: dict, partial=False, verbose=False):
@@ -267,11 +232,7 @@ def print_report(testcase_lookup: dict, tc_ids: list, results: dict, partial=Fal
267232
print(f" > {testcase['url']}")
268233

269234

270-
def create_report(config, spec, invocations, results):
271-
log = ['running: ' + shlex.join(sys.argv)]
272-
for invocation in invocations:
273-
log.append(f"$ {invocation['cmd']}")
274-
log.extend(invocation['stderr'])
235+
def create_report(config, spec, log, results):
275236
return {
276237
"uuid": str(uuid.uuid4()),
277238
"creator": "SCS test suite; version=0.1.0", # TODO put actual version of test suite here
@@ -294,6 +255,7 @@ def main(argv):
294255
logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO)
295256
config = Config()
296257
config.apply_argv(argv)
258+
check_cwd = os.path.dirname(config.arg0) or os.getcwd()
297259
if not config.subject:
298260
raise RuntimeError("You need pass --subject=SUBJECT.")
299261
with open(config.arg0, "r", encoding="UTF-8") as specfile:
@@ -313,8 +275,6 @@ def main(argv):
313275
raise RuntimeError(f"Requested version '{config.version}' not found")
314276
if not versions:
315277
raise RuntimeError(f"No valid version found for {config.checkdate}")
316-
check_cwd = os.path.dirname(config.arg0) or os.getcwd()
317-
runner = CheckRunner(check_cwd, assignment, verbosity=config.verbose and 2 or not config.quiet)
318278
title, partial = spec['name'], False
319279
if config.sections:
320280
title += f" [sections: {', '.join(config.sections)}]"
@@ -341,14 +301,13 @@ def main(argv):
341301
idx = script['_idx']
342302
script_tc_ids[idx].append(tc_id)
343303
# run scripts
344-
invocations = [
345-
runner.run(script, testcases=sorted(tc_ids))
346-
for script, tc_ids in zip(spec['scripts'], script_tc_ids)
347-
if tc_ids
348-
]
304+
log = ['running: ' + shlex.join(sys.argv)]
349305
results = {}
350-
for invocation in invocations:
351-
results.update(invocation['results'])
306+
runner = CheckRunner(check_cwd, assignment, results, log, verbose=config.verbose)
307+
for script, tc_ids in zip(spec['scripts'], script_tc_ids):
308+
if not tc_ids:
309+
continue
310+
runner.run(script, sorted(tc_ids))
352311
# now report:
353312
if config.verbose or not config.output:
354313
# print a horizontal line if we had any script output
@@ -359,10 +318,11 @@ def main(argv):
359318
print(f"- {version['version']}:", end=' ')
360319
print_report(testcase_lookup, version['testcase_ids'], results, partial, config.verbose)
361320
if config.output:
362-
report = create_report(config, spec, invocations, results)
321+
report = create_report(config, spec, log, results)
363322
with open(config.output, 'w', encoding='UTF-8') as fileobj:
364323
yaml.safe_dump(report, fileobj, default_flow_style=False, sort_keys=False, explicit_start=True)
365-
return min(127, runner.num_abort + (0 if config.critical_only else runner.num_error))
324+
num_error = len([tc_id for tc_id, value in results.items() if value != 1])
325+
return min(127, runner.num_abort + (0 if config.critical_only else num_error))
366326

367327

368328
if __name__ == "__main__":

0 commit comments

Comments
 (0)