Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FOUNDATIONS: Contributor RetrieveByIdAsync #249

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);
}
}
Loading