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 @@ -47,6 +47,34 @@ public async Task GetDailyPerformanceSummaryQuery_ReturnsMockedSummaryForToday()
Times.Once);
}

[Fact]
public async Task GetDailyPerformanceSummaryQuery_InvalidPeriod_ReturnsFailure()
{
Mock<IReportsService> reportsService = new();
Mock<IApplicationCache> applicationCache = new();
MerchantDetailsModel merchantDetails = new()
{
MerchantReportingId = 12345
};

applicationCache.Setup(a => a.GetMerchantDetails()).Returns(merchantDetails);

ReportRequestHandler handler = new(reportsService.Object, applicationCache.Object);

Result<DailyPerformanceSummaryModel> result = await handler.Handle(
new ReportQueries.GetDailyPerformanceSummaryQuery((PerformanceSummaryPeriod)999),
CancellationToken.None);

result.IsFailed.ShouldBeTrue();
reportsService.Verify(r => r.GetDailyPerformanceSummary(
It.IsAny<PerformanceSummaryPeriod>(),
It.IsAny<Int32>(),
It.IsAny<DateTime>(),
It.IsAny<DateTime>(),
It.IsAny<CancellationToken>()),
Times.Never);
}

[Fact]
public async Task GetTransactionMixSummaryQuery_ReturnsRequestedBreakdown()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,27 @@ public async Task SupportRequestHandlerTests_UploadLogsRequest_NoLogs_Handle_IsH
response.IsSuccess.ShouldBeTrue();
}

[Fact]
public async Task SupportRequestHandlerTests_UploadLogsRequest_NoConfiguration_ReturnsFailure()
{
Mock<IConfigurationService> configurationService = new Mock<IConfigurationService>();
Func<Boolean, IConfigurationService> configurationServiceResolver = _ => configurationService.Object;

Mock<IDatabaseContext> databaseContext = new Mock<IDatabaseContext>();
Mock<IApplicationCache> applicationCache = new Mock<IApplicationCache>();
applicationCache.Setup(s => s.GetConfiguration()).Returns((Configuration)null);

SupportRequestHandler handler = new SupportRequestHandler(configurationServiceResolver, databaseContext.Object, applicationCache.Object);

SupportCommands.UploadLogsCommand request = new(TestData.DeviceIdentifier);

Result response = await handler.Handle(request, CancellationToken.None);

response.IsFailed.ShouldBeTrue();
configurationService.Verify(c => c.PostDiagnosticLogs(It.IsAny<String>(), It.IsAny<List<Models.LogMessage>>(), It.IsAny<CancellationToken>()), Times.Never);
databaseContext.Verify(d => d.GetLogMessages(It.IsAny<Int32>(), It.IsAny<Boolean>()), Times.Never);
}

[Fact]
public async Task SupportRequestHandlerTests_UploadLogsRequest_LogsToUpload_Only10Messages_Handle_IsHandled()
{
Expand Down Expand Up @@ -117,6 +138,71 @@ public async Task SupportRequestHandlerTests_UploadLogsRequest_LogsToUpload_15Me
databaseContext.Verify(d => d.RemoveUploadedMessages(It.IsAny<List<Database.LogMessage>>()), Times.Exactly(2));
}

[Fact]
public async Task SupportRequestHandlerTests_UploadLogsRequest_InvalidLogLevel_ReturnsFailure()
{
Mock<IConfigurationService> configurationService = new Mock<IConfigurationService>();
Func<Boolean, IConfigurationService> configurationServiceResolver = _ => configurationService.Object;

Mock<IDatabaseContext> databaseContext = new Mock<IDatabaseContext>();
databaseContext.Setup(d => d.GetLogMessages(It.IsAny<Int32>(), It.IsAny<Boolean>())).ReturnsAsync(new List<Database.LogMessage>
{
new Database.LogMessage { LogLevel = "NotALogLevel" }
});

Mock<IApplicationCache> applicationCache = new Mock<IApplicationCache>();
applicationCache.Setup(s => s.GetConfiguration()).Returns(new Configuration());

SupportRequestHandler handler = new SupportRequestHandler(configurationServiceResolver, databaseContext.Object, applicationCache.Object);

SupportCommands.UploadLogsCommand request = new(TestData.DeviceIdentifier);

Result response = await handler.Handle(request, CancellationToken.None);

response.IsFailed.ShouldBeTrue();
configurationService.Verify(c => c.PostDiagnosticLogs(It.IsAny<String>(), It.IsAny<List<Models.LogMessage>>(), It.IsAny<CancellationToken>()), Times.Never);
databaseContext.Verify(d => d.RemoveUploadedMessages(It.IsAny<List<Database.LogMessage>>()), Times.Never);
}

[Fact]
public async Task SupportRequestHandlerTests_UploadLogsRequest_CancellationStopsFurtherProcessing()
{
Mock<IConfigurationService> configurationService = new Mock<IConfigurationService>();
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
configurationService.Setup(c => c.PostDiagnosticLogs(It.IsAny<String>(), It.IsAny<List<Models.LogMessage>>(), It.IsAny<CancellationToken>()))
.Callback<String, List<Models.LogMessage>, CancellationToken>((_, _, _) =>
{
cancellationTokenSource.Cancel();
})
.ReturnsAsync(Result.Success());

Func<Boolean, IConfigurationService> configurationServiceResolver = _ => configurationService.Object;

Mock<IDatabaseContext> databaseContext = new Mock<IDatabaseContext>();
databaseContext.SetupSequence(d => d.GetLogMessages(It.IsAny<Int32>(), It.IsAny<Boolean>()))
.ReturnsAsync(new List<Database.LogMessage>
{
new Database.LogMessage { LogLevel = LogLevel.Debug.ToString() }
})
.ReturnsAsync(new List<Database.LogMessage>
{
new Database.LogMessage { LogLevel = LogLevel.Debug.ToString() }
});

Mock<IApplicationCache> applicationCache = new Mock<IApplicationCache>();
applicationCache.Setup(s => s.GetConfiguration()).Returns(new Configuration());

SupportRequestHandler handler = new SupportRequestHandler(configurationServiceResolver, databaseContext.Object, applicationCache.Object);

SupportCommands.UploadLogsCommand request = new(TestData.DeviceIdentifier);

await Should.ThrowAsync<OperationCanceledException>(async () => await handler.Handle(request, cancellationTokenSource.Token));

configurationService.Verify(c => c.PostDiagnosticLogs(It.IsAny<String>(), It.IsAny<List<Models.LogMessage>>(), cancellationTokenSource.Token), Times.Once);
databaseContext.Verify(d => d.GetLogMessages(It.IsAny<Int32>(), It.IsAny<Boolean>()), Times.Once);
databaseContext.Verify(d => d.RemoveUploadedMessages(It.IsAny<List<Database.LogMessage>>()), Times.Once);
}

[Theory]
[InlineData(true, 4)]
[InlineData(false, 3)]
Expand Down Expand Up @@ -154,4 +240,4 @@ public async Task SupportRequestHandlerTests_ViewLogsRequest_Handle_IsHandled(Bo
result.IsSuccess.ShouldBeTrue();
result.Data.Count.ShouldBe(expectedNumberMessages);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public async Task TransactionRequestHandler_LogonTransactionRequest_Handle_IsHan
public async Task TransactionRequestHandler_LogonTransactionRequest_Handle_LogonFailed_IsHandled()
{
this.TransactionService.Setup(t => t.PerformLogon(It.IsAny<PerformLogonRequestModel>(), It.IsAny<CancellationToken>())).ReturnsAsync(
Result.Success(TestData.PerformLogonResponseFailedModel));
Result.Success(TestData.PerformLogonResponseFailedModel));

TransactionCommands.PerformLogonCommand request = new(TestData.TransactionDateTime);

Expand All @@ -75,6 +75,21 @@ public async Task TransactionRequestHandler_LogonTransactionRequest_Handle_Logon
result.IsSuccess.ShouldBeFalse();
}

[Fact]
public async Task TransactionRequestHandler_LogonTransactionRequest_Handle_ServiceFailure_ReturnsFailure_AndDoesNotUpdateTransaction()
{
this.DatabaseContext.Setup(d => d.CreateTransaction(It.IsAny<TransactionRecord>())).ReturnsAsync(1);
this.TransactionService.Setup(t => t.PerformLogon(It.IsAny<PerformLogonRequestModel>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(Result.Failure("Logon failed"));

TransactionCommands.PerformLogonCommand request = new(TestData.TransactionDateTime);

Result<PerformLogonResponseModel> result = await this.TransactionRequestHandler.Handle(request, CancellationToken.None);

result.IsFailed.ShouldBeTrue();
this.DatabaseContext.Verify(d => d.UpdateTransaction(It.IsAny<TransactionRecord>()), Times.Never);
}

[Fact]
public async Task TransactionRequestHandler_PerformMobileTopupRequest_Handle_IsHandled()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ public async Task<Result<DailyPerformanceSummaryModel>> Handle(ReportQueries.Get

DateTime current = DateTime.Now.Date;

if (request.Period is not (PerformanceSummaryPeriod.Today or
PerformanceSummaryPeriod.Yesterday or
PerformanceSummaryPeriod.ThisWeek or
PerformanceSummaryPeriod.MonthToDate))
{
return Result.Failure("Invalid performance summary period.");
}

(DateTime startDate, DateTime endDate) dates = request.Period switch {
PerformanceSummaryPeriod.Today => (current, current),
PerformanceSummaryPeriod.Yesterday => (current.AddDays(-1), current.AddDays(-1)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,35 +25,36 @@ public SupportRequestHandler(Func<Boolean, IConfigurationService> configurationS
this.ApplicationCache = applicationCache;
}

public async Task<Result> Handle(SupportCommands.UploadLogsCommand request, CancellationToken cancellationToken)
public async Task<Result> Handle(SupportCommands.UploadLogsCommand request, CancellationToken cancellationToken)
{
Boolean useTrainingMode = this.ApplicationCache.GetUseTrainingMode();
Configuration configuration = this.ApplicationCache.GetConfiguration();
if (configuration == null)
{
Boolean useTrainingMode = this.ApplicationCache.GetUseTrainingMode();
Configuration configuration = this.ApplicationCache.GetConfiguration();
while (true) {
IConfigurationService configurationService = this.ConfigurationServiceResolver(useTrainingMode);

List<LogMessage> logEntries = await this.DatabaseContext.GetLogMessages(configuration.LogMessageBatchSize.GetValueOrDefault(10), useTrainingMode);
return Result.Failure("Configuration is not available.");
}

if (logEntries.Any() == false) {
break;
}
while (true) {
cancellationToken.ThrowIfCancellationRequested();
IConfigurationService configurationService = this.ConfigurationServiceResolver(useTrainingMode);

List<Models.LogMessage> logMessageModels = new();
List<LogMessage> logEntries = await this.DatabaseContext.GetLogMessages(configuration.LogMessageBatchSize.GetValueOrDefault(10), useTrainingMode);

logEntries.ForEach(l => logMessageModels.Add(new Models.LogMessage {
LogLevel = Enum.Parse<Models.LogLevel>(l.LogLevel),
LogLevelString = l.LogLevel,
Message = l.Message,
EntryDateTime = l.EntryDateTime,
Id = l.Id
}));
if (logEntries.Any() == false) {
break;
}

Result<List<Models.LogMessage>> logMessageModelsResult = this.TryBuildLogMessageModels(logEntries);
if (logMessageModelsResult.IsFailed)
{
return Result.Failure(logMessageModelsResult.Errors.FirstOrDefault() ?? "Unable to map log messages.");
}

Result result = await configurationService.PostDiagnosticLogs(request.DeviceIdentifier, logMessageModels, CancellationToken.None);
Result result = await configurationService.PostDiagnosticLogs(request.DeviceIdentifier, logMessageModelsResult.Data, cancellationToken);

if (result.IsFailed) {
// We have had a failure posting the logs so we will stop trying to upload any more logs
return result;
if (result.IsFailed) {
// We have had a failure posting the logs so we will stop trying to upload any more logs
return result;
}

// Clear the logs that have been uploaded
Expand All @@ -70,17 +71,37 @@ public async Task<Result> Handle(SupportCommands.UploadLogsCommand request, Canc

List<LogMessage> logEntries = await this.DatabaseContext.GetLogMessages(50, useTrainingMode);

Result<List<Models.LogMessage>> logMessageModelsResult = this.TryBuildLogMessageModels(logEntries);
if (logMessageModelsResult.IsFailed)
{
return Result.Failure(logMessageModelsResult.Errors.FirstOrDefault() ?? "Unable to map log messages.");
}

return Result.Success(logMessageModelsResult.Data.OrderByDescending(l => l.EntryDateTime).ToList());
}

private Result<List<Models.LogMessage>> TryBuildLogMessageModels(List<LogMessage> logEntries)
{
List<Models.LogMessage> logMessageModels = new();

logEntries.ForEach(l => logMessageModels.Add(new Models.LogMessage {
LogLevel = Enum.Parse<Models.LogLevel>(l.LogLevel),
LogLevelString = l.LogLevel,
Message = l.Message,
EntryDateTime = l.EntryDateTime,
Id = l.Id
}));
foreach (LogMessage logEntry in logEntries)
{
if (Enum.TryParse<Models.LogLevel>(logEntry.LogLevel, ignoreCase: true, out Models.LogLevel logLevel) == false)
{
return Result.Failure($"Invalid log level '{logEntry.LogLevel}'.");
}

logMessageModels.Add(new Models.LogMessage
{
LogLevel = logLevel,
LogLevelString = logEntry.LogLevel,
Message = logEntry.Message,
EntryDateTime = logEntry.EntryDateTime,
Id = logEntry.Id
});
}

return Result.Success(logMessageModels.OrderByDescending(l => l.EntryDateTime).ToList());
return Result.Success(logMessageModels);
}
}
}
Loading
Loading