# -*- 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 Salt libs import salt.utils.decorators as decorators from salt.exceptions import CommandExecutionError, SaltConfigurationError from salt.version import SaltStackVersion from tests.support.mock import 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__