Skip to content

Commit 92050ba

Browse files
committed
Remove newly unnecessary code
Signed-off-by: Matthias Büchse <matthias.buechse@alasca.cloud>
1 parent cf0908b commit 92050ba

5 files changed

Lines changed: 70 additions & 119 deletions

File tree

Tests/scs-compliance-check.py

Lines changed: 44 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#
66
# (c) Eduard Itrich <eduard@itrich.net>
77
# (c) Kurt Garloff <kurt@garloff.de>
8-
# (c) Matthias Büchse <matthias.buechse@cloudandheat.com>
8+
# (c) Matthias Büchse <matthias.buechse@alasca.cloud>
99
# SPDX-License-Identifier: Apache-2.0
1010

1111
"""Main SCS compliance checker
@@ -26,7 +26,6 @@
2626
import getopt
2727
import datetime
2828
import subprocess
29-
from collections import defaultdict
3029
from itertools import chain
3130
import logging
3231
import yaml
@@ -153,10 +152,6 @@ def select_valid(versions: list) -> list:
153152
return [version for version in versions if version['_explicit_validity']]
154153

155154

156-
def suppress(*args, **kwargs):
157-
return
158-
159-
160155
def invoke_check_tool(exe, args, env, cwd):
161156
"""run check tool and return invokation dict to use in the report"""
162157
try:
@@ -182,7 +177,7 @@ def invoke_check_tool(exe, args, env, cwd):
182177
return invokation
183178

184179

185-
def compute_results(stdout):
180+
def compute_results(stdout, permissible_ids=()):
186181
"""pick out test results from stdout lines"""
187182
result = {}
188183
for line in stdout:
@@ -192,15 +187,18 @@ def compute_results(stdout):
192187
value = TESTCASE_VERDICTS.get(parts[1].strip().upper())
193188
if value is None:
194189
continue
195-
result[parts[0].strip()] = value
190+
testcase_id = parts[0].strip()
191+
if permissible_ids and testcase_id not in permissible_ids:
192+
logger.warning(f"ignoring invalid result id: {testcase_id}")
193+
continue
194+
result[testcase_id] = value
196195
return result
197196

198197

199198
class CheckRunner:
200199
def __init__(self, cwd, assignment, verbosity=0):
201200
self.cwd = cwd
202201
self.assignment = assignment
203-
self.memo = {}
204202
self.num_abort = 0
205203
self.num_error = 0
206204
self.verbosity = verbosity
@@ -212,61 +210,30 @@ def run(self, check, testcases=()):
212210
args = check.get('args', '').format(**assignment)
213211
env = {key: value.format(**assignment) for key, value in check.get('env', {}).items()}
214212
env_str = " ".join(f"{key}={value}" for key, value in env.items())
215-
memo_key = f"{env_str} {check['executable']} {args}".strip()
216-
logger.debug(f"running {memo_key!r}...")
217-
invocation = self.memo.get(memo_key)
218-
if invocation is None:
219-
check_env = {**os.environ, **env}
220-
invocation = invoke_check_tool(check["executable"], args, check_env, self.cwd)
221-
invocation = {
222-
'id': str(uuid.uuid4()),
223-
'cmd': memo_key,
224-
'result': 0, # keep this for backwards compatibility
225-
'results': compute_results(invocation['stdout']),
226-
**invocation
227-
}
228-
if self.verbosity > 1 and invocation["stdout"]:
229-
print("\n".join(invocation["stdout"]))
230-
self.spamminess += 1
231-
# the following check used to be "> 0", but this is quite verbose...
232-
if invocation['rc'] or self.verbosity > 1 and invocation["stderr"]:
233-
print("\n".join(invocation["stderr"]))
234-
self.spamminess += 1
235-
self.memo[memo_key] = invocation
213+
cmd = f"{env_str} {check['executable']} {args}".strip()
214+
logger.debug(f"running {cmd!r}...")
215+
check_env = {**os.environ, **env}
216+
invocation = invoke_check_tool(check["executable"], args, check_env, self.cwd)
217+
invocation = {
218+
'id': str(uuid.uuid4()),
219+
'cmd': cmd,
220+
'results': compute_results(invocation['stdout'], permissible_ids=testcases),
221+
**invocation
222+
}
223+
if self.verbosity > 1 and invocation["stdout"]:
224+
print("\n".join(invocation["stdout"]))
225+
self.spamminess += 1
226+
# the following check used to be "> 0", but this is quite verbose...
227+
if invocation['rc'] or self.verbosity > 1 and invocation["stderr"]:
228+
print("\n".join(invocation["stderr"]))
229+
self.spamminess += 1
236230
logger.debug(f".. rc {invocation['rc']}, {invocation['critical']} critical, {invocation['error']} error")
237231
self.num_abort += invocation["critical"]
238232
self.num_error += invocation["error"]
239233
# count failed testcases because they need not be reported redundantly on the error channel
240234
self.num_error + len([value for value in invocation['results'].values() if value < 0])
241235
return invocation
242236

243-
def get_invocations(self):
244-
return {invocation['id']: invocation for invocation in self.memo.values()}
245-
246-
247-
class ResultBuilder:
248-
def __init__(self, name):
249-
self.name = name
250-
self._raw = defaultdict(list)
251-
252-
def record(self, id_, **kwargs):
253-
self._raw[id_].append(kwargs)
254-
255-
def finalize(self, permissible_ids=None):
256-
final = {}
257-
for id_, ls in self._raw.items():
258-
if permissible_ids is not None and id_ not in permissible_ids:
259-
logger.warning(f"ignoring invalid result id: {id_}")
260-
continue
261-
# just in case: sort by value (worst first)
262-
ls.sort(key=lambda item: item['result'])
263-
winner, runnerups = ls[0], ls[1:]
264-
if runnerups:
265-
logger.warning(f"multiple result values for {id_}")
266-
winner = {**winner, 'runnerups': runnerups}
267-
final[id_] = winner
268-
return final
269-
270237

271238
def print_report(subject: str, title: str, testcase_lookup: dict, targets: dict, results: dict, partial=False, verbose=False):
272239
print(f"{subject} {title}:")
@@ -294,12 +261,12 @@ def print_report(subject: str, title: str, testcase_lookup: dict, targets: dict,
294261
print(f" - {category}:")
295262
for tc_id in offenders:
296263
print(f" - {tc_id}:")
297-
_, testcase = testcase_lookup[tc_id]
264+
testcase = testcase_lookup[tc_id]
298265
if 'description' in testcase: # used to be `verbose and ...`, but users need the URL!
299266
print(f" > {testcase['description'].strip()}")
300267

301268

302-
def create_report(argv, config, spec, results, invocations):
269+
def create_report(argv, config, spec, invocations):
303270
return {
304271
# these fields are essential:
305272
# results are no longer specific to version!
@@ -320,7 +287,7 @@ def create_report(argv, config, spec, results, invocations):
320287
"sections": config.sections,
321288
"forced_version": config.version or None,
322289
"forced_tests": None if config.tests is None else config.tests.pattern,
323-
"invocations": invocations,
290+
"invocations": {invocation['id']: invocation for invocation in invocations},
324291
},
325292
}
326293

@@ -358,15 +325,16 @@ def main(argv):
358325
title += f" [tests: '{config.tests.pattern}']"
359326
partial = True
360327
# collect all testcases we need
361-
all_testcases = set()
328+
all_testcase_ids = set()
362329
for version in versions:
363-
for target, testcase_ids in version['targets'].items():
364-
all_testcases.update(testcase_ids)
330+
for testcase_ids in version['targets'].values():
331+
all_testcase_ids.update(testcase_ids)
365332
# collect scripts to be run
366333
testcase_lookup = spec['testcases']
334+
tc_script_lookup = spec['tc_scripts']
367335
script_info = {}
368-
for tc_id in all_testcases:
369-
script, testcase = testcase_lookup[tc_id]
336+
for tc_id in all_testcase_ids:
337+
script = tc_script_lookup[tc_id]
370338
if 'executable' not in script:
371339
continue # manual check
372340
if config.sections and script.get('section') not in config.sections:
@@ -375,18 +343,18 @@ def main(argv):
375343
continue
376344
item = script_info.get(id(script))
377345
if item is None:
378-
_, testcases = script_info[id(script)] = (script, [])
346+
_, testcase_ids = script_info[id(script)] = (script, [])
379347
else:
380-
_, testcases = item
381-
testcases.append(tc_id)
348+
_, testcase_ids = item
349+
testcase_ids.append(tc_id)
382350
# run scripts
383-
builder = ResultBuilder('(dummy)')
384-
for item in script_info.values():
385-
script, testcases = item
386-
invocation = runner.run(script, testcases=sorted(testcases))
387-
for id_, value in invocation["results"].items():
388-
builder.record(id_, result=value, invocation=invocation['id'])
389-
results = builder.finalize(permissible_ids=all_testcases)
351+
invocations = [
352+
runner.run(script, testcases=sorted(testcases))
353+
for script, testcases in script_info.values()
354+
]
355+
results = {}
356+
for invocation in invocations:
357+
results.update(invocation['results'])
390358
# now report: to console if requested, and likewise for yaml output
391359
if not config.quiet:
392360
# print a horizontal line if we had any script output
@@ -395,7 +363,7 @@ def main(argv):
395363
for version in versions:
396364
print_report(config.subject, f"{title} {version['version']}", testcase_lookup, version['targets'], results, partial, config.verbose)
397365
if config.output:
398-
report = create_report(argv, config, spec, results, runner.get_invocations())
366+
report = create_report(argv, config, spec, invocations)
399367
with open(config.output, 'w', encoding='UTF-8') as fileobj:
400368
yaml.safe_dump(report, fileobj, default_flow_style=False, sort_keys=False, explicit_start=True)
401369
return min(127, runner.num_abort + (0 if config.critical_only else runner.num_error))

Tests/scs_cert_lib.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,15 @@ def _resolve_spec(spec: dict):
5757
# - modules, referenced by id
5858
# - versions, referenced by name (unfortunately, the field is called "version")
5959
# step 1. build lookups
60-
testcase_lookup = {} # {testcase['id']: testcase for testcase in spec['testcases']}
60+
testcase_lookup = {}
61+
tc_script_lookup = {}
6162
for script in spec.get('scripts', ()):
6263
for testcase in script.get('testcases', ()):
6364
id_ = testcase['id']
6465
if id_ in testcase_lookup:
6566
raise RuntimeError(f"duplicate testcase {id_}")
66-
testcase_lookup[id_] = (script, testcase)
67+
testcase_lookup[id_] = testcase
68+
tc_script_lookup[id_] = script
6769
module_lookup = {module['id']: module for module in spec['modules']}
6870
version_lookup = {version['version']: version for version in spec['versions']}
6971
# step 2. check for duplicates:
@@ -76,6 +78,7 @@ def _resolve_spec(spec: dict):
7678
spec['versions'] = version_lookup
7779
# step 3a. add testcase lookup
7880
spec['testcases'] = testcase_lookup
81+
spec['tc_scripts'] = tc_script_lookup
7982
# step 4. resolve references
8083
# step 4a. resolve references to modules in includes
8184
# in this step, we also normalize the include form
@@ -172,7 +175,9 @@ def eval_buckets(results, testcase_ids) -> dict:
172175
"""
173176
by_value = defaultdict(list)
174177
for testcase_id in testcase_ids:
175-
value = results.get(testcase_id, {}).get('result')
178+
value = results.get(testcase_id, {})
179+
if isinstance(value, dict):
180+
value = value.get('result')
176181
by_value[value].append(testcase_id)
177182
return by_value
178183

compliance-monitor/monitor.py

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -244,9 +244,7 @@ class PrecomputedVersion:
244244
def __init__(self, version, testcases):
245245
self.name = version['version']
246246
self.validity = version['validity']
247-
self.listed = bool(version['_explicit_validity'])
248247
self.targets = version['targets']
249-
self.testcases = testcases # TODO remove (see evaluate)
250248

251249
def evaluate(self, scope_results):
252250
"""evaluate the results for this version and return the canonical JSON output"""
@@ -257,8 +255,6 @@ def evaluate(self, scope_results):
257255
'result': evaluate(scope_results, tc_ids),
258256
}
259257
return {
260-
'testcases': self.testcases, # FIXME move towards scope eval dict
261-
'results': scope_results, # FIXME move towards scope eval dict
262258
'result': target_results['main']['result'],
263259
'targets': target_results,
264260
'validity': self.validity,
@@ -270,7 +266,7 @@ class PrecomputedScope:
270266
def __init__(self, spec):
271267
self.name = spec['name']
272268
self.spec = spec
273-
self.testcases = {tc_id: item[1] for tc_id, item in spec['testcases'].items()}
269+
self.testcases = spec['testcases']
274270
self.versions = {
275271
version['version']: PrecomputedVersion(version, self.testcases)
276272
for version in spec['versions'].values()
@@ -299,6 +295,8 @@ def evaluate(self, scope_results, include_drafts=False):
299295
passed = [vname for vname in relevant if version_results[vname]['result'] == 1]
300296
return {
301297
'name': self.name,
298+
'testcases': self.testcases,
299+
'results': scope_results,
302300
'versions': version_results,
303301
'relevant': relevant,
304302
'passed': passed,
@@ -312,18 +310,18 @@ def evaluate(self, scope_results, include_drafts=False):
312310
def update_lookup(self, target_dict):
313311
"""Create entries in a lookup mapping for each testcase that occurs in this scope.
314312
315-
This mapping from triples (scope uuid, version name, testcase id) to testcase facilitates
313+
This mapping from pairs (scope uuid, testcase id) to testcase facilitates
316314
evaluating result sets from database queries a great deal, because then just one lookup operation
317315
tells us whether a result row can be associated with any known testcase, and if so, whether the
318316
result is still valid (looking at the testcase's lifetime).
319317
320-
In the future, the mapping could even be simplified by deriving a unique id from each triple that
318+
In the future, the mapping could even be simplified by deriving a unique id from each pair that
321319
could then be stored (redundantly) in a dedicated database column, and the mapping could be from
322-
just one id (instead of a triple) to testcase.
320+
just one id (instead of a pair) to testcase.
323321
"""
324322
scope_uuid = self.spec['uuid']
325323
for tc_id, testcase in self.testcases.items():
326-
target_dict[(scope_uuid, '*', tc_id)] = testcase
324+
target_dict[(scope_uuid, tc_id)] = testcase
327325

328326

329327
def import_cert_yaml(yaml_path, target_dict):
@@ -484,6 +482,10 @@ async def post_report(
484482
except UniqueViolation:
485483
raise HTTPException(status_code=409, detail="Conflict: report already present")
486484
if 'versions' not in document:
485+
# If this key is missing, this means we have a newer-style report that doesn't redundantly list
486+
# results per version. One reason for this change is that the meaning of a testcase identifier
487+
# no longer depends on the scope version, and we can quite simply read off the results from the
488+
# invocations. -- Use the dummy version '*' as long as the db schema still expects a version.
487489
document['versions'] = {'*': {
488490
tc_id: {'result': result, 'invocation': inv_id}
489491
for inv_id, invocation in document['run']['invocations'].items()
@@ -507,13 +509,13 @@ def convert_result_rows_to_dict2(
507509
# collect result per subject/scope/version
508510
preliminary = defaultdict(lambda: defaultdict(dict)) # subject -> scope
509511
missing = set()
510-
for subject, scope_uuid, version, testcase_id, result, checked_at, report_uuid in rows:
511-
testcase = scopes_lookup.get((scope_uuid, version, testcase_id))
512+
for subject, scope_uuid, _, testcase_id, result, checked_at, report_uuid in rows:
513+
testcase = scopes_lookup.get((scope_uuid, testcase_id))
512514
if not testcase:
513515
# it can be False (testcase is known but version too old) or None (testcase not known)
514516
# only report the latter case
515517
if testcase is None:
516-
missing.add((scope_uuid, version, testcase_id))
518+
missing.add((scope_uuid, testcase_id))
517519
continue
518520
# drop value if too old
519521
lifetime = testcase.get('lifetime') # leave None if not present; to be handled by add_period

compliance-monitor/templates/details.md.j2

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ No recent test results available.
2828
| testcase id | result | description |
2929
|---|---|---|
3030
{% for testcase_id in target_result.testcases -%}
31-
{% set testcase = version_result.testcases[testcase_id] -%}
32-
{% set res = version_result.results[testcase_id] if testcase_id in version_result.results else dict(result=0) -%}
31+
{% set testcase = scope_result.testcases[testcase_id] -%}
32+
{% set res = scope_result.results[testcase_id] if testcase_id in scope_result.results else dict(result=0) -%}
3333
| {% if res.result != 1 %}⚠️ {% endif %}{{ testcase.id }} |
3434
{#- #} {% if res.report -%}
3535
[{{ res.result | verdict_check }}]({{ report_url(res.report, version, testcase_id) }})

compliance-monitor/templates/report.md.j2

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,34 +4,10 @@
44
- subject: {{ report.subject }}
55
- scope: [{{ report.spec.name }}]({{ scope_url(report.spec.uuid) }})
66
- checked at: {{ report.checked_at }}
7-
8-
## Results
9-
10-
{# % if report.versions %}{% for version, version_results in report.versions.items() %}{% if version_results %}
11-
### {{ version }}
12-
13-
| test case | result | invocation |
14-
|---|---|---|
15-
{% for testcase_id, result_data in version_results.items() -%}
16-
| {{ testcase_id }} {: #{{ version + '_' + testcase_id }} } | {{ result_data.result | verdict_check }} | [{{ result_data.invocation }}](#{{ result_data.invocation }}) |
17-
{% endfor %}
18-
{% endif %}
19-
{% endfor %}{% endif % #}
20-
21-
## Run
22-
23-
### Variable assignment
24-
25-
| key | value |
26-
|---|---|
27-
{% for key, value in report.run.assignment.items() -%}
28-
| `{{ key }}` | `{{ value }}` |
29-
{% endfor %}
30-
31-
### Check tool invocations
7+
- variable assignment: {% set comma = joiner(", ") %}{% for key, value in report.run.assignment.items() -%}{{comma()}}`{{ key }}`=`{{ value }}`{% endfor %}
328

339
{% for invid, invdata in report.run.invocations.items() %}
34-
#### Invocation {{invid}} {: #{{ invid }} }
10+
## Invocation {{invid}} {: #{{ invid }} }
3511

3612
- cmd: `{{ invdata.cmd }}`
3713
- rc: {{ invdata.rc }}

0 commit comments

Comments
 (0)