async def test_communicationtokencredential_throws_if_proactive_refresh_enabled_without_token_refresher(
         self):
     with pytest.raises(ValueError) as err:
         CommunicationTokenCredential(self.sample_token,
                                      proactive_refresh=True)
     assert str(
         err.value
     ) == "When 'proactive_refresh' is True, 'token_refresher' must not be None."
     with pytest.raises(ValueError) as err:
         CommunicationTokenCredential(self.sample_token,
                                      proactive_refresh=True,
                                      token_refresher=None)
     assert str(
         err.value
     ) == "When 'proactive_refresh' is True, 'token_refresher' must not be None."
    async def test_proactive_refresher_should_be_called_after_specified_time(
            self):
        refresh_minutes = 10
        token_validity_minutes = 60
        start_timestamp = get_current_utc_as_int()
        skip_to_timestamp = start_timestamp + \
            (token_validity_minutes - refresh_minutes + 5) * 60

        initial_token = generate_token_with_custom_expiry(
            token_validity_minutes * 60)
        refreshed_token = generate_token_with_custom_expiry(
            2 * token_validity_minutes * 60)
        refresher = MagicMock(return_value=self.get_completed_future(
            create_access_token(refreshed_token)))

        with patch(user_credential_async.__name__ + '.' +
                   get_current_utc_as_int.__name__,
                   return_value=skip_to_timestamp):
            credential = CommunicationTokenCredential(
                initial_token,
                token_refresher=refresher,
                proactive_refresh=True)
            async with credential:
                access_token = await credential.get_token()

        assert refresher.call_count == 1
        assert access_token.token == refreshed_token
        # check that next refresh is always scheduled
        assert credential._timer is not None
    def setUp(self):
        super(ChatClientTestAsync, self).setUp()

        self.recording_processors.extend([
            BodyReplacerProcessor(keys=[
                "id", "token", "createdBy", "participants", "multipleStatus",
                "value"
            ]),
            URIIdentityReplacer(),
            ResponseReplacerProcessor(keys=[self._resource_name]),
            ChatURIReplacer()
        ])

        endpoint, _ = parse_connection_str(self.connection_str)
        self.endpoint = endpoint

        self.identity_client = CommunicationIdentityClient.from_connection_string(
            self.connection_str)

        # create user
        self.user = self.identity_client.create_user()
        token_response = self.identity_client.get_token(self.user,
                                                        scopes=["chat"])
        self.token = token_response.token

        # create ChatClient
        refresh_options = CommunicationTokenRefreshOptions(self.token)
        self.chat_client = ChatClient(
            self.endpoint, CommunicationTokenCredential(refresh_options))
    async def test_fractional_backoff_applied_when_token_expiring(self):
        token_validity_seconds = 5 * 60
        expiring_token = generate_token_with_custom_expiry(
            token_validity_seconds)

        refresher = MagicMock(side_effect=[
            create_access_token(expiring_token),
            create_access_token(expiring_token)
        ])

        credential = CommunicationTokenCredential(expiring_token,
                                                  token_refresher=refresher,
                                                  proactive_refresh=True)

        next_milestone = token_validity_seconds / 2
        assert credential._timer.interval == next_milestone

        async with credential:
            with patch(user_credential_async.__name__ + '.' +
                       get_current_utc_as_int.__name__,
                       return_value=(get_current_utc_as_int() +
                                     next_milestone)):
                await credential.get_token()

        assert refresher.call_count == 1
        next_milestone = next_milestone / 2
        assert credential._timer.interval == next_milestone
예제 #5
0
    async def create_thread_async(self):
        from datetime import datetime
        from azure.communication.chat.aio import ChatClient
        from azure.communication.identity._shared.user_credential_async import CommunicationTokenCredential
        from azure.communication.chat._shared.user_token_refresh_options import CommunicationTokenRefreshOptions
        from azure.communication.chat import ChatThreadParticipant

        refresh_options = CommunicationTokenRefreshOptions(self.token)
        chat_client = ChatClient(self.endpoint,
                                 CommunicationTokenCredential(refresh_options))
        async with chat_client:
            # [START create_thread]
            topic = "test topic"
            participants = [
                ChatThreadParticipant(user=self.user,
                                      display_name='name',
                                      share_history_time=datetime.utcnow())
            ]
            # creates a new chat_thread everytime
            create_chat_thread_result = await chat_client.create_chat_thread(
                topic, thread_participants=participants)

            # creates a new chat_thread if not exists
            repeatability_request_id = 'b66d6031-fdcc-41df-8306-e524c9f226b8'  # unique identifier
            create_chat_thread_result_w_repeatability_id = await chat_client.create_chat_thread(
                topic,
                thread_participants=participants,
                repeatability_request_id=repeatability_request_id)
            # [END create_thread]

            self._thread_id = create_chat_thread_result.chat_thread.id
            print("thread created, id: " + self._thread_id)
    async def test_proactive_refresher_keeps_scheduling_again(self):
        refresh_minutes = 10
        token_validity_minutes = 60
        expired_token = generate_token_with_custom_expiry(-5 * 60)
        skip_to_timestamp = get_current_utc_as_int() + (
            token_validity_minutes - refresh_minutes) * 60 + 1
        first_refreshed_token = create_access_token(
            generate_token_with_custom_expiry(token_validity_minutes * 60))
        last_refreshed_token = create_access_token(
            generate_token_with_custom_expiry(2 * token_validity_minutes * 60))
        refresher = MagicMock(side_effect=[
            self.get_completed_future(first_refreshed_token),
            self.get_completed_future(last_refreshed_token)
        ])

        credential = CommunicationTokenCredential(expired_token,
                                                  token_refresher=refresher,
                                                  proactive_refresh=True)
        async with credential:
            access_token = await credential.get_token()
            with patch(user_credential_async.__name__ + '.' +
                       get_current_utc_as_int.__name__,
                       return_value=skip_to_timestamp):
                access_token = await credential.get_token()

        assert refresher.call_count == 2
        assert access_token.token == last_refreshed_token.token
        # check that next refresh is always scheduled
        assert credential._timer is not None
    async def create_chat_thread_client_async(self):
        # [START create_chat_thread_client]
        from datetime import datetime
        from azure.communication.chat.aio import ChatClient
        from azure.communication.chat import ChatThreadParticipant
        from azure.communication.identity import CommunicationUserIdentifier
        from azure.communication.identity._shared.user_credential_async import CommunicationTokenCredential
        from azure.communication.chat._shared.user_token_refresh_options import CommunicationTokenRefreshOptions

        refresh_options = CommunicationTokenRefreshOptions(self.token)
        chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(refresh_options))

        async with chat_client:
            topic = "test topic"
            participants = [ChatThreadParticipant(
                user=self.user,
                display_name='name',
                share_history_time=datetime.utcnow()
            )]
            create_chat_thread_result = await chat_client.create_chat_thread(topic, thread_participants=participants)
            chat_thread_client = chat_client.get_chat_thread_client(create_chat_thread_result.chat_thread.id)
        # [END create_chat_thread_client]

        self._thread_id = create_chat_thread_result.chat_thread.id
        print("thread created, id: " + self._thread_id)
        print("create_chat_thread_client_async succeeded")
    async def test_raises_if_refresher_returns_expired_token(self):
        expired_token = generate_token_with_custom_expiry(-(10 * 60))
        refresher = MagicMock(return_value=self.get_completed_future(
            create_access_token(expired_token)))

        credential = CommunicationTokenCredential(expired_token,
                                                  token_refresher=refresher)
        with self.assertRaises(ValueError):
            await credential.get_token()

        assert refresher.call_count == 1
예제 #9
0
    def create_chat_client(self):
        # [START create_chat_client]
        from azure.communication.chat.aio import ChatClient
        from azure.communication.identity._shared.user_credential_async import CommunicationTokenCredential
        from azure.communication.chat._shared.user_token_refresh_options import CommunicationTokenRefreshOptions

        refresh_options = CommunicationTokenRefreshOptions(self.token)
        chat_client = ChatClient(self.endpoint,
                                 CommunicationTokenCredential(refresh_options))
        # [END create_chat_client]
        print("chat_client created")
 async def test_exit_cancels_timer(self):
     refreshed_token = create_access_token(
         generate_token_with_custom_expiry(30 * 60))
     refresher = MagicMock(return_value=refreshed_token)
     expired_token = generate_token_with_custom_expiry(-10 * 60)
     credential = CommunicationTokenCredential(expired_token,
                                               token_refresher=refresher,
                                               proactive_refresh=True)
     async with credential:
         assert credential._timer is not None
     assert refresher.call_count == 0
     assert credential._timer is not None
    async def test_refresher_should_not_be_called_when_token_still_valid(self):
        generated_token = generate_token_with_custom_expiry(15 * 60)
        new_token = generate_token_with_custom_expiry(10 * 60)
        refresher = MagicMock(return_value=create_access_token(new_token))

        credential = CommunicationTokenCredential(generated_token,
                                                  token_refresher=refresher,
                                                  proactive_refresh=False)
        for _ in range(10):
            access_token = await credential.get_token()

        refresher.assert_not_called()
        assert generated_token == access_token.token
    async def test_refresher_should_not_be_called_before_expiring_time(self):
        initial_token = generate_token_with_custom_expiry(15 * 60)
        refreshed_token = generate_token_with_custom_expiry(10 * 60)
        refresher = MagicMock(
            return_value=create_access_token(refreshed_token))

        credential = CommunicationTokenCredential(initial_token,
                                                  token_refresher=refresher,
                                                  proactive_refresh=True)
        access_token = await credential.get_token()

        refresher.assert_not_called()
        assert initial_token == access_token.token
    async def test_refresher_should_be_called_immediately_with_expired_token(
            self):
        refreshed_token = generate_token_with_custom_expiry(10 * 60)
        refresher = MagicMock(return_value=self.get_completed_future(
            create_access_token(refreshed_token)))
        expired_token = generate_token_with_custom_expiry(-(5 * 60))

        credential = CommunicationTokenCredential(expired_token,
                                                  token_refresher=refresher)
        access_token = await credential.get_token()

        refresher.assert_called_once()
        assert refreshed_token == access_token.token
예제 #14
0
    async def delete_thread_async(self):
        from azure.communication.chat.aio import ChatClient
        from azure.communication.identity._shared.user_credential_async import CommunicationTokenCredential
        from azure.communication.chat._shared.user_token_refresh_options import CommunicationTokenRefreshOptions

        refresh_options = CommunicationTokenRefreshOptions(self.token)
        chat_client = ChatClient(self.endpoint,
                                 CommunicationTokenCredential(refresh_options))
        async with chat_client:
            # [START delete_thread]
            await chat_client.delete_chat_thread(self._thread_id)
            # [END delete_thread]
            print("delete_thread succeeded")
예제 #15
0
    async def get_thread_async(self):
        from azure.communication.chat.aio import ChatClient
        from azure.communication.identity._shared.user_credential_async import CommunicationTokenCredential
        from azure.communication.chat._shared.user_token_refresh_options import CommunicationTokenRefreshOptions

        refresh_options = CommunicationTokenRefreshOptions(self.token)
        chat_client = ChatClient(self.endpoint,
                                 CommunicationTokenCredential(refresh_options))
        async with chat_client:
            # [START get_thread]
            chat_thread = await chat_client.get_chat_thread(self._thread_id)
            # [END get_thread]
            print("get_thread succeeded, thread id: " + chat_thread.id +
                  ", thread topic: " + chat_thread.topic)
예제 #16
0
    def get_chat_thread_client(self):
        # [START get_chat_thread_client]
        from azure.communication.chat.aio import ChatClient
        from azure.communication.identity._shared.user_credential_async import CommunicationTokenCredential
        from azure.communication.chat._shared.user_token_refresh_options import CommunicationTokenRefreshOptions

        refresh_options = CommunicationTokenRefreshOptions(self.token)
        chat_client = ChatClient(self.endpoint,
                                 CommunicationTokenCredential(refresh_options))
        chat_thread_client = chat_client.get_chat_thread_client(
            self._thread_id)
        # [END get_chat_thread_client]

        print("chat_thread_client created with thread id: ",
              chat_thread_client.thread_id)
    async def test_exit_enter_scenario_throws_exception(self):
        refreshed_token = create_access_token(
            generate_token_with_custom_expiry(30 * 60))
        refresher = MagicMock(return_value=refreshed_token)
        expired_token = generate_token_with_custom_expiry(-10 * 60)
        credential = CommunicationTokenCredential(expired_token,
                                                  token_refresher=refresher,
                                                  proactive_refresh=True)
        credential.get_token()
        credential.close()
        assert credential._timer is not None

        with pytest.raises(RuntimeError) as err:
            credential.get_token()
        assert str(
            err.value
        ) == "An instance of CommunicationTokenCredential cannot be reused once it has been closed."
예제 #18
0
    async def get_chat_thread_properties_async(self):
        thread_id = self._thread_id
        # [START get_thread]
        from azure.communication.chat.aio import ChatClient
        from azure.communication.identity._shared.user_credential_async import CommunicationTokenCredential
        from azure.communication.chat._shared.user_token_refresh_options import CommunicationTokenRefreshOptions

        refresh_options = CommunicationTokenRefreshOptions(self.token)
        chat_client = ChatClient(self.endpoint,
                                 CommunicationTokenCredential(refresh_options))
        async with chat_client:
            chat_thread_client = chat_client.get_chat_thread_client(thread_id)

            async with chat_thread_client:
                chat_thread_properties = chat_thread_client.get_properties()
                print('Expected Thread Id: ', thread_id, ' Actual Value: ',
                      chat_thread_properties.id)
        # [END get_thread]
            print("get_chat_thread_properties_async succeeded, thread id: " +
                  chat_thread.id + ", thread topic: " + chat_thread.topic)
예제 #19
0
    async def list_threads_async(self):
        from azure.communication.chat.aio import ChatClient
        from azure.communication.identity._shared.user_credential_async import CommunicationTokenCredential
        from azure.communication.chat._shared.user_token_refresh_options import CommunicationTokenRefreshOptions

        refresh_options = CommunicationTokenRefreshOptions(self.token)
        chat_client = ChatClient(self.endpoint,
                                 CommunicationTokenCredential(refresh_options))
        async with chat_client:
            # [START list_threads]
            from datetime import datetime, timedelta
            import pytz
            start_time = datetime.utcnow() - timedelta(days=2)
            start_time = start_time.replace(tzinfo=pytz.utc)
            chat_thread_infos = chat_client.list_chat_threads(
                results_per_page=5, start_time=start_time)
            print(
                "list_threads succeeded with results_per_page is 5, and were created since 2 days ago."
            )
            async for chat_thread_info_page in chat_thread_infos.by_page():
                async for chat_thread_info in chat_thread_info_page:
                    print("thread id: ", chat_thread_info.id)
class ChatThreadClientSamplesAsync(object):
    from azure.communication.chat.aio import ChatClient
    from azure.communication.identity import CommunicationIdentityClient
    from azure.communication.identity._shared.user_credential_async import CommunicationTokenCredential
    from azure.communication.chat._shared.user_token_refresh_options import CommunicationTokenRefreshOptions

    connection_string = os.environ.get("AZURE_COMMUNICATION_SERVICE_CONNECTION_STRING", None)
    if not connection_string:
        raise ValueError("Set AZURE_COMMUNICATION_SERVICE_CONNECTION_STRING env before run this sample.")

    identity_client = CommunicationIdentityClient.from_connection_string(connection_string)
    user = identity_client.create_user()
    tokenresponse = identity_client.get_token(user, scopes=["chat"])
    token = tokenresponse.token

    endpoint = os.environ.get("AZURE_COMMUNICATION_SERVICE_ENDPOINT", None)
    if not endpoint:
        raise ValueError("Set AZURE_COMMUNICATION_SERVICE_ENDPOINT env before run this sample.")

    _thread_id = None
    _message_id = None
    new_user = identity_client.create_user()

    refresh_options = CommunicationTokenRefreshOptions(token)
    _chat_client = ChatClient(endpoint, CommunicationTokenCredential(refresh_options))

    async def create_chat_thread_client_async(self):
        # [START create_chat_thread_client]
        from datetime import datetime
        from azure.communication.chat.aio import ChatClient
        from azure.communication.chat import ChatThreadParticipant
        from azure.communication.identity import CommunicationUserIdentifier
        from azure.communication.identity._shared.user_credential_async import CommunicationTokenCredential
        from azure.communication.chat._shared.user_token_refresh_options import CommunicationTokenRefreshOptions

        refresh_options = CommunicationTokenRefreshOptions(self.token)
        chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(refresh_options))

        async with chat_client:
            topic = "test topic"
            participants = [ChatThreadParticipant(
                user=self.user,
                display_name='name',
                share_history_time=datetime.utcnow()
            )]
            create_chat_thread_result = await chat_client.create_chat_thread(topic, thread_participants=participants)
            chat_thread_client = chat_client.get_chat_thread_client(create_chat_thread_result.chat_thread.id)
        # [END create_chat_thread_client]

        self._thread_id = create_chat_thread_result.chat_thread.id
        print("thread created, id: " + self._thread_id)
        print("create_chat_thread_client_async succeeded")

    async def update_topic_async(self):
        thread_id = self._thread_id
        chat_client = self._chat_client

        # [START update_topic]
        # set `thread_id` to an existing thread id
        async with chat_client:
            chat_thread = await chat_client.get_chat_thread(thread_id=thread_id)
            previous_topic = chat_thread.topic
            chat_thread_client = chat_client.get_chat_thread_client(thread_id=thread_id)

            async with chat_thread_client:
                topic = "updated thread topic"
                await chat_thread_client.update_topic(topic=topic)

            chat_thread = await chat_client.get_chat_thread(thread_id=thread_id)
            updated_topic = chat_thread.topic
            print("Chat Thread Topic Update: Previous value: ", previous_topic, ", Current value: ", updated_topic)
        # [END update_topic]

        print("update_topic_async succeeded")

    async def send_message_async(self):
        thread_id = self._thread_id
        chat_client = self._chat_client

        # [START send_message]
        from azure.communication.chat import ChatMessageType
        async with chat_client:
            chat_thread_client = chat_client.get_chat_thread_client(thread_id=thread_id)
            async with chat_thread_client:
                # Scenario 1: Send message without specifying chat_message_type
                send_message_result_id = await chat_thread_client.send_message(
                    "Hello! My name is Fred Flinstone",
                    sender_display_name="Fred Flinstone")

                # Scenario 2: Send message specifying chat_message_type
                send_message_result_w_type_id = await chat_thread_client.send_message(
                    "Hello! My name is Wilma Flinstone",
                    sender_display_name="Wilma Flinstone",
                    chat_message_type=ChatMessageType.TEXT)  # equivalent to setting chat_message_type='text'

                # Verify message content
                print("First Message:", (await chat_thread_client.get_message(send_message_result_id)).content.message)
                print("Second Message:", (await chat_thread_client.get_message(send_message_result_w_type_id)).content.message)
        # [END send_message]
                self._message_id = send_message_result_id
            print("send_message succeeded, message id:", self._message_id)
            print("send_message succeeded with type specified, message id:", send_message_result_w_type_id)
        print("send_message_async succeeded")

    async def get_message_async(self):
        thread_id = self._thread_id
        chat_client = self._chat_client
        message_id = self._message_id

        # [START get_message]
        async with chat_client:
            # set `thread_id` to an existing thread id
            chat_thread_client = chat_client.get_chat_thread_client(thread_id=thread_id)
            async with chat_thread_client:
                # set `message_id` to an existing message id
                chat_message = await chat_thread_client.get_message(message_id)

                print("Message received: ChatMessage: content=", chat_message.content.message, ", id=", chat_message.id)
        # [END get_message]
        print("get_message_async succeeded")

    async def list_messages_async(self):
        thread_id = self._thread_id
        chat_client = self._chat_client

        # [START list_messages]
        from datetime import datetime, timedelta
        async with chat_client:
            # set `thread_id` to an existing thread id
            chat_thread_client = chat_client.get_chat_thread_client(thread_id=thread_id)
            async with chat_thread_client:
                start_time = datetime.utcnow() - timedelta(days=1)
                chat_messages = chat_thread_client.list_messages(results_per_page=1, start_time=start_time)
                print("list_messages succeeded with results_per_page is 1, and start time is yesterday UTC")
                async for chat_message_page in chat_messages.by_page():
                    async for chat_message in chat_message_page:
                        print("ChatMessage: message=", chat_message.content.message)
        # [END list_messages]
        print("list_messages_async succeeded")

    async def update_message_async(self):
        thread_id = self._thread_id
        chat_client = self._chat_client
        message_id = self._message_id

        # [START update_message]
        async with chat_client:
            # set `thread_id` to an existing thread id
            chat_thread_client = chat_client.get_chat_thread_client(thread_id=thread_id)
            async with chat_thread_client:
                # set `message_id` to an existing message id
                previous_content = (await chat_thread_client.get_message(message_id)).content.message

                content = "updated message content"
                await chat_thread_client.update_message(self._message_id, content=content)

                current_content = (await chat_thread_client.get_message(message_id)).content.message

                print("Chat Message Updated: Previous value: ", previous_content, ", Current value: ", current_content)
        # [END update_message]
        print("update_message_async succeeded")

    async def send_read_receipt_async(self):
        thread_id = self._thread_id
        chat_client = self._chat_client
        message_id = self._message_id
        # [START send_read_receipt]
        async with chat_client:
            # set `thread_id` to an existing thread id
            chat_thread_client = chat_client.get_chat_thread_client(thread_id=thread_id)
            async with chat_thread_client:
                # set `message_id` to an existing message id
                await chat_thread_client.send_read_receipt(message_id)
        # [END send_read_receipt]

        print("send_read_receipt_async succeeded")

    async def list_read_receipts_async(self):
        thread_id = self._thread_id
        chat_client = self._chat_client

        # [START list_read_receipts]
        async with chat_client:
            # set `thread_id` to an existing thread id
            chat_thread_client = chat_client.get_chat_thread_client(thread_id=thread_id)
            async with chat_thread_client:
                read_receipts = chat_thread_client.list_read_receipts()
                print("list_read_receipts succeeded, receipts:")
                async for read_receipt_page in read_receipts.by_page():
                    async for read_receipt in read_receipt_page:
                        print(read_receipt)
        # [END list_read_receipts]
        print("list_read_receipts_async succeeded")

    async def delete_message_async(self):
        thread_id = self._thread_id
        chat_client = self._chat_client
        message_id = self._message_id
        # [START delete_message]
        async with chat_client:
            # set `thread_id` to an existing thread id
            chat_thread_client = chat_client.get_chat_thread_client(thread_id=thread_id)
            async with chat_thread_client:
                # set `message_id` to an existing message id
                await chat_thread_client.delete_message(message_id)
        # [END delete_message]
        print("delete_message_async succeeded")

    async def list_participants_async(self):
        thread_id = self._thread_id
        chat_client = self._chat_client
        # [START list_participants]
        async with chat_client:
            # set `thread_id` to an existing thread id
            chat_thread_client = chat_client.get_chat_thread_client(thread_id=thread_id)
            async with chat_thread_client:
                chat_thread_participants = chat_thread_client.list_participants()
                print("list_participants succeeded, participants:")
                async for chat_thread_participant_page in chat_thread_participants.by_page():
                    async for chat_thread_participant in chat_thread_participant_page:
                        print("ChatThreadParticipant: ", chat_thread_participant)
        # [END list_participants]
        print("list_participants_async succeeded")

    async def add_participant_w_check_async(self):
        thread_id = self._thread_id
        chat_client = self._chat_client
        user = self.new_user
        # [START add_participant]
        def decide_to_retry(error):
            """
            Custom logic to decide whether to retry to add or not
            """
            return True

        async with chat_client:
            # set `thread_id` to an existing thread id
            chat_thread_client = chat_client.get_chat_thread_client(thread_id=thread_id)
            async with chat_thread_client:
                from azure.communication.chat import ChatThreadParticipant
                from datetime import datetime
                new_chat_thread_participant = ChatThreadParticipant(
                        user=user,
                        display_name='name',
                        share_history_time=datetime.utcnow())
                try:
                    await chat_thread_client.add_participant(new_chat_thread_participant)
                except RuntimeError as e:
                    if e is not None and decide_to_retry(error=e):
                        await chat_thread_client.add_participant(new_chat_thread_participant)
        # [END add_participant]
        print("add_participant_w_check_async succeeded")

    async def add_participants_w_check_async(self):
        thread_id = self._thread_id
        chat_client = self._chat_client
        user = self.new_user

        # [START add_participants]
        def decide_to_retry(error):
            """
            Custom logic to decide whether to retry to add or not
            """
            return True

        async with chat_client:
            # set `thread_id` to an existing thread id
            chat_thread_client = chat_client.get_chat_thread_client(thread_id=thread_id)
            async with chat_thread_client:
                from azure.communication.chat import ChatThreadParticipant
                from datetime import datetime
                new_participant = ChatThreadParticipant(
                        user=self.new_user,
                        display_name='name',
                        share_history_time=datetime.utcnow())
                thread_participants = [new_participant]
                result = await chat_thread_client.add_participants(thread_participants)

                # list of participants which were unsuccessful to be added to chat thread
                retry = [p for p, e in result if decide_to_retry(e)]
                if len(retry) > 0:
                    chat_thread_client.add_participants(retry)

        # [END add_participants]
        print("add_participants_w_check_async succeeded")

    async def remove_participant_async(self):
        thread_id = self._thread_id
        chat_client = self._chat_client
        identity_client = self.identity_client
        # [START remove_participant]
        from azure.communication.chat import ChatThreadParticipant
        from azure.communication.identity import CommunicationUserIdentifier
        from datetime import datetime

        async with chat_client:
            # create 2 new users using CommunicationIdentityClient.create_user method
            user1 = identity_client.create_user()
            user2 = identity_client.create_user()

            # set `thread_id` to an existing thread id
            chat_thread_client = chat_client.get_chat_thread_client(thread_id=thread_id)

            async with chat_thread_client:
                # add user1 and user2 to chat thread
                participant1 = ChatThreadParticipant(
                    user=user1,
                    display_name='Fred Flinstone',
                    share_history_time=datetime.utcnow())

                participant2 = ChatThreadParticipant(
                    user=user2,
                    display_name='Wilma Flinstone',
                    share_history_time=datetime.utcnow())

                thread_participants = [participant1, participant2]
                await chat_thread_client.add_participants(thread_participants)

                # Option 1 : Iterate through all participants, find and delete Fred Flinstone
                chat_thread_participants = chat_thread_client.list_participants()

                async for chat_thread_participant_page in chat_thread_participants.by_page():
                    async for chat_thread_participant in chat_thread_participant_page:
                        print("ChatThreadParticipant: ", chat_thread_participant)
                        if chat_thread_participant.user.identifier == user1.identifier:
                            print("Found Fred!")
                            await chat_thread_client.remove_participant(chat_thread_participant.user)
                            print("Fred has been removed from the thread...")
                            break

                # Option 2: Directly remove Wilma Flinstone
                unique_identifier = user2.identifier  # in real scenario the identifier would need to be retrieved from elsewhere
                await chat_thread_client.remove_participant(CommunicationUserIdentifier(unique_identifier))
                print("Wilma has been removed from the thread...")
        # [END remove_participant]

        # clean up temporary users
        self.identity_client.delete_user(user1)
        self.identity_client.delete_user(user2)
        print("remove_participant_async succeeded")

    async def send_typing_notification_async(self):
        thread_id = self._thread_id
        chat_client = self._chat_client
        # [START send_typing_notification]
        async with chat_client:
            # set `thread_id` to an existing thread id
            chat_thread_client = chat_client.get_chat_thread_client(thread_id=thread_id)
            async with chat_thread_client:
                await chat_thread_client.send_typing_notification()
        # [END send_typing_notification]
        print("send_typing_notification_async succeeded")

    def clean_up(self):
        print("cleaning up: deleting created users.")
        self.identity_client.delete_user(self.user)
        self.identity_client.delete_user(self.new_user)
 async def test_init_with_valid_token(self):
     initial_token = generate_token_with_custom_expiry(5 * 60)
     credential = CommunicationTokenCredential(initial_token)
     access_token = await credential.get_token()
     assert initial_token == access_token.token
 async def test_raises_error_for_init_with_invalid_token(self):
     with pytest.raises(ValueError) as err:
         CommunicationTokenCredential("not a token")
     assert str(err.value) == "Token is not formatted correctly"
 async def test_raises_error_for_init_with_nonstring_token(self):
     with pytest.raises(TypeError) as err:
         CommunicationTokenCredential(1234)
     assert str(err.value) == "Token must be a string."