async def test_message_expiry__group_send__one_channel_expires_message( channel_layer): expiry = 3 delay = 1 channel_layer = RedisChannelLayer(expiry=expiry) channel_1 = await channel_layer.new_channel() channel_2 = await channel_layer.new_channel(prefix="channel_2") await channel_layer.group_add("test-group", channel_1) await channel_layer.group_add("test-group", channel_2) # Let's give channel_1 one additional message and then sleep await channel_layer.send(channel_1, { "type": "test.message", "text": "Zero!" }) await asyncio.sleep(2) task = asyncio.ensure_future( group_send_three_messages_with_delay("test-group", channel_layer, delay)) await asyncio.wait_for(task, None) # message Zero! was sent about 2 + 1 + 1 seconds ago and it should have expired message = await channel_layer.receive(channel_1) assert message["type"] == "test.message" assert message["text"] == "First!" message = await channel_layer.receive(channel_1) assert message["type"] == "test.message" assert message["text"] == "Second!" message = await channel_layer.receive(channel_1) assert message["type"] == "test.message" assert message["text"] == "Third!" # Make sure there's no fourth message even out of order with pytest.raises(asyncio.TimeoutError): async with async_timeout.timeout(1): await channel_layer.receive(channel_1) # channel_2 should receive all three messages from group_send message = await channel_layer.receive(channel_2) assert message["type"] == "test.message" assert message["text"] == "First!" # the first message should have expired, we should only see the second message and the third message = await channel_layer.receive(channel_2) assert message["type"] == "test.message" assert message["text"] == "Second!" message = await channel_layer.receive(channel_2) assert message["type"] == "test.message" assert message["text"] == "Third!"
async def channel_layer(): """ Channel layer fixture that flushes automatically. """ channel_layer = RedisChannelLayer( hosts=TEST_HOSTS, capacity=3, channel_capacity={"tiny": 1}, ) await yield_(channel_layer) await channel_layer.flush()
async def test_groups_channel_full(channel_layer): """ Tests that group_send ignores ChannelFull """ channel_layer = RedisChannelLayer(hosts=TEST_HOSTS) await channel_layer.group_add("test-group", "test-gr-chan-1") await channel_layer.group_send("test-group", {"type": "message.1"}) await channel_layer.group_send("test-group", {"type": "message.1"}) await channel_layer.group_send("test-group", {"type": "message.1"}) await channel_layer.group_send("test-group", {"type": "message.1"}) await channel_layer.group_send("test-group", {"type": "message.1"})
async def test_send_specific_capacity(channel_layer): """ Makes sure we get ChannelFull when we hit the send capacity on a specific channel """ custom_channel_layer = RedisChannelLayer(hosts=TEST_HOSTS, capacity=3, channel_capacity={"one": 1}) await custom_channel_layer.send("one", {"type": "test.message"}) with pytest.raises(ChannelFull): await custom_channel_layer.send("one", {"type": "test.message"}) await custom_channel_layer.flush()
async def test_multi_send_receive(channel_layer): """ Tests overlapping sends and receives, and ordering. """ channel_layer = RedisChannelLayer(hosts=TEST_HOSTS) await channel_layer.send("test-channel-3", {"type": "message.1"}) await channel_layer.send("test-channel-3", {"type": "message.2"}) await channel_layer.send("test-channel-3", {"type": "message.3"}) assert (await channel_layer.receive("test-channel-3"))["type"] == "message.1" assert (await channel_layer.receive("test-channel-3"))["type"] == "message.2" assert (await channel_layer.receive("test-channel-3"))["type"] == "message.3"
async def test_random_reset__channel_name(channel_layer): """ Makes sure resetting random seed does not make us reuse channel names. """ channel_layer = RedisChannelLayer() random.seed(1) channel_name_1 = await channel_layer.new_channel() random.seed(1) channel_name_2 = await channel_layer.new_channel() assert channel_name_1 != channel_name_2
def test_receive_buffer_respects_capacity(): channel_layer = RedisChannelLayer() buff = channel_layer.receive_buffer["test-group"] for i in range(10000): buff.put_nowait(i) capacity = 100 assert channel_layer.capacity == capacity assert buff.full() is True assert buff.qsize() == capacity messages = [buff.get_nowait() for _ in range(capacity)] assert list(range(9900, 10000)) == messages
async def test_receive_cancel(channel_layer): """ Makes sure we can cancel a receive without blocking """ channel_layer = RedisChannelLayer(capacity=10) channel = await channel_layer.new_channel() delay = 0 while delay < 0.01: await channel_layer.send(channel, { "type": "test.message", "text": "Ahoy-hoy!" }) task = asyncio.ensure_future(channel_layer.receive(channel)) await asyncio.sleep(delay) task.cancel() delay += 0.001 try: await asyncio.wait_for(task, None) except asyncio.CancelledError: pass
async def test_groups_basic(channel_layer): """ Tests basic group operation. """ channel_layer = RedisChannelLayer(hosts=TEST_HOSTS) await channel_layer.group_add("test-group", "test-gr-chan-1") await channel_layer.group_add("test-group", "test-gr-chan-2") await channel_layer.group_add("test-group", "test-gr-chan-3") await channel_layer.group_discard("test-group", "test-gr-chan-2") await channel_layer.group_send("test-group", {"type": "message.1"}) # Make sure we get the message on the two channels that were in async with async_timeout.timeout(1): assert (await channel_layer.receive("test-gr-chan-1"))["type"] == "message.1" assert (await channel_layer.receive("test-gr-chan-3"))["type"] == "message.1" # Make sure the removed channel did not get the message with pytest.raises(asyncio.TimeoutError): async with async_timeout.timeout(1): await channel_layer.receive("test-gr-chan-2")
async def test_groups_same_prefix(channel_layer): """ Tests group_send with multiple channels with same channel prefix """ channel_layer = RedisChannelLayer(hosts=TEST_HOSTS) channel_name1 = await channel_layer.new_channel(prefix="test-gr-chan") channel_name2 = await channel_layer.new_channel(prefix="test-gr-chan") channel_name3 = await channel_layer.new_channel(prefix="test-gr-chan") await channel_layer.group_add("test-group", channel_name1) await channel_layer.group_add("test-group", channel_name2) await channel_layer.group_add("test-group", channel_name3) await channel_layer.group_send("test-group", {"type": "message.1"}) # Make sure we get the message on the channels that were in async with async_timeout.timeout(1): assert (await channel_layer.receive(channel_name1))["type"] == "message.1" assert (await channel_layer.receive(channel_name2))["type"] == "message.1" assert (await channel_layer.receive(channel_name3))["type"] == "message.1"
async def test_groups_multiple_hosts_performance(channel_layer_multiple_hosts, num_channels, timeout): """ Tests advanced group operation: can send efficiently to multiple channels with multiple hosts within a certain timeout """ channel_layer = RedisChannelLayer(hosts=MULTIPLE_TEST_HOSTS, capacity=100) channels = [] for i in range(0, num_channels): channel = await channel_layer.new_channel(prefix="channel%s" % i) await channel_layer.group_add("test-group", channel) channels.append(channel) async with async_timeout.timeout(timeout): await channel_layer.group_send("test-group", {"type": "message.1"}) # Make sure we get the message all the channels async with async_timeout.timeout(timeout): for channel in channels: assert (await channel_layer.receive(channel))["type"] == "message.1"
async def test_message_expiry__all_messages_under_expiration_time( channel_layer): expiry = 3 delay = 1 channel_layer = RedisChannelLayer(expiry=expiry) channel_name = await channel_layer.new_channel() task = asyncio.ensure_future( send_three_messages_with_delay(channel_name, channel_layer, delay)) await asyncio.wait_for(task, None) # expiry = 3, total delay under 3, all messages there message = await channel_layer.receive(channel_name) assert message["type"] == "test.message" assert message["text"] == "First!" message = await channel_layer.receive(channel_name) assert message["type"] == "test.message" assert message["text"] == "Second!" message = await channel_layer.receive(channel_name) assert message["type"] == "test.message" assert message["text"] == "Third!"
async def test_message_expiry__earliest_message_expires(channel_layer): expiry = 3 delay = 2 channel_layer = RedisChannelLayer(expiry=expiry) channel_name = await channel_layer.new_channel() task = asyncio.ensure_future( send_three_messages_with_delay(channel_name, channel_layer, delay)) await asyncio.wait_for(task, None) # the first message should have expired, we should only see the second message and the third message = await channel_layer.receive(channel_name) assert message["type"] == "test.message" assert message["text"] == "Second!" message = await channel_layer.receive(channel_name) assert message["type"] == "test.message" assert message["text"] == "Third!" # Make sure there's no third message even out of order with pytest.raises(asyncio.TimeoutError): async with async_timeout.timeout(1): await channel_layer.receive(channel_name)
async def test_groups_multiple_hosts(channel_layer_multiple_hosts): """ Tests advanced group operation with multiple hosts. """ channel_layer = RedisChannelLayer(hosts=MULTIPLE_TEST_HOSTS, capacity=100) channel_name1 = await channel_layer.new_channel(prefix="channel1") channel_name2 = await channel_layer.new_channel(prefix="channel2") channel_name3 = await channel_layer.new_channel(prefix="channel3") await channel_layer.group_add("test-group", channel_name1) await channel_layer.group_add("test-group", channel_name2) await channel_layer.group_add("test-group", channel_name3) await channel_layer.group_discard("test-group", channel_name2) await channel_layer.group_send("test-group", {"type": "message.1"}) await channel_layer.group_send("test-group", {"type": "message.1"}) # Make sure we get the message on the two channels that were in async with async_timeout.timeout(1): assert (await channel_layer.receive(channel_name1))["type"] == "message.1" assert (await channel_layer.receive(channel_name3))["type"] == "message.1" with pytest.raises(asyncio.TimeoutError): async with async_timeout.timeout(1): await channel_layer.receive(channel_name2)
def test_custom_group_key_format(): channel_layer = RedisChannelLayer(prefix="test_prefix") group_name = channel_layer._group_key("test_group") assert group_name == b"test_prefix:group:test_group"
def test_default_group_key_format(): channel_layer = RedisChannelLayer() group_name = channel_layer._group_key("test_group") assert group_name == b"asgi:group:test_group"