vmware-nsx/neutron/tests/unit/test_post_mortem_debug.py
Maru Newby 2c6bb6e8d7 Add post-mortem debug option for tests
Post-mortem debugging, the ability to drop into a debugger with the
execution state that triggered the exception, is very useful in
diagnosing failure conditions.  Our previous test runner, nose,
provided the ability to enable post-mortem debugging on test
failures (via --pdb-failure) and errors (via --pdb).  testr
lacks these options at present, so this change adds support
for enabling post-mortem debugging via an environment variable.
All test-triggered exceptions will result in a post-mortem debugger
being invoked if OS_POST_MORTEM_DEBUG is set to "1" or "True".

Implements: blueprint neutron-pm-debug-on-test-failure
Change-Id: Iddbe1335b059d062c0286df2ad27aef7728461b7
2013-12-10 03:56:50 +00:00

99 lines
3.2 KiB
Python

# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 Red Hat, Inc.
# All 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 sys
import mock
from neutron.tests import base
from neutron.tests import post_mortem_debug
class TestTesttoolsExceptionHandler(base.BaseTestCase):
def test_exception_handler(self):
try:
self.assertTrue(False)
except Exception:
exc_info = sys.exc_info()
with mock.patch('traceback.print_exception') as mock_print_exception:
with mock.patch('pdb.post_mortem') as mock_post_mortem:
with mock.patch.object(post_mortem_debug,
'get_ignored_traceback',
return_value=mock.Mock()):
post_mortem_debug.exception_handler(exc_info)
mock_print_exception.called_once_with(*exc_info)
mock_post_mortem.called_once()
class TestFilteredTraceback(base.BaseTestCase):
def test_filter_traceback(self):
tb1 = mock.Mock()
tb2 = mock.Mock()
tb1.tb_next = tb2
tb2.tb_next = None
ftb1 = post_mortem_debug.FilteredTraceback(tb1, tb2)
for attr in ['lasti', 'lineno', 'frame']:
attr_name = 'tb_%s' % attr
self.assertEqual(getattr(tb1, attr_name, None),
getattr(ftb1, attr_name, None))
self.assertIsNone(ftb1.tb_next)
class TestGetIgnoredTraceback(base.BaseTestCase):
def _test_get_ignored_traceback(self, ignored_bit_array, expected):
root_tb = mock.Mock()
tb = root_tb
tracebacks = [tb]
for x in xrange(len(ignored_bit_array) - 1):
tb.tb_next = mock.Mock()
tb = tb.tb_next
tracebacks.append(tb)
tb.tb_next = None
tb = root_tb
for ignored in ignored_bit_array:
if ignored:
tb.tb_frame.f_globals = ['__unittest']
else:
tb.tb_frame.f_globals = []
tb = tb.tb_next
actual = post_mortem_debug.get_ignored_traceback(root_tb)
if expected is not None:
expected = tracebacks[expected]
self.assertEqual(actual, expected)
def test_no_ignored_tracebacks(self):
self._test_get_ignored_traceback([0, 0, 0], None)
def test_single_member_trailing_chain(self):
self._test_get_ignored_traceback([0, 0, 1], 2)
def test_two_member_trailing_chain(self):
self._test_get_ignored_traceback([0, 1, 1], 1)
def test_first_traceback_ignored(self):
self._test_get_ignored_traceback([1, 0, 0], None)
def test_middle_traceback_ignored(self):
self._test_get_ignored_traceback([0, 1, 0], None)