Skip to content

Commit

Permalink
Merge pull request #203 from The-Standard-Organization/users/glhays/f…
Browse files Browse the repository at this point in the history
…oundations-repository-retrievebyid

FOUNDATIONS: Repository - `RetrieveById`
  • Loading branch information
cjdutoit authored Oct 5, 2024
2 parents 3ac26e2 + 4ee7ed6 commit 53ad531
Show file tree
Hide file tree
Showing 9 changed files with 327 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ public async Task ShouldThrowServiceExceptionOnAddIfServiceErrorOccurredAndLogIt

var failedServiceRepositoryException =
new FailedServiceRepositoryException(
message: "Failed service Repository error occurred, contact support.",
message: "Failed service repository error occurred, contact support.",
innerException: serviceException);

var expectedRepositoryServiceException =
Expand Down
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.Repositories;
using GitFyle.Core.Api.Models.Foundations.Repositories.Exceptions;
using Moq;

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

var failedStorageRepositoryException =
new FailedStorageRepositoryException(
message: "Failed storage repository error occurred, contact support.",
innerException: sqlException);

var expectedRepositoryDependencyException =
new RepositoryDependencyException(
message: "Repository dependency error occurred, contact support.",
innerException: failedStorageRepositoryException);

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

// when
ValueTask<Repository> retrieveRepositoryByIdTask =
this.repositoryService.RetrieveRepositoryByIdAsync(someGuid);

// then
await Assert.ThrowsAsync<RepositoryDependencyException>(
retrieveRepositoryByIdTask.AsTask);

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

this.loggingBrokerMock.Verify(broker =>
broker.LogCriticalAsync(It.Is(SameExceptionAs(
expectedRepositoryDependencyException))),
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 someRepositoryId = Guid.NewGuid();
var serviceException = new Exception();

var failedServiceRepositoryException =
new FailedServiceRepositoryException(
message: "Failed service repository error occurred, contact support.",
innerException: serviceException);

var expectedRepositoryServiceException =
new RepositoryServiceException(
message: "Service error occurred, contact support.",
innerException: failedServiceRepositoryException);

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

//when
ValueTask<Repository> retrieveRepositoryByIdTask =
this.repositoryService.RetrieveRepositoryByIdAsync(someRepositoryId);

RepositoryServiceException actualRepositoryServiceException =
await Assert.ThrowsAsync<RepositoryServiceException>(
retrieveRepositoryByIdTask.AsTask);

//then
actualRepositoryServiceException.Should().BeEquivalentTo(
expectedRepositoryServiceException);

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

this.loggingBrokerMock.Verify(broker =>
broker.LogErrorAsync(It.Is(SameExceptionAs(
expectedRepositoryServiceException))),
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.Repositories;
using Moq;

namespace GitFyle.Core.Api.Tests.Unit.Services.Foundations.Repositories
{
public partial class RepositoryServiceTests
{
[Fact]
public async Task ShouldRetrieveRepositoryByIdAsync()
{
// given
Repository randomRepository = CreateRandomRepository();
Repository storageRepository = randomRepository;
Repository expectedRepository = storageRepository.DeepClone();

this.storageBrokerMock.Setup(broker =>
broker.SelectRepositoryByIdAsync(randomRepository.Id))
.ReturnsAsync(storageRepository);

// when
Repository actualRepository =
await this.repositoryService.RetrieveRepositoryByIdAsync(
randomRepository.Id);

// then
actualRepository.Should().BeEquivalentTo(expectedRepository);

this.storageBrokerMock.Verify(broker =>
broker.SelectRepositoryByIdAsync(randomRepository.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.Repositories;
using GitFyle.Core.Api.Models.Foundations.Repositories.Exceptions;
using Moq;

namespace GitFyle.Core.Api.Tests.Unit.Services.Foundations.Repositories
{
public partial class RepositoryServiceTests
{
[Fact]
public async Task ShouldThrowValidationExceptionOnRetrieveByIdWhenRepositoryIdIsInvalidAndLogItAsync()
{
// given
var invalidRepositoryId = Guid.Empty;

var invalidRepositoryException =
new InvalidRepositoryException(
message: "Repository is invalid, fix the errors and try again.");

invalidRepositoryException.AddData(
key: nameof(Repository.Id),
values: "Id is invalid");

var expectedRepositoryValidationException =
new RepositoryValidationException(
message: "Repository validation error occurred, fix errors and try again.",
innerException: invalidRepositoryException);

// when
ValueTask<Repository> retrieveRepositoryByIdTask =
this.repositoryService.RetrieveRepositoryByIdAsync(invalidRepositoryId);

RepositoryValidationException actualRepositoryValidationException =
await Assert.ThrowsAsync<RepositoryValidationException>(
retrieveRepositoryByIdTask.AsTask);

// then
actualRepositoryValidationException.Should().BeEquivalentTo(
expectedRepositoryValidationException);

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

this.storageBrokerMock.Verify(broker =>
broker.SelectRepositoryByIdAsync(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 ShouldThrowValidationExceptionOnRetrieveByIdIfRepositoryIdNotFoundAndLogitAsync()
{
//given
var someRepositoryId = Guid.NewGuid();
Repository nullRepository = null;
var innerException = new Exception();

var notFoundRepositoryException =
new NotFoundRepositoryException(
message: $"Repository not found with id: {someRepositoryId}");

var expectedRepositoryValidationException =
new RepositoryValidationException(
message: "Repository validation error occurred, fix errors and try again.",
innerException: notFoundRepositoryException);

this.storageBrokerMock.Setup(broker =>
broker.SelectRepositoryByIdAsync(someRepositoryId))
.ReturnsAsync(nullRepository);

// when
ValueTask<Repository> retrieveRepositoryByIdTask =
this.repositoryService.RetrieveRepositoryByIdAsync(someRepositoryId);

RepositoryValidationException actualRepositoryValidationException =
await Assert.ThrowsAsync<RepositoryValidationException>(
retrieveRepositoryByIdTask.AsTask);

// then
actualRepositoryValidationException.Should().BeEquivalentTo(
expectedRepositoryValidationException);

this.storageBrokerMock.Verify(broker =>
broker.SelectRepositoryByIdAsync(someRepositoryId),
Times.Once);

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

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

using Xeptions;

namespace GitFyle.Core.Api.Models.Foundations.Repositories.Exceptions
{
public class NotFoundRepositoryException : Xeption
{
public NotFoundRepositoryException(string message)
: base(message)
{ }
}
}
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.Repositories;
Expand All @@ -13,5 +14,6 @@ public interface IRepositoryService
{
ValueTask<Repository> AddRepositoryAsync(Repository repository);
ValueTask<IQueryable<Repository>> RetrieveAllRepositoriesAsync();
ValueTask<Repository> RetrieveRepositoryByIdAsync(Guid repositoryId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,15 @@ private async ValueTask<Repository> TryCatch(ReturningRepositoryFunction returni
}
catch (NullRepositoryException nullRepositoryException)
{
throw await CreateAndLogValidationException(nullRepositoryException);
throw await CreateAndLogValidationExceptionAsync(nullRepositoryException);
}
catch (InvalidRepositoryException invalidRepositoryException)
{
throw await CreateAndLogValidationException(invalidRepositoryException);
throw await CreateAndLogValidationExceptionAsync(invalidRepositoryException);
}
catch (NotFoundRepositoryException notFoundRepositoryException)
{
throw await CreateAndLogValidationExceptionAsync(notFoundRepositoryException);
}
catch (SqlException sqlException)
{
Expand Down Expand Up @@ -65,19 +69,19 @@ private async ValueTask<Repository> TryCatch(ReturningRepositoryFunction returni
{
var failedServiceRepositoryException =
new FailedServiceRepositoryException(
message: "Failed service Repository error occurred, contact support.",
message: "Failed service repository error occurred, contact support.",
innerException: exception);

throw await CreateAndLogServiceExceptionAsync(failedServiceRepositoryException);
}
}

private async ValueTask<IQueryable<Repository>> TryCatch(
ReturningRepositoriesFunction returningRepositoriesunction)
ReturningRepositoriesFunction returningRepositoriesFunction)
{
try
{
return await returningRepositoriesunction();
return await returningRepositoriesFunction();
}
catch (SqlException sqlException)
{
Expand All @@ -97,8 +101,8 @@ private async ValueTask<IQueryable<Repository>> TryCatch(
throw await CreateAndLogServiceExceptionAsync(failedServiceRepositoryException);
}
}

private async ValueTask<RepositoryValidationException> CreateAndLogValidationException(
private async ValueTask<RepositoryValidationException> CreateAndLogValidationExceptionAsync(
Xeption exception)
{
var RepositoryValidationException = new RepositoryValidationException(
Expand All @@ -110,7 +114,8 @@ private async ValueTask<RepositoryValidationException> CreateAndLogValidationExc
return RepositoryValidationException;
}

private async Task<Exception> CreateAndLogCriticalDependencyExceptionAsync(Xeption exception)
private async Task<RepositoryDependencyException> CreateAndLogCriticalDependencyExceptionAsync(
Xeption exception)
{
var repositoryDependencyException = new RepositoryDependencyException(
message: "Repository dependency error occurred, contact support.",
Expand Down
Loading

0 comments on commit 53ad531

Please sign in to comment.