private void AndTheMapDatasetFailsToQueue(string exception, bool retriable = false)
 {
     if (retriable)
     {
         _jobsApiClient
         .CreateJob(Arg.Any <JobCreateModel>())
         .Throws(new NonRetriableException(exception));
     }
     else
     {
         _jobsApiClient
         .CreateJob(Arg.Any <JobCreateModel>())
         .Throws(new Exception(exception));
     }
 }
Esempio n. 2
0
        public void CreateInstructGenerateAggregationsAllocationJob_GivenCreatingJobReturnsNull_ThrowsException()
        {
            //Arrange
            JobNotification jobNotification = CreateJobNotification();

            string json = JsonConvert.SerializeObject(jobNotification);

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

            IJobsApiClient jobsApiClient = CreateJobsApiClient();

            jobsApiClient
            .CreateJob(Arg.Any <JobCreateModel>())
            .Returns((Job)null);

            ILogger logger = CreateLogger();

            JobService jobService = CreateJobService(jobsApiClient, logger);

            //Act
            Func <Task> test = () => jobService.CreateInstructAllocationJob(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}'"));
        }
Esempio n. 3
0
        public async Task CreateInstructGenerateAggregationsAllocationJob_GivenJobCreated_LogsInformation()
        {
            //Arrange
            JobNotification jobNotification = CreateJobNotification();

            string json = JsonConvert.SerializeObject(jobNotification);

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

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

            IJobsApiClient jobsApiClient = CreateJobsApiClient();

            jobsApiClient
            .CreateJob(Arg.Any <JobCreateModel>())
            .Returns(job);

            ILogger logger = CreateLogger();

            JobService jobService = CreateJobService(jobsApiClient, logger);

            //Act
            await jobService.CreateInstructAllocationJob(message);

            //Assert
            logger
            .Received(1)
            .Information(Arg.Is($"Created new job of type: '{JobConstants.DefinitionNames.CreateInstructAllocationJob}' with id: '{job.Id}'"));
        }
Esempio n. 4
0
        public async Task CreateInstructAllocationJob(Message message)
        {
            Guard.ArgumentNotNull(message, nameof(message));

            JobNotification jobNotification = message.GetPayloadAsInstanceOf <JobNotification>();

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

                Job newJob = await _jobsApiClient.CreateJob(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}'");
            }
        }
Esempio n. 5
0
        public async Task <Job> CreateJob(string forCorrelationId,
                                          bool isHardDelete,
                                          Reference user,
                                          string correlationId)
        {
            try
            {
                Job job = await _resilience.ExecuteAsync(() => _jobs.CreateJob(new JobCreateModel
                {
                    InvokerUserDisplayName = user.Name,
                    InvokerUserId          = user.Id,
                    JobDefinitionId        = PublishedFundingUndoJob,
                    Properties             = new Dictionary <string, string>
                    {
                        { ForCorrelationIdPropertyName, forCorrelationId },
                        { IsHardDeletePropertyName, isHardDelete.ToString() },
                        { "user-id", user.Id },
                        { "user-name", user.Name }
                    },
                    Trigger = new Trigger
                    {
                        Message = $"Rollback publishing since correlation Id {forCorrelationId}"
                    },
                    CorrelationId = correlationId
                }));

                if (job != null)
                {
                    _logger.Information($"New job of type '{PublishedFundingUndoJob}' created with id: '{job.Id}'");
                }
                else
                {
                    _logger.Error($"Failed to create job of type '{PublishedFundingUndoJob}' for correlation id '{forCorrelationId}'");
                }

                return(job);
            }
            catch (Exception ex)
            {
                _logger.Error(ex, $"Failed to queue published funding undo job for correlation id: {forCorrelationId}");

                throw;
            }
        }
Esempio n. 6
0
        private async Task <Job> SendInstructAllocationsToJobService(string specificationId, Reference user, Trigger trigger, string correlationId, bool generateAggregations = false)
        {
            JobCreateModel job = new 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 _jobsApiClientPolicy.ExecuteAsync(() => _jobsApiClient.CreateJob(job)));
        }
Esempio n. 7
0
        private async Task SendInstructAllocationsToJobService(string providerCacheKey, string specificationId, string userId, string userName, Trigger trigger, string correlationId, bool generateCalculationAggregations)
        {
            JobCreateModel job = new JobCreateModel
            {
                InvokerUserDisplayName = userName,
                InvokerUserId          = userId,
                JobDefinitionId        = generateCalculationAggregations ? JobConstants.DefinitionNames.CreateInstructGenerateAggregationsAllocationJob : JobConstants.DefinitionNames.CreateInstructAllocationJob,
                SpecificationId        = specificationId,
                Properties             = new Dictionary <string, string>
                {
                    { "specification-id", specificationId },
                    { "provider-cache-key", providerCacheKey }
                },
                Trigger       = trigger,
                CorrelationId = correlationId
            };

            Job createdJob = await _jobsApiClientPolicy.ExecuteAsync(() => _jobsApiClient.CreateJob(job));

            _logger.Information($"New job of type '{createdJob.JobDefinitionId}' created with id: '{createdJob.Id}'");
            return;
        }
Esempio n. 8
0
        public async Task <Job> CreateReIndexJob(Reference user, string correlationId)
        {
            try
            {
                Job job = await _jobsClientPolicy.ExecuteAsync(() => _jobs.CreateJob(new JobCreateModel
                {
                    JobDefinitionId        = JobConstants.DefinitionNames.ReIndexTemplatesJob,
                    InvokerUserId          = user.Id,
                    InvokerUserDisplayName = user.Name,
                    CorrelationId          = correlationId,
                    Trigger = new Trigger
                    {
                        Message    = "ReIndexing Templates",
                        EntityType = nameof(TemplateIndex),
                    }
                }));

                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.ReIndexTemplatesJob}'";

                    _logger.Error(errorMessage);
                }

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

                _logger.Error(ex, error);

                throw new Exception(error);
            }
        }
        public async Task QueueJob_Called_ReturnsJob()
        {
            string specificationId = "1234";
            string jobId           = "3456";

            IJobsApiClient jobsApiClient             = Substitute.For <IJobsApiClient>();
            JobManagementResiliencePolicies policies = new JobManagementResiliencePolicies
            {
                JobsApiClient = Policy.NoOpAsync()
            };
            IMessengerService messengerService = Substitute.For <IMessengerService>();
            ILogger           logger           = Substitute.For <ILogger>();

            Job jobApiResponse = new Job
            {
                Id = jobId
            };

            JobCreateModel jobCreateModel = new JobCreateModel
            {
                SpecificationId = specificationId
            };

            jobsApiClient
            .CreateJob(jobCreateModel)
            .Returns(jobApiResponse);

            JobManagement jobManagement = new JobManagement(jobsApiClient, logger, policies, messengerService);

            //Act
            await jobManagement.QueueJob(jobCreateModel);

            await jobsApiClient
            .Received(1)
            .CreateJob(jobCreateModel);
        }
        public async Task UpdateCalculationsForSpecification_GivenModelHasChangedPolicyNameAndSourceCodeContainsCalculationAggregate_SavesChangesEnsuresGenerateAggregationsJobCreated()
        {
            // Arrange
            const string specificationId = "spec-id";

            Models.Specs.SpecificationVersionComparisonModel specificationVersionComparison = new Models.Specs.SpecificationVersionComparisonModel()
            {
                Id      = specificationId,
                Current = new Models.Specs.SpecificationVersion
                {
                    FundingPeriod = new Reference {
                        Id = "fp1"
                    },
                    Name     = "any-name",
                    Policies = new[] { new Models.Specs.Policy {
                                           Id = "pol-id", Name = "policy2"
                                       } }
                },
                Previous = new Models.Specs.SpecificationVersion
                {
                    FundingPeriod = new Reference {
                        Id = "fp1"
                    },
                    Policies = new[] { new Models.Specs.Policy {
                                           Id = "pol-id", Name = "policy1"
                                       } }
                }
            };

            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",
                    Name            = "any name",
                    Id = "any-id",
                    CalculationSpecification = new Reference("any name", "any-id"),
                    FundingPeriod            = new Reference("18/19", "2018/2019"),
                    CalculationType          = CalculationType.Number,
                    FundingStream            = new Reference("fp1", "fs1-111"),
                    Current = new CalculationVersion
                    {
                        Author        = new Reference(UserId, Username),
                        Date          = DateTimeOffset.Now,
                        PublishStatus = PublishStatus.Draft,
                        SourceCode    = "return Min(calc1)",
                        Version       = 1
                    },
                    Policies = new List <Reference> {
                        new Reference {
                            Id = "pol-id", Name = "policy1"
                        }
                    }
                }
            };

            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);

            ISearchRepository <CalculationIndex> searchRepository = CreateSearchRepository();

            IJobsApiClient jobsApiClient = CreateJobsApiClient();

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

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

            // Act
            await service.UpdateCalculationsForSpecification(message);

            // Assert
            await
            jobsApiClient
            .Received(1)
            .CreateJob(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 == nameof(Models.Specs.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'"));
        }
        public async Task UpdateCalculationsForSpecification_GivenModelHasChangedPolicyNameButCreatingJobReturnsNull_LogsError()
        {
            // Arrange
            const string specificationId = "spec-id";

            Models.Specs.SpecificationVersionComparisonModel specificationVersionComparison = new Models.Specs.SpecificationVersionComparisonModel()
            {
                Id      = specificationId,
                Current = new Models.Specs.SpecificationVersion
                {
                    FundingPeriod = new Reference {
                        Id = "fp1"
                    },
                    Name     = "any-name",
                    Policies = new[] { new Models.Specs.Policy {
                                           Id = "pol-id", Name = "policy2"
                                       } }
                },
                Previous = new Models.Specs.SpecificationVersion
                {
                    FundingPeriod = new Reference {
                        Id = "fp1"
                    },
                    Policies = new[] { new Models.Specs.Policy {
                                           Id = "pol-id", Name = "policy1"
                                       } }
                }
            };

            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",
                    Name            = "any name",
                    Id = "any-id",
                    CalculationSpecification = new Reference("any name", "any-id"),
                    FundingPeriod            = new Reference("18/19", "2018/2019"),
                    CalculationType          = CalculationType.Number,
                    FundingStream            = new Reference("fp1", "fs1-111"),
                    Current = new CalculationVersion
                    {
                        Author        = new Reference(UserId, Username),
                        Date          = DateTimeOffset.Now,
                        PublishStatus = PublishStatus.Draft,
                        SourceCode    = "source code",
                        Version       = 1
                    },
                    Policies = new List <Reference> {
                        new Reference {
                            Id = "pol-id", Name = "policy1"
                        }
                    }
                }
            };

            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);

            ISearchRepository <CalculationIndex> searchRepository = CreateSearchRepository();

            IJobsApiClient jobsApiClient = CreateJobsApiClient();

            jobsApiClient
            .CreateJob(Arg.Any <JobCreateModel>())
            .Returns((Job)null);

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

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

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

            await
            jobsApiClient
            .Received(1)
            .CreateJob(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 == nameof(Models.Specs.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_GivenModelHasChangedFundingStreams_SetsTheAllocationLineAndFundingStreamToNull()
        {
            //Arrange
            const string specificationId = "spec-id";

            Models.Specs.SpecificationVersionComparisonModel specificationVersionComparison = new Models.Specs.SpecificationVersionComparisonModel()
            {
                Id      = specificationId,
                Current = new Models.Specs.SpecificationVersion
                {
                    FundingPeriod = new Reference {
                        Id = "fp1"
                    },
                    Name           = "any-name",
                    FundingStreams = new List <Reference> {
                        new Reference {
                            Id = "fs2"
                        }
                    }
                },
                Previous = new Models.Specs.SpecificationVersion
                {
                    FundingPeriod = new Reference {
                        Id = "fp1"
                    },
                    FundingStreams = new List <Reference> {
                        new Reference {
                            Id = "fs1"
                        }
                    }
                }
            };

            string json = JsonConvert.SerializeObject(specificationVersionComparison);

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

            ILogger logger = CreateLogger();

            IEnumerable <Calculation> calcs = new[]
            {
                new Calculation
                {
                    SpecificationId = "spec-id",
                    Name            = "any name",
                    Id = "any-id",
                    CalculationSpecification = new Reference("any name", "any-id"),
                    FundingPeriod            = new Reference("18/19", "2018/2019"),
                    CalculationType          = CalculationType.Number,
                    FundingStream            = new Reference("fs1", "fs1-111"),
                    Current = new CalculationVersion
                    {
                        Author        = new Reference(UserId, Username),
                        Date          = DateTimeOffset.Now,
                        PublishStatus = PublishStatus.Draft,
                        SourceCode    = "source code",
                        Version       = 1
                    },
                    Policies = new List <Reference>()
                }
            };

            BuildProject buildProject = new BuildProject();

            ICalculationsRepository calculationsRepository = CreateCalculationsRepository();

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

            IBuildProjectsService buildProjectsService = CreateBuildProjectsService();

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

            ISearchRepository <CalculationIndex> searchRepository = CreateSearchRepository();

            IJobsApiClient jobsApiClient = CreateJobsApiClient();

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

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

            //Act
            await service.UpdateCalculationsForSpecification(message);

            //Assert
            calcs
            .First()
            .FundingStream
            .Should()
            .BeNull();

            calcs
            .First()
            .AllocationLine
            .Should()
            .BeNull();

            await searchRepository
            .Received(1)
            .Index(Arg.Is <IEnumerable <CalculationIndex> >(c =>
                                                            c.First().Id == calcs.First().Id&&
                                                            c.First().FundingStreamId == "" &&
                                                            c.First().FundingStreamName == "No funding stream set"));
        }
        public async Task UpdatePublishedAllocationLineResultsStatus_GivenBatchingButNoUpdateModel_ReturnsBadRequest()
        {
            //arrange
            IQueryCollection queryStringValues = new QueryCollection(new Dictionary <string, StringValues>
            {
                { "specificationId", new StringValues(specificationId) },
            });

            IEnumerable <UpdatePublishedAllocationLineResultStatusProviderModel> Providers = new[]
            {
                new UpdatePublishedAllocationLineResultStatusProviderModel
                {
                    ProviderId        = "1111",
                    AllocationLineIds = new[] { "AAAAA" }
                },
                new UpdatePublishedAllocationLineResultStatusProviderModel
                {
                    ProviderId        = "1111-1",
                    AllocationLineIds = new[] { "AAAAA" }
                },
                new UpdatePublishedAllocationLineResultStatusProviderModel
                {
                    ProviderId        = "1111-2",
                    AllocationLineIds = new[] { "AAAAA" }
                }
            };

            UpdatePublishedAllocationLineResultStatusModel model = new UpdatePublishedAllocationLineResultStatusModel
            {
                Providers = Providers,
                Status    = AllocationLineStatus.Approved
            };

            string json = JsonConvert.SerializeObject(model);

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

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

            request
            .Query
            .Returns(queryStringValues);
            request
            .Body
            .Returns(stream);

            ILogger logger = CreateLogger();

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

            IEnumerable <PublishedProviderResult> publishedProviderResults = CreatePublishedProviderResultsWithDifferentProviders();

            foreach (PublishedProviderResult publishedProviderResult in publishedProviderResults)
            {
                publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.ProfilingPeriods = new[] { new ProfilingPeriod() };
            }

            IJobsApiClient jobsApiClient = CreateJobsApiClient();

            jobsApiClient
            .CreateJob(Arg.Any <JobCreateModel>())
            .Returns(newJob);

            ICacheProvider cacheProvider = CreateCacheProvider();

            PublishedResultsService resultsService = CreateResultsService(logger, jobsApiClient: jobsApiClient, cacheProvider: cacheProvider);

            //Act
            IActionResult actionResult = await resultsService.UpdatePublishedAllocationLineResultsStatus(request);

            //Arrange
            actionResult
            .Should()
            .BeAssignableTo <OkResult>();

            logger
            .Received(1)
            .Information(Arg.Is($"New job: '{JobConstants.DefinitionNames.CreateInstructAllocationLineResultStatusUpdateJob}' created with id: '{newJob.Id}'"));

            await
            cacheProvider
            .Received(1)
            .SetAsync <UpdatePublishedAllocationLineResultStatusModel>(Arg.Any <string>(), Arg.Any <UpdatePublishedAllocationLineResultStatusModel>());

            await
            jobsApiClient
            .Received(1)
            .CreateJob(Arg.Is <JobCreateModel>(m =>
                                               !string.IsNullOrWhiteSpace(m.InvokerUserDisplayName) &&
                                               !string.IsNullOrWhiteSpace(m.InvokerUserId) &&
                                               m.JobDefinitionId == JobConstants.DefinitionNames.CreateInstructAllocationLineResultStatusUpdateJob &&
                                               m.SpecificationId == specificationId &&
                                               m.Properties["specification-id"] == specificationId &&
                                               !string.IsNullOrWhiteSpace(m.Properties["cache-key"]) &&
                                               m.Trigger.EntityId == specificationId &&
                                               m.Trigger.EntityType == "Specification" &&
                                               m.Trigger.Message == $"Updating allocation line results status"
                                               ));
        }
Esempio n. 14
0
 public async Task <Job> QueueJob(JobCreateModel jobCreateModel) => await _jobsApiClientPolicy.ExecuteAsync(() => _jobsApiClient.CreateJob(jobCreateModel));
        public async Task <IActionResult> AssignDatasourceVersionToRelationship(HttpRequest request)
        {
            string json = await request.GetRawBodyStringAsync();

            AssignDatasourceModel model = JsonConvert.DeserializeObject <AssignDatasourceModel>(json);

            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.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));
            }

            Reference user = request.GetUser();

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

            string correlationId = request.GetCorrelationId();

            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 }
                },
                SpecificationId = relationship.Specification.Id,
                Trigger         = trigger,
                CorrelationId   = correlationId
            };

            await _jobsApiClientPolicy.ExecuteAsync(() => _jobsApiClient.CreateJob(job));

            return(new NoContentResult());
        }