diff --git a/masakarimonitors/tests/unit/instancemonitor/fakes.py b/masakarimonitors/tests/unit/instancemonitor/fakes.py deleted file mode 100644 index 29ef484..0000000 --- a/masakarimonitors/tests/unit/instancemonitor/fakes.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright(c) 2016 Nippon Telegraph and Telephone Corporation -# -# 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. - - -class FakeLibvirtOpenReadOnly(object): - def domainEventRegisterAny(self, dom, eventID, cb, opaque): - return 1 - - def setKeepAlive(self, interval, count): - return None - - def isAlive(self): - return 0 - - def domainEventDeregisterAny(self, cid): - return None - - def close(self): - raise EnvironmentError("Test Exception.") - - -class FakeConnection(object): - def __init__(self): - class Ha(object): - def create_notification(self, type, hostname, generated_time, - payload): - return {} - self.ha = Ha() diff --git a/masakarimonitors/tests/unit/instancemonitor/libvirt_handler/test_callback.py b/masakarimonitors/tests/unit/instancemonitor/libvirt_handler/test_callback.py index 06e68f4..0190ab5 100644 --- a/masakarimonitors/tests/unit/instancemonitor/libvirt_handler/test_callback.py +++ b/masakarimonitors/tests/unit/instancemonitor/libvirt_handler/test_callback.py @@ -13,15 +13,16 @@ # limitations under the License. import mock +import socket import testtools +import uuid import eventlet -from openstack import connection -from openstack import profile from oslo_utils import timeutils +from masakarimonitors.ha import masakari from masakarimonitors.instancemonitor.libvirt_handler import callback -from masakarimonitors.tests.unit.instancemonitor import fakes +from masakarimonitors.objects import event_constants as ec eventlet.monkey_patch(os=False) @@ -31,38 +32,36 @@ class TestCallback(testtools.TestCase): def setUp(self): super(TestCallback, self).setUp() - @mock.patch.object(connection, 'Connection') - @mock.patch.object(profile.Profile, 'set_interface') - @mock.patch.object(profile.Profile, 'set_version') - @mock.patch.object(profile.Profile, 'set_region') - @mock.patch.object(profile.Profile, 'set_name') - @mock.patch.object(profile.Profile, '_add_service') - def test_vir_event_filter(self, - mock_add_service, - mock_set_name, - mock_set_region, - mock_set_version, - mock_set_interface, - mock_Connection): + @mock.patch.object(masakari.SendNotification, 'send_notification') + def test_libvirt_event_callback(self, mock_send_notification): + + mock_send_notification.return_value = None obj = callback.Callback() - mock_add_service.return_value = None - mock_set_name.return_value = None - mock_set_region.return_value = None - mock_set_version.return_value = None - mock_set_interface.return_value = None - mock_Connection.return_value = fakes.FakeConnection() + event_id = 0 + details = 5 + domain_uuid = uuid.uuid4() + notice_type = ec.EventConstants.TYPE_VM + hostname = socket.gethostname() + current_time = timeutils.utcnow() - eventID_val = 0 - detail_val = 5 - uuID = 'test_uuid' - noticeType = 'VM' - hostname = 'masakari-node' - currentTime = timeutils.utcnow() - obj.libvirt_event_callback(eventID_val, - detail_val, - uuID, - noticeType, - hostname, - currentTime) + obj.libvirt_event_callback(event_id, details, domain_uuid, + notice_type, hostname, current_time) + + retry_max = 12 + retry_interval = 10 + event = { + 'notification': { + 'type': notice_type, + 'hostname': hostname, + 'generated_time': current_time, + 'payload': { + 'event': event_id, + 'instance_uuid': domain_uuid, + 'vir_domain_event': details + } + } + } + mock_send_notification.assert_called_once_with( + retry_max, retry_interval, event) diff --git a/masakarimonitors/tests/unit/instancemonitor/libvirt_handler/test_eventfilter.py b/masakarimonitors/tests/unit/instancemonitor/libvirt_handler/test_eventfilter.py index 990d341..094b905 100644 --- a/masakarimonitors/tests/unit/instancemonitor/libvirt_handler/test_eventfilter.py +++ b/masakarimonitors/tests/unit/instancemonitor/libvirt_handler/test_eventfilter.py @@ -13,12 +13,20 @@ # limitations under the License. import mock +import socket import testtools +import threading +import uuid import eventlet +from oslo_utils import excutils +from oslo_utils import timeutils from masakarimonitors.instancemonitor.libvirt_handler import callback from masakarimonitors.instancemonitor.libvirt_handler import eventfilter +from masakarimonitors.instancemonitor.libvirt_handler \ + import eventfilter_table as evft +from masakarimonitors.objects import event_constants as ec eventlet.monkey_patch(os=False) @@ -28,16 +36,123 @@ class TestEventFilter(testtools.TestCase): def setUp(self): super(TestEventFilter, self).setUp() + @mock.patch.object(excutils, 'save_and_reraise_exception') @mock.patch.object(callback.Callback, 'libvirt_event_callback') - def test_vir_event_filter(self, - mock_libvirt_event_callback): + @mock.patch.object(timeutils, 'utcnow') + def test_vir_event_filter(self, mock_utcnow, mock_libvirt_event_callback, + mock_save_and_reraise_exception): + + current_time = timeutils.utcnow() + mock_utcnow.return_value = current_time + mock_libvirt_event_callback.return_value = None + mock_save_and_reraise_exception.return_value = None obj = eventfilter.EventFilter() - - mock_libvirt_event_callback.return_value = 0 - eventID = 0 eventType = 5 detail = 5 - uuID = 'test_uuid' + uuID = uuid.uuid4() obj.vir_event_filter(eventID, eventType, detail, uuID) + + mock_libvirt_event_callback.assert_called_once_with( + evft.eventID_dic[eventID], + evft.detail_dic[eventID][eventType][detail], + uuID, + ec.EventConstants.TYPE_VM, + socket.gethostname(), + current_time) + mock_save_and_reraise_exception.assert_not_called() + + @mock.patch.object(excutils, 'save_and_reraise_exception') + @mock.patch.object(callback.Callback, 'libvirt_event_callback') + def test_vir_event_filter_unmatched(self, mock_libvirt_event_callback, + mock_save_and_reraise_exception): + + mock_libvirt_event_callback.return_value = None + mock_save_and_reraise_exception.return_value = None + + obj = eventfilter.EventFilter() + eventID = 0 + eventType = 5 + detail = 2 + uuID = uuid.uuid4() + obj.vir_event_filter(eventID, eventType, detail, uuID) + + mock_libvirt_event_callback.assert_not_called() + mock_save_and_reraise_exception.assert_not_called() + + @mock.patch.object(excutils, 'save_and_reraise_exception') + @mock.patch.object(callback.Callback, 'libvirt_event_callback') + def test_vir_event_filter_key_error(self, mock_libvirt_event_callback, + mock_save_and_reraise_exception): + + mock_libvirt_event_callback.return_value = None + mock_save_and_reraise_exception.return_value = None + + obj = eventfilter.EventFilter() + eventID = 0 + eventType = 0 + detail = 0 + uuID = uuid.uuid4() + obj.vir_event_filter(eventID, eventType, detail, uuID) + + mock_libvirt_event_callback.assert_not_called() + mock_save_and_reraise_exception.assert_not_called() + + @mock.patch.object(excutils, 'save_and_reraise_exception') + @mock.patch.object(callback.Callback, 'libvirt_event_callback') + @mock.patch.object(threading, 'Thread') + def test_vir_event_filter_type_error(self, mock_Thread, + mock_libvirt_event_callback, mock_save_and_reraise_exception): + + mock_Thread.side_effect = TypeError("Threading exception.") + mock_libvirt_event_callback.return_value = None + mock_save_and_reraise_exception.return_value = None + + obj = eventfilter.EventFilter() + eventID = 0 + eventType = 5 + detail = 5 + uuID = uuid.uuid4() + obj.vir_event_filter(eventID, eventType, detail, uuID) + + mock_libvirt_event_callback.assert_not_called() + mock_save_and_reraise_exception.assert_not_called() + + @mock.patch.object(excutils, 'save_and_reraise_exception') + @mock.patch.object(callback.Callback, 'libvirt_event_callback') + @mock.patch.object(threading, 'Thread') + def test_vir_event_filter_index_error(self, mock_Thread, + mock_libvirt_event_callback, mock_save_and_reraise_exception): + + mock_Thread.side_effect = IndexError("Threading exception.") + mock_libvirt_event_callback.return_value = None + mock_save_and_reraise_exception.return_value = None + + obj = eventfilter.EventFilter() + eventID = 0 + eventType = 5 + detail = 5 + uuID = uuid.uuid4() + obj.vir_event_filter(eventID, eventType, detail, uuID) + + mock_libvirt_event_callback.assert_not_called() + mock_save_and_reraise_exception.assert_not_called() + + @mock.patch.object(callback.Callback, 'libvirt_event_callback') + @mock.patch.object(threading, 'Thread') + def test_vir_event_filter_other_exception(self, mock_Thread, + mock_libvirt_event_callback): + + mock_Thread.side_effect = NameError("Threading exception.") + mock_libvirt_event_callback.return_value = None + + obj = eventfilter.EventFilter() + eventID = 0 + eventType = 5 + detail = 5 + uuID = uuid.uuid4() + self.assertRaises(NameError, obj.vir_event_filter, eventID, eventType, + detail, uuID) + + mock_libvirt_event_callback.assert_not_called() diff --git a/masakarimonitors/tests/unit/instancemonitor/test_instance.py b/masakarimonitors/tests/unit/instancemonitor/test_instance.py index 2b204bd..ead7d7e 100644 --- a/masakarimonitors/tests/unit/instancemonitor/test_instance.py +++ b/masakarimonitors/tests/unit/instancemonitor/test_instance.py @@ -15,12 +15,14 @@ import libvirt import mock import testtools +import threading +import time +import uuid import eventlet from masakarimonitors.instancemonitor import instance from masakarimonitors.instancemonitor.libvirt_handler import eventfilter -from masakarimonitors.tests.unit.instancemonitor import fakes eventlet.monkey_patch(os=False) @@ -30,25 +32,221 @@ class TestInstancemonitorManager(testtools.TestCase): def setUp(self): super(TestInstancemonitorManager, self).setUp() - @mock.patch.object(libvirt, 'openReadOnly') - @mock.patch.object(eventfilter.EventFilter, 'vir_event_filter') - @mock.patch.object(instance.InstancemonitorManager, - '_vir_event_loop_native_start') - def test_main(self, - mock_vir_event_loop_native_start, - mock_vir_event_filter, - mock_openReadOnly): + def _make_callback_params(self): + mock_conn = mock.Mock() + mock_dom = mock.Mock() + test_uuid = uuid.uuid4() + mock_dom.UUIDString.return_value = test_uuid + mock_opaque = mock.Mock() + + return mock_conn, mock_dom, mock_opaque, test_uuid + + @mock.patch.object(libvirt, 'virEventRunDefaultImpl') + def test_vir_event_loop_native_run(self, mock_virEventRunDefaultImpl): + mock_virEventRunDefaultImpl.side_effect = Exception("Test exception.") obj = instance.InstancemonitorManager() - - mock_vir_event_loop_native_start.return_value = None - mock_vir_event_filter.return_value = None - mock_openReadOnly.return_value = fakes.FakeLibvirtOpenReadOnly() - exception_flag = False try: - obj.main() - except EnvironmentError: + obj._vir_event_loop_native_run() + except Exception: exception_flag = True self.assertTrue(exception_flag) + mock_virEventRunDefaultImpl.assert_called_once() + + @mock.patch.object(eventfilter.EventFilter, 'vir_event_filter') + def test_my_domain_event_callback(self, mock_vir_event_filter): + mock_vir_event_filter.return_value = None + mock_conn, mock_dom, mock_opaque, test_uuid = \ + self._make_callback_params() + + obj = instance.InstancemonitorManager() + obj._my_domain_event_callback(mock_conn, mock_dom, 0, 1, mock_opaque) + + mock_vir_event_filter.assert_called_once_with( + libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE, 0, 1, test_uuid) + + @mock.patch.object(eventfilter.EventFilter, 'vir_event_filter') + def test_my_domain_event_reboot_callback(self, mock_vir_event_filter): + mock_vir_event_filter.return_value = None + mock_conn, mock_dom, mock_opaque, test_uuid = \ + self._make_callback_params() + + obj = instance.InstancemonitorManager() + obj._my_domain_event_reboot_callback(mock_conn, mock_dom, mock_opaque) + + mock_vir_event_filter.assert_called_once_with( + libvirt.VIR_DOMAIN_EVENT_ID_REBOOT, -1, -1, test_uuid) + + @mock.patch.object(eventfilter.EventFilter, 'vir_event_filter') + def test_my_domain_event_rtc_change_callback(self, mock_vir_event_filter): + mock_vir_event_filter.return_value = None + mock_conn, mock_dom, mock_opaque, test_uuid = \ + self._make_callback_params() + utcoffset = "" + + obj = instance.InstancemonitorManager() + obj._my_domain_event_rtc_change_callback( + mock_conn, mock_dom, utcoffset, mock_opaque) + + mock_vir_event_filter.assert_called_once_with( + libvirt.VIR_DOMAIN_EVENT_ID_RTC_CHANGE, -1, -1, test_uuid) + + @mock.patch.object(eventfilter.EventFilter, 'vir_event_filter') + def test_my_domain_event_watchdog_callback(self, mock_vir_event_filter): + mock_vir_event_filter.return_value = None + mock_conn, mock_dom, mock_opaque, test_uuid = \ + self._make_callback_params() + action = 0 + + obj = instance.InstancemonitorManager() + obj._my_domain_event_watchdog_callback( + mock_conn, mock_dom, action, mock_opaque) + + mock_vir_event_filter.assert_called_once_with( + libvirt.VIR_DOMAIN_EVENT_ID_WATCHDOG, action, -1, test_uuid) + + @mock.patch.object(eventfilter.EventFilter, 'vir_event_filter') + def test_my_domain_event_io_error_callback(self, mock_vir_event_filter): + mock_vir_event_filter.return_value = None + mock_conn, mock_dom, mock_opaque, test_uuid = \ + self._make_callback_params() + srcpath = "" + devalias = "" + action = 0 + + obj = instance.InstancemonitorManager() + obj._my_domain_event_io_error_callback( + mock_conn, mock_dom, srcpath, devalias, action, mock_opaque) + + mock_vir_event_filter.assert_called_once_with( + libvirt.VIR_DOMAIN_EVENT_ID_IO_ERROR, action, -1, test_uuid) + + @mock.patch.object(eventfilter.EventFilter, 'vir_event_filter') + def test_my_domain_event_graphics_callback(self, mock_vir_event_filter): + mock_vir_event_filter.return_value = None + mock_conn, mock_dom, mock_opaque, test_uuid = \ + self._make_callback_params() + phase = 0 + localAddr = "" + remoteAddr = "" + authScheme = "" + subject = "" + + obj = instance.InstancemonitorManager() + obj._my_domain_event_graphics_callback( + mock_conn, mock_dom, phase, localAddr, remoteAddr, authScheme, + subject, mock_opaque) + + mock_vir_event_filter.assert_called_once_with( + libvirt.VIR_DOMAIN_EVENT_ID_GRAPHICS, -1, phase, test_uuid) + + @mock.patch.object(eventfilter.EventFilter, 'vir_event_filter') + def test_my_domain_event_disk_change_callback( + self, mock_vir_event_filter): + mock_vir_event_filter.return_value = None + mock_conn, mock_dom, mock_opaque, test_uuid = \ + self._make_callback_params() + oldSrcPath = "" + newSrcPath = "" + devAlias = "" + reason = "" + + obj = instance.InstancemonitorManager() + obj._my_domain_event_disk_change_callback( + mock_conn, mock_dom, oldSrcPath, newSrcPath, devAlias, reason, + mock_opaque) + + mock_vir_event_filter.assert_called_once_with( + libvirt.VIR_DOMAIN_EVENT_ID_DISK_CHANGE, -1, -1, test_uuid) + + @mock.patch.object(eventfilter.EventFilter, 'vir_event_filter') + def test_my_domain_event_io_error_reason_callback( + self, mock_vir_event_filter): + mock_vir_event_filter.return_value = None + mock_conn, mock_dom, mock_opaque, test_uuid = \ + self._make_callback_params() + srcPath = "" + devAlias = "" + action = "" + reason = "" + + obj = instance.InstancemonitorManager() + obj._my_domain_event_io_error_reason_callback( + mock_conn, mock_dom, srcPath, devAlias, action, reason, + mock_opaque) + + mock_vir_event_filter.assert_called_once_with( + libvirt.VIR_DOMAIN_EVENT_ID_IO_ERROR_REASON, -1, -1, test_uuid) + + @mock.patch.object(eventfilter.EventFilter, 'vir_event_filter') + def test_my_domain_event_generic_callback(self, mock_vir_event_filter): + mock_vir_event_filter.return_value = None + mock_conn, mock_dom, mock_opaque, test_uuid = \ + self._make_callback_params() + + obj = instance.InstancemonitorManager() + obj._my_domain_event_generic_callback( + mock_conn, mock_dom, mock_opaque) + + mock_vir_event_filter.assert_called_once_with( + libvirt.VIR_DOMAIN_EVENT_ID_CONTROL_ERROR, -1, -1, test_uuid) + + def test_err_handler(self): + obj = instance.InstancemonitorManager() + obj._err_handler("Test context.", ('err0.', 'err1', 'err2')) + + def test_stop(self): + obj = instance.InstancemonitorManager() + obj.stop() + self.assertFalse(obj.running) + + @mock.patch.object(time, 'sleep') + @mock.patch.object(eventlet.greenthread, 'sleep') + @mock.patch.object(libvirt, 'openReadOnly') + @mock.patch.object(threading, 'Thread') + @mock.patch.object(libvirt, 'virEventRegisterDefaultImpl') + def test_main(self, + mock_virEventRegisterDefaultImpl, + mock_Thread, + mock_openReadOnly, + mock_greenthread_sleep, + mock_time_sleep): + + mock_virEventRegisterDefaultImpl.return_value = None + mock_event_loop_thread = mock.Mock(return_value=None) + mock_Thread.return_value = mock_event_loop_thread + mock_vc = mock.Mock() + mock_openReadOnly.return_value = mock_vc + mock_vc.domainEventRegisterAny.side_effect = \ + [0, 0, 0, 0, 0, 0, 0, 0, 0] + mock_vc.setKeepAlive.return_value = None + mock_vc.isAlive.side_effect = [1, 0] + mock_vc.domainEventDeregisterAny.side_effect = \ + [None, None, None, None, None, None, None, None, + Exception("Test exception.")] + mock_vc.close.return_value = None + mock_greenthread_sleep.return_value = None + mock_time_sleep.side_effect = Exception("Test exception.") + + obj = instance.InstancemonitorManager() + exception_flag = False + try: + obj.main() + except Exception: + exception_flag = True + + handlers_count = 9 + self.assertTrue(exception_flag) + mock_virEventRegisterDefaultImpl.assert_called_once() + mock_event_loop_thread.setDaemon.assert_called_once_with(True) + mock_event_loop_thread.start.assert_called_once() + mock_openReadOnly.assert_called_once_with("qemu:///system") + self.assertEqual( + handlers_count, mock_vc.domainEventRegisterAny.call_count) + mock_vc.setKeepAlive.assert_called_once_with(5, 3) + self.assertEqual(2, mock_vc.isAlive.call_count) + self.assertEqual( + handlers_count, mock_vc.domainEventDeregisterAny.call_count) + mock_vc.close.assert_called_once()