using System.Net; using System.Net.Http.Headers; using System.Net.Http.Json; using System.Text.Json; using Microsoft.AspNetCore.Mvc.Testing; using Vanguard.Server.Auth; using Xunit.Sdk; namespace Vanguard.Server.Tests; public class AuthTests { private static readonly JsonSerializerOptions Json = new(JsonSerializerDefaults.Web); [Fact] public async Task Register_Login_Refresh_Rotation_Logout() { using var factory = new WebApplicationFactory(); using var http = factory.CreateClient(); var userName = "user" + Guid.NewGuid().ToString("N")[..8]; var registered = await RegisterAsync(http, userName); Assert.False(registered.OnboardingCompleted); using var authed = factory.CreateClient(); authed.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", registered.AccessToken); var me = await authed.GetFromJsonAsync("/api/auth/me", Json); Assert.NotNull(me); Assert.Equal(userName, me!.UserName); Assert.Equal(0, me.Gold); Assert.Equal(0, me.Tokens); var loginResponse = await http.PostAsJsonAsync( "/api/auth/login", new { userName, password = "password123" }, Json); loginResponse.EnsureSuccessStatusCode(); var login = (await loginResponse.Content.ReadFromJsonAsync(Json))!; var refreshResponse = await http.PostAsJsonAsync( "/api/auth/refresh", new { refreshToken = login.RefreshToken }, Json); refreshResponse.EnsureSuccessStatusCode(); var refreshed = (await refreshResponse.Content.ReadFromJsonAsync(Json))!; Assert.NotEqual(login.RefreshToken, refreshed.RefreshToken); Assert.NotEqual(login.AccessToken, refreshed.AccessToken); // старый refresh после ротации больше не действует var reused = await http.PostAsJsonAsync( "/api/auth/refresh", new { refreshToken = login.RefreshToken }, Json); Assert.Equal(HttpStatusCode.Unauthorized, reused.StatusCode); var logout = await http.PostAsJsonAsync( "/api/auth/logout", new { refreshToken = refreshed.RefreshToken }, Json); Assert.Equal(HttpStatusCode.NoContent, logout.StatusCode); var afterLogout = await http.PostAsJsonAsync( "/api/auth/refresh", new { refreshToken = refreshed.RefreshToken }, Json); Assert.Equal(HttpStatusCode.Unauthorized, afterLogout.StatusCode); } [Fact] public async Task Weak_Password_And_Duplicate_User_Are_Rejected() { using var factory = new WebApplicationFactory(); using var http = factory.CreateClient(); var userName = "weak" + Guid.NewGuid().ToString("N")[..8]; var weak = await http.PostAsJsonAsync( "/api/auth/register", new { userName, password = "123" }, Json); Assert.Equal(HttpStatusCode.BadRequest, weak.StatusCode); var first = await RegisterAsync(http, userName); Assert.NotNull(first.AccessToken); var duplicate = await http.PostAsJsonAsync( "/api/auth/register", new { userName, password = "password123" }, Json); Assert.Equal(HttpStatusCode.Conflict, duplicate.StatusCode); } private static async Task RegisterAsync(HttpClient http, string userName) { var response = await http.PostAsJsonAsync( "/api/auth/register", new { userName, password = "password123" }, Json); if (!response.IsSuccessStatusCode) throw new XunitException(await response.Content.ReadAsStringAsync()); return (await response.Content.ReadFromJsonAsync(Json))!; } }