Files
PnvPanel/backend/tests/PnvPanel.Application.Tests/Admin/Inbounds/DeleteInboundCommandHandlerTests.cs
T
Leonid Pershin 33ad98cf62
CI / Backend (build + test) (push) Successful in 1m22s
CI / Frontend (lint + typecheck + build) (push) Successful in 34s
Enhance admin endpoints and queries for improved filtering and management
- Updated `ListPaymentRequestsQuery` to include `Kind` and `Search` parameters for better filtering of payment requests.
- Enhanced `ListAuditLogsQuery` to support additional filters: `Source`, `TargetType`, and `Action`, improving audit log retrieval.
- Modified `ListUsersQuery` to accept new filters: `RoleId`, `IsActivated`, `IsBlocked`, and `BillingExpired`, allowing for more granular user management.
- Introduced `DeleteInbound` endpoint to allow deletion of inbounds that are not currently available, enhancing inbound management capabilities.
- Updated frontend API calls to reflect new query parameters and support for additional filtering options in the admin interface.
- Revised API documentation to include new parameters and endpoint functionalities for better clarity and usage guidance.
2026-07-20 10:35:48 +03:00

89 lines
3.5 KiB
C#

using NSubstitute;
using PnvPanel.Application.Admin.Inbounds;
using PnvPanel.Application.Common.Interfaces;
using PnvPanel.Application.Tests.TestSupport;
using PnvPanel.Domain.Configs;
using PnvPanel.Domain.Inbounds;
using Xunit;
namespace PnvPanel.Application.Tests.Admin.Inbounds;
public class DeleteInboundCommandHandlerTests
{
private readonly IRealtimeNotifier _notifier = Substitute.For<IRealtimeNotifier>();
private readonly ICurrentUser _currentUser = Substitute.For<ICurrentUser>();
private DeleteInboundCommandHandler CreateHandler(IAppDbContext dbContext) =>
new(dbContext, _notifier, _currentUser);
[Fact]
public async Task Handle_WhenInboundNotFound_ReturnsNotFound()
{
using var dbContext = InMemoryDbContextFactory.Create();
var result = await CreateHandler(dbContext)
.Handle(new DeleteInboundCommand(Guid.NewGuid()), CancellationToken.None);
Assert.False(result.IsSuccess);
Assert.Equal(InboundErrors.NotFound, result.Error);
}
[Fact]
public async Task Handle_WhenInboundStillAvailable_ReturnsStillAvailable()
{
using var dbContext = InMemoryDbContextFactory.Create();
var inbound = Inbound.FromRemote(Guid.NewGuid(), "1", VpnProtocol.Vless, "remark", 443);
dbContext.Inbounds.Add(inbound);
await dbContext.SaveChangesAsync(CancellationToken.None);
var result = await CreateHandler(dbContext)
.Handle(new DeleteInboundCommand(inbound.Id), CancellationToken.None);
Assert.False(result.IsSuccess);
Assert.Equal(InboundErrors.StillAvailable, result.Error);
Assert.NotNull(await dbContext.Inbounds.FindAsync([inbound.Id], CancellationToken.None));
}
[Fact]
public async Task Handle_WhenUnavailable_RevokesActiveConfigsAndDeletesInbound()
{
using var dbContext = InMemoryDbContextFactory.Create();
var inbound = Inbound.FromRemote(Guid.NewGuid(), "1", VpnProtocol.Vless, "remark", 443);
inbound.MarkUnavailable();
var userId = Guid.NewGuid();
var activeConfig = VpnConfig.Create(userId, inbound.Id, VpnProtocol.Vless, null);
var alreadyRevoked = VpnConfig.Create(userId, inbound.Id, VpnProtocol.Vless, null);
alreadyRevoked.Revoke();
dbContext.Inbounds.Add(inbound);
dbContext.VpnConfigs.AddRange(activeConfig, alreadyRevoked);
await dbContext.SaveChangesAsync(CancellationToken.None);
var result = await CreateHandler(dbContext)
.Handle(new DeleteInboundCommand(inbound.Id), CancellationToken.None);
// UnitOfWorkBehavior делает это в реальном пайплайне — здесь хендлер вызывается напрямую.
await dbContext.SaveChangesAsync(CancellationToken.None);
Assert.True(result.IsSuccess);
Assert.Equal(ConfigStatus.Revoked, activeConfig.Status);
Assert.Null(await dbContext.Inbounds.FindAsync([inbound.Id], CancellationToken.None));
await _notifier
.Received(1)
.NotifyConfigStatusChangedAsync(
userId,
activeConfig.Id,
ConfigStatus.Revoked,
Arg.Any<CancellationToken>()
);
await _notifier
.DidNotReceive()
.NotifyConfigStatusChangedAsync(
userId,
alreadyRevoked.Id,
Arg.Any<ConfigStatus>(),
Arg.Any<CancellationToken>()
);
}
}