Skip to content

Commit

Permalink
fix schema validation prohibiting job execution with empty string input
Browse files Browse the repository at this point in the history
  • Loading branch information
fmigneault committed Sep 5, 2023
1 parent f6e37b7 commit 77271b6
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 17 deletions.
2 changes: 2 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down
15 changes: 15 additions & 0 deletions tests/wps_restapi/test_processes.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
6 changes: 3 additions & 3 deletions weaver/processes/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion weaver/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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([("\\", " "), (" ", " ")])
Expand Down
38 changes: 25 additions & 13 deletions weaver/wps_restapi/swagger_definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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.",
),
]


Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 77271b6

Please sign in to comment.