Skip to content

Commit 9c2b2c5

Browse files
authored
Fixing getTranscript loop on reconnection flow (#57)
* Fixing getTranscript loop on reconnection flow * Updating logic + bumping version to 1.0.10 * test fix
1 parent bbe13c4 commit 9c2b2c5

File tree

3 files changed

+73
-13
lines changed

3 files changed

+73
-13
lines changed

chat-sdk/src/main/java/com/amazon/connect/chat/sdk/repository/ChatService.kt

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ class ChatServiceImpl @Inject constructor(
259259
SDKLogger.logger.logDebug { "Connection Re-Established" }
260260
connectionDetailsProvider.setChatSessionState(true)
261261
removeTypingIndicators() // Make sure to remove typing indicators if still present
262-
fetchReconnectedTranscript(internalTranscript)
262+
fetchReconnectedTranscript()
263263
}
264264

265265
ChatEvent.ChatEnded -> {
@@ -715,7 +715,7 @@ class ChatServiceImpl @Inject constructor(
715715
}
716716
}
717717

718-
private suspend fun fetchReconnectedTranscript(internalTranscript: List<TranscriptItem>) {
718+
private suspend fun fetchReconnectedTranscript() {
719719
val lastItem = internalTranscript.lastOrNull { (it as? Message)?.metadata?.status != MessageStatus.Failed }
720720
?: return
721721

@@ -728,19 +728,28 @@ class ChatServiceImpl @Inject constructor(
728728
fetchTranscriptWith(startPosition)
729729
}
730730

731+
private fun isItemInInternalTranscript(Id: String?): Boolean {
732+
if (Id == null) return false
733+
for (item in internalTranscript.reversed()) {
734+
if (item.id == Id) {
735+
return true
736+
}
737+
}
738+
return false
739+
}
740+
731741
private suspend fun fetchTranscriptWith(startPosition: StartPosition?) {
732742
getTranscript(startPosition = startPosition,
733743
scanDirection = ScanDirection.FORWARD,
734744
sortKey = SortKey.ASCENDING,
735-
maxResults = 30,
745+
maxResults = 100,
736746
nextToken = null).onSuccess { transcriptResponse ->
737-
if (transcriptResponse.nextToken?.isNotEmpty() == true) {
738-
val newStartPosition = transcriptResponse.transcript.lastOrNull()?.let {
739-
StartPosition().apply {
740-
id = it.id
741-
}
747+
val lastItem = transcriptResponse.transcript.lastOrNull()
748+
if (transcriptResponse.nextToken?.isNotEmpty() == true && lastItem != null) {
749+
val newStartPosition = StartPosition().apply { id = lastItem.id }
750+
if (!isItemInInternalTranscript(lastItem?.id)) {
751+
fetchTranscriptWith(startPosition = newStartPosition)
742752
}
743-
fetchTranscriptWith(startPosition = newStartPosition)
744753
}
745754
}.onFailure { error ->
746755
SDKLogger.logger.logError { "Error fetching transcript with startPosition $startPosition: ${error.localizedMessage}" }

chat-sdk/src/test/java/com/amazon/connect/chat/sdk/repository/ChatServiceImplTest.kt

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import com.amazon.connect.chat.sdk.provider.ConnectionDetailsProvider
1818
import com.amazonaws.regions.Regions
1919
import com.amazonaws.services.connectparticipant.model.DisconnectParticipantResult
2020
import com.amazonaws.services.connectparticipant.model.GetTranscriptResult
21+
import com.amazonaws.services.connectparticipant.model.Item
2122
import com.amazonaws.services.connectparticipant.model.ScanDirection
2223
import com.amazonaws.services.connectparticipant.model.SendEventResult
2324
import com.amazonaws.services.connectparticipant.model.SendMessageResult
@@ -48,6 +49,12 @@ import org.robolectric.RobolectricTestRunner
4849
import io.mockk.every
4950
import io.mockk.mockkStatic
5051
import io.mockk.unmockkStatic
52+
import junit.framework.TestCase.fail
53+
import kotlinx.coroutines.Dispatchers
54+
import kotlinx.coroutines.test.StandardTestDispatcher
55+
import kotlinx.coroutines.test.advanceUntilIdle
56+
import kotlinx.coroutines.test.setMain
57+
import org.mockito.kotlin.any
5158
import java.util.UUID
5259
import java.net.URL
5360

@@ -76,18 +83,20 @@ class ChatServiceImplTest {
7683
@Mock
7784
private lateinit var messageReceiptsManager: MessageReceiptsManager
7885

79-
private lateinit var chatService: ChatService
86+
private lateinit var chatService: ChatServiceImpl
8087
private lateinit var eventSharedFlow: MutableSharedFlow<ChatEvent>
8188
private lateinit var transcriptSharedFlow: MutableSharedFlow<TranscriptItem>
8289
private lateinit var chatSessionStateFlow: MutableStateFlow<Boolean>
8390
private lateinit var transcriptListSharedFlow: MutableSharedFlow<List<TranscriptItem>>
8491
private lateinit var newWsUrlFlow: MutableSharedFlow<Unit>
8592

8693
private val mockUri: Uri = Uri.parse("https://example.com/dummy.pdf")
94+
private val testDispatcher = StandardTestDispatcher()
8795

8896
@Before
8997
fun setUp() {
9098
MockitoAnnotations.openMocks(this)
99+
Dispatchers.setMain(testDispatcher)
91100

92101
eventSharedFlow = MutableSharedFlow()
93102
transcriptSharedFlow = MutableSharedFlow()
@@ -510,6 +519,48 @@ class ChatServiceImplTest {
510519
verify(awsClient).getTranscript(anyOrNull())
511520
}
512521

522+
private fun createMockItem(id: String, timestamp: String): Item {
523+
val item = Item()
524+
item.absoluteTime = timestamp
525+
item.content = "test${id}"
526+
item.contentType = "text/plain"
527+
item.id = id
528+
item.type = "MESSAGE"
529+
item.participantId = id
530+
item.displayName = "test${id}"
531+
item.participantRole = "CUSTOMER"
532+
return item
533+
}
534+
535+
@Test
536+
fun test_fetchReconnectedTranscript_success() = runTest {
537+
val chatDetails = ChatDetails(participantToken = "token")
538+
val mockConnectionDetails = createMockConnectionDetails("valid_token")
539+
`when`(connectionDetailsProvider.getConnectionDetails()).thenReturn(mockConnectionDetails)
540+
chatService.createChatSession(chatDetails)
541+
advanceUntilIdle()
542+
543+
// Create a mock GetTranscriptResult and configure it to return expected values
544+
val mockGetTranscriptResult = mock<GetTranscriptResult>()
545+
546+
`when`(mockGetTranscriptResult.initialContactId).thenReturn("")
547+
`when`(awsClient.getTranscript(anyOrNull())).thenReturn(Result.success(mockGetTranscriptResult))
548+
549+
// Add items to the internal transcript and emit reconnection event.
550+
// This scenario should call getTranscript once since the empty transcript response.
551+
`when`(mockGetTranscriptResult.transcript).thenReturn(listOf())
552+
`when`(mockGetTranscriptResult.nextToken).thenReturn("nextToken1")
553+
554+
val transcriptItem1 = Message(id = "1", timeStamp = "2024-01-01T00:00:00Z", participant = "user", contentType = "text/plain", text = "Hello")
555+
val transcriptItem2 = Message(id = "2", timeStamp = "2025-01-01T00:01:00Z", participant = "agent", contentType = "text/plain", text = "Hi")
556+
chatService.internalTranscript.add(transcriptItem1)
557+
chatService.internalTranscript.add(transcriptItem2)
558+
val chatEvent = ChatEvent.ConnectionReEstablished
559+
eventSharedFlow.emit(chatEvent)
560+
advanceUntilIdle()
561+
verify(awsClient, times(1)).getTranscript(anyOrNull())
562+
}
563+
513564
@Test
514565
fun test_sendMessageReceipt_success() = runTest {
515566
val messageId = "messageId123"
@@ -615,15 +666,15 @@ class ChatServiceImplTest {
615666
// Add message in internal transcript
616667
val transcriptItem = Message(id = "1", timeStamp = "mockedTimestamp", participant = "user",
617668
contentType = "text/plain", text = "Hello")
618-
(chatService as ChatServiceImpl).internalTranscript.add(0, transcriptItem)
669+
chatService.internalTranscript.add(0, transcriptItem)
619670

620671
// Execute reset
621672
chatService.reset()
622673

623674
// Validate that websocket disconnected, tokens are reset and internal transcript is deleted
624675
verify(webSocketManager).disconnect("Resetting ChatService")
625676
verify(connectionDetailsProvider).reset()
626-
assertEquals(0, (chatService as ChatServiceImpl).internalTranscript.size)
677+
assertEquals(0, chatService.internalTranscript.size)
627678
}
628679

629680
private fun createMockConnectionDetails(token : String): ConnectionDetails {

chat-sdk/version.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
sdkVersion=1.0.9
1+
sdkVersion=1.0.10
22
groupId=software.aws.connect
33
artifactId=amazon-connect-chat-android

0 commit comments

Comments
 (0)