diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/IndividualSendJobV2.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/IndividualSendJobV2.kt index c225aef341..94d77b420b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/IndividualSendJobV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/IndividualSendJobV2.kt @@ -444,6 +444,7 @@ class IndividualSendJobV2 private constructor(parameters: Parameters, private va timestamp = timestamp, message = dataMessage, editMessage = editMessage, + expirationStartTimestamp = if ((dataMessage?.expireTimer ?: 0) > 0) System.currentTimeMillis() else null, unidentifiedStatus = listOf( SyncMessage.Sent.UnidentifiedDeliveryStatus( destinationServiceIdBinary = recipientServiceId.toByteString(), diff --git a/app/src/test/java/org/thoughtcrime/securesms/jobs/IndividualSendJobV2Test.kt b/app/src/test/java/org/thoughtcrime/securesms/jobs/IndividualSendJobV2Test.kt index 37c1b96843..3126e0eda5 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/jobs/IndividualSendJobV2Test.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/jobs/IndividualSendJobV2Test.kt @@ -11,6 +11,9 @@ import arrow.core.left import arrow.core.right import assertk.assertThat import assertk.assertions.isEqualTo +import assertk.assertions.isGreaterThan +import assertk.assertions.isNotNull +import assertk.assertions.isNull import assertk.assertions.isTrue import io.mockk.coEvery import io.mockk.coVerify @@ -427,6 +430,46 @@ class IndividualSendJobV2Test { } } + @Test + fun `Given multi-device and an expiring message, when send succeeds, then sync transcript carries expirationStartTimestamp`() { + every { signalStore.account.isMultiDevice } returns true + every { outgoingMessage.expiresIn } returns 60_000L + dataMessage = DataMessage(timestamp = sentTime, expireTimer = 60) + every { outgoingMessage.toDataMessage() } returns dataMessage.right() + + val syncSlot = slot() + val primaryContent = EnvelopeContent.encrypted(Content(dataMessage = dataMessage), ContentHint.RESENDABLE, Optional.empty()) + coEvery { + messageService.sendMessage(any(), any(), any(), any(), any(), any(), any(), any()) + } returns MessageService.SendSuccess(envelopeContent = primaryContent, sentSealedSender = false, devices = listOf(1)).right() + coEvery { + messageService.sendSyncMessage(timestamp = any(), envelopeContent = capture(syncSlot), urgent = any(), onEncrypted = any()) + } returns MessageService.SendSuccess(envelopeContent = primaryContent, sentSealedSender = false, devices = listOf(1)).right() + + createAndRunJob() + + val sent = syncSlot.captured.content.get().syncMessage!!.sent!! + assertThat(sent.expirationStartTimestamp).isNotNull().isGreaterThan(0L) + } + + @Test + fun `Given multi-device and a non-expiring message, when send succeeds, then sync transcript omits expirationStartTimestamp`() { + every { signalStore.account.isMultiDevice } returns true + + val syncSlot = slot() + coEvery { + messageService.sendSyncMessage(timestamp = any(), envelopeContent = capture(syncSlot), urgent = any(), onEncrypted = any()) + } returns MessageService.SendSuccess(envelopeContent = EnvelopeContent.encrypted(Content(dataMessage = dataMessage), ContentHint.RESENDABLE, Optional.empty()), sentSealedSender = false, devices = listOf(1)).right() + coEvery { + messageService.sendMessage(any(), any(), any(), any(), any(), any(), any(), any()) + } returns MessageService.SendSuccess(envelopeContent = EnvelopeContent.encrypted(Content(dataMessage = dataMessage), ContentHint.RESENDABLE, Optional.empty()), sentSealedSender = false, devices = listOf(1)).right() + + createAndRunJob() + + val sent = syncSlot.captured.content.get().syncMessage!!.sent!! + assertThat(sent.expirationStartTimestamp).isNull() + } + @Test fun `Given an edit of an already-edited message, when run, then target the edited revision's dateSent`() { val editTargetMessageId = messageId + 1