From 8a8178738d05a0003a6784acea6ba3e7f58a19d2 Mon Sep 17 00:00:00 2001 From: Frode Nordahl Date: Mon, 31 Aug 2020 16:26:14 +0200 Subject: [PATCH] Add support for resetting back to charm default on config_change Due to python-libjuju's requirement for coercing every config value into strings, some configuration type/values are not possible to specify the default for. Allow the config_change helper to optionally use reset back to charm default instead of specifying default config values in a dictionary. --- unit_tests/charm_tests/test_utils.py | 73 +++++++++++++++++++++++- zaza/openstack/charm_tests/test_utils.py | 27 +++++++-- 2 files changed, 93 insertions(+), 7 deletions(-) diff --git a/unit_tests/charm_tests/test_utils.py b/unit_tests/charm_tests/test_utils.py index 8e0661b..7ca3ba5 100644 --- a/unit_tests/charm_tests/test_utils.py +++ b/unit_tests/charm_tests/test_utils.py @@ -12,12 +12,26 @@ # See the License for the specific language governing permissions and # limitations under the License. +from unittest import mock + import zaza.openstack.charm_tests.test_utils as test_utils import unit_tests.utils as ut_utils -class TestBaseCharmTest(unittest.TestCase): +class TestBaseCharmTest(ut_utils.BaseTestCase): + + def setUp(self): + super(TestBaseCharmTest, self).setUp() + self.target = test_utils.BaseCharmTest() + + def patch_target(self, attr, return_value=None): + mocked = mock.patch.object(self.target, attr) + self._patches[attr] = mocked + started = mocked.start() + started.return_value = return_value + self._patches_start[attr] = started + setattr(self, attr, started) def test_get_my_tests_options(self): @@ -36,6 +50,63 @@ class TestBaseCharmTest(unittest.TestCase): }, }), 'aValue') + def test_config_change(self): + default_config = {'fakeKey': 'testProvidedDefault'} + alterna_config = {'fakeKey': 'testProvidedAlterna'} + self.target.model_name = 'aModel' + self.target.test_config = {} + self.patch_target('config_current') + self.config_current.return_value = default_config + self.patch_object(test_utils.model, 'set_application_config') + self.patch_object(test_utils.model, 'wait_for_agent_status') + self.patch_object(test_utils.model, 'wait_for_application_states') + self.patch_object(test_utils.model, 'block_until_all_units_idle') + with self.target.config_change( + default_config, alterna_config, application_name='anApp'): + self.set_application_config.assert_called_once_with( + 'anApp', alterna_config, model_name='aModel') + self.wait_for_agent_status.assert_called_once_with( + model_name='aModel') + self.wait_for_application_states.assert_called_once_with( + model_name='aModel', states={}) + self.block_until_all_units_idle.assert_called_once_with() + # after yield we will have different calls than the above, measure both + self.set_application_config.assert_has_calls([ + mock.call('anApp', alterna_config, model_name='aModel'), + mock.call('anApp', default_config, model_name='aModel'), + ]) + self.wait_for_application_states.assert_has_calls([ + mock.call(model_name='aModel', states={}), + mock.call(model_name='aModel', states={}), + ]) + self.block_until_all_units_idle.assert_has_calls([ + mock.call(), + mock.call(), + ]) + # confirm operation with `reset_to_charm_default` + self.set_application_config.reset_mock() + self.wait_for_agent_status.reset_mock() + self.wait_for_application_states.reset_mock() + self.patch_object(test_utils.model, 'reset_application_config') + with self.target.config_change( + default_config, alterna_config, application_name='anApp', + reset_to_charm_default=True): + self.set_application_config.assert_called_once_with( + 'anApp', alterna_config, model_name='aModel') + # we want to assert this not to be called after yield + self.set_application_config.reset_mock() + self.assertFalse(self.set_application_config.called) + self.reset_application_config.assert_called_once_with( + 'anApp', alterna_config.keys(), model_name='aModel') + self.wait_for_application_states.assert_has_calls([ + mock.call(model_name='aModel', states={}), + mock.call(model_name='aModel', states={}), + ]) + self.block_until_all_units_idle.assert_has_calls([ + mock.call(), + mock.call(), + ]) + class TestOpenStackBaseTest(ut_utils.BaseTestCase): diff --git a/zaza/openstack/charm_tests/test_utils.py b/zaza/openstack/charm_tests/test_utils.py index ee61336..9ba6955 100644 --- a/zaza/openstack/charm_tests/test_utils.py +++ b/zaza/openstack/charm_tests/test_utils.py @@ -182,7 +182,7 @@ class BaseCharmTest(unittest.TestCase): @contextlib.contextmanager def config_change(self, default_config, alternate_config, - application_name=None): + application_name=None, reset_to_charm_default=False): """Run change config tests. Change config to `alternate_config`, wait for idle workload status, @@ -202,6 +202,12 @@ class BaseCharmTest(unittest.TestCase): by a charm under test other than the object's application. :type application_name: str + :param reset_to_charm_default: When True we will ask Juju to reset each + configuration option mentioned in the + `alternate_config` dictionary back to + the charm default and ignore the + `default_config` dictionary. + :type reset_to_charm_default: bool """ if not application_name: application_name = self.application_name @@ -246,11 +252,20 @@ class BaseCharmTest(unittest.TestCase): yield - logging.debug('Restoring charm setting to {}'.format(default_config)) - model.set_application_config( - application_name, - self._stringed_value_config(default_config), - model_name=self.model_name) + if reset_to_charm_default: + logging.debug('Resetting these charm configuration options to the ' + 'charm default: "{}"' + .format(alternate_config.keys())) + model.reset_application_config(application_name, + alternate_config.keys(), + model_name=self.model_name) + else: + logging.debug('Restoring charm setting to {}' + .format(default_config)) + model.set_application_config( + application_name, + self._stringed_value_config(default_config), + model_name=self.model_name) logging.debug( 'Waiting for units to reach target states')