Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Communication chat - paginated results for participants and readreceipts #15682

4 changes: 2 additions & 2 deletions sdk/communication/azure-communication-chat/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ Use `list_participants` to retrieve the participants of the thread.
An iterator of `[ChatThreadParticipant]` is the response returned from listing participants

```python
chat_thread_participants = chat_thread_client.list_participants()
chat_thread_participants = chat_thread_client.list_participants(results_per_page=5, skip=5)
for chat_thread_participant in chat_thread_participants:
print(chat_thread_participant)
```
Expand Down Expand Up @@ -352,7 +352,7 @@ chat_thread_client.send_read_receipt(message_id)
An iterator of `[ChatMessageReadReceipt]` is the response returned from listing read receipts

```python
read_receipts = chat_thread_client.list_read_receipts()
read_receipts = chat_thread_client.list_read_receipts(results_per_page=5, skip=5)
for read_receipt in read_receipts:
print(read_receipt)
print(read_receipt.sender)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ def list_read_receipts(
# type: (...) -> ItemPaged[ChatMessageReadReceipt]
"""Gets read receipts for a thread.

:keyword int results_per_page: The maximum number of chat message read receipts to be returned per page.
:keyword int skip: Skips chat message read receipts up to a specified position in response.
:keyword callable cls: A custom type or function that will be passed the direct response
:return: ItemPaged[:class:`~azure.communication.chat.ChatMessageReadReceipt`]
:rtype: ~azure.core.paging.ItemPaged
Expand All @@ -201,8 +203,13 @@ def list_read_receipts(
:dedent: 8
:caption: Listing read receipts.
"""
results_per_page = kwargs.pop("results_per_page", None)
skip = kwargs.pop("skip", None)

return self._client.chat_thread.list_chat_read_receipts(
self._thread_id,
maxpagesize=results_per_page,
skip=skip,
cls=lambda objs: [ChatMessageReadReceipt._from_generated(x) for x in objs], # pylint:disable=protected-access
**kwargs)

Expand Down Expand Up @@ -423,6 +430,8 @@ def list_participants(
# type: (...) -> ItemPaged[ChatThreadParticipant]
"""Gets the participants of a thread.

:keyword int results_per_page: The maximum number of participants to be returned per page.
:keyword int skip: Skips participants up to a specified position in response.
:keyword callable cls: A custom type or function that will be passed the direct response
:return: ItemPaged[:class:`~azure.communication.chat.ChatThreadParticipant`]
:rtype: ~azure.core.paging.ItemPaged
Expand All @@ -438,8 +447,13 @@ def list_participants(
:caption: Listing participants of chat thread.
"""

results_per_page = kwargs.pop("results_per_page", None)
skip = kwargs.pop("skip", None)

return self._client.chat_thread.list_chat_participants(
self._thread_id,
maxpagesize=results_per_page,
skip=skip,
cls=lambda objs: [ChatThreadParticipant._from_generated(x) for x in objs], # pylint:disable=protected-access
**kwargs)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# ------------------------------------------------------------------------
sarkar-rajarshi marked this conversation as resolved.
Show resolved Hide resolved
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# -------------------------------------------------------------------------

def return_response(response, deserialized, _): # pylint: disable=unused-argument
sarkar-rajarshi marked this conversation as resolved.
Show resolved Hide resolved
return response, deserialized
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,8 @@ def list_read_receipts(
) -> AsyncItemPaged[ChatMessageReadReceipt]:
"""Gets read receipts for a thread.

:keyword int results_per_page: The maximum number of chat message read receipts to be returned per page.
:keyword int skip: Skips chat message read receipts up to a specified position in response.
:keyword callable cls: A custom type or function that will be passed the direct response
sarkar-rajarshi marked this conversation as resolved.
Show resolved Hide resolved
:return: AsyncItemPaged[:class:`~azure.communication.chat.ChatMessageReadReceipt`]
:rtype: ~azure.core.async_paging.AsyncItemPaged
Expand All @@ -197,8 +199,13 @@ def list_read_receipts(
:dedent: 12
:caption: Listing read receipts.
"""
results_per_page = kwargs.pop("results_per_page", None)
skip = kwargs.pop("skip", None)

return self._client.chat_thread.list_chat_read_receipts(
self._thread_id,
maxpagesize=results_per_page,
skip=skip,
cls=lambda objs: [ChatMessageReadReceipt._from_generated(x) for x in objs], # pylint:disable=protected-access
**kwargs)

Expand Down Expand Up @@ -412,6 +419,8 @@ def list_participants(
) -> AsyncItemPaged[ChatThreadParticipant]:
"""Gets the participants of a thread.

:keyword int results_per_page: The maximum number of participants to be returned per page.
:keyword int skip: Skips participants up to a specified position in response.
:keyword callable cls: A custom type or function that will be passed the direct response
:return: AsyncItemPaged[:class:`~azure.communication.chat.ChatThreadParticipant`]
:rtype: ~azure.core.async_paging.AsyncItemPaged
Expand All @@ -426,8 +435,14 @@ def list_participants(
:dedent: 12
:caption: Listing participants of chat thread.
"""

results_per_page = kwargs.pop("results_per_page", None)
skip = kwargs.pop("skip", None)

return self._client.chat_thread.list_chat_participants(
self._thread_id,
maxpagesize=results_per_page,
skip=skip,
cls=lambda objs: [ChatThreadParticipant._from_generated(x) for x in objs], # pylint:disable=protected-access
**kwargs)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,33 @@ def mock_send(*_, **__):
assert len(l) == 1
l[0].user.id = participant_id

def test_list_participants_with_results_per_page(self):
thread_id = "19:81181a8abbf54b5695f87a0042ddcba9@thread.v2"
participant_id_1 = "8:acs:9b665d53-8164-4923-ad5d-5e983b07d2e7_00000006-5399-552c-b274-5a3a0d0000dc"
participant_id_2 = "8:acs:9b665d53-8164-4923-ad5d-5e983b07d2e7_00000006-9d32-35c9-557d-5a3a0d0002f1"
raised = False

def mock_send(*_, **__):
return mock_response(status_code=200, json_payload={
"value": [
{"id": participant_id_1},
{"id": participant_id_2}
]})

chat_thread_client = ChatThreadClient("https://endpoint", TestChatThreadClient.credential, thread_id,
transport=Mock(send=mock_send))

chat_thread_participants = None
try:
chat_thread_participants = chat_thread_client.list_participants(results_per_page=2)
except:
raised = True

self.assertFalse(raised, 'Expected is no excpetion raised')
for chat_thread_participant_page in chat_thread_participants.by_page():
l = list(chat_thread_participant_page)
assert len(l) == 2

def test_add_participant(self):
thread_id = "19:bcaebfba0d314c2aa3e920d38fa3df08@thread.v2"
new_participant_id="8:acs:57b9bac9-df6c-4d39-a73b-26e944adf6ea_9b0110-08007f1041"
Expand Down Expand Up @@ -299,6 +326,31 @@ def mock_send(*_, **__):
l = list(read_receipt_page)
assert len(l) == 1

def test_list_read_receipts_with_results_per_page(self):
thread_id = "19:bcaebfba0d314c2aa3e920d38fa3df08@thread.v2"
message_id_1="1596823919339"
message_id_2="1596823919340"
raised = False

def mock_send(*_, **__):
return mock_response(status_code=200, json_payload={
"value": [
{"chatMessageId": message_id_1},
{"chatMessageId": message_id_2}
]})
chat_thread_client = ChatThreadClient("https://endpoint", TestChatThreadClient.credential, thread_id, transport=Mock(send=mock_send))

read_receipts = None
try:
read_receipts = chat_thread_client.list_read_receipts(results_per_page=2)
except:
raised = True

self.assertFalse(raised, 'Expected is no excpetion raised')
for read_receipt_page in read_receipts.by_page():
l = list(read_receipt_page)
assert len(l) == 2


if __name__ == '__main__':
unittest.main()
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,36 @@ async def mock_send(*_, **__):

assert len(items) == 1

@pytest.mark.asyncio
async def test_list_participants_with_results_per_page():
thread_id = "19:bcaebfba0d314c2aa3e920d38fa3df08@thread.v2"
participant_id_1 = "8:acs:9b665d53-8164-4923-ad5d-5e983b07d2e7_00000006-5399-552c-b274-5a3a0d0000dc"
participant_id_2 = "8:acs:9b665d53-8164-4923-ad5d-5e983b07d2e7_00000006-9d32-35c9-557d-5a3a0d0002f1"
raised = False

async def mock_send(*_, **__):
return mock_response(status_code=200, json_payload={
"value": [
{"id": participant_id_1},
{"id": participant_id_2}
]})
chat_thread_client = ChatThreadClient("https://endpoint", credential, thread_id, transport=Mock(send=mock_send))

chat_thread_participants = None
try:
chat_thread_participants = chat_thread_client.list_participants(results_per_page=2)
except:
raised = True

assert raised == False

items = []
async for item in chat_thread_participants:
items.append(item)

assert len(items) == 2


@pytest.mark.asyncio
async def test_add_participant():
thread_id = "19:bcaebfba0d314c2aa3e920d38fa3df08@thread.v2"
Expand Down Expand Up @@ -319,3 +349,32 @@ async def mock_send(*_, **__):
items.append(item)

assert len(items) == 1

@pytest.mark.asyncio
async def test_list_read_receipts_with_results_per_page():
thread_id = "19:bcaebfba0d314c2aa3e920d38fa3df08@thread.v2"
message_id_1 = "1596823919339"
message_id_2 = "1596823919340"
raised = False

async def mock_send(*_, **__):
return mock_response(status_code=200, json_payload={
"value": [
{"chatMessageId": message_id_1},
{"chatMessageId": message_id_2}
]})
chat_thread_client = ChatThreadClient("https://endpoint", credential, thread_id, transport=Mock(send=mock_send))

read_receipts = None
try:
read_receipts = chat_thread_client.list_read_receipts(results_per_page=2)
sarkar-rajarshi marked this conversation as resolved.
Show resolved Hide resolved
except:
raised = True

assert raised == False

items = []
async for item in read_receipts:
items.append(item)

assert len(items) == 2
sarkar-rajarshi marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,11 @@ def tearDown(self):
self.identity_client.delete_user(self.new_user)
self.chat_client.delete_chat_thread(self.thread_id)

def _create_thread(self):
def _create_thread(
self,
multiple_participants=False, # type: Optional[bool]
sarkar-rajarshi marked this conversation as resolved.
Show resolved Hide resolved
**kwargs
):
# create chat thread, and ChatThreadClient
topic = "test topic"
share_history_time = datetime.utcnow()
Expand Down Expand Up @@ -149,12 +153,27 @@ def test_list_participants(self):
if self.is_live:
time.sleep(2)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you need to do this kind of stuff, i.e. time.sleep() in the test code, due to service behavior, let's not write live tests for these scenarios, this causes inconsistency/unreliability issues in our live tests. Instead mocking the network call - as you already added.
We are removing these kinds of tests from the e2e tests in master branch too.


chat_thread_participants = self.chat_thread_client.list_participants()
# add another participant
share_history_time = datetime.utcnow()
share_history_time = share_history_time.replace(tzinfo=TZ_UTC)
new_participant = ChatThreadParticipant(
user=self.new_user,
display_name='name',
share_history_time=share_history_time)

self.chat_thread_client.add_participant(new_participant)

# fetch list of participants
chat_thread_participants = self.chat_thread_client.list_participants(results_per_page=1, skip=1)

participant_count = 0

for chat_thread_participant_page in chat_thread_participants.by_page():
li = list(chat_thread_participant_page)
assert len(li) == 1
assert len(li) <= 1
sarkar-rajarshi marked this conversation as resolved.
Show resolved Hide resolved
participant_count += len(li)
li[0].user.id = self.user.identifier
assert participant_count == 1

@pytest.mark.live_test_only
def test_add_participant(self):
Expand Down Expand Up @@ -217,17 +236,18 @@ def test_send_read_receipt(self):
@pytest.mark.live_test_only
def test_list_read_receipts(self):
self._create_thread()
self._send_message()

# send read receipts first
self.chat_thread_client.send_read_receipt(self.message_id)
if self.is_live:
time.sleep(2)
# send messages and read receipts
for i in range(2):
self._send_message()
self.chat_thread_client.send_read_receipt(self.message_id)
if self.is_live:
time.sleep(2)
sarkar-rajarshi marked this conversation as resolved.
Show resolved Hide resolved

# list read receipts
read_receipts = self.chat_thread_client.list_read_receipts()
read_receipts = self.chat_thread_client.list_read_receipts(results_per_page=1, skip=1)

items = []
for item in read_receipts:
items.append(item)
assert len(items) > 0
assert len(items) == 0
sarkar-rajarshi marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,17 @@ async def test_list_participants(self):
await self._create_thread()

async with self.chat_thread_client:
chat_thread_participants = self.chat_thread_client.list_participants()
# add another participant
share_history_time = datetime.utcnow()
share_history_time = share_history_time.replace(tzinfo=TZ_UTC)
new_participant = ChatThreadParticipant(
user=self.new_user,
display_name='name',
share_history_time=share_history_time)

await self.chat_thread_client.add_participant(new_participant)

chat_thread_participants = self.chat_thread_client.list_participants(results_per_page=1, skip=1)

items = []
async for item in chat_thread_participants:
Expand Down Expand Up @@ -304,15 +314,17 @@ async def test_list_read_receipts(self):
await self._create_thread()

async with self.chat_thread_client:
await self._send_message()

# send read receipts first
await self.chat_thread_client.send_read_receipt(self.message_id)
if self.is_live:
await asyncio.sleep(2)
for i in range(2):
await self._send_message()

# send read receipts first
await self.chat_thread_client.send_read_receipt(self.message_id)
if self.is_live:
await asyncio.sleep(2)
sarkar-rajarshi marked this conversation as resolved.
Show resolved Hide resolved

# list read receipts
read_receipts = self.chat_thread_client.list_read_receipts()
read_receipts = self.chat_thread_client.list_read_receipts(results_per_page=1, skip=0)

items = []
async for item in read_receipts:
Expand Down