123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467 |
- # -*- coding: utf-8 -*-
- """
- :codeauthor: Bo Maryniuk (bo@suse.de)
- unit.utils.decorators_test
- """
- # Import Python libs
- from __future__ import absolute_import, print_function, unicode_literals
- import inspect
- # Import Salt libs
- import salt.utils.decorators as decorators
- from salt.exceptions import CommandExecutionError, SaltConfigurationError
- from salt.version import SaltStackVersion
- from tests.support.mock import MagicMock, patch
- from tests.support.unit import TestCase
- class DummyLogger(object):
- """
- Dummy logger accepts everything and simply logs
- """
- def __init__(self, messages):
- self._messages = messages
- def __getattr__(self, item):
- return self._log
- def _log(self, msg):
- self._messages.append(msg)
- class DecoratorsTest(TestCase):
- """
- Testing decorators.
- """
- def old_function(self):
- return "old"
- def new_function(self):
- return "new"
- def _new_function(self):
- return "old"
- def _mk_version(self, name):
- """
- Make a version
- :return:
- """
- return name, SaltStackVersion.from_name(name)
- def setUp(self):
- """
- Setup a test
- :return:
- """
- self.globs = {
- "__virtualname__": "test",
- "__opts__": {},
- "__pillar__": {},
- "old_function": self.old_function,
- "new_function": self.new_function,
- "_new_function": self._new_function,
- }
- self.addCleanup(delattr, self, "globs")
- self.messages = list()
- self.addCleanup(delattr, self, "messages")
- patcher = patch.object(decorators, "log", DummyLogger(self.messages))
- patcher.start()
- self.addCleanup(patcher.stop)
- def test_is_deprecated_version_eol(self):
- """
- Use of is_deprecated will result to the exception,
- if the expiration version is lower than the current version.
- A successor function is not pointed out.
- :return:
- """
- depr = decorators.is_deprecated(self.globs, "Helium")
- depr._curr_version = self._mk_version("Beryllium")[1]
- with self.assertRaises(CommandExecutionError):
- depr(self.old_function)()
- self.assertEqual(
- self.messages, ['The lifetime of the function "old_function" expired.']
- )
- def test_is_deprecated_with_successor_eol(self):
- """
- Use of is_deprecated will result to the exception,
- if the expiration version is lower than the current version.
- A successor function is pointed out.
- :return:
- """
- depr = decorators.is_deprecated(
- self.globs, "Helium", with_successor="new_function"
- )
- depr._curr_version = self._mk_version("Beryllium")[1]
- with self.assertRaises(CommandExecutionError):
- depr(self.old_function)()
- self.assertEqual(
- self.messages,
- [
- 'The lifetime of the function "old_function" expired. '
- 'Please use its successor "new_function" instead.'
- ],
- )
- def test_is_deprecated(self):
- """
- Use of is_deprecated will result to the log message,
- if the expiration version is higher than the current version.
- A successor function is not pointed out.
- :return:
- """
- depr = decorators.is_deprecated(self.globs, "Beryllium")
- depr._curr_version = self._mk_version("Helium")[1]
- self.assertEqual(depr(self.old_function)(), self.old_function())
- self.assertEqual(
- self.messages,
- [
- 'The function "old_function" is deprecated '
- 'and will expire in version "Beryllium".'
- ],
- )
- def test_is_deprecated_with_successor(self):
- """
- Use of is_deprecated will result to the log message,
- if the expiration version is higher than the current version.
- A successor function is pointed out.
- :return:
- """
- depr = decorators.is_deprecated(
- self.globs, "Beryllium", with_successor="old_function"
- )
- depr._curr_version = self._mk_version("Helium")[1]
- self.assertEqual(depr(self.old_function)(), self.old_function())
- self.assertEqual(
- self.messages,
- [
- 'The function "old_function" is deprecated '
- 'and will expire in version "Beryllium". '
- 'Use successor "old_function" instead.'
- ],
- )
- def test_with_deprecated_notfound(self):
- """
- Test with_deprecated should raise an exception, if a same name
- function with the "_" prefix not implemented.
- :return:
- """
- del self.globs["_new_function"]
- self.globs["__opts__"]["use_deprecated"] = ["test.new_function"]
- depr = decorators.with_deprecated(self.globs, "Beryllium")
- depr._curr_version = self._mk_version("Helium")[1]
- with self.assertRaises(CommandExecutionError):
- depr(self.new_function)()
- self.assertEqual(
- self.messages,
- [
- 'The function "test.new_function" is using its deprecated '
- 'version and will expire in version "Beryllium".'
- ],
- )
- def test_with_deprecated_notfound_in_pillar(self):
- """
- Test with_deprecated should raise an exception, if a same name
- function with the "_" prefix not implemented.
- :return:
- """
- del self.globs["_new_function"]
- self.globs["__pillar__"]["use_deprecated"] = ["test.new_function"]
- depr = decorators.with_deprecated(self.globs, "Beryllium")
- depr._curr_version = self._mk_version("Helium")[1]
- with self.assertRaises(CommandExecutionError):
- depr(self.new_function)()
- self.assertEqual(
- self.messages,
- [
- 'The function "test.new_function" is using its deprecated '
- 'version and will expire in version "Beryllium".'
- ],
- )
- def test_with_deprecated_found(self):
- """
- Test with_deprecated should not raise an exception, if a same name
- function with the "_" prefix is implemented, but should use
- an old version instead, if "use_deprecated" is requested.
- :return:
- """
- self.globs["__opts__"]["use_deprecated"] = ["test.new_function"]
- self.globs["_new_function"] = self.old_function
- depr = decorators.with_deprecated(self.globs, "Beryllium")
- depr._curr_version = self._mk_version("Helium")[1]
- self.assertEqual(depr(self.new_function)(), self.old_function())
- log_msg = [
- 'The function "test.new_function" is using its deprecated version '
- 'and will expire in version "Beryllium".'
- ]
- self.assertEqual(self.messages, log_msg)
- def test_with_deprecated_found_in_pillar(self):
- """
- Test with_deprecated should not raise an exception, if a same name
- function with the "_" prefix is implemented, but should use
- an old version instead, if "use_deprecated" is requested.
- :return:
- """
- self.globs["__pillar__"]["use_deprecated"] = ["test.new_function"]
- self.globs["_new_function"] = self.old_function
- depr = decorators.with_deprecated(self.globs, "Beryllium")
- depr._curr_version = self._mk_version("Helium")[1]
- self.assertEqual(depr(self.new_function)(), self.old_function())
- log_msg = [
- 'The function "test.new_function" is using its deprecated version '
- 'and will expire in version "Beryllium".'
- ]
- self.assertEqual(self.messages, log_msg)
- def test_with_deprecated_found_eol(self):
- """
- Test with_deprecated should raise an exception, if a same name
- function with the "_" prefix is implemented, "use_deprecated" is requested
- and EOL is reached.
- :return:
- """
- self.globs["__opts__"]["use_deprecated"] = ["test.new_function"]
- self.globs["_new_function"] = self.old_function
- depr = decorators.with_deprecated(self.globs, "Helium")
- depr._curr_version = self._mk_version("Beryllium")[1]
- with self.assertRaises(CommandExecutionError):
- depr(self.new_function)()
- self.assertEqual(
- self.messages,
- [
- 'Although function "new_function" is called, an alias "new_function" '
- "is configured as its deprecated version. The lifetime of the function "
- '"new_function" expired. Please use its successor "new_function" instead.'
- ],
- )
- def test_with_deprecated_found_eol_in_pillar(self):
- """
- Test with_deprecated should raise an exception, if a same name
- function with the "_" prefix is implemented, "use_deprecated" is requested
- and EOL is reached.
- :return:
- """
- self.globs["__pillar__"]["use_deprecated"] = ["test.new_function"]
- self.globs["_new_function"] = self.old_function
- depr = decorators.with_deprecated(self.globs, "Helium")
- depr._curr_version = self._mk_version("Beryllium")[1]
- with self.assertRaises(CommandExecutionError):
- depr(self.new_function)()
- self.assertEqual(
- self.messages,
- [
- 'Although function "new_function" is called, an alias "new_function" '
- "is configured as its deprecated version. The lifetime of the function "
- '"new_function" expired. Please use its successor "new_function" instead.'
- ],
- )
- def test_with_deprecated_no_conf(self):
- """
- Test with_deprecated should not raise an exception, if a same name
- function with the "_" prefix is implemented, but should use
- a new version instead, if "use_deprecated" is not requested.
- :return:
- """
- self.globs["_new_function"] = self.old_function
- depr = decorators.with_deprecated(self.globs, "Beryllium")
- depr._curr_version = self._mk_version("Helium")[1]
- self.assertEqual(depr(self.new_function)(), self.new_function())
- self.assertFalse(self.messages)
- def test_with_deprecated_with_name(self):
- """
- Test with_deprecated should not raise an exception, if a different name
- function is implemented and specified with the "with_name" parameter,
- but should use an old version instead and log a warning log message.
- :return:
- """
- self.globs["__opts__"]["use_deprecated"] = ["test.new_function"]
- depr = decorators.with_deprecated(
- self.globs, "Beryllium", with_name="old_function"
- )
- depr._curr_version = self._mk_version("Helium")[1]
- self.assertEqual(depr(self.new_function)(), self.old_function())
- self.assertEqual(
- self.messages,
- [
- 'The function "old_function" is deprecated and will expire in version "Beryllium". '
- 'Use its successor "new_function" instead.'
- ],
- )
- def test_with_deprecated_with_name_eol(self):
- """
- Test with_deprecated should raise an exception, if a different name
- function is implemented and specified with the "with_name" parameter
- and EOL is reached.
- :return:
- """
- self.globs["__opts__"]["use_deprecated"] = ["test.new_function"]
- depr = decorators.with_deprecated(
- self.globs, "Helium", with_name="old_function"
- )
- depr._curr_version = self._mk_version("Beryllium")[1]
- with self.assertRaises(CommandExecutionError):
- depr(self.new_function)()
- self.assertEqual(
- self.messages,
- [
- 'Although function "new_function" is called, '
- 'an alias "old_function" is configured as its deprecated version. '
- 'The lifetime of the function "old_function" expired. '
- 'Please use its successor "new_function" instead.'
- ],
- )
- def test_with_deprecated_opt_in_default(self):
- """
- Test with_deprecated using opt-in policy,
- where newer function is not used, unless configured.
- :return:
- """
- depr = decorators.with_deprecated(
- self.globs, "Beryllium", policy=decorators._DeprecationDecorator.OPT_IN
- )
- depr._curr_version = self._mk_version("Helium")[1]
- assert depr(self.new_function)() == self.old_function()
- assert self.messages == [
- 'The function "test.new_function" is using its '
- 'deprecated version and will expire in version "Beryllium".'
- ]
- def test_with_deprecated_opt_in_use_superseded(self):
- """
- Test with_deprecated using opt-in policy,
- where newer function is used as per configuration.
- :return:
- """
- self.globs["__opts__"]["use_superseded"] = ["test.new_function"]
- depr = decorators.with_deprecated(
- self.globs, "Beryllium", policy=decorators._DeprecationDecorator.OPT_IN
- )
- depr._curr_version = self._mk_version("Helium")[1]
- assert depr(self.new_function)() == self.new_function()
- assert not self.messages
- def test_with_deprecated_opt_in_use_superseded_in_pillar(self):
- """
- Test with_deprecated using opt-in policy,
- where newer function is used as per configuration.
- :return:
- """
- self.globs["__pillar__"]["use_superseded"] = ["test.new_function"]
- depr = decorators.with_deprecated(
- self.globs, "Beryllium", policy=decorators._DeprecationDecorator.OPT_IN
- )
- depr._curr_version = self._mk_version("Helium")[1]
- assert depr(self.new_function)() == self.new_function()
- assert not self.messages
- def test_with_deprecated_opt_in_use_superseded_and_deprecated(self):
- """
- Test with_deprecated misconfiguration.
- :return:
- """
- self.globs["__opts__"]["use_deprecated"] = ["test.new_function"]
- self.globs["__opts__"]["use_superseded"] = ["test.new_function"]
- depr = decorators.with_deprecated(self.globs, "Beryllium")
- depr._curr_version = self._mk_version("Helium")[1]
- with self.assertRaises(SaltConfigurationError):
- assert depr(self.new_function)() == self.new_function()
- def test_with_deprecated_opt_in_use_superseded_and_deprecated_in_pillar(self):
- """
- Test with_deprecated misconfiguration.
- :return:
- """
- self.globs["__pillar__"]["use_deprecated"] = ["test.new_function"]
- self.globs["__pillar__"]["use_superseded"] = ["test.new_function"]
- depr = decorators.with_deprecated(self.globs, "Beryllium")
- depr._curr_version = self._mk_version("Helium")[1]
- with self.assertRaises(SaltConfigurationError):
- assert depr(self.new_function)() == self.new_function()
- def test_with_depreciated_should_wrap_function(self):
- wrapped = decorators.with_deprecated({}, "Beryllium")(self.old_function)
- assert wrapped.__module__ == self.old_function.__module__
- def test_is_deprecated_should_wrap_function(self):
- wrapped = decorators.is_deprecated({}, "Beryllium")(self.old_function)
- assert wrapped.__module__ == self.old_function.__module__
- def test_ensure_unicode_args_should_wrap_function(self):
- wrapped = decorators.ensure_unicode_args(self.old_function)
- assert wrapped.__module__ == self.old_function.__module__
- def test_ignores_kwargs_should_wrap_function(self):
- wrapped = decorators.ignores_kwargs("foo", "bar")(self.old_function)
- assert wrapped.__module__ == self.old_function.__module__
- def test_memoize_should_wrap_function(self):
- wrapped = decorators.memoize(self.old_function)
- assert wrapped.__module__ == self.old_function.__module__
- def timing_should_wrap_function(self):
- wrapped = decorators.timing(self.old_function)
- assert wrapped.__module__ == self.old_function.__module__
- class DependsDecoratorTest(TestCase):
- def function(self):
- return "foo"
- def test_depends_get_previous_frame(self):
- """
- Confirms that we're not grabbing the entire stack every time the
- depends decorator is invoked.
- """
- # Simply using True as a conditon; we aren't testing the dependency,
- # but rather the functions called within the decorator.
- dep = decorators.depends(True)
- # By mocking both inspect.stack and inspect.currentframe with
- # MagicMocks that return themselves, we don't affect normal operation
- # of the decorator, and at the same time we get to peek at whether or
- # not either was called.
- stack_mock = MagicMock(return_value=inspect.stack)
- currentframe_mock = MagicMock(return_value=inspect.currentframe)
- with patch.object(inspect, "stack", stack_mock), patch.object(
- inspect, "currentframe", currentframe_mock
- ):
- dep(self.function)()
- stack_mock.assert_not_called()
- currentframe_mock.assert_called_once_with()
|