Пример #1
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 async Task ProcessJobCompletion_JobIsNotComplete_ThenNoActionTaken()
        {
            // Arrange
            IJobRepository jobRepository = CreateJobRepository();

            JobManagementService jobManagementService = CreateJobManagementService(jobRepository);

            string jobId = "abc123";

            JobNotification jobNotification = new JobNotification
            {
                JobId         = jobId,
                RunningStatus = RunningStatus.InProgress
            };

            string json = JsonConvert.SerializeObject(jobNotification);

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

            message.UserProperties["jobId"] = jobId;

            // Act
            await jobManagementService.ProcessJobNotification(message);

            // Assert
            jobRepository
            .DidNotReceive()
            .GetJobById(Arg.Is(jobId));
        }
Пример #3
0
        public async Task SupersedeJob_WhenNotSameJobIdButSameParentJobId_ThenJobNotSuperseded()
        {
            // Arrange
            string jobId          = "job-id-1";
            string supersedeJobId = "job-id-2";

            Job runningJob = new Job
            {
                Id          = jobId,
                ParentJobId = "parent-1",
            };

            Job replacementJob = new Job
            {
                Id          = supersedeJobId,
                ParentJobId = "parent-1",
            };

            IJobRepository jobRepository = CreateJobRepository();

            JobManagementService jobManagementService = CreateJobManagementService(jobRepository);

            // Act
            await jobManagementService.SupersedeJob(runningJob, replacementJob);

            // Assert
            await jobRepository
            .DidNotReceive()
            .UpdateJob(Arg.Any <Job>());
        }
        public async Task ProcessJobCompletion_JobIdNotFound_ThenNoActionTakenAndErrorLogged()
        {
            // Arrange
            string jobId = "abc123";

            ILogger        logger        = CreateLogger();
            IJobRepository jobRepository = CreateJobRepository();

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

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

            JobNotification jobNotification = new JobNotification {
                RunningStatus = RunningStatus.Completed
            };

            string json = JsonConvert.SerializeObject(jobNotification);

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

            message.UserProperties["jobId"] = jobId;

            // Act
            await jobManagementService.ProcessJobNotification(message);

            // Assert
            logger
            .Received(1)
            .Error(Arg.Is("Could not find job with id {JobId}"), Arg.Is(jobId));
        }
Пример #5
0
        public async Task SupersedeJob_WhenNotSameJobIdAndNotSameParentJobId_ThenJobSuperseded()
        {
            // Arrange
            string jobId          = "job-id-1";
            string supersedeJobId = "job-id-2";

            Job runningJob = new Job
            {
                Id          = jobId,
                ParentJobId = "parent-1",
            };

            Job replacementJob = new Job
            {
                Id          = supersedeJobId,
                ParentJobId = "parent-2",
            };

            IJobRepository jobRepository = CreateJobRepository();

            JobManagementService jobManagementService = CreateJobManagementService(jobRepository);

            // Act
            await jobManagementService.SupersedeJob(runningJob, replacementJob);

            // Assert
            await jobRepository
            .Received(1)
            .UpdateJob(Arg.Is <Job>(j => j.CompletionStatus == CompletionStatus.Superseded && j.Completed.HasValue && j.RunningStatus == RunningStatus.Completed && j.SupersededByJobId == supersedeJobId));
        }
Пример #6
0
        public async Task SupersedeJob_WhenDifferentJobId_ThenJobSuperseded()
        {
            // Arrange
            string jobId          = "job-id-1";
            string supersedeJobId = "job-id-2";
            Job    runningJob     = new Job
            {
                Id = jobId,
            };

            Job replacementJob = new Job
            {
                Id = supersedeJobId
            };

            IJobRepository jobRepository = CreateJobRepository();

            jobRepository
            .UpdateJob(Arg.Any <Job>())
            .Returns(HttpStatusCode.OK);

            JobManagementService jobManagementService = CreateJobManagementService(jobRepository);

            // Act
            await jobManagementService.SupersedeJob(runningJob, replacementJob);

            // Assert
            await jobRepository
            .Received(1)
            .UpdateJob(Arg.Is <Job>(_ => _.CompletionStatus == CompletionStatus.Superseded &&
                                    _.Completed.HasValue &&
                                    _.OutcomeType == OutcomeType.Inconclusive &&
                                    _.RunningStatus == RunningStatus.Completed &&
                                    _.SupersededByJobId == supersedeJobId));
        }
Пример #7
0
        public async Task SupersedeJob_WhenJobSuperseded_ThenNotificationSent()
        {
            // Arrange
            string jobId          = "job-id-1";
            string supersedeJobId = "job-id-2";
            Job    runningJob     = new Job
            {
                Id = jobId
            };

            Job replacementJob = new Job
            {
                Id = supersedeJobId
            };

            IJobRepository jobRepository = CreateJobRepository();

            jobRepository
            .UpdateJob(Arg.Any <Job>())
            .Returns(HttpStatusCode.OK);

            INotificationService notificationService = CreateNotificationsService();

            JobManagementService jobManagementService = CreateJobManagementService(jobRepository, notificationService);

            // Act
            await jobManagementService.SupersedeJob(runningJob, replacementJob);

            // Assert
            await notificationService
            .Received(1)
            .SendNotification(Arg.Is <JobNotification>(n => n.JobId == jobId));
        }
        public async Task ProcessJobCompletion_JobHasParentTwoChildrenOnlyOneCompleted_ThenParentNotCompleted()
        {
            // Arrange
            string parentJobId = "parent123";
            string jobId       = "child123";

            Job job = new Job {
                Id = jobId, ParentJobId = parentJobId, CompletionStatus = CompletionStatus.Succeeded, RunningStatus = RunningStatus.Completed
            };

            Job job2 = new Job {
                Id = "child456", ParentJobId = parentJobId, RunningStatus = RunningStatus.InProgress
            };

            Job parentJob = new Job {
                Id = parentJobId, RunningStatus = RunningStatus.InProgress
            };

            ILogger        logger        = CreateLogger();
            IJobRepository jobRepository = CreateJobRepository();

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

            jobRepository
            .GetJobById(Arg.Is(parentJobId))
            .Returns(parentJob);

            jobRepository
            .GetChildJobsForParent(Arg.Is(parentJobId))
            .Returns(new List <Job> {
                job, job2
            });

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

            JobSummary JobSummary = new JobSummary {
                JobId = jobId, RunningStatus = RunningStatus.Completed
            };

            string  json    = JsonConvert.SerializeObject(JobSummary);
            Message message = new Message(Encoding.UTF8.GetBytes(json));

            message.UserProperties["jobId"] = jobId;

            // Act
            await jobManagementService.Process(message);

            // Assert
            await jobRepository
            .DidNotReceive()
            .UpdateJob(Arg.Is <Job>(j => j.Id == parentJobId && j.RunningStatus == RunningStatus.Completed && j.Completed.HasValue));

            logger
            .Received(1)
            .Information(Arg.Is("Completed Job {JobId} parent {ParentJobId} has in progress child jobs and cannot be completed"), Arg.Is(jobId), Arg.Is(parentJobId));
        }
        public async Task ProcessJobCompletion_JobHasParentTwoChildrenOnlyBothCompleted_ThenParentCompleted()
        {
            // Arrange
            string parentJobId = "parent123";
            string jobId       = "child123";

            Job job = new Job {
                Id = jobId, ParentJobId = parentJobId, CompletionStatus = CompletionStatus.Succeeded, RunningStatus = RunningStatus.Completed
            };

            Job job2 = new Job {
                Id = "child456", ParentJobId = parentJobId, CompletionStatus = CompletionStatus.Succeeded, RunningStatus = RunningStatus.Completed
            };

            Job parentJob = new Job {
                Id = parentJobId, RunningStatus = RunningStatus.InProgress
            };

            ILogger        logger        = CreateLogger();
            IJobRepository jobRepository = CreateJobRepository();

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

            jobRepository
            .GetJobById(Arg.Is(parentJobId))
            .Returns(parentJob);

            jobRepository
            .GetChildJobsForParent(Arg.Is(parentJobId))
            .Returns(new List <Job> {
                job, job2
            });

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

            JobNotification jobNotification = new JobNotification {
                JobId = jobId, RunningStatus = RunningStatus.Completed
            };

            string  json    = JsonConvert.SerializeObject(jobNotification);
            Message message = new Message(Encoding.UTF8.GetBytes(json));

            message.UserProperties["jobId"] = jobId;

            // Act
            await jobManagementService.ProcessJobNotification(message);

            // Assert
            await jobRepository
            .Received(1)
            .UpdateJob(Arg.Is <Job>(j => j.Id == parentJobId && j.RunningStatus == RunningStatus.Completed && j.Completed.HasValue && j.Outcome == "All child jobs completed"));

            logger
            .Received(1)
            .Information(Arg.Is("Parent Job {ParentJobId} of Completed Job {JobId} has been completed because all child jobs are now complete"), Arg.Is(job.ParentJobId), Arg.Is(jobId));
        }
        public async Task ProcessJobCompletion_JobHasParentWithMultipleCompletedChildrenWithAllSucceeded_ThenParentCompletedStatusIsSucceeded()
        {
            // Arrange
            string parentJobId = "parent123";
            string jobId       = "child123";

            Job job = new Job {
                Id = jobId, ParentJobId = parentJobId, CompletionStatus = CompletionStatus.Succeeded, RunningStatus = RunningStatus.Completed
            };

            Job job2 = new Job {
                Id = "child456", ParentJobId = parentJobId, RunningStatus = RunningStatus.Completed, CompletionStatus = CompletionStatus.Succeeded
            };

            Job job3 = new Job {
                Id = "child789", ParentJobId = parentJobId, RunningStatus = RunningStatus.Completed, CompletionStatus = CompletionStatus.Succeeded
            };

            Job parentJob = new Job {
                Id = parentJobId, RunningStatus = RunningStatus.InProgress
            };

            ILogger        logger        = CreateLogger();
            IJobRepository jobRepository = CreateJobRepository();

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

            jobRepository
            .GetJobById(Arg.Is(parentJobId))
            .Returns(parentJob);

            jobRepository
            .GetChildJobsForParent(Arg.Is(parentJobId))
            .Returns(new List <Job> {
                job, job2
            });

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

            JobSummary JobSummary = new JobSummary {
                JobId = jobId, RunningStatus = RunningStatus.Completed
            };

            string  json    = JsonConvert.SerializeObject(JobSummary);
            Message message = new Message(Encoding.UTF8.GetBytes(json));

            message.UserProperties["jobId"] = jobId;

            // Act
            await jobManagementService.Process(message);

            // Assert
            await jobRepository
            .Received(1)
            .UpdateJob(Arg.Is <Job>(j => j.Id == parentJobId && j.CompletionStatus == CompletionStatus.Succeeded));
        }
Пример #11
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));
        }
        public async Task ProcessJobCompletion_JobHasParentThatIsCompleted_ThenNotificationSent()
        {
            // Arrange
            string parentJobId = "parent123";
            string jobId       = "child123";

            Job job = new Job {
                Id = jobId, ParentJobId = parentJobId, CompletionStatus = CompletionStatus.Succeeded, RunningStatus = RunningStatus.Completed
            };

            Job parentJob = new Job {
                Id = parentJobId, RunningStatus = RunningStatus.InProgress
            };

            ILogger        logger        = CreateLogger();
            IJobRepository jobRepository = CreateJobRepository();

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

            jobRepository
            .GetJobById(Arg.Is(parentJobId))
            .Returns(parentJob);

            jobRepository
            .GetChildJobsForParent(Arg.Is(parentJobId))
            .Returns(new List <Job> {
                job
            });

            INotificationService notificationService = CreateNotificationsService();

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

            JobNotification jobNotification = new JobNotification {
                JobId = jobId, RunningStatus = RunningStatus.Completed
            };

            string  json    = JsonConvert.SerializeObject(jobNotification);
            Message message = new Message(Encoding.UTF8.GetBytes(json));

            message.UserProperties["jobId"] = jobId;

            // Act
            await jobManagementService.ProcessJobNotification(message);

            // Assert
            await notificationService
            .Received(1)
            .SendNotification(Arg.Is <JobNotification>(n => n.JobId == parentJobId && n.RunningStatus == RunningStatus.Completed));

            logger
            .Received(1)
            .Information(Arg.Is("Parent Job {ParentJobId} of Completed Job {JobId} has been completed because all child jobs are now complete"), Arg.Is(job.ParentJobId), Arg.Is(jobId));
        }
Пример #13
0
        public async Task CheckAndProcessTimedOutJobs_GivenNonCompletedJobsAndHasTimeOutButFailedToUpdate_LogsError()
        {
            //Arrange
            Job job = new Job {
                Id = "job-id-1", JobDefinitionId = "job-def-2", Created = DateTimeOffset.Now.AddHours(-13)
            };
            IEnumerable <Job> nonCompletedJobs = new[]
            {
                job
            };

            IJobRepository jobRepository = CreateJobRepository();

            jobRepository
            .GetNonCompletedJobs()
            .Returns(nonCompletedJobs);
            jobRepository
            .GetLatestJobBySpecificationIdAndDefinitionId(Arg.Any <string>(), Arg.Any <string>())
            .Returns(job);
            jobRepository
            .UpdateJob(Arg.Any <Job>())
            .Returns(HttpStatusCode.BadRequest);

            IEnumerable <JobDefinition> jobDefinitions = new[]
            {
                new JobDefinition
                {
                    Id      = "job-def-1",
                    Timeout = TimeSpan.FromHours(12)
                },
                new JobDefinition
                {
                    Id      = "job-def-2",
                    Timeout = TimeSpan.FromHours(12)
                }
            };

            IJobDefinitionsService jobDefinitionsService = CreateJobDefinitionsService();

            jobDefinitionsService
            .GetAllJobDefinitions()
            .Returns(jobDefinitions);

            ILogger logger = CreateLogger();

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

            //Act
            await jobManagementService.CheckAndProcessTimedOutJobs();

            //Assert
            logger
            .Received(1)
            .Error(Arg.Is("Failed to update timeout job, Id: 'job-id-1' with status code 400"));
        }
Пример #14
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>());
        }
Пример #15
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);
        }
Пример #16
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);
        }
Пример #17
0
        public void CheckAndProcessTimedOutJobs_GivenNonCompletedJobsFoundButNoDefinitionsReturned_LogsAndThrowsException()
        {
            //Arrange
            IEnumerable <Job> nonCompletedJobs = new[]
            {
                new Job {
                    Id = "job-id-1"
                },
                new Job {
                    Id = "job-id-2"
                }
            };

            IJobRepository jobRepository = CreateJobRepository();

            jobRepository
            .GetNonCompletedJobs()
            .Returns(nonCompletedJobs);

            IJobDefinitionsService jobDefinitionsService = CreateJobDefinitionsService();

            jobDefinitionsService
            .GetAllJobDefinitions()
            .Returns(Enumerable.Empty <JobDefinition>());

            ILogger logger = CreateLogger();

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

            //Act
            Func <Task> test = async() => await jobManagementService.CheckAndProcessTimedOutJobs();

            //Assert
            test
            .Should()
            .ThrowExactly <Exception>()
            .Which
            .Message
            .Should()
            .Be("Failed to retrieve job definitions when processing timed out jobs");

            logger
            .Received(1)
            .Error(Arg.Is("Failed to retrieve job definitions when processing timed out jobs"));

            logger
            .Received(1)
            .Information($"{nonCompletedJobs.Count()} non completed jobs to process");
        }
Пример #18
0
        public async Task CheckAndProcessTimedOutJobs_GivenNonCompletedJobsFoundButHasNotTimedOut_DoesNotUpdateJob()
        {
            //Arrange
            IEnumerable <Job> nonCompletedJobs = new[]
            {
                new Job {
                    Id = "job-id-1", JobDefinitionId = "job-def-2", Created = DateTimeOffset.Now.AddHours(-6)
                },
            };

            IJobRepository jobRepository = CreateJobRepository();

            jobRepository
            .GetNonCompletedJobs()
            .Returns(nonCompletedJobs);

            IEnumerable <JobDefinition> jobDefinitions = new[]
            {
                new JobDefinition
                {
                    Id      = "job-def-1",
                    Timeout = TimeSpan.FromHours(12)
                },
                new JobDefinition
                {
                    Id      = "job-def-2",
                    Timeout = TimeSpan.FromHours(12)
                }
            };

            IJobDefinitionsService jobDefinitionsService = CreateJobDefinitionsService();

            jobDefinitionsService
            .GetAllJobDefinitions()
            .Returns(jobDefinitions);

            ILogger logger = CreateLogger();

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

            //Act
            await jobManagementService.CheckAndProcessTimedOutJobs();

            //Assert
            await
            jobRepository
            .DidNotReceive()
            .UpdateJob(Arg.Any <Job>());
        }
Пример #19
0
        public async Task SupersedeJob_WhenJobSuperseded_ThenNotificationSent()
        {
            // Arrange
            string jobId          = "job-id-1";
            string supersedeJobId = "job-id-2";

            string         outcome  = "outcome-1";
            List <Outcome> outcomes = new List <Outcome>
            {
                new Outcome
                {
                    Description = "outcome-1"
                }
            };

            Job runningJob = new Job
            {
                Id       = jobId,
                Outcomes = outcomes,
                Outcome  = outcome
            };

            Job replacementJob = new Job
            {
                Id = supersedeJobId
            };

            IJobRepository jobRepository = CreateJobRepository();

            jobRepository
            .UpdateJob(Arg.Any <Job>())
            .Returns(HttpStatusCode.OK);

            INotificationService notificationService = CreateNotificationsService();

            JobManagementService jobManagementService = CreateJobManagementService(jobRepository, notificationService);

            // Act
            await jobManagementService.SupersedeJob(runningJob, replacementJob);

            // Assert
            await notificationService
            .Received(1)
            .SendNotification(Arg.Is <JobSummary>(n =>
                                                  n.JobId == jobId &&
                                                  n.Outcomes.SequenceEqual(outcomes) &&
                                                  n.Outcome == outcome));
        }
Пример #20
0
        public async Task CheckAndProcessTimedOutJobs_GivenNonCompletedJobsFoundButCouldNotFindJobDefinition_LogsError()
        {
            //Arrange
            IEnumerable <Job> nonCompletedJobs = new[]
            {
                new Job {
                    Id = "job-id-1", JobDefinitionId = "job-def-3"
                },
            };

            IJobRepository jobRepository = CreateJobRepository();

            jobRepository
            .GetNonCompletedJobs()
            .Returns(nonCompletedJobs);

            IEnumerable <JobDefinition> jobDefinitions = new[]
            {
                new JobDefinition
                {
                    Id      = "job-def-1",
                    Timeout = TimeSpan.FromHours(12)
                },
                new JobDefinition
                {
                    Id      = "job-def-2",
                    Timeout = TimeSpan.FromHours(12)
                }
            };

            IJobDefinitionsService jobDefinitionsService = CreateJobDefinitionsService();

            jobDefinitionsService
            .GetAllJobDefinitions()
            .Returns(jobDefinitions);

            ILogger logger = CreateLogger();

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

            //Act
            await jobManagementService.CheckAndProcessTimedOutJobs();

            //Assert
            logger
            .Received(1)
            .Error($"Failed to find job definition : 'job-def-3' for job id: 'job-id-1'");
        }
        public void ProcesJobCompletion_MessageIsNull_ArgumentNullExceptionThrown()
        {
            // Arrange
            JobManagementService jobManagementService = CreateJobManagementService();

            // Act
            Func <Task> action = async() => await jobManagementService.Process(null);

            // Assert
            action
            .Should()
            .Throw <ArgumentNullException>()
            .And
            .ParamName
            .Should()
            .Be("message");
        }
        public void ProcessJobCompletion_MessageBodyIsNull_ArgumentNullExceptionThrown()
        {
            // Arrange
            JobManagementService jobManagementService = CreateJobManagementService();

            Message message = new Message();

            // Act
            Func <Task> action = async() => await jobManagementService.ProcessJobNotification(message);

            // Assert
            action
            .Should()
            .Throw <ArgumentNullException>()
            .And
            .ParamName
            .Should()
            .Be("message payload");
        }
Пример #23
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);
        }
        public async Task ProcessJobCompletion_JobHasNoParent_ThenNoActionTakenAndMessageLogged()
        {
            // Arrange
            string jobId = "abc123";

            Job job = new Job {
                Id = jobId, ParentJobId = null
            };

            ILogger        logger        = CreateLogger();
            IJobRepository jobRepository = CreateJobRepository();

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

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

            JobSummary JobSummary = new JobSummary
            {
                JobId         = jobId,
                RunningStatus = RunningStatus.Completed
            };

            string json = JsonConvert.SerializeObject(JobSummary);

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

            message.UserProperties["jobId"] = jobId;

            // Act
            await jobManagementService.Process(message);

            // Assert
            logger
            .Received(1)
            .Information(Arg.Is("Completed Job {JobId} has no parent"), Arg.Is(jobId));

            await jobRepository
            .DidNotReceive()
            .GetChildJobsForParent(Arg.Any <string>());
        }
Пример #25
0
        public async Task CheckAndProcessTimedOutJobs_GivenZeroNonCompletedJobsToProcess_LogsAndReturns()
        {
            //Arrange
            IJobRepository jobRepository = CreateJobRepository();

            jobRepository
            .GetNonCompletedJobs()
            .Returns(Enumerable.Empty <Job>());

            ILogger logger = CreateLogger();

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

            //Act
            await jobManagementService.CheckAndProcessTimedOutJobs();

            //Assert
            logger
            .Received(1)
            .Information(Arg.Is("Zero non completed jobs to process, finished processing timed out jobs"));
        }
Пример #26
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
                                                       ));
        }
        public async Task ProcessJobCompletion_JobHasParentTwoChildrenOnlyBothCompleted_ThenParentCompleted(CompletionStatus childOneCompletionStatus,
                                                                                                            OutcomeType expectedOutcomeType)
        {
            // Arrange
            string parentJobId = "parent123";
            string jobId       = "child123";

            Outcome outcomeOne   = NewOutcome();
            Outcome outcomeTwo   = NewOutcome();
            Outcome outcomeThree = NewOutcome();
            Outcome outcomeFour  = NewOutcome();

            Job job = new Job
            {
                Id = jobId,
                JobDefinitionId  = NewRandomString(),
                ParentJobId      = parentJobId,
                CompletionStatus = childOneCompletionStatus,
                RunningStatus    = RunningStatus.Completed,
                OutcomeType      = OutcomeType.Succeeded,
                Outcome          = NewRandomString(),
                Outcomes         = new List <Outcome>
                {
                    outcomeOne,
                    outcomeTwo,
                    outcomeThree
                }
            };

            Job job2 = new Job
            {
                Id = "child456",
                JobDefinitionId  = NewRandomString(),
                ParentJobId      = parentJobId,
                CompletionStatus = CompletionStatus.Succeeded,
                RunningStatus    = RunningStatus.Completed,
                OutcomeType      = OutcomeType.Succeeded,
                Outcome          = NewRandomString(),
                Outcomes         = new List <Outcome>
                {
                    outcomeFour
                }
            };

            Job parentJob = new Job
            {
                Id            = parentJobId,
                RunningStatus = RunningStatus.InProgress
            };

            ILogger        logger        = CreateLogger();
            IJobRepository jobRepository = CreateJobRepository();

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

            jobRepository
            .GetJobById(Arg.Is(parentJobId))
            .Returns(parentJob);

            jobRepository
            .GetChildJobsForParent(Arg.Is(parentJobId))
            .Returns(new List <Job> {
                job, job2
            });

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

            JobSummary JobSummary = new JobSummary {
                JobId = jobId, RunningStatus = RunningStatus.Completed
            };

            string  json    = JsonConvert.SerializeObject(JobSummary);
            Message message = new Message(Encoding.UTF8.GetBytes(json));

            message.UserProperties["jobId"] = jobId;

            // Act
            await jobManagementService.Process(message);

            // Assert
            await jobRepository
            .Received(1)
            .UpdateJob(Arg.Is <Job>(_ => _.Id == parentJobId &&
                                    _.RunningStatus == RunningStatus.Completed &&
                                    _.OutcomeType == expectedOutcomeType &&
                                    _.Completed.HasValue &&
                                    _.Outcome == "All child jobs completed"));

            logger
            .Received(1)
            .Information(Arg.Is("Parent Job {ParentJobId} of Completed Job {JobId} has been completed because all child jobs are now complete"), Arg.Is(job.ParentJobId), Arg.Is(jobId));

            Outcome expectedChildJobOneOutcome = NewOutcome(_ => _.WithJobDefinitionId(job.JobDefinitionId)
                                                            .WithType(OutcomeType.Succeeded)
                                                            .WithDescription(job.Outcome)
                                                            .WithIsSuccessful(childOneCompletionStatus == CompletionStatus.Succeeded));
            Outcome expectedChildJobTwoOutcome = NewOutcome(_ => _.WithJobDefinitionId(job2.JobDefinitionId)
                                                            .WithType(OutcomeType.Succeeded)
                                                            .WithDescription(job2.Outcome)
                                                            .WithIsSuccessful(true));

            //rolls up all outcomes to the parent job
            parentJob.Outcomes
            .Should()
            .BeEquivalentTo(new object[]
            {
                outcomeOne,
                outcomeTwo,
                outcomeThree,
                outcomeFour,
                expectedChildJobOneOutcome,
                expectedChildJobTwoOutcome
            });
        }
        public async Task ProcessJobCompletion_WhenMultipleChildJobsCompleted_EnsuresOnlyCompletesParentOnce()
        {
            // Arrange
            string parentJobId = "parent123";
            string jobId1      = "child123";
            string jobId2      = "child456";

            Job job1 = new Job {
                Id = jobId1, ParentJobId = parentJobId, CompletionStatus = CompletionStatus.Succeeded, RunningStatus = RunningStatus.Completed
            };

            Job job2 = new Job {
                Id = jobId2, ParentJobId = parentJobId, RunningStatus = RunningStatus.Completed
            };

            Job parentJob = new Job {
                Id = parentJobId, RunningStatus = RunningStatus.InProgress
            };

            ILogger        logger        = CreateLogger();
            IJobRepository jobRepository = CreateJobRepository();

            jobRepository
            .GetJobById(jobId1)
            .Returns(job1);
            jobRepository
            .GetJobById(jobId2)
            .Returns(job2);

            jobRepository
            .GetJobById(Arg.Is(parentJobId))
            .Returns(parentJob, new Job {
                Id = parentJobId, RunningStatus = RunningStatus.Completed
            });

            jobRepository
            .GetChildJobsForParent(Arg.Is(parentJobId))
            .Returns(new List <Job> {
                job1, job2
            });

            INotificationService notificationService = CreateNotificationsService();

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

            JobSummary JobSummary = new JobSummary {
                JobId = jobId1, RunningStatus = RunningStatus.Completed
            };

            string json = JsonConvert.SerializeObject(JobSummary);

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

            message1.UserProperties["jobId"] = jobId1;

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

            message2.UserProperties["jobId"] = jobId2;

            // Act
            await jobManagementService.Process(message1);

            await jobManagementService.Process(message2);

            // Assert
            await jobRepository
            .Received(1)
            .UpdateJob(Arg.Is <Job>(j => j.Id == parentJobId && j.RunningStatus == RunningStatus.Completed && j.Completed.HasValue));

            await
            notificationService
            .Received(1)
            .SendNotification(Arg.Is <JobSummary>(m => m.JobId == parentJobId));
        }
Пример #29
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));
        }
        public async Task ProcessJobCompletion_JobHasParentOnlyOneChild_ThenCacheUpdated()
        {
            // Arrange
            string specificationId = "specification123";
            string parentJobId     = "parent123";
            string jobId           = "child123";

            Job job = new Job {
                Id = jobId, SpecificationId = specificationId, ParentJobId = parentJobId, CompletionStatus = CompletionStatus.Succeeded, RunningStatus = RunningStatus.Completed
            };

            Job parentJob = new Job {
                Id = parentJobId, SpecificationId = specificationId, RunningStatus = RunningStatus.InProgress
            };

            ILogger        logger        = CreateLogger();
            IJobRepository jobRepository = CreateJobRepository();

            jobRepository
            .GetJobById(Arg.Is(jobId))
            .Returns(job);
            jobRepository
            .GetJobById(Arg.Is(parentJobId))
            .Returns(parentJob);
            jobRepository
            .GetChildJobsForParent(Arg.Is(parentJobId))
            .Returns(new List <Job> {
                job
            });
            var moreRecentJob = new Job {
                Id = "newer-job-id", SpecificationId = specificationId
            };

            jobRepository
            .GetLatestJobBySpecificationIdAndDefinitionId(Arg.Any <string>(), Arg.Any <string>())
            .Returns(moreRecentJob);
            jobRepository
            .UpdateJob(Arg.Any <Job>())
            .Returns(HttpStatusCode.OK);

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

            ICacheProvider cacheProvider = CreateCacheProvider();

            cacheProvider
            .SetAsync(cacheKey, Arg.Is <Job>(_ => _.Id == job.Id))
            .Returns(Task.CompletedTask);

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

            JobSummary JobSummary = new JobSummary {
                JobId = jobId, RunningStatus = RunningStatus.Completed
            };

            string  json    = JsonConvert.SerializeObject(JobSummary);
            Message message = new Message(Encoding.UTF8.GetBytes(json));

            message.UserProperties["jobId"] = jobId;

            // Act
            await jobManagementService.Process(message);

            // Assert
            await jobRepository
            .Received(1)
            .UpdateJob(Arg.Is <Job>(j =>
                                    j.Id == parentJobId &&
                                    j.RunningStatus == RunningStatus.Completed &&
                                    j.Completed.HasValue &&
                                    j.Outcome == "All child jobs completed"));

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