2024-10-22 09:18:34 +10:00
#nullable enable
using Bit.Core.AdminConsole.Entities ;
using Bit.Core.AdminConsole.Enums ;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies ;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Implementations ;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models ;
using Bit.Core.AdminConsole.Repositories ;
2025-12-01 10:21:44 -05:00
using Bit.Core.Enums ;
2024-10-22 09:18:34 +10:00
using Bit.Core.Exceptions ;
2025-12-01 10:21:44 -05:00
using Bit.Core.Models ;
2024-10-22 09:18:34 +10:00
using Bit.Core.Models.Data.Organizations ;
2025-12-01 10:21:44 -05:00
using Bit.Core.Platform.Push ;
2024-10-22 09:18:34 +10:00
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 Xunit ;
using EventType = Bit . Core . Enums . EventType ;
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.Policies ;
public class SavePolicyCommandTests
{
[Theory, BitAutoData]
public async Task SaveAsync_NewPolicy_Success ( [ PolicyUpdate ( PolicyType . SingleOrg ) ] PolicyUpdate policyUpdate )
{
var fakePolicyValidator = new FakeSingleOrgPolicyValidator ( ) ;
fakePolicyValidator . ValidateAsyncMock ( policyUpdate , null ) . Returns ( "" ) ;
var sutProvider = SutProviderFactory ( [ fakePolicyValidator ] ) ;
ArrangeOrganization ( sutProvider , policyUpdate ) ;
sutProvider . GetDependency < IPolicyRepository > ( ) . GetManyByOrganizationIdAsync ( policyUpdate . OrganizationId ) . Returns ( [ ] ) ;
var creationDate = sutProvider . GetDependency < FakeTimeProvider > ( ) . Start ;
await sutProvider . Sut . SaveAsync ( policyUpdate ) ;
await fakePolicyValidator . ValidateAsyncMock . Received ( 1 ) . Invoke ( policyUpdate , null ) ;
fakePolicyValidator . OnSaveSideEffectsAsyncMock . Received ( 1 ) . Invoke ( policyUpdate , null ) ;
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 )
{
var fakePolicyValidator = new FakeSingleOrgPolicyValidator ( ) ;
fakePolicyValidator . ValidateAsyncMock ( policyUpdate , null ) . Returns ( "" ) ;
var sutProvider = SutProviderFactory ( [ fakePolicyValidator ] ) ;
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 ] ) ;
// Store mutable properties separately to assert later
var id = currentPolicy . Id ;
var organizationId = currentPolicy . OrganizationId ;
var type = currentPolicy . Type ;
var creationDate = currentPolicy . CreationDate ;
var revisionDate = sutProvider . GetDependency < FakeTimeProvider > ( ) . Start ;
await sutProvider . Sut . SaveAsync ( policyUpdate ) ;
await fakePolicyValidator . ValidateAsyncMock . Received ( 1 ) . Invoke ( policyUpdate , currentPolicy ) ;
fakePolicyValidator . OnSaveSideEffectsAsyncMock . Received ( 1 ) . Invoke ( policyUpdate , currentPolicy ) ;
await AssertPolicySavedAsync ( sutProvider , policyUpdate ) ;
// Additional assertions to ensure certain properties have or have not been updated
await sutProvider . GetDependency < IPolicyRepository > ( ) . Received ( 1 ) . UpsertAsync ( Arg . Is < Policy > ( p = >
p . Id = = id & &
p . OrganizationId = = organizationId & &
p . Type = = type & &
p . CreationDate = = creationDate & &
p . RevisionDate = = revisionDate ) ) ;
}
[Fact]
public void Constructor_DuplicatePolicyValidators_Throws ( )
{
var exception = Assert . Throws < Exception > ( ( ) = >
new SavePolicyCommand (
Substitute . For < IApplicationCacheService > ( ) ,
Substitute . For < IEventService > ( ) ,
Substitute . For < IPolicyRepository > ( ) ,
[new FakeSingleOrgPolicyValidator(), new FakeSingleOrgPolicyValidator()] ,
2025-09-10 10:13:04 -04:00
Substitute . For < TimeProvider > ( ) ,
2025-12-01 10:21:44 -05:00
Substitute . For < IPostSavePolicySideEffect > ( ) ,
Substitute . For < IPushNotificationService > ( ) ) ) ;
2024-10-22 09:18:34 +10:00
Assert . Contains ( "Duplicate PolicyValidator for SingleOrg policy" , exception . Message ) ;
}
[Theory, BitAutoData]
2024-11-26 16:37:12 -06:00
public async Task SaveAsync_OrganizationDoesNotExist_ThrowsBadRequest ( [ PolicyUpdate ( PolicyType . ActivateAutofill ) ] PolicyUpdate policyUpdate )
2024-10-22 09:18:34 +10:00
{
var sutProvider = SutProviderFactory ( ) ;
sutProvider . GetDependency < IApplicationCacheService > ( )
. GetOrganizationAbilityAsync ( policyUpdate . OrganizationId )
. Returns ( Task . FromResult < OrganizationAbility ? > ( null ) ) ;
var badRequestException = await Assert . ThrowsAsync < BadRequestException > (
( ) = > sutProvider . Sut . SaveAsync ( policyUpdate ) ) ;
Assert . Contains ( "Organization not found" , badRequestException . Message , StringComparison . OrdinalIgnoreCase ) ;
await AssertPolicyNotSavedAsync ( sutProvider ) ;
}
[Theory, BitAutoData]
2024-11-26 16:37:12 -06:00
public async Task SaveAsync_OrganizationCannotUsePolicies_ThrowsBadRequest ( [ PolicyUpdate ( PolicyType . ActivateAutofill ) ] PolicyUpdate policyUpdate )
2024-10-22 09:18:34 +10:00
{
var sutProvider = SutProviderFactory ( ) ;
sutProvider . GetDependency < IApplicationCacheService > ( )
. GetOrganizationAbilityAsync ( policyUpdate . OrganizationId )
. Returns ( new OrganizationAbility
{
Id = policyUpdate . OrganizationId ,
UsePolicies = false
} ) ;
var badRequestException = await Assert . ThrowsAsync < BadRequestException > (
( ) = > sutProvider . Sut . SaveAsync ( policyUpdate ) ) ;
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 )
{
var sutProvider = SutProviderFactory ( [
new FakeRequireSsoPolicyValidator ( ) ,
new FakeSingleOrgPolicyValidator ( )
] ) ;
ArrangeOrganization ( sutProvider , policyUpdate ) ;
sutProvider . GetDependency < IPolicyRepository > ( )
. GetManyByOrganizationIdAsync ( policyUpdate . OrganizationId )
. Returns ( [ ] ) ;
var badRequestException = await Assert . ThrowsAsync < BadRequestException > (
( ) = > sutProvider . Sut . SaveAsync ( policyUpdate ) ) ;
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 )
{
var sutProvider = SutProviderFactory ( [
new FakeRequireSsoPolicyValidator ( ) ,
new FakeSingleOrgPolicyValidator ( )
] ) ;
ArrangeOrganization ( sutProvider , policyUpdate ) ;
sutProvider . GetDependency < IPolicyRepository > ( )
. GetManyByOrganizationIdAsync ( policyUpdate . OrganizationId )
. Returns ( [ singleOrgPolicy ] ) ;
var badRequestException = await Assert . ThrowsAsync < BadRequestException > (
( ) = > sutProvider . Sut . SaveAsync ( policyUpdate ) ) ;
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 )
{
var sutProvider = SutProviderFactory ( [
new FakeRequireSsoPolicyValidator ( ) ,
new FakeSingleOrgPolicyValidator ( )
] ) ;
ArrangeOrganization ( sutProvider , policyUpdate ) ;
sutProvider . GetDependency < IPolicyRepository > ( )
. GetManyByOrganizationIdAsync ( policyUpdate . OrganizationId )
. Returns ( [ singleOrgPolicy ] ) ;
await sutProvider . Sut . SaveAsync ( policyUpdate ) ;
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 ) // depends on Single Org
{
var sutProvider = SutProviderFactory ( [
new FakeRequireSsoPolicyValidator ( ) ,
new FakeSingleOrgPolicyValidator ( )
] ) ;
ArrangeOrganization ( sutProvider , policyUpdate ) ;
sutProvider . GetDependency < IPolicyRepository > ( )
. GetManyByOrganizationIdAsync ( policyUpdate . OrganizationId )
. Returns ( [ currentPolicy , requireSsoPolicy ] ) ;
var badRequestException = await Assert . ThrowsAsync < BadRequestException > (
( ) = > sutProvider . Sut . SaveAsync ( policyUpdate ) ) ;
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 , // depends on Single Org
[Policy(PolicyType.MaximumVaultTimeout)] Policy vaultTimeoutPolicy ) // depends on Single Org
{
var sutProvider = SutProviderFactory ( [
new FakeRequireSsoPolicyValidator ( ) ,
new FakeSingleOrgPolicyValidator ( ) ,
new FakeVaultTimeoutPolicyValidator ( )
] ) ;
ArrangeOrganization ( sutProvider , policyUpdate ) ;
sutProvider . GetDependency < IPolicyRepository > ( )
. GetManyByOrganizationIdAsync ( policyUpdate . OrganizationId )
. Returns ( [ currentPolicy , requireSsoPolicy , vaultTimeoutPolicy ] ) ;
var badRequestException = await Assert . ThrowsAsync < BadRequestException > (
( ) = > sutProvider . Sut . SaveAsync ( policyUpdate ) ) ;
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 ) // depends on Single Org but is not enabled
{
var sutProvider = SutProviderFactory ( [
new FakeRequireSsoPolicyValidator ( ) ,
new FakeSingleOrgPolicyValidator ( )
] ) ;
ArrangeOrganization ( sutProvider , policyUpdate ) ;
sutProvider . GetDependency < IPolicyRepository > ( )
. GetManyByOrganizationIdAsync ( policyUpdate . OrganizationId )
. Returns ( [ currentPolicy , requireSsoPolicy ] ) ;
await sutProvider . Sut . SaveAsync ( policyUpdate ) ;
await AssertPolicySavedAsync ( sutProvider , policyUpdate ) ;
}
[Theory, BitAutoData]
public async Task SaveAsync_ThrowsOnValidationError ( [ PolicyUpdate ( PolicyType . SingleOrg ) ] PolicyUpdate policyUpdate )
{
var fakePolicyValidator = new FakeSingleOrgPolicyValidator ( ) ;
fakePolicyValidator . ValidateAsyncMock ( policyUpdate , null ) . Returns ( "Validation error!" ) ;
var sutProvider = SutProviderFactory ( [ fakePolicyValidator ] ) ;
ArrangeOrganization ( sutProvider , policyUpdate ) ;
sutProvider . GetDependency < IPolicyRepository > ( ) . GetManyByOrganizationIdAsync ( policyUpdate . OrganizationId ) . Returns ( [ ] ) ;
var badRequestException = await Assert . ThrowsAsync < BadRequestException > (
( ) = > sutProvider . Sut . SaveAsync ( policyUpdate ) ) ;
Assert . Contains ( "Validation error!" , badRequestException . Message , StringComparison . OrdinalIgnoreCase ) ;
await AssertPolicyNotSavedAsync ( sutProvider ) ;
}
2025-09-10 10:13:04 -04:00
[Theory, BitAutoData]
public async Task VNextSaveAsync_OrganizationDataOwnershipPolicy_ExecutesPostSaveSideEffects (
[PolicyUpdate(PolicyType.OrganizationDataOwnership)] PolicyUpdate policyUpdate ,
[Policy(PolicyType.OrganizationDataOwnership, false)] Policy currentPolicy )
{
// Arrange
var sutProvider = SutProviderFactory ( ) ;
2025-11-06 11:35:07 +00:00
var savePolicyModel = new SavePolicyModel ( policyUpdate ) ;
2025-09-10 10:13:04 -04:00
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
var result = await sutProvider . Sut . VNextSaveAsync ( savePolicyModel ) ;
// Assert
await sutProvider . GetDependency < IPolicyRepository > ( )
. Received ( 1 )
. UpsertAsync ( result ) ;
await sutProvider . GetDependency < IEventService > ( )
. Received ( 1 )
. LogPolicyEventAsync ( result , EventType . Policy_Updated ) ;
await sutProvider . GetDependency < IPostSavePolicySideEffect > ( )
. Received ( 1 )
. ExecuteSideEffectsAsync ( savePolicyModel , result , currentPolicy ) ;
}
[Theory]
[BitAutoData(PolicyType.SingleOrg)]
[BitAutoData(PolicyType.TwoFactorAuthentication)]
public async Task VNextSaveAsync_NonOrganizationDataOwnershipPolicy_DoesNotExecutePostSaveSideEffects (
PolicyType policyType ,
Policy currentPolicy ,
[PolicyUpdate] PolicyUpdate policyUpdate )
{
// Arrange
policyUpdate . Type = policyType ;
currentPolicy . Type = policyType ;
currentPolicy . OrganizationId = policyUpdate . OrganizationId ;
var sutProvider = SutProviderFactory ( ) ;
2025-11-06 11:35:07 +00:00
var savePolicyModel = new SavePolicyModel ( policyUpdate ) ;
2025-09-10 10:13:04 -04:00
sutProvider . GetDependency < IPolicyRepository > ( )
. GetByOrganizationIdTypeAsync ( policyUpdate . OrganizationId , policyUpdate . Type )
. Returns ( currentPolicy ) ;
ArrangeOrganization ( sutProvider , policyUpdate ) ;
sutProvider . GetDependency < IPolicyRepository > ( )
. GetManyByOrganizationIdAsync ( policyUpdate . OrganizationId )
. Returns ( [ currentPolicy ] ) ;
// Act
var result = await sutProvider . Sut . VNextSaveAsync ( savePolicyModel ) ;
// Assert
await sutProvider . GetDependency < IPolicyRepository > ( )
. Received ( 1 )
. UpsertAsync ( result ) ;
await sutProvider . GetDependency < IEventService > ( )
. Received ( 1 )
. LogPolicyEventAsync ( result , EventType . Policy_Updated ) ;
await sutProvider . GetDependency < IPostSavePolicySideEffect > ( )
. DidNotReceiveWithAnyArgs ( )
. ExecuteSideEffectsAsync ( default ! , default ! , default ! ) ;
}
2025-12-01 10:21:44 -05:00
[Theory, BitAutoData]
public async Task VNextSaveAsync_SendsPushNotification (
[PolicyUpdate(PolicyType.SingleOrg)] PolicyUpdate policyUpdate ,
[Policy(PolicyType.SingleOrg, false)] Policy currentPolicy )
{
// Arrange
var fakePolicyValidator = new FakeSingleOrgPolicyValidator ( ) ;
fakePolicyValidator . ValidateAsyncMock ( policyUpdate , null ) . Returns ( "" ) ;
var sutProvider = SutProviderFactory ( [ fakePolicyValidator ] ) ;
var savePolicyModel = new SavePolicyModel ( policyUpdate ) ;
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
var result = await sutProvider . Sut . VNextSaveAsync ( savePolicyModel ) ;
// Assert
await sutProvider . GetDependency < IPushNotificationService > ( ) . Received ( 1 )
. PushAsync ( Arg . Is < PushNotification < SyncPolicyPushNotification > > ( p = >
p . Type = = PushType . PolicyChanged & &
p . Target = = NotificationTarget . Organization & &
p . TargetId = = policyUpdate . OrganizationId & &
p . ExcludeCurrentContext = = false & &
p . Payload . OrganizationId = = policyUpdate . OrganizationId & &
p . Payload . Policy . Id = = result . Id & &
p . Payload . Policy . Type = = policyUpdate . Type & &
p . Payload . Policy . Enabled = = policyUpdate . Enabled & &
p . Payload . Policy . Data = = policyUpdate . Data ) ) ;
}
[Theory, BitAutoData]
public async Task SaveAsync_SendsPushNotification ( [ PolicyUpdate ( PolicyType . SingleOrg ) ] PolicyUpdate policyUpdate )
{
var fakePolicyValidator = new FakeSingleOrgPolicyValidator ( ) ;
fakePolicyValidator . ValidateAsyncMock ( policyUpdate , null ) . Returns ( "" ) ;
var sutProvider = SutProviderFactory ( [ fakePolicyValidator ] ) ;
ArrangeOrganization ( sutProvider , policyUpdate ) ;
sutProvider . GetDependency < IPolicyRepository > ( ) . GetManyByOrganizationIdAsync ( policyUpdate . OrganizationId ) . Returns ( [ ] ) ;
var result = await sutProvider . Sut . SaveAsync ( policyUpdate ) ;
await sutProvider . GetDependency < IPushNotificationService > ( ) . Received ( 1 )
. PushAsync ( Arg . Is < PushNotification < SyncPolicyPushNotification > > ( p = >
p . Type = = PushType . PolicyChanged & &
p . Target = = NotificationTarget . Organization & &
p . TargetId = = policyUpdate . OrganizationId & &
p . ExcludeCurrentContext = = false & &
p . Payload . OrganizationId = = policyUpdate . OrganizationId & &
p . Payload . Policy . Id = = result . Id & &
p . Payload . Policy . Type = = policyUpdate . Type & &
p . Payload . Policy . Enabled = = policyUpdate . Enabled & &
p . Payload . Policy . Data = = policyUpdate . Data ) ) ;
}
[Theory, BitAutoData]
public async Task SaveAsync_ExistingPolicy_SendsPushNotificationWithUpdatedPolicy (
[PolicyUpdate(PolicyType.SingleOrg)] PolicyUpdate policyUpdate ,
[Policy(PolicyType.SingleOrg, false)] Policy currentPolicy )
{
var fakePolicyValidator = new FakeSingleOrgPolicyValidator ( ) ;
fakePolicyValidator . ValidateAsyncMock ( policyUpdate , null ) . Returns ( "" ) ;
var sutProvider = SutProviderFactory ( [ fakePolicyValidator ] ) ;
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 ] ) ;
var result = await sutProvider . Sut . SaveAsync ( policyUpdate ) ;
await sutProvider . GetDependency < IPushNotificationService > ( ) . Received ( 1 )
. PushAsync ( Arg . Is < PushNotification < SyncPolicyPushNotification > > ( p = >
p . Type = = PushType . PolicyChanged & &
p . Target = = NotificationTarget . Organization & &
p . TargetId = = policyUpdate . OrganizationId & &
p . ExcludeCurrentContext = = false & &
p . Payload . OrganizationId = = policyUpdate . OrganizationId & &
p . Payload . Policy . Id = = result . Id & &
p . Payload . Policy . Type = = policyUpdate . Type & &
p . Payload . Policy . Enabled = = policyUpdate . Enabled & &
p . Payload . Policy . Data = = policyUpdate . Data ) ) ;
}
2024-10-22 09:18:34 +10:00
/// <summary>
/// Returns a new SutProvider with the PolicyValidators registered in the Sut.
/// </summary>
private static SutProvider < SavePolicyCommand > SutProviderFactory ( IEnumerable < IPolicyValidator > ? policyValidators = null )
{
return new SutProvider < SavePolicyCommand > ( )
. WithFakeTimeProvider ( )
2025-06-12 19:21:05 +10:00
. SetDependency ( policyValidators ? ? [ ] )
2025-09-10 10:13:04 -04:00
. SetDependency ( Substitute . For < IPostSavePolicySideEffect > ( ) )
2024-10-22 09:18:34 +10:00
. Create ( ) ;
}
private static void ArrangeOrganization ( SutProvider < SavePolicyCommand > sutProvider , PolicyUpdate policyUpdate )
{
sutProvider . GetDependency < IApplicationCacheService > ( )
. GetOrganizationAbilityAsync ( policyUpdate . OrganizationId )
. Returns ( new OrganizationAbility
{
Id = policyUpdate . OrganizationId ,
UsePolicies = true
} ) ;
}
private static async Task AssertPolicyNotSavedAsync ( SutProvider < SavePolicyCommand > sutProvider )
{
await sutProvider . GetDependency < IPolicyRepository > ( )
. DidNotReceiveWithAnyArgs ( )
. UpsertAsync ( default ! ) ;
await sutProvider . GetDependency < IEventService > ( )
. DidNotReceiveWithAnyArgs ( )
. LogPolicyEventAsync ( default , default ) ;
}
private static async Task AssertPolicySavedAsync ( SutProvider < SavePolicyCommand > sutProvider , PolicyUpdate policyUpdate )
{
var expectedPolicy = ( ) = > Arg . Is < Policy > ( p = >
p . Type = = policyUpdate . Type & &
p . OrganizationId = = policyUpdate . OrganizationId & &
p . Enabled = = policyUpdate . Enabled & &
p . Data = = policyUpdate . Data ) ;
await sutProvider . GetDependency < IPolicyRepository > ( ) . Received ( 1 ) . UpsertAsync ( expectedPolicy ( ) ) ;
await sutProvider . GetDependency < IEventService > ( ) . Received ( 1 )
. LogPolicyEventAsync ( expectedPolicy ( ) , EventType . Policy_Updated ) ;
}
}