setup_teardown: move to core anc cover by unit tests
setup_teardown: moved to core and covered by unit tests due to it's decorator: deprecation possibilities was limitted and prefferd to wait, until whole decorators will be moved. Blueprint: fuel-qa-join-helpers Change-Id: I0cd13e6695525c021e5a2096b50a5e6f1ea5e88e
This commit is contained in:
parent
3cd72bb60b
commit
73de714b78
240
core/_tests/helpers/test_setup_teardown.py
Normal file
240
core/_tests/helpers/test_setup_teardown.py
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from mock import call
|
||||||
|
from mock import patch
|
||||||
|
|
||||||
|
from core.helpers import setup_teardown
|
||||||
|
|
||||||
|
|
||||||
|
# Get helpers names (python will try to mangle it inside classes)
|
||||||
|
get_arg_names = setup_teardown.__get_arg_names
|
||||||
|
getcallargs = setup_teardown.__getcallargs
|
||||||
|
call_in_context = setup_teardown.__call_in_context
|
||||||
|
|
||||||
|
|
||||||
|
class TestWrappers(unittest.TestCase):
|
||||||
|
def test_get_arg_names(self):
|
||||||
|
def func_no_args():
|
||||||
|
pass
|
||||||
|
|
||||||
|
def func_arg(single):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def func_args(first, last):
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
get_arg_names(func_no_args),
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
get_arg_names(func_arg),
|
||||||
|
['single']
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
get_arg_names(func_args),
|
||||||
|
['first', 'last']
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_getcallargs(self):
|
||||||
|
def func_no_def(arg1, arg2):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def func_def(arg1, arg2='arg2'):
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
dict(getcallargs(func_no_def, *['arg1', 'arg2'], **{})),
|
||||||
|
{'arg1': 'arg1', 'arg2': 'arg2'}
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
dict(getcallargs(func_no_def, *['arg1'], **{'arg2': 'arg2'})),
|
||||||
|
{'arg1': 'arg1', 'arg2': 'arg2'}
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
dict(getcallargs(
|
||||||
|
func_no_def, *[], **{'arg1': 'arg1', 'arg2': 'arg2'})),
|
||||||
|
{'arg1': 'arg1', 'arg2': 'arg2'}
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
dict(getcallargs(func_def, *['arg1'], **{})),
|
||||||
|
{'arg1': 'arg1', 'arg2': 'arg2'}
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
dict(getcallargs(func_def, *[], **{'arg1': 'arg1'})),
|
||||||
|
{'arg1': 'arg1', 'arg2': 'arg2'}
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
dict(getcallargs(
|
||||||
|
func_def, *[], **{'arg1': 'arg1', 'arg2': 2})),
|
||||||
|
{'arg1': 'arg1', 'arg2': 2}
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_call_in_context(self):
|
||||||
|
def func_no_args():
|
||||||
|
return None
|
||||||
|
|
||||||
|
def func_args(first='first', last='last'):
|
||||||
|
return first, last
|
||||||
|
|
||||||
|
def func_self_arg(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def func_cls_arg(cls):
|
||||||
|
return cls
|
||||||
|
|
||||||
|
class Tst(object):
|
||||||
|
@classmethod
|
||||||
|
def tst(cls):
|
||||||
|
return cls
|
||||||
|
|
||||||
|
self.assertIsNone(
|
||||||
|
call_in_context(
|
||||||
|
func=func_no_args,
|
||||||
|
context_args={}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertIsNone(
|
||||||
|
call_in_context(
|
||||||
|
func=func_no_args,
|
||||||
|
context_args={'test': 'val'}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
call_in_context(
|
||||||
|
func=func_args,
|
||||||
|
context_args={'first': 0, 'last': -1}
|
||||||
|
),
|
||||||
|
(0, -1)
|
||||||
|
)
|
||||||
|
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
call_in_context(
|
||||||
|
func=func_args,
|
||||||
|
context_args={}
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
call_in_context(
|
||||||
|
func=func_self_arg,
|
||||||
|
context_args={'self': self}
|
||||||
|
),
|
||||||
|
self
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
call_in_context(
|
||||||
|
func=func_cls_arg,
|
||||||
|
context_args={'cls': self.__class__}
|
||||||
|
),
|
||||||
|
self.__class__
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
call_in_context(
|
||||||
|
func=func_cls_arg,
|
||||||
|
context_args={'self': self}
|
||||||
|
),
|
||||||
|
self.__class__
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
call_in_context(
|
||||||
|
func=Tst.tst,
|
||||||
|
context_args={'cls': self.__class__}
|
||||||
|
),
|
||||||
|
Tst,
|
||||||
|
'cls was not filtered from @classmethod!'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@patch('core.helpers.setup_teardown.__getcallargs', return_value={'arg': True})
|
||||||
|
@patch('core.helpers.setup_teardown.__call_in_context')
|
||||||
|
class TestSetupTeardown(unittest.TestCase):
|
||||||
|
def test_basic(self, call_in, getargs):
|
||||||
|
arg = True
|
||||||
|
|
||||||
|
def setup_func():
|
||||||
|
pass
|
||||||
|
|
||||||
|
def teardown_func():
|
||||||
|
pass
|
||||||
|
|
||||||
|
@setup_teardown.setup_teardown()
|
||||||
|
def positive_example(arg):
|
||||||
|
return arg
|
||||||
|
|
||||||
|
self.assertEqual(positive_example(arg), arg)
|
||||||
|
|
||||||
|
# Real function is under decorator, so we could not make full check
|
||||||
|
getargs.assert_called_once()
|
||||||
|
|
||||||
|
call_in.assert_has_calls((
|
||||||
|
call(None, {'arg': arg}),
|
||||||
|
call(None, {'arg': arg}),
|
||||||
|
))
|
||||||
|
|
||||||
|
def test_applied(self, call_in, getargs):
|
||||||
|
arg = True
|
||||||
|
|
||||||
|
def setup_func():
|
||||||
|
pass
|
||||||
|
|
||||||
|
def teardown_func():
|
||||||
|
pass
|
||||||
|
|
||||||
|
@setup_teardown.setup_teardown(
|
||||||
|
setup=setup_func,
|
||||||
|
teardown=teardown_func
|
||||||
|
)
|
||||||
|
def positive_example(arg):
|
||||||
|
return arg
|
||||||
|
|
||||||
|
self.assertEqual(positive_example(arg), arg)
|
||||||
|
|
||||||
|
# Real function is under decorator, so we could not make full check
|
||||||
|
getargs.assert_called_once()
|
||||||
|
|
||||||
|
call_in.assert_has_calls((
|
||||||
|
call(setup_func, {'arg': arg}),
|
||||||
|
call(teardown_func, {'arg': arg}),
|
||||||
|
))
|
||||||
|
|
||||||
|
def test_exception_applied(self, call_in, getargs):
|
||||||
|
arg = True
|
||||||
|
|
||||||
|
def setup_func():
|
||||||
|
pass
|
||||||
|
|
||||||
|
def teardown_func():
|
||||||
|
pass
|
||||||
|
|
||||||
|
@setup_teardown.setup_teardown(
|
||||||
|
setup=setup_func,
|
||||||
|
teardown=teardown_func
|
||||||
|
)
|
||||||
|
def positive_example(arg):
|
||||||
|
raise ValueError(arg)
|
||||||
|
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
positive_example(arg)
|
||||||
|
|
||||||
|
# Real function is under decorator, so we could not make full check
|
||||||
|
getargs.assert_called_once()
|
||||||
|
|
||||||
|
call_in.assert_has_calls((
|
||||||
|
call(setup_func, {'arg': arg}),
|
||||||
|
call(teardown_func, {'arg': arg}),
|
||||||
|
))
|
337
core/helpers/setup_teardown.py
Normal file
337
core/helpers/setup_teardown.py
Normal file
@ -0,0 +1,337 @@
|
|||||||
|
# Copyright 2016 Mirantis, Inc.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import functools
|
||||||
|
import inspect
|
||||||
|
|
||||||
|
import six
|
||||||
|
|
||||||
|
# Setup/Teardown decorators, which is missing in Proboscis.
|
||||||
|
# Usage: like in Nose.
|
||||||
|
|
||||||
|
|
||||||
|
# pylint: disable=no-member
|
||||||
|
def __getcallargs(func, *positional, **named):
|
||||||
|
"""get real function call arguments without calling function
|
||||||
|
|
||||||
|
:rtype: dict
|
||||||
|
"""
|
||||||
|
# noinspection PyUnresolvedReferences
|
||||||
|
if six.PY2:
|
||||||
|
return inspect.getcallargs(func, *positional, **named)
|
||||||
|
sig = inspect.signature(func).bind(*positional, **named)
|
||||||
|
sig.apply_defaults() # after bind we doesn't have defaults
|
||||||
|
return sig.arguments
|
||||||
|
|
||||||
|
|
||||||
|
def __get_arg_names(func):
|
||||||
|
"""get argument names for function
|
||||||
|
|
||||||
|
:param func: func
|
||||||
|
:return: list of function argnames
|
||||||
|
:rtype: list
|
||||||
|
|
||||||
|
>>> def tst_1():
|
||||||
|
... pass
|
||||||
|
|
||||||
|
>>> __get_arg_names(tst_1)
|
||||||
|
[]
|
||||||
|
|
||||||
|
>>> def tst_2(arg):
|
||||||
|
... pass
|
||||||
|
|
||||||
|
>>> __get_arg_names(tst_2)
|
||||||
|
['arg']
|
||||||
|
"""
|
||||||
|
# noinspection PyUnresolvedReferences
|
||||||
|
return (
|
||||||
|
[arg for arg in inspect.getargspec(func=func).args] if six.PY2 else
|
||||||
|
list(inspect.signature(obj=func).parameters.keys())
|
||||||
|
)
|
||||||
|
# pylint:enable=no-member
|
||||||
|
|
||||||
|
|
||||||
|
def __call_in_context(func, context_args):
|
||||||
|
"""call function with substitute arguments from dict
|
||||||
|
|
||||||
|
:param func: function or None
|
||||||
|
:param context_args: dict
|
||||||
|
:type context_args: dict
|
||||||
|
:return: function call results
|
||||||
|
|
||||||
|
>>> __call_in_context(None, {})
|
||||||
|
|
||||||
|
>>> def print_print():
|
||||||
|
... print ('print')
|
||||||
|
|
||||||
|
>>> __call_in_context(print_print, {})
|
||||||
|
print
|
||||||
|
|
||||||
|
>>> __call_in_context(print_print, {'val': 1})
|
||||||
|
print
|
||||||
|
|
||||||
|
>>> def print_val(val):
|
||||||
|
... print(val)
|
||||||
|
|
||||||
|
>>> __call_in_context(print_val, {'val': 1})
|
||||||
|
1
|
||||||
|
"""
|
||||||
|
if func is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
func_args = __get_arg_names(func)
|
||||||
|
if not func_args:
|
||||||
|
return func()
|
||||||
|
|
||||||
|
if inspect.ismethod(func) and 'cls' in func_args:
|
||||||
|
func_args.remove('cls')
|
||||||
|
# cls if used in @classmethod and could not be posted
|
||||||
|
# via args or kwargs, so classmethod decorators always has access
|
||||||
|
# to it's own class only, except direct class argument
|
||||||
|
elif 'self' in context_args:
|
||||||
|
context_args.setdefault('cls', context_args['self'].__class__)
|
||||||
|
try:
|
||||||
|
arg_values = [context_args[k] for k in func_args]
|
||||||
|
except KeyError as e:
|
||||||
|
raise ValueError("Argument '{}' is missing".format(str(e)))
|
||||||
|
|
||||||
|
return func(*arg_values)
|
||||||
|
|
||||||
|
|
||||||
|
def setup_teardown(setup=None, teardown=None):
|
||||||
|
"""Add setup and teardown for functions and methods.
|
||||||
|
|
||||||
|
:param setup: function
|
||||||
|
:param teardown: function
|
||||||
|
:return:
|
||||||
|
|
||||||
|
>>> def setup_func():
|
||||||
|
... print('setup_func called')
|
||||||
|
|
||||||
|
>>> def teardown_func():
|
||||||
|
... print('teardown_func called')
|
||||||
|
|
||||||
|
>>> @setup_teardown(setup=setup_func, teardown=teardown_func)
|
||||||
|
... def positive_example(arg):
|
||||||
|
... print(arg)
|
||||||
|
|
||||||
|
>>> positive_example(arg=1)
|
||||||
|
setup_func called
|
||||||
|
1
|
||||||
|
teardown_func called
|
||||||
|
|
||||||
|
>>> def print_call(text):
|
||||||
|
... print (text)
|
||||||
|
|
||||||
|
>>> @setup_teardown(
|
||||||
|
... setup=lambda: print_call('setup lambda'),
|
||||||
|
... teardown=lambda: print_call('teardown lambda'))
|
||||||
|
... def positive_example_lambda(arg):
|
||||||
|
... print(arg)
|
||||||
|
|
||||||
|
>>> positive_example_lambda(arg=1)
|
||||||
|
setup lambda
|
||||||
|
1
|
||||||
|
teardown lambda
|
||||||
|
|
||||||
|
>>> def setup_with_self(self):
|
||||||
|
... print(
|
||||||
|
... 'setup_with_self: '
|
||||||
|
... 'self.cls_val = {cls_val!s}, self.val = {val!s}'.format(
|
||||||
|
... cls_val=self.cls_val, val=self.val))
|
||||||
|
|
||||||
|
>>> def teardown_with_self(self):
|
||||||
|
... print(
|
||||||
|
... 'teardown_with_self: '
|
||||||
|
... 'self.cls_val = {cls_val!s}, self.val = {val!s}'.format(
|
||||||
|
... cls_val=self.cls_val, val=self.val))
|
||||||
|
|
||||||
|
>>> def setup_with_cls(cls):
|
||||||
|
... print(
|
||||||
|
... 'setup_with_cls: cls.cls_val = {cls_val!s}'.format(
|
||||||
|
... cls_val=cls.cls_val))
|
||||||
|
|
||||||
|
>>> def teardown_with_cls(cls):
|
||||||
|
... print('teardown_with_cls: cls.cls_val = {cls_val!s}'.format(
|
||||||
|
... cls_val=cls.cls_val))
|
||||||
|
|
||||||
|
>>> class HelpersBase(object):
|
||||||
|
... cls_val = None
|
||||||
|
... def __init__(self):
|
||||||
|
... self.val = None
|
||||||
|
... @classmethod
|
||||||
|
... def cls_setup(cls):
|
||||||
|
... print(
|
||||||
|
... 'cls_setup: cls.cls_val = {cls_val!s}'.format(
|
||||||
|
... cls_val=cls.cls_val))
|
||||||
|
... @classmethod
|
||||||
|
... def cls_teardown(cls):
|
||||||
|
... print(
|
||||||
|
... 'cls_teardown: cls.cls_val = {cls_val!s}'.format(
|
||||||
|
... cls_val=cls.cls_val))
|
||||||
|
... def self_setup(self):
|
||||||
|
... print(
|
||||||
|
... 'self_setup: '
|
||||||
|
... 'self.cls_val = {cls_val!s}, self.val = {val!s}'.format(
|
||||||
|
... cls_val=self.cls_val, val=self.val))
|
||||||
|
... def self_teardown(self):
|
||||||
|
... print(
|
||||||
|
... 'self_teardown: '
|
||||||
|
... 'self.cls_val = {cls_val!s}, self.val = {val!s}'.format(
|
||||||
|
... cls_val=self.cls_val, val=self.val))
|
||||||
|
|
||||||
|
>>> class Test(HelpersBase):
|
||||||
|
... @setup_teardown(
|
||||||
|
... setup=HelpersBase.self_setup,
|
||||||
|
... teardown=HelpersBase.self_teardown)
|
||||||
|
... def test_self_self(self, cls_val=0, val=0):
|
||||||
|
... print(
|
||||||
|
... 'test_self_self: '
|
||||||
|
... 'self.cls_val = {cls_val!s}, self.val = {val!s}'.format(
|
||||||
|
... cls_val=cls_val, val=val))
|
||||||
|
... self.val = val
|
||||||
|
... self.cls_val = cls_val
|
||||||
|
... @setup_teardown(
|
||||||
|
... setup=HelpersBase.cls_setup,
|
||||||
|
... teardown=HelpersBase.cls_teardown)
|
||||||
|
... def test_self_cls(self, cls_val=1, val=1):
|
||||||
|
... print(
|
||||||
|
... 'test_self_cls: '
|
||||||
|
... 'self.cls_val = {cls_val!s}, self.val = {val!s}'.format(
|
||||||
|
... cls_val=cls_val, val=val))
|
||||||
|
... self.val = val
|
||||||
|
... self.cls_val = cls_val
|
||||||
|
... @setup_teardown(
|
||||||
|
... setup=setup_func,
|
||||||
|
... teardown=teardown_func)
|
||||||
|
... def test_self_none(self, cls_val=2, val=2):
|
||||||
|
... print(
|
||||||
|
... 'test_self_cls: '
|
||||||
|
... 'self.cls_val = {cls_val!s}, self.val = {val!s}'.format(
|
||||||
|
... cls_val=cls_val, val=val))
|
||||||
|
... self.val = val
|
||||||
|
... self.cls_val = cls_val
|
||||||
|
... @setup_teardown(
|
||||||
|
... setup=setup_with_self,
|
||||||
|
... teardown=teardown_with_self)
|
||||||
|
... def test_self_ext_self(self, cls_val=-1, val=-1):
|
||||||
|
... print(
|
||||||
|
... 'test_self_ext_self: '
|
||||||
|
... 'self.cls_val = {cls_val!s}, self.val = {val!s}'.format(
|
||||||
|
... cls_val=cls_val, val=val))
|
||||||
|
... self.val = val
|
||||||
|
... self.cls_val = cls_val
|
||||||
|
... @setup_teardown(
|
||||||
|
... setup=setup_with_cls,
|
||||||
|
... teardown=teardown_with_cls)
|
||||||
|
... def test_self_ext_cls(self, cls_val=-2, val=-2):
|
||||||
|
... print(
|
||||||
|
... 'test_self_ext_cls: '
|
||||||
|
... 'self.cls_val = {cls_val!s}, self.val = {val!s}'.format(
|
||||||
|
... cls_val=cls_val, val=val))
|
||||||
|
... self.val = val
|
||||||
|
... self.cls_val = cls_val
|
||||||
|
... @classmethod
|
||||||
|
... @setup_teardown(
|
||||||
|
... setup=HelpersBase.cls_setup,
|
||||||
|
... teardown=HelpersBase.cls_teardown)
|
||||||
|
... def test_cls_cls(cls, cls_val=3):
|
||||||
|
... print(
|
||||||
|
... 'test_cls_cls: cls.cls_val = {cls_val!s}'.format(
|
||||||
|
... cls_val=cls_val))
|
||||||
|
... cls.cls_val = cls_val
|
||||||
|
... @classmethod
|
||||||
|
... @setup_teardown(
|
||||||
|
... setup=setup_func,
|
||||||
|
... teardown=teardown_func)
|
||||||
|
... def test_cls_none(cls, cls_val=4):
|
||||||
|
... print(
|
||||||
|
... 'test_cls_none: cls.cls_val = {cls_val!s}'.format(
|
||||||
|
... cls_val=cls_val))
|
||||||
|
... cls.cls_val = cls_val
|
||||||
|
... @classmethod
|
||||||
|
... @setup_teardown(
|
||||||
|
... setup=setup_with_cls,
|
||||||
|
... teardown=teardown_with_cls)
|
||||||
|
... def test_cls_ext_cls(cls, cls_val=-3):
|
||||||
|
... print(
|
||||||
|
... 'test_self_ext_cls: cls.cls_val = {cls_val!s}'.format(
|
||||||
|
... cls_val=cls_val))
|
||||||
|
... cls.cls_val = cls_val
|
||||||
|
... @staticmethod
|
||||||
|
... @setup_teardown(setup=setup_func, teardown=teardown_func)
|
||||||
|
... def test_none_none():
|
||||||
|
... print('test')
|
||||||
|
|
||||||
|
>>> test = Test()
|
||||||
|
|
||||||
|
>>> test.test_self_self()
|
||||||
|
self_setup: self.cls_val = None, self.val = None
|
||||||
|
test_self_self: self.cls_val = 0, self.val = 0
|
||||||
|
self_teardown: self.cls_val = 0, self.val = 0
|
||||||
|
|
||||||
|
>>> test.test_self_cls()
|
||||||
|
cls_setup: cls.cls_val = None
|
||||||
|
test_self_cls: self.cls_val = 1, self.val = 1
|
||||||
|
cls_teardown: cls.cls_val = None
|
||||||
|
|
||||||
|
>>> test.test_self_none()
|
||||||
|
setup_func called
|
||||||
|
test_self_cls: self.cls_val = 2, self.val = 2
|
||||||
|
teardown_func called
|
||||||
|
|
||||||
|
>>> test.test_self_ext_self()
|
||||||
|
setup_with_self: self.cls_val = 2, self.val = 2
|
||||||
|
test_self_ext_self: self.cls_val = -1, self.val = -1
|
||||||
|
teardown_with_self: self.cls_val = -1, self.val = -1
|
||||||
|
|
||||||
|
>>> test.test_self_ext_cls()
|
||||||
|
setup_with_cls: cls.cls_val = None
|
||||||
|
test_self_ext_cls: self.cls_val = -2, self.val = -2
|
||||||
|
teardown_with_cls: cls.cls_val = None
|
||||||
|
|
||||||
|
>>> test.test_cls_cls()
|
||||||
|
cls_setup: cls.cls_val = None
|
||||||
|
test_cls_cls: cls.cls_val = 3
|
||||||
|
cls_teardown: cls.cls_val = None
|
||||||
|
|
||||||
|
>>> test.test_cls_none()
|
||||||
|
setup_func called
|
||||||
|
test_cls_none: cls.cls_val = 4
|
||||||
|
teardown_func called
|
||||||
|
|
||||||
|
>>> test.test_cls_ext_cls()
|
||||||
|
setup_with_cls: cls.cls_val = 4
|
||||||
|
test_self_ext_cls: cls.cls_val = -3
|
||||||
|
teardown_with_cls: cls.cls_val = -3
|
||||||
|
|
||||||
|
>>> test.test_none_none()
|
||||||
|
setup_func called
|
||||||
|
test
|
||||||
|
teardown_func called
|
||||||
|
"""
|
||||||
|
def real_decorator(func):
|
||||||
|
@functools.wraps(func)
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
real_args = __getcallargs(func, *args, **kwargs)
|
||||||
|
__call_in_context(setup, real_args)
|
||||||
|
try:
|
||||||
|
result = func(*args, **kwargs)
|
||||||
|
finally:
|
||||||
|
__call_in_context(teardown, real_args)
|
||||||
|
return result
|
||||||
|
return wrapper
|
||||||
|
return real_decorator
|
@ -29,6 +29,10 @@ from proboscis.asserts import assert_true
|
|||||||
from six.moves import urllib
|
from six.moves import urllib
|
||||||
# pylint: enable=import-error
|
# pylint: enable=import-error
|
||||||
|
|
||||||
|
# pylint: disable=unused-import
|
||||||
|
from core.helpers.setup_teardown import setup_teardown # noqa
|
||||||
|
# pylint: enable=unused-import
|
||||||
|
|
||||||
from fuelweb_test import logger
|
from fuelweb_test import logger
|
||||||
from fuelweb_test import settings
|
from fuelweb_test import settings
|
||||||
from fuelweb_test.helpers.checkers import check_action_logs
|
from fuelweb_test.helpers.checkers import check_action_logs
|
||||||
@ -516,317 +520,6 @@ def check_repos_management(func):
|
|||||||
return result
|
return result
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
# Setup/Teardown decorators, which is missing in Proboscis.
|
|
||||||
# Usage: like in Nose.
|
|
||||||
# Python.six is less smart
|
|
||||||
|
|
||||||
|
|
||||||
# pylint: disable=no-member
|
|
||||||
def __getcallargs(func, *positional, **named):
|
|
||||||
if sys.version_info.major < 3:
|
|
||||||
return inspect.getcallargs(func, *positional, **named)
|
|
||||||
else:
|
|
||||||
# noinspection PyUnresolvedReferences
|
|
||||||
return inspect.signature(func).bind(*positional, **named).arguments
|
|
||||||
|
|
||||||
|
|
||||||
def __get_arg_names(func):
|
|
||||||
"""get argument names for function
|
|
||||||
|
|
||||||
:param func: func
|
|
||||||
:return: list of function argnames
|
|
||||||
|
|
||||||
>>> def tst_1():
|
|
||||||
... pass
|
|
||||||
|
|
||||||
>>> __get_arg_names(tst_1)
|
|
||||||
[]
|
|
||||||
|
|
||||||
>>> def tst_2(arg):
|
|
||||||
... pass
|
|
||||||
|
|
||||||
>>> __get_arg_names(tst_2)
|
|
||||||
['arg']
|
|
||||||
"""
|
|
||||||
if sys.version_info.major < 3:
|
|
||||||
return [arg for arg in inspect.getargspec(func=func).args]
|
|
||||||
else:
|
|
||||||
# noinspection PyUnresolvedReferences
|
|
||||||
return list(inspect.signature(obj=func).parameters.keys())
|
|
||||||
# pylint:enable=no-member
|
|
||||||
|
|
||||||
|
|
||||||
def __call_in_context(func, context_args):
|
|
||||||
"""call function with substitute arguments from dict
|
|
||||||
|
|
||||||
:param func: function or None
|
|
||||||
:param context_args: dict
|
|
||||||
:return: function call results
|
|
||||||
|
|
||||||
>>> __call_in_context(None, {})
|
|
||||||
|
|
||||||
>>> def print_print():
|
|
||||||
... print ('print')
|
|
||||||
|
|
||||||
>>> __call_in_context(print_print, {})
|
|
||||||
print
|
|
||||||
|
|
||||||
>>> __call_in_context(print_print, {'val': 1})
|
|
||||||
print
|
|
||||||
|
|
||||||
>>> def print_val(val):
|
|
||||||
... print(val)
|
|
||||||
|
|
||||||
>>> __call_in_context(print_val, {'val': 1})
|
|
||||||
1
|
|
||||||
"""
|
|
||||||
if func is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
func_args = __get_arg_names(func)
|
|
||||||
if not func_args:
|
|
||||||
return func()
|
|
||||||
|
|
||||||
if inspect.ismethod(func) and 'cls' in func_args:
|
|
||||||
func_args.remove('cls')
|
|
||||||
# cls if used in @classmethod and could not be posted
|
|
||||||
# via args or kwargs, so classmethod decorators always has access
|
|
||||||
# to it's own class only, except direct class argument
|
|
||||||
elif 'self' in context_args:
|
|
||||||
context_args.setdefault('cls', context_args['self'].__class__)
|
|
||||||
try:
|
|
||||||
arg_values = [context_args[k] for k in func_args]
|
|
||||||
except KeyError as e:
|
|
||||||
raise ValueError("Argument '{}' is missing".format(str(e)))
|
|
||||||
|
|
||||||
return func(*arg_values)
|
|
||||||
|
|
||||||
|
|
||||||
def setup_teardown(setup=None, teardown=None):
|
|
||||||
"""Add setup and teardown for functions and methods.
|
|
||||||
|
|
||||||
:param setup: function
|
|
||||||
:param teardown: function
|
|
||||||
:return:
|
|
||||||
|
|
||||||
>>> def setup_func():
|
|
||||||
... print('setup_func called')
|
|
||||||
|
|
||||||
>>> def teardown_func():
|
|
||||||
... print('teardown_func called')
|
|
||||||
|
|
||||||
>>> @setup_teardown(setup=setup_func, teardown=teardown_func)
|
|
||||||
... def positive_example(arg):
|
|
||||||
... print(arg)
|
|
||||||
|
|
||||||
>>> positive_example(arg=1)
|
|
||||||
setup_func called
|
|
||||||
1
|
|
||||||
teardown_func called
|
|
||||||
|
|
||||||
>>> def print_call(text):
|
|
||||||
... print (text)
|
|
||||||
|
|
||||||
>>> @setup_teardown(
|
|
||||||
... setup=lambda: print_call('setup lambda'),
|
|
||||||
... teardown=lambda: print_call('teardown lambda'))
|
|
||||||
... def positive_example_lambda(arg):
|
|
||||||
... print(arg)
|
|
||||||
|
|
||||||
>>> positive_example_lambda(arg=1)
|
|
||||||
setup lambda
|
|
||||||
1
|
|
||||||
teardown lambda
|
|
||||||
|
|
||||||
>>> def setup_with_self(self):
|
|
||||||
... print(
|
|
||||||
... 'setup_with_self: '
|
|
||||||
... 'self.cls_val = {cls_val!s}, self.val = {val!s}'.format(
|
|
||||||
... cls_val=self.cls_val, val=self.val))
|
|
||||||
|
|
||||||
>>> def teardown_with_self(self):
|
|
||||||
... print(
|
|
||||||
... 'teardown_with_self: '
|
|
||||||
... 'self.cls_val = {cls_val!s}, self.val = {val!s}'.format(
|
|
||||||
... cls_val=self.cls_val, val=self.val))
|
|
||||||
|
|
||||||
>>> def setup_with_cls(cls):
|
|
||||||
... print(
|
|
||||||
... 'setup_with_cls: cls.cls_val = {cls_val!s}'.format(
|
|
||||||
... cls_val=cls.cls_val))
|
|
||||||
|
|
||||||
>>> def teardown_with_cls(cls):
|
|
||||||
... print('teardown_with_cls: cls.cls_val = {cls_val!s}'.format(
|
|
||||||
... cls_val=cls.cls_val))
|
|
||||||
|
|
||||||
>>> class HelpersBase(object):
|
|
||||||
... cls_val = None
|
|
||||||
... def __init__(self):
|
|
||||||
... self.val = None
|
|
||||||
... @classmethod
|
|
||||||
... def cls_setup(cls):
|
|
||||||
... print(
|
|
||||||
... 'cls_setup: cls.cls_val = {cls_val!s}'.format(
|
|
||||||
... cls_val=cls.cls_val))
|
|
||||||
... @classmethod
|
|
||||||
... def cls_teardown(cls):
|
|
||||||
... print(
|
|
||||||
... 'cls_teardown: cls.cls_val = {cls_val!s}'.format(
|
|
||||||
... cls_val=cls.cls_val))
|
|
||||||
... def self_setup(self):
|
|
||||||
... print(
|
|
||||||
... 'self_setup: '
|
|
||||||
... 'self.cls_val = {cls_val!s}, self.val = {val!s}'.format(
|
|
||||||
... cls_val=self.cls_val, val=self.val))
|
|
||||||
... def self_teardown(self):
|
|
||||||
... print(
|
|
||||||
... 'self_teardown: '
|
|
||||||
... 'self.cls_val = {cls_val!s}, self.val = {val!s}'.format(
|
|
||||||
... cls_val=self.cls_val, val=self.val))
|
|
||||||
|
|
||||||
>>> class Test(HelpersBase):
|
|
||||||
... @setup_teardown(
|
|
||||||
... setup=HelpersBase.self_setup,
|
|
||||||
... teardown=HelpersBase.self_teardown)
|
|
||||||
... def test_self_self(self, cls_val=0, val=0):
|
|
||||||
... print(
|
|
||||||
... 'test_self_self: '
|
|
||||||
... 'self.cls_val = {cls_val!s}, self.val = {val!s}'.format(
|
|
||||||
... cls_val=cls_val, val=val))
|
|
||||||
... self.val = val
|
|
||||||
... self.cls_val = cls_val
|
|
||||||
... @setup_teardown(
|
|
||||||
... setup=HelpersBase.cls_setup,
|
|
||||||
... teardown=HelpersBase.cls_teardown)
|
|
||||||
... def test_self_cls(self, cls_val=1, val=1):
|
|
||||||
... print(
|
|
||||||
... 'test_self_cls: '
|
|
||||||
... 'self.cls_val = {cls_val!s}, self.val = {val!s}'.format(
|
|
||||||
... cls_val=cls_val, val=val))
|
|
||||||
... self.val = val
|
|
||||||
... self.cls_val = cls_val
|
|
||||||
... @setup_teardown(
|
|
||||||
... setup=setup_func,
|
|
||||||
... teardown=teardown_func)
|
|
||||||
... def test_self_none(self, cls_val=2, val=2):
|
|
||||||
... print(
|
|
||||||
... 'test_self_cls: '
|
|
||||||
... 'self.cls_val = {cls_val!s}, self.val = {val!s}'.format(
|
|
||||||
... cls_val=cls_val, val=val))
|
|
||||||
... self.val = val
|
|
||||||
... self.cls_val = cls_val
|
|
||||||
... @setup_teardown(
|
|
||||||
... setup=setup_with_self,
|
|
||||||
... teardown=teardown_with_self)
|
|
||||||
... def test_self_ext_self(self, cls_val=-1, val=-1):
|
|
||||||
... print(
|
|
||||||
... 'test_self_ext_self: '
|
|
||||||
... 'self.cls_val = {cls_val!s}, self.val = {val!s}'.format(
|
|
||||||
... cls_val=cls_val, val=val))
|
|
||||||
... self.val = val
|
|
||||||
... self.cls_val = cls_val
|
|
||||||
... @setup_teardown(
|
|
||||||
... setup=setup_with_cls,
|
|
||||||
... teardown=teardown_with_cls)
|
|
||||||
... def test_self_ext_cls(self, cls_val=-2, val=-2):
|
|
||||||
... print(
|
|
||||||
... 'test_self_ext_cls: '
|
|
||||||
... 'self.cls_val = {cls_val!s}, self.val = {val!s}'.format(
|
|
||||||
... cls_val=cls_val, val=val))
|
|
||||||
... self.val = val
|
|
||||||
... self.cls_val = cls_val
|
|
||||||
... @classmethod
|
|
||||||
... @setup_teardown(
|
|
||||||
... setup=HelpersBase.cls_setup,
|
|
||||||
... teardown=HelpersBase.cls_teardown)
|
|
||||||
... def test_cls_cls(cls, cls_val=3):
|
|
||||||
... print(
|
|
||||||
... 'test_cls_cls: cls.cls_val = {cls_val!s}'.format(
|
|
||||||
... cls_val=cls_val))
|
|
||||||
... cls.cls_val = cls_val
|
|
||||||
... @classmethod
|
|
||||||
... @setup_teardown(
|
|
||||||
... setup=setup_func,
|
|
||||||
... teardown=teardown_func)
|
|
||||||
... def test_cls_none(cls, cls_val=4):
|
|
||||||
... print(
|
|
||||||
... 'test_cls_none: cls.cls_val = {cls_val!s}'.format(
|
|
||||||
... cls_val=cls_val))
|
|
||||||
... cls.cls_val = cls_val
|
|
||||||
... @classmethod
|
|
||||||
... @setup_teardown(
|
|
||||||
... setup=setup_with_cls,
|
|
||||||
... teardown=teardown_with_cls)
|
|
||||||
... def test_cls_ext_cls(cls, cls_val=-3):
|
|
||||||
... print(
|
|
||||||
... 'test_self_ext_cls: cls.cls_val = {cls_val!s}'.format(
|
|
||||||
... cls_val=cls_val))
|
|
||||||
... cls.cls_val = cls_val
|
|
||||||
... @staticmethod
|
|
||||||
... @setup_teardown(setup=setup_func, teardown=teardown_func)
|
|
||||||
... def test_none_none():
|
|
||||||
... print('test')
|
|
||||||
|
|
||||||
>>> test = Test()
|
|
||||||
|
|
||||||
>>> test.test_self_self()
|
|
||||||
self_setup: self.cls_val = None, self.val = None
|
|
||||||
test_self_self: self.cls_val = 0, self.val = 0
|
|
||||||
self_teardown: self.cls_val = 0, self.val = 0
|
|
||||||
|
|
||||||
>>> test.test_self_cls()
|
|
||||||
cls_setup: cls.cls_val = None
|
|
||||||
test_self_cls: self.cls_val = 1, self.val = 1
|
|
||||||
cls_teardown: cls.cls_val = None
|
|
||||||
|
|
||||||
>>> test.test_self_none()
|
|
||||||
setup_func called
|
|
||||||
test_self_cls: self.cls_val = 2, self.val = 2
|
|
||||||
teardown_func called
|
|
||||||
|
|
||||||
>>> test.test_self_ext_self()
|
|
||||||
setup_with_self: self.cls_val = 2, self.val = 2
|
|
||||||
test_self_ext_self: self.cls_val = -1, self.val = -1
|
|
||||||
teardown_with_self: self.cls_val = -1, self.val = -1
|
|
||||||
|
|
||||||
>>> test.test_self_ext_cls()
|
|
||||||
setup_with_cls: cls.cls_val = None
|
|
||||||
test_self_ext_cls: self.cls_val = -2, self.val = -2
|
|
||||||
teardown_with_cls: cls.cls_val = None
|
|
||||||
|
|
||||||
>>> test.test_cls_cls()
|
|
||||||
cls_setup: cls.cls_val = None
|
|
||||||
test_cls_cls: cls.cls_val = 3
|
|
||||||
cls_teardown: cls.cls_val = None
|
|
||||||
|
|
||||||
>>> test.test_cls_none()
|
|
||||||
setup_func called
|
|
||||||
test_cls_none: cls.cls_val = 4
|
|
||||||
teardown_func called
|
|
||||||
|
|
||||||
>>> test.test_cls_ext_cls()
|
|
||||||
setup_with_cls: cls.cls_val = 4
|
|
||||||
test_self_ext_cls: cls.cls_val = -3
|
|
||||||
teardown_with_cls: cls.cls_val = -3
|
|
||||||
|
|
||||||
>>> test.test_none_none()
|
|
||||||
setup_func called
|
|
||||||
test
|
|
||||||
teardown_func called
|
|
||||||
"""
|
|
||||||
def real_decorator(func):
|
|
||||||
@functools.wraps(func)
|
|
||||||
def wrapper(*args, **kwargs):
|
|
||||||
real_args = __getcallargs(func, *args, **kwargs)
|
|
||||||
__call_in_context(setup, real_args)
|
|
||||||
try:
|
|
||||||
result = func(*args, **kwargs)
|
|
||||||
finally:
|
|
||||||
__call_in_context(teardown, real_args)
|
|
||||||
return result
|
|
||||||
return wrapper
|
|
||||||
return real_decorator
|
|
||||||
|
|
||||||
|
|
||||||
def token(func):
|
def token(func):
|
||||||
@functools.wraps(func)
|
@functools.wraps(func)
|
||||||
|
@ -16,10 +16,11 @@ from os.path import basename
|
|||||||
from proboscis.asserts import assert_true
|
from proboscis.asserts import assert_true
|
||||||
from proboscis import test
|
from proboscis import test
|
||||||
|
|
||||||
|
from core.helpers.setup_teardown import setup_teardown
|
||||||
|
|
||||||
from fuelweb_test import logger
|
from fuelweb_test import logger
|
||||||
from fuelweb_test.helpers.decorators import log_snapshot_after_test
|
from fuelweb_test.helpers.decorators import log_snapshot_after_test
|
||||||
from fuelweb_test.helpers.decorators import upload_manifests
|
from fuelweb_test.helpers.decorators import upload_manifests
|
||||||
from fuelweb_test.helpers.decorators import setup_teardown
|
|
||||||
from fuelweb_test.helpers.utils import get_node_hiera_roles
|
from fuelweb_test.helpers.utils import get_node_hiera_roles
|
||||||
from fuelweb_test.helpers import checkers
|
from fuelweb_test.helpers import checkers
|
||||||
from fuelweb_test.settings import DEPLOYMENT_MODE
|
from fuelweb_test.settings import DEPLOYMENT_MODE
|
||||||
|
@ -21,9 +21,10 @@ from paramiko.ssh_exception import ChannelException
|
|||||||
from proboscis import asserts
|
from proboscis import asserts
|
||||||
from proboscis import test
|
from proboscis import test
|
||||||
|
|
||||||
|
from core.helpers.setup_teardown import setup_teardown
|
||||||
|
|
||||||
from fuelweb_test.helpers import checkers
|
from fuelweb_test.helpers import checkers
|
||||||
from fuelweb_test.helpers.decorators import log_snapshot_after_test
|
from fuelweb_test.helpers.decorators import log_snapshot_after_test
|
||||||
from fuelweb_test.helpers.decorators import setup_teardown
|
|
||||||
from fuelweb_test.helpers.utils import get_network_template
|
from fuelweb_test.helpers.utils import get_network_template
|
||||||
from fuelweb_test.helpers.utils import preserve_partition
|
from fuelweb_test.helpers.utils import preserve_partition
|
||||||
from fuelweb_test import settings
|
from fuelweb_test import settings
|
||||||
|
@ -17,11 +17,12 @@ import time
|
|||||||
from proboscis import test
|
from proboscis import test
|
||||||
from proboscis.asserts import assert_true
|
from proboscis.asserts import assert_true
|
||||||
|
|
||||||
|
from core.helpers.setup_teardown import setup_teardown
|
||||||
|
|
||||||
from fuelweb_test import logger
|
from fuelweb_test import logger
|
||||||
from fuelweb_test import ostf_test_mapping
|
from fuelweb_test import ostf_test_mapping
|
||||||
from fuelweb_test import settings
|
from fuelweb_test import settings
|
||||||
from fuelweb_test.helpers.decorators import log_snapshot_after_test
|
from fuelweb_test.helpers.decorators import log_snapshot_after_test
|
||||||
from fuelweb_test.helpers.decorators import setup_teardown
|
|
||||||
from fuelweb_test.helpers.rally import RallyBenchmarkTest
|
from fuelweb_test.helpers.rally import RallyBenchmarkTest
|
||||||
from fuelweb_test.helpers.utils import fill_space
|
from fuelweb_test.helpers.utils import fill_space
|
||||||
from fuelweb_test.tests.base_test_case import SetupEnvironment
|
from fuelweb_test.tests.base_test_case import SetupEnvironment
|
||||||
|
@ -21,12 +21,13 @@ from proboscis.asserts import assert_true
|
|||||||
from six.moves import xrange
|
from six.moves import xrange
|
||||||
# pylint: enable=redefined-builtin
|
# pylint: enable=redefined-builtin
|
||||||
|
|
||||||
|
from core.helpers.setup_teardown import setup_teardown
|
||||||
|
|
||||||
from fuelweb_test import logger
|
from fuelweb_test import logger
|
||||||
from fuelweb_test import ostf_test_mapping
|
from fuelweb_test import ostf_test_mapping
|
||||||
from fuelweb_test import settings
|
from fuelweb_test import settings
|
||||||
from fuelweb_test.helpers.cic_maintenance_mode import change_config
|
from fuelweb_test.helpers.cic_maintenance_mode import change_config
|
||||||
from fuelweb_test.helpers.decorators import log_snapshot_after_test
|
from fuelweb_test.helpers.decorators import log_snapshot_after_test
|
||||||
from fuelweb_test.helpers.decorators import setup_teardown
|
|
||||||
from fuelweb_test.helpers.rally import RallyBenchmarkTest
|
from fuelweb_test.helpers.rally import RallyBenchmarkTest
|
||||||
from fuelweb_test.helpers.utils import fill_space
|
from fuelweb_test.helpers.utils import fill_space
|
||||||
from fuelweb_test.tests.base_test_case import SetupEnvironment
|
from fuelweb_test.tests.base_test_case import SetupEnvironment
|
||||||
|
Loading…
Reference in New Issue
Block a user