diff --git a/stream_chat/tests/async_chat/test_channel.py b/stream_chat/tests/async_chat/test_channel.py index d0d6447..dc2bf0e 100644 --- a/stream_chat/tests/async_chat/test_channel.py +++ b/stream_chat/tests/async_chat/test_channel.py @@ -1,3 +1,4 @@ +import asyncio import time import uuid from pathlib import Path @@ -300,10 +301,16 @@ async def test_channel_hide_show( assert len(response["channels"]) == 0 # send message await channel.send_message({"text": "hi"}, random_users[1]["id"]) - # channel should be listed now - response = await client.query_channels( - {"id": channel.id}, user_id=random_users[0]["id"] - ) + # channel should be listed now. The backend unhides it in a background + # task after the message is sent, which can take a while on a busy + # shared test app, so poll for up to 30s. + for _ in range(60): + response = await client.query_channels( + {"id": channel.id}, user_id=random_users[0]["id"] + ) + if len(response["channels"]) == 1: + break + await asyncio.sleep(0.5) assert len(response["channels"]) == 1 async def test_invites(self, client: StreamChatAsync, random_users: List[Dict]): diff --git a/stream_chat/tests/test_channel.py b/stream_chat/tests/test_channel.py index 193b44b..a61c4f4 100644 --- a/stream_chat/tests/test_channel.py +++ b/stream_chat/tests/test_channel.py @@ -302,10 +302,16 @@ def test_channel_hide_show( assert len(response["channels"]) == 0 # send message channel.send_message({"text": "hi"}, random_users[1]["id"]) - # channel should be listed now - response = client.query_channels( - {"id": channel.id}, user_id=random_users[0]["id"] - ) + # channel should be listed now. The backend unhides it in a background + # task after the message is sent, which can take a while on a busy + # shared test app, so poll for up to 30s. + for _ in range(60): + response = client.query_channels( + {"id": channel.id}, user_id=random_users[0]["id"] + ) + if len(response["channels"]) == 1: + break + time.sleep(0.5) assert len(response["channels"]) == 1 def test_invites(self, client: StreamChat, random_users: List[Dict]): diff --git a/stream_chat/tests/test_stream_response_headers.py b/stream_chat/tests/test_stream_response_headers.py new file mode 100644 index 0000000..830e74a --- /dev/null +++ b/stream_chat/tests/test_stream_response_headers.py @@ -0,0 +1,23 @@ +from datetime import datetime + +from stream_chat.types.stream_response import StreamResponse + + +class TestStreamResponseHeaders: + def test_rate_limit_reads_headers_in_any_case(self): + resp = StreamResponse( + {"duration": "1ms"}, + { + "X-Ratelimit-Limit": "1000", + "X-Ratelimit-Remaining": "999", + "X-Ratelimit-Reset": "1700000000", + }, + 200, + ) + + rate_limit = resp.rate_limit() + assert rate_limit is not None + assert rate_limit.limit == 1000 + assert rate_limit.remaining == 999 + assert type(rate_limit.reset) is datetime + assert resp.headers()["X-Ratelimit-Limit"] == "1000" diff --git a/stream_chat/types/stream_response.py b/stream_chat/types/stream_response.py index b42ac88..21d95b4 100644 --- a/stream_chat/types/stream_response.py +++ b/stream_chat/types/stream_response.py @@ -31,10 +31,13 @@ def __init__( self.__headers = headers self.__status_code = status_code self.__rate_limit: Optional[RateLimitInfo] = None + # Header names are case-insensitive. The async client passes a plain + # dict, which keeps the case the server sent (e.g. X-Ratelimit-Limit). + lowered = {k.lower(): v for k, v in headers.items()} limit, remaining, reset = ( - headers.get("x-ratelimit-limit"), - headers.get("x-ratelimit-remaining"), - headers.get("x-ratelimit-reset"), + lowered.get("x-ratelimit-limit"), + lowered.get("x-ratelimit-remaining"), + lowered.get("x-ratelimit-reset"), ) if limit and remaining and reset: self.__rate_limit = RateLimitInfo(