public override async Task Process(Message message) { Guard.ArgumentNotNull(message, nameof(message)); JobSummary jobSummary = message.GetPayloadAsInstanceOf <JobSummary>(); if (jobSummary.CompletionStatus == CompletionStatus.Succeeded && jobSummary.JobType == JobConstants.DefinitionNames.CreateInstructGenerateAggregationsAllocationJob) { JobCreateModel jobCreateModel = new JobCreateModel { JobDefinitionId = JobConstants.DefinitionNames.CreateInstructAllocationJob, InvokerUserDisplayName = jobSummary.InvokerUserDisplayName, InvokerUserId = jobSummary.InvokerUserId, CorrelationId = message.GetCorrelationId(), SpecificationId = jobSummary.SpecificationId, Properties = new Dictionary <string, string> { { "specification-id", jobSummary.SpecificationId } }, Trigger = jobSummary.Trigger }; Job newJob = await _jobManagement.QueueJob(jobCreateModel); if (newJob == null) { _logger.Error($"Failed to create new job of type: '{JobConstants.DefinitionNames.CreateInstructAllocationJob}'"); throw new Exception($"Failed to create new job of type: '{JobConstants.DefinitionNames.CreateInstructAllocationJob}'"); } _logger.Information($"Created new job of type: '{JobConstants.DefinitionNames.CreateInstructAllocationJob}' with id: '{newJob.Id}'"); } }
public async Task <IViewComponentResult> InvokeAsync(int jobId, int requestId, JobStatuses targetStatus, CancellationToken cancellationToken) { JobSummary job = null; if (jobId > 0) { job = await _requestService.GetJobSummaryAsync(jobId, cancellationToken); requestId = job.RequestID; } var request = await _requestService.GetRequestSummaryAsync(requestId, cancellationToken); var user = await _authService.GetCurrentUser(HttpContext, cancellationToken); bool userIsAdmin = await _groupMemberService.GetUserHasRole(user.ID, request.ReferringGroupID, GroupRoles.TaskAdmin, true, cancellationToken); JobStatusChangePopupViewModel vm = await BuildVm(request, job, targetStatus, cancellationToken); if (job == null) { return((request.SingleJobStatus(), targetStatus, userIsAdmin) switch { (_, JobStatuses.Done, true) => View("Admin_MarkRequestAsDonePopup", vm), (_, JobStatuses.Cancelled, true) => View("Admin_CancelRequestPopup", vm), _ => throw new Exception($"Unhandled status/admin combination for request: {request.SingleJobStatus()} -> {targetStatus} / admin:{userIsAdmin}") });
public async Task CreateInstructGenerateAggregationsAllocationJob_GivenJobCreated_LogsInformation() { //Arrange JobSummary jobNotification = CreateJobSummary(); string json = JsonConvert.SerializeObject(jobNotification); Message message = new Message(Encoding.UTF8.GetBytes(json)); Job job = new Job { Id = "job-id-1" }; IJobManagement jobManagement = CreateJobManagement(); jobManagement .QueueJob(Arg.Any <JobCreateModel>()) .Returns(job); ILogger logger = CreateLogger(); JobService jobService = CreateJobService(jobManagement, logger); //Act await jobService.Process(message); //Assert logger .Received(1) .Information(Arg.Is($"Created new job of type: '{JobConstants.DefinitionNames.CreateInstructAllocationJob}' with id: '{job.Id}'")); }
public void CreateInstructGenerateAggregationsAllocationJob_GivenCreatingJobReturnsNull_ThrowsException() { //Arrange JobSummary jobNotification = CreateJobSummary(); string json = JsonConvert.SerializeObject(jobNotification); Message message = new Message(Encoding.UTF8.GetBytes(json)); IJobManagement jobManagement = CreateJobManagement(); jobManagement .QueueJob(Arg.Any <JobCreateModel>()) .Returns((Job)null); ILogger logger = CreateLogger(); JobService jobService = CreateJobService(jobManagement, logger); //Act Func <Task> test = () => jobService.Process(message); //Assert test .Should() .ThrowExactly <Exception>() .Which .Message .Should() .Be($"Failed to create new job of type: '{JobConstants.DefinitionNames.CreateInstructAllocationJob}'"); logger .Received(1) .Error(Arg.Is($"Failed to create new job of type: '{JobConstants.DefinitionNames.CreateInstructAllocationJob}'")); }
public async Task <IActionResult> GetLatestSuccessfulJob(string specificationId, string jobDefinitionId) { Guard.ArgumentNotNull(specificationId, nameof(specificationId)); Guard.ArgumentNotNull(jobDefinitionId, nameof(jobDefinitionId)); string cacheKey = $"{CacheKeys.LatestSuccessfulJobs}{specificationId}:{jobDefinitionId}"; Job job = await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.GetAsync <Job>(cacheKey)); if (job == null) { job = await _jobRepository.GetLatestJobBySpecificationIdAndDefinitionId(specificationId, jobDefinitionId, CompletionStatus.Succeeded); if (job != null) { await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.SetAsync(cacheKey, job)); } } if (job == null) { return(new NotFoundObjectResult($"No successfully completed job found for specification '{specificationId}' and jobDefinitonId '{jobDefinitionId}'.")); } JobSummary jobSummary = _mapper.Map <JobSummary>(job); return(new OkObjectResult(jobSummary)); }
public async Task ProcessJobCompletion_JobIsNotComplete_ThenNoActionTaken() { // Arrange IJobRepository jobRepository = CreateJobRepository(); JobManagementService jobManagementService = CreateJobManagementService(jobRepository); string jobId = "abc123"; JobSummary JobSummary = new JobSummary { JobId = jobId, RunningStatus = RunningStatus.InProgress }; 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() .GetJobById(Arg.Is(jobId)); }
public async Task ProcessJobCompletion_JobIdIsNotSet_ThenNoActionTakenAndErrorLogged() { // Arrange ILogger logger = CreateLogger(); IJobRepository jobRepository = CreateJobRepository(); JobManagementService jobManagementService = CreateJobManagementService(jobRepository, logger: logger); JobSummary JobSummary = new JobSummary { RunningStatus = RunningStatus.Completed }; string json = JsonConvert.SerializeObject(JobSummary); Message message = new Message(Encoding.UTF8.GetBytes(json)); // Act await jobManagementService.Process(message); // Assert logger .Received(1) .Error(Arg.Is("Job Notification message has no JobId")); await jobRepository .DidNotReceive() .GetJobById(Arg.Any <string>()); }
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); JobSummary JobSummary = new JobSummary { 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) .Error(Arg.Is("Could not find job with id {JobId}"), Arg.Is(jobId)); }
public async Task <IActionResult> GetLatestJobs(string specificationId, string jobTypes) { Guard.ArgumentNotNull(specificationId, nameof(specificationId)); string[] jobDefinitionIds = !string.IsNullOrEmpty(jobTypes) ? jobTypes.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries) : Array.Empty <string>(); if (!jobDefinitionIds.Any()) { return(new BadRequestObjectResult("JobTypes must be provided to get latest jobs.")); } ConcurrentDictionary <string, Job> jobsByDefinition = new ConcurrentDictionary <string, Job>(); List <Task> allTasks = new List <Task>(); foreach (string jobDefinitionId in jobDefinitionIds.Distinct()) { allTasks.Add( Task.Run(async() => { string cacheKey = $"{CacheKeys.LatestJobs}{specificationId}:{jobDefinitionId}"; Job job = await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.GetAsync <Job>(cacheKey)); if (job != null) { jobsByDefinition[jobDefinitionId] = job; } else { job = await _jobRepository.GetLatestJobBySpecificationIdAndDefinitionId(specificationId, jobDefinitionId); // create a new empty job if no job so we don't continually make calls as the cache will be invalidated in the create job and update job // with a valid job so this will only be hit if redis is empty or a job has never been created job ??= new Job(); await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.SetAsync(cacheKey, job)); jobsByDefinition[jobDefinitionId] = job; } })); } await TaskHelper.WhenAllAndThrow(allTasks.ToArray()); IEnumerable <JobSummary> jobSummaries = _mapper.Map <IEnumerable <JobSummary> >(jobsByDefinition.Values); JobSummary[] results = new JobSummary[jobDefinitionIds.Length]; for (int i = 0; i < jobDefinitionIds.Length; i++) { results[i] = jobSummaries.FirstOrDefault(x => string.Equals(x.JobDefinitionId, jobDefinitionIds[i], StringComparison.InvariantCultureIgnoreCase)); } return(new OkObjectResult(results)); }
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_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)); }
public async Task GetLatestJobForSpecification() { string specificationId = NewRandomString(); string jobDefinitonId = NewRandomString(); JobSummary jobsummary = NewJobSummary(); await AssertGetRequest($"jobs/latest-success?specificationId={specificationId}&jobDefinitonId={jobDefinitonId}", jobsummary, () => _client.GetLatestSuccessfulJobForSpecification(specificationId, jobDefinitonId)); }
public async Task GetLatestJobByTriggerEntityId() { string specificationId = NewRandomString(); string entityId = NewRandomString(); JobSummary jobsummary = NewJobSummary(); await AssertGetRequest($"jobs/latest-by-entity-id?specificationId={specificationId}&entityId={entityId}", jobsummary, () => _client.GetLatestJobByTriggerEntityId(specificationId, entityId)); }
public async Task OnNotificationEvent_WhenChildJobWithSpecificationIdIsCreated_ThenSignalRMessagesAdded() { // Arrange NotificationService service = CreateService(); JobSummary jobNotification = new JobSummary() { CompletionStatus = null, JobId = JobId, JobType = "test", SpecificationId = SpecificationId, ParentJobId = "parentJobId1", }; string json = JsonConvert.SerializeObject(jobNotification); Message message = new Message(Encoding.UTF8.GetBytes(json)); IAsyncCollector <SignalRMessage> generatedMessages = CreateSignalRMessageCollector(); // Act await service.OnNotificationEvent(message, generatedMessages); // Assert await generatedMessages .Received(2) .AddAsync(Arg.Any <SignalRMessage>()); await generatedMessages .Received(1) .AddAsync( Arg.Is <SignalRMessage>( c => c.Target == JobConstants.NotificationsTargetFunction && c.Arguments.Length == 1 && c.Arguments.First() != null && c.GroupName == JobConstants.NotificationChannels.All)); await generatedMessages .Received(1) .AddAsync( Arg.Is <SignalRMessage>( c => c.Target == JobConstants.NotificationsTargetFunction && c.Arguments.Length == 1 && c.Arguments.First() != null && c.GroupName == $"{JobConstants.NotificationChannels.SpecificationPrefix}{SpecificationId.Replace("-", "")}")); await generatedMessages .Received(0) .AddAsync( Arg.Is <SignalRMessage>( c => c.Target == JobConstants.NotificationsTargetFunction && c.Arguments.Length == 1 && c.Arguments.First() != null && c.GroupName == JobConstants.NotificationChannels.ParentJobs)); }
public static JobViewModel ToViewModel(this JobSummary job) { if (job == null) { return(null); } return(new JobViewModel { Name = job.Name, Percent = job.Percent, Status = job.Status.ToString() }); }
private void GivenTheJobForTheJobId(Action <JobSummaryBuilder> setUp = null) { JobSummaryBuilder jobSummaryBuilder = new JobSummaryBuilder(); setUp?.Invoke(jobSummaryBuilder); _job = jobSummaryBuilder.Build(); _jobs.GetLatestJobsForSpecification(_specificationId, Arg.Is <IEnumerable <string> >(_ => _.Single() == JobConstants.DefinitionNames.CreateInstructAllocationJob)) .Returns(new[] { _job }); }
public async Task GetLatestSuccessfulJobs_WhenSucessfulJobForSpecificationAndJobDefinitionNOtExistsInCache_RetrieveAndReturnJobFromRepository() { // Arrange string specificationId = NewRandomString(); string jobDefinitionId = NewRandomString(); string jobId = NewRandomString(); Job job = new Job { Created = DateTimeOffset.UtcNow.AddHours(-1), Id = jobId, InvokerUserDisplayName = "test", InvokerUserId = "test1", JobDefinitionId = jobDefinitionId, LastUpdated = DateTimeOffset.UtcNow.AddHours(-1), RunningStatus = RunningStatus.InProgress, SpecificationId = specificationId, Trigger = new Trigger { EntityId = "calc1", EntityType = "Calculation", Message = "Calc run started" } }; ICacheProvider cacheProvider = CreateCacheProvider(); string cacheKey = $"{CacheKeys.LatestSuccessfulJobs}{specificationId}:{jobDefinitionId}"; cacheProvider.GetAsync <Job>(cacheKey).Returns((Job)null); IJobRepository jobRepository = CreateJobRepository(); jobRepository .GetLatestJobBySpecificationIdAndDefinitionId(specificationId, jobDefinitionId, CompletionStatus.Succeeded) .Returns(job); IJobService service = CreateJobService(cacheProvider: cacheProvider, jobRepository: jobRepository); // Act IActionResult result = await service.GetLatestSuccessfulJob(specificationId, jobDefinitionId); // Assert OkObjectResult okResult = result .Should() .BeOfType <OkObjectResult>() .Subject; JobSummary jobSummary = okResult.Value .Should() .BeAssignableTo <JobSummary>() .Subject; jobSummary.JobId.Should().Be(jobId); }
private async Task EnsureFeedbackCanBeGiven(JobSummary jobSummary, RequestRoles requestRole, int?userId) { if (jobSummary.JobStatus.Incomplete()) { throw new Exception($"Attempt to load feedback form for job {jobSummary.JobID}, but it is {jobSummary.JobStatus}"); } if (await _feedbackRepository.GetFeedbackExists(jobSummary.JobID, requestRole, userId)) { throw new Exception($"Attempt to load feedback form for job {jobSummary.JobID}, but feedback already exists for role {requestRole} / user {userId}"); } if (jobSummary.Archive == true) { throw new Exception($"Attempt to load feedback form for achived job {jobSummary.JobID}"); } }
public void GetJobs_CheckFieldsMapped() { // Arrange string entityId = "entity99"; IJobRepository jobRepository = CreateJobRepository(); jobRepository .GetJobs() .Returns(testData.AsQueryable()); IJobService jobService = CreateJobService(jobRepository); // Act IActionResult results = jobService.GetJobs(null, null, entityId, null, null, false, 1); // Assert OkObjectResult objResult = results .Should() .BeOfType <OkObjectResult>() .Subject; JobQueryResponseModel response = objResult.Value .Should() .BeOfType <JobQueryResponseModel>() .Subject; IEnumerable <JobSummary> summaries = response.Results; summaries .Should() .HaveCount(1); JobSummary item = summaries.First(); item.CompletionStatus.Should().Be(CompletionStatus.Succeeded); item.EntityId.Should().Be(entityId); item.InvokerUserDisplayName.Should().Be("Test User"); item.InvokerUserId.Should().Be("testuser"); item.JobId.Should().Be("job14"); item.JobType.Should().Be("jobType3"); item.ParentJobId.Should().Be("job1"); item.RunningStatus.Should().Be(RunningStatus.Completed); item.SpecificationId.Should().Be("spec123"); item.Created.Should().Be(DateTimeOffset.Parse("2018-12-20T15:15:00.000Z")); }
public async Task GetLatestJob_WhenSingleJobTypeGiven_ReturnLatestJobOfType() { // Arrange string specificationId = "spec123"; string jobType = "jobType1"; IJobRepository jobRepository = CreateJobRepository(); jobRepository .GetLatestJobBySpecificationId(Arg.Is(specificationId), Arg.Is <IEnumerable <string> >(m => m.First() == "jobType1")) .Returns( new Job { Created = DateTimeOffset.UtcNow.AddHours(-1), Id = "job1", InvokerUserDisplayName = "test", InvokerUserId = "test1", JobDefinitionId = "jobType1", LastUpdated = DateTimeOffset.UtcNow.AddHours(-1), RunningStatus = RunningStatus.InProgress, SpecificationId = specificationId, Trigger = new Trigger { EntityId = "calc1", EntityType = "Calculation", Message = "Calc run started" } }); IJobService service = CreateJobService(jobRepository); // Act IActionResult result = await service.GetLatestJob(specificationId, jobType); // Assert OkObjectResult okResult = result .Should() .BeOfType <OkObjectResult>() .Subject; JobSummary summary = okResult.Value .Should() .BeOfType <JobSummary>() .Subject; summary.JobId.Should().Be("job1"); }
public async Task OnNotificationEvent(Message message, IAsyncCollector <SignalRMessage> signalRMessages) { Guard.ArgumentNotNull(message, nameof(message)); Guard.ArgumentNotNull(signalRMessages, nameof(signalRMessages)); JobSummary jobNotification = message.GetPayloadAsInstanceOf <JobSummary>(); if (jobNotification == null) { throw new InvalidOperationException("Job notificiation was null"); } // Send to all notifications channel await signalRMessages.AddAsync( new SignalRMessage { Target = JobConstants.NotificationsTargetFunction, GroupName = JobConstants.NotificationChannels.All, Arguments = new[] { jobNotification } }); if (!string.IsNullOrWhiteSpace(jobNotification.SpecificationId)) { // Send to individual specifications group await signalRMessages.AddAsync( new SignalRMessage { Target = JobConstants.NotificationsTargetFunction, GroupName = $"{JobConstants.NotificationChannels.SpecificationPrefix}{jobNotification.SpecificationId.Replace("-", "")}", Arguments = new[] { jobNotification } }); } if (string.IsNullOrWhiteSpace(jobNotification.ParentJobId)) { // Send to parent jobs only group await signalRMessages.AddAsync( new SignalRMessage { Target = JobConstants.NotificationsTargetFunction, GroupName = JobConstants.NotificationChannels.ParentJobs, Arguments = new[] { jobNotification } }); } }
public async Task <bool> QueueJobAndWait(Func <Task <bool> > queueJob, string jobType, string specificationId, string correlationId, string jobNotificationTopic, double pollTimeout = 600000, double pollInterval = 120000) { if (IsServiceBusService) { await((IServiceBusService)_messengerService).CreateSubscription(jobNotificationTopic, correlationId, new TimeSpan(1, 0, 0, 0)); } bool jobQueued = await queueJob(); try { if (jobQueued) { if (IsServiceBusService) { JobSummary scopedJob = await _messengerService.ReceiveMessage <JobSummary>($"{jobNotificationTopic}/Subscriptions/{correlationId}", _ => { return(_?.JobType == jobType && _.SpecificationId == specificationId && (_.CompletionStatus == CompletionStatus.Succeeded || _.CompletionStatus == CompletionStatus.Failed)); }, TimeSpan.FromMilliseconds(pollTimeout)); return(scopedJob?.CompletionStatus == CompletionStatus.Succeeded); } else { return(await WaitForJobToComplete(jobType, specificationId, pollTimeout, pollInterval)); } } else { // if job not queued then return true return(true); } } finally { if (IsServiceBusService) { await((IServiceBusService)_messengerService).DeleteSubscription(jobNotificationTopic, correlationId); } } }
private async Task <bool> CheckAllJobs(string jobType, string specificationId, Predicate <JobSummary> predicate) { ApiResponse <IDictionary <string, JobSummary> > jobResponse = await _jobsApiClientPolicy.ExecuteAsync(() => { return(_jobsApiClient.GetLatestJobsForSpecification(specificationId, new string[] { jobType })); }); if ((int?)jobResponse?.StatusCode >= 200 && (int?)jobResponse?.StatusCode <= 299) { JobSummary summary = jobResponse.Content?.Values.FirstOrDefault(); return(predicate(summary)); } else { // any failures retrieving jobsummaries we ignore and keep polling as we don't know what state the jobs are in return(true); } }
public void BuildRequestModel_GivenJobNotificationWithDefinitionNotConfiguredForScaling_ContainsNoRepositoryTypes() { //Arrange JobSummary jobNotification = new JobSummary { JobType = "any-job-def-id" }; CosmosDbScalingRequestModelBuilder builder = new CosmosDbScalingRequestModelBuilder(); //Act CosmosDbScalingRequestModel requestModel = builder.BuildRequestModel(jobNotification); //Assert requestModel .RepositoryTypes .Should() .BeNull(); }
public async Task GetNonCompletedJobsWithinTimeFrame_Called_ReturnsJobSummaries() { string jobId = "5678"; DateTimeOffset from = DateTimeOffset.UtcNow.AddDays(-2); DateTimeOffset to = DateTimeOffset.UtcNow.AddDays(-1); IJobsApiClient jobsApiClient = Substitute.For <IJobsApiClient>(); JobManagementResiliencePolicies policies = new JobManagementResiliencePolicies { JobsApiClient = Policy.NoOpAsync() }; IMessengerService messengerService = Substitute.For <IMessengerService>(); ILogger logger = Substitute.For <ILogger>(); JobSummary jobSummary = new JobSummary { JobId = jobId }; IEnumerable <JobSummary> jobSummaries = new List <JobSummary> { jobSummary }; ApiResponse <IEnumerable <JobSummary> > jobSummariesApiResponse = new ApiResponse <IEnumerable <JobSummary> >(HttpStatusCode.OK, jobSummaries); jobsApiClient .GetNonCompletedJobsWithinTimeFrame(from, to) .Returns(jobSummariesApiResponse); JobManagement jobManagement = new JobManagement(jobsApiClient, logger, policies, messengerService); //Act IEnumerable <JobSummary> result = await jobManagement.GetNonCompletedJobsWithinTimeFrame(from, to); Assert.AreEqual(result, jobSummaries); await jobsApiClient .Received(1) .GetNonCompletedJobsWithinTimeFrame(from, to); }
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>()); }
public void SendNotification_WhenNoJobId_ThrowsArgumentException() { // Arrange INotificationService notificationService = CreateNotificationService(); JobSummary jobSummary = CreateJobSummary(); jobSummary.JobId = string.Empty; Func <Task> action = async() => await notificationService.SendNotification(jobSummary); // Act and Assert action .Should() .Throw <ArgumentException>() .And .ParamName .Should() .Be("JobId"); }
public void SendNotification_WhenNoTrigger_ThrowsArgumentNullException() { // Arrange INotificationService notificationService = CreateNotificationService(); JobSummary jobSummary = CreateJobSummary(); jobSummary.Trigger = null; Func <Task> action = async() => await notificationService.SendNotification(jobSummary); // Act and Assert action .Should() .Throw <ArgumentNullException>() .And .ParamName .Should() .Be("Trigger"); }
public void BuildRequestModel_GivenJobWithDefinitions_EnsuresCorrectRepositoryTypes(string jobDefinitionId, CosmosCollectionType[] cosmosRepositoryTypes) { //Arrange JobSummary jobNotification = new JobSummary { JobType = jobDefinitionId }; CosmosDbScalingRequestModelBuilder builder = new CosmosDbScalingRequestModelBuilder(); //Act CosmosDbScalingRequestModel requestModel = builder.BuildRequestModel(jobNotification); //Assert requestModel .RepositoryTypes .SequenceEqual(cosmosRepositoryTypes) .Should() .BeTrue(); }
private async Task QueueNotifications(IEnumerable <JobCreateResult> createdJobs, IEnumerable <JobDefinition> jobDefinitionsToSupersede) { List <Task> allTasks = new List <Task>(); SemaphoreSlim throttler = new SemaphoreSlim(initialCount: 30); foreach (JobCreateResult jobCreateResult in createdJobs) { await throttler.WaitAsync(); allTasks.Add( Task.Run(async() => { try { Job job = jobCreateResult.Job; JobDefinition jobDefinition = jobDefinitionsToSupersede.First(m => m.Id == job.JobDefinitionId); await QueueNewJob(job, jobDefinition, jobCreateResult.CreateRequest.Compress); JobSummary jobNotification = CreateJobNotificationFromJob(job); jobCreateResult.WasQueued = true; await _notificationService.SendNotification(jobNotification); } catch (QueueJobException queueJobException) { jobCreateResult.Error = queueJobException.Message; } finally { throttler.Release(); } })); } await TaskHelper.WhenAllAndThrow(allTasks.ToArray()); }