public void Validate_ValidatesAsExpected(CalculationCreateModel model, bool expectedResult, IEnumerable <string> expectedErrors)
        {
            //Arrange
            ISpecificationsRepository specsRepo     = CreateSpecificationsRepository(false);
            Specification             specification = new Specification
            {
                Current = new SpecificationVersion()
            };

            specsRepo
            .GetSpecificationById(specificationId)
            .Returns(specification);

            CalculationCreateModelValidator validator = CreateValidator(specsRepo);

            //Act
            ValidationResult result = validator.Validate(model);

            //Assert
            result
            .IsValid
            .Should()
            .Be(expectedResult);

            foreach (var error in expectedErrors)
            {
                result.Errors.Count(e => e.ErrorMessage == error).Should().Be(1, $"Expected to find error message '{error}'");
            }

            result
            .Errors
            .Count
            .Should()
            .Be(expectedErrors.Count());
        }
예제 #2
0
        public async Task CreateAdditionalCalculation_GivenCreateJobReturnsNull_ReturnsInternalServerError()
        {
            //Arrange
            CalculationCreateModel model = CreateCalculationCreateModel();

            Reference author = CreateAuthor();

            ICalculationsRepository calculationsRepository = CreateCalculationsRepository();

            calculationsRepository
            .CreateDraftCalculation(Arg.Any <Calculation>())
            .Returns(HttpStatusCode.OK);

            IVersionRepository <CalculationVersion> versionRepository = CreateCalculationVersionRepository();

            ISearchRepository <CalculationIndex> searchRepository = CreateSearchRepository();

            IJobManagement jobManagement = CreateJobManagement();

            jobManagement
            .QueueJob(Arg.Any <JobCreateModel>())
            .Returns((Job)null);

            ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient();

            specificationsApiClient
            .GetSpecificationSummaryById(Arg.Is(SpecificationId))
            .Returns(new ApiResponse <SpecificationSummary>(
                         HttpStatusCode.OK,
                         new SpecificationSummary {
                Id = SpecificationId
            }
                         ));

            ILogger logger = CreateLogger();

            CalculationService calculationService = CreateCalculationService(
                calculationsRepository: calculationsRepository,
                calculationVersionRepository: versionRepository,
                searchRepository: searchRepository,
                jobManagement: jobManagement,
                logger: logger,
                specificationsApiClient: specificationsApiClient);

            //Act
            IActionResult result = await calculationService.CreateAdditionalCalculation(SpecificationId, model, author, CorrelationId);

            //Assert
            result
            .Should()
            .BeOfType <InternalServerErrorResult>()
            .Which
            .Value
            .Should()
            .Be($"Failed to create job of type '{JobConstants.DefinitionNames.CreateInstructAllocationJob}' on specification '{SpecificationId}'");

            logger
            .Received(1)
            .Error(Arg.Is($"Failed to create job of type '{JobConstants.DefinitionNames.CreateInstructAllocationJob}' on specification '{SpecificationId}'"));
        }
예제 #3
0
        public async Task CreateAdditionalCalculation_GivenValidationFails_ReturnsBadRequest()
        {
            //Arrange
            string correlationId = "any-id";

            CalculationCreateModel model = new CalculationCreateModel();
            Reference author             = new Reference();

            ValidationResult validationResult = new ValidationResult(new[] {
                new ValidationFailure("prop1", "oh no an error!!!")
            });

            IValidator <CalculationCreateModel> validator = CreateCalculationCreateModelValidator(validationResult);

            ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient();

            specificationsApiClient
            .GetSpecificationSummaryById(Arg.Is(SpecificationId))
            .Returns(new ApiResponse <SpecificationSummary>(
                         HttpStatusCode.OK,
                         new SpecificationSummary {
                Id = SpecificationId
            }
                         ));

            CalculationService calculationService = CreateCalculationService(calculationCreateModelValidator: validator, specificationsApiClient: specificationsApiClient);

            //Act
            IActionResult result = await calculationService.CreateAdditionalCalculation(SpecificationId, model, author, correlationId);

            //Assert
            result
            .Should()
            .BeAssignableTo <BadRequestObjectResult>();
        }
예제 #4
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");
        }
예제 #5
0
        public async Task <IActionResult> CreateAdditionalCalculation([FromRoute] string specificationId,
                                                                      [FromBody] CalculationCreateModel model)
        {
            HttpRequest httpRequest = ControllerContext.HttpContext.Request;

            return(await _calcsService.CreateAdditionalCalculation(specificationId, model, httpRequest.GetUserOrDefault(), httpRequest.GetCorrelationId()));
        }
예제 #6
0
        public async Task <IActionResult> CreateCalculation(string specificationId, string calculationId, [FromBody] CreateAdditionalCalculationViewModel vm)
        {
            if (!ModelState.IsValid)
            {
                return(BadRequest(ModelState));
            }

            if (!await _authorizationHelper.DoesUserHavePermission(User, specificationId, SpecificationActionTypes.CanEditCalculations))
            {
                return(new ForbidResult());
            }

            CalculationCreateModel createCalculation = _mapper.Map <CalculationCreateModel>(vm);

            createCalculation.SpecificationId = specificationId;
            createCalculation.Id        = calculationId;
            createCalculation.Name      = vm.CalculationName;
            createCalculation.ValueType = vm.CalculationType;

            ValidatedApiResponse <Calculation> response = await _calcClient.CreateCalculation(specificationId, createCalculation);

            if (response.IsBadRequest(out BadRequestObjectResult badRequest))
            {
                return(badRequest);
            }

            if (response.StatusCode == HttpStatusCode.OK)
            {
                return(Ok(response.Content));
            }

            return(BadRequest($"An error occurred while saving calculation. Please check and try again."));
        }
예제 #7
0
        public async Task ValidateAsync_WhenSpecificationCanNotBeFound_ValidIsFalse()
        {
            //Arrange
            CalculationCreateModel model = CreateModel();

            ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient();

            specificationsApiClient
            .GetSpecificationSummaryById(Arg.Is(model.SpecificationId))
            .Returns(new Common.ApiClient.Models.ApiResponse <SpecModel.SpecificationSummary>(HttpStatusCode.OK, null));

            CalculationCreateModelValidator validator = CreateValidator(specificationsApiClient: specificationsApiClient);

            //Act
            ValidationResult result = await validator.ValidateAsync(model);

            //Assert
            result
            .IsValid
            .Should()
            .BeFalse();

            result.Errors
            .Should()
            .Contain(_ => _.ErrorMessage == "Failed to find specification for provided specification id.");
        }
예제 #8
0
        public async Task ValidateAsync_WhenSpecificationDoesNotContainFundingStreamValidIsFalse()
        {
            //Arrange
            CalculationCreateModel model = CreateModel();

            SpecModel.SpecificationSummary specificationSummary = new SpecModel.SpecificationSummary
            {
                FundingStreams = new[] { new Reference() }
            };

            ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient();

            specificationsApiClient
            .GetSpecificationSummaryById(Arg.Is(model.SpecificationId))
            .Returns(new Common.ApiClient.Models.ApiResponse <SpecModel.SpecificationSummary>(HttpStatusCode.OK, specificationSummary));

            CalculationCreateModelValidator validator = CreateValidator(specificationsApiClient: specificationsApiClient);

            //Act
            ValidationResult result = await validator.ValidateAsync(model);

            //Assert
            result
            .IsValid
            .Should()
            .BeFalse();

            result.Errors
            .Should()
            .Contain(_ => _.ErrorMessage == "The funding stream id provided is not associated with the provided specification.");
        }
        public async Task CreateCalculation_GivenDuplicateCalculationName_ReturnsBadRequest()
        {
            // Arrange
            Specification specification = CreateSpecification();

            CalculationCreateModel model = new CalculationCreateModel
            {
                SpecificationId = SpecificationId,
                PolicyId        = PolicyId,
                Name            = "calc1",
                CalculationType = CalculationType.Number
            };

            string json = JsonConvert.SerializeObject(model);

            byte[]       byteArray = Encoding.UTF8.GetBytes(json);
            MemoryStream stream    = new MemoryStream(byteArray);

            ClaimsPrincipal principal = new ClaimsPrincipal(new[]
            {
                new ClaimsIdentity(new [] { new Claim(ClaimTypes.Sid, UserId), new Claim(ClaimTypes.Name, Username) })
            });

            HttpContext context = Substitute.For <HttpContext>();

            context
            .User
            .Returns(principal);

            HttpRequest request = Substitute.For <HttpRequest>();

            request
            .Body
            .Returns(stream);

            request
            .HttpContext
            .Returns(context);

            ISpecificationsRepository specificationsRepository = CreateSpecificationsRepository();

            specificationsRepository
            .GetSpecificationById(Arg.Is(SpecificationId))
            .Returns(specification);

            IValidator <CalculationCreateModel> validator = CreateCalculationValidator(new ValidationResult(new[] { new ValidationFailure("prop1", "any error") }));

            SpecificationsService service = CreateService(specificationsRepository: specificationsRepository,
                                                          calculationCreateModelValidator: validator);

            // Act
            IActionResult result = await service.CreateCalculation(request);

            // Assert
            result
            .Should()
            .BeOfType <BadRequestObjectResult>();
        }
        public async Task CreateCalculation_GivenValidModelButNoPolicyFound_ReturnsPreconditionFailed()
        {
            //Arrange
            Specification specification = new Specification()
            {
                Current = new SpecificationVersion(),
            };

            CalculationCreateModel model = new CalculationCreateModel
            {
                SpecificationId = SpecificationId,
                PolicyId        = PolicyId
            };

            string json = JsonConvert.SerializeObject(model);

            byte[]       byteArray = Encoding.UTF8.GetBytes(json);
            MemoryStream stream    = new MemoryStream(byteArray);

            HttpRequest request = Substitute.For <HttpRequest>();

            request
            .Body
            .Returns(stream);

            ILogger logger = CreateLogger();

            ISpecificationsRepository specificationsRepository = CreateSpecificationsRepository();

            specificationsRepository
            .GetSpecificationById(Arg.Is(SpecificationId))
            .Returns(specification);

            Calculation calculation = new Calculation();
            IMapper     mapper      = CreateMapper();

            mapper
            .Map <Calculation>(model)
            .Returns(calculation);

            SpecificationsService service = CreateService(logs: logger, specificationsRepository: specificationsRepository, mapper: mapper);

            //Act
            IActionResult result = await service.CreateCalculation(request);

            //Assert
            result
            .Should()
            .BeOfType <PreconditionFailedResult>()
            .Which
            .Value
            .Should()
            .Be("Policy not found for policy id 'dda8ccb3-eb8e-4658-8b3f-f1e4c3a8f322'");

            logger
            .Received(1)
            .Warning($"Policy not found for policy id '{PolicyId}'");
        }
예제 #11
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");
        }
예제 #12
0
        public async Task CreateCalculation()
        {
            string id = NewRandomString();

            CalculationCreateModel calculationCreateModel = new CalculationCreateModel();

            await AssertPostRequest($"specifications/{id}/calculations",
                                    calculationCreateModel,
                                    new Calculation(),
                                    () => _client.CreateCalculation(id, calculationCreateModel));
        }
        public async Task <ValidatedApiResponse <Calculation> > CreateCalculation(
            string specificationId,
            CalculationCreateModel calculationCreateModel,
            bool skipCalcRun,
            bool skipQueueCodeContextCacheUpdate,
            bool overrideCreateModelAuthor,
            bool updateBuildProject)
        {
            Guard.IsNullOrWhiteSpace(specificationId, nameof(specificationId));
            Guard.ArgumentNotNull(calculationCreateModel, nameof(calculationCreateModel));

            string url = $"{UrlRoot}/specifications/{specificationId}/calculations/{skipCalcRun}/{skipQueueCodeContextCacheUpdate}/{overrideCreateModelAuthor}/{updateBuildProject}";

            return(await ValidatedPostAsync <Calculation, CalculationCreateModel>(url, calculationCreateModel));
        }
예제 #14
0
        public async Task CreateAdditionalCalculation_GivenSavingDraftCalcFails_ReturnsInternalServerErrorResult()
        {
            //Arrange
            string correlationId = "any-id";

            CalculationCreateModel model = CreateCalculationCreateModel();

            Reference author = CreateAuthor();

            ICalculationsRepository calculationsRepository = CreateCalculationsRepository();

            calculationsRepository
            .CreateDraftCalculation(Arg.Any <Calculation>())
            .Returns(HttpStatusCode.BadRequest);

            ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient();

            specificationsApiClient
            .GetSpecificationSummaryById(Arg.Is(SpecificationId))
            .Returns(new ApiResponse <SpecificationSummary>(
                         HttpStatusCode.OK,
                         new SpecificationSummary {
                Id = SpecificationId
            }
                         ));

            ILogger logger = CreateLogger();

            CalculationService calculationService = CreateCalculationService(logger: logger, calculationsRepository: calculationsRepository, specificationsApiClient: specificationsApiClient);

            string errorMessage = $"There was problem creating a new calculation with name {CalculationName} in Cosmos Db with status code 400";

            //Act
            IActionResult result = await calculationService.CreateAdditionalCalculation(SpecificationId, model, author, correlationId);

            //Assert
            result
            .Should()
            .BeAssignableTo <InternalServerErrorResult>()
            .Which
            .Value
            .Should()
            .Be(errorMessage);

            logger
            .Received(1)
            .Error(Arg.Is(errorMessage));
        }
예제 #15
0
        public async Task CreateCalculationWithSkipParameters()
        {
            string id = NewRandomString();

            CalculationCreateModel calculationCreateModel = new CalculationCreateModel();

            bool skipCalcRun = NewRandomBoolean();
            bool skipQueueCodeContextCacheUpdate = NewRandomBoolean();
            bool overrideCreateModelAuthor       = NewRandomBoolean();
            bool updateBuildProject = NewRandomBoolean();

            await AssertPostRequest($"specifications/{id}/calculations/{skipCalcRun}/{skipQueueCodeContextCacheUpdate}/{overrideCreateModelAuthor}/{updateBuildProject}",
                                    calculationCreateModel,
                                    new Calculation(),
                                    () => _client.CreateCalculation(id, calculationCreateModel, skipCalcRun, skipQueueCodeContextCacheUpdate, overrideCreateModelAuthor, updateBuildProject));
        }
예제 #16
0
        private async Task GenerateCalculations(SpecGeneratorConfiguration configuration, Specification specification)
        {
            int totalCalculations = 0;

            if (configuration.NumberOfCalculations > 0)
            {
                totalCalculations = configuration.NumberOfCalculations;
            }

            List <Policy> policies = new List <Policy>(specification.Policies);

            List <AllocationLine> allocationLines = new List <AllocationLine>();

            _logger.Information("Generating {totalCalculations} calculations across {Count} policies", totalCalculations, policies.Count);

            foreach (FundingStream fundingStream in specification.FundingStreams)
            {
                foreach (AllocationLine allocationLine in fundingStream.AllocationLines)
                {
                    allocationLines.Add(allocationLine);
                }
            }

            IEnumerable <string> allocationLineNames = allocationLines.Select(a => a.Name);

            _logger.Information("Creating calculations in the following Allocation Lines {allocationLineNames}", allocationLineNames);

            for (int i = 0; i < totalCalculations; i++)
            {
                Policy         policy         = policies[i % policies.Count];
                AllocationLine allocationLine = allocationLines[i % allocationLines.Count];

                CalculationCreateModel calculationCreateModel = new CalculationCreateModel()
                {
                    SpecificationId  = specification.Id,
                    PolicyId         = policy.Id,
                    AllocationLineId = allocationLine.Id,
                    CalculationType  = CalculationSpecificationType.Funding,
                    Description      = "SpecGenerator",
                    Name             = $"{specification.Name} - Calculation {i + 1}",
                    IsPublic         = false,
                };

                await _specsClient.CreateCalculation(calculationCreateModel);
            }
        }
        public void ValidateWithSpecificationAndFundingStreams_ValidatesAsExpected(CalculationCreateModel model,
                                                                                   Specification specification,
                                                                                   IEnumerable <FundingStream> fundingStreams,
                                                                                   bool expectedResult,
                                                                                   IEnumerable <string> expectedErrors)
        {
            //Arrange
            ISpecificationsRepository specsRepo = CreateSpecificationsRepository(false);

            specsRepo
            .GetSpecificationById(specificationId)
            .Returns(specification);

            specsRepo
            .GetFundingStreams()
            .Returns(fundingStreams);

            CalculationCreateModelValidator validator = CreateValidator(specsRepo);

            //Act
            ValidationResult result = validator.Validate(model);

            //Assert
            result
            .IsValid
            .Should()
            .Be(expectedResult);

            foreach (var error in expectedErrors)
            {
                result
                .Errors
                .Select(e => e.ErrorMessage)
                .Distinct()
                .Count(e => e == error)
                .Should()
                .Be(1, $"Expected to find error message '{error}'");
            }

            result
            .Errors
            .Count
            .Should()
            .Be(expectedErrors.Count());
        }
        public void Validate_GivenNameAlreadyExists_ValidIsFalse()
        {
            //Arrange
            CalculationCreateModel model = CreateModel();

            ISpecificationsRepository repository    = CreateSpecificationsRepository(true);
            Specification             specification = new Specification
            {
                Current = new SpecificationVersion()
            };

            repository
            .GetSpecificationById(specificationId)
            .Returns(specification);

            ICalculationsRepository calculationsRepository = Substitute.For <ICalculationsRepository>();

            calculationsRepository
            .IsCalculationNameValid(Arg.Any <string>(), Arg.Any <string>(), Arg.Any <string>())
            .Returns(false);

            CalculationCreateModelValidator validator = CreateValidator(repository, calculationsRepository);

            //Act
            ValidationResult result = validator.Validate(model);

            //Assert
            result
            .IsValid
            .Should()
            .BeFalse();

            result
            .Errors
            .Count
            .Should()
            .Be(1);

            result.Errors.Single().ErrorMessage.Should().Be("Calculation with the same generated source code name already exists in this specification");

            calculationsRepository
            .Received(1)
            .IsCalculationNameValid(specificationId, name);
        }
예제 #19
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 CreateCalculation_GivenValidModelButSpecificationcannotBeFoundd_ReturnsPreconditionFailed()
        {
            //Arrange
            CalculationCreateModel model = new CalculationCreateModel
            {
                SpecificationId = SpecificationId
            };

            string json = JsonConvert.SerializeObject(model);

            byte[]       byteArray = Encoding.UTF8.GetBytes(json);
            MemoryStream stream    = new MemoryStream(byteArray);

            HttpRequest request = Substitute.For <HttpRequest>();

            request
            .Body
            .Returns(stream);

            ILogger logger = CreateLogger();

            ISpecificationsRepository specificationsRepository = CreateSpecificationsRepository();

            specificationsRepository
            .GetSpecificationById(Arg.Is(SpecificationId))
            .Returns((Specification)null);

            SpecificationsService service = CreateService(logs: logger, specificationsRepository: specificationsRepository);

            //Act
            IActionResult result = await service.CreateCalculation(request);

            //Assert
            result
            .Should()
            .BeOfType <PreconditionFailedResult>();

            logger
            .Received(1)
            .Warning($"Specification not found for specification id {SpecificationId}");
        }
예제 #21
0
        public async Task ValidateAsync_WhenSpecificationIsEmpty_ValidIsFalse()
        {
            //Arrange
            CalculationCreateModel model = CreateModel();

            model.SpecificationId = string.Empty;

            CalculationCreateModelValidator validator = CreateValidator();

            //Act
            ValidationResult result = await validator.ValidateAsync(model);

            //Assert
            result
            .IsValid
            .Should()
            .BeFalse();

            result.Errors
            .Should()
            .Contain(_ => _.ErrorMessage == "'Specification Id' must not be empty.");
        }
예제 #22
0
        public async Task ValidateAsync_WhenNameIsEmpty_ValidIsFalse()
        {
            //Arrange
            CalculationCreateModel model = CreateModel();

            model.Name = string.Empty;

            CalculationCreateModelValidator validator = CreateValidator();

            //Act
            ValidationResult result = await validator.ValidateAsync(model);

            //Assert
            result
            .IsValid
            .Should()
            .BeFalse();

            result.Errors
            .Should()
            .Contain(_ => _.ErrorMessage == "Null or empty calculation name provided.");
        }
예제 #23
0
        public async Task ValidateAsync_WhenValueTypeIsMissing_ValidIsFalse()
        {
            //Arrange
            CalculationCreateModel model = CreateModel();

            model.ValueType = null;

            CalculationCreateModelValidator validator = CreateValidator();

            //Act
            ValidationResult result = await validator.ValidateAsync(model);

            //Assert
            result
            .IsValid
            .Should()
            .BeFalse();

            result.Errors
            .Should()
            .Contain(_ => _.ErrorMessage == "Null value type was provided.");
        }
        public async Task CreateCalculation_GivenModelButModelIsNotValid_ReturnsBadRequest()
        {
            //Arrange
            CalculationCreateModel model = new CalculationCreateModel();

            string json = JsonConvert.SerializeObject(model);

            byte[]       byteArray = Encoding.UTF8.GetBytes(json);
            MemoryStream stream    = new MemoryStream(byteArray);

            HttpRequest request = Substitute.For <HttpRequest>();

            request
            .Body
            .Returns(stream);

            ValidationResult validationResult = new ValidationResult(new[] {
                new ValidationFailure("prop1", "any error")
            });

            IValidator <CalculationCreateModel> validator = CreateCalculationValidator(validationResult);

            ILogger logger = CreateLogger();

            SpecificationsService service = CreateService(logs: logger, calculationCreateModelValidator: validator);

            //Act
            IActionResult result = await service.CreateCalculation(request);

            //Assert
            result
            .Should()
            .BeOfType <BadRequestObjectResult>();

            logger
            .Received(1)
            .Error("Invalid data was provided for CreateCalculation");
        }
예제 #25
0
        public async Task ValidateAsync_WhenFundingStreamIdEmptyForAdditionalCalcs_ValidIsTrue()
        {
            //Arrange
            CalculationCreateModel model = CreateModel(CalculationType.Additional);

            model.FundingStreamId = string.Empty;

            ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient();

            specificationsApiClient
            .GetSpecificationSummaryById(Arg.Is(model.SpecificationId))
            .Returns(new Common.ApiClient.Models.ApiResponse <SpecModel.SpecificationSummary>(HttpStatusCode.OK, new SpecModel.SpecificationSummary()));

            CalculationCreateModelValidator validator = CreateValidator(specificationsApiClient: specificationsApiClient);

            //Act
            ValidationResult result = await validator.ValidateAsync(model);

            //Assert
            result
            .IsValid
            .Should()
            .BeTrue();
        }
        public void OnPostAsync_GivenCalculationDoesNotAlreadyExistButSavingIsNotOK_InvalidOperationException()
        {
            //Arrange
            CreateCalculationViewModel viewModel = new CreateCalculationViewModel
            {
                Name = "any name"
            };

            Specification specification = CreateSpecification();

            IEnumerable <Reference> allocationLines = new[]
            {
                new Reference
                {
                    Id   = "alloc-id",
                    Name = "alloc-name"
                }
            };

            CalculationCreateModel createModel = new CalculationCreateModel
            {
                SpecificationId = specificationId
            };

            IMapper mapper = CreateMapper();

            mapper
            .Map <CalculationCreateModel>(Arg.Is(viewModel))
            .Returns(createModel);

            ApiResponse <Calculation> calcApiRespnse = new ApiResponse <Calculation>(HttpStatusCode.NotFound);

            ValidatedApiResponse <Calculation> newCalcApiResponse = new ValidatedApiResponse <Calculation>(HttpStatusCode.InternalServerError, new Calculation
            {
                Id = "new-calc-id",
            });

            newCalcApiResponse.ModelState = new Dictionary <string, IEnumerable <string> >();

            ISpecsApiClient specsClient = CreateSpecsApiClient();

            specsClient
            .GetCalculationBySpecificationIdAndCalculationName(Arg.Is(specificationId), Arg.Is(viewModel.Name))
            .Returns(calcApiRespnse);

            specsClient
            .CreateCalculation(Arg.Is(createModel))
            .Returns(newCalcApiResponse);

            List <FundingStream> fundingStreams = new List <FundingStream>();

            fundingStreams.Add(new FundingStream
            {
                Id = fundingStreamId,
                AllocationLines = new List <AllocationLine>()
                {
                    new AllocationLine()
                    {
                        Id   = "al1",
                        Name = "Allocation Line 1",
                    }
                }
            });

            ApiResponse <IEnumerable <FundingStream> > fundingStreamResponse = new ApiResponse <IEnumerable <FundingStream> >(HttpStatusCode.OK, fundingStreams);

            specsClient
            .GetFundingStreamsForSpecification(Arg.Is(specification.Id))
            .Returns(fundingStreamResponse);

            specsClient
            .GetBaselineCalculationsBySpecificationId(Arg.Is(specificationId))
            .Returns(new ApiResponse <IEnumerable <CalculationCurrentVersion> >(HttpStatusCode.OK, Enumerable.Empty <CalculationCurrentVersion>()));

            specsClient.GetSpecification(Arg.Is(specificationId))
            .Returns(new ApiResponse <Specification>(HttpStatusCode.OK, specification));

            CreateCalculationPageModel pageModel = CreatePageModel(specsClient, mapper);

            pageModel.PageContext = new PageContext();

            pageModel.CreateCalculationViewModel = viewModel;

            //Act
            Func <Task> test = async() => await pageModel.OnPostAsync(specificationId);

            //Assert
            test
            .Should()
            .ThrowExactly <InvalidOperationException>();
        }
예제 #27
0
        public async Task <ValidatedApiResponse <Calculation> > CreateCalculation(string specificationId, CalculationCreateModel calculationCreateModel)
        {
            Guard.IsNullOrWhiteSpace(specificationId, nameof(specificationId));
            Guard.ArgumentNotNull(calculationCreateModel, nameof(calculationCreateModel));

            string url = $"{UrlRoot}/specifications/{specificationId}/calculations";

            return(await ValidatedPostAsync <Calculation, CalculationCreateModel>(url, calculationCreateModel));
        }
예제 #28
0
        public Task <ApiResponse <Calculation> > CreateCalculation(CalculationCreateModel calculation)
        {
            Guard.ArgumentNotNull(calculation, nameof(calculation));

            return(PostAsync <Calculation, CalculationCreateModel>("calculations", calculation));
        }
        public async Task <IActionResult> OnPostAsync(string specificationId)
        {
            Guard.IsNullOrWhiteSpace(specificationId, nameof(specificationId));

            Specification specification = await GetSpecification(specificationId);

            if (!await _authorizationHelper.DoesUserHavePermission(User, specification, SpecificationActionTypes.CanEditSpecification))
            {
                return(new ForbidResult());
            }

            if (!string.IsNullOrWhiteSpace(CreateCalculationViewModel.Name))
            {
                ApiResponse <Calculation> existingCalculationResponse = await _specsClient
                                                                        .GetCalculationBySpecificationIdAndCalculationName(specificationId, CreateCalculationViewModel.Name);

                if (existingCalculationResponse.StatusCode != HttpStatusCode.NotFound)
                {
                    this.ModelState.AddModelError($"{nameof(CreateCalculationViewModel)}.{nameof(CreateCalculationViewModel.Name)}", ValidationMessages.CalculationNameAlreadyExists);
                }
            }

            if (CreateCalculationViewModel.CalculationType == "Funding" && string.IsNullOrWhiteSpace(CreateCalculationViewModel.AllocationLineId))
            {
                this.ModelState.AddModelError($"{nameof(CreateCalculationViewModel)}.{nameof(CreateCalculationViewModel.AllocationLineId)}", ValidationMessages.CalculationAllocationLineRequired);
            }

            if (!ModelState.IsValid)
            {
                SpecificationName = specification.Name;
                SpecificationId   = specificationId;
                FundingPeriodName = specification.FundingPeriod.Name;
                FundingPeriodId   = specification.FundingPeriod.Id;

                return(await PopulateForm(specification));
            }

            CalculationCreateModel calculation = _mapper.Map <CalculationCreateModel>(CreateCalculationViewModel);

            calculation.SpecificationId = specificationId;

            ValidatedApiResponse <Calculation> newCalculationResponse = await _specsClient.CreateCalculation(calculation);

            if (newCalculationResponse.StatusCode == HttpStatusCode.OK)
            {
                Calculation newCalculation = newCalculationResponse.Content;

                return(Redirect($"/specs/policies/{specificationId}?operationType=CalculationCreated&operationId={newCalculation.Id}"));
            }
            else if (newCalculationResponse.StatusCode == HttpStatusCode.BadRequest)
            {
                newCalculationResponse.AddValidationResultErrors(ModelState);

                SpecificationName = specification.Name;
                SpecificationId   = specificationId;
                FundingPeriodName = specification.FundingPeriod.Name;
                FundingPeriodId   = specification.FundingPeriod.Id;

                return(await PopulateForm(specification));
            }
            else
            {
                throw new InvalidOperationException($"Unable to create calculation specifications. Status Code = {newCalculationResponse.StatusCode}");
            }
        }
예제 #30
0
        public async Task CreateAdditionalCalculation_GivenCalcSaves_ReturnsOKObjectResult()
        {
            //Arrange
            string cacheKey = $"{CacheKeys.CalculationsMetadataForSpecification}{SpecificationId}";

            CalculationCreateModel model = CreateCalculationCreateModel();

            Reference author = CreateAuthor();

            ICalculationsRepository calculationsRepository = CreateCalculationsRepository();

            calculationsRepository
            .CreateDraftCalculation(Arg.Any <Calculation>())
            .Returns(HttpStatusCode.OK);

            IVersionRepository <CalculationVersion> versionRepository = CreateCalculationVersionRepository();

            ISearchRepository <CalculationIndex> searchRepository = CreateSearchRepository();

            IJobManagement jobManagement = CreateJobManagement();

            jobManagement
            .QueueJob(Arg.Any <JobCreateModel>())
            .Returns(new Job {
                Id = "job-id-1"
            });

            ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient();

            specificationsApiClient
            .GetSpecificationSummaryById(Arg.Is(SpecificationId))
            .Returns(new ApiResponse <SpecificationSummary>(
                         HttpStatusCode.OK,
                         new SpecificationSummary {
                Id            = SpecificationId,
                FundingPeriod = new FundingPeriod {
                    Id = FundingPeriodId
                }
            }
                         ));

            ILogger logger = CreateLogger();

            ICacheProvider cacheProvider = CreateCacheProvider();

            ICodeContextCache codeContextCache = Substitute.For <ICodeContextCache>();

            IResultsApiClient resultsApiClient = CreateResultsApiClient();

            CalculationService calculationService = CreateCalculationService(
                calculationsRepository: calculationsRepository,
                calculationVersionRepository: versionRepository,
                searchRepository: searchRepository,
                jobManagement: jobManagement,
                logger: logger,
                cacheProvider: cacheProvider,
                specificationsApiClient: specificationsApiClient,
                codeContextCache: codeContextCache,
                resultsApiClient: resultsApiClient);

            IEnumerable <CalculationIndex> indexedCalculations = null;

            await
            searchRepository
            .Index(Arg.Do <IEnumerable <CalculationIndex> >(m =>
                                                            indexedCalculations = m
                                                            ));

            CalculationVersion savedCalculationVersion = null;

            await
            versionRepository
            .SaveVersion(Arg.Do <CalculationVersion>(m => savedCalculationVersion = m));

            //Act
            IActionResult result = await calculationService.CreateAdditionalCalculation(SpecificationId, model, author, CorrelationId);

            //Assert
            result
            .Should()
            .BeAssignableTo <OkObjectResult>();

            Calculation calculation = (result as OkObjectResult).Value as Calculation;

            await
            jobManagement
            .Received(1)
            .QueueJob(Arg.Is <JobCreateModel>(
                          m =>
                          m.InvokerUserDisplayName == Username &&
                          m.InvokerUserId == UserId &&
                          m.JobDefinitionId == JobConstants.DefinitionNames.CreateInstructAllocationJob &&
                          m.Properties["specification-id"] == SpecificationId
                          ));

            logger
            .Received(1)
            .Information(Arg.Is($"New job of type '{JobConstants.DefinitionNames.CreateInstructAllocationJob}' created with id: 'job-id-1'"));


            await
            versionRepository
            .Received(1)
            .SaveVersion(Arg.Is <CalculationVersion>(m =>
                                                     m.PublishStatus == Models.Versioning.PublishStatus.Draft &&
                                                     m.Author.Id == UserId &&
                                                     m.Author.Name == Username &&
                                                     m.Date.Date == DateTimeOffset.Now.Date &&
                                                     m.Version == 1 &&
                                                     m.SourceCode == model.SourceCode &&
                                                     m.Description == model.Description &&
                                                     m.ValueType == model.ValueType &&
                                                     m.CalculationType == CalculationType.Additional &&
                                                     m.WasTemplateCalculation == false &&
                                                     m.Namespace == CalculationNamespace.Additional &&
                                                     m.Name == model.Name &&
                                                     m.SourceCodeName == new VisualBasicTypeIdentifierGenerator().GenerateIdentifier(model.Name) &&
                                                     m.DataType == CalculationDataType.Decimal
                                                     ));


            await searchRepository
            .Received(1)
            .Index(Arg.Any <IEnumerable <CalculationIndex> >());

            indexedCalculations
            .Should()
            .BeEquivalentTo(new List <CalculationIndex>()
            {
                new CalculationIndex()
                {
                    CalculationType   = "Additional",
                    Description       = "test description",
                    FundingStreamId   = "fs-1",
                    FundingStreamName = model.FundingStreamName,
                    Id                     = model.Id,
                    Name                   = model.Name,
                    Namespace              = "Additional",
                    SpecificationId        = "spec-id-1",
                    SpecificationName      = "spec-id-1_specificationName",
                    Status                 = "Draft",
                    ValueType              = "Currency",
                    WasTemplateCalculation = false,
                    LastUpdatedDate        = savedCalculationVersion.Date,
                }
            });

            //!string.IsNullOrWhiteSpace(m.First().Id) &&
            //m.First().Name == model.Name &&
            //m.First().SpecificationId == SpecificationId &&
            //m.First().SpecificationName == model.SpecificationName &&
            //m.First().ValueType == model.ValueType.ToString() &&
            //m.First().CalculationType == CalculationType.Additional.ToString() &&
            //m.First().Namespace == CalculationNamespace.Additional.ToString() &&
            //m.First().FundingStreamId == model.FundingStreamId &&
            //m.First().FundingStreamName == model.FundingStreamName &&
            //m.First().WasTemplateCalculation == false &&
            //m.First().Description == model.Description &&
            //m.First().Status == calculation.Current.PublishStatus.ToString()

            await
            cacheProvider
            .Received(1)
            .RemoveAsync <List <CalculationMetadata> >(Arg.Is(cacheKey));

            await codeContextCache
            .Received(1)
            .QueueCodeContextCacheUpdate(SpecificationId);
        }