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
10 changes: 0 additions & 10 deletions FIleProcessor.Models/FileDetails.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,5 @@ public class FileDetails
/// The processing summary.
/// </value>
public ProcessingSummary ProcessingSummary { get; set; }
}

public class ProcessingSummary
{
public Int32 TotalLines { get; set; }
public Int32 SuccessfullyProcessedLines { get; set; }
public Int32 FailedLines { get; set; }
public Int32 IgnoredLines { get; set; }
public Int32 NotProcessedLines { get; set; }

}
}
1 change: 1 addition & 0 deletions FIleProcessor.Models/FileLine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public class FileLine
/// </summary>
/// <value>
/// The transaction identifier.
/// 1011934
/// </value>
public Guid TransactionId { get; set; }

Expand Down
54 changes: 54 additions & 0 deletions FIleProcessor.Models/ProcessingSummary.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
namespace FIleProcessor.Models
{
using System;

/// <summary>
///
/// </summary>
public class ProcessingSummary
{
#region Properties

/// <summary>
/// Gets or sets the failed lines.
/// </summary>
/// <value>
/// The failed lines.
/// </value>
public Int32 FailedLines { get; set; }

/// <summary>
/// Gets or sets the ignored lines.
/// </summary>
/// <value>
/// The ignored lines.
/// </value>
public Int32 IgnoredLines { get; set; }

/// <summary>
/// Gets or sets the not processed lines.
/// </summary>
/// <value>
/// The not processed lines.
/// </value>
public Int32 NotProcessedLines { get; set; }

/// <summary>
/// Gets or sets the successfully processed lines.
/// </summary>
/// <value>
/// The successfully processed lines.
/// </value>
public Int32 SuccessfullyProcessedLines { get; set; }

/// <summary>
/// Gets or sets the total lines.
/// </summary>
/// <value>
/// The total lines.
/// </value>
public Int32 TotalLines { get; set; }

#endregion
}
}
99 changes: 93 additions & 6 deletions FileProcessor.BusinessLogic.Tests/FileProcessingManagerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,21 @@ namespace FileProcessor.BusinessLogic.Tests
using Common;
using EstateReporting.Database;
using EstateReporting.Database.Entities;
using FileAggregate;
using FIleProcessor.Models;
using Managers;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Moq;
using Shared.DomainDrivenDesign.EventSourcing;
using Shared.EntityFramework;
using Shared.EventStore.Aggregate;
using Shared.Exceptions;
using Shouldly;
using Testing;
using Xunit;
using FileImportLog = EstateReporting.Database.Entities.FileImportLog;
using FileLine = FIleProcessor.Models.FileLine;

public class FileProcessingManagerTests
{
Expand All @@ -29,7 +34,9 @@ public async Task FileProcessingManager_GetAllFileProfiles_AllFileProfilesReturn
var fileProfiles = TestData.FileProfiles;
var contextFactory = this.CreateMockContextFactory();
Mock<IModelFactory> modelFactory = new Mock<IModelFactory>();
FileProcessorManager manager = new FileProcessorManager(fileProfiles, contextFactory.Object,modelFactory.Object);
Mock<IAggregateRepository<FileAggregate, DomainEventRecord.DomainEvent>> fileAggregateRepository =
new Mock<IAggregateRepository<FileAggregate, DomainEventRecord.DomainEvent>>();
FileProcessorManager manager = new FileProcessorManager(fileProfiles, contextFactory.Object,modelFactory.Object, fileAggregateRepository.Object);

var allFileProfiles = await manager.GetAllFileProfiles(CancellationToken.None);
allFileProfiles.ShouldNotBeNull();
Expand All @@ -42,7 +49,9 @@ public async Task FileProcessingManager_GetFileProfile_FIleProfileReturned()
var fileProfiles = TestData.FileProfiles;
var contextFactory = this.CreateMockContextFactory();
Mock<IModelFactory> modelFactory = new Mock<IModelFactory>();
FileProcessorManager manager = new FileProcessorManager(fileProfiles, contextFactory.Object, modelFactory.Object);
Mock<IAggregateRepository<FileAggregate, DomainEventRecord.DomainEvent>> fileAggregateRepository =
new Mock<IAggregateRepository<FileAggregate, DomainEventRecord.DomainEvent>>();
FileProcessorManager manager = new FileProcessorManager(fileProfiles, contextFactory.Object, modelFactory.Object, fileAggregateRepository.Object);

var fileProfile = await manager.GetFileProfile(TestData.SafaricomFileProfileId, CancellationToken.None);
fileProfile.ShouldNotBeNull();
Expand All @@ -63,7 +72,9 @@ public async Task FileProcessingManager_GetFileImportLogs_NoMerchantId_ImportLog
context.FileImportLogFiles.AddRange(TestData.FileImportLog2Files);
context.SaveChanges();

FileProcessorManager manager = new FileProcessorManager(fileProfiles, contextFactory.Object, modelFactory);
Mock<IAggregateRepository<FileAggregate, DomainEventRecord.DomainEvent>> fileAggregateRepository =
new Mock<IAggregateRepository<FileAggregate, DomainEventRecord.DomainEvent>>();
FileProcessorManager manager = new FileProcessorManager(fileProfiles, contextFactory.Object, modelFactory, fileAggregateRepository.Object);

var importLogs = await manager.GetFileImportLogs(TestData.EstateId, TestData.ImportLogStartDate, TestData.ImportLogEndDate, null, CancellationToken.None);

Expand All @@ -84,7 +95,9 @@ public async Task FileProcessingManager_GetFileImportLogs_WithMerchantId_ImportL
context.FileImportLogFiles.AddRange(TestData.FileImportLog2Files);
context.SaveChanges();

FileProcessorManager manager = new FileProcessorManager(fileProfiles, contextFactory.Object, modelFactory);
Mock<IAggregateRepository<FileAggregate, DomainEventRecord.DomainEvent>> fileAggregateRepository =
new Mock<IAggregateRepository<FileAggregate, DomainEventRecord.DomainEvent>>();
FileProcessorManager manager = new FileProcessorManager(fileProfiles, contextFactory.Object, modelFactory, fileAggregateRepository.Object);

var importLogs = await manager.GetFileImportLogs(TestData.EstateId, TestData.ImportLogStartDate, TestData.ImportLogEndDate, TestData.MerchantId, CancellationToken.None);

Expand All @@ -105,7 +118,9 @@ public async Task FileProcessingManager_GetFileImportLog_NoMerchantId_ImportLogR
context.FileImportLogFiles.AddRange(TestData.FileImportLog2Files);
context.SaveChanges();

FileProcessorManager manager = new FileProcessorManager(fileProfiles, contextFactory.Object, modelFactory);
Mock<IAggregateRepository<FileAggregate, DomainEventRecord.DomainEvent>> fileAggregateRepository =
new Mock<IAggregateRepository<FileAggregate, DomainEventRecord.DomainEvent>>();
FileProcessorManager manager = new FileProcessorManager(fileProfiles, contextFactory.Object, modelFactory, fileAggregateRepository.Object);

var importLog = await manager.GetFileImportLog(TestData.FileImportLogId1, TestData.EstateId, null, CancellationToken.None);

Expand All @@ -126,13 +141,85 @@ public async Task FileProcessingManager_GetFileImportLog_WithMerchantId_ImportLo
context.FileImportLogFiles.AddRange(TestData.FileImportLog2Files);
context.SaveChanges();

FileProcessorManager manager = new FileProcessorManager(fileProfiles, contextFactory.Object, modelFactory);
Mock<IAggregateRepository<FileAggregate, DomainEventRecord.DomainEvent>> fileAggregateRepository =
new Mock<IAggregateRepository<FileAggregate, DomainEventRecord.DomainEvent>>();
FileProcessorManager manager = new FileProcessorManager(fileProfiles, contextFactory.Object, modelFactory, fileAggregateRepository.Object);

var importLog = await manager.GetFileImportLog(TestData.FileImportLogId1, TestData.EstateId, TestData.MerchantId, CancellationToken.None);

this.VerifyImportLog(TestData.FileImportLogs.First(),importLog, TestData.MerchantId);
}

[Fact]
public async Task FileProcessingManager_GetFile_FileReturned()
{
var fileProfiles = TestData.FileProfiles;
var context = await this.GetContext(Guid.NewGuid().ToString("N"));
var contextFactory = this.CreateMockContextFactory();
contextFactory.Setup(c => c.GetContext(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(context);
IModelFactory modelFactory = new ModelFactory();

Mock<IAggregateRepository<FileAggregate, DomainEventRecord.DomainEvent>> fileAggregateRepository =
new Mock<IAggregateRepository<FileAggregate, DomainEventRecord.DomainEvent>>();
fileAggregateRepository.Setup(f => f.GetLatestVersion(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(TestData.GetFileAggregateWithLines);
FileProcessorManager manager = new FileProcessorManager(fileProfiles, contextFactory.Object, modelFactory, fileAggregateRepository.Object);

var fileDetails = await manager.GetFile(TestData.FileId, TestData.EstateId, CancellationToken.None);

this.VerifyFile(TestData.GetFileAggregateWithLines(), fileDetails);
}

[Fact]
public async Task FileProcessingManager_GetFile_FileNotFound_ErrorThrown()
{
var fileProfiles = TestData.FileProfiles;
var context = await this.GetContext(Guid.NewGuid().ToString("N"));
var contextFactory = this.CreateMockContextFactory();
contextFactory.Setup(c => c.GetContext(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(context);
IModelFactory modelFactory = new ModelFactory();

Mock<IAggregateRepository<FileAggregate, DomainEventRecord.DomainEvent>> fileAggregateRepository =
new Mock<IAggregateRepository<FileAggregate, DomainEventRecord.DomainEvent>>();
fileAggregateRepository.Setup(f => f.GetLatestVersion(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(TestData.GetEmptyFileAggregate);
FileProcessorManager manager = new FileProcessorManager(fileProfiles, contextFactory.Object, modelFactory, fileAggregateRepository.Object);

Should.Throw<NotFoundException>(async () =>
{
await manager.GetFile(TestData.FileId, TestData.EstateId, CancellationToken.None);
});
}


private void VerifyFile(FileAggregate source, FileDetails fileDetails)
{
var fileModel = source.GetFile();

fileDetails.FileId.ShouldBe(fileModel.FileId);
fileDetails.FileImportLogId.ShouldBe(fileModel.FileImportLogId);
fileDetails.FileLocation.ShouldBe(fileModel.FileLocation);
fileDetails.FileProfileId.ShouldBe(fileModel.FileProfileId);
fileDetails.MerchantId.ShouldBe(fileModel.MerchantId);
fileDetails.ProcessingCompleted.ShouldBe(fileModel.ProcessingCompleted);
fileDetails.UserId.ShouldBe(fileModel.UserId);
fileDetails.EstateId.ShouldBe(fileModel.EstateId);

fileDetails.ProcessingSummary.ShouldNotBeNull();
fileDetails.ProcessingSummary.FailedLines.ShouldBe(fileModel.ProcessingSummary.FailedLines);
fileDetails.ProcessingSummary.IgnoredLines.ShouldBe(fileModel.ProcessingSummary.IgnoredLines);
fileDetails.ProcessingSummary.NotProcessedLines.ShouldBe(fileModel.ProcessingSummary.NotProcessedLines);
fileDetails.ProcessingSummary.SuccessfullyProcessedLines.ShouldBe(fileModel.ProcessingSummary.SuccessfullyProcessedLines);
fileDetails.ProcessingSummary.TotalLines.ShouldBe(fileModel.ProcessingSummary.TotalLines);

foreach (FileLine fileModelFileLine in fileModel.FileLines)
{
FileLine? fileLineToVerify = fileDetails.FileLines.SingleOrDefault(f => f.LineNumber == fileModelFileLine.LineNumber);
fileLineToVerify.ShouldNotBeNull();
fileLineToVerify.LineData.ShouldBe(fileModelFileLine.LineData);
fileLineToVerify.TransactionId.ShouldBe(fileModelFileLine.TransactionId);
fileLineToVerify.ProcessingResult.ShouldBe(fileModelFileLine.ProcessingResult);
}
}

private void VerifyImportLogs(List<FileImportLog> source, List<FIleProcessor.Models.FileImportLog> importLogs, Guid? merchantId = null)
{
importLogs.ShouldNotBeNull();
Expand Down
45 changes: 1 addition & 44 deletions FileProcessor.BusinessLogic.Tests/FileRequestHandlerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -447,50 +447,7 @@ public async Task FileRequestHandler_SafaricomTopupRequest_NoFileProfiles_Reques
await fileRequestHandler.Handle(safaricomTopupRequest, CancellationToken.None);
});
}

[Fact]
public async Task FileRequestHandler_SafaricomTopupRequest_InProgressDirectoryNotFound_RequestIsHandled()
{
Mock<IFileProcessorManager> fileProcessorManager = new Mock<IFileProcessorManager>();
fileProcessorManager.Setup(f => f.GetFileProfile(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(TestData.FileProfileSafaricom);
Mock<IAggregateRepository<FileImportLogAggregate, DomainEventRecord.DomainEvent>> fileImportLogAggregateRepository =
new Mock<IAggregateRepository<FileImportLogAggregate, DomainEventRecord.DomainEvent>>();
Mock<IAggregateRepository<FileAggregate, DomainEventRecord.DomainEvent>> fileAggregateRepository =
new Mock<IAggregateRepository<FileAggregate, DomainEventRecord.DomainEvent>>();

fileAggregateRepository.Setup(f => f.GetLatestVersion(It.IsAny<Guid>(), It.IsAny<CancellationToken>())).ReturnsAsync(TestData.GetCreatedFileAggregate);
Mock<ITransactionProcessorClient> transactionProcessorClient = new Mock<ITransactionProcessorClient>();
Mock<IEstateClient> estateClient = new Mock<IEstateClient>();
Mock<ISecurityServiceClient> securityServiceClient = new Mock<ISecurityServiceClient>();
Mock<IFileFormatHandler> fileFormatHandler = new Mock<IFileFormatHandler>();
Func<String, IFileFormatHandler> fileFormatHandlerResolver = (format) =>
{
return fileFormatHandler.Object;
};

MockFileSystem fileSystem = new MockFileSystem();
fileSystem.AddFile(TestData.FilePathWithName, new MockFileData("D,1,1,1"));

fileSystem.AddDirectory("home/txnproc/bulkfiles/safaricom/processed");
fileSystem.AddDirectory("home/txnproc/bulkfiles/safaricom/failed");

FileRequestHandler fileRequestHandler = new FileRequestHandler(fileProcessorManager.Object,
fileImportLogAggregateRepository.Object,
fileAggregateRepository.Object,
transactionProcessorClient.Object,
estateClient.Object,
securityServiceClient.Object,
fileFormatHandlerResolver,
fileSystem);
SafaricomTopupRequest safaricomTopupRequest =
new SafaricomTopupRequest(TestData.FileId, TestData.FilePathWithName, TestData.FileProfileId);

Should.Throw<DirectoryNotFoundException>(async () =>
{
await fileRequestHandler.Handle(safaricomTopupRequest, CancellationToken.None);
});
}


[Fact]
public async Task FileRequestHandler_SafaricomTopupRequest_ProcessedDirectoryNotFound_RequestIsHandled()
{
Expand Down
31 changes: 30 additions & 1 deletion FileProcessor.BusinessLogic/Managers/FileProcessorManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,12 @@
using EstateReporting.Database;
using EstateReporting.Database.Entities;
using EstateReporting.Database.ViewEntities;
using FileAggregate;
using FIleProcessor.Models;
using Microsoft.EntityFrameworkCore;
using Shared.DomainDrivenDesign.EventSourcing;
using Shared.EventStore.Aggregate;
using Shared.Exceptions;
using FileImportLog = FIleProcessor.Models.FileImportLog;
using FileLine = EstateReporting.Database.Entities.FileLine;

Expand All @@ -32,6 +36,8 @@ public class FileProcessorManager : IFileProcessorManager

private readonly IModelFactory ModelFactory;

private readonly IAggregateRepository<FileAggregate, DomainEventRecord.DomainEvent> FileAggregateRepository;

#endregion

#region Constructors
Expand All @@ -44,11 +50,13 @@ public class FileProcessorManager : IFileProcessorManager
/// <param name="modelFactory">The model factory.</param>
public FileProcessorManager(List<FileProfile> fileProfiles,
Shared.EntityFramework.IDbContextFactory<EstateReportingContext> dbContextFactory,
IModelFactory modelFactory)
IModelFactory modelFactory,
IAggregateRepository<FileAggregate, DomainEventRecord.DomainEvent> fileAggregateRepository)
{
this.FileProfiles = fileProfiles;
this.DbContextFactory = dbContextFactory;
this.ModelFactory = modelFactory;
this.FileAggregateRepository = fileAggregateRepository;
}

#endregion
Expand Down Expand Up @@ -139,6 +147,27 @@ public async Task<FileImportLog> GetFileImportLog(Guid fileImportLogId,
return this.ModelFactory.ConvertFrom(importLogQuery, importLogFileQuery);
}

/// <summary>
/// Gets the file.
/// </summary>
/// <param name="fileId">The file identifier.</param>
/// <param name="estateId">The estate identifier.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns></returns>
public async Task<FileDetails> GetFile(Guid fileId,
Guid estateId,
CancellationToken cancellationToken)
{
FileAggregate fileAggregate = await this.FileAggregateRepository.GetLatestVersion(fileId, cancellationToken);

if (fileAggregate.IsCreated == false)
{
throw new NotFoundException($"File with Id [{fileId}] not found");
}

return fileAggregate.GetFile();
}

#endregion
}
}
11 changes: 11 additions & 0 deletions FileProcessor.BusinessLogic/Managers/IFileProcessorManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,17 @@ Task<FileProfile> GetFileProfile(Guid fileProfileId,
/// <returns></returns>
Task<FileImportLog> GetFileImportLog(Guid fileImportLogId, Guid estateId, Guid? merchantId, CancellationToken cancellationToken);

/// <summary>
/// Gets the file.
/// </summary>
/// <param name="fileId">The file identifier.</param>
/// <param name="estateId">The estate identifier.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns></returns>
Task<FileDetails> GetFile(Guid fileId,
Guid estateId,
CancellationToken cancellationToken);

#endregion
}
}
Loading