コード例 #1
0
class Application(object):
    def __init__(self,
                 application_config,
                 entry_points=['zaf.addons', 'zaf.local_addons'],
                 signalhandler=None):
        root_logger = logging.getLogger()
        # Default config for rootlogger to not spam until logger is correctly configured
        root_logger.setLevel(logging.INFO)

        self.app_config = application_config
        self.signalhandler = signalhandler
        self.entry_points = entry_points
        self.extension_manager = ExtensionManager()
        self.component_manager = ComponentManager()
        self.component_factory = Factory(self.component_manager)
        self.session_scope = self.component_factory.enter_scope('session')
        self.messagebus = MessageBus(self.component_factory,
                                     self.session_scope)
        self.messagebus.define_endpoints_and_messages(
            {APPLICATION_ENDPOINT: [BEFORE_COMMAND, AFTER_COMMAND]})
        self.config = ConfigManager()
        self.command = None
        self._exit_code = 1
        self.app_config.apply_configuration(self.config)

        @component(name='MessageBus', scope='session')
        def messagebus():
            """
            Access the message bus.

            The message bus can be used to register dispatchers to specific
            endpoints, message_ids and entities and to send requests and events
            to the registered dispatchers.
            """
            return self.messagebus

        @component(name='ComponentFactory', scope='session')
        def component_factory():
            """
            Access the component factory.

            The component factory can be used to call callables inside a scope
            and have the correct components instantiated in the scope.
            """
            return self.component_factory

        @component(name='ComponentManager', scope='session')
        def component_manager():
            """
            Access the component manager.

            The component manager can be used to find out what components are
            available.
            """
            return self.component_manager

        @component(name='Config', scope='session')
        def config():
            """
            Access the Config Manager.

            The Config components gives full access to all the config.
            """
            return self.config

        @component(name='ExtensionManager', scope='session')
        def extension_manager():
            """
            Access the extension manager.

            The extension manager can be used to find out what extensions are
            loaded.
            """
            return self.extension_manager

    def run(self):
        with self as instance:
            instance._exit_code = instance.execute_command()
        return instance._exit_code

    def setup(self):
        application_config_options = [
            ConfigOption(MESSAGEBUS_TIMEOUT, required=False),
            ConfigOption(CWD, required=True),
        ]
        loader = ExtensionLoader(self.extension_manager, self.config,
                                 self.messagebus, application_config_options,
                                 self.component_manager)
        self.command = loader.load_extensions(self.entry_points)

    def teardown(self):
        try:
            self.messagebus.wait_for_not_active(
                timeout=self.config.get(MESSAGEBUS_TIMEOUT))
        except MessageBusTimeout as e:
            logger.critical(
                'Waiting for messagebus to be inactive timed out,'
                ' shutting down anyway. State: {state}'.format(state=e))
        finally:
            logger.debug(
                'Dispatchers still registered to the messagebus: {dispatchers}'
                .format(dispatchers=self.messagebus.get_dispatchers()))
            self.extension_manager.destroy()
            for th in threading.enumerate():
                try:
                    if th.name != 'MainThread':
                        logger.debug(th)
                        logger.debug('\n'.join(
                            traceback.format_stack(
                                sys._current_frames()[th.ident])))
                except KeyError:
                    logger.debug(th)

    def execute_command(self):
        logger.debug(
            'Executing command {command} for application {application} with version {version}'
            .format(command=self.command.name,
                    application=self.app_config.name,
                    version=self.app_config.version))
        self._activate_signalhandler()
        self.messagebus.trigger_event(BEFORE_COMMAND,
                                      APPLICATION_ENDPOINT,
                                      data=self.command.name)
        result = 0
        try:
            result = self.component_factory.call(self.command.callable,
                                                 self.session_scope, self)
            return result if result is not None else 0
        finally:
            logger.debug(
                'Command {command} exited with exit code {result}'.format(
                    command=self.command.name,
                    result=result).format(command=self.command.name,
                                          application=self.app_config.name,
                                          version=self.app_config.version))

            self.component_factory.exit_scope(self.session_scope)
            self.messagebus.trigger_event(AFTER_COMMAND,
                                          APPLICATION_ENDPOINT,
                                          data=self.command.name)

    def gather_metadata(self, metadata_filter=None):
        return ZafMetadata(self.extension_manager.all_extensions,
                           self.component_manager.get_components_info(),
                           self.config, self.app_config.entrypoint,
                           self.extension_manager, metadata_filter)

    def __enter__(self):
        try:
            self.setup()
        except Exception:
            self.__exit__(*sys.exc_info())
            raise
        return self

    def __exit__(self, *args):
        self.teardown()

    @property
    def exit_code(self):
        return self._exit_code

    def _activate_signalhandler(self):
        if self.signalhandler is not None:
            self.signalhandler.activate(self.messagebus)

    def _deactivate_signalhandler(self):
        if self.signalhandler is not None:
            self.signalhandler.deactivate()
コード例 #2
0
class TestWaitForLine(unittest.TestCase):
    def setUp(self):
        self.messagebus = MessageBus(Factory(ComponentManager({})))
        self.endpoint = MOCK_ENDPOINT
        self.sut = Mock()
        self.sut.entity = 'entity'
        self.config = Mock()
        self.config.get = MagicMock(side_effect=config_get_log_sources)
        self.messagebus.define_endpoints_and_messages(
            {self.endpoint: [LOG_LINE_RECEIVED]})

    def test_wait_for_line_times_out(self):
        sut_events = SutEvents(self.messagebus, self.config, self.sut)
        with sut_events.wait_for_log_line(r'not matching') as lines:
            self.messagebus.trigger_event(LOG_LINE_RECEIVED,
                                          self.endpoint,
                                          entity='log-entity',
                                          data='line')
            with self.assertRaises(NoMatchingLogLine):
                lines.get(timeout=0)

    def test_wait_for_line_matches_first_line(self):
        [match] = list(self.wait_for_lines(r'li\w+', ['line'], 1))
        self.assertEqual(match.string, 'line')

    def test_wait_for_line_matches_some_lines(self):
        [match1, match2] = list(
            self.wait_for_lines(r'match\d+',
                                ['match1', 'no match', 'match2', 'no match'],
                                2))
        self.assertEqual(match1.string, 'match1')
        self.assertEqual(match2.string, 'match2')

    def test_wait_for_line_matches_with_match_groups(self):
        [match] = list(self.wait_for_lines(r'(\S+) (\S+)', ['first second'],
                                           1))
        self.assertEqual(match.group(1), 'first')
        self.assertEqual(match.group(2), 'second')

    def test_wait_for_line_matches_with_named_match_groups(self):
        [match] = list(
            self.wait_for_lines(r'(?P<first>\S+) (?P<second>\S+)',
                                ['first second'], 1))
        self.assertEqual(match.group('first'), 'first')
        self.assertEqual(match.group('second'), 'second')

    def test_wait_for_line_matches_when_match_is_not_at_start_of_line(self):
        [match] = list(
            self.wait_for_lines(r'(?P<second>second)', ['first second'], 1))
        self.assertEqual(match.string, 'first second')
        self.assertEqual(match.group('second'), 'second')

    def wait_for_lines(self, log_line_regex, lines, expected_matches):
        sut_events = SutEvents(self.messagebus, self.config, self.sut)
        with sut_events.wait_for_log_line(log_line_regex) as received_lines:
            for line in lines:
                self.messagebus.trigger_event(LOG_LINE_RECEIVED,
                                              self.endpoint,
                                              entity='log-entity',
                                              data=line)

            return [
                received_lines.get(timeout=0)
                for _ in range(0, expected_matches)
            ]

    def test_get_all_lines(self):
        lines = ['first A', 'second B', 'third A', 'fourth B']
        regex = r'A'
        matching_lines = ['first A', 'third A']
        sut_events = SutEvents(self.messagebus, self.config, self.sut)
        with sut_events.wait_for_log_line(regex) as queue:
            for line in lines:
                self.messagebus.trigger_event(LOG_LINE_RECEIVED,
                                              self.endpoint,
                                              entity='log-entity',
                                              data=line)
            self.messagebus.wait_for_not_active()
            matches = queue.get_all()
        strings = [match.string for match in matches]
        self.assertEqual(strings, matching_lines)

    def test_wait_for_line_raises_no_log_sources_error_if_log_source_is_unavailable(
            self):
        sut_events = SutEvents(self.messagebus, self.config, self.sut)
        with self.assertRaises(NoLogSources):
            sut_events.wait_for_log_line(
                r'not matching',
                log_sources='log-source-unavailable').__enter__()

    def test_wait_for_line_raises_no_log_sources_error_if_no_log_sources_defined_for_sut(
            self):
        config = Mock()
        config.get = MagicMock(return_value=[])
        sut_events = SutEvents(self.messagebus, config, self.sut)
        with self.assertRaises(NoLogSources):
            sut_events.wait_for_log_line(
                r'not matching', log_sources='not-a-log-source').__enter__()

    def test_wait_for_line_matches_only_one_log_source(self):
        lines = ['first A', 'second B', 'third A', 'fourth B']
        regex = r'B'
        matching_lines = ['second B', 'fourth B']
        config = Mock()
        config.get = MagicMock(return_value=['log-source-A', 'log-source-B'])
        sut_events = SutEvents(self.messagebus, config, self.sut)
        with sut_events.wait_for_log_line(regex,
                                          log_sources='log-source-B') as queue:
            self.messagebus.trigger_event(LOG_LINE_RECEIVED,
                                          self.endpoint,
                                          entity='log-source-A',
                                          data=lines[0])
            self.messagebus.trigger_event(LOG_LINE_RECEIVED,
                                          self.endpoint,
                                          entity='log-source-B',
                                          data=lines[1])
            self.messagebus.trigger_event(LOG_LINE_RECEIVED,
                                          self.endpoint,
                                          entity='log-source-A',
                                          data=lines[2])
            self.messagebus.trigger_event(LOG_LINE_RECEIVED,
                                          self.endpoint,
                                          entity='log-source-B',
                                          data=lines[3])
            self.messagebus.wait_for_not_active()
            matches = queue.get_all()
        strings = [match.string for match in matches]
        self.assertEqual(strings, matching_lines)