Skip to content
This repository was archived by the owner on Apr 19, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -152,4 +152,4 @@ jobs:
- name: Run Performance Tests
env:
BASE_URL: ${{ env.SERVER_URL }}
run: k6 run server/Tests/performance/load-test.js
run: k6 run server/Tests/Performance/load-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ public async Task Login_ShouldReturn400_WhenLoginFails()
var response = await _client.PostAsJsonAsync("api/auth/login", new LoginCommand
{
Email = "nobody@nowhere.com",
Password = "wrongpassword"
Password = "wrong_password"
}, cancellationToken: TestContext.Current.CancellationToken);

Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public async Task AddAsync_ShouldPersistMessage()
var msg = MakeMessage();
var result = await _repo.AddAsync(msg);
Assert.NotEqual(Guid.Empty, result.Id);
var fromDb = await _context.ChatMessages.FindAsync(result.Id, TestContext.Current.CancellationToken);
var fromDb = await _context.ChatMessages.FindAsync([result.Id], TestContext.Current.CancellationToken);
Assert.NotNull(fromDb);
}

Expand All @@ -72,8 +72,7 @@ public async Task DeleteAsync_ByEntity_ShouldRemoveMessage()
var msg = await _repo.AddAsync(MakeMessage());
var result = await _repo.DeleteAsync(msg);
Assert.True(result);
Assert.Null(await _context.ChatMessages.FindAsync(msg.Id, TestContext.Current.CancellationToken));
}
Assert.Null(await _context.ChatMessages.FindAsync([msg.Id], TestContext.Current.CancellationToken)); }

[Fact]
public async Task DeleteAsync_ById_ShouldReturnTrue_WhenExists()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public async Task AddAsync_ShouldPersistRoom()
{
var room = await _repo.AddAsync(MakeRoom());
Assert.NotEqual(Guid.Empty, room.Id);
Assert.NotNull(await _context.ChatRooms.FindAsync(room.Id, TestContext.Current.CancellationToken));
Assert.NotNull(await _context.ChatRooms.FindAsync([room.Id], TestContext.Current.CancellationToken));
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,7 @@ public async Task AddAsync_ShouldPersistNotification()
{
var n = await _repo.AddAsync(MakeNotification());
Assert.NotEqual(Guid.Empty, n.Id);
Assert.NotNull(await _context.Notifications.FindAsync(n.Id, TestContext.Current.CancellationToken));
}
Assert.NotNull(await _context.Notifications.FindAsync([n.Id], TestContext.Current.CancellationToken)); }

[Fact]
public async Task FindByIdAsync_ShouldReturnNotification_WhenExists()
Expand Down
216 changes: 216 additions & 0 deletions server/Tests/Unit/AuthControllerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
using System.Security.Claims;
using Api.Controllers;
using Application.Common.Interfaces.Features;
using Application.Common.Results;
using Application.DTOs.Auth;
using Application.DTOs.Entities;
using Application.DTOs.Responses;
using Application.Features.Auth.Login;
using Application.Features.Auth.Register;
using Domain.Enums;
using Domain.Settings;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using NSubstitute;

namespace Unit;

public class AuthControllerTests
{
private readonly IAuthFeature _authFeature = Substitute.For<IAuthFeature>();
private readonly AppSettings _appSettings;
private readonly AuthController _controller;

public AuthControllerTests()
{
_appSettings = new AppSettings(
new CorsSettings { AllowedOrigins = new[] { "https://localhost" } },
new JwtSettings
{
Secret = new string('A', 32),
Issuer = "issuer",
Audience = "audience",
AccessTokenLifetime = 15,
RefreshTokenLifetime = 60
},
new DbSettings
{
PSqlConnectionString = "Host=localhost;Database=test;Username=test;Password=test",
RedisConnectionString = "localhost:6379"
});

_controller = new AuthController(_authFeature, _appSettings)
{
ControllerContext = new ControllerContext
{
HttpContext = new DefaultHttpContext()
}
};
}

private void Authenticate(Guid userId, params string[] roles)
{
var claims = new List<Claim> { new(ClaimTypes.NameIdentifier, userId.ToString()) };
claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role)));

_controller.ControllerContext = new ControllerContext
{
HttpContext = new DefaultHttpContext
{
User = new ClaimsPrincipal(new ClaimsIdentity(claims, "Test"))
}
};
}

[Fact]
public async Task Login_ShouldReturnNoContent_WhenUserIsAlreadyAuthenticated()
{
Authenticate(Guid.NewGuid());

var result = await _controller.Login(new LoginCommand { Email = "test@example.com", Password = "password" });

Assert.IsType<NoContentResult>(result);
}

[Fact]
public async Task Login_ShouldReturnUnauthorized_WhenLoginFailsWithUnauthorized()
{
_authFeature.HandleLogin(Arg.Any<LoginCommand>())
.Returns(Result<LoginResponseDto>.Failure("invalid", ResultStatus.Unauthorized));

var result = await _controller.Login(new LoginCommand { Email = "test@example.com", Password = "password" });

Assert.IsType<UnauthorizedResult>(result);
}

[Fact]
public async Task Login_ShouldReturnBadRequest_WhenLoginFailsWithFailure()
{
_authFeature.HandleLogin(Arg.Any<LoginCommand>())
.Returns(Result<LoginResponseDto>.Failure("failure", ResultStatus.Failure));

var result = await _controller.Login(new LoginCommand { Email = "test@example.com", Password = "password" });

Assert.IsType<BadRequestResult>(result);
}

[Fact]
public async Task Login_ShouldReturnOkAndAppendCookies_WhenLoginSucceeds()
{
var userDto = new UserDto { Email = "user@example.com", Username = "User Name" };
var responseDto = new LoginResponseDto
{
AccessToken = "access-token",
RefreshToken = "refresh-token",
User = userDto
};

_authFeature.HandleLogin(Arg.Any<LoginCommand>())
.Returns(Result<LoginResponseDto>.Success(responseDto));

var result = await _controller.Login(new LoginCommand { Email = "test@example.com", Password = "password" });

var ok = Assert.IsType<OkObjectResult>(result);
Assert.Same(userDto, ok.Value);
var setCookieHeaders = _controller.Response.Headers["Set-Cookie"].ToString();
Assert.Contains("accessToken=access-token", setCookieHeaders);
Assert.Contains("refreshToken=refresh-token", setCookieHeaders);
}

[Fact]
public async Task Register_ShouldReturnUnauthorized_WhenUserIsNotAllowedToRegisterAdmin()
{
Authenticate(Guid.NewGuid());

var request = new RegisterUserCommand
{
FirstName = "Test",
LastName = "User",
Email = "test@example.com",
Password = "password",
Role = RoleType.Admin
};

var result = await _controller.Register(request);

var unauthorized = Assert.IsType<UnauthorizedObjectResult>(result);
Assert.Contains("not authorized", unauthorized.Value!.ToString()!);
}

[Fact]
public async Task Register_ShouldReturnOk_WhenRegisterSucceeds()
{
var request = new RegisterUserCommand
{
FirstName = "Test",
LastName = "User",
Email = "test@example.com",
Password = "password",
Role = RoleType.User
};

_authFeature.HandleRegisterUser(request)
.Returns(Result.Success("ok"));

var result = await _controller.Register(request);

var ok = Assert.IsType<OkObjectResult>(result);
Assert.IsType<Result>(ok.Value);
}

[Fact]
public async Task GetMe_ShouldReturnOk_WhenFeatureReturnsSuccess()
{
var userId = Guid.NewGuid();
Authenticate(userId);

var dto = new UserDto { Email = "me@example.com", Username = "Me" };
_authFeature.HandleMeRequest(userId)
.Returns(Result<UserDto>.Success(dto));

var result = await _controller.GetMe();

var ok = Assert.IsType<OkObjectResult>(result);
Assert.Same(dto, ok.Value);
}

[Fact]
public async Task GetMe_ShouldReturnUnauthorized_WhenUserIdIsInvalid()
{
_controller.ControllerContext = new ControllerContext
{
HttpContext = new DefaultHttpContext { User = new ClaimsPrincipal(new ClaimsIdentity()) }
};

var result = await _controller.GetMe();

Assert.IsType<UnauthorizedObjectResult>(result);
}

[Fact]
public async Task Logout_ShouldReturnOk_WhenRevokeRefreshTokenSucceeds()
{
var userId = Guid.NewGuid();
Authenticate(userId);

_authFeature.RevokeRefreshToken(userId)
.Returns(Task.FromResult(Result.Success()));

var result = await _controller.Logout();

Assert.IsType<OkResult>(result);
}

[Fact]
public async Task Logout_ShouldReturnUnauthorized_WhenGetUserIdThrows()
{
_controller.ControllerContext = new ControllerContext
{
HttpContext = new DefaultHttpContext { User = new ClaimsPrincipal(new ClaimsIdentity()) }
};

var result = await _controller.Logout();

Assert.IsType<UnauthorizedObjectResult>(result);
}
}
Loading
Loading