From b5f5a16704c530622b320e856eda434a5878b0d9 Mon Sep 17 00:00:00 2001 From: Daniel Watkins Date: Fri, 17 Jul 2015 13:09:32 +0100 Subject: [PATCH] Use a registry to configure reporting handlers. Also ensure that the LogHandler is registered by default. Change-Id: Ib9e306a0aa45ab6f5c9b543782b5dd7019b72cf1 --- cloudinit/reporting.py | 7 ++-- cloudinit/tests/test_reporting.py | 53 ++++++++++++++++++++----------- 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/cloudinit/reporting.py b/cloudinit/reporting.py index c7a94b58..32f98bfe 100644 --- a/cloudinit/reporting.py +++ b/cloudinit/reporting.py @@ -12,6 +12,8 @@ report events in a structured manner. import abc import logging +from cloudinit.registry import DictRegistry + FINISH_EVENT_TYPE = 'finish' START_EVENT_TYPE = 'start' @@ -63,7 +65,8 @@ class LogHandler(ReportingHandler): logger.info(event.as_string()) -HANDLERS = [LogHandler()] +handler_registry = DictRegistry() +handler_registry.register_item('_logging', LogHandler()) def report_event(event): @@ -76,7 +79,7 @@ def report_event(event): The type of the event; this should be a constant from the reporting module. """ - for handler in HANDLERS: + for _, handler in handler_registry.registered_items.items(): handler.publish_event(event) diff --git a/cloudinit/tests/test_reporting.py b/cloudinit/tests/test_reporting.py index 54e0995a..a297ccdf 100644 --- a/cloudinit/tests/test_reporting.py +++ b/cloudinit/tests/test_reporting.py @@ -10,17 +10,22 @@ from cloudinit.tests import TestCase from cloudinit.tests.util import mock +def _fake_registry(): + return mock.Mock(registered_items={'a': mock.MagicMock(), + 'b': mock.MagicMock()}) + + class TestReportStartEvent(unittest.TestCase): - @mock.patch('cloudinit.reporting.HANDLERS', - new_callable=lambda: [mock.MagicMock(), mock.MagicMock()]) + @mock.patch('cloudinit.reporting.handler_registry', + new_callable=_fake_registry) def test_report_start_event_passes_something_with_as_string_to_handlers( - self, HANDLERS): + self, handler_registry): event_name, event_description = 'my_test_event', 'my description' reporting.report_start_event(event_name, event_description) expected_string_representation = ': '.join( ['start', event_name, event_description]) - for handler in HANDLERS: + for _, handler in handler_registry.registered_items.items(): self.assertEqual(1, handler.publish_event.call_count) event = handler.publish_event.call_args[0][0] self.assertEqual(expected_string_representation, event.as_string()) @@ -36,42 +41,42 @@ class TestReportFinishEvent(unittest.TestCase): def assertHandlersPassedObjectWithAsString( self, handlers, expected_as_string): - for handler in handlers: + for _, handler in handlers.items(): self.assertEqual(1, handler.publish_event.call_count) event = handler.publish_event.call_args[0][0] self.assertEqual(expected_as_string, event.as_string()) - @mock.patch('cloudinit.reporting.HANDLERS', - new_callable=lambda: [mock.MagicMock(), mock.MagicMock()]) + @mock.patch('cloudinit.reporting.handler_registry', + new_callable=_fake_registry) def test_report_finish_event_passes_something_with_as_string_to_handlers( - self, HANDLERS): + self, handler_registry): event_name, event_description = self._report_finish_event() expected_string_representation = ': '.join( ['finish', event_name, event_description]) self.assertHandlersPassedObjectWithAsString( - HANDLERS, expected_string_representation) + handler_registry.registered_items, expected_string_representation) - @mock.patch('cloudinit.reporting.HANDLERS', - new_callable=lambda: [mock.MagicMock(), mock.MagicMock()]) - def test_reporting_successful_finish_has_sensible_string_repr(self, - HANDLERS): + @mock.patch('cloudinit.reporting.handler_registry', + new_callable=_fake_registry) + def test_reporting_successful_finish_has_sensible_string_repr( + self, handler_registry): event_name, event_description = self._report_finish_event( successful=True) expected_string_representation = ': '.join( ['finish', event_name, 'success', event_description]) self.assertHandlersPassedObjectWithAsString( - HANDLERS, expected_string_representation) + handler_registry.registered_items, expected_string_representation) - @mock.patch('cloudinit.reporting.HANDLERS', - new_callable=lambda: [mock.MagicMock(), mock.MagicMock()]) - def test_reporting_unsuccessful_finish_has_sensible_string_repr(self, - HANDLERS): + @mock.patch('cloudinit.reporting.handler_registry', + new_callable=_fake_registry) + def test_reporting_unsuccessful_finish_has_sensible_string_repr( + self, handler_registry): event_name, event_description = self._report_finish_event( successful=False) expected_string_representation = ': '.join( ['finish', event_name, 'fail', event_description]) self.assertHandlersPassedObjectWithAsString( - HANDLERS, expected_string_representation) + handler_registry.registered_items, expected_string_representation) class TestReportingEvent(unittest.TestCase): @@ -115,3 +120,13 @@ class TestLogHandler(TestCase): reporting.LogHandler().publish_event(event) self.assertIn(event.as_string(), getLogger.return_value.info.call_args[0][0]) + + +class TestDefaultRegisteredHandler(TestCase): + + def test_log_handler_registered_by_default(self): + for _, item in reporting.handler_registry.registered_items.items(): + if isinstance(item, reporting.LogHandler): + break + else: + self.fail('No reporting LogHandler registered by default.')