using Bit.Core.AdminConsole.Entities; using Bit.Core.Entities; using Bit.Core.Enums; using Bit.Core.Repositories; using Xunit; namespace Bit.Infrastructure.IntegrationTest.AdminConsole.Repositories.CollectionRepository; /// /// Shared tests for CreateDefaultCollections methods - both bulk and non-bulk implementations, /// as they share the same behavior. Both test suites call the tests in this class. /// public static class CreateDefaultCollectionsSharedTests { public static async Task CreatesDefaultCollections_Success( Func, string, Task> createDefaultCollectionsFunc, IOrganizationRepository organizationRepository, IUserRepository userRepository, IOrganizationUserRepository organizationUserRepository, ICollectionRepository collectionRepository) { // Arrange var organization = await organizationRepository.CreateTestOrganizationAsync(); var resultOrganizationUsers = await Task.WhenAll( CreateUserForOrgAsync(userRepository, organizationUserRepository, organization), CreateUserForOrgAsync(userRepository, organizationUserRepository, organization) ); var affectedOrgUserIds = resultOrganizationUsers.Select(organizationUser => organizationUser.Id).ToList(); var defaultCollectionName = $"default-name-{organization.Id}"; // Act await createDefaultCollectionsFunc(organization.Id, affectedOrgUserIds, defaultCollectionName); // Assert await AssertAllUsersHaveOneDefaultCollectionAsync(collectionRepository, resultOrganizationUsers, organization.Id); await CleanupAsync(organizationRepository, userRepository, organization, resultOrganizationUsers); } public static async Task CreatesForNewUsersOnly_AndIgnoresExistingUsers( Func, string, Task> createDefaultCollectionsFunc, IOrganizationRepository organizationRepository, IUserRepository userRepository, IOrganizationUserRepository organizationUserRepository, ICollectionRepository collectionRepository) { // Arrange var organization = await organizationRepository.CreateTestOrganizationAsync(); var arrangedOrganizationUsers = await Task.WhenAll( CreateUserForOrgAsync(userRepository, organizationUserRepository, organization), CreateUserForOrgAsync(userRepository, organizationUserRepository, organization) ); var arrangedOrgUserIds = arrangedOrganizationUsers.Select(organizationUser => organizationUser.Id).ToList(); var defaultCollectionName = $"default-name-{organization.Id}"; await CreateUsersWithExistingDefaultCollectionsAsync(createDefaultCollectionsFunc, collectionRepository, organization.Id, arrangedOrgUserIds, defaultCollectionName, arrangedOrganizationUsers); var newOrganizationUsers = new List { await CreateUserForOrgAsync(userRepository, organizationUserRepository, organization) }; var affectedOrgUsers = newOrganizationUsers.Concat(arrangedOrganizationUsers).ToList(); var affectedOrgUserIds = affectedOrgUsers.Select(organizationUser => organizationUser.Id).ToList(); // Act await createDefaultCollectionsFunc(organization.Id, affectedOrgUserIds, defaultCollectionName); // Assert await AssertAllUsersHaveOneDefaultCollectionAsync(collectionRepository, affectedOrgUsers, organization.Id); await CleanupAsync(organizationRepository, userRepository, organization, affectedOrgUsers); } public static async Task IgnoresAllExistingUsers( Func, string, Task> createDefaultCollectionsFunc, IOrganizationRepository organizationRepository, IUserRepository userRepository, IOrganizationUserRepository organizationUserRepository, ICollectionRepository collectionRepository) { // Arrange var organization = await organizationRepository.CreateTestOrganizationAsync(); var resultOrganizationUsers = await Task.WhenAll( CreateUserForOrgAsync(userRepository, organizationUserRepository, organization), CreateUserForOrgAsync(userRepository, organizationUserRepository, organization) ); var affectedOrgUserIds = resultOrganizationUsers.Select(organizationUser => organizationUser.Id).ToList(); var defaultCollectionName = $"default-name-{organization.Id}"; await CreateUsersWithExistingDefaultCollectionsAsync(createDefaultCollectionsFunc, collectionRepository, organization.Id, affectedOrgUserIds, defaultCollectionName, resultOrganizationUsers); // Act - Try to create again, should silently filter and not create duplicates await createDefaultCollectionsFunc(organization.Id, affectedOrgUserIds, defaultCollectionName); // Assert - Original collections should remain unchanged, still only one per user await AssertAllUsersHaveOneDefaultCollectionAsync(collectionRepository, resultOrganizationUsers, organization.Id); await CleanupAsync(organizationRepository, userRepository, organization, resultOrganizationUsers); } private static async Task CreateUsersWithExistingDefaultCollectionsAsync( Func, string, Task> createDefaultCollectionsFunc, ICollectionRepository collectionRepository, Guid organizationId, IEnumerable affectedOrgUserIds, string defaultCollectionName, OrganizationUser[] resultOrganizationUsers) { await createDefaultCollectionsFunc(organizationId, affectedOrgUserIds, defaultCollectionName); await AssertAllUsersHaveOneDefaultCollectionAsync(collectionRepository, resultOrganizationUsers, organizationId); } private static async Task AssertAllUsersHaveOneDefaultCollectionAsync(ICollectionRepository collectionRepository, IEnumerable organizationUsers, Guid organizationId) { foreach (var organizationUser in organizationUsers) { var collectionDetails = await collectionRepository.GetManyByUserIdAsync(organizationUser!.UserId.Value); var defaultCollection = collectionDetails .SingleOrDefault(collectionDetail => collectionDetail.OrganizationId == organizationId && collectionDetail.Type == CollectionType.DefaultUserCollection); Assert.NotNull(defaultCollection); } } private static async Task CreateUserForOrgAsync(IUserRepository userRepository, IOrganizationUserRepository organizationUserRepository, Organization organization) { var user = await userRepository.CreateTestUserAsync(); var orgUser = await organizationUserRepository.CreateTestOrganizationUserAsync(organization, user); return orgUser; } private static async Task CleanupAsync(IOrganizationRepository organizationRepository, IUserRepository userRepository, Organization organization, IEnumerable organizationUsers) { await organizationRepository.DeleteAsync(organization); await userRepository.DeleteManyAsync( organizationUsers .Where(organizationUser => organizationUser.UserId != null) .Select(organizationUser => new User() { Id = organizationUser.UserId.Value }) ); } }