Skip to content

Commit

Permalink
Merge pull request #249 from SlimAhmad/users/slimahmad/foundations/co…
Browse files Browse the repository at this point in the history
…ntributor-RetrieveByIdAsync

FOUNDATIONS: Contributor RetrieveByIdAsync
  • Loading branch information
hassanhabib authored Nov 17, 2024
2 parents a443e1a + a7fec43 commit e97c8d2
Show file tree
Hide file tree
Showing 7 changed files with 302 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// ----------------------------------------------------------------------------------
// Copyright (c) The Standard Organization: A coalition of the Good-Hearted Engineers
// ----------------------------------------------------------------------------------

using System;
using System.Threading.Tasks;
using FluentAssertions;
using GitFyle.Core.Api.Models.Foundations.Contributors;
using GitFyle.Core.Api.Models.Foundations.Contributors.Exceptions;
using Moq;

namespace GitFyle.Core.Api.Tests.Unit.Services.Foundations.Contributors
{
public partial class ContributorServiceTests
{
[Fact]
public async Task ShouldThrowCriticalDependencyExceptionOnRetrieveByIdIfSQLErrorOccursAndLogItAsync()
{
// given
Guid someGuid = Guid.NewGuid();
var sqlException = CreateSqlException();

var failedStorageContributorException =
new FailedStorageContributorException(
message: "Failed storage contributor error occurred, contact support.",
innerException: sqlException);

var expectedContributorDependencyException =
new ContributorDependencyException(
message: "Contributor dependency error occurred, contact support.",
innerException: failedStorageContributorException);

this.storageBrokerMock.Setup(broker =>
broker.SelectContributorByIdAsync(It.IsAny<Guid>()))
.ThrowsAsync(sqlException);

// when
ValueTask<Contributor> retrieveContributorByIdTask =
this.contributorService.RetrieveContributorByIdAsync(someGuid);

// then
await Assert.ThrowsAsync<ContributorDependencyException>(
testCode: retrieveContributorByIdTask.AsTask);

this.storageBrokerMock.Verify(broker =>
broker.SelectContributorByIdAsync(It.IsAny<Guid>()),
Times.Once);

this.loggingBrokerMock.Verify(broker =>
broker.LogCriticalAsync(It.Is(SameExceptionAs(
expectedContributorDependencyException))),
Times.Once);

this.dateTimeBrokerMock.Verify(broker =>
broker.GetCurrentDateTimeOffsetAsync(),
Times.Never);

this.storageBrokerMock.VerifyNoOtherCalls();
this.loggingBrokerMock.VerifyNoOtherCalls();
this.dateTimeBrokerMock.VerifyNoOtherCalls();
}

[Fact]
public async Task ShouldThrowServiceExceptionOnRetrieveByIdIfServiceErrorOccursAndLogItAsync()
{
//given
var someContributorId = Guid.NewGuid();
var serviceException = new Exception();

var failedServiceContributorException =
new FailedServiceContributorException(
message: "Failed service contributor error occurred, contact support.",
innerException: serviceException);

var expectedContributorServiceException =
new ContributorServiceException(
message: "Service error occurred, contact support.",
innerException: failedServiceContributorException);

this.storageBrokerMock.Setup(broker =>
broker.SelectContributorByIdAsync(It.IsAny<Guid>()))
.ThrowsAsync(serviceException);

//when
ValueTask<Contributor> retrieveContributorByIdTask =
this.contributorService.RetrieveContributorByIdAsync(someContributorId);

ContributorServiceException actualContributorServiceException =
await Assert.ThrowsAsync<ContributorServiceException>(
testCode: retrieveContributorByIdTask.AsTask);

//then
actualContributorServiceException.Should().BeEquivalentTo(
expectedContributorServiceException);

this.storageBrokerMock.Verify(broker =>
broker.SelectContributorByIdAsync(It.IsAny<Guid>()),
Times.Once);

this.loggingBrokerMock.Verify(broker =>
broker.LogErrorAsync(It.Is(SameExceptionAs(
expectedContributorServiceException))),
Times.Once);

this.dateTimeBrokerMock.Verify(broker =>
broker.GetCurrentDateTimeOffsetAsync(),
Times.Never);

this.storageBrokerMock.VerifyNoOtherCalls();
this.loggingBrokerMock.VerifyNoOtherCalls();
this.dateTimeBrokerMock.VerifyNoOtherCalls();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// ----------------------------------------------------------------------------------
// Copyright (c) The Standard Organization: A coalition of the Good-Hearted Engineers
// ----------------------------------------------------------------------------------

using System.Threading.Tasks;
using FluentAssertions;
using Force.DeepCloner;
using GitFyle.Core.Api.Models.Foundations.Contributors;
using Moq;

namespace GitFyle.Core.Api.Tests.Unit.Services.Foundations.Contributors
{
public partial class ContributorServiceTests
{
[Fact]
public async Task ShouldRetrieveContributorByIdAsync()
{
// given
Contributor randomContributor = CreateRandomContributor();
Contributor storageContributor = randomContributor;
Contributor expectedContributor = storageContributor.DeepClone();

this.storageBrokerMock.Setup(broker =>
broker.SelectContributorByIdAsync(randomContributor.Id))
.ReturnsAsync(storageContributor);

// when
Contributor actualContributor =
await this.contributorService.RetrieveContributorByIdAsync(
randomContributor.Id);

// then
actualContributor.Should().BeEquivalentTo(expectedContributor);

this.storageBrokerMock.Verify(broker =>
broker.SelectContributorByIdAsync(randomContributor.Id),
Times.Once);

this.storageBrokerMock.VerifyNoOtherCalls();
this.loggingBrokerMock.VerifyNoOtherCalls();
this.dateTimeBrokerMock.VerifyNoOtherCalls();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// ----------------------------------------------------------------------------------
// Copyright (c) The Standard Organization: A coalition of the Good-Hearted Engineers
// ----------------------------------------------------------------------------------

using System;
using System.Threading.Tasks;
using FluentAssertions;
using GitFyle.Core.Api.Models.Foundations.Contributors;
using GitFyle.Core.Api.Models.Foundations.Contributors.Exceptions;
using Moq;

namespace GitFyle.Core.Api.Tests.Unit.Services.Foundations.Contributors
{
public partial class ContributorServiceTests
{
[Fact]
public async Task ShouldThrowValidationExceptionOnRetrieveByIdWhenContributorIdIsInvalidAndLogItAsync()
{
// given
var invalidContributorId = Guid.Empty;

var invalidContributorException =
new InvalidContributorException(
message: "Contributor is invalid, fix the errors and try again.");

invalidContributorException.AddData(
key: nameof(Contributor.Id),
values: "Id is invalid");

var expectedContributorValidationException =
new ContributorValidationException(
message: "Contributor validation error occurred, fix errors and try again.",
innerException: invalidContributorException);

// when
ValueTask<Contributor> retrieveContributorByIdTask =
this.contributorService.RetrieveContributorByIdAsync(invalidContributorId);

ContributorValidationException actualContributorValidationException =
await Assert.ThrowsAsync<ContributorValidationException>(
testCode: retrieveContributorByIdTask.AsTask);

// then
actualContributorValidationException.Should().BeEquivalentTo(
expectedContributorValidationException);

this.loggingBrokerMock.Verify(broker =>
broker.LogErrorAsync(It.Is(SameExceptionAs(
expectedContributorValidationException))),
Times.Once);

this.storageBrokerMock.Verify(broker =>
broker.SelectContributorByIdAsync(It.IsAny<Guid>()),
Times.Never);

this.dateTimeBrokerMock.Verify(broker =>
broker.GetCurrentDateTimeOffsetAsync(),
Times.Never);

this.loggingBrokerMock.VerifyNoOtherCalls();
this.storageBrokerMock.VerifyNoOtherCalls();
this.dateTimeBrokerMock.VerifyNoOtherCalls();
}

[Fact]
public async Task ShouldThrowValidationExceptionOnRetrieveByIdIfContributorIdNotFoundAndLogitAsync()
{
//given
var someContributorId = Guid.NewGuid();
Contributor nullContributor = null;
var innerException = new Exception();

var notFoundContributorException =
new NotFoundContributorException(
message: $"Contributor not found with id: {someContributorId}");

var expectedContributorValidationException =
new ContributorValidationException(
message: "Contributor validation error occurred, fix errors and try again.",
innerException: notFoundContributorException);

this.storageBrokerMock.Setup(broker =>
broker.SelectContributorByIdAsync(someContributorId))
.ReturnsAsync(nullContributor);

// when
ValueTask<Contributor> retrieveContributorByIdTask =
this.contributorService.RetrieveContributorByIdAsync(someContributorId);

ContributorValidationException actualContributorValidationException =
await Assert.ThrowsAsync<ContributorValidationException>(
testCode: retrieveContributorByIdTask.AsTask);

// then
actualContributorValidationException.Should().BeEquivalentTo(
expectedContributorValidationException);

this.storageBrokerMock.Verify(broker =>
broker.SelectContributorByIdAsync(someContributorId),
Times.Once);

this.loggingBrokerMock.Verify(broker =>
broker.LogErrorAsync(It.Is(SameExceptionAs(
expectedContributorValidationException))),
Times.Once);

this.storageBrokerMock.VerifyNoOtherCalls();
this.loggingBrokerMock.VerifyNoOtherCalls();
this.dateTimeBrokerMock.VerifyNoOtherCalls();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ private async ValueTask<Contributor> TryCatch(ReturningContributorFunction retur
{
throw await CreateAndLogValidationExceptionAsync(invalidContributorException);
}
catch (NotFoundContributorException notFoundContributorException)
{
throw await CreateAndLogValidationExceptionAsync(notFoundContributorException);
}
catch (SqlException sqlException)
{
var failedStorageContributorException = new FailedStorageContributorException(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,18 @@ private static void ValidateContributorIsNotNull(Contributor contributor)
}
}

private static void ValidateContributorIdAsync(Guid contributionTypeId) =>
Validate((Rule: IsInvalid(contributionTypeId), Parameter: nameof(Contributor.Id)));

private static void ValidateStorageContributorAsync(Contributor maybeContributor, Guid id)
{
if (maybeContributor is null)
{
throw new NotFoundContributorException(
message: $"Contributor not found with id: {id}");
}
}

private static void Validate(params (dynamic Rule, string Parameter)[] validations)
{
var invalidContributorException =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Copyright (c) The Standard Organization: A coalition of the Good-Hearted Engineers
// ----------------------------------------------------------------------------------

using System;
using System.Linq;
using System.Threading.Tasks;
using GitFyle.Core.Api.Brokers.DateTimes;
Expand Down Expand Up @@ -37,5 +38,18 @@ public ValueTask<Contributor> AddContributorAsync(Contributor contributor) =>

public ValueTask<IQueryable<Contributor>> RetrieveAllContributorsAsync() =>
TryCatch(async () => await this.storageBroker.SelectAllContributorsAsync());

public ValueTask<Contributor> RetrieveContributorByIdAsync(Guid contributorId) =>
TryCatch(async () =>
{
ValidateContributorIdAsync(contributorId);
Contributor maybeContributor =
await this.storageBroker.SelectContributorByIdAsync(contributorId);
ValidateStorageContributorAsync(maybeContributor, contributorId);
return maybeContributor;
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Copyright (c) The Standard Organization: A coalition of the Good-Hearted Engineers
// ----------------------------------------------------------------------------------

using System;
using System.Linq;
using System.Threading.Tasks;
using GitFyle.Core.Api.Models.Foundations.Contributors;
Expand All @@ -12,5 +13,6 @@ public interface IContributorService
{
ValueTask<Contributor> AddContributorAsync(Contributor contributor);
ValueTask<IQueryable<Contributor>> RetrieveAllContributorsAsync();
ValueTask<Contributor> RetrieveContributorByIdAsync(Guid contributorId);
}
}

0 comments on commit e97c8d2

Please sign in to comment.