1
0
mirror of https://github.com/bitwarden/server synced 2026-02-17 18:09:11 +00:00

Move filtering out of db layer

This commit is contained in:
Thomas Rittson
2026-01-01 13:51:10 +10:00
parent a6fcee7094
commit 21d7276625
6 changed files with 196 additions and 51 deletions

View File

@@ -6,10 +6,10 @@ using Xunit;
namespace Bit.Infrastructure.IntegrationTest.AdminConsole.Repositories.CollectionRepository;
public class UpsertDefaultCollectionsBulkTests
public class CreateDefaultCollectionsBulkTests
{
[Theory, DatabaseData]
public async Task UpsertDefaultCollectionsBulkAsync_ShouldCreateDefaultCollection_WhenUsersDoNotHaveDefaultCollection(
public async Task CreateDefaultCollectionsBulkAsync_ShouldCreateDefaultCollection_WhenUsersDoNotHaveDefaultCollection(
IOrganizationRepository organizationRepository,
IUserRepository userRepository,
IOrganizationUserRepository organizationUserRepository,
@@ -27,7 +27,7 @@ public class UpsertDefaultCollectionsBulkTests
var defaultCollectionName = $"default-name-{organization.Id}";
// Act
await collectionRepository.UpsertDefaultCollectionsBulkAsync(organization.Id, affectedOrgUserIds, defaultCollectionName);
await collectionRepository.CreateDefaultCollectionsBulkAsync(organization.Id, affectedOrgUserIds, defaultCollectionName);
// Assert
await AssertAllUsersHaveOneDefaultCollectionAsync(collectionRepository, resultOrganizationUsers, organization.Id);
@@ -37,7 +37,7 @@ public class UpsertDefaultCollectionsBulkTests
}
[Theory, DatabaseData]
public async Task UpsertDefaultCollectionsBulkAsync_ShouldUpsertCreateDefaultCollection_ForUsersWithAndWithoutDefaultCollectionsExist(
public async Task CreateDefaultCollectionsBulkAsync_CreatesForNewUsersOnly_WhenCallerFiltersExisting(
IOrganizationRepository organizationRepository,
IUserRepository userRepository,
IOrganizationUserRepository organizationUserRepository,
@@ -64,18 +64,20 @@ public class UpsertDefaultCollectionsBulkTests
var affectedOrgUsers = newOrganizationUsers.Concat(arrangedOrganizationUsers);
var affectedOrgUserIds = affectedOrgUsers.Select(organizationUser => organizationUser.Id).ToList();
// Act
await collectionRepository.UpsertDefaultCollectionsBulkAsync(organization.Id, affectedOrgUserIds, defaultCollectionName);
// Act - Caller filters out existing users (new pattern)
var existingSemaphores = await collectionRepository.GetDefaultCollectionSemaphoresAsync(affectedOrgUserIds);
var usersNeedingCollections = affectedOrgUserIds.Except(existingSemaphores).ToList();
await collectionRepository.CreateDefaultCollectionsBulkAsync(organization.Id, usersNeedingCollections, defaultCollectionName);
// Assert
await AssertAllUsersHaveOneDefaultCollectionAsync(collectionRepository, arrangedOrganizationUsers, organization.Id);
// Assert - All users now have exactly one collection
await AssertAllUsersHaveOneDefaultCollectionAsync(collectionRepository, affectedOrgUsers, organization.Id);
await AssertSempahoresCreatedAsync(collectionRepository, affectedOrgUserIds);
await CleanupAsync(organizationRepository, userRepository, organization, affectedOrgUsers);
}
[Theory, DatabaseData]
public async Task UpsertDefaultCollectionsBulkAsync_ShouldNotCreateDefaultCollection_WhenUsersAlreadyHaveOne(
public async Task CreateDefaultCollectionsBulkAsync_ThrowsException_WhenUsersAlreadyHaveOne(
IOrganizationRepository organizationRepository,
IUserRepository userRepository,
IOrganizationUserRepository organizationUserRepository,
@@ -94,21 +96,61 @@ public class UpsertDefaultCollectionsBulkTests
await CreateUsersWithExistingDefaultCollectionsAsync(collectionRepository, organization.Id, affectedOrgUserIds, defaultCollectionName, resultOrganizationUsers);
// Act
await collectionRepository.UpsertDefaultCollectionsBulkAsync(organization.Id, affectedOrgUserIds, defaultCollectionName);
// Act - Try to create again, should throw database constraint exception
await Assert.ThrowsAnyAsync<Exception>(() =>
collectionRepository.CreateDefaultCollectionsBulkAsync(organization.Id, affectedOrgUserIds, defaultCollectionName));
// Assert
// Assert - Original collections should remain unchanged
await AssertAllUsersHaveOneDefaultCollectionAsync(collectionRepository, resultOrganizationUsers, organization.Id);
await AssertSempahoresCreatedAsync(collectionRepository, affectedOrgUserIds);
await CleanupAsync(organizationRepository, userRepository, organization, resultOrganizationUsers);
}
[Theory, DatabaseData]
public async Task CreateDefaultCollectionsBulkAsync_ThrowsException_WhenDuplicatesNotFiltered(
IOrganizationRepository organizationRepository,
IUserRepository userRepository,
IOrganizationUserRepository organizationUserRepository,
ICollectionRepository collectionRepository)
{
// Arrange
var organization = await organizationRepository.CreateTestOrganizationAsync();
var existingUser = await CreateUserForOrgAsync(userRepository, organizationUserRepository, organization);
var newUser = await CreateUserForOrgAsync(userRepository, organizationUserRepository, organization);
var defaultCollectionName = $"default-name-{organization.Id}";
// Create collection for existing user
await collectionRepository.CreateDefaultCollectionsBulkAsync(organization.Id, [existingUser.Id], defaultCollectionName);
// Act - Try to create for both without filtering (incorrect usage)
await Assert.ThrowsAnyAsync<Exception>(() =>
collectionRepository.CreateDefaultCollectionsBulkAsync(
organization.Id,
[existingUser.Id, newUser.Id],
defaultCollectionName));
// Assert - Verify existing user still has collection
var existingUserCollections = await collectionRepository.GetManyByUserIdAsync(existingUser.UserId!.Value);
var existingUserDefaultCollection = existingUserCollections
.SingleOrDefault(c => c.OrganizationId == organization.Id && c.Type == CollectionType.DefaultUserCollection);
Assert.NotNull(existingUserDefaultCollection);
// Verify new user does NOT have collection (transaction rolled back)
var newUserCollections = await collectionRepository.GetManyByUserIdAsync(newUser.UserId!.Value);
var newUserDefaultCollection = newUserCollections
.FirstOrDefault(c => c.OrganizationId == organization.Id && c.Type == CollectionType.DefaultUserCollection);
Assert.Null(newUserDefaultCollection);
await CleanupAsync(organizationRepository, userRepository, organization, [existingUser, newUser]);
}
private static async Task CreateUsersWithExistingDefaultCollectionsAsync(ICollectionRepository collectionRepository,
Guid organizationId, IEnumerable<Guid> affectedOrgUserIds, string defaultCollectionName,
OrganizationUser[] resultOrganizationUsers)
{
await collectionRepository.UpsertDefaultCollectionsBulkAsync(organizationId, affectedOrgUserIds, defaultCollectionName);
await collectionRepository.CreateDefaultCollectionsBulkAsync(organizationId, affectedOrgUserIds, defaultCollectionName);
await AssertAllUsersHaveOneDefaultCollectionAsync(collectionRepository, resultOrganizationUsers, organizationId);
}