Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

REF: Refactor tests #39

Merged
merged 9 commits into from
Nov 2, 2020
5 changes: 1 addition & 4 deletions tests/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,4 @@ class BaseTestCase(unittest.TestCase):
""" Base test case for twined:
- sets a path to the test data directory
"""

def setUp(self):
self.path = str(os.path.join(os.path.dirname(os.path.abspath(__file__)), "data", ""))
super().setUp()
path = os.path.join(os.path.dirname(__file__), "data")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well simplified path. The reason I used abspath and str sprang from refactoring twined out of the old Octue SDK where the CLI required absolute string paths. Assuming tests still pass, this is fine now.

I prefer to keep the setUp() pattern in general, because that sets path on the instance, not on the class. Any subclasses can therefore modify self.path without potential-weirdness affecting other tests running in parallel.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I'm aware, __file__ is an absolute path already and os.path.join always creates a string - let me know if this isn't the case!

Good point, I'll put it back in setUp 👍

13 changes: 0 additions & 13 deletions tests/data/children/extra_key.json

This file was deleted.

8 changes: 0 additions & 8 deletions tests/data/children/extra_property.json

This file was deleted.

7 changes: 0 additions & 7 deletions tests/data/children/invalid_env_name.json

This file was deleted.

7 changes: 0 additions & 7 deletions tests/data/children/valid.json

This file was deleted.

3 changes: 0 additions & 3 deletions tests/data/twines/invalid_children_dict_not_array_twine.json

This file was deleted.

9 changes: 0 additions & 9 deletions tests/data/twines/invalid_children_no_key_twine.json

This file was deleted.

10 changes: 0 additions & 10 deletions tests/data/twines/valid_children_twine.json

This file was deleted.

4 changes: 0 additions & 4 deletions tests/data/twines/valid_empty_children_twine.json

This file was deleted.

87 changes: 57 additions & 30 deletions tests/test_children.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,92 +13,119 @@ def test_invalid_children_dict_not_array(self):
""" Ensures InvalidTwine exceptions are raised when instantiating twines where `children` entry is incorrectly
specified as a dict, not an array
"""
twine_file = self.path + "twines/invalid_children_dict_not_array_twine.json"
with self.assertRaises(exceptions.InvalidTwine):
Twine(source=twine_file)
Twine(source={"children": {}})

def test_invalid_children_no_key(self):
""" Ensures InvalidTwine exceptions are raised when instantiating twines where a child
is specified without the required `key` field
"""
twine_file = self.path + "twines/invalid_children_no_key_twine.json"
source = {
"children": [{"purpose": "The purpose.", "notes": "Here are some notes.", "filters": "tags:gis"}]
}

with self.assertRaises(exceptions.InvalidTwine):
Twine(source=twine_file)
Twine(source=source)

def test_valid_children(self):
""" Ensures that a twine can be instantiated with correctly specified children
""" Ensures that a twine with one child can be instantiated correctly.
"""
twine_file = self.path + "twines/valid_children_twine.json"
twine = Twine(source=twine_file)
self.assertEqual(len(twine._raw["children"]), 1)
source = {
"children": [{"key": "gis", "purpose": "The purpose.", "notes": "Some notes.", "filters": "tags:gis"}]
}
thclark marked this conversation as resolved.
Show resolved Hide resolved

self.assertEqual(len(Twine(source=source)._raw["children"]), 1)

def test_empty_children(self):
""" Ensures that a twine file will validate with an empty list object as children
"""
twine_file = self.path + "twines/valid_empty_children_twine.json"
twine = Twine(source=twine_file)
twine = Twine(source={"children": []})
self.assertEqual(len(twine._raw["children"]), 0)


class TestChildrenValidation(BaseTestCase):
""" Tests related to whether validation of children occurs successfully (given a valid twine)
"""

VALID_TWINE_WITH_CHILDREN = {
"children": [{"key": "gis", "purpose": "The purpose", "notes": "Some notes.", "filters": "tags:gis"}]
}

VALID_CHILDREN_VALUE = [
{"key": "gis", "id": "some-id", "uri_env_name": "NAME_OF_SOME_ENV_VAR_THAT_CONTAINS_A_URI"}
]

def test_no_children(self):
""" Test that a twine with no children will validate on an empty children input
"""
twine = Twine() # Creates empty twine
twine.validate_children(source="[]")
Twine().validate_children(source=[])

def test_missing_children(self):
""" Test that a twine with children will not validate on an empty children input
"""
twine = Twine(source=self.path + "twines/valid_children_twine.json")
with self.assertRaises(exceptions.InvalidValuesContents):
twine.validate_children(source="[]")
Twine(source=self.VALID_TWINE_WITH_CHILDREN).validate_children(source=[])

def test_extra_children(self):
""" Test that a twine with no children will not validate a non-empty children input
"""
twine = Twine() # Creates empty twine
with self.assertRaises(exceptions.InvalidValuesContents):
twine.validate_children(source=self.path + "children/valid.json")
Twine().validate_children(source=self.VALID_CHILDREN_VALUE)

def test_extra_key(self):
""" Test that children with extra data will not raise validation error
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.
"""
twine = Twine() # Creates empty twine
children_values_with_extra_data = [
{"key": "gis", "id": "id", "uri_env_name": "VAR_NAME", "an_extra_key": "shouldn't be a problem if present"},
{"key": "some_weird_other_child", "id": "some-other-id", "uri_env_name": "SOME_ENV_VAR_NAME"}
]

with self.assertRaises(exceptions.InvalidValuesContents):
twine.validate_children(source=self.path + "children/extra_key.json")
Twine().validate_children(source=children_values_with_extra_data)

def test_extra_property(self):
""" Test that children with extra data will not raise validation error
def test_extra_key_validation_on_valid_twine(self):
""" Test that children with extra data will not raise a validation error on a non-empty valid twine.
# TODO review this behaviour - possibly should raise an error but allow for a user specified extra_data property
"""
twine = Twine(source=self.path + "twines/valid_children_twine.json")
twine.validate_children(source=self.path + "children/extra_property.json")
single_child_with_extra_data = [
{
"key": "gis",
"id": "some-id",
"uri_env_name": "SOME_ENV_VAR_NAME",
"some_extra_property": "should not be a problem if present"
}
]

twine = Twine(source=self.VALID_TWINE_WITH_CHILDREN)
twine.validate_children(source=single_child_with_extra_data)

def test_invalid_env_name(self):
""" Test that a child uri env name not in ALL_CAPS_SNAKE_CASE doesn't validate
"""
twine = Twine() # Creates empty twine
child_with_invalid_environment_variable_name = [
{
"key": "gis",
"id": "some-id",
"uri_env_name": "an environment variable which isn't in CAPS_CASE is invalid per the credentials spec"
}
]

with self.assertRaises(exceptions.InvalidValuesContents):
twine.validate_children(source=self.path + "children/invalid_env_name.json")
Twine().validate_children(source=child_with_invalid_environment_variable_name)

def test_invalid_json(self):
""" Tests that a children entry with invalid json will raise an error
"""
twine = Twine(source=self.path + "twines/valid_children_twine.json")
with self.assertRaises(exceptions.InvalidValuesJson):
twine.validate_children(source="[")
Twine(source=self.VALID_TWINE_WITH_CHILDREN).validate_children(source="[")

def test_valid(self):
""" Test that a valid twine will validate valid children
Valiantly and Validly validating validity since 1983.
To those reading this, know that YOU'RE valid.
"""
twine = Twine(source=self.path + "twines/valid_children_twine.json")
twine.validate_children(source=self.path + "children/valid.json")
twine = Twine(source=self.VALID_TWINE_WITH_CHILDREN)
twine.validate_children(source=self.VALID_CHILDREN_VALUE)


if __name__ == "__main__":
Expand Down
16 changes: 8 additions & 8 deletions tests/test_credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,28 @@ def test_fails_on_no_name(self):
""" Ensures InvalidTwine exceptions are raised when instantiating twines
with a missing `name` field in a credential
"""
twine_file = self.path + "twines/invalid_credentials_no_name_twine.json"
twine_file = os.path.join(self.path, "twines", "invalid_credentials_no_name_twine.json")
with self.assertRaises(exceptions.InvalidTwine):
Twine(source=twine_file)

def test_fails_on_lowercase_name(self):
""" Ensures InvalidTwine exceptions are raised when instantiating twines
with lowercase letters in the `name` field
"""
twine_file = self.path + "twines/invalid_credentials_lowercase_name_twine.json"
twine_file = os.path.join(self.path, "twines", "invalid_credentials_lowercase_name_twine.json")
with self.assertRaises(exceptions.InvalidTwine):
Twine(source=twine_file)

def test_fails_on_dict(self):
""" Ensures InvalidTwine exceptions are raised when instantiating twines
with invalid `credentials` entries (given as a dict, not an array)
"""
twine_file = self.path + "twines/invalid_credentials_dict_not_array_twine.json"
twine_file = os.path.join(self.path, "twines", "invalid_credentials_dict_not_array_twine.json")
with self.assertRaises(exceptions.InvalidTwine):
Twine(source=twine_file)

def test_fails_on_name_whitespace(self):
twine_file = self.path + "twines/invalid_credentials_space_in_name_twine.json"
twine_file = os.path.join(self.path, "twines", "invalid_credentials_space_in_name_twine.json")
with self.assertRaises(exceptions.InvalidTwine):
Twine(source=twine_file)

Expand All @@ -48,20 +48,20 @@ class TestCredentialsValidation(BaseTestCase):
def test_no_credentials(self):
""" Test that a twine with no credentials will validate straightforwardly
"""
twine = Twine(source=self.path + "twines/valid_schema_twine.json")
twine = Twine(source=os.path.join(self.path, "twines", "valid_schema_twine.json"))
twine.validate_credentials()

def test_missing_credentials(self):
""" Test that a twine with credentials will not validate where they are missing from the environment
"""
twine = Twine(source=self.path + "twines/valid_credentials_twine.json")
twine = Twine(source=os.path.join(self.path, "twines", "valid_credentials_twine.json"))
with self.assertRaises(exceptions.CredentialNotFound):
twine.validate_credentials()

def test_default_credentials(self):
""" Test that a twine with credentials will validate where ones with defaults are missing from the environment
"""
twine = Twine(source=self.path + "twines/valid_credentials_twine.json")
twine = Twine(source=os.path.join(self.path, "twines", "valid_credentials_twine.json"))
with mock.patch.dict(os.environ, {"SECRET_THE_FIRST": "a value", "SECRET_THE_SECOND": "another value"}):
credentials = twine.validate_credentials()

Expand All @@ -73,7 +73,7 @@ def test_default_credentials(self):
def test_nondefault_credentials(self):
""" Test that the environment will override a default value for a credential
"""
twine = Twine(source=self.path + "twines/valid_credentials_twine.json")
twine = Twine(source=os.path.join(self.path, "twines", "valid_credentials_twine.json"))
with mock.patch.dict(
os.environ,
{"SECRET_THE_FIRST": "a value", "SECRET_THE_SECOND": "another value", "SECRET_THE_THIRD": "nondefault"},
Expand Down
Loading