2023-07-25 00:05:05 +02:00
using Bit.Core.Entities ;
using Bit.Core.Enums ;
using Bit.Core.Exceptions ;
using Bit.Core.Models.Business ;
using Bit.Core.Models.StaticStore ;
using Bit.Core.OrganizationFeatures.OrganizationSubscriptions ;
using Bit.Core.Repositories ;
using Bit.Core.SecretsManager.Repositories ;
using Bit.Core.Services ;
2023-08-04 23:51:12 +02:00
using Bit.Core.Settings ;
2023-07-25 00:05:05 +02:00
using Bit.Core.Utilities ;
using Bit.Test.Common.AutoFixture ;
using Bit.Test.Common.AutoFixture.Attributes ;
using NSubstitute ;
using Xunit ;
namespace Bit.Core.Test.OrganizationFeatures.OrganizationSubscriptionUpdate ;
[SutProviderCustomize]
public class UpdateSecretsManagerSubscriptionCommandTests
{
[Theory]
[BitAutoData]
2023-08-04 23:51:12 +02:00
public async Task UpdateSubscriptionAsync_NoOrganization_Throws (
SecretsManagerSubscriptionUpdate secretsManagerSubscriptionUpdate ,
2023-07-25 00:05:05 +02:00
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
2023-08-04 23:51:12 +02:00
secretsManagerSubscriptionUpdate . Organization = null ;
2023-07-25 00:05:05 +02:00
var exception = await Assert . ThrowsAsync < NotFoundException > (
2023-08-04 23:51:12 +02:00
( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( secretsManagerSubscriptionUpdate ) ) ;
2023-07-25 00:05:05 +02:00
Assert . Contains ( "Organization is not found" , exception . Message ) ;
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
[Theory]
[BitAutoData]
2023-08-04 23:51:12 +02:00
public async Task UpdateSubscriptionAsync_NoSecretsManagerAccess_ThrowsException (
2023-07-25 00:05:05 +02:00
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
var organization = new Organization
{
SmSeats = 10 ,
SmServiceAccounts = 5 ,
UseSecretsManager = false ,
MaxAutoscaleSmSeats = 20 ,
MaxAutoscaleSmServiceAccounts = 10
} ;
2023-08-04 23:51:12 +02:00
var secretsManagerSubscriptionUpdate = new SecretsManagerSubscriptionUpdate ( organization , seatAdjustment : 0 , maxAutoscaleSeats : null , serviceAccountAdjustment : 0 , maxAutoscaleServiceAccounts : null ) ;
2023-07-25 00:05:05 +02:00
var exception = await Assert . ThrowsAsync < BadRequestException > (
2023-08-04 23:51:12 +02:00
( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( secretsManagerSubscriptionUpdate ) ) ;
2023-07-25 00:05:05 +02:00
Assert . Contains ( "Organization has no access to Secrets Manager." , exception . Message ) ;
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
[Theory]
[BitAutoData]
2023-08-04 23:51:12 +02:00
public async Task UpdateSubscriptionAsync_SeatsAdjustmentGreaterThanMaxAutoscaleSeats_ThrowsException (
2023-07-25 00:05:05 +02:00
Guid organizationId ,
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
var organization = new Organization
{
Id = organizationId ,
SmSeats = 10 ,
UseSecretsManager = true ,
SmServiceAccounts = 5 ,
MaxAutoscaleSmSeats = 20 ,
MaxAutoscaleSmServiceAccounts = 10 ,
PlanType = PlanType . EnterpriseAnnually ,
2023-08-04 23:51:12 +02:00
GatewayCustomerId = "1" ,
GatewaySubscriptionId = "2"
2023-07-25 00:05:05 +02:00
} ;
2023-08-04 23:51:12 +02:00
var organizationUpdate = new SecretsManagerSubscriptionUpdate (
organization , seatAdjustment : 15 , maxAutoscaleSeats : 10 , serviceAccountAdjustment : 0 , maxAutoscaleServiceAccounts : null ) ;
2023-07-25 00:05:05 +02:00
2023-08-04 23:51:12 +02:00
var exception = await Assert . ThrowsAsync < BadRequestException > ( ( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( organizationUpdate ) ) ;
2023-07-25 00:05:05 +02:00
Assert . Contains ( "Cannot set max seat autoscaling below seat count." , exception . Message ) ;
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
[Theory]
[BitAutoData]
2023-08-04 23:51:12 +02:00
public async Task UpdateSubscriptionAsync_ServiceAccountsGreaterThanMaxAutoscaleSeats_ThrowsException (
2023-07-25 00:05:05 +02:00
Guid organizationId ,
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
var organization = new Organization
{
Id = organizationId ,
SmSeats = 10 ,
UseSecretsManager = true ,
SmServiceAccounts = 5 ,
MaxAutoscaleSmSeats = 20 ,
MaxAutoscaleSmServiceAccounts = 10 ,
PlanType = PlanType . EnterpriseAnnually ,
GatewayCustomerId = "1" ,
GatewaySubscriptionId = "9"
} ;
2023-08-04 23:51:12 +02:00
var organizationUpdate = new SecretsManagerSubscriptionUpdate (
organization , seatAdjustment : 1 , maxAutoscaleSeats : 15 , serviceAccountAdjustment : 11 , maxAutoscaleServiceAccounts : 10 ) ;
2023-07-25 00:05:05 +02:00
2023-08-04 23:51:12 +02:00
var exception = await Assert . ThrowsAsync < BadRequestException > ( ( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( organizationUpdate ) ) ;
Assert . Contains ( "Cannot set max service accounts autoscaling below service account amount" , exception . Message ) ;
2023-07-25 00:05:05 +02:00
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
[Theory]
[BitAutoData]
2023-08-04 23:51:12 +02:00
public async Task UpdateSubscriptionAsync_NullGatewayCustomerId_ThrowsException (
2023-07-25 00:05:05 +02:00
Guid organizationId ,
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
var organization = new Organization
{
Id = organizationId ,
SmSeats = 10 ,
SmServiceAccounts = 5 ,
UseSecretsManager = true ,
MaxAutoscaleSmSeats = 20 ,
MaxAutoscaleSmServiceAccounts = 15 ,
PlanType = PlanType . EnterpriseAnnually
} ;
2023-08-04 23:51:12 +02:00
var organizationUpdate = new SecretsManagerSubscriptionUpdate (
organization , seatAdjustment : 1 , maxAutoscaleSeats : 15 , serviceAccountAdjustment : 1 , maxAutoscaleServiceAccounts : 15 ) ;
2023-07-25 00:05:05 +02:00
2023-08-04 23:51:12 +02:00
var exception = await Assert . ThrowsAsync < BadRequestException > ( ( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( organizationUpdate ) ) ;
2023-07-25 00:05:05 +02:00
Assert . Contains ( "No payment method found." , exception . Message ) ;
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
[Theory]
[BitAutoData]
2023-08-04 23:51:12 +02:00
public async Task UpdateSubscriptionAsync_NullGatewaySubscriptionId_ThrowsException (
2023-07-25 00:05:05 +02:00
Guid organizationId ,
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
var organization = new Organization
{
Id = organizationId ,
SmSeats = 10 ,
UseSecretsManager = true ,
SmServiceAccounts = 5 ,
MaxAutoscaleSmSeats = 20 ,
MaxAutoscaleSmServiceAccounts = 15 ,
PlanType = PlanType . EnterpriseAnnually ,
GatewayCustomerId = "1"
} ;
2023-08-04 23:51:12 +02:00
var organizationUpdate = new SecretsManagerSubscriptionUpdate (
organization , seatAdjustment : 1 , maxAutoscaleSeats : 15 , serviceAccountAdjustment : 1 , maxAutoscaleServiceAccounts : 15 ) ;
2023-07-25 00:05:05 +02:00
2023-08-04 23:51:12 +02:00
var exception = await Assert . ThrowsAsync < BadRequestException > ( ( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( organizationUpdate ) ) ;
2023-07-25 00:05:05 +02:00
Assert . Contains ( "No subscription found." , exception . Message ) ;
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
[Theory]
[BitAutoData]
2023-08-04 23:51:12 +02:00
public async Task UpdateSubscriptionAsync_OrgWithNullSmSeatOnSeatsAdjustment_ThrowsException (
2023-07-25 00:05:05 +02:00
Guid organizationId ,
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
var organization = new Organization
{
Id = organizationId ,
SmSeats = null ,
UseSecretsManager = true ,
SmServiceAccounts = 5 ,
MaxAutoscaleSmSeats = 20 ,
MaxAutoscaleSmServiceAccounts = 15 ,
PlanType = PlanType . EnterpriseAnnually ,
2023-08-04 23:51:12 +02:00
GatewayCustomerId = "1" ,
GatewaySubscriptionId = "2"
2023-07-25 00:05:05 +02:00
} ;
2023-08-04 23:51:12 +02:00
var organizationUpdate = new SecretsManagerSubscriptionUpdate (
organization , seatAdjustment : 1 , maxAutoscaleSeats : 15 , serviceAccountAdjustment : 1 , maxAutoscaleServiceAccounts : 15 ) ;
2023-07-25 00:05:05 +02:00
var exception = await Assert . ThrowsAsync < BadRequestException > (
2023-08-04 23:51:12 +02:00
( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( organizationUpdate ) ) ;
2023-07-25 00:05:05 +02:00
Assert . Contains ( "Organization has no Secrets Manager seat limit, no need to adjust seats" , exception . Message ) ;
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
[Theory]
[BitAutoData(PlanType.Custom)]
[BitAutoData(PlanType.FamiliesAnnually)]
[BitAutoData(PlanType.FamiliesAnnually2019)]
[BitAutoData(PlanType.EnterpriseMonthly2019)]
[BitAutoData(PlanType.EnterpriseAnnually2019)]
[BitAutoData(PlanType.TeamsMonthly2019)]
[BitAutoData(PlanType.TeamsAnnually2019)]
2023-08-04 23:51:12 +02:00
public async Task UpdateSubscriptionAsync_WithNonSecretsManagerPlanType_ThrowsBadRequestException (
2023-07-25 00:05:05 +02:00
PlanType planType ,
Guid organizationId ,
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
var organization = new Organization
{
Id = organizationId ,
SmSeats = 10 ,
UseSecretsManager = true ,
SmServiceAccounts = 200 ,
MaxAutoscaleSmSeats = 20 ,
MaxAutoscaleSmServiceAccounts = 300 ,
2023-08-04 23:51:12 +02:00
PlanType = PlanType . EnterpriseAnnually ,
2023-07-25 00:05:05 +02:00
GatewayCustomerId = "1" ,
GatewaySubscriptionId = "2"
} ;
2023-08-04 23:51:12 +02:00
var organizationUpdate = new SecretsManagerSubscriptionUpdate (
organization , seatAdjustment : 1 , maxAutoscaleSeats : 15 , serviceAccountAdjustment : 1 , maxAutoscaleServiceAccounts : 300 ) ;
organization . PlanType = planType ;
2023-07-25 00:05:05 +02:00
2023-08-04 23:51:12 +02:00
var exception = await Assert . ThrowsAsync < BadRequestException > ( ( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( organizationUpdate ) ) ;
2023-07-25 00:05:05 +02:00
Assert . Contains ( "Existing plan not found" , exception . Message , StringComparison . InvariantCultureIgnoreCase ) ;
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
[Theory]
[BitAutoData(PlanType.Free)]
2023-08-04 23:51:12 +02:00
public async Task UpdateSubscriptionAsync_WithHasAdditionalSeatsOptionFalse_ThrowsBadRequestException (
2023-07-25 00:05:05 +02:00
PlanType planType ,
Guid organizationId ,
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
var organization = new Organization
{
Id = organizationId ,
UseSecretsManager = true ,
2023-08-04 23:51:12 +02:00
SmSeats = 2 ,
SmServiceAccounts = 3 ,
2023-07-25 00:05:05 +02:00
PlanType = planType ,
GatewayCustomerId = "1" ,
GatewaySubscriptionId = "2"
} ;
2023-08-04 23:51:12 +02:00
var organizationUpdate = new SecretsManagerSubscriptionUpdate (
organization , seatAdjustment : 1 , maxAutoscaleSeats : null , serviceAccountAdjustment : 0 , maxAutoscaleServiceAccounts : null ) ;
2023-07-25 00:05:05 +02:00
2023-08-04 23:51:12 +02:00
var exception = await Assert . ThrowsAsync < BadRequestException > ( ( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( organizationUpdate ) ) ;
Assert . Contains ( "You have reached the maximum number of Secrets Manager seats (2) for this plan" ,
exception . Message , StringComparison . InvariantCultureIgnoreCase ) ;
2023-07-25 00:05:05 +02:00
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
[Theory]
[BitAutoData(PlanType.Free)]
2023-08-04 23:51:12 +02:00
public async Task UpdateSubscriptionAsync_WithHasAdditionalServiceAccountOptionFalse_ThrowsBadRequestException (
2023-07-25 00:05:05 +02:00
PlanType planType ,
Guid organizationId ,
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
var organization = new Organization
{
Id = organizationId ,
UseSecretsManager = true ,
2023-08-04 23:51:12 +02:00
SmSeats = 2 ,
SmServiceAccounts = 3 ,
2023-07-25 00:05:05 +02:00
PlanType = planType ,
GatewayCustomerId = "1" ,
GatewaySubscriptionId = "2"
} ;
2023-08-04 23:51:12 +02:00
var organizationUpdate = new SecretsManagerSubscriptionUpdate (
organization , seatAdjustment : 0 , maxAutoscaleSeats : null , serviceAccountAdjustment : 1 , maxAutoscaleServiceAccounts : null ) ;
2023-07-25 00:05:05 +02:00
2023-08-04 23:51:12 +02:00
var exception = await Assert . ThrowsAsync < BadRequestException > ( ( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( organizationUpdate ) ) ;
Assert . Contains ( "You have reached the maximum number of service accounts (3) for this plan" ,
exception . Message , StringComparison . InvariantCultureIgnoreCase ) ;
2023-07-25 00:05:05 +02:00
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
[Theory]
[BitAutoData(PlanType.EnterpriseAnnually)]
[BitAutoData(PlanType.EnterpriseMonthly)]
[BitAutoData(PlanType.TeamsMonthly)]
[BitAutoData(PlanType.TeamsAnnually)]
2023-08-04 23:51:12 +02:00
public async Task UpdateSubscriptionAsync_ValidInput_Passes (
2023-07-25 00:05:05 +02:00
PlanType planType ,
Guid organizationId ,
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
const int organizationServiceAccounts = 200 ;
const int seatAdjustment = 5 ;
const int maxAutoscaleSeats = 15 ;
const int serviceAccountAdjustment = 100 ;
const int maxAutoScaleServiceAccounts = 300 ;
var organization = new Organization
{
Id = organizationId ,
UseSecretsManager = true ,
SmSeats = 10 ,
MaxAutoscaleSmSeats = 20 ,
SmServiceAccounts = organizationServiceAccounts ,
MaxAutoscaleSmServiceAccounts = 350 ,
PlanType = planType ,
GatewayCustomerId = "1" ,
GatewaySubscriptionId = "2"
} ;
var plan = StaticStore . SecretManagerPlans . FirstOrDefault ( x = > x . Type = = organization . PlanType ) ;
2023-08-04 23:51:12 +02:00
var organizationUpdate = new SecretsManagerSubscriptionUpdate (
organization ,
seatAdjustment : seatAdjustment , maxAutoscaleSeats : maxAutoscaleSeats ,
serviceAccountAdjustment : serviceAccountAdjustment , maxAutoscaleServiceAccounts : maxAutoScaleServiceAccounts ) ;
2023-07-25 00:05:05 +02:00
2023-08-04 23:51:12 +02:00
await sutProvider . Sut . UpdateSubscriptionAsync ( organizationUpdate ) ;
2023-07-25 00:05:05 +02:00
2023-08-04 23:51:12 +02:00
await sutProvider . GetDependency < IPaymentService > ( ) . Received ( 1 )
. AdjustSeatsAsync ( organization , plan , organizationUpdate . SmSeatsExcludingBase ) ;
await sutProvider . GetDependency < IPaymentService > ( ) . Received ( 1 )
. AdjustServiceAccountsAsync ( organization , plan , organizationUpdate . SmServiceAccountsExcludingBase ) ;
2023-07-25 00:05:05 +02:00
2023-08-04 23:51:12 +02:00
// TODO: call ReferenceEventService - see AC-1481
2023-07-25 00:05:05 +02:00
2023-08-04 23:51:12 +02:00
AssertUpdatedOrganization ( ( ) = > Arg . Is < Organization > ( org = >
org . Id = = organizationId
& & org . SmSeats = = organizationUpdate . SmSeats
& & org . MaxAutoscaleSmSeats = = organizationUpdate . MaxAutoscaleSmSeats
& & org . SmServiceAccounts = = ( organizationServiceAccounts + serviceAccountAdjustment )
& & org . MaxAutoscaleSmServiceAccounts = = organizationUpdate . MaxAutoscaleSmServiceAccounts ) , sutProvider ) ;
2023-07-25 00:05:05 +02:00
2023-08-04 23:51:12 +02:00
await sutProvider . GetDependency < IMailService > ( ) . Received ( 1 ) . SendSecretsManagerMaxSeatLimitReachedEmailAsync ( organization , organization . MaxAutoscaleSmSeats . Value , Arg . Any < IEnumerable < string > > ( ) ) ;
await sutProvider . GetDependency < IMailService > ( ) . Received ( 1 ) . SendSecretsManagerMaxServiceAccountLimitReachedEmailAsync ( organization , organization . MaxAutoscaleSmServiceAccounts . Value , Arg . Any < IEnumerable < string > > ( ) ) ;
}
2023-07-25 00:05:05 +02:00
2023-08-04 23:51:12 +02:00
[Theory]
[BitAutoData(PlanType.EnterpriseAnnually)]
[BitAutoData(PlanType.EnterpriseMonthly)]
[BitAutoData(PlanType.TeamsMonthly)]
[BitAutoData(PlanType.TeamsAnnually)]
public async Task UpdateSubscriptionAsync_ValidInput_WithNullMaxAutoscale_Passes (
PlanType planType ,
Guid organizationId ,
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
int organizationServiceAccounts = 200 ;
int seatAdjustment = 5 ;
int? maxAutoscaleSeats = null ;
int serviceAccountAdjustment = 100 ;
int? maxAutoScaleServiceAccounts = null ;
var organization = new Organization
2023-07-25 00:05:05 +02:00
{
2023-08-04 23:51:12 +02:00
Id = organizationId ,
UseSecretsManager = true ,
SmSeats = 10 ,
MaxAutoscaleSmSeats = 20 ,
SmServiceAccounts = organizationServiceAccounts ,
MaxAutoscaleSmServiceAccounts = 350 ,
PlanType = planType ,
GatewayCustomerId = "1" ,
GatewaySubscriptionId = "2"
} ;
2023-07-25 00:05:05 +02:00
2023-08-04 23:51:12 +02:00
var plan = StaticStore . SecretManagerPlans . FirstOrDefault ( x = > x . Type = = organization . PlanType ) ;
var organizationUpdate = new SecretsManagerSubscriptionUpdate (
organization ,
seatAdjustment : seatAdjustment , maxAutoscaleSeats : maxAutoscaleSeats ,
serviceAccountAdjustment : serviceAccountAdjustment , maxAutoscaleServiceAccounts : maxAutoScaleServiceAccounts ) ;
2023-07-25 00:05:05 +02:00
2023-08-04 23:51:12 +02:00
await sutProvider . Sut . UpdateSubscriptionAsync ( organizationUpdate ) ;
2023-07-25 00:05:05 +02:00
2023-08-04 23:51:12 +02:00
await sutProvider . GetDependency < IPaymentService > ( ) . Received ( 1 )
. AdjustSeatsAsync ( organization , plan , organizationUpdate . SmSeatsExcludingBase ) ;
await sutProvider . GetDependency < IPaymentService > ( ) . Received ( 1 )
. AdjustServiceAccountsAsync ( organization , plan , organizationUpdate . SmServiceAccountsExcludingBase ) ;
2023-07-25 00:05:05 +02:00
2023-08-04 23:51:12 +02:00
// TODO: call ReferenceEventService - see AC-1481
2023-07-25 00:05:05 +02:00
2023-08-04 23:51:12 +02:00
AssertUpdatedOrganization ( ( ) = > Arg . Is < Organization > ( org = >
org . Id = = organizationId
& & org . SmSeats = = organizationUpdate . SmSeats
& & org . MaxAutoscaleSmSeats = = organizationUpdate . MaxAutoscaleSmSeats
& & org . SmServiceAccounts = = ( organizationServiceAccounts + serviceAccountAdjustment )
& & org . MaxAutoscaleSmServiceAccounts = = organizationUpdate . MaxAutoscaleSmServiceAccounts ) , sutProvider ) ;
await sutProvider . GetDependency < IMailService > ( ) . DidNotReceiveWithAnyArgs ( ) . SendSecretsManagerMaxSeatLimitReachedEmailAsync ( default , default , default ) ;
await sutProvider . GetDependency < IMailService > ( ) . DidNotReceiveWithAnyArgs ( ) . SendSecretsManagerMaxServiceAccountLimitReachedEmailAsync ( default , default , default ) ;
2023-07-25 00:05:05 +02:00
}
[Theory]
[BitAutoData]
2023-08-04 23:51:12 +02:00
public async Task UpdateSubscriptionAsync_ThrowsBadRequestException_WhenMaxAutoscaleSeatsBelowSeatCount (
2023-07-25 00:05:05 +02:00
Guid organizationId ,
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
var organization = new Organization
{
Id = organizationId ,
UseSecretsManager = true ,
SmSeats = 5 ,
SmServiceAccounts = 200 ,
MaxAutoscaleSmSeats = 4 ,
MaxAutoscaleSmServiceAccounts = 300 ,
PlanType = PlanType . EnterpriseAnnually ,
GatewayCustomerId = "1" ,
GatewaySubscriptionId = "2"
} ;
2023-08-04 23:51:12 +02:00
var update = new SecretsManagerSubscriptionUpdate (
organization , seatAdjustment : 1 , maxAutoscaleSeats : 4 , serviceAccountAdjustment : 5 , maxAutoscaleServiceAccounts : 300 ) ;
2023-07-25 00:05:05 +02:00
2023-08-04 23:51:12 +02:00
var exception = await Assert . ThrowsAsync < BadRequestException > ( ( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( update ) ) ;
2023-07-25 00:05:05 +02:00
Assert . Contains ( "Cannot set max seat autoscaling below seat count." , exception . Message ) ;
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
[Theory]
[BitAutoData]
2023-08-04 23:51:12 +02:00
public async Task UpdateSubscriptionAsync_ThrowsBadRequestException_WhenOccupiedSeatsExceedNewSeatTotal (
2023-07-25 00:05:05 +02:00
Guid organizationId ,
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
var organization = new Organization
{
Id = organizationId ,
UseSecretsManager = true ,
SmSeats = 10 ,
GatewayCustomerId = "1" ,
GatewaySubscriptionId = "2" ,
PlanType = PlanType . EnterpriseAnnually
} ;
2023-08-04 23:51:12 +02:00
var update = new SecretsManagerSubscriptionUpdate (
organization , seatAdjustment : - 3 , maxAutoscaleSeats : 7 , serviceAccountAdjustment : 5 , maxAutoscaleServiceAccounts : 300 ) ;
2023-07-25 00:05:05 +02:00
sutProvider . GetDependency < IOrganizationUserRepository > ( ) . GetOccupiedSmSeatCountByOrganizationIdAsync ( organizationId ) . Returns ( 8 ) ;
2023-08-04 23:51:12 +02:00
var exception = await Assert . ThrowsAsync < BadRequestException > ( ( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( update ) ) ;
2023-07-25 00:05:05 +02:00
Assert . Contains ( "Your organization currently has 8 Secrets Manager seats. Your plan only allows 7 Secrets Manager seats. Remove some Secrets Manager users" , exception . Message ) ;
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
[Theory]
[BitAutoData]
public async Task AdjustServiceAccountsAsync_ThrowsBadRequestException_WhenSmServiceAccountsIsNull (
Guid organizationId ,
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
var organization = new Organization
{
Id = organizationId ,
SmSeats = 10 ,
UseSecretsManager = true ,
GatewayCustomerId = "1" ,
GatewaySubscriptionId = "2" ,
SmServiceAccounts = null ,
PlanType = PlanType . EnterpriseAnnually
} ;
2023-08-04 23:51:12 +02:00
var update = new SecretsManagerSubscriptionUpdate (
organization , seatAdjustment : 10 , maxAutoscaleSeats : 21 , serviceAccountAdjustment : 1 , maxAutoscaleServiceAccounts : 250 ) ;
2023-07-25 00:05:05 +02:00
2023-08-04 23:51:12 +02:00
var exception = await Assert . ThrowsAsync < BadRequestException > ( ( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( update ) ) ;
2023-07-25 00:05:05 +02:00
Assert . Contains ( "Organization has no Service Accounts limit, no need to adjust Service Accounts" , exception . Message ) ;
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
[Theory]
[BitAutoData]
public async Task AutoscaleSeatsAsync_ThrowsBadRequestException_WhenMaxAutoscaleSeatsExceedPlanMaxUsers (
Guid organizationId ,
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
var organization = new Organization
{
Id = organizationId ,
SmSeats = 3 ,
UseSecretsManager = true ,
SmServiceAccounts = 100 ,
PlanType = PlanType . Free ,
GatewayCustomerId = "1" ,
GatewaySubscriptionId = "2" ,
} ;
2023-08-04 23:51:12 +02:00
var organizationUpdate = new SecretsManagerSubscriptionUpdate (
organization , seatAdjustment : 0 , maxAutoscaleSeats : 15 , serviceAccountAdjustment : 0 , maxAutoscaleServiceAccounts : 200 ) ;
2023-07-25 00:05:05 +02:00
2023-08-04 23:51:12 +02:00
var exception = await Assert . ThrowsAsync < BadRequestException > ( ( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( organizationUpdate ) ) ;
2023-07-25 00:05:05 +02:00
Assert . Contains ( "Your plan has a Secrets Manager seat limit of 2, but you have specified a max autoscale count of 15.Reduce your max autoscale count." , exception . Message ) ;
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
[Theory]
[BitAutoData(PlanType.Free)]
public async Task AutoscaleSeatsAsync_ThrowsBadRequestException_WhenPlanDoesNotAllowSeatAutoscale (
PlanType planType ,
Guid organizationId ,
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
var organization = new Organization
{
Id = organizationId ,
UseSecretsManager = true ,
SmSeats = 1 ,
SmServiceAccounts = 200 ,
MaxAutoscaleSmSeats = 20 ,
MaxAutoscaleSmServiceAccounts = 350 ,
PlanType = planType ,
GatewayCustomerId = "1" ,
GatewaySubscriptionId = "2"
} ;
2023-08-04 23:51:12 +02:00
var organizationUpdate = new SecretsManagerSubscriptionUpdate (
organization , seatAdjustment : 0 , maxAutoscaleSeats : 1 , serviceAccountAdjustment : 0 , maxAutoscaleServiceAccounts : 300 ) ;
2023-07-25 00:05:05 +02:00
2023-08-04 23:51:12 +02:00
var exception = await Assert . ThrowsAsync < BadRequestException > ( ( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( organizationUpdate ) ) ;
2023-07-25 00:05:05 +02:00
Assert . Contains ( "Your plan does not allow Secrets Manager seat autoscaling" , exception . Message ) ;
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
[Theory]
[BitAutoData(PlanType.Free)]
public async Task UpdateServiceAccountAutoscaling_ThrowsBadRequestException_WhenPlanDoesNotAllowServiceAccountAutoscale (
PlanType planType ,
Guid organizationId ,
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
var organization = new Organization
{
Id = organizationId ,
UseSecretsManager = true ,
SmSeats = 10 ,
SmServiceAccounts = 200 ,
MaxAutoscaleSmSeats = 20 ,
MaxAutoscaleSmServiceAccounts = 350 ,
PlanType = planType ,
GatewayCustomerId = "1" ,
GatewaySubscriptionId = "2"
} ;
2023-08-04 23:51:12 +02:00
var organizationUpdate = new SecretsManagerSubscriptionUpdate (
organization , seatAdjustment : 0 , maxAutoscaleSeats : null , serviceAccountAdjustment : 0 , maxAutoscaleServiceAccounts : 300 ) ;
2023-07-25 00:05:05 +02:00
2023-08-04 23:51:12 +02:00
var exception = await Assert . ThrowsAsync < BadRequestException > ( ( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( organizationUpdate ) ) ;
2023-07-25 00:05:05 +02:00
Assert . Contains ( "Your plan does not allow Service Accounts autoscaling." , exception . Message ) ;
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
[Theory]
[BitAutoData(PlanType.EnterpriseAnnually)]
[BitAutoData(PlanType.EnterpriseMonthly)]
[BitAutoData(PlanType.TeamsMonthly)]
[BitAutoData(PlanType.TeamsAnnually)]
public async Task UpdateServiceAccountAutoscaling_WhenCurrentServiceAccountsIsGreaterThanNew_ThrowsBadRequestException (
PlanType planType ,
Guid organizationId ,
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
var organization = new Organization
{
Id = organizationId ,
UseSecretsManager = true ,
SmSeats = 10 ,
MaxAutoscaleSmSeats = 20 ,
2023-08-04 23:51:12 +02:00
SmServiceAccounts = 301 ,
2023-07-25 00:05:05 +02:00
MaxAutoscaleSmServiceAccounts = 350 ,
PlanType = planType ,
GatewayCustomerId = "1" ,
GatewaySubscriptionId = "2"
} ;
2023-08-04 23:51:12 +02:00
var organizationUpdate = new SecretsManagerSubscriptionUpdate (
organization , seatAdjustment : 5 , maxAutoscaleSeats : 15 , serviceAccountAdjustment : - 100 , maxAutoscaleServiceAccounts : 300 ) ;
2023-07-25 00:05:05 +02:00
var currentServiceAccounts = 301 ;
sutProvider . GetDependency < IServiceAccountRepository > ( )
. GetServiceAccountCountByOrganizationIdAsync ( organization . Id )
. Returns ( currentServiceAccounts ) ;
2023-08-04 23:51:12 +02:00
var exception = await Assert . ThrowsAsync < BadRequestException > ( ( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( organizationUpdate ) ) ;
Assert . Contains ( "Your organization currently has 301 Service Accounts. Your plan only allows 201 Service Accounts. Remove some Service Accounts" , exception . Message ) ;
2023-07-25 00:05:05 +02:00
await sutProvider . GetDependency < IServiceAccountRepository > ( ) . Received ( 1 ) . GetServiceAccountCountByOrganizationIdAsync ( organization . Id ) ;
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
2023-08-04 23:51:12 +02:00
[Theory]
[BitAutoData(PlanType.EnterpriseAnnually)]
[BitAutoData(PlanType.EnterpriseMonthly)]
[BitAutoData(PlanType.TeamsMonthly)]
[BitAutoData(PlanType.TeamsAnnually)]
public async Task AdjustServiceAccountsAsync_WithEnterpriseOrTeamsPlans_Success ( PlanType planType , Guid organizationId ,
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
var plan = StaticStore . SecretManagerPlans . FirstOrDefault ( p = > p . Type = = planType ) ;
var organizationSeats = plan . BaseSeats + 10 ;
var organizationMaxAutoscaleSeats = 20 ;
var organizationServiceAccounts = plan . BaseServiceAccount . GetValueOrDefault ( ) + 10 ;
var organizationMaxAutoscaleServiceAccounts = 300 ;
var organization = new Organization
{
Id = organizationId ,
PlanType = planType ,
GatewayCustomerId = "1" ,
GatewaySubscriptionId = "2" ,
UseSecretsManager = true ,
SmSeats = organizationSeats ,
MaxAutoscaleSmSeats = organizationMaxAutoscaleSeats ,
SmServiceAccounts = organizationServiceAccounts ,
MaxAutoscaleSmServiceAccounts = organizationMaxAutoscaleServiceAccounts
} ;
var smServiceAccountsAdjustment = 10 ;
var expectedSmServiceAccounts = organizationServiceAccounts + smServiceAccountsAdjustment ;
var expectedSmServiceAccountsExcludingBase = expectedSmServiceAccounts - plan . BaseServiceAccount . GetValueOrDefault ( ) ;
await sutProvider . Sut . AdjustServiceAccountsAsync ( organization , smServiceAccountsAdjustment ) ;
await sutProvider . GetDependency < IPaymentService > ( ) . Received ( 1 ) . AdjustServiceAccountsAsync (
Arg . Is < Organization > ( o = > o . Id = = organizationId ) ,
plan ,
expectedSmServiceAccountsExcludingBase ) ;
// TODO: call ReferenceEventService - see AC-1481
AssertUpdatedOrganization ( ( ) = > Arg . Is < Organization > ( o = >
o . Id = = organizationId
& & o . SmSeats = = organizationSeats
& & o . MaxAutoscaleSmSeats = = organizationMaxAutoscaleSeats
& & o . SmServiceAccounts = = expectedSmServiceAccounts
& & o . MaxAutoscaleSmServiceAccounts = = organizationMaxAutoscaleServiceAccounts ) , sutProvider ) ;
}
[Theory]
[BitAutoData(PlanType.EnterpriseAnnually)]
public async Task ServiceAccountAutoscaling_MaxLimitReached_ThrowsBadRequestException (
PlanType planType ,
Organization organization ,
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
organization . PlanType = planType ;
organization . UseSecretsManager = true ;
organization . SmServiceAccounts = 9 ;
organization . MaxAutoscaleSmServiceAccounts = 10 ;
var update = new SecretsManagerSubscriptionUpdate ( organization , true ) ;
update . AdjustServiceAccounts ( 2 ) ;
var exception = await Assert . ThrowsAsync < BadRequestException > ( ( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( update ) ) ;
Assert . Contains ( "Secrets Manager service account limit has been reached." , exception . Message ) ;
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
[Theory]
[BitAutoData(PlanType.EnterpriseAnnually)]
public async Task ServiceAccountAutoscaling_Subtracting_ThrowsBadRequestException (
PlanType planType ,
Organization organization ,
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
organization . PlanType = planType ;
organization . UseSecretsManager = true ;
var update = new SecretsManagerSubscriptionUpdate ( organization , true ) ;
update . AdjustServiceAccounts ( - 2 ) ;
var exception = await Assert . ThrowsAsync < BadRequestException > ( ( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( update ) ) ;
Assert . Contains ( "Cannot use autoscaling to subtract service accounts." , exception . Message ) ;
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
[Theory]
[BitAutoData(PlanType.EnterpriseAnnually)]
public async Task SmSeatAutoscaling_MaxLimitReached_ThrowsBadRequestException (
PlanType planType ,
Organization organization ,
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
organization . PlanType = planType ;
organization . UseSecretsManager = true ;
organization . SmSeats = 9 ;
organization . MaxAutoscaleSmSeats = 10 ;
var update = new SecretsManagerSubscriptionUpdate ( organization , true ) ;
update . AdjustSeats ( 2 ) ;
var exception = await Assert . ThrowsAsync < BadRequestException > ( ( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( update ) ) ;
Assert . Contains ( "Secrets Manager seat limit has been reached." , exception . Message ) ;
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
[Theory]
[BitAutoData(PlanType.EnterpriseAnnually)]
public async Task SmSeatAutoscaling_Subtracting_ThrowsBadRequestException (
PlanType planType ,
Organization organization ,
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
organization . PlanType = planType ;
organization . UseSecretsManager = true ;
var update = new SecretsManagerSubscriptionUpdate ( organization , true ) ;
update . AdjustSeats ( - 2 ) ;
var exception = await Assert . ThrowsAsync < BadRequestException > ( ( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( update ) ) ;
Assert . Contains ( "Cannot use autoscaling to subtract seats." , exception . Message ) ;
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
[Theory]
[BitAutoData(false, "Cannot update subscription on a self-hosted instance.")]
[BitAutoData(true, "Cannot autoscale on a self-hosted instance.")]
public async Task UpdatingSubscription_WhenSelfHosted_ThrowsBadRequestException (
bool autoscaling ,
string expectedError ,
Organization organization ,
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
organization . PlanType = PlanType . EnterpriseAnnually ;
organization . UseSecretsManager = true ;
var update = new SecretsManagerSubscriptionUpdate ( organization , autoscaling ) ;
update . AdjustSeats ( 2 ) ;
sutProvider . GetDependency < IGlobalSettings > ( ) . SelfHosted . Returns ( true ) ;
var exception = await Assert . ThrowsAsync < BadRequestException > ( ( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( update ) ) ;
Assert . Contains ( expectedError , exception . Message ) ;
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
2023-07-25 00:05:05 +02:00
private static async Task VerifyDependencyNotCalledAsync ( SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
await sutProvider . GetDependency < IPaymentService > ( ) . DidNotReceive ( )
. AdjustSeatsAsync ( Arg . Any < Organization > ( ) , Arg . Any < Plan > ( ) , Arg . Any < int > ( ) ) ;
await sutProvider . GetDependency < IPaymentService > ( ) . DidNotReceive ( )
. AdjustServiceAccountsAsync ( Arg . Any < Organization > ( ) , Arg . Any < Plan > ( ) , Arg . Any < int > ( ) ) ;
// TODO: call ReferenceEventService - see AC-1481
await sutProvider . GetDependency < IMailService > ( ) . DidNotReceive ( )
. SendOrganizationMaxSeatLimitReachedEmailAsync ( Arg . Any < Organization > ( ) , Arg . Any < int > ( ) ,
Arg . Any < IEnumerable < string > > ( ) ) ;
2023-08-04 23:51:12 +02:00
sutProvider . GetDependency < IOrganizationRepository > ( ) . DidNotReceiveWithAnyArgs ( ) . ReplaceAsync ( default ) ;
sutProvider . GetDependency < IApplicationCacheService > ( ) . DidNotReceiveWithAnyArgs ( ) . UpsertOrganizationAbilityAsync ( default ) ;
}
private void AssertUpdatedOrganization ( Func < Organization > organizationMatcher , SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
sutProvider . GetDependency < IOrganizationRepository > ( ) . Received ( 1 ) . ReplaceAsync ( organizationMatcher ( ) ) ;
sutProvider . GetDependency < IApplicationCacheService > ( ) . Received ( 1 ) . UpsertOrganizationAbilityAsync ( organizationMatcher ( ) ) ;
2023-07-25 00:05:05 +02:00
}
}