using NSubstitute; using PnvPanel.Application.Auth; using PnvPanel.Application.Common.Interfaces; 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); _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); } }