diff --git a/Govor.API.Tests/Govor.API.Tests.csproj b/Govor.API.Tests/Govor.API.Tests.csproj index 3a4ca0b..139f439 100644 --- a/Govor.API.Tests/Govor.API.Tests.csproj +++ b/Govor.API.Tests/Govor.API.Tests.csproj @@ -24,10 +24,6 @@ - - - - diff --git a/Govor.API.Tests/IntegrationTests/Controllers/AuthControllerTests.cs b/Govor.API.Tests/IntegrationTests/Controllers/AuthControllerTests.cs new file mode 100644 index 0000000..5de221f --- /dev/null +++ b/Govor.API.Tests/IntegrationTests/Controllers/AuthControllerTests.cs @@ -0,0 +1,218 @@ +using AutoFixture; +using Govor.API.Controllers; +using Govor.API.Services.Authentication; +using Govor.API.Services.Authentication.Interfaces; +using Govor.Core.Models; +using Govor.Core.Requests; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using Moq; + +namespace Govor.API.Tests.IntegrationTests.Controllers; + +[TestFixture] +public class AuthControllerTests +{ + private Fixture _fixture; + private Mock _accountServiceMock; + private Mock _invitesServiceMock; + private Mock> _loggerMock; + private AuthController _controller; + + [SetUp] + public void SetUp() + { + _fixture = new Fixture(); + _fixture.Behaviors.OfType().ToList().ForEach(b => _fixture.Behaviors.Remove(b)); + _fixture.Behaviors.Add(new OmitOnRecursionBehavior()); + + _accountServiceMock = new Mock(); + _invitesServiceMock = new Mock(); + _loggerMock = new Mock>(); + + _controller = new AuthController( + _accountServiceMock.Object, + _invitesServiceMock.Object, + _loggerMock.Object + ); + } + + // Tests for Register action + [Test] + public async Task Register_ValidRequest_ReturnsOkWithToken() + { + // Arrange + var request = _fixture.Create(); + var invitation = _fixture.Create(); + var token = _fixture.Create(); + + _invitesServiceMock.Setup(s => s.Validate(request.InviteLink)).Returns(invitation); + _accountServiceMock.Setup(s => s.RegistrationAsync(request.Name, request.Password, invitation)).ReturnsAsync(token); + + // Act + var result = await _controller.Register(request); + + // Assert + Assert.That(result, Is.InstanceOf()); + var okResult = result as OkObjectResult; + dynamic value = okResult.Value; + Assert.That((string)value.GetType().GetProperty("token").GetValue(value, null), Is.EqualTo(token)); + } + + [Test] + public async Task Register_InvalidModelState_ReturnsBadRequest() + { + // Arrange + var request = _fixture.Create(); + _controller.ModelState.AddModelError("Error", "Sample error"); + + // Act + var result = await _controller.Register(request); + + // Assert + Assert.That(result, Is.InstanceOf()); + } + + [Test] + public async Task Register_InviteLinkInvalid_ReturnsBadRequest() + { + // Arrange + var request = _fixture.Create(); + _invitesServiceMock.Setup(s => s.Validate(request.InviteLink)).Throws(new InviteLinkInvalidException(request.InviteLink)); + + // Act + var result = await _controller.Register(request); + + // Assert + Assert.That(result, Is.InstanceOf()); + var badRequestResult = result as BadRequestObjectResult; + Assert.That(badRequestResult.Value, Is.EqualTo("Invite link invalid.")); + } + + [Test] + public async Task Register_UserAlreadyExists_ReturnsBadRequest() + { + // Arrange + var request = _fixture.Create(); + var invitation = _fixture.Create(); + _invitesServiceMock.Setup(s => s.Validate(request.InviteLink)).Returns(invitation); + _accountServiceMock.Setup(s => s.RegistrationAsync(request.Name, request.Password, invitation)) + .ThrowsAsync(new UserAlreadyExistException(request.Name)); + + // Act + var result = await _controller.Register(request); + + // Assert + Assert.That(result, Is.InstanceOf()); + var badRequestResult = result as BadRequestObjectResult; + Assert.That(badRequestResult.Value, Is.EqualTo("Registration failed: user already exists.")); + } + + [Test] + public async Task Register_AccountServiceThrowsGenericException_ReturnsStatusCode500() + { + // Arrange + var request = _fixture.Create(); + var invitation = _fixture.Create(); + _invitesServiceMock.Setup(s => s.Validate(request.InviteLink)).Returns(invitation); + _accountServiceMock.Setup(s => s.RegistrationAsync(request.Name, request.Password, invitation)) + .ThrowsAsync(new System.Exception("Generic error")); + + // Act + var result = await _controller.Register(request); + + // Assert + Assert.That(result, Is.InstanceOf()); + var objectResult = result as ObjectResult; + Assert.That(objectResult.StatusCode, Is.EqualTo(500)); + Assert.That(objectResult.Value, Is.EqualTo("An unexpected error occurred. Please try again later.")); + } + + // Tests for Login action + [Test] + public async Task Login_ValidCredentials_ReturnsOkWithToken() + { + // Arrange + var loginRequest = _fixture.Create(); + var token = _fixture.Create(); + _accountServiceMock.Setup(l => l.LoginAsync(loginRequest.Name, loginRequest.Password)).ReturnsAsync(token); + + // Act + var result = await _controller.Login(loginRequest); + // Assert + Assert.That(result, Is.InstanceOf()); + var okResult = result as OkObjectResult; + dynamic value = okResult.Value; + Assert.That((string)value.GetType().GetProperty("token").GetValue(value, null), Is.EqualTo(token)); + } + + [Test] + public async Task Login_InvalidModelState_ReturnsBadRequest() + { + // Arrange + var request = _fixture.Create(); + _controller.ModelState.AddModelError("Error", "Sample error"); + + // Act + var result = await _controller.Login(request); + + // Assert + Assert.That(result, Is.InstanceOf()); + } + + [Test] + public async Task Login_UserNotRegistered_ReturnsBadRequest() + { + // Arrange + var request = _fixture.Create(); + _accountServiceMock.Setup(l => l.LoginAsync(request.Name, request.Password)).Throws(new UserNotRegisteredException(request.Name)); + + // Act + var result = await _controller.Login(request); + + // Assert + Assert.That(result, Is.InstanceOf()); + var badRequestResult = result as BadRequestObjectResult; + Assert.That(badRequestResult.Value, Is.EqualTo("Login failed: user does not exist.")); + } + + [Test] + public async Task Login_PasswordIsIncorrect_ReturnsBadRequest() + { + // Arrange + var request = _fixture.Create(); + _accountServiceMock.Setup(l => l.LoginAsync(request.Name, request.Password)).Throws(new LoginUserException()); + + // Act + var result = await _controller.Login(request); + + // Assert + Assert.That(result, Is.InstanceOf()); + var badRequestResult = result as BadRequestObjectResult; + Assert.That(badRequestResult.Value, Is.EqualTo("Login failed: username or password is incorrect.")); + } + + [Test] + public async Task Login_AccountServiceThrowsGenericException_ReturnsStatusCode500() + { + // Arrange + var request = _fixture.Create(); + _accountServiceMock.Setup(s => s.LoginAsync(request.Name, request.Password)) + .ThrowsAsync(new System.Exception("Generic error")); + + // Act + var result = await _controller.Login(request); + + // Assert + Assert.That(result, Is.InstanceOf()); + var objectResult = result as ObjectResult; + Assert.That(objectResult.StatusCode, Is.EqualTo(500)); + Assert.That(objectResult.Value, Is.EqualTo("An unexpected error occurred. Please try again later.")); + } + + [TearDown] + public void TearDown() + { + (_controller as IDisposable)?.Dispose(); + } +} \ No newline at end of file diff --git a/Govor.API.Tests/UnitTests/Services/AuthServiceTests.cs b/Govor.API.Tests/UnitTests/Services/Authentication/AuthServiceTests.cs similarity index 98% rename from Govor.API.Tests/UnitTests/Services/AuthServiceTests.cs rename to Govor.API.Tests/UnitTests/Services/Authentication/AuthServiceTests.cs index 24630d3..dcdf2bc 100644 --- a/Govor.API.Tests/UnitTests/Services/AuthServiceTests.cs +++ b/Govor.API.Tests/UnitTests/Services/Authentication/AuthServiceTests.cs @@ -8,7 +8,7 @@ using Govor.Core.Repositories.Admins; using Govor.Core.Repositories.Invaites; using Moq; -namespace Govor.API.Tests.UnitTests.Services; +namespace Govor.API.Tests.UnitTests.Services.Authentication; [TestFixture] public class AuthServiceTests diff --git a/Govor.API/Controllers/AuthController.cs b/Govor.API/Controllers/AuthController.cs index 8e4c9bb..295ca12 100644 --- a/Govor.API/Controllers/AuthController.cs +++ b/Govor.API/Controllers/AuthController.cs @@ -1,7 +1,6 @@ -using Govor.API.Services; using Govor.API.Services.Authentication; -using Govor.Core.DTOs; using Govor.API.Services.Authentication.Interfaces; +using Govor.Core.Requests; using Microsoft.AspNetCore.Mvc; namespace Govor.API.Controllers; @@ -75,6 +74,11 @@ public class AuthController : Controller _logger.LogWarning(ex, "Login failed for user {Name}", userRequest.Name); return BadRequest("Login failed: user does not exist."); } + catch (LoginUserException ex) + { + _logger.LogWarning(ex, "Login failed for user {Name}", userRequest.Name); + return BadRequest("Login failed: username or password is incorrect."); + } catch (Exception ex) { _logger.LogError(ex, "Unexpected error during login for user {Name}", userRequest.Name); diff --git a/Govor.Console/Program.cs b/Govor.Console/Program.cs index 0808d30..8ff42f0 100644 --- a/Govor.Console/Program.cs +++ b/Govor.Console/Program.cs @@ -1,11 +1,8 @@ using Microsoft.AspNetCore.SignalR.Client; -using System; using System.IdentityModel.Tokens.Jwt; -using System.Net.Http; using System.Net.Http.Json; using System.Text.Json; -using System.Threading.Tasks; -using Govor.Core.DTOs; +using Govor.Core.Requests; /*====================================