1
0
mirror of https://github.com/bitwarden/server synced 2025-12-06 00:03:34 +00:00

Ac/pm 25823/vnext policy upsert pattern (#6426)

This commit is contained in:
Jimmy Vo
2025-10-10 11:23:02 -04:00
committed by GitHub
parent a565fd9ee4
commit 6072104153
14 changed files with 1020 additions and 0 deletions

View File

@@ -0,0 +1,124 @@
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyUpdateEvents;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyUpdateEvents.Interfaces;
using OneOf.Types;
using Xunit;
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.Policies;
public class PolicyEventHandlerHandlerFactoryTests
{
[Fact]
public void GetHandler_ReturnsHandler_WhenHandlerExists()
{
// Arrange
var expectedHandler = new FakeSingleOrgDependencyEvent();
var factory = new PolicyEventHandlerHandlerFactory([expectedHandler]);
// Act
var result = factory.GetHandler<IEnforceDependentPoliciesEvent>(PolicyType.SingleOrg);
// Assert
Assert.True(result.IsT0);
Assert.Equal(expectedHandler, result.AsT0);
}
[Fact]
public void GetHandler_ReturnsNone_WhenHandlerDoesNotExist()
{
// Arrange
var factory = new PolicyEventHandlerHandlerFactory([new FakeSingleOrgDependencyEvent()]);
// Act
var result = factory.GetHandler<IEnforceDependentPoliciesEvent>(PolicyType.RequireSso);
// Assert
Assert.True(result.IsT1);
Assert.IsType<None>(result.AsT1);
}
[Fact]
public void GetHandler_ReturnsNone_WhenHandlerTypeDoesNotMatch()
{
// Arrange
var factory = new PolicyEventHandlerHandlerFactory([new FakeSingleOrgDependencyEvent()]);
// Act
var result = factory.GetHandler<IPolicyValidationEvent>(PolicyType.SingleOrg);
// Assert
Assert.True(result.IsT1);
Assert.IsType<None>(result.AsT1);
}
[Fact]
public void GetHandler_ReturnsCorrectHandler_WhenMultipleHandlerTypesExist()
{
// Arrange
var dependencyEvent = new FakeSingleOrgDependencyEvent();
var validationEvent = new FakeSingleOrgValidationEvent();
var factory = new PolicyEventHandlerHandlerFactory([dependencyEvent, validationEvent]);
// Act
var dependencyResult = factory.GetHandler<IEnforceDependentPoliciesEvent>(PolicyType.SingleOrg);
var validationResult = factory.GetHandler<IPolicyValidationEvent>(PolicyType.SingleOrg);
// Assert
Assert.True(dependencyResult.IsT0);
Assert.Equal(dependencyEvent, dependencyResult.AsT0);
Assert.True(validationResult.IsT0);
Assert.Equal(validationEvent, validationResult.AsT0);
}
[Fact]
public void GetHandler_ReturnsCorrectHandler_WhenMultiplePolicyTypesExist()
{
// Arrange
var singleOrgEvent = new FakeSingleOrgDependencyEvent();
var requireSsoEvent = new FakeRequireSsoDependencyEvent();
var factory = new PolicyEventHandlerHandlerFactory([singleOrgEvent, requireSsoEvent]);
// Act
var singleOrgResult = factory.GetHandler<IEnforceDependentPoliciesEvent>(PolicyType.SingleOrg);
var requireSsoResult = factory.GetHandler<IEnforceDependentPoliciesEvent>(PolicyType.RequireSso);
// Assert
Assert.True(singleOrgResult.IsT0);
Assert.Equal(singleOrgEvent, singleOrgResult.AsT0);
Assert.True(requireSsoResult.IsT0);
Assert.Equal(requireSsoEvent, requireSsoResult.AsT0);
}
[Fact]
public void GetHandler_Throws_WhenDuplicateHandlersExist()
{
// Arrange
var factory = new PolicyEventHandlerHandlerFactory([
new FakeSingleOrgDependencyEvent(),
new FakeSingleOrgDependencyEvent()
]);
// Act & Assert
var exception = Assert.Throws<InvalidOperationException>(() =>
factory.GetHandler<IEnforceDependentPoliciesEvent>(PolicyType.SingleOrg));
Assert.Contains("Multiple IPolicyUpdateEvent handlers of type IEnforceDependentPoliciesEvent found for PolicyType SingleOrg", exception.Message);
Assert.Contains("Expected one IEnforceDependentPoliciesEvent handler per PolicyType", exception.Message);
}
[Fact]
public void GetHandler_ReturnsNone_WhenNoHandlersProvided()
{
// Arrange
var factory = new PolicyEventHandlerHandlerFactory([]);
// Act
var result = factory.GetHandler<IEnforceDependentPoliciesEvent>(PolicyType.SingleOrg);
// Assert
Assert.True(result.IsT1);
Assert.IsType<None>(result.AsT1);
}
}

View File

@@ -0,0 +1,37 @@
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyUpdateEvents.Interfaces;
using NSubstitute;
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.Policies;
public class FakeSingleOrgDependencyEvent : IEnforceDependentPoliciesEvent
{
public PolicyType Type => PolicyType.SingleOrg;
public IEnumerable<PolicyType> RequiredPolicies => [];
}
public class FakeRequireSsoDependencyEvent : IEnforceDependentPoliciesEvent
{
public PolicyType Type => PolicyType.RequireSso;
public IEnumerable<PolicyType> RequiredPolicies => [PolicyType.SingleOrg];
}
public class FakeVaultTimeoutDependencyEvent : IEnforceDependentPoliciesEvent
{
public PolicyType Type => PolicyType.MaximumVaultTimeout;
public IEnumerable<PolicyType> RequiredPolicies => [PolicyType.SingleOrg];
}
public class FakeSingleOrgValidationEvent : IPolicyValidationEvent
{
public PolicyType Type => PolicyType.SingleOrg;
public readonly Func<SavePolicyModel, Policy?, Task<string>> ValidateAsyncMock = Substitute.For<Func<SavePolicyModel, Policy?, Task<string>>>();
public Task<string> ValidateAsync(SavePolicyModel policyRequest, Policy? currentPolicy)
{
return ValidateAsyncMock(policyRequest, currentPolicy);
}
}

View File

@@ -0,0 +1,471 @@
#nullable enable
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Implementations;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyUpdateEvents.Interfaces;
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Exceptions;
using Bit.Core.Models.Data.Organizations;
using Bit.Core.Services;
using Bit.Core.Test.AdminConsole.AutoFixture;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using Microsoft.Extensions.Time.Testing;
using NSubstitute;
using OneOf.Types;
using Xunit;
using EventType = Bit.Core.Enums.EventType;
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.Policies;
public class VNextSavePolicyCommandTests
{
[Theory, BitAutoData]
public async Task SaveAsync_NewPolicy_Success([PolicyUpdate(PolicyType.SingleOrg)] PolicyUpdate policyUpdate)
{
// Arrange
var fakePolicyValidationEvent = new FakeSingleOrgValidationEvent();
fakePolicyValidationEvent.ValidateAsyncMock(Arg.Any<SavePolicyModel>(), Arg.Any<Policy>()).Returns("");
var sutProvider = SutProviderFactory(
[new FakeSingleOrgDependencyEvent()],
[fakePolicyValidationEvent]);
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
var newPolicy = new Policy
{
Type = policyUpdate.Type,
OrganizationId = policyUpdate.OrganizationId,
Enabled = false
};
ArrangeOrganization(sutProvider, policyUpdate);
sutProvider.GetDependency<IPolicyRepository>().GetManyByOrganizationIdAsync(policyUpdate.OrganizationId).Returns([newPolicy]);
var creationDate = sutProvider.GetDependency<FakeTimeProvider>().Start;
// Act
await sutProvider.Sut.SaveAsync(savePolicyModel);
// Assert
await fakePolicyValidationEvent.ValidateAsyncMock
.Received(1)
.Invoke(Arg.Any<SavePolicyModel>(), Arg.Any<Policy>());
await AssertPolicySavedAsync(sutProvider, policyUpdate);
await sutProvider.GetDependency<IPolicyRepository>()
.Received(1)
.UpsertAsync(Arg.Is<Policy>(p =>
p.CreationDate == creationDate &&
p.RevisionDate == creationDate));
}
[Theory, BitAutoData]
public async Task SaveAsync_ExistingPolicy_Success(
[PolicyUpdate(PolicyType.SingleOrg)] PolicyUpdate policyUpdate,
[Policy(PolicyType.SingleOrg, false)] Policy currentPolicy)
{
// Arrange
var fakePolicyValidationEvent = new FakeSingleOrgValidationEvent();
fakePolicyValidationEvent.ValidateAsyncMock(Arg.Any<SavePolicyModel>(), Arg.Any<Policy>()).Returns("");
var sutProvider = SutProviderFactory(
[new FakeSingleOrgDependencyEvent()],
[fakePolicyValidationEvent]);
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
currentPolicy.OrganizationId = policyUpdate.OrganizationId;
sutProvider.GetDependency<IPolicyRepository>()
.GetByOrganizationIdTypeAsync(policyUpdate.OrganizationId, policyUpdate.Type)
.Returns(currentPolicy);
ArrangeOrganization(sutProvider, policyUpdate);
sutProvider.GetDependency<IPolicyRepository>()
.GetManyByOrganizationIdAsync(policyUpdate.OrganizationId)
.Returns([currentPolicy]);
// Act
await sutProvider.Sut.SaveAsync(savePolicyModel);
// Assert
await fakePolicyValidationEvent.ValidateAsyncMock
.Received(1)
.Invoke(Arg.Any<SavePolicyModel>(), currentPolicy);
await AssertPolicySavedAsync(sutProvider, policyUpdate);
var revisionDate = sutProvider.GetDependency<FakeTimeProvider>().Start;
await sutProvider.GetDependency<IPolicyRepository>()
.Received(1)
.UpsertAsync(Arg.Is<Policy>(p =>
p.Id == currentPolicy.Id &&
p.OrganizationId == currentPolicy.OrganizationId &&
p.Type == currentPolicy.Type &&
p.CreationDate == currentPolicy.CreationDate &&
p.RevisionDate == revisionDate));
}
[Fact]
public void Constructor_DuplicatePolicyDependencyEvents_Throws()
{
// Arrange & Act
var exception = Assert.Throws<Exception>(() =>
new VNextSavePolicyCommand(
Substitute.For<IApplicationCacheService>(),
Substitute.For<IEventService>(),
Substitute.For<IPolicyRepository>(),
[new FakeSingleOrgDependencyEvent(), new FakeSingleOrgDependencyEvent()],
Substitute.For<TimeProvider>(),
Substitute.For<IPolicyEventHandlerFactory>()));
// Assert
Assert.Contains("Duplicate PolicyValidationEvent for SingleOrg policy", exception.Message);
}
[Theory, BitAutoData]
public async Task SaveAsync_OrganizationDoesNotExist_ThrowsBadRequest([PolicyUpdate(PolicyType.ActivateAutofill)] PolicyUpdate policyUpdate)
{
// Arrange
var sutProvider = SutProviderFactory();
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
sutProvider.GetDependency<IApplicationCacheService>()
.GetOrganizationAbilityAsync(policyUpdate.OrganizationId)
.Returns(Task.FromResult<OrganizationAbility?>(null));
// Act
var badRequestException = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.SaveAsync(savePolicyModel));
// Assert
Assert.Contains("Organization not found", badRequestException.Message, StringComparison.OrdinalIgnoreCase);
await AssertPolicyNotSavedAsync(sutProvider);
}
[Theory, BitAutoData]
public async Task SaveAsync_OrganizationCannotUsePolicies_ThrowsBadRequest([PolicyUpdate(PolicyType.ActivateAutofill)] PolicyUpdate policyUpdate)
{
// Arrange
var sutProvider = SutProviderFactory();
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
sutProvider.GetDependency<IApplicationCacheService>()
.GetOrganizationAbilityAsync(policyUpdate.OrganizationId)
.Returns(new OrganizationAbility
{
Id = policyUpdate.OrganizationId,
UsePolicies = false
});
// Act
var badRequestException = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.SaveAsync(savePolicyModel));
// Assert
Assert.Contains("cannot use policies", badRequestException.Message, StringComparison.OrdinalIgnoreCase);
await AssertPolicyNotSavedAsync(sutProvider);
}
[Theory, BitAutoData]
public async Task SaveAsync_RequiredPolicyIsNull_Throws(
[PolicyUpdate(PolicyType.RequireSso)] PolicyUpdate policyUpdate)
{
// Arrange
var sutProvider = SutProviderFactory(
[
new FakeRequireSsoDependencyEvent(),
new FakeSingleOrgDependencyEvent()
]);
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
var requireSsoPolicy = new Policy
{
Type = PolicyType.RequireSso,
OrganizationId = policyUpdate.OrganizationId,
Enabled = false
};
ArrangeOrganization(sutProvider, policyUpdate);
sutProvider.GetDependency<IPolicyRepository>()
.GetManyByOrganizationIdAsync(policyUpdate.OrganizationId)
.Returns([requireSsoPolicy]);
// Act
var badRequestException = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.SaveAsync(savePolicyModel));
// Assert
Assert.Contains("Turn on the Single organization policy because it is required for the Require single sign-on authentication policy", badRequestException.Message, StringComparison.OrdinalIgnoreCase);
await AssertPolicyNotSavedAsync(sutProvider);
}
[Theory, BitAutoData]
public async Task SaveAsync_RequiredPolicyNotEnabled_Throws(
[PolicyUpdate(PolicyType.RequireSso)] PolicyUpdate policyUpdate,
[Policy(PolicyType.SingleOrg, false)] Policy singleOrgPolicy)
{
// Arrange
var sutProvider = SutProviderFactory(
[
new FakeRequireSsoDependencyEvent(),
new FakeSingleOrgDependencyEvent()
]);
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
var requireSsoPolicy = new Policy
{
Type = PolicyType.RequireSso,
OrganizationId = policyUpdate.OrganizationId,
Enabled = false
};
ArrangeOrganization(sutProvider, policyUpdate);
sutProvider.GetDependency<IPolicyRepository>()
.GetManyByOrganizationIdAsync(policyUpdate.OrganizationId)
.Returns([singleOrgPolicy, requireSsoPolicy]);
// Act
var badRequestException = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.SaveAsync(savePolicyModel));
// Assert
Assert.Contains("Turn on the Single organization policy because it is required for the Require single sign-on authentication policy", badRequestException.Message, StringComparison.OrdinalIgnoreCase);
await AssertPolicyNotSavedAsync(sutProvider);
}
[Theory, BitAutoData]
public async Task SaveAsync_RequiredPolicyEnabled_Success(
[PolicyUpdate(PolicyType.RequireSso)] PolicyUpdate policyUpdate,
[Policy(PolicyType.SingleOrg)] Policy singleOrgPolicy)
{
// Arrange
var sutProvider = SutProviderFactory(
[
new FakeRequireSsoDependencyEvent(),
new FakeSingleOrgDependencyEvent()
]);
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
var requireSsoPolicy = new Policy
{
Type = PolicyType.RequireSso,
OrganizationId = policyUpdate.OrganizationId,
Enabled = false
};
ArrangeOrganization(sutProvider, policyUpdate);
sutProvider.GetDependency<IPolicyRepository>()
.GetManyByOrganizationIdAsync(policyUpdate.OrganizationId)
.Returns([singleOrgPolicy, requireSsoPolicy]);
// Act
await sutProvider.Sut.SaveAsync(savePolicyModel);
// Assert
await AssertPolicySavedAsync(sutProvider, policyUpdate);
}
[Theory, BitAutoData]
public async Task SaveAsync_DependentPolicyIsEnabled_Throws(
[PolicyUpdate(PolicyType.SingleOrg, false)] PolicyUpdate policyUpdate,
[Policy(PolicyType.SingleOrg)] Policy currentPolicy,
[Policy(PolicyType.RequireSso)] Policy requireSsoPolicy)
{
// Arrange
var sutProvider = SutProviderFactory(
[
new FakeRequireSsoDependencyEvent(),
new FakeSingleOrgDependencyEvent()
]);
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
ArrangeOrganization(sutProvider, policyUpdate);
sutProvider.GetDependency<IPolicyRepository>()
.GetManyByOrganizationIdAsync(policyUpdate.OrganizationId)
.Returns([currentPolicy, requireSsoPolicy]);
// Act
var badRequestException = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.SaveAsync(savePolicyModel));
// Assert
Assert.Contains("Turn off the Require single sign-on authentication policy because it requires the Single organization policy", badRequestException.Message, StringComparison.OrdinalIgnoreCase);
await AssertPolicyNotSavedAsync(sutProvider);
}
[Theory, BitAutoData]
public async Task SaveAsync_MultipleDependentPoliciesAreEnabled_Throws(
[PolicyUpdate(PolicyType.SingleOrg, false)] PolicyUpdate policyUpdate,
[Policy(PolicyType.SingleOrg)] Policy currentPolicy,
[Policy(PolicyType.RequireSso)] Policy requireSsoPolicy,
[Policy(PolicyType.MaximumVaultTimeout)] Policy vaultTimeoutPolicy)
{
// Arrange
var sutProvider = SutProviderFactory(
[
new FakeRequireSsoDependencyEvent(),
new FakeSingleOrgDependencyEvent(),
new FakeVaultTimeoutDependencyEvent()
]);
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
ArrangeOrganization(sutProvider, policyUpdate);
sutProvider.GetDependency<IPolicyRepository>()
.GetManyByOrganizationIdAsync(policyUpdate.OrganizationId)
.Returns([currentPolicy, requireSsoPolicy, vaultTimeoutPolicy]);
// Act
var badRequestException = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.SaveAsync(savePolicyModel));
// Assert
Assert.Contains("Turn off all of the policies that require the Single organization policy", badRequestException.Message, StringComparison.OrdinalIgnoreCase);
await AssertPolicyNotSavedAsync(sutProvider);
}
[Theory, BitAutoData]
public async Task SaveAsync_DependentPolicyNotEnabled_Success(
[PolicyUpdate(PolicyType.SingleOrg, false)] PolicyUpdate policyUpdate,
[Policy(PolicyType.SingleOrg)] Policy currentPolicy,
[Policy(PolicyType.RequireSso, false)] Policy requireSsoPolicy)
{
// Arrange
var sutProvider = SutProviderFactory(
[
new FakeRequireSsoDependencyEvent(),
new FakeSingleOrgDependencyEvent()
]);
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
ArrangeOrganization(sutProvider, policyUpdate);
sutProvider.GetDependency<IPolicyRepository>()
.GetManyByOrganizationIdAsync(policyUpdate.OrganizationId)
.Returns([currentPolicy, requireSsoPolicy]);
// Act
await sutProvider.Sut.SaveAsync(savePolicyModel);
// Assert
await AssertPolicySavedAsync(sutProvider, policyUpdate);
}
[Theory, BitAutoData]
public async Task SaveAsync_ThrowsOnValidationError([PolicyUpdate(PolicyType.SingleOrg)] PolicyUpdate policyUpdate)
{
// Arrange
var fakePolicyValidationEvent = new FakeSingleOrgValidationEvent();
fakePolicyValidationEvent.ValidateAsyncMock(Arg.Any<SavePolicyModel>(), Arg.Any<Policy>()).Returns("Validation error!");
var sutProvider = SutProviderFactory(
[new FakeSingleOrgDependencyEvent()],
[fakePolicyValidationEvent]);
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel());
var singleOrgPolicy = new Policy
{
Type = PolicyType.SingleOrg,
OrganizationId = policyUpdate.OrganizationId,
Enabled = false
};
ArrangeOrganization(sutProvider, policyUpdate);
sutProvider.GetDependency<IPolicyRepository>().GetManyByOrganizationIdAsync(policyUpdate.OrganizationId).Returns([singleOrgPolicy]);
// Act
var badRequestException = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.SaveAsync(savePolicyModel));
// Assert
Assert.Contains("Validation error!", badRequestException.Message, StringComparison.OrdinalIgnoreCase);
await AssertPolicyNotSavedAsync(sutProvider);
}
/// <summary>
/// Returns a new SutProvider with the PolicyDependencyEvents registered in the Sut.
/// </summary>
private static SutProvider<VNextSavePolicyCommand> SutProviderFactory(
IEnumerable<IEnforceDependentPoliciesEvent>? policyDependencyEvents = null,
IEnumerable<IPolicyValidationEvent>? policyValidationEvents = null)
{
var policyEventHandlerFactory = Substitute.For<IPolicyEventHandlerFactory>();
// Setup factory to return handlers based on type
policyEventHandlerFactory.GetHandler<IEnforceDependentPoliciesEvent>(Arg.Any<PolicyType>())
.Returns(callInfo =>
{
var policyType = callInfo.Arg<PolicyType>();
var handler = policyDependencyEvents?.FirstOrDefault(e => e.Type == policyType);
return handler != null ? OneOf.OneOf<IEnforceDependentPoliciesEvent, None>.FromT0(handler) : OneOf.OneOf<IEnforceDependentPoliciesEvent, None>.FromT1(new None());
});
policyEventHandlerFactory.GetHandler<IPolicyValidationEvent>(Arg.Any<PolicyType>())
.Returns(callInfo =>
{
var policyType = callInfo.Arg<PolicyType>();
var handler = policyValidationEvents?.FirstOrDefault(e => e.Type == policyType);
return handler != null ? OneOf.OneOf<IPolicyValidationEvent, None>.FromT0(handler) : OneOf.OneOf<IPolicyValidationEvent, None>.FromT1(new None());
});
policyEventHandlerFactory.GetHandler<IOnPolicyPreUpdateEvent>(Arg.Any<PolicyType>())
.Returns(new None());
policyEventHandlerFactory.GetHandler<IOnPolicyPostUpdateEvent>(Arg.Any<PolicyType>())
.Returns(new None());
return new SutProvider<VNextSavePolicyCommand>()
.WithFakeTimeProvider()
.SetDependency(policyDependencyEvents ?? [])
.SetDependency(policyEventHandlerFactory)
.Create();
}
private static void ArrangeOrganization(SutProvider<VNextSavePolicyCommand> sutProvider, PolicyUpdate policyUpdate)
{
sutProvider.GetDependency<IApplicationCacheService>()
.GetOrganizationAbilityAsync(policyUpdate.OrganizationId)
.Returns(new OrganizationAbility
{
Id = policyUpdate.OrganizationId,
UsePolicies = true
});
}
private static async Task AssertPolicyNotSavedAsync(SutProvider<VNextSavePolicyCommand> sutProvider)
{
await sutProvider.GetDependency<IPolicyRepository>()
.DidNotReceiveWithAnyArgs()
.UpsertAsync(default!);
await sutProvider.GetDependency<IEventService>()
.DidNotReceiveWithAnyArgs()
.LogPolicyEventAsync(default, default);
}
private static async Task AssertPolicySavedAsync(SutProvider<VNextSavePolicyCommand> sutProvider, PolicyUpdate policyUpdate)
{
await sutProvider.GetDependency<IPolicyRepository>().Received(1).UpsertAsync(ExpectedPolicy());
await sutProvider.GetDependency<IEventService>().Received(1)
.LogPolicyEventAsync(ExpectedPolicy(), EventType.Policy_Updated);
return;
Policy ExpectedPolicy() => Arg.Is<Policy>(
p =>
p.Type == policyUpdate.Type
&& p.OrganizationId == policyUpdate.OrganizationId
&& p.Enabled == policyUpdate.Enabled
&& p.Data == policyUpdate.Data);
}
}