deckhand/deckhand/tests/unit/control/test_errors.py

234 lines
8.4 KiB
Python

# Copyright 2017 AT&T Intellectual Property. All other rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import yaml
import falcon
import mock
from deckhand.common import document as document_wrapper
from deckhand import policy
from deckhand.tests.unit.control import base as test_base
class TestErrorFormatting(test_base.BaseControllerTest):
"""Test suite for validating error formatting."""
def test_python_exception_formatting(self):
"""Verify formatting for an exception class that inherits from
:class:`Exception`.
"""
with mock.patch.object(
policy, '_do_enforce_rbac',
spec_set=policy._do_enforce_rbac) as m_enforce_rbac:
m_enforce_rbac.side_effect = Exception('test error')
resp = self.app.simulate_put(
'/api/v1.0/buckets/test/documents',
headers={'Content-Type': 'application/x-yaml'}, body=None)
expected = {
'status': 'Failure',
'kind': 'Status',
'code': '500 Internal Server Error',
'apiVersion': 'v1.0',
'reason': 'Unspecified',
'retry': True,
'details': {
'errorType': 'Exception',
'errorCount': 1,
'messageList': [
{
'message': 'Unhandled Exception raised: test error',
'error': True
}
]
},
'message': 'Unhandled Exception raised: test error',
'metadata': {}
}
body = yaml.load(resp.text)
self.assertEqual(500, resp.status_code)
self.assertEqual(expected, body)
def test_falcon_exception_formatting(self):
"""Verify formatting for an exception class that inherits from
:class:`falcon.HTTPError`.
"""
expected_msg = (
'deckhand:create_cleartext_documents is disallowed by policy')
with mock.patch.object(
policy, '_do_enforce_rbac',
spec_set=policy._do_enforce_rbac) as m_enforce_rbac:
m_enforce_rbac.side_effect = falcon.HTTPForbidden(
description=expected_msg)
resp = self.app.simulate_put(
'/api/v1.0/buckets/test/documents',
headers={'Content-Type': 'application/x-yaml'}, body=None)
expected = {
'status': 'Failure',
'kind': 'Status',
'code': '403 Forbidden',
'apiVersion': 'v1.0',
'reason': 'Unspecified',
'retry': False,
'details': {
'errorType': 'HTTPForbidden',
'errorCount': 1,
'messageList': [
{
'message': expected_msg,
'error': True
}
]
},
'message': expected_msg,
'metadata': {}
}
body = yaml.safe_load(resp.text)
self.assertEqual(403, resp.status_code)
self.assertEqual(expected, body)
class TestValidationMessageFormatting(test_base.BaseControllerTest):
"""Test suite for validating :class:`ValidationMessage` formatting."""
def test_put_bucket_validation_message_formatting(self):
"""Verify formatting for pre-validation during updating a bucket."""
rules = {'deckhand:create_cleartext_documents': '@'}
self.policy.set_rules(rules)
resp = self.app.simulate_put(
'/api/v1.0/buckets/test/documents',
headers={'Content-Type': 'application/x-yaml'},
body='foo: bar')
expected = {
'status': 'Failure',
'kind': 'Status',
'code': '400 Bad Request',
'apiVersion': 'v1.0',
'reason': 'Validation',
'retry': False,
'details': {
'errorType': 'InvalidDocumentFormat',
'errorCount': 2,
'messageList': [
{
'diagnostic': mock.ANY,
'documents': [{
'layer': '',
'name': '',
'schema': ''
}],
'error': True,
'kind': 'ValidationMessage',
'level': 'Error',
'message': mock.ANY,
# Indicates sanity-check failure pre-rendering.
'name': 'D001'
},
{
'diagnostic': mock.ANY,
'documents': [{
'layer': '',
'name': '',
'schema': ''
}],
'error': True,
'kind': 'ValidationMessage',
'level': 'Error',
'message': mock.ANY,
'name': 'D001'
}
]
},
'message': 'The provided documents failed schema validation',
'metadata': {}
}
body = yaml.safe_load(resp.text)
self.assertEqual(400, resp.status_code)
self.assertEqual(expected, body)
def test_rendered_documents_validation_message_formatting(self):
"""Verify formatting for post-validation during rendering revision
documents.
"""
rules = {'deckhand:create_cleartext_documents': '@',
'deckhand:list_cleartext_documents': '@',
'deckhand:list_encrypted_documents': '@'}
self.policy.set_rules(rules)
yaml_file = os.path.join(os.getcwd(), 'deckhand', 'tests', 'unit',
'resources', 'sample_layering_policy.yaml')
with open(yaml_file) as yaml_stream:
payload = yaml_stream.read()
resp = self.app.simulate_put(
'/api/v1.0/buckets/test/documents',
headers={'Content-Type': 'application/x-yaml'},
body=payload)
with mock.patch('deckhand.control.revision_documents.common'
'.get_rendered_docs', autospec=True) \
as mock_get_rendered_docs:
invalid_document = document_wrapper.DocumentDict(
yaml.safe_load(payload))
invalid_document.pop('metadata')
mock_get_rendered_docs.return_value = ([invalid_document], False)
resp = self.app.simulate_get(
'/api/v1.0/revisions/1/rendered-documents',
headers={'Content-Type': 'application/x-yaml'})
expected = {
'status': 'Failure',
'kind': 'Status',
'code': '500 Internal Server Error',
'apiVersion': 'v1.0',
'reason': 'Validation',
'retry': True,
'details': {
'errorType': 'InvalidDocumentFormat',
'errorCount': 1,
'messageList': [
{
'diagnostic': mock.ANY,
'documents': [{
'layer': '',
'name': '',
'schema': invalid_document['schema']
}],
'error': True,
'kind': 'ValidationMessage',
'level': 'Error',
'message': mock.ANY,
# Indicates sanity-check failure post-rendering.
'name': 'D001'
}
]
},
'message': 'The provided documents failed schema validation',
'metadata': {}
}
body = yaml.safe_load(resp.text)
self.assertEqual(500, resp.status_code)
self.assertEqual(expected, body)