Charmed-Kubernetes/nrpe/mod/charmhelpers/tests/contrib/openstack/test_deferred_events.py

367 lines
15 KiB
Python

import contextlib
import copy
import datetime
import json
import tempfile
import shutil
import yaml
from mock import patch, call
import charmhelpers.contrib.openstack.deferred_events as deferred_events
import tests.utils
class TestDB(object):
'''Test KV store for unitdata testing'''
def __init__(self):
self.data = {}
self.flushed = False
def get(self, key, default=None):
result = self.data.get(key, default)
if not result:
return default
return json.loads(result)
def set(self, key, value):
self.data[key] = json.dumps(value)
return value
def flush(self):
self.flushed = True
class TestHookData(object):
def __init__(self, kv):
self.kv = kv
@contextlib.contextmanager
def __call__(self):
yield self.kv, True, True
class DeferredCharmServiceEventsTestCase(tests.utils.BaseTestCase):
def setUp(self):
super(DeferredCharmServiceEventsTestCase, self).setUp()
self.tmp_dir = tempfile.mkdtemp()
self.addCleanup(lambda: shutil.rmtree(self.tmp_dir))
self.patch_object(deferred_events.hookenv, 'service_name')
self.service_name.return_value = 'myapp'
self.patch_object(deferred_events.unitdata, 'HookData')
self.db = TestDB()
self.HookData.return_value = TestHookData(self.db)
self.exp_event_a = deferred_events.ServiceEvent(
timestamp=123,
service='svcA',
reason='ReasonA',
action='restart',
policy_requestor_name='myapp',
policy_requestor_type='charm')
self.exp_event_b = deferred_events.ServiceEvent(
timestamp=223,
service='svcB',
reason='ReasonB',
action='restart')
self.exp_event_c = deferred_events.ServiceEvent(
timestamp=323,
service='svcB',
reason='ReasonB',
action='restart')
self.base_expect_events = [
self.exp_event_a,
self.exp_event_b,
self.exp_event_c]
self.event_file_pair = []
for index, event in enumerate(self.base_expect_events):
event_file = '{}/{}.deferred'.format('/tmpdir', str(index))
self.event_file_pair.append((
event_file,
event))
def test_matching_request_event(self):
self.assertTrue(
self.exp_event_b.matching_request(
self.exp_event_c))
self.assertFalse(
self.exp_event_a.matching_request(
self.exp_event_b))
@patch.object(deferred_events.glob, "glob")
def test_deferred_events_files(self, glob):
defer_files = [
'/var/lib/policy-rc.d/charm-myapp/1612346300.deferred',
'/var/lib/policy-rc.d/charm-myapp/1612346322.deferred',
'/var/lib/policy-rc.d/charm-myapp/1612346360.deferred']
glob.return_value = defer_files
self.assertEqual(
deferred_events.deferred_events_files(),
defer_files)
def test_read_event_file(self):
with tempfile.NamedTemporaryFile('w') as ftmp:
yaml.dump(vars(self.exp_event_a), ftmp)
ftmp.flush()
self.assertEqual(
deferred_events.read_event_file(ftmp.name),
self.exp_event_a)
@patch.object(deferred_events, "deferred_events_files")
def test_deferred_events(self, deferred_events_files):
event_files = []
expect = []
for index, event in enumerate(self.base_expect_events):
event_file = '{}/{}.deferred'.format(self.tmp_dir, str(index))
with open(event_file, 'w') as f:
yaml.dump(vars(event), f)
event_files.append(event_file)
expect.append((
event_file,
event))
deferred_events_files.return_value = event_files
self.assertEqual(
deferred_events.deferred_events(),
expect)
@patch.object(deferred_events, "deferred_events")
def test_duplicate_event_files(self, _deferred_events):
_deferred_events.return_value = self.event_file_pair
self.assertEqual(
deferred_events.duplicate_event_files(self.exp_event_b),
['/tmpdir/1.deferred', '/tmpdir/2.deferred'])
self.assertEqual(
deferred_events.duplicate_event_files(deferred_events.ServiceEvent(
timestamp=223,
service='svcX',
reason='ReasonX',
action='restart')),
[])
@patch.object(deferred_events.uuid, "uuid1")
def test_get_event_record_file(self, uuid1):
uuid1.return_value = '89eb8258'
self.assertEqual(
deferred_events.get_event_record_file(
'charm',
'neutron-ovs'),
'/var/lib/policy-rc.d/charm-neutron-ovs-89eb8258.deferred')
@patch.object(deferred_events, "get_event_record_file")
@patch.object(deferred_events, "duplicate_event_files")
@patch.object(deferred_events, "init_policy_log_dir")
def test_save_event(self, init_policy_log_dir, duplicate_event_files, get_event_record_file):
duplicate_event_files.return_value = []
test_file = '{}/test_save_event.yaml'.format(self.tmp_dir)
get_event_record_file.return_value = test_file
deferred_events.save_event(self.exp_event_a)
with open(test_file, 'r') as f:
contents = yaml.load(f)
self.assertEqual(contents, vars(self.exp_event_a))
@patch.object(deferred_events.os, "remove")
@patch.object(deferred_events, "read_event_file")
@patch.object(deferred_events, "deferred_events_files")
def test_clear_deferred_events(self, deferred_events_files, read_event_file,
remove):
deferred_events_files.return_value = ['/tmp/file1']
read_event_file.return_value = self.exp_event_a
deferred_events.clear_deferred_events('svcB', 'restart')
self.assertFalse(remove.called)
deferred_events.clear_deferred_events('svcA', 'restart')
remove.assert_called_once_with('/tmp/file1')
@patch.object(deferred_events.os, "mkdir")
@patch.object(deferred_events.os.path, "exists")
def test_init_policy_log_dir(self, exists, mkdir):
exists.return_value = True
deferred_events.init_policy_log_dir()
self.assertFalse(mkdir.called)
exists.return_value = False
deferred_events.init_policy_log_dir()
mkdir.assert_called_once_with('/var/lib/policy-rc.d')
@patch.object(deferred_events, "deferred_events")
def test_get_deferred_events(self, _deferred_events):
_deferred_events.return_value = self.event_file_pair
self.assertEqual(
deferred_events.get_deferred_events(),
self.base_expect_events)
@patch.object(deferred_events, "get_deferred_events")
def test_get_deferred_restarts(self, get_deferred_events):
test_events = copy.deepcopy(self.base_expect_events)
test_events.append(
deferred_events.ServiceEvent(
timestamp=523,
service='svcD',
reason='StopReasonD',
action='stop'))
get_deferred_events.return_value = test_events
self.assertEqual(
deferred_events.get_deferred_restarts(),
self.base_expect_events)
@patch.object(deferred_events, 'clear_deferred_events')
def test_clear_deferred_restarts(self, clear_deferred_events):
deferred_events.clear_deferred_restarts(['svcA', 'svcB'])
clear_deferred_events.assert_Called_once_with(
['svcA', 'svcB'],
'restart')
@patch.object(deferred_events, 'clear_deferred_restarts')
def test_process_svc_restart(self, clear_deferred_restarts):
deferred_events.process_svc_restart('svcA')
clear_deferred_restarts.assert_called_once_with(
['svcA'])
@patch.object(deferred_events.hookenv, 'config')
def test_is_restart_permitted(self, config):
config.return_value = None
self.assertTrue(deferred_events.is_restart_permitted())
config.return_value = True
self.assertTrue(deferred_events.is_restart_permitted())
config.return_value = False
self.assertFalse(deferred_events.is_restart_permitted())
@patch.object(deferred_events.time, 'time')
@patch.object(deferred_events, 'save_event')
@patch.object(deferred_events, 'is_restart_permitted')
def test_check_and_record_restart_request(self, is_restart_permitted,
save_event, time):
time.return_value = 123
is_restart_permitted.return_value = False
deferred_events.check_and_record_restart_request(
'svcA',
['/tmp/test1.conf', '/tmp/test2.conf'])
save_event.assert_called_once_with(deferred_events.ServiceEvent(
timestamp=123,
service='svcA',
reason='File(s) changed: /tmp/test1.conf, /tmp/test2.conf',
action='restart'))
@patch.object(deferred_events.time, 'time')
@patch.object(deferred_events, 'save_event')
@patch.object(deferred_events.host, 'service_restart')
@patch.object(deferred_events, 'is_restart_permitted')
def test_deferrable_svc_restart(self, is_restart_permitted,
service_restart, save_event, time):
time.return_value = 123
is_restart_permitted.return_value = True
deferred_events.deferrable_svc_restart('svcA', reason='ReasonA')
service_restart.assert_called_once_with('svcA')
service_restart.reset_mock()
is_restart_permitted.return_value = False
deferred_events.deferrable_svc_restart('svcA', reason='ReasonA')
self.assertFalse(service_restart.called)
save_event.assert_called_once_with(deferred_events.ServiceEvent(
timestamp=123,
service='svcA',
reason='ReasonA',
action='restart'))
@patch.object(deferred_events.policy_rcd, 'add_policy_block')
@patch.object(deferred_events.policy_rcd, 'remove_policy_file')
@patch.object(deferred_events, 'is_restart_permitted')
@patch.object(deferred_events.policy_rcd, 'install_policy_rcd')
def test_configure_deferred_restarts(self, install_policy_rcd,
is_restart_permitted,
remove_policy_file, add_policy_block):
is_restart_permitted.return_value = True
deferred_events.configure_deferred_restarts(['svcA', 'svcB'])
remove_policy_file.assert_called_once_with()
install_policy_rcd.assert_called_once_with()
remove_policy_file.reset_mock()
install_policy_rcd.reset_mock()
is_restart_permitted.return_value = False
deferred_events.configure_deferred_restarts(['svcA', 'svcB'])
self.assertFalse(remove_policy_file.called)
install_policy_rcd.assert_called_once_with()
add_policy_block.assert_has_calls([
call('svcA', ['stop', 'restart', 'try-restart']),
call('svcB', ['stop', 'restart', 'try-restart'])])
@patch.object(deferred_events.subprocess, 'check_output')
def test_get_service_start_time(self, check_output):
check_output.return_value = (
b'ActiveEnterTimestamp=Tue 2021-02-02 13:19:55 UTC')
expect = datetime.datetime.strptime(
'Tue 2021-02-02 13:19:55 UTC',
'%a %Y-%m-%d %H:%M:%S %Z')
self.assertEqual(
deferred_events.get_service_start_time('svcA'),
expect)
check_output.assert_called_once_with(
['systemctl', 'show', 'svcA', '--property=ActiveEnterTimestamp'])
@patch.object(deferred_events, 'get_deferred_restarts')
@patch.object(deferred_events, 'clear_deferred_restarts')
@patch.object(deferred_events.hookenv, 'log')
@patch.object(deferred_events, 'get_service_start_time')
def test_check_restart_timestamps(self, get_service_start_time, log,
clear_deferred_restarts,
get_deferred_restarts):
deferred_restarts = [
# 'Tue 2021-02-02 10:19:55 UTC'
deferred_events.ServiceEvent(
timestamp=1612261195.0,
service='svcA',
reason='ReasonA',
action='restart')]
get_deferred_restarts.return_value = deferred_restarts
get_service_start_time.return_value = datetime.datetime.strptime(
'Tue 2021-02-02 13:19:55 UTC',
'%a %Y-%m-%d %H:%M:%S %Z')
deferred_events.check_restart_timestamps()
clear_deferred_restarts.assert_called_once_with(['svcA'])
clear_deferred_restarts.reset_mock()
get_service_start_time.return_value = datetime.datetime.strptime(
'Tue 2021-02-02 10:10:55 UTC',
'%a %Y-%m-%d %H:%M:%S %Z')
deferred_events.check_restart_timestamps()
self.assertFalse(clear_deferred_restarts.called)
log.assert_called_once_with(
('Restart still required, svcA was started at 2021-02-02 10:10:55,'
' restart was requested after that at 2021-02-02 10:19:55'),
level='DEBUG')
def test_set_deferred_hook(self):
deferred_events.set_deferred_hook('config-changed')
self.assertEqual(self.db.get('deferred-hooks'), ['config-changed'])
deferred_events.set_deferred_hook('leader-settings-changed')
self.assertEqual(
self.db.get('deferred-hooks'),
['config-changed', 'leader-settings-changed'])
def test_get_deferred_hook(self):
deferred_events.set_deferred_hook('config-changed')
self.assertEqual(
deferred_events.get_deferred_hooks(),
['config-changed'])
def test_clear_deferred_hooks(self):
deferred_events.set_deferred_hook('config-changed')
deferred_events.set_deferred_hook('leader-settings-changed')
self.assertEqual(
deferred_events.get_deferred_hooks(),
['config-changed', 'leader-settings-changed'])
deferred_events.clear_deferred_hooks()
self.assertEqual(
deferred_events.get_deferred_hooks(),
[])
def test_clear_deferred_hook(self):
deferred_events.set_deferred_hook('config-changed')
deferred_events.set_deferred_hook('leader-settings-changed')
self.assertEqual(
deferred_events.get_deferred_hooks(),
['config-changed', 'leader-settings-changed'])
deferred_events.clear_deferred_hook('leader-settings-changed')
self.assertEqual(
deferred_events.get_deferred_hooks(),
['config-changed'])