using Bit.Core.AdminConsole.Entities; using Bit.Core.AdminConsole.Models.Data.Organizations; using Bit.Core.AdminConsole.OrganizationFeatures.Organizations; using Bit.Core.Billing.Enums; using Bit.Core.Billing.Models.StaticStore.Plans; using Bit.Core.Models.StaticStore; using Bit.Core.Repositories; using Bit.Core.Services; using Bit.Test.Common.AutoFixture; using Bit.Test.Common.AutoFixture.Attributes; using NSubstitute; using NSubstitute.ExceptionExtensions; using Xunit; namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.Organizations; [SutProviderCustomize] public class UpdateOrganizationSubscriptionCommandTests { [Theory] [BitAutoData] public async Task UpdateOrganizationSubscriptionAsync_WhenNoSubscriptionsNeedToBeUpdated_ThenNoSyncsOccur( SutProvider sutProvider) { // Arrange OrganizationSubscriptionUpdate[] subscriptionsToUpdate = []; // Act await sutProvider.Sut.UpdateOrganizationSubscriptionAsync(subscriptionsToUpdate); await sutProvider.GetDependency() .DidNotReceive() .AdjustSeatsAsync(Arg.Any(), Arg.Any(), Arg.Any()); await sutProvider.GetDependency() .DidNotReceive() .UpdateSuccessfulOrganizationSyncStatusAsync(Arg.Any>(), Arg.Any()); } [Theory] [BitAutoData] public async Task UpdateOrganizationSubscriptionAsync_WhenOrgUpdatePassedIn_ThenSyncedThroughPaymentService( Organization organization, SutProvider sutProvider) { // Arrange organization.PlanType = PlanType.EnterpriseAnnually2023; organization.Seats = 2; OrganizationSubscriptionUpdate[] subscriptionsToUpdate = [new() { Organization = organization, Plan = new Enterprise2023Plan(true) }]; // Act await sutProvider.Sut.UpdateOrganizationSubscriptionAsync(subscriptionsToUpdate); await sutProvider.GetDependency() .Received(1) .AdjustSeatsAsync( Arg.Is(x => x.Id == organization.Id), Arg.Is(x => x.Type == organization.PlanType), organization.Seats!.Value); await sutProvider.GetDependency() .Received(1) .UpdateSuccessfulOrganizationSyncStatusAsync( Arg.Is>(x => x.Contains(organization.Id)), Arg.Any()); } [Theory] [BitAutoData] public async Task UpdateOrganizationSubscriptionAsync_WhenOrgUpdateFails_ThenSyncDoesNotOccur( Organization organization, Exception exception, SutProvider sutProvider) { // Arrange organization.PlanType = PlanType.EnterpriseAnnually2023; organization.Seats = 2; OrganizationSubscriptionUpdate[] subscriptionsToUpdate = [new() { Organization = organization, Plan = new Enterprise2023Plan(true) }]; sutProvider.GetDependency() .AdjustSeatsAsync( Arg.Is(x => x.Id == organization.Id), Arg.Is(x => x.Type == organization.PlanType), organization.Seats!.Value).ThrowsAsync(exception); // Act await sutProvider.Sut.UpdateOrganizationSubscriptionAsync(subscriptionsToUpdate); await sutProvider.GetDependency() .DidNotReceive() .UpdateSuccessfulOrganizationSyncStatusAsync(Arg.Any>(), Arg.Any()); } [Theory] [BitAutoData] public async Task UpdateOrganizationSubscriptionAsync_WhenOneOrgUpdateFailsAndAnotherSucceeds_ThenSyncOccursForTheSuccessfulOrg( Organization successfulOrganization, Organization failedOrganization, Exception exception, SutProvider sutProvider) { // Arrange successfulOrganization.PlanType = PlanType.EnterpriseAnnually2023; successfulOrganization.Seats = 2; failedOrganization.PlanType = PlanType.EnterpriseAnnually2023; failedOrganization.Seats = 2; OrganizationSubscriptionUpdate[] subscriptionsToUpdate = [ new() { Organization = successfulOrganization, Plan = new Enterprise2023Plan(true) }, new() { Organization = failedOrganization, Plan = new Enterprise2023Plan(true) } ]; sutProvider.GetDependency() .AdjustSeatsAsync( Arg.Is(x => x.Id == failedOrganization.Id), Arg.Is(x => x.Type == failedOrganization.PlanType), failedOrganization.Seats!.Value).ThrowsAsync(exception); // Act await sutProvider.Sut.UpdateOrganizationSubscriptionAsync(subscriptionsToUpdate); await sutProvider.GetDependency() .Received(1) .AdjustSeatsAsync( Arg.Is(x => x.Id == successfulOrganization.Id), Arg.Is(x => x.Type == successfulOrganization.PlanType), successfulOrganization.Seats!.Value); await sutProvider.GetDependency() .Received(1) .UpdateSuccessfulOrganizationSyncStatusAsync( Arg.Is>(x => x.Contains(successfulOrganization.Id)), Arg.Any()); await sutProvider.GetDependency() .DidNotReceive() .UpdateSuccessfulOrganizationSyncStatusAsync( Arg.Is>(x => x.Contains(failedOrganization.Id)), Arg.Any()); } }