Skip validation for abstract documents & add unit tests.

This commit is contained in:
Felipe Monteiro 2017-07-24 17:16:20 +01:00
parent cb29a3f0ba
commit a0df0c459d
4 changed files with 52 additions and 10 deletions

View File

@ -13,17 +13,20 @@
# limitations under the License. # limitations under the License.
import jsonschema import jsonschema
from oslo_log import log as logging
import six
from deckhand.engine.schema.v1_0 import default_policy_validation from deckhand.engine.schema.v1_0 import default_policy_validation
from deckhand.engine.schema.v1_0 import default_schema_validation from deckhand.engine.schema.v1_0 import default_schema_validation
from deckhand import errors from deckhand import errors
LOG = logging.getLogger(__name__)
class DocumentValidation(object): class DocumentValidation(object):
"""Class for document validation logic for YAML files. """Class for document validation logic for YAML files.
This class is responsible for parsing, validating and retrieving secret This class is responsible for performing built-in validations on Documents.
values for values stored in the YAML file.
:param data: YAML data that requires secrets to be validated, merged and :param data: YAML data that requires secrets to be validated, merged and
consolidated. consolidated.
@ -45,6 +48,8 @@ class DocumentValidation(object):
- `deckhand-document-schema-validation` - `deckhand-document-schema-validation`
- `deckhand-policy-validation` - `deckhand-policy-validation`
""" """
# TODO: Use the correct validation based on the Document's schema.
internal_validations = [ internal_validations = [
{'version': 'v1', 'fqn': 'deckhand-document-schema-validation', {'version': 'v1', 'fqn': 'deckhand-document-schema-validation',
'schema': default_schema_validation}, 'schema': default_schema_validation},
@ -56,7 +61,7 @@ class DocumentValidation(object):
@property @property
def schema(self): def schema(self):
# TODO: return schema based on version and kind. # TODO: return schema based on Document's schema.
return [v['schema'] for v in self.internal_validations return [v['schema'] for v in self.internal_validations
if v['version'] == self.schema_version][0].schema if v['version'] == self.schema_version][0].schema
@ -64,11 +69,22 @@ class DocumentValidation(object):
"""Pre-validate that the YAML file is correctly formatted.""" """Pre-validate that the YAML file is correctly formatted."""
self._validate_with_schema() self._validate_with_schema()
# TODO(fm577c): Query Deckhand API to validate "src" values.
def _validate_with_schema(self): def _validate_with_schema(self):
# Validate the document using the schema defined by the document's # Validate the document using the document's ``schema``. Only validate
# `schemaVersion` and `kind`. # concrete documents.
try:
abstract = self.data['metadata']['layeringDefinition'][
'abstract']
is_abstract = six.text_type(abstract).lower() == 'true'
except KeyError as e:
raise errors.InvalidFormat(
"Could not find 'abstract' property from document.")
if is_abstract:
LOG.info(
"Skipping validation for the document because it is abstract")
return
try: try:
schema_version = self.data['schema'].split('/')[-1] schema_version = self.data['schema'].split('/')[-1]
doc_schema_version = self.SchemaVersion(schema_version) doc_schema_version = self.SchemaVersion(schema_version)

View File

@ -14,7 +14,7 @@
class DeckhandException(Exception): class DeckhandException(Exception):
"""Base Nova Exception """Base Deckhand Exception
To correctly use this class, inherit from it and define To correctly use this class, inherit from it and define
a 'msg_fmt' property. That msg_fmt will get printf'd a 'msg_fmt' property. That msg_fmt will get printf'd
with the keyword arguments provided to the constructor. with the keyword arguments provided to the constructor.

View File

@ -17,6 +17,7 @@ import os
import testtools import testtools
import yaml import yaml
import mock
import six import six
from deckhand.engine import document_validation from deckhand.engine import document_validation
@ -80,7 +81,6 @@ class TestDocumentValidation(testtools.TestCase):
"is a required property.") "is a required property.")
invalid_data = [ invalid_data = [
(self._corrupt_data('data'), 'data'), (self._corrupt_data('data'), 'data'),
(self._corrupt_data('metadata'), 'metadata'),
(self._corrupt_data('metadata.schema'), 'schema'), (self._corrupt_data('metadata.schema'), 'schema'),
(self._corrupt_data('metadata.name'), 'name'), (self._corrupt_data('metadata.name'), 'name'),
(self._corrupt_data('metadata.substitutions'), 'substitutions'), (self._corrupt_data('metadata.substitutions'), 'substitutions'),
@ -92,3 +92,29 @@ class TestDocumentValidation(testtools.TestCase):
with six.assertRaisesRegex(self, errors.InvalidFormat, with six.assertRaisesRegex(self, errors.InvalidFormat,
expected_err % missing_key): expected_err % missing_key):
document_validation.DocumentValidation(invalid_entry) document_validation.DocumentValidation(invalid_entry)
def test_initialization_missing_abstract_section(self):
expected_err = ("Could not find 'abstract' property from document.")
invalid_data = [
self._corrupt_data('metadata'),
self._corrupt_data('metadata.layeringDefinition'),
self._corrupt_data('metadata.layeringDefinition.abstract'),
]
for invalid_entry in invalid_data:
with six.assertRaisesRegex(self, errors.InvalidFormat,
expected_err):
document_validation.DocumentValidation(invalid_entry)
@mock.patch.object(document_validation, 'LOG', autospec=True)
def test_initialization_with_abstract_document(self, mock_log):
abstract_data = copy.deepcopy(self.data)
for true_val in (True, 'true', 'True'):
abstract_data['metadata']['layeringDefinition']['abstract'] = True
document_validation.DocumentValidation(abstract_data)
mock_log.info.assert_called_once_with(
"Skipping validation for the document because it is abstract")
mock_log.info.reset_mock()

View File

@ -8,7 +8,7 @@ metadata:
genesis: enabled genesis: enabled
master: enabled master: enabled
layeringDefinition: layeringDefinition:
abstract: true abstract: false
layer: region layer: region
parentSelector: parentSelector:
required_key_a: required_label_a required_key_a: required_label_a