From 77271b60897dc1555198187c73df8afbcb54c8e9 Mon Sep 17 00:00:00 2001 From: Francis Charette Migneault Date: Tue, 5 Sep 2023 16:13:05 -0400 Subject: [PATCH] fix schema validation prohibiting job execution with empty string input --- CHANGES.rst | 2 ++ tests/wps_restapi/test_processes.py | 15 +++++++++ weaver/processes/convert.py | 6 ++-- weaver/utils.py | 2 +- weaver/wps_restapi/swagger_definitions.py | 38 +++++++++++++++-------- 5 files changed, 46 insertions(+), 17 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index b0e3d3039..b369348d0 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -23,6 +23,8 @@ Changes: Fixes: ------ - Fix broken `OpenAPI` schema link references to `OGC API - Processes` repository. +- Fix `Job` creation failing when submitting an empty string as input for a `Process` that allows it due + to schema validation incorrectly preventing it. .. _changes_4.30.1: diff --git a/tests/wps_restapi/test_processes.py b/tests/wps_restapi/test_processes.py index 7cd4f0788..90c37ddb8 100644 --- a/tests/wps_restapi/test_processes.py +++ b/tests/wps_restapi/test_processes.py @@ -1951,6 +1951,21 @@ def test_execute_process_no_json_body(self): assert resp.status_code == 400 assert resp.content_type == ContentType.APP_JSON + def test_execute_process_valid_empty_string(self): + """ + Ensure that a process expecting an input string parameter can be provided as empty (not resolved as "missing"). + """ + path = f"/processes/{self.process_public.identifier}/jobs" + data = self.get_process_execute_template(test_input="") + + with contextlib.ExitStack() as stack: + for exe in mocked_process_job_runner(): + stack.enter_context(exe) + resp = self.app.post_json(path, params=data, headers=self.json_headers) + assert resp.status_code == 201, "Expected job submission without inputs created without error." + job = self.job_store.fetch_by_id(resp.json["jobID"]) + assert job.inputs[0]["data"] == "", "Input value should be an empty string." + def test_execute_process_missing_required_params(self): """ Validate execution against missing parameters. diff --git a/weaver/processes/convert.py b/weaver/processes/convert.py index 52e33b1de..58a216b5b 100644 --- a/weaver/processes/convert.py +++ b/weaver/processes/convert.py @@ -2861,10 +2861,10 @@ def wps2json_job_payload(wps_request, wps_process): for input_value in input_list: input_data = input_value.get("data") input_href = input_value.get("href") - if input_data: - data["inputs"].append({"id": iid, "data": input_data}) - elif input_href: + if input_href: # when href is provided, it must always be non-empty data["inputs"].append({"id": iid, "href": input_href}) + else: # no check if value to allow possible empty string, numeric zero or explicit null + data["inputs"].append({"id": iid, "data": input_data}) output_ids = list(wps_request.outputs) for output in wps_process.outputs: oid = output.identifier diff --git a/weaver/utils.py b/weaver/utils.py index b5d07d294..1e57a1748 100644 --- a/weaver/utils.py +++ b/weaver/utils.py @@ -3488,7 +3488,7 @@ def clean_json_text_body(body, remove_newlines=True, remove_indents=True): """ # cleanup various escape characters and u'' stings replaces = [(",\n", ", "), ("\\n", " "), (" \n", " "), ("\n'", "'"), ("\"", "\'"), - ("u\'", "\'"), ("u\"", "\'"), ("\'\'", "\'"), ("'. ", ""), ("'. '", ""), + ("u\'", "\'"), ("u\"", "\'"), ("'. ", ""), ("'. '", ""), ("}'", "}"), ("'{", "{")] if remove_indents: replaces.extend([("\\", " "), (" ", " ")]) diff --git a/weaver/wps_restapi/swagger_definitions.py b/weaver/wps_restapi/swagger_definitions.py index 11ba8097f..6d218b21a 100644 --- a/weaver/wps_restapi/swagger_definitions.py +++ b/weaver/wps_restapi/swagger_definitions.py @@ -1314,8 +1314,6 @@ class BoundingBoxInputType(ExtendedMappingSchema): supportedCRS = SupportedCRSList() -# FIXME: support byte/binary type (string + format:byte) ? -# https://github.com/opengeospatial/ogcapi-processes/blob/master/openapi/schemas/processes-core/binaryInputValue.yaml class AnyLiteralType(OneOfKeywordSchema): """ Submitted values that correspond to literal data. @@ -1326,10 +1324,29 @@ class AnyLiteralType(OneOfKeywordSchema): - :class:`AnyLiteralDefaultType` """ _one_of = [ - ExtendedSchemaNode(Float(), description="Literal data type representing a floating point number."), - ExtendedSchemaNode(Integer(), description="Literal data type representing an integer number."), - ExtendedSchemaNode(Boolean(), description="Literal data type representing a boolean flag."), - ExtendedSchemaNode(String(), description="Literal data type representing a generic string."), + ExtendedSchemaNode( + Float(), + title="LiteralDataFloat", + description="Literal data type representing a floating point number.", + ), + ExtendedSchemaNode( + Integer(), + title="LiteralDataInteger", + description="Literal data type representing an integer number.", + ), + ExtendedSchemaNode( + Boolean(), + title="LiteralDataBoolean", + description="Literal data type representing a boolean flag.", + ), + ExtendedSchemaNode( + # FIXME: support byte/binary type (string + format:byte) ? + # https://github.com/opengeospatial/ogcapi-processes/blob/master/openapi/schemas/processes-core/binaryInputValue.yaml + # see if we can use 'encoding' parameter available for below 'String' schema-type to handle this? + String(allow_empty=True), # valid to submit a process with empty string + title="LiteralDataString", + description="Literal data type representing a generic string.", + ), ] @@ -3489,14 +3506,9 @@ class ExecuteInputFile(AnyOfKeywordSchema): # https://github.com/opengeospatial/ogcapi-processes/blob/master/openapi/schemas/processes-core/binaryInputValue.yaml # FIXME: does not support bbox # https://github.com/opengeospatial/ogcapi-processes/blob/master/openapi/schemas/processes-core/bbox.yaml -class ExecuteInputInlineValue(OneOfKeywordSchema): +class ExecuteInputInlineValue(AnyLiteralType): + title = "ExecuteInputInlineValue" description = "Execute input value provided inline." - _one_of = [ - ExtendedSchemaNode(Float(), title="ExecuteInputValueFloat"), - ExtendedSchemaNode(Integer(), title="ExecuteInputValueInteger"), - ExtendedSchemaNode(Boolean(), title="ExecuteInputValueBoolean"), - ExtendedSchemaNode(String(), title="ExecuteInputValueString"), - ] # https://github.com/opengeospatial/ogcapi-processes/blob/master/openapi/schemas/processes-core/inputValue.yaml