Skip to content

Commit 4c199dd

Browse files
systemtests: add per-test max_time override for precice-config
1 parent ae2b3cc commit 4c199dd

6 files changed

Lines changed: 40 additions & 7 deletions

File tree

changelog-entries/402.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Add optional `max_time` field to `tests.yaml` entries to override `<max-time>` or `<max-time-windows>` in `precice-config.xml` per test case.

tools/tests/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ In order for the systemtests to pick up the tutorial we need to define a `metada
118118
To add a testsuite just open the `tests.yaml` file and use the output of `python print_case_combinations.py` to add the right case combinations you want to test. Note that you can specify a `reference_result` which is not yet present. The `generate_reference_data.py` will pick that up and create it for you.
119119
Note that its important to carefully check the paths of the `reference_result` in order to not have typos in there. Also note that same cases in different testsuites should use the same `reference_result`.
120120

121+
To cap the preCICE simulation time for a specific test without editing `precice-config.xml`, add an optional `max_time` field (positive number) to the tutorial entry. This overwrites the `<max-time>` (or `<max-time-windows>`) value in `precice-config.xml` before running. Applies to both test runs and reference result generation.
122+
121123
### Generate reference results
122124

123125
Since we need data to compare against, you need to run `python generate_reference_data.py`. This process might take a while.

tools/tests/generate_reference_results.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,12 @@ def main():
108108
for test_suite in test_suites:
109109
tutorials = test_suite.cases_of_tutorial.keys()
110110
for tutorial in tutorials:
111-
for case, reference_result in zip(
112-
test_suite.cases_of_tutorial[tutorial], test_suite.reference_results[tutorial]):
111+
max_times = test_suite.max_times.get(tutorial, [])
112+
for i, (case, reference_result) in enumerate(zip(
113+
test_suite.cases_of_tutorial[tutorial], test_suite.reference_results[tutorial])):
114+
max_time = max_times[i] if i < len(max_times) else None
113115
systemtests_to_run.add(
114-
Systemtest(tutorial, build_args, case, reference_result))
116+
Systemtest(tutorial, build_args, case, reference_result, max_time=max_time))
115117

116118
reference_result_per_tutorial = {}
117119
current_time_string = datetime.now().strftime('%Y-%m-%d %H:%M:%S')

tools/tests/systemtests.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,12 @@ def main():
5858
for test_suite in test_suites_to_execute:
5959
tutorials = test_suite.cases_of_tutorial.keys()
6060
for tutorial in tutorials:
61-
for case, reference_result in zip(
62-
test_suite.cases_of_tutorial[tutorial], test_suite.reference_results[tutorial]):
61+
max_times = test_suite.max_times.get(tutorial, [])
62+
for i, (case, reference_result) in enumerate(zip(
63+
test_suite.cases_of_tutorial[tutorial], test_suite.reference_results[tutorial])):
64+
max_time = max_times[i] if i < len(max_times) else None
6365
systemtests_to_run.append(
64-
Systemtest(tutorial, build_args, case, reference_result))
66+
Systemtest(tutorial, build_args, case, reference_result, max_time=max_time))
6567

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

tools/tests/systemtests/Systemtest.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ class Systemtest:
134134
arguments: SystemtestArguments
135135
case_combination: CaseCombination
136136
reference_result: ReferenceResult
137+
max_time: float | None = None
137138
params_to_use: Dict[str, str] = field(init=False)
138139
env: Dict[str, str] = field(init=False)
139140

@@ -513,11 +514,29 @@ def __write_logs(self, stdout_data: List[str], stderr_data: List[str]):
513514
with open(self.system_test_dir / "stderr.log", 'w') as stderr_file:
514515
stderr_file.write("\n".join(stderr_data))
515516

517+
def __apply_max_time_override(self):
518+
"""Overwrite <max-time> or <max-time-windows> value in precice-config.xml if max_time is set."""
519+
if self.max_time is None:
520+
return
521+
config_path = self.system_test_dir / "precice-config.xml"
522+
text = config_path.read_text()
523+
pattern = r'(<max-time\s+value=")[^"]*(")'
524+
new_text, count = re.subn(pattern, rf'\g<1>{self.max_time}\2', text)
525+
if count == 0:
526+
pattern_windows = r'(<max-time-windows\s+value=")[^"]*(")'
527+
new_text, count = re.subn(pattern_windows, rf'\g<1>{int(self.max_time)}\2', text)
528+
if count == 0:
529+
logging.warning(f"No <max-time> or <max-time-windows> tag found in {config_path}")
530+
return
531+
config_path.write_text(new_text)
532+
logging.info(f"Overwrote max-time in {config_path} to {self.max_time}")
533+
516534
def __prepare_for_run(self, run_directory: Path):
517535
"""
518536
Prepares the run_directory with folders and datastructures needed for every systemtest execution
519537
"""
520538
self.__copy_tutorial_into_directory(run_directory)
539+
self.__apply_max_time_override()
521540
self.__copy_tools(run_directory)
522541
self.__put_gitignore(run_directory)
523542
host_uid, host_gid = self.__get_uid_gid()

tools/tests/systemtests/TestSuite.py

Lines changed: 8 additions & 1 deletion
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] = field(default_factory=dict)
1314

1415
def __repr__(self) -> str:
1516
return_string = f"Test suite: {self.name} contains:"
@@ -48,6 +49,7 @@ def from_yaml(cls, path, parsed_tutorials: Tutorials):
4849
for test_suite_name in test_suites_raw:
4950
case_combinations_of_tutorial = {}
5051
reference_results_of_tutorial = {}
52+
max_times_of_tutorial = {}
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,6 +59,7 @@ 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(
@@ -65,12 +68,16 @@ def from_yaml(cls, path, parsed_tutorials: Tutorials):
6568
case_combinations_of_tutorial[tutorial].append(case_combination_requested)
6669
reference_results_of_tutorial[tutorial].append(ReferenceResult(
6770
tutorial_case['reference_result'], case_combination_requested))
71+
max_time_raw = tutorial_case.get('max_time', None)
72+
if max_time_raw is not None and (not isinstance(max_time_raw, (int, float)) or max_time_raw <= 0):
73+
raise ValueError(f"max_time must be a positive number, got {max_time_raw!r}")
74+
max_times_of_tutorial[tutorial].append(max_time_raw)
6875
else:
6976
raise Exception(
7077
f"Could not find the following cases {tutorial_case['case-combination']} in the current metadata of tutorial {tutorial.name}")
7178

7279
testsuites.append(TestSuite(test_suite_name, case_combinations_of_tutorial,
73-
reference_results_of_tutorial))
80+
reference_results_of_tutorial, max_times_of_tutorial))
7481

7582
return cls(testsuites)
7683

0 commit comments

Comments
 (0)