From 0990df260fd413514f7643d31be162cad5d27666 Mon Sep 17 00:00:00 2001 From: Nguyen Quang Chien Date: Mon, 29 May 2023 17:41:27 +0700 Subject: [PATCH 1/6] add: integration test --- .../Rooms/Commands/EnableRoomTests.cs | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 tests/Application.Tests.Integration/Rooms/Commands/EnableRoomTests.cs diff --git a/tests/Application.Tests.Integration/Rooms/Commands/EnableRoomTests.cs b/tests/Application.Tests.Integration/Rooms/Commands/EnableRoomTests.cs new file mode 100644 index 00000000..8683a92c --- /dev/null +++ b/tests/Application.Tests.Integration/Rooms/Commands/EnableRoomTests.cs @@ -0,0 +1,94 @@ +using Application.Common.Exceptions; +using Application.Rooms.Commands; +using Domain.Entities; +using Domain.Entities.Physical; +using FluentAssertions; +using Xunit; + +namespace Application.Tests.Integration.Rooms.Commands; + +public class EnableRoomTests : BaseClassFixture +{ + public EnableRoomTests(CustomApiFactory apiFactory) : base(apiFactory) + { + } + + [Fact] + public async Task ShouldEnableRoom_WhenRoomExistsAndIsDisabled() + { + // Arrange + var department = CreateDepartment(); + var folder = CreateFolder(); + var locker = CreateLocker(folder); + var room = CreateRoom(department, locker); + folder.IsAvailable = false; + locker.IsAvailable = false; + room.IsAvailable = false; + await AddAsync(room); + + var command = new EnableRoom.Command() + { + RoomId = room.Id + }; + + // Act + var result = await SendAsync(command); + + // Assert + var folderResult = await FindAsync(folder.Id); + var lockerResult = await FindAsync(locker.Id); + + result.IsAvailable.Should().BeTrue(); + folderResult!.IsAvailable.Should().BeFalse(); + lockerResult!.IsAvailable.Should().BeFalse(); + + // Cleanup + Remove(folder); + Remove(locker); + Remove(room); + Remove(await FindAsync(department.Id)); + } + + [Fact] + public async Task ShouldThrowKeyNotFoundException_WhenRoomDoesNotExist() + { + // Arrange + var command = new EnableRoom.Command() + { + RoomId = Guid.NewGuid() + }; + + // Act + var action = async () => await SendAsync(command); + + // Assert + await action.Should().ThrowAsync() + .WithMessage("Room does not exist."); + } + + [Fact] + public async Task ShouldThrowConflictException_WhenRoomIsAlreadyAvailable() + { + // Arrange + var department = CreateDepartment(); + var room = CreateRoom(department); + room.IsAvailable = true; + await AddAsync(room); + + var command = new DisableRoom.Command() + { + RoomId = room.Id + }; + + // Act + var action = async () => await SendAsync(command); + + // Assert + await action.Should().ThrowAsync() + .WithMessage("Room have already been disabled."); + + // Cleanup + Remove(room); + Remove(await FindAsync(department.Id)); + } +} \ No newline at end of file From 664902f90b5b033e2dfaaad17c4c2682b5c07e3e Mon Sep 17 00:00:00 2001 From: Vzart Date: Mon, 29 May 2023 20:02:15 +0700 Subject: [PATCH 2/6] feat: enable room --- .../Common/Models/Dtos/Physical/RoomDto.cs | 2 +- src/Application/Rooms/Commands/EnableRoom.cs | 37 +++++++++++++++++++ .../CustomApiFactory.cs | 2 +- .../Rooms/Commands/EnableRoomTests.cs | 4 +- 4 files changed, 41 insertions(+), 4 deletions(-) diff --git a/src/Application/Common/Models/Dtos/Physical/RoomDto.cs b/src/Application/Common/Models/Dtos/Physical/RoomDto.cs index a2ed7b95..ff0ab27a 100644 --- a/src/Application/Common/Models/Dtos/Physical/RoomDto.cs +++ b/src/Application/Common/Models/Dtos/Physical/RoomDto.cs @@ -11,7 +11,7 @@ public class RoomDto : IMapFrom public string Name { get; set; } = null!; public string? Description { get; set; } public StaffDto? Staff { get; set; } - public DepartmentDto? Department { get; set; } + public DepartmentDto Department { get; set; } public int Capacity { get; set; } public int NumberOfLockers { get; set; } public bool IsAvailable { get; set; } diff --git a/src/Application/Rooms/Commands/EnableRoom.cs b/src/Application/Rooms/Commands/EnableRoom.cs index 0e0cf048..f98a39ae 100644 --- a/src/Application/Rooms/Commands/EnableRoom.cs +++ b/src/Application/Rooms/Commands/EnableRoom.cs @@ -1,5 +1,9 @@ +using Application.Common.Exceptions; +using Application.Common.Interfaces; using Application.Common.Models.Dtos.Physical; +using AutoMapper; using MediatR; +using Microsoft.EntityFrameworkCore; namespace Application.Rooms.Commands; @@ -9,4 +13,37 @@ public record Command : IRequest { public Guid RoomId { get; init; } } + + public class EnableRoomCommandHandler : IRequestHandler + { + private readonly IApplicationDbContext _context; + private readonly IMapper _mapper; + + public EnableRoomCommandHandler(IApplicationDbContext context, IMapper mapper) + { + _context = context; + _mapper = mapper; + } + + public async Task Handle(Command request, CancellationToken cancellationToken) + { + var room = await _context.Rooms + .FirstOrDefaultAsync(x => x.Id.Equals(request.RoomId), cancellationToken: cancellationToken); + + if (room is null) + { + throw new KeyNotFoundException("Room does not exist."); + } + + if (room.IsAvailable) + { + throw new ConflictException("Room have already been enabled."); + } + + room.IsAvailable = true; + var result = _context.Rooms.Update(room); + await _context.SaveChangesAsync(cancellationToken); + return _mapper.Map(result.Entity); + } + } } \ No newline at end of file diff --git a/tests/Application.Tests.Integration/CustomApiFactory.cs b/tests/Application.Tests.Integration/CustomApiFactory.cs index f76d4ac3..a4b2c7f1 100644 --- a/tests/Application.Tests.Integration/CustomApiFactory.cs +++ b/tests/Application.Tests.Integration/CustomApiFactory.cs @@ -28,7 +28,7 @@ protected override void ConfigureWebHost(IWebHostBuilder builder) var databaseSettings = GetConfiguration().GetSection(nameof(DatabaseSettings)).Get(); services.AddDbContext(options => { - options.UseNpgsql(databaseSettings!.ConnectionString, optionsBuilder => optionsBuilder.UseNodaTime()); + options.UseNpgsql("Server=localhost;Port=5432;Database=mytestdb;User ID=profiletester;Password=supasupasecured", optionsBuilder => optionsBuilder.UseNodaTime()); }); }); } diff --git a/tests/Application.Tests.Integration/Rooms/Commands/EnableRoomTests.cs b/tests/Application.Tests.Integration/Rooms/Commands/EnableRoomTests.cs index 8683a92c..58d2f3c7 100644 --- a/tests/Application.Tests.Integration/Rooms/Commands/EnableRoomTests.cs +++ b/tests/Application.Tests.Integration/Rooms/Commands/EnableRoomTests.cs @@ -75,7 +75,7 @@ public async Task ShouldThrowConflictException_WhenRoomIsAlreadyAvailable() room.IsAvailable = true; await AddAsync(room); - var command = new DisableRoom.Command() + var command = new EnableRoom.Command() { RoomId = room.Id }; @@ -85,7 +85,7 @@ public async Task ShouldThrowConflictException_WhenRoomIsAlreadyAvailable() // Assert await action.Should().ThrowAsync() - .WithMessage("Room have already been disabled."); + .WithMessage("Room have already been enabled."); // Cleanup Remove(room); From b1ccfd5e672130b38c054fe2b145d862f79f11e0 Mon Sep 17 00:00:00 2001 From: Vzart Date: Mon, 29 May 2023 20:08:30 +0700 Subject: [PATCH 3/6] fix: resolve test --- tests/Application.Tests.Integration/CustomApiFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Application.Tests.Integration/CustomApiFactory.cs b/tests/Application.Tests.Integration/CustomApiFactory.cs index a4b2c7f1..f76d4ac3 100644 --- a/tests/Application.Tests.Integration/CustomApiFactory.cs +++ b/tests/Application.Tests.Integration/CustomApiFactory.cs @@ -28,7 +28,7 @@ protected override void ConfigureWebHost(IWebHostBuilder builder) var databaseSettings = GetConfiguration().GetSection(nameof(DatabaseSettings)).Get(); services.AddDbContext(options => { - options.UseNpgsql("Server=localhost;Port=5432;Database=mytestdb;User ID=profiletester;Password=supasupasecured", optionsBuilder => optionsBuilder.UseNodaTime()); + options.UseNpgsql(databaseSettings!.ConnectionString, optionsBuilder => optionsBuilder.UseNodaTime()); }); }); } From df39fb1898a82f70ad24962456c943e55b7ede9d Mon Sep 17 00:00:00 2001 From: Vzart Date: Mon, 29 May 2023 20:25:33 +0700 Subject: [PATCH 4/6] add: add validator for enable room --- src/Application/Rooms/Commands/EnableRoom.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Application/Rooms/Commands/EnableRoom.cs b/src/Application/Rooms/Commands/EnableRoom.cs index f98a39ae..7ea5dd53 100644 --- a/src/Application/Rooms/Commands/EnableRoom.cs +++ b/src/Application/Rooms/Commands/EnableRoom.cs @@ -2,6 +2,7 @@ using Application.Common.Interfaces; using Application.Common.Models.Dtos.Physical; using AutoMapper; +using FluentValidation; using MediatR; using Microsoft.EntityFrameworkCore; @@ -9,6 +10,15 @@ namespace Application.Rooms.Commands; public class EnableRoom { + public class Validator : AbstractValidator + { + public Validator() + { + RuleLevelCascadeMode = CascadeMode.Stop; + RuleFor(x => x.RoomId) + .NotEmpty().WithMessage("RoomId is required."); + } + } public record Command : IRequest { public Guid RoomId { get; init; } From 92a4d8704dc5e4085f6b77425db2ef98a8f20623 Mon Sep 17 00:00:00 2001 From: Vzart Date: Mon, 29 May 2023 21:01:31 +0700 Subject: [PATCH 5/6] refactor: remove unesscary validator and refactor name of handler --- src/Application/Rooms/Commands/EnableRoom.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Application/Rooms/Commands/EnableRoom.cs b/src/Application/Rooms/Commands/EnableRoom.cs index 7ea5dd53..ae5ff190 100644 --- a/src/Application/Rooms/Commands/EnableRoom.cs +++ b/src/Application/Rooms/Commands/EnableRoom.cs @@ -24,12 +24,12 @@ public record Command : IRequest public Guid RoomId { get; init; } } - public class EnableRoomCommandHandler : IRequestHandler + public class CommandHandler : IRequestHandler { private readonly IApplicationDbContext _context; private readonly IMapper _mapper; - public EnableRoomCommandHandler(IApplicationDbContext context, IMapper mapper) + public CommandHandler(IApplicationDbContext context, IMapper mapper) { _context = context; _mapper = mapper; From e980fccbf5adf93adcee2af52dc9200fa917a989 Mon Sep 17 00:00:00 2001 From: Vzart Date: Mon, 29 May 2023 21:04:08 +0700 Subject: [PATCH 6/6] refactor: grammar for a happy chien-san --- src/Application/Rooms/Commands/EnableRoom.cs | 2 +- .../Rooms/Commands/EnableRoomTests.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Application/Rooms/Commands/EnableRoom.cs b/src/Application/Rooms/Commands/EnableRoom.cs index ae5ff190..af5d710b 100644 --- a/src/Application/Rooms/Commands/EnableRoom.cs +++ b/src/Application/Rooms/Commands/EnableRoom.cs @@ -47,7 +47,7 @@ public async Task Handle(Command request, CancellationToken cancellatio if (room.IsAvailable) { - throw new ConflictException("Room have already been enabled."); + throw new ConflictException("Room has already been enabled."); } room.IsAvailable = true; diff --git a/tests/Application.Tests.Integration/Rooms/Commands/EnableRoomTests.cs b/tests/Application.Tests.Integration/Rooms/Commands/EnableRoomTests.cs index 58d2f3c7..fa07d0b8 100644 --- a/tests/Application.Tests.Integration/Rooms/Commands/EnableRoomTests.cs +++ b/tests/Application.Tests.Integration/Rooms/Commands/EnableRoomTests.cs @@ -85,7 +85,7 @@ public async Task ShouldThrowConflictException_WhenRoomIsAlreadyAvailable() // Assert await action.Should().ThrowAsync() - .WithMessage("Room have already been enabled."); + .WithMessage("Room has already been enabled."); // Cleanup Remove(room);