Skip to content

Commit

Permalink
fix: commit strategy for mls commit missing reference (#3272) (#3276)
Browse files Browse the repository at this point in the history
Co-authored-by: Jakub Żerko <iot.zerko@gmail.com>
Co-authored-by: Vitor Hugo Schwaab <vitor@schwaab.dev>
  • Loading branch information
3 people authored Feb 5, 2025
1 parent d1e4487 commit 9ca21c1
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -180,11 +180,12 @@ private fun CoreFailure.getStrategy(
this is NetworkFailure.ServerMiscommunication &&
kaliumException is KaliumException.InvalidRequestError
) {
if (this.kaliumException.isMlsClientMismatch() && retryOnClientMismatch) {
if ((this.kaliumException.isMlsClientMismatch() && retryOnClientMismatch) ||
this.kaliumException.isMlsCommitMissingReferences()
) {
CommitStrategy.DISCARD_AND_RETRY
} else if (
this.kaliumException.isMlsStaleMessage() && retryOnStaleMessage ||
this.kaliumException.isMlsCommitMissingReferences()
this.kaliumException.isMlsStaleMessage() && retryOnStaleMessage
) {
CommitStrategy.KEEP_AND_RETRY
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1601,6 +1601,77 @@ class MLSConversationRepositoryTest {
}
}

@Test
fun givenMlsCommitMissingReferencesError_whenEstablishMLSSubConversationGroup_thenShouldDiscardAndRetry() = runTest {
val (arrangement, mlsConversationRepository) = Arrangement(testKaliumDispatcher)
.withCommitPendingProposalsReturningNothing()
.withClaimKeyPackagesSuccessful(emptyList())
.withGetMLSClientSuccessful()
.withGetMLSGroupIdByConversationIdReturns(Arrangement.GROUP_ID.value)
.withGetExternalSenderKeySuccessful()
.withGetDefaultCipherSuiteSuccessful()
.withKeyForCipherSuite()
.withUpdateKeyingMaterialSuccessful()
.withWaitUntilLiveSuccessful()
.withSendCommitBundleFailing(Arrangement.MLS_COMMIT_MISSING_REFERENCES_ERROR, times = 1)
.arrange()

val result = mlsConversationRepository.establishMLSSubConversationGroup(Arrangement.GROUP_ID, TestConversation.ID)

result.shouldSucceed()

coVerify { arrangement.mlsMessageApi.sendCommitBundle(any()) }.wasInvoked(2) // Retry should occur
coVerify { arrangement.mlsClient.clearPendingCommit(eq(Arrangement.RAW_GROUP_ID)) }
.wasInvoked(once) // indicates that the commit was discarded
}

@Test
fun givenStaleMessageError_whenUpdateKeyingMaterial_thenShouldKeepAndRetry() = runTest {
val (arrangement, mlsConversationRepository) = Arrangement(testKaliumDispatcher)
.withCommitPendingProposalsSuccessful()
.withClaimKeyPackagesSuccessful(emptyList())
.withGetMLSClientSuccessful()
.withGetMLSGroupIdByConversationIdReturns(Arrangement.GROUP_ID.value)
.withGetExternalSenderKeySuccessful()
.withKeyForCipherSuite()
.withGetDefaultCipherSuiteSuccessful()
.withUpdateKeyingMaterialSuccessful()
.withSendCommitBundleFailing(Arrangement.MLS_STALE_MESSAGE_ERROR, times = 1)
.withWaitUntilLiveSuccessful()
.arrange()

val result = mlsConversationRepository.updateKeyingMaterial(Arrangement.GROUP_ID)

result.shouldSucceed()

coVerify { arrangement.mlsMessageApi.sendCommitBundle(any()) }.wasInvoked(2) // Retry should occur
coVerify { arrangement.mlsClient.clearPendingCommit(eq(Arrangement.RAW_GROUP_ID)) }
.wasNotInvoked() // indicates that the commit was not discarded
}

@Test
fun givenUnexpectedError_whenEstablishMLSSubConversationGroup_thenShouldAbort() = runTest {
val (arrangement, mlsConversationRepository) = Arrangement(testKaliumDispatcher)
.withCommitPendingProposalsReturningNothing()
.withClaimKeyPackagesSuccessful(emptyList())
.withGetMLSClientSuccessful()
.withGetDefaultCipherSuiteSuccessful()
.withGetMLSGroupIdByConversationIdReturns(Arrangement.GROUP_ID.value)
.withGetExternalSenderKeySuccessful()
.withKeyForCipherSuite()
.withUpdateKeyingMaterialSuccessful()
.withSendCommitBundleFailing(Arrangement.INVALID_REQUEST_ERROR, times = 1)
.arrange()

val result = mlsConversationRepository.establishMLSSubConversationGroup(Arrangement.GROUP_ID, TestConversation.ID)

result.shouldFail()

coVerify { arrangement.mlsMessageApi.sendCommitBundle(any()) }.wasInvoked(1) // No retry should happen
coVerify { arrangement.mlsClient.clearPendingCommit(eq(Arrangement.RAW_GROUP_ID)) }
.wasInvoked(once) // indicates that the commit was discarded
}

private class Arrangement(
var kaliumDispatcher: KaliumDispatcher = TestKaliumDispatcher
) {
Expand Down Expand Up @@ -1888,6 +1959,8 @@ class MLSConversationRepositoryTest {
val INVALID_REQUEST_ERROR = KaliumException.InvalidRequestError(ErrorResponse(405, "", ""))
val MLS_STALE_MESSAGE_ERROR = KaliumException.InvalidRequestError(ErrorResponse(409, "", "mls-stale-message"))
val MLS_CLIENT_MISMATCH_ERROR = KaliumException.InvalidRequestError(ErrorResponse(409, "", "mls-client-mismatch"))
val MLS_COMMIT_MISSING_REFERENCES_ERROR =
KaliumException.InvalidRequestError(ErrorResponse(409, "", "mls-commit-missing-references"))
val MLS_PUBLIC_KEY = MLSPublicKeys(
removal = mapOf(
"ed25519" to "gRNvFYReriXbzsGu7zXiPtS8kaTvhU1gUJEV9rdFHVw="
Expand Down

0 comments on commit 9ca21c1

Please sign in to comment.