Skip to content

Source test cases from other repositories#732

Open
PranjalManhgaye wants to merge 19 commits into
precice:developfrom
PranjalManhgaye:external-source-fix
Open

Source test cases from other repositories#732
PranjalManhgaye wants to merge 19 commits into
precice:developfrom
PranjalManhgaye:external-source-fix

Conversation

@PranjalManhgaye

@PranjalManhgaye PranjalManhgaye commented Mar 1, 2026

Copy link
Copy Markdown
Collaborator

What this is about

(closes #538)

right now, every entry in tests.yaml assumes the tutorial folder is already in this repo. you give a path like flow-over-heated-plate, and the runner finds it under the local precice/tutorials checkout.

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 source block in tests.yaml for that.

What happens at runtime

I have not touched the local behaviour : if there is no source field, behaviour is the same as today.

If source is set:

  1. The runner fetches the tutorial (git shallow clone or archive download) into a cache directory (~/.cache/precice-tutorials by default, or PRECICE_EXTERNAL_CACHE_DIR if you set it).
  2. It loads metadata.yaml from that folder, same as for in-repo tutorials.
  3. It copies the tutorial into the usual run directory and continues with Docker build, docker compose up, and fieldcompare.

TUTORIALS_REF / TUTORIALS_PR still only affect local tutorials. For external ones, the version is whatever you put in source.ref.

Example

Git:

- path: flow-over-heated-plate
  source:
    type: git
    url: https://github.com/precice/tutorials.git
    ref: develop
    subdir: .
  case_combination:
    - fluid-openfoam
    - solid-openfoam
  reference_result: ./flow-over-heated-plate/reference-results/fluid-openfoam_solid-openfoam.tar.gz

Archive:

- path: some-tutorial
  source:
    type: archive
    url: https://example.org/tutorial-bundle.tar.gz
  case_combination: [...]
  reference_result: ./some-tutorial/reference-results/...

type can be git or archive. If you omit source, it stays local.

For git, if clone --branch ref fails, 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]
Loading

Files touched

  • tools/tests/systemtests/sources.py — new: fetch + cache + resolve_tutorial_root
  • tools/tests/systemtests/TestSuite.py — read source, load external metadata when needed
  • tools/tests/systemtests/Systemtest.py — copy from resolved path; ref/PR checkout only for local
  • tools/tests/metadata_parser/metdata.pyTutorial.source, ReferenceResult.base_dir
  • tools/tests/README.md — short how-to
  • changelog-entries/732.md

I did not add a real source: entry to tests.yaml yet, so existing suites should behave as before until someone opts in.

Rebased onto current develop and 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 compileall on 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 entry in changelog-entries/732.md

@PranjalManhgaye PranjalManhgaye changed the title Add external tutorial sources for systemtests (Closes #538) Source test cases from other repositories (Closes #538) Mar 1, 2026
@PranjalManhgaye

Copy link
Copy Markdown
Collaborator Author

@MakisH , sir happy to update anything needed before review .

@MakisH MakisH added systemtests GSoC Contributed in the context of the Google Summer of Code labels Mar 1, 2026
@precice-bot

Copy link
Copy Markdown
Collaborator

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

@MakisH

MakisH commented May 17, 2026

Copy link
Copy Markdown
Member

@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.

@MakisH MakisH changed the title Source test cases from other repositories (Closes #538) Source test cases from other repositories May 17, 2026
@PranjalManhgaye

Copy link
Copy Markdown
Collaborator Author

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.
Rebase onto latest precice/develop and resolve conflicts in systemtests
files and README for external tutorial sources (PR precice#732).
@PranjalManhgaye

Copy link
Copy Markdown
Collaborator Author

@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 MakisH left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
@PranjalManhgaye

Copy link
Copy Markdown
Collaborator Author

@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 ,,

@PranjalManhgaye PranjalManhgaye requested a review from MakisH June 16, 2026 19:06

@MakisH MakisH left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Comment thread tools/tests/README.md Outdated
Comment thread tools/tests/README.md Outdated
Use external: instead of tutorials: for external suites, put source
before path in examples, and move docs under Extending.
@PranjalManhgaye

Copy link
Copy Markdown
Collaborator Author

@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.
@PranjalManhgaye

Copy link
Copy Markdown
Collaborator Author

@MakisH I have merged latest develop and pushed - now it should address the conflict and the external skip_compare about which we talked earlier. Ready for another look when you have time.

@PranjalManhgaye PranjalManhgaye requested a review from MakisH June 30, 2026 03:50
Integrate precice#724, precice#849, precice#854 and resolve TestSuite.py conflict
(external sources + tolerance/skip_compare + run-before/run-after).

@MakisH MakisH left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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!

Comment thread tools/tests/metadata_parser/metdata.py Outdated
Comment thread tools/tests/metadata_parser/metdata.py Outdated
Comment thread tools/tests/systemtests/TestSuite.py Outdated
Comment on lines +84 to +87
raise ValueError(
f"Test suite '{test_suite_name}' must use either 'tutorials' or "
f"'external', not both."
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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-openfoam

which would also allow the external cases to be used in the openfoam-adapter test suite, for example.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +16 to +18
# 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))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the motivation for this cache?
Similarly for the _cache_key function.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread tools/tests/systemtests/sources.py Outdated
Comment thread tools/tests/systemtests/sources.py Outdated
["git", "-C", str(checkout), "fetch", "origin", ref, "--depth", "1"],
check=True,
capture_output=True,
timeout=120,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Comment thread tools/tests/systemtests/sources.py Outdated
Comment on lines +92 to +97
# 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"
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +162 to +166
else:
import zipfile

with zipfile.ZipFile(tmp_path, "r") as zf:
zf.extractall(extract_dir)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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/

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
@PranjalManhgaye PranjalManhgaye requested a review from MakisH July 1, 2026 16:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

GSoC Contributed in the context of the Google Summer of Code systemtests

Projects

Status: Needs review

Development

Successfully merging this pull request may close these issues.

Source test cases from other repositories

3 participants