using NSubstitute; using PnvPanel.Application.Admin.Users; using PnvPanel.Application.Common.Interfaces; using PnvPanel.Application.Common.Models; using PnvPanel.Application.Plans; using PnvPanel.Application.Tests.TestSupport; using PnvPanel.Domain.Plans; using Xunit; namespace PnvPanel.Application.Tests.Admin.Users; public class AdminSetUserPlanCommandHandlerTests { private readonly IIdentityService _identityService = Substitute.For(); private static CurrentUserProfile Profile(Guid userId, string role, int configQuota) => new( userId, "alice", Guid.NewGuid(), role, IsActivated: true, IsBlocked: false, ConfigQuota: configQuota, PlanId: null, MaxIpLimit: 2, SubscriptionToken: "sub-token", BillingEnabled: false, BillingPaidUntil: null, BillingSuspended: false ); [Fact] public async Task Handle_WhenUnlimitedForNonAdmin_ReturnsUnlimitedOnlyForAdmin() { using var dbContext = InMemoryDbContextFactory.Create(); var userId = Guid.NewGuid(); _identityService .GetProfileAsync(userId, Arg.Any()) .Returns(Profile(userId, "user", 3)); var handler = new AdminSetUserPlanCommandHandler( dbContext, _identityService, FakeCurrentUser.Authenticated(Guid.NewGuid()) ); var result = await handler.Handle( new AdminSetUserPlanCommand(userId, null, RoleQuota.Unlimited), CancellationToken.None ); Assert.False(result.IsSuccess); Assert.Equal(PlanErrors.UnlimitedOnlyForAdmin, result.Error); await _identityService .DidNotReceive() .SetConfigQuotaAsync(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()); } [Fact] public async Task Handle_WhenUnlimitedForAdmin_Succeeds() { using var dbContext = InMemoryDbContextFactory.Create(); var userId = Guid.NewGuid(); _identityService .GetProfileAsync(userId, Arg.Any()) .Returns(Profile(userId, "admin", -1)); _identityService .SetConfigQuotaAsync(userId, RoleQuota.Unlimited, null, Arg.Any()) .Returns(Result.Success()); var handler = new AdminSetUserPlanCommandHandler( dbContext, _identityService, FakeCurrentUser.Authenticated(Guid.NewGuid()) ); var result = await handler.Handle( new AdminSetUserPlanCommand(userId, null, RoleQuota.Unlimited), CancellationToken.None ); Assert.True(result.IsSuccess); await _identityService .Received(1) .SetConfigQuotaAsync(userId, RoleQuota.Unlimited, null, Arg.Any()); } [Fact] public async Task Handle_WithPlanId_UsesPlanConfigCount() { using var dbContext = InMemoryDbContextFactory.Create(); var userId = Guid.NewGuid(); var plan = Plan.Create("Плюс", 6, 0); dbContext.Plans.Add(plan); await dbContext.SaveChangesAsync(CancellationToken.None); _identityService .SetConfigQuotaAsync(userId, 6, plan.Id, Arg.Any()) .Returns(Result.Success()); var handler = new AdminSetUserPlanCommandHandler( dbContext, _identityService, FakeCurrentUser.Authenticated(Guid.NewGuid()) ); var result = await handler.Handle( new AdminSetUserPlanCommand(userId, plan.Id, null), CancellationToken.None ); Assert.True(result.IsSuccess); await _identityService .Received(1) .SetConfigQuotaAsync(userId, 6, plan.Id, Arg.Any()); Assert.Single(dbContext.AuditLogs.Local); } [Fact] public async Task Handle_WhenPlanNotFound_ReturnsNotFound() { using var dbContext = InMemoryDbContextFactory.Create(); var handler = new AdminSetUserPlanCommandHandler( dbContext, _identityService, FakeCurrentUser.Authenticated(Guid.NewGuid()) ); var result = await handler.Handle( new AdminSetUserPlanCommand(Guid.NewGuid(), Guid.NewGuid(), null), CancellationToken.None ); Assert.False(result.IsSuccess); Assert.Equal(PlanErrors.NotFound, result.Error); } }