1
0
mirror of https://github.com/bitwarden/server synced 2025-12-10 13:23:27 +00:00

[PM-25097] Remove DeleteClaimedUserAccountRefactor flag (#6364)

* Remove feature flag
* Remove old code
This commit is contained in:
Thomas Rittson
2025-09-25 10:14:02 +10:00
committed by GitHub
parent f0953ed6b0
commit b83f95f78c
18 changed files with 86 additions and 930 deletions

View File

@@ -1,4 +1,4 @@
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.DeleteClaimedAccountvNext;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.DeleteClaimedAccount;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
using Bit.Core.Entities;
using Bit.Core.Enums;
@@ -17,12 +17,12 @@ using Xunit;
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.OrganizationUsers.DeleteClaimedAccountvNext;
[SutProviderCustomize]
public class DeleteClaimedOrganizationUserAccountCommandvNextTests
public class DeleteClaimedOrganizationUserAccountCommandTests
{
[Theory]
[BitAutoData]
public async Task DeleteUserAsync_WithValidSingleUser_CallsDeleteManyUsersAsync(
SutProvider<DeleteClaimedOrganizationUserAccountCommandvNext> sutProvider,
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider,
User user,
Guid organizationId,
Guid deletingUserId,
@@ -65,7 +65,7 @@ public class DeleteClaimedOrganizationUserAccountCommandvNextTests
[Theory]
[BitAutoData]
public async Task DeleteManyUsersAsync_WithEmptyUserIds_ReturnsEmptyResults(
SutProvider<DeleteClaimedOrganizationUserAccountCommandvNext> sutProvider,
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider,
Guid organizationId,
Guid deletingUserId)
{
@@ -77,7 +77,7 @@ public class DeleteClaimedOrganizationUserAccountCommandvNextTests
[Theory]
[BitAutoData]
public async Task DeleteManyUsersAsync_WithValidUsers_DeletesUsersAndLogsEvents(
SutProvider<DeleteClaimedOrganizationUserAccountCommandvNext> sutProvider,
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider,
User user1,
User user2,
Guid organizationId,
@@ -135,7 +135,7 @@ public class DeleteClaimedOrganizationUserAccountCommandvNextTests
[Theory]
[BitAutoData]
public async Task DeleteManyUsersAsync_WithValidationErrors_ReturnsErrorResults(
SutProvider<DeleteClaimedOrganizationUserAccountCommandvNext> sutProvider,
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider,
Guid organizationId,
Guid orgUserId1,
Guid orgUserId2,
@@ -183,7 +183,7 @@ public class DeleteClaimedOrganizationUserAccountCommandvNextTests
[Theory]
[BitAutoData]
public async Task DeleteManyUsersAsync_WithMixedValidationResults_HandlesPartialSuccessCorrectly(
SutProvider<DeleteClaimedOrganizationUserAccountCommandvNext> sutProvider,
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider,
User validUser,
Guid organizationId,
Guid validOrgUserId,
@@ -243,7 +243,7 @@ public class DeleteClaimedOrganizationUserAccountCommandvNextTests
[Theory]
[BitAutoData]
public async Task DeleteManyUsersAsync_CancelPremiumsAsync_HandlesGatewayExceptionAndLogsWarning(
SutProvider<DeleteClaimedOrganizationUserAccountCommandvNext> sutProvider,
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider,
User user,
Guid organizationId,
Guid deletingUserId,
@@ -285,7 +285,7 @@ public class DeleteClaimedOrganizationUserAccountCommandvNextTests
await sutProvider.GetDependency<IUserService>().Received(1).CancelPremiumAsync(user);
await AssertSuccessfulUserOperations(sutProvider, [user], [orgUser]);
sutProvider.GetDependency<ILogger<DeleteClaimedOrganizationUserAccountCommandvNext>>()
sutProvider.GetDependency<ILogger<DeleteClaimedOrganizationUserAccountCommand>>()
.Received(1)
.Log(
LogLevel.Warning,
@@ -299,7 +299,7 @@ public class DeleteClaimedOrganizationUserAccountCommandvNextTests
[Theory]
[BitAutoData]
public async Task CreateInternalRequests_CreatesCorrectRequestsForAllUsers(
SutProvider<DeleteClaimedOrganizationUserAccountCommandvNext> sutProvider,
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider,
User user1,
User user2,
Guid organizationId,
@@ -326,7 +326,7 @@ public class DeleteClaimedOrganizationUserAccountCommandvNextTests
.GetUsersOrganizationClaimedStatusAsync(organizationId, Arg.Any<IEnumerable<Guid>>())
.Returns(claimedStatuses);
sutProvider.GetDependency<IDeleteClaimedOrganizationUserAccountValidatorvNext>()
sutProvider.GetDependency<IDeleteClaimedOrganizationUserAccountValidator>()
.ValidateAsync(Arg.Any<IEnumerable<DeleteUserValidationRequest>>())
.Returns(callInfo =>
{
@@ -338,7 +338,7 @@ public class DeleteClaimedOrganizationUserAccountCommandvNextTests
await sutProvider.Sut.DeleteManyUsersAsync(organizationId, orgUserIds, deletingUserId);
// Assert
await sutProvider.GetDependency<IDeleteClaimedOrganizationUserAccountValidatorvNext>()
await sutProvider.GetDependency<IDeleteClaimedOrganizationUserAccountValidator>()
.Received(1)
.ValidateAsync(Arg.Is<IEnumerable<DeleteUserValidationRequest>>(requests =>
requests.Count() == 2 &&
@@ -359,7 +359,7 @@ public class DeleteClaimedOrganizationUserAccountCommandvNextTests
[Theory]
[BitAutoData]
public async Task GetUsersAsync_WithNullUserIds_ReturnsEmptyCollection(
SutProvider<DeleteClaimedOrganizationUserAccountCommandvNext> sutProvider,
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider,
Guid organizationId,
Guid deletingUserId,
[OrganizationUser] OrganizationUser orgUserWithoutUserId)
@@ -374,7 +374,7 @@ public class DeleteClaimedOrganizationUserAccountCommandvNextTests
.GetManyAsync(Arg.Is<IEnumerable<Guid>>(ids => !ids.Any()))
.Returns([]);
sutProvider.GetDependency<IDeleteClaimedOrganizationUserAccountValidatorvNext>()
sutProvider.GetDependency<IDeleteClaimedOrganizationUserAccountValidator>()
.ValidateAsync(Arg.Any<IEnumerable<DeleteUserValidationRequest>>())
.Returns(callInfo =>
{
@@ -386,7 +386,7 @@ public class DeleteClaimedOrganizationUserAccountCommandvNextTests
await sutProvider.Sut.DeleteManyUsersAsync(organizationId, [orgUserWithoutUserId.Id], deletingUserId);
// Assert
await sutProvider.GetDependency<IDeleteClaimedOrganizationUserAccountValidatorvNext>()
await sutProvider.GetDependency<IDeleteClaimedOrganizationUserAccountValidator>()
.Received(1)
.ValidateAsync(Arg.Is<IEnumerable<DeleteUserValidationRequest>>(requests =>
requests.Count() == 1 &&
@@ -406,7 +406,7 @@ public class DeleteClaimedOrganizationUserAccountCommandvNextTests
ValidationResultHelpers.Invalid(request, error);
private static void SetupRepositoryMocks(
SutProvider<DeleteClaimedOrganizationUserAccountCommandvNext> sutProvider,
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider,
ICollection<OrganizationUser> orgUsers,
IEnumerable<User> users,
Guid organizationId,
@@ -426,16 +426,16 @@ public class DeleteClaimedOrganizationUserAccountCommandvNextTests
}
private static void SetupValidatorMock(
SutProvider<DeleteClaimedOrganizationUserAccountCommandvNext> sutProvider,
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider,
IEnumerable<ValidationResult<DeleteUserValidationRequest>> validationResults)
{
sutProvider.GetDependency<IDeleteClaimedOrganizationUserAccountValidatorvNext>()
sutProvider.GetDependency<IDeleteClaimedOrganizationUserAccountValidator>()
.ValidateAsync(Arg.Any<IEnumerable<DeleteUserValidationRequest>>())
.Returns(validationResults);
}
private static async Task AssertSuccessfulUserOperations(
SutProvider<DeleteClaimedOrganizationUserAccountCommandvNext> sutProvider,
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider,
IEnumerable<User> expectedUsers,
IEnumerable<OrganizationUser> expectedOrgUsers)
{
@@ -457,7 +457,7 @@ public class DeleteClaimedOrganizationUserAccountCommandvNextTests
events.Any(e => e.Item1.Id == expectedOrgUser.Id && e.Item2 == EventType.OrganizationUser_Deleted))));
}
private static async Task AssertNoUserOperations(SutProvider<DeleteClaimedOrganizationUserAccountCommandvNext> sutProvider)
private static async Task AssertNoUserOperations(SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider)
{
await sutProvider.GetDependency<IUserRepository>().DidNotReceiveWithAnyArgs().DeleteManyAsync(default);
await sutProvider.GetDependency<IPushNotificationService>().DidNotReceiveWithAnyArgs().PushLogOutAsync(default);

View File

@@ -1,4 +1,4 @@
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.DeleteClaimedAccountvNext;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.DeleteClaimedAccount;
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Context;
using Bit.Core.Entities;
@@ -13,12 +13,12 @@ using Xunit;
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.OrganizationUsers.DeleteClaimedAccountvNext;
[SutProviderCustomize]
public class DeleteClaimedOrganizationUserAccountValidatorvNextTests
public class DeleteClaimedOrganizationUserAccountValidatorTests
{
[Theory]
[BitAutoData]
public async Task ValidateAsync_WithValidSingleRequest_ReturnsValidResult(
SutProvider<DeleteClaimedOrganizationUserAccountValidatorvNext> sutProvider,
SutProvider<DeleteClaimedOrganizationUserAccountValidator> sutProvider,
User user,
Guid organizationId,
Guid deletingUserId,
@@ -50,7 +50,7 @@ public class DeleteClaimedOrganizationUserAccountValidatorvNextTests
[Theory]
[BitAutoData]
public async Task ValidateAsync_WithMultipleValidRequests_ReturnsAllValidResults(
SutProvider<DeleteClaimedOrganizationUserAccountValidatorvNext> sutProvider,
SutProvider<DeleteClaimedOrganizationUserAccountValidator> sutProvider,
User user1,
User user2,
Guid organizationId,
@@ -97,7 +97,7 @@ public class DeleteClaimedOrganizationUserAccountValidatorvNextTests
[Theory]
[BitAutoData]
public async Task ValidateAsync_WithNullUser_ReturnsUserNotFoundError(
SutProvider<DeleteClaimedOrganizationUserAccountValidatorvNext> sutProvider,
SutProvider<DeleteClaimedOrganizationUserAccountValidator> sutProvider,
Guid organizationId,
Guid deletingUserId,
[OrganizationUser] OrganizationUser organizationUser)
@@ -123,7 +123,7 @@ public class DeleteClaimedOrganizationUserAccountValidatorvNextTests
[Theory]
[BitAutoData]
public async Task ValidateAsync_WithNullOrganizationUser_ReturnsUserNotFoundError(
SutProvider<DeleteClaimedOrganizationUserAccountValidatorvNext> sutProvider,
SutProvider<DeleteClaimedOrganizationUserAccountValidator> sutProvider,
User user,
Guid organizationId,
Guid deletingUserId)
@@ -149,7 +149,7 @@ public class DeleteClaimedOrganizationUserAccountValidatorvNextTests
[Theory]
[BitAutoData]
public async Task ValidateAsync_WithInvitedUser_ReturnsInvalidUserStatusError(
SutProvider<DeleteClaimedOrganizationUserAccountValidatorvNext> sutProvider,
SutProvider<DeleteClaimedOrganizationUserAccountValidator> sutProvider,
User user,
Guid organizationId,
Guid deletingUserId,
@@ -178,7 +178,7 @@ public class DeleteClaimedOrganizationUserAccountValidatorvNextTests
[Theory]
[BitAutoData]
public async Task ValidateAsync_WhenDeletingYourself_ReturnsCannotDeleteYourselfError(
SutProvider<DeleteClaimedOrganizationUserAccountValidatorvNext> sutProvider,
SutProvider<DeleteClaimedOrganizationUserAccountValidator> sutProvider,
User user,
Guid organizationId,
[OrganizationUser] OrganizationUser organizationUser)
@@ -206,7 +206,7 @@ public class DeleteClaimedOrganizationUserAccountValidatorvNextTests
[Theory]
[BitAutoData]
public async Task ValidateAsync_WithUnclaimedUser_ReturnsUserNotClaimedError(
SutProvider<DeleteClaimedOrganizationUserAccountValidatorvNext> sutProvider,
SutProvider<DeleteClaimedOrganizationUserAccountValidator> sutProvider,
User user,
Guid organizationId,
Guid deletingUserId,
@@ -235,7 +235,7 @@ public class DeleteClaimedOrganizationUserAccountValidatorvNextTests
[Theory]
[BitAutoData]
public async Task ValidateAsync_DeletingOwnerWhenCurrentUserIsNotOwner_ReturnsCannotDeleteOwnersError(
SutProvider<DeleteClaimedOrganizationUserAccountValidatorvNext> sutProvider,
SutProvider<DeleteClaimedOrganizationUserAccountValidator> sutProvider,
User user,
Guid organizationId,
Guid deletingUserId,
@@ -266,7 +266,7 @@ public class DeleteClaimedOrganizationUserAccountValidatorvNextTests
[Theory]
[BitAutoData]
public async Task ValidateAsync_DeletingOwnerWhenCurrentUserIsOwner_ReturnsValidResult(
SutProvider<DeleteClaimedOrganizationUserAccountValidatorvNext> sutProvider,
SutProvider<DeleteClaimedOrganizationUserAccountValidator> sutProvider,
User user,
Guid organizationId,
Guid deletingUserId,
@@ -296,7 +296,7 @@ public class DeleteClaimedOrganizationUserAccountValidatorvNextTests
[Theory]
[BitAutoData]
public async Task ValidateAsync_WithSoleOwnerOfOrganization_ReturnsSoleOwnerError(
SutProvider<DeleteClaimedOrganizationUserAccountValidatorvNext> sutProvider,
SutProvider<DeleteClaimedOrganizationUserAccountValidator> sutProvider,
User user,
Guid organizationId,
Guid deletingUserId,
@@ -331,7 +331,7 @@ public class DeleteClaimedOrganizationUserAccountValidatorvNextTests
[Theory]
[BitAutoData]
public async Task ValidateAsync_WithSoleProviderOwner_ReturnsSoleProviderError(
SutProvider<DeleteClaimedOrganizationUserAccountValidatorvNext> sutProvider,
SutProvider<DeleteClaimedOrganizationUserAccountValidator> sutProvider,
User user,
Guid organizationId,
Guid deletingUserId,
@@ -366,7 +366,7 @@ public class DeleteClaimedOrganizationUserAccountValidatorvNextTests
[Theory]
[BitAutoData]
public async Task ValidateAsync_CustomUserDeletingAdmin_ReturnsCannotDeleteAdminsError(
SutProvider<DeleteClaimedOrganizationUserAccountValidatorvNext> sutProvider,
SutProvider<DeleteClaimedOrganizationUserAccountValidator> sutProvider,
User user,
Guid organizationId,
Guid deletingUserId,
@@ -397,7 +397,7 @@ public class DeleteClaimedOrganizationUserAccountValidatorvNextTests
[Theory]
[BitAutoData]
public async Task ValidateAsync_AdminDeletingAdmin_ReturnsValidResult(
SutProvider<DeleteClaimedOrganizationUserAccountValidatorvNext> sutProvider,
SutProvider<DeleteClaimedOrganizationUserAccountValidator> sutProvider,
User user,
Guid organizationId,
Guid deletingUserId,
@@ -427,7 +427,7 @@ public class DeleteClaimedOrganizationUserAccountValidatorvNextTests
[Theory]
[BitAutoData]
public async Task ValidateAsync_WithMixedValidAndInvalidRequests_ReturnsCorrespondingResults(
SutProvider<DeleteClaimedOrganizationUserAccountValidatorvNext> sutProvider,
SutProvider<DeleteClaimedOrganizationUserAccountValidator> sutProvider,
User validUser,
User invalidUser,
Guid organizationId,
@@ -475,7 +475,7 @@ public class DeleteClaimedOrganizationUserAccountValidatorvNextTests
}
private static void SetupMocks(
SutProvider<DeleteClaimedOrganizationUserAccountValidatorvNext> sutProvider,
SutProvider<DeleteClaimedOrganizationUserAccountValidator> sutProvider,
Guid organizationId,
Guid userId,
OrganizationUserType currentUserType = OrganizationUserType.Owner)

View File

@@ -1,526 +0,0 @@
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
using Bit.Core.Context;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Test.AutoFixture.OrganizationUserFixtures;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using NSubstitute;
using Xunit;
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.OrganizationUsers;
[SutProviderCustomize]
public class DeleteClaimedOrganizationUserAccountCommandTests
{
[Theory]
[BitAutoData]
public async Task DeleteUserAsync_WithValidUser_DeletesUserAndLogsEvent(
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider, User user, Guid deletingUserId,
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.User)] OrganizationUser organizationUser)
{
// Arrange
organizationUser.UserId = user.Id;
sutProvider.GetDependency<IUserRepository>()
.GetByIdAsync(user.Id)
.Returns(user);
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetByIdAsync(organizationUser.Id)
.Returns(organizationUser);
sutProvider.GetDependency<IGetOrganizationUsersClaimedStatusQuery>()
.GetUsersOrganizationClaimedStatusAsync(
organizationUser.OrganizationId,
Arg.Is<IEnumerable<Guid>>(ids => ids.Contains(organizationUser.Id)))
.Returns(new Dictionary<Guid, bool> { { organizationUser.Id, true } });
sutProvider.GetDependency<IHasConfirmedOwnersExceptQuery>()
.HasConfirmedOwnersExceptAsync(
organizationUser.OrganizationId,
Arg.Is<IEnumerable<Guid>>(ids => ids.Contains(organizationUser.Id)),
includeProvider: Arg.Any<bool>())
.Returns(true);
// Act
await sutProvider.Sut.DeleteUserAsync(organizationUser.OrganizationId, organizationUser.Id, deletingUserId);
// Assert
await sutProvider.GetDependency<IUserService>().Received(1).DeleteAsync(user);
await sutProvider.GetDependency<IEventService>().Received(1)
.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Deleted);
}
[Theory]
[BitAutoData]
public async Task DeleteUserAsync_WithUserNotFound_ThrowsException(
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider,
Guid organizationId, Guid organizationUserId)
{
// Arrange
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetByIdAsync(organizationUserId)
.Returns((OrganizationUser?)null);
// Act
var exception = await Assert.ThrowsAsync<NotFoundException>(() =>
sutProvider.Sut.DeleteUserAsync(organizationId, organizationUserId, null));
// Assert
Assert.Equal("Member not found.", exception.Message);
await sutProvider.GetDependency<IUserService>().Received(0).DeleteAsync(Arg.Any<User>());
await sutProvider.GetDependency<IEventService>().Received(0)
.LogOrganizationUserEventAsync(Arg.Any<OrganizationUser>(), Arg.Any<EventType>(), Arg.Any<DateTime?>());
}
[Theory]
[BitAutoData]
public async Task DeleteUserAsync_DeletingYourself_ThrowsException(
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider,
User user,
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.User)] OrganizationUser organizationUser,
Guid deletingUserId)
{
// Arrange
organizationUser.UserId = user.Id = deletingUserId;
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetByIdAsync(organizationUser.Id)
.Returns(organizationUser);
sutProvider.GetDependency<IUserRepository>().GetByIdAsync(user.Id)
.Returns(user);
// Act
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
sutProvider.Sut.DeleteUserAsync(organizationUser.OrganizationId, organizationUser.Id, deletingUserId));
// Assert
Assert.Equal("You cannot delete yourself.", exception.Message);
await sutProvider.GetDependency<IUserService>().Received(0).DeleteAsync(Arg.Any<User>());
await sutProvider.GetDependency<IEventService>().Received(0)
.LogOrganizationUserEventAsync(Arg.Any<OrganizationUser>(), Arg.Any<EventType>(), Arg.Any<DateTime?>());
}
[Theory]
[BitAutoData]
public async Task DeleteUserAsync_WhenUserIsInvited_ThrowsException(
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider,
[OrganizationUser(OrganizationUserStatusType.Invited, OrganizationUserType.User)] OrganizationUser organizationUser)
{
// Arrange
organizationUser.UserId = null;
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetByIdAsync(organizationUser.Id)
.Returns(organizationUser);
// Act
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
sutProvider.Sut.DeleteUserAsync(organizationUser.OrganizationId, organizationUser.Id, null));
// Assert
Assert.Equal("You cannot delete a member with Invited status.", exception.Message);
await sutProvider.GetDependency<IUserService>().Received(0).DeleteAsync(Arg.Any<User>());
await sutProvider.GetDependency<IEventService>().Received(0)
.LogOrganizationUserEventAsync(Arg.Any<OrganizationUser>(), Arg.Any<EventType>(), Arg.Any<DateTime?>());
}
[Theory]
[BitAutoData]
public async Task DeleteUserAsync_WhenCustomUserDeletesAdmin_ThrowsException(
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider, User user,
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Admin)] OrganizationUser organizationUser,
Guid deletingUserId)
{
// Arrange
organizationUser.UserId = user.Id;
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetByIdAsync(organizationUser.Id)
.Returns(organizationUser);
sutProvider.GetDependency<IUserRepository>().GetByIdAsync(user.Id)
.Returns(user);
sutProvider.GetDependency<ICurrentContext>()
.OrganizationCustom(organizationUser.OrganizationId)
.Returns(true);
// Act
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
sutProvider.Sut.DeleteUserAsync(organizationUser.OrganizationId, organizationUser.Id, deletingUserId));
// Assert
Assert.Equal("Custom users can not delete admins.", exception.Message);
await sutProvider.GetDependency<IUserService>().Received(0).DeleteAsync(Arg.Any<User>());
await sutProvider.GetDependency<IEventService>().Received(0)
.LogOrganizationUserEventAsync(Arg.Any<OrganizationUser>(), Arg.Any<EventType>(), Arg.Any<DateTime?>());
}
[Theory]
[BitAutoData]
public async Task DeleteUserAsync_DeletingOwnerWhenNotOwner_ThrowsException(
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider, User user,
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Owner)] OrganizationUser organizationUser,
Guid deletingUserId)
{
// Arrange
organizationUser.UserId = user.Id;
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetByIdAsync(organizationUser.Id)
.Returns(organizationUser);
sutProvider.GetDependency<IUserRepository>().GetByIdAsync(user.Id)
.Returns(user);
sutProvider.GetDependency<ICurrentContext>()
.OrganizationOwner(organizationUser.OrganizationId)
.Returns(false);
// Act
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
sutProvider.Sut.DeleteUserAsync(organizationUser.OrganizationId, organizationUser.Id, deletingUserId));
// Assert
Assert.Equal("Only owners can delete other owners.", exception.Message);
await sutProvider.GetDependency<IUserService>().Received(0).DeleteAsync(Arg.Any<User>());
await sutProvider.GetDependency<IEventService>().Received(0)
.LogOrganizationUserEventAsync(Arg.Any<OrganizationUser>(), Arg.Any<EventType>(), Arg.Any<DateTime?>());
}
[Theory]
[BitAutoData]
public async Task DeleteUserAsync_DeletingLastConfirmedOwner_ThrowsException(
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider, User user,
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Owner)] OrganizationUser organizationUser,
Guid deletingUserId)
{
// Arrange
organizationUser.UserId = user.Id;
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetByIdAsync(organizationUser.Id)
.Returns(organizationUser);
sutProvider.GetDependency<IUserRepository>().GetByIdAsync(user.Id)
.Returns(user);
sutProvider.GetDependency<ICurrentContext>()
.OrganizationOwner(organizationUser.OrganizationId)
.Returns(true);
sutProvider.GetDependency<IHasConfirmedOwnersExceptQuery>()
.HasConfirmedOwnersExceptAsync(
organizationUser.OrganizationId,
Arg.Is<IEnumerable<Guid>>(ids => ids.Contains(organizationUser.Id)),
includeProvider: Arg.Any<bool>())
.Returns(false);
// Act
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
sutProvider.Sut.DeleteUserAsync(organizationUser.OrganizationId, organizationUser.Id, deletingUserId));
// Assert
Assert.Equal("Organization must have at least one confirmed owner.", exception.Message);
await sutProvider.GetDependency<IUserService>().Received(0).DeleteAsync(Arg.Any<User>());
await sutProvider.GetDependency<IEventService>().Received(0)
.LogOrganizationUserEventAsync(Arg.Any<OrganizationUser>(), Arg.Any<EventType>(), Arg.Any<DateTime?>());
}
[Theory]
[BitAutoData]
public async Task DeleteUserAsync_WithUserNotManaged_ThrowsException(
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider, User user,
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.User)] OrganizationUser organizationUser)
{
// Arrange
organizationUser.UserId = user.Id;
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetByIdAsync(organizationUser.Id)
.Returns(organizationUser);
sutProvider.GetDependency<IUserRepository>().GetByIdAsync(user.Id)
.Returns(user);
sutProvider.GetDependency<IGetOrganizationUsersClaimedStatusQuery>()
.GetUsersOrganizationClaimedStatusAsync(organizationUser.OrganizationId, Arg.Any<IEnumerable<Guid>>())
.Returns(new Dictionary<Guid, bool> { { organizationUser.Id, false } });
// Act
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
sutProvider.Sut.DeleteUserAsync(organizationUser.OrganizationId, organizationUser.Id, null));
// Assert
Assert.Equal("Member is not claimed by the organization.", exception.Message);
await sutProvider.GetDependency<IUserService>().Received(0).DeleteAsync(Arg.Any<User>());
await sutProvider.GetDependency<IEventService>().Received(0)
.LogOrganizationUserEventAsync(Arg.Any<OrganizationUser>(), Arg.Any<EventType>(), Arg.Any<DateTime?>());
}
[Theory]
[BitAutoData]
public async Task DeleteManyUsersAsync_WithValidUsers_DeletesUsersAndLogsEvents(
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider, User user1, User user2, Guid organizationId,
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.User)] OrganizationUser orgUser1,
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.User)] OrganizationUser orgUser2)
{
// Arrange
orgUser1.OrganizationId = orgUser2.OrganizationId = organizationId;
orgUser1.UserId = user1.Id;
orgUser2.UserId = user2.Id;
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetManyAsync(Arg.Any<IEnumerable<Guid>>())
.Returns(new List<OrganizationUser> { orgUser1, orgUser2 });
sutProvider.GetDependency<IUserRepository>()
.GetManyAsync(Arg.Is<IEnumerable<Guid>>(ids => ids.Contains(user1.Id) && ids.Contains(user2.Id)))
.Returns(new[] { user1, user2 });
sutProvider.GetDependency<IGetOrganizationUsersClaimedStatusQuery>()
.GetUsersOrganizationClaimedStatusAsync(organizationId, Arg.Any<IEnumerable<Guid>>())
.Returns(new Dictionary<Guid, bool> { { orgUser1.Id, true }, { orgUser2.Id, true } });
// Act
var userIds = new[] { orgUser1.Id, orgUser2.Id };
var results = await sutProvider.Sut.DeleteManyUsersAsync(organizationId, userIds, null);
// Assert
Assert.Equal(2, results.Count());
Assert.All(results, r => Assert.Empty(r.Item2));
await sutProvider.GetDependency<IOrganizationUserRepository>().Received(1).GetManyAsync(userIds);
await sutProvider.GetDependency<IUserRepository>().Received(1).DeleteManyAsync(Arg.Is<IEnumerable<User>>(users => users.Any(u => u.Id == user1.Id) && users.Any(u => u.Id == user2.Id)));
await sutProvider.GetDependency<IEventService>().Received(1).LogOrganizationUserEventsAsync(
Arg.Is<IEnumerable<(OrganizationUser, EventType, DateTime?)>>(events =>
events.Count(e => e.Item1.Id == orgUser1.Id && e.Item2 == EventType.OrganizationUser_Deleted) == 1
&& events.Count(e => e.Item1.Id == orgUser2.Id && e.Item2 == EventType.OrganizationUser_Deleted) == 1));
}
[Theory]
[BitAutoData]
public async Task DeleteManyUsersAsync_WhenUserNotFound_ReturnsErrorMessage(
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider,
Guid organizationId,
Guid orgUserId)
{
// Act
var result = await sutProvider.Sut.DeleteManyUsersAsync(organizationId, new[] { orgUserId }, null);
// Assert
Assert.Single(result);
Assert.Equal(orgUserId, result.First().Item1);
Assert.Contains("Member not found.", result.First().Item2);
await sutProvider.GetDependency<IUserRepository>()
.DidNotReceiveWithAnyArgs()
.DeleteManyAsync(default);
await sutProvider.GetDependency<IEventService>().Received(0)
.LogOrganizationUserEventsAsync(Arg.Any<IEnumerable<(OrganizationUser, EventType, DateTime?)>>());
}
[Theory]
[BitAutoData]
public async Task DeleteManyUsersAsync_WhenDeletingYourself_ReturnsErrorMessage(
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider,
User user, [OrganizationUser] OrganizationUser orgUser, Guid deletingUserId)
{
// Arrange
orgUser.UserId = user.Id = deletingUserId;
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetManyAsync(Arg.Any<IEnumerable<Guid>>())
.Returns(new List<OrganizationUser> { orgUser });
sutProvider.GetDependency<IUserRepository>()
.GetManyAsync(Arg.Is<IEnumerable<Guid>>(ids => ids.Contains(user.Id)))
.Returns(new[] { user });
// Act
var result = await sutProvider.Sut.DeleteManyUsersAsync(orgUser.OrganizationId, new[] { orgUser.Id }, deletingUserId);
// Assert
Assert.Single(result);
Assert.Equal(orgUser.Id, result.First().Item1);
Assert.Contains("You cannot delete yourself.", result.First().Item2);
await sutProvider.GetDependency<IUserService>().Received(0).DeleteAsync(Arg.Any<User>());
await sutProvider.GetDependency<IEventService>().Received(0)
.LogOrganizationUserEventsAsync(Arg.Any<IEnumerable<(OrganizationUser, EventType, DateTime?)>>());
}
[Theory]
[BitAutoData]
public async Task DeleteManyUsersAsync_WhenUserIsInvited_ReturnsErrorMessage(
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider,
[OrganizationUser(OrganizationUserStatusType.Invited, OrganizationUserType.User)] OrganizationUser orgUser)
{
// Arrange
orgUser.UserId = null;
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetManyAsync(Arg.Any<IEnumerable<Guid>>())
.Returns(new List<OrganizationUser> { orgUser });
// Act
var result = await sutProvider.Sut.DeleteManyUsersAsync(orgUser.OrganizationId, new[] { orgUser.Id }, null);
// Assert
Assert.Single(result);
Assert.Equal(orgUser.Id, result.First().Item1);
Assert.Contains("You cannot delete a member with Invited status.", result.First().Item2);
await sutProvider.GetDependency<IUserService>().Received(0).DeleteAsync(Arg.Any<User>());
await sutProvider.GetDependency<IEventService>().Received(0)
.LogOrganizationUserEventsAsync(Arg.Any<IEnumerable<(OrganizationUser, EventType, DateTime?)>>());
}
[Theory]
[BitAutoData]
public async Task DeleteManyUsersAsync_WhenDeletingOwnerAsNonOwner_ReturnsErrorMessage(
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider, User user,
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Owner)] OrganizationUser orgUser,
Guid deletingUserId)
{
// Arrange
orgUser.UserId = user.Id;
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetManyAsync(Arg.Any<IEnumerable<Guid>>())
.Returns(new List<OrganizationUser> { orgUser });
sutProvider.GetDependency<IUserRepository>()
.GetManyAsync(Arg.Is<IEnumerable<Guid>>(i => i.Contains(user.Id)))
.Returns(new[] { user });
sutProvider.GetDependency<ICurrentContext>()
.OrganizationOwner(orgUser.OrganizationId)
.Returns(false);
var result = await sutProvider.Sut.DeleteManyUsersAsync(orgUser.OrganizationId, new[] { orgUser.Id }, deletingUserId);
Assert.Single(result);
Assert.Equal(orgUser.Id, result.First().Item1);
Assert.Contains("Only owners can delete other owners.", result.First().Item2);
await sutProvider.GetDependency<IUserService>().Received(0).DeleteAsync(Arg.Any<User>());
await sutProvider.GetDependency<IEventService>().Received(0)
.LogOrganizationUserEventsAsync(Arg.Any<IEnumerable<(OrganizationUser, EventType, DateTime?)>>());
}
[Theory]
[BitAutoData]
public async Task DeleteManyUsersAsync_WhenDeletingLastOwner_ReturnsErrorMessage(
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider, User user,
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Owner)] OrganizationUser orgUser,
Guid deletingUserId)
{
// Arrange
orgUser.UserId = user.Id;
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetManyAsync(Arg.Any<IEnumerable<Guid>>())
.Returns(new List<OrganizationUser> { orgUser });
sutProvider.GetDependency<IUserRepository>()
.GetManyAsync(Arg.Is<IEnumerable<Guid>>(i => i.Contains(user.Id)))
.Returns(new[] { user });
sutProvider.GetDependency<ICurrentContext>()
.OrganizationOwner(orgUser.OrganizationId)
.Returns(true);
sutProvider.GetDependency<IHasConfirmedOwnersExceptQuery>()
.HasConfirmedOwnersExceptAsync(orgUser.OrganizationId, Arg.Any<IEnumerable<Guid>>(), Arg.Any<bool>())
.Returns(false);
// Act
var result = await sutProvider.Sut.DeleteManyUsersAsync(orgUser.OrganizationId, new[] { orgUser.Id }, deletingUserId);
// Assert
Assert.Single(result);
Assert.Equal(orgUser.Id, result.First().Item1);
Assert.Contains("Organization must have at least one confirmed owner.", result.First().Item2);
await sutProvider.GetDependency<IUserService>().Received(0).DeleteAsync(Arg.Any<User>());
await sutProvider.GetDependency<IEventService>().Received(0)
.LogOrganizationUserEventsAsync(Arg.Any<IEnumerable<(OrganizationUser, EventType, DateTime?)>>());
}
[Theory]
[BitAutoData]
public async Task DeleteManyUsersAsync_WhenUserNotManaged_ReturnsErrorMessage(
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider, User user,
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.User)] OrganizationUser orgUser)
{
// Arrange
orgUser.UserId = user.Id;
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetManyAsync(Arg.Any<IEnumerable<Guid>>())
.Returns(new List<OrganizationUser> { orgUser });
sutProvider.GetDependency<IUserRepository>()
.GetManyAsync(Arg.Is<IEnumerable<Guid>>(ids => ids.Contains(orgUser.UserId.Value)))
.Returns(new[] { user });
sutProvider.GetDependency<IGetOrganizationUsersClaimedStatusQuery>()
.GetUsersOrganizationClaimedStatusAsync(Arg.Any<Guid>(), Arg.Any<IEnumerable<Guid>>())
.Returns(new Dictionary<Guid, bool> { { orgUser.Id, false } });
// Act
var result = await sutProvider.Sut.DeleteManyUsersAsync(orgUser.OrganizationId, new[] { orgUser.Id }, null);
// Assert
Assert.Single(result);
Assert.Equal(orgUser.Id, result.First().Item1);
Assert.Contains("Member is not claimed by the organization.", result.First().Item2);
await sutProvider.GetDependency<IUserService>().Received(0).DeleteAsync(Arg.Any<User>());
await sutProvider.GetDependency<IEventService>().Received(0)
.LogOrganizationUserEventsAsync(Arg.Any<IEnumerable<(OrganizationUser, EventType, DateTime?)>>());
}
[Theory]
[BitAutoData]
public async Task DeleteManyUsersAsync_MixedValidAndInvalidUsers_ReturnsAppropriateResults(
SutProvider<DeleteClaimedOrganizationUserAccountCommand> sutProvider, User user1, User user3,
Guid organizationId,
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.User)] OrganizationUser orgUser1,
[OrganizationUser(OrganizationUserStatusType.Invited, OrganizationUserType.User)] OrganizationUser orgUser2,
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.User)] OrganizationUser orgUser3)
{
// Arrange
orgUser1.UserId = user1.Id;
orgUser2.UserId = null;
orgUser3.UserId = user3.Id;
orgUser1.OrganizationId = orgUser2.OrganizationId = orgUser3.OrganizationId = organizationId;
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetManyAsync(Arg.Any<IEnumerable<Guid>>())
.Returns(new List<OrganizationUser> { orgUser1, orgUser2, orgUser3 });
sutProvider.GetDependency<IUserRepository>()
.GetManyAsync(Arg.Is<IEnumerable<Guid>>(ids => ids.Contains(user1.Id) && ids.Contains(user3.Id)))
.Returns(new[] { user1, user3 });
sutProvider.GetDependency<IGetOrganizationUsersClaimedStatusQuery>()
.GetUsersOrganizationClaimedStatusAsync(organizationId, Arg.Any<IEnumerable<Guid>>())
.Returns(new Dictionary<Guid, bool> { { orgUser1.Id, true }, { orgUser3.Id, false } });
// Act
var results = await sutProvider.Sut.DeleteManyUsersAsync(organizationId, new[] { orgUser1.Id, orgUser2.Id, orgUser3.Id }, null);
// Assert
Assert.Equal(3, results.Count());
Assert.Empty(results.First(r => r.Item1 == orgUser1.Id).Item2);
Assert.Equal("You cannot delete a member with Invited status.", results.First(r => r.Item1 == orgUser2.Id).Item2);
Assert.Equal("Member is not claimed by the organization.", results.First(r => r.Item1 == orgUser3.Id).Item2);
await sutProvider.GetDependency<IEventService>().Received(1).LogOrganizationUserEventsAsync(
Arg.Is<IEnumerable<(OrganizationUser, EventType, DateTime?)>>(events =>
events.Count(e => e.Item1.Id == orgUser1.Id && e.Item2 == EventType.OrganizationUser_Deleted) == 1));
}
}