using FluentAssertions; using Microsoft.EntityFrameworkCore; using Xunit; using BuildFlow.Platform.Application.Auth.Commands; using BuildFlow.Platform.Application.Auth.Handlers; using BuildFlow.Shared.Domain.Exceptions; namespace BuildFlow.Platform.Tests.Auth; /// /// 刷新令牌 Command 处理器单元测试。覆盖正常刷新 + Rotation、过期/吊销、不存在等路径。 /// public class RefreshTokenCommandHandlerTests { private static async Task<(Platform.Infrastructure.Persistence.PlatformDbContext db, string refreshToken)> SeedTokenAsync( bool revoked = false, DateTime? expiresAt = null, int permissionVersion = 0) { var db = PlatformTestDb.CreateDbContext(); var userId = Guid.NewGuid(); await PlatformTestDb.SeedUserAsync(db, userId, "refresher", permissionVersion: permissionVersion); var token = "valid-refresh-token"; db.RefreshTokens.Add(new BuildFlow.Platform.Domain.Entities.RefreshToken.RefreshTokenEntity { Id = Guid.NewGuid(), UserId = userId, Token = token, ExpiresAt = expiresAt ?? DateTime.UtcNow.AddDays(1), IsRevoked = revoked, CreatedBy = "test", CreatedAt = DateTime.UtcNow, UpdatedBy = "test", UpdatedAt = DateTime.UtcNow, }); await db.SaveChangesAsync(); return (db, token); } [Fact] public async Task Handle_ValidToken_ShouldRotateAndIssueNewToken() { // Arrange var (db, token) = await SeedTokenAsync(); var handler = new RefreshTokenCommandHandler(db, PlatformTestDb.CreateConfig()); // Act var result = await handler.Handle(new RefreshTokenCommand(token), CancellationToken.None); // Assert:新 token 签发 + 旧 token 被吊销(Rotation) result.AccessToken.Should().NotBeNullOrWhiteSpace(); result.RefreshToken.Should().NotBe(token); var oldToken = await db.RefreshTokens.FirstAsync(rt => rt.Token == token); oldToken.IsRevoked.Should().BeTrue(); } [Fact] public async Task Handle_RevokedToken_ShouldThrowExpired() { // Arrange var (db, token) = await SeedTokenAsync(revoked: true); var handler = new RefreshTokenCommandHandler(db, PlatformTestDb.CreateConfig()); // Act var act = () => handler.Handle(new RefreshTokenCommand(token), CancellationToken.None); // Assert await act.Should().ThrowAsync() .WithMessage("*刷新令牌已过期或已吊销*"); } [Fact] public async Task Handle_NonExistentToken_ShouldThrowUnauthorized() { // Arrange var db = PlatformTestDb.CreateDbContext(); var handler = new RefreshTokenCommandHandler(db, PlatformTestDb.CreateConfig()); // Act var act = () => handler.Handle(new RefreshTokenCommand("nonexistent"), CancellationToken.None); // Assert await act.Should().ThrowAsync() .WithMessage("*无效的刷新令牌*"); } }