diff --git a/.github/workflows/ApplicationTesting.yml b/.github/workflows/ApplicationTesting.yml index 381d5461..32e6e3e3 100644 --- a/.github/workflows/ApplicationTesting.yml +++ b/.github/workflows/ApplicationTesting.yml @@ -34,6 +34,16 @@ on: required: false default: '' type: string + artifacts_pattern: + description: 'Glob of the names of artifacts to download before the tests run, e.g. ''Example-*''.' + required: false + default: '' + type: string + artifacts_directory: + description: 'Directory the artifacts are downloaded into, each into a subdirectory named after the artifact.' + required: false + default: 'artifacts' + type: string apt: description: 'Ubuntu dependencies to be installed through apt.' required: false @@ -251,6 +261,13 @@ jobs: run: | python -m pip install -v --disable-pip-version-check (Get-Item .\install\*.whl).FullName + - name: 📥 Download artifacts '${{ inputs.artifacts_pattern }}' + if: inputs.artifacts_pattern != '' + uses: pyTooling/download-artifact@v8 + with: + pattern: ${{ inputs.artifacts_pattern }} + path: ${{ inputs.artifacts_directory }} + # Run pytests - name: ✅ Run application tests (Ubuntu/macOS) diff --git a/.github/workflows/_Checking_JobTemplates.yml b/.github/workflows/_Checking_JobTemplates.yml index 71857f79..d3839b6f 100644 --- a/.github/workflows/_Checking_JobTemplates.yml +++ b/.github/workflows/_Checking_JobTemplates.yml @@ -175,6 +175,21 @@ jobs: wheel: ${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).package_all }} package_name: ${{ needs.UnitTestingParams.outputs.package_fullname }} + ExampleReport: + name: 📄 Example report for the application tests + runs-on: ubuntu-26.04 + steps: + - name: 📄 Write an example report + run: | + mkdir -p report + printf -- '%s\n' 'Report of an example job.' > report/Example.txt + + - name: 📤 Upload the example report as artifact + uses: pyTooling/upload-artifact@v7 + with: + name: Example-Report + path: report/Example.txt + AppTesting: uses: pyTooling/Actions/.github/workflows/ApplicationTesting.yml@dev needs: @@ -182,9 +197,11 @@ jobs: - AppTestingParams - UnitTestingParams - Package + - ExampleReport with: jobs: ${{ needs.AppTestingParams.outputs.python_jobs }} wheel: ${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).package_all }} + artifacts_pattern: 'Example-*' apptest_report_xml: ${{ needs.ConfigParams.outputs.unittest_report_xml }} apptest_xml_artifact: ${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).apptesting_xml }} diff --git a/doc/JobTemplate/Testing/ApplicationTesting.rst b/doc/JobTemplate/Testing/ApplicationTesting.rst index 2dceb5b1..0a03f8d4 100644 --- a/doc/JobTemplate/Testing/ApplicationTesting.rst +++ b/doc/JobTemplate/Testing/ApplicationTesting.rst @@ -41,13 +41,16 @@ Configuration options for :term:`pytest` should be given via section ``[tool.pyt :ref:`JOBTMPL/ApplicationTesting/Input/ubuntu_before_script`. 5. Download the Python package artifact containing the wheel (:ref:`JOBTMPL/ApplicationTesting/Input/wheel`). 6. Install the wheel using :term:`pip`. - 7. Run the application tests using :term:`pytest` (:ref:`JOBTMPL/ApplicationTesting/Input/apptest_directory`, + 7. Download further artifacts the tests read, if requested + (:ref:`JOBTMPL/ApplicationTesting/Input/artifacts_pattern`, + :ref:`JOBTMPL/ApplicationTesting/Input/artifacts_directory`). + 8. Run the application tests using :term:`pytest` (:ref:`JOBTMPL/ApplicationTesting/Input/apptest_directory`, :ref:`JOBTMPL/ApplicationTesting/Input/tests_directory`, :ref:`JOBTMPL/ApplicationTesting/Input/root_directory`), in parallel if :file:`pytest-xdist` is installed (:ref:`JOBTMPL/ApplicationTesting/Input/parallel`). The environment variable ``GITHUB_TOKEN`` holds the job's token, so a program reading GitHub's REST API authenticates and isn't limited to 60 requests per hour per IP address. - 8. Upload the test report summary as an artifact (:ref:`JOBTMPL/ApplicationTesting/Input/apptest_xml_artifact`, + 9. Upload the test report summary as an artifact (:ref:`JOBTMPL/ApplicationTesting/Input/apptest_xml_artifact`, :ref:`JOBTMPL/ApplicationTesting/Input/apptest_report_xml`). .. note:: @@ -136,6 +139,10 @@ Parameter Summary +-------------------------------------------------------------------+----------+---------------+------------------------------------------------------------------------------------------------------------------------------+ | :ref:`JOBTMPL/ApplicationTesting/Input/wheel` | no | string | ``''`` | +-------------------------------------------------------------------+----------+---------------+------------------------------------------------------------------------------------------------------------------------------+ +| :ref:`JOBTMPL/ApplicationTesting/Input/artifacts_pattern` | no | string | ``''`` | ++-------------------------------------------------------------------+----------+---------------+------------------------------------------------------------------------------------------------------------------------------+ +| :ref:`JOBTMPL/ApplicationTesting/Input/artifacts_directory` | no | string | ``'artifacts'`` | ++-------------------------------------------------------------------+----------+---------------+------------------------------------------------------------------------------------------------------------------------------+ | :ref:`JOBTMPL/ApplicationTesting/Input/apt` | no | string | ``''`` | +-------------------------------------------------------------------+----------+---------------+------------------------------------------------------------------------------------------------------------------------------+ | :ref:`JOBTMPL/ApplicationTesting/Input/brew` | no | string | ``''`` | @@ -221,6 +228,32 @@ wheel Produced by :ref:`JOBTMPL/Package`. If empty, no package is downloaded and the tests run against whatever is installed in the environment. +.. _JOBTMPL/ApplicationTesting/Input/artifacts_pattern: + +artifacts_pattern +================= + +:Type: string +:Required: no +:Default Value: ``''`` +:Possible Values: A glob pattern of artifact names, e.g. ``'Example-*'``. An empty string disables the download. +:Description: Artifacts to download before the application tests run, e.g. the reports example jobs wrote, which the + tests read with the installed package. Each artifact is extracted into a subdirectory of + :ref:`JOBTMPL/ApplicationTesting/Input/artifacts_directory` named after the artifact. |br| + The jobs uploading them must be listed in the calling job's ``needs``. + +.. _JOBTMPL/ApplicationTesting/Input/artifacts_directory: + +artifacts_directory +=================== + +:Type: string +:Required: no +:Default Value: ``'artifacts'`` +:Possible Values: Any valid directory path, relative to the repository's root. +:Description: Directory the artifacts of :ref:`JOBTMPL/ApplicationTesting/Input/artifacts_pattern` are downloaded + into. + .. _JOBTMPL/ApplicationTesting/Input/apt: apt diff --git a/tests/app/AppTest.py b/tests/app/AppTest.py index 14b051a9..54585b27 100644 --- a/tests/app/AppTest.py +++ b/tests/app/AppTest.py @@ -30,6 +30,7 @@ # from importlib.metadata import version as get_version from json import loads as json_loads, JSONDecodeError +from pathlib import Path from re import IGNORECASE, MULTILINE from shutil import which from subprocess import CompletedProcess, run as subprocess_run, TimeoutExpired @@ -107,3 +108,14 @@ class Basic(Testcase): def test_NoArguments(self) -> None: result = self.RunEntrypoint() self.assertExitCode(result, 0) + + +class DownloadedArtifacts(TestCase): + """``ApplicationTesting.yml`` downloads the artifacts ``artifacts_pattern`` names into ``artifacts//``.""" + + def test_ExampleReport(self) -> None: + directory = Path("artifacts") + if not directory.exists(): + self.skipTest("No artifacts downloaded: the calling pipeline sets no 'artifacts_pattern'.") + + self.assertEqual("Report of an example job.\n", (directory / "Example-Report" / "Example.txt").read_text())