Skip to content

Commit

Permalink
[wip] add test cases to validate JS requirement applied to CWL for ps…
Browse files Browse the repository at this point in the history
…eudo enum validation
  • Loading branch information
fmigneault committed Sep 12, 2023
1 parent 84b7a88 commit 2496092
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 1 deletion.
101 changes: 100 additions & 1 deletion tests/processes/test_convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
from weaver.formats import IANA_NAMESPACE_DEFINITION, OGC_MAPPING, OGC_NAMESPACE_DEFINITION, ContentType
from weaver.processes.constants import (
CWL_REQUIREMENT_APP_OGC_API,
CWL_REQUIREMENT_APP_WPS1,
CWL_REQUIREMENT_INLINE_JAVASCRIPT,
IO_INPUT,
IO_OUTPUT,
WPS_BOUNDINGBOX,
Expand Down Expand Up @@ -58,7 +60,8 @@
parse_cwl_enum_type,
repr2json_input_values,
set_field,
wps2json_io
wps2json_io,
xml_wps2cwl
)
from weaver.utils import null

Expand Down Expand Up @@ -1796,3 +1799,99 @@ def test_ogcapi2cwl_process_without_extra():
body["executionUnit"] = [{"unit": cwl}]
body["deploymentProfile"] = "http://www.opengis.net/profiles/eoc/ogcapiApplication"
assert info == body, "Process information should be updated with minimal details since no CWL detected in input."



@pytest.mark.parametrize(
["input_str", "input_int", "input_float"],
[
# OpenAPI schema references
(
{"schema": {"type": "string", "enum": ["a", "b", "c"]}},
{"schema": {"type": "integer", "enum": [1, 2, 3]}},
{"schema": {"type": "number", "format": "float", "enum": [1.2, 3.4]}},
),
# OGC-API input definitions
(
{"data_type": "string", "allowed_values": ["a", "b", "c"]},
{"data_type": "integer", "allowed_values": [1, 2, 3]},
{"data_type": "float", "allowed_values": [1.2, 3.4]},
),
]
)
def test_ogcapi2cwl_process_cwl_enum_updated(input_str, input_int, input_float):
"""
Test that a :term:`CWL` with pseudo-``Enum`` type has the necessary :term:`CWL` requirements to perform validation.
.. seealso::
- :func:`test_any2cwl_io_enum_convert`
- :func:`test_any2cwl_io_enum_validate`
"""
href = "https://remote-server.com/processes/test-process"
body = {
"inputs": {
"enum-str": input_str,
"enum-int": input_int,
"enum-float": input_float,
},
"outputs": {
"output": {"schema": {"type": "string", "contentMediaType": ContentType.TEXT_PLAIN}},
}
}
cwl, info = ogcapi2cwl_process(body, href)
assert info is not body, "copy should be created, not inplace modifications"

assert cwl["inputs"]["enum-str"]["type"] == {"type": "enum", "symbols": ["a", "b", "c"]}
assert cwl["inputs"]["enum-int"]["type"] == "int"
assert "symbols" not in cwl["inputs"]["enum-int"]
cwl_value_from = cwl["inputs"]["enum-int"]["inputBinding"]["valueFrom"].strip()
assert cwl_value_from.startswith("${") and cwl_value_from.endswith("}")
assert "[1, 2, 3]" in cwl_value_from
assert cwl["inputs"]["enum-float"]["type"] == "float"
assert "symbols" not in cwl["inputs"]["enum-float"]
cwl_value_from = cwl["inputs"]["enum-float"]["inputBinding"]["valueFrom"].strip()
assert cwl_value_from.startswith("${") and cwl_value_from.endswith("}")
assert "[1.2, 3.4]" in cwl_value_from
assert cwl["requirements"] == {CWL_REQUIREMENT_INLINE_JAVASCRIPT: {}}
assert cwl["hints"] == {CWL_REQUIREMENT_APP_OGC_API: {"process": href}}


def test_xml_wps2cwl_enum_updated():
"""
Test that a :term:`CWL` with pseudo-``Enum`` type has the necessary :term:`CWL` requirements to perform validation.
.. seealso::
- :func:`test_any2cwl_io_enum_convert`
- :func:`test_any2cwl_io_enum_validate`
"""
raise NotImplementedError # FIXME

proc = "test-process"
prov = "https://remote-server.com"
href = f"{prov}?service=WPS&version=1.0.0&request=DescribeProcess&identifier={proc}"
body = {
"inputs": {
"enum-str": input_str,
"enum-int": input_int,
"enum-float": input_float,
},
"outputs": {
"output": {"schema": {"type": "string", "contentMediaType": ContentType.TEXT_PLAIN}},
}
}
cwl, info = ogcapi2cwl_process(body, href)
assert info is not body, "copy should be created, not inplace modifications"

assert cwl["inputs"]["enum-str"]["type"] == {"type": "enum", "symbols": ["a", "b", "c"]}
assert cwl["inputs"]["enum-int"]["type"] == "int"
assert "symbols" not in cwl["inputs"]["enum-int"]
cwl_value_from = cwl["inputs"]["enum-int"]["inputBinding"]["valueFrom"].strip()
assert cwl_value_from.startswith("${") and cwl_value_from.endswith("}")
assert "[1, 2, 3]" in cwl_value_from
assert cwl["inputs"]["enum-float"]["type"] == "float"
assert "symbols" not in cwl["inputs"]["enum-float"]
cwl_value_from = cwl["inputs"]["enum-float"]["inputBinding"]["valueFrom"].strip()
assert cwl_value_from.startswith("${") and cwl_value_from.endswith("}")
assert "[1.2, 3.4]" in cwl_value_from
assert cwl["requirements"] == {CWL_REQUIREMENT_INLINE_JAVASCRIPT: {}}
assert cwl["hints"] == {CWL_REQUIREMENT_APP_WPS1: {"provider": prov, "process": proc}}
27 changes: 27 additions & 0 deletions weaver/processes/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
from weaver.processes.constants import (
CWL_REQUIREMENT_APP_OGC_API,
CWL_REQUIREMENT_APP_WPS1,
CWL_REQUIREMENT_INLINE_JAVASCRIPT,
IO_INPUT,
IO_OUTPUT,
OAS_ARRAY_TYPES,
Expand Down Expand Up @@ -773,6 +774,29 @@ def any2cwl_io(wps_io, io_select):
return cwl_io, cwl_ns


def _patch_cwl_enum_js_requirement(cwl_package):
# type: (CWL) -> None
"""
Applies the JavaScript requirement to validate a pseudo-``Enum`` applied to a :term:`CWL` input definition.
.. seealso::
- :func:`any2cwl_io`
- :func:`_convert_cwl_io_enum`
- :func:`_get_cwl_js_value_from`
"""
cwl_items = cwl_package.get("inputs", [])
if isinstance(cwl_items, dict):
cwl_items = list(cwl_items.values())
for cwl_input in cwl_items:
cwl_value_from = cwl_input.get("inputBinding", {}).get("valueFrom", {})
if isinstance(cwl_value_from, str):
cwl_value_from = cwl_value_from.strip()
if cwl_value_from.startswith("${") and cwl_value_from.endswith("}"):
cwl_package.setdefault("requirements", {})
cwl_package["requirements"].setdefault(CWL_REQUIREMENT_INLINE_JAVASCRIPT, {})
return # early exit, no need to check more


def wps2cwl_requirement(wps_service_url, wps_process_id):
# type: (Union[str, ParseResult], str) -> JSON
"""
Expand Down Expand Up @@ -829,6 +853,7 @@ def ows2json(wps_process, wps_service_name, wps_service_url, wps_provider_name=N
if "$namespaces" not in cwl_package:
cwl_package["$namespaces"] = {}
cwl_package["$namespaces"].update(cwl_ns)
_patch_cwl_enum_js_requirement(cwl_package)
return cwl_package, process_info


Expand Down Expand Up @@ -952,6 +977,7 @@ def ogcapi2cwl_process(payload, reference):
}
}
cwl_package.update(cwl_pkg) # type: ignore
_patch_cwl_enum_js_requirement(cwl_package)
payload_copy["executionUnit"] = [{"unit": cwl_package}]
payload_copy["deploymentProfile"] = "http://www.opengis.net/profiles/eoc/ogcapiApplication"
return cwl_package, payload_copy
Expand Down Expand Up @@ -2279,6 +2305,7 @@ def oas2json_io_literal(io_info):
io_allow.update(io_info) # noqa
io_allow["data_type"] = data_type
domains = any2json_literal_data_domains(io_allow)
io_json["allowed_values"] = io_allow["allowed_values"] # propagate to help CWL resolution of enum later on
io_json["literalDataDomains"] = domains
return io_json

Expand Down

0 comments on commit 2496092

Please sign in to comment.