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
1 change: 1 addition & 0 deletions application/CohortManager/compose.cohort-distribution.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ services:
- AddCohortDistributionURL=http://localhost:7077/api/AddCohortDistributionData
- ValidateCohortDistributionRecordURL=http://localhost:7084/api/ValidateCohortDistributionRecord
- DtOsDatabaseConnectionString=Server=localhost,1433;Database=${DB_NAME};User Id=SA;Password=${PASSWORD};TrustServerCertificate=True
- ParticipantManagementUrl=http://localhost:7994/api/ParticipantManagementDataService
- CohortQueueName=cohort-distribution-queue
- CohortQueueNamePoison=cohort-distribution-queue-poison
- IgnoreParticipantExceptions=false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,23 @@ public class CreateCohortDistribution
private readonly ICohortDistributionHelper _CohortDistributionHelper;
private readonly IExceptionHandler _exceptionHandler;
private readonly IAzureQueueStorageHelper _azureQueueStorageHelper;
private readonly IDataServiceClient<ParticipantManagement> _participantManagementClient;
private readonly CreateCohortDistributionConfig _config;

public CreateCohortDistribution(ILogger<CreateCohortDistribution> logger,
ICallFunction callFunction,
ICohortDistributionHelper CohortDistributionHelper,
IExceptionHandler exceptionHandler,
IAzureQueueStorageHelper azureQueueStorageHelper,
IOptions<CreateCohortDistributionConfig> createCohortDistributionConfig)
ICallFunction callFunction,
ICohortDistributionHelper CohortDistributionHelper,
IExceptionHandler exceptionHandler,
IAzureQueueStorageHelper azureQueueStorageHelper,
IDataServiceClient<ParticipantManagement> participantManagementClient,
IOptions<CreateCohortDistributionConfig> createCohortDistributionConfig)
{
_logger = logger;
_callFunction = callFunction;
_CohortDistributionHelper = CohortDistributionHelper;
_exceptionHandler = exceptionHandler;
_azureQueueStorageHelper = azureQueueStorageHelper;
_participantManagementClient = participantManagementClient;
_config = createCohortDistributionConfig.Value;
}

Expand Down Expand Up @@ -67,12 +70,12 @@ public async Task RunAsync([QueueTrigger("%CohortQueueName%", Connection = "Azur
return;
}
}

// Check if participant has exceptions
bool ignoreParticipantExceptions = _config.IgnoreParticipantExceptions;
_logger.LogInformation("Environment variable IgnoreParticipantExceptions is set to {IgnoreParticipantExceptions}", ignoreParticipantExceptions);
bool participantHasException = participantData.ExceptionFlag == 1;

bool participantHasException = participantData.ExceptionFlag == 1;
if (participantHasException && !ignoreParticipantExceptions) // Will only run if IgnoreParticipantExceptions is false.
{
await HandleErrorResponseAsync($"Unable to add to cohort distribution. As participant with ParticipantId: {participantData.ParticipantId}. Has an Exception against it",
Expand All @@ -82,13 +85,21 @@ await HandleErrorResponseAsync($"Unable to add to cohort distribution. As partic

// Validation
participantData.RecordType = basicParticipantCsvRecord.RecordType;
var validationRecordCreated = await _CohortDistributionHelper.ValidateCohortDistributionRecordAsync(basicParticipantCsvRecord.NhsNumber, basicParticipantCsvRecord.FileName, participantData);
var validationResponse = await _CohortDistributionHelper.ValidateCohortDistributionRecordAsync(basicParticipantCsvRecord.NhsNumber, basicParticipantCsvRecord.FileName, participantData);

if (validationRecordCreated && !ignoreParticipantExceptions)
// Update participant exception flag
if (validationResponse.CreatedException)
{
var errorMessage = $"Validation error: A rule triggered a fatal error, preventing the cohort distribution record with participant Id {participantData.ParticipantId} from being added to the database";
var errorMessage = $"Participant {participantData.ParticipantId} triggered a validation rule, so will not be added to cohort distribution";
_logger.LogInformation(errorMessage);
await _exceptionHandler.CreateRecordValidationExceptionLog(participantData.NhsNumber, basicParticipantCsvRecord.FileName, errorMessage, serviceProvider, JsonSerializer.Serialize(participantData));

var participantMangement = await _participantManagementClient.GetSingle(participantData.ParticipantId);
participantMangement.ExceptionFlag = 1;

bool excpetionFlagUpdated = await _participantManagementClient.Update(participantMangement);
Comment thread
SamRobinson75684 marked this conversation as resolved.
if (!excpetionFlagUpdated) throw new IOException("Failed to update exception flag");

return;
}
_logger.LogInformation("Validation has passed or exceptions are ignored, the record with participant id: {ParticipantId} will be added to the database", participantData.ParticipantId);
Expand All @@ -109,7 +120,7 @@ await HandleErrorResponseAsync($"Unable to add to cohort distribution. As partic
}
catch (Exception ex)
{
var errorMessage = $"Failed during TransformParticipant or AddCohortDistribution Function.\nMessage: {ex.Message}\nStack Trace: {ex.StackTrace}";
var errorMessage = $"Create Cohort Distribution failed .\nMessage: {ex.Message}\nStack Trace: {ex.StackTrace}";
_logger.LogError(ex, errorMessage);
await _exceptionHandler.CreateSystemExceptionLogFromNhsNumber(ex, basicParticipantCsvRecord.NhsNumber, basicParticipantCsvRecord.FileName, "", JsonSerializer.Serialize(basicParticipantCsvRecord.ErrorRecord) ?? "N/A");
throw;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
var host = new HostBuilder()
.AddConfiguration<CreateCohortDistributionConfig>(out CreateCohortDistributionConfig config)
.ConfigureFunctionsWorkerDefaults()
.AddDataServicesHandler()
.AddDataService<ParticipantManagement>(Environment.GetEnvironmentVariable("ParticipantManagementUrl"))
.Build()
.ConfigureServices(services =>
{
services.AddSingleton<ICallFunction, CallFunction>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,7 @@ public async Task<HttpResponseData> RunAsync([HttpTrigger(AuthorizationLevel.Ano
var newParticipant = requestBody.CohortDistributionParticipant;

var validationResult = await ValidateDataAsync(existingParticipant, newParticipant, requestBody.FileName);
if (validationResult.CreatedException)
{
return _createResponse.CreateHttpResponse(HttpStatusCode.Created, req, JsonSerializer.Serialize(validationResult));
}
return _createResponse.CreateHttpResponse(HttpStatusCode.OK, req);
return _createResponse.CreateHttpResponse(HttpStatusCode.OK, req, JsonSerializer.Serialize(validationResult));

}
catch (Exception ex)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public async Task<CohortDistributionParticipant> TransformParticipantAsync(strin
return null;
}

public async Task<bool> ValidateCohortDistributionRecordAsync(string nhsNumber, string FileName, CohortDistributionParticipant cohortDistributionParticipant)
public async Task<ValidationExceptionLog> ValidateCohortDistributionRecordAsync(string nhsNumber, string FileName, CohortDistributionParticipant cohortDistributionParticipant)
{
var lookupValidationRequestBody = new ValidateCohortDistributionRecordBody()
{
Expand All @@ -88,13 +88,7 @@ public async Task<bool> ValidateCohortDistributionRecordAsync(string nhsNumber,

_logger.LogInformation("Called cohort validation service");
var response = await GetResponseAsync(json, Environment.GetEnvironmentVariable("ValidateCohortDistributionRecordURL"));
if (!string.IsNullOrEmpty(response))
{
var responseObj = JsonSerializer.Deserialize<ValidationExceptionLog>(response);
return responseObj.IsFatal;
}
_logger.LogInformation("The response from the validation for cohort distribution returned null or empty");
return false;
return JsonSerializer.Deserialize<ValidationExceptionLog>(response);
}

private async Task<string> GetResponseAsync(string requestBodyJson, string functionURL)
Expand All @@ -104,7 +98,8 @@ private async Task<string> GetResponseAsync(string requestBodyJson, string funct
{
return "";
}
if (response.StatusCode == HttpStatusCode.OK)

if (response.StatusCode == HttpStatusCode.OK || response.StatusCode == HttpStatusCode.Created)
{
var responseText = await _callFunction.GetResponseText(response);
if (!string.IsNullOrEmpty(responseText))
Expand All @@ -113,7 +108,6 @@ private async Task<string> GetResponseAsync(string requestBodyJson, string funct
}

}


return "";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ public interface ICohortDistributionHelper
Task<CohortDistributionParticipant?> RetrieveParticipantDataAsync(CreateCohortDistributionRequestBody cohortDistributionRequestBody);
Task<string> AllocateServiceProviderAsync(string nhsNumber, string screeningAcronym, string postCode, string errorRecord);
Task<CohortDistributionParticipant> TransformParticipantAsync(string serviceProvider, CohortDistributionParticipant participantData);
Task<bool> ValidateCohortDistributionRecordAsync(string nhsNumber, string FileName, CohortDistributionParticipant cohortDistributionParticipant);
Task<ValidationExceptionLog> ValidateCohortDistributionRecordAsync(string nhsNumber, string FileName, CohortDistributionParticipant cohortDistributionParticipant);
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,21 @@ public CreateCohortDistributionTests()
.Setup(x => x.RetrieveParticipantDataAsync(It.IsAny<CreateCohortDistributionRequestBody>()))
.ReturnsAsync(_cohortDistributionParticipant);

_cohortDistributionHelper
.Setup(x => x.ValidateCohortDistributionRecordAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CohortDistributionParticipant>()))
.ReturnsAsync(new ValidationExceptionLog {CreatedException = false, IsFatal = false});

_participantManagementClientMock
.Setup(x => x.GetSingle(It.IsAny<string>()))
.ReturnsAsync(new ParticipantManagement {ExceptionFlag = 0});

_participantManagementClientMock
.Setup(x => x.Update(It.IsAny<ParticipantManagement>()))
.ReturnsAsync(true);

_sut = new CreateCohortDistribution(_logger.Object, _callFunction.Object, _cohortDistributionHelper.Object,
_exceptionHandler.Object, _azureQueueStorageHelper.Object,
_participantManagementClientMock.Object);
_config.Object);

}
Expand Down Expand Up @@ -120,7 +133,7 @@ public async Task RunAsync_RetrieveParticipantDataRequestFails_ReturnBadRequest(
// Assert
_logger.Verify(x => x.Log(It.Is<LogLevel>(l => l == LogLevel.Error),
It.IsAny<EventId>(),
It.Is<It.IsAnyType>((v, t) => v.ToString().Contains("Failed during TransformParticipant or AddCohortDistribution Function.")),
It.Is<It.IsAnyType>((v, t) => v.ToString().Contains("Create Cohort Distribution failed")),
It.IsAny<Exception>(),
It.IsAny<Func<It.IsAnyType, Exception, string>>()),
Times.Once);
Expand Down Expand Up @@ -168,7 +181,7 @@ public async Task RunAsync_AllocateServiceProviderToParticipantRequestFails_Retu
// Assert
_logger.Verify(x => x.Log(It.Is<LogLevel>(l => l == LogLevel.Error),
It.IsAny<EventId>(),
It.Is<It.IsAnyType>((v, t) => v.ToString().Contains("Failed during TransformParticipant or AddCohortDistribution Function.")),
It.Is<It.IsAnyType>((v, t) => v.ToString().Contains("Create Cohort Distribution failed")),
It.IsAny<Exception>(),
It.IsAny<Func<It.IsAnyType, Exception, string>>()),
Times.Once);
Expand All @@ -181,9 +194,6 @@ public async Task RunAsync_AllocateServiceProviderToParticipantRequestFails_Retu
public async Task RunAsync_TransformDataServiceRequestFails_ReturnEarly()
{
// Arrange
_cohortDistributionHelper
.Setup(x => x.ValidateCohortDistributionRecordAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CohortDistributionParticipant>()))
.ReturnsAsync(false);
_cohortDistributionHelper
.Setup(x => x.AllocateServiceProviderAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.ReturnsAsync("");
Expand All @@ -209,9 +219,6 @@ public async Task RunAsync_AddCohortDistributionRequestFails_LogError()
Exception caughtException = null;
_request = _setupRequest.Setup(JsonSerializer.Serialize(_requestBody));

_cohortDistributionHelper
.Setup(x => x.ValidateCohortDistributionRecordAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CohortDistributionParticipant>()))
.ReturnsAsync(false);
_cohortDistributionHelper
.Setup(x => x.AllocateServiceProviderAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.ReturnsAsync("");
Expand Down Expand Up @@ -239,7 +246,7 @@ public async Task RunAsync_AddCohortDistributionRequestFails_LogError()
// Assert
_logger.Verify(x => x.Log(It.Is<LogLevel>(l => l == LogLevel.Error),
It.IsAny<EventId>(),
It.Is<It.IsAnyType>((v, t) => v.ToString().Contains("Failed during TransformParticipant or AddCohortDistribution Function.")),
It.Is<It.IsAnyType>((v, t) => v.ToString().Contains("Create Cohort Distribution failed")),
It.IsAny<Exception>(),
It.IsAny<Func<It.IsAnyType, Exception, string>>()),
Times.Once);
Expand All @@ -252,20 +259,13 @@ public async Task RunAsync_AddCohortDistributionRequestFails_LogError()
public async Task RunAsync_AllSuccessfulRequests_AddsToCOhort()
{
// Arrange
_cohortDistributionHelper
.Setup(x => x.ValidateCohortDistributionRecordAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CohortDistributionParticipant>()))
.ReturnsAsync(false);
_cohortDistributionHelper
.Setup(x => x.AllocateServiceProviderAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.ReturnsAsync("");
_cohortDistributionHelper
.Setup(x => x.TransformParticipantAsync(It.IsAny<string>(), It.IsAny<CohortDistributionParticipant>()))
.ReturnsAsync(new CohortDistributionParticipant());

_participantManagementClientMock
.Setup(c => c.GetSingleByFilter(It.IsAny<Expression<Func<ParticipantManagement, bool>>>()))
.ReturnsAsync(new ParticipantManagement { ExceptionFlag = 0 });

_sendToCohortDistributionResponse
.Setup(x => x.StatusCode)
.Returns(HttpStatusCode.OK);
Expand All @@ -278,7 +278,9 @@ public async Task RunAsync_AllSuccessfulRequests_AddsToCOhort()
.ReturnsAsync(new ParticipantManagement() { ExceptionFlag = 0 });

var response = MockHelpers.CreateMockHttpResponseData(HttpStatusCode.OK);
_callFunction.Setup(call => call.SendPost(It.IsAny<string>(), It.IsAny<string>())).Returns(Task.FromResult(response));
_callFunction
.Setup(call => call.SendPost(It.IsAny<string>(), It.IsAny<string>()))
.ReturnsAsync(response);

// Act
await _sut.RunAsync(_requestBody);
Expand Down Expand Up @@ -321,12 +323,12 @@ public async Task RunAsync_ParticipantHasException_CreatesSystemExceptionLog()
}

[TestMethod]
public async Task RunAsync_ValidationRequestFailed_CreateValidationExceptionLog()
public async Task RunAsync_ValidationRuleTriggered_UpdateExceptionFlagAndLog()
{
// Arrange
_cohortDistributionHelper
.Setup(x => x.ValidateCohortDistributionRecordAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CohortDistributionParticipant>()))
.ReturnsAsync(true);
.ReturnsAsync(new ValidationExceptionLog { CreatedException = true, IsFatal = false });
_cohortDistributionHelper
.Setup(x => x.AllocateServiceProviderAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.ReturnsAsync("");
Expand All @@ -351,10 +353,13 @@ public async Task RunAsync_ValidationRequestFailed_CreateValidationExceptionLog(
It.IsAny<string>(),
It.IsAny<string>()
), Times.Once);

_participantManagementClientMock
.Verify(x => x.Update(It.IsAny<ParticipantManagement>()), Times.Once);
}

[TestMethod]
public async Task RunAsync_ParticipantHasExceptionAndEnvironmentVariableFalse_CreateSystemExceptionLog()
public async Task RunAsync_ParticipantHasExceptionAndEnvironmentVariableFalse_CreateExceptionAndReturn()
{
// Arrange
Environment.SetEnvironmentVariable("IgnoreParticipantExceptions", "false");
Expand All @@ -376,5 +381,12 @@ public async Task RunAsync_ParticipantHasExceptionAndEnvironmentVariableFalse_Cr
It.Is<It.IsAnyType>((v, t) => v.ToString().Contains($"Unable to add to cohort distribution")),
It.IsAny<Exception>(),
It.IsAny<Func<It.IsAnyType, Exception, string>>()));

_cohortDistributionHelper
.Verify(x => x.ValidateCohortDistributionRecordAsync(
It.IsAny<string>(),
It.IsAny<string>(),
It.IsAny<CohortDistributionParticipant>()),
Times.Never);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ public async Task Run_RequestBodyInvalid_BadRequest()
}

[TestMethod]
public async Task Run_LookupValidationCreatesValidationError_Created()
public async Task Run_LookupValidationCreatesValidationError_ReturnOk()
{
// Arrange
SetUpRequestBody(JsonSerializer.Serialize(_requestBody));
Expand All @@ -162,7 +162,7 @@ public async Task Run_LookupValidationCreatesValidationError_Created()
var result = await _function.RunAsync(_request.Object);

// Assert
Assert.AreEqual(HttpStatusCode.Created, result.StatusCode);
Assert.AreEqual(HttpStatusCode.OK, result.StatusCode);
}

[TestMethod]
Expand Down
Loading