Skip to content

Commit 9da11ce

Browse files
feat(systemtests): add per-test max_time override for precice-config (fix #402)
1 parent e9c2f2e commit 9da11ce

File tree

3 files changed

+98
-29
lines changed

3 files changed

+98
-29
lines changed

tools/tests/systemtests.py

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -39,29 +39,33 @@ def main():
3939

4040
build_args = SystemtestArguments.from_args(args.build_args)
4141
run_directory = Path(args.rundir)
42-
if args.suites:
43-
test_suites_requested = args.suites.split(',')
44-
available_testsuites = TestSuites.from_yaml(
45-
PRECICE_TESTS_DIR / "tests.yaml", available_tutorials)
46-
test_suites_to_execute = []
47-
for test_suite_requested in test_suites_requested:
48-
test_suite_found = available_testsuites.get_by_name(
49-
test_suite_requested)
50-
if not test_suite_found:
51-
logging.error(f"Did not find the testsuite with name {test_suite_requested}")
52-
else:
53-
test_suites_to_execute.append(test_suite_found)
54-
if not test_suites_to_execute:
55-
raise RuntimeError(
56-
f"No matching test suites with names {test_suites_requested} found. Use print_test_suites.py to get an overview")
57-
# now convert the test_suites into systemtests
58-
for test_suite in test_suites_to_execute:
59-
tutorials = test_suite.cases_of_tutorial.keys()
60-
for tutorial in tutorials:
61-
for case, reference_result in zip(
62-
test_suite.cases_of_tutorial[tutorial], test_suite.reference_results[tutorial]):
63-
systemtests_to_run.append(
64-
Systemtest(tutorial, build_args, case, reference_result))
42+
if args.suites:
43+
test_suites_requested = args.suites.split(',')
44+
available_testsuites = TestSuites.from_yaml(
45+
PRECICE_TESTS_DIR / "tests.yaml", available_tutorials)
46+
test_suites_to_execute = []
47+
for test_suite_requested in test_suites_requested:
48+
test_suite_found = available_testsuites.get_by_name(
49+
test_suite_requested)
50+
if not test_suite_found:
51+
logging.error(f"Did not find the testsuite with name {test_suite_requested}")
52+
else:
53+
test_suites_to_execute.append(test_suite_found)
54+
if not test_suites_to_execute:
55+
raise RuntimeError(
56+
f"No matching test suites with names {test_suites_requested} found. Use print_test_suites.py to get an overview")
57+
# now convert the test_suites into systemtests
58+
for test_suite in test_suites_to_execute:
59+
tutorials = test_suite.cases_of_tutorial.keys()
60+
for tutorial in tutorials:
61+
cases = test_suite.cases_of_tutorial[tutorial]
62+
reference_results = test_suite.reference_results[tutorial]
63+
max_times = test_suite.max_times.get(tutorial, [None] * len(cases))
64+
for case, reference_result, max_time in zip(
65+
cases, reference_results, max_times):
66+
systemtest = Systemtest(tutorial, build_args, case, reference_result)
67+
systemtest.max_time = max_time
68+
systemtests_to_run.append(systemtest)
6569

6670
if not systemtests_to_run:
6771
raise RuntimeError("Did not find any Systemtests to execute.")

tools/tests/systemtests/Systemtest.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ class Systemtest:
136136
reference_result: ReferenceResult
137137
params_to_use: Dict[str, str] = field(init=False)
138138
env: Dict[str, str] = field(init=False)
139+
max_time: Optional[float] = field(default=None, init=False)
139140

140141
def __eq__(self, other) -> bool:
141142
if isinstance(other, Systemtest):
@@ -321,6 +322,53 @@ def __copy_tutorial_into_directory(self, run_directory: Path):
321322
file.write(ref_requested)
322323
self._checkout_ref_in_subfolder(PRECICE_TUTORIAL_DIR, self.tutorial.path, current_ref)
323324

325+
def __apply_precice_max_time_override(self):
326+
"""
327+
If max_time is set, override the <max-time value=\"...\"/> entry in the
328+
root precice-config.xml of the copied tutorial directory.
329+
"""
330+
if self.max_time is None:
331+
return
332+
333+
config_path = self.system_test_dir / "precice-config.xml"
334+
if not config_path.exists():
335+
logging.warning(
336+
f\"Requested max_time override for {self}, but no precice-config.xml "
337+
f\"found in {self.system_test_dir}\"
338+
)
339+
return
340+
341+
try:
342+
text = config_path.read_text()
343+
except Exception as e:
344+
logging.warning(f\"Could not read {config_path} to apply max_time override: {e}\")
345+
return
346+
347+
# Replace the first occurrence of value=\"...\" on a <max-time ...> tag
348+
pattern = r'(<max-time[^>]*\\svalue=\")([^\"]*)(\")'
349+
match = re.search(pattern, text)
350+
if not match:
351+
logging.warning(
352+
f\"Requested max_time override for {self}, but no <max-time .../> tag "
353+
f\"found in {config_path}\"
354+
)
355+
return
356+
357+
new_text = re.sub(
358+
pattern,
359+
rf'\\1{self.max_time}\\3',
360+
text,
361+
count=1,
362+
)
363+
364+
try:
365+
config_path.write_text(new_text)
366+
logging.info(
367+
f\"Overwrote max-time in {config_path} to {self.max_time} for {self}\"
368+
)
369+
except Exception as e:
370+
logging.warning(f\"Failed to write updated {config_path}: {e}\")
371+
324372
def __copy_tools(self, run_directory: Path):
325373
destination = run_directory / "tools"
326374
src = PRECICE_TOOLS_DIR
@@ -518,6 +566,7 @@ def __prepare_for_run(self, run_directory: Path):
518566
Prepares the run_directory with folders and datastructures needed for every systemtest execution
519567
"""
520568
self.__copy_tutorial_into_directory(run_directory)
569+
self.__apply_precice_max_time_override()
521570
self.__copy_tools(run_directory)
522571
self.__put_gitignore(run_directory)
523572
host_uid, host_gid = self.__get_uid_gid()

tools/tests/systemtests/TestSuite.py

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class TestSuite:
1010
name: str
1111
cases_of_tutorial: Dict[Tutorial, List[CaseCombination]]
1212
reference_results: Dict[Tutorial, List[ReferenceResult]]
13+
max_times: Dict[Tutorial, List[Optional[float]]] = field(default_factory=dict)
1314

1415
def __repr__(self) -> str:
1516
return_string = f"Test suite: {self.name} contains:"
@@ -46,8 +47,9 @@ def from_yaml(cls, path, parsed_tutorials: Tutorials):
4647
data = yaml.safe_load(f)
4748
test_suites_raw = data['test_suites']
4849
for test_suite_name in test_suites_raw:
49-
case_combinations_of_tutorial = {}
50-
reference_results_of_tutorial = {}
50+
case_combinations_of_tutorial: Dict[Tutorial, List[CaseCombination]] = {}
51+
reference_results_of_tutorial: Dict[Tutorial, List[ReferenceResult]] = {}
52+
max_times_of_tutorial: Dict[Tutorial, List[Optional[float]]] = {}
5153
# iterate over tutorials:
5254
for tutorial_case in test_suites_raw[test_suite_name]['tutorials']:
5355
tutorial = parsed_tutorials.get_by_path(tutorial_case['path'])
@@ -57,20 +59,34 @@ def from_yaml(cls, path, parsed_tutorials: Tutorials):
5759
if tutorial not in case_combinations_of_tutorial:
5860
case_combinations_of_tutorial[tutorial] = []
5961
reference_results_of_tutorial[tutorial] = []
62+
max_times_of_tutorial[tutorial] = []
6063

6164
all_case_combinations = tutorial.case_combinations
6265
case_combination_requested = CaseCombination.from_string_list(
6366
tutorial_case['case_combination'], tutorial)
6467
if case_combination_requested in all_case_combinations:
6568
case_combinations_of_tutorial[tutorial].append(case_combination_requested)
66-
reference_results_of_tutorial[tutorial].append(ReferenceResult(
67-
tutorial_case['reference_result'], case_combination_requested))
69+
reference_results_of_tutorial[tutorial].append(
70+
ReferenceResult(
71+
tutorial_case['reference_result'],
72+
case_combination_requested,
73+
)
74+
)
75+
max_times_of_tutorial[tutorial].append(
76+
tutorial_case.get('max_time')
77+
)
6878
else:
6979
raise Exception(
7080
f"Could not find the following cases {tutorial_case['case-combination']} in the current metadata of tutorial {tutorial.name}")
7181

72-
testsuites.append(TestSuite(test_suite_name, case_combinations_of_tutorial,
73-
reference_results_of_tutorial))
82+
testsuites.append(
83+
TestSuite(
84+
test_suite_name,
85+
case_combinations_of_tutorial,
86+
reference_results_of_tutorial,
87+
max_times_of_tutorial,
88+
)
89+
)
7490

7591
return cls(testsuites)
7692

0 commit comments

Comments
 (0)