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();
        }
Exemple #2
0
        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");
        }
Exemple #3
0
        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");
        }
Exemple #4
0
        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),
            });
        }
Exemple #5
0
        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();
        }
Exemple #7
0
        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}"));
        }
Exemple #8
0
        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");
                        }
                    }
                }
            });
        }