Source test cases from other repositories#732
Conversation
|
@MakisH , sir happy to update anything needed before review . |
|
This pull request has been mentioned on preCICE Forum on Discourse. There might be relevant details there: https://precice.discourse.group/t/gsoc-2026-pranjal-manhgaye/2769/6 |
|
@PranjalManhgaye this seems quite long. Is it still intended for review in its current form? In the PR description, I would expect some explanation of the whole concept. Please also resolve the conflicts. |
|
thanks @MakisH , i will take an another look of this pr and will inform you if its indeed necessary to review it . |
Allow tests.yaml entries to load tutorials from external git repos or archives. Rebased on develop and documented usage in the README.
3ba6044 to
57b1807
Compare
Rebase onto latest precice/develop and resolve conflicts in systemtests files and README for external tutorial sources (PR precice#732).
|
@MakisH , i updated the description, rebased on develop, resolved the conflicts, and retested everything locally ,Existing suites are unchanged and both external git + archive quickstart paths are passing now. i think everything should be good now, but happy to change anything if you spot something ,, |
MakisH
left a comment
There was a problem hiding this comment.
Thanks for including a configuration example and a Mermaid graph, this helps a lot!
Looking at the example, I think that defining a source: in tests.yaml makes sense. I also like that it works both for repositories and for archives.
Could you please update your branch to the latest state? I am through with the larger changes I wanted to do for now, and it would be a good time to review this in the next days.
Integrate latest develop; external tutorial source support unchanged.
|
@MakisH i have merged latest develop into the branch , also fixed the conflicts and retested locally , it is ready for a review when you get time in next days ,, |
MakisH
left a comment
There was a problem hiding this comment.
I tried this locally with a concrete example (from #845) and it seems to work. 🎉
Still, I think the configuration looks a bit strange/unintuitive at the moment. Let's refine the configuration based on that example.
I have not yet tried generating reference results, which might be an issue, as it would not be easy/always possible for the runner to push to the external repository (some sources are even static archives). We should also not store those reference results in the tutorials repository, as they have nothing to do with the tutorials, and might not be public. For the specific test, I could push reference results to the same repository/branch and use a more relaxed tolerance. Other than that, I would just expect to skip the comparison now (both related to #847).
Use external: instead of tutorials: for external suites, put source before path in examples, and move docs under Extending.
|
@MakisH addressed the review points => tested locally, all existing suites still load fine and the external example parses correctly , for reference results on external tests i'll wire up skip_compare from #847 once that's in rather than storing refs here , let me know if the config shape looks better now ,, |
Integrate latest develop (precice#847 tolerance/skip_compare, precice#848, precice#852, etc.) and resolve TestSuite.py conflict while keeping external: tutorial support. Set skip_compare on external suite entries now that precice#847 is merged.
|
@MakisH I have merged latest develop and pushed - now it should address the conflict and the external |
Integrate precice#724, precice#849, precice#854 and resolve TestSuite.py conflict (external sources + tolerance/skip_compare + run-before/run-after).
MakisH
left a comment
There was a problem hiding this comment.
I had another look and test, and while it generally works, I think some aspects can be simplified. My main doubts were regarding the cache, the restriction to not mix tutorials: and external:, and some issue with ZIP archives.
Getting there!
| raise ValueError( | ||
| f"Test suite '{test_suite_name}' must use either 'tutorials' or " | ||
| f"'external', not both." | ||
| ) |
There was a problem hiding this comment.
Why are they not possible to combine? It would be convenient to be able to write:
release:
tutorials:
- *breaking-dam-2d_fluid-openfoam_solid-calculix
- *channel-transport_fluid-openfoam_transport-nutils
- ...
external:
- *partitioned-heat-conduction-robin_lrft-openfoam_right-openfoam
- *partitioned-heat-conduction-mixedbc_left-openfoam_right-openfoamwhich would also allow the external cases to be used in the openfoam-adapter test suite, for example.
There was a problem hiding this comment.
I have dropped the mutual-exclusion check so a suite can list both tutorials and external. External cases can be defined once with anchors and referenced from release (and other suites). Also, I have updated the README example accordingly.
| # Cache directory for fetched tutorials. Can be overridden via PRECICE_EXTERNAL_CACHE_DIR env. | ||
| _DEFAULT_CACHE = Path(os.environ.get("XDG_CACHE_HOME", Path.home() / ".cache")) / "precice-tutorials" | ||
| PRECICE_EXTERNAL_CACHE_DIR = Path(os.environ.get("PRECICE_EXTERNAL_CACHE_DIR", _DEFAULT_CACHE)) |
There was a problem hiding this comment.
What is the motivation for this cache?
Similarly for the _cache_key function.
There was a problem hiding this comment.
I have added a short explanation in the README: the cache avoids re-cloning/re-downloading the same external source on every run and in CI; And it is keyed by URL, ref, and optional subdir. Override with PRECICE_EXTERNAL_CACHE_DIR if needed.
| ["git", "-C", str(checkout), "fetch", "origin", ref, "--depth", "1"], | ||
| check=True, | ||
| capture_output=True, | ||
| timeout=120, |
There was a problem hiding this comment.
There is a short timeout defined globally somewhere else. Why not use that?
Similarly in different places.
No strong opinion on the one or the other approach, but it looks inconsistent.
There was a problem hiding this comment.
I have replaced the hardcoded fetch timeouts with _FETCH_TIMEOUT, driven by the same PRECICE_SYSTEMTESTS_TIMEOUT env var as GLOBAL_TIMEOUT (could not import GLOBAL_TIMEOUT directly without a circular import).
| # Fallback: branch may not exist (e.g. repo uses develop/master instead of main) | ||
| # Clone without branch, then fetch and checkout ref (with common aliases) | ||
| shutil.rmtree(checkout, ignore_errors=True) | ||
| logging.debug( | ||
| f"git clone --branch {ref} failed ({result.stderr}), trying clone + fetch" | ||
| ) |
There was a problem hiding this comment.
If the ref does not exist, shouldn't the user get an error to choose a different ref?
In general, I think that parts of this function can be simplified. Better throw an error / let it crash and let the user fix the configuration, rather than trying to guess.
There was a problem hiding this comment.
I have removed the main/develop/master fallback. If git clone --branch fails, we now raise a clear error so the config can be fixed.
| else: | ||
| import zipfile | ||
|
|
||
| with zipfile.ZipFile(tmp_path, "r") as zf: | ||
| zf.extractall(extract_dir) |
There was a problem hiding this comment.
When downloading a zip file (https://github.com/vidulejs/tutorials/archive/refs/heads/partitioned-heat-conduction-mixed-robin.zip) I am getting a permission denied when trying to run the respective run.sh scripts in the system tests.
See the Partitioned heat conduction mixed BC (left-openfoam, right-openfoam) case (sourced from an archive), which reports success, even though the logs show this error: https://github.com/precice/tutorials/actions/runs/28495445035/attempts/5
However, if I just unzip and run the tutorial locally, it just works. So the ZIP file seems to have maintained the file permissions. This seems to be a common issue:
https://stackoverflow.com/q/76645832/2254346
https://www.w3reference.com/blog/python-zipfile-removes-execute-permissions-from-binaries/
There was a problem hiding this comment.
After the zip/tar extract (and on cache hits), we restore execute bits on *.sh files. I have also reproduced the mixed-BC archive case locally; the external suite passes end-to-end with no permission denied on run.sh.
Allow mixed tutorials/external suites, fail fast on bad git refs, restore shell execute bits after ZIP extract, align fetch timeouts with GLOBAL_TIMEOUT, and document external cache behaviour in README.
What this is about
(closes #538)
right now, every entry in
tests.yamlassumes the tutorial folder is already in this repo. you give apathlikeflow-over-heated-plate, and the runner finds it under the localprecice/tutorialscheckout.Issue #538 asks for a way to run cases that live somewhere else — another git repo, a fork, or from a direct download link (e.g. a .tar.gz ), without copying the files into this repo first.
This PR adds an optional
sourceblock intests.yamlfor that.What happens at runtime
I have not touched the local behaviour : if there is no
sourcefield, behaviour is the same as today.If
sourceis set:~/.cache/precice-tutorialsby default, orPRECICE_EXTERNAL_CACHE_DIRif you set it).metadata.yamlfrom that folder, same as for in-repo tutorials.docker compose up, and fieldcompare.TUTORIALS_REF/TUTORIALS_PRstill only affect local tutorials. For external ones, the version is whatever you put insource.ref.Example
Git:
Archive:
typecan begitorarchive. If you omitsource, it stays local.For git, if
clone --branch reffails, there is a small fallback that tries fetching without a branch and then checks a few common default branch names.How it works
flowchart LR A[tests.yaml entry] --> B{Has source?} B -->|No| C[Use local tutorial] B -->|Yes| D[Fetch git or archive] D --> E[Resolve tutorial folder] E --> F[Copy into run directory] F --> G[Docker build and run] G --> H[fieldcompare vs reference]Files touched
tools/tests/systemtests/sources.py— new: fetch + cache +resolve_tutorial_roottools/tests/systemtests/TestSuite.py— readsource, load external metadata when neededtools/tests/systemtests/Systemtest.py— copy from resolved path; ref/PR checkout only for localtools/tests/metadata_parser/metdata.py—Tutorial.source,ReferenceResult.base_dirtools/tests/README.md— short how-tochangelog-entries/732.mdI did not add a real
source:entry totests.yamlyet, so existing suites should behave as before until someone opts in.Rebased onto current
developand fixed the merge conflicts in README /Systemtest.py/TestSuite.py.testing
I ran the usual checks on external-source-fix after rebasing onto develop:
python3 -m compileallon tools/tests/systemtests and metadata_parser — no issues.Loaded all 13 suites from
tests.yaml— unchanged for entries without source.For git, I used a smoke test that drops quickstart from the local index and points at precice/tutorials on develop. The tutorial was fetched into PRECICE_EXTERNAL_CACHE_DIR, source.type was git, and the quickstart systemtest (fluid-openfoam + solid-cpp) passed end to end. No tutorials_ref symlink in the run directory.
For archive, I built a quickstart-develop.tar.gz from the same develop checkout (symlinks resolved so scripts are real files), served it via a file:// URL, and ran the same smoke path with source.type: archive. Download, extract, cache, copy, Docker build/run, and fieldcompare all passed. Again, no tutorials_ref.
I also ran the normal quickstart entry from tests.yaml with TUTORIALS_REF:develop so local tutorials still behave as today when the path exists in the repo.
Docker images were already cached, so both external runs were on the order of ~15–20s each; the steps were still the full pipeline.
Checklist
changelog-entries/732.md