From aff25bad70d6565d3f16b32b9e8922bd9b6504a6 Mon Sep 17 00:00:00 2001 From: Fred Hornsey Date: Tue, 21 Jan 2025 17:12:48 -0600 Subject: [PATCH] Try to Fix Issues in ACE/TAO Scoreboard See https://github.com/DOCGroup/scoreboard/pull/8 These changes fix the parsing in the integrated page generator and try to make matrix.py more robust by inserting skipped tests when builds or test results cause an error instead of crashing. --- common/integratedparser.pm | 6 ++++++ testmatrix/matrix.py | 44 ++++++++++++++++++++++++++------------ 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/common/integratedparser.pm b/common/integratedparser.pm index 975da8202..89bc5f98d 100644 --- a/common/integratedparser.pm +++ b/common/integratedparser.pm @@ -6,6 +6,8 @@ use warnings; use FileHandle; +use common::utility; + ############################################################################### # Constructor @@ -95,6 +97,8 @@ sub Parse ($\@) # Make the global name null $global_build_name = ''; } + elsif (utility::parse_prop ($_, {})) { # NOP, just parse it + } elsif (m/^\s*\s*$/i) { $state = 'group'; } @@ -181,6 +185,8 @@ sub Parse ($\@) elsif (m/^\s*(.*)<\/html>\s*$/i) { $build_info{HTML} = $1; } + elsif (utility::parse_prop ($_, {})) { # NOP, just parse it + } else { print STDERR "Error: Unexpected in state <$state>: $_\n"; return 0; diff --git a/testmatrix/matrix.py b/testmatrix/matrix.py index 07540c059..5ae09229e 100644 --- a/testmatrix/matrix.py +++ b/testmatrix/matrix.py @@ -5,6 +5,7 @@ from datetime import timedelta from pathlib import Path from urllib.request import urlopen +from traceback import print_exception use_ansi = os.name != 'nt' and sys.stdout.isatty() @@ -159,16 +160,26 @@ def __str__(self): return f'{self.name}: time={self.time_str()} result={self.result}' +def print_error(exc, context): + exc.add_note(context) + print_exception(exc) + + class Build: def __init__(self, name, builds_dir, misc=None): - if misc is None: - misc = {} self.name = name self.dir = builds_dir / name - self.misc = misc + self.misc = misc or {} + self.basename = self.misc.get('basename') + self.props = self.misc.get('props', {}) + self.tests = {} self.stats = TestStats() - self.basename = misc['basename'] - self.props = misc.get('props', {}) + + if misc is None: + return + + if self.basename is None: + raise ValueError(f'Build {name!r} is missing a basename, probably a missing latest.txt') # Get build.json. It should either exist locally or can be downloaded. build_json_name = self.basename + '.build.json' @@ -182,15 +193,20 @@ def __init__(self, name, builds_dir, misc=None): with urlopen(url) as f: data = json.load(f) else: - raise ValueError(f'Can not get {build_json_name} for {name}') + raise ValueError(f'Can not get {build_json_name!r} for {name!r}') - self.tests = {} for t in data['tests']: - test_run = TestRun(t['name'], int(t['result']), timedelta(seconds=int(t['time'])), t) - self.stats.add(test_run.status, test_run.time) - if test_run.name in self.tests: - raise ValueError(f'Multiple {repr(test_run.name)} in {self.name}!') - self.tests[test_run.name] = test_run + try: + self.add_test_run(t) + except BaseException as e: + print_error(e, f'Test {name!r} in build {name!r} caused this error') + + def add_test_run(self, t): + test_run = TestRun(t['name'], int(t['result']), timedelta(seconds=int(t['time'])), t) + self.stats.add(test_run.status, test_run.time) + if test_run.name in self.tests: + raise ValueError(f'Multiple {repr(test_run.name)} in {self.name}!') + self.tests[test_run.name] = test_run def __iter__(self): return iter(self.tests.values()) @@ -245,8 +261,8 @@ def __init__(self, builds_dir: Path): try: build = Build(name, builds_dir, b) except BaseException as e: - e.add_note(f'The build that caused an error was {name}') - raise + print_error(e, f'The build that caused this error was {name!r}') + build = Build(name, builds_dir) self.builds[name] = build # Collect all the tests