Example #1
0
        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);
            }
        }
Example #2
0
        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);
        }
Example #5
0
        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);
            }));
        }
Example #6
0
        private async Task UpdateJobRecord(ExportJobRecord jobRecord, CancellationToken cancellationToken)
        {
            ExportJobOutcome updatedExportJobOutcome = await _fhirOperationDataStore.UpdateExportJobAsync(jobRecord, _weakETag, cancellationToken);

            _exportJobRecord = updatedExportJobOutcome.JobRecord;
            _weakETag        = updatedExportJobOutcome.ETag;
        }
Example #7
0
        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);
            });
        }
Example #10
0
        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);
        }
Example #11
0
        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);
            }));
        }