using NSubstitute; using PnvPanel.Application.Auth; using PnvPanel.Application.Common.Interfaces; using PnvPanel.Application.Common.Models; using PnvPanel.Application.Tests.TestSupport; using PnvPanel.Domain.Telegram; using Xunit; using TelegramNs = PnvPanel.Application.Telegram; namespace PnvPanel.Application.Tests.Telegram; public class GetLoginRequestStatusQueryHandlerTests { private readonly IIdentityService _identityService = Substitute.For(); private readonly IJwtTokenService _jwtTokenService = Substitute.For(); private readonly IRefreshTokenService _refreshTokenService = Substitute.For(); private TelegramNs.GetLoginRequestStatusQueryHandler CreateHandler( PnvPanel.Infrastructure.Persistence.AppDbContext dbContext ) => new(dbContext, _identityService, _jwtTokenService, _refreshTokenService); [Fact] public async Task Handle_WhenRequestNotFound_ReturnsNotFound() { using var dbContext = InMemoryDbContextFactory.Create(); var handler = CreateHandler(dbContext); var result = await handler.Handle( new TelegramNs.GetLoginRequestStatusQuery(Guid.NewGuid()), CancellationToken.None ); Assert.False(result.IsSuccess); Assert.Equal(TelegramNs.TelegramErrors.LoginRequestNotFound, result.Error); } [Fact] public async Task Handle_WhenPendingAndExpired_ReturnsExpiredStatusWithoutIssuingTokens() { using var dbContext = InMemoryDbContextFactory.Create(); var request = TelegramLoginRequest.Create(TimeSpan.FromMinutes(-5), null); dbContext.TelegramLoginRequests.Add(request); await dbContext.SaveChangesAsync(CancellationToken.None); var handler = CreateHandler(dbContext); var result = await handler.Handle( new TelegramNs.GetLoginRequestStatusQuery(request.Id), CancellationToken.None ); Assert.True(result.IsSuccess); Assert.Equal(TelegramLoginStatus.Expired, result.Value.Status); Assert.Null(result.Value.Auth); await _refreshTokenService .DidNotReceive() .IssueAsync(Arg.Any(), Arg.Any()); } [Fact] public async Task Handle_WhenStillPending_ReturnsPendingStatusWithoutAuth() { using var dbContext = InMemoryDbContextFactory.Create(); var request = TelegramLoginRequest.Create(TimeSpan.FromMinutes(5), null); dbContext.TelegramLoginRequests.Add(request); await dbContext.SaveChangesAsync(CancellationToken.None); var handler = CreateHandler(dbContext); var result = await handler.Handle( new TelegramNs.GetLoginRequestStatusQuery(request.Id), CancellationToken.None ); Assert.True(result.IsSuccess); Assert.Equal(TelegramLoginStatus.Pending, result.Value.Status); Assert.Null(result.Value.Auth); } [Fact] public async Task Handle_WhenApproved_ConsumesRequestAndReturnsAuthResult() { using var dbContext = InMemoryDbContextFactory.Create(); var userId = Guid.NewGuid(); var request = TelegramLoginRequest.Create(TimeSpan.FromMinutes(5), null); request.Approve(userId); dbContext.TelegramLoginRequests.Add(request); await dbContext.SaveChangesAsync(CancellationToken.None); var profile = new CurrentUserProfile( userId, "alice", Guid.NewGuid(), "user", true, false, 3, RoleQuota.Unlimited, "sub-token", false, null, false ); _identityService.GetProfileAsync(userId, Arg.Any()).Returns(profile); _jwtTokenService .GenerateAccessToken(Arg.Any()) .Returns(("access-token", DateTimeOffset.UtcNow.AddMinutes(15))); _refreshTokenService .IssueAsync(userId, Arg.Any()) .Returns(new IssuedRefreshToken("refresh-token", DateTimeOffset.UtcNow.AddDays(30))); var handler = CreateHandler(dbContext); var result = await handler.Handle( new TelegramNs.GetLoginRequestStatusQuery(request.Id), CancellationToken.None ); Assert.True(result.IsSuccess); Assert.Equal(TelegramLoginStatus.Approved, result.Value.Status); Assert.NotNull(result.Value.Auth); Assert.Equal("access-token", result.Value.Auth!.AccessToken); Assert.True(result.Value.Auth.User.TelegramLinked); Assert.Equal(TelegramLoginStatus.Consumed, request.Status); } [Fact] public async Task Handle_WhenApprovedButProfileMissing_ReturnsUnauthorized() { using var dbContext = InMemoryDbContextFactory.Create(); var userId = Guid.NewGuid(); var request = TelegramLoginRequest.Create(TimeSpan.FromMinutes(5), null); request.Approve(userId); dbContext.TelegramLoginRequests.Add(request); await dbContext.SaveChangesAsync(CancellationToken.None); _identityService .GetProfileAsync(userId, Arg.Any()) .Returns((CurrentUserProfile?)null); var handler = CreateHandler(dbContext); var result = await handler.Handle( new TelegramNs.GetLoginRequestStatusQuery(request.Id), CancellationToken.None ); Assert.False(result.IsSuccess); Assert.Equal(AuthErrors.Unauthorized, result.Error); } }