Skip to content

Commit

Permalink
Merge pull request #64 from octue/fix/fix-child-validation-and-missin…
Browse files Browse the repository at this point in the history
…g-strand-validation

Fix child validation and missing strand data validation, and add backend field to children schema
  • Loading branch information
cortadocodes authored Jan 26, 2021
2 parents ba5fee2 + 536dee5 commit b46f76d
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 16 deletions.
27 changes: 23 additions & 4 deletions tests/test_children.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ def test_valid_children(self):
"children": [{"key": "gis", "purpose": "The purpose.", "notes": "Some notes.", "filters": "tags:gis"}]
}
"""
self.assertEqual(len(Twine(source=source)._children), 1)
self.assertEqual(len(Twine(source=source).children), 1)

def test_empty_children(self):
""" Ensures that a twine file will validate with an empty list object as children
"""
twine = Twine(source="""{"children": []}""")
self.assertEqual(len(twine._children), 0)
self.assertEqual(len(twine.children), 0)


class TestChildrenValidation(BaseTestCase):
Expand All @@ -58,7 +58,15 @@ class TestChildrenValidation(BaseTestCase):

VALID_CHILD_VALUE = """
[
{"key": "gis", "id": "some-id", "uri_env_name": "NAME_OF_SOME_ENV_VAR_THAT_CONTAINS_A_URI"}
{
"key": "gis",
"id": "some-id",
"backend": {
"name": "GCPPubSubBackend",
"project_name": "my-project",
"credentials_filename": "hello.json"
}
}
]
"""

Expand All @@ -79,6 +87,13 @@ def test_extra_children(self):
with self.assertRaises(exceptions.InvalidValuesContents):
Twine().validate_children(source=self.VALID_CHILD_VALUE)

def test_backend_cannot_be_empty(self):
""" Test that the backend field of a child cannot be empty. """
single_child_missing_backend = """[{"key": "gis", "id": "some-id", "backend": {}}]"""

with self.assertRaises(exceptions.InvalidValuesContents):
Twine().validate_children(source=single_child_missing_backend)

def test_extra_key_validation_on_empty_twine(self):
""" Test that children with extra data will not raise a validation error on an empty twine.
"""
Expand All @@ -101,7 +116,11 @@ def test_extra_key_validation_on_valid_twine(self):
{
"key": "gis",
"id": "some-id",
"uri_env_name": "SOME_ENV_VAR_NAME",
"backend": {
"name": "GCPPubSubBackend",
"project_name": "my-project",
"credentials_filename": "hello.json"
},
"some_extra_property": "should not be a problem if present"
}
]
Expand Down
33 changes: 27 additions & 6 deletions twined/schema/children_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,36 @@
"type": "string"
},
"id": {
"description": "The universally unique ID of the running child twin",
"description": "The universally unique ID (UUID) of the running child twin",
"type": "string"
},
"uri_env_name": {
"description": "Name of the environment variable containing the URI of the twin (which may contain credentials)",
"type": "string",
"pattern": "^[A-Z]+(?:_[A-Z]+)*$"
"backend": {
"description": "The backend running the child.",
"type": "object",
"oneOf": [
{
"type": "object",
"title": "GCP Pub/Sub",
"properties": {
"name": {
"description": "Type of backend (in this case, it can only be GCPPubSubBackend)",
"type": "string",
"pattern": "^(GCPPubSubBackend)$"
},
"project_name": {
"description": "Name of the Google Cloud Platform (GCP) project the child exists in.",
"type": "string"
},
"credentials_filename": {
"description": "Absolute path to Google Cloud Platform credentials JSON file.",
"type": "string"
}
},
"required": ["name", "project_name", "credentials_filename"]
}
]
}
},
"required": ["key", "id", "uri_env_name"]
"required": ["key", "id", "backend"]
}
}
12 changes: 6 additions & 6 deletions twined/twine.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def __init__(self, **kwargs):
""" Constructor for the twine class
"""
for name, strand in self._load_twine(**kwargs).items():
setattr(self, "_" + name, strand)
setattr(self, name, strand)

self._available_strands = tuple(trim_suffix(name, "_schema") for name in vars(self))

Expand Down Expand Up @@ -119,7 +119,7 @@ def _validate_against_schema(self, strand, data):
else:
if strand not in SCHEMA_STRANDS:
raise exceptions.UnknownStrand(f"Unknown strand {strand}. Try one of {ALL_STRANDS}.")
schema_key = "_" + strand + "_schema"
schema_key = strand + "_schema"
try:
schema = getattr(self, schema_key)
except AttributeError:
Expand Down Expand Up @@ -178,14 +178,14 @@ def available_strands(self):
"""
return self._available_strands

def validate_children(self, **kwargs):
def validate_children(self, source, **kwargs):
""" Validates that the children values, passed as either a file or a json string, are correct
"""
# TODO cache this loaded data keyed on a hashed version of kwargs
children = self._load_json("children", **kwargs)
children = self._load_json("children", source, **kwargs)
self._validate_against_schema("children", children)

strand = getattr(self, "_children", [])
strand = getattr(self, "children", [])

# Loop the children and accumulate values so we have an O(1) check
children_keys = {}
Expand Down Expand Up @@ -249,7 +249,7 @@ def validate_credentials(self, dotenv_path=None):

# Loop through the required credentials to check for presence of each
credentials = {}
for credential in getattr(self, "_credentials", []):
for credential in getattr(self, "credentials", []):
name = credential["name"]
default = credential.get("default", None)
credentials[name] = os.environ.get(name, default)
Expand Down

0 comments on commit b46f76d

Please sign in to comment.