Skip validation for abstract documents & add unit tests.
This commit is contained in:
parent
cb29a3f0ba
commit
a0df0c459d
|
@ -13,17 +13,20 @@
|
|||
# limitations under the License.
|
||||
|
||||
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_schema_validation
|
||||
from deckhand import errors
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DocumentValidation(object):
|
||||
"""Class for document validation logic for YAML files.
|
||||
|
||||
This class is responsible for parsing, validating and retrieving secret
|
||||
values for values stored in the YAML file.
|
||||
This class is responsible for performing built-in validations on Documents.
|
||||
|
||||
:param data: YAML data that requires secrets to be validated, merged and
|
||||
consolidated.
|
||||
|
@ -45,6 +48,8 @@ class DocumentValidation(object):
|
|||
- `deckhand-document-schema-validation`
|
||||
- `deckhand-policy-validation`
|
||||
"""
|
||||
|
||||
# TODO: Use the correct validation based on the Document's schema.
|
||||
internal_validations = [
|
||||
{'version': 'v1', 'fqn': 'deckhand-document-schema-validation',
|
||||
'schema': default_schema_validation},
|
||||
|
@ -56,7 +61,7 @@ class DocumentValidation(object):
|
|||
|
||||
@property
|
||||
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
|
||||
if v['version'] == self.schema_version][0].schema
|
||||
|
||||
|
@ -64,11 +69,22 @@ class DocumentValidation(object):
|
|||
"""Pre-validate that the YAML file is correctly formatted."""
|
||||
self._validate_with_schema()
|
||||
|
||||
# TODO(fm577c): Query Deckhand API to validate "src" values.
|
||||
|
||||
def _validate_with_schema(self):
|
||||
# Validate the document using the schema defined by the document's
|
||||
# `schemaVersion` and `kind`.
|
||||
# Validate the document using the document's ``schema``. Only validate
|
||||
# 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:
|
||||
schema_version = self.data['schema'].split('/')[-1]
|
||||
doc_schema_version = self.SchemaVersion(schema_version)
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
|
||||
class DeckhandException(Exception):
|
||||
"""Base Nova Exception
|
||||
"""Base Deckhand Exception
|
||||
To correctly use this class, inherit from it and define
|
||||
a 'msg_fmt' property. That msg_fmt will get printf'd
|
||||
with the keyword arguments provided to the constructor.
|
||||
|
|
|
@ -17,6 +17,7 @@ import os
|
|||
import testtools
|
||||
import yaml
|
||||
|
||||
import mock
|
||||
import six
|
||||
|
||||
from deckhand.engine import document_validation
|
||||
|
@ -80,7 +81,6 @@ class TestDocumentValidation(testtools.TestCase):
|
|||
"is a required property.")
|
||||
invalid_data = [
|
||||
(self._corrupt_data('data'), 'data'),
|
||||
(self._corrupt_data('metadata'), 'metadata'),
|
||||
(self._corrupt_data('metadata.schema'), 'schema'),
|
||||
(self._corrupt_data('metadata.name'), 'name'),
|
||||
(self._corrupt_data('metadata.substitutions'), 'substitutions'),
|
||||
|
@ -92,3 +92,29 @@ class TestDocumentValidation(testtools.TestCase):
|
|||
with six.assertRaisesRegex(self, errors.InvalidFormat,
|
||||
expected_err % missing_key):
|
||||
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()
|
||||
|
|
|
@ -8,7 +8,7 @@ metadata:
|
|||
genesis: enabled
|
||||
master: enabled
|
||||
layeringDefinition:
|
||||
abstract: true
|
||||
abstract: false
|
||||
layer: region
|
||||
parentSelector:
|
||||
required_key_a: required_label_a
|
||||
|
|
Loading…
Reference in New Issue