Handle string types for InstanceActionEvent exc_tb serialization

Commit 59a6cf233b added code to handle
serializing non-str exception traceback objects, but didn't account for
unicode.  This change uses six.string_types to handle str and unicode
objects for the exc_tb argument.

Adds a new unit test for the unicode case and firms up two existing
tests for how traceback.format_tb is mocked (or shouldn't be in the case
of exc_tb being a str).

Closes-Bug: #1327476

Change-Id: Icc10b62a3f65610c50e86c0b366c2b70b1a0932d
This commit is contained in:
Matt Riedemann
2014-06-10 08:07:03 -07:00
parent 99d6dfcc0c
commit 8f8b6e656a
2 changed files with 27 additions and 2 deletions

View File

@@ -14,6 +14,8 @@
import traceback
import six
from nova import db
from nova.objects import base
from nova.objects import fields
@@ -115,7 +117,7 @@ def serialize_args(fn):
exc_tb = kwargs.get('exc_tb')
if exc_val is not None:
kwargs['exc_val'] = str(exc_val)
if not isinstance(exc_tb, str) and exc_tb is not None:
if not isinstance(exc_tb, six.string_types) and exc_tb is not None:
kwargs['exc_tb'] = ''.join(traceback.format_tb(exc_tb))
# NOTE(danms): We wrap a descriptor, so use that protocol
return fn.__get__(None, cls)(*args, **kwargs)

View File

@@ -267,6 +267,7 @@ class _TestInstanceActionEventObject(object):
@mock.patch.object(traceback, 'format_tb')
@mock.patch.object(db, 'action_event_finish')
def test_event_finish_with_failure_legacy(self, mock_finish, mock_tb):
# Tests that exc_tb is serialized when it's not a string type.
mock_tb.return_value = 'fake-tb'
timeutils.set_time_override(override_time=NOW)
test_class = instance_action.InstanceActionEvent
@@ -275,9 +276,28 @@ class _TestInstanceActionEventObject(object):
expected_packed_values['finish_time'] = timeutils.utcnow()
mock_finish.return_value = fake_event
fake_tb = mock.sentinel.fake_tb
event = test_class.event_finish_with_failure(
self.context, 'fake-uuid', 'fake-event', exc_val='val',
exc_tb=mock.sentinel.fake_tb, want_result=True)
exc_tb=fake_tb, want_result=True)
mock_finish.assert_called_once_with(self.context,
expected_packed_values)
self.compare_obj(event, fake_event)
mock_tb.assert_called_once_with(fake_tb)
@mock.patch.object(db, 'action_event_finish')
def test_event_finish_with_failure_legacy_unicode(self, mock_finish):
# Tests that traceback.format_tb is not called when exc_tb is unicode.
timeutils.set_time_override(override_time=NOW)
test_class = instance_action.InstanceActionEvent
expected_packed_values = test_class.pack_action_event_finish(
self.context, 'fake-uuid', 'fake-event', 'val', unicode('fake-tb'))
expected_packed_values['finish_time'] = timeutils.utcnow()
mock_finish.return_value = fake_event
event = test_class.event_finish_with_failure(
self.context, 'fake-uuid', 'fake-event', exc_val='val',
exc_tb=unicode('fake-tb'), want_result=True)
mock_finish.assert_called_once_with(self.context,
expected_packed_values)
self.compare_obj(event, fake_event)
@@ -285,6 +305,8 @@ class _TestInstanceActionEventObject(object):
@mock.patch.object(traceback, 'format_tb')
@mock.patch.object(db, 'action_event_finish')
def test_event_finish_with_failure_no_result(self, mock_finish, mock_tb):
# Tests that traceback.format_tb is not called when exc_tb is a str
# and want_result is False, so no event should come back.
mock_tb.return_value = 'fake-tb'
timeutils.set_time_override(override_time=NOW)
test_class = instance_action.InstanceActionEvent
@@ -299,6 +321,7 @@ class _TestInstanceActionEventObject(object):
mock_finish.assert_called_once_with(self.context,
expected_packed_values)
self.assertIsNone(event)
self.assertFalse(mock_tb.called)
@mock.patch.object(db, 'action_events_get')
def test_get_by_action(self, mock_get):