Files
UniVerse/backend/UniVerse.Api.Tests/Auth/AuthServiceTests.cs
T
serega404 038f0d89a6
gitea-push-docker.yml (push) Invalid workflow file
Backend CI / build-and-test (push) Successful in 3m34s
Frontend CI / build-and-check (push) Failing after 21s
feat: добавил отображение аватарки
2026-10-01 00:17:16 +03:00

140 lines
5.3 KiB
C#

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging.Abstractions;
using NSubstitute;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using UniVerse.Application.DTOs.Notifications;
using UniVerse.Application.Interfaces;
using UniVerse.Domain.Entities;
using UniVerse.Domain.Enums;
using UniVerse.Domain.Exceptions;
using UniVerse.Infrastructure.Data;
using UniVerse.Infrastructure.Services;
using Xunit;
namespace UniVerse.Api.Tests.Auth;
public class AuthServiceTests
{
[Fact]
public async Task RefreshTokenAsync_InactiveUser_RevokesTokenAndThrowsForbidden()
{
await using var db = CreateDbContext();
db.Users.Add(new User
{
Id = 1,
Email = "blocked@test.local",
IsActive = false,
Roles = [new UserRoleAssignment { UserId = 1, Role = UserRole.Student }]
});
db.RefreshTokens.Add(new RefreshToken
{
Id = 1,
UserId = 1,
Token = "refresh-token",
ExpiresAt = DateTime.UtcNow.AddDays(1),
CreatedAt = DateTime.UtcNow
});
await db.SaveChangesAsync();
var service = CreateService(db);
await Assert.ThrowsAsync<ForbiddenException>(() => service.RefreshTokenAsync("refresh-token"));
var token = await db.RefreshTokens.SingleAsync(t => t.Token == "refresh-token");
Assert.NotNull(token.RevokedAt);
}
[Fact]
public async Task GetCurrentUserAsync_InactiveUser_ThrowsForbidden()
{
await using var db = CreateDbContext();
db.Users.Add(new User
{
Id = 1,
Email = "blocked@test.local",
IsActive = false,
Roles = [new UserRoleAssignment { UserId = 1, Role = UserRole.Student }]
});
await db.SaveChangesAsync();
var service = CreateService(db);
await Assert.ThrowsAsync<ForbiddenException>(() => service.GetCurrentUserAsync(1));
}
[Fact]
public async Task LoginWithMicrosoftAsync_LinksScheduleTeacherBySubId()
{
await using var db = CreateDbContext();
db.Users.Add(new User
{
Id = 10,
Email = "modeus-person-1@modeus.local",
DisplayName = "Иванов Иван Иванович",
MicrosoftId = "sso-sub-1",
IsActive = true,
Roles = [new UserRoleAssignment { UserId = 10, Role = UserRole.Teacher }],
TeacherProfile = new TeacherProfile { UserId = 10, ModeusId = "person-1" }
});
await db.SaveChangesAsync();
var microsoftAuth = Substitute.For<IMicrosoftAuthClient>();
microsoftAuth.ExchangeAuthorizationCodeAsync("code", "http://localhost/callback", Arg.Any<CancellationToken>())
.Returns(new MicrosoftTokenResult(BuildIdToken("sso-sub-1", "teacher@sfedu.ru", "Иванов Иван Иванович")));
var service = CreateService(db, microsoftAuth);
var result = await service.LoginWithMicrosoftAsync("code", "http://localhost/callback");
Assert.Equal(10, result.Response.User.Id);
Assert.Equal("teacher@sfedu.ru", result.Response.User.Email);
Assert.Contains(UserRole.Teacher, result.Response.User.Roles);
Assert.Single(await db.Users.ToListAsync());
var user = await db.Users.Include(u => u.TeacherProfile).SingleAsync();
Assert.Equal("sso-sub-1", user.MicrosoftId);
Assert.Equal("person-1", user.TeacherProfile?.ModeusId);
await microsoftAuth.Received(1).SaveTokenCacheAsync(10, Arg.Any<MicrosoftTokenResult>(), Arg.Any<CancellationToken>());
}
private static AppDbContext CreateDbContext()
{
var options = new DbContextOptionsBuilder<AppDbContext>()
.UseInMemoryDatabase($"AuthServiceTests_{Guid.NewGuid()}")
.Options;
return new AppDbContext(options);
}
private static AuthService CreateService(AppDbContext db, IMicrosoftAuthClient? microsoftAuth = null)
{
var config = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string?>
{
["Jwt:Secret"] = "test-secret-test-secret-test-secret-test-secret",
["Jwt:Issuer"] = "UniVerse.Tests",
["Jwt:Audience"] = "UniVerse.Tests",
["Jwt:AccessTokenExpirationMinutes"] = "15",
["Jwt:RefreshTokenExpirationDays"] = "30"
})
.Build();
var gamification = Substitute.For<IGamificationService>();
gamification.CalculateLevelAsync(Arg.Any<int>()).Returns(1);
var notifications = Substitute.For<INotificationService>();
notifications.SendAsync(Arg.Any<NotificationMessage>(), Arg.Any<CancellationToken>())
.Returns(Task.CompletedTask);
microsoftAuth ??= Substitute.For<IMicrosoftAuthClient>();
return new AuthService(db, config, microsoftAuth, gamification, notifications, NullLogger<AuthService>.Instance);
}
private static string BuildIdToken(string sub, string email, string name)
{
var token = new JwtSecurityToken(claims:
[
new Claim(JwtRegisteredClaimNames.Sub, sub),
new Claim("preferred_username", email),
new Claim("name", name)
]);
return new JwtSecurityTokenHandler().WriteToken(token);
}
}