diff --git a/tests/Application.Tests.Integration/BaseClassFixture.cs b/tests/Application.Tests.Integration/BaseClassFixture.cs index ee1f2c14..304ec0e7 100644 --- a/tests/Application.Tests.Integration/BaseClassFixture.cs +++ b/tests/Application.Tests.Integration/BaseClassFixture.cs @@ -207,8 +207,8 @@ protected static Borrow CreateBorrowRequest(User borrower, Document document, Bo Document = document, Reason = "something something", Status = status, - BorrowTime = LocalDateTime.FromDateTime(DateTime.UtcNow), - DueTime = LocalDateTime.FromDateTime(DateTime.UtcNow + TimeSpan.FromDays(1)) + BorrowTime = LocalDateTime.FromDateTime(DateTime.Now), + DueTime = LocalDateTime.FromDateTime(DateTime.Now + TimeSpan.FromDays(1)) }; } } \ No newline at end of file diff --git a/tests/Application.Tests.Integration/Borrows/Commands/BorrowDocumentTests.cs b/tests/Application.Tests.Integration/Borrows/Commands/BorrowDocumentTests.cs new file mode 100644 index 00000000..b595d20f --- /dev/null +++ b/tests/Application.Tests.Integration/Borrows/Commands/BorrowDocumentTests.cs @@ -0,0 +1,354 @@ +using Application.Borrows.Commands; +using Application.Common.Exceptions; +using Application.Identity; +using Domain.Entities; +using Domain.Entities.Physical; +using Domain.Statuses; +using FluentAssertions; +using Infrastructure.Persistence; +using Microsoft.Extensions.DependencyInjection; +using NodaTime; +using Xunit; + +namespace Application.Tests.Integration.Borrows.Commands; + +public class BorrowDocumentTests : BaseClassFixture +{ + public BorrowDocumentTests(CustomApiFactory apiFactory) : base(apiFactory) + { + + } + + [Fact] + public async Task ShouldCreateBorrowRequest_WhenDetailsAreValid() + { + // Arrange + using var scope = ScopeFactory.CreateScope(); + var context = scope.ServiceProvider.GetRequiredService(); + var department = CreateDepartment(); + await context.AddAsync(department); + + var user = CreateUser(IdentityData.Roles.Employee, "aaaaaa"); + user.Department = department; + await context.AddAsync(user); + + var document = CreateNDocuments(1).First(); + document.Status = DocumentStatus.Available; + document.Department = department; + await context.AddAsync(document); + await context.SaveChangesAsync(); + + var command = new BorrowDocument.Command() + { + BorrowerId = user.Id, + DocumentId = document.Id, + Reason = "Example", + BorrowFrom = DateTime.Now.Add(TimeSpan.FromHours(1)), + BorrowTo = DateTime.Now.Add(TimeSpan.FromDays(1)), + }; + + // Act + var result = await SendAsync(command); + + // Assert + result.DocumentId.Should().Be(command.DocumentId); + result.BorrowerId.Should().Be(command.BorrowerId); + result.Reason.Should().Be(command.Reason); + result.BorrowTime.Should().Be(command.BorrowFrom); + result.DueTime.Should().Be(command.BorrowTo); + result.Status.Should().Be(BorrowRequestStatus.Pending.ToString()); + + // Cleanup + Remove(await FindAsync(result.Id)); + Remove(user); + Remove(document); + Remove(await FindAsync(department.Id)); + } + + [Fact] + public async Task ShouldThrowKeyNotFoundException_WhenUserDoesNotExist() + { + // Arrange + var document = CreateNDocuments(1).First(); + document.Status = DocumentStatus.Available; + await AddAsync(document); + + var command = new BorrowDocument.Command() + { + BorrowerId = Guid.NewGuid(), + DocumentId = document.Id, + BorrowFrom = DateTime.Now.Add(TimeSpan.FromDays(1)), + BorrowTo = DateTime.Now.Add(TimeSpan.FromDays(2)), + Reason = "Example", + }; + + // Act + var result = async () => await SendAsync(command); + + // Assert + await result.Should().ThrowAsync() + .WithMessage("User does not exist."); + + // Cleanup + Remove(document); + } + + [Fact] + public async Task ShouldThrowConflictException_WhenUserIsNotActive() + { + // Arrange + var document = CreateNDocuments(1).First(); + document.Status = DocumentStatus.Available; + await AddAsync(document); + + var user = CreateUser(IdentityData.Roles.Employee, "aaaaaa"); + user.IsActive = false; + await AddAsync(user); + + var command = new BorrowDocument.Command() + { + BorrowerId = user.Id, + DocumentId = document.Id, + BorrowFrom = DateTime.Now.Add(TimeSpan.FromDays(1)), + BorrowTo = DateTime.Now.Add(TimeSpan.FromDays(2)), + Reason = "Example", + }; + + // Act + var result = async () => await SendAsync(command); + + // Assert + await result.Should().ThrowAsync() + .WithMessage("User is not active."); + + // Cleanup + Remove(document); + Remove(user); + } + + [Fact] + public async Task ShouldThrowConflictException_WhenUserIsNotActivated() + { + // Arrange + var document = CreateNDocuments(1).First(); + document.Status = DocumentStatus.Available; + await AddAsync(document); + + var user = CreateUser(IdentityData.Roles.Employee, "aaaaaa"); + user.IsActivated = false; + await AddAsync(user); + + var command = new BorrowDocument.Command() + { + BorrowerId = user.Id, + DocumentId = document.Id, + BorrowFrom = DateTime.Now.Add(TimeSpan.FromDays(1)), + BorrowTo = DateTime.Now.Add(TimeSpan.FromDays(2)), + Reason = "Example", + }; + + // Act + var result = async () => await SendAsync(command); + + // Assert + await result.Should().ThrowAsync() + .WithMessage("User is not activated."); + + // Cleanup + Remove(document); + Remove(user); + } + + [Fact] + public async Task ShouldThrowKeyNotFoundException_WhenDocumentDoesNotExist() + { + // Arrange + var user = CreateUser(IdentityData.Roles.Employee, "bbbbbb"); + await AddAsync(user); + + var command = new BorrowDocument.Command() + { + BorrowerId = user.Id, + DocumentId = Guid.NewGuid(), + BorrowFrom = DateTime.Now.Add(TimeSpan.FromDays(1)), + BorrowTo = DateTime.Now.Add(TimeSpan.FromDays(2)), + Reason = "Example", + }; + + // Act + var result = async () => await SendAsync(command); + + // Assert + await result.Should().ThrowAsync() + .WithMessage("Document does not exist."); + + // Cleanup + Remove(user); + } + + [Fact] + public async Task ShouldConflictException_WhenDocumentIsNotAvailable() + { + // Arrange + var user = CreateUser(IdentityData.Roles.Employee, "bbbbbb"); + await AddAsync(user); + + var document = CreateNDocuments(1).First(); + document.Status = DocumentStatus.Borrowed; + await AddAsync(document); + + var command = new BorrowDocument.Command() + { + BorrowerId = user.Id, + DocumentId = document.Id, + BorrowFrom = DateTime.Now.Add(TimeSpan.FromDays(1)), + BorrowTo = DateTime.Now.Add(TimeSpan.FromDays(2)), + Reason = "Example", + }; + + // Act + var result = async () => await SendAsync(command); + + // Assert + await result.Should().ThrowAsync() + .WithMessage("Document is not available."); + + // Cleanup + Remove(user); + Remove(document); + } + + [Fact] + public async Task ShouldConflictException_WhenUserAndDocumentDoesNotBelongToTheSameDepartment() + { + // Arrange + using var scope = ScopeFactory.CreateScope(); + var context = scope.ServiceProvider.GetRequiredService(); + var department1 = CreateDepartment(); + var department2 = CreateDepartment(); + + var user = CreateUser(IdentityData.Roles.Employee, "bbbbbb"); + user.Department = department1; + await context.AddAsync(user); + + var document = CreateNDocuments(1).First(); + document.Status = DocumentStatus.Available; + document.Department = department2; + await context.AddAsync(document); + + await context.SaveChangesAsync(); + + var command = new BorrowDocument.Command() + { + BorrowerId = user.Id, + DocumentId = document.Id, + BorrowFrom = DateTime.Now.Add(TimeSpan.FromDays(1)), + BorrowTo = DateTime.Now.Add(TimeSpan.FromDays(2)), + Reason = "Example", + }; + + // Act + var result = async () => await SendAsync(command); + + // Assert + await result.Should().ThrowAsync() + .WithMessage("User is not allowed to borrow this document."); + + // Cleanup + Remove(user); + Remove(document); + Remove(department1); + Remove(department2); + } + + [Fact] + public async Task ShouldThrowConflictException_WhenRequestWithSameUserAndDocumentAlreadyExists() + { + // Arrange + using var scope = ScopeFactory.CreateScope(); + var context = scope.ServiceProvider.GetRequiredService(); + var department = CreateDepartment(); + + var user = CreateUser(IdentityData.Roles.Employee, "bbbbbb"); + user.Department = department; + + var document = CreateNDocuments(1).First(); + document.Status = DocumentStatus.Available; + document.Department = department; + + var borrow = CreateBorrowRequest(user, document, BorrowRequestStatus.Pending); + await context.AddAsync(borrow); + + await context.SaveChangesAsync(); + + var command = new BorrowDocument.Command() + { + BorrowerId = user.Id, + DocumentId = document.Id, + BorrowFrom = DateTime.Now.Add(TimeSpan.FromDays(1)), + BorrowTo = DateTime.Now.Add(TimeSpan.FromDays(2)), + Reason = "Example", + }; + + // Act + var result = async () => await SendAsync(command); + + // Assert + await result.Should().ThrowAsync() + .WithMessage("This document is already requested borrow from the same user."); + + // Cleanup; + Remove(borrow); + Remove(user); + Remove(document); + Remove(department); + } + + [Fact] + public async Task ShouldThrowConflictException_WhenARequestIsMadeWhileDocumentIsAlreadyBeingBorrowed() + { + // Arrange + using var scope = ScopeFactory.CreateScope(); + var context = scope.ServiceProvider.GetRequiredService(); + var department = CreateDepartment(); + + var user1 = CreateUser(IdentityData.Roles.Employee, "bbbbbb"); + user1.Department = department; + + var user2 = CreateUser(IdentityData.Roles.Employee, "bbbbbb"); + user2.Department = department; + await context.AddAsync(user2); + + var document = CreateNDocuments(1).First(); + document.Status = DocumentStatus.Available; + document.Department = department; + + var borrow = CreateBorrowRequest(user1, document, BorrowRequestStatus.Approved); + await context.AddAsync(borrow); + + await context.SaveChangesAsync(); + + var command = new BorrowDocument.Command() + { + BorrowerId = user2.Id, + DocumentId = document.Id, + BorrowFrom = DateTime.Now.AddHours(1), + BorrowTo = DateTime.Now.Add(TimeSpan.FromDays(2)), + Reason = "Example", + }; + + // Act + var result = async () => await SendAsync(command); + + // Assert + await result.Should().ThrowAsync() + .WithMessage("This document cannot be borrowed."); + + // Cleanup; + Remove(borrow); + Remove(user1); + Remove(user2); + Remove(document); + Remove(department); + } +} \ No newline at end of file