From 5fe863f8080e0b24ea64761b5110a901915589f6 Mon Sep 17 00:00:00 2001 From: Nguyen Quang Chien Date: Mon, 29 May 2023 21:10:59 +0700 Subject: [PATCH 1/4] add: integration test --- .../Folders/Commands/RemoveFolderTests.cs | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 tests/Application.Tests.Integration/Folders/Commands/RemoveFolderTests.cs diff --git a/tests/Application.Tests.Integration/Folders/Commands/RemoveFolderTests.cs b/tests/Application.Tests.Integration/Folders/Commands/RemoveFolderTests.cs new file mode 100644 index 00000000..b966c9d3 --- /dev/null +++ b/tests/Application.Tests.Integration/Folders/Commands/RemoveFolderTests.cs @@ -0,0 +1,93 @@ +using Application.Folders.Commands; +using Application.Lockers.Commands; +using Domain.Entities; +using Domain.Entities.Physical; +using FluentAssertions; +using Xunit; + +namespace Application.Tests.Integration.Folders.Commands; + +public class RemoveFolderTests : BaseClassFixture +{ + public RemoveFolderTests(CustomApiFactory apiFactory) : base(apiFactory) + { + } + + [Fact] + public async Task ShouldRemoveFolder_WhenFolderHasNoDocuments() + { + // Arrange + var department = CreateDepartment(); + var folder = CreateFolder(); + var locker = CreateLocker(folder); + var room = CreateRoom(department, locker); + await Add(room); + + var command = new RemoveFolder.Command() + { + FolderId = folder.Id, + }; + + // Act + var result = await SendAsync(command); + + // Assert + result.Id.Should().Be(folder.Id); + var removedFolder = await FindAsync(folder.Id); + removedFolder.Should().BeNull(); + + // Cleanup + Remove(folder); + Remove(locker); + Remove(room); + Remove(await FindAsync(department.Id)); + } + + [Fact] + public async Task ShouldThrowConflictException_WhenFolderStillHasDocuments() + { + // Arrange + var department = CreateDepartment(); + var documents = CreateNDocuments(1); + var folder = CreateFolder(documents); + var locker = CreateLocker(folder); + var room = CreateRoom(department, locker); + await AddAsync(room); + + var command = new RemoveFolder.Command() + { + FolderId = folder.Id + }; + + // Act + var action = async () => await SendAsync(command); + + // Assert + await action.Should().ThrowAsync() + .WithMessage("Folder cannot be removed because it contains documents."); + + // Cleanup + Remove(documents.First()); + Remove(folder); + Remove(locker); + Remove(room); + Remove(await FindAsync(department.Id)); + } + + [Fact] + public async Task ShouldThrowKeyNotFoundException_WhenFolderDoesNotExist() + { + // Arrange + var command = new RemoveFolder.Command() + { + FolderId = Guid.NewGuid(), + }; + + // Act + var action = async () => await SendAsync(command); + + // Assert + await action.Should().ThrowAsync() + .WithMessage("Folder does not exist."); + } +} \ No newline at end of file From aad9bd6a308aeebbec9a1e03c1f6e6c838d1c78e Mon Sep 17 00:00:00 2001 From: kaitoz11 <43519768+kaitoz11@users.noreply.github.com> Date: Thu, 1 Jun 2023 15:15:57 +0700 Subject: [PATCH 2/4] feat(RemoveFolder.cs): add remove folder feature --- .../Folders/Commands/RemoveFolder.cs | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/Application/Folders/Commands/RemoveFolder.cs b/src/Application/Folders/Commands/RemoveFolder.cs index 528184ce..97e0de47 100644 --- a/src/Application/Folders/Commands/RemoveFolder.cs +++ b/src/Application/Folders/Commands/RemoveFolder.cs @@ -1,12 +1,61 @@ +using Application.Common.Interfaces; using Application.Common.Models.Dtos.Physical; +using AutoMapper; +using FluentValidation; using MediatR; +using Microsoft.EntityFrameworkCore; namespace Application.Folders.Commands; public class RemoveFolder { + public class Validator : AbstractValidator + { + public Validator() + { + RuleLevelCascadeMode = CascadeMode.Stop; + + RuleFor(f => f.FolderId) + .NotEmpty().WithMessage("FolderId is required."); + } + } + public record Command : IRequest { public Guid FolderId { get; init; } } + + public class CommandHandler : IRequestHandler + { + private readonly IApplicationDbContext _context; + private readonly IMapper _mapper; + + public CommandHandler(IApplicationDbContext context, IMapper mapper) + { + _context = context; + _mapper = mapper; + } + + public async Task Handle(Command request, CancellationToken cancellationToken) + { + var folder = await _context.Folders + .FirstOrDefaultAsync(x => x.Id.Equals(request.FolderId), cancellationToken); + + if (folder is null) + { + throw new KeyNotFoundException("Folder does not exist."); + } + + var containDocument = folder.NumberOfDocuments > 0; + + if (containDocument) + { + throw new InvalidOperationException("Folder cannot be removed because it contains documents."); + } + + var result = _context.Folders.Remove(folder); + await _context.SaveChangesAsync(cancellationToken); + return _mapper.Map(result.Entity); + } + } } \ No newline at end of file From 46ad9c2cabdf08251763f16cdfd93771c9a8f245 Mon Sep 17 00:00:00 2001 From: kaitoz11 <43519768+kaitoz11@users.noreply.github.com> Date: Thu, 1 Jun 2023 16:45:09 +0700 Subject: [PATCH 3/4] Fix(RemoveFolderTest.cs): Sorry for not doing review code properly. Lesson learnt: never trust codes from a sleepy coder! --- .../Folders/Commands/RemoveFolderTests.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/Application.Tests.Integration/Folders/Commands/RemoveFolderTests.cs b/tests/Application.Tests.Integration/Folders/Commands/RemoveFolderTests.cs index b966c9d3..5d5f4a14 100644 --- a/tests/Application.Tests.Integration/Folders/Commands/RemoveFolderTests.cs +++ b/tests/Application.Tests.Integration/Folders/Commands/RemoveFolderTests.cs @@ -1,5 +1,4 @@ using Application.Folders.Commands; -using Application.Lockers.Commands; using Domain.Entities; using Domain.Entities.Physical; using FluentAssertions; @@ -37,9 +36,9 @@ public async Task ShouldRemoveFolder_WhenFolderHasNoDocuments() removedFolder.Should().BeNull(); // Cleanup - Remove(folder); - Remove(locker); - Remove(room); + //Remove(folder); + Remove(await FindAsync(locker.Id)); + Remove(await FindAsync(room.Id)); Remove(await FindAsync(department.Id)); } From 83a52ab2bcaf9c7b743b3e2d751068c72160f7c2 Mon Sep 17 00:00:00 2001 From: kaitoz11 <43519768+kaitoz11@users.noreply.github.com> Date: Thu, 1 Jun 2023 23:53:12 +0700 Subject: [PATCH 4/4] fix: number of folder in locker decrease by 1 --- .../Folders/Commands/RemoveFolder.cs | 19 +++++++------------ .../Folders/Commands/RemoveFolderTests.cs | 10 ++++++---- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/Application/Folders/Commands/RemoveFolder.cs b/src/Application/Folders/Commands/RemoveFolder.cs index 97e0de47..30fb5776 100644 --- a/src/Application/Folders/Commands/RemoveFolder.cs +++ b/src/Application/Folders/Commands/RemoveFolder.cs @@ -1,6 +1,8 @@ +using Application.Common.Exceptions; using Application.Common.Interfaces; using Application.Common.Models.Dtos.Physical; using AutoMapper; +using Domain.Entities.Physical; using FluentValidation; using MediatR; using Microsoft.EntityFrameworkCore; @@ -9,17 +11,6 @@ namespace Application.Folders.Commands; public class RemoveFolder { - public class Validator : AbstractValidator - { - public Validator() - { - RuleLevelCascadeMode = CascadeMode.Stop; - - RuleFor(f => f.FolderId) - .NotEmpty().WithMessage("FolderId is required."); - } - } - public record Command : IRequest { public Guid FolderId { get; init; } @@ -39,6 +30,7 @@ public CommandHandler(IApplicationDbContext context, IMapper mapper) public async Task Handle(Command request, CancellationToken cancellationToken) { var folder = await _context.Folders + .Include(x => x.Locker) .FirstOrDefaultAsync(x => x.Id.Equals(request.FolderId), cancellationToken); if (folder is null) @@ -50,10 +42,13 @@ public async Task Handle(Command request, CancellationToken cancellat if (containDocument) { - throw new InvalidOperationException("Folder cannot be removed because it contains documents."); + throw new ConflictException("Folder cannot be removed because it contains documents."); } + var locker = folder.Locker; var result = _context.Folders.Remove(folder); + locker.NumberOfFolders -= 1; + await _context.SaveChangesAsync(cancellationToken); return _mapper.Map(result.Entity); } diff --git a/tests/Application.Tests.Integration/Folders/Commands/RemoveFolderTests.cs b/tests/Application.Tests.Integration/Folders/Commands/RemoveFolderTests.cs index 5d5f4a14..a03af6b3 100644 --- a/tests/Application.Tests.Integration/Folders/Commands/RemoveFolderTests.cs +++ b/tests/Application.Tests.Integration/Folders/Commands/RemoveFolderTests.cs @@ -1,3 +1,4 @@ +using Application.Common.Exceptions; using Application.Folders.Commands; using Domain.Entities; using Domain.Entities.Physical; @@ -34,10 +35,11 @@ public async Task ShouldRemoveFolder_WhenFolderHasNoDocuments() result.Id.Should().Be(folder.Id); var removedFolder = await FindAsync(folder.Id); removedFolder.Should().BeNull(); + var lockerOfRemovedFolder = await FindAsync(locker.Id); + locker.NumberOfFolders.Should().Be(lockerOfRemovedFolder!.NumberOfFolders + 1); // Cleanup - //Remove(folder); - Remove(await FindAsync(locker.Id)); + Remove(lockerOfRemovedFolder); Remove(await FindAsync(room.Id)); Remove(await FindAsync(department.Id)); } @@ -62,9 +64,9 @@ public async Task ShouldThrowConflictException_WhenFolderStillHasDocuments() var action = async () => await SendAsync(command); // Assert - await action.Should().ThrowAsync() + await action.Should().ThrowAsync() .WithMessage("Folder cannot be removed because it contains documents."); - + // Cleanup Remove(documents.First()); Remove(folder);