예제 #1
0
    def init_component_handling(self, components):
        self.component_registry = create_registry()
        self.component_manager = ComponentManager(self.component_registry)
        self.component_factory = Factory(self.component_manager)
        self.messagebus = MessageBus(self.component_factory, Scope('session'))

        components.append(
            ComponentMock(name='ComponentFactory',
                          mock=self.component_factory))
        components.append(
            ComponentMock(name='MessageBus', mock=self.messagebus))
        components.append(ComponentMock(name='Config', mock=self.config))
        components.append(
            ComponentMock(name='ComponentManager',
                          mock=self.component_manager))
        components.append(
            ComponentMock(name='ExtensionManager', mock=MagicMock()))
        for comp in components:
            if type(comp) == ComponentMock:
                component(name=comp.name,
                          scope=comp.scope,
                          can=comp.can,
                          provided_by_extension=comp.provided_by_extension)(
                              comp, self.component_manager)
            else:
                self.component_manager.register_component(comp)
예제 #2
0
    def setUp(self):
        self.component_manager = ComponentManager()
        self.component_manager.clear_component_registry()
        component(scope='session')(TestTestRunnerComponents.Verifier)
        self.load_components()
        self.verifier = TestTestRunnerComponents.Verifier()
        self.parent_scope = Scope('session', None)
        self.parent_scope.register_instance(
            _InstanceId(TestTestRunnerComponents.Verifier, ()), self.verifier)
        self.run_queue = []
        self.messagebus = Mock()

        def send_request(message_id,
                         endpoint_id=None,
                         entities=None,
                         data=None):
            futures = Mock()
            if message_id == SCHEDULE_NEXT_TEST:
                future = Mock()
                if self.run_queue:
                    future.result.return_value = self.run_queue.pop(0)
                else:
                    future.result.return_value = None

                futures.wait.return_value = [future]
            return futures

        self.messagebus.send_request.side_effect = send_request
        self.tr = TestRunner(self.messagebus,
                             Factory(self.component_manager),
                             'suite-name',
                             parent_scope=self.parent_scope)
예제 #3
0
    def test_enabling_remote_client_registers_component(self):
        component_manager = ComponentManager()
        component_manager.clear_component_registry()

        config = ConfigManager()
        config.set(REMOTE_CLIENT_ENABLED, True)

        with ExtensionTestHarness(RemoteClientExtension, config=config):
            self.assertIn('RemoteClient', component_manager.COMPONENT_REGISTRY)
예제 #4
0
    def setUp(self):
        self.run_queue = []
        messagebus = Mock()

        def send_request(message_id,
                         endpoint_id=None,
                         entities=None,
                         data=None):
            futures = Mock()
            if message_id == SCHEDULE_NEXT_TEST:
                future = Mock()
                if self.run_queue:
                    future.result.return_value = self.run_queue.pop(0)
                else:
                    future.result.return_value = None

                futures.wait.return_value = [future]
            return futures

        messagebus.send_request.side_effect = send_request

        self.tr = TestRunner(messagebus=messagebus,
                             component_factory=Factory(ComponentManager()),
                             suite_name='suite-name')
        self.tr.QUEUE_TIMEOUT_SECONDS = 1
        self.tr.EXECUTION_PAUSED_TIMEOUT_SECONDS = 1
예제 #5
0
 def test_fail_when_no_serial_connection_is_registered_to_send_command(self):
     messagebus = MessageBus(Factory(ComponentManager(COMPONENT_REGISTRY)))
     messagebus.define_endpoints_and_messages({SERIAL_ENDPOINT: [LOG_LINE_RECEIVED]})
     client = SerialClient(messagebus, 'entity')
     with self.assertRaises(SerialError) as error:
         client.send_line('line', timeout=1)
         assert 'No serial connection' in error.msg
예제 #6
0
 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]})
예제 #7
0
    def setUp(self):
        self.messagebus = MessageBus(Factory(ComponentManager({})))
        self.sut = MagicMock()
        self.sut.entity = 'entity1'
        config = Mock()

        self.messagebus.define_endpoints_and_messages({
            MOCK_ENDPOINT: [SUT_RESET_EXPECTED],
            SUTEVENTSCOMPONENT_ENDPOINT: [SUT_RESET_EXPECTED, SUT_RESET_DONE]
        })
        self.sut_events = SutEvents(self.messagebus, config, self.sut)
예제 #8
0
 def setUp(self):
     self.component_manager = ComponentManager()
     self.component_manager.clear_component_registry()
     self.load_components()
예제 #9
0
class TestComponentsOnHandlers(unittest.TestCase):
    def load_components(self):
        @component(scope='message')
        class MessageScoped(object):
            def __init__(self):
                self.calls = 0

            def __call__(self, *args, **kwargs):
                self.calls += 1
                return self.calls

        @component(scope='dispatcher')
        class DispatcherScoped(object):
            def __init__(self):
                self.calls = 0

            def __call__(self, *args, **kwargs):
                self.calls += 1
                return self.calls

        @component(scope='session')
        class SessionScoped(object):
            def __init__(self):
                self.calls = 0

            def __call__(self, *args, **kwargs):
                self.calls += 1
                return self.calls

    def setUp(self):
        self.component_manager = ComponentManager()
        self.component_manager.clear_component_registry()
        self.load_components()

    def test_sequential_dispatcher_requires_component(self):
        messagebus = create_messagebus()
        comp_counts = Queue()

        @requires(comp='MessageScoped')
        def handle_message(message, comp):
            comp_counts.put(comp())

        dispatcher = SequentialDispatcher(messagebus, handle_message)
        try:
            dispatcher.register([defined_message])
            messagebus.trigger_event(defined_message,
                                     defined_endpoint,
                                     data='data1')
            self.assertEqual(comp_counts.get(timeout=1), 1)
        finally:
            dispatcher.destroy()

    def test_concurrent_dispatcher_requires_component(self):
        messagebus = create_messagebus()
        comp_counts = Queue()

        @requires(comp='MessageScoped')
        def handle_message(message, comp):
            comp_counts.put(comp())

        dispatcher = ConcurrentDispatcher(messagebus, handle_message)
        try:
            dispatcher.register([defined_message])
            messagebus.trigger_event(defined_message,
                                     defined_endpoint,
                                     data='data1')
            self.assertEqual(comp_counts.get(timeout=1), 1)
        finally:
            dispatcher.destroy()

    def test_callback_dispatcher_requires_component(self):
        messagebus = create_messagebus()
        comp_counts = Queue()

        @requires(comp='MessageScoped')
        def handle_message(message, comp):
            comp_counts.put(comp())

        dispatcher = CallbackDispatcher(messagebus, handle_message)
        try:
            dispatcher.register([defined_message])
            messagebus.trigger_event(defined_message,
                                     defined_endpoint,
                                     data='data1')
            self.assertEqual(comp_counts.get(timeout=1), 1)
        finally:
            dispatcher.destroy()

    def test_multiple_calls_give_different_message_scoped_components(self):
        messagebus = create_messagebus()
        comp_counts = Queue()

        @requires(comp='MessageScoped')
        def handle_message(message, comp):
            comp_counts.put(comp())

        dispatcher = CallbackDispatcher(messagebus, handle_message)
        try:
            dispatcher.register([defined_message])
            messagebus.trigger_event(defined_message,
                                     defined_endpoint,
                                     data='data1')
            messagebus.trigger_event(defined_message,
                                     defined_endpoint,
                                     data='data2')
            self.assertEqual(comp_counts.get(timeout=1), 1)
            self.assertEqual(comp_counts.get(timeout=1), 1)
        finally:
            dispatcher.destroy()

    def test_multiple_calls_give_same_dispatcher_scoped_component(self):
        messagebus = create_messagebus()
        comp_counts_a = Queue()
        comp_counts_b = Queue()

        @requires(comp='DispatcherScoped')
        def handle_message_a(message, comp):
            comp_counts_a.put(comp())

        @requires(comp='DispatcherScoped')
        def handle_message_b(message, comp):
            comp_counts_b.put(comp())

        dispatcher_a = CallbackDispatcher(messagebus, handle_message_a)
        dispatcher_b = CallbackDispatcher(messagebus, handle_message_b)
        try:
            try:
                dispatcher_a.register([defined_message])
                dispatcher_b.register([defined_message])
                messagebus.trigger_event(defined_message,
                                         defined_endpoint,
                                         data='data1')
                messagebus.trigger_event(defined_message,
                                         defined_endpoint,
                                         data='data2')
                self.assertEqual(comp_counts_a.get(timeout=1), 1)
                self.assertEqual(comp_counts_a.get(timeout=1), 2)
                self.assertEqual(comp_counts_b.get(timeout=1), 1)
                self.assertEqual(comp_counts_b.get(timeout=1), 2)
            finally:
                dispatcher_a.destroy()
                messagebus.trigger_event(defined_message,
                                         defined_endpoint,
                                         data='data2')
                assert comp_counts_a.empty()
                self.assertEqual(comp_counts_b.get(timeout=1), 3)
        finally:
            dispatcher_b.destroy()

    def test_multiple_calls_give_same_session_scoped_component(self):
        messagebus = create_messagebus()
        comp_counts = Queue()

        @requires(comp='SessionScoped')
        def handle_message(message, comp):
            comp_counts.put(comp())

        dispatcher = CallbackDispatcher(messagebus, handle_message)
        try:
            dispatcher.register([defined_message])
            messagebus.trigger_event(defined_message,
                                     defined_endpoint,
                                     data='data1')
            messagebus.trigger_event(defined_message,
                                     defined_endpoint,
                                     data='data2')
            self.assertEqual(comp_counts.get(timeout=1), 1)
            self.assertEqual(comp_counts.get(timeout=1), 2)
        finally:
            dispatcher.destroy()

    def test_message_entity_is_used_to_fixate_entities(self):
        messagebus = create_messagebus()
        calls = Queue()

        @component(name='A')
        class a1():
            entity = 'a1'

        @component(name='A')
        class a2():
            entity = 'a2'

        @requires(a='A')
        def handle_message(message, a):
            calls.put(a.entity)

        dispatcher = CallbackDispatcher(messagebus, handle_message)
        try:
            dispatcher.register([defined_message], entities=['a1', 'a2'])
            messagebus.trigger_event(defined_message,
                                     defined_endpoint,
                                     entity='a2',
                                     data='data1')
            self.assertEqual(calls.get(timeout=1), 'a2')
            messagebus.trigger_event(defined_message,
                                     defined_endpoint,
                                     entity='a1',
                                     data='data2')
            self.assertEqual(calls.get(timeout=1), 'a1')
        finally:
            dispatcher.destroy()

    def test_combination_of_fixated_and_not_fixated_entities(self):
        messagebus = create_messagebus()
        calls = Queue()

        @component(name='A')
        class a1():
            entity = 'a1'

        @component(name='A', can=['2'])
        class a2():
            entity = 'a2'

        @requires(a='A')
        @requires(a2='A', can=['2'], fixate_entities=False)
        def handle_message(message, a, a2):
            calls.put(a.entity)
            calls.put(a2.entity)

        dispatcher = CallbackDispatcher(messagebus, handle_message)
        try:
            dispatcher.register([defined_message], entities=['a1', 'a2'])
            messagebus.trigger_event(defined_message,
                                     defined_endpoint,
                                     entity='a2',
                                     data='data1')
            self.assertEqual(calls.get(timeout=1), 'a2')
            self.assertEqual(calls.get(timeout=1), 'a2')
            messagebus.trigger_event(defined_message,
                                     defined_endpoint,
                                     entity='a1',
                                     data='data2')
            self.assertEqual(calls.get(timeout=1), 'a1')
            self.assertEqual(calls.get(timeout=1), 'a2')
        finally:
            dispatcher.destroy()
예제 #10
0
class ExtensionTestHarness(object):
    """
    Class that helps testing extensions by creating and configuration the surroundings.

    It can be used as a context manager and helps with multi threaded tests.

    .. code-block:: python

        with ExtensionTestHarness(
                MyExtension(), {endpoint: [message1, message2]}, {option1: value1, option2: value2}) as harness:
            with harness.patch('module.to.patch') as m:
                harness.trigger_event(message1, endpoint, data=MyData())
                m.wait_for_call() # Waits for the call to module.to.patch. Needed due to multi threading.
                m.assert_called_with('the wanted value')

    """
    def __init__(self,
                 constructor,
                 entity=None,
                 endpoints_and_messages=None,
                 config=None,
                 components=None):
        """
        Initialize a new Harness for an extension and defines endpoints_and_messages in the messagebus.

        :param constructor: the constructor of the extension to test
        :param entity: If not given and the extension is instantiated on an entity the first entity
                       in the config will be used. Otherwise this can be used to set the wanted entity.
        :param endpoints_and_messages: endpoints and messages that the extensions wants to subscribe to
        :param config: Instance of ConfigManager with the wanted config for the extension.
        :param components: The components to insert into the component registry. List of ComponentMock
        """
        self._constructor = constructor

        self.config = ConfigManager() if config is None else config
        self._all_dispatchers = []
        self._instances = {}
        self._entity = None
        self._entity_option_id = None
        self.init_component_handling([] if components is None else components)

        if not isinstance(self._constructor, type):
            raise Exception(
                'Extension should be a constructor of an extension, not an instance.'
            )

        if endpoints_and_messages:
            self.messagebus.define_endpoints_and_messages(
                endpoints_and_messages)

        config_options = self._constructor.config_options
        config_option_ids = [c.option_id for c in config_options]
        self.config.set_default_values(config_option_ids)
        self.init_entity(entity, config_options)

        self.assert_required_options(config_options, self._entity_option_id)

        self._config_view = ConfigView(self.config, config_option_ids,
                                       self._entity_option_id, self._entity)
        self._active = _is_extension_active(self._config_view, constructor)

    def init_entity(self, entity, config_options):
        self._entity_option_id = None

        entity_option_ids = [
            c.option_id for c in config_options if c.instantiate_on
        ]
        if entity_option_ids:
            self._entity_option_id = entity_option_ids[0]
            entities = self.config.get(self._entity_option_id)
            if entity:
                if entity not in entities:
                    AssertionError(
                        "Entity '{entity}' is not a valid entity for '{option_id}', "
                        "valid options are '{entities}'".format(
                            entity=entity,
                            option_id=self._entity_option_id.key,
                            entities=entities))
                self._entity = entity
            else:
                self._entity = entities[0]

            self._instances[self._entity_option_id] = self._entity

    def init_component_handling(self, components):
        self.component_registry = create_registry()
        self.component_manager = ComponentManager(self.component_registry)
        self.component_factory = Factory(self.component_manager)
        self.messagebus = MessageBus(self.component_factory, Scope('session'))

        components.append(
            ComponentMock(name='ComponentFactory',
                          mock=self.component_factory))
        components.append(
            ComponentMock(name='MessageBus', mock=self.messagebus))
        components.append(ComponentMock(name='Config', mock=self.config))
        components.append(
            ComponentMock(name='ComponentManager',
                          mock=self.component_manager))
        components.append(
            ComponentMock(name='ExtensionManager', mock=MagicMock()))
        for comp in components:
            if type(comp) == ComponentMock:
                component(name=comp.name,
                          scope=comp.scope,
                          can=comp.can,
                          provided_by_extension=comp.provided_by_extension)(
                              comp, self.component_manager)
            else:
                self.component_manager.register_component(comp)

    def assert_required_options(self, config_options, entity_option_id):
        def assert_in_config(option_id, entity=None):
            if self.config.get(option_id, entity=entity) is None:
                raise AssertionError(
                    'Missing required option {option}{for_entity}'.format(
                        option=option.option_id.key,
                        for_entity='for entity {entity}'.format(
                            entity=entity) if entity else ''))

        for option in config_options:
            if option.required and not option.option_id.has_default:
                if option.option_id.at is not None and option.option_id == entity_option_id:
                    assert_in_config(option.option_id, entity=self._entity)
                elif option.option_id.at is not None:
                    entities = self.config.get(option.option_id.at)
                    if not option.option_id.at.multiple:
                        entities = [entities]

                    for entity in entities:
                        assert_in_config(option.option_id, entity=entity)
                else:
                    assert_in_config(option.option_id)

    @property
    def extension(self):
        return self._instance

    def __enter__(self):
        self._instance = self._constructor(self._config_view, self._instances)
        self.messagebus.define_endpoints_and_messages(
            self._instance.endpoints_and_messages)

        if hasattr(self._instance, 'register_components'):
            self._instance.register_components(self.component_manager)

        for method, descriptor in get_dispatcher_descriptors(self._instance):
            dispatcher = descriptor.dispatcher_constructor(
                self.messagebus, method)
            entities = None
            if descriptor.entity_option_id is not None:
                entities = [self._instances[descriptor.entity_option_id]]
            if self._active:
                dispatcher.register(descriptor.message_ids,
                                    endpoint_ids=descriptor.endpoint_ids,
                                    entities=entities)
            self._all_dispatchers.append(dispatcher)

        self._instance.register_dispatchers(self.messagebus)
        return self

    def __exit__(self, *exc_info):
        for dispatcher in self._all_dispatchers:
            if self._active:
                dispatcher.destroy()
        self._instance.destroy()

    def trigger_event(self,
                      message_id,
                      sender_endpoint_id,
                      entity=None,
                      data=None):
        self.messagebus.trigger_event(message_id, sender_endpoint_id, entity,
                                      data)

    def send_request(self,
                     message_id,
                     receiver_endpoint_id=None,
                     entity=None,
                     data=None):
        return self.messagebus.send_request(message_id, receiver_endpoint_id,
                                            entity, data)

    def any_registered_dispatchers(self,
                                   message_id,
                                   endpoint_id=None,
                                   entity=None):
        return self.messagebus.has_registered_dispatchers(
            message_id, endpoint_id, entity)

    @contextmanager
    def message_queue(self,
                      message_ids,
                      endpoint_ids=None,
                      entities=None,
                      match=None,
                      priority=0):
        with LocalMessageQueue(self.messagebus, message_ids, endpoint_ids,
                               entities, match, priority) as q:
            yield q

    def patch(self, target, *patch_args, **patch_kwargs):
        """
        Patch with a special multi threaded wait_for_call method.

        The returned mock stores the arguments when it's called in a queue and then
        wait_for_call can be used to get the a tuple of *args* and *kwargs* that the
        mock was called with.
        The mock is a normal mock so after waiting for a call the normal mock asserts
        can be called.

        .. code-block:: python

            harness = ExtensionTestHarness(...)

            with harness.patch('function.to.patch') as mock:
                trigger_something()
                mock_args, mock_kwargs = mock.wait_for_call(timeout=4)
                mock.assert_called_once()
                self.assertEqual(mock_args[0], 'expected_value')

        :param target: the target
        :param patch_args: args sent to normal patch
        :param patch_kwargs: kwargs sent to normal patch
        :return: a mock with the extra wait_for_call method
        """

        return patch(target, *patch_args, new=SyncMock(), **patch_kwargs)
예제 #11
0
 def setUp(self):
     self.component_manager = ComponentManager(create_registry(),
                                               create_entity_map())
예제 #12
0
    def test_multiple_message_dispatchers_triggered_by_applicable_messages(
            self):
        messagebus = MessageBus(Factory(ComponentManager()))

        message_endpoint = EndpointId('message_endpoint', '')
        message_endpoint2 = EndpointId('message_endpoint2', '')
        message_endpoint_entity1 = 'endpoint_entity1'
        message_endpoint_entity2 = 'endpoint_entity2'

        sent_from_endpoint = MessageId('sent_from_endpoint', '')
        sent_from_entity1 = MessageId('sent_from_entity1', '')

        messagebus.define_endpoint(message_endpoint)
        messagebus.define_endpoint(message_endpoint2)
        messagebus.define_message(sent_from_endpoint, message_endpoint)
        messagebus.define_message(sent_from_entity1, message_endpoint)
        messagebus.define_message(sent_from_endpoint, message_endpoint2)
        messagebus.define_message(sent_from_entity1, message_endpoint2)

        received = {
            message_endpoint: [],
            message_endpoint2: [],
            message_endpoint_entity1: [],
            message_endpoint_entity2: []
        }

        def endpoint1(message):
            received[message_endpoint].append(message.message_id)

        messagebus.register_dispatcher(create_dispatcher(endpoint1),
                                       [sent_from_endpoint, sent_from_entity1],
                                       [message_endpoint])

        def endpoint2(message):
            received[message_endpoint2].append(message.message_id)

        messagebus.register_dispatcher(create_dispatcher(endpoint2),
                                       [sent_from_endpoint, sent_from_entity1],
                                       [message_endpoint2])

        def endpoint_entity1(message):
            received[message_endpoint_entity1].append(message.message_id)

        messagebus.register_dispatcher(create_dispatcher(endpoint_entity1),
                                       [sent_from_endpoint, sent_from_entity1],
                                       [message_endpoint],
                                       [message_endpoint_entity1])

        def endpoint_entity2(message):
            received[message_endpoint_entity2].append(message.message_id)

        messagebus.register_dispatcher(create_dispatcher(endpoint_entity2),
                                       [sent_from_endpoint, sent_from_entity1],
                                       [message_endpoint],
                                       [message_endpoint_entity2])

        messagebus.trigger_event(sent_from_endpoint, message_endpoint)
        messagebus.trigger_event(sent_from_entity1, message_endpoint,
                                 message_endpoint_entity1)

        self.assertEqual(received[message_endpoint],
                         [sent_from_endpoint, sent_from_entity1])
        self.assertEqual(received[message_endpoint2], [])
        self.assertEqual(received[message_endpoint_entity1],
                         [sent_from_entity1])
        self.assertEqual(received[message_endpoint_entity2], [])
예제 #13
0
class TestTestRunnerComponents(unittest.TestCase):
    class Verifier(object):
        def __init__(self):
            self.data = []

    def load_components(self):
        @component()
        @requires(verifier='Verifier')
        class MyComponent(object):
            def __init__(self, verifier):
                self.verifier = verifier

            def __enter__(self):
                self.verifier.data.append('enter')
                return self

            def __exit__(self, exc_type, exc_val, exc_tb):
                self.verifier.data.append('exit')

            def __call__(self, *args, **kwargs):
                self.verifier.data.append('call')

        @component()
        @requires(verifier='Verifier')
        class MyEnterFailComponent(object):
            def __init__(self, verifier):
                self.verifier = verifier

            def __enter__(self):
                self.verifier.data.append('enter')
                raise (Exception('enter fails'))

            def __exit__(self, exc_type, exc_val, exc_tb):
                self.verifier.data.append('exit')

            def __call__(self, *args, **kwargs):
                self.verifier.data.append('call')

        @component()
        @requires(verifier='Verifier')
        class MyExitFailComponent(object):
            def __init__(self, verifier):
                self.verifier = verifier

            def __enter__(self):
                self.verifier.data.append('enter')
                return self

            def __exit__(self, exc_type, exc_val, exc_tb):
                self.verifier.data.append('exit')
                raise (Exception('exit fails'))

            def __call__(self, *args, **kwargs):
                self.verifier.data.append('call')

    def setUp(self):
        self.component_manager = ComponentManager()
        self.component_manager.clear_component_registry()
        component(scope='session')(TestTestRunnerComponents.Verifier)
        self.load_components()
        self.verifier = TestTestRunnerComponents.Verifier()
        self.parent_scope = Scope('session', None)
        self.parent_scope.register_instance(
            _InstanceId(TestTestRunnerComponents.Verifier, ()), self.verifier)
        self.run_queue = []
        self.messagebus = Mock()

        def send_request(message_id,
                         endpoint_id=None,
                         entities=None,
                         data=None):
            futures = Mock()
            if message_id == SCHEDULE_NEXT_TEST:
                future = Mock()
                if self.run_queue:
                    future.result.return_value = self.run_queue.pop(0)
                else:
                    future.result.return_value = None

                futures.wait.return_value = [future]
            return futures

        self.messagebus.send_request.side_effect = send_request
        self.tr = TestRunner(self.messagebus,
                             Factory(self.component_manager),
                             'suite-name',
                             parent_scope=self.parent_scope)

    def test_enters_and_exit_called_on_component_with_test_scope(self):
        @requires(comp='MyComponent', scope='test')
        def my_test_case(comp):
            comp()

        self.run_queue.append(TestCaseDefinition(my_test_case))
        self.tr.run()
        assert 'enter' in self.verifier.data
        assert 'call' in self.verifier.data
        assert 'exit' in self.verifier.data

    def test_enters_and_exit_called_on_component_with_module_scope(self):
        @requires(comp='MyComponent', scope='module')
        def my_test_case(comp):
            comp()

        self.run_queue.append(TestCaseDefinition(my_test_case))
        self.tr.run()
        assert 'enter' in self.verifier.data
        assert 'call' in self.verifier.data
        assert 'exit' in self.verifier.data

    def test_enters_and_exit_called_on_component_with_class_scope(self):
        class TestMyTestCase(object):
            @requires(comp='MyComponent', scope='class')
            def my_test_case(self, comp):
                comp()

        self.run_queue.append(TestCaseDefinition(
            TestMyTestCase().my_test_case))
        self.tr.run()
        assert 'enter' in self.verifier.data
        assert 'call' in self.verifier.data
        assert 'exit' in self.verifier.data

    def test_enters_and_exit_called_on_component_with_runner_scope(self):
        @requires(comp='MyComponent', scope='module')
        def my_test_case(comp):
            comp()

        self.run_queue.append(TestCaseDefinition(my_test_case))
        self.tr.run()
        assert 'enter' in self.verifier.data
        assert 'call' in self.verifier.data
        assert 'exit' in self.verifier.data

    def test_enter_and_exit_called_once_on_class_scope_component_for_test_cases_in_same_class(
            self):
        class TestMyTestCase(object):
            @requires(comp='MyComponent', scope='class')
            def my_test_case1(self, comp):
                comp()

            @requires(comp='MyComponent', scope='class')
            def my_test_case2(self, comp):
                comp()

        test_case_class = TestMyTestCase()
        self.run_queue.extend([
            TestCaseDefinition(test_case_class.my_test_case1),
            TestCaseDefinition(test_case_class.my_test_case2)
        ])
        self.tr.run()
        assert self.verifier.data.count('enter') == 1
        assert self.verifier.data.count('call') == 2
        assert self.verifier.data.count('exit') == 1

    def test_enter_and_exit_called_once_on_module_scope_component_for_test_cases_in_same_module(
            self):
        @requires(comp='MyComponent', scope='module')
        def my_test_case1(comp):
            comp()

        @requires(comp='MyComponent', scope='module')
        def my_test_case2(comp):
            comp()

        self.run_queue.extend([
            TestCaseDefinition(my_test_case1),
            TestCaseDefinition(my_test_case2)
        ])
        self.tr.run()
        assert self.verifier.data.count('enter') == 1
        assert self.verifier.data.count('call') == 2
        assert self.verifier.data.count('exit') == 1

    def test_enter_and_exit_called_once_on_runner_scope_component(self):
        @requires(comp='MyComponent', scope='runner')
        def my_test_case1(comp):
            comp()

        @requires(comp='MyComponent', scope='runner')
        def my_test_case2(comp):
            comp()

        self.run_queue.extend([
            TestCaseDefinition(my_test_case1),
            TestCaseDefinition(my_test_case2)
        ])
        self.tr.run()
        assert self.verifier.data.count('enter') == 1
        assert self.verifier.data.count('call') == 2
        assert self.verifier.data.count('exit') == 1

    def test_enter_fails_sets_test_case_verdict_to_error_and_exit_is_called(
            self):
        @requires(comp='MyEnterFailComponent', scope='runner')
        def my_test_case1(comp):
            comp()

        self.run_queue.extend([TestCaseDefinition(my_test_case1)])
        self.tr.run()
        assert self.tr.run_history[0].verdict == Verdict.ERROR
        assert 'enter' in self.verifier.data
        assert 'call' not in self.verifier.data
        assert 'exit' in self.verifier.data

    def test_enter_fails_sets_test_case_verdict_to_error_and_continues_to_next_test_case(
            self):
        @requires(comp='MyEnterFailComponent', scope='runner')
        def my_test_case1(comp):
            comp()

        @requires(comp='MyComponent', scope='runner')
        def my_test_case2(comp):
            comp()

        self.run_queue.extend([
            TestCaseDefinition(my_test_case1),
            TestCaseDefinition(my_test_case2)
        ])
        self.tr.run()
        assert self.tr.run_history[0].verdict == Verdict.ERROR
        assert self.tr.run_history[1].verdict == Verdict.PASSED

    def test_exit_fails_on_test_scope_aborts_test_run(self):
        @requires(comp='MyExitFailComponent', scope='test')
        def my_test_case1(comp):
            comp()

        @requires(comp='MyComponent', scope='runner')
        def my_test_case2(comp):
            comp()

        self.run_queue.extend([
            TestCaseDefinition(my_test_case1),
            TestCaseDefinition(my_test_case2)
        ])
        self.tr.run()
        assert self.tr.run_history[0].verdict == Verdict.PASSED
        assert self.tr.run_history[1].verdict == Verdict.SKIPPED

    def test_exit_fails_on_non_test_scope_aborts_test_run(self):
        class MyTestCase1(object):
            @requires(comp='MyExitFailComponent', scope='class')
            def my_test_case1(self, comp):
                comp()

        class MyTestCase2(object):
            @requires(comp='MyComponent', scope='class')
            def my_test_case2(self, comp):
                comp()

        self.run_queue.extend([
            TestCaseDefinition(MyTestCase1().my_test_case1),
            TestCaseDefinition(MyTestCase2().my_test_case2)
        ])
        self.tr.run()
        assert self.tr.run_history[0].verdict == Verdict.PASSED
        assert self.tr.run_history[1].verdict == Verdict.SKIPPED
예제 #14
0
    def test_multiple_request_dispatchers_triggered_by_applicable_requests(
            self):
        messagebus = MessageBus(Factory(ComponentManager()))

        request_target = EndpointId('request_target', '')
        request_target2 = EndpointId('request_target2', '')
        request_target_entity1 = 'target_entity1'
        request_target_entity2 = 'target_entity2'

        sent_to_all = MessageId('request_to_all', '')
        sent_to_target = MessageId('request_to_target', '')
        sent_to_entity1 = MessageId('request_to_entity1', '')

        messagebus.define_endpoint(request_target)
        messagebus.define_endpoint(request_target2)

        messagebus.define_message(sent_to_all, request_target)
        messagebus.define_message(sent_to_target, request_target)
        messagebus.define_message(sent_to_entity1, request_target)

        messagebus.define_message(sent_to_all, request_target2)
        messagebus.define_message(sent_to_target, request_target2)
        messagebus.define_message(sent_to_entity1, request_target2)

        received = {
            request_target: [],
            request_target2: [],
            request_target_entity1: [],
            request_target_entity2: []
        }

        def target1(message):
            received[request_target].append(message.message_id)

        messagebus.register_dispatcher(
            create_dispatcher(target1),
            [sent_to_all, sent_to_target, sent_to_entity1], [request_target])

        def target2(message):
            received[request_target2].append(message.message_id)

        messagebus.register_dispatcher(
            create_dispatcher(target2),
            [sent_to_all, sent_to_target, sent_to_entity1], [request_target2])

        def target_entity1(message):
            received[request_target_entity1].append(message.message_id)

        messagebus.register_dispatcher(
            create_dispatcher(target_entity1),
            [sent_to_all, sent_to_target, sent_to_entity1], [request_target],
            [request_target_entity1])

        def target_entity2(message):
            received[request_target_entity2].append(message.message_id)

        messagebus.register_dispatcher(
            create_dispatcher(target_entity2),
            [sent_to_all, sent_to_target, sent_to_entity1], [request_target],
            [request_target_entity2])

        messagebus.send_request(sent_to_all)
        messagebus.send_request(sent_to_target, request_target)
        messagebus.send_request(sent_to_entity1, request_target,
                                request_target_entity1)

        self.assertEqual(received[request_target],
                         [sent_to_all, sent_to_target])
        self.assertEqual(received[request_target2], [sent_to_all])
        self.assertEqual(received[request_target_entity1],
                         [sent_to_all, sent_to_target, sent_to_entity1])
        self.assertEqual(received[request_target_entity2],
                         [sent_to_all, sent_to_target])
예제 #15
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()
예제 #16
0
    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
예제 #17
0
 def setUp(self):
     self.component_manager = ComponentManager(create_registry(),
                                               create_entity_map())
     self.registry = self.component_manager.COMPONENT_REGISTRY
     self.builder = DependencyGraphBuilder(self.registry)
     self.scope = Scope('scope')
예제 #18
0
 def setUp(self):
     ComponentManager().clear_component_registry()
예제 #19
0
 def setUp(self):
     component_manager = ComponentManager()
     component_manager.clear_component_registry()
     self.registry = component_manager.COMPONENT_REGISTRY
     self.builder = DependencyGraphBuilder(self.registry)