From d989c61bc24f4e1c33f17bc1b975551d59e87ccb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bispo?= Date: Mon, 14 Apr 2025 21:50:59 +0100 Subject: [PATCH] [PM-19613] Save attachment error message update (#5013) --- .../network/model/InvalidJsonResponse.kt | 3 + .../network/service/CiphersService.kt | 2 +- .../network/service/CiphersServiceImpl.kt | 22 +++-- .../data/vault/manager/CipherManagerImpl.kt | 34 ++++++-- .../model/CreateAttachmentResult.kt | 5 +- .../attachments/AttachmentsViewModel.kt | 3 +- .../network/service/CiphersServiceTest.kt | 46 ++++++++--- .../data/vault/manager/CipherManagerTest.kt | 21 +++-- .../attachments/AttachmentsViewModelTest.kt | 81 ++++++++++++++++++- .../com/bitwarden/network/api/CiphersApi.kt | 2 +- .../network/model/AttachmentJsonResponse.kt | 49 ++++++++--- .../network/model/InvalidJsonResponse.kt | 28 +++++++ .../model/AttachmentJsonResponseUtil.kt | 16 +++- 13 files changed, 264 insertions(+), 48 deletions(-) create mode 100644 network/src/main/kotlin/com/bitwarden/network/model/InvalidJsonResponse.kt diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/InvalidJsonResponse.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/InvalidJsonResponse.kt index 61451923e0..9de8167427 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/InvalidJsonResponse.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/InvalidJsonResponse.kt @@ -1,5 +1,8 @@ package com.x8bit.bitwarden.data.vault.datasource.network.model +// TODO: Remove this file once all models have been moved to the network module +// This class has already been moved to the network module + /** * Represents the json body of an invalid send json request. */ diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/service/CiphersService.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/service/CiphersService.kt index e12b46b347..b4a0b5bf84 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/service/CiphersService.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/service/CiphersService.kt @@ -34,7 +34,7 @@ interface CiphersService { * Attempt to upload an attachment file. */ suspend fun uploadAttachment( - attachmentJsonResponse: AttachmentJsonResponse, + attachment: AttachmentJsonResponse.Success, encryptedFile: File, ): Result diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/service/CiphersServiceImpl.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/service/CiphersServiceImpl.kt index 928580c068..163d4a2aa4 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/service/CiphersServiceImpl.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/service/CiphersServiceImpl.kt @@ -58,23 +58,31 @@ class CiphersServiceImpl( body = body, ) .toResult() + .recoverCatching { throwable -> + throwable.toBitwardenError() + .parseErrorBodyOrNull( + code = NetworkErrorCode.BAD_REQUEST, + json = json, + ) + ?: throw throwable + } override suspend fun uploadAttachment( - attachmentJsonResponse: AttachmentJsonResponse, + attachment: AttachmentJsonResponse.Success, encryptedFile: File, ): Result { - val cipher = attachmentJsonResponse.cipherResponse - return when (attachmentJsonResponse.fileUploadType) { + val cipher = attachment.cipherResponse + return when (attachment.fileUploadType) { FileUploadType.DIRECT -> { ciphersApi.uploadAttachment( cipherId = requireNotNull(cipher.id), - attachmentId = attachmentJsonResponse.attachmentId, + attachmentId = attachment.attachmentId, body = this .createMultipartBodyBuilder( encryptedFile = encryptedFile, filename = cipher .attachments - ?.find { it.id == attachmentJsonResponse.attachmentId } + ?.find { it.id == attachment.attachmentId } ?.fileName, ) .build(), @@ -83,11 +91,11 @@ class CiphersServiceImpl( FileUploadType.AZURE -> { azureApi.uploadAzureBlob( - url = attachmentJsonResponse.url, + url = attachment.url, date = DateTimeFormatter .RFC_1123_DATE_TIME .format(ZonedDateTime.ofInstant(clock.instant(), ZoneOffset.UTC)), - version = attachmentJsonResponse.url.toUri().getQueryParameter("sv"), + version = attachment.url.toUri().getQueryParameter("sv"), body = encryptedFile.asRequestBody(), ) } diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/manager/CipherManagerImpl.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/manager/CipherManagerImpl.kt index 8d9b49437c..abbeeec93d 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/vault/manager/CipherManagerImpl.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/manager/CipherManagerImpl.kt @@ -5,6 +5,7 @@ import androidx.core.net.toUri import com.bitwarden.core.data.util.asFailure import com.bitwarden.core.data.util.asSuccess import com.bitwarden.core.data.util.flatMap +import com.bitwarden.network.model.AttachmentJsonResponse import com.bitwarden.network.model.CreateCipherInOrganizationJsonRequest import com.bitwarden.network.model.ShareCipherJsonRequest import com.bitwarden.network.model.UpdateCipherCollectionsJsonRequest @@ -327,7 +328,15 @@ class CipherManagerImpl( fileUri = fileUri, ) .fold( - onFailure = { CreateAttachmentResult.Error(error = it) }, + onFailure = { + CreateAttachmentResult.Error( + error = it, + message = when (it) { + is IllegalStateException -> it.message + else -> null + }, + ) + }, onSuccess = { CreateAttachmentResult.Success(cipherView = it) }, ) @@ -371,11 +380,22 @@ class CipherManagerImpl( cipherId = cipherId, body = attachment.toNetworkAttachmentRequest(), ) - .flatMap { attachmentJsonResponse -> - val encryptedFile = File("${cacheFile.absolutePath}.enc") + } + .flatMap { attachmentResponse -> + when (attachmentResponse) { + is AttachmentJsonResponse.Invalid -> { + return IllegalStateException( + attachmentResponse.message, + ).asFailure() + } + + is AttachmentJsonResponse.Success -> { + val encryptedFile = File( + "${cacheFile.absolutePath}.enc", + ) ciphersService .uploadAttachment( - attachmentJsonResponse = attachmentJsonResponse, + attachment = attachmentResponse, encryptedFile = encryptedFile, ) .onSuccess { @@ -385,6 +405,7 @@ class CipherManagerImpl( fileManager.delete(cacheFile, encryptedFile) } } + } } } } @@ -488,7 +509,10 @@ class CipherManagerImpl( .flatMap { response -> when (response) { is UpdateCipherResponseJson.Invalid -> { - IllegalStateException(response.message).asFailure() + IllegalStateException( + response.message, + ) + .asFailure() } is UpdateCipherResponseJson.Success -> { diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/CreateAttachmentResult.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/CreateAttachmentResult.kt index 0db1654fac..c27bcb8eb6 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/CreateAttachmentResult.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/model/CreateAttachmentResult.kt @@ -17,5 +17,8 @@ sealed class CreateAttachmentResult { /** * Generic error while creating an attachment. */ - data class Error(val error: Throwable) : CreateAttachmentResult() + data class Error( + val error: Throwable, + val message: String? = null, + ) : CreateAttachmentResult() } diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/attachments/AttachmentsViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/attachments/AttachmentsViewModel.kt index 50a05260a3..6f92aa2afb 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/attachments/AttachmentsViewModel.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/attachments/AttachmentsViewModel.kt @@ -271,7 +271,8 @@ class AttachmentsViewModel @Inject constructor( it.copy( dialogState = AttachmentsState.DialogState.Error( title = R.string.an_error_has_occurred.asText(), - message = R.string.generic_error_message.asText(), + message = result.message?.asText() + ?: R.string.generic_error_message.asText(), throwable = result.error, ), ) diff --git a/app/src/test/java/com/x8bit/bitwarden/data/vault/datasource/network/service/CiphersServiceTest.kt b/app/src/test/java/com/x8bit/bitwarden/data/vault/datasource/network/service/CiphersServiceTest.kt index 0527ed50d2..0cc2dc15ea 100644 --- a/app/src/test/java/com/x8bit/bitwarden/data/vault/datasource/network/service/CiphersServiceTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/data/vault/datasource/network/service/CiphersServiceTest.kt @@ -4,6 +4,7 @@ import android.net.Uri import com.bitwarden.network.api.AzureApi import com.bitwarden.network.api.CiphersApi import com.bitwarden.network.base.BaseServiceTest +import com.bitwarden.network.model.AttachmentJsonResponse import com.bitwarden.network.model.CreateCipherInOrganizationJsonRequest import com.bitwarden.network.model.FileUploadType import com.bitwarden.network.model.ImportCiphersJsonRequest @@ -12,6 +13,7 @@ import com.bitwarden.network.model.UpdateCipherCollectionsJsonRequest import com.bitwarden.network.model.createMockAttachment import com.bitwarden.network.model.createMockAttachmentJsonRequest import com.bitwarden.network.model.createMockAttachmentJsonResponse +import com.bitwarden.network.model.createMockAttachmentResponse import com.bitwarden.network.model.createMockCipher import com.bitwarden.network.model.createMockCipherJsonRequest import com.x8bit.bitwarden.data.vault.datasource.network.model.ImportCiphersResponseJson @@ -99,19 +101,37 @@ class CiphersServiceTest : BaseServiceTest() { ) } + @Test + fun `createAttachment with invalid response should return an Invalid with the correct data`() = + runTest { + server.enqueue( + MockResponse().setResponseCode(400).setBody(CREATE_ATTACHMENT_INVALID_JSON), + ) + val result = ciphersService.createAttachment( + cipherId = "mockId-1", + body = createMockAttachmentJsonRequest(number = 1), + ) + assertEquals( + AttachmentJsonResponse.Invalid( + message = "You do not have permission.", + validationErrors = null, + ), + result.getOrThrow(), + ) + } + @Test fun `uploadAttachment with Azure uploadFile success should return cipher`() = runTest { setupMockUri(url = "mockUrl-1", queryParams = mapOf("sv" to "2024-04-03")) val mockCipher = createMockCipher(number = 1) - val attachmentJsonResponse = createMockAttachmentJsonResponse( - number = 1, - fileUploadType = FileUploadType.AZURE, - ) val encryptedFile = File.createTempFile("mockFile", "temp") server.enqueue(MockResponse().setResponseCode(201)) val result = ciphersService.uploadAttachment( - attachmentJsonResponse = attachmentJsonResponse, + attachment = createMockAttachmentResponse( + number = 1, + fileUploadType = FileUploadType.AZURE, + ), encryptedFile = encryptedFile, ) @@ -121,15 +141,14 @@ class CiphersServiceTest : BaseServiceTest() { @Test fun `uploadAttachment with Direct uploadFile success should return cipher`() = runTest { val mockCipher = createMockCipher(number = 1) - val attachmentJsonResponse = createMockAttachmentJsonResponse( - number = 1, - fileUploadType = FileUploadType.DIRECT, - ) val encryptedFile = File.createTempFile("mockFile", "temp") server.enqueue(MockResponse().setResponseCode(201)) val result = ciphersService.uploadAttachment( - attachmentJsonResponse = attachmentJsonResponse, + attachment = createMockAttachmentResponse( + number = 1, + fileUploadType = FileUploadType.DIRECT, + ), encryptedFile = encryptedFile, ) @@ -484,6 +503,13 @@ private const val CREATE_ATTACHMENT_SUCCESS_JSON = """ } """ +private const val CREATE_ATTACHMENT_INVALID_JSON = """ +{ + "message": "You do not have permission.", + "validationErrors": null +} +""" + private const val CREATE_RESTORE_UPDATE_CIPHER_SUCCESS_JSON = """ { "notes": "mockNotes-1", diff --git a/app/src/test/java/com/x8bit/bitwarden/data/vault/manager/CipherManagerTest.kt b/app/src/test/java/com/x8bit/bitwarden/data/vault/manager/CipherManagerTest.kt index bc7cd41a89..7cd00779a2 100644 --- a/app/src/test/java/com/x8bit/bitwarden/data/vault/manager/CipherManagerTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/data/vault/manager/CipherManagerTest.kt @@ -11,6 +11,7 @@ import com.bitwarden.network.model.SyncResponseJson import com.bitwarden.network.model.UpdateCipherCollectionsJsonRequest import com.bitwarden.network.model.createMockAttachment import com.bitwarden.network.model.createMockAttachmentJsonResponse +import com.bitwarden.network.model.createMockAttachmentResponse import com.bitwarden.network.model.createMockCipher import com.bitwarden.network.model.createMockCipherJsonRequest import com.bitwarden.vault.Attachment @@ -896,7 +897,7 @@ class CipherManagerTest { } returns mockAttachmentJsonResponse.asSuccess() coEvery { ciphersService.uploadAttachment( - attachmentJsonResponse = mockAttachmentJsonResponse, + attachment = createMockAttachmentResponse(number = 1), encryptedFile = File("${cacheFile.absolutePath}.enc"), ) } returns mockNetworkCipher.asSuccess() @@ -1174,7 +1175,13 @@ class CipherManagerTest { fileUri = mockk(), ) - assertEquals(CreateAttachmentResult.Error(NoActiveUserException()), result) + assertEquals( + CreateAttachmentResult.Error( + error = NoActiveUserException(), + message = "No current active user!", + ), + result, + ) } @Suppress("MaxLineLength") @@ -1389,7 +1396,7 @@ class CipherManagerTest { } returns mockAttachmentJsonResponse.asSuccess() coEvery { ciphersService.uploadAttachment( - attachmentJsonResponse = mockAttachmentJsonResponse, + attachment = createMockAttachmentResponse(number = 1), encryptedFile = File("${mockFile.absoluteFile}.enc"), ) } returns error.asFailure() @@ -1458,7 +1465,7 @@ class CipherManagerTest { } returns mockAttachmentJsonResponse.asSuccess() coEvery { ciphersService.uploadAttachment( - attachmentJsonResponse = mockAttachmentJsonResponse, + attachment = createMockAttachmentResponse(number = 1), encryptedFile = File("${mockFile.absoluteFile}.enc"), ) } returns mockCipherResponse.asSuccess() @@ -1535,7 +1542,7 @@ class CipherManagerTest { } returns mockAttachmentJsonResponse.asSuccess() coEvery { ciphersService.uploadAttachment( - attachmentJsonResponse = mockAttachmentJsonResponse, + attachment = createMockAttachmentResponse(number = 1), encryptedFile = File("${mockFile.absolutePath}.enc"), ) } returns mockCipherResponse.asSuccess() @@ -1610,7 +1617,7 @@ class CipherManagerTest { } returns mockAttachmentJsonResponse.asSuccess() coEvery { ciphersService.uploadAttachment( - attachmentJsonResponse = mockAttachmentJsonResponse, + attachment = createMockAttachmentResponse(number = 1), encryptedFile = File("${mockFile.absolutePath}.enc"), ) } returns mockCipherResponse.asSuccess() @@ -1683,7 +1690,7 @@ class CipherManagerTest { } returns mockAttachmentJsonResponse.asSuccess() coEvery { ciphersService.uploadAttachment( - attachmentJsonResponse = mockAttachmentJsonResponse, + attachment = createMockAttachmentResponse(number = 1), encryptedFile = File("${mockFile.absolutePath}.enc"), ) } returns Throwable("Fail").asFailure() diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/attachments/AttachmentsViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/attachments/AttachmentsViewModelTest.kt index 1b594b6bf0..00df890441 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/attachments/AttachmentsViewModelTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/attachments/AttachmentsViewModelTest.kt @@ -4,6 +4,8 @@ import android.net.Uri import androidx.lifecycle.SavedStateHandle import app.cash.turbine.test import com.bitwarden.core.data.repository.model.DataState +import com.bitwarden.ui.util.asText +import com.bitwarden.ui.util.concat import com.bitwarden.vault.CipherView import com.x8bit.bitwarden.R import com.x8bit.bitwarden.data.auth.datasource.disk.model.OnboardingStatus @@ -17,8 +19,6 @@ import com.x8bit.bitwarden.data.vault.repository.VaultRepository import com.x8bit.bitwarden.data.vault.repository.model.CreateAttachmentResult import com.x8bit.bitwarden.data.vault.repository.model.DeleteAttachmentResult import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest -import com.bitwarden.ui.util.asText -import com.bitwarden.ui.util.concat import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager import com.x8bit.bitwarden.ui.vault.feature.attachments.util.toViewState import io.mockk.coEvery @@ -204,7 +204,82 @@ class AttachmentsViewModelTest : BaseViewModelTest() { ) mutableVaultItemStateFlow.value = DataState.Loaded(cipherView) mutableUserStateFlow.value = DEFAULT_USER_STATE - val error = NoActiveUserException() + val error = IllegalStateException("No permissions.") + coEvery { + vaultRepository.createAttachment( + cipherId = state.cipherId, + cipherView = cipherView, + fileSizeBytes = sizeJustRight.toString(), + fileName = fileName, + fileUri = uri, + ) + } returns CreateAttachmentResult.Error( + error = error, + message = "No permissions.", + ) + + val viewModel = createViewModel() + // Need to populate the VM with a file + viewModel.trySendAction(AttachmentsAction.FileChoose(fileData)) + + viewModel.stateFlow.test { + assertEquals(state, awaitItem()) + viewModel.trySendAction(AttachmentsAction.SaveClick) + assertEquals( + state.copy( + dialogState = AttachmentsState.DialogState.Loading( + message = R.string.saving.asText(), + ), + ), + awaitItem(), + ) + assertEquals( + state.copy( + dialogState = AttachmentsState.DialogState.Error( + title = R.string.an_error_has_occurred.asText(), + message = error.message!!.asText(), + throwable = error, + ), + ), + awaitItem(), + ) + } + coVerify(exactly = 1) { + vaultRepository.createAttachment( + cipherId = state.cipherId, + cipherView = cipherView, + fileSizeBytes = sizeJustRight.toString(), + fileName = fileName, + fileUri = uri, + ) + } + } + + @Test + fun `SaveClick should display generic error message dialog when createAttachment fails`() = + runTest { + val cipherView = createMockCipherView(number = 1) + val fileName = "test.png" + val uri = mockk() + val sizeJustRight = 104_857_600L + val state = DEFAULT_STATE.copy( + viewState = DEFAULT_CONTENT_WITH_ATTACHMENTS.copy( + newAttachment = AttachmentsState.NewAttachment( + displayName = fileName, + uri = uri, + sizeBytes = sizeJustRight, + ), + ), + isPremiumUser = true, + ) + val fileData = IntentManager.FileData( + fileName = fileName, + uri = uri, + sizeBytes = sizeJustRight, + ) + mutableVaultItemStateFlow.value = DataState.Loaded(cipherView) + mutableUserStateFlow.value = DEFAULT_USER_STATE + val error = Exception() coEvery { vaultRepository.createAttachment( cipherId = state.cipherId, diff --git a/network/src/main/kotlin/com/bitwarden/network/api/CiphersApi.kt b/network/src/main/kotlin/com/bitwarden/network/api/CiphersApi.kt index 4eed35314b..ef17b87b9c 100644 --- a/network/src/main/kotlin/com/bitwarden/network/api/CiphersApi.kt +++ b/network/src/main/kotlin/com/bitwarden/network/api/CiphersApi.kt @@ -45,7 +45,7 @@ interface CiphersApi { suspend fun createAttachment( @Path("cipherId") cipherId: String, @Body body: AttachmentJsonRequest, - ): NetworkResult + ): NetworkResult /** * Uploads the attachment associated with a cipher. diff --git a/network/src/main/kotlin/com/bitwarden/network/model/AttachmentJsonResponse.kt b/network/src/main/kotlin/com/bitwarden/network/model/AttachmentJsonResponse.kt index 5ae426a0b3..c860b5f3d0 100644 --- a/network/src/main/kotlin/com/bitwarden/network/model/AttachmentJsonResponse.kt +++ b/network/src/main/kotlin/com/bitwarden/network/model/AttachmentJsonResponse.kt @@ -6,17 +6,44 @@ import kotlinx.serialization.Serializable /** * Represents the JSON response from creating a new attachment. */ -@Serializable -data class AttachmentJsonResponse( - @SerialName("attachmentId") - val attachmentId: String, +sealed class AttachmentJsonResponse { + /** + * Represents a successful response from create attachment request. + * + * @property attachmentId The ID of the attachment. + * @property url The URL of the attachment. + * @property fileUploadType The type of file upload. + * @property cipherResponse The cipher response associated with the attachment. + */ + @Serializable + data class Success( + @SerialName("attachmentId") + val attachmentId: String, - @SerialName("url") - val url: String, + @SerialName("url") + val url: String, - @SerialName("fileUploadType") - val fileUploadType: FileUploadType, + @SerialName("fileUploadType") + val fileUploadType: FileUploadType, - @SerialName("cipherResponse") - val cipherResponse: SyncResponseJson.Cipher, -) + @SerialName("cipherResponse") + val cipherResponse: SyncResponseJson.Cipher, + ) : AttachmentJsonResponse() + + /** + * Represents the json body of an invalid create request. + * + * @property message A general, user-displayable error message. + * @property validationErrors a map where each value is a list of error messages for each + * key. The values in the array should be used for display to the user, since the keys tend + * to come back as nonsense. (eg: empty string key) + */ + @Serializable + data class Invalid( + @SerialName("message") + override val message: String, + + @SerialName("validationErrors") + override val validationErrors: Map>?, + ) : AttachmentJsonResponse(), InvalidJsonResponse +} diff --git a/network/src/main/kotlin/com/bitwarden/network/model/InvalidJsonResponse.kt b/network/src/main/kotlin/com/bitwarden/network/model/InvalidJsonResponse.kt new file mode 100644 index 0000000000..25d31bc7ab --- /dev/null +++ b/network/src/main/kotlin/com/bitwarden/network/model/InvalidJsonResponse.kt @@ -0,0 +1,28 @@ +package com.bitwarden.network.model + +/** + * Represents the json body of an invalid send json request. + */ +sealed interface InvalidJsonResponse { + + /** + * A general, user-displayable error message. + */ + val message: String + + /** + * a map where each value is a list of error messages for each key. + * The values in the array should be used for display to the user, since the keys tend to come + * back as nonsense. (eg: empty string key) + */ + val validationErrors: Map>? + + /** + * Returns the first error message found in [validationErrors], or [message] if there are no + * [validationErrors] present. + */ + val firstValidationErrorMessage: String? + get() = validationErrors + ?.flatMap { it.value } + ?.first() +} diff --git a/network/src/testFixtures/kotlin/com/bitwarden/network/model/AttachmentJsonResponseUtil.kt b/network/src/testFixtures/kotlin/com/bitwarden/network/model/AttachmentJsonResponseUtil.kt index 426b552cda..d1e908449b 100644 --- a/network/src/testFixtures/kotlin/com/bitwarden/network/model/AttachmentJsonResponseUtil.kt +++ b/network/src/testFixtures/kotlin/com/bitwarden/network/model/AttachmentJsonResponseUtil.kt @@ -7,7 +7,21 @@ fun createMockAttachmentJsonResponse( number: Int, fileUploadType: FileUploadType = FileUploadType.AZURE, ): AttachmentJsonResponse = - AttachmentJsonResponse( + AttachmentJsonResponse.Success( + attachmentId = "mockAttachmentId-$number", + url = "mockUrl-$number", + fileUploadType = fileUploadType, + cipherResponse = createMockCipher(number = number), + ) + +/** + * Create a mock [AttachmentJsonResponse.Success] with a given [number]. + */ +fun createMockAttachmentResponse( + number: Int, + fileUploadType: FileUploadType = FileUploadType.AZURE, +): AttachmentJsonResponse.Success = + AttachmentJsonResponse.Success( attachmentId = "mockAttachmentId-$number", url = "mockUrl-$number", fileUploadType = fileUploadType,