BIT-782: Implement Personal Ownership policy support (#920)

This commit is contained in:
Caleb Derosier
2024-01-31 20:54:08 -07:00
committed by Álison Fernandes
parent f380e21600
commit debfbc04b0
17 changed files with 427 additions and 29 deletions

View File

@@ -13,6 +13,7 @@ import com.x8bit.bitwarden.data.auth.repository.model.ValidatePasswordResult
import com.x8bit.bitwarden.data.autofill.manager.AutofillSelectionManager
import com.x8bit.bitwarden.data.autofill.manager.AutofillSelectionManagerImpl
import com.x8bit.bitwarden.data.autofill.model.AutofillSelectionData
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManagerImpl
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
@@ -21,6 +22,8 @@ import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
import com.x8bit.bitwarden.data.platform.repository.model.DataState
import com.x8bit.bitwarden.data.platform.repository.model.Environment
import com.x8bit.bitwarden.data.vault.datasource.network.model.PolicyTypeJson
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCipherView
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCollectionView
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockFolderView
@@ -77,6 +80,11 @@ class SearchViewModelTest : BaseViewModelTest() {
private val clipboardManager: BitwardenClipboardManager = mockk {
every { setText(any<String>()) } just runs
}
private val policyManager: PolicyManager = mockk<PolicyManager> {
every {
getActivePolicies(type = PolicyTypeJson.PERSONAL_OWNERSHIP)
} returns emptyList()
}
private val mutableVaultDataStateFlow =
MutableStateFlow<DataState<VaultData>>(DataState.Loading)
private val vaultRepository: VaultRepository = mockk {
@@ -124,6 +132,26 @@ class SearchViewModelTest : BaseViewModelTest() {
assertEquals(state, viewModel.stateFlow.value)
}
@Test
fun `initial state should be correct when user has PERSONAL_OWNERSHIP policy`() {
every {
policyManager.getActivePolicies(type = PolicyTypeJson.PERSONAL_OWNERSHIP)
} returns listOf(
SyncResponseJson.Policy(
organizationId = "Test Org",
id = "testId",
type = PolicyTypeJson.PERSONAL_OWNERSHIP,
isEnabled = true,
data = null,
),
)
val viewModel = createViewModel()
assertEquals(DEFAULT_STATE, viewModel.stateFlow.value)
verify {
policyManager.getActivePolicies(type = PolicyTypeJson.PERSONAL_OWNERSHIP)
}
}
@Test
fun `BackClick should emit NavigateBack`() = runTest {
val viewModel = createViewModel()
@@ -1232,6 +1260,7 @@ class SearchViewModelTest : BaseViewModelTest() {
environmentRepo = environmentRepository,
settingsRepo = settingsRepository,
clipboardManager = clipboardManager,
policyManager = policyManager,
specialCircumstanceManager = specialCircumstanceManager,
autofillSelectionManager = autofillSelectionManager,
)

View File

@@ -305,6 +305,7 @@ class VaultAddEditScreenTest : BaseComposeTest() {
viewState = VaultAddEditState.ViewState.Content(
common = VaultAddEditState.ViewState.Content.Common(),
type = VaultAddEditState.ViewState.Content.ItemType.Login(),
isIndividualVaultDisabled = false,
),
)
}
@@ -333,6 +334,7 @@ class VaultAddEditScreenTest : BaseComposeTest() {
viewState = VaultAddEditState.ViewState.Content(
common = VaultAddEditState.ViewState.Content.Common(),
type = VaultAddEditState.ViewState.Content.ItemType.Login(),
isIndividualVaultDisabled = false,
),
)
}
@@ -371,6 +373,7 @@ class VaultAddEditScreenTest : BaseComposeTest() {
viewState = VaultAddEditState.ViewState.Content(
common = VaultAddEditState.ViewState.Content.Common(),
type = VaultAddEditState.ViewState.Content.ItemType.Card(),
isIndividualVaultDisabled = false,
),
)
}
@@ -403,6 +406,7 @@ class VaultAddEditScreenTest : BaseComposeTest() {
type = VaultAddEditState.ViewState.Content.ItemType.Login(
password = "p@ssw0rd",
),
isIndividualVaultDisabled = false,
),
)
}
@@ -440,6 +444,7 @@ class VaultAddEditScreenTest : BaseComposeTest() {
password = "p@ssw0rd",
canViewPassword = false,
),
isIndividualVaultDisabled = false,
),
)
}
@@ -2490,6 +2495,7 @@ class VaultAddEditScreenTest : BaseComposeTest() {
originalCipher = createMockCipherView(1),
),
type = VaultAddEditState.ViewState.Content.ItemType.SecureNotes,
isIndividualVaultDisabled = false,
),
)
}
@@ -2530,6 +2536,7 @@ class VaultAddEditScreenTest : BaseComposeTest() {
),
),
type = VaultAddEditState.ViewState.Content.ItemType.SecureNotes,
isIndividualVaultDisabled = false,
),
)
}
@@ -2558,6 +2565,48 @@ class VaultAddEditScreenTest : BaseComposeTest() {
.assertIsDisplayed()
}
@Test
fun `should display policy warning when personal vault is disabled for add item type`() {
mutableStateFlow.update {
it.copy(
vaultAddEditType = VaultAddEditType.AddItem,
viewState = VaultAddEditState.ViewState.Content(
common = VaultAddEditState.ViewState.Content.Common(
originalCipher = createMockCipherView(1),
),
type = VaultAddEditState.ViewState.Content.ItemType.SecureNotes,
isIndividualVaultDisabled = true,
),
)
}
composeTestRule
.onNodeWithTextAfterScroll(
text = "An organization policy is affecting your ownership options.",
)
.assertIsDisplayed()
}
@Test
fun `should not display policy warning when personal vault is disabled for edit item type`() {
mutableStateFlow.update {
it.copy(
vaultAddEditType = VaultAddEditType.EditItem("mockId-1"),
viewState = VaultAddEditState.ViewState.Content(
common = VaultAddEditState.ViewState.Content.Common(
originalCipher = createMockCipherView(1),
),
type = VaultAddEditState.ViewState.Content.ItemType.SecureNotes,
isIndividualVaultDisabled = true,
),
)
}
composeTestRule
.onNodeWithText(text = "An organization policy is affecting your ownership options.")
.assertDoesNotExist()
}
@Test
fun `Delete dialog ok click should send ConfirmDeleteClick`() {
mutableStateFlow.update {
@@ -2568,6 +2617,7 @@ class VaultAddEditScreenTest : BaseComposeTest() {
originalCipher = createMockCipherView(1),
),
type = VaultAddEditState.ViewState.Content.ItemType.SecureNotes,
isIndividualVaultDisabled = false,
),
)
}
@@ -2615,6 +2665,7 @@ class VaultAddEditScreenTest : BaseComposeTest() {
originalCipher = createMockCipherView(1),
),
type = VaultAddEditState.ViewState.Content.ItemType.SecureNotes,
isIndividualVaultDisabled = false,
),
)
}
@@ -2763,6 +2814,7 @@ class VaultAddEditScreenTest : BaseComposeTest() {
viewState = VaultAddEditState.ViewState.Content(
common = VaultAddEditState.ViewState.Content.Common(),
type = VaultAddEditState.ViewState.Content.ItemType.Login(),
isIndividualVaultDisabled = false,
),
dialog = VaultAddEditState.DialogState.Generic(message = "test".asText()),
vaultAddEditType = VaultAddEditType.AddItem,
@@ -2773,6 +2825,7 @@ class VaultAddEditScreenTest : BaseComposeTest() {
viewState = VaultAddEditState.ViewState.Content(
common = VaultAddEditState.ViewState.Content.Common(),
type = VaultAddEditState.ViewState.Content.ItemType.Login(),
isIndividualVaultDisabled = false,
),
dialog = null,
)
@@ -2782,6 +2835,7 @@ class VaultAddEditScreenTest : BaseComposeTest() {
viewState = VaultAddEditState.ViewState.Content(
common = VaultAddEditState.ViewState.Content.Common(),
type = VaultAddEditState.ViewState.Content.ItemType.Identity(),
isIndividualVaultDisabled = false,
),
dialog = null,
)
@@ -2791,6 +2845,7 @@ class VaultAddEditScreenTest : BaseComposeTest() {
viewState = VaultAddEditState.ViewState.Content(
common = VaultAddEditState.ViewState.Content.Common(),
type = VaultAddEditState.ViewState.Content.ItemType.Card(),
isIndividualVaultDisabled = false,
),
dialog = null,
)
@@ -2810,6 +2865,7 @@ class VaultAddEditScreenTest : BaseComposeTest() {
),
),
type = VaultAddEditState.ViewState.Content.ItemType.SecureNotes,
isIndividualVaultDisabled = false,
),
dialog = null,
vaultAddEditType = VaultAddEditType.AddItem,
@@ -2820,6 +2876,7 @@ class VaultAddEditScreenTest : BaseComposeTest() {
viewState = VaultAddEditState.ViewState.Content(
common = VaultAddEditState.ViewState.Content.Common(),
type = VaultAddEditState.ViewState.Content.ItemType.SecureNotes,
isIndividualVaultDisabled = false,
),
dialog = null,
)

View File

@@ -16,6 +16,7 @@ import com.x8bit.bitwarden.data.auth.repository.model.UserState
import com.x8bit.bitwarden.data.auth.repository.model.VaultUnlockType
import com.x8bit.bitwarden.data.autofill.model.AutofillSaveItem
import com.x8bit.bitwarden.data.autofill.model.AutofillSelectionData
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManagerImpl
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
@@ -26,6 +27,8 @@ import com.x8bit.bitwarden.data.platform.repository.model.Environment
import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFlow
import com.x8bit.bitwarden.data.tools.generator.repository.GeneratorRepository
import com.x8bit.bitwarden.data.tools.generator.repository.util.FakeGeneratorRepository
import com.x8bit.bitwarden.data.vault.datasource.network.model.PolicyTypeJson
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCipherView
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
import com.x8bit.bitwarden.data.vault.repository.model.CreateCipherResult
@@ -95,6 +98,11 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
every { getString(R.string.folder_none) } returns "No Folder"
}
private val clipboardManager: BitwardenClipboardManager = mockk()
private val policyManager: PolicyManager = mockk {
every {
getActivePolicies(type = PolicyTypeJson.PERSONAL_OWNERSHIP)
} returns emptyList()
}
private val vaultRepository: VaultRepository = mockk {
every { vaultDataStateFlow } returns mutableVaultDataFlow
every { totpCodeFlow } returns totpTestCodeFlow
@@ -134,6 +142,9 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
awaitItem(),
)
}
verify {
policyManager.getActivePolicies(type = PolicyTypeJson.PERSONAL_OWNERSHIP)
}
}
@Test
@@ -155,6 +166,57 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
}
}
@Test
fun `initial add state should be correct with individual vault disabled`() = runTest {
every {
policyManager.getActivePolicies(type = PolicyTypeJson.PERSONAL_OWNERSHIP)
} returns listOf(
SyncResponseJson.Policy(
organizationId = "Test Org",
id = "testId",
type = PolicyTypeJson.PERSONAL_OWNERSHIP,
isEnabled = true,
data = null,
),
)
val vaultAddEditType = VaultAddEditType.AddItem
mutableVaultDataFlow.value = DataState.Loaded(
data = createVaultData(),
)
val viewModel = createAddVaultItemViewModel(
savedStateHandle = createSavedStateHandleWithState(
state = null,
vaultAddEditType = vaultAddEditType,
),
)
assertEquals(
VaultAddEditState(
vaultAddEditType = vaultAddEditType,
viewState = VaultAddEditState.ViewState.Content(
common = createCommonContentViewState(
availableOwners = listOf(
VaultAddEditState.Owner(
id = "organizationId",
name = "organizationName",
collections = emptyList(),
),
),
),
isIndividualVaultDisabled = true,
type = VaultAddEditState.ViewState.Content.ItemType.Login(),
),
dialog = null,
),
viewModel.stateFlow.value,
)
verify(exactly = 1) {
vaultRepository.vaultDataStateFlow
}
verify {
policyManager.getActivePolicies(type = PolicyTypeJson.PERSONAL_OWNERSHIP)
}
}
@Test
fun `initial add state should be correct when autofill selection`() = runTest {
val autofillSelectionData = AutofillSelectionData(
@@ -165,7 +227,9 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
autofillSelectionData = autofillSelectionData,
shouldFinishWhenComplete = true,
)
val autofillContentState = autofillSelectionData.toDefaultAddTypeContent()
val autofillContentState = autofillSelectionData.toDefaultAddTypeContent(
isIndividualVaultDisabled = false,
)
val vaultAddEditType = VaultAddEditType.AddItem
val initState = createVaultAddItemState(
vaultAddEditType = vaultAddEditType,
@@ -197,7 +261,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
specialCircumstanceManager.specialCircumstance = SpecialCircumstance.AutofillSave(
autofillSaveItem = autofillSaveItem,
)
val autofillContentState = autofillSaveItem.toDefaultAddTypeContent()
val autofillContentState = autofillSaveItem.toDefaultAddTypeContent(false)
val vaultAddEditType = VaultAddEditType.AddItem
val initState = createVaultAddItemState(
vaultAddEditType = vaultAddEditType,
@@ -685,6 +749,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
every {
cipherView.toViewState(
isClone = false,
isIndividualVaultDisabled = false,
resourceManager = resourceManager,
)
} returns stateWithName.viewState
@@ -713,6 +778,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
coVerify(exactly = 1) {
cipherView.toViewState(
isClone = false,
isIndividualVaultDisabled = false,
resourceManager = resourceManager,
)
vaultRepository.updateCipher(DEFAULT_EDIT_ITEM_ID, any())
@@ -744,6 +810,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
every {
cipherView.toViewState(
isClone = false,
isIndividualVaultDisabled = false,
resourceManager = resourceManager,
)
} returns stateWithName.viewState
@@ -801,7 +868,11 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
val errorMessage = "You do not have permission to edit this."
every {
cipherView.toViewState(isClone = false, resourceManager = resourceManager)
cipherView.toViewState(
isClone = false,
isIndividualVaultDisabled = false,
resourceManager = resourceManager,
)
} returns stateWithName.viewState
coEvery {
vaultRepository.updateCipher(DEFAULT_EDIT_ITEM_ID, any())
@@ -907,6 +978,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
val expectedState = loginInitialState.copy(
viewState = VaultAddEditState.ViewState.Content(
common = createCommonContentViewState(),
isIndividualVaultDisabled = false,
type = createLoginTypeContentViewState(),
previousItemTypes = mapOf(
VaultAddEditState.ItemTypeOption.LOGIN
@@ -936,6 +1008,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
val expectedState = loginInitialState.copy(
viewState = VaultAddEditState.ViewState.Content(
common = createCommonContentViewState(),
isIndividualVaultDisabled = false,
type = VaultAddEditState.ViewState.Content.ItemType.Card(),
previousItemTypes = mapOf(
VaultAddEditState.ItemTypeOption.LOGIN
@@ -965,6 +1038,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
val expectedState = loginInitialState.copy(
viewState = VaultAddEditState.ViewState.Content(
common = createCommonContentViewState(),
isIndividualVaultDisabled = false,
type = VaultAddEditState.ViewState.Content.ItemType.Identity(),
previousItemTypes = mapOf(
VaultAddEditState.ItemTypeOption.LOGIN
@@ -994,6 +1068,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
val expectedState = loginInitialState.copy(
viewState = VaultAddEditState.ViewState.Content(
common = createCommonContentViewState(),
isIndividualVaultDisabled = false,
type = VaultAddEditState.ViewState.Content.ItemType.SecureNotes,
previousItemTypes = mapOf(
VaultAddEditState.ItemTypeOption.LOGIN
@@ -1074,6 +1149,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
val loginState = loginInitialState.copy(
viewState = VaultAddEditState.ViewState.Content(
common = createCommonContentViewState(),
isIndividualVaultDisabled = false,
type = createLoginTypeContentViewState(
password = password,
),
@@ -1209,6 +1285,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
val expectedState = loginInitialState.copy(
viewState = VaultAddEditState.ViewState.Content(
common = createCommonContentViewState(),
isIndividualVaultDisabled = false,
type = createLoginTypeContentViewState(
totpCode = null,
),
@@ -1233,6 +1310,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
val expectedState = loginInitialState.copy(
viewState = VaultAddEditState.ViewState.Content(
common = createCommonContentViewState(),
isIndividualVaultDisabled = false,
type = createLoginTypeContentViewState(
totpCode = "TestKey",
),
@@ -1274,6 +1352,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
val expectedState = loginInitialState.copy(
viewState = VaultAddEditState.ViewState.Content(
common = createCommonContentViewState(),
isIndividualVaultDisabled = false,
type = createLoginTypeContentViewState(
uri = listOf(UriItem("testID", "Test", null)),
),
@@ -1306,6 +1385,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
val expectedState = loginInitialState.copy(
viewState = VaultAddEditState.ViewState.Content(
common = createCommonContentViewState(),
isIndividualVaultDisabled = false,
type = createLoginTypeContentViewState(
uri = listOf(),
),
@@ -1772,6 +1852,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
vaultRepository = vaultRepository,
generatorRepository = generatorRepository,
specialCircumstanceManager = specialCircumstanceManager,
policyManager = policyManager,
resourceManager = resourceManager,
authRepository = authRepository,
settingsRepository = settingsRepository,
@@ -1789,6 +1870,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
common = createCommonContentViewState(
name = "newName",
),
isIndividualVaultDisabled = false,
type = createLoginTypeContentViewState(),
),
)
@@ -1811,6 +1893,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
viewState = VaultAddEditState.ViewState.Content(
common = createCommonContentViewState()
.copy(selectedFolderId = "mockId-1"),
isIndividualVaultDisabled = false,
type = createLoginTypeContentViewState(),
),
)
@@ -1829,6 +1912,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
common = createCommonContentViewState(
favorite = true,
),
isIndividualVaultDisabled = false,
type = createLoginTypeContentViewState(),
),
)
@@ -1850,6 +1934,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
common = createCommonContentViewState(
masterPasswordReprompt = true,
),
isIndividualVaultDisabled = false,
type = createLoginTypeContentViewState(),
),
)
@@ -1869,6 +1954,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
common = createCommonContentViewState(
notes = "newNotes",
),
isIndividualVaultDisabled = false,
type = createLoginTypeContentViewState(),
),
)
@@ -1892,6 +1978,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
viewState = VaultAddEditState.ViewState.Content(
common = createCommonContentViewState()
.copy(selectedOwnerId = "mockId-1"),
isIndividualVaultDisabled = false,
type = createLoginTypeContentViewState(),
),
)
@@ -2217,6 +2304,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
private fun createVaultAddItemState(
vaultAddEditType: VaultAddEditType = VaultAddEditType.AddItem,
commonContentViewState: VaultAddEditState.ViewState.Content.Common = createCommonContentViewState(),
isIndividualVaultDisabled: Boolean = false,
typeContentViewState: VaultAddEditState.ViewState.Content.ItemType = createLoginTypeContentViewState(),
dialogState: VaultAddEditState.DialogState? = null,
): VaultAddEditState =
@@ -2224,6 +2312,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
vaultAddEditType = vaultAddEditType,
viewState = VaultAddEditState.ViewState.Content(
common = commonContentViewState,
isIndividualVaultDisabled = isIndividualVaultDisabled,
type = typeContentViewState,
),
dialog = dialogState,
@@ -2313,6 +2402,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
vaultRepository = vaultRepo,
generatorRepository = generatorRepo,
specialCircumstanceManager = specialCircumstanceManager,
policyManager = policyManager,
resourceManager = bitwardenResourceManager,
authRepository = authRepository,
settingsRepository = settingsRepository,

View File

@@ -28,6 +28,7 @@ class AutofillSaveItemExtensionsTest {
assertEquals(
VaultAddEditState.ViewState.Content(
common = VaultAddEditState.ViewState.Content.Common(),
isIndividualVaultDisabled = false,
type = VaultAddEditState.ViewState.Content.ItemType.Card(
number = "number",
expirationMonth = VaultCardExpirationMonth.JANUARY,
@@ -41,7 +42,7 @@ class AutofillSaveItemExtensionsTest {
expirationYear = "2024",
securityCode = "securityCode",
)
.toDefaultAddTypeContent(),
.toDefaultAddTypeContent(isIndividualVaultDisabled = false),
)
}
@@ -53,6 +54,7 @@ class AutofillSaveItemExtensionsTest {
common = VaultAddEditState.ViewState.Content.Common(
name = "www.test.com",
),
isIndividualVaultDisabled = true,
type = VaultAddEditState.ViewState.Content.ItemType.Login(
username = "username",
password = "password",
@@ -70,7 +72,7 @@ class AutofillSaveItemExtensionsTest {
password = "password",
uri = "https://www.test.com",
)
.toDefaultAddTypeContent(),
.toDefaultAddTypeContent(isIndividualVaultDisabled = true),
)
}
}

View File

@@ -27,13 +27,14 @@ class AutofillSelectionDataExtensionsTest {
assertEquals(
VaultAddEditState.ViewState.Content(
common = VaultAddEditState.ViewState.Content.Common(),
isIndividualVaultDisabled = false,
type = VaultAddEditState.ViewState.Content.ItemType.Card(),
),
AutofillSelectionData(
type = AutofillSelectionData.Type.CARD,
uri = null,
)
.toDefaultAddTypeContent(),
.toDefaultAddTypeContent(isIndividualVaultDisabled = false),
)
}
@@ -45,6 +46,7 @@ class AutofillSelectionDataExtensionsTest {
common = VaultAddEditState.ViewState.Content.Common(
name = "www.test.com",
),
isIndividualVaultDisabled = true,
type = VaultAddEditState.ViewState.Content.ItemType.Login(
uriList = listOf(
UriItem(
@@ -59,7 +61,7 @@ class AutofillSelectionDataExtensionsTest {
type = AutofillSelectionData.Type.LOGIN,
uri = "https://www.test.com",
)
.toDefaultAddTypeContent(),
.toDefaultAddTypeContent(isIndividualVaultDisabled = true),
)
}
}

View File

@@ -52,6 +52,7 @@ class CipherViewExtensionsTest {
val result = cipherView.toViewState(
isClone = false,
isIndividualVaultDisabled = false,
resourceManager = resourceManager,
)
@@ -76,6 +77,7 @@ class CipherViewExtensionsTest {
availableFolders = emptyList(),
availableOwners = emptyList(),
),
isIndividualVaultDisabled = false,
type = VaultAddEditState.ViewState.Content.ItemType.Card(
cardHolderName = "Bit Warden",
number = "4012888888881881",
@@ -94,6 +96,7 @@ class CipherViewExtensionsTest {
val result = cipherView.toViewState(
isClone = false,
isIndividualVaultDisabled = true,
resourceManager = resourceManager,
)
@@ -118,6 +121,7 @@ class CipherViewExtensionsTest {
availableFolders = emptyList(),
availableOwners = emptyList(),
),
isIndividualVaultDisabled = true,
type = VaultAddEditState.ViewState.Content.ItemType.Identity(
firstName = "John",
middleName = "Richard",
@@ -141,6 +145,7 @@ class CipherViewExtensionsTest {
val result = cipherView.toViewState(
isClone = false,
isIndividualVaultDisabled = false,
resourceManager = resourceManager,
)
@@ -165,6 +170,7 @@ class CipherViewExtensionsTest {
),
),
),
isIndividualVaultDisabled = false,
type = VaultAddEditState.ViewState.Content.ItemType.Login(
username = "username",
password = "password",
@@ -183,6 +189,7 @@ class CipherViewExtensionsTest {
val result = cipherView.toViewState(
isClone = false,
isIndividualVaultDisabled = true,
resourceManager = resourceManager,
)
@@ -202,6 +209,7 @@ class CipherViewExtensionsTest {
availableFolders = emptyList(),
availableOwners = emptyList(),
),
isIndividualVaultDisabled = true,
type = VaultAddEditState.ViewState.Content.ItemType.SecureNotes,
),
result,
@@ -214,6 +222,7 @@ class CipherViewExtensionsTest {
val result = cipherView.toViewState(
isClone = true,
isIndividualVaultDisabled = false,
resourceManager = resourceManager,
)
@@ -233,6 +242,7 @@ class CipherViewExtensionsTest {
availableFolders = emptyList(),
availableOwners = emptyList(),
),
isIndividualVaultDisabled = false,
type = VaultAddEditState.ViewState.Content.ItemType.SecureNotes,
),
result,

View File

@@ -6,11 +6,14 @@ import com.x8bit.bitwarden.data.auth.repository.AuthRepository
import com.x8bit.bitwarden.data.auth.repository.model.Organization
import com.x8bit.bitwarden.data.auth.repository.model.SwitchAccountResult
import com.x8bit.bitwarden.data.auth.repository.model.UserState
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
import com.x8bit.bitwarden.data.platform.repository.model.DataState
import com.x8bit.bitwarden.data.platform.repository.model.Environment
import com.x8bit.bitwarden.data.platform.repository.util.baseIconUrl
import com.x8bit.bitwarden.data.vault.datasource.network.model.PolicyTypeJson
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCipherView
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCollectionView
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockFolderView
@@ -52,6 +55,11 @@ class VaultViewModelTest : BaseViewModelTest() {
private val clipboardManager: BitwardenClipboardManager = mockk {
every { setText(any<String>()) } just runs
}
private val policyManager: PolicyManager = mockk {
every {
getActivePolicies(type = PolicyTypeJson.PERSONAL_OWNERSHIP)
} returns emptyList()
}
private val mutablePullToRefreshEnabledFlow = MutableStateFlow(false)
private val mutableIsIconLoadingDisabledFlow = MutableStateFlow(false)
@@ -93,7 +101,10 @@ class VaultViewModelTest : BaseViewModelTest() {
fun `initial state should be correct and should trigger a syncIfNecessary call`() {
val viewModel = createViewModel()
assertEquals(DEFAULT_STATE, viewModel.stateFlow.value)
verify { vaultRepository.syncIfNecessary() }
verify {
vaultRepository.syncIfNecessary()
policyManager.getActivePolicies(type = PolicyTypeJson.PERSONAL_OWNERSHIP)
}
}
@Test
@@ -143,7 +154,7 @@ class VaultViewModelTest : BaseViewModelTest() {
@Suppress("MaxLineLength")
@Test
fun `UserState updates with a non-null value when not switching accounts should update the account information in the state`() {
fun `UserState updates with a non-null value when not switching accounts should update the account information in the state when personal ownership enabled`() {
val viewModel = createViewModel()
assertEquals(
DEFAULT_STATE,
@@ -207,6 +218,82 @@ class VaultViewModelTest : BaseViewModelTest() {
)
}
@Suppress("MaxLineLength")
@Test
fun `UserState updates with a non-null value when not switching accounts should update the account information in the state when personal ownership disabled`() {
every {
policyManager.getActivePolicies(type = PolicyTypeJson.PERSONAL_OWNERSHIP)
} returns listOf(
SyncResponseJson.Policy(
organizationId = "Test Organization",
id = "testId",
type = PolicyTypeJson.PERSONAL_OWNERSHIP,
isEnabled = true,
data = null,
),
)
val viewModel = createViewModel()
assertEquals(
DEFAULT_STATE,
viewModel.stateFlow.value,
)
mutableUserStateFlow.value =
DEFAULT_USER_STATE.copy(
accounts = listOf(
UserState.Account(
userId = "activeUserId",
name = "Other User",
email = "active@bitwarden.com",
avatarColorHex = "#00aaaa",
environment = Environment.Us,
isPremium = true,
isLoggedIn = true,
isVaultUnlocked = true,
needsPasswordReset = false,
isBiometricsEnabled = false,
organizations = listOf(
Organization(
id = "organizationId",
name = "Test Organization",
),
),
),
),
)
assertEquals(
DEFAULT_STATE.copy(
appBarTitle = R.string.vaults.asText(),
avatarColorString = "#00aaaa",
initials = "OU",
accountSummaries = listOf(
AccountSummary(
userId = "activeUserId",
name = "Other User",
email = "active@bitwarden.com",
avatarColorHex = "#00aaaa",
environmentLabel = "bitwarden.com",
isActive = true,
isLoggedIn = true,
isVaultUnlocked = true,
),
),
vaultFilterData = VaultFilterData(
selectedVaultFilterType = VaultFilterType.AllVaults,
vaultFilterTypes = listOf(
VaultFilterType.AllVaults,
VaultFilterType.OrganizationVault(
organizationId = "organizationId",
organizationName = "Test Organization",
),
),
),
),
viewModel.stateFlow.value,
)
}
@Test
fun `on LockAccountClick should call lockVault for the given account`() {
val accountUserId = "userId"
@@ -1245,6 +1332,7 @@ class VaultViewModelTest : BaseViewModelTest() {
VaultViewModel(
authRepository = authRepository,
clipboardManager = clipboardManager,
policyManager = policyManager,
clock = clock,
settingsRepository = settingsRepository,
vaultRepository = vaultRepository,

View File

@@ -273,13 +273,13 @@ class UserStateExtensionsTest {
isBiometricsEnabled = false,
organizations = emptyList(),
)
.toVaultFilterData(),
.toVaultFilterData(isIndividualVaultDisabled = false),
)
}
@Suppress("MaxLineLength")
@Test
fun `toVaultFilterData for an account with organizations should return data with the available types in the correct order`() {
fun `toVaultFilterData for an account with organizations and individual vault enabled should return data with the available types in the correct order`() {
assertEquals(
VaultFilterData(
selectedVaultFilterType = VaultFilterType.AllVaults,
@@ -318,7 +318,55 @@ class UserStateExtensionsTest {
),
),
)
.toVaultFilterData(),
.toVaultFilterData(
isIndividualVaultDisabled = false,
),
)
}
@Suppress("MaxLineLength")
@Test
fun `toVaultFilterData for an account with organizations and individual vault disabled should return data with the available types in the correct order`() {
assertEquals(
VaultFilterData(
selectedVaultFilterType = VaultFilterType.AllVaults,
vaultFilterTypes = listOf(
VaultFilterType.AllVaults,
VaultFilterType.OrganizationVault(
organizationId = "organizationId-A",
organizationName = "Organization A",
),
VaultFilterType.OrganizationVault(
organizationId = "organizationId-B",
organizationName = "Organization B",
),
),
),
UserState.Account(
userId = "activeUserId",
name = "name",
email = "email",
avatarColorHex = "avatarColorHex",
environment = Environment.Us,
isPremium = true,
isLoggedIn = true,
isVaultUnlocked = true,
needsPasswordReset = false,
isBiometricsEnabled = false,
organizations = listOf(
Organization(
id = "organizationId-B",
name = "Organization B",
),
Organization(
id = "organizationId-A",
name = "Organization A",
),
),
)
.toVaultFilterData(
isIndividualVaultDisabled = true,
),
)
}
}

View File

@@ -47,6 +47,7 @@ class VaultAddItemStateExtensionsTest {
notes = "mockNotes-1",
selectedOwnerId = "mockOwnerId-1",
),
isIndividualVaultDisabled = false,
type = VaultAddEditState.ViewState.Content.ItemType.Login(
username = "mockUsername-1",
password = "mockPassword-1",
@@ -124,6 +125,7 @@ class VaultAddItemStateExtensionsTest {
notes = "mockNotes-1",
selectedOwnerId = "mockOwnerId-1",
),
isIndividualVaultDisabled = false,
type = VaultAddEditState.ViewState.Content.ItemType.Login(
username = "mockUsername-1",
password = "mockPassword-1",
@@ -212,6 +214,7 @@ class VaultAddItemStateExtensionsTest {
VaultAddEditState.Custom.HiddenField("testId", "TestHidden", "TestHidden"),
),
),
isIndividualVaultDisabled = false,
type = VaultAddEditState.ViewState.Content.ItemType.SecureNotes,
)
@@ -281,6 +284,7 @@ class VaultAddItemStateExtensionsTest {
selectedOwnerId = "mockOwnerId-1",
customFieldData = emptyList(),
),
isIndividualVaultDisabled = false,
type = VaultAddEditState.ViewState.Content.ItemType.SecureNotes,
)
@@ -314,6 +318,7 @@ class VaultAddItemStateExtensionsTest {
notes = "mockNotes-1",
selectedOwnerId = "mockOwnerId-1",
),
isIndividualVaultDisabled = false,
type = VaultAddEditState.ViewState.Content.ItemType.Identity(
selectedTitle = VaultIdentityTitle.MR,
firstName = "mockFirstName",
@@ -411,6 +416,7 @@ class VaultAddItemStateExtensionsTest {
notes = "mockNotes-1",
selectedOwnerId = "mockOwnerId-1",
),
isIndividualVaultDisabled = false,
type = VaultAddEditState.ViewState.Content.ItemType.Identity(
selectedTitle = VaultIdentityTitle.MR,
firstName = "mockFirstName",