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

feat: Implement message unknown strategy #WPB-11913 #3092

Merged
merged 1 commit into from
Nov 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import com.wire.kalium.protobuf.messages.Quote
import com.wire.kalium.protobuf.messages.Reaction
import com.wire.kalium.protobuf.messages.Text
import com.wire.kalium.protobuf.messages.TrackingIdentifier
import com.wire.kalium.protobuf.messages.UnknownStrategy
import kotlinx.datetime.Instant
import pbandk.ByteArr

Expand All @@ -82,7 +83,10 @@ class ProtoContentMapperImpl(
is ProtoContent.Readable -> mapReadableContentToProtobuf(protoContent)
}

val message = GenericMessage(protoContent.messageUid, messageContent)
val message = GenericMessage(
messageId = protoContent.messageUid,
content = messageContent
)
return PlainMessageBlob(message.encodeToByteArray())
}

Expand Down Expand Up @@ -374,8 +378,17 @@ class ProtoContentMapperImpl(
}

null -> {
kaliumLogger.w("Null content when parsing protobuf. Message UUID = ${genericMessage.messageId.obfuscateId()}")
MessageContent.Ignored
kaliumLogger.w(
"Null content when parsing protobuf. Message UUID = ${genericMessage.messageId.obfuscateId()}" +
" Message Unknown Strategy = ${genericMessage.unknownStrategy}"
)
when (genericMessage.unknownStrategy) {
UnknownStrategy.DISCARD_AND_WARN -> MessageContent.Unknown()
UnknownStrategy.WARN_USER_ALLOW_RETRY -> MessageContent.Unknown(encodedData = encodedContent.data)
UnknownStrategy.IGNORE,
is UnknownStrategy.UNRECOGNIZED,
null -> MessageContent.Ignored
}
}
}
return readableContent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import com.wire.kalium.protobuf.messages.Confirmation
import com.wire.kalium.protobuf.messages.GenericMessage
import com.wire.kalium.protobuf.messages.MessageEdit
import com.wire.kalium.protobuf.messages.Text
import com.wire.kalium.protobuf.messages.UnknownStrategy
import io.ktor.utils.io.core.toByteArray
import kotlin.test.BeforeTest
import kotlin.test.Test
Expand Down Expand Up @@ -91,7 +92,8 @@ class ProtoContentMapperTest {
val assetName = "Mocked-Asset.bin"
val mockedAsset = assetName.toByteArray()
val protobuf = GenericMessage(
TEST_MESSAGE_UUID, GenericMessage.Content.Asset(
messageId = TEST_MESSAGE_UUID,
content = GenericMessage.Content.Asset(
Asset(
original = Asset.Original(
mimeType = "file/binary",
Expand Down Expand Up @@ -193,7 +195,12 @@ class ProtoContentMapperTest {
fun givenEditedTextGenericMessage_whenMappingFromProtoData_thenTheReturnValueShouldHaveTheCorrectEditedMessageId() {
val replacedMessageId = "replacedMessageId"
val textContent = MessageEdit.Content.Text(Text("textContent"))
val genericMessage = GenericMessage(TEST_MESSAGE_UUID, GenericMessage.Content.Edited(MessageEdit(replacedMessageId, textContent)))
val genericMessage = GenericMessage(
messageId = TEST_MESSAGE_UUID,
content = GenericMessage.Content.Edited(
MessageEdit(replacedMessageId, textContent)
)
)
val protobufBlob = PlainMessageBlob(genericMessage.encodeToByteArray())

val result = protoContentMapper.decodeFromProtobuf(protobufBlob)
Expand All @@ -208,7 +215,10 @@ class ProtoContentMapperTest {
fun givenEditedTextGenericMessage_whenMappingFromProtoData_thenTheReturnValueShouldHaveTheCorrectUpdatedContent() {
val replacedMessageId = "replacedMessageId"
val textContent = MessageEdit.Content.Text(Text("textContent"))
val genericMessage = GenericMessage(TEST_MESSAGE_UUID, GenericMessage.Content.Edited(MessageEdit(replacedMessageId, textContent)))
val genericMessage = GenericMessage(
messageId = TEST_MESSAGE_UUID,
content = GenericMessage.Content.Edited(MessageEdit(replacedMessageId, textContent))
)
val protobufBlob = PlainMessageBlob(genericMessage.encodeToByteArray())

val result = protoContentMapper.decodeFromProtobuf(protobufBlob)
Expand Down Expand Up @@ -324,15 +334,71 @@ class ProtoContentMapperTest {
val messageUid = "uid"

val protobuf = GenericMessage(
messageUid,
GenericMessage.Content.Confirmation(Confirmation(Confirmation.Type.fromValue(-1), messageUid))
messageId = messageUid,
content = GenericMessage.Content.Confirmation(Confirmation(Confirmation.Type.fromValue(-1), messageUid))
)
val decoded = protoContentMapper.decodeFromProtobuf(PlainMessageBlob(protobuf.encodeToByteArray()))

assertIs<ProtoContent.Readable>(decoded)
assertIs<MessageContent.Ignored>(decoded.messageContent)
}

@Test
fun givenNonParseableContentWithDefaultUnknownStrategy_whenMappingFromProto_thenShouldReturnIgnoredContent() {
val protobuf = GenericMessage(
messageId = "uid"
)

val decoded = protoContentMapper.decodeFromProtobuf(PlainMessageBlob(protobuf.encodeToByteArray()))

assertIs<ProtoContent.Readable>(decoded)
assertIs<MessageContent.Ignored>(decoded.messageContent)
}

@Test
fun givenNonParseableContentWithUnknownStrategyIgnore_whenMappingFromProto_thenShouldReturnIgnoredContent() {
val protobuf = GenericMessage(
messageId = "uid",
unknownStrategy = UnknownStrategy.IGNORE
)

val decoded = protoContentMapper.decodeFromProtobuf(PlainMessageBlob(protobuf.encodeToByteArray()))

assertIs<ProtoContent.Readable>(decoded)
assertIs<MessageContent.Ignored>(decoded.messageContent)
}

@Test
fun givenNonParseableContentWithUnknownStrategyDiscardAndWarn_whenMappingFromProto_thenShouldReturnUnknownContentWithoutByteData() {
val protobuf = GenericMessage(
messageId = "uid",
unknownStrategy = UnknownStrategy.DISCARD_AND_WARN
)

val decoded = protoContentMapper.decodeFromProtobuf(PlainMessageBlob(protobuf.encodeToByteArray()))

assertIs<ProtoContent.Readable>(decoded)
val content = decoded.messageContent
assertIs<MessageContent.Unknown>(content)
assertEquals(content.encodedData, null)
}

@Test
fun givenNonParseableContentWithUnknownStrategyWarnUserAllowEntry_whenMappingFromProto_thenShouldReturnUnknownContentWithByteData() {
val protobuf = GenericMessage(
messageId = "uid",
unknownStrategy = UnknownStrategy.WARN_USER_ALLOW_RETRY
)
val protobufByteArray = protobuf.encodeToByteArray()

val decoded = protoContentMapper.decodeFromProtobuf(PlainMessageBlob(protobufByteArray))

assertIs<ProtoContent.Readable>(decoded)
val content = decoded.messageContent
assertIs<MessageContent.Unknown>(content)
assertEquals(content.encodedData, protobufByteArray)
}

@Test
fun givenExternalMessageInstructions_whenEncodingToProtoAndBack_thenTheResultContentShouldEqualTheOriginal() {
val messageUid = TEST_MESSAGE_UUID
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,10 @@ class PersistMigratedMessagesUseCaseTest {
@Mock
val migrationDAO: MigrationDAO = mock(MigrationDAO::class)

val genericMessage = GenericMessage("uuid", GenericMessage.Content.Text(Text("some_text")))
val genericMessage = GenericMessage(
messageId = "uuid",
content = GenericMessage.Content.Text(Text("some_text"))
)

fun fakeMigratedMessage() = MigratedMessage(
conversationId = TestConversation.ID,
Expand Down
7 changes: 7 additions & 0 deletions protobuf-codegen/src/main/proto/messages.proto
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ message GenericMessage {
ButtonActionConfirmation buttonActionConfirmation = 22;
DataTransfer dataTransfer = 23; // client-side synchronization across devices of the same user
}
optional UnknownStrategy unknownStrategy = 24 [default = IGNORE];
}

message QualifiedUserId {
Expand Down Expand Up @@ -360,3 +361,9 @@ enum LegalHoldStatus {
DISABLED = 1;
ENABLED = 2;
}

enum UnknownStrategy {
IGNORE = 0; // Ignore the message completely.
m-zagorski marked this conversation as resolved.
Show resolved Hide resolved
DISCARD_AND_WARN = 1; // Warn the user, but discard the message, as it may not be helpful in the future
WARN_USER_ALLOW_RETRY = 2; // Warn the user. Client has freedom to store it and retry in the future.
}
Loading