public async Task GivenThereIsNoRunningJob_WhenExecuted_ThenATaskShouldBeCreated()
        {
            ReindexJobWrapper job = CreateReindexJobWrapper();

            SetupOperationDataStore(job);

            _cancellationTokenSource.CancelAfter(DefaultJobPollingFrequency);

            await _reindexJobWorker.ExecuteAsync(_cancellationToken);

            _reindexJobTaskFactory().Received(1);
        }
 protected override async Task ExecuteAsync(CancellationToken stoppingToken)
 {
     if (_reindexJobConfiguration.Enabled)
     {
         await _reindexJobWorker.ExecuteAsync(stoppingToken);
     }
 }
        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);
        }
        public async Task GivenNoMatchingResources_WhenRunningReindexJob_ThenJobIsCompleted()
        {
            var searchParam = _supportedSearchParameterDefinitionManager.GetSearchParameter(new Uri("http://hl7.org/fhir/SearchParameter/Measure-name"));

            searchParam.IsSearchable = false;
            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.Completed &&
                       delayCount < 10)
                {
                    await Task.Delay(1000);

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

                Assert.True(delayCount <= 9);
                Assert.True(searchParam.IsSearchable);
            }
            finally
            {
                cancellationTokenSource.Cancel();
                searchParam.IsSearchable = true;
            }
        }
        public async Task GivenNewSearchParam_WhenReindexJobCompleted_ThenParamIsSearchable()
        {
            var searchParamName = "foo";
            var searchParamCode = "fooCode";
            var searchParam     = new SearchParameterInfo(
                name: searchParamName,
                code: searchParamCode,
                searchParamType: ValueSets.SearchParamType.String,
                url: new Uri("http://hl7.org/fhir/SearchParameter/Patient-foo"),
                components: null,
                expression: "Patient.name",
                targetResourceTypes: null,
                baseResourceTypes: new List <string>()
            {
                "Patient"
            })
            {
                IsSupported  = true,
                IsSearchable = false,
            };

            _searchParameterDefinitionManager.UrlLookup.TryAdd(searchParam.Url, searchParam);
            _searchParameterDefinitionManager.TypeLookup["Patient"].TryAdd(searchParamCode, searchParam);

            await UpsertPatientData("searchIndicesPatient1");
            await UpsertPatientData("searchIndicesPatient2");

            var queryParams = new List <Tuple <string, string> >()
            {
                new Tuple <string, string>("fooCode", "searchIndicesPatient1")
            };
            var searchResults = await _searchService.Value.SearchAsync("Patient", queryParams, CancellationToken.None);

            Assert.Equal(searchParamCode, searchResults.UnsupportedSearchParameters.FirstOrDefault().Item1);
            Assert.Equal(2, searchResults.Results.Count());

            var searchIndexValues1 = new List <SearchIndexEntry>();

            searchIndexValues1.Add(new SearchIndexEntry(searchParam, new StringSearchValue("searchIndicesPatient1")));
            _searchIndexer.Extract(Arg.Is <ResourceElement>(r => r.Id.Equals("searchIndicesPatient1"))).Returns(searchIndexValues1);

            var searchIndexValues2 = new List <SearchIndexEntry>();

            searchIndexValues2.Add(new SearchIndexEntry(searchParam, new StringSearchValue("searchIndicesPatient2")));
            _searchIndexer.Extract(Arg.Is <ResourceElement>(r => r.Id.Equals("searchIndicesPatient2"))).Returns(searchIndexValues2);

            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.Completed &&
                       delayCount < 10)
                {
                    await Task.Delay(1000);

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

                Assert.True(delayCount <= 9);

                searchResults = await _searchService.Value.SearchAsync("Patient", queryParams, CancellationToken.None);

                Assert.Single(searchResults.Results);

                var patient = searchResults.Results.FirstOrDefault().Resource;
                Assert.Contains("searchIndicesPatient1", patient.RawResource.Data);
            }
            finally
            {
                cancellationTokenSource.Cancel();
            }
        }
Example #6
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);
            }
        }