using Bit.Core.Entities; using Bit.Core.Entities.Provider; using Bit.Core.Enums; using Bit.Core.Enums.Provider; 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.Services; 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 AddSecretsManagerSubscriptionCommandTests { [Theory] [BitAutoData(PlanType.TeamsAnnually)] [BitAutoData(PlanType.TeamsMonthly)] [BitAutoData(PlanType.EnterpriseAnnually)] [BitAutoData(PlanType.EnterpriseMonthly)] public async Task SignUpAsync_ReturnsSuccessAndClientSecret_WhenOrganizationAndPlanExist(PlanType planType, SutProvider sutProvider, int additionalServiceAccounts, int additionalSmSeats, Organization organization, bool useSecretsManager) { organization.PlanType = planType; var plan = StaticStore.Plans.FirstOrDefault(p => p.Type == organization.PlanType); await sutProvider.Sut.SignUpAsync(organization, additionalSmSeats, additionalServiceAccounts); sutProvider.GetDependency().Received(1) .ValidateSecretsManagerPlan(plan, Arg.Is(c => c.UseSecretsManager == useSecretsManager && c.AdditionalSmSeats == additionalSmSeats && c.AdditionalServiceAccounts == additionalServiceAccounts && c.AdditionalSeats == organization.Seats.GetValueOrDefault())); await sutProvider.GetDependency().Received() .AddSecretsManagerToSubscription(organization, plan, additionalSmSeats, additionalServiceAccounts); // TODO: call ReferenceEventService - see AC-1481 sutProvider.GetDependency().Received(1).ReplaceAndUpdateCacheAsync(Arg.Is(c => c.SmSeats == plan.SecretsManager.BaseSeats + additionalSmSeats && c.SmServiceAccounts == plan.SecretsManager.BaseServiceAccount + additionalServiceAccounts && c.UseSecretsManager == true)); } [Theory] [BitAutoData] public async Task SignUpAsync_ThrowsNotFoundException_WhenOrganizationIsNull( SutProvider sutProvider, int additionalServiceAccounts, int additionalSmSeats) { await Assert.ThrowsAsync(() => sutProvider.Sut.SignUpAsync(null, additionalSmSeats, additionalServiceAccounts)); await VerifyDependencyNotCalledAsync(sutProvider); } [Theory] [BitAutoData] public async Task SignUpAsync_ThrowsGatewayException_WhenGatewayCustomerIdIsNullOrWhitespace( SutProvider sutProvider, Organization organization, int additionalServiceAccounts, int additionalSmSeats) { organization.GatewayCustomerId = null; organization.PlanType = PlanType.EnterpriseAnnually; var exception = await Assert.ThrowsAsync(() => sutProvider.Sut.SignUpAsync(organization, additionalSmSeats, additionalServiceAccounts)); Assert.Contains("No payment method found.", exception.Message); await VerifyDependencyNotCalledAsync(sutProvider); } [Theory] [BitAutoData] public async Task SignUpAsync_ThrowsGatewayException_WhenGatewaySubscriptionIdIsNullOrWhitespace( SutProvider sutProvider, Organization organization, int additionalServiceAccounts, int additionalSmSeats) { organization.GatewaySubscriptionId = null; organization.PlanType = PlanType.EnterpriseAnnually; var exception = await Assert.ThrowsAsync(() => sutProvider.Sut.SignUpAsync(organization, additionalSmSeats, additionalServiceAccounts)); Assert.Contains("No subscription found.", exception.Message); await VerifyDependencyNotCalledAsync(sutProvider); } [Theory] [BitAutoData] public async Task SignUpAsync_ThrowsException_WhenOrganizationEnrolledInSmBeta( SutProvider sutProvider, Organization organization) { organization.UseSecretsManager = true; organization.SecretsManagerBeta = true; var exception = await Assert.ThrowsAsync( () => sutProvider.Sut.SignUpAsync(organization, 10, 10)); Assert.Contains("Organization is enrolled in Secrets Manager Beta", exception.Message); await VerifyDependencyNotCalledAsync(sutProvider); } [Theory] [BitAutoData] public async Task SignUpAsync_ThrowsException_WhenOrganizationAlreadyHasSecretsManager( SutProvider sutProvider, Organization organization) { organization.UseSecretsManager = true; organization.SecretsManagerBeta = false; var exception = await Assert.ThrowsAsync( () => sutProvider.Sut.SignUpAsync(organization, 10, 10)); Assert.Contains("Organization already uses Secrets Manager", exception.Message); await VerifyDependencyNotCalledAsync(sutProvider); } [Theory] [BitAutoData] public async Task SignUpAsync_ThrowsException_WhenOrganizationIsManagedByMSP( SutProvider sutProvider, Organization organization, Provider provider) { organization.UseSecretsManager = false; organization.SecretsManagerBeta = false; provider.Type = ProviderType.Msp; sutProvider.GetDependency().GetByOrganizationIdAsync(organization.Id).Returns(provider); var exception = await Assert.ThrowsAsync( () => sutProvider.Sut.SignUpAsync(organization, 10, 10)); Assert.Contains("Organizations with a Managed Service Provider do not support Secrets Manager.", exception.Message); await VerifyDependencyNotCalledAsync(sutProvider); } private static async Task VerifyDependencyNotCalledAsync(SutProvider sutProvider) { await sutProvider.GetDependency().DidNotReceive() .AddSecretsManagerToSubscription(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()); // TODO: call ReferenceEventService - see AC-1481 await sutProvider.GetDependency().DidNotReceive().ReplaceAndUpdateCacheAsync(Arg.Any()); } }