Exemplo n.º 1
0
async def test_rabbit_cr_auth_demo(connect_to_broker):
    auth = RabbitAuthMechanismCrDemo()
    async with await connect_to_broker(auth=auth) as connection:
        async with connection.channel() as channel:
            pass
        check_clean_channel_close(channel)
    check_clean_connection_close(connection)
Exemplo n.º 2
0
async def test_message_ttl(event_loop, connect_to_broker):
    queue_name = 'testcase_queue'
    exchange_name = 'testcase_exchange'
    routing_key = 'testcase_routing_key'
    async with await connect_to_broker() as connection:
        async with connection.channel() as channel:
            await channel.select_confirm()
            await channel.delete_queue(queue_name)
            await channel.declare_queue(queue_name)
            await channel.delete_exchange(exchange_name)
            await channel.declare_exchange(exchange_name, 'direct')
            await channel.bind_queue(queue_name, exchange_name, routing_key)

            # this one we fetch in time
            await channel.publish(exchange_name, routing_key, 'test body 1', expiration=1000)
            message = await channel.get(queue_name)  # if we run slow and this takes over 1 secs, test may fail
            assert message.decode() == 'test body 1'
            await message.ack()

            # and this one we don't
            await channel.publish(exchange_name, routing_key, 'test body 1', expiration='100')
            await asyncio.sleep(0.3, loop=event_loop)
            with raises(EmptyQueue):
                await channel.get(queue_name)  # if rabbitmq is slow this might succeed
        check_clean_channel_close(channel)
    check_clean_connection_close(connection)
Exemplo n.º 3
0
async def test_queue_ttl(event_loop, connect_to_broker):
    queue_name = 'testcase_queue'
    exchange_name = 'testcase_exchange'
    routing_key = 'testcase_routing_key'
    async with await connect_to_broker() as connection:
        async with connection.channel() as channel:
            await channel.select_confirm()
            await channel.delete_queue(queue_name)
            await channel.declare_queue(queue_name, ttl=1000)
            await channel.delete_exchange(exchange_name)
            await channel.declare_exchange(exchange_name, 'direct')
            await channel.bind_queue(queue_name, exchange_name, routing_key)

            await channel.publish(exchange_name, routing_key, 'test body 1')
            message = await channel.get(queue_name)  # if we run slow and this takes over 1 secs, test may fail
            assert message.decode() == 'test body 1'
            await message.ack()

            await channel.publish(exchange_name, routing_key, 'test body 2')
            await asyncio.sleep(1.5, loop=event_loop)  # test may fail if rabbitmq hasn't deleted message in 0.5 secs
            with raises(EmptyQueue):
                await channel.get(queue_name)

            # this should work again
            await channel.publish(exchange_name, routing_key, 'test body 3')
            message = await channel.get(queue_name)  # if we run slow and this takes over 1 secs, test may fail
            assert message.decode() == 'test body 3'
            await message.ack()
        check_clean_channel_close(channel)
    check_clean_connection_close(connection)
Exemplo n.º 4
0
async def test_message_reject(event_loop, connect_to_broker):
    queue_name = 'testcase_queue'
    async with await connect_to_broker() as connection:
        async with connection.channel() as channel:
            await channel.select_confirm()
            await channel.delete_queue(queue_name)
            await channel.declare_queue(queue_name)

            # requeue false
            await channel.publish('', queue_name, b'test message 1')
            message = await channel.get(queue_name)
            assert message.body == b'test message 1'
            await message.reject(requeue=False)
            await asyncio.sleep(0.1, loop=event_loop)
            with raises(EmptyQueue):
                await channel.get(queue_name)

            # requeue true
            await channel.publish('', queue_name, b'test message 2')
            message = await channel.get(queue_name)
            assert message.body == b'test message 2'
            await message.reject(requeue=True)
            message = await channel.get(queue_name)
            assert message.body == b'test message 2'
            await message.ack()
        check_clean_channel_close(channel)
    check_clean_connection_close(connection)
Exemplo n.º 5
0
async def test_amqplain_auth(connect_to_broker):
    auth = AmqPlainOnlyAuth()
    async with await connect_to_broker(auth=auth) as connection:
        async with connection.channel() as channel:
            pass
        check_clean_channel_close(channel)
    check_clean_connection_close(connection)
Exemplo n.º 6
0
async def test_qos(event_loop, connect_to_broker):
    async with await connect_to_broker() as connection:
        prefetch_count = 23
        message_count = prefetch_count + 10
        async with connection.channel(prefetch_count=prefetch_count) as channel:
            setup = await setup_channel(event_loop, channel)
            for i in range(1, message_count+1):
                await channel.publish(setup.exchange_name, setup.routing_key, 'message {}'.format(i))
            # no_ack must be false, otherwise broker will deliver as many messages as possible
            async with channel.consume(setup.queue_name, no_ack=False) as consumer:
                # gice broker a chance to deliver prefetch_count messages to us
                await asyncio.sleep(1.0, loop=event_loop)
                async for i, message in aenumerate(consumer, 1):
                    assert message.body.decode() == 'message {}'.format(i)
                    messages_left = message_count - i
                    if prefetch_count <= messages_left:
                        # queue object on Consumer() has one message less, this one
                        assert consumer._message_queue.qsize() == prefetch_count - 1, i
                    else:
                        assert consumer._message_queue.qsize() == messages_left, i
                    await message.ack()
                    await asyncio.sleep(0.1, loop=event_loop)
                    # and now it should be back up to prefetch count
                    if prefetch_count <= messages_left:
                        assert consumer._message_queue.qsize() == prefetch_count, i
                    else:
                        assert consumer._message_queue.qsize() == messages_left, i
                    if i == message_count:
                        assert consumer._message_queue.qsize() == 0
                        break
        check_clean_channel_close(channel)
    check_clean_connection_close(connection)
Exemplo n.º 7
0
async def test_queue_max_length(connect_to_broker):
    queue_name = 'testcase_queue'
    exchange_name = 'testcase_exchange'
    routing_key = 'testcase_routing_key'
    async with await connect_to_broker() as connection:
        async with connection.channel() as channel:
            await channel.select_confirm()
            await channel.delete_exchange(exchange_name)
            await channel.declare_exchange(exchange_name, 'direct')
            await channel.delete_queue(queue_name)
            await channel.declare_queue(queue_name, max_length=3)
            await channel.bind_queue(queue_name, exchange_name, routing_key)

            for i in [1, 2, 3, 4]:
                await channel.publish(exchange_name, routing_key,
                                      'test body {}'.format(i))

            # oldest message is thrown out first
            for i in [2, 3, 4]:
                message = await channel.get(queue_name)
                assert message.body.decode() == 'test body {}'.format(i)

            with raises(EmptyQueue):
                await channel.get(queue_name)
        check_clean_channel_close(channel)
    check_clean_connection_close(connection)
Exemplo n.º 8
0
async def test_multiple_select_confirms(connect_to_broker):
    async with await connect_to_broker() as connection:
        async with connection.channel() as channel:
            await channel.select_confirm()
            await channel.select_confirm()
        check_clean_channel_close(channel)
    check_clean_connection_close(connection)
Exemplo n.º 9
0
async def test_reply(connect_to_broker):
    """Publish a message with reply_to and correlation_id, get it from queue, use Message.reply(), get the reply message
    from the server"""
    async with await connect_to_broker() as connection:
        async with connection.channel() as channel:
            await channel.select_confirm()
            await channel.delete_queue('testcase_queue')
            await channel.declare_queue('testcase_queue')
            await channel.delete_exchange('testcase_exchange')
            await channel.declare_exchange('testcase_exchange', 'direct')
            await channel.bind_queue('testcase_queue', 'testcase_exchange',
                                     'testcase_routing_key')

            reply_queue_name = (await channel.declare_queue(
                '', exclusive=True, durable=False)).queue_name
            await channel.publish('testcase_exchange',
                                  'testcase_routing_key',
                                  'original body',
                                  correlation_id='test correlation id',
                                  reply_to=reply_queue_name)
            orig_message = await channel.get('testcase_queue')
            assert orig_message.properties.correlation_id == 'test correlation id'
            assert orig_message.decode() == 'original body'
            await orig_message.reply(b'reply body')
            await orig_message.ack()

            reply_message = await channel.get(reply_queue_name, no_ack=True)
            assert reply_message.properties.correlation_id == 'test correlation id'
            assert reply_message.body == b'reply body'
        check_clean_channel_close(channel)
    check_clean_connection_close(connection)
Exemplo n.º 10
0
async def test_purge_no_queue_name(connect_to_broker):
    async with await connect_to_broker() as connection:
        # first channel gets closed because we purge a nonexisting queue
        async with connection.channel() as channel:
            with raises(ServerClosedChannel) as excinfo:
                await channel.purge_queue('')
            assert excinfo.value.reply_code == 404
            assert excinfo.value.reply_text == "NOT_FOUND - no previously declared queue"
            assert excinfo.value.class_id == CLASS_QUEUE
            assert excinfo.value.method_id == METHOD_QUEUE_PURGE
        assert channel._closing_exc is excinfo.value

        # second purge ought to work ok
        async with connection.channel() as channel:
            await channel.select_confirm()
            queue_name_1 = (await channel.declare_queue('')).queue_name
            queue_name_2 = (await channel.declare_queue('')).queue_name
            # put different amount of messages to queues to know which one was purged based on purge-ok message count
            await channel.publish('', queue_name_1, 'q1 msg 1')
            await channel.publish('', queue_name_2, 'q2 msg 1')
            await channel.publish('', queue_name_2, 'q2 msg 2')
            assert queue_name_1 != queue_name_2

            assert await channel.purge_queue('') == 2  # queue 2 was purged
            assert await channel.purge_queue(''
                                             ) == 0  # queue 2 was purged again
            assert await channel.purge_queue(
                queue_name_1) == 1  # queue 1 purge with queue name
        check_clean_channel_close(channel)
    check_clean_connection_close(connection)
Exemplo n.º 11
0
async def test_open_channel(connect_to_broker):
    async with await connect_to_broker() as connection:
        async with connection.channel() as channel:
            assert isinstance(channel, Channel)
            assert channel.channel_id == 1
        check_clean_channel_close(channel)
    check_clean_connection_close(connection)
Exemplo n.º 12
0
async def test_queue_max_length_bytes(connect_to_broker):
    queue_name = 'testcase_queue'
    exchange_name = 'testcase_exchange'
    routing_key = 'testcase_routing_key'
    async with await connect_to_broker() as connection:
        async with connection.channel() as channel:
            await channel.select_confirm()
            await channel.delete_exchange(exchange_name)
            await channel.declare_exchange(exchange_name, 'direct')
            await channel.delete_queue(queue_name)
            await channel.declare_queue(queue_name,
                                        max_length_bytes=3 * 500 * 1024)
            await channel.bind_queue(queue_name, exchange_name, routing_key)

            for i in [1, 2, 3, 4]:
                # a bit less than the total limit/message count to make room for message/frame overhead
                body = str(i).encode('ascii') * (470 * 1024)
                await channel.publish(exchange_name, routing_key, body)

            # oldest message is thrown out first
            for i in [2, 3, 4]:
                message = await channel.get(queue_name)
                assert message.body == str(i).encode('ascii') * (470 * 1024)

            with raises(EmptyQueue):
                await channel.get(queue_name)
        check_clean_channel_close(channel)
    check_clean_connection_close(connection)
Exemplo n.º 13
0
async def test_amqplain_auth_directly(connect_to_broker):
    """directly as in no Authentication to choose the mech first"""
    auth = AMQPlainAuth('guest', 'guest')
    async with await connect_to_broker(auth=auth) as connection:
        async with connection.channel() as channel:
            pass
        check_clean_channel_close(channel)
    check_clean_connection_close(connection)
Exemplo n.º 14
0
async def test_get_empty(connect_to_broker):
    async with await connect_to_broker() as connection:
        async with connection.channel() as channel:
            await channel.delete_queue('testcase_queue')
            await channel.declare_queue('testcase_queue')
            with raises(EmptyQueue):
                await channel.get('testcase_queue')
        check_clean_channel_close(channel)
    check_clean_connection_close(connection)
Exemplo n.º 15
0
async def test_exchange_declare(connect_to_broker):
    async with await connect_to_broker() as connection:
        async with connection.channel() as channel:
            await channel.delete_exchange('testcase_exchange')
            await channel.declare_exchange('testcase_exchange', 'fanout')
            await channel.delete_exchange('testcase_exchange')
            await channel.delete_exchange('testcase_exchange')
        check_clean_channel_close(channel)
    check_clean_connection_close(connection)
Exemplo n.º 16
0
async def test_queue_declare(connect_to_broker):
    async with await connect_to_broker() as connection:
        async with connection.channel() as channel:
            await channel.delete_queue('testcase_queue')
            await channel.declare_queue('testcase_queue')
            assert await channel.purge_queue('testcase_queue') == 0
            assert await channel.delete_queue('testcase_queue') == 0
            assert await channel.delete_queue('testcase_queue') == 0
        check_clean_channel_close(channel)
    check_clean_connection_close(connection)
Exemplo n.º 17
0
async def test_publish_bytes(connect_to_broker):
    async with await connect_to_broker() as connection:
        async with connection.channel() as channel:
            await channel.declare_exchange('testcase_exchange', 'fanout')
            await channel.select_confirm(
            )  # so server has a chance to nack/close
            await channel.publish('testcase_exchange', 'test_routing_key',
                                  b'abc')  # bytes
            await channel.publish('testcase_exchange', 'test_routing_key',
                                  'böö')  # str
            await channel.delete_exchange('testcase_exchange')
        check_clean_channel_close(channel)
    check_clean_connection_close(connection)
Exemplo n.º 18
0
async def test_queue_bind(connect_to_broker):
    async with await connect_to_broker() as connection:
        async with connection.channel() as channel:
            await channel.declare_queue('testcase_queue')
            await channel.declare_exchange('testcase_exchange', 'fanout')
            await channel.bind_queue('testcase_queue', 'testcase_exchange',
                                     'test_routing_key')
            await channel.unbind_queue('testcase_queue', 'testcase_exchange',
                                       'test_routing_key')
            await channel.unbind_queue('testcase_queue', 'testcase_exchange',
                                       'test_routing_key')
        check_clean_channel_close(channel)
    check_clean_connection_close(connection)
Exemplo n.º 19
0
async def test_publish_json(connect_to_broker):
    async with await connect_to_broker() as connection:
        async with connection.channel() as channel:
            await channel.declare_exchange('testcase_exchange', 'fanout')
            await channel.select_confirm()
            await channel.publish('testcase_exchange',
                                  'test_routing_key',
                                  json=['string', {
                                      'dict': 123
                                  }])
            await channel.delete_exchange('testcase_exchange')
        check_clean_channel_close(channel)
    check_clean_connection_close(connection)
Exemplo n.º 20
0
async def test_concurrency(connect_to_broker, event_loop):
    logger = logging.getLogger('testcase')
    iterations = 10
    publish_batch_size = 300
    async with await connect_to_broker() as connection:
        async with connection.channel() as channel_one, connection.channel(
        ) as channel_two:
            names = await setup_concurrent_queues(channel_one)
            consumed_ids = set()
            ack_consumer_task = event_loop.create_task(
                consume_messages(channel_one, names, True, event_loop, 100,
                                 consumed_ids))
            noack_consumer_one_task = event_loop.create_task(
                consume_messages(channel_two, names, True, event_loop, 500,
                                 consumed_ids))
            publish_task = event_loop.create_task(
                publish_messages(channel_one, iterations, names,
                                 publish_batch_size, event_loop))
            get_message_count = (iterations * publish_batch_size) // 4
            get_ids = set()
            while len(get_ids) < get_message_count:
                logger.info('Got %s/%s messages', len(get_ids),
                            get_message_count)
                try:
                    message = await channel_two.get(names.get_queue_name,
                                                    no_ack=False)
                except EmptyQueue:
                    logger.info('No message in queue, sleeping a bit')
                    await asyncio.sleep(0.1, loop=event_loop)
                else:
                    get_ids.add(message.json())
                    await message.ack()
            await publish_task
            consume_message_count = (3 * iterations * publish_batch_size) // 4
            while len(consumed_ids) < consume_message_count:
                logger.info('%s/%s messages consumed', len(consumed_ids),
                            consume_message_count)
                await asyncio.sleep(0.1, loop=event_loop)
            for consumer_task in ack_consumer_task, noack_consumer_one_task:
                assert not consumer_task.done()
                consumer_task.cancel()
                with raises(asyncio.CancelledError):
                    await consumer_task
            assert not channel_one._consumers
            assert not channel_two._consumers
            assert get_ids | consumed_ids == set(
                range(iterations * publish_batch_size))
        check_clean_channel_close(channel_one)
        check_clean_channel_close(channel_two)
    check_clean_connection_close(connection)
Exemplo n.º 21
0
async def test_empty_message(event_loop, connect_to_broker):
    async with await connect_to_broker() as connection:
        async with connection.channel() as channel:
            await channel.select_confirm()
            await channel.delete_queue('testcase_queue')
            await channel.declare_queue('testcase_queue')
            await channel.delete_exchange('testcase_exchange')
            await channel.declare_exchange('testcase_exchange', 'direct')
            await channel.bind_queue('testcase_queue', 'testcase_exchange',
                                     'testcase_routing_key')
            await channel.publish('testcase_exchange', 'testcase_routing_key',
                                  b'')
            message = await channel.get('testcase_queue')
            assert isinstance(message, GetMessage)
            assert message.body == b''
            await message.ack()
            await asyncio.sleep(0.05, loop=event_loop)
        check_clean_channel_close(channel)
    check_clean_connection_close(connection)
Exemplo n.º 22
0
async def test_server_cancel(event_loop, connect_to_broker):
    async with await connect_to_broker() as connection:
        async with connection.channel() as channel:
            await channel.delete_queue('testcase_queue')
            await channel.declare_queue('testcase_queue')
            async with channel.consume('testcase_queue') as consumer:
                assert isinstance(consumer, Consumer)
                async def go():
                    async for message in consumer:
                        raise ValueError("Didn't expect to get a message: {!r}".format(message))
                    raise ValueError('consumer iteration done')
                task = event_loop.create_task(go())
                await channel.delete_queue('testcase_queue')
                with raises(ServerCancelledConsumer) as excinfo:
                    await task
            assert consumer._closing_exc is excinfo.value
            await channel.delete_queue('testcase_queue')  # just testing operations on channel still work
        check_clean_channel_close(channel)
    check_clean_connection_close(connection)
Exemplo n.º 23
0
async def test_consume_and_cancel(connect_to_broker):
    async with await connect_to_broker() as connection:
        async with connection.channel() as channel:
            await channel.select_confirm()
            await channel.delete_queue('testcase_queue')
            await channel.declare_queue('testcase_queue')
            await channel.delete_exchange('testcase_exchange')
            await channel.declare_exchange('testcase_exchange', 'direct')
            await channel.bind_queue('testcase_queue', 'testcase_exchange', 'testcase_routing_key')
            await channel.publish('testcase_exchange', 'testcase_routing_key', b'message one')
            async with channel.consume('testcase_queue') as consumer:
                assert isinstance(consumer, Consumer)
                await channel.publish('testcase_exchange', 'testcase_routing_key', b'message two')
                assert consumer._message_queue.qsize() == 2, consumer._message_queue.qsize()
                async for i, message in aenumerate(consumer, 1):
                    assert isinstance(message, DeliverMessage)
                    await message.ack()
                    if i == 2:
                        break
            check_clean_consumer_cancel(consumer)
        check_clean_channel_close(channel)
    check_clean_connection_close(connection)
Exemplo n.º 24
0
async def test_priority(event_loop, connect_to_broker):
    queue_name = 'testcase_queue'
    exchange_name = 'testcase_exchange'
    routing_key = 'testcase_routing_key'
    async with await connect_to_broker() as connection:
        async with connection.channel(prefetch_count=2) as channel:
            await channel.select_confirm()
            await asyncio.gather(channel.delete_queue(queue_name),
                                 channel.delete_exchange(exchange_name),
                                 loop=event_loop)
            await asyncio.gather(channel.declare_exchange(
                exchange_name, 'direct'),
                                 channel.declare_queue(queue_name,
                                                       max_priority=7),
                                 loop=event_loop)
            await channel.bind_queue(queue_name, exchange_name, routing_key)
            message_priorities = [0, 3, 1, 6, 7, 9, 4, 2, 8, 5]
            # list items are (message_priorities index, priority). max_priority 7 -> 7 sorts before 9
            expected_order = [(4, 7), (5, 9), (8, 8), (3, 6), (9, 5), (6, 4),
                              (1, 3), (7, 2), (2, 1), (0, 0)]
            for i, message_priority in enumerate(message_priorities):
                await channel.publish(exchange_name,
                                      routing_key,
                                      'message {} priority {}'.format(
                                          i, message_priority),
                                      priority=message_priority)
            async with channel.consume(queue_name) as consumer:
                async for i, (message, (send_i,
                                        expected_priority)) in aenumerate(
                                            azip(consumer, expected_order), 1):
                    assert message.body.decode(
                    ) == 'message {} priority {}'.format(
                        send_i, expected_priority)
                    assert message.properties.priority == expected_priority
                    await message.ack()
                    if i == len(message_priorities):
                        break
        check_clean_channel_close(channel)
    check_clean_connection_close(connection)
Exemplo n.º 25
0
async def test_recover(event_loop, connect_to_broker):
    logger = logging.getLogger('test_recover')
    message_n = 10
    async with await connect_to_broker() as connection:
        async with connection.channel(prefetch_count=50) as channel:
            setup = await setup_channel(event_loop, channel)
            # TODO: test this, it causes the server to send basic.ack with multiple=True which we don't support yet
            await asyncio.gather(*(
                event_loop.create_task(
                    channel.publish(setup.exchange_name, setup.routing_key, 'message {}'.format(i))
                ) for i in range(10)
            ), loop=event_loop)
            #for i in range(10):
            #    await channel.publish(setup.exchange_name, setup.routing_key, 'message {}'.format(i))
            async with channel.consume(setup.queue_name) as consumer:
                async for i, message in aenumerate(consumer):
                    logger.info(
                        'Got message number %s: redelivered = %s body = %r',
                        i, message.redelivered, message.body)
                    if i < 10:
                        assert message.decode() == 'message {}'.format(i)
                        assert message.redelivered is False
                    else:
                        # 10 -> 1, 11 -> 3, 12 -> 5 etc
                        assert message.decode() == 'message {}'.format((i - 10) * 2 +1 )
                        assert message.redelivered is True
                    if i % 2 == 0 or i >= 10:
                        await message.ack()  # messages 0, 2, 4, 6, 8 and 10+
                    elif i == 9:
                        assert consumer._message_queue.qsize() == 0
                        await channel.recover(requeue=True)
                        await asyncio.sleep(0.2, loop=event_loop)
                        assert consumer._message_queue.qsize() == 5  # 10 - 5 = 5
                    if i == 14:
                        assert consumer._message_queue.qsize() == 0
                        break
        check_clean_channel_close(channel)
    check_clean_connection_close(connection)
Exemplo n.º 26
0
async def test_frame_max(event_loop, connect_to_broker):
    frame_max = 10 * 1024  # 10kB
    async with await connect_to_broker(
            frame_max=frame_max,
            connection_factory=FrameMaxConnection) as connection:
        assert connection.frame_max == frame_max
        assert isinstance(connection, FrameMaxConnection)
        async with connection.channel() as channel:
            setup = await setup_channel(event_loop, channel)
            body = b''.join(bytes([i]) * (frame_max - 8)
                            for i in range(7)) + bytes([8]) * (7 * 8)
            assert len(body) == frame_max * 7
            await channel.publish(setup.exchange_name, setup.routing_key, body)

            # check published message was sent in body frames with size == frame-max except the last one
            assert len(connection.sent_body_payloads) == 8
            assert b''.join(connection.sent_body_payloads) == body
            for i, payload in enumerate(connection.sent_body_payloads[:-1]):
                assert payload == bytes([i]) * (
                    10 * 1024 - 8)  # 7 bytes for frame header, 1 for frame end
            # 7 * 8 = num of frames with max_frame payload * leftover/frame
            assert connection.sent_body_payloads[-1] == bytes([8]) * (7 * 8)

            # get a message, check that it's split into body frames with size == frame-max except the last one
            message = await channel.get(setup.queue_name)

            assert message.body == body
            assert len(connection.received_body_frames) == 8
            for i, body_frame in enumerate(
                    connection.received_body_frames[:-1]):
                assert body_frame.payload_size == 10 * 1024 - 8
                assert body_frame.payload == bytes([i]) * (10 * 1024 - 8)
            assert connection.received_body_frames[-1].payload_size == 7 * 8
            assert connection.received_body_frames[-1].payload == bytes(
                [8]) * (7 * 8)
        check_clean_channel_close(channel)
    check_clean_connection_close(connection)
Exemplo n.º 27
0
async def test_consumer_priority(event_loop, connect_to_broker):
    """
    - Set qos prefetch count to 2
    - Publishes 10 messages to a queue
    - Start two consumers, one with priority 5 and one with 0
    - Coordinate message acks in consumers so that broker will deliver messages to the high priority one when it can
      and to the low one when the high one is blocked
    - Check both consumers get the messages coordination from previous step should result in
    """
    low_to_high = asyncio.Queue(loop=event_loop)  # low signals to high that high can continue
    high_to_low = asyncio.Queue(loop=event_loop)  # and vice versa

    async def consume_high(consumer):
        """This one takes messages 0, 1 and 4"""
        message_iter = aiter(consumer)
        message0 = await anext(message_iter)
        assert message0.body == b'message 0'
        message1 = await anext(message_iter)
        assert message1.body == b'message 1'
        assert consumer._message_queue.qsize() == 0  # now messages go to the low consumer too until we ack
        await message0.ack()  # our queue gets another one
        assert (await low_to_high.get()) == 'l1'
        message4 = await anext(message_iter)
        assert message4.body == b'message 4'
        assert consumer._message_queue.qsize() == 0  # now messages go to the low consumer too until we ack
        high_to_low.put_nowait('h1')  # signal that low can take rest of messages
        assert (await low_to_high.get()) == 'l2'
        await message1.ack()
        await message4.ack()
        assert consumer._message_queue.qsize() == 0
        with raises(asyncio.TimeoutError):
            await asyncio.wait_for(anext(message_iter), 1.0, loop=event_loop)
        assert consumer._message_queue.qsize() == 0

    async def consume_low(consumer):
        """This one takes messages 2, 3 and 5-9"""
        message_iter = aiter(consumer)
        message2 = await anext(message_iter)
        assert message2.body == b'message 2'
        message3 = await anext(message_iter)
        assert message3.body == b'message 3'
        assert consumer._message_queue.qsize() == 0
        low_to_high.put_nowait('l1')  # signal that high can ack a message
        assert (await high_to_low.get()) == 'h1'
        await message2.ack()
        await message3.ack()
        async for i, message in aenumerate(message_iter, 5):
            assert message.decode() == 'message {}'.format(i)
            await message.ack()
            if i == 9:
                break
        assert consumer._message_queue.qsize() == 0
        low_to_high.put_nowait('l2')  # go on then, nothing left for high

    async with await connect_to_broker() as connection:
        async with connection.channel(prefetch_count=2) as channel:
            setup = await setup_channel(event_loop, channel)
            for i in range(10):
                await channel.publish(setup.exchange_name, setup.routing_key, 'message {}'.format(i))
            async with channel.consume(setup.queue_name, priority=5) as consumer_high:
                async with channel.consume(setup.queue_name) as consumer_low:  # implicit priority 0
                    high_task = event_loop.create_task(consume_high(consumer_high))
                    low_task = event_loop.create_task(consume_low(consumer_low))
                    await asyncio.gather(high_task, low_task, loop=event_loop)
        check_clean_channel_close(channel)
    check_clean_connection_close(connection)
Exemplo n.º 28
0
async def test_dead_letter_exchange(event_loop, connect_to_broker):
    def check_message_1(message):
        assert message.body == b'message 1'
        assert message.routing_key == 'orig_rk1'
        x_death_headers = message.properties.headers['x-death']
        assert len(x_death_headers) == 1
        x_death_header, = x_death_headers
        assert x_death_header['count'] == 1
        assert x_death_header['reason'] == 'expired'
        assert x_death_header['queue'] == orig_queue_name_1
        assert isinstance(
            x_death_header['time'],
            datetime)  # TODO: convert this from UTC in datetime_pb
        assert x_death_header['exchange'] == orig_exchange_name
        assert x_death_header['routing-keys'] == ['orig_rk1']

    def check_message_2(message):
        assert message.body == b'message 2'
        # routing should have changed because of dead_letter_routing_key
        assert message.routing_key == 'dead_rk'
        x_death_headers = message.properties.headers['x-death']
        assert len(x_death_headers) == 1
        x_death_header, = x_death_headers
        assert x_death_header['count'] == 1
        assert x_death_header['reason'] == 'expired'
        assert x_death_header['queue'] == orig_queue_name_2
        assert isinstance(x_death_header['time'], datetime)
        assert x_death_header['exchange'] == orig_exchange_name
        assert x_death_header['routing-keys'] == ['orig_rk2']

    orig_queue_name_1 = 'testcase_queue_1'
    orig_queue_name_2 = 'testcase_queue_2'
    dead_queue_name = 'testcase_dead_queue'
    orig_exchange_name = 'testcase_orig_exchange'
    dead_exchange_name = 'testcase_dead_exchange'
    async with await connect_to_broker() as connection:
        async with connection.channel() as channel:
            await channel.select_confirm()
            await asyncio.gather(channel.delete_queue(orig_queue_name_1),
                                 channel.delete_queue(orig_queue_name_2),
                                 channel.delete_queue(dead_queue_name),
                                 channel.delete_exchange(dead_exchange_name),
                                 channel.delete_exchange(orig_exchange_name),
                                 loop=event_loop)
            # this is where the dead lettering puts rejected/expired messages
            await asyncio.gather(channel.declare_exchange(
                dead_exchange_name, 'direct'),
                                 channel.declare_queue(dead_queue_name),
                                 loop=event_loop)
            # queue 1 with dead lettering, keeps original routing key
            # queue 2 with dead lettering, modifies routing key
            await asyncio.gather(
                channel.declare_queue(orig_queue_name_1,
                                      dead_letter_exchange=dead_exchange_name,
                                      ttl=0),
                channel.declare_queue(orig_queue_name_2,
                                      dead_letter_exchange=dead_exchange_name,
                                      dead_letter_routing_key='dead_rk',
                                      ttl=0),
                channel.bind_queue(dead_queue_name, dead_exchange_name,
                                   'orig_rk1'),
                channel.bind_queue(dead_queue_name, dead_exchange_name,
                                   'dead_rk'),
                channel.declare_exchange(orig_exchange_name, 'direct'),
                loop=event_loop)

            await asyncio.gather(channel.bind_queue(orig_queue_name_1,
                                                    orig_exchange_name,
                                                    'orig_rk1'),
                                 channel.bind_queue(orig_queue_name_2,
                                                    orig_exchange_name,
                                                    'orig_rk2'),
                                 loop=event_loop)

            await channel.publish(orig_exchange_name, 'orig_rk1', 'message 1')
            await asyncio.sleep(0.1, loop=event_loop)
            for queue_name in orig_queue_name_1, orig_queue_name_2:
                with raises(EmptyQueue):
                    await channel.get(queue_name)
            message = await channel.get(dead_queue_name)
            check_message_1(message)

            await channel.publish(orig_exchange_name, 'orig_rk2', 'message 2')
            await asyncio.sleep(0.1, loop=event_loop)
            for queue_name in orig_queue_name_1, orig_queue_name_2:
                with raises(EmptyQueue):
                    await channel.get(queue_name)
            message = await channel.get(dead_queue_name)
            check_message_2(message)
        check_clean_channel_close(channel)
    check_clean_connection_close(connection)