mirror of
https://github.com/bitwarden/server
synced 2026-01-03 17:14:00 +00:00
Merge branch 'main' into jmccannon/ac/pm-27131-auto-confirm-req
This commit is contained in:
@@ -0,0 +1,414 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Organizations.Update;
|
||||
using Bit.Core.Billing.Organizations.Services;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.Organizations;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class OrganizationUpdateCommandTests
|
||||
{
|
||||
[Theory, BitAutoData]
|
||||
public async Task UpdateAsync_WhenValidOrganization_UpdatesOrganization(
|
||||
Guid organizationId,
|
||||
string name,
|
||||
string billingEmail,
|
||||
Organization organization,
|
||||
SutProvider<OrganizationUpdateCommand> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
|
||||
var organizationService = sutProvider.GetDependency<IOrganizationService>();
|
||||
var organizationBillingService = sutProvider.GetDependency<IOrganizationBillingService>();
|
||||
|
||||
organization.Id = organizationId;
|
||||
organization.GatewayCustomerId = null; // No Stripe customer, so no billing update
|
||||
|
||||
organizationRepository
|
||||
.GetByIdAsync(organizationId)
|
||||
.Returns(organization);
|
||||
|
||||
var request = new OrganizationUpdateRequest
|
||||
{
|
||||
OrganizationId = organizationId,
|
||||
Name = name,
|
||||
BillingEmail = billingEmail
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.UpdateAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(organizationId, result.Id);
|
||||
Assert.Equal(name, result.Name);
|
||||
Assert.Equal(billingEmail.ToLowerInvariant().Trim(), result.BillingEmail);
|
||||
|
||||
await organizationRepository
|
||||
.Received(1)
|
||||
.GetByIdAsync(Arg.Is<Guid>(id => id == organizationId));
|
||||
await organizationService
|
||||
.Received(1)
|
||||
.ReplaceAndUpdateCacheAsync(
|
||||
result,
|
||||
EventType.Organization_Updated);
|
||||
await organizationBillingService
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpdateOrganizationNameAndEmail(Arg.Any<Organization>());
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task UpdateAsync_WhenOrganizationNotFound_ThrowsNotFoundException(
|
||||
Guid organizationId,
|
||||
string name,
|
||||
string billingEmail,
|
||||
SutProvider<OrganizationUpdateCommand> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
|
||||
|
||||
organizationRepository
|
||||
.GetByIdAsync(organizationId)
|
||||
.Returns((Organization)null);
|
||||
|
||||
var request = new OrganizationUpdateRequest
|
||||
{
|
||||
OrganizationId = organizationId,
|
||||
Name = name,
|
||||
BillingEmail = billingEmail
|
||||
};
|
||||
|
||||
// Act/Assert
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.UpdateAsync(request));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData("")]
|
||||
[BitAutoData((string)null)]
|
||||
public async Task UpdateAsync_WhenGatewayCustomerIdIsNullOrEmpty_SkipsBillingUpdate(
|
||||
string gatewayCustomerId,
|
||||
Guid organizationId,
|
||||
Organization organization,
|
||||
SutProvider<OrganizationUpdateCommand> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
|
||||
var organizationService = sutProvider.GetDependency<IOrganizationService>();
|
||||
var organizationBillingService = sutProvider.GetDependency<IOrganizationBillingService>();
|
||||
|
||||
organization.Id = organizationId;
|
||||
organization.Name = "Old Name";
|
||||
organization.GatewayCustomerId = gatewayCustomerId;
|
||||
|
||||
organizationRepository
|
||||
.GetByIdAsync(organizationId)
|
||||
.Returns(organization);
|
||||
|
||||
var request = new OrganizationUpdateRequest
|
||||
{
|
||||
OrganizationId = organizationId,
|
||||
Name = "New Name",
|
||||
BillingEmail = organization.BillingEmail
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.UpdateAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(organizationId, result.Id);
|
||||
Assert.Equal("New Name", result.Name);
|
||||
|
||||
await organizationService
|
||||
.Received(1)
|
||||
.ReplaceAndUpdateCacheAsync(
|
||||
result,
|
||||
EventType.Organization_Updated);
|
||||
await organizationBillingService
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpdateOrganizationNameAndEmail(Arg.Any<Organization>());
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task UpdateAsync_WhenKeysProvided_AndNotAlreadySet_SetsKeys(
|
||||
Guid organizationId,
|
||||
string publicKey,
|
||||
string encryptedPrivateKey,
|
||||
Organization organization,
|
||||
SutProvider<OrganizationUpdateCommand> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
|
||||
var organizationService = sutProvider.GetDependency<IOrganizationService>();
|
||||
|
||||
organization.Id = organizationId;
|
||||
organization.PublicKey = null;
|
||||
organization.PrivateKey = null;
|
||||
|
||||
organizationRepository
|
||||
.GetByIdAsync(organizationId)
|
||||
.Returns(organization);
|
||||
|
||||
var request = new OrganizationUpdateRequest
|
||||
{
|
||||
OrganizationId = organizationId,
|
||||
Name = organization.Name,
|
||||
BillingEmail = organization.BillingEmail,
|
||||
PublicKey = publicKey,
|
||||
EncryptedPrivateKey = encryptedPrivateKey
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.UpdateAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(organizationId, result.Id);
|
||||
Assert.Equal(publicKey, result.PublicKey);
|
||||
Assert.Equal(encryptedPrivateKey, result.PrivateKey);
|
||||
|
||||
await organizationService
|
||||
.Received(1)
|
||||
.ReplaceAndUpdateCacheAsync(
|
||||
result,
|
||||
EventType.Organization_Updated);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task UpdateAsync_WhenKeysProvided_AndAlreadySet_DoesNotOverwriteKeys(
|
||||
Guid organizationId,
|
||||
string newPublicKey,
|
||||
string newEncryptedPrivateKey,
|
||||
Organization organization,
|
||||
SutProvider<OrganizationUpdateCommand> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
|
||||
var organizationService = sutProvider.GetDependency<IOrganizationService>();
|
||||
|
||||
organization.Id = organizationId;
|
||||
var existingPublicKey = organization.PublicKey;
|
||||
var existingPrivateKey = organization.PrivateKey;
|
||||
|
||||
organizationRepository
|
||||
.GetByIdAsync(organizationId)
|
||||
.Returns(organization);
|
||||
|
||||
var request = new OrganizationUpdateRequest
|
||||
{
|
||||
OrganizationId = organizationId,
|
||||
Name = organization.Name,
|
||||
BillingEmail = organization.BillingEmail,
|
||||
PublicKey = newPublicKey,
|
||||
EncryptedPrivateKey = newEncryptedPrivateKey
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.UpdateAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(organizationId, result.Id);
|
||||
Assert.Equal(existingPublicKey, result.PublicKey);
|
||||
Assert.Equal(existingPrivateKey, result.PrivateKey);
|
||||
|
||||
await organizationService
|
||||
.Received(1)
|
||||
.ReplaceAndUpdateCacheAsync(
|
||||
result,
|
||||
EventType.Organization_Updated);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task UpdateAsync_UpdatingNameOnly_UpdatesNameAndNotBillingEmail(
|
||||
Guid organizationId,
|
||||
string newName,
|
||||
Organization organization,
|
||||
SutProvider<OrganizationUpdateCommand> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
|
||||
var organizationService = sutProvider.GetDependency<IOrganizationService>();
|
||||
var organizationBillingService = sutProvider.GetDependency<IOrganizationBillingService>();
|
||||
|
||||
organization.Id = organizationId;
|
||||
organization.Name = "Old Name";
|
||||
var originalBillingEmail = organization.BillingEmail;
|
||||
|
||||
organizationRepository
|
||||
.GetByIdAsync(organizationId)
|
||||
.Returns(organization);
|
||||
|
||||
var request = new OrganizationUpdateRequest
|
||||
{
|
||||
OrganizationId = organizationId,
|
||||
Name = newName,
|
||||
BillingEmail = null
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.UpdateAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(organizationId, result.Id);
|
||||
Assert.Equal(newName, result.Name);
|
||||
Assert.Equal(originalBillingEmail, result.BillingEmail);
|
||||
|
||||
await organizationService
|
||||
.Received(1)
|
||||
.ReplaceAndUpdateCacheAsync(
|
||||
result,
|
||||
EventType.Organization_Updated);
|
||||
await organizationBillingService
|
||||
.Received(1)
|
||||
.UpdateOrganizationNameAndEmail(result);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task UpdateAsync_UpdatingBillingEmailOnly_UpdatesBillingEmailAndNotName(
|
||||
Guid organizationId,
|
||||
string newBillingEmail,
|
||||
Organization organization,
|
||||
SutProvider<OrganizationUpdateCommand> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
|
||||
var organizationService = sutProvider.GetDependency<IOrganizationService>();
|
||||
var organizationBillingService = sutProvider.GetDependency<IOrganizationBillingService>();
|
||||
|
||||
organization.Id = organizationId;
|
||||
organization.BillingEmail = "old@example.com";
|
||||
var originalName = organization.Name;
|
||||
|
||||
organizationRepository
|
||||
.GetByIdAsync(organizationId)
|
||||
.Returns(organization);
|
||||
|
||||
var request = new OrganizationUpdateRequest
|
||||
{
|
||||
OrganizationId = organizationId,
|
||||
Name = null,
|
||||
BillingEmail = newBillingEmail
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.UpdateAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(organizationId, result.Id);
|
||||
Assert.Equal(originalName, result.Name);
|
||||
Assert.Equal(newBillingEmail.ToLowerInvariant().Trim(), result.BillingEmail);
|
||||
|
||||
await organizationService
|
||||
.Received(1)
|
||||
.ReplaceAndUpdateCacheAsync(
|
||||
result,
|
||||
EventType.Organization_Updated);
|
||||
await organizationBillingService
|
||||
.Received(1)
|
||||
.UpdateOrganizationNameAndEmail(result);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task UpdateAsync_WhenNoChanges_PreservesBothFields(
|
||||
Guid organizationId,
|
||||
Organization organization,
|
||||
SutProvider<OrganizationUpdateCommand> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
|
||||
var organizationService = sutProvider.GetDependency<IOrganizationService>();
|
||||
var organizationBillingService = sutProvider.GetDependency<IOrganizationBillingService>();
|
||||
|
||||
organization.Id = organizationId;
|
||||
var originalName = organization.Name;
|
||||
var originalBillingEmail = organization.BillingEmail;
|
||||
|
||||
organizationRepository
|
||||
.GetByIdAsync(organizationId)
|
||||
.Returns(organization);
|
||||
|
||||
var request = new OrganizationUpdateRequest
|
||||
{
|
||||
OrganizationId = organizationId,
|
||||
Name = null,
|
||||
BillingEmail = null
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.UpdateAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(organizationId, result.Id);
|
||||
Assert.Equal(originalName, result.Name);
|
||||
Assert.Equal(originalBillingEmail, result.BillingEmail);
|
||||
|
||||
await organizationService
|
||||
.Received(1)
|
||||
.ReplaceAndUpdateCacheAsync(
|
||||
result,
|
||||
EventType.Organization_Updated);
|
||||
await organizationBillingService
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpdateOrganizationNameAndEmail(Arg.Any<Organization>());
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task UpdateAsync_SelfHosted_OnlyUpdatesKeysNotOrganizationDetails(
|
||||
Guid organizationId,
|
||||
string newName,
|
||||
string newBillingEmail,
|
||||
string publicKey,
|
||||
string encryptedPrivateKey,
|
||||
Organization organization,
|
||||
SutProvider<OrganizationUpdateCommand> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
var organizationBillingService = sutProvider.GetDependency<IOrganizationBillingService>();
|
||||
var globalSettings = sutProvider.GetDependency<IGlobalSettings>();
|
||||
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
|
||||
|
||||
globalSettings.SelfHosted.Returns(true);
|
||||
|
||||
organization.Id = organizationId;
|
||||
organization.Name = "Original Name";
|
||||
organization.BillingEmail = "original@example.com";
|
||||
organization.PublicKey = null;
|
||||
organization.PrivateKey = null;
|
||||
|
||||
organizationRepository.GetByIdAsync(organizationId).Returns(organization);
|
||||
|
||||
var request = new OrganizationUpdateRequest
|
||||
{
|
||||
OrganizationId = organizationId,
|
||||
Name = newName, // Should be ignored
|
||||
BillingEmail = newBillingEmail, // Should be ignored
|
||||
PublicKey = publicKey,
|
||||
EncryptedPrivateKey = encryptedPrivateKey
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.UpdateAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("Original Name", result.Name); // Not changed
|
||||
Assert.Equal("original@example.com", result.BillingEmail); // Not changed
|
||||
Assert.Equal(publicKey, result.PublicKey); // Changed
|
||||
Assert.Equal(encryptedPrivateKey, result.PrivateKey); // Changed
|
||||
|
||||
await organizationBillingService
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.UpdateOrganizationNameAndEmail(Arg.Any<Organization>());
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ using Bit.Test.Common.Helpers;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
using ZiggyCreatures.Caching.Fusion;
|
||||
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
@@ -25,7 +26,6 @@ public class EventIntegrationHandlerTests
|
||||
private const string _templateWithOrganization = "Org: #OrganizationName#";
|
||||
private const string _templateWithUser = "#UserName#, #UserEmail#, #UserType#";
|
||||
private const string _templateWithActingUser = "#ActingUserName#, #ActingUserEmail#, #ActingUserType#";
|
||||
private static readonly Guid _groupId = Guid.NewGuid();
|
||||
private static readonly Guid _organizationId = Guid.NewGuid();
|
||||
private static readonly Uri _uri = new Uri("https://localhost");
|
||||
private static readonly Uri _uri2 = new Uri("https://example.com");
|
||||
@@ -113,6 +113,232 @@ public class EventIntegrationHandlerTests
|
||||
return [config];
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task BuildContextAsync_ActingUserIdPresent_UsesCache(EventMessage eventMessage, OrganizationUserUserDetails actingUser)
|
||||
{
|
||||
var sutProvider = GetSutProvider(OneConfiguration(_templateWithActingUser));
|
||||
var cache = sutProvider.GetDependency<IFusionCache>();
|
||||
|
||||
eventMessage.OrganizationId ??= Guid.NewGuid();
|
||||
eventMessage.ActingUserId ??= Guid.NewGuid();
|
||||
|
||||
cache.GetOrSetAsync(
|
||||
key: Arg.Any<string>(),
|
||||
factory: Arg.Any<Func<FusionCacheFactoryExecutionContext<OrganizationUserUserDetails?>, CancellationToken, Task<OrganizationUserUserDetails?>>>()
|
||||
).Returns(actingUser);
|
||||
|
||||
var context = await sutProvider.Sut.BuildContextAsync(eventMessage, _templateWithActingUser);
|
||||
|
||||
await cache.Received(1).GetOrSetAsync(
|
||||
key: Arg.Any<string>(),
|
||||
factory: Arg.Any<Func<FusionCacheFactoryExecutionContext<OrganizationUserUserDetails?>, CancellationToken, Task<OrganizationUserUserDetails?>>>()
|
||||
);
|
||||
|
||||
Assert.Equal(actingUser, context.ActingUser);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task BuildContextAsync_ActingUserIdNull_SkipsCache(EventMessage eventMessage)
|
||||
{
|
||||
var sutProvider = GetSutProvider(OneConfiguration(_templateWithActingUser));
|
||||
var cache = sutProvider.GetDependency<IFusionCache>();
|
||||
|
||||
eventMessage.OrganizationId ??= Guid.NewGuid();
|
||||
eventMessage.ActingUserId = null;
|
||||
|
||||
var context = await sutProvider.Sut.BuildContextAsync(eventMessage, _templateWithActingUser);
|
||||
|
||||
await cache.DidNotReceive().GetOrSetAsync(
|
||||
key: Arg.Any<string>(),
|
||||
factory: Arg.Any<Func<FusionCacheFactoryExecutionContext<OrganizationUserUserDetails?>, CancellationToken, Task<OrganizationUserUserDetails?>>>()
|
||||
);
|
||||
Assert.Null(context.ActingUser);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task BuildContextAsync_ActingUserOrganizationIdNull_SkipsCache(EventMessage eventMessage)
|
||||
{
|
||||
var sutProvider = GetSutProvider(OneConfiguration(_templateWithActingUser));
|
||||
var cache = sutProvider.GetDependency<IFusionCache>();
|
||||
|
||||
eventMessage.OrganizationId = null;
|
||||
eventMessage.ActingUserId ??= Guid.NewGuid();
|
||||
|
||||
var context = await sutProvider.Sut.BuildContextAsync(eventMessage, _templateWithActingUser);
|
||||
|
||||
await cache.DidNotReceive().GetOrSetAsync(
|
||||
key: Arg.Any<string>(),
|
||||
factory: Arg.Any<Func<FusionCacheFactoryExecutionContext<OrganizationUserUserDetails?>, CancellationToken, Task<OrganizationUserUserDetails?>>>()
|
||||
);
|
||||
Assert.Null(context.ActingUser);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task BuildContextAsync_GroupIdPresent_UsesCache(EventMessage eventMessage, Group group)
|
||||
{
|
||||
var sutProvider = GetSutProvider(OneConfiguration(_templateWithGroup));
|
||||
var cache = sutProvider.GetDependency<IFusionCache>();
|
||||
|
||||
eventMessage.GroupId ??= Guid.NewGuid();
|
||||
|
||||
cache.GetOrSetAsync(
|
||||
key: Arg.Any<string>(),
|
||||
factory: Arg.Any<Func<FusionCacheFactoryExecutionContext<Group?>, CancellationToken, Task<Group?>>>()
|
||||
).Returns(group);
|
||||
|
||||
var context = await sutProvider.Sut.BuildContextAsync(eventMessage, _templateWithGroup);
|
||||
|
||||
await cache.Received(1).GetOrSetAsync(
|
||||
key: Arg.Any<string>(),
|
||||
factory: Arg.Any<Func<FusionCacheFactoryExecutionContext<Group?>, CancellationToken, Task<Group?>>>()
|
||||
);
|
||||
Assert.Equal(group, context.Group);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task BuildContextAsync_GroupIdNull_SkipsCache(EventMessage eventMessage)
|
||||
{
|
||||
var sutProvider = GetSutProvider(OneConfiguration(_templateWithGroup));
|
||||
var cache = sutProvider.GetDependency<IFusionCache>();
|
||||
eventMessage.GroupId = null;
|
||||
|
||||
var context = await sutProvider.Sut.BuildContextAsync(eventMessage, _templateWithGroup);
|
||||
|
||||
await cache.DidNotReceive().GetOrSetAsync(
|
||||
key: Arg.Any<string>(),
|
||||
factory: Arg.Any<Func<FusionCacheFactoryExecutionContext<Group?>, CancellationToken, Task<Group?>>>()
|
||||
);
|
||||
Assert.Null(context.Group);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task BuildContextAsync_OrganizationIdPresent_UsesCache(EventMessage eventMessage, Organization organization)
|
||||
{
|
||||
var sutProvider = GetSutProvider(OneConfiguration(_templateWithOrganization));
|
||||
var cache = sutProvider.GetDependency<IFusionCache>();
|
||||
|
||||
eventMessage.OrganizationId ??= Guid.NewGuid();
|
||||
|
||||
cache.GetOrSetAsync(
|
||||
key: Arg.Any<string>(),
|
||||
factory: Arg.Any<Func<FusionCacheFactoryExecutionContext<Organization?>, CancellationToken, Task<Organization?>>>()
|
||||
).Returns(organization);
|
||||
|
||||
var context = await sutProvider.Sut.BuildContextAsync(eventMessage, _templateWithOrganization);
|
||||
|
||||
await cache.Received(1).GetOrSetAsync(
|
||||
key: Arg.Any<string>(),
|
||||
factory: Arg.Any<Func<FusionCacheFactoryExecutionContext<Organization?>, CancellationToken, Task<Organization?>>>()
|
||||
);
|
||||
Assert.Equal(organization, context.Organization);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task BuildContextAsync_OrganizationIdNull_SkipsCache(EventMessage eventMessage)
|
||||
{
|
||||
var sutProvider = GetSutProvider(OneConfiguration(_templateWithOrganization));
|
||||
var cache = sutProvider.GetDependency<IFusionCache>();
|
||||
|
||||
eventMessage.OrganizationId = null;
|
||||
|
||||
var context = await sutProvider.Sut.BuildContextAsync(eventMessage, _templateWithOrganization);
|
||||
|
||||
await cache.DidNotReceive().GetOrSetAsync(
|
||||
key: Arg.Any<string>(),
|
||||
factory: Arg.Any<Func<FusionCacheFactoryExecutionContext<Organization?>, CancellationToken, Task<Organization?>>>()
|
||||
);
|
||||
Assert.Null(context.Organization);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task BuildContextAsync_UserIdPresent_UsesCache(EventMessage eventMessage, OrganizationUserUserDetails userDetails)
|
||||
{
|
||||
var sutProvider = GetSutProvider(OneConfiguration(_templateWithUser));
|
||||
var cache = sutProvider.GetDependency<IFusionCache>();
|
||||
|
||||
eventMessage.OrganizationId ??= Guid.NewGuid();
|
||||
eventMessage.UserId ??= Guid.NewGuid();
|
||||
|
||||
cache.GetOrSetAsync(
|
||||
key: Arg.Any<string>(),
|
||||
factory: Arg.Any<Func<FusionCacheFactoryExecutionContext<OrganizationUserUserDetails?>, CancellationToken, Task<OrganizationUserUserDetails?>>>()
|
||||
).Returns(userDetails);
|
||||
|
||||
var context = await sutProvider.Sut.BuildContextAsync(eventMessage, _templateWithUser);
|
||||
|
||||
await cache.Received(1).GetOrSetAsync(
|
||||
key: Arg.Any<string>(),
|
||||
factory: Arg.Any<Func<FusionCacheFactoryExecutionContext<OrganizationUserUserDetails?>, CancellationToken, Task<OrganizationUserUserDetails?>>>()
|
||||
);
|
||||
|
||||
Assert.Equal(userDetails, context.User);
|
||||
}
|
||||
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task BuildContextAsync_UserIdNull_SkipsCache(EventMessage eventMessage)
|
||||
{
|
||||
var sutProvider = GetSutProvider(OneConfiguration(_templateWithUser));
|
||||
var cache = sutProvider.GetDependency<IFusionCache>();
|
||||
|
||||
eventMessage.OrganizationId = null;
|
||||
eventMessage.UserId ??= Guid.NewGuid();
|
||||
|
||||
var context = await sutProvider.Sut.BuildContextAsync(eventMessage, _templateWithUser);
|
||||
|
||||
await cache.DidNotReceive().GetOrSetAsync(
|
||||
key: Arg.Any<string>(),
|
||||
factory: Arg.Any<Func<FusionCacheFactoryExecutionContext<OrganizationUserUserDetails?>, CancellationToken, Task<OrganizationUserUserDetails?>>>()
|
||||
);
|
||||
|
||||
Assert.Null(context.User);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task BuildContextAsync_OrganizationUserIdNull_SkipsCache(EventMessage eventMessage)
|
||||
{
|
||||
var sutProvider = GetSutProvider(OneConfiguration(_templateWithUser));
|
||||
var cache = sutProvider.GetDependency<IFusionCache>();
|
||||
|
||||
eventMessage.OrganizationId ??= Guid.NewGuid();
|
||||
eventMessage.UserId = null;
|
||||
|
||||
var context = await sutProvider.Sut.BuildContextAsync(eventMessage, _templateWithUser);
|
||||
|
||||
await cache.DidNotReceive().GetOrSetAsync(
|
||||
key: Arg.Any<string>(),
|
||||
factory: Arg.Any<Func<FusionCacheFactoryExecutionContext<OrganizationUserUserDetails?>, CancellationToken, Task<OrganizationUserUserDetails?>>>()
|
||||
);
|
||||
|
||||
Assert.Null(context.User);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task BuildContextAsync_NoSpecialTokens_DoesNotCallAnyCache(EventMessage eventMessage)
|
||||
{
|
||||
var sutProvider = GetSutProvider(OneConfiguration(_templateWithUser));
|
||||
var cache = sutProvider.GetDependency<IFusionCache>();
|
||||
|
||||
eventMessage.ActingUserId ??= Guid.NewGuid();
|
||||
eventMessage.GroupId ??= Guid.NewGuid();
|
||||
eventMessage.OrganizationId ??= Guid.NewGuid();
|
||||
eventMessage.UserId ??= Guid.NewGuid();
|
||||
|
||||
await sutProvider.Sut.BuildContextAsync(eventMessage, _templateBase);
|
||||
|
||||
await cache.DidNotReceive().GetOrSetAsync(
|
||||
key: Arg.Any<string>(),
|
||||
factory: Arg.Any<Func<FusionCacheFactoryExecutionContext<Group?>, CancellationToken, Task<Group?>>>()
|
||||
);
|
||||
await cache.DidNotReceive().GetOrSetAsync(
|
||||
key: Arg.Any<string>(),
|
||||
factory: Arg.Any<Func<FusionCacheFactoryExecutionContext<Organization?>, CancellationToken, Task<Organization?>>>()
|
||||
);
|
||||
await cache.DidNotReceive().GetOrSetAsync(
|
||||
key: Arg.Any<string>(),
|
||||
factory: Arg.Any<Func<FusionCacheFactoryExecutionContext<OrganizationUserUserDetails?>, CancellationToken, Task<OrganizationUserUserDetails?>>>()
|
||||
);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task HandleEventAsync_BaseTemplateNoConfigurations_DoesNothing(EventMessage eventMessage)
|
||||
@@ -176,99 +402,6 @@ public class EventIntegrationHandlerTests
|
||||
await sutProvider.GetDependency<IOrganizationUserRepository>().DidNotReceiveWithAnyArgs().GetDetailsByOrganizationIdUserIdAsync(Arg.Any<Guid>(), Arg.Any<Guid>());
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task HandleEventAsync_ActingUserTemplate_LoadsUserFromRepository(EventMessage eventMessage)
|
||||
{
|
||||
var sutProvider = GetSutProvider(OneConfiguration(_templateWithActingUser));
|
||||
var user = Substitute.For<OrganizationUserUserDetails>();
|
||||
user.Email = "test@example.com";
|
||||
user.Name = "Test";
|
||||
eventMessage.OrganizationId = _organizationId;
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.GetDetailsByOrganizationIdUserIdAsync(Arg.Any<Guid>(), Arg.Any<Guid>()).Returns(user);
|
||||
await sutProvider.Sut.HandleEventAsync(eventMessage);
|
||||
|
||||
var expectedMessage = EventIntegrationHandlerTests.ExpectedMessage($"{user.Name}, {user.Email}, {user.Type}");
|
||||
|
||||
Assert.Single(_eventIntegrationPublisher.ReceivedCalls());
|
||||
await _eventIntegrationPublisher.Received(1).PublishAsync(Arg.Is(
|
||||
AssertHelper.AssertPropertyEqual(expectedMessage, new[] { "MessageId" })));
|
||||
await sutProvider.GetDependency<IGroupRepository>().DidNotReceiveWithAnyArgs().GetByIdAsync(Arg.Any<Guid>());
|
||||
await sutProvider.GetDependency<IOrganizationRepository>().DidNotReceiveWithAnyArgs().GetByIdAsync(Arg.Any<Guid>());
|
||||
await sutProvider.GetDependency<IOrganizationUserRepository>().Received(1).GetDetailsByOrganizationIdUserIdAsync(Arg.Any<Guid>(), eventMessage.ActingUserId ?? Guid.Empty);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task HandleEventAsync_GroupTemplate_LoadsGroupFromRepository(EventMessage eventMessage)
|
||||
{
|
||||
var sutProvider = GetSutProvider(OneConfiguration(_templateWithGroup));
|
||||
var group = Substitute.For<Group>();
|
||||
group.Name = "Test";
|
||||
eventMessage.GroupId = _groupId;
|
||||
eventMessage.OrganizationId = _organizationId;
|
||||
|
||||
sutProvider.GetDependency<IGroupRepository>().GetByIdAsync(Arg.Any<Guid>()).Returns(group);
|
||||
await sutProvider.Sut.HandleEventAsync(eventMessage);
|
||||
|
||||
Assert.Single(_eventIntegrationPublisher.ReceivedCalls());
|
||||
|
||||
var expectedMessage = EventIntegrationHandlerTests.ExpectedMessage($"Group: {group.Name}");
|
||||
|
||||
Assert.Single(_eventIntegrationPublisher.ReceivedCalls());
|
||||
await _eventIntegrationPublisher.Received(1).PublishAsync(Arg.Is(
|
||||
AssertHelper.AssertPropertyEqual(expectedMessage, new[] { "MessageId" })));
|
||||
await sutProvider.GetDependency<IGroupRepository>().Received(1).GetByIdAsync(eventMessage.GroupId ?? Guid.Empty);
|
||||
await sutProvider.GetDependency<IOrganizationRepository>().DidNotReceiveWithAnyArgs().GetByIdAsync(Arg.Any<Guid>());
|
||||
await sutProvider.GetDependency<IOrganizationUserRepository>().DidNotReceiveWithAnyArgs().GetDetailsByOrganizationIdUserIdAsync(Arg.Any<Guid>(), Arg.Any<Guid>());
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task HandleEventAsync_OrganizationTemplate_LoadsOrganizationFromRepository(EventMessage eventMessage)
|
||||
{
|
||||
var sutProvider = GetSutProvider(OneConfiguration(_templateWithOrganization));
|
||||
var organization = Substitute.For<Organization>();
|
||||
organization.Name = "Test";
|
||||
eventMessage.OrganizationId = _organizationId;
|
||||
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(Arg.Any<Guid>()).Returns(organization);
|
||||
await sutProvider.Sut.HandleEventAsync(eventMessage);
|
||||
|
||||
Assert.Single(_eventIntegrationPublisher.ReceivedCalls());
|
||||
|
||||
var expectedMessage = EventIntegrationHandlerTests.ExpectedMessage($"Org: {organization.Name}");
|
||||
|
||||
Assert.Single(_eventIntegrationPublisher.ReceivedCalls());
|
||||
await _eventIntegrationPublisher.Received(1).PublishAsync(Arg.Is(
|
||||
AssertHelper.AssertPropertyEqual(expectedMessage, new[] { "MessageId" })));
|
||||
await sutProvider.GetDependency<IGroupRepository>().DidNotReceiveWithAnyArgs().GetByIdAsync(Arg.Any<Guid>());
|
||||
await sutProvider.GetDependency<IOrganizationRepository>().Received(1).GetByIdAsync(eventMessage.OrganizationId ?? Guid.Empty);
|
||||
await sutProvider.GetDependency<IOrganizationUserRepository>().DidNotReceiveWithAnyArgs().GetDetailsByOrganizationIdUserIdAsync(Arg.Any<Guid>(), Arg.Any<Guid>());
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task HandleEventAsync_UserTemplate_LoadsUserFromRepository(EventMessage eventMessage)
|
||||
{
|
||||
var sutProvider = GetSutProvider(OneConfiguration(_templateWithUser));
|
||||
var user = Substitute.For<OrganizationUserUserDetails>();
|
||||
user.Email = "test@example.com";
|
||||
user.Name = "Test";
|
||||
eventMessage.OrganizationId = _organizationId;
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.GetDetailsByOrganizationIdUserIdAsync(Arg.Any<Guid>(), Arg.Any<Guid>()).Returns(user);
|
||||
await sutProvider.Sut.HandleEventAsync(eventMessage);
|
||||
|
||||
var expectedMessage = EventIntegrationHandlerTests.ExpectedMessage($"{user.Name}, {user.Email}, {user.Type}");
|
||||
|
||||
Assert.Single(_eventIntegrationPublisher.ReceivedCalls());
|
||||
await _eventIntegrationPublisher.Received(1).PublishAsync(Arg.Is(
|
||||
AssertHelper.AssertPropertyEqual(expectedMessage, new[] { "MessageId" })));
|
||||
await sutProvider.GetDependency<IGroupRepository>().DidNotReceiveWithAnyArgs().GetByIdAsync(Arg.Any<Guid>());
|
||||
await sutProvider.GetDependency<IOrganizationRepository>().DidNotReceiveWithAnyArgs().GetByIdAsync(Arg.Any<Guid>());
|
||||
await sutProvider.GetDependency<IOrganizationUserRepository>().Received(1).GetDetailsByOrganizationIdUserIdAsync(Arg.Any<Guid>(), eventMessage.UserId ?? Guid.Empty);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task HandleEventAsync_FilterReturnsFalse_DoesNothing(EventMessage eventMessage)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user