Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,22 @@ public async Task FileRequestHandler_UploadFileRequest_NoFileProfiles_RequestIsH
result.Status.ShouldBe(ResultStatus.NotFound);
}

[Fact]
public async Task FileRequestHandler_UploadFileRequest_ArchivedProfileIsRejected()
{
this.FileImportLogAggregateRepository.GetLatestVersion(Arg<Guid>.Any(), Arg<CancellationToken>.Any())
.ReturnsAsync(Result.Success(TestData.GetEmptyFileImportLogAggregate()));
this.FileProcessorManager.GetFileProfile(Arg<Guid>.Any(), Arg<CancellationToken>.Any())
.ReturnsAsync(Result.NotFound($"No file profile found for File Profile Id {TestData.FileProfileId}"));

Result<Guid> result = await this.FileProcessorDomainService.UploadFile(TestData.UploadFileCommand, CancellationToken.None);

result.IsFailed.ShouldBeTrue();
result.Status.ShouldBe(ResultStatus.NotFound);
this.FileImportLogAggregateRepository.SaveChanges(Arg<FileImportLogAggregate>.Any(), Arg<CancellationToken>.Any())
.Called(Count.Never());
}

[Fact]
public async Task FileRequestHandler_UploadFileRequest_FileNotFound_RequestIsHandled()
{
Expand Down Expand Up @@ -713,6 +729,43 @@ public async Task ProcessTransactionForFileLine_UsesRecordedProfileVersionAfterA
result.IsSuccess.ShouldBeTrue();
}

[Fact]
public async Task ProcessTransactionForFileLine_UsesRecordedVersionWhenParentProfileIsArchived()
{
this.FileProcessorManager.GetFileProfile(Arg<Guid>.Any(), Arg<CancellationToken>.Any())
.ReturnsAsync(Result.NotFound());
this.FileProcessorManager.GetFileProfileVersion(Arg<Guid>.Any(),
TestData.FileProfileVersionId,
Arg<CancellationToken>.Any())
.ReturnsAsync(TestData.FileProfileSafaricom with
{
FileProfileId = TestData.FileProfileId,
FileProfileVersionId = TestData.FileProfileVersionId
});
this.FileAggregateRepository.GetLatestVersion(Arg<Guid>.Any(), Arg<CancellationToken>.Any())
.ReturnsAsync(Result.Success(TestData.GetFileAggregateWithLines()));
this.FileAggregateRepository.SaveChanges(Arg<FileAggregate>.Any(), Arg<CancellationToken>.Any())
.ReturnsAsync(Result.Success());
this.TransactionProcessorClient.PerformTransaction(Arg<String>.Any(), Arg<SaleTransactionRequest>.Any(), Arg<CancellationToken>.Any())
.ReturnsAsync(TestData.ClientSaleTransactionResponse);
this.TransactionProcessorClient.GetMerchant(Arg<String>.Any(), Arg<Guid>.Any(), Arg<Guid>.Any(), Arg<CancellationToken>.Any())
.ReturnsAsync(TestData.GetMerchantResponseWithOperator);
this.TransactionProcessorClient.GetMerchantContracts(Arg<String>.Any(), Arg<Guid>.Any(), Arg<Guid>.Any(), Arg<CancellationToken>.Any())
.ReturnsAsync(Result.Success(TestData.GetMerchantContractsResponse()
.Where(contract => contract.OperatorName == TestData.SafaricomOperatorIdentifier)
.ToList()));
this.SecurityServiceClient.GetToken(Arg<String>.Any(), Arg<String>.Any(), Arg<CancellationToken>.Any())
.ReturnsAsync(Result.Success(TestData.TokenResponse()));
this.FileFormatHandler.FileLineCanBeIgnored(Arg<String>.Any()).Returns(false);
this.FileFormatHandler.ParseFileLine(Arg<String>.Any()).Returns(TestData.TransactionMetadata);

Result result = await this.FileProcessorDomainService.ProcessTransactionForFileLine(
TestData.ProcessTransactionForFileLineCommand,
CancellationToken.None);

result.IsSuccess.ShouldBeTrue();
}

[Theory]
[InlineData("Safaricom")]
[InlineData("Voucher")]
Expand Down
79 changes: 79 additions & 0 deletions FileProcessor.BusinessLogic.Tests/FileProfileManagerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using FileProcessor.BusinessLogic.Managers;
using FileProcessor.DataTransferObjects.Requests;
using FileProcessor.FileProfileAggregate;
using FileProcessor.Testing;
using Imposter.Abstractions;
using Shared.DomainDrivenDesign.EventSourcing;
using Shared.EventStore.Aggregate;
using Shouldly;
using SimpleResults;
using Xunit;
using FileProfileAggregateRoot = FileProcessor.FileProfileAggregate.FileProfileAggregate;
using FileProfileModel = FileProcessor.Models.FileProfile;

namespace FileProcessor.BusinessLogic.Tests;

public class FileProfileManagerTests
{
[Fact]
public async Task GetFileProfileVersions_WhenProfileIsArchived_ReturnsHistoricalVersions()
{
FileProfileAggregateRoot aggregate = this.CreateArchivedAggregate();
IAggregateRepositoryImposter<FileProfileAggregateRoot, DomainEvent> repository = new();
repository.GetLatestVersion(Arg<Guid>.Any(), Arg<CancellationToken>.Any())
.ReturnsAsync(Result.Success(aggregate));
FileProfileManager manager = new(repository.Instance());

Result<List<FileProfileModel>> result = await manager.GetFileProfileVersions(TestData.FileProfileId, CancellationToken.None);

result.IsSuccess.ShouldBeTrue();
result.Data.Count.ShouldBe(2);
result.Data[0].FileProfileVersion.ShouldBe(1);
result.Data[1].FileProfileVersion.ShouldBe(2);
}

[Fact]
public async Task GetFileProfileVersion_WhenVersionDoesNotExist_ReturnsActionableNotFound()
{
FileProfileAggregateRoot aggregate = this.CreateArchivedAggregate();
IAggregateRepositoryImposter<FileProfileAggregateRoot, DomainEvent> repository = new();
repository.GetLatestVersion(Arg<Guid>.Any(), Arg<CancellationToken>.Any())
.ReturnsAsync(Result.Success(aggregate));
FileProfileManager manager = new(repository.Instance());
Guid missingVersionId = Guid.NewGuid();

Result<FileProfileModel> result = await manager.GetFileProfileVersion(TestData.FileProfileId,
missingVersionId,
CancellationToken.None);

result.IsFailed.ShouldBeTrue();
result.Status.ShouldBe(ResultStatus.NotFound);
result.Message.ShouldContain(TestData.FileProfileId.ToString());
result.Message.ShouldContain(missingVersionId.ToString());
}

private FileProfileAggregateRoot CreateArchivedAggregate()
{
FileProfileAggregateRoot aggregate = FileProfileAggregateRoot.Create();
aggregate.CreateProfile(new CreateFileProfileRequest
{
FileProfileId = TestData.FileProfileId,
Name = TestData.SafaricomProfileName,
ListeningDirectory = TestData.SafaricomListeningDirectory,
RequestType = TestData.SafaricomRequestType,
OperatorName = TestData.SafaricomOperatorIdentifier,
LineTerminator = LineTerminatorType.LineFeed,
FileFormatHandler = TestData.SafaricomFileFormatHandler
});
aggregate.UpdateProfile(TestData.FileProfileId, new UpdateFileProfileRequest
{
FileFormatHandler = "UpdatedHandler"
});
aggregate.ArchiveProfile(TestData.FileProfileId);
return aggregate;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using FileProcessor.BusinessLogic.Managers;
using FileProcessor.BusinessLogic.RequestHandlers;
using FileProcessor.BusinessLogic.Requests;
using FileProcessor.Models;
using Imposter.Abstractions;
using Shouldly;
using SimpleResults;
using Xunit;
using FileProfileModel = FileProcessor.Models.FileProfile;

namespace FileProcessor.BusinessLogic.Tests;

public class FileProfileRequestHandlerTests
{
[Fact]
public async Task GetFileProfileVersionsQuery_ForwardsToManager()
{
IFileProfileManagerImposter manager = new();
List<FileProfileModel> expected = new();
manager.GetFileProfileVersions(Arg<Guid>.Any(), Arg<CancellationToken>.Any())
.ReturnsAsync(Result.Success(expected));
FileProfileRequestHandler handler = new(manager.Instance());
FileProfileQueries.GetFileProfileVersionsQuery query = new(Guid.NewGuid());

Result<List<FileProfileModel>> result = await handler.Handle(query, CancellationToken.None);

result.Data.ShouldBeSameAs(expected);
manager.GetFileProfileVersions(query.FileProfileId, CancellationToken.None).Called(Count.Once());
}

[Fact]
public async Task GetFileProfileVersionQuery_ForwardsToManager()
{
IFileProfileManagerImposter manager = new();
FileProfileModel expected = new(Guid.NewGuid(), "Profile", "/tmp/profile", "Request", "Operator", "\n", "Handler");
manager.GetFileProfileVersion(Arg<Guid>.Any(), Arg<Guid>.Any(), Arg<CancellationToken>.Any())
.ReturnsAsync(Result.Success(expected));
FileProfileRequestHandler handler = new(manager.Instance());
FileProfileQueries.GetFileProfileVersionQuery query = new(Guid.NewGuid(), Guid.NewGuid());

Result<FileProfileModel> result = await handler.Handle(query, CancellationToken.None);

result.Data.ShouldBeSameAs(expected);
manager.GetFileProfileVersion(query.FileProfileId,
query.FileProfileVersionId,
CancellationToken.None).Called(Count.Once());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ public class FileProfileRequestHandler : IRequestHandler<FileProfileCommands.Cre
IRequestHandler<FileProfileCommands.UpdateFileProfileCommand, Result<FileProfileModel>>,
IRequestHandler<FileProfileCommands.ArchiveFileProfileCommand, Result>,
IRequestHandler<FileProfileQueries.GetFileProfilesQuery, Result<List<FileProfileModel>>>,
IRequestHandler<FileProfileQueries.GetFileProfileQuery, Result<FileProfileModel>>
IRequestHandler<FileProfileQueries.GetFileProfileQuery, Result<FileProfileModel>>,
IRequestHandler<FileProfileQueries.GetFileProfileVersionsQuery, Result<List<FileProfileModel>>>,
IRequestHandler<FileProfileQueries.GetFileProfileVersionQuery, Result<FileProfileModel>>
{
private readonly IFileProfileManager FileProfileManager;

Expand Down Expand Up @@ -47,4 +49,18 @@ public Task<Result<FileProfileModel>> Handle(FileProfileQueries.GetFileProfileQu
{
return this.FileProfileManager.GetFileProfile(request.FileProfileId, cancellationToken);
}

public Task<Result<List<FileProfileModel>>> Handle(FileProfileQueries.GetFileProfileVersionsQuery request,
CancellationToken cancellationToken)
{
return this.FileProfileManager.GetFileProfileVersions(request.FileProfileId, cancellationToken);
}

public Task<Result<FileProfileModel>> Handle(FileProfileQueries.GetFileProfileVersionQuery request,
CancellationToken cancellationToken)
{
return this.FileProfileManager.GetFileProfileVersion(request.FileProfileId,
request.FileProfileVersionId,
cancellationToken);
}
}
5 changes: 5 additions & 0 deletions FileProcessor.BusinessLogic/Requests/FileProfileQueries.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,9 @@ public record FileProfileQueries
public record GetFileProfilesQuery : IRequest<Result<List<FileProfileModel>>>;

public record GetFileProfileQuery(Guid FileProfileId) : IRequest<Result<FileProfileModel>>;

public record GetFileProfileVersionsQuery(Guid FileProfileId) : IRequest<Result<List<FileProfileModel>>>;

public record GetFileProfileVersionQuery(Guid FileProfileId,
Guid FileProfileVersionId) : IRequest<Result<FileProfileModel>>;
}
21 changes: 20 additions & 1 deletion FileProcessor.Client/FileProcessorClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,23 @@ public async Task<Result<FileProfile>> GetFileProfile(String accessToken,
return await this.SendRequest<FileProfile>(HttpMethod.Get, requestUri, accessToken, null, cancellationToken);
}

public async Task<Result<List<FileProfile>>> GetFileProfileVersions(String accessToken,
Guid fileProfileId,
CancellationToken cancellationToken)
{
String requestUri = this.BuildRequestUrl($"/api/file-profiles/{fileProfileId}/versions");
return await this.SendRequest<List<FileProfile>>(HttpMethod.Get, requestUri, accessToken, null, cancellationToken);
}

public async Task<Result<FileProfile>> GetFileProfileVersion(String accessToken,
Guid fileProfileId,
Guid fileProfileVersionId,
CancellationToken cancellationToken)
{
String requestUri = this.BuildRequestUrl($"/api/file-profiles/{fileProfileId}/versions/{fileProfileVersionId}");
return await this.SendRequest<FileProfile>(HttpMethod.Get, requestUri, accessToken, null, cancellationToken);
}

public async Task<Result<FileProfile>> CreateFileProfile(String accessToken,
CreateFileProfileRequest request,
CancellationToken cancellationToken)
Expand Down Expand Up @@ -296,7 +313,9 @@ private async Task<Result<T>> SendRequest<T>(HttpMethod method,
? $"Request failed with status code {(Int32)response.StatusCode}"
: responseContent;

return Result.Failure(message);
return response.StatusCode == System.Net.HttpStatusCode.NotFound
? Result.NotFound(message)
: Result.Failure(message);
}

if (String.IsNullOrWhiteSpace(responseContent))
Expand Down
9 changes: 9 additions & 0 deletions FileProcessor.Client/IFileProcessorClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ Task<Result<FileProfile>> GetFileProfile(String accessToken,
Guid fileProfileId,
CancellationToken cancellationToken);

Task<Result<List<FileProfile>>> GetFileProfileVersions(String accessToken,
Guid fileProfileId,
CancellationToken cancellationToken);

Task<Result<FileProfile>> GetFileProfileVersion(String accessToken,
Guid fileProfileId,
Guid fileProfileVersionId,
CancellationToken cancellationToken);

Task<Result<FileProfile>> CreateFileProfile(String accessToken,
DataTransferObjects.Requests.CreateFileProfileRequest request,
CancellationToken cancellationToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,59 @@ public void FileProfileAggregate_Update_WithNoEffectiveChanges_DoesNotChangeAppl
updateResult.IsSuccess.ShouldBeTrue();
}

[Fact]
public void FileProfileAggregate_Archive_RetainsHistoricalVersionsButHidesActiveProfile()
{
FileProfileAggregateRoot aggregate = FileProfileAggregateRoot.Create();
aggregate.CreateProfile(this.CreateProfile(
TestData.FileProfileId,
TestData.SafaricomProfileName,
TestData.SafaricomListeningDirectory,
TestData.SafaricomRequestType,
TestData.SafaricomOperatorIdentifier,
LineTerminatorType.LineFeed,
TestData.SafaricomFileFormatHandler));

FileProcessor.Models.FileProfile originalVersion = aggregate.GetProfile(TestData.FileProfileId);
aggregate.UpdateProfile(TestData.FileProfileId, new UpdateFileProfileRequest
{
FileFormatHandler = "UpdatedHandler"
});

Result archiveResult = aggregate.ArchiveProfile(TestData.FileProfileId);

archiveResult.IsSuccess.ShouldBeTrue();
aggregate.GetProfile(TestData.FileProfileId).ShouldBeNull();
List<FileProcessor.Models.FileProfile> versions = aggregate.GetProfileVersions(TestData.FileProfileId);
versions.Count.ShouldBe(2);
versions[0].FileProfileVersion.ShouldBe(1);
versions[1].FileProfileVersion.ShouldBe(2);
aggregate.GetProfileVersion(TestData.FileProfileId, originalVersion.FileProfileVersionId)
.FileFormatHandler.ShouldBe(TestData.SafaricomFileFormatHandler);
}

[Fact]
public void FileProfileAggregate_Archive_WhenAlreadyArchived_IsIdempotent()
{
FileProfileAggregateRoot aggregate = FileProfileAggregateRoot.Create();
aggregate.CreateProfile(this.CreateProfile(
TestData.FileProfileId,
TestData.SafaricomProfileName,
TestData.SafaricomListeningDirectory,
TestData.SafaricomRequestType,
TestData.SafaricomOperatorIdentifier,
LineTerminatorType.LineFeed,
TestData.SafaricomFileFormatHandler));

Result firstArchive = aggregate.ArchiveProfile(TestData.FileProfileId);
Result secondArchive = aggregate.ArchiveProfile(TestData.FileProfileId);

firstArchive.IsSuccess.ShouldBeTrue();
secondArchive.IsSuccess.ShouldBeTrue();
aggregate.ActiveProfileCount.ShouldBe(0);
aggregate.GetProfileVersions(TestData.FileProfileId).Count.ShouldBe(1);
}

[Fact]
public void FileProfileAggregate_Update_ListeningDirectoryUpdatesDerivedDirectories()
{
Expand Down
Loading
Loading