From 02acbaac7d551a5e9cd53b760843ee49516d1467 Mon Sep 17 00:00:00 2001 From: Juho Inkinen <34240031+juhoinkinen@users.noreply.github.com> Date: Tue, 12 Aug 2025 12:25:15 +0300 Subject: [PATCH 1/7] Upgrade to schemathesis 4.* --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 2658c28ee..1e7a0a175 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -69,7 +69,7 @@ flake8 = "*" bumpversion = "*" black = "25.*" isort = "*" -schemathesis = "3.*.*" +schemathesis = "4.*" [tool.poetry.extras] fasttext = ["fasttext-wheel"] From 34e7b424ca62834a25fb0e64570c4b319f172f0d Mon Sep 17 00:00:00 2001 From: Juho Inkinen <34240031+juhoinkinen@users.noreply.github.com> Date: Wed, 13 Aug 2025 16:35:23 +0300 Subject: [PATCH 2/7] Adapt to schemathesis v4 --- tests/test_openapi.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/test_openapi.py b/tests/test_openapi.py index 09d7ae5ba..dba092a68 100644 --- a/tests/test_openapi.py +++ b/tests/test_openapi.py @@ -2,12 +2,12 @@ import pytest import schemathesis -from hypothesis import settings +from hypothesis import HealthCheck, settings import annif cxapp = annif.create_app(config_name="annif.default_config.TestingConfig") -schema = schemathesis.from_path("annif/openapi/annif.yaml", app=cxapp) +schema = schemathesis.openapi.from_asgi("/v1/openapi.json", app=cxapp) @schemathesis.hook("filter_path_parameters") @@ -20,14 +20,14 @@ def filter_path_parameters(context, path_parameters): @schema.parametrize() -@settings(max_examples=10) +@settings(max_examples=10, suppress_health_check=[HealthCheck.filter_too_much]) def test_openapi_fuzzy(case): case.call_and_validate() @pytest.mark.slow -@schema.include(path_regex="/v1/projects/{project_id}").parametrize() -@settings(max_examples=50) +@schema.include(path_regex="projects/{project_id}").parametrize() +@settings(max_examples=50, suppress_health_check=[HealthCheck.filter_too_much]) def test_openapi_fuzzy_target_dummy_fi(case): case.path_parameters = {"project_id": "dummy-fi"} case.call_and_validate() From 3037ccaf90238c666111b48ea9213be4952ce723 Mon Sep 17 00:00:00 2001 From: Juho Inkinen <34240031+juhoinkinen@users.noreply.github.com> Date: Wed, 13 Aug 2025 17:01:55 +0300 Subject: [PATCH 3/7] Add http code 400 as response of /learn method --- annif/openapi/annif.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/annif/openapi/annif.yaml b/annif/openapi/annif.yaml index d73de9526..1d6362783 100644 --- a/annif/openapi/annif.yaml +++ b/annif/openapi/annif.yaml @@ -201,6 +201,8 @@ paths: content: application/json: {} + "400": + $ref: '#/components/responses/BadRequest' "403": $ref: '#/components/responses/NotAllowed' "404": From 1dba274332e17ae6ed1fe168be39428b90470a26 Mon Sep 17 00:00:00 2001 From: Juho Inkinen <34240031+juhoinkinen@users.noreply.github.com> Date: Fri, 15 Aug 2025 14:31:28 +0300 Subject: [PATCH 4/7] Add bcp45 format to API schme and use langs supported by simplemma for fuzzying /detect-language --- annif/openapi/annif.yaml | 1 + tests/test_openapi.py | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/annif/openapi/annif.yaml b/annif/openapi/annif.yaml index 1d6362783..bf1ec947e 100644 --- a/annif/openapi/annif.yaml +++ b/annif/openapi/annif.yaml @@ -234,6 +234,7 @@ paths: description: candidate languages as IETF BCP 47 codes items: type: string + format: bcp47 maxLength: 3 minLength: 2 example: en diff --git a/tests/test_openapi.py b/tests/test_openapi.py index dba092a68..0c10d0b55 100644 --- a/tests/test_openapi.py +++ b/tests/test_openapi.py @@ -2,10 +2,15 @@ import pytest import schemathesis -from hypothesis import HealthCheck, settings +from hypothesis import HealthCheck, settings, strategies +from simplemma.strategies.dictionaries.dictionary_factory import SUPPORTED_LANGUAGES import annif +bcp47_strategy = strategies.sampled_from(SUPPORTED_LANGUAGES) +schemathesis.openapi.format("bcp47", bcp47_strategy) + + cxapp = annif.create_app(config_name="annif.default_config.TestingConfig") schema = schemathesis.openapi.from_asgi("/v1/openapi.json", app=cxapp) From 642c2dbc00291732bbaac54706d104cd69df0b7e Mon Sep 17 00:00:00 2001 From: Juho Inkinen <34240031+juhoinkinen@users.noreply.github.com> Date: Wed, 25 Feb 2026 17:29:54 +0200 Subject: [PATCH 5/7] Disable checking success of all schema-compliant requests --- tests/test_openapi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_openapi.py b/tests/test_openapi.py index 0c10d0b55..48bc5cdf6 100644 --- a/tests/test_openapi.py +++ b/tests/test_openapi.py @@ -13,7 +13,7 @@ cxapp = annif.create_app(config_name="annif.default_config.TestingConfig") schema = schemathesis.openapi.from_asgi("/v1/openapi.json", app=cxapp) - +schema.config.checks.positive_data_acceptance.enabled = False @schemathesis.hook("filter_path_parameters") def filter_path_parameters(context, path_parameters): From 81e2112516d24b085aa699f5104b02ffe2391429 Mon Sep 17 00:00:00 2001 From: Juho Inkinen <34240031+juhoinkinen@users.noreply.github.com> Date: Thu, 26 Feb 2026 16:32:11 +0200 Subject: [PATCH 6/7] Disable producing unexpected query, header or cookie parameters --- tests/test_openapi.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_openapi.py b/tests/test_openapi.py index 48bc5cdf6..bcb20104c 100644 --- a/tests/test_openapi.py +++ b/tests/test_openapi.py @@ -14,6 +14,7 @@ cxapp = annif.create_app(config_name="annif.default_config.TestingConfig") schema = schemathesis.openapi.from_asgi("/v1/openapi.json", app=cxapp) schema.config.checks.positive_data_acceptance.enabled = False +schema.config.generation.allow_extra_parameters = False @schemathesis.hook("filter_path_parameters") def filter_path_parameters(context, path_parameters): From 077bbf3a9f4dc91cdf6edff1e668b2aa5ae67cc2 Mon Sep 17 00:00:00 2001 From: Juho Inkinen <34240031+juhoinkinen@users.noreply.github.com> Date: Tue, 3 Mar 2026 10:42:04 +0200 Subject: [PATCH 7/7] Use filter_body hook to bypass Connexion crashes with non-UTF8 body --- pyproject.toml | 2 +- tests/test_openapi.py | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 7538952e6..5f30f3a41 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -80,7 +80,7 @@ dev = [ "bumpversion", "black==25.*", "isort", - "schemathesis==4.*", + "schemathesis==4.11.*", ] [tool.isort] diff --git a/tests/test_openapi.py b/tests/test_openapi.py index bcb20104c..95d84264a 100644 --- a/tests/test_openapi.py +++ b/tests/test_openapi.py @@ -16,9 +16,24 @@ schema.config.checks.positive_data_acceptance.enabled = False schema.config.generation.allow_extra_parameters = False + +@schemathesis.hook("filter_body") +def filter_body(context, body): + # Exclude body containing non-utf8 content to avoid crashing Connexion: + # https://github.com/spec-first/connexion/issues/1860 + if body is None or isinstance(body, (dict, list, str, int, float, bool)): + return True + elif isinstance(body, (bytes, bytearray)): + try: + _ = body.decode("utf-8") + except UnicodeDecodeError: + return False + return True + + @schemathesis.hook("filter_path_parameters") def filter_path_parameters(context, path_parameters): - # Exclude path parameters containing newline which crashes application + # Exclude path parameters containing newline to avoid crashing Connexion: # https://github.com/spec-first/connexion/issues/1908 if path_parameters is not None and "project_id" in path_parameters: return "%0A" not in path_parameters["project_id"]