308 lines
10 KiB
C#
308 lines
10 KiB
C#
using Application.Common.Results;
|
|
using Application.DTOs;
|
|
using Application.Errors;
|
|
using Application.Interfaces;
|
|
using Application.Models;
|
|
using Application.Services;
|
|
using Application.Validators;
|
|
using Domain.Entities;
|
|
using Domain.Interface;
|
|
using Microsoft.AspNetCore.Identity;
|
|
using NSubstitute;
|
|
|
|
namespace Application.UnitTest.Services;
|
|
|
|
public class AuthenticationServiceTests
|
|
{
|
|
private readonly IUnitOfWork _unitOfWork = Substitute.For<IUnitOfWork>();
|
|
private readonly IUserRepository _userRepository = Substitute.For<IUserRepository>();
|
|
private readonly IJwtService _jwtService = Substitute.For<IJwtService>();
|
|
private readonly IEmailService _emailService = Substitute.For<IEmailService>();
|
|
private readonly AuthenticationService _sut;
|
|
|
|
public AuthenticationServiceTests()
|
|
{
|
|
_sut = new AuthenticationService(
|
|
_unitOfWork,
|
|
_userRepository,
|
|
new LoginRequestValidator(),
|
|
new RegisterRequestValidator(),
|
|
_jwtService,
|
|
_emailService);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task RegisterAsync_ShouldReturnSuccess_WhenRequestIsValid()
|
|
{
|
|
var request = new RegisterRequest("newuser", "new@example.com", "ValidP@ss1!");
|
|
_userRepository.GetUserByEmailAsync(request.Email).Returns((User?)null);
|
|
_userRepository.GetUserByUsernameAsync(request.Username).Returns((User?)null);
|
|
|
|
var result = await _sut.RegisterAsync(request);
|
|
|
|
Assert.True(result.IsSuccess);
|
|
await _userRepository.Received(1).AddAsync(Arg.Any<User>());
|
|
await _unitOfWork.Received(1).CommitAsync();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task RegisterAsync_ShouldReturnFailure_WhenValidationFails()
|
|
{
|
|
var request = new RegisterRequest("", "", "");
|
|
|
|
var result = await _sut.RegisterAsync(request);
|
|
|
|
Assert.True(result.IsFailure);
|
|
Assert.Equal(ErrorTypeConstant.ValidationError, result.Error.Code);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task RegisterAsync_ShouldReturnFailure_WhenEmailAlreadyExists()
|
|
{
|
|
var request = new RegisterRequest("newuser", "existing@example.com", "ValidP@ss1!");
|
|
_userRepository.GetUserByEmailAsync(request.Email).Returns(new User
|
|
{
|
|
Username = "existing", Email = "existing@example.com", Password = "hash"
|
|
});
|
|
|
|
var result = await _sut.RegisterAsync(request);
|
|
|
|
Assert.True(result.IsFailure);
|
|
Assert.Equal(AuthError.EmailAlreadyExists, result.Error);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task RegisterAsync_ShouldReturnFailure_WhenUsernameAlreadyExists()
|
|
{
|
|
var request = new RegisterRequest("existinguser", "new@example.com", "ValidP@ss1!");
|
|
_userRepository.GetUserByEmailAsync(request.Email).Returns((User?)null);
|
|
_userRepository.GetUserByUsernameAsync(request.Username).Returns(new User
|
|
{
|
|
Username = "existinguser", Email = "existing@example.com", Password = "hash"
|
|
});
|
|
|
|
var result = await _sut.RegisterAsync(request);
|
|
|
|
Assert.True(result.IsFailure);
|
|
Assert.Equal(AuthError.UsernameAlreadyExists, result.Error);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task LoginAsync_ShouldReturnSuccess_WhenCredentialsAreValid()
|
|
{
|
|
var password = "ValidP@ss1!";
|
|
var user = new User
|
|
{
|
|
Id = 1,
|
|
Username = "testuser",
|
|
Email = "test@example.com",
|
|
Password = new PasswordHasher<User>().HashPassword(
|
|
new User { Username = "testuser", Email = "test@example.com", Password = password },
|
|
password)
|
|
};
|
|
var request = new LoginRequest(user.Email, password);
|
|
_userRepository.GetUserByEmailAsync(request.Email).Returns(user);
|
|
_jwtService.GenerateTokenAsync(user).Returns("access-token");
|
|
_jwtService.GenerateAndSaveRefreshTokenAsync(user).Returns("refresh-token");
|
|
|
|
var result = await _sut.LoginAsync(request);
|
|
|
|
Assert.True(result.IsSuccess);
|
|
_userRepository.Received(1).Update(user);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task LoginAsync_ShouldReturnFailure_WhenValidationFails()
|
|
{
|
|
var request = new LoginRequest("", "");
|
|
|
|
var result = await _sut.LoginAsync(request);
|
|
|
|
Assert.True(result.IsFailure);
|
|
Assert.Equal(ErrorTypeConstant.ValidationError, result.Error.Code);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task LoginAsync_ShouldReturnFailure_WhenUserNotFound()
|
|
{
|
|
var request = new LoginRequest("unknown@example.com", "password123");
|
|
_userRepository.GetUserByEmailAsync(request.Email).Returns((User?)null);
|
|
|
|
var result = await _sut.LoginAsync(request);
|
|
|
|
Assert.True(result.IsFailure);
|
|
Assert.Equal(AuthError.UserNotFound, result.Error);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task LoginAsync_ShouldReturnFailure_WhenPasswordIsWrong()
|
|
{
|
|
var password = "ValidP@ss1!";
|
|
var user = new User
|
|
{
|
|
Id = 1,
|
|
Username = "testuser",
|
|
Email = "test@example.com",
|
|
Password = new PasswordHasher<User>().HashPassword(
|
|
new User { Username = "testuser", Email = "test@example.com", Password = password },
|
|
password)
|
|
};
|
|
var request = new LoginRequest(user.Email, "WrongPassword1!");
|
|
_userRepository.GetUserByEmailAsync(request.Email).Returns(user);
|
|
|
|
var result = await _sut.LoginAsync(request);
|
|
|
|
Assert.True(result.IsFailure);
|
|
Assert.Equal(AuthError.InvalidPassword, result.Error);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task RefreshTokensAsync_ShouldReturnSuccess_WhenRefreshTokenIsValid()
|
|
{
|
|
var request = new RefreshTokenRequest { UserId = 1, RefreshToken = "valid-refresh-token" };
|
|
var user = new User { Id = 1, Username = "testuser", Email = "test@example.com", Password = "hash" };
|
|
_jwtService.ValidateRefreshTokenAsync(request.UserId, request.RefreshToken).Returns(user);
|
|
_jwtService.GenerateTokenAsync(user).Returns("new-access-token");
|
|
_jwtService.GenerateAndSaveRefreshTokenAsync(user).Returns("new-refresh-token");
|
|
|
|
var result = await _sut.RefreshTokensAsync(request);
|
|
|
|
Assert.True(result.IsSuccess);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task RefreshTokensAsync_ShouldReturnFailure_WhenUserNotFound()
|
|
{
|
|
var request = new RefreshTokenRequest { UserId = 99, RefreshToken = "invalid-token" };
|
|
_jwtService.ValidateRefreshTokenAsync(request.UserId, request.RefreshToken).Returns((User?)null);
|
|
|
|
var result = await _sut.RefreshTokensAsync(request);
|
|
|
|
Assert.True(result.IsFailure);
|
|
Assert.Equal(AuthError.UserNotFound, result.Error);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task SendResetEmailAsync_ShouldReturnSuccess_WhenUserExists()
|
|
{
|
|
var email = "test@example.com";
|
|
var user = new User { Id = 1, Username = "testuser", Email = email, Password = "hash" };
|
|
_userRepository.GetUserByEmailAsync(email).Returns(user);
|
|
|
|
var result = await _sut.SendResetEmailAsync(email);
|
|
|
|
Assert.True(result.IsSuccess);
|
|
_emailService.Received(1).SendEmailAsync(Arg.Any<EmailRequest>());
|
|
_userRepository.Received(1).Update(user);
|
|
await _unitOfWork.Received(1).CommitAsync();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task SendResetEmailAsync_ShouldReturnFailure_WhenUserNotFound()
|
|
{
|
|
var email = "unknown@example.com";
|
|
_userRepository.GetUserByEmailAsync(email).Returns((User?)null);
|
|
|
|
var result = await _sut.SendResetEmailAsync(email);
|
|
|
|
Assert.True(result.IsFailure);
|
|
Assert.Equal(AuthError.UserNotFound, result.Error);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ResetPasswordAsync_ShouldReturnSuccess_WhenTokenIsValid()
|
|
{
|
|
var dto = new ResetPasswordDto
|
|
{
|
|
Email = "test@example.com",
|
|
EmailToken = "valid-token",
|
|
NewPassword = "NewValidP@ss1"
|
|
};
|
|
var user = new User
|
|
{
|
|
Id = 1,
|
|
Username = "testuser",
|
|
Email = dto.Email,
|
|
Password = "old-hash",
|
|
ResetPasswordToken = "valid-token",
|
|
ResetPasswordTokenExpiryTime = DateTime.UtcNow.AddHours(1)
|
|
};
|
|
_userRepository.GetUserByEmailAsync(dto.Email).Returns(user);
|
|
|
|
var result = await _sut.ResetPasswordAsync(dto);
|
|
|
|
Assert.True(result.IsSuccess);
|
|
_userRepository.Received(1).Update(user);
|
|
await _unitOfWork.Received(1).CommitAsync();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ResetPasswordAsync_ShouldReturnFailure_WhenUserNotFound()
|
|
{
|
|
var dto = new ResetPasswordDto
|
|
{
|
|
Email = "unknown@example.com",
|
|
EmailToken = "token",
|
|
NewPassword = "NewValidP@ss1"
|
|
};
|
|
_userRepository.GetUserByEmailAsync(dto.Email).Returns((User?)null);
|
|
|
|
var result = await _sut.ResetPasswordAsync(dto);
|
|
|
|
Assert.True(result.IsFailure);
|
|
Assert.Equal(AuthError.UserNotFound, result.Error);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ResetPasswordAsync_ShouldReturnFailure_WhenTokenIsInvalid()
|
|
{
|
|
var dto = new ResetPasswordDto
|
|
{
|
|
Email = "test@example.com",
|
|
EmailToken = "wrong-token",
|
|
NewPassword = "NewValidP@ss1"
|
|
};
|
|
var user = new User
|
|
{
|
|
Id = 1,
|
|
Username = "testuser",
|
|
Email = dto.Email,
|
|
Password = "old-hash",
|
|
ResetPasswordToken = "valid-token",
|
|
ResetPasswordTokenExpiryTime = DateTime.UtcNow.AddHours(1)
|
|
};
|
|
_userRepository.GetUserByEmailAsync(dto.Email).Returns(user);
|
|
|
|
var result = await _sut.ResetPasswordAsync(dto);
|
|
|
|
Assert.True(result.IsFailure);
|
|
Assert.Equal(AuthError.InvalidResetLink, result.Error);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ResetPasswordAsync_ShouldReturnFailure_WhenTokenIsExpired()
|
|
{
|
|
var dto = new ResetPasswordDto
|
|
{
|
|
Email = "test@example.com",
|
|
EmailToken = "valid-token",
|
|
NewPassword = "NewValidP@ss1"
|
|
};
|
|
var user = new User
|
|
{
|
|
Id = 1,
|
|
Username = "testuser",
|
|
Email = dto.Email,
|
|
Password = "old-hash",
|
|
ResetPasswordToken = "valid-token",
|
|
ResetPasswordTokenExpiryTime = DateTime.UtcNow.AddHours(-1)
|
|
};
|
|
_userRepository.GetUserByEmailAsync(dto.Email).Returns(user);
|
|
|
|
var result = await _sut.ResetPasswordAsync(dto);
|
|
|
|
Assert.True(result.IsFailure);
|
|
Assert.Equal(AuthError.InvalidResetLink, result.Error);
|
|
}
|
|
}
|