diff --git a/lib/galaxy/tool_util/verify/asserts/__init__.py b/lib/galaxy/tool_util/verify/asserts/__init__.py index 8ffe4babaa1..f37bc018e09 100644 --- a/lib/galaxy/tool_util/verify/asserts/__init__.py +++ b/lib/galaxy/tool_util/verify/asserts/__init__.py @@ -9,7 +9,7 @@ from galaxy.util import unicodify log = logging.getLogger(__name__) -assertion_module_names = ["text", "tabular", "xml", "hdf5", "archive", "size"] +assertion_module_names = ["text", "tabular", "xml", "json", "hdf5", "archive", "size"] # Code for loading modules containing assertion checking functions, to # create a new module of assertion functions, create the needed python diff --git a/lib/galaxy/tool_util/verify/asserts/json.py b/lib/galaxy/tool_util/verify/asserts/json.py new file mode 100644 index 00000000000..1ba151ba26c --- /dev/null +++ b/lib/galaxy/tool_util/verify/asserts/json.py @@ -0,0 +1,53 @@ +import json +from typing import ( + Any, + Callable, + cast, +) + +PropertyVisitor = Callable[[str, Any], Any] + + +def any_in_tree(f: PropertyVisitor, json_tree: Any): + if isinstance(json_tree, list): + for element in json_tree: + if any_in_tree(f, element): + return True + + elif isinstance(json_tree, dict): + for key, value in json_tree.items(): + if f(cast(str, key), value): + return True + elif any_in_tree(f, value): + return True + + return False + + +def assert_has_json_property_with_value( + output, + property: str, + value: str, +): + """Assert JSON tree contains the specified property with specified JSON-ified value.""" + output_json = json.loads(output) + expected_value = json.loads(value) + + def is_property(key, value): + return key == property and value == expected_value + + assert any_in_tree(is_property, output_json), f"Failed to find property [{property}] with JSON value [{value}]" + + +def assert_has_json_property_with_text( + output, + property: str, + text: str, +): + """Assert JSON tree contains the specified property with specified JSON-ified value.""" + output_json = json.loads(output) + + def is_property(key, value): + return key == property and value == text + + assert any_in_tree(is_property, output_json), f"Failed to find property [{property}] with text [{text}]" diff --git a/lib/galaxy/tool_util/xsd/galaxy.xsd b/lib/galaxy/tool_util/xsd/galaxy.xsd index c4115d9e717..4b9e1bad82b 100644 --- a/lib/galaxy/tool_util/xsd/galaxy.xsd +++ b/lib/galaxy/tool_util/xsd/galaxy.xsd @@ -2070,6 +2070,7 @@ module. + @@ -2126,6 +2127,15 @@ module. + + + + + + + + + @@ -2356,6 +2366,7 @@ $attribute_list::5 + @@ -2607,6 +2618,46 @@ $attribute_list::5 + + + +``` + +$attribute_list::5 +]]> + + + + + + JSON-ified value to search for. This will be converted from an XML string to JSON with Python's json.loads function. + + + + + + +``` + +$attribute_list::5 +]]> + + + + + + Text value to search for. + + + + + + + JSON property to search the target for. + + + + diff --git a/test/unit/tool_util/verify/test_asserts.py b/test/unit/tool_util/verify/test_asserts.py index 6806f4cba37..a6519e57f70 100644 --- a/test/unit/tool_util/verify/test_asserts.py +++ b/test/unit/tool_util/verify/test_asserts.py @@ -216,6 +216,18 @@ XML_XML_ELEMENT = """ """ +JSON_HAS_PROPERTY_WITH_VALUE = """ + + + +""" + +JSON_HAS_PROPERTY_WITH_WITH = """ + + + +""" + VALID_XML = """ BAR @@ -227,6 +239,9 @@ VALID_XML = """ """ INVALID_XML = '' +VALID_SIMPLE_JSON = """{"foo": 5, "list": [{"textprop": "right"}]}""" + + if h5py is not None: with tempfile.NamedTemporaryFile(delete=False) as tmp: h5name = tmp.name @@ -693,6 +708,26 @@ TESTS = [ lambda x: "Text of element with path './/more': Did not expect text matching expression '(BA[RZ]|QUX)$' in output ('BAR')" in x, ), + ( + JSON_HAS_PROPERTY_WITH_VALUE.format(property="foo", value="5"), + VALID_SIMPLE_JSON, + lambda x: len(x) == 0, + ), + ( + JSON_HAS_PROPERTY_WITH_VALUE.format(property="foo", value="6"), + VALID_SIMPLE_JSON, + lambda x: "Failed to find property [foo] with JSON value [6]" in x, + ), + ( + JSON_HAS_PROPERTY_WITH_WITH.format(property="textprop", text="right"), + VALID_SIMPLE_JSON, + lambda x: len(x) == 0, + ), + ( + JSON_HAS_PROPERTY_WITH_WITH.format(property="textprop", text="wrong"), + VALID_SIMPLE_JSON, + lambda x: "Failed to find property [textprop] with text [wrong]" in x, + ), # test has_archive_member with zip ( ARCHIVE_HAS_ARCHIVE_MEMBER.format(path="(\\./)?testdir/file1.txt", content_assert="", all="false"), @@ -988,6 +1023,10 @@ TEST_IDS = [ "xml_element failure (due to n)", "xml_element failure (due to min/max in combination with negate)", "xml_element failure (due to subassertion)", + "has_json_property_with_value success", + "has_json_property_with_value failure", + "has_json_property_with_text success", + "has_json_property_with_text failure", "has_archive_member zip", "has_archive_member tar", "has_archive_member non-archive",