Merge "Add validation of base exception type(s) in failure type"

This commit is contained in:
Jenkins
2015-12-15 00:40:56 +00:00
committed by Gerrit Code Review
2 changed files with 40 additions and 0 deletions

View File

@@ -168,6 +168,19 @@ class FailureObjectTestCase(test.TestCase):
f2 = failure.Failure.from_dict(d_f) f2 = failure.Failure.from_dict(d_f)
self.assertTrue(f.matches(f2)) self.assertTrue(f.matches(f2))
def test_bad_root_exception(self):
f = _captured_failure('Woot!')
d_f = f.to_dict()
d_f['exc_type_names'] = ['Junk']
self.assertRaises(exceptions.InvalidFormat,
failure.Failure.validate, d_f)
def test_valid_from_dict_to_dict_2(self):
f = _captured_failure('Woot!')
d_f = f.to_dict()
d_f['exc_type_names'] = ['RuntimeError', 'Exception', 'BaseException']
failure.Failure.validate(d_f)
def test_dont_catch_base_exception(self): def test_dont_catch_base_exception(self):
try: try:
raise SystemExit() raise SystemExit()

View File

@@ -14,6 +14,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import collections
import copy import copy
import os import os
import sys import sys
@@ -28,6 +29,7 @@ from taskflow.utils import iter_utils
from taskflow.utils import mixins from taskflow.utils import mixins
from taskflow.utils import schema_utils as su from taskflow.utils import schema_utils as su
_exception_message = encodeutils.exception_to_unicode _exception_message = encodeutils.exception_to_unicode
@@ -121,6 +123,13 @@ class Failure(mixins.StrMixin):
""" """
DICT_VERSION = 1 DICT_VERSION = 1
BASE_EXCEPTIONS = ('BaseException', 'Exception')
"""
Root exceptions of all other python exceptions.
See: https://docs.python.org/2/library/exceptions.html
"""
#: Expected failure schema (in json schema format). #: Expected failure schema (in json schema format).
SCHEMA = { SCHEMA = {
"$ref": "#/definitions/cause", "$ref": "#/definitions/cause",
@@ -206,11 +215,29 @@ class Failure(mixins.StrMixin):
@classmethod @classmethod
def validate(cls, data): def validate(cls, data):
"""Validate input data matches expected failure ``dict`` format."""
try: try:
su.schema_validate(data, cls.SCHEMA) su.schema_validate(data, cls.SCHEMA)
except su.ValidationError as e: except su.ValidationError as e:
raise exc.InvalidFormat("Failure data not of the" raise exc.InvalidFormat("Failure data not of the"
" expected format: %s" % (e.message), e) " expected format: %s" % (e.message), e)
else:
# Ensure that all 'exc_type_names' originate from one of
# BASE_EXCEPTIONS, because those are the root exceptions that
# python mandates/provides and anything else is invalid...
causes = collections.deque([data])
while causes:
cause = causes.popleft()
root_exc_type = cause['exc_type_names'][-1]
if root_exc_type not in cls.BASE_EXCEPTIONS:
raise exc.InvalidFormat(
"Failure data 'exc_type_names' must"
" have an initial exception type that is one"
" of %s types: '%s' is not one of those"
" types" % (cls.BASE_EXCEPTIONS, root_exc_type))
sub_causes = cause.get('causes')
if sub_causes:
causes.extend(sub_causes)
def _matches(self, other): def _matches(self, other):
if self is other: if self is other: