diff --git a/test/Core.Test/AdminConsole/Services/OrganizationServiceTests.cs b/test/Core.Test/AdminConsole/Services/OrganizationServiceTests.cs index 33f2e7879988..b8a756db717d 100644 --- a/test/Core.Test/AdminConsole/Services/OrganizationServiceTests.cs +++ b/test/Core.Test/AdminConsole/Services/OrganizationServiceTests.cs @@ -1330,6 +1330,109 @@ await sutProvider.GetDependency() .GetByIdAsync(organizationId); } + [Theory] + [OrganizationInviteCustomize(InviteeUserType = OrganizationUserType.User, + InvitorUserType = OrganizationUserType.Owner), OrganizationCustomize, BitAutoData] + public async Task InviteUsers_WhenSeatCountIncreasesAndOwnersNotNotified_SendsAutoscaledEmailOnce( + Organization organization, + OrganizationUser invitor, + [OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Owner)] OrganizationUser owner, + OrganizationUserInvite invite, + SutProvider sutProvider) + { + // Arrange + sutProvider.SetDependency(_orgUserInviteTokenDataFactory, "orgUserInviteTokenDataFactory"); + sutProvider.Create(); + + organization.Seats = 1; + organization.SmSeats = 0; + organization.OwnersNotifiedOfAutoscaling = null; + organization.GatewayCustomerId = "customer_id"; + organization.GatewaySubscriptionId = "subscription_id"; + invite.Emails = invite.Emails.Take(1); + invite.AccessSecretsManager = false; + + sutProvider.GetDependency().GetByIdAsync(organization.Id).Returns(organization); + sutProvider.GetDependency().GetOccupiedSeatCountByOrganizationIdAsync(organization.Id) + .Returns(new OrganizationSeatCounts { Sponsored = 0, Users = 1 }); + sutProvider.GetDependency().GetManyByMinimumRoleAsync(organization.Id, OrganizationUserType.Owner) + .ReturnsForAnyArgs([new OrganizationUserUserDetails { Id = owner.Id, Email = owner.Email }]); + sutProvider.GetDependency().SelectKnownEmailsAsync(organization.Id, Arg.Any>(), false) + .Returns(Array.Empty()); + sutProvider.GetDependency().OrganizationOwner(organization.Id).Returns(true); + sutProvider.GetDependency().ManageUsers(organization.Id).Returns(true); + sutProvider.GetDependency() + .HasConfirmedOwnersExceptAsync(organization.Id, Arg.Any>(), Arg.Any()).Returns(true); + sutProvider.GetDependency() + .CountNewSmSeatsRequiredAsync(organization.Id, Arg.Any()).Returns(0); + sutProvider.GetDependency().GetPlanOrThrow(organization.PlanType).Returns(StaticStore.GetPlan(organization.PlanType)); + sutProvider.GetDependency().AdjustSeatsAsync(Arg.Any(), Arg.Any(), Arg.Any()) + .Returns(Task.FromResult(null)); + sutProvider.GetDependency().SelfHosted.Returns(false); + SetupOrgUserRepositoryCreateManyAsyncMock(sutProvider.GetDependency()); + + // Act + await sutProvider.Sut.InviteUsersAsync(organization.Id, invitor.UserId, systemUser: null, invites: [(invite, null)]); + + // Assert + await sutProvider.GetDependency() + .Received(1) + .SendOrganizationAutoscaledEmailAsync( + Arg.Is(o => o.Id == organization.Id), + initialSeatCount: 1, + Arg.Is>(emails => emails.Contains(owner.Email))); + await sutProvider.GetDependency() + .Received(1) + .UpsertAsync( + Arg.Is(o => o.Id == organization.Id && o.OwnersNotifiedOfAutoscaling.HasValue)); + } + + [Theory] + [OrganizationInviteCustomize(InviteeUserType = OrganizationUserType.User, + InvitorUserType = OrganizationUserType.Owner), OrganizationCustomize, BitAutoData] + public async Task InviteUsers_WhenOwnersAlreadyNotified_DoesNotSendAutoscaleEmail( + Organization organization, + OrganizationUser invitor, + OrganizationUserInvite invite, + SutProvider sutProvider) + { + // Arrange + sutProvider.SetDependency(_orgUserInviteTokenDataFactory, "orgUserInviteTokenDataFactory"); + sutProvider.Create(); + + organization.Seats = 1; + organization.SmSeats = 0; + organization.OwnersNotifiedOfAutoscaling = DateTime.UtcNow.AddDays(-1); + organization.GatewayCustomerId = "customer_id"; + organization.GatewaySubscriptionId = "subscription_id"; + invite.Emails = invite.Emails.Take(1); + invite.AccessSecretsManager = false; + + sutProvider.GetDependency().GetByIdAsync(organization.Id).Returns(organization); + sutProvider.GetDependency().GetOccupiedSeatCountByOrganizationIdAsync(organization.Id) + .Returns(new OrganizationSeatCounts { Sponsored = 0, Users = 1 }); + sutProvider.GetDependency().SelectKnownEmailsAsync(organization.Id, Arg.Any>(), false) + .Returns(Array.Empty()); + sutProvider.GetDependency().OrganizationOwner(organization.Id).Returns(true); + sutProvider.GetDependency().ManageUsers(organization.Id).Returns(true); + sutProvider.GetDependency() + .HasConfirmedOwnersExceptAsync(organization.Id, Arg.Any>(), Arg.Any()).Returns(true); + sutProvider.GetDependency() + .CountNewSmSeatsRequiredAsync(organization.Id, Arg.Any()).Returns(0); + sutProvider.GetDependency().GetPlanOrThrow(organization.PlanType).Returns(StaticStore.GetPlan(organization.PlanType)); + sutProvider.GetDependency().AdjustSeatsAsync(Arg.Any(), Arg.Any(), Arg.Any()) + .Returns(Task.FromResult(null)); + sutProvider.GetDependency().SelfHosted.Returns(false); + SetupOrgUserRepositoryCreateManyAsyncMock(sutProvider.GetDependency()); + + // Act + await sutProvider.Sut.InviteUsersAsync(organization.Id, invitor.UserId, systemUser: null, invites: [(invite, null)]); + + // Assert + await sutProvider.GetDependency().DidNotReceive().SendOrganizationAutoscaledEmailAsync( + Arg.Any(), Arg.Any(), Arg.Any>()); + } + // Must set real guids in order for dictionary of guids to not throw aggregate exceptions private void SetupOrgUserRepositoryCreateManyAsyncMock(IOrganizationUserRepository organizationUserRepository) {