diff --git a/src/Billing/Services/Implementations/UpcomingInvoiceHandler.cs b/src/Billing/Services/Implementations/UpcomingInvoiceHandler.cs
index 96220b5071ba..8356d871208c 100644
--- a/src/Billing/Services/Implementations/UpcomingInvoiceHandler.cs
+++ b/src/Billing/Services/Implementations/UpcomingInvoiceHandler.cs
@@ -112,14 +112,11 @@ private async Task HandleOrganizationUpcomingInvoiceAsync(
var plan = await pricingClient.GetPlanOrThrow(organization.PlanType);
- var milestone3 = featureService.IsEnabled(FeatureFlagKeys.PM26462_Milestone_3);
-
var subscriptionAligned = await AlignOrganizationSubscriptionConcernsAsync(
organization,
@event,
subscription,
- plan,
- milestone3);
+ plan);
/*
* Subscription alignment sends out a different version of our Upcoming Invoice email, so we don't need to continue
@@ -210,17 +207,14 @@ await stripeAdapter.UpdateCustomerAsync(subscription.CustomerId,
/// The Stripe event associated with this operation.
/// The organization's subscription.
/// The organization's current plan.
- /// A flag indicating whether the third milestone is enabled.
/// Whether the operation resulted in an updated subscription.
private async Task AlignOrganizationSubscriptionConcernsAsync(
Organization organization,
Event @event,
Subscription subscription,
- Plan plan,
- bool milestone3)
+ Plan plan)
{
- // currently these are the only plans that need aligned and both require the same flag and share most of the logic
- if (!milestone3 || plan.Type is not (PlanType.FamiliesAnnually2019 or PlanType.FamiliesAnnually2025))
+ if (plan.Type is not (PlanType.FamiliesAnnually2019 or PlanType.FamiliesAnnually2025))
{
return false;
}
diff --git a/src/Core/Billing/Pricing/PricingClient.cs b/src/Core/Billing/Pricing/PricingClient.cs
index 127eab1fbcd0..c95fc450efb3 100644
--- a/src/Core/Billing/Pricing/PricingClient.cs
+++ b/src/Core/Billing/Pricing/PricingClient.cs
@@ -3,7 +3,6 @@
using Bit.Core.Billing.Enums;
using Bit.Core.Billing.Pricing.Organizations;
using Bit.Core.Exceptions;
-using Bit.Core.Services;
using Bit.Core.Settings;
using Microsoft.Extensions.Logging;
@@ -13,7 +12,6 @@ namespace Bit.Core.Billing.Pricing;
using PremiumPlan = Premium.Plan;
public class PricingClient(
- IFeatureService featureService,
GlobalSettings globalSettings,
HttpClient httpClient,
ILogger logger) : IPricingClient
@@ -40,7 +38,7 @@ public class PricingClient(
var plan = await response.Content.ReadFromJsonAsync();
return plan == null
? throw new BillingException(message: "Deserialization of Pricing Service response resulted in null")
- : new PlanAdapter(PreProcessFamiliesPreMigrationPlan(plan));
+ : new PlanAdapter(plan);
}
if (response.StatusCode == HttpStatusCode.NotFound)
@@ -74,7 +72,7 @@ public async Task> ListPlans()
var plans = await response.Content.ReadFromJsonAsync>();
return plans == null
? throw new BillingException(message: "Deserialization of Pricing Service response resulted in null")
- : plans.Select(OrganizationPlan (plan) => new PlanAdapter(PreProcessFamiliesPreMigrationPlan(plan))).ToList();
+ : plans.Select(OrganizationPlan (plan) => new PlanAdapter(plan)).ToList();
}
throw new BillingException(
@@ -121,10 +119,7 @@ public async Task> ListPremiumPlans()
PlanType.EnterpriseMonthly2020 => "enterprise-monthly-2020",
PlanType.EnterpriseMonthly2023 => "enterprise-monthly-2023",
PlanType.FamiliesAnnually => "families",
- PlanType.FamiliesAnnually2025 =>
- featureService.IsEnabled(FeatureFlagKeys.PM26462_Milestone_3)
- ? "families-2025"
- : "families",
+ PlanType.FamiliesAnnually2025 => "families-2025",
PlanType.FamiliesAnnually2019 => "families-2019",
PlanType.Free => "free",
PlanType.TeamsAnnually => "teams-annually",
@@ -139,19 +134,4 @@ public async Task> ListPremiumPlans()
PlanType.TeamsStarter2023 => "teams-starter-2023",
_ => null
};
-
- ///
- /// Safeguard used until the feature flag is enabled. Pricing service will return the
- /// 2025PreMigration plan with "families" lookup key. When that is detected and the FF
- /// is still disabled, set the lookup key to families-2025 so PlanAdapter will assign
- /// the correct plan.
- ///
- /// The plan to preprocess
- private Plan PreProcessFamiliesPreMigrationPlan(Plan plan)
- {
- if (plan.LookupKey == "families" && !featureService.IsEnabled(FeatureFlagKeys.PM26462_Milestone_3))
- plan.LookupKey = "families-2025";
- return plan;
- }
-
}
diff --git a/test/Billing.Test/Services/UpcomingInvoiceHandlerTests.cs b/test/Billing.Test/Services/UpcomingInvoiceHandlerTests.cs
index 3f26e0b533f5..b12200f7db69 100644
--- a/test/Billing.Test/Services/UpcomingInvoiceHandlerTests.cs
+++ b/test/Billing.Test/Services/UpcomingInvoiceHandlerTests.cs
@@ -1419,7 +1419,6 @@ public async Task HandleAsync_WhenMilestone3Enabled_AndFamilies2019Plan_UpdatesS
_organizationRepository.GetByIdAsync(_organizationId).Returns(organization);
_pricingClient.GetPlanOrThrow(PlanType.FamiliesAnnually2019).Returns(families2019Plan);
_pricingClient.GetPlanOrThrow(PlanType.FamiliesAnnually).Returns(familiesPlan);
- _featureService.IsEnabled(FeatureFlagKeys.PM26462_Milestone_3).Returns(true);
_stripeEventUtilityService.IsSponsoredSubscription(subscription).Returns(false);
// Act
@@ -1527,7 +1526,6 @@ public async Task HandleAsync_WhenMilestone3Enabled_AndFamilies2019Plan_WithoutP
_organizationRepository.GetByIdAsync(_organizationId).Returns(organization);
_pricingClient.GetPlanOrThrow(PlanType.FamiliesAnnually2019).Returns(families2019Plan);
_pricingClient.GetPlanOrThrow(PlanType.FamiliesAnnually).Returns(familiesPlan);
- _featureService.IsEnabled(FeatureFlagKeys.PM26462_Milestone_3).Returns(true);
_stripeEventUtilityService.IsSponsoredSubscription(subscription).Returns(false);
// Act
@@ -1558,88 +1556,6 @@ await _stripeAdapter.DidNotReceive().UpdateCustomerAsync(
Arg.Any());
}
- [Fact]
- public async Task HandleAsync_WhenMilestone3Disabled_AndFamilies2019Plan_DoesNotUpdateSubscription()
- {
- // Arrange
- var parsedEvent = new Event { Id = "evt_123", Type = "invoice.upcoming" };
- var customerId = "cus_123";
- var subscriptionId = "sub_123";
- var passwordManagerItemId = "si_pm_123";
-
- var invoice = new Invoice
- {
- CustomerId = customerId,
- AmountDue = 40000,
- NextPaymentAttempt = DateTime.UtcNow.AddDays(7),
- Lines = new StripeList
- {
- Data = [new() { Description = "Test Item" }]
- }
- };
-
- var families2019Plan = new Families2019Plan();
-
- var subscription = new Subscription
- {
- Id = subscriptionId,
- CustomerId = customerId,
- Items = new StripeList
- {
- Data =
- [
- new()
- {
- Id = passwordManagerItemId,
- Price = new Price { Id = families2019Plan.PasswordManager.StripePlanId }
- }
- ]
- },
- AutomaticTax = new SubscriptionAutomaticTax { Enabled = true },
- Metadata = new Dictionary()
- };
-
- var customer = new Customer
- {
- Id = customerId,
- Subscriptions = new StripeList { Data = [subscription] },
- Address = new Address { Country = "US" }
- };
-
- var organization = new Organization
- {
- Id = _organizationId,
- BillingEmail = "org@example.com",
- PlanType = PlanType.FamiliesAnnually2019
- };
-
- _stripeEventService.GetInvoice(parsedEvent).Returns(invoice);
- _stripeAdapter.GetCustomerAsync(customerId, Arg.Any()).Returns(customer);
- _stripeEventUtilityService
- .GetIdsFromMetadata(subscription.Metadata)
- .Returns(new Tuple(_organizationId, null, null));
- _organizationRepository.GetByIdAsync(_organizationId).Returns(organization);
- _pricingClient.GetPlanOrThrow(PlanType.FamiliesAnnually2019).Returns(families2019Plan);
- _featureService.IsEnabled(FeatureFlagKeys.PM26462_Milestone_3).Returns(false);
- _stripeEventUtilityService.IsSponsoredSubscription(subscription).Returns(false);
-
- // Act
- await _sut.HandleAsync(parsedEvent);
-
- // Assert - should not update subscription or organization when feature flag is disabled
- await _stripeAdapter.DidNotReceive().UpdateSubscriptionAsync(
- Arg.Any(),
- Arg.Is(o => o.Discounts != null));
-
- await _organizationRepository.DidNotReceive().ReplaceAsync(
- Arg.Is(org => org.PlanType == PlanType.FamiliesAnnually));
-
- // Families plan is excluded from tax exempt alignment
- await _stripeAdapter.DidNotReceive().UpdateCustomerAsync(
- Arg.Any(),
- Arg.Any());
- }
-
[Fact]
public async Task HandleAsync_WhenMilestone3Enabled_ButNotFamilies2019Plan_DoesNotUpdateSubscription()
{
@@ -1697,7 +1613,6 @@ public async Task HandleAsync_WhenMilestone3Enabled_ButNotFamilies2019Plan_DoesN
.Returns(new Tuple(_organizationId, null, null));
_organizationRepository.GetByIdAsync(_organizationId).Returns(organization);
_pricingClient.GetPlanOrThrow(PlanType.FamiliesAnnually).Returns(familiesPlan);
- _featureService.IsEnabled(FeatureFlagKeys.PM26462_Milestone_3).Returns(true);
_stripeEventUtilityService.IsSponsoredSubscription(subscription).Returns(false);
// Act
@@ -1772,7 +1687,6 @@ public async Task HandleAsync_WhenMilestone3Enabled_AndPasswordManagerItemNotFou
.Returns(new Tuple(_organizationId, null, null));
_organizationRepository.GetByIdAsync(_organizationId).Returns(organization);
_pricingClient.GetPlanOrThrow(PlanType.FamiliesAnnually2019).Returns(families2019Plan);
- _featureService.IsEnabled(FeatureFlagKeys.PM26462_Milestone_3).Returns(true);
_stripeEventUtilityService.IsSponsoredSubscription(subscription).Returns(false);
// Act
@@ -1860,7 +1774,6 @@ public async Task HandleAsync_WhenMilestone3Enabled_AndUpdateFails_LogsErrorAndS
_organizationRepository.GetByIdAsync(_organizationId).Returns(organization);
_pricingClient.GetPlanOrThrow(PlanType.FamiliesAnnually2019).Returns(families2019Plan);
_pricingClient.GetPlanOrThrow(PlanType.FamiliesAnnually).Returns(familiesPlan);
- _featureService.IsEnabled(FeatureFlagKeys.PM26462_Milestone_3).Returns(true);
_stripeEventUtilityService.IsSponsoredSubscription(subscription).Returns(false);
// Simulate update failure
@@ -1958,7 +1871,6 @@ public async Task HandleAsync_WhenMilestone3Enabled_AndCouponNotFound_LogsErrorA
_organizationRepository.GetByIdAsync(_organizationId).Returns(organization);
_pricingClient.GetPlanOrThrow(PlanType.FamiliesAnnually2019).Returns(families2019Plan);
_pricingClient.GetPlanOrThrow(PlanType.FamiliesAnnually).Returns(familiesPlan);
- _featureService.IsEnabled(FeatureFlagKeys.PM26462_Milestone_3).Returns(true);
_stripeEventUtilityService.IsSponsoredSubscription(subscription).Returns(false);
_stripeAdapter.GetCouponAsync(CouponIDs.Milestone3SubscriptionDiscount).Returns((Coupon)null);
_stripeAdapter.UpdateSubscriptionAsync(Arg.Any(), Arg.Any())
@@ -2058,7 +1970,6 @@ public async Task HandleAsync_WhenMilestone3Enabled_AndCouponPercentOffIsNull_Lo
_organizationRepository.GetByIdAsync(_organizationId).Returns(organization);
_pricingClient.GetPlanOrThrow(PlanType.FamiliesAnnually2019).Returns(families2019Plan);
_pricingClient.GetPlanOrThrow(PlanType.FamiliesAnnually).Returns(familiesPlan);
- _featureService.IsEnabled(FeatureFlagKeys.PM26462_Milestone_3).Returns(true);
_stripeEventUtilityService.IsSponsoredSubscription(subscription).Returns(false);
_stripeAdapter.GetCouponAsync(CouponIDs.Milestone3SubscriptionDiscount).Returns(coupon);
_stripeAdapter.UpdateSubscriptionAsync(Arg.Any(), Arg.Any())
@@ -2163,7 +2074,6 @@ public async Task HandleAsync_WhenMilestone3Enabled_AndSeatAddOnExists_DeletesIt
_organizationRepository.GetByIdAsync(_organizationId).Returns(organization);
_pricingClient.GetPlanOrThrow(PlanType.FamiliesAnnually2019).Returns(families2019Plan);
_pricingClient.GetPlanOrThrow(PlanType.FamiliesAnnually).Returns(familiesPlan);
- _featureService.IsEnabled(FeatureFlagKeys.PM26462_Milestone_3).Returns(true);
_stripeEventUtilityService.IsSponsoredSubscription(subscription).Returns(false);
// Act
@@ -2277,7 +2187,6 @@ public async Task HandleAsync_WhenMilestone3Enabled_AndSeatAddOnWithQuantityOne_
_organizationRepository.GetByIdAsync(_organizationId).Returns(organization);
_pricingClient.GetPlanOrThrow(PlanType.FamiliesAnnually2019).Returns(families2019Plan);
_pricingClient.GetPlanOrThrow(PlanType.FamiliesAnnually).Returns(familiesPlan);
- _featureService.IsEnabled(FeatureFlagKeys.PM26462_Milestone_3).Returns(true);
_stripeEventUtilityService.IsSponsoredSubscription(subscription).Returns(false);
// Act
@@ -2398,7 +2307,6 @@ public async Task HandleAsync_WhenMilestone3Enabled_WithPremiumAccessAndSeatAddO
_organizationRepository.GetByIdAsync(_organizationId).Returns(organization);
_pricingClient.GetPlanOrThrow(PlanType.FamiliesAnnually2019).Returns(families2019Plan);
_pricingClient.GetPlanOrThrow(PlanType.FamiliesAnnually).Returns(familiesPlan);
- _featureService.IsEnabled(FeatureFlagKeys.PM26462_Milestone_3).Returns(true);
_stripeEventUtilityService.IsSponsoredSubscription(subscription).Returns(false);
// Act
@@ -2503,7 +2411,6 @@ public async Task HandleAsync_WhenMilestone3Enabled_AndFamilies2025Plan_UpdatesS
_organizationRepository.GetByIdAsync(_organizationId).Returns(organization);
_pricingClient.GetPlanOrThrow(PlanType.FamiliesAnnually2025).Returns(families2025Plan);
_pricingClient.GetPlanOrThrow(PlanType.FamiliesAnnually).Returns(familiesPlan);
- _featureService.IsEnabled(FeatureFlagKeys.PM26462_Milestone_3).Returns(true);
_stripeEventUtilityService.IsSponsoredSubscription(subscription).Returns(false);
// Act
@@ -2534,83 +2441,6 @@ await _mailer.Received(1).SendEmail(
email.View.MonthlyRenewalPrice == (familiesPlan.PasswordManager.BasePrice / 12).ToString("C", new CultureInfo("en-US"))));
}
- [Fact]
- public async Task HandleAsync_WhenMilestone3Disabled_AndFamilies2025Plan_DoesNotUpdateSubscription()
- {
- // Arrange
- var parsedEvent = new Event { Id = "evt_123", Type = "invoice.upcoming" };
- var customerId = "cus_123";
- var subscriptionId = "sub_123";
- var passwordManagerItemId = "si_pm_123";
-
- var invoice = new Invoice
- {
- CustomerId = customerId,
- AmountDue = 40000,
- NextPaymentAttempt = DateTime.UtcNow.AddDays(7),
- Lines = new StripeList
- {
- Data = [new() { Description = "Test Item" }]
- }
- };
-
- var families2025Plan = new Families2025Plan();
-
- var subscription = new Subscription
- {
- Id = subscriptionId,
- CustomerId = customerId,
- Items = new StripeList
- {
- Data =
- [
- new()
- {
- Id = passwordManagerItemId,
- Price = new Price { Id = families2025Plan.PasswordManager.StripePlanId }
- }
- ]
- },
- AutomaticTax = new SubscriptionAutomaticTax { Enabled = true },
- Metadata = new Dictionary()
- };
-
- var customer = new Customer
- {
- Id = customerId,
- Subscriptions = new StripeList { Data = [subscription] },
- Address = new Address { Country = "US" }
- };
-
- var organization = new Organization
- {
- Id = _organizationId,
- BillingEmail = "org@example.com",
- PlanType = PlanType.FamiliesAnnually2025
- };
-
- _stripeEventService.GetInvoice(parsedEvent).Returns(invoice);
- _stripeAdapter.GetCustomerAsync(customerId, Arg.Any()).Returns(customer);
- _stripeEventUtilityService
- .GetIdsFromMetadata(subscription.Metadata)
- .Returns(new Tuple(_organizationId, null, null));
- _organizationRepository.GetByIdAsync(_organizationId).Returns(organization);
- _pricingClient.GetPlanOrThrow(PlanType.FamiliesAnnually2025).Returns(families2025Plan);
- _featureService.IsEnabled(FeatureFlagKeys.PM26462_Milestone_3).Returns(false);
- _stripeEventUtilityService.IsSponsoredSubscription(subscription).Returns(false);
-
- // Act
- await _sut.HandleAsync(parsedEvent);
-
- // Assert - should not update subscription or organization when feature flag is disabled
- await _stripeAdapter.DidNotReceive().UpdateSubscriptionAsync(
- Arg.Any(),
- Arg.Any());
-
- await _organizationRepository.DidNotReceive().ReplaceAsync(
- Arg.Is(org => org.PlanType == PlanType.FamiliesAnnually));
- }
-
#region Premium Renewal Email Tests
[Fact]
@@ -3084,7 +2914,6 @@ public async Task HandleAsync_Families_DeferEnabled_CallsScheduler()
_organizationRepository.GetByIdAsync(_organizationId).Returns(organization);
_pricingClient.GetPlanOrThrow(PlanType.FamiliesAnnually2019).Returns(families2019Plan);
_pricingClient.GetPlanOrThrow(PlanType.FamiliesAnnually).Returns(new FamiliesPlan());
- _featureService.IsEnabled(FeatureFlagKeys.PM26462_Milestone_3).Returns(true);
_featureService.IsEnabled(FeatureFlagKeys.PM32645_DeferPriceMigrationToRenewal).Returns(true);
_stripeEventUtilityService.IsSponsoredSubscription(subscription).Returns(false);
_stripeAdapter.GetCouponAsync(CouponIDs.Milestone3SubscriptionDiscount)
diff --git a/test/Core.Test/Billing/Pricing/PricingClientTests.cs b/test/Core.Test/Billing/Pricing/PricingClientTests.cs
index caca997ed1db..83105ea7d17f 100644
--- a/test/Core.Test/Billing/Pricing/PricingClientTests.cs
+++ b/test/Core.Test/Billing/Pricing/PricingClientTests.cs
@@ -3,7 +3,6 @@
using Bit.Core.Billing.Enums;
using Bit.Core.Billing.Pricing;
using Bit.Core.Exceptions;
-using Bit.Core.Services;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using Microsoft.Extensions.Logging;
@@ -17,10 +16,10 @@ namespace Bit.Core.Test.Billing.Pricing;
[SutProviderCustomize]
public class PricingClientTests
{
- #region GetLookupKey Tests (via GetPlan)
+ #region GetPlan Lookup Key Tests
[Fact]
- public async Task GetPlan_WithFamiliesAnnually2025AndFeatureFlagEnabled_UsesFamilies2025LookupKey()
+ public async Task GetPlan_WithFamiliesAnnually2025_UsesFamilies2025LookupKey()
{
// Arrange
var mockHttp = new MockHttpMessageHandler();
@@ -32,82 +31,6 @@ public async Task GetPlan_WithFamiliesAnnually2025AndFeatureFlagEnabled_UsesFami
mockHttp.When(HttpMethod.Get, "*/plans/organization/*")
.Respond("application/json", planJson);
- var featureService = Substitute.For();
- featureService.IsEnabled(FeatureFlagKeys.PM26462_Milestone_3).Returns(true);
-
- var globalSettings = new GlobalSettings { SelfHosted = false };
-
- var httpClient = new HttpClient(mockHttp)
- {
- BaseAddress = new Uri("https://test.com/")
- };
-
- var logger = Substitute.For>();
- var pricingClient = new PricingClient(featureService, globalSettings, httpClient, logger);
-
- // Act
- var result = await pricingClient.GetPlan(PlanType.FamiliesAnnually2025);
-
- // Assert
- Assert.NotNull(result);
- Assert.Equal(PlanType.FamiliesAnnually2025, result.Type);
- mockHttp.VerifyNoOutstandingExpectation();
- }
-
- [Fact]
- public async Task GetPlan_WithFamiliesAnnually2025AndFeatureFlagDisabled_UsesFamiliesLookupKey()
- {
- // Arrange
- var mockHttp = new MockHttpMessageHandler();
- var planJson = CreatePlanJson("families", "Families", "families", 40M, "price_id");
-
- mockHttp.Expect(HttpMethod.Get, "https://test.com/plans/organization/families")
- .Respond("application/json", planJson);
-
- mockHttp.When(HttpMethod.Get, "*/plans/organization/*")
- .Respond("application/json", planJson);
-
- var featureService = Substitute.For();
- featureService.IsEnabled(FeatureFlagKeys.PM26462_Milestone_3).Returns(false);
-
- var globalSettings = new GlobalSettings { SelfHosted = false };
-
- var httpClient = new HttpClient(mockHttp)
- {
- BaseAddress = new Uri("https://test.com/")
- };
-
- var logger = Substitute.For>();
- var pricingClient = new PricingClient(featureService, globalSettings, httpClient, logger);
-
- // Act
- var result = await pricingClient.GetPlan(PlanType.FamiliesAnnually2025);
-
- // Assert
- Assert.NotNull(result);
- // PreProcessFamiliesPreMigrationPlan should change "families" to "families-2025" when FF is disabled
- Assert.Equal(PlanType.FamiliesAnnually2025, result.Type);
- mockHttp.VerifyNoOutstandingExpectation();
- }
-
- #endregion
-
- #region PreProcessFamiliesPreMigrationPlan Tests (via GetPlan)
-
- [Fact]
- public async Task GetPlan_WithFamiliesAnnually2025AndFeatureFlagDisabled_ReturnsFamiliesAnnually2025PlanType()
- {
- // Arrange
- var mockHttp = new MockHttpMessageHandler();
- // billing-pricing returns "families" lookup key because the flag is off
- var planJson = CreatePlanJson("families", "Families", "families", 40M, "price_id");
-
- mockHttp.When(HttpMethod.Get, "*/plans/organization/*")
- .Respond("application/json", planJson);
-
- var featureService = Substitute.For();
- featureService.IsEnabled(FeatureFlagKeys.PM26462_Milestone_3).Returns(false);
-
var globalSettings = new GlobalSettings { SelfHosted = false };
var httpClient = new HttpClient(mockHttp)
@@ -116,21 +39,19 @@ public async Task GetPlan_WithFamiliesAnnually2025AndFeatureFlagDisabled_Returns
};
var logger = Substitute.For>();
- var pricingClient = new PricingClient(featureService, globalSettings, httpClient, logger);
+ var pricingClient = new PricingClient(globalSettings, httpClient, logger);
// Act
var result = await pricingClient.GetPlan(PlanType.FamiliesAnnually2025);
// Assert
Assert.NotNull(result);
- // PreProcessFamiliesPreMigrationPlan should convert the families lookup key to families-2025
- // and the PlanAdapter should assign the correct FamiliesAnnually2025 plan type
Assert.Equal(PlanType.FamiliesAnnually2025, result.Type);
mockHttp.VerifyNoOutstandingExpectation();
}
[Fact]
- public async Task GetPlan_WithFamiliesAnnually2025AndFeatureFlagEnabled_ReturnsFamiliesAnnually2025PlanType()
+ public async Task GetPlan_WithFamiliesAnnually2025_ReturnsFamiliesAnnually2025PlanType()
{
// Arrange
var mockHttp = new MockHttpMessageHandler();
@@ -139,9 +60,6 @@ public async Task GetPlan_WithFamiliesAnnually2025AndFeatureFlagEnabled_ReturnsF
mockHttp.When(HttpMethod.Get, "*/plans/organization/*")
.Respond("application/json", planJson);
- var featureService = Substitute.For();
- featureService.IsEnabled(FeatureFlagKeys.PM26462_Milestone_3).Returns(true);
-
var globalSettings = new GlobalSettings { SelfHosted = false };
var httpClient = new HttpClient(mockHttp)
@@ -150,21 +68,19 @@ public async Task GetPlan_WithFamiliesAnnually2025AndFeatureFlagEnabled_ReturnsF
};
var logger = Substitute.For>();
- var pricingClient = new PricingClient(featureService, globalSettings, httpClient, logger);
+ var pricingClient = new PricingClient(globalSettings, httpClient, logger);
// Act
var result = await pricingClient.GetPlan(PlanType.FamiliesAnnually2025);
// Assert
Assert.NotNull(result);
- // PreProcessFamiliesPreMigrationPlan should ignore the lookup key because the flag is on
- // and the PlanAdapter should assign the correct FamiliesAnnually2025 plan type
Assert.Equal(PlanType.FamiliesAnnually2025, result.Type);
mockHttp.VerifyNoOutstandingExpectation();
}
[Fact]
- public async Task GetPlan_WithFamiliesAnnuallyAndFeatureFlagEnabled_ReturnsFamiliesAnnuallyPlanType()
+ public async Task GetPlan_WithFamiliesAnnually_ReturnsFamiliesAnnuallyPlanType()
{
// Arrange
var mockHttp = new MockHttpMessageHandler();
@@ -173,9 +89,6 @@ public async Task GetPlan_WithFamiliesAnnuallyAndFeatureFlagEnabled_ReturnsFamil
mockHttp.When(HttpMethod.Get, "*/plans/organization/*")
.Respond("application/json", planJson);
- var featureService = Substitute.For();
- featureService.IsEnabled(FeatureFlagKeys.PM26462_Milestone_3).Returns(true);
-
var globalSettings = new GlobalSettings { SelfHosted = false };
var httpClient = new HttpClient(mockHttp)
@@ -184,15 +97,13 @@ public async Task GetPlan_WithFamiliesAnnuallyAndFeatureFlagEnabled_ReturnsFamil
};
var logger = Substitute.For>();
- var pricingClient = new PricingClient(featureService, globalSettings, httpClient, logger);
+ var pricingClient = new PricingClient(globalSettings, httpClient, logger);
// Act
var result = await pricingClient.GetPlan(PlanType.FamiliesAnnually);
// Assert
Assert.NotNull(result);
- // PreProcessFamiliesPreMigrationPlan should ignore the lookup key because the flag is on
- // and the PlanAdapter should assign the correct FamiliesAnnually plan type
Assert.Equal(PlanType.FamiliesAnnually, result.Type);
mockHttp.VerifyNoOutstandingExpectation();
}
@@ -210,9 +121,6 @@ public async Task GetPlan_WithOtherLookupKey_KeepsLookupKeyUnchanged()
mockHttp.When(HttpMethod.Get, "*/plans/organization/*")
.Respond("application/json", planJson);
- var featureService = Substitute.For();
- featureService.IsEnabled(FeatureFlagKeys.PM26462_Milestone_3).Returns(false);
-
var globalSettings = new GlobalSettings { SelfHosted = false };
var httpClient = new HttpClient(mockHttp)
@@ -221,7 +129,7 @@ public async Task GetPlan_WithOtherLookupKey_KeepsLookupKeyUnchanged()
};
var logger = Substitute.For>();
- var pricingClient = new PricingClient(featureService, globalSettings, httpClient, logger);
+ var pricingClient = new PricingClient(globalSettings, httpClient, logger);
// Act
var result = await pricingClient.GetPlan(PlanType.EnterpriseAnnually);
@@ -237,47 +145,7 @@ public async Task GetPlan_WithOtherLookupKey_KeepsLookupKeyUnchanged()
#region ListPlans Tests
[Fact]
- public async Task ListPlans_WithFeatureFlagDisabled_ReturnsListWithPreProcessing()
- {
- // Arrange
- var mockHttp = new MockHttpMessageHandler();
- // biling-pricing would return "families" because the flag is disabled
- var plansJson = $@"[
- {CreatePlanJson("families", "Families", "families", 40M, "price_id")},
- {CreatePlanJson("enterprise-annually", "Enterprise", "enterprise", 144M, "price_id")}
- ]";
-
- mockHttp.When(HttpMethod.Get, "*/plans/organization")
- .Respond("application/json", plansJson);
-
- var featureService = Substitute.For();
- featureService.IsEnabled(FeatureFlagKeys.PM26462_Milestone_3).Returns(false);
-
- var globalSettings = new GlobalSettings { SelfHosted = false };
-
- var httpClient = new HttpClient(mockHttp)
- {
- BaseAddress = new Uri("https://test.com/")
- };
-
- var logger = Substitute.For>();
- var pricingClient = new PricingClient(featureService, globalSettings, httpClient, logger);
-
- // Act
- var result = await pricingClient.ListPlans();
-
- // Assert
- Assert.NotNull(result);
- Assert.Equal(2, result.Count);
- // First plan should have been preprocessed from "families" to "families-2025"
- Assert.Equal(PlanType.FamiliesAnnually2025, result[0].Type);
- // Second plan should remain unchanged
- Assert.Equal(PlanType.EnterpriseAnnually, result[1].Type);
- mockHttp.VerifyNoOutstandingExpectation();
- }
-
- [Fact]
- public async Task ListPlans_WithFeatureFlagEnabled_ReturnsListWithoutPreProcessing()
+ public async Task ListPlans_ReturnsPlans()
{
// Arrange
var mockHttp = new MockHttpMessageHandler();
@@ -288,9 +156,6 @@ public async Task ListPlans_WithFeatureFlagEnabled_ReturnsListWithoutPreProcessi
mockHttp.When(HttpMethod.Get, "*/plans/organization")
.Respond("application/json", plansJson);
- var featureService = Substitute.For();
- featureService.IsEnabled(FeatureFlagKeys.PM26462_Milestone_3).Returns(true);
-
var globalSettings = new GlobalSettings { SelfHosted = false };
var httpClient = new HttpClient(mockHttp)
@@ -299,7 +164,7 @@ public async Task ListPlans_WithFeatureFlagEnabled_ReturnsListWithoutPreProcessi
};
var logger = Substitute.For>();
- var pricingClient = new PricingClient(featureService, globalSettings, httpClient, logger);
+ var pricingClient = new PricingClient(globalSettings, httpClient, logger);
// Act
var result = await pricingClient.ListPlans();
@@ -307,7 +172,6 @@ public async Task ListPlans_WithFeatureFlagEnabled_ReturnsListWithoutPreProcessi
// Assert
Assert.NotNull(result);
Assert.Single(result);
- // Plan should remain as FamiliesAnnually when FF is enabled
Assert.Equal(PlanType.FamiliesAnnually, result[0].Type);
mockHttp.VerifyNoOutstandingExpectation();
}
@@ -353,9 +217,6 @@ public async Task GetPlan_WhenPricingServiceReturnsNotFound_ReturnsNull()
mockHttp.When(HttpMethod.Get, "*/plans/organization/*")
.Respond(HttpStatusCode.NotFound);
- var featureService = Substitute.For();
- featureService.IsEnabled(FeatureFlagKeys.PM26462_Milestone_3).Returns(true);
-
var globalSettings = new GlobalSettings { SelfHosted = false };
var httpClient = new HttpClient(mockHttp)
@@ -364,7 +225,7 @@ public async Task GetPlan_WhenPricingServiceReturnsNotFound_ReturnsNull()
};
var logger = Substitute.For>();
- var pricingClient = new PricingClient(featureService, globalSettings, httpClient, logger);
+ var pricingClient = new PricingClient(globalSettings, httpClient, logger);
// Act
var result = await pricingClient.GetPlan(PlanType.FamiliesAnnually2025);
@@ -381,9 +242,6 @@ public async Task GetPlan_WhenPricingServiceReturnsError_ThrowsBillingException(
mockHttp.When(HttpMethod.Get, "*/plans/organization/*")
.Respond(HttpStatusCode.InternalServerError);
- var featureService = Substitute.For();
- featureService.IsEnabled(FeatureFlagKeys.PM26462_Milestone_3).Returns(true);
-
var globalSettings = new GlobalSettings { SelfHosted = false };
var httpClient = new HttpClient(mockHttp)
@@ -392,7 +250,7 @@ public async Task GetPlan_WhenPricingServiceReturnsError_ThrowsBillingException(
};
var logger = Substitute.For>();
- var pricingClient = new PricingClient(featureService, globalSettings, httpClient, logger);
+ var pricingClient = new PricingClient(globalSettings, httpClient, logger);
// Act & Assert
await Assert.ThrowsAsync(() =>
@@ -427,8 +285,6 @@ public async Task ListPlans_WhenPricingServiceReturnsError_ThrowsBillingExceptio
mockHttp.When(HttpMethod.Get, "*/plans/organization")
.Respond(HttpStatusCode.InternalServerError);
- var featureService = Substitute.For();
-
var globalSettings = new GlobalSettings { SelfHosted = false };
var httpClient = new HttpClient(mockHttp)
@@ -437,7 +293,7 @@ public async Task ListPlans_WhenPricingServiceReturnsError_ThrowsBillingExceptio
};
var logger = Substitute.For>();
- var pricingClient = new PricingClient(featureService, globalSettings, httpClient, logger);
+ var pricingClient = new PricingClient(globalSettings, httpClient, logger);
// Act & Assert
await Assert.ThrowsAsync(() =>
@@ -461,7 +317,6 @@ public async Task ListPremiumPlans_Success_ReturnsPremiumPlans()
mockHttp.When(HttpMethod.Get, "*/plans/premium")
.Respond("application/json", plansJson);
- var featureService = Substitute.For();
var globalSettings = new GlobalSettings { SelfHosted = false };
var httpClient = new HttpClient(mockHttp)
@@ -470,7 +325,7 @@ public async Task ListPremiumPlans_Success_ReturnsPremiumPlans()
};
var logger = Substitute.For>();
- var pricingClient = new PricingClient(featureService, globalSettings, httpClient, logger);
+ var pricingClient = new PricingClient(globalSettings, httpClient, logger);
// Act
var result = await pricingClient.ListPremiumPlans();
@@ -514,7 +369,6 @@ public async Task ListPremiumPlans_WhenPricingServiceReturnsError_ThrowsBillingE
mockHttp.When(HttpMethod.Get, "*/plans/premium")
.Respond(HttpStatusCode.InternalServerError);
- var featureService = Substitute.For();
var globalSettings = new GlobalSettings { SelfHosted = false };
var httpClient = new HttpClient(mockHttp)
@@ -523,7 +377,7 @@ public async Task ListPremiumPlans_WhenPricingServiceReturnsError_ThrowsBillingE
};
var logger = Substitute.For>();
- var pricingClient = new PricingClient(featureService, globalSettings, httpClient, logger);
+ var pricingClient = new PricingClient(globalSettings, httpClient, logger);
// Act & Assert
await Assert.ThrowsAsync(() =>
@@ -547,7 +401,6 @@ public async Task GetAvailablePremiumPlan_WithAvailablePlan_ReturnsIt()
mockHttp.When(HttpMethod.Get, "*/plans/premium")
.Respond("application/json", plansJson);
- var featureService = Substitute.For();
var globalSettings = new GlobalSettings { SelfHosted = false };
var httpClient = new HttpClient(mockHttp)
@@ -556,7 +409,7 @@ public async Task GetAvailablePremiumPlan_WithAvailablePlan_ReturnsIt()
};
var logger = Substitute.For>();
- var pricingClient = new PricingClient(featureService, globalSettings, httpClient, logger);
+ var pricingClient = new PricingClient(globalSettings, httpClient, logger);
// Act
var result = await pricingClient.GetAvailablePremiumPlan();
@@ -579,7 +432,6 @@ public async Task GetAvailablePremiumPlan_WithNoAvailablePlan_ThrowsNotFoundExce
mockHttp.When(HttpMethod.Get, "*/plans/premium")
.Respond("application/json", plansJson);
- var featureService = Substitute.For();
var globalSettings = new GlobalSettings { SelfHosted = false };
var httpClient = new HttpClient(mockHttp)
@@ -588,7 +440,7 @@ public async Task GetAvailablePremiumPlan_WithNoAvailablePlan_ThrowsNotFoundExce
};
var logger = Substitute.For>();
- var pricingClient = new PricingClient(featureService, globalSettings, httpClient, logger);
+ var pricingClient = new PricingClient(globalSettings, httpClient, logger);
// Act & Assert
await Assert.ThrowsAsync(() =>
@@ -603,7 +455,6 @@ public async Task GetAvailablePremiumPlan_WithEmptyList_ThrowsNotFoundException(
mockHttp.When(HttpMethod.Get, "*/plans/premium")
.Respond("application/json", "[]");
- var featureService = Substitute.For();
var globalSettings = new GlobalSettings { SelfHosted = false };
var httpClient = new HttpClient(mockHttp)
@@ -612,7 +463,7 @@ public async Task GetAvailablePremiumPlan_WithEmptyList_ThrowsNotFoundException(
};
var logger = Substitute.For>();
- var pricingClient = new PricingClient(featureService, globalSettings, httpClient, logger);
+ var pricingClient = new PricingClient(globalSettings, httpClient, logger);
// Act & Assert
await Assert.ThrowsAsync(() =>