示例#1
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.");
        }
示例#2
0
        public async Task RunTests_GivenNoTestResults_LogsAndreturnsEmptyResults()
        {
            //Arrange
            IEnumerable <ProviderResult> providerResults = new[] { new ProviderResult {
                                                                       Provider = new ProviderSummary {
                                                                           Id = ProviderId
                                                                       }, SpecificationId = SpecificationId
                                                                   } };
            IEnumerable <TestScenario>          scenarios = new[] { new TestScenario() };
            IEnumerable <ProviderSourceDataset> providerSourceDatasets = new ProviderSourceDataset[0];
            IEnumerable <TestScenarioResult>    testScenarioResults    = new TestScenarioResult[0];

            SpecModel.SpecificationSummary specificationSummary = new SpecModel.SpecificationSummary();
            BuildProject buildProject = new BuildProject();

            ILogger logger = CreateLogger();

            TestEngine testEngine = CreateTestEngine(logger: logger);

            //Act
            IEnumerable <TestScenarioResult> results = await testEngine.RunTests(scenarios, providerResults, providerSourceDatasets,
                                                                                 testScenarioResults, specificationSummary, buildProject);

            results
            .Count()
            .Should()
            .Be(0);

            logger
            .Received(1)
            .Warning(Arg.Is($"No test results generated for provider: {ProviderId} on specification: {SpecificationId}"));
        }
示例#3
0
 private async Task UpdateSearch(IEnumerable <Calculation> calculations, SpecModel.SpecificationSummary specificationSummary)
 {
     await _searchRepository.Index(calculations.Select(_ =>
     {
         return(CreateCalculationIndexItem(_, specificationSummary));
     }));
 }
示例#4
0
        public async Task RunTests_GivenNoProviders_LogsAndreturnsEmptyResults()
        {
            //Arrange
            IEnumerable <ProviderResult>        providerResults        = new ProviderResult[0];
            IEnumerable <TestScenario>          scenarios              = new TestScenario[0];
            IEnumerable <ProviderSourceDataset> providerSourceDatasets = new ProviderSourceDataset[0];
            IEnumerable <TestScenarioResult>    testScenarioResults    = new TestScenarioResult[0];

            SpecModel.SpecificationSummary specificationSummary = new SpecModel.SpecificationSummary();
            BuildProject buildProject = new BuildProject();

            ILogger logger = CreateLogger();

            TestEngine testEngine = CreateTestEngine(logger: logger);

            //Act
            IEnumerable <TestScenarioResult> results = await testEngine.RunTests(scenarios, providerResults, providerSourceDatasets,
                                                                                 testScenarioResults, specificationSummary, buildProject);

            results
            .Count()
            .Should()
            .Be(0);

            logger
            .Received(1)
            .Warning(Arg.Is("No provider results were supplied to execute tests"));
        }
        public async Task <bool?> IsCalculationNameInUse(string specificationId, string calculationName, string existingCalculationId)
        {
            Guard.IsNullOrWhiteSpace(specificationId, nameof(specificationId));
            Guard.IsNullOrWhiteSpace(calculationName, nameof(calculationName));

            ApiResponse <SpecModel.SpecificationSummary> specificationApiResponse = await _specificationsApiClientPolicy.ExecuteAsync(() => _specificationsApiClient.GetSpecificationSummaryById(specificationId));

            if (specificationApiResponse == null || !specificationApiResponse.StatusCode.IsSuccess() || specificationApiResponse.Content == null)
            {
                return(null);
            }

            SpecModel.SpecificationSummary specification = specificationApiResponse.Content;

            IEnumerable <Calculation> existingCalculations = await _calculationRepositoryPolicy.ExecuteAsync(() => _calculationsRepository.GetCalculationsBySpecificationId(specificationId));

            if (!existingCalculations.IsNullOrEmpty())
            {
                string calcSourceName = _typeIdentifierGenerator.GenerateIdentifier(calculationName);

                foreach (Calculation calculation in existingCalculations)
                {
                    if (calculation.Id != existingCalculationId && string.Compare(calculation.Current.SourceCodeName, calcSourceName, true) == 0)
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
示例#6
0
        private async Task UpdateCalculationsInCache(SpecModel.SpecificationSummary specificationSummary)
        {
            // Invalidate cached calculations for this specification
            await _cachePolicy.ExecuteAsync(() => _cacheProvider.KeyDeleteAsync <List <CalculationSummaryModel> >($"{CacheKeys.CalculationsSummariesForSpecification}{specificationSummary.Id}"));

            await _cachePolicy.ExecuteAsync(() => _cacheProvider.KeyDeleteAsync <List <CalculationResponseModel> >($"{CacheKeys.CurrentCalculationsForSpecification}{specificationSummary.Id}"));

            await _cachePolicy.ExecuteAsync(() => _cacheProvider.KeyDeleteAsync <List <CalculationResponseModel> >($"{CacheKeys.CalculationsMetadataForSpecification}{specificationSummary.Id}"));
        }
示例#7
0
        public async Task ApproveAllCalculations_CalcExistsOnGivenSpecification_UpdateBulkPublishStatus()
        {
            ApproveAllCalculationsService approveAllCalculationsService = BuildApproveAllCalculationsService();

            GivenTheOtherwiseValidMessage();

            IEnumerable <Calculation> calculations = new List <Calculation> {
                NewCalculation(c => c.WithId("calc_1").WithFundingStreamId(_fundingStreamId).WithCurrentVersion(NewCalculationVersion(cv => cv.WithPublishStatus(PublishStatus.Draft)))),
                NewCalculation(c => c.WithId("calc_2").WithFundingStreamId(_fundingStreamId).WithCurrentVersion(NewCalculationVersion(cv => cv.WithPublishStatus(PublishStatus.Updated))))
            };

            _calculationsRepositoryMock
            .Setup(_ => _.GetCalculationsBySpecificationId(_specificationId))
            .ReturnsAsync(calculations);

            SpecModel.SpecificationSummary specificationSummary = new SpecModel.SpecificationSummary()
            {
                Id             = _specificationId,
                Name           = "spec name",
                FundingStreams = new[]
                {
                    new Reference(_fundingStreamId, "funding stream name")
                }
            };

            _specificationsApiClientMock
            .Setup(_ => _.GetSpecificationSummaryById(_specificationId))
            .ReturnsAsync(new Common.ApiClient.Models.ApiResponse <SpecModel.SpecificationSummary>(HttpStatusCode.OK, specificationSummary));

            await approveAllCalculationsService.Process(_message);

            _cacheProviderMock.Verify(_ => _.KeyDeleteAsync <List <CalculationSummaryModel> >($"{CacheKeys.CalculationsSummariesForSpecification}{_specificationId}")
                                      , Times.Once);

            _cacheProviderMock.Verify(_ => _.KeyDeleteAsync <List <CalculationResponseModel> >($"{CacheKeys.CurrentCalculationsForSpecification}{_specificationId}")
                                      , Times.Once);

            _cacheProviderMock.Verify(_ => _.KeyDeleteAsync <List <CalculationResponseModel> >($"{CacheKeys.CalculationsMetadataForSpecification}{_specificationId}")
                                      , Times.Once);

            _cacheProviderMock.Verify(_ => _.SetAsync($"{CacheKeys.CurrentCalculation}calc_1", It.IsAny <CalculationResponseModel>(), TimeSpan.FromDays(7), true, null)
                                      , Times.Once);

            _cacheProviderMock.Verify(_ => _.SetAsync($"{CacheKeys.CurrentCalculation}calc_2", It.IsAny <CalculationResponseModel>(), TimeSpan.FromDays(7), true, null)
                                      , Times.Once);

            _searchRepositoryMock.Verify(_ => _.Index(It.Is <IEnumerable <CalculationIndex> >(c =>
                                                                                              c.FirstOrDefault() != null && c.FirstOrDefault().Status == PublishStatus.Approved.ToString() &&
                                                                                              c.LastOrDefault() != null && c.LastOrDefault().Status == PublishStatus.Approved.ToString()))
                                         , Times.Once);

            _calculationsRepositoryMock
            .Verify(_ => _.UpdateCalculations(
                        It.Is <IEnumerable <Calculation> >(c =>
                                                           c.FirstOrDefault() != null && c.FirstOrDefault().Current.PublishStatus == PublishStatus.Approved &&
                                                           c.LastOrDefault() != null && c.LastOrDefault().Current.PublishStatus == PublishStatus.Approved)), Times.Once);
        }
示例#8
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");
        }
示例#9
0
        public async Task RunTests_GivenTestResultsReturnedFromExecutorWhereNoStepsExecuted_ReturnsOneIgnoreTestResult()
        {
            //Arrange
            ProviderResult providerResult = new ProviderResult {
                Provider = new ProviderSummary {
                    Id = ProviderId, Name = "any provider"
                }, SpecificationId = SpecificationId
            };

            IEnumerable <ProviderResult>        providerResults        = new[] { providerResult };
            IEnumerable <TestScenario>          scenarios              = new[] { new TestScenario() };
            IEnumerable <ProviderSourceDataset> providerSourceDatasets = new ProviderSourceDataset[0];
            IEnumerable <TestScenarioResult>    testScenarioResults    = new TestScenarioResult[0];

            SpecModel.SpecificationSummary specificationSummary = new SpecModel.SpecificationSummary {
                Id = SpecificationId, Name = "spec-name"
            };

            BuildProject buildProject = new BuildProject();

            IEnumerable <ScenarioResult> scenarioResults = new[]
            {
                new ScenarioResult  {
                    Scenario = new Reference("sceanrio=id", "scenario name")
                }
            };

            ILogger logger = CreateLogger();

            IGherkinExecutor gherkinExecutor = CreateGherkinExecutor();

            gherkinExecutor
            .Execute(Arg.Any <ProviderResult>(), Arg.Any <IEnumerable <ProviderSourceDataset> >(), Arg.Any <IEnumerable <TestScenario> >(), Arg.Any <BuildProject>())
            .Returns(scenarioResults);

            TestEngine testEngine = CreateTestEngine(gherkinExecutor, logger);

            //Act
            IEnumerable <TestScenarioResult> results = await testEngine.RunTests(scenarios, providerResults, providerSourceDatasets,
                                                                                 testScenarioResults, specificationSummary, buildProject);

            results
            .Count()
            .Should()
            .Be(1);

            results
            .First()
            .TestResult
            .Should()
            .Be(TestResult.Ignored);
        }
        public async Task QueryMethodDelegatesToApiClientAndReturnsContentFromResponse()
        {
            string specificationId = new RandomString();
            ApiSpecificationSummary expectedSpecificationSummary = new ApiSpecificationSummary();

            GivenTheApiResponseContentForTheSpecificationId(expectedSpecificationSummary, specificationId);

            ApiSpecificationSummary specificationSummary = await WhenTheSpecificationSummaryIsQueried(specificationId);

            specificationSummary
            .Should()
            .BeSameAs(expectedSpecificationSummary);
        }
        public async Task <IActionResult> ReIndex()
        {
            IEnumerable <DocumentEntity <TestScenario> > testScenarios = await _scenariosRepository.GetAllTestScenarios();

            List <ScenarioIndex> testScenarioIndexes = new List <ScenarioIndex>();

            Dictionary <string, SpecModel.SpecificationSummary> specifications = new Dictionary <string, SpecModel.SpecificationSummary>();

            foreach (DocumentEntity <TestScenario> entity in testScenarios)
            {
                TestScenario testScenario = entity.Content;

                SpecModel.SpecificationSummary specificationSummary = null;
                if (!specifications.ContainsKey(testScenario.SpecificationId))
                {
                    Common.ApiClient.Models.ApiResponse <SpecModel.SpecificationSummary> specificationApiResponse =
                        await _specificationsApiClientPolicy.ExecuteAsync(() => _specificationsApiClient.GetSpecificationSummaryById(testScenario.SpecificationId));

                    specificationSummary = specificationApiResponse.Content;

                    specifications.Add(testScenario.SpecificationId, specificationSummary);
                }
                else
                {
                    specificationSummary = specifications[testScenario.SpecificationId];
                }

                testScenarioIndexes.Add(new ScenarioIndex()
                {
                    Id                 = testScenario.Id,
                    Name               = testScenario.Name,
                    Description        = testScenario.Current.Description,
                    LastUpdatedDate    = entity.UpdatedAt,
                    FundingStreamIds   = testScenario.Current?.FundingStreamIds.ToArray(),
                    FundingStreamNames = specificationSummary.FundingStreams.Select(s => s.Name).ToArray(),
                    FundingPeriodId    = testScenario.Current?.FundingPeriodId,
                    FundingPeriodName  = specificationSummary.FundingPeriod.Name,
                    SpecificationId    = testScenario.SpecificationId,
                    SpecificationName  = specificationSummary.Name,
                    Status             = Enum.GetName(typeof(PublishStatus), testScenario.Current.PublishStatus),
                });
            }

            await _searchRepository.Index(testScenarioIndexes);

            return(new OkObjectResult($"Updated {testScenarioIndexes.Count} records"));
        }
示例#12
0
        public async Task GetEffectivePermissionsForUser_WhenNotFoundInCacheButSpecificationNotFound_ThenPreconditionFailedResultReturned()
        {
            // Arrange
            ICacheProvider cacheProvider = CreateCacheProvider();
            EffectiveSpecificationPermission cachedPermission = null;

            cacheProvider
            .GetHashValue <EffectiveSpecificationPermission>(Arg.Is($"{CacheKeys.EffectivePermissions}:{UserId}"), Arg.Is(SpecificationId))
            .Returns(cachedPermission);

            ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient();

            SpecModel.SpecificationSummary specificationSummary = null;
            specificationsApiClient
            .GetSpecificationSummaryById(Arg.Is(SpecificationId))
            .Returns(new ApiResponse <SpecModel.SpecificationSummary>(HttpStatusCode.OK, specificationSummary));


            FundingStreamPermissionService service = CreateService(
                specificationsApiClient: specificationsApiClient,
                cacheProvider: cacheProvider);


            // Act
            IActionResult result = await service.GetEffectivePermissionsForUser(UserId, SpecificationId);

            // Assert
            result
            .Should()
            .BeOfType <PreconditionFailedResult>()
            .Which
            .Value
            .Should()
            .Be("Specification not found");

            await cacheProvider
            .Received(1)
            .GetHashValue <EffectiveSpecificationPermission>(Arg.Is($"{CacheKeys.EffectivePermissions}:{UserId}"), Arg.Is(SpecificationId));

            await cacheProvider
            .Received(0)
            .SetHashValue(
                Arg.Is($"{CacheKeys.EffectivePermissions}:{UserId}"),
                Arg.Is(SpecificationId),
                Arg.Any <EffectiveSpecificationPermission>());
        }
        public async Task EditCalculationStatus_GivenNewStatusButUpdatingDbReturnsBadRequest_ReturnsStatusCode400()
        {
            //Arrange
            EditStatusModel CalculationEditStatusModel = new EditStatusModel
            {
                PublishStatus = PublishStatus.Approved
            };

            ILogger logger = CreateLogger();

            Calculation calculation = CreateCalculation();

            ICalculationsRepository CalculationsRepository = CreateCalculationsRepository();

            CalculationsRepository
            .GetCalculationById(Arg.Is(CalculationId))
            .Returns(calculation);

            CalculationsRepository
            .UpdateCalculation(Arg.Any <Calculation>())
            .Returns(HttpStatusCode.BadRequest);

            SpecModel.SpecificationSummary specificationSummary = new SpecModel.SpecificationSummary();

            ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient();

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


            CalculationService service = CreateCalculationService(
                logger: logger, calculationsRepository: CalculationsRepository, specificationsApiClient: specificationsApiClient);

            //Act
            IActionResult result = await service.UpdateCalculationStatus(CalculationId, CalculationEditStatusModel);

            //Arrange
            result
            .Should()
            .BeAssignableTo <StatusCodeResult>()
            .Which
            .StatusCode
            .Should()
            .Be(400);
        }
示例#14
0
        public override async Task Process(Message message)
        {
            Guard.ArgumentNotNull(message, nameof(message));

            string specificationId = UserPropertyFrom(message, "specification-id");

            IEnumerable <Calculation> calculations =
                (await _calculationRepositoryPolicy.ExecuteAsync(() =>
                                                                 _calculationsRepository.GetCalculationsBySpecificationId(specificationId)))
                .ToArraySafe();

            if (calculations.IsNullOrEmpty())
            {
                string calcNotFoundMessage = $"No calculations found for specification id: {specificationId}";

                _logger.Information(calcNotFoundMessage);

                return;
            }

            foreach (Calculation calculation in calculations)
            {
                calculation.Current.PublishStatus = Models.Versioning.PublishStatus.Approved;
            }

            ApiResponse <SpecModel.SpecificationSummary> specificationApiResponse =
                await _specificationsApiClientPolicy.ExecuteAsync(() => _specificationsApiClient.GetSpecificationSummaryById(specificationId));

            if (!specificationApiResponse.StatusCode.IsSuccess() || specificationApiResponse.Content == null)
            {
                throw new NonRetriableException("Specification not found");
            }

            SpecModel.SpecificationSummary specificationSummary = specificationApiResponse.Content;

            await _calculationRepositoryPolicy.ExecuteAsync(() => _calculationsRepository.UpdateCalculations(calculations));

            await UpdateSearch(calculations, specificationSummary);

            IEnumerable <Task> tasks = calculations.Select(_ => UpdateCalculationInCache(_.ToResponseModel()));

            await TaskHelper.WhenAllAndThrow(tasks.ToArraySafe());

            await UpdateCalculationsInCache(specificationSummary);
        }
示例#15
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");
        }
示例#16
0
 private CalculationIndex CreateCalculationIndexItem(Calculation calculation, SpecModel.SpecificationSummary specificationSummary)
 {
     return(new CalculationIndex
     {
         Id = calculation.Id,
         SpecificationId = calculation.SpecificationId,
         SpecificationName = specificationSummary.Name,
         Name = calculation.Current.Name,
         ValueType = calculation.Current.ValueType.ToString(),
         FundingStreamId = calculation.FundingStreamId ?? "N/A",
         FundingStreamName = specificationSummary.FundingStreams.FirstOrDefault(_ => _.Id == calculation.FundingStreamId)?.Name ?? "N/A",
         Namespace = calculation.Current.Namespace.ToString(),
         CalculationType = calculation.Current.CalculationType.ToString(),
         Description = calculation.Current.Description,
         WasTemplateCalculation = calculation.Current.WasTemplateCalculation,
         Status = calculation.Current.PublishStatus.ToString(),
         LastUpdatedDate = DateTimeOffset.Now
     });
 }
示例#17
0
        private static ISpecificationsApiClient CreateSpecificationsApiClient()
        {
            ISpecificationsApiClient specificationsApiClient = Substitute.For <ISpecificationsApiClient>();

            SpecModel.SpecificationSummary specificationSummary = new SpecModel.SpecificationSummary()
            {
                TemplateIds = new Dictionary <string, string> {
                    { "fs-1", "2.2" }
                },
                FundingStreams = new List <Reference>()
                {
                    new Reference("fs-1", "PE and Sports"),
                },
            };

            specificationsApiClient
            .GetSpecificationSummaryById(Arg.Any <string>())
            .Returns(new ApiResponse <SpecModel.SpecificationSummary>(HttpStatusCode.OK, specificationSummary));

            return(specificationsApiClient);
        }
        public async Task EditCalculationStatus_GivenCalculationIsApprovedButNewStatusIsDraft_UpdatesSearchReturnsOK()
        {
            //Arrange
            EditStatusModel CalculationEditStatusModel = new EditStatusModel
            {
                PublishStatus = PublishStatus.Draft
            };

            ILogger logger = CreateLogger();

            Calculation calculation = CreateCalculation();

            calculation.Current.PublishStatus = PublishStatus.Approved;

            ICalculationsRepository CalculationsRepository = CreateCalculationsRepository();

            CalculationsRepository
            .GetCalculationById(Arg.Is(CalculationId))
            .Returns(calculation);

            CalculationsRepository
            .UpdateCalculation(Arg.Any <Calculation>())
            .Returns(HttpStatusCode.OK);


            SpecModel.SpecificationSummary specificationSummary = new SpecModel.SpecificationSummary();

            ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient();

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

            ISearchRepository <CalculationIndex> searchRepository = CreateSearchRepository();

            CalculationService service = CreateCalculationService(
                logger: logger, calculationsRepository: CalculationsRepository, searchRepository: searchRepository, specificationsApiClient: specificationsApiClient);

            //Act
            IActionResult result = await service.UpdateCalculationStatus(CalculationId, CalculationEditStatusModel);

            //Arrange
            result
            .Should()
            .BeOfType <BadRequestObjectResult>()
            .Which
            .Value
            .Should()
            .Be("Publish status can't be changed to Draft from Updated or Approved");

            calculation
            .Current
            .PublishStatus
            .Should()
            .Be(PublishStatus.Approved);

            await
            searchRepository
            .Received(0)
            .Index(Arg.Any <IEnumerable <CalculationIndex> >());
        }
示例#19
0
        public async Task UpdateCalculationCodeOnCalculationChange_WhenCalculationsFoundReferencingCalculationToBeUpdated_ThenSourceCodeUpdated()
        {
            // Arrange
            ICalculationsRepository  calculationsRepository           = CreateCalculationsRepository();
            ISpecificationsApiClient specificationsApiClient          = CreateSpecificationsApiClient();
            IVersionRepository <CalculationVersion> versionRepository = CreateCalculationVersionRepository();
            IBuildProjectsService buildProjectsService = CreateBuildProjectsService();
            ISourceCodeService    sourceCodeService    = CreateSourceCodeService();

            CalculationService service = CreateCalculationService(calculationsRepository: calculationsRepository,
                                                                  specificationsApiClient: specificationsApiClient,
                                                                  calculationVersionRepository: versionRepository,
                                                                  buildProjectsService: buildProjectsService,
                                                                  sourceCodeService: sourceCodeService);

            const string specificationId    = "specId";
            const string calculationId      = "updatedCalc";
            const string originalCodeUpdate = @"Dim test as OriginalNameOptions? 
                                                OriginalNameOptions.enumName 
                                                Return Calculations.OriginalName()";
            const string newCodeUpdated     = @"Dim test as CalculationToUpdateOptions? 
                                                CalculationToUpdateOptions.enumName 
                                                Return Calculations.CalculationToUpdate()";
            const string originalCodeIgnore = "Return 10";
            const string fundingStreamId    = "fundingstreamid";

            CalculationVersionComparisonModel comparison = new CalculationVersionComparisonModel()
            {
                CalculationId       = calculationId,
                CurrentName         = "Calculation To Update",
                PreviousName        = "Original Name",
                SpecificationId     = specificationId,
                CalculationDataType = CalculationDataType.Enum,
                Namespace           = "Calculations"
            };

            Reference user = new Reference("userId", "User Name");

            List <Calculation> calculations = new List <Calculation>
            {
                new Calculation
                {
                    Id = calculationId,
                    SpecificationId = specificationId,
                    FundingStreamId = fundingStreamId,
                    Current         = new CalculationVersion
                    {
                        SourceCode      = originalCodeIgnore,
                        Name            = "Calculation to Update",
                        CalculationType = CalculationType.Template,
                        Description     = "Calculation Description",
                        DataType        = CalculationDataType.Enum
                    }
                },
                new Calculation
                {
                    Id = "referenceCalc",
                    SpecificationId = specificationId,
                    FundingStreamId = fundingStreamId,
                    Current         = new CalculationVersion
                    {
                        SourceCode      = originalCodeUpdate,
                        Name            = "Calling Calculation To Update",
                        CalculationType = CalculationType.Template,
                        Description     = "Calculation Description"
                    }
                }
            };

            calculationsRepository
            .GetCalculationsBySpecificationId(Arg.Is(specificationId))
            .Returns(calculations);

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

            calculationsRepository
            .GetCalculationById(Arg.Is(calculations[0].Id))
            .Returns(calculations[0]);

            SpecModel.SpecificationSummary specification = new SpecModel.SpecificationSummary()
            {
                Id             = specificationId,
                Name           = "Specification Name",
                FundingStreams = new [] { new Reference(fundingStreamId, "fundingStreamName"), }
            };

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

            CalculationVersion calculationVersion = new CalculationVersion
            {
                SourceCode = newCodeUpdated,
                Version    = 2
            };

            versionRepository
            .CreateVersion(Arg.Is <CalculationVersion>(_ => _.SourceCode == newCodeUpdated), Arg.Any <CalculationVersion>())
            .Returns(calculationVersion);

            buildProjectsService
            .GetBuildProjectForSpecificationId(specificationId)
            .Returns(new BuildProject());

            sourceCodeService
            .Compile(Arg.Any <BuildProject>(), Arg.Any <IEnumerable <Calculation> >(), Arg.Any <CompilerOptions>())
            .Returns(new Build());

            // Act
            IEnumerable <Calculation> updatedCalculations = await service.UpdateCalculationCodeOnCalculationChange(comparison, user);

            // Assert
            updatedCalculations
            .Should()
            .HaveCount(1);

            Calculation calculation = updatedCalculations.Single();

            calculation.Current.SourceCode
            .Should()
            .Be(newCodeUpdated);


            calculation.Current.Version
            .Should()
            .Be(2);

            calculation.Id
            .Should()
            .Be("referenceCalc");
        }
示例#20
0
        public async Task GetEffectivePermissionsForUser_WhenNotFoundInCacheResultsAreQueriedWithMultipleFundingStreamAndNoPermissionsAreInRepository_ThenOkResultReturnedWithNoPermissions()
        {
            // Arrange
            IUserRepository          userRepository          = CreateUserRepository();
            ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient();
            ICacheProvider           cacheProvider           = CreateCacheProvider();
            IMapper mapper = CreateMappingConfiguration();

            EffectiveSpecificationPermission cachedPermission = null;

            cacheProvider
            .GetHashValue <EffectiveSpecificationPermission>(Arg.Is($"{CacheKeys.EffectivePermissions}:{UserId}"), Arg.Is(SpecificationId))
            .Returns(cachedPermission);

            SpecModel.SpecificationSummary specificationSummary = new SpecModel.SpecificationSummary()
            {
                Id             = SpecificationId,
                FundingStreams = new List <Reference>()
                {
                    new Reference("fs1", "Funding Stream 1"),
                    new Reference("fs2", "Funding Stream 2")
                }
            };

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

            FundingStreamPermission fs1Permission = null;

            userRepository
            .GetFundingStreamPermission(Arg.Is(UserId), Arg.Is("fs1"))
            .Returns(fs1Permission);

            FundingStreamPermission fs2Permission = null;

            userRepository
            .GetFundingStreamPermission(Arg.Is(UserId), Arg.Is("fs2"))
            .Returns(fs2Permission);

            FundingStreamPermissionService service = CreateService(userRepository, specificationsApiClient, cacheProvider: cacheProvider, mapper: mapper);


            // Act
            IActionResult result = await service.GetEffectivePermissionsForUser(UserId, SpecificationId);

            // Assert
            result
            .Should()
            .BeOfType <OkObjectResult>()
            .Which
            .Value
            .Should()
            .BeEquivalentTo(new EffectiveSpecificationPermission()
            {
                UserId                     = UserId,
                SpecificationId            = SpecificationId,
                CanApproveFunding          = false,
                CanCreateSpecification     = false,
                CanMapDatasets             = false,
                CanChooseFunding           = false,
                CanEditCalculations        = false,
                CanEditSpecification       = false,
                CanReleaseFunding          = false,
                CanAdministerFundingStream = false,
                CanApproveSpecification    = false,
                CanCreateQaTests           = false,
                CanEditQaTests             = false,
                CanRefreshFunding          = false,
            });

            await cacheProvider
            .Received(1)
            .SetHashValue(
                Arg.Is($"{CacheKeys.EffectivePermissions}:{UserId}"),
                Arg.Is(SpecificationId),
                Arg.Is <EffectiveSpecificationPermission>(p =>
                                                          !p.CanApproveFunding &&
                                                          !p.CanChooseFunding &&
                                                          !p.CanCreateSpecification &&
                                                          !p.CanEditCalculations &&
                                                          !p.CanEditSpecification &&
                                                          !p.CanMapDatasets &&
                                                          !p.CanReleaseFunding &&
                                                          !p.CanAdministerFundingStream &&
                                                          !p.CanApproveSpecification &&
                                                          !p.CanCreateQaTests &&
                                                          !p.CanEditQaTests &&
                                                          !p.CanRefreshFunding &&
                                                          p.SpecificationId == SpecificationId &&
                                                          p.UserId == UserId
                                                          ));
        }
        public async Task EditCalculationStatus_GivenNewStatusOfUpdated_UpdatesSearchReturnsOK()
        {
            //Arrange
            EditStatusModel CalculationEditStatusModel = new EditStatusModel
            {
                PublishStatus = PublishStatus.Updated
            };

            ILogger logger = CreateLogger();

            Calculation calculation = CreateCalculation();

            calculation.Current.PublishStatus = PublishStatus.Approved;

            CalculationVersion calculationVersion = calculation.Current.Clone() as CalculationVersion;

            calculationVersion.PublishStatus = PublishStatus.Updated;

            ICalculationsRepository CalculationsRepository = CreateCalculationsRepository();

            CalculationsRepository
            .GetCalculationById(Arg.Is(CalculationId))
            .Returns(calculation);

            CalculationsRepository
            .UpdateCalculation(Arg.Any <Calculation>())
            .Returns(HttpStatusCode.OK);


            ISearchRepository <CalculationIndex> searchRepository = CreateSearchRepository();

            SpecModel.SpecificationSummary specificationSummary = new SpecModel.SpecificationSummary()
            {
                Id             = calculation.SpecificationId,
                Name           = "spec name",
                FundingStreams = new[]
                {
                    new Reference(calculation.FundingStreamId, "funding stream name")
                }
            };

            ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient();

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

            IVersionRepository <CalculationVersion> versionRepository = CreateCalculationVersionRepository();

            versionRepository
            .CreateVersion(Arg.Any <CalculationVersion>(), Arg.Any <CalculationVersion>())
            .Returns(calculationVersion);

            Build build = new Build
            {
                SourceFiles = new List <SourceFile> {
                    new SourceFile()
                }
            };

            BuildProject buildProject = new BuildProject();

            IBuildProjectsService buildProjectsService = CreateBuildProjectsService();

            buildProjectsService
            .GetBuildProjectForSpecificationId(Arg.Is(calculation.SpecificationId))
            .Returns(buildProject);

            ISourceCodeService sourceCodeService = CreateSourceCodeService();

            sourceCodeService
            .Compile(Arg.Any <BuildProject>(), Arg.Any <IEnumerable <Models.Calcs.Calculation> >(), Arg.Any <CompilerOptions>())
            .Returns(build);

            CalculationService service = CreateCalculationService(
                logger: logger, calculationsRepository: CalculationsRepository, searchRepository: searchRepository,
                specificationsApiClient: specificationsApiClient, calculationVersionRepository: versionRepository,
                sourceCodeService: sourceCodeService, buildProjectsService: buildProjectsService);

            //Act
            IActionResult result = await service.UpdateCalculationStatus(CalculationId, CalculationEditStatusModel);

            //Arrange
            result
            .Should()
            .BeOfType <OkObjectResult>()
            .Which
            .Value
            .Should()
            .BeOfType <PublishStatusResultModel>()
            .Which
            .PublishStatus
            .Should()
            .Be(PublishStatus.Updated);

            calculation
            .Current
            .PublishStatus
            .Should()
            .Be(PublishStatus.Updated);
        }
 private void GivenTheApiResponseContentForTheSpecificationId(ApiSpecificationSummary specificationSummary,
                                                              string specificationId)
 {
     _specifications.GetSpecificationSummaryById(specificationId)
     .Returns(new ApiResponse <ApiSpecificationSummary>(HttpStatusCode.OK, specificationSummary));
 }
        public async Task <IActionResult> ReIndexCalculationProviderResults()
        {
            IEnumerable <DocumentEntity <ProviderResult> > providerResults = await _resultsRepositoryPolicy.ExecuteAsync(() => _resultsRepository.GetAllProviderResults());

            IList <ProviderCalculationResultsIndex> searchItems = new List <ProviderCalculationResultsIndex>();

            Dictionary <string, SpecModel.SpecificationSummary> specifications = new Dictionary <string, SpecModel.SpecificationSummary>();

            foreach (DocumentEntity <ProviderResult> documentEntity in providerResults)
            {
                ProviderResult providerResult = documentEntity.Content;

                foreach (CalculationResult calculationResult in providerResult.CalculationResults)
                {
                    SpecModel.SpecificationSummary specificationSummary = null;
                    if (!specifications.ContainsKey(providerResult.SpecificationId))
                    {
                        Common.ApiClient.Models.ApiResponse <SpecModel.SpecificationSummary> specificationApiResponse =
                            await _specificationsApiClientPolicy.ExecuteAsync(() => _specificationsApiClient.GetSpecificationSummaryById(providerResult.SpecificationId));

                        if (!specificationApiResponse.StatusCode.IsSuccess() || specificationApiResponse.Content == null)
                        {
                            throw new InvalidOperationException($"Specification Summary returned null for specification ID '{providerResult.SpecificationId}'");
                        }

                        specificationSummary = specificationApiResponse.Content;

                        specifications.Add(providerResult.SpecificationId, specificationSummary);
                    }
                    else
                    {
                        specificationSummary = specifications[providerResult.SpecificationId];
                    }

                    ProviderCalculationResultsIndex searchItem = new ProviderCalculationResultsIndex
                    {
                        SpecificationId   = providerResult.SpecificationId,
                        SpecificationName = specificationSummary?.Name,
                        CalculationName   = providerResult.CalculationResults.Select(x => x.Calculation.Name).ToArraySafe(),
                        CalculationId     = providerResult.CalculationResults.Select(x => x.Calculation.Id).ToArraySafe(),
                        ProviderId        = providerResult.Provider.Id,
                        ProviderName      = providerResult.Provider.Name,
                        ProviderType      = providerResult.Provider.ProviderType,
                        ProviderSubType   = providerResult.Provider.ProviderSubType,
                        LocalAuthority    = providerResult.Provider.Authority,
                        LastUpdatedDate   = documentEntity.UpdatedAt,
                        UKPRN             = providerResult.Provider.UKPRN,
                        URN  = providerResult.Provider.URN,
                        UPIN = providerResult.Provider.UPIN,
                        EstablishmentNumber = providerResult.Provider.EstablishmentNumber,
                        OpenDate            = providerResult.Provider.DateOpened,
                        CalculationResult   = providerResult.CalculationResults.Select(m => !string.IsNullOrEmpty(m.Value?.ToString()) ? m.Value.ToString() : "null").ToArraySafe()
                    };

                    if (_featureToggle.IsExceptionMessagesEnabled())
                    {
                        searchItem.CalculationException = providerResult.CalculationResults
                                                          .Where(m => !string.IsNullOrWhiteSpace(m.ExceptionType))
                                                          .Select(e => e.Calculation.Id)
                                                          .ToArraySafe();

                        searchItem.CalculationExceptionType = providerResult.CalculationResults
                                                              .Select(m => m.ExceptionType ?? string.Empty)
                                                              .ToArraySafe();

                        searchItem.CalculationExceptionMessage = providerResult.CalculationResults
                                                                 .Select(m => m.ExceptionMessage ?? string.Empty)
                                                                 .ToArraySafe();
                    }

                    searchItems.Add(searchItem);
                }
            }

            const int partitionSize = 500;

            for (int i = 0; i < searchItems.Count; i += partitionSize)
            {
                IEnumerable <ProviderCalculationResultsIndex> partitionedResults = searchItems
                                                                                   .Skip(i)
                                                                                   .Take(partitionSize);

                IEnumerable <IndexError> errors = await _resultsSearchRepositoryPolicy.ExecuteAsync(() => _calculationProviderResultsSearchRepository.Index(partitionedResults));

                if (errors.Any())
                {
                    _logger.Error($"Failed to index calculation provider result documents with errors: { string.Join(";", errors.Select(m => m.ErrorMessage)) }");

                    return(new InternalServerErrorResult(null));
                }
            }

            return(new NoContentResult());
        }
        public async Task <IActionResult> GetEffectivePermissionsForUser(string userId, string specificationId)
        {
            if (string.IsNullOrWhiteSpace(userId))
            {
                return(new BadRequestObjectResult($"{nameof(userId)} is empty or null"));
            }

            if (string.IsNullOrWhiteSpace(specificationId))
            {
                return(new BadRequestObjectResult($"{nameof(specificationId)} is empty or null"));
            }

            EffectiveSpecificationPermission cachedPermissions = await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.GetHashValue <EffectiveSpecificationPermission>($"{CacheKeys.EffectivePermissions}:{userId}", specificationId));

            if (cachedPermissions != null)
            {
                return(new OkObjectResult(cachedPermissions));
            }
            else
            {
                ApiResponse <SpecModel.SpecificationSummary> specificationApiResponse =
                    await _specificationsApiClientPolicy.ExecuteAsync(() => _specificationsApiClient.GetSpecificationSummaryById(specificationId));

                if (!specificationApiResponse.StatusCode.IsSuccess() || specificationApiResponse.Content == null)
                {
                    return(new PreconditionFailedResult("Specification not found"));
                }

                SpecModel.SpecificationSummary specification = specificationApiResponse.Content;

                List <FundingStreamPermission> permissionsForUser = new List <FundingStreamPermission>();
                foreach (Reference fundingStream in specification.FundingStreams)
                {
                    FundingStreamPermission permission = await _userRepositoryPolicy.ExecuteAsync(() => _userRepository.GetFundingStreamPermission(userId, fundingStream.Id));

                    if (permission != null)
                    {
                        permissionsForUser.Add(permission);
                    }
                    else
                    {
                        // Add permission for this funding stream with no permissions - used further down to calculate permissions (required for pessimistic permissions)
                        permissionsForUser.Add(new FundingStreamPermission
                        {
                            UserId                       = userId,
                            FundingStreamId              = fundingStream.Id,
                            CanApproveFunding            = false,
                            CanChooseFunding             = false,
                            CanCreateSpecification       = false,
                            CanEditCalculations          = false,
                            CanEditSpecification         = false,
                            CanMapDatasets               = false,
                            CanReleaseFunding            = false,
                            CanAdministerFundingStream   = false,
                            CanApproveSpecification      = false,
                            CanCreateQaTests             = false,
                            CanDeleteCalculations        = false,
                            CanDeleteSpecification       = false,
                            CanDeleteQaTests             = false,
                            CanEditQaTests               = false,
                            CanRefreshFunding            = false,
                            CanCreateTemplates           = false,
                            CanEditTemplates             = false,
                            CanDeleteTemplates           = false,
                            CanApproveTemplates          = false,
                            CanCreateProfilePattern      = false,
                            CanEditProfilePattern        = false,
                            CanDeleteProfilePattern      = false,
                            CanAssignProfilePattern      = false,
                            CanApplyCustomProfilePattern = false,
                            CanApproveCalculations       = false,
                            CanApproveAnyCalculations    = false,
                            CanApproveAllCalculations    = false
                        });
                    }
                }

                EffectiveSpecificationPermission specificationPermissions = GeneratePermissions(permissionsForUser, specificationId, userId);

                string userPermissionHashKey = $"{CacheKeys.EffectivePermissions}:{userId}";

                // Does the hash set for this user already exist - used to determine the timeout for the hash set below
                bool existingHashSetExists = await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.HashSetExists(userPermissionHashKey));

                // Cache effective permissions for the specification / user
                await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.SetHashValue(userPermissionHashKey, specificationId, specificationPermissions));

                // If the hash set does not exist, then set an expiry for the whole hash set. This stops the users permissions being stored indefinitely
                if (!existingHashSetExists)
                {
                    await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.SetHashExpiry(userPermissionHashKey, DateTime.UtcNow.AddHours(12)));
                }

                return(new OkObjectResult(specificationPermissions));
            }
        }
        public async Task <IEnumerable <TestScenarioResult> > RunTests(IEnumerable <TestScenario> testScenarios, IEnumerable <ProviderResult> providerResults,
                                                                       IEnumerable <ProviderSourceDataset> sourceDatasets, IEnumerable <TestScenarioResult> currentResults, SpecModel.SpecificationSummary specification, BuildProject buildProject)
        {
            Guard.ArgumentNotNull(testScenarios, nameof(testScenarios));
            Guard.ArgumentNotNull(providerResults, nameof(providerResults));
            Guard.ArgumentNotNull(sourceDatasets, nameof(sourceDatasets));
            Guard.ArgumentNotNull(currentResults, nameof(currentResults));
            Guard.ArgumentNotNull(specification, nameof(specification));
            Guard.ArgumentNotNull(buildProject, nameof(buildProject));

            IList <TestScenarioResult> scenarioResults = new List <TestScenarioResult>();

            if (!providerResults.Any())
            {
                _logger.Warning("No provider results were supplied to execute tests");
            }
            else if (!testScenarios.Any())
            {
                _logger.Warning("No test scenarios were supplied to execute tests");
            }
            else
            {
                foreach (ProviderResult providerResult in providerResults)
                {
                    IEnumerable <ProviderSourceDataset> providerSourceDatasets = sourceDatasets.Where(m => m.ProviderId == providerResult.Provider.Id);

                    IEnumerable <ScenarioResult> testResults = await RunTests(testScenarios, providerResult, providerSourceDatasets, buildProject);

                    if (!testResults.IsNullOrEmpty())
                    {
                        foreach (ScenarioResult testResult in testResults)
                        {
                            TestResult status = (testResult.StepsExecuted == 0 || testResult.StepsExecuted < testResult.TotalSteps)
                                        ? TestResult.Ignored
                                        : testResult.HasErrors
                                            ? TestResult.Failed
                                            : TestResult.Passed;

                            TestScenarioResult filteredCurrentResults = currentResults.FirstOrDefault(m => m.Provider.Id == providerResult.Provider.Id && m.TestScenario.Id == testResult.Scenario.Id && m.TestResult == status);

                            if (filteredCurrentResults == null)
                            {
                                scenarioResults.Add(new TestScenarioResult
                                {
                                    TestResult    = status,
                                    Specification = new Reference(specification.Id, specification.Name),
                                    TestScenario  = new Reference(testResult.Scenario.Id, testResult.Scenario.Name),
                                    Provider      = new Reference(providerResult.Provider.Id, providerResult.Provider.Name)
                                });
                            }
                        }
                    }
                    else
                    {
                        _logger.Warning($"No test results generated for provider: {providerResult.Provider?.Id} on specification: {providerResult.SpecificationId}");
                    }
                }
            }
            return(scenarioResults);
        }
示例#26
0
 private ScenarioIndex CreateScenarioIndexFromScenario(TestScenario testScenario, SpecModel.SpecificationSummary specification)
 {
     return(new ScenarioIndex
     {
         Id = testScenario.Id,
         Name = testScenario.Name,
         Description = testScenario.Current.Description,
         SpecificationId = testScenario.SpecificationId,
         SpecificationName = specification.Name,
         FundingPeriodId = specification.FundingPeriod.Id,
         FundingPeriodName = specification.FundingPeriod.Name,
         FundingStreamIds = specification.FundingStreams?.Select(s => s.Id).ToArray(),
         FundingStreamNames = specification.FundingStreams?.Select(s => s.Name).ToArray(),
         Status = testScenario.Current.PublishStatus.ToString(),
         LastUpdatedDate = DateTimeOffset.Now
     });
 }
示例#27
0
        public async Task <IActionResult> SaveVersion(CreateNewTestScenarioVersion scenarioVersion, Reference user, string correlationId)
        {
            if (scenarioVersion == null)
            {
                _logger.Error("A null scenario version was provided");

                return(new BadRequestObjectResult("Null or empty calculation Id provided"));
            }

            BadRequestObjectResult validationResult = (await _createNewTestScenarioVersionValidator.ValidateAsync(scenarioVersion)).PopulateModelState();

            if (validationResult != null)
            {
                return(validationResult);
            }

            TestScenario testScenario = null;

            if (!string.IsNullOrEmpty(scenarioVersion.Id))
            {
                testScenario = await _scenariosRepository.GetTestScenarioById(scenarioVersion.Id);
            }

            bool saveAsVersion = true;

            Common.ApiClient.Models.ApiResponse <SpecModel.SpecificationSummary> specificationApiResponse =
                await _specificationsApiClientPolicy.ExecuteAsync(() => _specificationsApiClient.GetSpecificationSummaryById(scenarioVersion.SpecificationId));

            if (!specificationApiResponse.StatusCode.IsSuccess() || specificationApiResponse.Content == null)
            {
                _logger.Error($"Unable to find a specification for specification id : {scenarioVersion.SpecificationId}");
                return(new StatusCodeResult(412));
            }

            SpecModel.SpecificationSummary specification = specificationApiResponse.Content;

            if (testScenario == null)
            {
                string Id = Guid.NewGuid().ToString();

                testScenario = new TestScenario
                {
                    Id = Id,
                    SpecificationId = specification.Id,
                    Name            = scenarioVersion.Name,
                    Current         = new TestScenarioVersion
                    {
                        Date             = DateTimeOffset.Now.ToLocalTime(),
                        TestScenarioId   = Id,
                        PublishStatus    = PublishStatus.Draft,
                        Version          = 1,
                        Author           = user,
                        Gherkin          = scenarioVersion.Scenario,
                        Description      = scenarioVersion.Description,
                        FundingPeriodId  = specification.FundingPeriod.Id,
                        FundingStreamIds = specification.FundingStreams.Select(s => s.Id).ToArraySafe(),
                    }
                };
            }
            else
            {
                testScenario.Name = scenarioVersion.Name;

                saveAsVersion = !string.Equals(scenarioVersion.Scenario, testScenario.Current.Gherkin) ||
                                scenarioVersion.Description != testScenario.Current.Description;

                TestScenarioVersion newVersion = testScenario.Current.Clone() as TestScenarioVersion;

                if (saveAsVersion == true)
                {
                    newVersion.Author           = user;
                    newVersion.Gherkin          = scenarioVersion.Scenario;
                    newVersion.Description      = scenarioVersion.Description;
                    newVersion.FundingStreamIds = specification.FundingStreams.Select(s => s.Id).ToArraySafe();
                    newVersion.FundingPeriodId  = specification.FundingPeriod.Id;

                    newVersion = await _versionRepository.CreateVersion(newVersion, testScenario.Current);

                    testScenario.Current = newVersion;
                }
            }

            HttpStatusCode statusCode = await _scenariosRepository.SaveTestScenario(testScenario);

            if (!statusCode.IsSuccess())
            {
                _logger.Error($"Failed to save test scenario with status code: {statusCode}");

                return(new StatusCodeResult((int)statusCode));
            }

            await _versionRepository.SaveVersion(testScenario.Current);

            ScenarioIndex scenarioIndex = CreateScenarioIndexFromScenario(testScenario, specification);

            await _searchRepository.Index(new List <ScenarioIndex> {
                scenarioIndex
            });

            await _cacheProvider.RemoveAsync <List <TestScenario> >($"{CacheKeys.TestScenarios}{testScenario.SpecificationId}");

            await _cacheProvider.RemoveAsync <GherkinParseResult>($"{CacheKeys.GherkinParseResult}{testScenario.Id}");

            IEnumerable <Common.ApiClient.Calcs.Models.Calculation> calculations = await _calcsRepositoryPolicy.ExecuteAsync(() => _calcsRepository.GetCurrentCalculationsBySpecificationId(specification.Id));

            if (calculations.IsNullOrEmpty())
            {
                _logger.Information($"No calculations found to test for specification id: '{specification.Id}'");
            }
            else
            {
                try
                {
                    JobsModels.Trigger trigger = new JobsModels.Trigger
                    {
                        EntityId   = testScenario.Id,
                        EntityType = nameof(TestScenario),
                        Message    = $"Saving test scenario: '{testScenario.Id}'"
                    };

                    bool generateCalculationAggregations = SourceCodeHelpers.HasCalculationAggregateFunctionParameters(calculations.Select(m => m.SourceCode));

                    JobsModels.Job job = await SendInstructAllocationsToJobService(specification.Id, user, trigger, correlationId, generateCalculationAggregations);

                    _logger.Information($"New job of type '{job.JobDefinitionId}' created with id: '{job.Id}'");
                }
                catch (Exception ex)
                {
                    _logger.Error(ex, $"Failed to create job of type '{JobConstants.DefinitionNames.CreateInstructAllocationJob}' on specification '{specification.Id}'");

                    return(new InternalServerErrorResult($"An error occurred attempting to execute calculations prior to running tests on specification '{specification.Id}'"));
                }
            }

            CurrentTestScenario testScenarioResult = await _scenariosRepository.GetCurrentTestScenarioById(testScenario.Id);

            return(new OkObjectResult(testScenarioResult));
        }
示例#28
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 async Task ResetCalculationForFieldDefinitionChanges_GivenCalculationRequiresReset_UpdatesCalculationsAndDeletesAssembly()
        {
            //Arrange
            const string specificationId = "spec-id";

            IEnumerable <DatasetSpecificationRelationshipViewModel> relationships = new[]
            {
                new DatasetSpecificationRelationshipViewModel
                {
                    Name = "Test Name"
                }
            };

            IEnumerable <string> currentFieldDefinitionNames = new[]
            {
                "Test Field"
            };

            ILogger logger = CreateLogger();

            CalculationVersion calculationVersion = new CalculationVersion
            {
                SourceCode = "return Datasets.TestName.TestField",
                Date       = DateTimeOffset.Now
            };

            Calculation calculation = new Calculation
            {
                Current         = calculationVersion,
                SpecificationId = specificationId,
                FundingStreamId = "funding stream id",
            };

            IEnumerable <Calculation> calculations = new[]
            {
                calculation
            };

            BuildProject buildProject = new BuildProject();

            Build build = new Build
            {
                SourceFiles = new List <SourceFile>()
            };

            SpecModel.SpecificationSummary specificationSummary = new SpecModel.SpecificationSummary()
            {
                Id             = specificationId,
                Name           = "Test Spec Name",
                FundingStreams = new []
                {
                    new Reference(calculation.FundingStreamId, "funding stream name")
                }
            };

            ICalculationsRepository calculationsRepository = CreateCalculationsRepository();

            calculationsRepository
            .GetCalculationsBySpecificationId(Arg.Is(specificationId))
            .Returns(calculations);
            calculationsRepository
            .UpdateCalculation(Arg.Any <Calculation>())
            .Returns(HttpStatusCode.OK);

            ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient();

            specificationsApiClient
            .GetSpecificationSummaryById(Arg.Is(specificationId))
            .Returns(new ApiResponse <SpecModel.SpecificationSummary>(HttpStatusCode.OK, specificationSummary));

            IBuildProjectsService buildProjectsService = CreateBuildProjectsService();

            buildProjectsService
            .GetBuildProjectForSpecificationId(Arg.Is(specificationId))
            .Returns(buildProject);

            ISourceCodeService sourceCodeService = CreateSourceCodeService();

            sourceCodeService
            .Compile(Arg.Is(buildProject), Arg.Any <IEnumerable <Calculation> >(), Arg.Any <CompilerOptions>())
            .Returns(build);

            IVersionRepository <CalculationVersion> calculationVersionRepository = CreateCalculationVersionRepository();

            calculationVersionRepository
            .CreateVersion(Arg.Any <CalculationVersion>(), Arg.Any <CalculationVersion>())
            .Returns(calculationVersion);

            ICacheProvider cacheProvider = CreateCacheProvider();

            CalculationService calculationService = CreateCalculationService(
                logger: logger,
                calculationsRepository: calculationsRepository,
                specificationsApiClient: specificationsApiClient,
                buildProjectsService: buildProjectsService,
                sourceCodeService: sourceCodeService,
                calculationVersionRepository: calculationVersionRepository,
                cacheProvider: cacheProvider);

            //Act
            await calculationService.ResetCalculationForFieldDefinitionChanges(relationships, specificationId, currentFieldDefinitionNames);

            //Assert
            await
            sourceCodeService
            .Received(1)
            .DeleteAssembly(Arg.Is(specificationId));

            await
            cacheProvider
            .Received(1)
            .RemoveAsync <List <DatasetSchemaRelationshipModel> >(Arg.Is($"{CacheKeys.DatasetRelationshipFieldsForSpecification}{specificationId}"));
        }
示例#30
0
        public async Task UpdateCalculationCodeOnCalculationChange_WhenNoCalculationsFoundReferencingCalculationToBeUpdated_ThenNoCalculationsUpdated()
        {
            // Arrange
            ICalculationsRepository  calculationsRepository           = CreateCalculationsRepository();
            ISpecificationsApiClient specificationsApiClient          = CreateSpecificationsApiClient();
            IVersionRepository <CalculationVersion> versionRepository = CreateCalculationVersionRepository();

            CalculationService service = CreateCalculationService(calculationsRepository: calculationsRepository,
                                                                  specificationsApiClient: specificationsApiClient,
                                                                  calculationVersionRepository: versionRepository);

            const string specificationId = "specId";
            const string calculationId   = "updatedCalc";

            CalculationVersionComparisonModel comparison = new CalculationVersionComparisonModel()
            {
                CalculationId   = calculationId,
                CurrentName     = "Calculation To Update",
                PreviousName    = "Original Name",
                SpecificationId = specificationId,
            };

            Reference user = new Reference("userId", "User Name");

            List <Calculation> calculations = new List <Calculation>()
            {
                new Calculation
                {
                    Id = calculationId,
                    SpecificationId = specificationId,
                    Current         = new CalculationVersion
                    {
                        SourceCode      = "Return 10",
                        Name            = "Calculation to Update",
                        CalculationType = CalculationType.Template,
                        Description     = "Calculation Description"
                    }
                },
                new Calculation
                {
                    Id = "referenceCalc",
                    SpecificationId = specificationId,
                    Current         = new CalculationVersion
                    {
                        SourceCode      = "Return 50",
                        Name            = "Calling Calculation To Update",
                        CalculationType = CalculationType.Template,
                        Description     = "Calculation Description",
                    }
                }
            };

            calculationsRepository
            .GetCalculationsBySpecificationId(Arg.Is(specificationId))
            .Returns(calculations);

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

            calculationsRepository
            .GetCalculationById(Arg.Is(calculations[0].Id))
            .Returns(calculations[0]);

            SpecModel.SpecificationSummary specification = new SpecModel.SpecificationSummary()
            {
                Id   = specificationId,
                Name = "Specification Name",
            };

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

            CalculationVersion calculationVersion = new CalculationVersion
            {
                SourceCode = "Return CalculationToUpdate()",
                Version    = 2
            };

            versionRepository
            .CreateVersion(Arg.Any <CalculationVersion>(), Arg.Any <CalculationVersion>())
            .Returns(calculationVersion);

            // Act
            IEnumerable <Calculation> updatedCalculations = await service.UpdateCalculationCodeOnCalculationChange(comparison, user);

            // Assert
            updatedCalculations
            .Should()
            .HaveCount(0);
        }