private Task <Job> QueueAssignTemplateCalculationsJob(Reference user,
                                                       string correlationId,
                                                       string specificationId,
                                                       string fundingStreamId,
                                                       string fundingPeriodId,
                                                       string templateVersionId) =>
 _jobs.QueueJob(new JobCreateModel
 {
     JobDefinitionId        = AssignTemplateCalculationsJob,
     InvokerUserId          = user?.Id,
     InvokerUserDisplayName = user?.Name,
     CorrelationId          = correlationId,
     SpecificationId        = specificationId,
     Trigger = new Trigger
     {
         Message    = "Changed template version for specification",
         EntityId   = specificationId,
         EntityType = nameof(Specification)
     },
     Properties = new Dictionary <string, string>
     {
         {
             "specification-id", specificationId
         },
         {
             "fundingstream-id", fundingStreamId
         },
         {
             "fundingperiod-id", fundingPeriodId
         },
         {
             "template-version", templateVersionId
         }
     }
 });
        public override async Task Process(Message message)
        {
            Guard.ArgumentNotNull(message, nameof(message));

            JobSummary jobSummary = message.GetPayloadAsInstanceOf <JobSummary>();

            if (jobSummary.CompletionStatus == CompletionStatus.Succeeded && jobSummary.JobType == JobConstants.DefinitionNames.CreateInstructGenerateAggregationsAllocationJob)
            {
                JobCreateModel jobCreateModel = new JobCreateModel
                {
                    JobDefinitionId        = JobConstants.DefinitionNames.CreateInstructAllocationJob,
                    InvokerUserDisplayName = jobSummary.InvokerUserDisplayName,
                    InvokerUserId          = jobSummary.InvokerUserId,
                    CorrelationId          = message.GetCorrelationId(),
                    SpecificationId        = jobSummary.SpecificationId,
                    Properties             = new Dictionary <string, string>
                    {
                        { "specification-id", jobSummary.SpecificationId }
                    },
                    Trigger = jobSummary.Trigger
                };

                Job newJob = await _jobManagement.QueueJob(jobCreateModel);

                if (newJob == null)
                {
                    _logger.Error($"Failed to create new job of type: '{JobConstants.DefinitionNames.CreateInstructAllocationJob}'");

                    throw new Exception($"Failed to create new job of type: '{JobConstants.DefinitionNames.CreateInstructAllocationJob}'");
                }

                _logger.Information($"Created new job of type: '{JobConstants.DefinitionNames.CreateInstructAllocationJob}' with id: '{newJob.Id}'");
            }
        }
        public async Task CreateInstructGenerateAggregationsAllocationJob_GivenJobCreated_LogsInformation()
        {
            //Arrange
            JobSummary jobNotification = CreateJobSummary();

            string json = JsonConvert.SerializeObject(jobNotification);

            Message message = new Message(Encoding.UTF8.GetBytes(json));

            Job job = new Job
            {
                Id = "job-id-1"
            };

            IJobManagement jobManagement = CreateJobManagement();

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

            ILogger logger = CreateLogger();

            JobService jobService = CreateJobService(jobManagement, logger);

            //Act
            await jobService.Process(message);

            //Assert
            logger
            .Received(1)
            .Information(Arg.Is($"Created new job of type: '{JobConstants.DefinitionNames.CreateInstructAllocationJob}' with id: '{job.Id}'"));
        }
示例#4
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}'"));
        }
示例#5
0
        public void SetUp()
        {
            _policies = Substitute.For <IPoliciesApiClient>();
            _jobs     = Substitute.For <IJobManagement>();

            _userId   = NewRandomString();
            _userName = NewRandomString();

            _user = NewReference(_ => _.WithId(_userId)
                                 .WithName(_userName));

            _correlationId = NewRandomString();

            _action = new QueueCreateSpecificationJobAction(_policies,
                                                            _jobs,
                                                            new SpecificationsResiliencePolicies
            {
                JobsApiClient     = Policy.NoOpAsync(),
                PoliciesApiClient = Policy.NoOpAsync()
            },
                                                            Substitute.For <ILogger>());

            _jobs.QueueJob(Arg.Any <JobCreateModel>())
            .Returns(new Job());    //default instance as we assert was called but have null checks in the test now
        }
        public async Task <IActionResult> QueueSpecificationIndexJob(string specificationId,
                                                                     Reference user,
                                                                     string correlationId)
        {
            Guard.IsNullOrWhiteSpace(specificationId, nameof(specificationId));

            return(new OkObjectResult(await _jobs.QueueJob(new JobCreateModel
            {
                JobDefinitionId = ReIndexSpecificationJob,
                InvokerUserId = user?.Id,
                CorrelationId = correlationId,
                SpecificationId = specificationId,
                Trigger = new Trigger
                {
                    Message = "Specification change requires reindexing",
                    EntityType = nameof(Specification),
                    EntityId = specificationId
                },
                Properties = new Dictionary <string, string>
                {
                    {
                        SpecificationId, specificationId
                    }
                }
            })));
        }
        public void CreateInstructGenerateAggregationsAllocationJob_GivenCreatingJobReturnsNull_ThrowsException()
        {
            //Arrange
            JobSummary jobNotification = CreateJobSummary();

            string json = JsonConvert.SerializeObject(jobNotification);

            Message message = new Message(Encoding.UTF8.GetBytes(json));

            IJobManagement jobManagement = CreateJobManagement();

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

            ILogger logger = CreateLogger();

            JobService jobService = CreateJobService(jobManagement, logger);

            //Act
            Func <Task> test = () => jobService.Process(message);

            //Assert
            test
            .Should()
            .ThrowExactly <Exception>()
            .Which
            .Message
            .Should()
            .Be($"Failed to create new job of type: '{JobConstants.DefinitionNames.CreateInstructAllocationJob}'");

            logger
            .Received(1)
            .Error(Arg.Is($"Failed to create new job of type: '{JobConstants.DefinitionNames.CreateInstructAllocationJob}'"));
        }
示例#8
0
        private async Task <long> QueueSearchIndexWriterJob(
            IEnumerable <ProviderResult> providerResults,
            SpecificationSummary specificationSummary,
            Reference user,
            string correlationId,
            string parentJobId)
        {
            Stopwatch stopwatch = Stopwatch.StartNew();

            string specificationId           = specificationSummary.GetSpecificationId();
            IEnumerable <string> providerIds = providerResults.Select(x => x.Provider?.Id).Where(x => !string.IsNullOrWhiteSpace(x)).ToArray();

            if (!providerIds.Any())
            {
                return(0);
            }

            try
            {
                Common.ApiClient.Jobs.Models.Job searchIndexWriterJob = await _jobManagement.QueueJob(
                    new JobCreateModel()
                {
                    Trigger = new Trigger
                    {
                        EntityId   = specificationId,
                        EntityType = "Specification",
                        Message    = "Write ProviderCalculationResultsIndex serach index for specification"
                    },
                    InvokerUserId          = user.Id,
                    InvokerUserDisplayName = user.Name,
                    JobDefinitionId        = JobConstants.DefinitionNames.SearchIndexWriterJob,
                    ParentJobId            = parentJobId,
                    SpecificationId        = specificationId,
                    CorrelationId          = correlationId,
                    Properties             = new Dictionary <string, string>
                    {
                        { "specification-id", specificationId },
                        { "specification-name", specificationSummary.Name },
                        { "index-writer-type", SearchIndexWriterTypes.ProviderCalculationResultsIndexWriter }
                    },
                    MessageBody = JsonConvert.SerializeObject(providerIds)
                });
            }
            catch (Exception ex)
            {
                string errorMessage = $"Failed to queue SearchIndexWriterJob for specification - {specificationId}";
                _logger.Error(ex, errorMessage);
                throw;
            }

            stopwatch.Stop();
            return(stopwatch.ElapsedMilliseconds);
        }
示例#9
0
        public async Task <Job> CreateReIndexJob(Reference user, string correlationId, string specificationId = null, string parentJobId = null)
        {
            try
            {
                Job job = await _jobManagement.QueueJob(new JobCreateModel
                {
                    JobDefinitionId        = JobConstants.DefinitionNames.ReIndexPublishedProvidersJob,
                    InvokerUserId          = user.Id,
                    InvokerUserDisplayName = user.Name,
                    CorrelationId          = correlationId,
                    Trigger = new Trigger
                    {
                        Message    = "ReIndexing PublishedProviders",
                        EntityType = nameof(PublishedProviderIndex),
                    }
                });

                if (!string.IsNullOrWhiteSpace(parentJobId))
                {
                    job.ParentJobId = parentJobId;
                }

                if (!string.IsNullOrWhiteSpace(specificationId))
                {
                    job.Properties = new Dictionary <string, string>
                    {
                        { "specification-id", specificationId }
                    };
                }

                if (job != null)
                {
                    _logger.Information($"New job of type '{job.JobDefinitionId}' created with id: '{job.Id}'");
                }
                else
                {
                    string errorMessage = $"Failed to create job of type '{JobConstants.DefinitionNames.ReIndexPublishedProvidersJob}'";

                    _logger.Error(errorMessage);
                }

                return(job);
            }
            catch (Exception ex)
            {
                string error = $"Failed to queue published provider re-index job";

                _logger.Error(ex, error);

                throw new Exception(error);
            }
        }
示例#10
0
        private async Task <Job> CreateJob(string errorMessage, JobCreateModel createModel)
        {
            try
            {
                Job job = await _jobManagement.QueueJob(createModel);

                return(job);
            }
            catch (Exception ex)
            {
                _logger.Error(ex, errorMessage);

                throw new Exception(errorMessage);
            }
        }
        private async Task <Job> CreateJob(JobCreateModel createModel)
        {
            try
            {
                var job = await _jobManagement.QueueJob(createModel);

                GuardAgainstNullJob(job, createModel);

                return(job);
            }
            catch (Exception ex)
            {
                _logger.Error($"Failed to create job of type '{createModel.JobDefinitionId}' on specification '{createModel.Trigger.EntityId}'. {ex}");
                throw;
            }
        }
示例#12
0
        private async Task <bool> RegenerateScopedProvidersForSpecification(string specificationId,
                                                                            bool setCachedProviders)
        {
            string scopedProviderSummariesCountCacheKey = $"{CacheKeys.ScopedProviderSummariesCount}{specificationId}";
            string currentProviderCount = await _cachePolicy.ExecuteAsync(() => _cacheProvider.GetAsync <string>(scopedProviderSummariesCountCacheKey));

            string cacheKeyScopedListCacheKey   = $"{CacheKeys.ScopedProviderSummariesPrefix}{specificationId}";
            long   scopedProviderRedisListCount = await _cachePolicy.ExecuteAsync(() => _cacheProvider.ListLengthAsync <ProviderSummary>(cacheKeyScopedListCacheKey));

            if (string.IsNullOrWhiteSpace(currentProviderCount) || int.Parse(currentProviderCount) != scopedProviderRedisListCount || setCachedProviders)
            {
                IEnumerable <JobSummary> latestJob = await _jobManagement.GetLatestJobsForSpecification(specificationId,
                                                                                                        new[]
                {
                    JobConstants.DefinitionNames.PopulateScopedProvidersJob
                });

                // the populate scoped providers job is already running so don't need to queue another job
                if (latestJob?.FirstOrDefault()?.RunningStatus == RunningStatus.InProgress)
                {
                    return(true);
                }

                await _jobManagement.QueueJob(new JobCreateModel
                {
                    JobDefinitionId = JobConstants.DefinitionNames.PopulateScopedProvidersJob,
                    SpecificationId = specificationId,
                    Trigger         = new Trigger
                    {
                        EntityId   = specificationId,
                        EntityType = "Specification",
                        Message    = "Triggered for specification changes"
                    },
                    Properties = new Dictionary <string, string>
                    {
                        {
                            "specification-id", specificationId
                        }
                    }
                });

                return(true);
            }

            return(false);
        }
示例#13
0
        public void SetUp()
        {
            _jobs = Substitute.For <IJobManagement>();

            _userId   = NewRandomString();
            _userName = NewRandomString();

            _user = NewReference(_ => _.WithId(_userId)
                                 .WithName(_userName));

            _correlationId = NewRandomString();

            _action = new QueueDeleteSpecificationJobAction(
                _jobs,
                Substitute.For <ILogger>());

            _jobs.QueueJob(Arg.Any <JobCreateModel>())
            .Returns(new Job());    //default instance as we assert was called but have null checks in the test now
        }
示例#14
0
        private async Task <JobsModels.Job> SendInstructAllocationsToJobService(string specificationId, Reference user, JobsModels.Trigger trigger, string correlationId, bool generateAggregations = false)
        {
            JobsModels.JobCreateModel job = new JobsModels.JobCreateModel
            {
                InvokerUserDisplayName = user?.Name,
                InvokerUserId          = user?.Id,
                JobDefinitionId        = generateAggregations ? JobConstants.DefinitionNames.CreateInstructGenerateAggregationsAllocationJob : JobConstants.DefinitionNames.CreateInstructAllocationJob,
                SpecificationId        = specificationId,
                Properties             = new Dictionary <string, string>
                {
                    { "specification-id", specificationId },
                    { "ignore-save-provider-results", "true" }
                },
                Trigger       = trigger,
                CorrelationId = correlationId
            };

            return(await _jobManagement.QueueJob(job));
        }
        public async Task <Job> CreateJob(string fundingStreamId,
                                          string fundingPeriodId,
                                          string correlationId)
        {
            Dictionary <string, string> messageProperties = new Dictionary <string, string>
            {
                { "funding-stream-id", fundingStreamId },
                { "funding-period-id", fundingPeriodId }
            };

            try
            {
                Job job = await _jobManagement.QueueJob(new JobCreateModel
                {
                    JobDefinitionId = DeletePublishedProvidersJob,
                    Properties      = messageProperties,
                    Trigger         = new Trigger
                    {
                        EntityId = "N/A",
                        Message  = $"Requested deletion of published providers for funding stream {fundingStreamId} and funding period {fundingPeriodId}"
                    },
                    CorrelationId = correlationId
                });

                if (job != null)
                {
                    _logger.Information($"New job of type '{DeletePublishedProvidersJob}' created with id: '{job.Id}'");
                }
                else
                {
                    _logger.Error(
                        $"Failed to create job of type '{DeletePublishedProvidersJob}' on funding stream '{fundingStreamId}' and funding period {fundingPeriodId}");
                }

                return(job);
            }
            catch (Exception ex)
            {
                _logger.Error(ex, $"Failed to create job of type '{DeletePublishedProvidersJob}' on funding stream '{fundingStreamId}' and funding period {fundingPeriodId}");

                throw;
            }
        }
        public async Task <IActionResult> QueueForSpecification(string specificationId)
        {
            Guard.IsNullOrWhiteSpace(specificationId, nameof(specificationId));

            await _jobManagement.QueueJob(new JobCreateModel
            {
                JobDefinitionId = JobConstants.DefinitionNames.ReIndexSpecificationCalculationRelationshipsJob,
                SpecificationId = specificationId,
                Trigger         = new Trigger
                {
                    EntityId   = specificationId,
                    EntityType = nameof(Specification),
                    Message    = "Triggered for specification changes"
                },
                Properties = new Dictionary <string, string>
                {
                    { "specification-id", specificationId }
                }
            });

            return(new OkResult());
        }
示例#17
0
 private void GivenTheCreateJobThrowsException(Exception exception)
 {
     Jobs.QueueJob(Arg.Any <JobCreateModel>())
     .Throws(exception);
 }
示例#18
0
 protected async Task <Job> QueueJob(JobCreateModel job)
 => await _jobManagement.QueueJob(job);
示例#19
0
 private void WhenJobIsCreateForARequestModelMatching(Expression <Predicate <JobCreateModel> > jobCreateModelMatching, Job job)
 {
     _jobs.QueueJob(Arg.Is(jobCreateModelMatching))
     .Returns(job);
 }
示例#20
0
        public override async Task Process(Message message)
        {
            Guard.ArgumentNotNull(message, nameof(message));

            string specificationId            = message.GetUserProperty <string>(SpecificationIdKey);
            string fundingStreamId            = message.GetUserProperty <string>(FundingStreamIdKey);
            string providerSnapshotIdValue    = message.GetUserProperty <string>(ProviderSnapshotIdKey);
            string disableQueueCalculationJob = message.GetUserProperty <string>(DisableQueueCalculationJobKey);

            Reference user          = message.GetUserDetails();
            string    correlationId = message.GetCorrelationId();

            if (string.IsNullOrWhiteSpace(providerSnapshotIdValue) || !int.TryParse(providerSnapshotIdValue, out int providerSnapshotId))
            {
                throw new NonRetriableException("Invalid provider snapshot id");
            }

            ProviderSnapshot providerSnapshot = await GetProviderSnapshot(fundingStreamId, providerSnapshotId);

            string providerVersionId       = $"{fundingStreamId}-{providerSnapshot.TargetDate:yyyy}-{providerSnapshot.TargetDate:MM}-{providerSnapshot.TargetDate:dd}-{providerSnapshotId}";
            bool   isProviderVersionExists = await _providerVersionService.Exists(providerVersionId);

            if (!isProviderVersionExists)
            {
                IEnumerable <Common.ApiClient.FundingDataZone.Models.Provider> fdzProviders = await GetProvidersInSnapshot(providerSnapshotId);

                ProviderVersionViewModel providerVersionViewModel = CreateProviderVersionViewModel(fundingStreamId, providerVersionId, providerSnapshot, fdzProviders);
                (bool success, IActionResult actionResult) = await _providerVersionService.UploadProviderVersion(providerVersionId, providerVersionViewModel);

                if (!success)
                {
                    string errorMessage = $"Failed to upload provider version {providerVersionId}. {GetErrorMessage(actionResult, providerVersionId)}";

                    _logger.Error(errorMessage);

                    throw new Exception(errorMessage);
                }
            }

            HttpStatusCode httpStatusCode = await _specificationsApiClientPolicy.ExecuteAsync(() => _specificationsApiClient.SetProviderVersion(specificationId, providerVersionId));

            if (!httpStatusCode.IsSuccess())
            {
                string errorMessage = $"Unable to update the specification - {specificationId}, with provider version id  - {providerVersionId}. HttpStatusCode - {httpStatusCode}";

                _logger.Error(errorMessage);

                throw new Exception(errorMessage);
            }

            JobCreateModel mapFdzDatasetsJobCreateModel = new JobCreateModel
            {
                Trigger = new Trigger
                {
                    EntityId   = specificationId,
                    EntityType = "Specification",
                    Message    = "Map datasets for all relationships in specification"
                },
                InvokerUserId          = user.Id,
                InvokerUserDisplayName = user.Name,
                JobDefinitionId        = JobConstants.DefinitionNames.MapFdzDatasetsJob,
                ParentJobId            = null,
                SpecificationId        = specificationId,
                CorrelationId          = correlationId,
                Properties             = new Dictionary <string, string>
                {
                    { "specification-id", specificationId },
                    { "disableQueueCalculationJob", disableQueueCalculationJob },
                }
            };

            try
            {
                await _jobManagement.QueueJob(mapFdzDatasetsJobCreateModel);
            }
            catch (Exception ex)
            {
                string errorMessage = $"Failed to queue MapFdzDatasetsJob for specification - {specificationId}";
                _logger.Error(ex, errorMessage);
                throw;
            }
        }
示例#21
0
        public async Task <Job> CreateJob(string specificationId,
                                          Reference user,
                                          string correlationId,
                                          Dictionary <string, string> properties = null,
                                          string messageBody = null,
                                          string parentJobId = null,
                                          bool compress      = false)
        {
            Dictionary <string, string> messageProperties =
                properties ?? new Dictionary <string, string>();

            messageProperties.Add("specification-id", specificationId);
            messageProperties.Add("user-id", user.Id);
            messageProperties.Add("user-name", user.Name);

            AddExtraMessageProperties(messageProperties);

            try
            {
                Job job = await _jobManagement.QueueJob(new JobCreateModel
                {
                    InvokerUserDisplayName = user.Name,
                    InvokerUserId          = user.Id,
                    JobDefinitionId        = JobDefinitionId,
                    Properties             = messageProperties,
                    MessageBody            = messageBody ?? string.Empty,
                    SpecificationId        = specificationId,
                    Trigger = new Trigger
                    {
                        EntityId   = specificationId,
                        EntityType = "Specification",
                        Message    = TriggerMessage
                    },
                    CorrelationId = correlationId,
                    Compress      = compress
                });

                if (!string.IsNullOrWhiteSpace(parentJobId))
                {
                    job.ParentJobId = parentJobId;
                }

                if (job != null)
                {
                    _logger.Information($"New job of type '{job.JobDefinitionId}' created with id: '{job.Id}'");
                }
                else
                {
                    string errorMessage = $"Failed to create job of type '{job.JobDefinitionId}' on specification '{specificationId}'";

                    _logger.Error(errorMessage);
                }

                return(job);
            }
            catch (Exception ex)
            {
                string error = $"Failed to queue publishing of specification with id: {specificationId}";

                _logger.Error(ex, error);

                throw new Exception(error);
            }
        }
示例#22
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);
        }
示例#23
0
        public async Task <Job> SendInstructAllocationsToJobService(string specificationId, string userId, string userName, Trigger trigger, string correlationId, bool initiateCalcRUn = true)
        {
            Job parentJob = null;

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

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



            string jobDefinitionId = generateCalculationAggregations ?
                                     JobConstants.DefinitionNames.CreateInstructGenerateAggregationsAllocationJob :
                                     JobConstants.DefinitionNames.CreateInstructAllocationJob;

            if (await GraphEnabled())
            {
                // if the graph is enabled then we need to queue a reindex of the graph
                jobDefinitionId = JobConstants.DefinitionNames.ReIndexSpecificationCalculationRelationshipsJob;
            }

            JobCreateModel job = new JobCreateModel
            {
                InvokerUserDisplayName = userName,
                InvokerUserId          = userId,
                JobDefinitionId        = jobDefinitionId,
                SpecificationId        = specificationId,
                Properties             = new Dictionary <string, string>
                {
                    { "specification-id", specificationId }
                },
                Trigger       = trigger,
                CorrelationId = correlationId
            };


            if (await GraphEnabled())
            {
                string parentJobDefinition = generateCalculationAggregations ?
                                             JobConstants.DefinitionNames.GenerateGraphAndInstructGenerateAggregationAllocationJob :
                                             JobConstants.DefinitionNames.GenerateGraphAndInstructAllocationJob;

                try
                {
                    JobCreateModel instructJob = new JobCreateModel
                    {
                        InvokerUserDisplayName = userName,
                        InvokerUserId          = userId,
                        JobDefinitionId        = parentJobDefinition,
                        SpecificationId        = specificationId,
                        Properties             = new Dictionary <string, string>
                        {
                            { "specification-id", specificationId }
                        },
                        Trigger       = trigger,
                        CorrelationId = correlationId
                    };

                    parentJob = await _jobManagement.QueueJob(instructJob);

                    _logger.Information($"New job of type '{parentJob.JobDefinitionId}' created with id: '{parentJob.Id}'");
                }
                catch (Exception ex)
                {
                    string errorMessage = $"Failed to create job of type '{parentJobDefinition}' on specification '{specificationId}'";

                    _logger.Error(ex, errorMessage);

                    throw new RetriableException(errorMessage, ex);
                }
            }

            if (parentJob != null)
            {
                job.ParentJobId = parentJob.Id;
            }

            try
            {
                return(await _jobManagement.QueueJob(job));
            }
            catch (Exception ex)
            {
                string errorMessage = $"Failed to create job of type '{job.JobDefinitionId}' on specification '{specificationId}'";

                _logger.Error(ex, errorMessage);

                throw new RetriableException(errorMessage, ex);
            }
        }
        public async Task UpdateCalculationsForSpecification_GivenModelHasChangedPolicyNameButCreatingJobReturnsNull_LogsError()
        {
            // Arrange
            const string specificationId = "spec-id";

            SpecificationVersionComparisonModel specificationVersionComparison = new SpecificationVersionComparisonModel()
            {
                Id      = specificationId,
                Current = new SpecificationVersion
                {
                    FundingPeriod = new Reference {
                        Id = "fp1"
                    },
                    Name = "any-name"
                },
                Previous = new SpecificationVersion
                {
                    FundingPeriod = new Reference {
                        Id = "fp1"
                    }
                }
            };

            string json = JsonConvert.SerializeObject(specificationVersionComparison);

            Message message = new Message(Encoding.UTF8.GetBytes(json));

            message.UserProperties.Add("user-id", UserId);
            message.UserProperties.Add("user-name", Username);

            ILogger logger = CreateLogger();

            IEnumerable <Calculation> calcs = new[]
            {
                new Calculation
                {
                    SpecificationId = "spec-id",
                    Id      = "any-id",
                    Current = new CalculationVersion
                    {
                        Author          = new Reference(UserId, Username),
                        Date            = DateTimeOffset.Now,
                        PublishStatus   = PublishStatus.Draft,
                        SourceCode      = "source code",
                        Version         = 1,
                        Name            = "any name",
                        CalculationType = CalculationType.Template
                    }
                }
            };

            BuildProject buildProject = new BuildProject
            {
                Id = "build-project-1",
                SpecificationId = specificationId
            };

            ICalculationsRepository calculationsRepository = CreateCalculationsRepository();

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

            IBuildProjectsService buildProjectsService = CreateBuildProjectsService();

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

            IJobManagement jobManagement = CreateJobManagement();

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


            CalculationService service = CreateCalculationService(
                calculationsRepository,
                logger,
                buildProjectsService: buildProjectsService,
                jobManagement: jobManagement);

            // Act
            Func <Task> test = async() => await service.Run(message);

            // Assert
            test
            .Should()
            .ThrowExactly <RetriableException>()
            .Which
            .Message
            .Should()
            .Be($"Failed to create job: '{JobConstants.DefinitionNames.CreateInstructAllocationJob} for specification id '{specificationId}'");

            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 &&
                          m.Trigger.EntityId == specificationId &&
                          m.Trigger.EntityType == "Specification" &&
                          m.Trigger.Message == $"Updating calculations for specification: '{specificationId}'"
                          ));

            logger
            .Received(1)
            .Error(Arg.Is($"Failed to create job: '{JobConstants.DefinitionNames.CreateInstructAllocationJob} for specification id '{specificationId}'"));
        }
        public async Task UpdateCalculationsForSpecification_GivenModelHasChangedPolicyNameAndSourceCodeContainsCalculationAggregate_SavesChangesEnsuresGenerateAggregationsJobCreated()
        {
            // Arrange
            const string specificationId = "spec-id";

            SpecificationVersionComparisonModel specificationVersionComparison = new SpecificationVersionComparisonModel()
            {
                Id      = specificationId,
                Current = new SpecificationVersion
                {
                    FundingPeriod = new Reference {
                        Id = "fp1"
                    },
                    Name = "any-name"
                },
                Previous = new SpecificationVersion
                {
                    FundingPeriod = new Reference {
                        Id = "fp1"
                    }
                }
            };

            string json = JsonConvert.SerializeObject(specificationVersionComparison);

            Message message = new Message(Encoding.UTF8.GetBytes(json));

            message.UserProperties.Add("user-id", UserId);
            message.UserProperties.Add("user-name", Username);

            ILogger logger = CreateLogger();

            IEnumerable <Calculation> calcs = new[]
            {
                new Calculation
                {
                    SpecificationId = "spec-id",
                    Id      = "any-id",
                    Current = new CalculationVersion
                    {
                        Author          = new Reference(UserId, Username),
                        Date            = DateTimeOffset.Now,
                        PublishStatus   = PublishStatus.Draft,
                        SourceCode      = "return Min(calc1)",
                        Version         = 1,
                        Name            = "any name",
                        CalculationType = CalculationType.Template
                    }
                }
            };

            BuildProject buildProject = new BuildProject
            {
                Id = "build-project-1",
                SpecificationId = specificationId
            };

            ICalculationsRepository calculationsRepository = CreateCalculationsRepository();

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

            IBuildProjectsService buildProjectsService = CreateBuildProjectsService();

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

            IJobManagement jobManagement = CreateJobManagement();

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


            CalculationService service = CreateCalculationService(
                calculationsRepository,
                logger,
                buildProjectsService: buildProjectsService,
                jobManagement: jobManagement);

            // Act
            await service.Run(message);

            // Assert
            await
            jobManagement
            .Received(1)
            .QueueJob(Arg.Is <JobCreateModel>(
                          m =>
                          m.InvokerUserDisplayName == Username &&
                          m.InvokerUserId == UserId &&
                          m.JobDefinitionId == JobConstants.DefinitionNames.CreateInstructGenerateAggregationsAllocationJob &&
                          m.Properties["specification-id"] == specificationId &&
                          m.Trigger.EntityId == specificationId &&
                          m.Trigger.EntityType == "Specification" &&
                          m.Trigger.Message == $"Updating calculations for specification: '{specificationId}'"
                          ));

            logger
            .Received(1)
            .Information(Arg.Is($"New job of type '{JobConstants.DefinitionNames.CreateInstructGenerateAggregationsAllocationJob}' created with id: 'job-id-1'"));
        }
示例#26
0
        public async Task <IActionResult> AssignDatasourceVersionToRelationship(AssignDatasourceModel model, Reference user, string correlationId)
        {
            if (model == null)
            {
                _logger.Error("Null AssignDatasourceModel was provided to AssignDatasourceVersionToRelationship");
                return(new BadRequestObjectResult("Null AssignDatasourceModel was provided"));
            }

            Dataset dataset = await _datasetRepository.GetDatasetByDatasetId(model.DatasetId);

            if (dataset == null)
            {
                _logger.Error($"Dataset not found for dataset id: {model.DatasetId}");
                return(new StatusCodeResult(412));
            }

            DefinitionSpecificationRelationship relationship = await _datasetRepository.GetDefinitionSpecificationRelationshipById(model.RelationshipId);

            if (relationship == null)
            {
                _logger.Error($"Relationship not found for relationship id: {model.RelationshipId}");
                return(new StatusCodeResult(412));
            }

            relationship.Author         = user;
            relationship.LastUpdated    = _dateTimeProvider.UtcNow;
            relationship.DatasetVersion = new DatasetRelationshipVersion
            {
                Id      = model.DatasetId,
                Version = model.Version
            };

            HttpStatusCode statusCode = await _datasetRepository.UpdateDefinitionSpecificationRelationship(relationship);

            if (!statusCode.IsSuccess())
            {
                _logger.Error($"Failed to assign data source to relationship : {model.RelationshipId} with status code {statusCode.ToString()}");

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

            IEnumerable <CalculationResponseModel> allCalculations = await _calcsRepository.GetCurrentCalculationsBySpecificationId(relationship.Specification.Id);

            bool generateCalculationAggregations = !allCalculations.IsNullOrEmpty() &&
                                                   SourceCodeHelpers.HasCalculationAggregateFunctionParameters(allCalculations.Select(m => m.SourceCode));

            Trigger trigger = new Trigger
            {
                EntityId   = dataset.Id,
                EntityType = nameof(Dataset),
                Message    = $"Mapping dataset: '{dataset.Id}'"
            };

            JobCreateModel job = new JobCreateModel
            {
                InvokerUserDisplayName = user?.Name,
                InvokerUserId          = user?.Id,
                JobDefinitionId        = JobConstants.DefinitionNames.MapDatasetJob,
                MessageBody            = JsonConvert.SerializeObject(dataset),
                Properties             = new Dictionary <string, string>
                {
                    { "specification-id", relationship.Specification.Id },
                    { "relationship-id", relationship.Id },
                    { "user-id", user?.Id },
                    { "user-name", user?.Name },
                },
                SpecificationId = relationship.Specification.Id,
                Trigger         = trigger,
                CorrelationId   = correlationId
            };

            Job parentJob = null;

            if (relationship.IsSetAsProviderData)
            {
                string parentJobDefinition = generateCalculationAggregations ?
                                             JobConstants.DefinitionNames.MapScopedDatasetJobWithAggregation :
                                             JobConstants.DefinitionNames.MapScopedDatasetJob;

                parentJob = await _jobManagement.QueueJob(new JobCreateModel
                {
                    InvokerUserDisplayName = user?.Name,
                    InvokerUserId          = user?.Id,
                    JobDefinitionId        = parentJobDefinition,
                    Properties             = new Dictionary <string, string>
                    {
                        { "specification-id", relationship.Specification.Id },
                        { "provider-cache-key", $"{CacheKeys.ScopedProviderSummariesPrefix}{relationship.Specification.Id}" },
                        { "specification-summary-cache-key", $"{CacheKeys.SpecificationSummaryById}{relationship.Specification.Id}" }
                    },
                    SpecificationId = relationship.Specification.Id,
                    Trigger         = trigger,
                    CorrelationId   = correlationId
                });
            }

            if (parentJob != null)
            {
                job.ParentJobId = parentJob.Id;
                job.Properties.Add("parentJobId", parentJob.Id);
            }

            await _jobManagement.QueueJob(job);

            return(new NoContentResult());
        }