public async Task ValidateAsync_WhenCalculationNameAlreadyExistsButItsTheSameCalc_EnsuresValidIsTrue() { //Arrange CalculationEditModel model = CreateModel(); Calculation calculationWithSameName = new Calculation { Id = model.CalculationId }; ICalculationsRepository calculationsRepository = CreateCalculationRepository(); calculationsRepository .GetCalculationsBySpecificationIdAndCalculationName(Arg.Is(model.SpecificationId), Arg.Is(model.Name)) .Returns(calculationWithSameName); CalculationEditModelValidator validator = CreateValidator(calculationRepository: calculationsRepository); //Act ValidationResult result = await validator.ValidateAsync(model); //Assert result .IsValid .Should() .BeTrue(); }
public async Task ValidateAsync_WhenCalculationNameAlreadyExists_ValidIsFalse() { //Arrange CalculationCreateModel model = CreateModel(); Calculation calculationWithSameName = new Calculation(); ICalculationsRepository calculationsRepository = CreateCalculationRepository(); calculationsRepository .GetCalculationsBySpecificationIdAndCalculationName(Arg.Is(model.SpecificationId), Arg.Is(model.Name)) .Returns(calculationWithSameName); CalculationCreateModelValidator validator = CreateValidator(calculationRepository: calculationsRepository); //Act ValidationResult result = await validator.ValidateAsync(model); //Assert result .IsValid .Should() .BeFalse(); result.Errors .Should() .Contain(_ => _.ErrorMessage == "A calculation already exists with the name: 'test calc' for this specification"); }
public async Task ValidateAsync_WhenSourceCodeDoesNotCompile__ValidIsFalse() { //Arrange CalculationCreateModel model = CreateModel(); model.CalculationType = CalculationType.Additional; ICalculationsRepository calculationsRepository = CreateCalculationRepository(); calculationsRepository .GetCalculationsBySpecificationIdAndCalculationName(Arg.Is(model.SpecificationId), Arg.Is(model.Name)) .Returns((Calculation)null); SpecModel.SpecificationSummary specificationSummary = new SpecModel.SpecificationSummary { Name = "spec name", FundingStreams = new[] { new Reference(model.FundingStreamId, "funding stream name") } }; ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient(); specificationsApiClient .GetSpecificationSummaryById(Arg.Is(model.SpecificationId)) .Returns(new Common.ApiClient.Models.ApiResponse <SpecModel.SpecificationSummary>(HttpStatusCode.OK, specificationSummary)); PreviewResponse previewResponse = new PreviewResponse { CompilerOutput = new Build { CompilerMessages = new List <CompilerMessage> { new CompilerMessage { Message = "Failed" } } } }; IPreviewService previewService = CreatePreviewService(previewResponse); CalculationCreateModelValidator validator = CreateValidator( calculationsRepository, previewService: previewService, specificationsApiClient: specificationsApiClient); //Act ValidationResult result = await validator.ValidateAsync(model); //Assert result .IsValid .Should() .BeFalse(); result.Errors .Should() .Contain(_ => _.ErrorMessage == "There are errors in the source code provided"); }
public async Task GetCalculationByName_GivenSpecificationExistsAndCalculationExists_ReturnsSuccess() { //Arrange CalculationVersion calculationVersion = new CalculationVersion { Name = CalculationName, Date = new DateTimeOffset(2013, 1, 2, 3, 4, 55, TimeSpan.Zero), }; Calculation calc = new Calculation { Current = calculationVersion }; CalculationGetModel model = new CalculationGetModel { SpecificationId = SpecificationId, Name = CalculationName }; ILogger logger = CreateLogger(); ICalculationsRepository calculationsRepository = CreateCalculationsRepository(); calculationsRepository .GetCalculationsBySpecificationIdAndCalculationName(Arg.Is(SpecificationId), Arg.Is(CalculationName)) .Returns(calc); CalculationService service = CreateCalculationService(calculationsRepository: calculationsRepository, logger: logger); //Act IActionResult result = await service.GetCalculationByName(model); //Assert result .Should() .BeOfType <OkObjectResult>() .Which .Value .Should() .BeEquivalentTo(new CalculationResponseModel() { Name = CalculationName, SourceCode = "Return 0", LastUpdated = new DateTimeOffset(2013, 1, 2, 3, 4, 55, TimeSpan.Zero), }); }
public async Task ValidateAsync_WhenValidModel_ValidIsTrue() { //Arrange CalculationCreateModel model = CreateModel(); ICalculationsRepository calculationsRepository = CreateCalculationRepository(); calculationsRepository .GetCalculationsBySpecificationIdAndCalculationName(Arg.Is(model.SpecificationId), Arg.Is(model.Name)) .Returns((Calculation)null); SpecModel.SpecificationSummary specificationSummary = new SpecModel.SpecificationSummary { Name = "spec name", FundingStreams = new[] { new Reference(model.FundingStreamId, "funding stream name") } }; ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient(); specificationsApiClient .GetSpecificationSummaryById(Arg.Is(model.SpecificationId)) .Returns(new Common.ApiClient.Models.ApiResponse <SpecModel.SpecificationSummary>(HttpStatusCode.OK, specificationSummary)); CalculationCreateModelValidator validator = CreateValidator( calculationsRepository, specificationsApiClient: specificationsApiClient); //Act ValidationResult result = await validator.ValidateAsync(model); //Assert result .IsValid .Should() .BeTrue(); model.SpecificationName .Should() .Be("spec name"); model.FundingStreamName .Should() .Be("funding stream name"); }
public async Task ValidateAsync_WhenValidModel_ValidIsTrue() { //Arrange CalculationEditModel model = CreateModel(); ICalculationsRepository calculationsRepository = CreateCalculationRepository(); calculationsRepository .GetCalculationsBySpecificationIdAndCalculationName(Arg.Is(model.SpecificationId), Arg.Is(model.Name)) .Returns((Calculation)null); CalculationEditModelValidator validator = CreateValidator(calculationsRepository); //Act ValidationResult result = await validator.ValidateAsync(model); //Assert result .IsValid .Should() .BeTrue(); }
public async Task GetCalculationByName_GivenSpecificationExistsAndCalculationDoesNotExist_ReturnsNotFound() { //Arrange Calculation calc = new Calculation { Current = new CalculationVersion { Name = CalculationName } }; CalculationGetModel model = new CalculationGetModel { SpecificationId = SpecificationId, Name = CalculationName }; ILogger logger = CreateLogger(); ICalculationsRepository calculationsRepository = CreateCalculationsRepository(); calculationsRepository .GetCalculationsBySpecificationIdAndCalculationName(Arg.Is(SpecificationId), Arg.Is(CalculationName)) .Returns((Calculation)null); CalculationService service = CreateCalculationService(calculationsRepository: calculationsRepository, logger: logger); //Act IActionResult result = await service.GetCalculationByName(model); //Assert result .Should() .BeOfType <NotFoundResult>(); logger .Received(1) .Information(Arg.Is($"A calculation was not found for specification id {SpecificationId} and name {CalculationName}")); }
public CalculationCreateModelValidator( ICalculationsRepository calculationRepository, IPreviewService previewService, ISpecificationsApiClient specificationsApiClient, ICalcsResiliencePolicies calcsResiliencePolicies) { Guard.ArgumentNotNull(calculationRepository, nameof(calculationRepository)); Guard.ArgumentNotNull(previewService, nameof(previewService)); Guard.ArgumentNotNull(specificationsApiClient, nameof(specificationsApiClient)); Guard.ArgumentNotNull(calcsResiliencePolicies, nameof(calcsResiliencePolicies)); Guard.ArgumentNotNull(calcsResiliencePolicies?.SpecificationsApiClient, nameof(calcsResiliencePolicies.SpecificationsApiClient)); _calculationRepository = calculationRepository; _previewService = previewService; _specificationsApiClient = specificationsApiClient; _specificationsApiClientPolicy = calcsResiliencePolicies.SpecificationsApiClient; CascadeMode = CascadeMode.StopOnFirstFailure; RuleFor(model => model.SpecificationId) .NotEmpty() .NotNull() .WithMessage("Null or empty specification id provided."); RuleFor(model => model.ValueType) .NotNull() .WithMessage("Null value type was provided."); RuleFor(model => model.Name) .Custom((name, context) => { CalculationCreateModel calculationCreateModel = context.ParentContext.InstanceToValidate as CalculationCreateModel; if (string.IsNullOrWhiteSpace(calculationCreateModel.Name)) { context.AddFailure("Null or empty calculation name provided."); } else { if (!string.IsNullOrWhiteSpace(calculationCreateModel.SpecificationId)) { Calculation calculation = _calculationRepository.GetCalculationsBySpecificationIdAndCalculationName(calculationCreateModel.SpecificationId, calculationCreateModel.Name).Result; if (calculation != null) { context.AddFailure($"A calculation already exists with the name: '{calculationCreateModel.Name}' for this specification"); } } } }); RuleFor(model => model.SourceCode) .Custom((sc, context) => { CalculationCreateModel calculationCreateModel = context.ParentContext.InstanceToValidate as CalculationCreateModel; if (string.IsNullOrWhiteSpace(calculationCreateModel.SourceCode)) { context.AddFailure("Null or empty source code provided."); } else { if (calculationCreateModel.CalculationType == CalculationType.Additional) { PreviewRequest previewRequest = new PreviewRequest { SpecificationId = calculationCreateModel.SpecificationId, CalculationId = calculationCreateModel.Id, Name = calculationCreateModel.Name, SourceCode = calculationCreateModel.SourceCode }; IActionResult result = _previewService.Compile(previewRequest).Result; OkObjectResult okObjectResult = result as OkObjectResult; PreviewResponse response = okObjectResult.Value as PreviewResponse; if (response != null) { if (!response.CompilerOutput.CompilerMessages.IsNullOrEmpty()) { context.AddFailure("There are errors in the source code provided"); } } } } }); RuleFor(model => model.FundingStreamId) .Custom((fs, context) => { CalculationCreateModel calculationCreateModel = context.ParentContext.InstanceToValidate as CalculationCreateModel; //only validate funding stream id for template calcs var isTemplateCalculation = calculationCreateModel.CalculationType == CalculationType.Template; if (isTemplateCalculation && string.IsNullOrWhiteSpace(calculationCreateModel.FundingStreamId)) { context.AddFailure("Null or empty funding stream id provided."); } else { ApiResponse <SpecModel.SpecificationSummary> specificationApiResponse = _specificationsApiClientPolicy.ExecuteAsync(() => _specificationsApiClient.GetSpecificationSummaryById(calculationCreateModel.SpecificationId)).GetAwaiter().GetResult(); if (specificationApiResponse == null || !specificationApiResponse.StatusCode.IsSuccess() || specificationApiResponse.Content == null) { context.AddFailure("Failed to find specification for provided specification id."); } else { SpecModel.SpecificationSummary specificationSummary = specificationApiResponse.Content; //I don't want to have to fetch the spec summary again outside of this method to get the name and funding stream so we set them on input model here calculationCreateModel.SpecificationName = specificationSummary.Name; //only validate funding stream ids for template calcs if (!isTemplateCalculation) { return; } Reference fundingStream = specificationSummary.FundingStreams.FirstOrDefault(m => m.Id == calculationCreateModel.FundingStreamId); if (fundingStream == null) { context.AddFailure("The funding stream id provided is not associated with the provided specification."); } else { calculationCreateModel.FundingStreamName = fundingStream.Name; } } } }); }
public CalculationEditModelValidator( IPreviewService previewService, ICalculationsRepository calculationRepository) { Guard.ArgumentNotNull(previewService, nameof(previewService)); Guard.ArgumentNotNull(calculationRepository, nameof(calculationRepository)); _previewService = previewService; _calculationRepository = calculationRepository; RuleFor(model => model.SpecificationId) .NotEmpty() .NotNull() .WithMessage("Null or empty specification id provided."); RuleFor(model => model.ValueType) .NotNull() .WithMessage("Null value type was provided."); RuleFor(model => model.CalculationId) .NotEmpty() .NotNull() .WithMessage("Null or empty calculation id provided."); RuleFor(model => model.Name) .Custom((name, context) => { CalculationEditModel calculationEditModel = context.ParentContext.InstanceToValidate as CalculationEditModel; if (string.IsNullOrWhiteSpace(calculationEditModel.Name)) { context.AddFailure("Null or empty calculation name provided."); } else { if (!string.IsNullOrWhiteSpace(calculationEditModel.SpecificationId)) { Calculation calculation = _calculationRepository.GetCalculationsBySpecificationIdAndCalculationName(calculationEditModel.SpecificationId, calculationEditModel.Name).Result; if (calculation != null && calculation.Id != calculationEditModel.CalculationId) { context.AddFailure($"A calculation already exists with the name: '{calculationEditModel.Name}' for this specification"); } } } }); RuleFor(model => model.SourceCode) .Custom((sc, context) => { CalculationEditModel calculationEditModel = context.ParentContext.InstanceToValidate as CalculationEditModel; if (string.IsNullOrWhiteSpace(calculationEditModel.SourceCode)) { context.AddFailure("Null or empty source code provided."); } else { PreviewRequest previewRequest = new PreviewRequest { SpecificationId = calculationEditModel.SpecificationId, CalculationId = calculationEditModel.CalculationId, Name = calculationEditModel.Name, SourceCode = calculationEditModel.SourceCode, DataType = calculationEditModel.DataType }; IActionResult result = _previewService.Compile(previewRequest).Result; OkObjectResult okObjectResult = result as OkObjectResult; if (okObjectResult.Value is PreviewResponse response) { if (!response.CompilerOutput.CompilerMessages.IsNullOrEmpty()) { context.AddFailure("There are errors in the source code provided"); } } } }); }