Example #1
0
        public async Task GivenAMatchingReindexJob_WhenGettingById_ThenTheMatchingReindexJobShouldBeReturned()
        {
            ReindexJobRecord jobRecord = await InsertNewReindexJobRecordAsync();

            ReindexJobWrapper jobWrapper = await _operationDataStore.GetReindexJobByIdAsync(jobRecord.Id, CancellationToken.None);

            Assert.Equal(jobRecord.Id, jobWrapper?.JobRecord?.Id);
        }
Example #2
0
        public async Task <CancelReindexResponse> Handle(CancelReindexRequest request, CancellationToken cancellationToken)
        {
            EnsureArg.IsNotNull(request, nameof(request));

            if (await _authorizationService.CheckAccess(DataActions.Reindex, cancellationToken) != DataActions.Reindex)
            {
                throw new UnauthorizedFhirActionException();
            }

            return(await _retryPolicy.ExecuteAsync(async() =>
            {
                ReindexJobWrapper outcome = await _fhirOperationDataStore.GetReindexJobByIdAsync(request.JobId, cancellationToken);

                // If the job is already completed for any reason, return conflict status.
                if (outcome.JobRecord.Status.IsFinished())
                {
                    throw new RequestNotValidException(
                        string.Format(Resources.ReindexJobInCompletedState, outcome.JobRecord.Id, outcome.JobRecord.Status));
                }

                // Try to cancel the job.
                outcome.JobRecord.Status = OperationStatus.Canceled;
                outcome.JobRecord.CanceledTime = Clock.UtcNow;

                await _fhirOperationDataStore.UpdateReindexJobAsync(outcome.JobRecord, outcome.ETag, cancellationToken);

                return new CancelReindexResponse(HttpStatusCode.Conflict, outcome);
            }));
        }
        private async Task PerformReindexingOperation(CreateReindexResponse response, OperationStatus operationStatus, CancellationTokenSource cancellationTokenSource)
        {
            Task reindexWorkerTask = _reindexJobWorker.ExecuteAsync(cancellationTokenSource.Token);
            ReindexJobWrapper reindexJobWrapper = await _fhirOperationDataStore.GetReindexJobByIdAsync(response.Job.JobRecord.Id, cancellationTokenSource.Token);

            int delayCount = 0;

            while (reindexJobWrapper.JobRecord.Status != operationStatus && delayCount < 10)
            {
                await Task.Delay(1000);

                delayCount++;
                reindexJobWrapper = await _fhirOperationDataStore.GetReindexJobByIdAsync(response.Job.JobRecord.Id, cancellationTokenSource.Token);
            }

            Assert.InRange(delayCount, 0, 9);
        }
Example #4
0
        private async Task <GetReindexResponse> GetSingleReindexJobAsync(string jobId, CancellationToken cancellationToken)
        {
            try
            {
                ReindexJobWrapper reindexJob = await _fhirOperationDataStore.GetReindexJobByIdAsync(jobId, cancellationToken);

                return(new GetReindexResponse(HttpStatusCode.OK, reindexJob));
            }
            catch (Exception ex)
            {
                throw new OperationFailedException($"Unable to read reindex job with id {jobId}, error: {ex.Message}", HttpStatusCode.BadRequest);
            }
        }
        public async Task GivenAGetRequest_WhenGettingAnExistingJob_ThenHttpResponseCodeShouldBeOk()
        {
            var request = new GetReindexRequest("id");

            var jobRecord  = new ReindexJobRecord("hash", 1, null);
            var jobWrapper = new ReindexJobWrapper(jobRecord, WeakETag.FromVersionId("id"));

            _fhirOperationDataStore.GetReindexJobByIdAsync("id", Arg.Any <CancellationToken>()).Returns(jobWrapper);

            var handler = new GetReindexRequestHandler(_fhirOperationDataStore, DisabledFhirAuthorizationService.Instance);

            var result = await handler.Handle(request, CancellationToken.None);

            Assert.Equal(HttpStatusCode.OK, result.StatusCode);
        }
        public async Task GivenNoSupportedSearchParameters_WhenRunningReindexJob_ThenJobIsCanceled()
        {
            var request = new CreateReindexRequest();

            CreateReindexResponse response = await _createReindexRequestHandler.Handle(request, CancellationToken.None);

            Assert.NotNull(response);
            Assert.False(string.IsNullOrWhiteSpace(response.Job.JobRecord.Id));

            _reindexJobWorker = new ReindexJobWorker(
                () => _scopedOperationDataStore,
                Options.Create(_jobConfiguration),
                InitializeReindexJobTask,
                NullLogger <ReindexJobWorker> .Instance);

            var cancellationTokenSource = new CancellationTokenSource();

            try
            {
                var reindexWorkerTask = _reindexJobWorker.ExecuteAsync(cancellationTokenSource.Token);
                var reindexJobWrapper = await _fhirOperationDataStore.GetReindexJobByIdAsync(response.Job.JobRecord.Id, cancellationTokenSource.Token);

                int delayCount = 0;
                while (reindexJobWrapper.JobRecord.Status != OperationStatus.Canceled &&
                       delayCount < 10)
                {
                    await Task.Delay(1000);

                    delayCount++;
                    reindexJobWrapper = await _fhirOperationDataStore.GetReindexJobByIdAsync(response.Job.JobRecord.Id, cancellationTokenSource.Token);
                }

                Assert.True(delayCount <= 9);
            }
            finally
            {
                cancellationTokenSource.Cancel();
            }
        }
Example #7
0
        public async Task GivenReindexJobRunning_WhenReindexJobCancelRequest_ThenReindexJobStopsAndMarkedCanceled()
        {
            var             randomName      = Guid.NewGuid().ToString().ComputeHash().Substring(0, 14).ToLower();
            string          searchParamName = randomName;
            string          searchParamCode = randomName + "Code";
            SearchParameter searchParam     = await CreateSearchParam(searchParamName, SearchParamType.String, ResourceType.Patient, "Patient.name", searchParamCode);

            const string sampleName1 = "searchIndicesPatient1";
            const string sampleName2 = "searchIndicesPatient2";
            const string sampleName3 = "searchIndicesPatient3";
            const string sampleName4 = "searchIndicesPatient4";

            string sampleId1 = Guid.NewGuid().ToString();
            string sampleId2 = Guid.NewGuid().ToString();
            string sampleId3 = Guid.NewGuid().ToString();
            string sampleId4 = Guid.NewGuid().ToString();

            // Set up the values that the search index extraction should return during reindexing
            var searchValues = new List <(string, ISearchValue)>
            {
                (sampleId1, new StringSearchValue(sampleName1)),
                (sampleId2, new StringSearchValue(sampleName2)),
                (sampleId3, new StringSearchValue(sampleName3)),
                (sampleId4, new StringSearchValue(sampleName4)),
            };

            MockSearchIndexExtraction(searchValues, searchParam);

            UpsertOutcome sample1 = await CreatePatientResource(sampleName1, sampleId1);

            UpsertOutcome sample2 = await CreatePatientResource(sampleName2, sampleId2);

            UpsertOutcome sample3 = await CreatePatientResource(sampleName3, sampleId3);

            UpsertOutcome sample4 = await CreatePatientResource(sampleName4, sampleId4);

            // Create the query <fhirserver>/Patient?foo=searchIndicesPatient1
            var queryParams = new List <Tuple <string, string> > {
                new(searchParamCode, sampleName1)
            };
            SearchResult searchResults = await _searchService.Value.SearchAsync("Patient", queryParams, CancellationToken.None);

            // Confirm that the search parameter "foo" is marked as unsupported
            Assert.Equal(searchParamCode, searchResults.UnsupportedSearchParameters.FirstOrDefault()?.Item1);

            // When search parameters aren't recognized, they are ignored
            // Confirm that "foo" is dropped from the query string and all patients are returned
            Assert.Equal(4, searchResults.Results.Count());

            var createReindexRequest       = new CreateReindexRequest(1, 1, 500);
            CreateReindexResponse response = await SetUpForReindexing(createReindexRequest);

            var cancellationTokenSource = new CancellationTokenSource();

            try
            {
                var  cancelReindexHandler = new CancelReindexRequestHandler(_fhirOperationDataStore, DisabledFhirAuthorizationService.Instance);
                Task reindexWorkerTask    = _reindexJobWorker.ExecuteAsync(cancellationTokenSource.Token);
                await cancelReindexHandler.Handle(new CancelReindexRequest(response.Job.JobRecord.Id), CancellationToken.None);

                var reindexWrapper = await _fhirOperationDataStore.GetReindexJobByIdAsync(response.Job.JobRecord.Id, cancellationTokenSource.Token);

                Assert.Equal(OperationStatus.Canceled, reindexWrapper.JobRecord.Status);
            }
            catch (RequestNotValidException ex)
            {
                // Despite the settings above of the create reindex request which processes only one resource
                // every 500ms, sometimes when the test runs the reindex job is completed before the
                // the cancellation request is processed.  We will ignore this error
                if (!ex.Message.Contains("in state Completed and cannot be cancelled", StringComparison.OrdinalIgnoreCase))
                {
                    throw;
                }
            }
            finally
            {
                cancellationTokenSource.Cancel();

                _searchParameterDefinitionManager.DeleteSearchParameter(searchParam.ToTypedElement());
                await _testHelper.DeleteSearchParameterStatusAsync(searchParam.Url, CancellationToken.None);

                await _fixture.DataStore.HardDeleteAsync(sample1.Wrapper.ToResourceKey(), CancellationToken.None);

                await _fixture.DataStore.HardDeleteAsync(sample2.Wrapper.ToResourceKey(), CancellationToken.None);

                await _fixture.DataStore.HardDeleteAsync(sample3.Wrapper.ToResourceKey(), CancellationToken.None);

                await _fixture.DataStore.HardDeleteAsync(sample4.Wrapper.ToResourceKey(), CancellationToken.None);
            }
        }