mirror of
https://github.com/bitwarden/server.git
synced 2025-06-30 15:42:48 -05:00
Merge branch 'main' into jmccannon/ac/pm-16811-scim-invite-optimization
# Conflicts: # src/Core/AdminConsole/Services/Implementations/OrganizationService.cs # test/Infrastructure.IntegrationTest/AdminConsole/Repositories/OrganizationUserRepositoryTests.cs
This commit is contained in:
@ -0,0 +1,35 @@
|
||||
using System.Reflection;
|
||||
using AutoFixture;
|
||||
using AutoFixture.Xunit2;
|
||||
using Bit.Core.AdminConsole.Enums;
|
||||
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
||||
using Bit.Core.Enums;
|
||||
|
||||
namespace Bit.Core.Test.AdminConsole.AutoFixture;
|
||||
|
||||
internal class PolicyDetailsCustomization(
|
||||
PolicyType policyType,
|
||||
OrganizationUserType userType,
|
||||
bool isProvider,
|
||||
OrganizationUserStatusType userStatus) : ICustomization
|
||||
{
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
fixture.Customize<PolicyDetails>(composer => composer
|
||||
.With(o => o.PolicyType, policyType)
|
||||
.With(o => o.OrganizationUserType, userType)
|
||||
.With(o => o.IsProvider, isProvider)
|
||||
.With(o => o.OrganizationUserStatus, userStatus)
|
||||
.Without(o => o.PolicyData)); // avoid autogenerating invalid json data
|
||||
}
|
||||
}
|
||||
|
||||
public class PolicyDetailsAttribute(
|
||||
PolicyType policyType,
|
||||
OrganizationUserType userType = OrganizationUserType.User,
|
||||
bool isProvider = false,
|
||||
OrganizationUserStatusType userStatus = OrganizationUserStatusType.Confirmed) : CustomizeAttribute
|
||||
{
|
||||
public override ICustomization GetCustomization(ParameterInfo parameter)
|
||||
=> new PolicyDetailsCustomization(policyType, userType, isProvider, userStatus);
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Organizations;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.Organizations;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class OrganizationDisableCommandTests
|
||||
{
|
||||
[Theory, BitAutoData]
|
||||
public async Task DisableAsync_WhenOrganizationEnabled_DisablesSuccessfully(
|
||||
Organization organization,
|
||||
DateTime expirationDate,
|
||||
SutProvider<OrganizationDisableCommand> sutProvider)
|
||||
{
|
||||
organization.Enabled = true;
|
||||
sutProvider.GetDependency<IOrganizationRepository>()
|
||||
.GetByIdAsync(organization.Id)
|
||||
.Returns(organization);
|
||||
|
||||
await sutProvider.Sut.DisableAsync(organization.Id, expirationDate);
|
||||
|
||||
Assert.False(organization.Enabled);
|
||||
Assert.Equal(expirationDate, organization.ExpirationDate);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationRepository>()
|
||||
.Received(1)
|
||||
.ReplaceAsync(organization);
|
||||
await sutProvider.GetDependency<IApplicationCacheService>()
|
||||
.Received(1)
|
||||
.UpsertOrganizationAbilityAsync(organization);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task DisableAsync_WhenOrganizationNotFound_DoesNothing(
|
||||
Guid organizationId,
|
||||
DateTime expirationDate,
|
||||
SutProvider<OrganizationDisableCommand> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationRepository>()
|
||||
.GetByIdAsync(organizationId)
|
||||
.Returns((Organization)null);
|
||||
|
||||
await sutProvider.Sut.DisableAsync(organizationId, expirationDate);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationRepository>()
|
||||
.DidNotReceive()
|
||||
.ReplaceAsync(Arg.Any<Organization>());
|
||||
await sutProvider.GetDependency<IApplicationCacheService>()
|
||||
.DidNotReceive()
|
||||
.UpsertOrganizationAbilityAsync(Arg.Any<Organization>());
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task DisableAsync_WhenOrganizationAlreadyDisabled_DoesNothing(
|
||||
Organization organization,
|
||||
DateTime expirationDate,
|
||||
SutProvider<OrganizationDisableCommand> sutProvider)
|
||||
{
|
||||
organization.Enabled = false;
|
||||
sutProvider.GetDependency<IOrganizationRepository>()
|
||||
.GetByIdAsync(organization.Id)
|
||||
.Returns(organization);
|
||||
|
||||
await sutProvider.Sut.DisableAsync(organization.Id, expirationDate);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationRepository>()
|
||||
.DidNotReceive()
|
||||
.ReplaceAsync(Arg.Any<Organization>());
|
||||
await sutProvider.GetDependency<IApplicationCacheService>()
|
||||
.DidNotReceive()
|
||||
.UpsertOrganizationAbilityAsync(Arg.Any<Organization>());
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Organizations;
|
||||
using Bit.Core.Billing.Enums;
|
||||
using Bit.Core.Billing.Models.Sales;
|
||||
using Bit.Core.Billing.Pricing;
|
||||
using Bit.Core.Billing.Services;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
@ -38,6 +39,8 @@ public class CloudICloudOrganizationSignUpCommandTests
|
||||
signup.IsFromSecretsManagerTrial = false;
|
||||
signup.IsFromProvider = false;
|
||||
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(signup.Plan).Returns(StaticStore.GetPlan(signup.Plan));
|
||||
|
||||
var result = await sutProvider.Sut.SignUpOrganizationAsync(signup);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationRepository>().Received(1).CreateAsync(
|
||||
@ -66,7 +69,7 @@ public class CloudICloudOrganizationSignUpCommandTests
|
||||
sale.CustomerSetup.TokenizedPaymentSource.Token == signup.PaymentToken &&
|
||||
sale.CustomerSetup.TaxInformation.Country == signup.TaxInfo.BillingAddressCountry &&
|
||||
sale.CustomerSetup.TaxInformation.PostalCode == signup.TaxInfo.BillingAddressPostalCode &&
|
||||
sale.SubscriptionSetup.Plan == plan &&
|
||||
sale.SubscriptionSetup.PlanType == plan.Type &&
|
||||
sale.SubscriptionSetup.PasswordManagerOptions.Seats == signup.AdditionalSeats &&
|
||||
sale.SubscriptionSetup.PasswordManagerOptions.Storage == signup.AdditionalStorageGb &&
|
||||
sale.SubscriptionSetup.SecretsManagerOptions == null));
|
||||
@ -84,6 +87,8 @@ public class CloudICloudOrganizationSignUpCommandTests
|
||||
signup.UseSecretsManager = false;
|
||||
signup.IsFromProvider = false;
|
||||
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(signup.Plan).Returns(StaticStore.GetPlan(signup.Plan));
|
||||
|
||||
// Extract orgUserId when created
|
||||
Guid? orgUserId = null;
|
||||
await sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
@ -128,6 +133,7 @@ public class CloudICloudOrganizationSignUpCommandTests
|
||||
signup.IsFromSecretsManagerTrial = false;
|
||||
signup.IsFromProvider = false;
|
||||
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(signup.Plan).Returns(StaticStore.GetPlan(signup.Plan));
|
||||
|
||||
var result = await sutProvider.Sut.SignUpOrganizationAsync(signup);
|
||||
|
||||
@ -157,7 +163,7 @@ public class CloudICloudOrganizationSignUpCommandTests
|
||||
sale.CustomerSetup.TokenizedPaymentSource.Token == signup.PaymentToken &&
|
||||
sale.CustomerSetup.TaxInformation.Country == signup.TaxInfo.BillingAddressCountry &&
|
||||
sale.CustomerSetup.TaxInformation.PostalCode == signup.TaxInfo.BillingAddressPostalCode &&
|
||||
sale.SubscriptionSetup.Plan == plan &&
|
||||
sale.SubscriptionSetup.PlanType == plan.Type &&
|
||||
sale.SubscriptionSetup.PasswordManagerOptions.Seats == signup.AdditionalSeats &&
|
||||
sale.SubscriptionSetup.PasswordManagerOptions.Storage == signup.AdditionalStorageGb &&
|
||||
sale.SubscriptionSetup.SecretsManagerOptions.Seats == signup.AdditionalSmSeats &&
|
||||
@ -177,6 +183,8 @@ public class CloudICloudOrganizationSignUpCommandTests
|
||||
signup.PremiumAccessAddon = false;
|
||||
signup.IsFromProvider = true;
|
||||
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(signup.Plan).Returns(StaticStore.GetPlan(signup.Plan));
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.SignUpOrganizationAsync(signup));
|
||||
Assert.Contains("Organizations with a Managed Service Provider do not support Secrets Manager.", exception.Message);
|
||||
}
|
||||
@ -195,6 +203,8 @@ public class CloudICloudOrganizationSignUpCommandTests
|
||||
signup.AdditionalStorageGb = 0;
|
||||
signup.IsFromProvider = false;
|
||||
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(signup.Plan).Returns(StaticStore.GetPlan(signup.Plan));
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SignUpOrganizationAsync(signup));
|
||||
Assert.Contains("Plan does not allow additional Machine Accounts.", exception.Message);
|
||||
@ -213,6 +223,8 @@ public class CloudICloudOrganizationSignUpCommandTests
|
||||
signup.AdditionalServiceAccounts = 10;
|
||||
signup.IsFromProvider = false;
|
||||
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(signup.Plan).Returns(StaticStore.GetPlan(signup.Plan));
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SignUpOrganizationAsync(signup));
|
||||
Assert.Contains("You cannot have more Secrets Manager seats than Password Manager seats", exception.Message);
|
||||
@ -231,6 +243,8 @@ public class CloudICloudOrganizationSignUpCommandTests
|
||||
signup.AdditionalServiceAccounts = -10;
|
||||
signup.IsFromProvider = false;
|
||||
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(signup.Plan).Returns(StaticStore.GetPlan(signup.Plan));
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SignUpOrganizationAsync(signup));
|
||||
Assert.Contains("You can't subtract Machine Accounts!", exception.Message);
|
||||
@ -249,6 +263,8 @@ public class CloudICloudOrganizationSignUpCommandTests
|
||||
Owner = new User { Id = Guid.NewGuid() }
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(signup.Plan).Returns(StaticStore.GetPlan(signup.Plan));
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.GetCountByFreeOrganizationAdminUserAsync(signup.Owner.Id)
|
||||
.Returns(1);
|
||||
|
@ -0,0 +1,10 @@
|
||||
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
||||
|
||||
public static class PolicyDetailsTestExtensions
|
||||
{
|
||||
public static void SetDataModel<T>(this PolicyDetails policyDetails, T data) where T : IPolicyDataModel
|
||||
=> policyDetails.PolicyData = CoreHelpers.ClassToJsonData(data);
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
using AutoFixture.Xunit2;
|
||||
using Bit.Core.AdminConsole.Enums;
|
||||
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Test.AdminConsole.AutoFixture;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
||||
|
||||
public class SendPolicyRequirementTests
|
||||
{
|
||||
[Theory, AutoData]
|
||||
public void DisableSend_IsFalse_IfNoDisableSendPolicies(
|
||||
[PolicyDetails(PolicyType.RequireSso)] PolicyDetails otherPolicy1,
|
||||
[PolicyDetails(PolicyType.SendOptions)] PolicyDetails otherPolicy2)
|
||||
{
|
||||
EnableDisableHideEmail(otherPolicy2);
|
||||
|
||||
var actual = SendPolicyRequirement.Create([otherPolicy1, otherPolicy2]);
|
||||
|
||||
Assert.False(actual.DisableSend);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineAutoData(OrganizationUserType.Owner, false)]
|
||||
[InlineAutoData(OrganizationUserType.Admin, false)]
|
||||
[InlineAutoData(OrganizationUserType.User, true)]
|
||||
[InlineAutoData(OrganizationUserType.Custom, true)]
|
||||
public void DisableSend_TestRoles(
|
||||
OrganizationUserType userType,
|
||||
bool shouldBeEnforced,
|
||||
[PolicyDetails(PolicyType.DisableSend)] PolicyDetails policyDetails)
|
||||
{
|
||||
policyDetails.OrganizationUserType = userType;
|
||||
|
||||
var actual = SendPolicyRequirement.Create([policyDetails]);
|
||||
|
||||
Assert.Equal(shouldBeEnforced, actual.DisableSend);
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public void DisableSend_Not_EnforcedAgainstProviders(
|
||||
[PolicyDetails(PolicyType.DisableSend, isProvider: true)] PolicyDetails policyDetails)
|
||||
{
|
||||
var actual = SendPolicyRequirement.Create([policyDetails]);
|
||||
|
||||
Assert.False(actual.DisableSend);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineAutoData(OrganizationUserStatusType.Confirmed, true)]
|
||||
[InlineAutoData(OrganizationUserStatusType.Accepted, true)]
|
||||
[InlineAutoData(OrganizationUserStatusType.Invited, false)]
|
||||
[InlineAutoData(OrganizationUserStatusType.Revoked, false)]
|
||||
public void DisableSend_TestStatuses(
|
||||
OrganizationUserStatusType userStatus,
|
||||
bool shouldBeEnforced,
|
||||
[PolicyDetails(PolicyType.DisableSend)] PolicyDetails policyDetails)
|
||||
{
|
||||
policyDetails.OrganizationUserStatus = userStatus;
|
||||
|
||||
var actual = SendPolicyRequirement.Create([policyDetails]);
|
||||
|
||||
Assert.Equal(shouldBeEnforced, actual.DisableSend);
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public void DisableHideEmail_IsFalse_IfNoSendOptionsPolicies(
|
||||
[PolicyDetails(PolicyType.RequireSso)] PolicyDetails otherPolicy1,
|
||||
[PolicyDetails(PolicyType.DisableSend)] PolicyDetails otherPolicy2)
|
||||
{
|
||||
var actual = SendPolicyRequirement.Create([otherPolicy1, otherPolicy2]);
|
||||
|
||||
Assert.False(actual.DisableHideEmail);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineAutoData(OrganizationUserType.Owner, false)]
|
||||
[InlineAutoData(OrganizationUserType.Admin, false)]
|
||||
[InlineAutoData(OrganizationUserType.User, true)]
|
||||
[InlineAutoData(OrganizationUserType.Custom, true)]
|
||||
public void DisableHideEmail_TestRoles(
|
||||
OrganizationUserType userType,
|
||||
bool shouldBeEnforced,
|
||||
[PolicyDetails(PolicyType.SendOptions)] PolicyDetails policyDetails)
|
||||
{
|
||||
EnableDisableHideEmail(policyDetails);
|
||||
policyDetails.OrganizationUserType = userType;
|
||||
|
||||
var actual = SendPolicyRequirement.Create([policyDetails]);
|
||||
|
||||
Assert.Equal(shouldBeEnforced, actual.DisableHideEmail);
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public void DisableHideEmail_Not_EnforcedAgainstProviders(
|
||||
[PolicyDetails(PolicyType.SendOptions, isProvider: true)] PolicyDetails policyDetails)
|
||||
{
|
||||
EnableDisableHideEmail(policyDetails);
|
||||
|
||||
var actual = SendPolicyRequirement.Create([policyDetails]);
|
||||
|
||||
Assert.False(actual.DisableHideEmail);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineAutoData(OrganizationUserStatusType.Confirmed, true)]
|
||||
[InlineAutoData(OrganizationUserStatusType.Accepted, true)]
|
||||
[InlineAutoData(OrganizationUserStatusType.Invited, false)]
|
||||
[InlineAutoData(OrganizationUserStatusType.Revoked, false)]
|
||||
public void DisableHideEmail_TestStatuses(
|
||||
OrganizationUserStatusType userStatus,
|
||||
bool shouldBeEnforced,
|
||||
[PolicyDetails(PolicyType.SendOptions)] PolicyDetails policyDetails)
|
||||
{
|
||||
EnableDisableHideEmail(policyDetails);
|
||||
policyDetails.OrganizationUserStatus = userStatus;
|
||||
|
||||
var actual = SendPolicyRequirement.Create([policyDetails]);
|
||||
|
||||
Assert.Equal(shouldBeEnforced, actual.DisableHideEmail);
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public void DisableHideEmail_HandlesNullData(
|
||||
[PolicyDetails(PolicyType.SendOptions)] PolicyDetails policyDetails)
|
||||
{
|
||||
policyDetails.PolicyData = null;
|
||||
|
||||
var actual = SendPolicyRequirement.Create([policyDetails]);
|
||||
|
||||
Assert.False(actual.DisableHideEmail);
|
||||
}
|
||||
|
||||
private static void EnableDisableHideEmail(PolicyDetails policyDetails)
|
||||
=> policyDetails.SetDataModel(new SendOptionsPolicyData { DisableHideEmail = true });
|
||||
}
|
@ -9,6 +9,7 @@ using Bit.Core.AdminConsole.Services;
|
||||
using Bit.Core.Auth.Models.Business.Tokenables;
|
||||
using Bit.Core.Auth.UserFeatures.TwoFactorAuth.Interfaces;
|
||||
using Bit.Core.Billing.Enums;
|
||||
using Bit.Core.Billing.Pricing;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
@ -186,10 +187,12 @@ public class OrganizationServiceTests
|
||||
{
|
||||
signup.Plan = PlanType.TeamsMonthly;
|
||||
|
||||
var (organization, _, _) = await sutProvider.Sut.SignupClientAsync(signup);
|
||||
|
||||
var plan = StaticStore.GetPlan(signup.Plan);
|
||||
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(signup.Plan).Returns(plan);
|
||||
|
||||
var (organization, _, _) = await sutProvider.Sut.SignupClientAsync(signup);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationRepository>().Received(1).CreateAsync(Arg.Is<Organization>(org =>
|
||||
org.Id == organization.Id &&
|
||||
org.Name == signup.Name &&
|
||||
@ -733,6 +736,8 @@ public class OrganizationServiceTests
|
||||
SetupOrgUserRepositoryCreateManyAsyncMock(organizationUserRepository);
|
||||
SetupOrgUserRepositoryCreateAsyncMock(organizationUserRepository);
|
||||
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(organization.PlanType).Returns(StaticStore.GetPlan(organization.PlanType));
|
||||
|
||||
await sutProvider.Sut.InviteUsersAsync(organization.Id, savingUser.Id, systemUser: null, invites);
|
||||
|
||||
await sutProvider.GetDependency<IUpdateSecretsManagerSubscriptionCommand>().Received(1)
|
||||
@ -772,6 +777,9 @@ public class OrganizationServiceTests
|
||||
sutProvider.GetDependency<IReferenceEventService>().RaiseEventAsync(default)
|
||||
.ThrowsForAnyArgs<BadRequestException>();
|
||||
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(organization.PlanType)
|
||||
.Returns(StaticStore.GetPlan(organization.PlanType));
|
||||
|
||||
await Assert.ThrowsAsync<AggregateException>(async () =>
|
||||
await sutProvider.Sut.InviteUsersAsync(organization.Id, savingUser.Id, systemUser: null, invites));
|
||||
|
||||
@ -1179,6 +1187,9 @@ public class OrganizationServiceTests
|
||||
organization.MaxAutoscaleSeats = currentMaxAutoscaleSeats;
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(organization.PlanType)
|
||||
.Returns(StaticStore.GetPlan(organization.PlanType));
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.UpdateSubscription(organization.Id,
|
||||
seatAdjustment, maxAutoscaleSeats));
|
||||
|
||||
@ -1201,6 +1212,9 @@ public class OrganizationServiceTests
|
||||
organization.Seats = 100;
|
||||
organization.SmSeats = 100;
|
||||
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(organization.PlanType)
|
||||
.Returns(StaticStore.GetPlan(organization.PlanType));
|
||||
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
|
||||
var actual = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.UpdateSubscription(organization.Id, seatAdjustment, null));
|
||||
|
@ -19,6 +19,7 @@ using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Bit.Test.Common.Helpers;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
using GlobalSettings = Bit.Core.Settings.GlobalSettings;
|
||||
|
||||
#nullable enable
|
||||
|
||||
@ -138,7 +139,7 @@ public class AuthRequestServiceTests
|
||||
|
||||
sutProvider.GetDependency<IGlobalSettings>()
|
||||
.PasswordlessAuth
|
||||
.Returns(new Settings.GlobalSettings.PasswordlessAuthSettings());
|
||||
.Returns(new GlobalSettings.PasswordlessAuthSettings());
|
||||
|
||||
var foundAuthRequest = await sutProvider.Sut.GetValidatedAuthRequestAsync(authRequest.Id, authRequest.AccessCode);
|
||||
|
||||
@ -513,7 +514,7 @@ public class AuthRequestServiceTests
|
||||
|
||||
sutProvider.GetDependency<IGlobalSettings>()
|
||||
.PasswordlessAuth
|
||||
.Returns(new Settings.GlobalSettings.PasswordlessAuthSettings());
|
||||
.Returns(new GlobalSettings.PasswordlessAuthSettings());
|
||||
|
||||
var updateModel = new AuthRequestUpdateRequestModel
|
||||
{
|
||||
@ -582,7 +583,7 @@ public class AuthRequestServiceTests
|
||||
|
||||
sutProvider.GetDependency<IGlobalSettings>()
|
||||
.PasswordlessAuth
|
||||
.Returns(new Settings.GlobalSettings.PasswordlessAuthSettings());
|
||||
.Returns(new GlobalSettings.PasswordlessAuthSettings());
|
||||
|
||||
sutProvider.GetDependency<IDeviceRepository>()
|
||||
.GetByIdentifierAsync(device.Identifier, authRequest.UserId)
|
||||
@ -736,7 +737,7 @@ public class AuthRequestServiceTests
|
||||
|
||||
sutProvider.GetDependency<IGlobalSettings>()
|
||||
.PasswordlessAuth
|
||||
.Returns(new Settings.GlobalSettings.PasswordlessAuthSettings());
|
||||
.Returns(new GlobalSettings.PasswordlessAuthSettings());
|
||||
|
||||
var updateModel = new AuthRequestUpdateRequestModel
|
||||
{
|
||||
@ -803,7 +804,7 @@ public class AuthRequestServiceTests
|
||||
|
||||
sutProvider.GetDependency<IGlobalSettings>()
|
||||
.PasswordlessAuth
|
||||
.Returns(new Settings.GlobalSettings.PasswordlessAuthSettings());
|
||||
.Returns(new GlobalSettings.PasswordlessAuthSettings());
|
||||
|
||||
var updateModel = new AuthRequestUpdateRequestModel
|
||||
{
|
||||
|
@ -1,8 +1,10 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.Billing.Constants;
|
||||
using Bit.Core.Billing.Pricing;
|
||||
using Bit.Core.Billing.Services;
|
||||
using Bit.Core.Billing.Services.Implementations;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
@ -15,43 +17,6 @@ namespace Bit.Core.Test.Billing.Services;
|
||||
public class OrganizationBillingServiceTests
|
||||
{
|
||||
#region GetMetadata
|
||||
[Theory, BitAutoData]
|
||||
public async Task GetMetadata_OrganizationNull_ReturnsNull(
|
||||
Guid organizationId,
|
||||
SutProvider<OrganizationBillingService> sutProvider)
|
||||
{
|
||||
var metadata = await sutProvider.Sut.GetMetadata(organizationId);
|
||||
|
||||
Assert.Null(metadata);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task GetMetadata_CustomerNull_ReturnsNull(
|
||||
Guid organizationId,
|
||||
Organization organization,
|
||||
SutProvider<OrganizationBillingService> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organizationId).Returns(organization);
|
||||
|
||||
var metadata = await sutProvider.Sut.GetMetadata(organizationId);
|
||||
|
||||
Assert.False(metadata.IsOnSecretsManagerStandalone);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task GetMetadata_SubscriptionNull_ReturnsNull(
|
||||
Guid organizationId,
|
||||
Organization organization,
|
||||
SutProvider<OrganizationBillingService> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organizationId).Returns(organization);
|
||||
|
||||
sutProvider.GetDependency<ISubscriberService>().GetCustomer(organization).Returns(new Customer());
|
||||
|
||||
var metadata = await sutProvider.Sut.GetMetadata(organizationId);
|
||||
|
||||
Assert.False(metadata.IsOnSecretsManagerStandalone);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task GetMetadata_Succeeds(
|
||||
@ -61,6 +26,11 @@ public class OrganizationBillingServiceTests
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organizationId).Returns(organization);
|
||||
|
||||
sutProvider.GetDependency<IPricingClient>().ListPlans().Returns(StaticStore.Plans.ToList());
|
||||
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(organization.PlanType)
|
||||
.Returns(StaticStore.GetPlan(organization.PlanType));
|
||||
|
||||
var subscriberService = sutProvider.GetDependency<ISubscriberService>();
|
||||
|
||||
subscriberService
|
||||
@ -99,7 +69,8 @@ public class OrganizationBillingServiceTests
|
||||
|
||||
var metadata = await sutProvider.Sut.GetMetadata(organizationId);
|
||||
|
||||
Assert.True(metadata.IsOnSecretsManagerStandalone);
|
||||
Assert.True(metadata!.IsOnSecretsManagerStandalone);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ using Xunit;
|
||||
using static Bit.Core.Test.Billing.Utilities;
|
||||
using Address = Stripe.Address;
|
||||
using Customer = Stripe.Customer;
|
||||
using GlobalSettings = Bit.Core.Settings.GlobalSettings;
|
||||
using PaymentMethod = Stripe.PaymentMethod;
|
||||
using Subscription = Stripe.Subscription;
|
||||
|
||||
@ -1446,7 +1447,7 @@ public class SubscriberServiceTests
|
||||
});
|
||||
|
||||
sutProvider.GetDependency<IGlobalSettings>().BaseServiceUri
|
||||
.Returns(new Settings.GlobalSettings.BaseServiceUriSettings(new Settings.GlobalSettings())
|
||||
.Returns(new GlobalSettings.BaseServiceUriSettings(new GlobalSettings())
|
||||
{
|
||||
CloudRegion = "US"
|
||||
});
|
||||
@ -1488,7 +1489,7 @@ public class SubscriberServiceTests
|
||||
});
|
||||
|
||||
sutProvider.GetDependency<IGlobalSettings>().BaseServiceUri
|
||||
.Returns(new Settings.GlobalSettings.BaseServiceUriSettings(new Settings.GlobalSettings())
|
||||
.Returns(new GlobalSettings.BaseServiceUriSettings(new GlobalSettings())
|
||||
{
|
||||
CloudRegion = "US"
|
||||
});
|
||||
|
@ -12,19 +12,15 @@ namespace Bit.Core.Test.Models.Api.Request;
|
||||
public class PushSendRequestModelTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(null, null)]
|
||||
[InlineData(null, "")]
|
||||
[InlineData(null, " ")]
|
||||
[InlineData("", null)]
|
||||
[InlineData(" ", null)]
|
||||
[InlineData("", "")]
|
||||
[InlineData(" ", " ")]
|
||||
public void Validate_UserIdOrganizationIdNullOrEmpty_Invalid(string? userId, string? organizationId)
|
||||
[RepeatingPatternBitAutoData([null, "", " "], [null, "", " "], [null, "", " "])]
|
||||
public void Validate_UserIdOrganizationIdInstallationIdNullOrEmpty_Invalid(string? userId, string? organizationId,
|
||||
string? installationId)
|
||||
{
|
||||
var model = new PushSendRequestModel
|
||||
{
|
||||
UserId = userId,
|
||||
OrganizationId = organizationId,
|
||||
InstallationId = installationId,
|
||||
Type = PushType.SyncCiphers,
|
||||
Payload = "test"
|
||||
};
|
||||
@ -32,7 +28,65 @@ public class PushSendRequestModelTests
|
||||
var results = Validate(model);
|
||||
|
||||
Assert.Single(results);
|
||||
Assert.Contains(results, result => result.ErrorMessage == "UserId or OrganizationId is required.");
|
||||
Assert.Contains(results,
|
||||
result => result.ErrorMessage == "UserId or OrganizationId or InstallationId is required.");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[RepeatingPatternBitAutoData([null, "", " "], [null, "", " "])]
|
||||
public void Validate_UserIdProvidedOrganizationIdInstallationIdNullOrEmpty_Valid(string? organizationId,
|
||||
string? installationId)
|
||||
{
|
||||
var model = new PushSendRequestModel
|
||||
{
|
||||
UserId = Guid.NewGuid().ToString(),
|
||||
OrganizationId = organizationId,
|
||||
InstallationId = installationId,
|
||||
Type = PushType.SyncCiphers,
|
||||
Payload = "test"
|
||||
};
|
||||
|
||||
var results = Validate(model);
|
||||
|
||||
Assert.Empty(results);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[RepeatingPatternBitAutoData([null, "", " "], [null, "", " "])]
|
||||
public void Validate_OrganizationIdProvidedUserIdInstallationIdNullOrEmpty_Valid(string? userId,
|
||||
string? installationId)
|
||||
{
|
||||
var model = new PushSendRequestModel
|
||||
{
|
||||
UserId = userId,
|
||||
OrganizationId = Guid.NewGuid().ToString(),
|
||||
InstallationId = installationId,
|
||||
Type = PushType.SyncCiphers,
|
||||
Payload = "test"
|
||||
};
|
||||
|
||||
var results = Validate(model);
|
||||
|
||||
Assert.Empty(results);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[RepeatingPatternBitAutoData([null, "", " "], [null, "", " "])]
|
||||
public void Validate_InstallationIdProvidedUserIdOrganizationIdNullOrEmpty_Valid(string? userId,
|
||||
string? organizationId)
|
||||
{
|
||||
var model = new PushSendRequestModel
|
||||
{
|
||||
UserId = userId,
|
||||
OrganizationId = organizationId,
|
||||
InstallationId = Guid.NewGuid().ToString(),
|
||||
Type = PushType.SyncCiphers,
|
||||
Payload = "test"
|
||||
};
|
||||
|
||||
var results = Validate(model);
|
||||
|
||||
Assert.Empty(results);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
@ -43,7 +43,7 @@ public class CompleteSubscriptionUpdateTests
|
||||
PurchasedPasswordManagerSeats = 20
|
||||
};
|
||||
|
||||
var subscriptionUpdate = new CompleteSubscriptionUpdate(organization, updatedSubscriptionData);
|
||||
var subscriptionUpdate = new CompleteSubscriptionUpdate(organization, teamsStarterPlan, updatedSubscriptionData);
|
||||
|
||||
var upgradeItemOptions = subscriptionUpdate.UpgradeItemsOptions(subscription);
|
||||
|
||||
@ -114,7 +114,7 @@ public class CompleteSubscriptionUpdateTests
|
||||
PurchasedAdditionalStorage = 10
|
||||
};
|
||||
|
||||
var subscriptionUpdate = new CompleteSubscriptionUpdate(organization, updatedSubscriptionData);
|
||||
var subscriptionUpdate = new CompleteSubscriptionUpdate(organization, teamsMonthlyPlan, updatedSubscriptionData);
|
||||
|
||||
var upgradeItemOptions = subscriptionUpdate.UpgradeItemsOptions(subscription);
|
||||
|
||||
@ -221,7 +221,7 @@ public class CompleteSubscriptionUpdateTests
|
||||
PurchasedAdditionalStorage = 10
|
||||
};
|
||||
|
||||
var subscriptionUpdate = new CompleteSubscriptionUpdate(organization, updatedSubscriptionData);
|
||||
var subscriptionUpdate = new CompleteSubscriptionUpdate(organization, teamsMonthlyPlan, updatedSubscriptionData);
|
||||
|
||||
var upgradeItemOptions = subscriptionUpdate.UpgradeItemsOptions(subscription);
|
||||
|
||||
@ -302,7 +302,7 @@ public class CompleteSubscriptionUpdateTests
|
||||
PurchasedPasswordManagerSeats = 20
|
||||
};
|
||||
|
||||
var subscriptionUpdate = new CompleteSubscriptionUpdate(organization, updatedSubscriptionData);
|
||||
var subscriptionUpdate = new CompleteSubscriptionUpdate(organization, teamsStarterPlan, updatedSubscriptionData);
|
||||
|
||||
var revertItemOptions = subscriptionUpdate.RevertItemsOptions(subscription);
|
||||
|
||||
@ -372,7 +372,7 @@ public class CompleteSubscriptionUpdateTests
|
||||
PurchasedAdditionalStorage = 10
|
||||
};
|
||||
|
||||
var subscriptionUpdate = new CompleteSubscriptionUpdate(organization, updatedSubscriptionData);
|
||||
var subscriptionUpdate = new CompleteSubscriptionUpdate(organization, teamsMonthlyPlan, updatedSubscriptionData);
|
||||
|
||||
var revertItemOptions = subscriptionUpdate.RevertItemsOptions(subscription);
|
||||
|
||||
@ -478,7 +478,7 @@ public class CompleteSubscriptionUpdateTests
|
||||
PurchasedAdditionalStorage = 10
|
||||
};
|
||||
|
||||
var subscriptionUpdate = new CompleteSubscriptionUpdate(organization, updatedSubscriptionData);
|
||||
var subscriptionUpdate = new CompleteSubscriptionUpdate(organization, teamsMonthlyPlan, updatedSubscriptionData);
|
||||
|
||||
var revertItemOptions = subscriptionUpdate.RevertItemsOptions(subscription);
|
||||
|
||||
|
@ -2,7 +2,9 @@
|
||||
using Bit.Core.Billing.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Models.Business;
|
||||
using Bit.Core.Models.StaticStore;
|
||||
using Bit.Core.Test.AutoFixture.OrganizationFixtures;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Xunit;
|
||||
|
||||
@ -11,19 +13,40 @@ namespace Bit.Core.Test.Models.Business;
|
||||
[SecretsManagerOrganizationCustomize]
|
||||
public class SecretsManagerSubscriptionUpdateTests
|
||||
{
|
||||
private static TheoryData<Plan> ToPlanTheory(List<PlanType> types)
|
||||
{
|
||||
var theoryData = new TheoryData<Plan>();
|
||||
var plans = types.Select(StaticStore.GetPlan).ToArray();
|
||||
theoryData.AddRange(plans);
|
||||
return theoryData;
|
||||
}
|
||||
|
||||
public static TheoryData<Plan> NonSmPlans =>
|
||||
ToPlanTheory([PlanType.Custom, PlanType.FamiliesAnnually, PlanType.FamiliesAnnually2019]);
|
||||
|
||||
public static TheoryData<Plan> SmPlans => ToPlanTheory([
|
||||
PlanType.EnterpriseAnnually2019,
|
||||
PlanType.EnterpriseAnnually,
|
||||
PlanType.TeamsMonthly2019,
|
||||
PlanType.TeamsAnnually2020,
|
||||
PlanType.TeamsMonthly,
|
||||
PlanType.TeamsAnnually2019,
|
||||
PlanType.TeamsAnnually2020,
|
||||
PlanType.TeamsAnnually,
|
||||
PlanType.TeamsStarter
|
||||
]);
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(PlanType.Custom)]
|
||||
[BitAutoData(PlanType.FamiliesAnnually)]
|
||||
[BitAutoData(PlanType.FamiliesAnnually2019)]
|
||||
[BitMemberAutoData(nameof(NonSmPlans))]
|
||||
public Task UpdateSubscriptionAsync_WithNonSecretsManagerPlanType_ThrowsBadRequestException(
|
||||
PlanType planType,
|
||||
Plan plan,
|
||||
Organization organization)
|
||||
{
|
||||
// Arrange
|
||||
organization.PlanType = planType;
|
||||
organization.PlanType = plan.Type;
|
||||
|
||||
// Act
|
||||
var exception = Assert.Throws<NotFoundException>(() => new SecretsManagerSubscriptionUpdate(organization, false));
|
||||
var exception = Assert.Throws<NotFoundException>(() => new SecretsManagerSubscriptionUpdate(organization, plan, false));
|
||||
|
||||
// Assert
|
||||
Assert.Contains("Invalid Secrets Manager plan", exception.Message, StringComparison.InvariantCultureIgnoreCase);
|
||||
@ -31,28 +54,16 @@ public class SecretsManagerSubscriptionUpdateTests
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(PlanType.EnterpriseMonthly2019)]
|
||||
[BitAutoData(PlanType.EnterpriseMonthly2020)]
|
||||
[BitAutoData(PlanType.EnterpriseMonthly)]
|
||||
[BitAutoData(PlanType.EnterpriseAnnually2019)]
|
||||
[BitAutoData(PlanType.EnterpriseAnnually2020)]
|
||||
[BitAutoData(PlanType.EnterpriseAnnually)]
|
||||
[BitAutoData(PlanType.TeamsMonthly2019)]
|
||||
[BitAutoData(PlanType.TeamsMonthly2020)]
|
||||
[BitAutoData(PlanType.TeamsMonthly)]
|
||||
[BitAutoData(PlanType.TeamsAnnually2019)]
|
||||
[BitAutoData(PlanType.TeamsAnnually2020)]
|
||||
[BitAutoData(PlanType.TeamsAnnually)]
|
||||
[BitAutoData(PlanType.TeamsStarter)]
|
||||
[BitMemberAutoData(nameof(SmPlans))]
|
||||
public void UpdateSubscription_WithNonSecretsManagerPlanType_DoesNotThrowException(
|
||||
PlanType planType,
|
||||
Plan plan,
|
||||
Organization organization)
|
||||
{
|
||||
// Arrange
|
||||
organization.PlanType = planType;
|
||||
organization.PlanType = plan.Type;
|
||||
|
||||
// Act
|
||||
var ex = Record.Exception(() => new SecretsManagerSubscriptionUpdate(organization, false));
|
||||
var ex = Record.Exception(() => new SecretsManagerSubscriptionUpdate(organization, plan, false));
|
||||
|
||||
// Assert
|
||||
Assert.Null(ex);
|
||||
|
@ -69,4 +69,19 @@ public class CreateNotificationCommandTest
|
||||
.Received(0)
|
||||
.PushNotificationStatusAsync(Arg.Any<Notification>(), Arg.Any<NotificationStatus>());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task CreateAsync_Authorized_NotificationPushSkipped(
|
||||
SutProvider<CreateNotificationCommand> sutProvider,
|
||||
Notification notification)
|
||||
{
|
||||
Setup(sutProvider, notification, true);
|
||||
|
||||
var newNotification = await sutProvider.Sut.CreateAsync(notification, false);
|
||||
|
||||
await sutProvider.GetDependency<IPushNotificationService>()
|
||||
.Received(0)
|
||||
.PushNotificationAsync(newNotification);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Core.NotificationHub;
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Core.Utilities;
|
||||
using Xunit;
|
||||
|
||||
|
@ -6,6 +6,7 @@ using Bit.Core.Models.Data;
|
||||
using Bit.Core.NotificationCenter.Entities;
|
||||
using Bit.Core.NotificationHub;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Core.Test.NotificationCenter.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
@ -21,9 +22,11 @@ public class NotificationHubPushNotificationServiceTests
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
[NotificationCustomize]
|
||||
public async Task PushNotificationAsync_Global_NotSent(
|
||||
public async Task PushNotificationAsync_GlobalInstallationIdDefault_NotSent(
|
||||
SutProvider<NotificationHubPushNotificationService> sutProvider, Notification notification)
|
||||
{
|
||||
sutProvider.GetDependency<IGlobalSettings>().Installation.Id = default;
|
||||
|
||||
await sutProvider.Sut.PushNotificationAsync(notification);
|
||||
|
||||
await sutProvider.GetDependency<INotificationHubPool>()
|
||||
@ -36,6 +39,50 @@ public class NotificationHubPushNotificationServiceTests
|
||||
.UpsertAsync(Arg.Any<InstallationDeviceEntity>());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
[NotificationCustomize]
|
||||
public async Task PushNotificationAsync_GlobalInstallationIdSetClientTypeAll_SentToInstallationId(
|
||||
SutProvider<NotificationHubPushNotificationService> sutProvider, Notification notification, Guid installationId)
|
||||
{
|
||||
sutProvider.GetDependency<IGlobalSettings>().Installation.Id = installationId;
|
||||
notification.ClientType = ClientType.All;
|
||||
var expectedNotification = ToNotificationPushNotification(notification, null, installationId);
|
||||
|
||||
await sutProvider.Sut.PushNotificationAsync(notification);
|
||||
|
||||
await AssertSendTemplateNotificationAsync(sutProvider, PushType.Notification,
|
||||
expectedNotification,
|
||||
$"(template:payload && installationId:{installationId})");
|
||||
await sutProvider.GetDependency<IInstallationDeviceRepository>()
|
||||
.Received(0)
|
||||
.UpsertAsync(Arg.Any<InstallationDeviceEntity>());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(ClientType.Browser)]
|
||||
[BitAutoData(ClientType.Desktop)]
|
||||
[BitAutoData(ClientType.Web)]
|
||||
[BitAutoData(ClientType.Mobile)]
|
||||
[NotificationCustomize]
|
||||
public async Task PushNotificationAsync_GlobalInstallationIdSetClientTypeNotAll_SentToInstallationIdAndClientType(
|
||||
ClientType clientType, SutProvider<NotificationHubPushNotificationService> sutProvider,
|
||||
Notification notification, Guid installationId)
|
||||
{
|
||||
sutProvider.GetDependency<IGlobalSettings>().Installation.Id = installationId;
|
||||
notification.ClientType = clientType;
|
||||
var expectedNotification = ToNotificationPushNotification(notification, null, installationId);
|
||||
|
||||
await sutProvider.Sut.PushNotificationAsync(notification);
|
||||
|
||||
await AssertSendTemplateNotificationAsync(sutProvider, PushType.Notification,
|
||||
expectedNotification,
|
||||
$"(template:payload && installationId:{installationId} && clientType:{clientType})");
|
||||
await sutProvider.GetDependency<IInstallationDeviceRepository>()
|
||||
.Received(0)
|
||||
.UpsertAsync(Arg.Any<InstallationDeviceEntity>());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(false)]
|
||||
[BitAutoData(true)]
|
||||
@ -50,11 +97,11 @@ public class NotificationHubPushNotificationServiceTests
|
||||
}
|
||||
|
||||
notification.ClientType = ClientType.All;
|
||||
var expectedNotification = ToNotificationPushNotification(notification, null);
|
||||
var expectedNotification = ToNotificationPushNotification(notification, null, null);
|
||||
|
||||
await sutProvider.Sut.PushNotificationAsync(notification);
|
||||
|
||||
await AssertSendTemplateNotificationAsync(sutProvider, PushType.SyncNotification,
|
||||
await AssertSendTemplateNotificationAsync(sutProvider, PushType.Notification,
|
||||
expectedNotification,
|
||||
$"(template:payload_userId:{notification.UserId})");
|
||||
await sutProvider.GetDependency<IInstallationDeviceRepository>()
|
||||
@ -74,11 +121,11 @@ public class NotificationHubPushNotificationServiceTests
|
||||
{
|
||||
notification.OrganizationId = null;
|
||||
notification.ClientType = clientType;
|
||||
var expectedNotification = ToNotificationPushNotification(notification, null);
|
||||
var expectedNotification = ToNotificationPushNotification(notification, null, null);
|
||||
|
||||
await sutProvider.Sut.PushNotificationAsync(notification);
|
||||
|
||||
await AssertSendTemplateNotificationAsync(sutProvider, PushType.SyncNotification,
|
||||
await AssertSendTemplateNotificationAsync(sutProvider, PushType.Notification,
|
||||
expectedNotification,
|
||||
$"(template:payload_userId:{notification.UserId} && clientType:{clientType})");
|
||||
await sutProvider.GetDependency<IInstallationDeviceRepository>()
|
||||
@ -97,11 +144,11 @@ public class NotificationHubPushNotificationServiceTests
|
||||
Notification notification)
|
||||
{
|
||||
notification.ClientType = clientType;
|
||||
var expectedNotification = ToNotificationPushNotification(notification, null);
|
||||
var expectedNotification = ToNotificationPushNotification(notification, null, null);
|
||||
|
||||
await sutProvider.Sut.PushNotificationAsync(notification);
|
||||
|
||||
await AssertSendTemplateNotificationAsync(sutProvider, PushType.SyncNotification,
|
||||
await AssertSendTemplateNotificationAsync(sutProvider, PushType.Notification,
|
||||
expectedNotification,
|
||||
$"(template:payload_userId:{notification.UserId} && clientType:{clientType})");
|
||||
await sutProvider.GetDependency<IInstallationDeviceRepository>()
|
||||
@ -117,11 +164,11 @@ public class NotificationHubPushNotificationServiceTests
|
||||
{
|
||||
notification.UserId = null;
|
||||
notification.ClientType = ClientType.All;
|
||||
var expectedNotification = ToNotificationPushNotification(notification, null);
|
||||
var expectedNotification = ToNotificationPushNotification(notification, null, null);
|
||||
|
||||
await sutProvider.Sut.PushNotificationAsync(notification);
|
||||
|
||||
await AssertSendTemplateNotificationAsync(sutProvider, PushType.SyncNotification,
|
||||
await AssertSendTemplateNotificationAsync(sutProvider, PushType.Notification,
|
||||
expectedNotification,
|
||||
$"(template:payload && organizationId:{notification.OrganizationId})");
|
||||
await sutProvider.GetDependency<IInstallationDeviceRepository>()
|
||||
@ -141,11 +188,11 @@ public class NotificationHubPushNotificationServiceTests
|
||||
{
|
||||
notification.UserId = null;
|
||||
notification.ClientType = clientType;
|
||||
var expectedNotification = ToNotificationPushNotification(notification, null);
|
||||
var expectedNotification = ToNotificationPushNotification(notification, null, null);
|
||||
|
||||
await sutProvider.Sut.PushNotificationAsync(notification);
|
||||
|
||||
await AssertSendTemplateNotificationAsync(sutProvider, PushType.SyncNotification,
|
||||
await AssertSendTemplateNotificationAsync(sutProvider, PushType.Notification,
|
||||
expectedNotification,
|
||||
$"(template:payload && organizationId:{notification.OrganizationId} && clientType:{clientType})");
|
||||
await sutProvider.GetDependency<IInstallationDeviceRepository>()
|
||||
@ -156,10 +203,12 @@ public class NotificationHubPushNotificationServiceTests
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
[NotificationCustomize]
|
||||
public async Task PushNotificationStatusAsync_Global_NotSent(
|
||||
public async Task PushNotificationStatusAsync_GlobalInstallationIdDefault_NotSent(
|
||||
SutProvider<NotificationHubPushNotificationService> sutProvider, Notification notification,
|
||||
NotificationStatus notificationStatus)
|
||||
{
|
||||
sutProvider.GetDependency<IGlobalSettings>().Installation.Id = default;
|
||||
|
||||
await sutProvider.Sut.PushNotificationStatusAsync(notification, notificationStatus);
|
||||
|
||||
await sutProvider.GetDependency<INotificationHubPool>()
|
||||
@ -172,6 +221,54 @@ public class NotificationHubPushNotificationServiceTests
|
||||
.UpsertAsync(Arg.Any<InstallationDeviceEntity>());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
[NotificationCustomize]
|
||||
public async Task PushNotificationStatusAsync_GlobalInstallationIdSetClientTypeAll_SentToInstallationId(
|
||||
SutProvider<NotificationHubPushNotificationService> sutProvider,
|
||||
Notification notification, NotificationStatus notificationStatus, Guid installationId)
|
||||
{
|
||||
sutProvider.GetDependency<IGlobalSettings>().Installation.Id = installationId;
|
||||
notification.ClientType = ClientType.All;
|
||||
|
||||
var expectedNotification = ToNotificationPushNotification(notification, notificationStatus, installationId);
|
||||
|
||||
await sutProvider.Sut.PushNotificationStatusAsync(notification, notificationStatus);
|
||||
|
||||
await AssertSendTemplateNotificationAsync(sutProvider, PushType.NotificationStatus,
|
||||
expectedNotification,
|
||||
$"(template:payload && installationId:{installationId})");
|
||||
await sutProvider.GetDependency<IInstallationDeviceRepository>()
|
||||
.Received(0)
|
||||
.UpsertAsync(Arg.Any<InstallationDeviceEntity>());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(ClientType.Browser)]
|
||||
[BitAutoData(ClientType.Desktop)]
|
||||
[BitAutoData(ClientType.Web)]
|
||||
[BitAutoData(ClientType.Mobile)]
|
||||
[NotificationCustomize]
|
||||
public async Task
|
||||
PushNotificationStatusAsync_GlobalInstallationIdSetClientTypeNotAll_SentToInstallationIdAndClientType(
|
||||
ClientType clientType, SutProvider<NotificationHubPushNotificationService> sutProvider,
|
||||
Notification notification, NotificationStatus notificationStatus, Guid installationId)
|
||||
{
|
||||
sutProvider.GetDependency<IGlobalSettings>().Installation.Id = installationId;
|
||||
notification.ClientType = clientType;
|
||||
|
||||
var expectedNotification = ToNotificationPushNotification(notification, notificationStatus, installationId);
|
||||
|
||||
await sutProvider.Sut.PushNotificationStatusAsync(notification, notificationStatus);
|
||||
|
||||
await AssertSendTemplateNotificationAsync(sutProvider, PushType.NotificationStatus,
|
||||
expectedNotification,
|
||||
$"(template:payload && installationId:{installationId} && clientType:{clientType})");
|
||||
await sutProvider.GetDependency<IInstallationDeviceRepository>()
|
||||
.Received(0)
|
||||
.UpsertAsync(Arg.Any<InstallationDeviceEntity>());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(false)]
|
||||
[BitAutoData(true)]
|
||||
@ -186,11 +283,11 @@ public class NotificationHubPushNotificationServiceTests
|
||||
}
|
||||
|
||||
notification.ClientType = ClientType.All;
|
||||
var expectedNotification = ToNotificationPushNotification(notification, notificationStatus);
|
||||
var expectedNotification = ToNotificationPushNotification(notification, notificationStatus, null);
|
||||
|
||||
await sutProvider.Sut.PushNotificationStatusAsync(notification, notificationStatus);
|
||||
|
||||
await AssertSendTemplateNotificationAsync(sutProvider, PushType.SyncNotificationStatus,
|
||||
await AssertSendTemplateNotificationAsync(sutProvider, PushType.NotificationStatus,
|
||||
expectedNotification,
|
||||
$"(template:payload_userId:{notification.UserId})");
|
||||
await sutProvider.GetDependency<IInstallationDeviceRepository>()
|
||||
@ -210,11 +307,11 @@ public class NotificationHubPushNotificationServiceTests
|
||||
{
|
||||
notification.OrganizationId = null;
|
||||
notification.ClientType = clientType;
|
||||
var expectedNotification = ToNotificationPushNotification(notification, notificationStatus);
|
||||
var expectedNotification = ToNotificationPushNotification(notification, notificationStatus, null);
|
||||
|
||||
await sutProvider.Sut.PushNotificationStatusAsync(notification, notificationStatus);
|
||||
|
||||
await AssertSendTemplateNotificationAsync(sutProvider, PushType.SyncNotificationStatus,
|
||||
await AssertSendTemplateNotificationAsync(sutProvider, PushType.NotificationStatus,
|
||||
expectedNotification,
|
||||
$"(template:payload_userId:{notification.UserId} && clientType:{clientType})");
|
||||
await sutProvider.GetDependency<IInstallationDeviceRepository>()
|
||||
@ -233,11 +330,11 @@ public class NotificationHubPushNotificationServiceTests
|
||||
Notification notification, NotificationStatus notificationStatus)
|
||||
{
|
||||
notification.ClientType = clientType;
|
||||
var expectedNotification = ToNotificationPushNotification(notification, notificationStatus);
|
||||
var expectedNotification = ToNotificationPushNotification(notification, notificationStatus, null);
|
||||
|
||||
await sutProvider.Sut.PushNotificationStatusAsync(notification, notificationStatus);
|
||||
|
||||
await AssertSendTemplateNotificationAsync(sutProvider, PushType.SyncNotificationStatus,
|
||||
await AssertSendTemplateNotificationAsync(sutProvider, PushType.NotificationStatus,
|
||||
expectedNotification,
|
||||
$"(template:payload_userId:{notification.UserId} && clientType:{clientType})");
|
||||
await sutProvider.GetDependency<IInstallationDeviceRepository>()
|
||||
@ -254,11 +351,11 @@ public class NotificationHubPushNotificationServiceTests
|
||||
{
|
||||
notification.UserId = null;
|
||||
notification.ClientType = ClientType.All;
|
||||
var expectedNotification = ToNotificationPushNotification(notification, notificationStatus);
|
||||
var expectedNotification = ToNotificationPushNotification(notification, notificationStatus, null);
|
||||
|
||||
await sutProvider.Sut.PushNotificationStatusAsync(notification, notificationStatus);
|
||||
|
||||
await AssertSendTemplateNotificationAsync(sutProvider, PushType.SyncNotificationStatus,
|
||||
await AssertSendTemplateNotificationAsync(sutProvider, PushType.NotificationStatus,
|
||||
expectedNotification,
|
||||
$"(template:payload && organizationId:{notification.OrganizationId})");
|
||||
await sutProvider.GetDependency<IInstallationDeviceRepository>()
|
||||
@ -279,11 +376,11 @@ public class NotificationHubPushNotificationServiceTests
|
||||
{
|
||||
notification.UserId = null;
|
||||
notification.ClientType = clientType;
|
||||
var expectedNotification = ToNotificationPushNotification(notification, notificationStatus);
|
||||
var expectedNotification = ToNotificationPushNotification(notification, notificationStatus, null);
|
||||
|
||||
await sutProvider.Sut.PushNotificationStatusAsync(notification, notificationStatus);
|
||||
|
||||
await AssertSendTemplateNotificationAsync(sutProvider, PushType.SyncNotificationStatus,
|
||||
await AssertSendTemplateNotificationAsync(sutProvider, PushType.NotificationStatus,
|
||||
expectedNotification,
|
||||
$"(template:payload && organizationId:{notification.OrganizationId} && clientType:{clientType})");
|
||||
await sutProvider.GetDependency<IInstallationDeviceRepository>()
|
||||
@ -363,8 +460,44 @@ public class NotificationHubPushNotificationServiceTests
|
||||
.UpsertAsync(Arg.Any<InstallationDeviceEntity>());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData([null])]
|
||||
[BitAutoData(ClientType.All)]
|
||||
public async Task SendPayloadToInstallationAsync_ClientTypeNullOrAll_SentToInstallation(ClientType? clientType,
|
||||
SutProvider<NotificationHubPushNotificationService> sutProvider, Guid installationId, PushType pushType,
|
||||
string payload, string identifier)
|
||||
{
|
||||
await sutProvider.Sut.SendPayloadToInstallationAsync(installationId.ToString(), pushType, payload, identifier,
|
||||
null, clientType);
|
||||
|
||||
await AssertSendTemplateNotificationAsync(sutProvider, pushType, payload,
|
||||
$"(template:payload && installationId:{installationId} && !deviceIdentifier:{identifier})");
|
||||
await sutProvider.GetDependency<IInstallationDeviceRepository>()
|
||||
.Received(0)
|
||||
.UpsertAsync(Arg.Any<InstallationDeviceEntity>());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(ClientType.Browser)]
|
||||
[BitAutoData(ClientType.Desktop)]
|
||||
[BitAutoData(ClientType.Mobile)]
|
||||
[BitAutoData(ClientType.Web)]
|
||||
public async Task SendPayloadToInstallationAsync_ClientTypeExplicit_SentToInstallationAndClientType(
|
||||
ClientType clientType, SutProvider<NotificationHubPushNotificationService> sutProvider, Guid installationId,
|
||||
PushType pushType, string payload, string identifier)
|
||||
{
|
||||
await sutProvider.Sut.SendPayloadToInstallationAsync(installationId.ToString(), pushType, payload, identifier,
|
||||
null, clientType);
|
||||
|
||||
await AssertSendTemplateNotificationAsync(sutProvider, pushType, payload,
|
||||
$"(template:payload && installationId:{installationId} && !deviceIdentifier:{identifier} && clientType:{clientType})");
|
||||
await sutProvider.GetDependency<IInstallationDeviceRepository>()
|
||||
.Received(0)
|
||||
.UpsertAsync(Arg.Any<InstallationDeviceEntity>());
|
||||
}
|
||||
|
||||
private static NotificationPushNotification ToNotificationPushNotification(Notification notification,
|
||||
NotificationStatus? notificationStatus) =>
|
||||
NotificationStatus? notificationStatus, Guid? installationId) =>
|
||||
new()
|
||||
{
|
||||
Id = notification.Id,
|
||||
@ -373,6 +506,7 @@ public class NotificationHubPushNotificationServiceTests
|
||||
ClientType = notification.ClientType,
|
||||
UserId = notification.UserId,
|
||||
OrganizationId = notification.OrganizationId,
|
||||
InstallationId = installationId,
|
||||
Title = notification.Title,
|
||||
Body = notification.Body,
|
||||
CreationDate = notification.CreationDate,
|
||||
|
@ -14,15 +14,13 @@ namespace Bit.Core.Test.NotificationHub;
|
||||
public class NotificationHubPushRegistrationServiceTests
|
||||
{
|
||||
[Theory]
|
||||
[BitAutoData([null])]
|
||||
[BitAutoData("")]
|
||||
[BitAutoData(" ")]
|
||||
[RepeatingPatternBitAutoData([null, "", " "])]
|
||||
public async Task CreateOrUpdateRegistrationAsync_PushTokenNullOrEmpty_InstallationNotCreated(string? pushToken,
|
||||
SutProvider<NotificationHubPushRegistrationService> sutProvider, Guid deviceId, Guid userId, Guid identifier,
|
||||
Guid organizationId)
|
||||
Guid organizationId, Guid installationId)
|
||||
{
|
||||
await sutProvider.Sut.CreateOrUpdateRegistrationAsync(pushToken, deviceId.ToString(), userId.ToString(),
|
||||
identifier.ToString(), DeviceType.Android, [organizationId.ToString()]);
|
||||
await sutProvider.Sut.CreateOrUpdateRegistrationAsync(new PushRegistrationData(pushToken), deviceId.ToString(), userId.ToString(),
|
||||
identifier.ToString(), DeviceType.Android, [organizationId.ToString()], installationId);
|
||||
|
||||
sutProvider.GetDependency<INotificationHubPool>()
|
||||
.Received(0)
|
||||
@ -30,22 +28,21 @@ public class NotificationHubPushRegistrationServiceTests
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(false, false)]
|
||||
[BitAutoData(false, true)]
|
||||
[BitAutoData(true, false)]
|
||||
[BitAutoData(true, true)]
|
||||
[RepeatingPatternBitAutoData([false, true], [false, true], [false, true])]
|
||||
public async Task CreateOrUpdateRegistrationAsync_DeviceTypeAndroid_InstallationCreated(bool identifierNull,
|
||||
bool partOfOrganizationId, SutProvider<NotificationHubPushRegistrationService> sutProvider, Guid deviceId,
|
||||
Guid userId, Guid? identifier, Guid organizationId)
|
||||
bool partOfOrganizationId, bool installationIdNull,
|
||||
SutProvider<NotificationHubPushRegistrationService> sutProvider, Guid deviceId, Guid userId, Guid? identifier,
|
||||
Guid organizationId, Guid installationId)
|
||||
{
|
||||
var notificationHubClient = Substitute.For<INotificationHubClient>();
|
||||
sutProvider.GetDependency<INotificationHubPool>().ClientFor(Arg.Any<Guid>()).Returns(notificationHubClient);
|
||||
|
||||
var pushToken = "test push token";
|
||||
|
||||
await sutProvider.Sut.CreateOrUpdateRegistrationAsync(pushToken, deviceId.ToString(), userId.ToString(),
|
||||
await sutProvider.Sut.CreateOrUpdateRegistrationAsync(new PushRegistrationData(pushToken), deviceId.ToString(), userId.ToString(),
|
||||
identifierNull ? null : identifier.ToString(), DeviceType.Android,
|
||||
partOfOrganizationId ? [organizationId.ToString()] : []);
|
||||
partOfOrganizationId ? [organizationId.ToString()] : [],
|
||||
installationIdNull ? Guid.Empty : installationId);
|
||||
|
||||
sutProvider.GetDependency<INotificationHubPool>()
|
||||
.Received(1)
|
||||
@ -60,6 +57,7 @@ public class NotificationHubPushRegistrationServiceTests
|
||||
installation.Tags.Contains("clientType:Mobile") &&
|
||||
(identifierNull || installation.Tags.Contains($"deviceIdentifier:{identifier}")) &&
|
||||
(!partOfOrganizationId || installation.Tags.Contains($"organizationId:{organizationId}")) &&
|
||||
(installationIdNull || installation.Tags.Contains($"installationId:{installationId}")) &&
|
||||
installation.Templates.Count == 3));
|
||||
await notificationHubClient
|
||||
.Received(1)
|
||||
@ -73,6 +71,7 @@ public class NotificationHubPushRegistrationServiceTests
|
||||
"clientType:Mobile",
|
||||
identifierNull ? null : $"template:payload_deviceIdentifier:{identifier}",
|
||||
partOfOrganizationId ? $"organizationId:{organizationId}" : null,
|
||||
installationIdNull ? null : $"installationId:{installationId}",
|
||||
})));
|
||||
await notificationHubClient
|
||||
.Received(1)
|
||||
@ -86,6 +85,7 @@ public class NotificationHubPushRegistrationServiceTests
|
||||
"clientType:Mobile",
|
||||
identifierNull ? null : $"template:message_deviceIdentifier:{identifier}",
|
||||
partOfOrganizationId ? $"organizationId:{organizationId}" : null,
|
||||
installationIdNull ? null : $"installationId:{installationId}",
|
||||
})));
|
||||
await notificationHubClient
|
||||
.Received(1)
|
||||
@ -99,26 +99,26 @@ public class NotificationHubPushRegistrationServiceTests
|
||||
"clientType:Mobile",
|
||||
identifierNull ? null : $"template:badgeMessage_deviceIdentifier:{identifier}",
|
||||
partOfOrganizationId ? $"organizationId:{organizationId}" : null,
|
||||
installationIdNull ? null : $"installationId:{installationId}",
|
||||
})));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(false, false)]
|
||||
[BitAutoData(false, true)]
|
||||
[BitAutoData(true, false)]
|
||||
[BitAutoData(true, true)]
|
||||
[RepeatingPatternBitAutoData([false, true], [false, true], [false, true])]
|
||||
public async Task CreateOrUpdateRegistrationAsync_DeviceTypeIOS_InstallationCreated(bool identifierNull,
|
||||
bool partOfOrganizationId, SutProvider<NotificationHubPushRegistrationService> sutProvider, Guid deviceId,
|
||||
Guid userId, Guid identifier, Guid organizationId)
|
||||
bool partOfOrganizationId, bool installationIdNull,
|
||||
SutProvider<NotificationHubPushRegistrationService> sutProvider, Guid deviceId, Guid userId, Guid identifier,
|
||||
Guid organizationId, Guid installationId)
|
||||
{
|
||||
var notificationHubClient = Substitute.For<INotificationHubClient>();
|
||||
sutProvider.GetDependency<INotificationHubPool>().ClientFor(Arg.Any<Guid>()).Returns(notificationHubClient);
|
||||
|
||||
var pushToken = "test push token";
|
||||
|
||||
await sutProvider.Sut.CreateOrUpdateRegistrationAsync(pushToken, deviceId.ToString(), userId.ToString(),
|
||||
await sutProvider.Sut.CreateOrUpdateRegistrationAsync(new PushRegistrationData(pushToken), deviceId.ToString(), userId.ToString(),
|
||||
identifierNull ? null : identifier.ToString(), DeviceType.iOS,
|
||||
partOfOrganizationId ? [organizationId.ToString()] : []);
|
||||
partOfOrganizationId ? [organizationId.ToString()] : [],
|
||||
installationIdNull ? Guid.Empty : installationId);
|
||||
|
||||
sutProvider.GetDependency<INotificationHubPool>()
|
||||
.Received(1)
|
||||
@ -133,6 +133,7 @@ public class NotificationHubPushRegistrationServiceTests
|
||||
installation.Tags.Contains("clientType:Mobile") &&
|
||||
(identifierNull || installation.Tags.Contains($"deviceIdentifier:{identifier}")) &&
|
||||
(!partOfOrganizationId || installation.Tags.Contains($"organizationId:{organizationId}")) &&
|
||||
(installationIdNull || installation.Tags.Contains($"installationId:{installationId}")) &&
|
||||
installation.Templates.Count == 3));
|
||||
await notificationHubClient
|
||||
.Received(1)
|
||||
@ -146,6 +147,7 @@ public class NotificationHubPushRegistrationServiceTests
|
||||
"clientType:Mobile",
|
||||
identifierNull ? null : $"template:payload_deviceIdentifier:{identifier}",
|
||||
partOfOrganizationId ? $"organizationId:{organizationId}" : null,
|
||||
installationIdNull ? null : $"installationId:{installationId}",
|
||||
})));
|
||||
await notificationHubClient
|
||||
.Received(1)
|
||||
@ -159,6 +161,7 @@ public class NotificationHubPushRegistrationServiceTests
|
||||
"clientType:Mobile",
|
||||
identifierNull ? null : $"template:message_deviceIdentifier:{identifier}",
|
||||
partOfOrganizationId ? $"organizationId:{organizationId}" : null,
|
||||
installationIdNull ? null : $"installationId:{installationId}",
|
||||
})));
|
||||
await notificationHubClient
|
||||
.Received(1)
|
||||
@ -172,26 +175,26 @@ public class NotificationHubPushRegistrationServiceTests
|
||||
"clientType:Mobile",
|
||||
identifierNull ? null : $"template:badgeMessage_deviceIdentifier:{identifier}",
|
||||
partOfOrganizationId ? $"organizationId:{organizationId}" : null,
|
||||
installationIdNull ? null : $"installationId:{installationId}",
|
||||
})));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(false, false)]
|
||||
[BitAutoData(false, true)]
|
||||
[BitAutoData(true, false)]
|
||||
[BitAutoData(true, true)]
|
||||
[RepeatingPatternBitAutoData([false, true], [false, true], [false, true])]
|
||||
public async Task CreateOrUpdateRegistrationAsync_DeviceTypeAndroidAmazon_InstallationCreated(bool identifierNull,
|
||||
bool partOfOrganizationId, SutProvider<NotificationHubPushRegistrationService> sutProvider, Guid deviceId,
|
||||
Guid userId, Guid identifier, Guid organizationId)
|
||||
bool partOfOrganizationId, bool installationIdNull,
|
||||
SutProvider<NotificationHubPushRegistrationService> sutProvider, Guid deviceId,
|
||||
Guid userId, Guid identifier, Guid organizationId, Guid installationId)
|
||||
{
|
||||
var notificationHubClient = Substitute.For<INotificationHubClient>();
|
||||
sutProvider.GetDependency<INotificationHubPool>().ClientFor(Arg.Any<Guid>()).Returns(notificationHubClient);
|
||||
|
||||
var pushToken = "test push token";
|
||||
|
||||
await sutProvider.Sut.CreateOrUpdateRegistrationAsync(pushToken, deviceId.ToString(), userId.ToString(),
|
||||
await sutProvider.Sut.CreateOrUpdateRegistrationAsync(new PushRegistrationData(pushToken), deviceId.ToString(), userId.ToString(),
|
||||
identifierNull ? null : identifier.ToString(), DeviceType.AndroidAmazon,
|
||||
partOfOrganizationId ? [organizationId.ToString()] : []);
|
||||
partOfOrganizationId ? [organizationId.ToString()] : [],
|
||||
installationIdNull ? Guid.Empty : installationId);
|
||||
|
||||
sutProvider.GetDependency<INotificationHubPool>()
|
||||
.Received(1)
|
||||
@ -206,6 +209,7 @@ public class NotificationHubPushRegistrationServiceTests
|
||||
installation.Tags.Contains("clientType:Mobile") &&
|
||||
(identifierNull || installation.Tags.Contains($"deviceIdentifier:{identifier}")) &&
|
||||
(!partOfOrganizationId || installation.Tags.Contains($"organizationId:{organizationId}")) &&
|
||||
(installationIdNull || installation.Tags.Contains($"installationId:{installationId}")) &&
|
||||
installation.Templates.Count == 3));
|
||||
await notificationHubClient
|
||||
.Received(1)
|
||||
@ -219,6 +223,7 @@ public class NotificationHubPushRegistrationServiceTests
|
||||
"clientType:Mobile",
|
||||
identifierNull ? null : $"template:payload_deviceIdentifier:{identifier}",
|
||||
partOfOrganizationId ? $"organizationId:{organizationId}" : null,
|
||||
installationIdNull ? null : $"installationId:{installationId}",
|
||||
})));
|
||||
await notificationHubClient
|
||||
.Received(1)
|
||||
@ -232,6 +237,7 @@ public class NotificationHubPushRegistrationServiceTests
|
||||
"clientType:Mobile",
|
||||
identifierNull ? null : $"template:message_deviceIdentifier:{identifier}",
|
||||
partOfOrganizationId ? $"organizationId:{organizationId}" : null,
|
||||
installationIdNull ? null : $"installationId:{installationId}",
|
||||
})));
|
||||
await notificationHubClient
|
||||
.Received(1)
|
||||
@ -245,6 +251,7 @@ public class NotificationHubPushRegistrationServiceTests
|
||||
"clientType:Mobile",
|
||||
identifierNull ? null : $"template:badgeMessage_deviceIdentifier:{identifier}",
|
||||
partOfOrganizationId ? $"organizationId:{organizationId}" : null,
|
||||
installationIdNull ? null : $"installationId:{installationId}",
|
||||
})));
|
||||
}
|
||||
|
||||
@ -254,15 +261,15 @@ public class NotificationHubPushRegistrationServiceTests
|
||||
[BitAutoData(DeviceType.MacOsDesktop)]
|
||||
public async Task CreateOrUpdateRegistrationAsync_DeviceTypeNotMobile_InstallationCreated(DeviceType deviceType,
|
||||
SutProvider<NotificationHubPushRegistrationService> sutProvider, Guid deviceId, Guid userId, Guid identifier,
|
||||
Guid organizationId)
|
||||
Guid organizationId, Guid installationId)
|
||||
{
|
||||
var notificationHubClient = Substitute.For<INotificationHubClient>();
|
||||
sutProvider.GetDependency<INotificationHubPool>().ClientFor(Arg.Any<Guid>()).Returns(notificationHubClient);
|
||||
|
||||
var pushToken = "test push token";
|
||||
|
||||
await sutProvider.Sut.CreateOrUpdateRegistrationAsync(pushToken, deviceId.ToString(), userId.ToString(),
|
||||
identifier.ToString(), deviceType, [organizationId.ToString()]);
|
||||
await sutProvider.Sut.CreateOrUpdateRegistrationAsync(new PushRegistrationData(pushToken), deviceId.ToString(), userId.ToString(),
|
||||
identifier.ToString(), deviceType, [organizationId.ToString()], installationId);
|
||||
|
||||
sutProvider.GetDependency<INotificationHubPool>()
|
||||
.Received(1)
|
||||
@ -276,6 +283,7 @@ public class NotificationHubPushRegistrationServiceTests
|
||||
installation.Tags.Contains($"clientType:{DeviceTypes.ToClientType(deviceType)}") &&
|
||||
installation.Tags.Contains($"deviceIdentifier:{identifier}") &&
|
||||
installation.Tags.Contains($"organizationId:{organizationId}") &&
|
||||
installation.Tags.Contains($"installationId:{installationId}") &&
|
||||
installation.Templates.Count == 0));
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ using Bit.Core.AdminConsole.Entities.Provider;
|
||||
using Bit.Core.AdminConsole.Enums.Provider;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
using Bit.Core.Billing.Enums;
|
||||
using Bit.Core.Billing.Pricing;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Models.Business;
|
||||
using Bit.Core.Models.StaticStore;
|
||||
@ -41,7 +42,8 @@ public class AddSecretsManagerSubscriptionCommandTests
|
||||
{
|
||||
organization.PlanType = planType;
|
||||
|
||||
var plan = StaticStore.Plans.FirstOrDefault(p => p.Type == organization.PlanType);
|
||||
var plan = StaticStore.GetPlan(organization.PlanType);
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(organization.PlanType).Returns(plan);
|
||||
|
||||
await sutProvider.Sut.SignUpAsync(organization, additionalSmSeats, additionalServiceAccounts);
|
||||
|
||||
@ -85,6 +87,8 @@ public class AddSecretsManagerSubscriptionCommandTests
|
||||
{
|
||||
organization.GatewayCustomerId = null;
|
||||
organization.PlanType = PlanType.EnterpriseAnnually;
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(organization.PlanType)
|
||||
.Returns(StaticStore.GetPlan(organization.PlanType));
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.SignUpAsync(organization, additionalSmSeats, additionalServiceAccounts));
|
||||
Assert.Contains("No payment method found.", exception.Message);
|
||||
@ -101,6 +105,8 @@ public class AddSecretsManagerSubscriptionCommandTests
|
||||
{
|
||||
organization.GatewaySubscriptionId = null;
|
||||
organization.PlanType = PlanType.EnterpriseAnnually;
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(organization.PlanType)
|
||||
.Returns(StaticStore.GetPlan(organization.PlanType));
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.SignUpAsync(organization, additionalSmSeats, additionalServiceAccounts));
|
||||
Assert.Contains("No subscription found.", exception.Message);
|
||||
@ -132,6 +138,8 @@ public class AddSecretsManagerSubscriptionCommandTests
|
||||
organization.UseSecretsManager = false;
|
||||
provider.Type = ProviderType.Msp;
|
||||
sutProvider.GetDependency<IProviderRepository>().GetByOrganizationIdAsync(organization.Id).Returns(provider);
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(organization.PlanType)
|
||||
.Returns(StaticStore.GetPlan(organization.PlanType));
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SignUpAsync(organization, 10, 10));
|
||||
|
@ -21,26 +21,48 @@ namespace Bit.Core.Test.OrganizationFeatures.OrganizationSubscriptionUpdate;
|
||||
[SecretsManagerOrganizationCustomize]
|
||||
public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
{
|
||||
private static TheoryData<Plan> ToPlanTheory(List<PlanType> types)
|
||||
{
|
||||
var theoryData = new TheoryData<Plan>();
|
||||
var plans = types.Select(StaticStore.GetPlan).ToArray();
|
||||
theoryData.AddRange(plans);
|
||||
return theoryData;
|
||||
}
|
||||
|
||||
public static TheoryData<Plan> AllTeamsAndEnterprise
|
||||
=> ToPlanTheory([
|
||||
PlanType.EnterpriseAnnually2019,
|
||||
PlanType.EnterpriseAnnually2020,
|
||||
PlanType.EnterpriseAnnually,
|
||||
PlanType.EnterpriseMonthly2019,
|
||||
PlanType.EnterpriseMonthly2020,
|
||||
PlanType.EnterpriseMonthly,
|
||||
PlanType.TeamsMonthly2019,
|
||||
PlanType.TeamsMonthly2020,
|
||||
PlanType.TeamsMonthly,
|
||||
PlanType.TeamsAnnually2019,
|
||||
PlanType.TeamsAnnually2020,
|
||||
PlanType.TeamsAnnually,
|
||||
PlanType.TeamsStarter
|
||||
]);
|
||||
|
||||
public static TheoryData<Plan> CurrentTeamsAndEnterprise
|
||||
=> ToPlanTheory([
|
||||
PlanType.EnterpriseAnnually,
|
||||
PlanType.EnterpriseMonthly,
|
||||
PlanType.TeamsMonthly,
|
||||
PlanType.TeamsAnnually,
|
||||
PlanType.TeamsStarter
|
||||
]);
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(PlanType.EnterpriseAnnually2019)]
|
||||
[BitAutoData(PlanType.EnterpriseAnnually2020)]
|
||||
[BitAutoData(PlanType.EnterpriseAnnually)]
|
||||
[BitAutoData(PlanType.EnterpriseMonthly2019)]
|
||||
[BitAutoData(PlanType.EnterpriseMonthly2020)]
|
||||
[BitAutoData(PlanType.EnterpriseMonthly)]
|
||||
[BitAutoData(PlanType.TeamsMonthly2019)]
|
||||
[BitAutoData(PlanType.TeamsMonthly2020)]
|
||||
[BitAutoData(PlanType.TeamsMonthly)]
|
||||
[BitAutoData(PlanType.TeamsAnnually2019)]
|
||||
[BitAutoData(PlanType.TeamsAnnually2020)]
|
||||
[BitAutoData(PlanType.TeamsAnnually)]
|
||||
[BitAutoData(PlanType.TeamsStarter)]
|
||||
[BitMemberAutoData(nameof(AllTeamsAndEnterprise))]
|
||||
public async Task UpdateSubscriptionAsync_UpdateEverything_ValidInput_Passes(
|
||||
PlanType planType,
|
||||
Plan plan,
|
||||
Organization organization,
|
||||
SutProvider<UpdateSecretsManagerSubscriptionCommand> sutProvider)
|
||||
{
|
||||
organization.PlanType = planType;
|
||||
organization.PlanType = plan.Type;
|
||||
organization.Seats = 400;
|
||||
organization.SmSeats = 10;
|
||||
organization.MaxAutoscaleSmSeats = 20;
|
||||
@ -52,7 +74,7 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
var updateMaxAutoscaleSmSeats = 16;
|
||||
var updateMaxAutoscaleSmServiceAccounts = 301;
|
||||
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, false)
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, plan, false)
|
||||
{
|
||||
SmSeats = updateSmSeats,
|
||||
SmServiceAccounts = updateSmServiceAccounts,
|
||||
@ -62,7 +84,6 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
|
||||
await sutProvider.Sut.UpdateSubscriptionAsync(update);
|
||||
|
||||
var plan = StaticStore.GetPlan(organization.PlanType);
|
||||
await sutProvider.GetDependency<IPaymentService>().Received(1)
|
||||
.AdjustSmSeatsAsync(organization, plan, update.SmSeatsExcludingBase);
|
||||
await sutProvider.GetDependency<IPaymentService>().Received(1)
|
||||
@ -83,17 +104,13 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(PlanType.EnterpriseAnnually)]
|
||||
[BitAutoData(PlanType.EnterpriseMonthly)]
|
||||
[BitAutoData(PlanType.TeamsMonthly)]
|
||||
[BitAutoData(PlanType.TeamsAnnually)]
|
||||
[BitAutoData(PlanType.TeamsStarter)]
|
||||
[BitMemberAutoData(nameof(CurrentTeamsAndEnterprise))]
|
||||
public async Task UpdateSubscriptionAsync_ValidInput_WithNullMaxAutoscale_Passes(
|
||||
PlanType planType,
|
||||
Plan plan,
|
||||
Organization organization,
|
||||
SutProvider<UpdateSecretsManagerSubscriptionCommand> sutProvider)
|
||||
{
|
||||
organization.PlanType = planType;
|
||||
organization.PlanType = plan.Type;
|
||||
organization.Seats = 20;
|
||||
|
||||
const int updateSmSeats = 15;
|
||||
@ -102,7 +119,7 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
// Ensure that SmSeats is different from the original organization.SmSeats
|
||||
organization.SmSeats = updateSmSeats + 5;
|
||||
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, false)
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, plan, false)
|
||||
{
|
||||
SmSeats = updateSmSeats,
|
||||
MaxAutoscaleSmSeats = null,
|
||||
@ -112,7 +129,6 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
|
||||
await sutProvider.Sut.UpdateSubscriptionAsync(update);
|
||||
|
||||
var plan = StaticStore.GetPlan(organization.PlanType);
|
||||
await sutProvider.GetDependency<IPaymentService>().Received(1)
|
||||
.AdjustSmSeatsAsync(organization, plan, update.SmSeatsExcludingBase);
|
||||
await sutProvider.GetDependency<IPaymentService>().Received(1)
|
||||
@ -141,7 +157,8 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
Organization organization,
|
||||
SutProvider<UpdateSecretsManagerSubscriptionCommand> sutProvider)
|
||||
{
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, autoscaling).AdjustSeats(2);
|
||||
var plan = StaticStore.GetPlan(organization.PlanType);
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, plan, autoscaling).AdjustSeats(2);
|
||||
|
||||
sutProvider.GetDependency<IGlobalSettings>().SelfHosted.Returns(true);
|
||||
|
||||
@ -156,8 +173,10 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
SutProvider<UpdateSecretsManagerSubscriptionCommand> sutProvider,
|
||||
Organization organization)
|
||||
{
|
||||
var plan = StaticStore.GetPlan(organization.PlanType);
|
||||
|
||||
organization.UseSecretsManager = false;
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, false);
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, plan, false);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.UpdateSubscriptionAsync(update));
|
||||
@ -167,27 +186,16 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(PlanType.EnterpriseAnnually2019)]
|
||||
[BitAutoData(PlanType.EnterpriseAnnually2020)]
|
||||
[BitAutoData(PlanType.EnterpriseAnnually)]
|
||||
[BitAutoData(PlanType.EnterpriseMonthly2019)]
|
||||
[BitAutoData(PlanType.EnterpriseMonthly2020)]
|
||||
[BitAutoData(PlanType.EnterpriseMonthly)]
|
||||
[BitAutoData(PlanType.TeamsMonthly2019)]
|
||||
[BitAutoData(PlanType.TeamsMonthly2020)]
|
||||
[BitAutoData(PlanType.TeamsMonthly)]
|
||||
[BitAutoData(PlanType.TeamsAnnually2019)]
|
||||
[BitAutoData(PlanType.TeamsAnnually2020)]
|
||||
[BitAutoData(PlanType.TeamsAnnually)]
|
||||
[BitAutoData(PlanType.TeamsStarter)]
|
||||
[BitMemberAutoData(nameof(AllTeamsAndEnterprise))]
|
||||
public async Task UpdateSubscriptionAsync_PaidPlan_NullGatewayCustomerId_ThrowsException(
|
||||
PlanType planType,
|
||||
Plan plan,
|
||||
Organization organization,
|
||||
SutProvider<UpdateSecretsManagerSubscriptionCommand> sutProvider)
|
||||
{
|
||||
organization.PlanType = planType;
|
||||
organization.PlanType = plan.Type;
|
||||
organization.GatewayCustomerId = null;
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, false).AdjustSeats(1);
|
||||
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, plan, false).AdjustSeats(1);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.UpdateSubscriptionAsync(update));
|
||||
Assert.Contains("No payment method found.", exception.Message);
|
||||
@ -195,27 +203,15 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(PlanType.EnterpriseAnnually2019)]
|
||||
[BitAutoData(PlanType.EnterpriseAnnually2020)]
|
||||
[BitAutoData(PlanType.EnterpriseAnnually)]
|
||||
[BitAutoData(PlanType.EnterpriseMonthly2019)]
|
||||
[BitAutoData(PlanType.EnterpriseMonthly2020)]
|
||||
[BitAutoData(PlanType.EnterpriseMonthly)]
|
||||
[BitAutoData(PlanType.TeamsMonthly2019)]
|
||||
[BitAutoData(PlanType.TeamsMonthly2020)]
|
||||
[BitAutoData(PlanType.TeamsMonthly)]
|
||||
[BitAutoData(PlanType.TeamsAnnually2019)]
|
||||
[BitAutoData(PlanType.TeamsAnnually2020)]
|
||||
[BitAutoData(PlanType.TeamsAnnually)]
|
||||
[BitAutoData(PlanType.TeamsStarter)]
|
||||
[BitMemberAutoData(nameof(AllTeamsAndEnterprise))]
|
||||
public async Task UpdateSubscriptionAsync_PaidPlan_NullGatewaySubscriptionId_ThrowsException(
|
||||
PlanType planType,
|
||||
Plan plan,
|
||||
Organization organization,
|
||||
SutProvider<UpdateSecretsManagerSubscriptionCommand> sutProvider)
|
||||
{
|
||||
organization.PlanType = planType;
|
||||
organization.PlanType = plan.Type;
|
||||
organization.GatewaySubscriptionId = null;
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, false).AdjustSeats(1);
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, plan, false).AdjustSeats(1);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.UpdateSubscriptionAsync(update));
|
||||
Assert.Contains("No subscription found.", exception.Message);
|
||||
@ -223,24 +219,12 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(PlanType.EnterpriseAnnually2019)]
|
||||
[BitAutoData(PlanType.EnterpriseAnnually2020)]
|
||||
[BitAutoData(PlanType.EnterpriseAnnually)]
|
||||
[BitAutoData(PlanType.EnterpriseMonthly2019)]
|
||||
[BitAutoData(PlanType.EnterpriseMonthly2020)]
|
||||
[BitAutoData(PlanType.EnterpriseMonthly)]
|
||||
[BitAutoData(PlanType.TeamsMonthly2019)]
|
||||
[BitAutoData(PlanType.TeamsMonthly2020)]
|
||||
[BitAutoData(PlanType.TeamsMonthly)]
|
||||
[BitAutoData(PlanType.TeamsAnnually2019)]
|
||||
[BitAutoData(PlanType.TeamsAnnually2020)]
|
||||
[BitAutoData(PlanType.TeamsAnnually)]
|
||||
[BitAutoData(PlanType.TeamsStarter)]
|
||||
public async Task AdjustServiceAccountsAsync_WithEnterpriseOrTeamsPlans_Success(PlanType planType, Guid organizationId,
|
||||
[BitMemberAutoData(nameof(AllTeamsAndEnterprise))]
|
||||
public async Task AdjustServiceAccountsAsync_WithEnterpriseOrTeamsPlans_Success(
|
||||
Plan plan,
|
||||
Guid organizationId,
|
||||
SutProvider<UpdateSecretsManagerSubscriptionCommand> sutProvider)
|
||||
{
|
||||
var plan = StaticStore.GetPlan(planType);
|
||||
|
||||
var organizationSeats = plan.SecretsManager.BaseSeats + 10;
|
||||
var organizationMaxAutoscaleSeats = 20;
|
||||
var organizationServiceAccounts = plan.SecretsManager.BaseServiceAccount + 10;
|
||||
@ -249,7 +233,7 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
var organization = new Organization
|
||||
{
|
||||
Id = organizationId,
|
||||
PlanType = planType,
|
||||
PlanType = plan.Type,
|
||||
GatewayCustomerId = "1",
|
||||
GatewaySubscriptionId = "2",
|
||||
UseSecretsManager = true,
|
||||
@ -263,7 +247,7 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
var expectedSmServiceAccounts = organizationServiceAccounts + smServiceAccountsAdjustment;
|
||||
var expectedSmServiceAccountsExcludingBase = expectedSmServiceAccounts - plan.SecretsManager.BaseServiceAccount;
|
||||
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, false).AdjustServiceAccounts(10);
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, plan, false).AdjustServiceAccounts(10);
|
||||
|
||||
await sutProvider.Sut.UpdateSubscriptionAsync(update);
|
||||
|
||||
@ -290,8 +274,9 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
|
||||
// Make sure Password Manager seats is greater or equal to Secrets Manager seats
|
||||
organization.Seats = seatCount;
|
||||
var plan = StaticStore.GetPlan(organization.PlanType);
|
||||
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, false)
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, plan, false)
|
||||
{
|
||||
SmSeats = seatCount,
|
||||
MaxAutoscaleSmSeats = seatCount
|
||||
@ -310,7 +295,8 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
SutProvider<UpdateSecretsManagerSubscriptionCommand> sutProvider)
|
||||
{
|
||||
organization.SmSeats = null;
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, false).AdjustSeats(1);
|
||||
var plan = StaticStore.GetPlan(organization.PlanType);
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, plan, false).AdjustSeats(1);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.UpdateSubscriptionAsync(update));
|
||||
@ -325,7 +311,8 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
Organization organization,
|
||||
SutProvider<UpdateSecretsManagerSubscriptionCommand> sutProvider)
|
||||
{
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, true).AdjustSeats(-2);
|
||||
var plan = StaticStore.GetPlan(organization.PlanType);
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, plan, true).AdjustSeats(-2);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.UpdateSubscriptionAsync(update));
|
||||
Assert.Contains("Cannot use autoscaling to subtract seats.", exception.Message);
|
||||
@ -340,7 +327,8 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
SutProvider<UpdateSecretsManagerSubscriptionCommand> sutProvider)
|
||||
{
|
||||
organization.PlanType = planType;
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, false).AdjustSeats(1);
|
||||
var plan = StaticStore.GetPlan(organization.PlanType);
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, plan, false).AdjustSeats(1);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.UpdateSubscriptionAsync(update));
|
||||
Assert.Contains("You have reached the maximum number of Secrets Manager seats (2) for this plan",
|
||||
@ -357,7 +345,8 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
organization.SmSeats = 9;
|
||||
organization.MaxAutoscaleSmSeats = 10;
|
||||
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, true).AdjustSeats(2);
|
||||
var plan = StaticStore.GetPlan(organization.PlanType);
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, plan, true).AdjustSeats(2);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.UpdateSubscriptionAsync(update));
|
||||
Assert.Contains("Secrets Manager seat limit has been reached.", exception.Message);
|
||||
@ -370,7 +359,8 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
Organization organization,
|
||||
SutProvider<UpdateSecretsManagerSubscriptionCommand> sutProvider)
|
||||
{
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, false)
|
||||
var plan = StaticStore.GetPlan(organization.PlanType);
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, plan, false)
|
||||
{
|
||||
SmSeats = organization.SmSeats + 10,
|
||||
MaxAutoscaleSmSeats = organization.SmSeats + 5
|
||||
@ -388,7 +378,8 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
Organization organization,
|
||||
SutProvider<UpdateSecretsManagerSubscriptionCommand> sutProvider)
|
||||
{
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, false)
|
||||
var plan = StaticStore.GetPlan(organization.PlanType);
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, plan, false)
|
||||
{
|
||||
SmSeats = 0,
|
||||
};
|
||||
@ -407,7 +398,8 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
SutProvider<UpdateSecretsManagerSubscriptionCommand> sutProvider)
|
||||
{
|
||||
organization.SmSeats = 8;
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, false)
|
||||
var plan = StaticStore.GetPlan(organization.PlanType);
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, plan, false)
|
||||
{
|
||||
SmSeats = 7,
|
||||
};
|
||||
@ -425,7 +417,8 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
Organization organization,
|
||||
SutProvider<UpdateSecretsManagerSubscriptionCommand> sutProvider)
|
||||
{
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, false)
|
||||
var plan = StaticStore.GetPlan(organization.PlanType);
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, plan, false)
|
||||
{
|
||||
SmServiceAccounts = 300,
|
||||
MaxAutoscaleSmServiceAccounts = 300
|
||||
@ -444,7 +437,8 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
SutProvider<UpdateSecretsManagerSubscriptionCommand> sutProvider)
|
||||
{
|
||||
organization.SmServiceAccounts = null;
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, false).AdjustServiceAccounts(1);
|
||||
var plan = StaticStore.GetPlan(organization.PlanType);
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, plan, false).AdjustServiceAccounts(1);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.UpdateSubscriptionAsync(update));
|
||||
Assert.Contains("Organization has no machine accounts limit, no need to adjust machine accounts", exception.Message);
|
||||
@ -457,7 +451,8 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
Organization organization,
|
||||
SutProvider<UpdateSecretsManagerSubscriptionCommand> sutProvider)
|
||||
{
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, true).AdjustServiceAccounts(-2);
|
||||
var plan = StaticStore.GetPlan(organization.PlanType);
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, plan, true).AdjustServiceAccounts(-2);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.UpdateSubscriptionAsync(update));
|
||||
Assert.Contains("Cannot use autoscaling to subtract machine accounts.", exception.Message);
|
||||
@ -472,7 +467,8 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
SutProvider<UpdateSecretsManagerSubscriptionCommand> sutProvider)
|
||||
{
|
||||
organization.PlanType = planType;
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, false).AdjustServiceAccounts(1);
|
||||
var plan = StaticStore.GetPlan(organization.PlanType);
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, plan, false).AdjustServiceAccounts(1);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.UpdateSubscriptionAsync(update));
|
||||
Assert.Contains("You have reached the maximum number of machine accounts (3) for this plan",
|
||||
@ -489,7 +485,8 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
organization.SmServiceAccounts = 9;
|
||||
organization.MaxAutoscaleSmServiceAccounts = 10;
|
||||
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, true).AdjustServiceAccounts(2);
|
||||
var plan = StaticStore.GetPlan(organization.PlanType);
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, plan, true).AdjustServiceAccounts(2);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.UpdateSubscriptionAsync(update));
|
||||
Assert.Contains("Secrets Manager machine account limit has been reached.", exception.Message);
|
||||
@ -508,7 +505,8 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
organization.SmServiceAccounts = smServiceAccount - 5;
|
||||
organization.MaxAutoscaleSmServiceAccounts = 2 * smServiceAccount;
|
||||
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, false)
|
||||
var plan = StaticStore.GetPlan(organization.PlanType);
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, plan, false)
|
||||
{
|
||||
SmServiceAccounts = smServiceAccount,
|
||||
MaxAutoscaleSmServiceAccounts = maxAutoscaleSmServiceAccounts
|
||||
@ -530,7 +528,8 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
|
||||
organization.SmServiceAccounts = newSmServiceAccounts - 10;
|
||||
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, false)
|
||||
var plan = StaticStore.GetPlan(organization.PlanType);
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, plan, false)
|
||||
{
|
||||
SmServiceAccounts = newSmServiceAccounts,
|
||||
};
|
||||
@ -542,28 +541,16 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(PlanType.EnterpriseAnnually2019)]
|
||||
[BitAutoData(PlanType.EnterpriseAnnually2020)]
|
||||
[BitAutoData(PlanType.EnterpriseAnnually)]
|
||||
[BitAutoData(PlanType.EnterpriseMonthly2019)]
|
||||
[BitAutoData(PlanType.EnterpriseMonthly2020)]
|
||||
[BitAutoData(PlanType.EnterpriseMonthly)]
|
||||
[BitAutoData(PlanType.TeamsMonthly2019)]
|
||||
[BitAutoData(PlanType.TeamsMonthly2020)]
|
||||
[BitAutoData(PlanType.TeamsMonthly)]
|
||||
[BitAutoData(PlanType.TeamsAnnually2019)]
|
||||
[BitAutoData(PlanType.TeamsAnnually2020)]
|
||||
[BitAutoData(PlanType.TeamsAnnually)]
|
||||
[BitAutoData(PlanType.TeamsStarter)]
|
||||
[BitMemberAutoData(nameof(AllTeamsAndEnterprise))]
|
||||
public async Task UpdateSmServiceAccounts_WhenCurrentServiceAccountsIsGreaterThanNew_ThrowsBadRequestException(
|
||||
PlanType planType,
|
||||
Plan plan,
|
||||
Organization organization,
|
||||
SutProvider<UpdateSecretsManagerSubscriptionCommand> sutProvider)
|
||||
{
|
||||
var currentServiceAccounts = 301;
|
||||
organization.PlanType = planType;
|
||||
organization.PlanType = plan.Type;
|
||||
organization.SmServiceAccounts = currentServiceAccounts;
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, false) { SmServiceAccounts = 201 };
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, plan, false) { SmServiceAccounts = 201 };
|
||||
|
||||
sutProvider.GetDependency<IServiceAccountRepository>()
|
||||
.GetServiceAccountCountByOrganizationIdAsync(organization.Id)
|
||||
@ -586,7 +573,8 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
organization.SmSeats = smSeats - 1;
|
||||
organization.MaxAutoscaleSmSeats = smSeats * 2;
|
||||
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, false)
|
||||
var plan = StaticStore.GetPlan(organization.PlanType);
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, plan, false)
|
||||
{
|
||||
SmSeats = smSeats,
|
||||
MaxAutoscaleSmSeats = maxAutoscaleSmSeats
|
||||
@ -606,7 +594,8 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
{
|
||||
organization.PlanType = planType;
|
||||
organization.SmSeats = 2;
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, false)
|
||||
var plan = StaticStore.GetPlan(organization.PlanType);
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, plan, false)
|
||||
{
|
||||
MaxAutoscaleSmSeats = 3
|
||||
};
|
||||
@ -625,7 +614,8 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
{
|
||||
organization.PlanType = planType;
|
||||
organization.SmSeats = 2;
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, false)
|
||||
var plan = StaticStore.GetPlan(organization.PlanType);
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, plan, false)
|
||||
{
|
||||
MaxAutoscaleSmSeats = 2
|
||||
};
|
||||
@ -645,7 +635,8 @@ public class UpdateSecretsManagerSubscriptionCommandTests
|
||||
organization.PlanType = planType;
|
||||
organization.SmServiceAccounts = 3;
|
||||
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, false) { MaxAutoscaleSmServiceAccounts = 3 };
|
||||
var plan = StaticStore.GetPlan(organization.PlanType);
|
||||
var update = new SecretsManagerSubscriptionUpdate(organization, plan, false) { MaxAutoscaleSmServiceAccounts = 3 };
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.UpdateSubscriptionAsync(update));
|
||||
Assert.Contains("Your plan does not allow machine accounts autoscaling.", exception.Message);
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Bit.Core.Billing.Enums;
|
||||
using Bit.Core.Billing.Pricing;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Models.Business;
|
||||
using Bit.Core.OrganizationFeatures.OrganizationSubscriptions;
|
||||
@ -43,6 +44,7 @@ public class UpgradeOrganizationPlanCommandTests
|
||||
SutProvider<UpgradeOrganizationPlanCommand> sutProvider)
|
||||
{
|
||||
upgrade.Plan = organization.PlanType;
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(organization.PlanType).Returns(StaticStore.GetPlan(organization.PlanType));
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.UpgradePlanAsync(organization.Id, upgrade));
|
||||
@ -58,6 +60,7 @@ public class UpgradeOrganizationPlanCommandTests
|
||||
upgrade.AdditionalSmSeats = 10;
|
||||
upgrade.AdditionalServiceAccounts = 10;
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(organization.PlanType).Returns(StaticStore.GetPlan(organization.PlanType));
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.UpgradePlanAsync(organization.Id, upgrade));
|
||||
Assert.Contains("already on this plan", exception.Message);
|
||||
@ -69,9 +72,11 @@ public class UpgradeOrganizationPlanCommandTests
|
||||
SutProvider<UpgradeOrganizationPlanCommand> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(organization.PlanType).Returns(StaticStore.GetPlan(organization.PlanType));
|
||||
upgrade.AdditionalSmSeats = 10;
|
||||
upgrade.AdditionalSeats = 10;
|
||||
upgrade.Plan = PlanType.TeamsAnnually;
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(upgrade.Plan).Returns(StaticStore.GetPlan(upgrade.Plan));
|
||||
await sutProvider.Sut.UpgradePlanAsync(organization.Id, upgrade);
|
||||
await sutProvider.GetDependency<IOrganizationService>().Received(1).ReplaceAndUpdateCacheAsync(organization);
|
||||
}
|
||||
@ -92,6 +97,8 @@ public class UpgradeOrganizationPlanCommandTests
|
||||
|
||||
organization.PlanType = PlanType.FamiliesAnnually;
|
||||
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(organization.PlanType).Returns(StaticStore.GetPlan(organization.PlanType));
|
||||
|
||||
organizationUpgrade.AdditionalSeats = 30;
|
||||
organizationUpgrade.UseSecretsManager = true;
|
||||
organizationUpgrade.AdditionalSmSeats = 20;
|
||||
@ -99,6 +106,8 @@ public class UpgradeOrganizationPlanCommandTests
|
||||
organizationUpgrade.AdditionalStorageGb = 3;
|
||||
organizationUpgrade.Plan = planType;
|
||||
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(organizationUpgrade.Plan).Returns(StaticStore.GetPlan(organizationUpgrade.Plan));
|
||||
|
||||
await sutProvider.Sut.UpgradePlanAsync(organization.Id, organizationUpgrade);
|
||||
await sutProvider.GetDependency<IPaymentService>().Received(1).AdjustSubscription(
|
||||
organization,
|
||||
@ -120,7 +129,10 @@ public class UpgradeOrganizationPlanCommandTests
|
||||
public async Task UpgradePlan_SM_Passes(PlanType planType, Organization organization, OrganizationUpgrade upgrade,
|
||||
SutProvider<UpgradeOrganizationPlanCommand> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(organization.PlanType).Returns(StaticStore.GetPlan(organization.PlanType));
|
||||
|
||||
upgrade.Plan = planType;
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(upgrade.Plan).Returns(StaticStore.GetPlan(upgrade.Plan));
|
||||
|
||||
var plan = StaticStore.GetPlan(upgrade.Plan);
|
||||
|
||||
@ -155,8 +167,10 @@ public class UpgradeOrganizationPlanCommandTests
|
||||
upgrade.AdditionalSeats = 15;
|
||||
upgrade.AdditionalSmSeats = 1;
|
||||
upgrade.AdditionalServiceAccounts = 0;
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(upgrade.Plan).Returns(StaticStore.GetPlan(upgrade.Plan));
|
||||
|
||||
organization.SmSeats = 2;
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(organization.PlanType).Returns(StaticStore.GetPlan(organization.PlanType));
|
||||
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
@ -181,9 +195,11 @@ public class UpgradeOrganizationPlanCommandTests
|
||||
upgrade.AdditionalSeats = 15;
|
||||
upgrade.AdditionalSmSeats = 1;
|
||||
upgrade.AdditionalServiceAccounts = 0;
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(upgrade.Plan).Returns(StaticStore.GetPlan(upgrade.Plan));
|
||||
|
||||
organization.SmSeats = 1;
|
||||
organization.SmServiceAccounts = currentServiceAccounts;
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(organization.PlanType).Returns(StaticStore.GetPlan(organization.PlanType));
|
||||
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
|
@ -5,6 +5,8 @@ using Bit.Core.Context;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models;
|
||||
using Bit.Core.NotificationCenter.Entities;
|
||||
using Bit.Core.Platform.Push.Internal;
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Core.Test.AutoFixture;
|
||||
using Bit.Core.Test.AutoFixture.CurrentContextFixtures;
|
||||
using Bit.Core.Test.NotificationCenter.AutoFixture;
|
||||
@ -14,7 +16,7 @@ using Microsoft.AspNetCore.Http;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Platform.Push.Internal.Test;
|
||||
namespace Bit.Core.Test.Platform.Push.Services;
|
||||
|
||||
[QueueClientCustomize]
|
||||
[SutProviderCustomize]
|
||||
@ -24,20 +26,43 @@ public class AzureQueuePushNotificationServiceTests
|
||||
[BitAutoData]
|
||||
[NotificationCustomize]
|
||||
[CurrentContextCustomize]
|
||||
public async Task PushNotificationAsync_Notification_Sent(
|
||||
public async Task PushNotificationAsync_NotificationGlobal_Sent(
|
||||
SutProvider<AzureQueuePushNotificationService> sutProvider, Notification notification, Guid deviceIdentifier,
|
||||
ICurrentContext currentContext)
|
||||
ICurrentContext currentContext, Guid installationId)
|
||||
{
|
||||
currentContext.DeviceIdentifier.Returns(deviceIdentifier.ToString());
|
||||
sutProvider.GetDependency<IHttpContextAccessor>().HttpContext!.RequestServices
|
||||
.GetService(Arg.Any<Type>()).Returns(currentContext);
|
||||
sutProvider.GetDependency<IGlobalSettings>().Installation.Id = installationId;
|
||||
|
||||
await sutProvider.Sut.PushNotificationAsync(notification);
|
||||
|
||||
await sutProvider.GetDependency<QueueClient>().Received(1)
|
||||
.SendMessageAsync(Arg.Is<string>(message =>
|
||||
MatchMessage(PushType.SyncNotification, message,
|
||||
new NotificationPushNotificationEquals(notification, null),
|
||||
MatchMessage(PushType.Notification, message,
|
||||
new NotificationPushNotificationEquals(notification, null, installationId),
|
||||
deviceIdentifier.ToString())));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
[NotificationCustomize(false)]
|
||||
[CurrentContextCustomize]
|
||||
public async Task PushNotificationAsync_NotificationNotGlobal_Sent(
|
||||
SutProvider<AzureQueuePushNotificationService> sutProvider, Notification notification, Guid deviceIdentifier,
|
||||
ICurrentContext currentContext, Guid installationId)
|
||||
{
|
||||
currentContext.DeviceIdentifier.Returns(deviceIdentifier.ToString());
|
||||
sutProvider.GetDependency<IHttpContextAccessor>().HttpContext!.RequestServices
|
||||
.GetService(Arg.Any<Type>()).Returns(currentContext);
|
||||
sutProvider.GetDependency<IGlobalSettings>().Installation.Id = installationId;
|
||||
|
||||
await sutProvider.Sut.PushNotificationAsync(notification);
|
||||
|
||||
await sutProvider.GetDependency<QueueClient>().Received(1)
|
||||
.SendMessageAsync(Arg.Is<string>(message =>
|
||||
MatchMessage(PushType.Notification, message,
|
||||
new NotificationPushNotificationEquals(notification, null, null),
|
||||
deviceIdentifier.ToString())));
|
||||
}
|
||||
|
||||
@ -46,20 +71,44 @@ public class AzureQueuePushNotificationServiceTests
|
||||
[NotificationCustomize]
|
||||
[NotificationStatusCustomize]
|
||||
[CurrentContextCustomize]
|
||||
public async Task PushNotificationStatusAsync_Notification_Sent(
|
||||
public async Task PushNotificationStatusAsync_NotificationGlobal_Sent(
|
||||
SutProvider<AzureQueuePushNotificationService> sutProvider, Notification notification, Guid deviceIdentifier,
|
||||
ICurrentContext currentContext, NotificationStatus notificationStatus)
|
||||
ICurrentContext currentContext, NotificationStatus notificationStatus, Guid installationId)
|
||||
{
|
||||
currentContext.DeviceIdentifier.Returns(deviceIdentifier.ToString());
|
||||
sutProvider.GetDependency<IHttpContextAccessor>().HttpContext!.RequestServices
|
||||
.GetService(Arg.Any<Type>()).Returns(currentContext);
|
||||
sutProvider.GetDependency<IGlobalSettings>().Installation.Id = installationId;
|
||||
|
||||
await sutProvider.Sut.PushNotificationStatusAsync(notification, notificationStatus);
|
||||
|
||||
await sutProvider.GetDependency<QueueClient>().Received(1)
|
||||
.SendMessageAsync(Arg.Is<string>(message =>
|
||||
MatchMessage(PushType.SyncNotificationStatus, message,
|
||||
new NotificationPushNotificationEquals(notification, notificationStatus),
|
||||
MatchMessage(PushType.NotificationStatus, message,
|
||||
new NotificationPushNotificationEquals(notification, notificationStatus, installationId),
|
||||
deviceIdentifier.ToString())));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
[NotificationCustomize(false)]
|
||||
[NotificationStatusCustomize]
|
||||
[CurrentContextCustomize]
|
||||
public async Task PushNotificationStatusAsync_NotificationNotGlobal_Sent(
|
||||
SutProvider<AzureQueuePushNotificationService> sutProvider, Notification notification, Guid deviceIdentifier,
|
||||
ICurrentContext currentContext, NotificationStatus notificationStatus, Guid installationId)
|
||||
{
|
||||
currentContext.DeviceIdentifier.Returns(deviceIdentifier.ToString());
|
||||
sutProvider.GetDependency<IHttpContextAccessor>().HttpContext!.RequestServices
|
||||
.GetService(Arg.Any<Type>()).Returns(currentContext);
|
||||
sutProvider.GetDependency<IGlobalSettings>().Installation.Id = installationId;
|
||||
|
||||
await sutProvider.Sut.PushNotificationStatusAsync(notification, notificationStatus);
|
||||
|
||||
await sutProvider.GetDependency<QueueClient>().Received(1)
|
||||
.SendMessageAsync(Arg.Is<string>(message =>
|
||||
MatchMessage(PushType.NotificationStatus, message,
|
||||
new NotificationPushNotificationEquals(notification, notificationStatus, null),
|
||||
deviceIdentifier.ToString())));
|
||||
}
|
||||
|
||||
@ -73,7 +122,10 @@ public class AzureQueuePushNotificationServiceTests
|
||||
pushNotificationData.ContextId == contextId;
|
||||
}
|
||||
|
||||
private class NotificationPushNotificationEquals(Notification notification, NotificationStatus? notificationStatus)
|
||||
private class NotificationPushNotificationEquals(
|
||||
Notification notification,
|
||||
NotificationStatus? notificationStatus,
|
||||
Guid? installationId)
|
||||
: IEquatable<NotificationPushNotification>
|
||||
{
|
||||
public bool Equals(NotificationPushNotification? other)
|
||||
@ -87,6 +139,8 @@ public class AzureQueuePushNotificationServiceTests
|
||||
other.UserId == notification.UserId &&
|
||||
other.OrganizationId.HasValue == notification.OrganizationId.HasValue &&
|
||||
other.OrganizationId == notification.OrganizationId &&
|
||||
other.ClientType == notification.ClientType &&
|
||||
other.InstallationId == installationId &&
|
||||
other.Title == notification.Title &&
|
||||
other.Body == notification.Body &&
|
||||
other.CreationDate == notification.CreationDate &&
|
||||
|
@ -1,13 +1,15 @@
|
||||
#nullable enable
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.NotificationCenter.Entities;
|
||||
using Bit.Core.Platform.Push;
|
||||
using Bit.Core.Platform.Push.Internal;
|
||||
using Bit.Core.Test.NotificationCenter.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Platform.Push.Internal.Test;
|
||||
namespace Bit.Core.Test.Platform.Push.Services;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class MultiServicePushNotificationServiceTests
|
||||
@ -75,4 +77,22 @@ public class MultiServicePushNotificationServiceTests
|
||||
.Received(1)
|
||||
.SendPayloadToOrganizationAsync(organizationId, type, payload, identifier, deviceId, clientType);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData([null, null])]
|
||||
[BitAutoData(ClientType.All, null)]
|
||||
[BitAutoData([null, "test device id"])]
|
||||
[BitAutoData(ClientType.All, "test device id")]
|
||||
public async Task SendPayloadToInstallationAsync_Message_Sent(ClientType? clientType, string? deviceId,
|
||||
string installationId, PushType type, object payload, string identifier,
|
||||
SutProvider<MultiServicePushNotificationService> sutProvider)
|
||||
{
|
||||
await sutProvider.Sut.SendPayloadToInstallationAsync(installationId, type, payload, identifier, deviceId,
|
||||
clientType);
|
||||
|
||||
await sutProvider.GetDependency<IEnumerable<IPushNotificationService>>()
|
||||
.First()
|
||||
.Received(1)
|
||||
.SendPayloadToInstallationAsync(installationId, type, payload, identifier, deviceId, clientType);
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,11 @@
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Core.Platform.Push;
|
||||
using Bit.Core.Settings;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Platform.Push.Internal.Test;
|
||||
namespace Bit.Core.Test.Platform.Push.Services;
|
||||
|
||||
public class NotificationsApiPushNotificationServiceTests
|
||||
{
|
||||
|
@ -1,11 +1,12 @@
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Platform.Push.Internal;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Settings;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Platform.Push.Internal.Test;
|
||||
namespace Bit.Core.Test.Platform.Push.Services;
|
||||
|
||||
public class RelayPushNotificationServiceTests
|
||||
{
|
||||
|
@ -1,9 +1,10 @@
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Core.Platform.Push.Internal;
|
||||
using Bit.Core.Settings;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Platform.Push.Internal.Test;
|
||||
namespace Bit.Core.Test.Platform.Push.Services;
|
||||
|
||||
public class RelayPushRegistrationServiceTests
|
||||
{
|
||||
|
@ -4,9 +4,11 @@ using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||
using Bit.Core.NotificationHub;
|
||||
using Bit.Core.Platform.Push;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
@ -20,7 +22,7 @@ public class DeviceServiceTests
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SaveAsync_IdProvided_UpdatedRevisionDateAndPushRegistration(Guid id, Guid userId,
|
||||
Guid organizationId1, Guid organizationId2,
|
||||
Guid organizationId1, Guid organizationId2, Guid installationId,
|
||||
OrganizationUserOrganizationDetails organizationUserOrganizationDetails1,
|
||||
OrganizationUserOrganizationDetails organizationUserOrganizationDetails2)
|
||||
{
|
||||
@ -32,7 +34,9 @@ public class DeviceServiceTests
|
||||
var organizationUserRepository = Substitute.For<IOrganizationUserRepository>();
|
||||
organizationUserRepository.GetManyDetailsByUserAsync(Arg.Any<Guid>(), Arg.Any<OrganizationUserStatusType?>())
|
||||
.Returns([organizationUserOrganizationDetails1, organizationUserOrganizationDetails2]);
|
||||
var deviceService = new DeviceService(deviceRepo, pushRepo, organizationUserRepository);
|
||||
var globalSettings = Substitute.For<IGlobalSettings>();
|
||||
globalSettings.Installation.Id.Returns(installationId);
|
||||
var deviceService = new DeviceService(deviceRepo, pushRepo, organizationUserRepository, globalSettings);
|
||||
|
||||
var device = new Device
|
||||
{
|
||||
@ -40,13 +44,13 @@ public class DeviceServiceTests
|
||||
Name = "test device",
|
||||
Type = DeviceType.Android,
|
||||
UserId = userId,
|
||||
PushToken = "testtoken",
|
||||
PushToken = "testToken",
|
||||
Identifier = "testid"
|
||||
};
|
||||
await deviceService.SaveAsync(device);
|
||||
|
||||
Assert.True(device.RevisionDate - DateTime.UtcNow < TimeSpan.FromSeconds(1));
|
||||
await pushRepo.Received(1).CreateOrUpdateRegistrationAsync("testtoken", id.ToString(),
|
||||
await pushRepo.Received(1).CreateOrUpdateRegistrationAsync(Arg.Is<PushRegistrationData>(v => v.Token == "testToken"), id.ToString(),
|
||||
userId.ToString(), "testid", DeviceType.Android,
|
||||
Arg.Do<IEnumerable<string>>(organizationIds =>
|
||||
{
|
||||
@ -54,13 +58,13 @@ public class DeviceServiceTests
|
||||
Assert.Equal(2, organizationIdsList.Count);
|
||||
Assert.Contains(organizationId1.ToString(), organizationIdsList);
|
||||
Assert.Contains(organizationId2.ToString(), organizationIdsList);
|
||||
}));
|
||||
}), installationId);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SaveAsync_IdNotProvided_CreatedAndPushRegistration(Guid userId, Guid organizationId1,
|
||||
Guid organizationId2,
|
||||
Guid organizationId2, Guid installationId,
|
||||
OrganizationUserOrganizationDetails organizationUserOrganizationDetails1,
|
||||
OrganizationUserOrganizationDetails organizationUserOrganizationDetails2)
|
||||
{
|
||||
@ -72,19 +76,21 @@ public class DeviceServiceTests
|
||||
var organizationUserRepository = Substitute.For<IOrganizationUserRepository>();
|
||||
organizationUserRepository.GetManyDetailsByUserAsync(Arg.Any<Guid>(), Arg.Any<OrganizationUserStatusType?>())
|
||||
.Returns([organizationUserOrganizationDetails1, organizationUserOrganizationDetails2]);
|
||||
var deviceService = new DeviceService(deviceRepo, pushRepo, organizationUserRepository);
|
||||
var globalSettings = Substitute.For<IGlobalSettings>();
|
||||
globalSettings.Installation.Id.Returns(installationId);
|
||||
var deviceService = new DeviceService(deviceRepo, pushRepo, organizationUserRepository, globalSettings);
|
||||
|
||||
var device = new Device
|
||||
{
|
||||
Name = "test device",
|
||||
Type = DeviceType.Android,
|
||||
UserId = userId,
|
||||
PushToken = "testtoken",
|
||||
PushToken = "testToken",
|
||||
Identifier = "testid"
|
||||
};
|
||||
await deviceService.SaveAsync(device);
|
||||
|
||||
await pushRepo.Received(1).CreateOrUpdateRegistrationAsync("testtoken",
|
||||
await pushRepo.Received(1).CreateOrUpdateRegistrationAsync(Arg.Is<PushRegistrationData>(v => v.Token == "testToken"),
|
||||
Arg.Do<string>(id => Guid.TryParse(id, out var _)), userId.ToString(), "testid", DeviceType.Android,
|
||||
Arg.Do<IEnumerable<string>>(organizationIds =>
|
||||
{
|
||||
@ -92,7 +98,7 @@ public class DeviceServiceTests
|
||||
Assert.Equal(2, organizationIdsList.Count);
|
||||
Assert.Contains(organizationId1.ToString(), organizationIdsList);
|
||||
Assert.Contains(organizationId2.ToString(), organizationIdsList);
|
||||
}));
|
||||
}), installationId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -8,6 +8,7 @@ using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using LaunchDarkly.Sdk.Server.Interfaces;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
using GlobalSettings = Bit.Core.Settings.GlobalSettings;
|
||||
|
||||
namespace Bit.Core.Test.Services;
|
||||
|
||||
@ -41,7 +42,7 @@ public class LaunchDarklyFeatureServiceTests
|
||||
[Theory, BitAutoData]
|
||||
public void DefaultFeatureValue_WhenSelfHost(string key)
|
||||
{
|
||||
var sutProvider = GetSutProvider(new Settings.GlobalSettings { SelfHosted = true });
|
||||
var sutProvider = GetSutProvider(new GlobalSettings { SelfHosted = true });
|
||||
|
||||
Assert.False(sutProvider.Sut.IsEnabled(key));
|
||||
}
|
||||
@ -49,7 +50,7 @@ public class LaunchDarklyFeatureServiceTests
|
||||
[Fact]
|
||||
public void DefaultFeatureValue_NoSdkKey()
|
||||
{
|
||||
var sutProvider = GetSutProvider(new Settings.GlobalSettings());
|
||||
var sutProvider = GetSutProvider(new GlobalSettings());
|
||||
|
||||
Assert.False(sutProvider.Sut.IsEnabled(_fakeFeatureKey));
|
||||
}
|
||||
@ -57,7 +58,7 @@ public class LaunchDarklyFeatureServiceTests
|
||||
[Fact(Skip = "For local development")]
|
||||
public void FeatureValue_Boolean()
|
||||
{
|
||||
var settings = new Settings.GlobalSettings { LaunchDarkly = { SdkKey = _fakeSdkKey } };
|
||||
var settings = new GlobalSettings { LaunchDarkly = { SdkKey = _fakeSdkKey } };
|
||||
|
||||
var sutProvider = GetSutProvider(settings);
|
||||
|
||||
@ -67,7 +68,7 @@ public class LaunchDarklyFeatureServiceTests
|
||||
[Fact(Skip = "For local development")]
|
||||
public void FeatureValue_Int()
|
||||
{
|
||||
var settings = new Settings.GlobalSettings { LaunchDarkly = { SdkKey = _fakeSdkKey } };
|
||||
var settings = new GlobalSettings { LaunchDarkly = { SdkKey = _fakeSdkKey } };
|
||||
|
||||
var sutProvider = GetSutProvider(settings);
|
||||
|
||||
@ -77,7 +78,7 @@ public class LaunchDarklyFeatureServiceTests
|
||||
[Fact(Skip = "For local development")]
|
||||
public void FeatureValue_String()
|
||||
{
|
||||
var settings = new Settings.GlobalSettings { LaunchDarkly = { SdkKey = _fakeSdkKey } };
|
||||
var settings = new GlobalSettings { LaunchDarkly = { SdkKey = _fakeSdkKey } };
|
||||
|
||||
var sutProvider = GetSutProvider(settings);
|
||||
|
||||
@ -87,7 +88,7 @@ public class LaunchDarklyFeatureServiceTests
|
||||
[Fact(Skip = "For local development")]
|
||||
public void GetAll()
|
||||
{
|
||||
var sutProvider = GetSutProvider(new Settings.GlobalSettings());
|
||||
var sutProvider = GetSutProvider(new GlobalSettings());
|
||||
|
||||
var results = sutProvider.Sut.GetAll();
|
||||
|
||||
|
@ -66,8 +66,8 @@ public class UserServiceTests
|
||||
user.EmailVerified = true;
|
||||
user.Email = userLicense.Email;
|
||||
|
||||
sutProvider.GetDependency<Settings.IGlobalSettings>().SelfHosted = true;
|
||||
sutProvider.GetDependency<Settings.IGlobalSettings>().LicenseDirectory = tempDir.Directory;
|
||||
sutProvider.GetDependency<IGlobalSettings>().SelfHosted = true;
|
||||
sutProvider.GetDependency<IGlobalSettings>().LicenseDirectory = tempDir.Directory;
|
||||
sutProvider.GetDependency<ILicensingService>()
|
||||
.VerifyLicense(userLicense)
|
||||
.Returns(true);
|
||||
@ -96,6 +96,9 @@ public class UserServiceTests
|
||||
{
|
||||
var email = user.Email.ToLowerInvariant();
|
||||
var token = "thisisatokentocompare";
|
||||
var authentication = true;
|
||||
var IpAddress = "1.1.1.1";
|
||||
var deviceType = "Android";
|
||||
|
||||
var userTwoFactorTokenProvider = Substitute.For<IUserTwoFactorTokenProvider<User>>();
|
||||
userTwoFactorTokenProvider
|
||||
@ -105,6 +108,10 @@ public class UserServiceTests
|
||||
.GenerateAsync("TwoFactor", Arg.Any<UserManager<User>>(), user)
|
||||
.Returns(Task.FromResult(token));
|
||||
|
||||
var context = sutProvider.GetDependency<ICurrentContext>();
|
||||
context.DeviceType = DeviceType.Android;
|
||||
context.IpAddress = IpAddress;
|
||||
|
||||
sutProvider.Sut.RegisterTokenProvider("Custom_Email", userTwoFactorTokenProvider);
|
||||
|
||||
user.SetTwoFactorProviders(new Dictionary<TwoFactorProviderType, TwoFactorProvider>
|
||||
@ -119,7 +126,7 @@ public class UserServiceTests
|
||||
|
||||
await sutProvider.GetDependency<IMailService>()
|
||||
.Received(1)
|
||||
.SendTwoFactorEmailAsync(email, token);
|
||||
.SendTwoFactorEmailAsync(email, user.Email, token, IpAddress, deviceType, authentication);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
@ -160,6 +167,44 @@ public class UserServiceTests
|
||||
await Assert.ThrowsAsync<ArgumentNullException>("No email.", () => sutProvider.Sut.SendTwoFactorEmailAsync(user));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task SendNewDeviceVerificationEmailAsync_ExceptionBecauseUserNull(SutProvider<UserService> sutProvider)
|
||||
{
|
||||
await Assert.ThrowsAsync<ArgumentNullException>(() => sutProvider.Sut.SendNewDeviceVerificationEmailAsync(null));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(DeviceType.UnknownBrowser, "Unknown Browser")]
|
||||
[BitAutoData(DeviceType.Android, "Android")]
|
||||
public async Task SendNewDeviceVerificationEmailAsync_DeviceMatches(DeviceType deviceType, string deviceTypeName, SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
SetupFakeTokenProvider(sutProvider, user);
|
||||
var context = sutProvider.GetDependency<ICurrentContext>();
|
||||
context.DeviceType = deviceType;
|
||||
context.IpAddress = "1.1.1.1";
|
||||
|
||||
await sutProvider.Sut.SendNewDeviceVerificationEmailAsync(user);
|
||||
|
||||
await sutProvider.GetDependency<IMailService>()
|
||||
.Received(1)
|
||||
.SendTwoFactorEmailAsync(Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), deviceTypeName, Arg.Any<bool>());
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task SendNewDeviceVerificationEmailAsync_NullDeviceTypeShouldSendUnkownBrowserType(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
SetupFakeTokenProvider(sutProvider, user);
|
||||
var context = sutProvider.GetDependency<ICurrentContext>();
|
||||
context.DeviceType = null;
|
||||
context.IpAddress = "1.1.1.1";
|
||||
|
||||
await sutProvider.Sut.SendNewDeviceVerificationEmailAsync(user);
|
||||
|
||||
await sutProvider.GetDependency<IMailService>()
|
||||
.Received(1)
|
||||
.SendTwoFactorEmailAsync(Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), "Unknown Browser", Arg.Any<bool>());
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task HasPremiumFromOrganization_Returns_False_If_No_Orgs(SutProvider<UserService> sutProvider, User user)
|
||||
{
|
||||
@ -248,6 +293,7 @@ public class UserServiceTests
|
||||
sutProvider.GetDependency<ICipherRepository>(),
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>(),
|
||||
sutProvider.GetDependency<IOrganizationRepository>(),
|
||||
sutProvider.GetDependency<IOrganizationDomainRepository>(),
|
||||
sutProvider.GetDependency<IMailService>(),
|
||||
sutProvider.GetDependency<IPushNotificationService>(),
|
||||
sutProvider.GetDependency<IUserStore<User>>(),
|
||||
@ -576,7 +622,7 @@ public class UserServiceTests
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task ResendNewDeviceVerificationEmail_UserNull_SendOTPAsyncNotCalled(
|
||||
public async Task ResendNewDeviceVerificationEmail_UserNull_SendTwoFactorEmailAsyncNotCalled(
|
||||
SutProvider<UserService> sutProvider, string email, string secret)
|
||||
{
|
||||
sutProvider.GetDependency<IUserRepository>()
|
||||
@ -587,11 +633,11 @@ public class UserServiceTests
|
||||
|
||||
await sutProvider.GetDependency<IMailService>()
|
||||
.DidNotReceive()
|
||||
.SendOTPEmailAsync(Arg.Any<string>(), Arg.Any<string>());
|
||||
.SendTwoFactorEmailAsync(Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<bool>());
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task ResendNewDeviceVerificationEmail_SecretNotValid_SendOTPAsyncNotCalled(
|
||||
public async Task ResendNewDeviceVerificationEmail_SecretNotValid_SendTwoFactorEmailAsyncNotCalled(
|
||||
SutProvider<UserService> sutProvider, string email, string secret)
|
||||
{
|
||||
sutProvider.GetDependency<IUserRepository>()
|
||||
@ -602,7 +648,7 @@ public class UserServiceTests
|
||||
|
||||
await sutProvider.GetDependency<IMailService>()
|
||||
.DidNotReceive()
|
||||
.SendOTPEmailAsync(Arg.Any<string>(), Arg.Any<string>());
|
||||
.SendTwoFactorEmailAsync(Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<bool>());
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
@ -636,6 +682,10 @@ public class UserServiceTests
|
||||
.GetByEmailAsync(user.Email)
|
||||
.Returns(user);
|
||||
|
||||
var context = sutProvider.GetDependency<ICurrentContext>();
|
||||
context.DeviceType = DeviceType.Android;
|
||||
context.IpAddress = "1.1.1.1";
|
||||
|
||||
// HACK: SutProvider is being weird about not injecting the IPasswordHasher that I configured
|
||||
var sut = RebuildSut(sutProvider);
|
||||
|
||||
@ -643,7 +693,8 @@ public class UserServiceTests
|
||||
|
||||
await sutProvider.GetDependency<IMailService>()
|
||||
.Received(1)
|
||||
.SendOTPEmailAsync(user.Email, Arg.Any<string>());
|
||||
.SendTwoFactorEmailAsync(Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<bool>());
|
||||
|
||||
}
|
||||
|
||||
[Theory]
|
||||
@ -829,6 +880,7 @@ public class UserServiceTests
|
||||
sutProvider.GetDependency<ICipherRepository>(),
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>(),
|
||||
sutProvider.GetDependency<IOrganizationRepository>(),
|
||||
sutProvider.GetDependency<IOrganizationDomainRepository>(),
|
||||
sutProvider.GetDependency<IMailService>(),
|
||||
sutProvider.GetDependency<IPushNotificationService>(),
|
||||
sutProvider.GetDependency<IUserStore<User>>(),
|
||||
|
134
test/Core.Test/Settings/GlobalSettingsTests.cs
Normal file
134
test/Core.Test/Settings/GlobalSettingsTests.cs
Normal file
@ -0,0 +1,134 @@
|
||||
using Bit.Core.Settings;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Settings;
|
||||
|
||||
public class GlobalSettingsTests
|
||||
{
|
||||
public class SqlSettingsTests
|
||||
{
|
||||
private const string _testingConnectionString =
|
||||
"Server=server;Database=database;User Id=user;Password=password;";
|
||||
|
||||
private const string _testingReadOnlyConnectionString =
|
||||
"Server=server_read;Database=database_read;User Id=user_read;Password=password_read;";
|
||||
|
||||
[Fact]
|
||||
public void ConnectionString_ValueInDoubleQuotes_Stripped()
|
||||
{
|
||||
var settings = new GlobalSettings.SqlSettings { ConnectionString = $"\"{_testingConnectionString}\"", };
|
||||
|
||||
Assert.Equal(_testingConnectionString, settings.ConnectionString);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConnectionString_ValueWithoutDoubleQuotes_TheSameValue()
|
||||
{
|
||||
var settings = new GlobalSettings.SqlSettings { ConnectionString = _testingConnectionString };
|
||||
|
||||
Assert.Equal(_testingConnectionString, settings.ConnectionString);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConnectionString_SetTwice_ReturnsSecondConnectionString()
|
||||
{
|
||||
var settings = new GlobalSettings.SqlSettings { ConnectionString = _testingConnectionString };
|
||||
|
||||
Assert.Equal(_testingConnectionString, settings.ConnectionString);
|
||||
|
||||
var newConnectionString = $"{_testingConnectionString}_new";
|
||||
settings.ConnectionString = newConnectionString;
|
||||
|
||||
Assert.Equal(newConnectionString, settings.ConnectionString);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadOnlyConnectionString_ValueInDoubleQuotes_Stripped()
|
||||
{
|
||||
var settings = new GlobalSettings.SqlSettings
|
||||
{
|
||||
ReadOnlyConnectionString = $"\"{_testingReadOnlyConnectionString}\"",
|
||||
};
|
||||
|
||||
Assert.Equal(_testingReadOnlyConnectionString, settings.ReadOnlyConnectionString);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadOnlyConnectionString_ValueWithoutDoubleQuotes_TheSameValue()
|
||||
{
|
||||
var settings = new GlobalSettings.SqlSettings
|
||||
{
|
||||
ReadOnlyConnectionString = _testingReadOnlyConnectionString
|
||||
};
|
||||
|
||||
Assert.Equal(_testingReadOnlyConnectionString, settings.ReadOnlyConnectionString);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadOnlyConnectionString_NotSet_DefaultsToConnectionString()
|
||||
{
|
||||
var settings = new GlobalSettings.SqlSettings { ConnectionString = _testingConnectionString };
|
||||
|
||||
Assert.Equal(_testingConnectionString, settings.ReadOnlyConnectionString);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadOnlyConnectionString_Set_ReturnsReadOnlyConnectionString()
|
||||
{
|
||||
var settings = new GlobalSettings.SqlSettings
|
||||
{
|
||||
ConnectionString = _testingConnectionString,
|
||||
ReadOnlyConnectionString = _testingReadOnlyConnectionString
|
||||
};
|
||||
|
||||
Assert.Equal(_testingReadOnlyConnectionString, settings.ReadOnlyConnectionString);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadOnlyConnectionString_SetTwice_ReturnsSecondReadOnlyConnectionString()
|
||||
{
|
||||
var settings = new GlobalSettings.SqlSettings
|
||||
{
|
||||
ConnectionString = _testingConnectionString,
|
||||
ReadOnlyConnectionString = _testingReadOnlyConnectionString
|
||||
};
|
||||
|
||||
Assert.Equal(_testingReadOnlyConnectionString, settings.ReadOnlyConnectionString);
|
||||
|
||||
var newReadOnlyConnectionString = $"{_testingReadOnlyConnectionString}_new";
|
||||
settings.ReadOnlyConnectionString = newReadOnlyConnectionString;
|
||||
|
||||
Assert.Equal(newReadOnlyConnectionString, settings.ReadOnlyConnectionString);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadOnlyConnectionString_NotSetAndConnectionStringSetTwice_ReturnsSecondConnectionString()
|
||||
{
|
||||
var settings = new GlobalSettings.SqlSettings { ConnectionString = _testingConnectionString };
|
||||
|
||||
Assert.Equal(_testingConnectionString, settings.ReadOnlyConnectionString);
|
||||
|
||||
var newConnectionString = $"{_testingConnectionString}_new";
|
||||
settings.ConnectionString = newConnectionString;
|
||||
|
||||
Assert.Equal(newConnectionString, settings.ReadOnlyConnectionString);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadOnlyConnectionString_SetAndConnectionStringSetTwice_ReturnsReadOnlyConnectionString()
|
||||
{
|
||||
var settings = new GlobalSettings.SqlSettings
|
||||
{
|
||||
ConnectionString = _testingConnectionString,
|
||||
ReadOnlyConnectionString = _testingReadOnlyConnectionString
|
||||
};
|
||||
|
||||
Assert.Equal(_testingReadOnlyConnectionString, settings.ReadOnlyConnectionString);
|
||||
|
||||
var newConnectionString = $"{_testingConnectionString}_new";
|
||||
settings.ConnectionString = newConnectionString;
|
||||
|
||||
Assert.Equal(_testingReadOnlyConnectionString, settings.ReadOnlyConnectionString);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,6 @@
|
||||
using AutoFixture;
|
||||
using System.Reflection;
|
||||
using AutoFixture;
|
||||
using AutoFixture.Xunit2;
|
||||
using Bit.Core.Tools.Entities;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
|
||||
@ -19,3 +21,20 @@ internal class UserSendCustomizeAttribute : BitCustomizeAttribute
|
||||
{
|
||||
public override ICustomization GetCustomization() => new UserSend();
|
||||
}
|
||||
|
||||
internal class NewUserSend : ICustomization
|
||||
{
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
fixture.Customize<Send>(composer => composer
|
||||
.With(s => s.Id, Guid.Empty)
|
||||
.Without(s => s.OrganizationId));
|
||||
}
|
||||
}
|
||||
|
||||
internal class NewUserSendCustomizeAttribute : CustomizeAttribute
|
||||
{
|
||||
public override ICustomization GetCustomization(ParameterInfo parameterInfo)
|
||||
=> new NewUserSend();
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,8 @@ using System.Text.Json;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Enums;
|
||||
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
||||
using Bit.Core.AdminConsole.Services;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Exceptions;
|
||||
@ -22,8 +24,11 @@ using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using NSubstitute;
|
||||
using NSubstitute.ExceptionExtensions;
|
||||
using Xunit;
|
||||
|
||||
using GlobalSettings = Bit.Core.Settings.GlobalSettings;
|
||||
|
||||
namespace Bit.Core.Test.Tools.Services;
|
||||
|
||||
[SutProviderCustomize]
|
||||
@ -116,6 +121,93 @@ public class SendServiceTests
|
||||
await sutProvider.GetDependency<ISendRepository>().Received(1).CreateAsync(send);
|
||||
}
|
||||
|
||||
// Disable Send policy check - vNext
|
||||
private void SaveSendAsync_Setup_vNext(SutProvider<SendService> sutProvider, Send send,
|
||||
SendPolicyRequirement sendPolicyRequirement)
|
||||
{
|
||||
sutProvider.GetDependency<IPolicyRequirementQuery>().GetAsync<SendPolicyRequirement>(send.UserId!.Value)
|
||||
.Returns(sendPolicyRequirement);
|
||||
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.PolicyRequirements).Returns(true);
|
||||
|
||||
// Should not be called in these tests
|
||||
sutProvider.GetDependency<IPolicyService>().AnyPoliciesApplicableToUserAsync(
|
||||
Arg.Any<Guid>(), Arg.Any<PolicyType>()).ThrowsAsync<Exception>();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(SendType.File)]
|
||||
[BitAutoData(SendType.Text)]
|
||||
public async Task SaveSendAsync_DisableSend_Applies_Throws_vNext(SendType sendType,
|
||||
SutProvider<SendService> sutProvider, [NewUserSendCustomize] Send send)
|
||||
{
|
||||
send.Type = sendType;
|
||||
SaveSendAsync_Setup_vNext(sutProvider, send, new SendPolicyRequirement { DisableSend = true });
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.SaveSendAsync(send));
|
||||
Assert.Contains("Due to an Enterprise Policy, you are only able to delete an existing Send.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(SendType.File)]
|
||||
[BitAutoData(SendType.Text)]
|
||||
public async Task SaveSendAsync_DisableSend_DoesntApply_Success_vNext(SendType sendType,
|
||||
SutProvider<SendService> sutProvider, [NewUserSendCustomize] Send send)
|
||||
{
|
||||
send.Type = sendType;
|
||||
SaveSendAsync_Setup_vNext(sutProvider, send, new SendPolicyRequirement());
|
||||
|
||||
await sutProvider.Sut.SaveSendAsync(send);
|
||||
|
||||
await sutProvider.GetDependency<ISendRepository>().Received(1).CreateAsync(send);
|
||||
}
|
||||
|
||||
// Send Options Policy - Disable Hide Email check
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(SendType.File)]
|
||||
[BitAutoData(SendType.Text)]
|
||||
public async Task SaveSendAsync_DisableHideEmail_Applies_Throws_vNext(SendType sendType,
|
||||
SutProvider<SendService> sutProvider, [NewUserSendCustomize] Send send)
|
||||
{
|
||||
send.Type = sendType;
|
||||
SaveSendAsync_Setup_vNext(sutProvider, send, new SendPolicyRequirement { DisableHideEmail = true });
|
||||
send.HideEmail = true;
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.SaveSendAsync(send));
|
||||
Assert.Contains("Due to an Enterprise Policy, you are not allowed to hide your email address from recipients when creating or editing a Send.", exception.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(SendType.File)]
|
||||
[BitAutoData(SendType.Text)]
|
||||
public async Task SaveSendAsync_DisableHideEmail_Applies_ButEmailNotHidden_Success_vNext(SendType sendType,
|
||||
SutProvider<SendService> sutProvider, [NewUserSendCustomize] Send send)
|
||||
{
|
||||
send.Type = sendType;
|
||||
SaveSendAsync_Setup_vNext(sutProvider, send, new SendPolicyRequirement { DisableHideEmail = true });
|
||||
send.HideEmail = false;
|
||||
|
||||
await sutProvider.Sut.SaveSendAsync(send);
|
||||
|
||||
await sutProvider.GetDependency<ISendRepository>().Received(1).CreateAsync(send);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(SendType.File)]
|
||||
[BitAutoData(SendType.Text)]
|
||||
public async Task SaveSendAsync_DisableHideEmail_DoesntApply_Success_vNext(SendType sendType,
|
||||
SutProvider<SendService> sutProvider, [NewUserSendCustomize] Send send)
|
||||
{
|
||||
send.Type = sendType;
|
||||
SaveSendAsync_Setup_vNext(sutProvider, send, new SendPolicyRequirement());
|
||||
send.HideEmail = true;
|
||||
|
||||
await sutProvider.Sut.SaveSendAsync(send);
|
||||
|
||||
await sutProvider.GetDependency<ISendRepository>().Received(1).CreateAsync(send);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SaveSendAsync_ExistingSend_Updates(SutProvider<SendService> sutProvider,
|
||||
@ -309,7 +401,7 @@ public class SendServiceTests
|
||||
.CanAccessPremium(user)
|
||||
.Returns(true);
|
||||
|
||||
sutProvider.GetDependency<Settings.GlobalSettings>()
|
||||
sutProvider.GetDependency<GlobalSettings>()
|
||||
.SelfHosted = true;
|
||||
|
||||
var badRequest = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
@ -342,7 +434,7 @@ public class SendServiceTests
|
||||
.CanAccessPremium(user)
|
||||
.Returns(true);
|
||||
|
||||
sutProvider.GetDependency<Settings.GlobalSettings>()
|
||||
sutProvider.GetDependency<GlobalSettings>()
|
||||
.SelfHosted = false;
|
||||
|
||||
var badRequest = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
|
@ -9,7 +9,6 @@ using Bit.Core.Test.AutoFixture.UserFixtures;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using IdentityModel;
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
using Xunit;
|
||||
|
||||
|
@ -0,0 +1,150 @@
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Models.Data.Organizations;
|
||||
using Bit.Core.Vault.Authorization.Permissions;
|
||||
using Bit.Core.Vault.Models.Data;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Vault.Authorization.Permissions;
|
||||
|
||||
public class NormalCipherPermissionTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(true, true, true, true)]
|
||||
[InlineData(true, false, false, false)]
|
||||
[InlineData(false, true, false, true)]
|
||||
[InlineData(false, false, true, true)]
|
||||
[InlineData(false, false, false, false)]
|
||||
public void CanRestore_WhenCipherIsOwnedByOrganization(
|
||||
bool limitItemDeletion, bool manage, bool edit, bool expectedResult)
|
||||
{
|
||||
// Arrange
|
||||
var user = new User { Id = Guid.Empty };
|
||||
var organizationId = Guid.NewGuid();
|
||||
var cipherDetails = new CipherDetails { Manage = manage, Edit = edit, UserId = null, OrganizationId = organizationId };
|
||||
var organizationAbility = new OrganizationAbility { Id = organizationId, LimitItemDeletion = limitItemDeletion };
|
||||
|
||||
// Act
|
||||
var result = NormalCipherPermissions.CanRestore(user, cipherDetails, organizationAbility);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(result, expectedResult);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanRestore_WhenCipherIsOwnedByUser()
|
||||
{
|
||||
// Arrange
|
||||
var userId = Guid.NewGuid();
|
||||
var user = new User { Id = userId };
|
||||
var cipherDetails = new CipherDetails { UserId = userId };
|
||||
var organizationAbility = new OrganizationAbility { };
|
||||
|
||||
// Act
|
||||
var result = NormalCipherPermissions.CanRestore(user, cipherDetails, organizationAbility);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanRestore_WhenCipherHasNoOwner_ShouldThrowException()
|
||||
{
|
||||
// Arrange
|
||||
var user = new User { Id = Guid.NewGuid() };
|
||||
var cipherDetails = new CipherDetails { UserId = null };
|
||||
|
||||
|
||||
// Act
|
||||
// Assert
|
||||
Assert.Throws<Exception>(() => NormalCipherPermissions.CanRestore(user, cipherDetails, null));
|
||||
}
|
||||
|
||||
public static List<object[]> TestCases =>
|
||||
[
|
||||
new object[] { new OrganizationAbility { Id = Guid.Empty } },
|
||||
new object[] { null },
|
||||
];
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(TestCases))]
|
||||
public void CanRestore_WhenCipherDoesNotBelongToInputOrganization_ShouldThrowException(OrganizationAbility? organizationAbility)
|
||||
{
|
||||
// Arrange
|
||||
var user = new User { Id = Guid.NewGuid() };
|
||||
var cipherDetails = new CipherDetails { UserId = null, OrganizationId = Guid.NewGuid() };
|
||||
|
||||
// Act
|
||||
var exception = Assert.Throws<Exception>(() => NormalCipherPermissions.CanDelete(user, cipherDetails, organizationAbility));
|
||||
|
||||
// Assert
|
||||
Assert.Equal("Cipher does not belong to the input organization.", exception.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true, true, true, true)]
|
||||
[InlineData(true, false, false, false)]
|
||||
[InlineData(false, true, false, true)]
|
||||
[InlineData(false, false, true, true)]
|
||||
[InlineData(false, false, false, false)]
|
||||
public void CanDelete_WhenCipherIsOwnedByOrganization(
|
||||
bool limitItemDeletion, bool manage, bool edit, bool expectedResult)
|
||||
{
|
||||
// Arrange
|
||||
var user = new User { Id = Guid.Empty };
|
||||
var organizationId = Guid.NewGuid();
|
||||
var cipherDetails = new CipherDetails { Manage = manage, Edit = edit, UserId = null, OrganizationId = organizationId };
|
||||
var organizationAbility = new OrganizationAbility { Id = organizationId, LimitItemDeletion = limitItemDeletion };
|
||||
|
||||
// Act
|
||||
var result = NormalCipherPermissions.CanRestore(user, cipherDetails, organizationAbility);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(result, expectedResult);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanDelete_WhenCipherIsOwnedByUser()
|
||||
{
|
||||
// Arrange
|
||||
var userId = Guid.NewGuid();
|
||||
var user = new User { Id = userId };
|
||||
var cipherDetails = new CipherDetails { UserId = userId };
|
||||
var organizationAbility = new OrganizationAbility { };
|
||||
|
||||
// Act
|
||||
var result = NormalCipherPermissions.CanDelete(user, cipherDetails, organizationAbility);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanDelete_WhenCipherHasNoOwner_ShouldThrowException()
|
||||
{
|
||||
// Arrange
|
||||
var user = new User { Id = Guid.NewGuid() };
|
||||
var cipherDetails = new CipherDetails { UserId = null };
|
||||
|
||||
|
||||
// Act
|
||||
var exception = Assert.Throws<Exception>(() => NormalCipherPermissions.CanDelete(user, cipherDetails, null));
|
||||
|
||||
// Assert
|
||||
Assert.Equal("Cipher needs to belong to a user or an organization.", exception.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(TestCases))]
|
||||
public void CanDelete_WhenCipherDoesNotBelongToInputOrganization_ShouldThrowException(OrganizationAbility? organizationAbility)
|
||||
{
|
||||
// Arrange
|
||||
var user = new User { Id = Guid.NewGuid() };
|
||||
var cipherDetails = new CipherDetails { UserId = null, OrganizationId = Guid.NewGuid() };
|
||||
|
||||
// Act
|
||||
var exception = Assert.Throws<Exception>(() => NormalCipherPermissions.CanDelete(user, cipherDetails, organizationAbility));
|
||||
|
||||
// Assert
|
||||
Assert.Equal("Cipher does not belong to the input organization.", exception.Message);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user