Ejemplo n.º 1
0
    def test_the_pump_should_fail_on_a_missing_message_mapper(self):
        """
            Given that I have a message pump for a channel
             When there is no message mapper for that channel
             Then we shhould throw an exception to indicate a configuration error
        """
        handler = MyCommandHandler()
        request = MyCommand()
        channel = Mock(spec=Channel)
        command_processor = Mock(spec=CommandProcessor)

        message_pump = MessagePump(command_processor, channel, None)

        header = BrightsideMessageHeader(uuid4(), request.__class__.__name__, BrightsideMessageType.MT_COMMAND)
        body = BrightsideMessageBody(JsonRequestSerializer(request=request).serialize_to_json(),
                                     BrightsideMessageBodyType.application_json)
        message = BrightsideMessage(header, body)

        quit_message = create_quit_message()

        # add messages to that when channel is called it returns first message then qui tmessage
        response_queue = [message, quit_message]
        channel_spec = {"receive.side_effect": response_queue}
        channel.configure_mock(**channel_spec)

        excepton_caught = False
        try:
            message_pump.run()
        except ConfigurationException:
            excepton_caught = True

        self.assertTrue(excepton_caught)
Ejemplo n.º 2
0
    def test_the_pump_should_dispatch_a_command_processor(self):
        """
            Given that I have a message pump for a channel
             When I read a message from that channel
             Then the message should be dispatched to a handler
        """
        handler = MyCommandHandler()
        request = MyCommand()
        channel = Mock(spec=Channel)
        command_processor = Mock(spec=CommandProcessor)

        message_pump = MessagePump(command_processor, channel, map_my_command_to_request)

        header = BrightsideMessageHeader(uuid4(), request.__class__.__name__, BrightsideMessageType.MT_COMMAND)
        body = BrightsideMessageBody(JsonRequestSerializer(request=request).serialize_to_json(),
                                     BrightsideMessageBodyType.application_json)
        message = BrightsideMessage(header, body)

        quit_message = create_quit_message()

        # add messages to that when channel is called it returns first message then quit message
        response_queue = [message, quit_message]
        channel_spec = {"receive.side_effect": response_queue}
        channel.configure_mock(**channel_spec)

        message_pump.run()

        channel.receive.assert_called_with(0.5)
        self.assertEqual(channel.receive.call_count, 2)
        self.assertTrue(command_processor.send.call_count, 1)
        self.assertEqual(channel.acknowledge.call_count, 1)
Ejemplo n.º 3
0
    def test_the_pump_should_ack_failed_messages(self):
        """
            Given that I have a message pump for a channel
             When the handler raises an application exception for that message
             Then ack the message to prevent 'poison pill' message
        """
        handler = MyCommandHandler()
        request = MyCommand()
        channel = Mock(spec=Channel)
        command_processor = Mock(spec=CommandProcessor)

        message_pump = MessagePump(command_processor, channel, map_my_command_to_request)

        header = BrightsideMessageHeader(uuid4(), request.__class__.__name__, BrightsideMessageType.MT_COMMAND)
        body = BrightsideMessageBody(JsonRequestSerializer(request=request).serialize_to_json(),
                                     BrightsideMessageBodyType.application_json)
        message = BrightsideMessage(header, body)

        quit_message = create_quit_message()

        # add messages to that when channel is called it returns first message then qui tmessage
        response_queue = [message, quit_message]
        channel_spec = {"receive.side_effect": response_queue}
        channel.configure_mock(**channel_spec)

        app_error_spec = {"send.side_effect": ZeroDivisionError()}
        command_processor.configure_mock(**app_error_spec)

        message_pump.run()

        channel.receive.assert_called_with(0.5)
        self.assertEqual(channel.receive.call_count, 2)
        self.assertTrue(command_processor.send.call_count, 1)
        self.assertEqual(channel.acknowledge.call_count, 1)
Ejemplo n.º 4
0
    def test_the_pump_should_acknowledge_and_discard_an_unacceptable_message(self):
        """
            Given that I have a message pump for a channel
             When I cannot read the message received from that channel
             Then I should acknowledge the message to dicard it
        """
        handler = MyCommandHandler()
        request = MyCommand()
        channel = Mock(spec=Channel)
        command_processor = Mock(spec=CommandProcessor)

        message_pump = MessagePump(command_processor, channel, map_my_command_to_request)

        header = BrightsideMessageHeader(uuid4(), request.__class__.__name__, BrightsideMessageType.MT_UNACCEPTABLE)
        body = BrightsideMessageBody(JsonRequestSerializer(request=request).serialize_to_json(),
                                     BrightsideMessageBodyType.application_json)
        message = BrightsideMessage(header, body)

        quit_message = create_quit_message()

        # add messages to that when channel is called it returns first message then qui tmessage
        response_queue = [message, quit_message]
        channel_spec = {"receive.side_effect": response_queue}
        channel.configure_mock(**channel_spec)

        message_pump.run()

        channel.receive.assert_called_with(0.5)
        self.assertEqual(channel.receive.call_count, 2)
        # We acknowledge so that a 'poison pill' message cannot block our queue
        self.assertEqual(channel.acknowledge.call_count, 1)
        # Does not send the message, just discards it
        self.assertEqual(command_processor.send.call_count, 0)
Ejemplo n.º 5
0
def _sub_process_main(
        started_event: Event, channel_name: str, connection: Connection,
        consumer_configuration: BrightsideConsumerConfiguration,
        consumer_factory: Callable[
            [Connection, BrightsideConsumerConfiguration, logging.Logger],
            BrightsideConsumer],
        command_processor_factory: Callable[[str], CommandProcessor],
        mapper_func: Callable[[BrightsideMessage], Request]) -> None:
    """
    This is the main method for the sub=process, everything we need to create the message pump and
    channel it needs to be passed in as parameters that can be pickled as when we run they will be serialized
    into this process. The data should be value types, not reference types as we will receive a copy of the original.
    Inter-process communication is signalled by the event - to indicate startup - and the pipeline to facilitate a
    sentinel or stop message
    :param started_event: Used by the sub-process to signal that it is ready
    :param channel_name: The name we want to give the channel to the broker for identification
    :param connection: The 'broker' connection
    :param consumer_configuration: How to configure our consumer of messages from the channel
    :param consumer_factory: Callback to create the consumer. User code as we don't know what consumer library they
        want to use. Arame? Something else?
    :param command_processor_factory: Callback to  register subscribers, policies, and task queues then build command
        processor. User code that provides us with their requests and handlers
    :param mapper_func: We need to map between messages on the wire and our handlers
    :return:
    """

    logger = logging.getLogger(__name__)
    consumer = consumer_factory(connection, consumer_configuration, logger)
    channel = Channel(name=channel_name,
                      consumer=consumer,
                      pipeline=consumer_configuration.pipeline)

    # TODO: Fix defaults that need passed in config values
    command_processor = command_processor_factory(channel_name)
    message_pump = MessagePump(command_processor=command_processor,
                               channel=channel,
                               mapper_func=mapper_func,
                               timeout=500,
                               unacceptable_message_limit=None,
                               requeue_count=None)

    logger.debug("Starting the message pump for %s", channel_name)
    message_pump.run(started_event)
Ejemplo n.º 6
0
    def test_handle_requeue_has_upper_bound(self):
        """
        Given that I have a channel
        When I receive a requeue on that channel
        I should ask the consumer to requeue, up to a retry limit
        So that poison messages do not fill our queues
        """
        handler = MyCommandHandler()
        request = MyCommand()
        channel = FakeChannel(name="MyCommand")
        command_processor = Mock(spec=CommandProcessor)

        message_pump = MessagePump(command_processor, channel, map_my_command_to_request, requeue_count=3)

        header = BrightsideMessageHeader(uuid4(), request.__class__.__name__, BrightsideMessageType.MT_COMMAND)
        body = BrightsideMessageBody(JsonRequestSerializer(request=request).serialize_to_json(),
                                     BrightsideMessageBodyType.application_json)
        message = BrightsideMessage(header, body)

        channel.add(message)

        requeue_spec = {"send.side_effect": DeferMessageException()}

        command_processor.configure_mock(**requeue_spec)

        started_event = Event()

        t = Thread(target=message_pump.run, args=(started_event,))

        t.start()

        started_event.wait()

        time.sleep(1)

        channel.stop()

        t.join()

        self.assertTrue(command_processor.send.call_count, 3)