Skip to content

Commit 8a96d5b

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

File tree

6 files changed

+58
-7
lines changed

6 files changed

+58
-7
lines changed

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` and `max_time_windows` fields 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` (positive float, overrides `<max-time>`) or `max_time_windows` (positive integer, overrides `<max-time-windows>`) field to the tutorial entry. 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: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,14 @@ 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+
mtw_list = test_suite.max_time_windows.get(tutorial, [])
113+
for i, (case, reference_result) in enumerate(zip(
114+
test_suite.cases_of_tutorial[tutorial], test_suite.reference_results[tutorial])):
115+
max_time = max_times[i] if i < len(max_times) else None
116+
max_time_windows = mtw_list[i] if i < len(mtw_list) else None
113117
systemtests_to_run.add(
114-
Systemtest(tutorial, build_args, case, reference_result))
118+
Systemtest(tutorial, build_args, case, reference_result, max_time=max_time, max_time_windows=max_time_windows))
115119

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

tools/tests/systemtests.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,14 @@ 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+
mtw_list = test_suite.max_time_windows.get(tutorial, [])
63+
for i, (case, reference_result) in enumerate(zip(
64+
test_suite.cases_of_tutorial[tutorial], test_suite.reference_results[tutorial])):
65+
max_time = max_times[i] if i < len(max_times) else None
66+
max_time_windows = mtw_list[i] if i < len(mtw_list) else None
6367
systemtests_to_run.append(
64-
Systemtest(tutorial, build_args, case, reference_result))
68+
Systemtest(tutorial, build_args, case, reference_result, max_time=max_time, max_time_windows=max_time_windows))
6569

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

tools/tests/systemtests/Systemtest.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ class Systemtest:
134134
arguments: SystemtestArguments
135135
case_combination: CaseCombination
136136
reference_result: ReferenceResult
137+
max_time: float | None = None
138+
max_time_windows: int | None = None
137139
params_to_use: Dict[str, str] = field(init=False)
138140
env: Dict[str, str] = field(init=False)
139141

@@ -513,11 +515,35 @@ def __write_logs(self, stdout_data: List[str], stderr_data: List[str]):
513515
with open(self.system_test_dir / "stderr.log", 'w') as stderr_file:
514516
stderr_file.write("\n".join(stderr_data))
515517

518+
def __apply_max_time_override(self):
519+
"""Overwrite <max-time> or <max-time-windows> value in precice-config.xml."""
520+
if self.max_time is None and self.max_time_windows is None:
521+
return
522+
config_path = self.system_test_dir / "precice-config.xml"
523+
text = config_path.read_text()
524+
new_text = text
525+
if self.max_time is not None:
526+
pattern = r'(<max-time\s+value=")[^"]*(")'
527+
new_text, count = re.subn(pattern, rf'\g<1>{self.max_time}\2', new_text)
528+
if count == 0:
529+
logging.warning(f"No <max-time> tag found in {config_path}")
530+
else:
531+
logging.info(f"Overwrote <max-time> to {self.max_time} in {config_path}")
532+
if self.max_time_windows is not None:
533+
pattern = r'(<max-time-windows\s+value=")[^"]*(")'
534+
new_text, count = re.subn(pattern, rf'\g<1>{self.max_time_windows}\2', new_text)
535+
if count == 0:
536+
logging.warning(f"No <max-time-windows> tag found in {config_path}")
537+
else:
538+
logging.info(f"Overwrote <max-time-windows> to {self.max_time_windows} in {config_path}")
539+
config_path.write_text(new_text)
540+
516541
def __prepare_for_run(self, run_directory: Path):
517542
"""
518543
Prepares the run_directory with folders and datastructures needed for every systemtest execution
519544
"""
520545
self.__copy_tutorial_into_directory(run_directory)
546+
self.__apply_max_time_override()
521547
self.__copy_tools(run_directory)
522548
self.__put_gitignore(run_directory)
523549
host_uid, host_gid = self.__get_uid_gid()

tools/tests/systemtests/TestSuite.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ 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)
14+
max_time_windows: Dict[Tutorial, list] = field(default_factory=dict)
1315

1416
def __repr__(self) -> str:
1517
return_string = f"Test suite: {self.name} contains:"
@@ -48,6 +50,8 @@ def from_yaml(cls, path, parsed_tutorials: Tutorials):
4850
for test_suite_name in test_suites_raw:
4951
case_combinations_of_tutorial = {}
5052
reference_results_of_tutorial = {}
53+
max_times_of_tutorial = {}
54+
max_time_windows_of_tutorial = {}
5155
# iterate over tutorials:
5256
for tutorial_case in test_suites_raw[test_suite_name]['tutorials']:
5357
tutorial = parsed_tutorials.get_by_path(tutorial_case['path'])
@@ -57,6 +61,8 @@ def from_yaml(cls, path, parsed_tutorials: Tutorials):
5761
if tutorial not in case_combinations_of_tutorial:
5862
case_combinations_of_tutorial[tutorial] = []
5963
reference_results_of_tutorial[tutorial] = []
64+
max_times_of_tutorial[tutorial] = []
65+
max_time_windows_of_tutorial[tutorial] = []
6066

6167
all_case_combinations = tutorial.case_combinations
6268
case_combination_requested = CaseCombination.from_string_list(
@@ -65,12 +71,20 @@ def from_yaml(cls, path, parsed_tutorials: Tutorials):
6571
case_combinations_of_tutorial[tutorial].append(case_combination_requested)
6672
reference_results_of_tutorial[tutorial].append(ReferenceResult(
6773
tutorial_case['reference_result'], case_combination_requested))
74+
max_time_raw = tutorial_case.get('max_time', None)
75+
if max_time_raw is not None and (not isinstance(max_time_raw, (int, float)) or max_time_raw <= 0):
76+
raise ValueError(f"max_time must be a positive number, got {max_time_raw!r}")
77+
max_times_of_tutorial[tutorial].append(max_time_raw)
78+
mtw_raw = tutorial_case.get('max_time_windows', None)
79+
if mtw_raw is not None and (not isinstance(mtw_raw, int) or mtw_raw <= 0):
80+
raise ValueError(f"max_time_windows must be a positive integer, got {mtw_raw!r}")
81+
max_time_windows_of_tutorial[tutorial].append(mtw_raw)
6882
else:
6983
raise Exception(
7084
f"Could not find the following cases {tutorial_case['case-combination']} in the current metadata of tutorial {tutorial.name}")
7185

7286
testsuites.append(TestSuite(test_suite_name, case_combinations_of_tutorial,
73-
reference_results_of_tutorial))
87+
reference_results_of_tutorial, max_times_of_tutorial, max_time_windows_of_tutorial))
7488

7589
return cls(testsuites)
7690

0 commit comments

Comments
 (0)