mirror of
https://github.com/bitwarden/server
synced 2026-01-28 15:23:38 +00:00
Added tests
This commit is contained in:
@@ -104,19 +104,18 @@ public class RestoreOrganizationUserCommand(
|
||||
var status = OrganizationService.GetPriorActiveOrganizationUserStatusType(organizationUser);
|
||||
|
||||
await organizationUserRepository.RestoreAsync(organizationUser.Id, status);
|
||||
organizationUser.Status = status;
|
||||
|
||||
if (organizationUser.UserId.HasValue
|
||||
&& (await policyRequirementQuery.GetAsync<OrganizationDataOwnershipPolicyRequirement>(organizationUser.UserId
|
||||
.Value)).State == OrganizationDataOwnershipState.Enabled
|
||||
&& organizationUser.Status == OrganizationUserStatusType.Confirmed
|
||||
&& status == OrganizationUserStatusType.Confirmed
|
||||
&& !string.IsNullOrWhiteSpace(defaultCollectionName))
|
||||
{
|
||||
await collectionRepository.CreateDefaultCollectionsAsync(organizationUser.OrganizationId,
|
||||
[organizationUser.Id],
|
||||
defaultCollectionName);
|
||||
}
|
||||
|
||||
organizationUser.Status = status;
|
||||
}
|
||||
|
||||
private async Task CheckUserForOtherFreeOrganizationOwnershipAsync(OrganizationUser organizationUser)
|
||||
|
||||
@@ -37,7 +37,7 @@ public class RestoreOrganizationUserCommandTests
|
||||
Sponsored = 0,
|
||||
Users = 1
|
||||
});
|
||||
await sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id);
|
||||
await sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id, null);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.Received(1)
|
||||
@@ -81,7 +81,7 @@ public class RestoreOrganizationUserCommandTests
|
||||
RestoreUser_Setup(organization, owner, organizationUser, sutProvider);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id));
|
||||
() => sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id, null));
|
||||
|
||||
Assert.Contains("you cannot restore yourself", exception.Message.ToLowerInvariant());
|
||||
|
||||
@@ -107,7 +107,7 @@ public class RestoreOrganizationUserCommandTests
|
||||
RestoreUser_Setup(organization, restoringUser, organizationUser, sutProvider);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.RestoreUserAsync(organizationUser, restoringUser.Id));
|
||||
() => sutProvider.Sut.RestoreUserAsync(organizationUser, restoringUser.Id, null));
|
||||
|
||||
Assert.Contains("only owners can restore other owners", exception.Message.ToLowerInvariant());
|
||||
|
||||
@@ -133,7 +133,7 @@ public class RestoreOrganizationUserCommandTests
|
||||
RestoreUser_Setup(organization, owner, organizationUser, sutProvider);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id));
|
||||
() => sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id, null));
|
||||
|
||||
Assert.Contains("already active", exception.Message.ToLowerInvariant());
|
||||
|
||||
@@ -172,7 +172,7 @@ public class RestoreOrganizationUserCommandTests
|
||||
sutProvider.GetDependency<IUserRepository>().GetByIdAsync(organizationUser.UserId.Value).Returns(user);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id));
|
||||
() => sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id, null));
|
||||
|
||||
Assert.Contains("test@bitwarden.com belongs to an organization that doesn't allow them to join multiple organizations", exception.Message.ToLowerInvariant());
|
||||
|
||||
@@ -216,7 +216,7 @@ public class RestoreOrganizationUserCommandTests
|
||||
sutProvider.GetDependency<IUserRepository>().GetByIdAsync(organizationUser.UserId.Value).Returns(user);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id));
|
||||
() => sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id, null));
|
||||
|
||||
Assert.Contains("test@bitwarden.com is not compliant with the two-step login policy", exception.Message.ToLowerInvariant());
|
||||
|
||||
@@ -272,7 +272,7 @@ public class RestoreOrganizationUserCommandTests
|
||||
sutProvider.GetDependency<IUserRepository>().GetByIdAsync(organizationUser.UserId.Value).Returns(user);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id));
|
||||
() => sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id, null));
|
||||
|
||||
Assert.Contains("test@bitwarden.com is not compliant with the two-step login policy", exception.Message.ToLowerInvariant());
|
||||
|
||||
@@ -309,7 +309,7 @@ public class RestoreOrganizationUserCommandTests
|
||||
Sponsored = 0,
|
||||
Users = 1
|
||||
});
|
||||
await sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id);
|
||||
await sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id, null);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.Received(1)
|
||||
@@ -349,7 +349,7 @@ public class RestoreOrganizationUserCommandTests
|
||||
}
|
||||
]));
|
||||
|
||||
await sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id);
|
||||
await sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id, null);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.Received(1)
|
||||
@@ -395,7 +395,7 @@ public class RestoreOrganizationUserCommandTests
|
||||
sutProvider.GetDependency<IUserRepository>().GetByIdAsync(organizationUser.UserId.Value).Returns(user);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id));
|
||||
() => sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id, null));
|
||||
|
||||
Assert.Contains("test@bitwarden.com is not compliant with the single organization policy", exception.Message.ToLowerInvariant());
|
||||
|
||||
@@ -447,7 +447,7 @@ public class RestoreOrganizationUserCommandTests
|
||||
sutProvider.GetDependency<IUserRepository>().GetByIdAsync(organizationUser.UserId.Value).Returns(user);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id));
|
||||
() => sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id, null));
|
||||
|
||||
Assert.Contains("test@bitwarden.com is not compliant with the single organization and two-step login policy", exception.Message.ToLowerInvariant());
|
||||
|
||||
@@ -509,7 +509,7 @@ public class RestoreOrganizationUserCommandTests
|
||||
sutProvider.GetDependency<IUserRepository>().GetByIdAsync(organizationUser.UserId.Value).Returns(user);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id));
|
||||
() => sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id, null));
|
||||
|
||||
Assert.Contains("test@bitwarden.com is not compliant with the single organization and two-step login policy", exception.Message.ToLowerInvariant());
|
||||
|
||||
@@ -548,7 +548,7 @@ public class RestoreOrganizationUserCommandTests
|
||||
.TwoFactorIsEnabledAsync(Arg.Is<IEnumerable<Guid>>(i => i.Contains(organizationUser.UserId.Value)))
|
||||
.Returns(new List<(Guid userId, bool twoFactorIsEnabled)> { (organizationUser.UserId.Value, true) });
|
||||
|
||||
await sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id);
|
||||
await sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id, null);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.Received(1)
|
||||
@@ -599,7 +599,7 @@ public class RestoreOrganizationUserCommandTests
|
||||
.Returns(new List<(Guid userId, bool twoFactorIsEnabled)> { (organizationUser.UserId.Value, true) });
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id));
|
||||
() => sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id, null));
|
||||
|
||||
Assert.Equal("User is an owner/admin of another free organization. Please have them upgrade to a paid plan to restore their account.", exception.Message);
|
||||
}
|
||||
@@ -651,7 +651,7 @@ public class RestoreOrganizationUserCommandTests
|
||||
.TwoFactorIsEnabledAsync(Arg.Is<IEnumerable<Guid>>(i => i.Contains(organizationUser.UserId.Value)))
|
||||
.Returns(new List<(Guid userId, bool twoFactorIsEnabled)> { (organizationUser.UserId.Value, true) });
|
||||
|
||||
await sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id);
|
||||
await sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id, null);
|
||||
|
||||
await organizationUserRepository
|
||||
.Received(1)
|
||||
@@ -707,7 +707,7 @@ public class RestoreOrganizationUserCommandTests
|
||||
.TwoFactorIsEnabledAsync(Arg.Is<IEnumerable<Guid>>(i => i.Contains(organizationUser.UserId.Value)))
|
||||
.Returns(new List<(Guid userId, bool twoFactorIsEnabled)> { (organizationUser.UserId.Value, true) });
|
||||
|
||||
await sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id);
|
||||
await sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id, null);
|
||||
|
||||
await organizationUserRepository
|
||||
.Received(1)
|
||||
@@ -782,7 +782,7 @@ public class RestoreOrganizationUserCommandTests
|
||||
});
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.RestoreUsersAsync(organization.Id, new[] { orgUser1.Id, orgUser2.Id }, owner.Id, userService);
|
||||
var result = await sutProvider.Sut.RestoreUsersAsync(organization.Id, new[] { orgUser1.Id, orgUser2.Id }, owner.Id, userService, null);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, result.Count);
|
||||
@@ -843,7 +843,7 @@ public class RestoreOrganizationUserCommandTests
|
||||
});
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.RestoreUsersAsync(organization.Id, [orgUser1.Id, orgUser2.Id, orgUser3.Id], owner.Id, userService);
|
||||
var result = await sutProvider.Sut.RestoreUsersAsync(organization.Id, [orgUser1.Id, orgUser2.Id, orgUser3.Id], owner.Id, userService, null);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(3, result.Count);
|
||||
@@ -914,7 +914,7 @@ public class RestoreOrganizationUserCommandTests
|
||||
});
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.RestoreUsersAsync(organization.Id, [orgUser1.Id, orgUser2.Id, orgUser3.Id], owner.Id, userService);
|
||||
var result = await sutProvider.Sut.RestoreUsersAsync(organization.Id, [orgUser1.Id, orgUser2.Id, orgUser3.Id], owner.Id, userService, null);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(3, result.Count);
|
||||
@@ -992,7 +992,7 @@ public class RestoreOrganizationUserCommandTests
|
||||
});
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.RestoreUsersAsync(organization.Id, [orgUser1.Id, orgUser2.Id, orgUser3.Id], owner.Id, userService);
|
||||
var result = await sutProvider.Sut.RestoreUsersAsync(organization.Id, [orgUser1.Id, orgUser2.Id, orgUser3.Id], owner.Id, userService, null);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(3, result.Count);
|
||||
@@ -1056,7 +1056,7 @@ public class RestoreOrganizationUserCommandTests
|
||||
});
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.RestoreUsersAsync(organization.Id, [orgUser1.Id], owner.Id, userService);
|
||||
var result = await sutProvider.Sut.RestoreUsersAsync(organization.Id, [orgUser1.Id], owner.Id, userService, null);
|
||||
|
||||
// Assert
|
||||
Assert.Single(result);
|
||||
@@ -1107,7 +1107,7 @@ public class RestoreOrganizationUserCommandTests
|
||||
.Returns([new OrganizationUserPolicyDetails { OrganizationId = organization.Id, PolicyType = PolicyType.TwoFactorAuthentication }]);
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.RestoreUsersAsync(organization.Id, [orgUser1.Id], owner.Id, userService);
|
||||
var result = await sutProvider.Sut.RestoreUsersAsync(organization.Id, [orgUser1.Id], owner.Id, userService, null);
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(string.Empty, result[0].Item2);
|
||||
@@ -1138,5 +1138,396 @@ public class RestoreOrganizationUserCommandTests
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(organization.Id).Returns(requestingOrganizationUser != null && requestingOrganizationUser.Type is OrganizationUserType.Owner);
|
||||
sutProvider.GetDependency<ICurrentContext>().ManageUsers(organization.Id).Returns(requestingOrganizationUser != null && (requestingOrganizationUser.Type is OrganizationUserType.Owner or OrganizationUserType.Admin));
|
||||
|
||||
// Setup default disabled OrganizationDataOwnershipPolicyRequirement for any user
|
||||
sutProvider.GetDependency<IPolicyRequirementQuery>()
|
||||
.GetAsync<OrganizationDataOwnershipPolicyRequirement>(Arg.Any<Guid>())
|
||||
.Returns(new OrganizationDataOwnershipPolicyRequirement(OrganizationDataOwnershipState.Disabled, []));
|
||||
}
|
||||
|
||||
private static void SetupOrganizationDataOwnershipPolicy(
|
||||
SutProvider<RestoreOrganizationUserCommand> sutProvider,
|
||||
Guid userId,
|
||||
Guid organizationId,
|
||||
OrganizationUserStatusType orgUserStatus,
|
||||
bool policyEnabled)
|
||||
{
|
||||
var policyDetails = policyEnabled
|
||||
? new List<PolicyDetails>
|
||||
{
|
||||
new()
|
||||
{
|
||||
OrganizationId = organizationId,
|
||||
OrganizationUserId = Guid.NewGuid(),
|
||||
OrganizationUserStatus = orgUserStatus,
|
||||
PolicyType = PolicyType.OrganizationDataOwnership
|
||||
}
|
||||
}
|
||||
: new List<PolicyDetails>();
|
||||
|
||||
var policyRequirement = new OrganizationDataOwnershipPolicyRequirement(
|
||||
policyEnabled ? OrganizationDataOwnershipState.Enabled : OrganizationDataOwnershipState.Disabled,
|
||||
policyDetails);
|
||||
|
||||
sutProvider.GetDependency<IPolicyRequirementQuery>()
|
||||
.GetAsync<OrganizationDataOwnershipPolicyRequirement>(userId)
|
||||
.Returns(policyRequirement);
|
||||
}
|
||||
|
||||
#region Single User Restore - Default Collection Tests
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task RestoreUser_WithDataOwnershipPolicyEnabled_AndConfirmedUser_CreatesDefaultCollection(
|
||||
Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Owner)] OrganizationUser owner,
|
||||
[OrganizationUser(OrganizationUserStatusType.Revoked)] OrganizationUser organizationUser,
|
||||
string defaultCollectionName,
|
||||
SutProvider<RestoreOrganizationUserCommand> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
organizationUser.Email = null; // This causes user to restore to Confirmed status
|
||||
RestoreUser_Setup(organization, owner, organizationUser, sutProvider);
|
||||
|
||||
SetupOrganizationDataOwnershipPolicy(
|
||||
sutProvider,
|
||||
organizationUser.UserId!.Value,
|
||||
organization.Id,
|
||||
OrganizationUserStatusType.Revoked,
|
||||
policyEnabled: true);
|
||||
|
||||
// Act
|
||||
await sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id, defaultCollectionName);
|
||||
|
||||
// Assert
|
||||
await sutProvider.GetDependency<ICollectionRepository>()
|
||||
.Received(1)
|
||||
.CreateDefaultCollectionsAsync(
|
||||
organization.Id,
|
||||
Arg.Is<IEnumerable<Guid>>(ids => ids.Single() == organizationUser.Id),
|
||||
defaultCollectionName);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task RestoreUser_WithDataOwnershipPolicyDisabled_DoesNotCreateDefaultCollection(
|
||||
Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Owner)] OrganizationUser owner,
|
||||
[OrganizationUser(OrganizationUserStatusType.Revoked)] OrganizationUser organizationUser,
|
||||
string defaultCollectionName,
|
||||
SutProvider<RestoreOrganizationUserCommand> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
organizationUser.Email = null; // This causes user to restore to Confirmed status
|
||||
RestoreUser_Setup(organization, owner, organizationUser, sutProvider);
|
||||
|
||||
SetupOrganizationDataOwnershipPolicy(
|
||||
sutProvider,
|
||||
organizationUser.UserId!.Value,
|
||||
organization.Id,
|
||||
OrganizationUserStatusType.Revoked,
|
||||
policyEnabled: false);
|
||||
|
||||
// Act
|
||||
await sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id, defaultCollectionName);
|
||||
|
||||
// Assert
|
||||
await sutProvider.GetDependency<ICollectionRepository>()
|
||||
.DidNotReceive()
|
||||
.CreateDefaultCollectionsAsync(Arg.Any<Guid>(), Arg.Any<IEnumerable<Guid>>(), Arg.Any<string>());
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task RestoreUser_WithNullDefaultCollectionName_DoesNotCreateDefaultCollection(
|
||||
Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Owner)] OrganizationUser owner,
|
||||
[OrganizationUser(OrganizationUserStatusType.Revoked)] OrganizationUser organizationUser,
|
||||
SutProvider<RestoreOrganizationUserCommand> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
organizationUser.Email = null; // This causes user to restore to Confirmed status
|
||||
RestoreUser_Setup(organization, owner, organizationUser, sutProvider);
|
||||
|
||||
SetupOrganizationDataOwnershipPolicy(
|
||||
sutProvider,
|
||||
organizationUser.UserId!.Value,
|
||||
organization.Id,
|
||||
OrganizationUserStatusType.Revoked,
|
||||
policyEnabled: true);
|
||||
|
||||
// Act
|
||||
await sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id, null);
|
||||
|
||||
// Assert
|
||||
await sutProvider.GetDependency<ICollectionRepository>()
|
||||
.DidNotReceive()
|
||||
.CreateDefaultCollectionsAsync(Arg.Any<Guid>(), Arg.Any<IEnumerable<Guid>>(), Arg.Any<string>());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData("")]
|
||||
[BitAutoData(" ")]
|
||||
public async Task RestoreUser_WithEmptyOrWhitespaceDefaultCollectionName_DoesNotCreateDefaultCollection(
|
||||
string defaultCollectionName,
|
||||
Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Owner)] OrganizationUser owner,
|
||||
[OrganizationUser(OrganizationUserStatusType.Revoked)] OrganizationUser organizationUser,
|
||||
SutProvider<RestoreOrganizationUserCommand> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
organizationUser.Email = null; // This causes user to restore to Confirmed status
|
||||
RestoreUser_Setup(organization, owner, organizationUser, sutProvider);
|
||||
|
||||
SetupOrganizationDataOwnershipPolicy(
|
||||
sutProvider,
|
||||
organizationUser.UserId!.Value,
|
||||
organization.Id,
|
||||
OrganizationUserStatusType.Revoked,
|
||||
policyEnabled: true);
|
||||
|
||||
// Act
|
||||
await sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id, defaultCollectionName);
|
||||
|
||||
// Assert
|
||||
await sutProvider.GetDependency<ICollectionRepository>()
|
||||
.DidNotReceive()
|
||||
.CreateDefaultCollectionsAsync(Arg.Any<Guid>(), Arg.Any<IEnumerable<Guid>>(), Arg.Any<string>());
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task RestoreUser_UserRestoredToInvitedStatus_DoesNotCreateDefaultCollection(
|
||||
Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Owner)] OrganizationUser owner,
|
||||
[OrganizationUser(OrganizationUserStatusType.Revoked)] OrganizationUser organizationUser,
|
||||
string defaultCollectionName,
|
||||
SutProvider<RestoreOrganizationUserCommand> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
organization.PlanType = PlanType.EnterpriseAnnually; // Non-Free plan to avoid ownership check requiring UserId
|
||||
organizationUser.Email = "test@example.com"; // Non-null email means user restores to Invited status
|
||||
organizationUser.UserId = null; // User not linked to account yet
|
||||
organizationUser.Key = null;
|
||||
RestoreUser_Setup(organization, owner, organizationUser, sutProvider);
|
||||
|
||||
// Act
|
||||
await sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id, defaultCollectionName);
|
||||
|
||||
// Assert - User was restored to Invited status, so no collection should be created
|
||||
await sutProvider.GetDependency<ICollectionRepository>()
|
||||
.DidNotReceive()
|
||||
.CreateDefaultCollectionsAsync(Arg.Any<Guid>(), Arg.Any<IEnumerable<Guid>>(), Arg.Any<string>());
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task RestoreUser_WithNoUserId_DoesNotCreateDefaultCollection(
|
||||
Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Owner)] OrganizationUser owner,
|
||||
[OrganizationUser(OrganizationUserStatusType.Revoked)] OrganizationUser organizationUser,
|
||||
string defaultCollectionName,
|
||||
SutProvider<RestoreOrganizationUserCommand> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
organization.PlanType = PlanType.EnterpriseAnnually; // Non-Free plan to avoid ownership check requiring UserId
|
||||
organizationUser.UserId = null; // No linked user account
|
||||
organizationUser.Email = "test@example.com";
|
||||
organizationUser.Key = null;
|
||||
RestoreUser_Setup(organization, owner, organizationUser, sutProvider);
|
||||
|
||||
// Act
|
||||
await sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id, defaultCollectionName);
|
||||
|
||||
// Assert
|
||||
await sutProvider.GetDependency<ICollectionRepository>()
|
||||
.DidNotReceive()
|
||||
.CreateDefaultCollectionsAsync(Arg.Any<Guid>(), Arg.Any<IEnumerable<Guid>>(), Arg.Any<string>());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Bulk User Restore - Default Collection Tests
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task RestoreUsers_Bulk_WithDataOwnershipPolicy_CreatesCollectionsForEligibleUsers(
|
||||
Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Owner)] OrganizationUser owner,
|
||||
[OrganizationUser(OrganizationUserStatusType.Revoked)] OrganizationUser orgUser1,
|
||||
[OrganizationUser(OrganizationUserStatusType.Revoked)] OrganizationUser orgUser2,
|
||||
string defaultCollectionName,
|
||||
SutProvider<RestoreOrganizationUserCommand> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
RestoreUser_Setup(organization, owner, orgUser1, sutProvider);
|
||||
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
|
||||
var userService = Substitute.For<IUserService>();
|
||||
|
||||
// orgUser1: Will restore to Confirmed (Email = null)
|
||||
orgUser1.Email = null;
|
||||
orgUser1.OrganizationId = organization.Id;
|
||||
|
||||
// orgUser2: Will restore to Invited (Email not null)
|
||||
orgUser2.Email = "test@example.com";
|
||||
orgUser2.UserId = null;
|
||||
orgUser2.Key = null;
|
||||
orgUser2.OrganizationId = organization.Id;
|
||||
|
||||
organizationUserRepository
|
||||
.GetManyAsync(Arg.Is<IEnumerable<Guid>>(ids => ids.Contains(orgUser1.Id) && ids.Contains(orgUser2.Id)))
|
||||
.Returns([orgUser1, orgUser2]);
|
||||
|
||||
// Setup policy for orgUser1 (the one with UserId)
|
||||
SetupOrganizationDataOwnershipPolicy(
|
||||
sutProvider,
|
||||
orgUser1.UserId!.Value,
|
||||
organization.Id,
|
||||
OrganizationUserStatusType.Revoked,
|
||||
policyEnabled: true);
|
||||
|
||||
sutProvider.GetDependency<ITwoFactorIsEnabledQuery>()
|
||||
.TwoFactorIsEnabledAsync(Arg.Any<IEnumerable<Guid>>())
|
||||
.Returns(new List<(Guid userId, bool twoFactorIsEnabled)>
|
||||
{
|
||||
(orgUser1.UserId!.Value, true)
|
||||
});
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.RestoreUsersAsync(
|
||||
organization.Id,
|
||||
[orgUser1.Id, orgUser2.Id],
|
||||
owner.Id,
|
||||
userService,
|
||||
defaultCollectionName);
|
||||
|
||||
// Assert - Only orgUser1 should have a collection created (Confirmed with policy enabled)
|
||||
await sutProvider.GetDependency<ICollectionRepository>()
|
||||
.Received(1)
|
||||
.CreateDefaultCollectionsAsync(
|
||||
organization.Id,
|
||||
Arg.Is<IEnumerable<Guid>>(ids => ids.Single() == orgUser1.Id),
|
||||
defaultCollectionName);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task RestoreUsers_Bulk_WithMixedPolicyStates_OnlyCreatesForEnabledPolicy(
|
||||
Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Owner)] OrganizationUser owner,
|
||||
[OrganizationUser(OrganizationUserStatusType.Revoked)] OrganizationUser orgUser1,
|
||||
[OrganizationUser(OrganizationUserStatusType.Revoked)] OrganizationUser orgUser2,
|
||||
string defaultCollectionName,
|
||||
SutProvider<RestoreOrganizationUserCommand> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
RestoreUser_Setup(organization, owner, orgUser1, sutProvider);
|
||||
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
|
||||
var userService = Substitute.For<IUserService>();
|
||||
|
||||
// Both users will restore to Confirmed
|
||||
orgUser1.Email = null;
|
||||
orgUser1.OrganizationId = organization.Id;
|
||||
orgUser2.Email = null;
|
||||
orgUser2.OrganizationId = organization.Id;
|
||||
|
||||
organizationUserRepository
|
||||
.GetManyAsync(Arg.Is<IEnumerable<Guid>>(ids => ids.Contains(orgUser1.Id) && ids.Contains(orgUser2.Id)))
|
||||
.Returns([orgUser1, orgUser2]);
|
||||
|
||||
// Setup policy enabled only for orgUser1
|
||||
SetupOrganizationDataOwnershipPolicy(
|
||||
sutProvider,
|
||||
orgUser1.UserId!.Value,
|
||||
organization.Id,
|
||||
OrganizationUserStatusType.Revoked,
|
||||
policyEnabled: true);
|
||||
|
||||
// Setup policy disabled for orgUser2
|
||||
SetupOrganizationDataOwnershipPolicy(
|
||||
sutProvider,
|
||||
orgUser2.UserId!.Value,
|
||||
organization.Id,
|
||||
OrganizationUserStatusType.Revoked,
|
||||
policyEnabled: false);
|
||||
|
||||
sutProvider.GetDependency<ITwoFactorIsEnabledQuery>()
|
||||
.TwoFactorIsEnabledAsync(Arg.Any<IEnumerable<Guid>>())
|
||||
.Returns(new List<(Guid userId, bool twoFactorIsEnabled)>
|
||||
{
|
||||
(orgUser1.UserId!.Value, true),
|
||||
(orgUser2.UserId!.Value, true)
|
||||
});
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.RestoreUsersAsync(
|
||||
organization.Id,
|
||||
[orgUser1.Id, orgUser2.Id],
|
||||
owner.Id,
|
||||
userService,
|
||||
defaultCollectionName);
|
||||
|
||||
// Assert - Only orgUser1 should have a collection created (policy enabled)
|
||||
await sutProvider.GetDependency<ICollectionRepository>()
|
||||
.Received(1)
|
||||
.CreateDefaultCollectionsAsync(
|
||||
organization.Id,
|
||||
Arg.Is<IEnumerable<Guid>>(ids => ids.Single() == orgUser1.Id),
|
||||
defaultCollectionName);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task RestoreUsers_Bulk_WithNullCollectionName_DoesNotCreateAnyCollections(
|
||||
Organization organization,
|
||||
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Owner)] OrganizationUser owner,
|
||||
[OrganizationUser(OrganizationUserStatusType.Revoked)] OrganizationUser orgUser1,
|
||||
[OrganizationUser(OrganizationUserStatusType.Revoked)] OrganizationUser orgUser2,
|
||||
SutProvider<RestoreOrganizationUserCommand> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
RestoreUser_Setup(organization, owner, orgUser1, sutProvider);
|
||||
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
|
||||
var userService = Substitute.For<IUserService>();
|
||||
|
||||
// Both users will restore to Confirmed
|
||||
orgUser1.Email = null;
|
||||
orgUser1.OrganizationId = organization.Id;
|
||||
orgUser2.Email = null;
|
||||
orgUser2.OrganizationId = organization.Id;
|
||||
|
||||
organizationUserRepository
|
||||
.GetManyAsync(Arg.Is<IEnumerable<Guid>>(ids => ids.Contains(orgUser1.Id) && ids.Contains(orgUser2.Id)))
|
||||
.Returns([orgUser1, orgUser2]);
|
||||
|
||||
// Setup policy enabled for both users
|
||||
SetupOrganizationDataOwnershipPolicy(
|
||||
sutProvider,
|
||||
orgUser1.UserId!.Value,
|
||||
organization.Id,
|
||||
OrganizationUserStatusType.Revoked,
|
||||
policyEnabled: true);
|
||||
|
||||
SetupOrganizationDataOwnershipPolicy(
|
||||
sutProvider,
|
||||
orgUser2.UserId!.Value,
|
||||
organization.Id,
|
||||
OrganizationUserStatusType.Revoked,
|
||||
policyEnabled: true);
|
||||
|
||||
sutProvider.GetDependency<ITwoFactorIsEnabledQuery>()
|
||||
.TwoFactorIsEnabledAsync(Arg.Any<IEnumerable<Guid>>())
|
||||
.Returns(new List<(Guid userId, bool twoFactorIsEnabled)>
|
||||
{
|
||||
(orgUser1.UserId!.Value, true),
|
||||
(orgUser2.UserId!.Value, true)
|
||||
});
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.RestoreUsersAsync(
|
||||
organization.Id,
|
||||
[orgUser1.Id, orgUser2.Id],
|
||||
owner.Id,
|
||||
userService,
|
||||
null); // Null collection name
|
||||
|
||||
// Assert - No collections should be created
|
||||
await sutProvider.GetDependency<ICollectionRepository>()
|
||||
.DidNotReceive()
|
||||
.CreateDefaultCollectionsAsync(Arg.Any<Guid>(), Arg.Any<IEnumerable<Guid>>(), Arg.Any<string>());
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user