Files
server/test/Core.Test/AdminConsole/Services/GroupServiceTests.cs
Rui Tomé 53b8b3e868 [PM-34601] Bump Group.RevisionDate on edits and access changes (#7467)
* Add optional RevisionDate param to group sprocs

When provided, bump Group.RevisionDate on affected groups during
membership and collection-access changes. Defaults to NULL for
backward compatibility.

* Add migration for group RevisionDate bump

* Add revisionDate param to group repository methods

Update IGroupRepository and IOrganizationUserRepository interfaces
and their Dapper and Entity Framework implementations.

* Pass revisionDate through business logic to repos

Inject TimeProvider into commands, services, and controllers to
supply the timestamp when modifying group membership.

* Update unit tests for group revisionDate param

* Update and add integration tests for group revision

* Enhance IGroupRepository and IOrganizationUserRepository with detailed XML documentation

* Bump date on migration script

* Bump date on migration script
2026-04-29 17:24:08 +01:00

104 lines
4.9 KiB
C#

using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.AdminConsole.Services.Implementations;
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.OrganizationFixtures;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using Microsoft.Extensions.Time.Testing;
using NSubstitute;
using Xunit;
namespace Bit.Core.Test.AdminConsole.Services;
[SutProviderCustomize]
[OrganizationCustomize(UseGroups = true)]
public class GroupServiceTests
{
private static readonly DateTime _expectedRevisionDate = DateTime.UtcNow.AddYears(1);
[Theory, BitAutoData]
public async Task DeleteAsync_ValidData_DeletesGroup(Group group, SutProvider<GroupService> sutProvider)
{
await sutProvider.Sut.DeleteAsync(group);
await sutProvider.GetDependency<IGroupRepository>().Received().DeleteAsync(group);
await sutProvider.GetDependency<IEventService>().Received().LogGroupEventAsync(group, EventType.Group_Deleted);
}
[Theory, BitAutoData]
public async Task DeleteAsync_ValidData_WithEventSystemUser_DeletesGroup(Group group, EventSystemUser eventSystemUser, SutProvider<GroupService> sutProvider)
{
await sutProvider.Sut.DeleteAsync(group, eventSystemUser);
await sutProvider.GetDependency<IGroupRepository>().Received().DeleteAsync(group);
await sutProvider.GetDependency<IEventService>().Received().LogGroupEventAsync(group, EventType.Group_Deleted, eventSystemUser);
}
[Theory, BitAutoData]
public async Task DeleteUserAsync_ValidData_DeletesUserInGroupRepository(Group group, Organization organization, OrganizationUser organizationUser)
{
var sutProvider = SetupSutProvider();
group.OrganizationId = organization.Id;
organization.UseGroups = true;
organizationUser.OrganizationId = organization.Id;
sutProvider.GetDependency<IOrganizationUserRepository>().GetByIdAsync(organizationUser.Id)
.Returns(organizationUser);
await sutProvider.Sut.DeleteUserAsync(group, organizationUser.Id);
await sutProvider.GetDependency<IGroupRepository>().Received().DeleteUserAsync(group.Id, organizationUser.Id, Arg.Is<DateTime>(d => d == _expectedRevisionDate));
await sutProvider.GetDependency<IEventService>().Received()
.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_UpdatedGroups);
}
[Theory, BitAutoData]
public async Task DeleteUserAsync_ValidData_WithEventSystemUser_DeletesUserInGroupRepository(Group group, Organization organization, OrganizationUser organizationUser, EventSystemUser eventSystemUser)
{
var sutProvider = SetupSutProvider();
group.OrganizationId = organization.Id;
organization.UseGroups = true;
organizationUser.OrganizationId = organization.Id;
sutProvider.GetDependency<IOrganizationUserRepository>().GetByIdAsync(organizationUser.Id)
.Returns(organizationUser);
await sutProvider.Sut.DeleteUserAsync(group, organizationUser.Id, eventSystemUser);
await sutProvider.GetDependency<IGroupRepository>().Received().DeleteUserAsync(group.Id, organizationUser.Id, Arg.Is<DateTime>(d => d == _expectedRevisionDate));
await sutProvider.GetDependency<IEventService>().Received()
.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_UpdatedGroups, eventSystemUser);
}
[Theory, BitAutoData]
public async Task DeleteUserAsync_InvalidUser_ThrowsNotFound(Group group, Organization organization, OrganizationUser organizationUser, SutProvider<GroupService> sutProvider)
{
group.OrganizationId = organization.Id;
organization.UseGroups = true;
// organizationUser.OrganizationId = organization.Id;
sutProvider.GetDependency<IOrganizationUserRepository>().GetByIdAsync(organizationUser.Id)
.Returns(organizationUser);
// user not in organization
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.DeleteUserAsync(group, organizationUser.Id));
// invalid user
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.DeleteUserAsync(group, Guid.NewGuid()));
await sutProvider.GetDependency<IGroupRepository>().DidNotReceiveWithAnyArgs()
.DeleteUserAsync(default, default, default);
await sutProvider.GetDependency<IEventService>().DidNotReceiveWithAnyArgs()
.LogOrganizationUserEventAsync<OrganizationUser>(default, default);
}
private static SutProvider<GroupService> SetupSutProvider()
{
var sutProvider = new SutProvider<GroupService>()
.WithFakeTimeProvider()
.Create();
sutProvider.GetDependency<FakeTimeProvider>().SetUtcNow(_expectedRevisionDate);
return sutProvider;
}
}