2023-11-29 00:18:08 +01:00
using Bit.Core.AdminConsole.Entities ;
2024-06-14 21:34:47 +02:00
using Bit.Core.Billing.Enums ;
2023-07-25 00:05:05 +02:00
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-08-22 01:55:39 +02:00
using Bit.Core.Test.AutoFixture.OrganizationFixtures ;
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]
2023-08-22 01:55:39 +02:00
[SecretsManagerOrganizationCustomize]
2023-07-25 00:05:05 +02:00
public class UpdateSecretsManagerSubscriptionCommandTests
{
[Theory]
2023-11-03 23:26:47 +01:00
[BitAutoData(PlanType.EnterpriseAnnually2019)]
[BitAutoData(PlanType.EnterpriseAnnually2020)]
2023-08-22 01:55:39 +02:00
[BitAutoData(PlanType.EnterpriseAnnually)]
2023-11-03 23:26:47 +01:00
[BitAutoData(PlanType.EnterpriseMonthly2019)]
[BitAutoData(PlanType.EnterpriseMonthly2020)]
2023-08-22 01:55:39 +02:00
[BitAutoData(PlanType.EnterpriseMonthly)]
2023-11-03 23:26:47 +01:00
[BitAutoData(PlanType.TeamsMonthly2019)]
[BitAutoData(PlanType.TeamsMonthly2020)]
2023-08-22 01:55:39 +02:00
[BitAutoData(PlanType.TeamsMonthly)]
2023-11-03 23:26:47 +01:00
[BitAutoData(PlanType.TeamsAnnually2019)]
[BitAutoData(PlanType.TeamsAnnually2020)]
2023-08-22 01:55:39 +02:00
[BitAutoData(PlanType.TeamsAnnually)]
2023-11-03 23:26:47 +01:00
[BitAutoData(PlanType.TeamsStarter)]
2023-08-22 01:55:39 +02:00
public async Task UpdateSubscriptionAsync_UpdateEverything_ValidInput_Passes (
PlanType planType ,
Organization organization ,
2023-07-25 00:05:05 +02:00
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
2023-08-22 01:55:39 +02:00
organization . PlanType = planType ;
2023-11-03 23:26:47 +01:00
organization . Seats = 400 ;
2023-08-22 01:55:39 +02:00
organization . SmSeats = 10 ;
organization . MaxAutoscaleSmSeats = 20 ;
organization . SmServiceAccounts = 200 ;
organization . MaxAutoscaleSmServiceAccounts = 350 ;
2023-07-25 00:05:05 +02:00
2023-08-22 01:55:39 +02:00
var updateSmSeats = 15 ;
var updateSmServiceAccounts = 300 ;
var updateMaxAutoscaleSmSeats = 16 ;
var updateMaxAutoscaleSmServiceAccounts = 301 ;
2023-08-04 23:51:12 +02:00
2023-08-22 01:55:39 +02:00
var update = new SecretsManagerSubscriptionUpdate ( organization , false )
{
SmSeats = updateSmSeats ,
SmServiceAccounts = updateSmServiceAccounts ,
MaxAutoscaleSmSeats = updateMaxAutoscaleSmSeats ,
MaxAutoscaleSmServiceAccounts = updateMaxAutoscaleSmServiceAccounts
} ;
await sutProvider . Sut . UpdateSubscriptionAsync ( update ) ;
2023-10-17 16:56:35 +02:00
var plan = StaticStore . GetPlan ( organization . PlanType ) ;
2023-08-22 01:55:39 +02:00
await sutProvider . GetDependency < IPaymentService > ( ) . Received ( 1 )
2023-10-23 12:28:13 +02:00
. AdjustSmSeatsAsync ( organization , plan , update . SmSeatsExcludingBase ) ;
2023-08-22 01:55:39 +02:00
await sutProvider . GetDependency < IPaymentService > ( ) . Received ( 1 )
. AdjustServiceAccountsAsync ( organization , plan , update . SmServiceAccountsExcludingBase ) ;
// TODO: call ReferenceEventService - see AC-1481
AssertUpdatedOrganization ( ( ) = > Arg . Is < Organization > ( org = >
org . Id = = organization . Id & &
org . SmSeats = = updateSmSeats & &
org . MaxAutoscaleSmSeats = = updateMaxAutoscaleSmSeats & &
org . SmServiceAccounts = = updateSmServiceAccounts & &
org . MaxAutoscaleSmServiceAccounts = = updateMaxAutoscaleSmServiceAccounts ) ,
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]
2023-08-22 01:55:39 +02:00
[BitAutoData(PlanType.EnterpriseAnnually)]
[BitAutoData(PlanType.EnterpriseMonthly)]
[BitAutoData(PlanType.TeamsMonthly)]
[BitAutoData(PlanType.TeamsAnnually)]
2023-11-03 23:26:47 +01:00
[BitAutoData(PlanType.TeamsStarter)]
2023-08-22 01:55:39 +02:00
public async Task UpdateSubscriptionAsync_ValidInput_WithNullMaxAutoscale_Passes (
PlanType planType ,
Organization organization ,
2023-07-25 00:05:05 +02:00
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
2023-08-22 01:55:39 +02:00
organization . PlanType = planType ;
2023-11-29 15:57:56 +01:00
organization . Seats = 20 ;
2023-08-22 01:55:39 +02:00
const int updateSmSeats = 15 ;
const int updateSmServiceAccounts = 450 ;
2023-12-04 21:28:41 +01:00
// Ensure that SmSeats is different from the original organization.SmSeats
organization . SmSeats = updateSmSeats + 5 ;
2023-08-22 01:55:39 +02:00
var update = new SecretsManagerSubscriptionUpdate ( organization , false )
2023-07-25 00:05:05 +02:00
{
2023-08-22 01:55:39 +02:00
SmSeats = updateSmSeats ,
MaxAutoscaleSmSeats = null ,
SmServiceAccounts = updateSmServiceAccounts ,
MaxAutoscaleSmServiceAccounts = null
2023-07-25 00:05:05 +02:00
} ;
2023-08-22 01:55:39 +02:00
await sutProvider . Sut . UpdateSubscriptionAsync ( update ) ;
2023-10-17 16:56:35 +02:00
var plan = StaticStore . GetPlan ( organization . PlanType ) ;
2023-08-22 01:55:39 +02:00
await sutProvider . GetDependency < IPaymentService > ( ) . Received ( 1 )
2023-10-23 12:28:13 +02:00
. AdjustSmSeatsAsync ( organization , plan , update . SmSeatsExcludingBase ) ;
2023-08-22 01:55:39 +02:00
await sutProvider . GetDependency < IPaymentService > ( ) . Received ( 1 )
. AdjustServiceAccountsAsync ( organization , plan , update . SmServiceAccountsExcludingBase ) ;
// TODO: call ReferenceEventService - see AC-1481
AssertUpdatedOrganization ( ( ) = > Arg . Is < Organization > ( org = >
org . Id = = organization . Id & &
org . SmSeats = = updateSmSeats & &
org . MaxAutoscaleSmSeats = = null & &
org . SmServiceAccounts = = updateSmServiceAccounts & &
org . MaxAutoscaleSmServiceAccounts = = null ) ,
sutProvider ) ;
await sutProvider . GetDependency < IMailService > ( ) . DidNotReceiveWithAnyArgs ( ) . SendSecretsManagerMaxSeatLimitReachedEmailAsync ( default , default , default ) ;
await sutProvider . GetDependency < IMailService > ( ) . DidNotReceiveWithAnyArgs ( ) . SendSecretsManagerMaxServiceAccountLimitReachedEmailAsync ( default , default , default ) ;
}
[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 )
{
2023-08-28 00:05:23 +02:00
var update = new SecretsManagerSubscriptionUpdate ( organization , autoscaling ) . AdjustSeats ( 2 ) ;
2023-08-22 01:55:39 +02:00
sutProvider . GetDependency < IGlobalSettings > ( ) . SelfHosted . Returns ( true ) ;
var exception = await Assert . ThrowsAsync < BadRequestException > ( ( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( update ) ) ;
Assert . Contains ( expectedError , exception . Message ) ;
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
[Theory]
[BitAutoData]
public async Task UpdateSubscriptionAsync_NoSecretsManagerAccess_ThrowsException (
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider ,
Organization organization )
{
organization . UseSecretsManager = false ;
var update = new SecretsManagerSubscriptionUpdate ( organization , false ) ;
2023-07-25 00:05:05 +02:00
var exception = await Assert . ThrowsAsync < BadRequestException > (
2023-08-22 01:55:39 +02:00
( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( update ) ) ;
2023-08-04 23:51:12 +02:00
2023-07-25 00:05:05 +02:00
Assert . Contains ( "Organization has no access to Secrets Manager." , exception . Message ) ;
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
2023-08-28 00:05:23 +02:00
2023-07-25 00:05:05 +02:00
[Theory]
2023-11-03 23:26:47 +01:00
[BitAutoData(PlanType.EnterpriseAnnually2019)]
[BitAutoData(PlanType.EnterpriseAnnually2020)]
2023-08-22 01:55:39 +02:00
[BitAutoData(PlanType.EnterpriseAnnually)]
2023-11-03 23:26:47 +01:00
[BitAutoData(PlanType.EnterpriseMonthly2019)]
[BitAutoData(PlanType.EnterpriseMonthly2020)]
2023-08-22 01:55:39 +02:00
[BitAutoData(PlanType.EnterpriseMonthly)]
2023-11-03 23:26:47 +01:00
[BitAutoData(PlanType.TeamsMonthly2019)]
[BitAutoData(PlanType.TeamsMonthly2020)]
2023-08-22 01:55:39 +02:00
[BitAutoData(PlanType.TeamsMonthly)]
2023-11-03 23:26:47 +01:00
[BitAutoData(PlanType.TeamsAnnually2019)]
[BitAutoData(PlanType.TeamsAnnually2020)]
2023-08-22 01:55:39 +02:00
[BitAutoData(PlanType.TeamsAnnually)]
2023-11-03 23:26:47 +01:00
[BitAutoData(PlanType.TeamsStarter)]
2023-08-22 01:55:39 +02:00
public async Task UpdateSubscriptionAsync_PaidPlan_NullGatewayCustomerId_ThrowsException (
PlanType planType ,
Organization organization ,
2023-07-25 00:05:05 +02:00
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
2023-08-22 01:55:39 +02:00
organization . PlanType = planType ;
organization . GatewayCustomerId = null ;
2023-08-28 00:05:23 +02:00
var update = new SecretsManagerSubscriptionUpdate ( organization , false ) . AdjustSeats ( 1 ) ;
2023-07-25 00:05:05 +02:00
2023-08-22 01:55:39 +02:00
var exception = await Assert . ThrowsAsync < BadRequestException > ( ( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( update ) ) ;
Assert . Contains ( "No payment method found." , exception . Message ) ;
2023-07-25 00:05:05 +02:00
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
[Theory]
2023-11-03 23:26:47 +01:00
[BitAutoData(PlanType.EnterpriseAnnually2019)]
[BitAutoData(PlanType.EnterpriseAnnually2020)]
2023-08-22 01:55:39 +02:00
[BitAutoData(PlanType.EnterpriseAnnually)]
2023-11-03 23:26:47 +01:00
[BitAutoData(PlanType.EnterpriseMonthly2019)]
[BitAutoData(PlanType.EnterpriseMonthly2020)]
2023-08-22 01:55:39 +02:00
[BitAutoData(PlanType.EnterpriseMonthly)]
2023-11-03 23:26:47 +01:00
[BitAutoData(PlanType.TeamsMonthly2019)]
[BitAutoData(PlanType.TeamsMonthly2020)]
2023-08-22 01:55:39 +02:00
[BitAutoData(PlanType.TeamsMonthly)]
2023-11-03 23:26:47 +01:00
[BitAutoData(PlanType.TeamsAnnually2019)]
[BitAutoData(PlanType.TeamsAnnually2020)]
2023-08-22 01:55:39 +02:00
[BitAutoData(PlanType.TeamsAnnually)]
2023-11-03 23:26:47 +01:00
[BitAutoData(PlanType.TeamsStarter)]
2023-08-22 01:55:39 +02:00
public async Task UpdateSubscriptionAsync_PaidPlan_NullGatewaySubscriptionId_ThrowsException (
PlanType planType ,
Organization organization ,
2023-07-25 00:05:05 +02:00
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
2023-08-22 01:55:39 +02:00
organization . PlanType = planType ;
organization . GatewaySubscriptionId = null ;
2023-08-28 00:05:23 +02:00
var update = new SecretsManagerSubscriptionUpdate ( organization , false ) . AdjustSeats ( 1 ) ;
2023-07-25 00:05:05 +02:00
2023-08-22 01:55:39 +02:00
var exception = await Assert . ThrowsAsync < BadRequestException > ( ( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( update ) ) ;
Assert . Contains ( "No subscription found." , exception . Message ) ;
2023-07-25 00:05:05 +02:00
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
[Theory]
2023-11-03 23:26:47 +01:00
[BitAutoData(PlanType.EnterpriseAnnually2019)]
[BitAutoData(PlanType.EnterpriseAnnually2020)]
2023-08-22 01:55:39 +02:00
[BitAutoData(PlanType.EnterpriseAnnually)]
2023-11-03 23:26:47 +01:00
[BitAutoData(PlanType.EnterpriseMonthly2019)]
[BitAutoData(PlanType.EnterpriseMonthly2020)]
2023-08-22 01:55:39 +02:00
[BitAutoData(PlanType.EnterpriseMonthly)]
2023-11-03 23:26:47 +01:00
[BitAutoData(PlanType.TeamsMonthly2019)]
[BitAutoData(PlanType.TeamsMonthly2020)]
2023-08-22 01:55:39 +02:00
[BitAutoData(PlanType.TeamsMonthly)]
2023-11-03 23:26:47 +01:00
[BitAutoData(PlanType.TeamsAnnually2019)]
[BitAutoData(PlanType.TeamsAnnually2020)]
2023-08-22 01:55:39 +02:00
[BitAutoData(PlanType.TeamsAnnually)]
2023-11-03 23:26:47 +01:00
[BitAutoData(PlanType.TeamsStarter)]
2023-08-22 01:55:39 +02:00
public async Task AdjustServiceAccountsAsync_WithEnterpriseOrTeamsPlans_Success ( PlanType planType , Guid organizationId ,
2023-07-25 00:05:05 +02:00
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
2023-10-17 16:56:35 +02:00
var plan = StaticStore . GetPlan ( planType ) ;
2023-08-22 01:55:39 +02:00
2023-10-17 16:56:35 +02:00
var organizationSeats = plan . SecretsManager . BaseSeats + 10 ;
2023-08-22 01:55:39 +02:00
var organizationMaxAutoscaleSeats = 20 ;
2023-10-17 16:56:35 +02:00
var organizationServiceAccounts = plan . SecretsManager . BaseServiceAccount + 10 ;
2023-08-22 01:55:39 +02:00
var organizationMaxAutoscaleServiceAccounts = 300 ;
2023-07-25 00:05:05 +02:00
var organization = new Organization
{
Id = organizationId ,
2023-08-22 01:55:39 +02:00
PlanType = planType ,
GatewayCustomerId = "1" ,
GatewaySubscriptionId = "2" ,
2023-07-25 00:05:05 +02:00
UseSecretsManager = true ,
2023-08-22 01:55:39 +02:00
SmSeats = organizationSeats ,
MaxAutoscaleSmSeats = organizationMaxAutoscaleSeats ,
SmServiceAccounts = organizationServiceAccounts ,
MaxAutoscaleSmServiceAccounts = organizationMaxAutoscaleServiceAccounts
2023-07-25 00:05:05 +02:00
} ;
2023-08-22 01:55:39 +02:00
var smServiceAccountsAdjustment = 10 ;
var expectedSmServiceAccounts = organizationServiceAccounts + smServiceAccountsAdjustment ;
2023-10-17 16:56:35 +02:00
var expectedSmServiceAccountsExcludingBase = expectedSmServiceAccounts - plan . SecretsManager . BaseServiceAccount ;
2023-08-22 01:55:39 +02:00
2023-08-28 00:05:23 +02:00
var update = new SecretsManagerSubscriptionUpdate ( organization , false ) . AdjustServiceAccounts ( 10 ) ;
2023-08-22 01:55:39 +02:00
await sutProvider . Sut . UpdateSubscriptionAsync ( update ) ;
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 ) ;
2023-07-25 00:05:05 +02:00
}
[Theory]
[BitAutoData]
2023-08-22 01:55:39 +02:00
public async Task UpdateSubscriptionAsync_UpdateSeatsToAutoscaleLimit_EmailsOwners (
Organization organization ,
2023-07-25 00:05:05 +02:00
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
2023-12-04 21:28:41 +01:00
const int seatCount = 10 ;
// Make sure Password Manager seats is greater or equal to Secrets Manager seats
organization . Seats = seatCount ;
2023-08-22 01:55:39 +02:00
var update = new SecretsManagerSubscriptionUpdate ( organization , false )
2023-07-25 00:05:05 +02:00
{
2023-12-04 21:28:41 +01:00
SmSeats = seatCount ,
MaxAutoscaleSmSeats = seatCount
2023-07-25 00:05:05 +02:00
} ;
2023-08-22 01:55:39 +02:00
await sutProvider . Sut . UpdateSubscriptionAsync ( update ) ;
await sutProvider . GetDependency < IMailService > ( ) . Received ( 1 ) . SendSecretsManagerMaxSeatLimitReachedEmailAsync (
organization , organization . MaxAutoscaleSmSeats . Value , Arg . Any < IEnumerable < string > > ( ) ) ;
2023-07-25 00:05:05 +02:00
}
[Theory]
[BitAutoData]
2023-08-04 23:51:12 +02:00
public async Task UpdateSubscriptionAsync_OrgWithNullSmSeatOnSeatsAdjustment_ThrowsException (
2023-08-22 01:55:39 +02:00
Organization organization ,
2023-07-25 00:05:05 +02:00
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
2023-08-22 01:55:39 +02:00
organization . SmSeats = null ;
2023-08-28 00:05:23 +02:00
var update = new SecretsManagerSubscriptionUpdate ( organization , false ) . AdjustSeats ( 1 ) ;
2023-07-25 00:05:05 +02:00
var exception = await Assert . ThrowsAsync < BadRequestException > (
2023-08-22 01:55:39 +02:00
( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( update ) ) ;
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]
2023-08-22 01:55:39 +02:00
[BitAutoData]
public async Task UpdateSubscriptionAsync_SmSeatAutoscaling_Subtracting_ThrowsBadRequestException (
Organization organization ,
2023-07-25 00:05:05 +02:00
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
2023-08-28 00:05:23 +02:00
var update = new SecretsManagerSubscriptionUpdate ( organization , true ) . AdjustSeats ( - 2 ) ;
2023-07-25 00:05:05 +02:00
2023-08-22 01:55:39 +02:00
var exception = await Assert . ThrowsAsync < BadRequestException > ( ( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( update ) ) ;
Assert . Contains ( "Cannot use autoscaling to subtract seats." , exception . Message ) ;
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_WithHasAdditionalSeatsOptionFalse_ThrowsBadRequestException (
2023-07-25 00:05:05 +02:00
PlanType planType ,
2023-08-22 01:55:39 +02:00
Organization organization ,
2023-07-25 00:05:05 +02:00
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
2023-08-22 01:55:39 +02:00
organization . PlanType = planType ;
2023-08-28 00:05:23 +02:00
var update = new SecretsManagerSubscriptionUpdate ( organization , false ) . AdjustSeats ( 1 ) ;
2023-07-25 00:05:05 +02:00
2023-08-22 01:55:39 +02:00
var exception = await Assert . ThrowsAsync < BadRequestException > ( ( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( update ) ) ;
2023-08-04 23:51:12 +02:00
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]
2023-08-22 01:55:39 +02:00
[BitAutoData]
public async Task SmSeatAutoscaling_MaxLimitReached_ThrowsBadRequestException (
Organization organization ,
2023-07-25 00:05:05 +02:00
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
2023-08-22 01:55:39 +02:00
organization . SmSeats = 9 ;
organization . MaxAutoscaleSmSeats = 10 ;
2023-07-25 00:05:05 +02:00
2023-08-28 00:05:23 +02:00
var update = new SecretsManagerSubscriptionUpdate ( organization , true ) . AdjustSeats ( 2 ) ;
2023-08-22 01:55:39 +02:00
var exception = await Assert . ThrowsAsync < BadRequestException > ( ( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( update ) ) ;
Assert . Contains ( "Secrets Manager seat limit has been reached." , exception . Message ) ;
2023-07-25 00:05:05 +02:00
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
[Theory]
2023-08-22 01:55:39 +02:00
[BitAutoData]
public async Task UpdateSubscriptionAsync_SeatsAdjustmentGreaterThanMaxAutoscaleSeats_ThrowsException (
Organization organization ,
2023-07-25 00:05:05 +02:00
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
2023-08-22 01:55:39 +02:00
var update = new SecretsManagerSubscriptionUpdate ( organization , false )
2023-07-25 00:05:05 +02:00
{
2023-12-04 21:28:41 +01:00
SmSeats = organization . SmSeats + 10 ,
MaxAutoscaleSmSeats = organization . SmSeats + 5
2023-07-25 00:05:05 +02:00
} ;
2023-08-22 01:55:39 +02:00
var exception = await Assert . ThrowsAsync < BadRequestException > (
( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( update ) ) ;
Assert . Contains ( "Cannot set max seat autoscaling below seat count." , exception . Message ) ;
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
2023-08-04 23:51:12 +02:00
}
2023-07-25 00:05:05 +02:00
2023-08-04 23:51:12 +02:00
[Theory]
2023-08-22 01:55:39 +02:00
[BitAutoData]
public async Task UpdateSubscriptionAsync_ThrowsBadRequestException_WhenSmSeatsLessThanOne (
Organization organization ,
2023-08-04 23:51:12 +02:00
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
2023-08-22 01:55:39 +02:00
var update = new SecretsManagerSubscriptionUpdate ( organization , false )
2023-07-25 00:05:05 +02:00
{
2023-08-22 01:55:39 +02:00
SmSeats = 0 ,
2023-08-04 23:51:12 +02:00
} ;
2023-07-25 00:05:05 +02:00
2023-08-22 01:55:39 +02:00
sutProvider . GetDependency < IOrganizationUserRepository > ( ) . GetOccupiedSmSeatCountByOrganizationIdAsync ( organization . Id ) . Returns ( 8 ) ;
2023-07-25 00:05:05 +02:00
2023-08-22 01:55:39 +02:00
var exception = await Assert . ThrowsAsync < BadRequestException > ( ( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( update ) ) ;
Assert . Contains ( "You must have at least 1 Secrets Manager seat." , exception . Message ) ;
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
2023-07-25 00:05:05 +02:00
}
[Theory]
[BitAutoData]
2023-08-22 01:55:39 +02:00
public async Task UpdateSubscriptionAsync_ThrowsBadRequestException_WhenOccupiedSeatsExceedNewSeatTotal (
Organization organization ,
2023-07-25 00:05:05 +02:00
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
2023-10-18 17:00:55 +02:00
organization . SmSeats = 8 ;
2023-08-22 01:55:39 +02:00
var update = new SecretsManagerSubscriptionUpdate ( organization , false )
2023-07-25 00:05:05 +02:00
{
2023-08-22 01:55:39 +02:00
SmSeats = 7 ,
2023-07-25 00:05:05 +02:00
} ;
2023-08-22 01:55:39 +02:00
sutProvider . GetDependency < IOrganizationUserRepository > ( ) . GetOccupiedSmSeatCountByOrganizationIdAsync ( organization . Id ) . Returns ( 8 ) ;
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-08-28 00:05:23 +02:00
Assert . Contains ( "8 users are currently occupying Secrets Manager seats. You cannot decrease your subscription below your current occupied seat count" , exception . Message ) ;
2023-07-25 00:05:05 +02:00
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
[Theory]
[BitAutoData]
2023-08-22 01:55:39 +02:00
public async Task UpdateSubscriptionAsync_UpdateServiceAccountsToAutoscaleLimit_EmailsOwners (
Organization organization ,
2023-07-25 00:05:05 +02:00
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
2023-08-22 01:55:39 +02:00
var update = new SecretsManagerSubscriptionUpdate ( organization , false )
2023-07-25 00:05:05 +02:00
{
2023-08-22 01:55:39 +02:00
SmServiceAccounts = 300 ,
MaxAutoscaleSmServiceAccounts = 300
2023-07-25 00:05:05 +02:00
} ;
2023-08-22 01:55:39 +02:00
await sutProvider . Sut . UpdateSubscriptionAsync ( update ) ;
2023-07-25 00:05:05 +02:00
2023-08-22 01:55:39 +02:00
await sutProvider . GetDependency < IMailService > ( ) . Received ( 1 ) . SendSecretsManagerMaxServiceAccountLimitReachedEmailAsync (
organization , organization . MaxAutoscaleSmServiceAccounts . Value , Arg . Any < IEnumerable < string > > ( ) ) ;
2023-07-25 00:05:05 +02:00
}
[Theory]
[BitAutoData]
public async Task AdjustServiceAccountsAsync_ThrowsBadRequestException_WhenSmServiceAccountsIsNull (
2023-08-22 01:55:39 +02:00
Organization organization ,
2023-07-25 00:05:05 +02:00
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
2023-08-22 01:55:39 +02:00
organization . SmServiceAccounts = null ;
2023-08-28 00:05:23 +02:00
var update = new SecretsManagerSubscriptionUpdate ( organization , false ) . AdjustServiceAccounts ( 1 ) ;
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 ) ) ;
2024-04-05 14:54:36 +02:00
Assert . Contains ( "Organization has no machine accounts limit, no need to adjust machine accounts" , exception . Message ) ;
2023-07-25 00:05:05 +02:00
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
[Theory]
[BitAutoData]
2023-08-22 01:55:39 +02:00
public async Task UpdateSubscriptionAsync_ServiceAccountAutoscaling_Subtracting_ThrowsBadRequestException (
Organization organization ,
2023-07-25 00:05:05 +02:00
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
2023-08-28 00:05:23 +02:00
var update = new SecretsManagerSubscriptionUpdate ( organization , true ) . AdjustServiceAccounts ( - 2 ) ;
2023-07-25 00:05:05 +02:00
2023-08-22 01:55:39 +02:00
var exception = await Assert . ThrowsAsync < BadRequestException > ( ( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( update ) ) ;
2024-04-05 14:54:36 +02:00
Assert . Contains ( "Cannot use autoscaling to subtract machine accounts." , exception . Message ) ;
2023-07-25 00:05:05 +02:00
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
[Theory]
[BitAutoData(PlanType.Free)]
2023-08-22 01:55:39 +02:00
public async Task UpdateSubscriptionAsync_WithHasAdditionalServiceAccountOptionFalse_ThrowsBadRequestException (
2023-07-25 00:05:05 +02:00
PlanType planType ,
2023-08-22 01:55:39 +02:00
Organization organization ,
2023-07-25 00:05:05 +02:00
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
2023-08-22 01:55:39 +02:00
organization . PlanType = planType ;
2023-08-28 00:05:23 +02:00
var update = new SecretsManagerSubscriptionUpdate ( organization , false ) . AdjustServiceAccounts ( 1 ) ;
2023-07-25 00:05:05 +02:00
2023-08-22 01:55:39 +02:00
var exception = await Assert . ThrowsAsync < BadRequestException > ( ( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( update ) ) ;
2024-04-05 14:54:36 +02:00
Assert . Contains ( "You have reached the maximum number of machine accounts (3) for this plan" ,
2023-08-22 01:55:39 +02:00
exception . Message , StringComparison . InvariantCultureIgnoreCase ) ;
2023-07-25 00:05:05 +02:00
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
[Theory]
2023-08-22 01:55:39 +02:00
[BitAutoData]
public async Task ServiceAccountAutoscaling_MaxLimitReached_ThrowsBadRequestException (
Organization organization ,
2023-07-25 00:05:05 +02:00
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
2023-08-22 01:55:39 +02:00
organization . SmServiceAccounts = 9 ;
organization . MaxAutoscaleSmServiceAccounts = 10 ;
2023-07-25 00:05:05 +02:00
2023-08-28 00:05:23 +02:00
var update = new SecretsManagerSubscriptionUpdate ( organization , true ) . AdjustServiceAccounts ( 2 ) ;
2023-07-25 00:05:05 +02:00
2023-08-22 01:55:39 +02:00
var exception = await Assert . ThrowsAsync < BadRequestException > ( ( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( update ) ) ;
2024-04-05 14:54:36 +02:00
Assert . Contains ( "Secrets Manager machine account limit has been reached." , exception . Message ) ;
2023-07-25 00:05:05 +02:00
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
[Theory]
2023-08-22 01:55:39 +02:00
[BitAutoData]
public async Task UpdateSubscriptionAsync_ServiceAccountsGreaterThanMaxAutoscaleSeats_ThrowsException (
Organization organization ,
2023-07-25 00:05:05 +02:00
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
2023-12-04 21:28:41 +01:00
const int smServiceAccount = 15 ;
const int maxAutoscaleSmServiceAccounts = 10 ;
organization . SmServiceAccounts = smServiceAccount - 5 ;
organization . MaxAutoscaleSmServiceAccounts = 2 * smServiceAccount ;
2023-08-22 01:55:39 +02:00
var update = new SecretsManagerSubscriptionUpdate ( organization , false )
2023-07-25 00:05:05 +02:00
{
2023-12-04 21:28:41 +01:00
SmServiceAccounts = smServiceAccount ,
MaxAutoscaleSmServiceAccounts = maxAutoscaleSmServiceAccounts
2023-07-25 00:05:05 +02:00
} ;
2023-08-22 01:55:39 +02:00
var exception = await Assert . ThrowsAsync < BadRequestException > (
( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( update ) ) ;
2024-04-05 14:54:36 +02:00
Assert . Contains ( "Cannot set max machine accounts autoscaling below machine account amount" , exception . Message ) ;
2023-07-25 00:05:05 +02:00
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
2023-08-04 23:51:12 +02:00
[Theory]
2023-08-22 01:55:39 +02:00
[BitAutoData]
public async Task UpdateSubscriptionAsync_ServiceAccountsLessThanPlanMinimum_ThrowsException (
Organization organization ,
2023-08-04 23:51:12 +02:00
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
2024-04-08 20:42:01 +02:00
const int newSmServiceAccounts = 49 ;
2023-12-04 21:28:41 +01:00
organization . SmServiceAccounts = newSmServiceAccounts - 10 ;
2023-08-22 01:55:39 +02:00
var update = new SecretsManagerSubscriptionUpdate ( organization , false )
2023-08-04 23:51:12 +02:00
{
2023-12-04 21:28:41 +01:00
SmServiceAccounts = newSmServiceAccounts ,
2023-08-04 23:51:12 +02:00
} ;
2023-08-22 01:55:39 +02:00
var exception = await Assert . ThrowsAsync < BadRequestException > (
( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( update ) ) ;
2024-04-08 20:42:01 +02:00
Assert . Contains ( "Plan has a minimum of 50 machine accounts" , exception . Message ) ;
2023-08-22 01:55:39 +02:00
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
2023-08-04 23:51:12 +02:00
}
[Theory]
2023-11-03 23:26:47 +01:00
[BitAutoData(PlanType.EnterpriseAnnually2019)]
[BitAutoData(PlanType.EnterpriseAnnually2020)]
2023-08-04 23:51:12 +02:00
[BitAutoData(PlanType.EnterpriseAnnually)]
2023-11-03 23:26:47 +01:00
[BitAutoData(PlanType.EnterpriseMonthly2019)]
[BitAutoData(PlanType.EnterpriseMonthly2020)]
2023-08-22 01:55:39 +02:00
[BitAutoData(PlanType.EnterpriseMonthly)]
2023-11-03 23:26:47 +01:00
[BitAutoData(PlanType.TeamsMonthly2019)]
[BitAutoData(PlanType.TeamsMonthly2020)]
2023-08-22 01:55:39 +02:00
[BitAutoData(PlanType.TeamsMonthly)]
2023-11-03 23:26:47 +01:00
[BitAutoData(PlanType.TeamsAnnually2019)]
[BitAutoData(PlanType.TeamsAnnually2020)]
2023-08-22 01:55:39 +02:00
[BitAutoData(PlanType.TeamsAnnually)]
2023-11-03 23:26:47 +01:00
[BitAutoData(PlanType.TeamsStarter)]
2023-08-22 01:55:39 +02:00
public async Task UpdateSmServiceAccounts_WhenCurrentServiceAccountsIsGreaterThanNew_ThrowsBadRequestException (
2023-08-04 23:51:12 +02:00
PlanType planType ,
Organization organization ,
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
2023-08-22 01:55:39 +02:00
var currentServiceAccounts = 301 ;
2023-08-04 23:51:12 +02:00
organization . PlanType = planType ;
2023-08-22 01:55:39 +02:00
organization . SmServiceAccounts = currentServiceAccounts ;
var update = new SecretsManagerSubscriptionUpdate ( organization , false ) { SmServiceAccounts = 201 } ;
2023-08-04 23:51:12 +02:00
2023-08-22 01:55:39 +02:00
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 ( update ) ) ;
2024-04-05 14:54:36 +02:00
Assert . Contains ( "Your organization currently has 301 machine accounts. You cannot decrease your subscription below your current machine account usage" , exception . Message ) ;
2023-08-04 23:51:12 +02:00
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
[Theory]
2023-08-22 01:55:39 +02:00
[BitAutoData]
public async Task UpdateSubscriptionAsync_ThrowsBadRequestException_WhenMaxAutoscaleSeatsBelowSeatCount (
2023-08-04 23:51:12 +02:00
Organization organization ,
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
2023-12-04 21:28:41 +01:00
const int smSeats = 10 ;
const int maxAutoscaleSmSeats = 5 ;
organization . SmSeats = smSeats - 1 ;
organization . MaxAutoscaleSmSeats = smSeats * 2 ;
2023-08-22 01:55:39 +02:00
var update = new SecretsManagerSubscriptionUpdate ( organization , false )
{
2023-12-04 21:28:41 +01:00
SmSeats = smSeats ,
MaxAutoscaleSmSeats = maxAutoscaleSmSeats
2023-08-22 01:55:39 +02:00
} ;
2023-08-04 23:51:12 +02:00
var exception = await Assert . ThrowsAsync < BadRequestException > ( ( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( update ) ) ;
2023-08-22 01:55:39 +02:00
Assert . Contains ( "Cannot set max seat autoscaling below seat count." , exception . Message ) ;
2023-08-04 23:51:12 +02:00
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
[Theory]
2023-08-22 01:55:39 +02:00
[BitAutoData(PlanType.Free)]
public async Task UpdateMaxAutoscaleSmSeats_ThrowsBadRequestException_WhenExceedsPlanMaxUsers (
2023-08-04 23:51:12 +02:00
PlanType planType ,
Organization organization ,
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
organization . PlanType = planType ;
2023-08-22 01:55:39 +02:00
organization . SmSeats = 2 ;
var update = new SecretsManagerSubscriptionUpdate ( organization , false )
{
MaxAutoscaleSmSeats = 3
} ;
2023-08-04 23:51:12 +02:00
var exception = await Assert . ThrowsAsync < BadRequestException > ( ( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( update ) ) ;
2023-08-22 01:55:39 +02:00
Assert . Contains ( "Your plan has a Secrets Manager seat limit of 2, but you have specified a max autoscale count of 3.Reduce your max autoscale count." , exception . Message ) ;
2023-08-04 23:51:12 +02:00
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
[Theory]
2023-08-22 01:55:39 +02:00
[BitAutoData(PlanType.Free)]
public async Task UpdateMaxAutoscaleSmSeats_ThrowsBadRequestException_WhenPlanDoesNotAllowAutoscale (
2023-08-04 23:51:12 +02:00
PlanType planType ,
Organization organization ,
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
organization . PlanType = planType ;
2023-08-22 01:55:39 +02:00
organization . SmSeats = 2 ;
var update = new SecretsManagerSubscriptionUpdate ( organization , false )
{
MaxAutoscaleSmSeats = 2
} ;
2023-08-04 23:51:12 +02:00
var exception = await Assert . ThrowsAsync < BadRequestException > ( ( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( update ) ) ;
2023-08-22 01:55:39 +02:00
Assert . Contains ( "Your plan does not allow Secrets Manager seat autoscaling" , exception . Message ) ;
2023-08-04 23:51:12 +02:00
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
[Theory]
2023-08-22 01:55:39 +02:00
[BitAutoData(PlanType.Free)]
public async Task UpdateMaxAutoscaleSmServiceAccounts_ThrowsBadRequestException_WhenPlanDoesNotAllowAutoscale (
PlanType planType ,
2023-08-04 23:51:12 +02:00
Organization organization ,
SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
2023-08-22 01:55:39 +02:00
organization . PlanType = planType ;
organization . SmServiceAccounts = 3 ;
2023-08-04 23:51:12 +02:00
2023-08-22 01:55:39 +02:00
var update = new SecretsManagerSubscriptionUpdate ( organization , false ) { MaxAutoscaleSmServiceAccounts = 3 } ;
2023-08-04 23:51:12 +02:00
var exception = await Assert . ThrowsAsync < BadRequestException > ( ( ) = > sutProvider . Sut . UpdateSubscriptionAsync ( update ) ) ;
2024-04-05 14:54:36 +02:00
Assert . Contains ( "Your plan does not allow machine accounts autoscaling." , exception . Message ) ;
2023-08-04 23:51:12 +02:00
await VerifyDependencyNotCalledAsync ( sutProvider ) ;
}
2023-07-25 00:05:05 +02:00
private static async Task VerifyDependencyNotCalledAsync ( SutProvider < UpdateSecretsManagerSubscriptionCommand > sutProvider )
{
await sutProvider . GetDependency < IPaymentService > ( ) . DidNotReceive ( )
2023-10-23 12:28:13 +02:00
. AdjustSmSeatsAsync ( Arg . Any < Organization > ( ) , Arg . Any < Plan > ( ) , Arg . Any < int > ( ) ) ;
2023-07-25 00:05:05 +02:00
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
2024-08-15 23:14:22 +02:00
await sutProvider . GetDependency < IOrganizationRepository > ( ) . DidNotReceiveWithAnyArgs ( ) . ReplaceAsync ( default ) ;
await sutProvider . GetDependency < IApplicationCacheService > ( ) . DidNotReceiveWithAnyArgs ( ) . UpsertOrganizationAbilityAsync ( default ) ;
2023-08-04 23:51:12 +02:00
}
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
}
}