Blame tests/unittests/test_reporting.py

Packit bc9a3a
# Copyright 2015 Canonical Ltd.
Packit bc9a3a
#
Packit bc9a3a
# This file is part of cloud-init. See LICENSE file for license information.
Packit bc9a3a
Packit bc9a3a
from cloudinit import reporting
Packit bc9a3a
from cloudinit.reporting import events
Packit bc9a3a
from cloudinit.reporting import handlers
Packit bc9a3a
Packit bc9a3a
import mock
Packit bc9a3a
Packit bc9a3a
from cloudinit.tests.helpers import TestCase
Packit bc9a3a
Packit bc9a3a
Packit bc9a3a
def _fake_registry():
Packit bc9a3a
    return mock.Mock(registered_items={'a': mock.MagicMock(),
Packit bc9a3a
                                       'b': mock.MagicMock()})
Packit bc9a3a
Packit bc9a3a
Packit bc9a3a
class TestReportStartEvent(TestCase):
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.reporting.events.instantiated_handler_registry',
Packit bc9a3a
                new_callable=_fake_registry)
Packit bc9a3a
    def test_report_start_event_passes_something_with_as_string_to_handlers(
Packit bc9a3a
            self, instantiated_handler_registry):
Packit bc9a3a
        event_name, event_description = 'my_test_event', 'my description'
Packit bc9a3a
        events.report_start_event(event_name, event_description)
Packit bc9a3a
        expected_string_representation = ': '.join(
Packit bc9a3a
            ['start', event_name, event_description])
Packit bc9a3a
        for _, handler in (
Packit bc9a3a
                instantiated_handler_registry.registered_items.items()):
Packit bc9a3a
            self.assertEqual(1, handler.publish_event.call_count)
Packit bc9a3a
            event = handler.publish_event.call_args[0][0]
Packit bc9a3a
            self.assertEqual(expected_string_representation, event.as_string())
Packit bc9a3a
Packit bc9a3a
Packit bc9a3a
class TestReportFinishEvent(TestCase):
Packit bc9a3a
Packit bc9a3a
    def _report_finish_event(self, result=events.status.SUCCESS):
Packit bc9a3a
        event_name, event_description = 'my_test_event', 'my description'
Packit bc9a3a
        events.report_finish_event(
Packit bc9a3a
            event_name, event_description, result=result)
Packit bc9a3a
        return event_name, event_description
Packit bc9a3a
Packit bc9a3a
    def assertHandlersPassedObjectWithAsString(
Packit bc9a3a
            self, handlers, expected_as_string):
Packit bc9a3a
        for _, handler in handlers.items():
Packit bc9a3a
            self.assertEqual(1, handler.publish_event.call_count)
Packit bc9a3a
            event = handler.publish_event.call_args[0][0]
Packit bc9a3a
            self.assertEqual(expected_as_string, event.as_string())
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.reporting.events.instantiated_handler_registry',
Packit bc9a3a
                new_callable=_fake_registry)
Packit bc9a3a
    def test_report_finish_event_passes_something_with_as_string_to_handlers(
Packit bc9a3a
            self, instantiated_handler_registry):
Packit bc9a3a
        event_name, event_description = self._report_finish_event()
Packit bc9a3a
        expected_string_representation = ': '.join(
Packit bc9a3a
            ['finish', event_name, events.status.SUCCESS,
Packit bc9a3a
             event_description])
Packit bc9a3a
        self.assertHandlersPassedObjectWithAsString(
Packit bc9a3a
            instantiated_handler_registry.registered_items,
Packit bc9a3a
            expected_string_representation)
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.reporting.events.instantiated_handler_registry',
Packit bc9a3a
                new_callable=_fake_registry)
Packit bc9a3a
    def test_reporting_successful_finish_has_sensible_string_repr(
Packit bc9a3a
            self, instantiated_handler_registry):
Packit bc9a3a
        event_name, event_description = self._report_finish_event(
Packit bc9a3a
            result=events.status.SUCCESS)
Packit bc9a3a
        expected_string_representation = ': '.join(
Packit bc9a3a
            ['finish', event_name, events.status.SUCCESS,
Packit bc9a3a
             event_description])
Packit bc9a3a
        self.assertHandlersPassedObjectWithAsString(
Packit bc9a3a
            instantiated_handler_registry.registered_items,
Packit bc9a3a
            expected_string_representation)
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.reporting.events.instantiated_handler_registry',
Packit bc9a3a
                new_callable=_fake_registry)
Packit bc9a3a
    def test_reporting_unsuccessful_finish_has_sensible_string_repr(
Packit bc9a3a
            self, instantiated_handler_registry):
Packit bc9a3a
        event_name, event_description = self._report_finish_event(
Packit bc9a3a
            result=events.status.FAIL)
Packit bc9a3a
        expected_string_representation = ': '.join(
Packit bc9a3a
            ['finish', event_name, events.status.FAIL, event_description])
Packit bc9a3a
        self.assertHandlersPassedObjectWithAsString(
Packit bc9a3a
            instantiated_handler_registry.registered_items,
Packit bc9a3a
            expected_string_representation)
Packit bc9a3a
Packit bc9a3a
    def test_invalid_result_raises_attribute_error(self):
Packit bc9a3a
        self.assertRaises(ValueError, self._report_finish_event, ("BOGUS",))
Packit bc9a3a
Packit bc9a3a
Packit bc9a3a
class TestReportingEvent(TestCase):
Packit bc9a3a
Packit bc9a3a
    def test_as_string(self):
Packit bc9a3a
        event_type, name, description = 'test_type', 'test_name', 'test_desc'
Packit bc9a3a
        event = events.ReportingEvent(event_type, name, description)
Packit bc9a3a
        expected_string_representation = ': '.join(
Packit bc9a3a
            [event_type, name, description])
Packit bc9a3a
        self.assertEqual(expected_string_representation, event.as_string())
Packit bc9a3a
Packit bc9a3a
    def test_as_dict(self):
Packit bc9a3a
        event_type, name, desc = 'test_type', 'test_name', 'test_desc'
Packit bc9a3a
        event = events.ReportingEvent(event_type, name, desc)
Packit bc9a3a
        expected = {'event_type': event_type, 'name': name,
Packit bc9a3a
                    'description': desc, 'origin': 'cloudinit'}
Packit bc9a3a
Packit bc9a3a
        # allow for timestamp to differ, but must be present
Packit bc9a3a
        as_dict = event.as_dict()
Packit bc9a3a
        self.assertIn('timestamp', as_dict)
Packit bc9a3a
        del as_dict['timestamp']
Packit bc9a3a
Packit bc9a3a
        self.assertEqual(expected, as_dict)
Packit bc9a3a
Packit bc9a3a
Packit bc9a3a
class TestFinishReportingEvent(TestCase):
Packit bc9a3a
    def test_as_has_result(self):
Packit bc9a3a
        result = events.status.SUCCESS
Packit bc9a3a
        name, desc = 'test_name', 'test_desc'
Packit bc9a3a
        event = events.FinishReportingEvent(name, desc, result)
Packit bc9a3a
        ret = event.as_dict()
Packit bc9a3a
        self.assertTrue('result' in ret)
Packit bc9a3a
        self.assertEqual(ret['result'], result)
Packit bc9a3a
Packit bc9a3a
Packit bc9a3a
class TestBaseReportingHandler(TestCase):
Packit bc9a3a
Packit bc9a3a
    def test_base_reporting_handler_is_abstract(self):
Packit bc9a3a
        regexp = r".*abstract.*publish_event.*"
Packit bc9a3a
        self.assertRaisesRegex(TypeError, regexp, handlers.ReportingHandler)
Packit bc9a3a
Packit bc9a3a
Packit bc9a3a
class TestLogHandler(TestCase):
Packit bc9a3a
Packit bc9a3a
    @mock.patch.object(reporting.handlers.logging, 'getLogger')
Packit bc9a3a
    def test_appropriate_logger_used(self, getLogger):
Packit bc9a3a
        event_type, event_name = 'test_type', 'test_name'
Packit bc9a3a
        event = events.ReportingEvent(event_type, event_name, 'description')
Packit bc9a3a
        reporting.handlers.LogHandler().publish_event(event)
Packit bc9a3a
        self.assertEqual(
Packit bc9a3a
            [mock.call(
Packit bc9a3a
                'cloudinit.reporting.{0}.{1}'.format(event_type, event_name))],
Packit bc9a3a
            getLogger.call_args_list)
Packit bc9a3a
Packit bc9a3a
    @mock.patch.object(reporting.handlers.logging, 'getLogger')
Packit bc9a3a
    def test_single_log_message_at_info_published(self, getLogger):
Packit bc9a3a
        event = events.ReportingEvent('type', 'name', 'description')
Packit bc9a3a
        reporting.handlers.LogHandler().publish_event(event)
Packit bc9a3a
        self.assertEqual(1, getLogger.return_value.log.call_count)
Packit bc9a3a
Packit bc9a3a
    @mock.patch.object(reporting.handlers.logging, 'getLogger')
Packit bc9a3a
    def test_log_message_uses_event_as_string(self, getLogger):
Packit bc9a3a
        event = events.ReportingEvent('type', 'name', 'description')
Packit bc9a3a
        reporting.handlers.LogHandler(level="INFO").publish_event(event)
Packit bc9a3a
        self.assertIn(event.as_string(),
Packit bc9a3a
                      getLogger.return_value.log.call_args[0][1])
Packit bc9a3a
Packit bc9a3a
Packit bc9a3a
class TestDefaultRegisteredHandler(TestCase):
Packit bc9a3a
Packit bc9a3a
    def test_log_handler_registered_by_default(self):
Packit bc9a3a
        registered_items = (
Packit bc9a3a
            reporting.instantiated_handler_registry.registered_items)
Packit bc9a3a
        for _, item in registered_items.items():
Packit bc9a3a
            if isinstance(item, reporting.handlers.LogHandler):
Packit bc9a3a
                break
Packit bc9a3a
        else:
Packit bc9a3a
            self.fail('No reporting LogHandler registered by default.')
Packit bc9a3a
Packit bc9a3a
Packit bc9a3a
class TestReportingConfiguration(TestCase):
Packit bc9a3a
Packit bc9a3a
    @mock.patch.object(reporting, 'instantiated_handler_registry')
Packit bc9a3a
    def test_empty_configuration_doesnt_add_handlers(
Packit bc9a3a
            self, instantiated_handler_registry):
Packit bc9a3a
        reporting.update_configuration({})
Packit bc9a3a
        self.assertEqual(
Packit bc9a3a
            0, instantiated_handler_registry.register_item.call_count)
Packit bc9a3a
Packit bc9a3a
    @mock.patch.object(
Packit bc9a3a
        reporting, 'instantiated_handler_registry', reporting.DictRegistry())
Packit bc9a3a
    @mock.patch.object(reporting, 'available_handlers')
Packit bc9a3a
    def test_looks_up_handler_by_type_and_adds_it(self, available_handlers):
Packit bc9a3a
        handler_type_name = 'test_handler'
Packit bc9a3a
        handler_cls = mock.Mock()
Packit bc9a3a
        available_handlers.registered_items = {handler_type_name: handler_cls}
Packit bc9a3a
        handler_name = 'my_test_handler'
Packit bc9a3a
        reporting.update_configuration(
Packit bc9a3a
            {handler_name: {'type': handler_type_name}})
Packit bc9a3a
        self.assertEqual(
Packit bc9a3a
            {handler_name: handler_cls.return_value},
Packit bc9a3a
            reporting.instantiated_handler_registry.registered_items)
Packit bc9a3a
Packit bc9a3a
    @mock.patch.object(
Packit bc9a3a
        reporting, 'instantiated_handler_registry', reporting.DictRegistry())
Packit bc9a3a
    @mock.patch.object(reporting, 'available_handlers')
Packit bc9a3a
    def test_uses_non_type_parts_of_config_dict_as_kwargs(
Packit bc9a3a
            self, available_handlers):
Packit bc9a3a
        handler_type_name = 'test_handler'
Packit bc9a3a
        handler_cls = mock.Mock()
Packit bc9a3a
        available_handlers.registered_items = {handler_type_name: handler_cls}
Packit bc9a3a
        extra_kwargs = {'foo': 'bar', 'bar': 'baz'}
Packit bc9a3a
        handler_config = extra_kwargs.copy()
Packit bc9a3a
        handler_config.update({'type': handler_type_name})
Packit bc9a3a
        handler_name = 'my_test_handler'
Packit bc9a3a
        reporting.update_configuration({handler_name: handler_config})
Packit bc9a3a
        self.assertEqual(
Packit bc9a3a
            handler_cls.return_value,
Packit bc9a3a
            reporting.instantiated_handler_registry.registered_items[
Packit bc9a3a
                handler_name])
Packit bc9a3a
        self.assertEqual([mock.call(**extra_kwargs)],
Packit bc9a3a
                         handler_cls.call_args_list)
Packit bc9a3a
Packit bc9a3a
    @mock.patch.object(
Packit bc9a3a
        reporting, 'instantiated_handler_registry', reporting.DictRegistry())
Packit bc9a3a
    @mock.patch.object(reporting, 'available_handlers')
Packit bc9a3a
    def test_handler_config_not_modified(self, available_handlers):
Packit bc9a3a
        handler_type_name = 'test_handler'
Packit bc9a3a
        handler_cls = mock.Mock()
Packit bc9a3a
        available_handlers.registered_items = {handler_type_name: handler_cls}
Packit bc9a3a
        handler_config = {'type': handler_type_name, 'foo': 'bar'}
Packit bc9a3a
        expected_handler_config = handler_config.copy()
Packit bc9a3a
        reporting.update_configuration({'my_test_handler': handler_config})
Packit bc9a3a
        self.assertEqual(expected_handler_config, handler_config)
Packit bc9a3a
Packit bc9a3a
    @mock.patch.object(
Packit bc9a3a
        reporting, 'instantiated_handler_registry', reporting.DictRegistry())
Packit bc9a3a
    @mock.patch.object(reporting, 'available_handlers')
Packit bc9a3a
    def test_handlers_removed_if_falseish_specified(self, available_handlers):
Packit bc9a3a
        handler_type_name = 'test_handler'
Packit bc9a3a
        handler_cls = mock.Mock()
Packit bc9a3a
        available_handlers.registered_items = {handler_type_name: handler_cls}
Packit bc9a3a
        handler_name = 'my_test_handler'
Packit bc9a3a
        reporting.update_configuration(
Packit bc9a3a
            {handler_name: {'type': handler_type_name}})
Packit bc9a3a
        self.assertEqual(
Packit bc9a3a
            1, len(reporting.instantiated_handler_registry.registered_items))
Packit bc9a3a
        reporting.update_configuration({handler_name: None})
Packit bc9a3a
        self.assertEqual(
Packit bc9a3a
            0, len(reporting.instantiated_handler_registry.registered_items))
Packit bc9a3a
Packit bc9a3a
Packit bc9a3a
class TestReportingEventStack(TestCase):
Packit bc9a3a
    @mock.patch('cloudinit.reporting.events.report_finish_event')
Packit bc9a3a
    @mock.patch('cloudinit.reporting.events.report_start_event')
Packit bc9a3a
    def test_start_and_finish_success(self, report_start, report_finish):
Packit bc9a3a
        with events.ReportEventStack(name="myname", description="mydesc"):
Packit bc9a3a
            pass
Packit bc9a3a
        self.assertEqual(
Packit bc9a3a
            [mock.call('myname', 'mydesc')], report_start.call_args_list)
Packit bc9a3a
        self.assertEqual(
Packit bc9a3a
            [mock.call('myname', 'mydesc', events.status.SUCCESS,
Packit bc9a3a
                       post_files=[])],
Packit bc9a3a
            report_finish.call_args_list)
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.reporting.events.report_finish_event')
Packit bc9a3a
    @mock.patch('cloudinit.reporting.events.report_start_event')
Packit bc9a3a
    def test_finish_exception_defaults_fail(self, report_start, report_finish):
Packit bc9a3a
        name = "myname"
Packit bc9a3a
        desc = "mydesc"
Packit bc9a3a
        try:
Packit bc9a3a
            with events.ReportEventStack(name, description=desc):
Packit bc9a3a
                raise ValueError("This didnt work")
Packit bc9a3a
        except ValueError:
Packit bc9a3a
            pass
Packit bc9a3a
        self.assertEqual([mock.call(name, desc)], report_start.call_args_list)
Packit bc9a3a
        self.assertEqual(
Packit bc9a3a
            [mock.call(name, desc, events.status.FAIL, post_files=[])],
Packit bc9a3a
            report_finish.call_args_list)
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.reporting.events.report_finish_event')
Packit bc9a3a
    @mock.patch('cloudinit.reporting.events.report_start_event')
Packit bc9a3a
    def test_result_on_exception_used(self, report_start, report_finish):
Packit bc9a3a
        name = "myname"
Packit bc9a3a
        desc = "mydesc"
Packit bc9a3a
        try:
Packit bc9a3a
            with events.ReportEventStack(
Packit bc9a3a
                    name, desc, result_on_exception=events.status.WARN):
Packit bc9a3a
                raise ValueError("This didnt work")
Packit bc9a3a
        except ValueError:
Packit bc9a3a
            pass
Packit bc9a3a
        self.assertEqual([mock.call(name, desc)], report_start.call_args_list)
Packit bc9a3a
        self.assertEqual(
Packit bc9a3a
            [mock.call(name, desc, events.status.WARN, post_files=[])],
Packit bc9a3a
            report_finish.call_args_list)
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.reporting.events.report_start_event')
Packit bc9a3a
    def test_child_fullname_respects_parent(self, report_start):
Packit bc9a3a
        parent_name = "topname"
Packit bc9a3a
        c1_name = "c1name"
Packit bc9a3a
        c2_name = "c2name"
Packit bc9a3a
        c2_expected_fullname = '/'.join([parent_name, c1_name, c2_name])
Packit bc9a3a
        c1_expected_fullname = '/'.join([parent_name, c1_name])
Packit bc9a3a
Packit bc9a3a
        parent = events.ReportEventStack(parent_name, "topdesc")
Packit bc9a3a
        c1 = events.ReportEventStack(c1_name, "c1desc", parent=parent)
Packit bc9a3a
        c2 = events.ReportEventStack(c2_name, "c2desc", parent=c1)
Packit bc9a3a
        with c1:
Packit bc9a3a
            report_start.assert_called_with(c1_expected_fullname, "c1desc")
Packit bc9a3a
            with c2:
Packit bc9a3a
                report_start.assert_called_with(c2_expected_fullname, "c2desc")
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.reporting.events.report_finish_event')
Packit bc9a3a
    @mock.patch('cloudinit.reporting.events.report_start_event')
Packit bc9a3a
    def test_child_result_bubbles_up(self, report_start, report_finish):
Packit bc9a3a
        parent = events.ReportEventStack("topname", "topdesc")
Packit bc9a3a
        child = events.ReportEventStack("c_name", "c_desc", parent=parent)
Packit bc9a3a
        with parent:
Packit bc9a3a
            with child:
Packit bc9a3a
                child.result = events.status.WARN
Packit bc9a3a
Packit bc9a3a
        report_finish.assert_called_with(
Packit bc9a3a
            "topname", "topdesc", events.status.WARN, post_files=[])
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.reporting.events.report_finish_event')
Packit bc9a3a
    def test_message_used_in_finish(self, report_finish):
Packit bc9a3a
        with events.ReportEventStack("myname", "mydesc",
Packit bc9a3a
                                     message="mymessage"):
Packit bc9a3a
            pass
Packit bc9a3a
        self.assertEqual(
Packit bc9a3a
            [mock.call("myname", "mymessage", events.status.SUCCESS,
Packit bc9a3a
                       post_files=[])],
Packit bc9a3a
            report_finish.call_args_list)
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.reporting.events.report_finish_event')
Packit bc9a3a
    def test_message_updatable(self, report_finish):
Packit bc9a3a
        with events.ReportEventStack("myname", "mydesc") as c:
Packit bc9a3a
            c.message = "all good"
Packit bc9a3a
        self.assertEqual(
Packit bc9a3a
            [mock.call("myname", "all good", events.status.SUCCESS,
Packit bc9a3a
                       post_files=[])],
Packit bc9a3a
            report_finish.call_args_list)
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.reporting.events.report_start_event')
Packit bc9a3a
    @mock.patch('cloudinit.reporting.events.report_finish_event')
Packit bc9a3a
    def test_reporting_disabled_does_not_report_events(
Packit bc9a3a
            self, report_start, report_finish):
Packit bc9a3a
        with events.ReportEventStack("a", "b", reporting_enabled=False):
Packit bc9a3a
            pass
Packit bc9a3a
        self.assertEqual(report_start.call_count, 0)
Packit bc9a3a
        self.assertEqual(report_finish.call_count, 0)
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.reporting.events.report_start_event')
Packit bc9a3a
    @mock.patch('cloudinit.reporting.events.report_finish_event')
Packit bc9a3a
    def test_reporting_child_default_to_parent(
Packit bc9a3a
            self, report_start, report_finish):
Packit bc9a3a
        parent = events.ReportEventStack(
Packit bc9a3a
            "pname", "pdesc", reporting_enabled=False)
Packit bc9a3a
        child = events.ReportEventStack("cname", "cdesc", parent=parent)
Packit bc9a3a
        with parent:
Packit bc9a3a
            with child:
Packit bc9a3a
                pass
Packit bc9a3a
            pass
Packit bc9a3a
        self.assertEqual(report_start.call_count, 0)
Packit bc9a3a
        self.assertEqual(report_finish.call_count, 0)
Packit bc9a3a
Packit bc9a3a
    def test_reporting_event_has_sane_repr(self):
Packit bc9a3a
        myrep = events.ReportEventStack("fooname", "foodesc",
Packit bc9a3a
                                        reporting_enabled=True).__repr__()
Packit bc9a3a
        self.assertIn("fooname", myrep)
Packit bc9a3a
        self.assertIn("foodesc", myrep)
Packit bc9a3a
        self.assertIn("True", myrep)
Packit bc9a3a
Packit bc9a3a
    def test_set_invalid_result_raises_value_error(self):
Packit bc9a3a
        f = events.ReportEventStack("myname", "mydesc")
Packit bc9a3a
        self.assertRaises(ValueError, setattr, f, "result", "BOGUS")
Packit bc9a3a
Packit bc9a3a
Packit bc9a3a
class TestStatusAccess(TestCase):
Packit bc9a3a
    def test_invalid_status_access_raises_value_error(self):
Packit bc9a3a
        self.assertRaises(AttributeError, getattr, events.status, "BOGUS")
Packit bc9a3a
Packit bc9a3a
# vi: ts=4 expandtab