blob: f82f707afbcb3bd6dbb41f8387004bc7f8a99e55 [file] [log] [blame]
Matthew Treinish9e26ca82016-02-23 11:43:20 -05001# Copyright 2015 Hewlett-Packard Development Company, L.P.
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14
15import functools
16import uuid
17
Jordan Pittier9aa23f32017-02-14 17:30:31 +010018import debtcollector.removals
Jordan Pittierc5665a62017-04-12 16:42:53 +020019from oslo_log import log as logging
Matthew Treinish9e26ca82016-02-23 11:43:20 -050020import six
21import testtools
22
Jordan Pittierc5665a62017-04-12 16:42:53 +020023LOG = logging.getLogger(__name__)
24
Matthew Treinish9e26ca82016-02-23 11:43:20 -050025
26def skip_because(*args, **kwargs):
27 """A decorator useful to skip tests hitting known bugs
28
29 @param bug: bug number causing the test to skip
30 @param condition: optional condition to be True for the skip to have place
31 """
32 def decorator(f):
33 @functools.wraps(f)
34 def wrapper(self, *func_args, **func_kwargs):
35 skip = False
36 if "condition" in kwargs:
37 if kwargs["condition"] is True:
38 skip = True
39 else:
40 skip = True
41 if "bug" in kwargs and skip is True:
42 if not kwargs['bug'].isdigit():
43 raise ValueError('bug must be a valid bug number')
44 msg = "Skipped until Bug: %s is resolved." % kwargs["bug"]
45 raise testtools.TestCase.skipException(msg)
46 return f(self, *func_args, **func_kwargs)
47 return wrapper
48 return decorator
49
50
Jordan Pittierc5665a62017-04-12 16:42:53 +020051def related_bug(bug, status_code=None):
52 """A decorator useful to know solutions from launchpad bug reports
53
54 @param bug: The launchpad bug number causing the test
55 @param status_code: The status code related to the bug report
56 """
57 def decorator(f):
58 @functools.wraps(f)
59 def wrapper(self, *func_args, **func_kwargs):
60 try:
61 return f(self, *func_args, **func_kwargs)
62 except Exception as exc:
63 exc_status_code = getattr(exc, 'status_code', None)
64 if status_code is None or status_code == exc_status_code:
65 LOG.error('Hints: This test was made for the bug %s. '
66 'The failure could be related to '
67 'https://launchpad.net/bugs/%s', bug, bug)
68 raise exc
69 return wrapper
70 return decorator
71
72
Matthew Treinish9e26ca82016-02-23 11:43:20 -050073def idempotent_id(id):
74 """Stub for metadata decorator"""
75 if not isinstance(id, six.string_types):
76 raise TypeError('Test idempotent_id must be string not %s'
77 '' % type(id).__name__)
78 uuid.UUID(id)
79
80 def decorator(f):
81 f = testtools.testcase.attr('id-%s' % id)(f)
82 if f.__doc__:
83 f.__doc__ = 'Test idempotent id: %s\n%s' % (id, f.__doc__)
84 else:
85 f.__doc__ = 'Test idempotent id: %s' % id
86 return f
87 return decorator
88
89
Jordan Pittier9aa23f32017-02-14 17:30:31 +010090@debtcollector.removals.remove(removal_version='Queen')
Matthew Treinish9e26ca82016-02-23 11:43:20 -050091class skip_unless_attr(object):
92 """Decorator to skip tests if a specified attr does not exists or False"""
93 def __init__(self, attr, msg=None):
94 self.attr = attr
95 self.message = msg or ("Test case attribute %s not found "
96 "or False") % attr
97
98 def __call__(self, func):
lkuchlanc5f48b82016-05-29 13:02:16 +030099 @functools.wraps(func)
Matthew Treinish9e26ca82016-02-23 11:43:20 -0500100 def _skipper(*args, **kw):
101 """Wrapped skipper function."""
102 testobj = args[0]
103 if not getattr(testobj, self.attr, False):
104 raise testtools.TestCase.skipException(self.message)
105 func(*args, **kw)
Matthew Treinish9e26ca82016-02-23 11:43:20 -0500106 return _skipper
Jordan Pittier3b46d272017-04-12 16:17:28 +0200107
108
109def attr(**kwargs):
110 """A decorator which applies the testtools attr decorator
111
112 This decorator applies the testtools.testcase.attr if it is in the list of
113 attributes to testtools we want to apply.
114 """
115
116 def decorator(f):
117 if 'type' in kwargs and isinstance(kwargs['type'], str):
118 f = testtools.testcase.attr(kwargs['type'])(f)
119 elif 'type' in kwargs and isinstance(kwargs['type'], list):
120 for attr in kwargs['type']:
121 f = testtools.testcase.attr(attr)(f)
122 return f
123
124 return decorator