BIT-1330, BIT-1331: Implementation to use sdk for forwarded service email generation (#470)

This commit is contained in:
joshua-livefront
2024-01-02 16:40:39 -05:00
committed by GitHub
parent 2624819282
commit b493ffe7f1
12 changed files with 356 additions and 4 deletions

View File

@@ -1,7 +1,9 @@
package com.x8bit.bitwarden.data.tools.generator.datasource.sdk
import com.bitwarden.core.ForwarderServiceType
import com.bitwarden.core.PassphraseGeneratorRequest
import com.bitwarden.core.PasswordGeneratorRequest
import com.bitwarden.core.UsernameGeneratorRequest
import com.bitwarden.sdk.ClientGenerators
import io.mockk.coEvery
import io.mockk.coVerify
@@ -67,4 +69,27 @@ class GeneratorSdkSourceTest {
clientGenerators.passphrase(request)
}
}
@Suppress("MaxLineLength")
@Test
fun `generateForwardedServiceEmail should call SDK and return a Result with the generated email`() =
runBlocking {
val request = UsernameGeneratorRequest.Forwarded(
service = ForwarderServiceType.DuckDuckGo(token = "testToken"),
website = null,
)
val expectedResult = "generated@email.com"
coEvery {
clientGenerators.username(request)
} returns expectedResult
val result = generatorSdkSource.generateForwardedServiceEmail(request)
assertEquals(Result.success(expectedResult), result)
coVerify {
clientGenerators.username(request)
}
}
}

View File

@@ -1,10 +1,12 @@
package com.x8bit.bitwarden.data.tools.generator.repository
import app.cash.turbine.test
import com.bitwarden.core.ForwarderServiceType
import com.bitwarden.core.PassphraseGeneratorRequest
import com.bitwarden.core.PasswordGeneratorRequest
import com.bitwarden.core.PasswordHistory
import com.bitwarden.core.PasswordHistoryView
import com.bitwarden.core.UsernameGeneratorRequest
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
import com.x8bit.bitwarden.data.auth.datasource.disk.model.AccountJson
import com.x8bit.bitwarden.data.auth.datasource.disk.model.EnvironmentUrlDataJson
@@ -21,6 +23,7 @@ import com.x8bit.bitwarden.data.tools.generator.datasource.disk.PasswordHistoryD
import com.x8bit.bitwarden.data.tools.generator.datasource.disk.entity.PasswordHistoryEntity
import com.x8bit.bitwarden.data.tools.generator.datasource.disk.entity.toPasswordHistoryEntity
import com.x8bit.bitwarden.data.tools.generator.datasource.sdk.GeneratorSdkSource
import com.x8bit.bitwarden.data.tools.generator.repository.model.GeneratedForwardedServiceUsernameResult
import com.x8bit.bitwarden.data.tools.generator.repository.model.GeneratedPassphraseResult
import com.x8bit.bitwarden.data.tools.generator.repository.model.GeneratedPasswordResult
import com.x8bit.bitwarden.data.tools.generator.repository.model.PasscodeGenerationOptions
@@ -250,6 +253,48 @@ class GeneratorRepositoryTest {
coVerify { generatorSdkSource.generatePassphrase(request) }
}
@Suppress("MaxLineLength")
@Test
fun `generateForwardedService should emit Success result and store the generated email`() = runTest {
val userId = "testUserId"
val request = UsernameGeneratorRequest.Forwarded(
service = ForwarderServiceType.DuckDuckGo(
token = "testToken",
),
website = null,
)
val generatedEmail = "generated@email.com"
coEvery { authDiskSource.userState?.activeUserId } returns userId
coEvery { generatorSdkSource.generateForwardedServiceEmail(request) } returns
Result.success(generatedEmail)
val result = repository.generateForwardedServiceUsername(request)
assertEquals(
generatedEmail,
(result as GeneratedForwardedServiceUsernameResult.Success).generatedEmailAddress,
)
coVerify { generatorSdkSource.generateForwardedServiceEmail(request) }
}
@Suppress("MaxLineLength")
@Test
fun `generateForwardedService should emit InvalidRequest result when SDK throws exception`() = runTest {
val request = UsernameGeneratorRequest.Forwarded(
service = ForwarderServiceType.DuckDuckGo(token = "testToken"),
website = null,
)
val exception = RuntimeException("An error occurred")
coEvery { generatorSdkSource.generateForwardedServiceEmail(request) } returns Result.failure(exception)
val result = repository.generateForwardedServiceUsername(request)
assertTrue(result is GeneratedForwardedServiceUsernameResult.InvalidRequest)
coVerify { generatorSdkSource.generateForwardedServiceEmail(request) }
}
@Test
fun `getPasscodeGenerationOptions should return options when available`() = runTest {
val userId = "activeUserId"

View File

@@ -3,8 +3,10 @@ package com.x8bit.bitwarden.data.tools.generator.repository.util
import com.bitwarden.core.PassphraseGeneratorRequest
import com.bitwarden.core.PasswordGeneratorRequest
import com.bitwarden.core.PasswordHistoryView
import com.bitwarden.core.UsernameGeneratorRequest
import com.x8bit.bitwarden.data.platform.repository.model.LocalDataState
import com.x8bit.bitwarden.data.tools.generator.repository.GeneratorRepository
import com.x8bit.bitwarden.data.tools.generator.repository.model.GeneratedForwardedServiceUsernameResult
import com.x8bit.bitwarden.data.tools.generator.repository.model.GeneratedPassphraseResult
import com.x8bit.bitwarden.data.tools.generator.repository.model.GeneratedPasswordResult
import com.x8bit.bitwarden.data.tools.generator.repository.model.PasscodeGenerationOptions
@@ -28,6 +30,11 @@ class FakeGeneratorRepository : GeneratorRepository {
private val mutablePasswordHistoryStateFlow =
MutableStateFlow<LocalDataState<List<PasswordHistoryView>>>(LocalDataState.Loading)
private var generateForwardedServiceResult: GeneratedForwardedServiceUsernameResult =
GeneratedForwardedServiceUsernameResult.Success(
generatedEmailAddress = "updatedUsername",
)
override val passwordHistoryStateFlow: StateFlow<LocalDataState<List<PasswordHistoryView>>>
get() = mutablePasswordHistoryStateFlow
@@ -44,6 +51,12 @@ class FakeGeneratorRepository : GeneratorRepository {
return generatePassphraseResult
}
override suspend fun generateForwardedServiceUsername(
forwardedServiceGeneratorRequest: UsernameGeneratorRequest.Forwarded,
): GeneratedForwardedServiceUsernameResult {
return generateForwardedServiceResult
}
override fun getPasscodeGenerationOptions(): PasscodeGenerationOptions? {
return passcodeGenerationOptions
}
@@ -90,4 +103,11 @@ class FakeGeneratorRepository : GeneratorRepository {
fun emitPasswordHistoryState(state: LocalDataState<List<PasswordHistoryView>>) {
mutablePasswordHistoryStateFlow.value = state
}
/**
* Sets the mock result for the generateForwardedService function.
*/
fun setMockGenerateForwardedServiceResult(result: GeneratedForwardedServiceUsernameResult) {
generateForwardedServiceResult = result
}
}

View File

@@ -3,6 +3,7 @@ package com.x8bit.bitwarden.ui.tools.feature.generator
import androidx.lifecycle.SavedStateHandle
import app.cash.turbine.test
import com.x8bit.bitwarden.R
import com.x8bit.bitwarden.data.tools.generator.repository.model.GeneratedForwardedServiceUsernameResult
import com.x8bit.bitwarden.data.tools.generator.repository.model.GeneratedPassphraseResult
import com.x8bit.bitwarden.data.tools.generator.repository.model.GeneratedPasswordResult
import com.x8bit.bitwarden.data.tools.generator.repository.model.PasscodeGenerationOptions
@@ -942,6 +943,12 @@ class GeneratorViewModelTest : BaseViewModelTest() {
.ADDY_IO,
)
fakeGeneratorRepository.setMockGenerateForwardedServiceResult(
GeneratedForwardedServiceUsernameResult.Success(
generatedEmailAddress = "defaultForwardedEmailAlias",
),
)
viewModel.actionChannel.trySend(action)
val expectedState = defaultForwardedEmailAliasState.copy(
@@ -989,6 +996,12 @@ class GeneratorViewModelTest : BaseViewModelTest() {
accessToken = newAccessToken,
)
fakeGeneratorRepository.setMockGenerateForwardedServiceResult(
GeneratedForwardedServiceUsernameResult.Success(
generatedEmailAddress = "defaultAddyIo",
),
)
viewModel.actionChannel.trySend(action)
val expectedState = defaultAddyIoState.copy(
@@ -1006,7 +1019,6 @@ class GeneratorViewModelTest : BaseViewModelTest() {
),
),
)
assertEquals(expectedState, viewModel.stateFlow.value)
}
@@ -1023,6 +1035,12 @@ class GeneratorViewModelTest : BaseViewModelTest() {
domain = newDomainName,
)
fakeGeneratorRepository.setMockGenerateForwardedServiceResult(
GeneratedForwardedServiceUsernameResult.Success(
generatedEmailAddress = "defaultAddyIo",
),
)
viewModel.actionChannel.trySend(action)
val expectedState = defaultAddyIoState.copy(
@@ -1067,6 +1085,12 @@ class GeneratorViewModelTest : BaseViewModelTest() {
apiKey = newApiKey,
)
fakeGeneratorRepository.setMockGenerateForwardedServiceResult(
GeneratedForwardedServiceUsernameResult.Success(
generatedEmailAddress = "defaultDuckDuckGo",
),
)
viewModel.actionChannel.trySend(action)
val expectedState = defaultDuckDuckGoState.copy(
@@ -1111,6 +1135,12 @@ class GeneratorViewModelTest : BaseViewModelTest() {
apiKey = newApiKey,
)
fakeGeneratorRepository.setMockGenerateForwardedServiceResult(
GeneratedForwardedServiceUsernameResult.Success(
generatedEmailAddress = "defaultFastMail",
),
)
viewModel.actionChannel.trySend(action)
val expectedState = defaultFastMailState.copy(
@@ -1156,6 +1186,12 @@ class GeneratorViewModelTest : BaseViewModelTest() {
accessToken = newAccessToken,
)
fakeGeneratorRepository.setMockGenerateForwardedServiceResult(
GeneratedForwardedServiceUsernameResult.Success(
generatedEmailAddress = "defaultFirefoxRelay",
),
)
viewModel.actionChannel.trySend(action)
val expectedState = defaultFirefoxRelayState.copy(
@@ -1201,6 +1237,12 @@ class GeneratorViewModelTest : BaseViewModelTest() {
apiKey = newApiKey,
)
fakeGeneratorRepository.setMockGenerateForwardedServiceResult(
GeneratedForwardedServiceUsernameResult.Success(
generatedEmailAddress = "defaultSimpleLogin",
),
)
viewModel.actionChannel.trySend(action)
val expectedState = defaultSimpleLoginState.copy(

View File

@@ -0,0 +1,64 @@
package com.x8bit.bitwarden.ui.tools.feature.generator.util
import com.bitwarden.core.ForwarderServiceType
import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorState.MainType.Username.UsernameType.ForwardedEmailAlias.ServiceType
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.Assertions.assertEquals
internal class ServiceTypeExtensionsTest {
@Test
fun `toUsernameGeneratorRequest for AddyIo returns correct request`() {
val addyIoServiceType = ServiceType.AddyIo(
apiAccessToken = "testToken",
domainName = "test.com",
baseUrl = "http://test.com",
)
val request = addyIoServiceType.toUsernameGeneratorRequest()
assertEquals(
ForwarderServiceType.AddyIo(
apiToken = "testToken",
domain = "test.com",
baseUrl = "http://test.com",
), request.service,
)
assertEquals(null, request.website)
}
@Test
fun `toUsernameGeneratorRequest for DuckDuckGo returns correct request`() {
val duckDuckGoServiceType = ServiceType.DuckDuckGo(apiKey = "testKey")
val request = duckDuckGoServiceType.toUsernameGeneratorRequest()
assertEquals(ForwarderServiceType.DuckDuckGo("testKey"), request.service)
assertEquals(null, request.website)
}
@Test
fun `toUsernameGeneratorRequest for FirefoxRelay returns correct request`() {
val firefoxRelayServiceType = ServiceType.FirefoxRelay(apiAccessToken = "testToken")
val request = firefoxRelayServiceType.toUsernameGeneratorRequest()
assertEquals(ForwarderServiceType.Firefox(apiToken = "testToken"), request.service)
assertEquals(null, request.website)
}
@Test
fun `toUsernameGeneratorRequest for FastMail returns correct request`() {
val fastMailServiceType = ServiceType.FastMail(apiKey = "testKey")
val request = fastMailServiceType.toUsernameGeneratorRequest()
assertEquals(ForwarderServiceType.Fastmail(apiToken = "testKey"), request.service)
assertEquals(null, request.website)
}
@Test
fun `toUsernameGeneratorRequest for SimpleLogin returns correct request`() {
val simpleLoginServiceType = ServiceType.SimpleLogin(apiKey = "testKey")
val request = simpleLoginServiceType.toUsernameGeneratorRequest()
assertEquals(ForwarderServiceType.SimpleLogin(apiKey = "testKey"), request.service)
assertEquals(null, request.website)
}
}