public async Task GivenAFhirMediator_WhenCancelingExistingExportJobEncountersJobConflictException_ThenItWillBeRetried() { _retryCount = 3; var weakETags = new WeakETag[] { WeakETag.FromVersionId("1"), WeakETag.FromVersionId("2"), WeakETag.FromVersionId("3"), }; var jobRecord = CreateExportJobRecord(OperationStatus.Queued); _fhirOperationDataStore.GetExportJobByIdAsync(JobId, _cancellationToken) .Returns( _ => CreateExportJobOutcome(CreateExportJobRecord(OperationStatus.Queued), weakETags[0]), _ => CreateExportJobOutcome(CreateExportJobRecord(OperationStatus.Queued), weakETags[1]), _ => CreateExportJobOutcome(CreateExportJobRecord(OperationStatus.Queued), weakETags[2])); SetupOperationDataStore(0, _ => throw new JobConflictException()); SetupOperationDataStore(1, _ => throw new JobConflictException()); SetupOperationDataStore(2, _ => CreateExportJobOutcome(jobRecord, WeakETag.FromVersionId("123"))); // No error should be thrown. CancelExportResponse response = await _mediator.CancelExportAsync(JobId, _cancellationToken); Assert.Equal(HttpStatusCode.Accepted, response.StatusCode); void SetupOperationDataStore(int index, Func <NSubstitute.Core.CallInfo, ExportJobOutcome> returnThis) { _fhirOperationDataStore.UpdateExportJobAsync(Arg.Any <ExportJobRecord>(), weakETags[index], Arg.Any <CancellationToken>()) .Returns(returnThis); } }
public ExportJobTaskTests() { _cancellationToken = _cancellationTokenSource.Token; _fhirOperationDataStore.UpdateExportJobAsync(_exportJobRecord, _weakETag, _cancellationToken).Returns(x => new ExportJobOutcome(_exportJobRecord, _weakETag)); _exportJobTask = new ExportJobTask( _fhirOperationDataStore, NullLogger <ExportJobTask> .Instance); }
public async Task GivenARunningJob_WhenUpdatingTheJob_ThenTheJobShouldBeUpdated() { ExportJobOutcome jobOutcome = await CreateRunningJob(); ExportJobRecord job = jobOutcome.JobRecord; job.Status = OperationStatus.Completed; await _operationDataStore.UpdateExportJobAsync(job, jobOutcome.ETag, CancellationToken.None); ExportJobOutcome updatedJobOutcome = await _operationDataStore.GetExportJobByIdAsync(job.Id, CancellationToken.None); ValidateExportJobOutcome(job, updatedJobOutcome?.JobRecord); }
public ExportJobTaskTests() { _cancellationToken = _cancellationTokenSource.Token; _exportJobRecord = new ExportJobRecord( new Uri("https://localhost/ExportJob/"), "Patient", "hash"); _fhirOperationDataStore.UpdateExportJobAsync(_exportJobRecord, _weakETag, _cancellationToken).Returns(x => { _lastExportJobOutcome = new ExportJobOutcome(_exportJobRecord, _weakETag); return(_lastExportJobOutcome); }); _secretStore.GetSecretAsync(Arg.Any <string>(), _cancellationToken).Returns(x => new SecretWrapper(x.ArgAt <string>(0), "{\"destinationType\": \"in-memory\"}")); _exportDestinationClientFactory.Create("in-memory").Returns(_inMemoryDestinationClient); _resourceToByteArraySerializer.Serialize(Arg.Any <ResourceWrapper>()).Returns(x => Encoding.UTF8.GetBytes(x.ArgAt <ResourceWrapper>(0).ResourceId)); _exportJobTask = new ExportJobTask( () => _fhirOperationDataStore.CreateMockScope(), _secretStore, Options.Create(_exportJobConfiguration), () => _searchService.CreateMockScope(), _resourceToByteArraySerializer, _exportDestinationClientFactory, NullLogger <ExportJobTask> .Instance); }
public async Task <CancelExportResponse> Handle(CancelExportRequest request, CancellationToken cancellationToken) { EnsureArg.IsNotNull(request, nameof(request)); if (_authorizationService.CheckAccess(DataActions.Export) != DataActions.Export) { throw new UnauthorizedFhirActionException(); } return(await _retryPolicy.ExecuteAsync(async() => { ExportJobOutcome outcome = await _fhirOperationDataStore.GetExportJobByIdAsync(request.JobId, cancellationToken); // If the job is already completed for any reason, return conflict status. if (outcome.JobRecord.Status.IsFinished()) { return new CancelExportResponse(HttpStatusCode.Conflict); } // Try to cancel the job. outcome.JobRecord.Status = OperationStatus.Canceled; outcome.JobRecord.CanceledTime = Clock.UtcNow; outcome.JobRecord.FailureDetails = new ExportJobFailureDetails(Resources.UserRequestedCancellation, HttpStatusCode.NoContent); await _fhirOperationDataStore.UpdateExportJobAsync(outcome.JobRecord, outcome.ETag, cancellationToken); return new CancelExportResponse(HttpStatusCode.Accepted); })); }
private async Task UpdateJobRecord(ExportJobRecord jobRecord, CancellationToken cancellationToken) { ExportJobOutcome updatedExportJobOutcome = await _fhirOperationDataStore.UpdateExportJobAsync(jobRecord, _weakETag, cancellationToken); _exportJobRecord = updatedExportJobOutcome.JobRecord; _weakETag = updatedExportJobOutcome.ETag; }
private async Task UpdateJobStatus(OperationStatus operationStatus, CancellationToken cancellationToken) { _exportJobRecord.Status = operationStatus; ExportJobOutcome updatedExportJobOutcome = await _fhirOperationDataStore.UpdateExportJobAsync(_exportJobRecord, _weakETag, cancellationToken); _weakETag = updatedExportJobOutcome.ETag; }
private void SetupExportJobRecordAndOperationDataStore(ExportJobRecord exportJobRecord = null) { _exportJobRecord = exportJobRecord ?? new ExportJobRecord( new Uri("https://localhost/ExportJob/"), "Patient", "hash"); _fhirOperationDataStore.UpdateExportJobAsync(_exportJobRecord, _weakETag, _cancellationToken).Returns(x => { _lastExportJobOutcome = new ExportJobOutcome(_exportJobRecord, _weakETag); return(_lastExportJobOutcome); }); }
private void SetupExportJobRecordAndOperationDataStore(ExportJobRecord exportJobRecord = null) { _exportJobRecord = exportJobRecord ?? new ExportJobRecord( new Uri("https://localhost/ExportJob/"), "Patient", "hash", storageAccountConnectionHash: string.Empty, storageAccountUri: _exportJobConfiguration.StorageAccountUri); _fhirOperationDataStore.UpdateExportJobAsync(_exportJobRecord, _weakETag, _cancellationToken).Returns(x => { _lastExportJobOutcome = new ExportJobOutcome(_exportJobRecord, _weakETag); return(_lastExportJobOutcome); }); }
public async Task GivenAnExportJobRecordThatWasUpdated_WhenExecuted_ThenTheExportJobRecordShouldBeUpdated() { ExportJobOutcome initialJob = await CreateAndExecuteCreateExportJobAsync(); // Update the job to be canceled. ExportJobRecord jobRecord = initialJob.JobRecord; jobRecord.Status = OperationStatus.Cancelled; ExportJobOutcome updatedJob = await _fhirOperationDataStore.UpdateExportJobAsync(jobRecord, initialJob.ETag, CancellationToken.None); // Create a new task with the old ETag. await _exportJobTask.ExecuteAsync(initialJob.JobRecord, initialJob.ETag, CancellationToken.None); ExportJobOutcome actual = await _fhirOperationDataStore.GetExportJobByIdAsync(jobRecord.Id, CancellationToken.None); Assert.NotNull(actual); // The job should remain canceled since it shouldn't have been able to acquire the job. Assert.Equal(OperationStatus.Cancelled, actual.JobRecord.Status); }
public async Task <CancelExportResponse> Handle(CancelExportRequest request, CancellationToken cancellationToken) { EnsureArg.IsNotNull(request, nameof(request)); return(await _retryPolicy.ExecuteAsync(async() => { ExportJobOutcome outcome = await _fhirOperationDataStore.GetExportJobByIdAsync(request.JobId, cancellationToken); // If the job is already completed for any reason, return conflict status. if (outcome.JobRecord.Status.IsFinished()) { return new CancelExportResponse(HttpStatusCode.Conflict); } // Try to cancel the job. outcome.JobRecord.Status = OperationStatus.Canceled; outcome.JobRecord.CanceledTime = Clock.UtcNow; await _fhirOperationDataStore.UpdateExportJobAsync(outcome.JobRecord, outcome.ETag, cancellationToken); return new CancelExportResponse(HttpStatusCode.Accepted); })); }