Move the related_bug
decorator from test.py to tempest/lib
I think it's a good idea to move all utility decorators into tempest/lib/decorators.py. This patch does that for the `related_bug` decorator. Change-Id: I846d575e41f4dddfd5642b7750e988f75a717e7d
This commit is contained in:
parent
0d93900ba6
commit
c5665a6cc7
@ -0,0 +1,6 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
A new ``related_bug`` decorator has been added to
|
||||
``tempest.lib.decorators``. Use it to decorate and tag a test that was
|
||||
added in relation to a launchpad bug report.
|
@ -18,7 +18,6 @@ from tempest.common import fixed_network
|
||||
from tempest.common import waiters
|
||||
from tempest.lib.common.utils import data_utils
|
||||
from tempest.lib import decorators
|
||||
from tempest import test
|
||||
|
||||
|
||||
class ServersAdminTestJSON(base.BaseV2ComputeAdminTest):
|
||||
@ -93,7 +92,7 @@ class ServersAdminTestJSON(base.BaseV2ComputeAdminTest):
|
||||
self.assertIn(self.s1_name, servers_name)
|
||||
self.assertIn(self.s2_name, servers_name)
|
||||
|
||||
@test.related_bug('1659811')
|
||||
@decorators.related_bug('1659811')
|
||||
@decorators.idempotent_id('7e5d6b8f-454a-4ba1-8ae2-da857af8338b')
|
||||
def test_list_servers_by_admin_with_specified_tenant(self):
|
||||
# In nova v2, tenant_id is ignored unless all_tenants is specified
|
||||
|
@ -46,7 +46,7 @@ class VolumesAdminNegativeTest(base.BaseV2ComputeAdminTest):
|
||||
self.server['id'], nonexistent_volume,
|
||||
volumeId=volume['id'])
|
||||
|
||||
@test.related_bug('1629110', status_code=400)
|
||||
@decorators.related_bug('1629110', status_code=400)
|
||||
@test.attr(type=['negative'])
|
||||
@decorators.idempotent_id('7dcac15a-b107-46d3-a5f6-cb863f4e454a')
|
||||
def test_update_attached_volume_with_nonexistent_volume_in_body(self):
|
||||
|
@ -178,7 +178,7 @@ class ServersNegativeTestJSON(base.BaseV2ComputeTest):
|
||||
self.client.rebuild_server,
|
||||
server['id'], self.image_ref)
|
||||
|
||||
@test.related_bug('1660878', status_code=409)
|
||||
@decorators.related_bug('1660878', status_code=409)
|
||||
@test.attr(type=['negative'])
|
||||
@decorators.idempotent_id('581a397d-5eab-486f-9cf9-1014bbd4c984')
|
||||
def test_reboot_deleted_server(self):
|
||||
@ -219,7 +219,7 @@ class ServersNegativeTestJSON(base.BaseV2ComputeTest):
|
||||
name=server_name)
|
||||
|
||||
@test.attr(type=['negative'])
|
||||
@test.related_bug('1651064', status_code=500)
|
||||
@decorators.related_bug('1651064', status_code=500)
|
||||
@decorators.idempotent_id('12146ac1-d7df-4928-ad25-b1f99e5286cd')
|
||||
def test_create_server_invalid_bdm_in_2nd_dict(self):
|
||||
volume = self.create_volume()
|
||||
|
@ -31,7 +31,7 @@ class AttachVolumeNegativeTest(base.BaseV2ComputeTest):
|
||||
raise cls.skipException(skip_msg)
|
||||
|
||||
@test.attr(type=['negative'])
|
||||
@test.related_bug('1630783', status_code=500)
|
||||
@decorators.related_bug('1630783', status_code=500)
|
||||
@decorators.idempotent_id('a313b5cd-fbd0-49cc-94de-870e99f763c7')
|
||||
def test_delete_attached_volume(self):
|
||||
server = self.create_test_server(wait_until='ACTIVE')
|
||||
|
@ -16,9 +16,12 @@ import functools
|
||||
import uuid
|
||||
|
||||
import debtcollector.removals
|
||||
from oslo_log import log as logging
|
||||
import six
|
||||
import testtools
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def skip_because(*args, **kwargs):
|
||||
"""A decorator useful to skip tests hitting known bugs
|
||||
@ -45,6 +48,28 @@ def skip_because(*args, **kwargs):
|
||||
return decorator
|
||||
|
||||
|
||||
def related_bug(bug, status_code=None):
|
||||
"""A decorator useful to know solutions from launchpad bug reports
|
||||
|
||||
@param bug: The launchpad bug number causing the test
|
||||
@param status_code: The status code related to the bug report
|
||||
"""
|
||||
def decorator(f):
|
||||
@functools.wraps(f)
|
||||
def wrapper(self, *func_args, **func_kwargs):
|
||||
try:
|
||||
return f(self, *func_args, **func_kwargs)
|
||||
except Exception as exc:
|
||||
exc_status_code = getattr(exc, 'status_code', None)
|
||||
if status_code is None or status_code == exc_status_code:
|
||||
LOG.error('Hints: This test was made for the bug %s. '
|
||||
'The failure could be related to '
|
||||
'https://launchpad.net/bugs/%s', bug, bug)
|
||||
raise exc
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
|
||||
def idempotent_id(id):
|
||||
"""Stub for metadata decorator"""
|
||||
if not isinstance(id, six.string_types):
|
||||
|
@ -45,6 +45,11 @@ idempotent_id = debtcollector.moves.moved_function(
|
||||
version='Mitaka', removal_version='?')
|
||||
|
||||
|
||||
related_bug = debtcollector.moves.moved_function(
|
||||
decorators.related_bug, 'related_bug', __name__,
|
||||
version='Pike', removal_version='?')
|
||||
|
||||
|
||||
def attr(**kwargs):
|
||||
"""A decorator which applies the testtools attr decorator
|
||||
|
||||
@ -143,28 +148,6 @@ def is_extension_enabled(extension_name, service):
|
||||
return False
|
||||
|
||||
|
||||
def related_bug(bug, status_code=None):
|
||||
"""A decorator useful to know solutions from launchpad bug reports
|
||||
|
||||
@param bug: The launchpad bug number causing the test
|
||||
@param status_code: The status code related to the bug report
|
||||
"""
|
||||
def decorator(f):
|
||||
@functools.wraps(f)
|
||||
def wrapper(self, *func_args, **func_kwargs):
|
||||
try:
|
||||
return f(self, *func_args, **func_kwargs)
|
||||
except Exception as exc:
|
||||
exc_status_code = getattr(exc, 'status_code', None)
|
||||
if status_code is None or status_code == exc_status_code:
|
||||
LOG.error('Hints: This test was made for the bug %s. '
|
||||
'The failure could be related to '
|
||||
'https://launchpad.net/bugs/%s', bug, bug)
|
||||
raise exc
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
|
||||
def is_scheduler_filter_enabled(filter_name):
|
||||
"""Check the list of enabled compute scheduler filters from config.
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import mock
|
||||
import testtools
|
||||
|
||||
from tempest.lib import base as test
|
||||
@ -123,3 +124,33 @@ class TestSkipUnlessAttrDecorator(base.TestCase):
|
||||
|
||||
def test_no_skip_for_attr_exist_and_true(self):
|
||||
self._test_skip_unless_attr('expected_attr', expected_to_skip=False)
|
||||
|
||||
|
||||
class TestRelatedBugDecorator(base.TestCase):
|
||||
def test_relatedbug_when_no_exception(self):
|
||||
f = mock.Mock()
|
||||
sentinel = object()
|
||||
|
||||
@decorators.related_bug(bug="1234", status_code=500)
|
||||
def test_foo(self):
|
||||
f(self)
|
||||
|
||||
test_foo(sentinel)
|
||||
f.assert_called_once_with(sentinel)
|
||||
|
||||
def test_relatedbug_when_exception(self):
|
||||
class MyException(Exception):
|
||||
def __init__(self, status_code):
|
||||
self.status_code = status_code
|
||||
|
||||
def f(self):
|
||||
raise MyException(status_code=500)
|
||||
|
||||
@decorators.related_bug(bug="1234", status_code=500)
|
||||
def test_foo(self):
|
||||
f(self)
|
||||
|
||||
with mock.patch.object(decorators.LOG, 'error') as m_error:
|
||||
self.assertRaises(MyException, test_foo, object())
|
||||
|
||||
m_error.assert_called_once_with(mock.ANY, '1234', '1234')
|
||||
|
Loading…
Reference in New Issue
Block a user