Customer Portal : StripeService.CreateBillingPortalSessionAsync + POST /api/onboarding/billing-portal, calqué sur checkout-session. Une garde absente de l'énoncé : StripeCustomerId peut être nul, car CreateCustomerAsync n'est appelée que par l'inscription self-service. Les 4 instances venues de Mongo n'ont jamais vu Stripe — sans la garde, elles recevaient une erreur d'API Stripe illisible côté front. 409, distinct du 404 d'instance inconnue. Ratio jetons -> questions : InstanceQuotaDTO.aiTokensPerQuestion, mesuré sur les VisitorQuestion.TokensUsed de l'instance, seuil de 20 questions avant de faire foi — une seule réponse citant un long article doublerait la moyenne. En dessous, repli sur l'hypothèse de la grille tarifaire (10 000, pas 1 000 : le /1000 de manager-app était faux d'un facteur 10). Trois autres points du lot F étaient déjà faits et n'attendaient qu'une vérification : rate limiting, endpoint ApplicationInstance, quotas seed. 6 tests. dotnet test : 197 passés, 14 sautés, 0 échec. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
78 lines
2.7 KiB
C#
78 lines
2.7 KiB
C#
using ManagerService.Controllers;
|
|
using ManagerService.Data;
|
|
using ManagerService.Helpers;
|
|
using ManagerService.Services;
|
|
using ManagerService.Tests.Infrastructure;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.Logging.Abstractions;
|
|
using Microsoft.Extensions.Options;
|
|
using Moq;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Net.Http;
|
|
using System.Threading.Tasks;
|
|
using Xunit;
|
|
|
|
namespace ManagerService.Tests.Controllers
|
|
{
|
|
/// <summary>
|
|
/// Les deux gardes du portail de facturation. L'appel à Stripe lui-même n'est pas couvert :
|
|
/// il part sur le réseau, et ces tests s'arrêtent avant — c'est justement ce qui compte,
|
|
/// un client sans compte Stripe ne doit jamais atteindre l'API.
|
|
/// </summary>
|
|
public class OnboardingControllerTests
|
|
{
|
|
private OnboardingController BuildController(MyInfoMateDbContext db, string callerInstanceId = "i1")
|
|
{
|
|
var configuration = new ConfigurationBuilder()
|
|
.AddInMemoryCollection(new Dictionary<string, string>
|
|
{
|
|
["AppUrls:ManagerApp"] = "https://manager.myinfomate.be"
|
|
})
|
|
.Build();
|
|
|
|
var stripeService = new StripeService(Options.Create(new StripeSettings
|
|
{
|
|
SecretKey = "sk_test_dummy",
|
|
WebhookSecret = "whsec_dummy",
|
|
EssentielPriceId = "price_dummy"
|
|
}));
|
|
|
|
var controller = new OnboardingController(
|
|
db,
|
|
new ProfileLogic(NullLogger<ProfileLogic>.Instance),
|
|
new Mock<IEmailService>().Object,
|
|
configuration,
|
|
NullLogger<OnboardingController>.Instance,
|
|
new Mock<IHttpClientFactory>().Object,
|
|
stripeService);
|
|
|
|
FakeUser.SetUser(controller, FakeUser.Create(Permissions.SuperAdmin, callerInstanceId));
|
|
return controller;
|
|
}
|
|
|
|
[Fact]
|
|
public async Task CreateBillingPortalSession_UnknownInstance_Returns404()
|
|
{
|
|
using var db = DbContextFactory.Create();
|
|
|
|
var result = await BuildController(db, "unknown").CreateBillingPortalSession();
|
|
|
|
Assert.IsType<NotFoundObjectResult>(result);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task CreateBillingPortalSession_NoStripeCustomer_Returns409()
|
|
{
|
|
using var db = DbContextFactory.Create();
|
|
db.Instances.Add(new Instance { Id = "i1", Name = "Musée", DateCreation = DateTime.UtcNow });
|
|
db.SaveChanges();
|
|
|
|
var result = await BuildController(db).CreateBillingPortalSession();
|
|
|
|
Assert.IsType<ConflictObjectResult>(result);
|
|
}
|
|
}
|
|
}
|