async def test_internal_exchange( self, channel: aio_pika.Channel, declare_exchange, declare_queue ): routing_key = get_random_name() exchange_name = get_random_name("internal", "exchange") exchange = await declare_exchange( exchange_name, auto_delete=True, internal=True, ) queue = await declare_queue(auto_delete=True) await queue.bind(exchange, routing_key) body = bytes(shortuuid.uuid(), "utf-8") with pytest.raises(ValueError): f = exchange.publish( Message( body, content_type="text/plain", headers={"foo": "bar"}, ), routing_key, ) await f await queue.unbind(exchange, routing_key)
async def test_simple_publish_and_receive_to_bound_exchange( self, channel: aio_pika.Channel, declare_exchange: Callable, declare_queue: Callable, add_cleanup: Callable, ): routing_key = get_random_name() src_name = get_random_name("source", "exchange") dest_name = get_random_name("destination", "exchange") src_exchange = await declare_exchange(src_name, auto_delete=True) dest_exchange = await declare_exchange(dest_name, auto_delete=True) queue = await declare_queue(auto_delete=True) await queue.bind(dest_exchange, routing_key) await dest_exchange.bind(src_exchange, routing_key) add_cleanup(dest_exchange.unbind, src_exchange, routing_key) body = bytes(shortuuid.uuid(), "utf-8") await src_exchange.publish( Message(body, content_type="text/plain", headers={"foo": "bar"}), routing_key, ) incoming_message = await queue.get(timeout=5) incoming_message.ack() assert incoming_message.body == body await queue.unbind(dest_exchange, routing_key)
async def test_reject_twice( self, channel: aio_pika.Channel, add_cleanup: Callable, declare_queue: Callable, declare_exchange: Callable, ): queue_name = get_random_name("test_connection") routing_key = get_random_name() exchange = await declare_exchange("direct", auto_delete=True) queue = await declare_queue(queue_name, auto_delete=True) await queue.bind(exchange, routing_key) add_cleanup(queue.unbind, exchange, routing_key) body = bytes(shortuuid.uuid(), "utf-8") await exchange.publish( Message(body, content_type="text/plain", headers={"foo": "bar"}), routing_key, ) incoming_message = await queue.get(timeout=5) incoming_message.reject(requeue=False) with pytest.raises(MessageProcessError): incoming_message.reject(requeue=False) assert incoming_message.body == body
async def test_simple_publish_without_confirm( self, connection: aio_pika.Connection, declare_exchange: Callable, declare_queue: Callable, ): queue_name = get_random_name("test_connection") routing_key = get_random_name() channel = await connection.channel(publisher_confirms=False) exchange = await declare_exchange( "direct", auto_delete=True, channel=channel, ) queue = await declare_queue( queue_name, auto_delete=True, channel=channel, ) await queue.bind(exchange, routing_key) body = bytes(shortuuid.uuid(), "utf-8") result = await exchange.publish( Message(body, content_type="text/plain", headers={"foo": "bar"}), routing_key, ) assert result is None incoming_message = await queue.get(timeout=5) incoming_message.ack() assert incoming_message.body == body await queue.unbind(exchange, routing_key)
async def test_big_message( self, channel: aio_pika.Channel, add_cleanup: Callable, declare_queue, declare_exchange, ): queue_name = get_random_name("test_big") routing_key = get_random_name() exchange = await declare_exchange("direct", auto_delete=True) queue = await declare_queue(queue_name, auto_delete=True) await queue.bind(exchange, routing_key) add_cleanup(queue.unbind, exchange, routing_key) add_cleanup(queue.delete) body = bytes(shortuuid.uuid(), "utf-8") * 1000000 await exchange.publish( Message(body, content_type="text/plain", headers={"foo": "bar"}), routing_key, ) incoming_message = await queue.get(timeout=5) incoming_message.ack() assert incoming_message.body == body
async def test_purge_queue( self, declare_queue: Callable, declare_exchange: Callable, channel: aio_pika.Channel, ): queue_name = get_random_name("test_connection4") routing_key = get_random_name() exchange = await declare_exchange("direct", auto_delete=True) queue = await declare_queue(queue_name, auto_delete=True) await queue.bind(exchange, routing_key) try: body = bytes(shortuuid.uuid(), "utf-8") await exchange.publish( Message( body, content_type="text/plain", headers={"foo": "bar"}, ), routing_key, ) await queue.purge() with pytest.raises(asyncio.TimeoutError): await queue.get(timeout=1) except aio_pika.exceptions.QueueEmpty: await queue.unbind(exchange, routing_key) await queue.delete()
async def test_delete_queue_and_exchange( self, connection, declare_exchange, declare_queue ): queue_name = get_random_name("test_connection") exchange = get_random_name() channel = await self.create_channel(connection) await declare_exchange(exchange, auto_delete=True) await declare_queue(queue_name, auto_delete=True) await channel.queue_delete(queue_name) await channel.exchange_delete(exchange)
async def test_no_ack_redelivery( self, connection, add_cleanup: Callable, declare_queue, declare_exchange, ): queue_name = get_random_name("test_connection") routing_key = get_random_name() channel = await self.create_channel(connection) exchange = await declare_exchange( "direct", auto_delete=True, channel=channel, ) queue = await declare_queue( queue_name, auto_delete=False, channel=channel, cleanup=False, ) await queue.bind(exchange, routing_key) # publish 2 messages for _ in range(2): body = bytes(shortuuid.uuid(), "utf-8") msg = Message(body) await exchange.publish(msg, routing_key) if not channel._publisher_confirms: await asyncio.sleep(1) # ack 1 message out of 2 first_message = await queue.get(timeout=5) last_message = await queue.get(timeout=5) last_message.ack() # close channel, not acked message should be redelivered await channel.close() channel = await self.create_channel(connection) exchange = await declare_exchange( "direct", auto_delete=True, channel=channel, ) queue = await declare_queue( queue_name, auto_delete=False, channel=channel, ) # receive not acked message message = await queue.get(timeout=5) assert message.body == first_message.body message.ack() await queue.unbind(exchange, routing_key)
async def test_queue_iterator_close_with_noack( self, create_connection: Callable, loop, add_cleanup: Callable, declare_queue, ): messages = [] queue_name = get_random_name("test_queue") body = get_random_name("test_body").encode() async def task_inner(): nonlocal messages nonlocal create_connection nonlocal add_cleanup connection = await create_connection() add_cleanup(connection.close) async with connection: channel = await self.create_channel(connection) queue = await declare_queue( queue_name, channel=channel, cleanup=False, passive=True, ) async with queue.iterator(no_ack=True) as q: async for message in q: messages.append(message) return async with await create_connection() as connection: channel = await self.create_channel(connection) queue = await declare_queue( queue_name, channel=channel, cleanup=False, ) try: await channel.default_exchange.publish( Message(body), routing_key=queue_name, ) task = loop.create_task(task_inner()) await task assert messages assert messages[0].body == body finally: await queue.delete()
async def test_ack_multiple( self, connection, declare_exchange, declare_queue, add_cleanup: Callable, ): queue_name = get_random_name("test_connection") routing_key = get_random_name() channel = await self.create_channel(connection) exchange = await declare_exchange( "direct", auto_delete=True, channel=channel, ) queue = await declare_queue( queue_name, auto_delete=False, cleanup=False, channel=channel, ) await queue.bind(exchange, routing_key) # publish 2 messages for _ in range(2): body = bytes(shortuuid.uuid(), "utf-8") msg = Message(body) await exchange.publish(msg, routing_key) if not channel._publisher_confirms: await asyncio.sleep(1) # ack only last mesage with multiple flag, first # message should be acked too await queue.get(timeout=5) last_message = await queue.get(timeout=5) last_message.ack(multiple=True) # close channel, no messages should be redelivered await channel.close() channel = await self.create_channel(connection) exchange = await declare_exchange( "direct", auto_delete=True, channel=channel, ) queue = await declare_queue( queue_name, auto_delete=False, cleanup=False, channel=channel, ) with pytest.raises(aio_pika.exceptions.QueueEmpty): await queue.get() await queue.unbind(exchange, routing_key) await queue.delete()
async def test_basic_return(self, connection: aio_pika.connection, loop): channel = await self.create_channel( connection, ) # type: aio_pika.Channel f = loop.create_future() def handler(sender, *args, **kwargs): f.set_result(*args, **kwargs) channel.add_on_return_callback(handler) body = bytes(shortuuid.uuid(), "utf-8") await channel.default_exchange.publish( Message(body, content_type="text/plain", headers={"foo": "bar"}), get_random_name("test_basic_return"), ) returned = await f assert returned.body == body # handler with exception f = loop.create_future() await channel.close() channel = await self.create_channel( connection, ) # type: aio_pika.Channel def bad_handler(sender, message): try: raise ValueError finally: f.set_result(message) channel.add_on_return_callback(bad_handler) body = bytes(shortuuid.uuid(), "utf-8") await channel.default_exchange.publish( Message(body, content_type="text/plain", headers={"foo": "bar"}), get_random_name("test_basic_return"), ) returned = await f assert returned.body == body
async def test_context_process_redelivery( self, channel: aio_pika.Channel, declare_exchange: Callable, declare_queue: Callable, add_cleanup: Callable, ): queue_name = get_random_name("test_connection") routing_key = get_random_name() exchange = await declare_exchange("direct", auto_delete=True) queue = await declare_queue(queue_name, auto_delete=True) await queue.bind(exchange, routing_key) add_cleanup(queue.unbind, exchange, routing_key) body = bytes(shortuuid.uuid(), "utf-8") await exchange.publish( Message(body, content_type="text/plain", headers={"foo": "bar"}), routing_key, ) if not channel._publisher_confirms: await asyncio.sleep(1) incoming_message = await queue.get(timeout=5) with pytest.raises(AssertionError): async with incoming_message.process( requeue=True, reject_on_redelivered=True, ): raise AssertionError incoming_message = await queue.get(timeout=5) with mock.patch("aio_pika.message.log") as message_logger: with pytest.raises(Exception): async with incoming_message.process( requeue=True, reject_on_redelivered=True, ): raise Exception assert message_logger.info.called assert ( message_logger.info.mock_calls[0][1][1].body == incoming_message.body ) assert incoming_message.body == body
async def test_async_for_queue(self, loop, connection, declare_queue): channel2 = await self.create_channel(connection) queue = await declare_queue( get_random_name("queue", "is_async", "for"), auto_delete=True, channel=channel2, ) messages = 100 async def publisher(): channel1 = await self.create_channel(connection) for i in range(messages): await channel1.default_exchange.publish( Message(body=str(i).encode()), routing_key=queue.name, ) loop.create_task(publisher()) count = 0 data = list() async for message in queue: async with message.process(): count += 1 data.append(message.body) if count >= messages: break assert data == list(map(lambda x: str(x).encode(), range(messages)))
async def test_declaration_result_with_messages( self, connection, declare_queue, declare_exchange ): channel1 = await self.create_channel(connection) channel2 = await self.create_channel(connection) queue_name = get_random_name("queue", "declaration-result") queue1 = await declare_queue( queue_name, auto_delete=True, channel=channel1, ) await channel1.default_exchange.publish( Message(body=b"test"), routing_key=queue1.name, ) await asyncio.sleep(1) queue2 = await declare_queue( queue_name, passive=True, channel=channel2, ) await queue2.get() await queue2.delete() assert queue2.declaration_result.consumer_count == 0 assert queue2.declaration_result.message_count == 1
async def test_queue_empty_fail_false( self, channel: aio_pika.Channel, declare_queue ): queue_name = get_random_name("test_get_on_empty_queue") queue = await declare_queue(queue_name, auto_delete=True) result = await queue.get(fail=False) assert result is None
async def test_expiration( self, channel: aio_pika.Channel, loop, declare_exchange, declare_queue ): dlx_queue = await declare_queue( get_random_name("test_dlx"), cleanup=False, ) # type: aio_pika.Queue dlx_exchange = await declare_exchange( get_random_name("dlx"), cleanup=False, ) # type: aio_pika.Exchange await dlx_queue.bind(dlx_exchange, routing_key=dlx_queue.name) queue = await declare_queue( get_random_name("test_expiration"), arguments={ "x-message-ttl": 10000, "x-dead-letter-exchange": dlx_exchange.name, "x-dead-letter-routing-key": dlx_queue.name, }, ) # type: aio_pika.Queue body = bytes(shortuuid.uuid(), "utf-8") await channel.default_exchange.publish( Message( body, content_type="text/plain", headers={"foo": "bar"}, expiration=0.5, ), queue.name, ) f = loop.create_future() await dlx_queue.consume(f.set_result, no_ack=True) message = await f assert message.body == body assert message.headers["x-death"][0]["original-expiration"] == b"500"
async def test_context_process_abrupt_channel_close( connection: aio_pika.RobustConnection, declare_exchange: Callable, declare_queue: Callable, ): # https://github.com/mosquito/aio-pika/issues/302 queue_name = get_random_name("test_connection") routing_key = get_random_name("rounting_key") channel = await connection.channel() exchange = await declare_exchange( "direct", auto_delete=True, channel=channel, ) queue = await declare_queue(queue_name, auto_delete=True, channel=channel) await queue.bind(exchange, routing_key) body = bytes(shortuuid.uuid(), "utf-8") await exchange.publish( Message(body, content_type="text/plain", headers={"foo": "bar"}), routing_key, ) incoming_message = await queue.get(timeout=5) # close aiormq channel to emulate abrupt connection/channel close await channel.channel.close() with pytest.raises(aiormq.exceptions.ChannelInvalidStateError): async with incoming_message.process(): # emulate some activity on closed channel await channel.channel.basic_publish( "dummy", exchange="", routing_key="non_existent", ) # emulate connection/channel restoration of connect_robust await channel.reopen() # cleanup queue incoming_message = await queue.get(timeout=5) async with incoming_message.process(): pass await queue.unbind(exchange, routing_key)
async def test_get_queue(self, connection, declare_queue): channel = await self.create_channel(connection) name = get_random_name("passive", "queue") with pytest.raises(aio_pika.exceptions.ChannelNotFoundEntity): await channel.get_queue(name) channel = await self.create_channel(connection) queue = await declare_queue(name, auto_delete=True, channel=channel) queue_passive = await channel.get_queue(name) assert queue.name, queue_passive.name
async def test_channel_locked_resource2(connection: aio_pika.RobustConnection): ch1 = await connection.channel() ch2 = await connection.channel() qname = get_random_name("channel", "locked", "resource") q1 = await ch1.declare_queue(qname, exclusive=True, robust=False) await q1.consume(print, exclusive=True) with pytest.raises(aiormq.exceptions.ChannelAccessRefused): q2 = await ch2.declare_queue(qname, exclusive=True, robust=False) await q2.consume(print, exclusive=True)
async def test_consuming_not_coroutine( self, loop, channel: aio_pika.Channel, declare_exchange: Callable, declare_queue: Callable, add_cleanup: Callable, ): queue_name = get_random_name("tc2") routing_key = get_random_name() exchange = await declare_exchange("direct", auto_delete=True) queue = await declare_queue(queue_name, auto_delete=True) add_cleanup(queue.unbind, exchange, routing_key) await queue.bind(exchange, routing_key) body = bytes(shortuuid.uuid(), "utf-8") f = loop.create_future() def handle(message): message.ack() assert message.body == body assert message.routing_key == routing_key f.set_result(True) await queue.consume(handle) await exchange.publish( Message(body, content_type="text/plain", headers={"foo": "bar"}), routing_key, ) if not f.done(): await f
async def test_simple_publish_and_receive_delivery_mode_explicitly( self, channel: aio_pika.Channel, declare_queue: Callable, declare_exchange: Callable, ): queue_name = get_random_name("test_connection") routing_key = get_random_name() exchange = await declare_exchange( "direct", auto_delete=True, channel=channel, ) queue = await declare_queue( queue_name, auto_delete=True, channel=channel, ) await queue.bind(exchange, routing_key) body = bytes(shortuuid.uuid(), "utf-8") await exchange.publish( Message( body, content_type="text/plain", headers={"foo": "bar"}, delivery_mode=None, ), routing_key, ) incoming_message = await queue.get(timeout=5) incoming_message.ack() assert incoming_message.body == body await queue.unbind(exchange, routing_key)
async def test_passive_queue( self, declare_queue: Callable, connection: aio_pika.Connection ): name = get_random_name("passive", "queue") ch1 = await self.create_channel(connection) ch2 = await self.create_channel(connection) ch3 = await self.create_channel(connection) with pytest.raises(aio_pika.exceptions.ChannelNotFoundEntity): await declare_queue(name, passive=True, channel=ch1) queue = await declare_queue(name, auto_delete=True, channel=ch2) queue_passive = await declare_queue(name, passive=True, channel=ch3) assert queue.name == queue_passive.name
async def test_declaration_result_with_consumers( self, connection, declare_queue ): channel1 = await self.create_channel(connection) channel2 = await self.create_channel(connection) queue_name = get_random_name("queue", "declaration-result") queue1 = await declare_queue( queue_name, auto_delete=True, channel=channel1, ) await queue1.consume(print) queue2 = await declare_queue( queue_name, passive=True, channel=channel2, cleanup=False, ) assert queue2.declaration_result.consumer_count == 1
async def test_revive_passive_queue_on_reconnect(create_connection): client1 = await create_connection() assert isinstance(client1, RobustConnection) client2 = await create_connection() assert isinstance(client2, RobustConnection) reconnect_event = asyncio.Event() reconnect_count = 0 def reconnect_callback(sender, conn): nonlocal reconnect_count reconnect_count += 1 reconnect_event.set() reconnect_event.clear() client2.add_reconnect_callback(reconnect_callback) queue_name = get_random_name() channel1 = await client1.channel() assert isinstance(channel1, RobustChannel) channel2 = await client2.channel() assert isinstance(channel2, RobustChannel) queue1 = await channel1.declare_queue( queue_name, auto_delete=False, passive=False, ) assert isinstance(queue1, RobustQueue) queue2 = await channel2.declare_queue(queue_name, passive=True) assert isinstance(queue2, RobustQueue) await client2.connection.close(aiormq.AMQPError(320, "Closed")) await reconnect_event.wait() assert reconnect_count == 1 with suppress(asyncio.TimeoutError): await asyncio.wait_for( reconnect_event.wait(), client2.reconnect_interval * 2, ) assert reconnect_count == 1
async def test_on_return_raises(self, connection: aio_pika.Connection): queue_name = get_random_name("test_on_return_raises") body = uuid.uuid4().bytes with pytest.raises(RuntimeError): await connection.channel( publisher_confirms=False, on_return_raises=True, ) channel = await connection.channel( publisher_confirms=True, on_return_raises=True, ) for _ in range(100): with pytest.raises(aio_pika.exceptions.DeliveryError): await channel.default_exchange.publish( Message(body=body), routing_key=queue_name, )
async def test_passive_for_exchange( self, declare_exchange: Callable, connection, add_cleanup: Callable, ): name = get_random_name("passive", "exchange") ch1 = await self.create_channel(connection) ch2 = await self.create_channel(connection) ch3 = await self.create_channel(connection) with pytest.raises(aio_pika.exceptions.ChannelNotFoundEntity): await declare_exchange(name, passive=True, channel=ch1) exchange = await declare_exchange(name, auto_delete=True, channel=ch2) exchange_passive = await declare_exchange( name, passive=True, channel=ch3, ) assert exchange.name == exchange_passive.name
async def test_queue_iterator_close_was_called_twice( self, create_connection: Callable, loop, declare_queue ): future = loop.create_future() event = asyncio.Event() queue_name = get_random_name() async def task_inner(): nonlocal future nonlocal event nonlocal create_connection try: connection = await create_connection() async with connection: channel = await self.create_channel(connection) queue = await declare_queue( queue_name, channel=channel, cleanup=False, ) async with queue.iterator() as q: event.set() async for message in q: with message.process(): break except asyncio.CancelledError as e: future.set_exception(e) raise task = loop.create_task(task_inner()) await event.wait() loop.call_soon(task.cancel) with pytest.raises(asyncio.CancelledError): await task with pytest.raises(asyncio.CancelledError): await future
async def test_channel_close_when_exclusive_queue( create_connection, create_direct_connection, proxy: TCPProxy, loop ): direct_conn, proxy_conn = await asyncio.gather( create_direct_connection(), create_connection(), ) direct_channel, proxy_channel = await asyncio.gather( direct_conn.channel(), proxy_conn.channel(), ) reconnect_event = asyncio.Event() proxy_conn.reconnect_callbacks.add( lambda *_: reconnect_event.set(), weak=False ) qname = get_random_name("robust", "exclusive", "queue") proxy_queue = await proxy_channel.declare_queue( qname, exclusive=True, durable=True, ) logging.info("Disconnecting all proxy connections") await proxy.disconnect_all() await asyncio.sleep(0.5) logging.info("Declaring exclusive queue through direct channel") await direct_channel.declare_queue(qname, exclusive=True, durable=True) async def close_after(delay, closer): await asyncio.sleep(delay) await closer() logging.info("Closed") await loop.create_task(close_after(5, direct_conn.close)) # reconnect fired await reconnect_event.wait() # Wait method ready await proxy_conn.connected.wait() await proxy_queue.delete()
async def test_close_cancelling(self, channel: aio_pika.Channel, loop): rpc = await RPC.create(channel, auto_delete=True) async def sleeper(): await asyncio.sleep(60) method_name = get_random_name("test", "sleeper") await rpc.register(method_name, sleeper, auto_delete=True) tasks = set() for _ in range(10): tasks.add(loop.create_task(rpc.call(method_name))) await rpc.close() logging.info("Waiting for results") for task in tasks: with pytest.raises(asyncio.CancelledError): await task
async def test_declare_queue_with_passive_flag( self, connection, declare_exchange: Callable, declare_queue: Callable, ): queue_name = get_random_name() ch1 = await self.create_channel(connection) ch2 = await self.create_channel(connection) ch3 = await self.create_channel(connection) with pytest.raises(aio_pika.exceptions.ChannelNotFoundEntity): await declare_queue( queue_name, auto_delete=True, passive=True, channel=ch1, ) await declare_queue( queue_name, auto_delete=True, passive=False, channel=ch2, ) # Check ignoring different queue options await declare_queue( queue_name, auto_delete=False, passive=True, channel=ch3, )