Skip to content

Commit 57b1807

Browse files
Add external tutorial sources support (git/archive) for systemtests
Allow tests.yaml entries to load tutorials from external git repos or archives. Rebased on develop and documented usage in the README.
1 parent 1f54fc5 commit 57b1807

6 files changed

Lines changed: 482 additions & 51 deletions

File tree

changelog-entries/732.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Added optional `source` blocks in `tests.yaml` so system tests can load tutorials from external git repositories or archives ([#732](https://github.com/precice/tutorials/pull/732)).

tools/tests/README.md

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ Workflow for the preCICE v3 release testing:
3636

3737
6. Download the build artifacts from Summary > runs.
3838

39-
- In there, you may want to check the `stdout.log` and `stderr.log` files.
39+
- In there, you may want to check the `system-tests-stdout.log` and `system-tests-stderr.log` files.
4040
- The produced results are in `precice-exports/`, the reference results in `reference-results-unpacked`.
4141
- Compare using, e.g., ParaView or [fieldcompare](https://gitlab.com/dglaeser/fieldcompare): `fieldcompare dir precice-exports/ reference/`. The `--diff` option will give you `precice-exports/diff_*.vtu` files, while you can also try different tolerances with `-rtol` and `-atol`.
4242

@@ -105,7 +105,9 @@ In this case, building and running seems to work out, but the tests fail because
105105

106106
The easiest way to debug a systemtest run is first to have a look at the output written into the action on GitHub.
107107
If this does not provide enough hints, the next step is to download the generated `system_tests_run_<run_id>_<run_attempt>` artifact. Note that by default this will only be generated if the systemtests fail.
108-
Inside the archive, a test-specific subfolder like `flow-over-heated-plate_fluid-openfoam-solid-fenics_2023-11-19-211723` contains two log files: a `stderr.log` and `stdout.log`. This can be a starting point for a further investigation.
108+
Inside the archive, a test-specific subfolder like `flow-over-heated-plate_fluid-openfoam-solid-fenics_2023-11-19-211723` contains two log files: `system-tests-stderr.log` and `system-tests-stdout.log`. This can be a starting point for a further investigation. When fieldcompare runs with `--diff`, it writes VTK diff files under `precice-exports/`; if the comparison fails, those files are copied into a `diff-results/` subfolder in the same run directory (mirroring any subpaths under `precice-exports/`) so you can open them (e.g. in ParaView) to see where results differ from the reference. On successful comparisons, `diff-results/` is therefore absent.
109+
110+
For implicit-coupling runs, `precice-*-iterations.log` files are collected into `iterations-logs/` and compared by hash against archived reference copies (stored next to each reference `.tar.gz` in a `*.iterations-logs/` directory, or legacy `.iterations-hashes.json` sidecars). A mismatch fails the test.
109111

110112
## Adding new tests
111113

@@ -118,6 +120,8 @@ In order for the systemtests to pick up the tutorial we need to define a `metada
118120
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.
119121
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`.
120122

123+
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.
124+
121125
### Generate reference results
122126

123127
Since we need data to compare against, you need to run `python generate_reference_data.py`. This process might take a while.
@@ -167,7 +171,7 @@ Metadata and workflow/script files:
167171
- ...
168172
- `dockerfiles/`
169173
- Multi-stage build Dockerfiles that define how to build each component, in a layered approach
170-
- `docker-compose.template.yaml`: Describes how to prepare each test (Docker Componse service template)
174+
- `docker-compose.template.yaml`: Describes how to prepare each test (Docker Compose service template)
171175
- `docker-compose.field_compare.template.yaml`: Describes how to compare results with fieldcompare (Docker Compose service template)
172176
- `components.yaml`: Declares the available components and their parameters/options
173177
- `reference_results.metadata.template`: Template for reporting the versions used to generate the reference results
@@ -231,9 +235,9 @@ cases:
231235
Description:
232236
233237
- `name`: A human-readable, descriptive name
234-
- `path`: Where the tutorial is located, relative to the tutorials repository
238+
- `path`: Where the tutorial is located, relative to the tutorials repository (or the tutorial folder name for external sources)
235239
- `url`: A web page with more information on the tutorial
236-
- `participants`: A list of preCICE participants, typically corresponing to different domains of the simulation
240+
- `participants`: A list of preCICE participants, typically corresponding to different domains of the simulation
237241
- `cases`: A list of solver configuration directories. Each element of the list includes:
238242
- `participant`: Which participant this solver case can serve as
239243
- `directory`: Where the case directory is located, relative to the tutorial directory
@@ -279,7 +283,9 @@ This `openfoam-adapter` component has the following attributes:
279283
280284
Since the docker containers are still a bit mixed in terms of capabilities and support for different build_argument combinations the following rules apply:
281285
282-
- A build_argument ending in **_REF** means that it refers to a git commit-ish (like a tag or commit) beeing used to build the image. Its important to not use branch names here as we heavily rely on dockers build cache to speedup things. But since the input variable to the docker builder will not change, we might have wrong cache hits.
286+
- A build argument ending in `_REF` refers to a git commit-ish (like a tag or commit) being used to build the image. It is important to not use branch names here as we heavily rely on Docker's build cache to speedup things. But since the input variable to the docker builder will not change, we might have wrong cache hits.
287+
- Some workflows set variables ending in `_PR`. These specify the GitHub pull request which provides the above `_REF` and can be on a fork.
288+
- A build argument ending in `_VERSION` refers to the version of a third-party dependency to use (e.g., DUNE).
283289
- All other build_arguments are free of rules and up to the container maintainer.
284290

285291
### Component templates
@@ -331,15 +337,43 @@ test_suites:
331337
- fluid-openfoam
332338
- solid-fenics
333339
reference_result: ./flow-over-heated-plate/reference-results/fluid-openfoam_solid-fenics.tar.gz
340+
timeout: 1200
334341
```
335342

343+
The optional `timeout` field (in seconds) sets the maximum time for the solver run and fieldcompare phases of that specific case. If omitted, it defaults to `GLOBAL_TIMEOUT` (currently 900s, overridable via the `PRECICE_SYSTEMTESTS_TIMEOUT` environment variable).
344+
345+
#### External tutorial sources
346+
347+
By default, every `path` must exist in the local `precice/tutorials` checkout. For tutorials maintained elsewhere, add an optional `source` block:
348+
349+
```yaml
350+
- path: flow-over-heated-plate
351+
source:
352+
type: git
353+
url: https://github.com/precice/tutorials.git
354+
ref: develop
355+
subdir: . # optional subdirectory inside the repository
356+
case_combination:
357+
- fluid-openfoam
358+
- solid-openfoam
359+
reference_result: ./flow-over-heated-plate/reference-results/fluid-openfoam_solid-openfoam.tar.gz
360+
```
361+
362+
Supported `type` values:
363+
364+
- `local` (default): use the tutorial from this repository.
365+
- `git`: shallow-clone `url` at `ref` (cached under `~/.cache/precice-tutorials` or `PRECICE_EXTERNAL_CACHE_DIR`).
366+
- `archive`: download and extract a `.tar.gz` / `.zip` from `url`.
367+
368+
The runner copies the resolved tutorial into the run directory, then continues with the usual Docker build/run and fieldcompare steps. `TUTORIALS_REF` / `TUTORIALS_PR` build arguments still apply only to **local** tutorials; external tutorials are pinned by `source.ref`.
369+
336370
This defines two test suites, namely `openfoam_adapter_pr` and `openfoam_adapter_release`. Each of them defines which case combinations of which tutorials to run.
337371

338372
### Generate Reference Results
339373

340374
#### via GitHub workflow (recommended)
341375

342-
The preferred way of adding reference results is via the manual triggerable `Generate reference results (manual)` workflow. This takes two inputs:
376+
The preferred way of adding reference results is via the manual `Generate reference results (manual)` workflow. This takes two inputs:
343377

344378
- `from_ref`: branch where the new test configuration (e.g added tests, new reference_versions.yaml) is
345379
- `commit_msg`: commit message for adding the reference results into the branch

tools/tests/metadata_parser/metdata.py

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
import itertools
77
from paths import PRECICE_TESTS_DIR, PRECICE_TUTORIAL_DIR
88

9+
# Import TutorialSource from systemtests.sources (used for external tutorial sources).
10+
from systemtests.sources import TutorialSource
11+
912

1013
@dataclass
1114
class BuildArgument:
@@ -279,13 +282,15 @@ def from_cases_tuple(cls, cases: Tuple[Case], tutorial: Tutorial):
279282
class ReferenceResult:
280283
path: Path
281284
case_combination: CaseCombination
285+
base_dir: Optional[Path] = None
282286

283287
def __repr__(self) -> str:
284288
return f"{self.path.as_posix()}"
285289

286290
def __post_init__(self):
287291
# built full path
288-
self.path = PRECICE_TUTORIAL_DIR / self.path
292+
base = self.base_dir if self.base_dir is not None else PRECICE_TUTORIAL_DIR
293+
self.path = Path(base) / self.path
289294

290295

291296
@dataclass
@@ -299,6 +304,7 @@ class Tutorial:
299304
url: str
300305
participants: List[str]
301306
cases: List[Case]
307+
source: "TutorialSource" = field(default_factory=TutorialSource.local)
302308
case_combinations: List[CaseCombination] = field(init=False)
303309

304310
def __post_init__(self):
@@ -355,29 +361,36 @@ def get_case_by_string(self, case_name: str) -> Optional[Case]:
355361
return None
356362

357363
@classmethod
358-
def from_yaml(cls, path, available_components):
364+
def from_yaml(cls, path, available_components, base_dir=None, source=None):
359365
"""
360366
Creates a Tutorial instance from a YAML file.
361367
362368
Args:
363-
path: The path to the YAML file.
369+
path: The path to the metadata.yaml file.
364370
available_components: The Components instance containing available components.
371+
base_dir: Optional base directory for resolving tutorial path (for external sources).
372+
Defaults to PRECICE_TUTORIAL_DIR.
373+
source: Optional TutorialSource (for external tutorials).
365374
366375
Returns:
367376
An instance of Tutorial.
368377
"""
369378
with open(path, 'r') as f:
370379
data = yaml.safe_load(f)
371380
name = data['name']
372-
path = PRECICE_TUTORIAL_DIR / data['path']
381+
base = base_dir if base_dir is not None else PRECICE_TUTORIAL_DIR
382+
tutorial_path = Path(base) / data['path']
373383
url = data['url']
374384
participants = data.get('participants', [])
375385
cases_raw = data.get('cases', {})
376386
cases = []
377387
for case_name in cases_raw.keys():
378388
cases.append(Case.from_dict(
379389
case_name, cases_raw[case_name], available_components))
380-
return cls(name, path, url, participants, cases)
390+
tut = cls(name, tutorial_path, url, participants, cases)
391+
if source is not None:
392+
tut.source = source
393+
return tut
381394

382395

383396
class Tutorials(list):
@@ -440,4 +453,4 @@ def from_path(cls, path):
440453
for yaml_path in yaml_files:
441454
tut = Tutorial.from_yaml(yaml_path, available_components)
442455
tutorials.append(tut)
443-
return cls(tutorials)
456+
return cls(tutorials)

0 commit comments

Comments
 (0)