diff --git a/.gitignore b/.gitignore index eae4d3884..a53c79951 100644 --- a/.gitignore +++ b/.gitignore @@ -56,6 +56,7 @@ app/src/beta/google-services.json .idea/**/usage.statistics.xml .idea/**/dictionaries/** .idea/assetWizardSettings.xml +.idea/deploymentTargetDropDown.xml # Do not exclude project Dictionary !.idea/**/dictionaries/project.xml .idea/**/shelf @@ -126,6 +127,3 @@ fabric.properties # Android studio 3.1+ serialized cache file .idea/caches/build_file_checksums.ser -# # # # # # # # # -# IDEA SETTINGS # -# # # # # # # # # diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml deleted file mode 100644 index 5c46a1db3..000000000 --- a/.idea/deploymentTargetDropDown.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/java/ch/protonmail/android/attachments/UploadAttachments.kt b/app/src/main/java/ch/protonmail/android/attachments/UploadAttachments.kt index 9b58009f3..fcaca0cf9 100644 --- a/app/src/main/java/ch/protonmail/android/attachments/UploadAttachments.kt +++ b/app/src/main/java/ch/protonmail/android/attachments/UploadAttachments.kt @@ -55,7 +55,7 @@ internal const val KEY_INPUT_UPLOAD_ATTACHMENTS_IS_MESSAGE_SENDING = "keyUploadA internal const val KEY_OUTPUT_RESULT_UPLOAD_ATTACHMENTS_ERROR = "keyUploadAttachmentResultError" private const val UPLOAD_ATTACHMENTS_WORK_NAME_PREFIX = "uploadAttachmentUniqueWorkName" -private const val UPLOAD_ATTACHMENTS_MAX_RETRIES = 3 +private const val UPLOAD_ATTACHMENTS_MAX_RETRIES = 1 class UploadAttachments @WorkerInject constructor( @Assisted context: Context, @@ -214,7 +214,7 @@ class UploadAttachments @WorkerInject constructor( KEY_INPUT_UPLOAD_ATTACHMENTS_IS_MESSAGE_SENDING to isMessageSending ) ) - .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 2 * TEN_SECONDS, TimeUnit.SECONDS) + .setBackoffCriteria(BackoffPolicy.LINEAR, TEN_SECONDS, TimeUnit.SECONDS) .build() workManager.enqueueUniqueWork( diff --git a/app/src/main/java/ch/protonmail/android/compose/send/SendMessageWorker.kt b/app/src/main/java/ch/protonmail/android/compose/send/SendMessageWorker.kt index a986ee0f2..eb6779ee6 100644 --- a/app/src/main/java/ch/protonmail/android/compose/send/SendMessageWorker.kt +++ b/app/src/main/java/ch/protonmail/android/compose/send/SendMessageWorker.kt @@ -69,7 +69,10 @@ import ch.protonmail.android.usecase.compose.SaveDraft import ch.protonmail.android.usecase.compose.SaveDraftResult import ch.protonmail.android.utils.notifier.UserNotifier import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.withContext +import me.proton.core.util.kotlin.EMPTY_STRING import me.proton.core.util.kotlin.deserialize import me.proton.core.util.kotlin.serialize import timber.log.Timber @@ -89,7 +92,7 @@ internal const val KEY_INPUT_SEND_MESSAGE_SECURITY_OPTIONS_SERIALIZED = "keySend internal const val KEY_OUTPUT_RESULT_SEND_MESSAGE_ERROR_ENUM = "keySendMessageErrorResult" private const val INPUT_MESSAGE_DB_ID_NOT_FOUND = -1L -private const val SEND_MESSAGE_MAX_RETRIES = 3 +private const val SEND_MESSAGE_MAX_RETRIES = 2 private const val NO_CONTACTS_AUTO_SAVE = 0 private const val SEND_MESSAGE_WORK_NAME_PREFIX = "sendMessageUniqueWorkName" private const val NO_SUBJECT = "" @@ -109,8 +112,12 @@ class SendMessageWorker @WorkerInject constructor( override suspend fun doWork(): Result { val messageDatabaseId = getInputMessageDatabaseId() - Timber.i("Send Message Worker executing with messageDatabaseId $messageDatabaseId") + val inputMessageId = getInputMessageId() + Timber.i( + "Send Message Worker executing with messageDatabaseId $messageDatabaseId - messageID $inputMessageId" + ) val message = messageDetailsRepository.findMessageByMessageDbId(messageDatabaseId) + ?: messageDetailsRepository.findMessageById(inputMessageId) if (message == null) { showSendMessageError(NO_SUBJECT) pendingActionsDao.deletePendingSendByDbId(messageDatabaseId) @@ -122,8 +129,7 @@ class SendMessageWorker @WorkerInject constructor( val previousSenderAddressId = requireNotNull(getInputPreviousSenderAddressId()) val username = requireNotNull(getInputCurrentUsername()) - val result = saveDraft(message, previousSenderAddressId) - return when (result) { + return when (val result = saveDraft(message, previousSenderAddressId)) { is SaveDraftResult.Success -> { val messageId = result.draftId Timber.i("Send Message Worker saved draft successfully for messageId $messageId") @@ -148,8 +154,10 @@ class SendMessageWorker @WorkerInject constructor( } return try { - val response = apiManager.sendMessage(messageId, requestBody, RetrofitTag(username)) - handleSendMessageResponse(messageId, response, savedDraftMessage) + withContext(NonCancellable) { + val response = apiManager.sendMessage(messageId, requestBody, RetrofitTag(username)) + handleSendMessageResponse(messageId, response, savedDraftMessage) + } } catch (exception: IOException) { retryOrFail(ErrorPerformingApiRequest, savedDraftMessage, exception) } catch (exception: Exception) { @@ -323,6 +331,9 @@ class SendMessageWorker @WorkerInject constructor( private fun getInputParentId() = inputData.getString(KEY_INPUT_SEND_MESSAGE_MSG_PARENT_ID) + private fun getInputMessageId() = + inputData.getString(KEY_INPUT_SEND_MESSAGE_MESSAGE_ID) ?: EMPTY_STRING + private fun getInputMessageDatabaseId() = inputData.getLong(KEY_INPUT_SEND_MESSAGE_MSG_DB_ID, INPUT_MESSAGE_DB_ID_NOT_FOUND) @@ -359,16 +370,15 @@ class SendMessageWorker @WorkerInject constructor( KEY_INPUT_SEND_MESSAGE_SECURITY_OPTIONS_SERIALIZED to securityOptions.serialize() ) ) - .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 2 * TEN_SECONDS, TimeUnit.SECONDS) + .setBackoffCriteria(BackoffPolicy.LINEAR, TEN_SECONDS, TimeUnit.SECONDS) .build() workManager.enqueueUniqueWork( - "${SEND_MESSAGE_WORK_NAME_PREFIX}-${requireNotNull(message.messageId)}", + "$SEND_MESSAGE_WORK_NAME_PREFIX-${requireNotNull(message.messageId)}", ExistingWorkPolicy.REPLACE, sendMessageRequest ) return workManager.getWorkInfoByIdLiveData(sendMessageRequest.id).asFlow() } } - } diff --git a/app/src/main/java/ch/protonmail/android/worker/drafts/CreateDraftWorker.kt b/app/src/main/java/ch/protonmail/android/worker/drafts/CreateDraftWorker.kt index bf224a8a2..d9dfd371a 100644 --- a/app/src/main/java/ch/protonmail/android/worker/drafts/CreateDraftWorker.kt +++ b/app/src/main/java/ch/protonmail/android/worker/drafts/CreateDraftWorker.kt @@ -77,7 +77,7 @@ internal const val KEY_OUTPUT_RESULT_SAVE_DRAFT_ERROR_ENUM = "keySaveDraftErrorR internal const val KEY_OUTPUT_RESULT_SAVE_DRAFT_MESSAGE_ID = "keySaveDraftSuccessResultDbId" private const val INPUT_MESSAGE_DB_ID_NOT_FOUND = -1L -private const val SAVE_DRAFT_MAX_RETRIES = 3 +private const val SAVE_DRAFT_MAX_RETRIES = 1 class CreateDraftWorker @WorkerInject constructor( @Assisted context: Context, @@ -336,7 +336,7 @@ class CreateDraftWorker @WorkerInject constructor( KEY_INPUT_SAVE_DRAFT_PREV_SENDER_ADDR_ID to previousSenderAddressId ) ) - .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 2 * TEN_SECONDS, TimeUnit.SECONDS) + .setBackoffCriteria(BackoffPolicy.LINEAR, TEN_SECONDS, TimeUnit.SECONDS) .build() val uniqueWorkId = "$SAVE_DRAFT_UNIQUE_WORK_ID_PREFIX-${message.messageId}" diff --git a/app/src/test/java/ch/protonmail/android/attachments/UploadAttachmentsTest.kt b/app/src/test/java/ch/protonmail/android/attachments/UploadAttachmentsTest.kt index fe51f039d..862e0d1f4 100644 --- a/app/src/test/java/ch/protonmail/android/attachments/UploadAttachmentsTest.kt +++ b/app/src/test/java/ch/protonmail/android/attachments/UploadAttachmentsTest.kt @@ -139,8 +139,8 @@ class UploadAttachmentsTest : CoroutinesTest { assertEquals(true, actualIsMessageSending) assertArrayEquals(attachmentIds.toTypedArray(), actualAttachmentIds) assertEquals(NetworkType.CONNECTED, constraints.requiredNetworkType) - assertEquals(BackoffPolicy.EXPONENTIAL, workSpec.backoffPolicy) - assertEquals(20000, workSpec.backoffDelayDuration) + assertEquals(BackoffPolicy.LINEAR, workSpec.backoffPolicy) + assertEquals(10000, workSpec.backoffDelayDuration) verify { workManager.getWorkInfoByIdLiveData(any()) } } } @@ -261,7 +261,7 @@ class UploadAttachmentsTest : CoroutinesTest { coEvery { attachmentsRepository.upload(attachment2, crypto) } answers { AttachmentsRepository.Result.Failure("Failed to upload attachment2") } - every { parameters.runAttemptCount } returns 2 + every { parameters.runAttemptCount } returns 0 val result = uploadAttachments.doWork() @@ -325,7 +325,7 @@ class UploadAttachmentsTest : CoroutinesTest { coEvery { attachmentsRepository.uploadPublicKey(message, crypto) } answers { AttachmentsRepository.Result.Failure("Failed to upload public key") } - every { parameters.runAttemptCount } returns 2 + every { parameters.runAttemptCount } returns 0 val result = uploadAttachments.doWork() diff --git a/app/src/test/java/ch/protonmail/android/compose/send/SendMessageWorkerTest.kt b/app/src/test/java/ch/protonmail/android/compose/send/SendMessageWorkerTest.kt index d26d051c9..a62b181ff 100644 --- a/app/src/test/java/ch/protonmail/android/compose/send/SendMessageWorkerTest.kt +++ b/app/src/test/java/ch/protonmail/android/compose/send/SendMessageWorkerTest.kt @@ -180,8 +180,8 @@ class SendMessageWorkerTest : CoroutinesTest { assertEquals(previousSenderAddressId, actualPreviousSenderAddress) assertEquals(securityOptions, actualMessageSecurityOptions?.deserialize(MessageSecurityOptions.serializer())) assertEquals(NetworkType.CONNECTED, constraints.requiredNetworkType) - assertEquals(BackoffPolicy.EXPONENTIAL, workSpec.backoffPolicy) - assertEquals(20000, workSpec.backoffDelayDuration) + assertEquals(BackoffPolicy.LINEAR, workSpec.backoffPolicy) + assertEquals(10000, workSpec.backoffDelayDuration) verify { workManager.getWorkInfoByIdLiveData(any()) } } } @@ -220,12 +220,33 @@ class SendMessageWorkerTest : CoroutinesTest { coVerify { saveDraft(expectedParameters) } } + @Test + fun workerTriesFindingTheMessageByMessageIdWhenMessageIsNotFoundByDatabaseId() = runBlockingTest { + val messageDbId = 23712L + val messageId = "8322224-1341" + val message = Message(messageId = messageId) + val createdDraftId = "createdDraftId" + givenFullValidInput(messageDbId, messageId) + coEvery { messageDetailsRepository.findMessageByMessageDbId(messageDbId) } returns null + coEvery { messageDetailsRepository.findMessageById(messageId) } returns message + coEvery { messageDetailsRepository.findMessageById(createdDraftId) } returns null + coEvery { saveDraft.invoke(any()) } returns SaveDraftResult.Success(createdDraftId) + + worker.doWork() + + verify { userNotifier wasNot Called } + val paramsSlot = slot() + coVerify { saveDraft.invoke(capture(paramsSlot)) } + assertEquals(message, paramsSlot.captured.message) + } + @Test fun workerNotifiesUserAndFailsWhenMessageIsNotFoundInTheDatabase() = runBlockingTest { val messageDbId = 2373L val messageId = "8322223" givenFullValidInput(messageDbId, messageId) coEvery { messageDetailsRepository.findMessageByMessageDbId(messageDbId) } returns null + coEvery { messageDetailsRepository.findMessageById(messageId) } returns null every { context.getString(R.string.message_drafted) } returns "error message 9214" val result = worker.doWork() @@ -685,7 +706,7 @@ class SendMessageWorkerTest : CoroutinesTest { coEvery { saveDraft(any()) } returns SaveDraftResult.Success(savedDraftMessageId) every { sendPreferencesFactory.fetch(any()) } returns mapOf() every { packageFactory.generatePackages(any(), any(), any(), any()) } throws exception - every { parameters.runAttemptCount } returns 2 + every { parameters.runAttemptCount } returns 1 mockkStatic(Timber::class) val result = worker.doWork() @@ -1027,3 +1048,4 @@ class SendMessageWorkerTest : CoroutinesTest { } } } + diff --git a/app/src/test/java/ch/protonmail/android/worker/CreateDraftWorkerTest.kt b/app/src/test/java/ch/protonmail/android/worker/CreateDraftWorkerTest.kt index 80775b20f..5989b084e 100644 --- a/app/src/test/java/ch/protonmail/android/worker/CreateDraftWorkerTest.kt +++ b/app/src/test/java/ch/protonmail/android/worker/CreateDraftWorkerTest.kt @@ -174,8 +174,8 @@ class CreateDraftWorkerTest : CoroutinesTest { assertEquals(messageActionType.messageActionTypeValue, actualMessageActionType) assertEquals(previousSenderAddressId, actualPreviousSenderAddress) assertEquals(NetworkType.CONNECTED, constraints.requiredNetworkType) - assertEquals(BackoffPolicy.EXPONENTIAL, workSpec.backoffPolicy) - assertEquals(20000, workSpec.backoffDelayDuration) + assertEquals(BackoffPolicy.LINEAR, workSpec.backoffPolicy) + assertEquals(10000, workSpec.backoffDelayDuration) verify { workManager.getWorkInfoByIdLiveData(any()) } } } @@ -954,7 +954,7 @@ class CreateDraftWorkerTest : CoroutinesTest { every { this@mockk.message.subject } returns "Subject001" } coEvery { apiManager.createDraft(any()) } throws IOException(errorMessage) - every { parameters.runAttemptCount } returns 2 + every { parameters.runAttemptCount } returns 0 val attachment = Attachment("attachment", keyPackets = "OriginalAttachmentPackets", inline = true) val parentMessage = mockk { coEvery { this@mockk.Attachments } returns listOf(attachment)