diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 384aa1e..65a2d61 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -61,7 +61,7 @@ repos: - '^release/(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)(?:-(?P(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$' - repo: https://github.com/octue/pre-commit-hooks - rev: 0.0.3 + rev: 0.5.0 hooks: - id: check-commit-message-is-conventional stages: [commit-msg] diff --git a/docs/source/anatomy_monitors.rst b/docs/source/anatomy_monitors.rst index 8704877..7d034b3 100644 --- a/docs/source/anatomy_monitors.rst +++ b/docs/source/anatomy_monitors.rst @@ -1,13 +1,11 @@ .. _monitors_strand: -=============== -Monitors Strand -=============== +====================== +Monitor Message Strand +====================== -The ``configuration_values_schema``, ``input_values_schema`` and ``output_values_schema`` strands are *values-based*, -meaning the data that matches these strands is in JSON form. - -Each of these strands is a *json schema* which describes that data. +The ``monitor_message_schema`` strand is *values-based* meaning the data that matches the strand is in JSON form. It is +a *json schema* which describes a monitor message. .. tabs:: @@ -40,5 +38,18 @@ Let's look at basic examples for twines containing each of these strands: **Monitor data (output)** - **Log data (output)** + .. code-block:: javascript + { + "monitor_message_schema": { + "type": "object", + "properties": { + "my_property": { + "type": "number" + } + }, + "required": ["my_property"] + } + } + + **Log data (output)** diff --git a/setup.py b/setup.py index 9bff06d..5fa88e3 100644 --- a/setup.py +++ b/setup.py @@ -16,7 +16,7 @@ setup( name="twined", - version="0.0.26", + version="0.1.0", py_modules=[], install_requires=["jsonschema ~= 3.2.0", "python-dotenv"], url="https://www.github.com/octue/twined", diff --git a/tests/test_monitors.py b/tests/test_monitors.py new file mode 100644 index 0000000..156d3cf --- /dev/null +++ b/tests/test_monitors.py @@ -0,0 +1,30 @@ +from twined import Twine, exceptions +from .base import BaseTestCase + + +class TestMonitorMessageTwine(BaseTestCase): + STRAND_WITH_MONITOR_MESSAGE_SCHEMA = """ + { + "monitor_message_schema": { + "type": "object", + "properties": { + "my_property": { + "type": "number" + } + }, + "required": ["my_property"] + } + } + """ + + def test_validate_monitor_message_raises_error_if_monitor_message_schema_not_met(self): + """Test that an error is raised if an invalid monitor update is validated.""" + twine = Twine(source=self.STRAND_WITH_MONITOR_MESSAGE_SCHEMA) + + with self.assertRaises(exceptions.InvalidValuesContents): + twine.validate_monitor_message([]) + + def test_validate_monitor_message_with_valid_monitor_update(self): + """Test that a valid monitor update validates successfully.""" + twine = Twine(source=self.STRAND_WITH_MONITOR_MESSAGE_SCHEMA) + twine.validate_monitor_message({"my_property": 3.7}) diff --git a/twined/exceptions.py b/twined/exceptions.py index fb03716..03a01c9 100644 --- a/twined/exceptions.py +++ b/twined/exceptions.py @@ -156,6 +156,7 @@ class UnexpectedNumberOfResults(TwineException): "configuration_values": InvalidValuesJson, "input_values": InvalidValuesJson, "output_values": InvalidValuesJson, + "monitor_message": InvalidValuesJson, "configuration_manifest": InvalidManifestJson, "input_manifest": InvalidManifestJson, "output_manifest": InvalidManifestJson, @@ -168,6 +169,7 @@ class UnexpectedNumberOfResults(TwineException): "configuration_values": InvalidValuesContents, "input_values": InvalidValuesContents, "output_values": InvalidValuesContents, + "monitor_message": InvalidValuesContents, "configuration_manifest": InvalidManifestContents, "input_manifest": InvalidManifestContents, "output_manifest": InvalidManifestContents, diff --git a/twined/twine.py b/twined/twine.py index 9ccb7e3..27d53a5 100644 --- a/twined/twine.py +++ b/twined/twine.py @@ -12,11 +12,7 @@ logger = logging.getLogger(__name__) -SCHEMA_STRANDS = ( - "input_values", - "configuration_values", - "output_values", -) +SCHEMA_STRANDS = ("input_values", "configuration_values", "output_values", "monitor_message") MANIFEST_STRANDS = ( "configuration_manifest", @@ -28,14 +24,11 @@ CHILDREN_STRANDS = ("children",) -MONITOR_STRANDS = ("monitors",) - ALL_STRANDS = ( *SCHEMA_STRANDS, *MANIFEST_STRANDS, *CREDENTIAL_STRANDS, *CHILDREN_STRANDS, - *MONITOR_STRANDS, ) @@ -119,6 +112,8 @@ def _get_schema(self, strand): else: if strand not in SCHEMA_STRANDS: raise exceptions.UnknownStrand(f"Unknown strand {strand}. Try one of {ALL_STRANDS}.") + + # Get schema from twine.json file. schema_key = strand + "_schema" try: @@ -318,6 +313,10 @@ def validate_output_values(self, source, **kwargs): """Validates that the output values, passed as either a file or a json string, are correct""" return self._validate_values("output_values", source, **kwargs) + def validate_monitor_message(self, source, **kwargs): + """Validate monitor message against the monitor message schema strand.""" + return self._validate_values(kind="monitor_message", source=source, **kwargs) + def validate_configuration_manifest(self, source, **kwargs): """Validates the input manifest, passed as either a file or a json string""" return self._validate_manifest("configuration_manifest", source, **kwargs)