public async Task UpdateJobStatus_ApiResponseSuccess_Runs()
        {
            //Arrange
            IJobsApiClient jobsApiClient             = Substitute.For <IJobsApiClient>();
            JobManagementResiliencePolicies policies = new JobManagementResiliencePolicies
            {
                JobsApiClient = Policy.NoOpAsync()
            };
            IMessengerService messengerService = Substitute.For <IMessengerService>();
            ILogger           logger           = Substitute.For <ILogger>();

            ApiResponse <JobLog> jobLogApiResponse = new ApiResponse <JobLog>(HttpStatusCode.OK, new JobLog());

            jobsApiClient
            .AddJobLog(Arg.Any <string>(), Arg.Any <JobLogUpdateModel>())
            .Returns(jobLogApiResponse);

            JobLogUpdateModel updateModel = new JobLogUpdateModel();

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

            string jobId = "3456";

            //Act
            await jobManagement.UpdateJobStatus(jobId, updateModel);

            //Assert
            await jobsApiClient
            .Received(1)
            .AddJobLog(jobId, updateModel);

            logger
            .Received(0)
            .Write(Arg.Any <LogEventLevel>(), Arg.Any <string>());
        }
        public async Task UpdateJobStatusInternal_ApiResponseFailure_Logs(ApiResponse <JobLog> jobLogApiResponse)
        {
            //Arrange
            IJobsApiClient jobsApiClient             = Substitute.For <IJobsApiClient>();
            JobManagementResiliencePolicies policies = new JobManagementResiliencePolicies
            {
                JobsApiClient = Policy.NoOpAsync()
            };
            IMessengerService messengerService = Substitute.For <IMessengerService>();
            ILogger           logger           = Substitute.For <ILogger>();

            jobsApiClient
            .AddJobLog(Arg.Any <string>(), Arg.Any <JobLogUpdateModel>())
            .Returns(jobLogApiResponse);

            JobLogUpdateModel updateModel = new JobLogUpdateModel();

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

            string jobId = "3456";

            //Act
            await jobManagement.UpdateJobStatus(jobId, updateModel);

            //Assert
            await jobsApiClient
            .Received(1)
            .AddJobLog(jobId, updateModel);

            logger
            .Received(1)
            .Write(LogEventLevel.Error, $"Failed to add a job log for job id '{jobId}'");
        }
        public async Task AddJobLog_Called_ReturnsJobLog()
        {
            string jobId = "5678";

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

            JobLog jobLog = new JobLog
            {
                JobId = jobId
            };
            ApiResponse <JobLog> jobLogApiResponse = new ApiResponse <JobLog>(HttpStatusCode.OK, jobLog);

            JobLogUpdateModel jobLogUpdateModel = new JobLogUpdateModel();

            jobsApiClient
            .AddJobLog(jobId, jobLogUpdateModel)
            .Returns(jobLogApiResponse);

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

            //Act
            JobLog result = await jobManagement.AddJobLog(jobId, jobLogUpdateModel);

            Assert.AreEqual(result, jobLog);

            await jobsApiClient
            .Received(1)
            .AddJobLog(jobId, jobLogUpdateModel);
        }
예제 #4
0
        public async Task AddJobLog_GivenJobNotFound_ReturnsNotFoundResult()
        {
            //Arrange
            string jobId = "job-id-1";

            JobLogUpdateModel jobLogUpdateModel = new JobLogUpdateModel();

            IJobRepository jobRepository = CreateJobRepository();

            jobRepository
            .GetJobById(Arg.Is(jobId))
            .Returns((Job)null);

            ILogger logger = CreateLogger();

            JobManagementService jobManagementService = CreateJobManagementService(jobRepository: jobRepository, logger: logger);

            //Act
            IActionResult actionResult = await jobManagementService.AddJobLog(jobId, jobLogUpdateModel);

            //Assert
            actionResult
            .Should()
            .BeAssignableTo <NotFoundObjectResult>()
            .Which
            .Value
            .Should()
            .Be($"A job could not be found for job id: '{jobId}'");

            logger
            .Received(1)
            .Error($"A job could not be found for job id: '{jobId}'");
        }
        public Task <ApiResponse <JobLog> > AddJobLog(string jobId, JobLogUpdateModel jobLogUpdateModel)
        {
            if (!_jobs.ContainsKey(jobId))
            {
                throw new Exception("Job not found");
            }

            if (!_jobLogs.ContainsKey(jobId))
            {
                _jobLogs.Add(jobId, new List <JobLog>());
            }

            Job job = _jobs[jobId];

            JobLog jobLog = new JobLog()
            {
                CompletedSuccessfully = jobLogUpdateModel.CompletedSuccessfully,
                Id             = Guid.NewGuid().ToString(),
                ItemsFailed    = jobLogUpdateModel.ItemsFailed,
                ItemsProcessed = jobLogUpdateModel.ItemsProcessed,
                ItemsSucceeded = jobLogUpdateModel.ItemsSucceeded,
                JobId          = jobId,
                Outcome        = jobLogUpdateModel.Outcome,
                Timestamp      = DateTime.UtcNow,
            };

            if (job.RunningStatus == RunningStatus.Queued)
            {
                job.RunningStatus = RunningStatus.InProgress;
            }

            _jobLogs[jobId].Add(jobLog);

            return(Task.FromResult(new ApiResponse <JobLog>(System.Net.HttpStatusCode.OK, jobLog)));
        }
예제 #6
0
        public async Task <JobLog> AddJobLog(string jobId, JobLogUpdateModel jobLogUpdateModel)
        {
            ApiResponse <JobLog> jobLogResponse = await _jobsApiClientPolicy.ExecuteAsync(() => _jobsApiClient.AddJobLog(jobId, jobLogUpdateModel));

            JobLog jobLog = jobLogResponse?.Content;

            return(jobLog);
        }
        public async Task <ApiResponse <JobLog> > AddJobLog(string jobId,
                                                            JobLogUpdateModel jobLogUpdateModel)
        {
            Guard.IsNullOrWhiteSpace(jobId, nameof(jobId));
            Guard.ArgumentNotNull(jobLogUpdateModel, nameof(jobLogUpdateModel));

            return(await PostAsync <JobLog, JobLogUpdateModel>($"jobs/{jobId}/logs", jobLogUpdateModel));
        }
예제 #8
0
        public async Task AddJobLog_GivenJobUpdated_EnsuresNewJobLogCreated()
        {
            //Arrange
            string jobId = "job-id-1";

            JobLogUpdateModel jobLogUpdateModel = new JobLogUpdateModel
            {
                CompletedSuccessfully = false,
                Outcome        = "outcome",
                ItemsFailed    = 40,
                ItemsProcessed = 100,
                ItemsSucceeded = 60
            };

            Job job = new Job
            {
                Id            = jobId,
                RunningStatus = RunningStatus.InProgress
            };

            IJobRepository jobRepository = CreateJobRepository();

            jobRepository
            .GetJobById(Arg.Is(jobId))
            .Returns(job);

            jobRepository
            .UpdateJob(Arg.Is(job))
            .Returns(HttpStatusCode.OK);

            jobRepository
            .CreateJobLog(Arg.Any <JobLog>())
            .Returns(HttpStatusCode.OK);

            ILogger logger = CreateLogger();

            JobManagementService jobManagementService = CreateJobManagementService(jobRepository: jobRepository, logger: logger);

            //Act
            IActionResult actionResult = await jobManagementService.AddJobLog(jobId, jobLogUpdateModel);

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

            await
            jobRepository
            .Received(1)
            .CreateJobLog(Arg.Is <JobLog>(m =>
                                          !string.IsNullOrWhiteSpace(m.Id) &&
                                          m.JobId == jobId &&
                                          m.ItemsProcessed == 100 &&
                                          m.ItemsFailed == 40 &&
                                          m.ItemsSucceeded == 60 &&
                                          m.CompletedSuccessfully == false &&
                                          m.Timestamp.Date == DateTimeOffset.Now.ToLocalTime().Date));
        }
예제 #9
0
        public async Task UpdateJobStatus(string jobId, JobLogUpdateModel jobLogUpdateModel)
        {
            ApiResponse <JobLog> jobLogResponse = await _jobsApiClientPolicy.ExecuteAsync(() => _jobsApiClient.AddJobLog(jobId, jobLogUpdateModel));

            if (jobLogResponse?.Content == null)
            {
                _logger.Write(LogEventLevel.Error, $"Failed to add a job log for job id '{jobId}'");
            }
        }
        public async Task AddJobLog()
        {
            string            id = NewRandomString();
            JobLogUpdateModel jobLogUpdateModel = new JobLogUpdateModel();

            await AssertPostRequest($"jobs/{id}/logs",
                                    jobLogUpdateModel,
                                    new JobLog(),
                                    () => _client.AddJobLog(id, jobLogUpdateModel));
        }
예제 #11
0
        public async Task UpdateJobStatus(string jobId, int percentComplete = 0, bool?completedSuccessfully = null, string outcome = null)
        {
            JobLogUpdateModel jobLogUpdateModel = new JobLogUpdateModel
            {
                CompletedSuccessfully = completedSuccessfully,
                ItemsProcessed        = percentComplete,
                Outcome = outcome
            };

            await UpdateJobStatus(jobId, jobLogUpdateModel);
        }
예제 #12
0
        public async Task AddJobLog_GivenJobUpdatedButCreatingJobLogFails_ThrowsExceptionDoesNotSendNotification()
        {
            //Arrange
            string jobId = "job-id-1";

            JobLogUpdateModel jobLogUpdateModel = new JobLogUpdateModel
            {
                CompletedSuccessfully = false,
                Outcome        = "outcome",
                ItemsFailed    = 40,
                ItemsProcessed = 100,
                ItemsSucceeded = 60
            };

            Job job = new Job
            {
                Id            = jobId,
                RunningStatus = RunningStatus.InProgress
            };

            IJobRepository jobRepository = CreateJobRepository();

            jobRepository
            .GetJobById(Arg.Is(jobId))
            .Returns(job);

            jobRepository
            .UpdateJob(Arg.Is(job))
            .Returns(HttpStatusCode.OK);

            jobRepository
            .CreateJobLog(Arg.Any <JobLog>())
            .Returns(HttpStatusCode.BadRequest);

            INotificationService notificationService = CreateNotificationsService();

            JobManagementService jobManagementService = CreateJobManagementService(jobRepository: jobRepository, notificationService: notificationService);

            //Act
            Func <Task> test = async() => await jobManagementService.AddJobLog(jobId, jobLogUpdateModel);

            //Assert
            test
            .Should()
            .ThrowExactly <Exception>()
            .Which.Message
            .Should()
            .Be($"Failed to create a job log for job id: '{jobId}'");

            await
            notificationService
            .DidNotReceive()
            .SendNotification(Arg.Any <JobNotification>());
        }
예제 #13
0
        public async Task UpdateJobStatus(string jobId, int totalItemsCount, int failedItemsCount, bool?completedSuccessfully = null, string outcome = null)
        {
            JobLogUpdateModel jobLogUpdateModel = new JobLogUpdateModel
            {
                CompletedSuccessfully = completedSuccessfully,
                ItemsProcessed        = totalItemsCount,
                ItemsFailed           = failedItemsCount,
                ItemsSucceeded        = totalItemsCount - failedItemsCount,
                Outcome = outcome
            };

            await UpdateJobStatus(jobId, jobLogUpdateModel);
        }
예제 #14
0
        public async Task AddJobLog_GivenJobFoundAndSetToInProgressButFailedToUpdateJob_ReturnsInternalServerErrorResult()
        {
            //Arrange
            string jobId = "job-id-1";

            JobLogUpdateModel jobLogUpdateModel = new JobLogUpdateModel();

            Job job = new Job
            {
                Id            = jobId,
                RunningStatus = RunningStatus.Queued
            };

            IJobRepository jobRepository = CreateJobRepository();

            jobRepository
            .GetJobById(Arg.Is(jobId))
            .Returns(job);
            jobRepository
            .GetLatestJobBySpecificationIdAndDefinitionId(Arg.Any <string>(), Arg.Any <string>())
            .Returns(job);

            jobRepository
            .UpdateJob(Arg.Is(job))
            .Returns(HttpStatusCode.BadRequest);

            ILogger logger = CreateLogger();

            JobManagementService jobManagementService = CreateJobManagementService(jobRepository: jobRepository, logger: logger);

            //Act
            IActionResult actionResult = await jobManagementService.AddJobLog(jobId, jobLogUpdateModel);

            //Assert
            actionResult
            .Should()
            .BeAssignableTo <InternalServerErrorResult>()
            .Which
            .Value
            .Should()
            .Be($"Failed to update job id: '{jobId}' with status code '400'");

            logger
            .Received(1)
            .Error($"Failed to update job id: '{jobId}' with status code '400'");

            job
            .RunningStatus
            .Should()
            .Be(RunningStatus.InProgress);
        }
예제 #15
0
        public async Task AddJobLog_GivenJobFoundAndSetToCompletedAndIsFailed_EnsuresJobIsUpdatedWithCorrectValues()
        {
            //Arrange
            string jobId = "job-id-1";

            JobLogUpdateModel jobLogUpdateModel = new JobLogUpdateModel
            {
                CompletedSuccessfully = false,
                Outcome     = "outcome",
                OutcomeType = NewRandomOutcomeType()
            };

            Job job = new Job
            {
                Id            = jobId,
                RunningStatus = RunningStatus.InProgress
            };

            IJobRepository jobRepository = CreateJobRepository();

            jobRepository
            .GetJobById(Arg.Is(jobId))
            .Returns(job);

            jobRepository
            .UpdateJob(Arg.Is(job))
            .Returns(HttpStatusCode.OK);

            jobRepository
            .CreateJobLog(Arg.Any <JobLog>())
            .Returns(HttpStatusCode.OK);

            ILogger logger = CreateLogger();

            JobManagementService jobManagementService = CreateJobManagementService(jobRepository: jobRepository, logger: logger);

            //Act
            IActionResult actionResult = await jobManagementService.AddJobLog(jobId, jobLogUpdateModel);

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

            job.RunningStatus.Should().Be(RunningStatus.Completed);
            job.Completed.Should().NotBeNull();
            job.CompletionStatus.Should().Be(CompletionStatus.Failed);
            job.Outcome.Should().Be("outcome");
            job.OutcomeType.Should().Be(jobLogUpdateModel.OutcomeType);
        }
예제 #16
0
        public async Task <IResultModel> Update(JobLogUpdateModel model)
        {
            var entity = await _repository.FirstAsync(model.Id);

            if (entity == null)
            {
                return(ResultModel.NotExists);
            }

            _mapper.Map(model, entity);

            var result = await _repository.UpdateAsync(entity);

            return(ResultModel.Result(result));
        }
예제 #17
0
        private async Task UpdateJobStatus(string jobId, bool?completedSuccessfully, int percentComplete, string outcome = null)
        {
            JobLogUpdateModel jobLogUpdateModel = new JobLogUpdateModel
            {
                CompletedSuccessfully = completedSuccessfully,
                ItemsProcessed        = percentComplete,
                Outcome = outcome
            };

            ApiResponse <JobLog> jobLogResponse = await _jobsApiClientPolicy.ExecuteAsync(() => _jobsApiClient.AddJobLog(jobId, jobLogUpdateModel));

            if (jobLogResponse == null || jobLogResponse.Content == null)
            {
                _logger.Error($"Failed to add a job log for job id '{jobId}'");
            }
        }
예제 #18
0
 public Task <IResultModel> Update(JobLogUpdateModel model)
 {
     return(_service.Update(model));
 }
        public async Task <IActionResult> AddJobLog(string jobId, JobLogUpdateModel jobLogUpdateModel)
        {
            Guard.IsNullOrWhiteSpace(jobId, nameof(jobId));
            Guard.ArgumentNotNull(jobLogUpdateModel, nameof(jobLogUpdateModel));

            Job job = await _jobsRepositoryPolicy.ExecuteAsync(() => _jobRepository.GetJobById(jobId));

            if (job == null)
            {
                string error = $"A job could not be found for job id: '{jobId}'";

                _logger.Error(error);

                return(new NotFoundObjectResult(error));
            }

            bool needToSaveJob = false;

            if (jobLogUpdateModel.CompletedSuccessfully.HasValue)
            {
                bool completedSuccessfully = jobLogUpdateModel.CompletedSuccessfully.Value;

                job.Completed        = DateTimeOffset.UtcNow;
                job.RunningStatus    = RunningStatus.Completed;
                job.CompletionStatus = completedSuccessfully ? CompletionStatus.Succeeded : CompletionStatus.Failed;
                job.OutcomeType      = GetCompletedJobOutcomeType(jobLogUpdateModel);
                job.Outcome          = jobLogUpdateModel.Outcome;
                needToSaveJob        = true;
            }
            else
            {
                if (job.RunningStatus != RunningStatus.InProgress)
                {
                    job.RunningStatus = RunningStatus.InProgress;
                    needToSaveJob     = true;
                }
            }

            if (needToSaveJob)
            {
                HttpStatusCode statusCode = await UpdateJob(job);

                if (!statusCode.IsSuccess())
                {
                    string error = $"Failed to update job id: '{jobId}' with status code '{(int)statusCode}'";

                    _logger.Error(error);

                    return(new InternalServerErrorResult(error));
                }
            }

            JobLog jobLog = new JobLog
            {
                Id                    = Guid.NewGuid().ToString(),
                JobId                 = jobId,
                ItemsProcessed        = jobLogUpdateModel.ItemsProcessed,
                ItemsSucceeded        = jobLogUpdateModel.ItemsSucceeded,
                ItemsFailed           = jobLogUpdateModel.ItemsFailed,
                OutcomeType           = jobLogUpdateModel.OutcomeType,
                Outcome               = jobLogUpdateModel.Outcome,
                CompletedSuccessfully = jobLogUpdateModel.CompletedSuccessfully,
                Timestamp             = DateTimeOffset.UtcNow
            };

            HttpStatusCode createJobLogStatus = await _jobsRepositoryPolicy.ExecuteAsync(() => _jobRepository.CreateJobLog(jobLog));

            if (!createJobLogStatus.IsSuccess())
            {
                string error = $"Failed to create a job log for job id: '{jobId}'";

                _logger.Error(error);

                throw new Exception(error);
            }

            await SendJobLogNotification(job, jobLog);

            return(new OkObjectResult(jobLog));
        }
예제 #20
0
        public async Task AddJobLog_GivenJobUpdated_EnsuresNewNotificationIsSent()
        {
            //Arrange
            string jobId = "job-id-1";

            JobLogUpdateModel jobLogUpdateModel = new JobLogUpdateModel
            {
                CompletedSuccessfully = false,
                Outcome        = "outcome",
                ItemsFailed    = 40,
                ItemsProcessed = 100,
                ItemsSucceeded = 60
            };

            Job job = new Job
            {
                Id                     = jobId,
                RunningStatus          = RunningStatus.InProgress,
                JobDefinitionId        = "job-definition-id",
                InvokerUserDisplayName = "authorName",
                InvokerUserId          = "authorId",
                ItemCount              = 100,
                SpecificationId        = "spec-id-1",
                Trigger                = new Trigger
                {
                    EntityId   = "spec-id-1",
                    EntityType = "Specification",
                    Message    = "allocating"
                }
            };

            IJobRepository jobRepository = CreateJobRepository();

            jobRepository
            .GetJobById(Arg.Is(jobId))
            .Returns(job);

            jobRepository
            .UpdateJob(Arg.Is(job))
            .Returns(HttpStatusCode.OK);

            jobRepository
            .CreateJobLog(Arg.Any <JobLog>())
            .Returns(HttpStatusCode.OK);

            ILogger logger = CreateLogger();

            INotificationService notificationService = CreateNotificationsService();

            JobManagementService jobManagementService = CreateJobManagementService(jobRepository: jobRepository, logger: logger, notificationService: notificationService);

            //Act
            IActionResult actionResult = await jobManagementService.AddJobLog(jobId, jobLogUpdateModel);

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

            await
            notificationService
            .Received(1)
            .SendNotification(Arg.Is <JobNotification>(m =>
                                                       m.JobId == jobId &&
                                                       m.JobType == "job-definition-id" &&
                                                       m.CompletionStatus == CompletionStatus.Failed &&
                                                       m.InvokerUserDisplayName == "authorName" &&
                                                       m.InvokerUserId == "authorId" &&
                                                       m.ItemCount == 100 &&
                                                       m.Outcome == "outcome" &&
                                                       m.OverallItemsFailed == 40 &&
                                                       m.OverallItemsProcessed == 100 &&
                                                       m.OverallItemsSucceeded == 60 &&
                                                       m.ParentJobId == null &&
                                                       m.SpecificationId == "spec-id-1" &&
                                                       m.StatusDateTime.Date == DateTimeOffset.Now.ToLocalTime().Date&&
                                                       string.IsNullOrWhiteSpace(m.SupersededByJobId) &&
                                                       m.Trigger.EntityId == "spec-id-1" &&
                                                       m.Trigger.EntityType == "Specification" &&
                                                       m.Trigger.Message == "allocating" &&
                                                       m.RunningStatus == RunningStatus.Completed
                                                       ));
        }
예제 #21
0
        public async Task AddJobLog_GivenJobUpdatedAndCompletedSuccessfully_EnsuresLatestCacheIsUpdated()
        {
            //Arrange
            string         jobId       = "job-id-1";
            DateTimeOffset lastUpdated = new RandomDateTime();
            List <Outcome> outcomes    = new List <Outcome>
            {
                new Outcome
                {
                    Description = "outcome-1"
                }
            };

            string specificationId = "spec-id-1";
            string jobDefinitionId = "job-definition-id";

            JobLogUpdateModel jobLogUpdateModel = new JobLogUpdateModel
            {
                CompletedSuccessfully = true,
                Outcome        = "outcome",
                ItemsFailed    = 40,
                ItemsProcessed = 100,
                ItemsSucceeded = 60
            };

            Job job = new Job
            {
                Id                     = jobId,
                RunningStatus          = RunningStatus.InProgress,
                JobDefinitionId        = jobDefinitionId,
                InvokerUserDisplayName = "authorName",
                InvokerUserId          = "authorId",
                LastUpdated            = lastUpdated,
                ItemCount              = 100,
                SpecificationId        = specificationId,
                Trigger                = new Trigger
                {
                    EntityId   = "spec-id-1",
                    EntityType = "Specification",
                    Message    = "allocating"
                },
                Outcomes = outcomes
            };

            IJobRepository jobRepository = CreateJobRepository();

            jobRepository
            .GetJobById(Arg.Is(jobId))
            .Returns(job);

            jobRepository
            .UpdateJob(Arg.Is(job))
            .Returns(HttpStatusCode.OK);

            jobRepository
            .CreateJobLog(Arg.Any <JobLog>())
            .Returns(HttpStatusCode.OK);

            jobRepository
            .GetLatestJobBySpecificationIdAndDefinitionId(Arg.Is(specificationId), Arg.Is(jobDefinitionId))
            .Returns(job);

            ILogger logger = CreateLogger();

            INotificationService notificationService = CreateNotificationsService();

            ICacheProvider cacheProvider = CreateCacheProvider();

            JobManagementService jobManagementService = CreateJobManagementService(
                jobRepository: jobRepository,
                logger: logger,
                notificationService: notificationService,
                cacheProvider: cacheProvider);

            //Act
            IActionResult actionResult = await jobManagementService.AddJobLog(jobId, jobLogUpdateModel);

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

            await
            notificationService
            .Received(1)
            .SendNotification(Arg.Is <JobSummary>(m =>
                                                  m.JobId == jobId &&
                                                  m.JobType == "job-definition-id" &&
                                                  m.CompletionStatus == CompletionStatus.Succeeded &&
                                                  m.InvokerUserDisplayName == "authorName" &&
                                                  m.InvokerUserId == "authorId" &&
                                                  m.ItemCount == 100 &&
                                                  m.Outcome == "outcome" &&
                                                  m.OverallItemsFailed == 40 &&
                                                  m.OverallItemsProcessed == 100 &&
                                                  m.OverallItemsSucceeded == 60 &&
                                                  m.ParentJobId == null &&
                                                  m.SpecificationId == "spec-id-1" &&
                                                  string.IsNullOrWhiteSpace(m.SupersededByJobId) &&
                                                  m.Trigger.EntityId == "spec-id-1" &&
                                                  m.Trigger.EntityType == "Specification" &&
                                                  m.Trigger.Message == "allocating" &&
                                                  m.RunningStatus == RunningStatus.Completed &&
                                                  m.LastUpdated == lastUpdated &&
                                                  m.Outcomes.SequenceEqual(outcomes) &&
                                                  m.OutcomeType == OutcomeType.Succeeded
                                                  ));

            string cacheKey = $"{CacheKeys.LatestJobs}{job.SpecificationId}:{job.JobDefinitionId}";
            string latestSuccessfulJobCacheKey = $"{CacheKeys.LatestSuccessfulJobs}{job.SpecificationId}:{job.JobDefinitionId}";


            await cacheProvider
            .Received(1)
            .SetAsync(cacheKey, Arg.Is <Job>(_ => _.Id == jobId));

            await cacheProvider
            .Received(1)
            .SetAsync(latestSuccessfulJobCacheKey, Arg.Is <Job>(_ => _.Id == jobId));
        }
예제 #22
0
        public async Task AddJobLog_GivenJobUpdatedAndCompletedUnsuccesfully_EnsuresLatestCacheIsNotUpdated(CompletionStatus completionStatus)
        {
            //Arrange
            string         jobId       = "job-id-1";
            DateTimeOffset lastUpdated = new RandomDateTime();
            List <Outcome> outcomes    = new List <Outcome>
            {
                new Outcome
                {
                    Description = "outcome-1"
                }
            };

            string specificationId = "spec-id-1";
            string jobDefinitionId = "job-definition-id";

            JobLogUpdateModel jobLogUpdateModel = new JobLogUpdateModel
            {
                CompletedSuccessfully = false,
                Outcome        = "outcome",
                ItemsFailed    = 40,
                ItemsProcessed = 100,
                ItemsSucceeded = 60
            };

            Job job = new Job
            {
                Id                     = jobId,
                RunningStatus          = RunningStatus.InProgress,
                JobDefinitionId        = jobDefinitionId,
                InvokerUserDisplayName = "authorName",
                InvokerUserId          = "authorId",
                LastUpdated            = lastUpdated,
                ItemCount              = 100,
                SpecificationId        = specificationId,
                Trigger                = new Trigger
                {
                    EntityId   = "spec-id-1",
                    EntityType = "Specification",
                    Message    = "allocating"
                },
                Outcomes = outcomes
            };

            Job completedJob = new Job
            {
                Id                     = jobId,
                RunningStatus          = RunningStatus.Completed,
                JobDefinitionId        = jobDefinitionId,
                InvokerUserDisplayName = "authorName",
                InvokerUserId          = "authorId",
                LastUpdated            = lastUpdated,
                ItemCount              = 100,
                SpecificationId        = specificationId,
                Trigger                = new Trigger
                {
                    EntityId   = "spec-id-1",
                    EntityType = "Specification",
                    Message    = "allocating"
                },
                Outcomes         = outcomes,
                CompletionStatus = completionStatus,
            };

            IJobRepository jobRepository = CreateJobRepository();

            jobRepository
            .GetJobById(Arg.Is(jobId))
            .Returns(job);

            jobRepository
            .UpdateJob(Arg.Is(job))
            .Returns(HttpStatusCode.OK);

            jobRepository
            .CreateJobLog(Arg.Any <JobLog>())
            .Returns(HttpStatusCode.OK);

            jobRepository
            .GetLatestJobBySpecificationIdAndDefinitionId(Arg.Is(specificationId), Arg.Is(jobDefinitionId))
            .Returns(completedJob);

            ILogger logger = CreateLogger();

            ICacheProvider cacheProvider = CreateCacheProvider();

            JobManagementService jobManagementService = CreateJobManagementService(
                jobRepository: jobRepository,
                logger: logger,
                cacheProvider: cacheProvider);

            //Act
            IActionResult actionResult = await jobManagementService.AddJobLog(jobId, jobLogUpdateModel);

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

            string cacheKey = $"{CacheKeys.LatestJobs}{job.SpecificationId}:{job.JobDefinitionId}";
            string latestSuccessfulJobCacheKey = $"{CacheKeys.LatestSuccessfulJobs}{job.SpecificationId}:{job.JobDefinitionId}";


            await cacheProvider
            .Received(1)
            .SetAsync(cacheKey, Arg.Is <Job>(_ => _.Id == jobId));

            await cacheProvider
            .Received(0)
            .SetAsync(latestSuccessfulJobCacheKey, Arg.Is <Job>(_ => _.Id == jobId));
        }
예제 #23
0
        public async Task UpdateAllocations(Message message)
        {
            Guard.ArgumentNotNull(message, nameof(message));

            JobViewModel job = null;

            if (!message.UserProperties.ContainsKey("jobId"))
            {
                _logger.Error("Missing parent job id to instruct generating allocations");

                return;
            }

            string jobId = message.UserProperties["jobId"].ToString();

            ApiResponse <JobViewModel> response = await _jobsApiClientPolicy.ExecuteAsync(() => _jobsApiClient.GetJobById(jobId));

            if (response == null || response.Content == null)
            {
                _logger.Error($"Could not find the parent job with job id: '{jobId}'");

                throw new Exception($"Could not find the parent job with job id: '{jobId}'");
            }

            job = response.Content;

            if (job.CompletionStatus.HasValue)
            {
                _logger.Information($"Received job with id: '{job.Id}' is already in a completed state with status {job.CompletionStatus.ToString()}");

                return;
            }

            await _jobsApiClientPolicy.ExecuteAsync(() => _jobsApiClient.AddJobLog(jobId, new Common.ApiClient.Jobs.Models.JobLogUpdateModel()));

            IDictionary <string, string> properties = message.BuildMessageProperties();

            string specificationId = message.UserProperties["specification-id"].ToString();

            BuildProject buildProject = await GetBuildProjectForSpecificationId(specificationId);

            if (message.UserProperties.ContainsKey("ignore-save-provider-results"))
            {
                properties.Add("ignore-save-provider-results", "true");
            }

            string cacheKey = "";

            if (message.UserProperties.ContainsKey("provider-cache-key"))
            {
                cacheKey = message.UserProperties["provider-cache-key"].ToString();
            }
            else
            {
                cacheKey = $"{CacheKeys.ScopedProviderSummariesPrefix}{specificationId}";
            }

            bool summariesExist = await _cacheProvider.KeyExists <ProviderSummary>(cacheKey);

            long totalCount = await _cacheProvider.ListLengthAsync <ProviderSummary>(cacheKey);

            bool refreshCachedScopedProviders = false;

            if (summariesExist)
            {
                IEnumerable <string> scopedProviderIds = await _providerResultsRepository.GetScopedProviderIds(specificationId);

                if (scopedProviderIds.Count() != totalCount)
                {
                    refreshCachedScopedProviders = true;
                }
                else
                {
                    IEnumerable <ProviderSummary> cachedScopedSummaries = await _cacheProvider.ListRangeAsync <ProviderSummary>(cacheKey, 0, (int)totalCount);

                    IEnumerable <string> differences = scopedProviderIds.Except(cachedScopedSummaries.Select(m => m.Id));

                    refreshCachedScopedProviders = differences.AnyWithNullCheck();
                }
            }

            if (!summariesExist || refreshCachedScopedProviders)
            {
                totalCount = await _providerResultsRepository.PopulateProviderSummariesForSpecification(specificationId);
            }

            const string providerSummariesPartitionIndex = "provider-summaries-partition-index";

            const string providerSummariesPartitionSize = "provider-summaries-partition-size";

            properties.Add(providerSummariesPartitionSize, _engineSettings.MaxPartitionSize.ToString());

            properties.Add("provider-cache-key", cacheKey);

            properties.Add("specification-id", specificationId);

            IList <IDictionary <string, string> > allJobProperties = new List <IDictionary <string, string> >();

            for (int partitionIndex = 0; partitionIndex < totalCount; partitionIndex += _engineSettings.MaxPartitionSize)
            {
                if (properties.ContainsKey(providerSummariesPartitionIndex))
                {
                    properties[providerSummariesPartitionIndex] = partitionIndex.ToString();
                }
                else
                {
                    properties.Add(providerSummariesPartitionIndex, partitionIndex.ToString());
                }

                IDictionary <string, string> jobProperties = new Dictionary <string, string>();

                foreach (KeyValuePair <string, string> item in properties)
                {
                    jobProperties.Add(item.Key, item.Value);
                }
                allJobProperties.Add(jobProperties);
            }

            await _specificationsRepository.UpdateCalculationLastUpdatedDate(specificationId);

            try
            {
                if (!allJobProperties.Any())
                {
                    _logger.Information($"No scoped providers set for specification '{specificationId}'");

                    JobLogUpdateModel jobCompletedLog = new JobLogUpdateModel
                    {
                        CompletedSuccessfully = true,
                        Outcome = "Calculations not run as no scoped providers set for specification"
                    };
                    await _jobsApiClientPolicy.ExecuteAsync(() => _jobsApiClient.AddJobLog(job.Id, jobCompletedLog));

                    return;
                }

                IEnumerable <Job> newJobs = await CreateGenerateAllocationJobs(job, allJobProperties);

                int newJobsCount = newJobs.Count();
                int batchCount   = allJobProperties.Count();

                if (newJobsCount != batchCount)
                {
                    throw new Exception($"Only {newJobsCount} child jobs from {batchCount} were created with parent id: '{job.Id}'");
                }
                else
                {
                    _logger.Information($"{newJobsCount} child jobs were created for parent id: '{job.Id}'");
                }
            }
            catch (Exception ex)
            {
                _logger.Error(ex.Message);

                throw new Exception($"Failed to create child jobs for parent job: '{job.Id}'");
            }
        }
 private async Task AddJobLog(JobLogUpdateModel jobLog, string jobId)
 {
     await _jobs.AddJobLog(jobId, jobLog);
 }
예제 #25
0
        public async Task AddJobLog_WhenNoOutcomeTypeIsSuppliedInTheViewModelItIsDeterminedByTheJobLogDetails(JobLogUpdateModel jobLogUpdateModel,
                                                                                                              OutcomeType?expectedOutcomeType)
        {
            //Arrange
            string jobId = "job-id-1";

            Job job = new Job
            {
                Id            = jobId,
                RunningStatus = RunningStatus.InProgress
            };

            IJobRepository jobRepository = CreateJobRepository();

            jobRepository
            .GetJobById(Arg.Is(jobId))
            .Returns(job);

            jobRepository
            .UpdateJob(Arg.Is(job))
            .Returns(HttpStatusCode.OK);

            jobRepository
            .CreateJobLog(Arg.Any <JobLog>())
            .Returns(HttpStatusCode.OK);

            ILogger logger = CreateLogger();

            JobManagementService jobManagementService = CreateJobManagementService(jobRepository: jobRepository, logger: logger);

            //Act
            IActionResult actionResult = await jobManagementService.AddJobLog(jobId, jobLogUpdateModel);

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

            job.RunningStatus.Should().Be(RunningStatus.Completed);
            job.Completed.Should().NotBeNull();
            job.OutcomeType.Should().Be(expectedOutcomeType);
        }
예제 #26
0
 private async Task AddJobTracking(string jobId, JobLogUpdateModel tracking)
 {
     await _jobManagement.AddJobLog(jobId, tracking);
 }
예제 #27
0
 public async Task <IActionResult> UpdateJobStatusLog([FromRoute] string jobId, [FromBody] JobLogUpdateModel job)
 {
     return(await _jobManagementService.AddJobLog(jobId, job));
 }