test(billing): prove downgrade lifecycle
CI and Deploy / test (pull_request) Successful in 5m27s
CI and Deploy / deploy (pull_request) Has been skipped

This commit is contained in:
cesnimda
2026-08-15 20:28:23 +02:00
parent 25a6da951e
commit 191de69c48
9 changed files with 217 additions and 17 deletions
+10 -10
View File
@@ -18,19 +18,22 @@ public sealed class BillingController : ControllerBase
private readonly RoleManager<IdentityRole> _roles;
private readonly ILogger<BillingController> _logger;
private readonly ExternalOrigin _externalOrigin;
private readonly IStripeBillingGateway _stripe;
public BillingController(
IConfiguration configuration,
UserManager<ApplicationUser> users,
RoleManager<IdentityRole> roles,
ILogger<BillingController> logger,
ExternalOrigin? externalOrigin = null)
ExternalOrigin? externalOrigin = null,
IStripeBillingGateway? stripe = null)
{
_configuration = configuration;
_users = users;
_roles = roles;
_logger = logger;
_externalOrigin = externalOrigin ?? ExternalOrigin.FromConfiguration(configuration);
_stripe = stripe ?? new StripeBillingGateway();
}
public sealed record BillingRedirectDto(string Url);
@@ -86,8 +89,7 @@ public sealed class BillingController : ControllerBase
try
{
var session = await new Stripe.Checkout.SessionService(new StripeClient(secretKey))
.CreateAsync(options, cancellationToken: cancellationToken);
var session = await _stripe.CreateCheckoutAsync(secretKey, options, cancellationToken);
if (string.IsNullOrWhiteSpace(session.Url))
return Problem(statusCode: StatusCodes.Status502BadGateway, title: "Stripe did not return a checkout URL.");
return Ok(new BillingRedirectDto(session.Url));
@@ -113,12 +115,11 @@ public sealed class BillingController : ControllerBase
try
{
var session = await new Stripe.BillingPortal.SessionService(new StripeClient(secretKey))
.CreateAsync(new Stripe.BillingPortal.SessionCreateOptions
var session = await _stripe.CreatePortalAsync(secretKey, new Stripe.BillingPortal.SessionCreateOptions
{
Customer = user.StripeCustomerId,
ReturnUrl = $"{publicBaseUrl}/settings",
}, cancellationToken: cancellationToken);
}, cancellationToken);
return Ok(new BillingRedirectDto(session.Url));
}
catch (StripeException ex)
@@ -143,7 +144,7 @@ public sealed class BillingController : ControllerBase
Event stripeEvent;
try
{
stripeEvent = EventUtility.ConstructEvent(json, Request.Headers["Stripe-Signature"].ToString(), webhookSecret);
stripeEvent = _stripe.ConstructEvent(json, Request.Headers["Stripe-Signature"].ToString(), webhookSecret);
}
catch (StripeException ex)
{
@@ -164,8 +165,7 @@ public sealed class BillingController : ControllerBase
{
// Stripe does not guarantee webhook delivery order. Re-read the subscription so a late
// event cannot restore access after a newer cancellation or payment failure.
subscription = await new SubscriptionService(new StripeClient(secretKey))
.GetAsync(eventSubscription.Id, cancellationToken: cancellationToken);
subscription = await _stripe.GetSubscriptionAsync(secretKey, eventSubscription.Id, cancellationToken);
}
catch (StripeException ex)
{
@@ -229,6 +229,6 @@ public sealed class BillingController : ControllerBase
premiumPrice = (_configuration["Stripe:PricePremium"] ?? string.Empty).Trim();
webhookSecret = (_configuration["Stripe:WebhookSecret"] ?? string.Empty).Trim();
publicBaseUrl = _externalOrigin.BaseUrl;
return secretKey.Length > 0 && premiumPrice.Length > 0 && webhookSecret.Length > 0;
return secretKey.Length > 0 && premiumPrice.StartsWith("price_", StringComparison.Ordinal) && webhookSecret.Length > 0;
}
}