mirror of
https://github.com/bitwarden/android.git
synced 2026-10-22 02:53:19 -05:00
PM-30774: Add archiving and unarchiving network requests (#6356)
This commit is contained in:
1 parent
6d72d3a1c9
commit
a9b1623f8b
9 files changed
+463
-1
No files matched your search
@@ -3,6 +3,7 @@ package com.x8bit.bitwarden.data.vault.manager
|
||||
import android.net.Uri
|
||||
import com.bitwarden.vault.CipherView
|
||||
import com.x8bit.bitwarden.data.vault.manager.model.GetCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.ArchiveCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.CreateAttachmentResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.CreateCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.DeleteAttachmentResult
|
||||
@@ -10,6 +11,7 @@ import com.x8bit.bitwarden.data.vault.repository.model.DeleteCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.DownloadAttachmentResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.RestoreCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.ShareCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.UnarchiveCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.UpdateCipherResult
|
||||
|
||||
/**
|
||||
@@ -57,6 +59,22 @@ interface CipherManager {
|
||||
*/
|
||||
suspend fun getCipher(cipherId: String): GetCipherResult
|
||||
|
||||
/**
|
||||
* Attempt to archive a cipher.
|
||||
*/
|
||||
suspend fun archiveCipher(
|
||||
cipherId: String,
|
||||
cipherView: CipherView,
|
||||
): ArchiveCipherResult
|
||||
|
||||
/**
|
||||
* Attempt to unarchive a cipher.
|
||||
*/
|
||||
suspend fun unarchiveCipher(
|
||||
cipherId: String,
|
||||
cipherView: CipherView,
|
||||
): UnarchiveCipherResult
|
||||
|
||||
/**
|
||||
* Attempt to delete a cipher.
|
||||
*/
|
||||
|
||||
@@ -28,6 +28,7 @@ import com.x8bit.bitwarden.data.platform.manager.model.SyncCipherUpsertData
|
||||
import com.x8bit.bitwarden.data.vault.datasource.disk.VaultDiskSource
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.VaultSdkSource
|
||||
import com.x8bit.bitwarden.data.vault.manager.model.GetCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.ArchiveCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.CreateAttachmentResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.CreateCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.DeleteAttachmentResult
|
||||
@@ -35,6 +36,7 @@ import com.x8bit.bitwarden.data.vault.repository.model.DeleteCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.DownloadAttachmentResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.RestoreCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.ShareCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.UnarchiveCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.UpdateCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.util.toEncryptedNetworkCipher
|
||||
import com.x8bit.bitwarden.data.vault.repository.util.toEncryptedNetworkCipherResponse
|
||||
@@ -161,6 +163,76 @@ class CipherManagerImpl(
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun archiveCipher(
|
||||
cipherId: String,
|
||||
cipherView: CipherView,
|
||||
): ArchiveCipherResult {
|
||||
val userId = activeUserId ?: return ArchiveCipherResult.Error(NoActiveUserException())
|
||||
return cipherView
|
||||
.encryptCipherAndCheckForMigration(userId = userId, cipherId = cipherId)
|
||||
.flatMap { encryptionContext ->
|
||||
ciphersService
|
||||
.archiveCipher(cipherId = cipherId)
|
||||
.flatMap {
|
||||
vaultSdkSource.decryptCipher(
|
||||
userId = userId,
|
||||
cipher = encryptionContext.cipher,
|
||||
)
|
||||
}
|
||||
}
|
||||
.flatMap {
|
||||
vaultSdkSource.encryptCipher(
|
||||
userId = userId,
|
||||
cipherView = it.copy(archivedDate = clock.instant()),
|
||||
)
|
||||
}
|
||||
.onSuccess {
|
||||
vaultDiskSource.saveCipher(
|
||||
userId = userId,
|
||||
cipher = it.toEncryptedNetworkCipherResponse(),
|
||||
)
|
||||
}
|
||||
.fold(
|
||||
onSuccess = { ArchiveCipherResult.Success },
|
||||
onFailure = { ArchiveCipherResult.Error(error = it) },
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun unarchiveCipher(
|
||||
cipherId: String,
|
||||
cipherView: CipherView,
|
||||
): UnarchiveCipherResult {
|
||||
val userId = activeUserId ?: return UnarchiveCipherResult.Error(NoActiveUserException())
|
||||
return cipherView
|
||||
.encryptCipherAndCheckForMigration(userId = userId, cipherId = cipherId)
|
||||
.flatMap { encryptionContext ->
|
||||
ciphersService
|
||||
.unarchiveCipher(cipherId = cipherId)
|
||||
.flatMap {
|
||||
vaultSdkSource.decryptCipher(
|
||||
userId = userId,
|
||||
cipher = encryptionContext.cipher,
|
||||
)
|
||||
}
|
||||
}
|
||||
.flatMap {
|
||||
vaultSdkSource.encryptCipher(
|
||||
userId = userId,
|
||||
cipherView = it.copy(archivedDate = null),
|
||||
)
|
||||
}
|
||||
.onSuccess {
|
||||
vaultDiskSource.saveCipher(
|
||||
userId = userId,
|
||||
cipher = it.toEncryptedNetworkCipherResponse(),
|
||||
)
|
||||
}
|
||||
.fold(
|
||||
onSuccess = { UnarchiveCipherResult.Success },
|
||||
onFailure = { UnarchiveCipherResult.Error(error = it) },
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun hardDeleteCipher(cipherId: String): DeleteCipherResult {
|
||||
val userId = activeUserId
|
||||
?: return DeleteCipherResult.Error(error = NoActiveUserException())
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.x8bit.bitwarden.data.vault.repository.model
|
||||
|
||||
/**
|
||||
* Models result of archiving a cipher.
|
||||
*/
|
||||
sealed class ArchiveCipherResult {
|
||||
|
||||
/**
|
||||
* Cipher archived successfully.
|
||||
*/
|
||||
data object Success : ArchiveCipherResult()
|
||||
|
||||
/**
|
||||
* Generic error while archiving a cipher.
|
||||
*/
|
||||
data class Error(val error: Throwable) : ArchiveCipherResult()
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.x8bit.bitwarden.data.vault.repository.model
|
||||
|
||||
/**
|
||||
* Models result of unarchiving a cipher.
|
||||
*/
|
||||
sealed class UnarchiveCipherResult {
|
||||
|
||||
/**
|
||||
* Cipher unarchived successfully.
|
||||
*/
|
||||
data object Success : UnarchiveCipherResult()
|
||||
|
||||
/**
|
||||
* Generic error while unarchiving a cipher.
|
||||
*/
|
||||
data class Error(val error: Throwable) : UnarchiveCipherResult()
|
||||
}
|
||||
@@ -45,6 +45,7 @@ import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockEncryptionC
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockSdkAttachment
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockSdkCipher
|
||||
import com.x8bit.bitwarden.data.vault.manager.model.GetCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.ArchiveCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.CreateAttachmentResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.CreateCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.DeleteAttachmentResult
|
||||
@@ -52,6 +53,7 @@ import com.x8bit.bitwarden.data.vault.repository.model.DeleteCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.DownloadAttachmentResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.RestoreCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.ShareCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.UnarchiveCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.UpdateCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.util.toEncryptedNetworkCipher
|
||||
import com.x8bit.bitwarden.data.vault.repository.util.toEncryptedNetworkCipherResponse
|
||||
@@ -693,6 +695,289 @@ class CipherManagerTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `archiveCipher with no active user should return ArchiveCipherResult Error`() = runTest {
|
||||
fakeAuthDiskSource.userState = null
|
||||
|
||||
val result = cipherManager.archiveCipher(
|
||||
cipherId = "cipherId",
|
||||
cipherView = mockk(),
|
||||
)
|
||||
|
||||
assertEquals(ArchiveCipherResult.Error(error = NoActiveUserException()), result)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `archiveCipher with ciphersService archiveCipher failure should return ArchiveCipherResult Error`() =
|
||||
runTest {
|
||||
fakeAuthDiskSource.userState = MOCK_USER_STATE
|
||||
val userId = MOCK_USER_STATE.activeUserId
|
||||
val cipherId = "mockId-1"
|
||||
val cipherView = createMockCipherView(number = 1)
|
||||
val encryptionContext = createMockEncryptionContext(number = 1)
|
||||
val error = Throwable("Fail")
|
||||
coEvery {
|
||||
vaultSdkSource.encryptCipher(userId = userId, cipherView = cipherView)
|
||||
} returns encryptionContext.asSuccess()
|
||||
coEvery {
|
||||
ciphersService.archiveCipher(cipherId = cipherId)
|
||||
} returns error.asFailure()
|
||||
|
||||
val result = cipherManager.archiveCipher(
|
||||
cipherId = cipherId,
|
||||
cipherView = cipherView,
|
||||
)
|
||||
|
||||
assertEquals(ArchiveCipherResult.Error(error = error), result)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `archiveCipher with ciphersService archiveCipher success should return ArchiveCipherResult success`() =
|
||||
runTest {
|
||||
val fixedInstant = Instant.parse("2023-10-27T12:00:00Z")
|
||||
val userId = "mockId-1"
|
||||
val cipherId = "mockId-1"
|
||||
val encryptionContext = createMockEncryptionContext(
|
||||
number = 1,
|
||||
cipher = createMockSdkCipher(number = 1, clock = clock),
|
||||
)
|
||||
val cipherView = createMockCipherView(number = 1)
|
||||
coEvery {
|
||||
vaultSdkSource.encryptCipher(userId = userId, cipherView = cipherView)
|
||||
} returns encryptionContext.asSuccess()
|
||||
coEvery {
|
||||
vaultSdkSource.encryptCipher(
|
||||
userId = userId,
|
||||
cipherView = cipherView.copy(archivedDate = fixedInstant),
|
||||
)
|
||||
} returns encryptionContext.asSuccess()
|
||||
coEvery {
|
||||
vaultSdkSource.decryptCipher(userId = userId, cipher = encryptionContext.cipher)
|
||||
} returns cipherView.asSuccess()
|
||||
fakeAuthDiskSource.userState = MOCK_USER_STATE
|
||||
coEvery { ciphersService.archiveCipher(cipherId = cipherId) } returns Unit.asSuccess()
|
||||
coEvery {
|
||||
vaultDiskSource.saveCipher(
|
||||
userId = userId,
|
||||
cipher = encryptionContext.toEncryptedNetworkCipherResponse(),
|
||||
)
|
||||
} just runs
|
||||
|
||||
val result = cipherManager.archiveCipher(
|
||||
cipherId = cipherId,
|
||||
cipherView = cipherView,
|
||||
)
|
||||
|
||||
assertEquals(ArchiveCipherResult.Success, result)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `archiveCipher with cipher migration success should return ArchiveCipherResult success`() =
|
||||
runTest {
|
||||
val fixedInstant = Instant.parse("2023-10-27T12:00:00Z")
|
||||
val userId = "mockId-1"
|
||||
val cipherId = "mockId-1"
|
||||
val encryptionContext = createMockEncryptionContext(
|
||||
number = 1,
|
||||
cipher = createMockSdkCipher(number = 1, clock = clock),
|
||||
)
|
||||
val cipherView = createMockCipherView(number = 1).copy(key = null)
|
||||
val networkCipher = createMockCipher(number = 1).copy(key = null)
|
||||
coEvery {
|
||||
vaultSdkSource.encryptCipher(userId = userId, cipherView = cipherView)
|
||||
} returns encryptionContext.asSuccess()
|
||||
coEvery {
|
||||
ciphersService.updateCipher(
|
||||
cipherId = cipherId,
|
||||
body = encryptionContext.toEncryptedNetworkCipher(),
|
||||
)
|
||||
} returns UpdateCipherResponseJson.Success(networkCipher).asSuccess()
|
||||
coEvery {
|
||||
vaultDiskSource.saveCipher(userId = userId, cipher = networkCipher)
|
||||
} just runs
|
||||
coEvery {
|
||||
vaultSdkSource.decryptCipher(
|
||||
userId = userId,
|
||||
cipher = networkCipher.toEncryptedSdkCipher(),
|
||||
)
|
||||
} returns cipherView.asSuccess()
|
||||
coEvery {
|
||||
vaultSdkSource.encryptCipher(
|
||||
userId = userId,
|
||||
cipherView = cipherView.copy(archivedDate = fixedInstant),
|
||||
)
|
||||
} returns encryptionContext.asSuccess()
|
||||
coEvery {
|
||||
vaultSdkSource.decryptCipher(userId = userId, cipher = encryptionContext.cipher)
|
||||
} returns cipherView.asSuccess()
|
||||
fakeAuthDiskSource.userState = MOCK_USER_STATE
|
||||
coEvery { ciphersService.archiveCipher(cipherId = cipherId) } returns Unit.asSuccess()
|
||||
coEvery {
|
||||
vaultDiskSource.saveCipher(
|
||||
userId = userId,
|
||||
cipher = encryptionContext.toEncryptedNetworkCipherResponse(),
|
||||
)
|
||||
} just runs
|
||||
|
||||
val result = cipherManager.archiveCipher(
|
||||
cipherId = cipherId,
|
||||
cipherView = cipherView,
|
||||
)
|
||||
|
||||
assertEquals(ArchiveCipherResult.Success, result)
|
||||
coVerify(exactly = 1) {
|
||||
ciphersService.updateCipher(
|
||||
cipherId = cipherId,
|
||||
body = encryptionContext.toEncryptedNetworkCipher(),
|
||||
)
|
||||
vaultDiskSource.saveCipher(userId = userId, cipher = networkCipher)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `unarchiveCipher with no active user should return UnarchiveCipherResult Error`() =
|
||||
runTest {
|
||||
fakeAuthDiskSource.userState = null
|
||||
|
||||
val result = cipherManager.unarchiveCipher(
|
||||
cipherId = "cipherId",
|
||||
cipherView = mockk(),
|
||||
)
|
||||
|
||||
assertEquals(UnarchiveCipherResult.Error(error = NoActiveUserException()), result)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `unarchiveCipher with ciphersService unarchiveCipher failure should return UnarchiveCipherResult Error`() =
|
||||
runTest {
|
||||
fakeAuthDiskSource.userState = MOCK_USER_STATE
|
||||
val userId = MOCK_USER_STATE.activeUserId
|
||||
val cipherId = "mockId-1"
|
||||
val cipherView = createMockCipherView(number = 1)
|
||||
val encryptionContext = createMockEncryptionContext(number = 1)
|
||||
val error = Throwable("Fail")
|
||||
coEvery {
|
||||
vaultSdkSource.encryptCipher(userId = userId, cipherView = cipherView)
|
||||
} returns encryptionContext.asSuccess()
|
||||
coEvery {
|
||||
ciphersService.unarchiveCipher(cipherId = cipherId)
|
||||
} returns error.asFailure()
|
||||
|
||||
val result = cipherManager.unarchiveCipher(
|
||||
cipherId = cipherId,
|
||||
cipherView = cipherView,
|
||||
)
|
||||
|
||||
assertEquals(UnarchiveCipherResult.Error(error = error), result)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `unarchiveCipher with ciphersService unarchiveCipher success should return UnarchiveCipherResult success`() =
|
||||
runTest {
|
||||
val userId = "mockId-1"
|
||||
val cipherId = "mockId-1"
|
||||
val encryptionContext = createMockEncryptionContext(
|
||||
number = 1,
|
||||
cipher = createMockSdkCipher(number = 1, clock = clock),
|
||||
)
|
||||
val cipherView = createMockCipherView(number = 1)
|
||||
coEvery {
|
||||
vaultSdkSource.encryptCipher(userId = userId, cipherView = cipherView)
|
||||
} returns encryptionContext.asSuccess()
|
||||
coEvery {
|
||||
vaultSdkSource.encryptCipher(
|
||||
userId = userId,
|
||||
cipherView = cipherView.copy(archivedDate = null),
|
||||
)
|
||||
} returns encryptionContext.asSuccess()
|
||||
coEvery {
|
||||
vaultSdkSource.decryptCipher(userId = userId, cipher = encryptionContext.cipher)
|
||||
} returns cipherView.asSuccess()
|
||||
fakeAuthDiskSource.userState = MOCK_USER_STATE
|
||||
coEvery { ciphersService.unarchiveCipher(cipherId = cipherId) } returns Unit.asSuccess()
|
||||
coEvery {
|
||||
vaultDiskSource.saveCipher(
|
||||
userId = userId,
|
||||
cipher = encryptionContext.toEncryptedNetworkCipherResponse(),
|
||||
)
|
||||
} just runs
|
||||
|
||||
val result = cipherManager.unarchiveCipher(
|
||||
cipherId = cipherId,
|
||||
cipherView = cipherView,
|
||||
)
|
||||
|
||||
assertEquals(UnarchiveCipherResult.Success, result)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `unarchiveCipher with cipher migration success should return UnarchiveCipherResult success`() =
|
||||
runTest {
|
||||
val userId = "mockId-1"
|
||||
val cipherId = "mockId-1"
|
||||
val encryptionContext = createMockEncryptionContext(
|
||||
number = 1,
|
||||
cipher = createMockSdkCipher(number = 1, clock = clock),
|
||||
)
|
||||
val cipherView = createMockCipherView(number = 1).copy(key = null)
|
||||
val networkCipher = createMockCipher(number = 1).copy(key = null)
|
||||
coEvery {
|
||||
vaultSdkSource.encryptCipher(userId = userId, cipherView = cipherView)
|
||||
} returns encryptionContext.asSuccess()
|
||||
coEvery {
|
||||
ciphersService.updateCipher(
|
||||
cipherId = cipherId,
|
||||
body = encryptionContext.toEncryptedNetworkCipher(),
|
||||
)
|
||||
} returns UpdateCipherResponseJson.Success(networkCipher).asSuccess()
|
||||
coEvery {
|
||||
vaultDiskSource.saveCipher(userId = userId, cipher = networkCipher)
|
||||
} just runs
|
||||
coEvery {
|
||||
vaultSdkSource.decryptCipher(
|
||||
userId = userId,
|
||||
cipher = networkCipher.toEncryptedSdkCipher(),
|
||||
)
|
||||
} returns cipherView.asSuccess()
|
||||
coEvery {
|
||||
vaultSdkSource.encryptCipher(
|
||||
userId = userId,
|
||||
cipherView = cipherView.copy(archivedDate = null),
|
||||
)
|
||||
} returns encryptionContext.asSuccess()
|
||||
coEvery {
|
||||
vaultSdkSource.decryptCipher(userId = userId, cipher = encryptionContext.cipher)
|
||||
} returns cipherView.asSuccess()
|
||||
fakeAuthDiskSource.userState = MOCK_USER_STATE
|
||||
coEvery { ciphersService.unarchiveCipher(cipherId = cipherId) } returns Unit.asSuccess()
|
||||
coEvery {
|
||||
vaultDiskSource.saveCipher(
|
||||
userId = userId,
|
||||
cipher = encryptionContext.toEncryptedNetworkCipherResponse(),
|
||||
)
|
||||
} just runs
|
||||
|
||||
val result = cipherManager.unarchiveCipher(
|
||||
cipherId = cipherId,
|
||||
cipherView = cipherView,
|
||||
)
|
||||
|
||||
assertEquals(UnarchiveCipherResult.Success, result)
|
||||
coVerify(exactly = 1) {
|
||||
ciphersService.updateCipher(
|
||||
cipherId = cipherId,
|
||||
body = encryptionContext.toEncryptedNetworkCipher(),
|
||||
)
|
||||
vaultDiskSource.saveCipher(userId = userId, cipher = networkCipher)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `hardDeleteCipher with no active user should return DeleteCipherResult Error`() = runTest {
|
||||
fakeAuthDiskSource.userState = null
|
||||
|
||||
@@ -26,6 +26,22 @@ import retrofit2.http.Query
|
||||
@Suppress("TooManyFunctions")
|
||||
internal interface CiphersApi {
|
||||
|
||||
/**
|
||||
* Archive a cipher.
|
||||
*/
|
||||
@PUT("ciphers/{cipherId}/archive")
|
||||
suspend fun archiveCipher(
|
||||
@Path("cipherId") cipherId: String,
|
||||
): NetworkResult<Unit>
|
||||
|
||||
/**
|
||||
* Unarchive a cipher.
|
||||
*/
|
||||
@PUT("ciphers/{cipherId}/unarchive")
|
||||
suspend fun unarchiveCipher(
|
||||
@Path("cipherId") cipherId: String,
|
||||
): NetworkResult<Unit>
|
||||
|
||||
/**
|
||||
* Create a cipher.
|
||||
*/
|
||||
|
||||
@@ -21,6 +21,16 @@ import java.io.File
|
||||
*/
|
||||
@Suppress("TooManyFunctions")
|
||||
interface CiphersService {
|
||||
/**
|
||||
* Attempt to archive a cipher.
|
||||
*/
|
||||
suspend fun archiveCipher(cipherId: String): Result<Unit>
|
||||
|
||||
/**
|
||||
* Attempt to unarchive a cipher.
|
||||
*/
|
||||
suspend fun unarchiveCipher(cipherId: String): Result<Unit>
|
||||
|
||||
/**
|
||||
* Attempt to create a cipher.
|
||||
*/
|
||||
|
||||
@@ -39,6 +39,18 @@ internal class CiphersServiceImpl(
|
||||
private val json: Json,
|
||||
private val clock: Clock,
|
||||
) : CiphersService {
|
||||
override suspend fun archiveCipher(
|
||||
cipherId: String,
|
||||
): Result<Unit> = ciphersApi
|
||||
.archiveCipher(cipherId = cipherId)
|
||||
.toResult()
|
||||
|
||||
override suspend fun unarchiveCipher(
|
||||
cipherId: String,
|
||||
): Result<Unit> = ciphersApi
|
||||
.unarchiveCipher(cipherId = cipherId)
|
||||
.toResult()
|
||||
|
||||
override suspend fun createCipher(
|
||||
body: CipherJsonRequest,
|
||||
): Result<CreateCipherResponseJson> =
|
||||
|
||||
@@ -27,7 +27,6 @@ import io.mockk.mockk
|
||||
import io.mockk.mockkStatic
|
||||
import io.mockk.unmockkStatic
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlinx.serialization.encodeToString
|
||||
import okhttp3.mockwebserver.MockResponse
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
@@ -65,6 +64,22 @@ class CiphersServiceTest : BaseServiceTest() {
|
||||
unmockkStatic(Uri::class)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `archiveCipher should execute the archiveCipher API`() = runTest {
|
||||
server.enqueue(MockResponse().setResponseCode(200))
|
||||
val cipherId = "cipherId"
|
||||
val result = ciphersService.archiveCipher(cipherId = cipherId)
|
||||
assertEquals(Unit, result.getOrThrow())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `unarchiveCipher should execute the unarchiveCipher API`() = runTest {
|
||||
server.enqueue(MockResponse().setResponseCode(200))
|
||||
val cipherId = "cipherId"
|
||||
val result = ciphersService.unarchiveCipher(cipherId = cipherId)
|
||||
assertEquals(Unit, result.getOrThrow())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `createCipher should return the correct response`() = runTest {
|
||||
server.enqueue(MockResponse().setBody(CREATE_RESTORE_UPDATE_CIPHER_SUCCESS_JSON))
|
||||
|
||||
Reference in new issue
Block a user