diff --git a/clients/python/test/e2e/_utils.py b/clients/python/test/e2e/_utils.py index de197d57..bf702d52 100644 --- a/clients/python/test/e2e/_utils.py +++ b/clients/python/test/e2e/_utils.py @@ -1,6 +1,7 @@ import os import subprocess from pathlib import Path +from typing import Optional import osparc import pytest @@ -23,7 +24,7 @@ def repo_version() -> Version: return Version(version_file.read_text()) -def requires_dev_features(test): +def skip_if_no_dev_features(test): if ( Version(osparc.__version__) < repo_version() or not osparc_dev_features_enabled() @@ -31,7 +32,26 @@ def requires_dev_features(test): return pytest.mark.skip( ( f"{osparc.__version__=}<{str(repo_version)} " - "or {osparc_dev_features_enabled()=}" + f"or {osparc_dev_features_enabled()=}" ) )(test) return test + + +def skip_if_osparc_version( + *, + at_least: Optional[Version] = None, + at_most: Optional[Version] = None, + exactly: Optional[Version] = None, +): + def _wrapper(test): + osparc_version = Version(osparc.__version__) + if at_least and osparc_version < at_least: + return pytest.mark.skip((f"{osparc_version=}<{at_least}"))(test) + if at_most and osparc_version > at_most: + return pytest.mark.skip((f"{osparc_version=}>{at_most}"))(test) + if exactly and osparc_version != exactly: + return pytest.mark.skip((f"{osparc_version=}!={exactly}"))(test) + return test + + return _wrapper diff --git a/clients/python/test/e2e/ci/e2e/e2e/postprocess.py b/clients/python/test/e2e/ci/e2e/e2e/postprocess.py index 3b40e337..94852ca8 100644 --- a/clients/python/test/e2e/ci/e2e/e2e/postprocess.py +++ b/clients/python/test/e2e/ci/e2e/e2e/postprocess.py @@ -11,11 +11,13 @@ import typer from pydantic import PositiveInt from tenacity import ( + RetryError, Retrying, retry_if_exception_type, stop_after_attempt, stop_after_delay, ) +from urllib3.exceptions import HTTPError as Urllib3HttpError from ._models import Artifacts, ClientSettings, PytestIniFile, ServerSettings from ._utils import E2eExitCodes, E2eScriptFailure, handle_validation_error @@ -219,22 +221,34 @@ def clean_up_jobs(artifacts_dir: Path, retry_minutes: Optional[PositiveInt] = No msg = "Cleaning up jobs for user: " msg += f"\n{server_config.model_dump_json(indent=1)}" typer.echo(msg) - for attempt in Retrying( - retry=retry_if_exception_type(osparc.ApiException), - stop=stop_after_delay(timedelta(minutes=retry_minutes)) - if retry_minutes - else stop_after_attempt(1), - ): - with attempt: - with osparc.ApiClient(config) as api_client: - solvers_api = osparc.SolversApi(api_client) - assert isinstance( - solvers := solvers_api.list_solvers_releases(), list - ) - for solver in solvers: - assert isinstance(solver, osparc.Solver) - assert (id_ := solver.id) is not None - assert (version := solver.version) is not None - for job in solvers_api.jobs(id_, version): - assert isinstance(job, osparc.Job) - solvers_api.delete_job(id_, version, job.id) + try: + for attempt in Retrying( + retry=retry_if_exception_type((osparc.ApiException, Urllib3HttpError)), + stop=stop_after_delay(timedelta(minutes=retry_minutes)) + if retry_minutes + else stop_after_attempt(1), + ): + with attempt: + with osparc.ApiClient(config) as api_client: + solvers_api = osparc.SolversApi(api_client) + assert isinstance( + solvers := solvers_api.list_solvers_releases(), list + ) + for solver in solvers: + assert isinstance(solver, osparc.Solver) + assert (id_ := solver.id) is not None + assert (version := solver.version) is not None + for job in solvers_api.jobs(id_, version): + assert isinstance(job, osparc.Job) + solvers_api.delete_job(id_, version, job.id) + except RetryError as exc: + typer.echo( + typer.style( + ( + "Failed when cleaning jobs when encountering " + f"the following exception:\n{exc.last_attempt.exception()}" + ), + fg=typer.colors.RED, + bold=True, + ) + ) diff --git a/clients/python/test/e2e/test_files_api.py b/clients/python/test/e2e/test_files_api.py index 4bfe3699..c7519203 100644 --- a/clients/python/test/e2e/test_files_api.py +++ b/clients/python/test/e2e/test_files_api.py @@ -3,7 +3,7 @@ import osparc import pytest -from _utils import requires_dev_features +from _utils import skip_if_no_dev_features from conftest import _KB @@ -19,7 +19,7 @@ def _hash_file(file: Path) -> str: return sha256.hexdigest() -@requires_dev_features +@skip_if_no_dev_features def test_upload_file(tmp_file: Path, api_client: osparc.ApiClient) -> None: """Test that we can upload a file via the multipart upload""" tmp_path: Path = tmp_file.parent @@ -37,7 +37,7 @@ def test_upload_file(tmp_file: Path, api_client: osparc.ApiClient) -> None: files_api.delete_file(uploaded_file1.id) -@requires_dev_features +@skip_if_no_dev_features @pytest.mark.parametrize("use_checksum", [True, False]) @pytest.mark.parametrize("use_id", [True, False]) def test_search_files( diff --git a/clients/python/test/e2e/test_solvers_api.py b/clients/python/test/e2e/test_solvers_api.py index 719a6561..55422f55 100644 --- a/clients/python/test/e2e/test_solvers_api.py +++ b/clients/python/test/e2e/test_solvers_api.py @@ -1,13 +1,14 @@ import json import osparc -from _utils import requires_dev_features +from _utils import skip_if_no_dev_features, skip_if_osparc_version from httpx import AsyncClient +from packaging.version import Version DEFAULT_TIMEOUT_SECONDS = 10 * 60 # 10 min -@requires_dev_features +@skip_if_no_dev_features def test_jobs(api_client: osparc.ApiClient, sleeper: osparc.Solver): """Test the jobs method @@ -48,14 +49,11 @@ def test_jobs(api_client: osparc.ApiClient, sleeper: osparc.Solver): solvers_api.delete_job(sleeper.id, sleeper.version, elm) +@skip_if_osparc_version(at_least=Version("0.6.5")) async def test_logstreaming( api_client: osparc.ApiClient, sleeper: osparc.Solver, async_client: AsyncClient ): - """Test the log streaming - - Args: - configuration (osparc.Configuration): The Configuration - """ + """Test log streaming""" solvers_api: osparc.SolversApi = osparc.SolversApi(api_client) job: osparc.Job = solvers_api.create_job( sleeper.id, sleeper.version, osparc.JobInputs({"input1": 1.0})