-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[RSN-31] - Create validators according to constraints (#32)
Created validators according to constraints using fluent validation. --------- Co-authored-by: raczu <[email protected]>
- Loading branch information
Showing
50 changed files
with
2,707 additions
and
67 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
93 changes: 93 additions & 0 deletions
93
Server/ReasnAPI/ReasnAPI.Tests/UnitTests/Exceptions/ServiceExceptionHandlerTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
using System.Net; | ||
using Microsoft.AspNetCore.Http; | ||
using Moq; | ||
using ReasnAPI.Exceptions; | ||
using ReasnAPI.Services.Exceptions; | ||
|
||
namespace ReasnAPI.Tests.UnitTests.Exceptions; | ||
|
||
[TestClass] | ||
public class ServiceExceptionHandlerTests | ||
{ | ||
private Mock<IProblemDetailsService> _mockProblemDetailsService = null!; | ||
private ServiceExceptionHandler _handler = null!; | ||
|
||
[TestInitialize] | ||
public void Setup() | ||
{ | ||
_mockProblemDetailsService = new Mock<IProblemDetailsService>(); | ||
_handler = new ServiceExceptionHandler(_mockProblemDetailsService.Object); | ||
} | ||
|
||
[TestMethod] | ||
public async Task HandleException_WhenBadRequestException_ShouldReturnProblemDetails() | ||
{ | ||
var httpContext = new DefaultHttpContext(); | ||
var exception = new BadRequestException("Bad request"); | ||
|
||
ProblemDetailsContext? problemDetailsContext = null; | ||
_mockProblemDetailsService.Setup(x => | ||
x.TryWriteAsync(It.IsAny<ProblemDetailsContext>())) | ||
.Callback<ProblemDetailsContext>(context => problemDetailsContext = context) | ||
.ReturnsAsync(true); | ||
|
||
await _handler.TryHandleAsync(httpContext, exception, CancellationToken.None); | ||
|
||
Assert.AreEqual((int)HttpStatusCode.BadRequest, httpContext.Response.StatusCode); | ||
Assert.IsNotNull(problemDetailsContext); | ||
Assert.AreEqual("https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.1", | ||
problemDetailsContext.ProblemDetails.Type); | ||
Assert.AreEqual("A bad request was made", | ||
problemDetailsContext.ProblemDetails.Title); | ||
Assert.AreEqual(exception, problemDetailsContext.Exception); | ||
Assert.AreEqual(exception.Message, problemDetailsContext.ProblemDetails.Detail); | ||
} | ||
|
||
[TestMethod] | ||
public async Task HandleException_WhenNotFoundException_ShouldReturnProblemDetails() | ||
{ | ||
var httpContext = new DefaultHttpContext(); | ||
var exception = new NotFoundException("Resource not found"); | ||
|
||
ProblemDetailsContext? problemDetailsContext = null; | ||
_mockProblemDetailsService.Setup(x => | ||
x.TryWriteAsync(It.IsAny<ProblemDetailsContext>())) | ||
.Callback<ProblemDetailsContext>(context => problemDetailsContext = context) | ||
.ReturnsAsync(true); | ||
|
||
await _handler.TryHandleAsync(httpContext, exception, CancellationToken.None); | ||
|
||
Assert.AreEqual((int)HttpStatusCode.NotFound, httpContext.Response.StatusCode); | ||
Assert.IsNotNull(problemDetailsContext); | ||
Assert.AreEqual("https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.4", | ||
problemDetailsContext.ProblemDetails.Type); | ||
Assert.AreEqual("A resource was not found", | ||
problemDetailsContext.ProblemDetails.Title); | ||
Assert.AreEqual(exception, problemDetailsContext.Exception); | ||
Assert.AreEqual(exception.Message, problemDetailsContext.ProblemDetails.Detail); | ||
} | ||
|
||
[TestMethod] | ||
public async Task HandleException_WhenVerificationException_ShouldReturnProblemDetails() | ||
{ | ||
var httpContext = new DefaultHttpContext(); | ||
var exception = new VerificationException("Verification error"); | ||
|
||
ProblemDetailsContext? problemDetailsContext = null; | ||
_mockProblemDetailsService.Setup(x => | ||
x.TryWriteAsync(It.IsAny<ProblemDetailsContext>())) | ||
.Callback<ProblemDetailsContext>(context => problemDetailsContext = context) | ||
.ReturnsAsync(true); | ||
|
||
await _handler.TryHandleAsync(httpContext, exception, CancellationToken.None); | ||
|
||
Assert.AreEqual((int)HttpStatusCode.BadRequest, httpContext.Response.StatusCode); | ||
Assert.IsNotNull(problemDetailsContext); | ||
Assert.AreEqual("https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.1", | ||
problemDetailsContext.ProblemDetails.Type); | ||
Assert.AreEqual("A verification error occurred", | ||
problemDetailsContext.ProblemDetails.Title); | ||
Assert.AreEqual(exception, problemDetailsContext.Exception); | ||
Assert.AreEqual(exception.Message, problemDetailsContext.ProblemDetails.Detail); | ||
} | ||
} |
54 changes: 54 additions & 0 deletions
54
Server/ReasnAPI/ReasnAPI.Tests/UnitTests/Exceptions/ValidationExceptionHandlerTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
using System.Net; | ||
using FluentValidation; | ||
using FluentValidation.Results; | ||
using Microsoft.AspNetCore.Http; | ||
using Moq; | ||
using ReasnAPI.Exceptions; | ||
|
||
namespace ReasnAPI.Tests.UnitTests.Exceptions; | ||
|
||
[TestClass] | ||
public class ValidationExceptionHandlerTests | ||
{ | ||
private Mock<IProblemDetailsService> _mockProblemDetailsService = null!; | ||
private ValidationExceptionHandler _handler = null!; | ||
|
||
[TestInitialize] | ||
public void Setup() | ||
{ | ||
_mockProblemDetailsService = new Mock<IProblemDetailsService>(); | ||
_handler = new ValidationExceptionHandler(_mockProblemDetailsService.Object); | ||
} | ||
|
||
[TestMethod] | ||
public async Task HandleException_WhenValidationException_ShouldReturnProblemDetails() | ||
{ | ||
var httpContext = new DefaultHttpContext(); | ||
var exception = new ValidationException(new List<ValidationFailure> | ||
{ | ||
new ("Email", "'Email' must not be empty."), | ||
new ("Password", "'Password' must not be empty.") | ||
}); | ||
|
||
ProblemDetailsContext? problemDetailsContext = null; | ||
_mockProblemDetailsService.Setup(x => | ||
x.TryWriteAsync(It.IsAny<ProblemDetailsContext>())) | ||
.Callback<ProblemDetailsContext>(context => problemDetailsContext = context) | ||
.ReturnsAsync(true); | ||
|
||
await _handler.TryHandleAsync(httpContext, exception, CancellationToken.None); | ||
|
||
Assert.AreEqual((int)HttpStatusCode.BadRequest, httpContext.Response.StatusCode); | ||
Assert.IsNotNull(problemDetailsContext); | ||
Assert.AreEqual("https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.1", | ||
problemDetailsContext.ProblemDetails.Type); | ||
Assert.AreEqual("A validation error occurred", | ||
problemDetailsContext.ProblemDetails.Title); | ||
Assert.AreEqual(exception, problemDetailsContext.Exception); | ||
Assert.AreEqual("One or more validation errors occurred", | ||
problemDetailsContext.ProblemDetails.Detail); | ||
|
||
Assert.IsNotNull(problemDetailsContext.ProblemDetails.Extensions); | ||
Assert.IsTrue(problemDetailsContext.ProblemDetails.Extensions.ContainsKey("errors")); | ||
} | ||
} |
125 changes: 125 additions & 0 deletions
125
Server/ReasnAPI/ReasnAPI.Tests/UnitTests/Services/Authentication/AuthServiceTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
using Microsoft.AspNetCore.Identity; | ||
using Microsoft.AspNetCore.WebUtilities; | ||
using Moq; | ||
using Moq.EntityFrameworkCore; | ||
using ReasnAPI.Models.Authentication; | ||
using ReasnAPI.Models.Database; | ||
using ReasnAPI.Models.DTOs; | ||
using ReasnAPI.Services.Authentication; | ||
using ReasnAPI.Services.Exceptions; | ||
|
||
namespace ReasnAPI.Tests.UnitTests.Services.Authentication; | ||
|
||
[TestClass] | ||
public class AuthServiceTests | ||
{ | ||
private Mock<ReasnContext> _mockContext = null!; | ||
private PasswordHasher<User> _hasher = null!; | ||
private AuthService _service = null!; | ||
|
||
[TestInitialize] | ||
public void Setup() | ||
{ | ||
_mockContext = new Mock<ReasnContext>(); | ||
_hasher = new PasswordHasher<User>(); | ||
_service = new AuthService(_mockContext.Object); | ||
|
||
var user = new User | ||
{ | ||
Email = "[email protected]", | ||
Username = "jsnow", | ||
Password = _hasher.HashPassword(null!, "password") | ||
}; | ||
|
||
_mockContext.Setup(c => c.Users) | ||
.ReturnsDbSet(new List<User> { user }); | ||
} | ||
|
||
[TestMethod] | ||
public void Login_WhenUserExistsAndPasswordIsCorrect_ShouldReturnUser() | ||
{ | ||
var request = new LoginRequest | ||
{ | ||
Email = "[email protected]", | ||
Password = "password" | ||
}; | ||
|
||
var result = _service.Login(request); | ||
|
||
Assert.IsNotNull(result); | ||
Assert.IsInstanceOfType(result, typeof(User)); | ||
} | ||
|
||
[TestMethod] | ||
public void Login_WhenUserDoesNotExist_ShouldThrowNotFoundException() | ||
{ | ||
var request = new LoginRequest | ||
{ | ||
Email = "[email protected]" | ||
}; | ||
|
||
Assert.ThrowsException<NotFoundException>(() => _service.Login(request)); | ||
} | ||
|
||
[TestMethod] | ||
public void Login_WhenPasswordIsIncorrect_ShouldThrowVerificationException() | ||
{ | ||
var request = new LoginRequest | ||
{ | ||
Email = "[email protected]", | ||
Password = "wrong-password" | ||
}; | ||
|
||
Assert.ThrowsException<VerificationException>(() => _service.Login(request)); | ||
} | ||
|
||
[TestMethod] | ||
public void Register_WhenUserWithEmailAlreadyExists_ShouldThrowBadRequestException() | ||
{ | ||
var request = new RegisterRequest | ||
{ | ||
Email = "[email protected]" | ||
}; | ||
|
||
Assert.ThrowsException<BadRequestException>(() => _service.Register(request)); | ||
} | ||
|
||
[TestMethod] | ||
public void Register_WhenUserWithUsernameAlreadyExists_ShouldThrowBadRequestException() | ||
{ | ||
var request = new RegisterRequest | ||
{ | ||
Email = "[email protected]", | ||
Username = "jsnow" | ||
}; | ||
|
||
Assert.ThrowsException<BadRequestException>(() => _service.Register(request)); | ||
} | ||
|
||
[TestMethod] | ||
public void Register_WhenUserDoesNotExist_ShouldReturnRegisteredUser() | ||
{ | ||
var request = new RegisterRequest | ||
{ | ||
Name = "Jon", | ||
Surname = "Stark", | ||
Email = "[email protected]", | ||
Username = "jstark", | ||
Password = "S3cureP@ssword!", | ||
Phone = "+123 456789", | ||
Address = new AddressDto | ||
{ | ||
Street = "The Wall", | ||
City = "Castle Black", | ||
Country = "Westeros", | ||
State = "The North" | ||
}, | ||
Role = "User" | ||
}; | ||
|
||
var result = _service.Register(request); | ||
|
||
Assert.IsNotNull(result); | ||
Assert.IsInstanceOfType(result, typeof(User)); | ||
} | ||
} |
83 changes: 83 additions & 0 deletions
83
Server/ReasnAPI/ReasnAPI.Tests/UnitTests/Services/Authentication/TokenServiceTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
using System.IdentityModel.Tokens.Jwt; | ||
using System.Security.Cryptography; | ||
using Microsoft.Extensions.Configuration; | ||
using Moq; | ||
using ReasnAPI.Models.Database; | ||
using ReasnAPI.Models.Enums; | ||
using ReasnAPI.Services.Authentication; | ||
|
||
namespace ReasnAPI.Tests.UnitTests.Services.Authentication; | ||
|
||
[TestClass] | ||
public class TokenServiceTests | ||
{ | ||
private const int DurationInHours = 8; | ||
private const string IssAudValue = "http://localhost:5272"; | ||
private TokenService _service = null!; | ||
private Mock<IConfiguration> _mockConfiguration = null!; | ||
private User _validUser = null!; | ||
|
||
[TestInitialize] | ||
public void Setup() | ||
{ | ||
_mockConfiguration = new Mock<IConfiguration>(); | ||
|
||
var bytes = new byte[32]; | ||
RandomNumberGenerator.Fill(bytes); | ||
_mockConfiguration.Setup(x => | ||
x["JwtSettings:Key"]).Returns(Convert.ToBase64String(bytes)); | ||
|
||
_mockConfiguration.Setup(x => | ||
x["JwtSettings:Issuer"]).Returns(IssAudValue); | ||
|
||
var mockSection = new Mock<IConfigurationSection>(); | ||
var mockAudienceValue = new Mock<IConfigurationSection>(); | ||
mockAudienceValue.Setup(x => x.Value).Returns(IssAudValue); | ||
mockSection.Setup(x => | ||
x.GetChildren()).Returns(new List<IConfigurationSection> { mockAudienceValue.Object }); | ||
_mockConfiguration.Setup(x => | ||
x.GetSection("JwtSettings:Audiences")).Returns(mockSection.Object); | ||
|
||
var mockDurationValue = new Mock<IConfigurationSection>(); | ||
mockDurationValue.SetupGet(x => x.Value).Returns(DurationInHours.ToString()); | ||
_mockConfiguration.Setup(x => | ||
x.GetSection("JwtSettings:DurationInHours")).Returns(mockDurationValue.Object); | ||
|
||
_service = new TokenService(_mockConfiguration.Object); | ||
|
||
_validUser = new User | ||
{ | ||
Id = 1, | ||
Name = "Jon", | ||
Surname = "Snow", | ||
Email = "[email protected]", | ||
Role = UserRole.User | ||
}; | ||
} | ||
|
||
[TestMethod] | ||
public void GenerateToken_WhenValidUser_ShouldReturnTokenPayload() | ||
{ | ||
var result = _service.GenerateToken(_validUser); | ||
|
||
Assert.IsNotNull(result); | ||
Assert.AreEqual("Bearer", result.TokenType); | ||
Assert.IsNotNull(result.AccessToken); | ||
Assert.AreEqual(DurationInHours * 60 * 60, result.ExpiresIn); | ||
} | ||
|
||
[TestMethod] | ||
public void GenerateToken_WhenValidUser_ShouldReturnValidToken() | ||
{ | ||
var result = _service.GenerateToken(_validUser); | ||
|
||
var tokenHandler = new JwtSecurityTokenHandler(); | ||
var token = tokenHandler.ReadToken(result.AccessToken) as JwtSecurityToken; | ||
|
||
Assert.IsNotNull(token); | ||
Assert.AreEqual(IssAudValue, token.Issuer); | ||
Assert.AreEqual(IssAudValue, token.Audiences.First()); | ||
Assert.AreEqual(_validUser.Email, token.Subject); | ||
Assert.AreEqual(DurationInHours * 60 * 60, (token.ValidTo - token.ValidFrom).TotalSeconds); | ||
} | ||
} |
Oops, something went wrong.