- Reversed ldap-config-flags vs charm configs precedence for https://review.opendev.org/748364 - Added new functional test to validate the precedence - Added zaza helper function to assist handling charm configs that do not accept "" (like booleans and ints), and reverting to unset values through config_change() - Fixed zaza reset helper function that apparently never worked ({}.keys() returns dict_keys which is not a sequence)
202 lines
8.1 KiB
Python
202 lines
8.1 KiB
Python
# Copyright 2020 Canonical Ltd.
|
|
#
|
|
# 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 unittest import mock
|
|
|
|
import zaza.openstack.charm_tests.test_utils as test_utils
|
|
|
|
import unit_tests.utils as ut_utils
|
|
|
|
|
|
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):
|
|
|
|
class FakeTest(test_utils.BaseCharmTest):
|
|
|
|
def method(self, test_config):
|
|
self.test_config = test_config
|
|
return self.get_my_tests_options('aKey', 'aDefault')
|
|
|
|
f = FakeTest()
|
|
self.assertEquals(f.method({}), 'aDefault')
|
|
self.assertEquals(f.method({
|
|
'tests_options': {
|
|
'unit_tests.charm_tests.test_utils.'
|
|
'FakeTest.method.aKey': 'aValue',
|
|
},
|
|
}), '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', list(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(),
|
|
])
|
|
# confirm operation where both default and alternate config passed in
|
|
# are the same. This is used to set config and not change it back.
|
|
self.set_application_config.reset_mock()
|
|
self.wait_for_agent_status.reset_mock()
|
|
self.wait_for_application_states.reset_mock()
|
|
self.reset_application_config.reset_mock()
|
|
with self.target.config_change(
|
|
alterna_config, alterna_config, application_name='anApp'):
|
|
self.set_application_config.assert_called_once_with(
|
|
'anApp', alterna_config, model_name='aModel')
|
|
# we want to assert these not to be called after yield
|
|
self.set_application_config.reset_mock()
|
|
self.wait_for_agent_status.reset_mock()
|
|
self.wait_for_application_states.reset_mock()
|
|
self.assertFalse(self.set_application_config.called)
|
|
self.assertFalse(self.reset_application_config.called)
|
|
self.assertFalse(self.wait_for_agent_status.called)
|
|
self.assertFalse(self.wait_for_application_states.called)
|
|
|
|
def test_separate_non_string_config(self):
|
|
intended_cfg_keys = ['foo2', 'foo3', 'foo4', 'foo5']
|
|
current_config_mock = {
|
|
'foo2': None,
|
|
'foo3': 'old_bar3',
|
|
'foo4': None,
|
|
'foo5': 'old_bar5',
|
|
}
|
|
self.patch_target('config_current')
|
|
self.config_current.return_value = current_config_mock
|
|
non_string_type_keys = ['foo2', 'foo3', 'foo4']
|
|
expected_result_filtered = {
|
|
'foo3': 'old_bar3',
|
|
'foo5': 'old_bar5',
|
|
}
|
|
expected_result_special = {
|
|
'foo2': None,
|
|
'foo4': None,
|
|
}
|
|
current, non_string = (
|
|
self.target.config_current_separate_non_string_type_keys(
|
|
non_string_type_keys, intended_cfg_keys, 'application_name')
|
|
)
|
|
|
|
self.assertEqual(expected_result_filtered, current)
|
|
self.assertEqual(expected_result_special, non_string)
|
|
|
|
self.config_current.assert_called_once_with(
|
|
'application_name', intended_cfg_keys)
|
|
|
|
def test_separate_special_config_None_params(self):
|
|
current_config_mock = {
|
|
'foo1': 'old_bar1',
|
|
'foo2': None,
|
|
'foo3': 'old_bar3',
|
|
'foo4': None,
|
|
'foo5': 'old_bar5',
|
|
}
|
|
self.patch_target('config_current')
|
|
self.config_current.return_value = current_config_mock
|
|
non_string_type_keys = ['foo2', 'foo3', 'foo4']
|
|
expected_result_filtered = {
|
|
'foo1': 'old_bar1',
|
|
'foo3': 'old_bar3',
|
|
'foo5': 'old_bar5',
|
|
}
|
|
expected_result_special = {
|
|
'foo2': None,
|
|
'foo4': None,
|
|
}
|
|
current, non_string = (
|
|
self.target.config_current_separate_non_string_type_keys(
|
|
non_string_type_keys)
|
|
)
|
|
|
|
self.assertEqual(expected_result_filtered, current)
|
|
self.assertEqual(expected_result_special, non_string)
|
|
|
|
self.config_current.assert_called_once_with(None, None)
|
|
|
|
|
|
class TestOpenStackBaseTest(ut_utils.BaseTestCase):
|
|
|
|
def test_setUpClass(self):
|
|
self.patch_object(test_utils.openstack_utils, 'get_cacert')
|
|
self.patch_object(test_utils.openstack_utils,
|
|
'get_overcloud_keystone_session')
|
|
self.patch_object(test_utils.BaseCharmTest, 'setUpClass')
|
|
|
|
class MyTestClass(test_utils.OpenStackBaseTest):
|
|
model_name = 'deadbeef'
|
|
|
|
MyTestClass.setUpClass('foo', 'bar')
|
|
self.setUpClass.assert_called_with('foo', 'bar')
|