diff --git a/Taarafo.Core.Tests.Unit/Services/Foundations/GroupMemberships/GroupMembershipServiceTests.Exceptions.RetrieveById.cs b/Taarafo.Core.Tests.Unit/Services/Foundations/GroupMemberships/GroupMembershipServiceTests.Exceptions.RetrieveById.cs new file mode 100644 index 00000000..0d610b59 --- /dev/null +++ b/Taarafo.Core.Tests.Unit/Services/Foundations/GroupMemberships/GroupMembershipServiceTests.Exceptions.RetrieveById.cs @@ -0,0 +1,105 @@ +// --------------------------------------------------------------- +// Copyright (c) Coalition of the Good-Hearted Engineers +// FREE TO USE TO CONNECT THE WORLD +// --------------------------------------------------------------- + +using System; +using System.Threading.Tasks; +using FluentAssertions; +using Microsoft.Data.SqlClient; +using Moq; +using Taarafo.Core.Models.GroupMemberships; +using Taarafo.Core.Models.GroupMemberships.Exceptions; +using Xunit; + +namespace Taarafo.Core.Tests.Unit.Services.Foundations.GroupMemberships +{ + public partial class GroupMembershipServiceTests + { + [Fact] + public async Task ShouldThrowCriticalDependencyExceptionOnRetrieveByIdIfSqlErrorOccursAndLogItAsync() + { + // given + Guid someId = Guid.NewGuid(); + SqlException sqlException = GetSqlException(); + + var failedGroupMembershipStorageException = + new FailedGroupMembershipStorageException(sqlException); + + var expectedGroupMembershipDependencyException = + new GroupMembershipDependencyException(failedGroupMembershipStorageException); + + this.storageBrokerMock.Setup(broker => + broker.SelectGroupMembershipByIdAsync(It.IsAny())) + .ThrowsAsync(sqlException); + + // when + ValueTask retrieveGroupMembershipByIdTask = + this.groupMembershipService.RetrieveGroupMembershipByIdAsync(someId); + + GroupMembershipDependencyException actualGroupMembershipDependencyException = + await Assert.ThrowsAsync( + retrieveGroupMembershipByIdTask.AsTask); + + // then + actualGroupMembershipDependencyException.Should().BeEquivalentTo( + expectedGroupMembershipDependencyException); + + this.storageBrokerMock.Verify(broker => + broker.SelectGroupMembershipByIdAsync(It.IsAny()), + Times.Once); + + this.loggingBrokerMock.Verify(broker => + broker.LogCritical(It.Is(SameExceptionAs( + expectedGroupMembershipDependencyException))), + Times.Once); + + this.storageBrokerMock.VerifyNoOtherCalls(); + this.loggingBrokerMock.VerifyNoOtherCalls(); + this.dateTimeBrokerMock.VerifyNoOtherCalls(); + } + + [Fact] + public async Task ShouldThrowServiceExceptionOnRetrieveByIdIfServiceErrorOccursAndLogItAsync() + { + // given + Guid someId = Guid.NewGuid(); + var serviceException = new Exception(); + + var failedGroupMembershipServiceException = + new FailedGroupMembershipServiceException(serviceException); + + var expectedGroupMembershipServiceException = + new GroupMembershipServiceException(failedGroupMembershipServiceException); + + this.storageBrokerMock.Setup(broker => + broker.SelectGroupMembershipByIdAsync(It.IsAny())) + .ThrowsAsync(serviceException); + + // when + ValueTask retrieveGroupMembershipByIdTask = + this.groupMembershipService.RetrieveGroupMembershipByIdAsync(someId); + + GroupMembershipServiceException actualGroupMembershipServiceException = + await Assert.ThrowsAsync( + retrieveGroupMembershipByIdTask.AsTask); + + // then + actualGroupMembershipServiceException.Should().BeEquivalentTo( + expectedGroupMembershipServiceException); + + this.storageBrokerMock.Verify(broker => + broker.SelectGroupMembershipByIdAsync(It.IsAny()), + Times.Once); + + this.loggingBrokerMock.Verify(broker => + broker.LogError(It.Is(SameExceptionAs( + expectedGroupMembershipServiceException))), + Times.Once); + + this.storageBrokerMock.VerifyNoOtherCalls(); + this.loggingBrokerMock.VerifyNoOtherCalls(); + this.dateTimeBrokerMock.VerifyNoOtherCalls(); + } + } +} \ No newline at end of file diff --git a/Taarafo.Core.Tests.Unit/Services/Foundations/GroupMemberships/GroupMembershipServiceTests.Logic.RetrieveById.cs b/Taarafo.Core.Tests.Unit/Services/Foundations/GroupMemberships/GroupMembershipServiceTests.Logic.RetrieveById.cs new file mode 100644 index 00000000..402e56a8 --- /dev/null +++ b/Taarafo.Core.Tests.Unit/Services/Foundations/GroupMemberships/GroupMembershipServiceTests.Logic.RetrieveById.cs @@ -0,0 +1,45 @@ +// --------------------------------------------------------------- +// Copyright (c) Coalition of the Good-Hearted Engineers +// FREE TO USE TO CONNECT THE WORLD +// --------------------------------------------------------------- + +using System.Threading.Tasks; +using FluentAssertions; +using Force.DeepCloner; +using Moq; +using Taarafo.Core.Models.GroupMemberships; +using Xunit; + +namespace Taarafo.Core.Tests.Unit.Services.Foundations.GroupMemberships +{ + public partial class GroupMembershipServiceTests + { + [Fact] + public async Task ShouldRetrieveGroupMembershipByIdAsync() + { + // given + GroupMembership randomGroupMembership = CreateRandomGroupMembership(); + GroupMembership storageGroupMembership = randomGroupMembership; + GroupMembership expectedGroupMembership = storageGroupMembership.DeepClone(); + + this.storageBrokerMock.Setup(broker => + broker.SelectGroupMembershipByIdAsync(randomGroupMembership.Id)) + .ReturnsAsync(storageGroupMembership); + + // when + GroupMembership actualGroupMembership = + await this.groupMembershipService.RetrieveGroupMembershipByIdAsync(randomGroupMembership.Id); + + // then + actualGroupMembership.Should().BeEquivalentTo(expectedGroupMembership); + + this.storageBrokerMock.Verify(broker => + broker.SelectGroupMembershipByIdAsync(randomGroupMembership.Id), + Times.Once); + + this.storageBrokerMock.VerifyNoOtherCalls(); + this.dateTimeBrokerMock.VerifyNoOtherCalls(); + this.loggingBrokerMock.VerifyNoOtherCalls(); + } + } +} \ No newline at end of file diff --git a/Taarafo.Core.Tests.Unit/Services/Foundations/GroupMemberships/GroupMembershipServiceTests.Validations.RetrieveById.cs b/Taarafo.Core.Tests.Unit/Services/Foundations/GroupMemberships/GroupMembershipServiceTests.Validations.RetrieveById.cs new file mode 100644 index 00000000..990c64b2 --- /dev/null +++ b/Taarafo.Core.Tests.Unit/Services/Foundations/GroupMemberships/GroupMembershipServiceTests.Validations.RetrieveById.cs @@ -0,0 +1,102 @@ +// --------------------------------------------------------------- +// Copyright (c) Coalition of the Good-Hearted Engineers +// FREE TO USE TO CONNECT THE WORLD +// --------------------------------------------------------------- + +using System; +using System.Threading.Tasks; +using FluentAssertions; +using Moq; +using Taarafo.Core.Models.GroupMemberships; +using Taarafo.Core.Models.GroupMemberships.Exceptions; +using Xunit; + +namespace Taarafo.Core.Tests.Unit.Services.Foundations.GroupMemberships +{ + public partial class GroupMembershipServiceTests + { + [Fact] + public async Task ShouldThrowValidationExceptionOnRetrieveByIdIfIdIsInvalidAndLogItAsync() + { + // given + var invalidGroupMembershipId = Guid.Empty; + + var invalidGroupMembershipException = + new InvalidGroupMembershipException(); + invalidGroupMembershipException.AddData( + key: nameof(GroupMembership.Id), + values: "Id is required"); + + var expectedGroupMembershipValidationException = + new GroupMembershipValidationException(invalidGroupMembershipException); + + // when + ValueTask retrieveGroupMembershipByIdTask = + this.groupMembershipService.RetrieveGroupMembershipByIdAsync(invalidGroupMembershipId); + + GroupMembershipValidationException actualGroupMembershipValidationException = + await Assert.ThrowsAsync( + retrieveGroupMembershipByIdTask.AsTask); + + // then + actualGroupMembershipValidationException.Should().BeEquivalentTo( + expectedGroupMembershipValidationException); + + this.loggingBrokerMock.Verify(broker => + broker.LogError(It.Is(SameExceptionAs( + expectedGroupMembershipValidationException))), + Times.Once); + + this.storageBrokerMock.Verify(broker => + broker.SelectGroupMembershipByIdAsync(It.IsAny()), + Times.Never); + + this.loggingBrokerMock.VerifyNoOtherCalls(); + this.storageBrokerMock.VerifyNoOtherCalls(); + this.dateTimeBrokerMock.VerifyNoOtherCalls(); + } + + [Fact] + public async Task ShouldThrowNotFoundExceptionOnRetrieveByIdIfGroupMembershipIsNotFoundAndLogItAsync() + { + //given + Guid someGroupMembershipId = Guid.NewGuid(); + GroupMembership noGroupMembership = null; + + var notFoundGroupMembershipException = + new NotFoundGroupMembershipException(someGroupMembershipId); + + var expectedGroupMembershipValidationException = + new GroupMembershipValidationException(notFoundGroupMembershipException); + + this.storageBrokerMock.Setup(broker => + broker.SelectGroupMembershipByIdAsync(It.IsAny())) + .ReturnsAsync(noGroupMembership); + + //when + ValueTask retrieveGroupMembershipByIdTask = + this.groupMembershipService.RetrieveGroupMembershipByIdAsync(someGroupMembershipId); + + GroupMembershipValidationException actualGroupMembershipValidationException = + await Assert.ThrowsAsync( + retrieveGroupMembershipByIdTask.AsTask); + + // then + actualGroupMembershipValidationException.Should().BeEquivalentTo( + expectedGroupMembershipValidationException); + + this.storageBrokerMock.Verify(broker => + broker.SelectGroupMembershipByIdAsync(It.IsAny()), + Times.Once()); + + this.loggingBrokerMock.Verify(broker => + broker.LogError(It.Is(SameExceptionAs( + expectedGroupMembershipValidationException))), + Times.Once); + + this.storageBrokerMock.VerifyNoOtherCalls(); + this.loggingBrokerMock.VerifyNoOtherCalls(); + this.dateTimeBrokerMock.VerifyNoOtherCalls(); + } + } +} \ No newline at end of file diff --git a/Taarafo.Core/Models/GroupMemberships/Exceptions/NotFoundGroupMembershipException.cs b/Taarafo.Core/Models/GroupMemberships/Exceptions/NotFoundGroupMembershipException.cs new file mode 100644 index 00000000..061dac28 --- /dev/null +++ b/Taarafo.Core/Models/GroupMemberships/Exceptions/NotFoundGroupMembershipException.cs @@ -0,0 +1,17 @@ +// --------------------------------------------------------------- +// Copyright (c) Coalition of the Good-Hearted Engineers +// FREE TO USE TO CONNECT THE WORLD +// --------------------------------------------------------------- + +using System; +using Xeptions; + +namespace Taarafo.Core.Models.GroupMemberships.Exceptions +{ + public class NotFoundGroupMembershipException : Xeption + { + public NotFoundGroupMembershipException(Guid groupMembershipId) + : base(message: $"Couldn't find GroupMembership with id: {groupMembershipId}.") + { } + } +} \ No newline at end of file diff --git a/Taarafo.Core/Services/Foundations/GroupMemberships/GroupMembershipService.Exceptions.cs b/Taarafo.Core/Services/Foundations/GroupMemberships/GroupMembershipService.Exceptions.cs index fec278ae..f368f27a 100644 --- a/Taarafo.Core/Services/Foundations/GroupMemberships/GroupMembershipService.Exceptions.cs +++ b/Taarafo.Core/Services/Foundations/GroupMemberships/GroupMembershipService.Exceptions.cs @@ -39,6 +39,10 @@ private async ValueTask TryCatch(ReturningGroupMembershipFuncti throw CreateAndLogCriticalDependencyException(failedGroupMembershipStorageException); } + catch (NotFoundGroupMembershipException notFoundGroupMembershipException) + { + throw CreateAndLogValidationException(notFoundGroupMembershipException); + } catch (DuplicateKeyException duplicateKeyException) { var alreadyExistsGroupMembershipException = diff --git a/Taarafo.Core/Services/Foundations/GroupMemberships/GroupMembershipService.Validations.cs b/Taarafo.Core/Services/Foundations/GroupMemberships/GroupMembershipService.Validations.cs index aeaa1776..76d0f455 100644 --- a/Taarafo.Core/Services/Foundations/GroupMemberships/GroupMembershipService.Validations.cs +++ b/Taarafo.Core/Services/Foundations/GroupMemberships/GroupMembershipService.Validations.cs @@ -23,6 +23,9 @@ public void ValidateGroupMembershipOnAdd(GroupMembership groupMembership) (Rule: IsNotRecent(groupMembership.MembershipDate), Parameter: nameof(GroupMembership.MembershipDate))); } + public void ValidateGroupMembershipId(Guid groupMembershipId) => + Validate((Rule: IsInvalid(groupMembershipId), Parameter: nameof(GroupMembership.Id))); + private void ValidateGroupMembershipIsNotNull(GroupMembership groupMembership) { if (groupMembership is null) @@ -31,6 +34,14 @@ private void ValidateGroupMembershipIsNotNull(GroupMembership groupMembership) } } + private static void ValidateStorageGroupMembership(GroupMembership maybeGroupMembership, Guid groupMembershipId) + { + if (maybeGroupMembership is null) + { + throw new NotFoundGroupMembershipException(groupMembershipId); + } + } + private static dynamic IsInvalid(Guid id) => new { Condition = id == Guid.Empty, diff --git a/Taarafo.Core/Services/Foundations/GroupMemberships/GroupMembershipService.cs b/Taarafo.Core/Services/Foundations/GroupMemberships/GroupMembershipService.cs index 04dfa0dd..3efc43db 100644 --- a/Taarafo.Core/Services/Foundations/GroupMemberships/GroupMembershipService.cs +++ b/Taarafo.Core/Services/Foundations/GroupMemberships/GroupMembershipService.cs @@ -3,6 +3,7 @@ // FREE TO USE TO CONNECT THE WORLD // --------------------------------------------------------------- +using System; using System.Threading.Tasks; using Taarafo.Core.Brokers.DateTimes; using Taarafo.Core.Brokers.Loggings; @@ -34,5 +35,18 @@ public ValueTask AddGroupMembershipAsync(GroupMembership groupM return await this.storageBroker.InsertGroupMembershipAsync(groupMembership); }); + + public ValueTask RetrieveGroupMembershipByIdAsync(Guid groupMembershipId) => + TryCatch(async () => + { + ValidateGroupMembershipId(groupMembershipId); + + GroupMembership maybeGroupMembership = + await this.storageBroker.SelectGroupMembershipByIdAsync(groupMembershipId); + + ValidateStorageGroupMembership(maybeGroupMembership, groupMembershipId); + + return maybeGroupMembership; + }); } } \ No newline at end of file diff --git a/Taarafo.Core/Services/Foundations/GroupMemberships/IGroupMembershipService.cs b/Taarafo.Core/Services/Foundations/GroupMemberships/IGroupMembershipService.cs index 444218dd..39928754 100644 --- a/Taarafo.Core/Services/Foundations/GroupMemberships/IGroupMembershipService.cs +++ b/Taarafo.Core/Services/Foundations/GroupMemberships/IGroupMembershipService.cs @@ -3,6 +3,7 @@ // FREE TO USE TO CONNECT THE WORLD // --------------------------------------------------------------- +using System; using System.Threading.Tasks; using Taarafo.Core.Models.GroupMemberships; @@ -11,5 +12,6 @@ namespace Taarafo.Core.Services.Foundations.GroupMemberships public interface IGroupMembershipService { ValueTask AddGroupMembershipAsync(GroupMembership groupMembership); + ValueTask RetrieveGroupMembershipByIdAsync(Guid groupMembershipId); } } \ No newline at end of file