コード例 #1
0
        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,
                _searchParameterOperations,
                NullLogger <ReindexJobWorker> .Instance);

            await _reindexJobWorker.Handle(new SearchParametersInitializedNotification(), CancellationToken.None);

            var cancellationTokenSource = new CancellationTokenSource();

            try
            {
                await PerformReindexingOperation(response, OperationStatus.Canceled, cancellationTokenSource);
            }
            finally
            {
                cancellationTokenSource.Cancel();
            }
        }
コード例 #2
0
        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,
                _searchParameterOperations,
                NullLogger <ReindexJobWorker> .Instance);

            await _reindexJobWorker.Handle(new SearchParametersInitializedNotification(), CancellationToken.None);

            var cancellationTokenSource = new CancellationTokenSource();

            try
            {
                await PerformReindexingOperation(response, OperationStatus.Completed, cancellationTokenSource);

                Assert.True(searchParam.IsSearchable);
            }
            finally
            {
                cancellationTokenSource.Cancel();
                searchParam.IsSearchable = true;
            }
        }
コード例 #3
0
        public async Task GivenNewSearchParamCreatedAfterResourcesToBeIndexed_WhenReindexJobCompleted_ThenResourcesAreIndexedAndParamIsSearchable()
        {
            const string sampleName1 = "searchIndicesPatient1";
            const string sampleName2 = "searchIndicesPatient2";

            UpsertOutcome sample1 = await CreatePatientResource(sampleName1);

            UpsertOutcome sample2 = await CreatePatientResource(sampleName2);

            const string    searchParamName = "foo";
            const string    searchParamCode = "fooCode";
            SearchParameter searchParam     = await CreateSearchParam(searchParamName, searchParamCode);

            // Create the query <fhirserver>/Patient?foo=searchIndicesPatient1
            var queryParams = new List <Tuple <string, string> >()
            {
                new Tuple <string, string>(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(2, searchResults.Results.Count());

            // Set up the values that the search index extraction should return during reindexing
            MockSearchIndexExtraction(sampleName1, sampleName2, searchParam);

            CreateReindexResponse response = await SetUpForReindexing();

            var cancellationTokenSource = new CancellationTokenSource();

            try
            {
                await PerformReindexingOperation(response, OperationStatus.Completed, cancellationTokenSource);

                // Rerun the same search as above
                searchResults = await _searchService.Value.SearchAsync("Patient", queryParams, CancellationToken.None);

                // This time, foo should not be dropped from the query string
                Assert.Single(searchResults.Results);

                // The foo search parameter can be used to filter for the first test patient
                ResourceWrapper patient = searchResults.Results.FirstOrDefault().Resource;
                Assert.Contains(sampleName1, patient.RawResource.Data);
            }
            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);
            }
        }
コード例 #4
0
        public static async Task <ResourceElement> CreateReindexJobAsync(
            this IMediator mediator,
            ushort?maximumConcurrency,
            uint?maxResourcesPerQuery,
            int?queryDelay,
            ushort?targetDataStoreResourcePercentage,
            string targetResourceTypesString,
            CancellationToken cancellationToken)
        {
            EnsureArg.IsNotNull(mediator, nameof(mediator));

            var targetResourceTypes = new List <string>();

            if (!string.IsNullOrEmpty(targetResourceTypesString))
            {
                targetResourceTypes.AddRange(targetResourceTypesString.Split(",").Select(s => s.Trim()));
                foreach (var resourceType in targetResourceTypes)
                {
                    if (!Enum.TryParse <Hl7.Fhir.Model.ResourceType>(resourceType, out var result))
                    {
                        throw new RequestNotValidException(string.Format(Resources.ResourceNotSupported, resourceType));
                    }
                }
            }

            var request = new CreateReindexRequest(targetResourceTypes, maximumConcurrency, maxResourcesPerQuery, queryDelay, targetDataStoreResourcePercentage);

            CreateReindexResponse response = await mediator.Send(request, cancellationToken);

            return(response.Job.ToParametersResourceElement());
        }
コード例 #5
0
        public async Task GivenValidReindexParameter_WhenCreatingAReindexJob_ThenNewJobShouldBeCreated(string jobRecordProperty, int value)
        {
            CreateReindexRequest request;

            switch (jobRecordProperty)
            {
            case JobRecordProperties.MaximumConcurrency:
                request = new CreateReindexRequest(new List <string>(), (ushort?)value);
                break;

            case JobRecordProperties.MaximumNumberOfResourcesPerQuery:
                request = new CreateReindexRequest(new List <string>(), null, (uint?)value);
                break;

            case JobRecordProperties.QueryDelayIntervalInMilliseconds:
                request = new CreateReindexRequest(new List <string>(), null, null, value);
                break;

            case JobRecordProperties.TargetDataStoreUsagePercentage:
                request = new CreateReindexRequest(new List <string>(), null, null, null, (ushort?)value);
                break;

            default:
                request = new CreateReindexRequest(new List <string>()
                {
                    jobRecordProperty
                });
                break;
            }

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

            Assert.NotNull(response);
            Assert.False(string.IsNullOrWhiteSpace(response.Job.JobRecord.Id));
        }
コード例 #6
0
        public async Task GivenLessThanMaximumRunningJobs_WhenCreatingAReindexJob_ThenNewJobShouldBeCreated()
        {
            var request = new CreateReindexRequest(new List <string>());
            CreateReindexResponse response = await _createReindexRequestHandler.Handle(request, CancellationToken.None);

            Assert.NotNull(response);
            Assert.False(string.IsNullOrWhiteSpace(response.Job.JobRecord.Id));
        }
コード例 #7
0
        public async Task GivenAlreadyRunningJob_WhenCreatingAReindexJob_ThenJobConflictExceptionThrown()
        {
            var request = new CreateReindexRequest();

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

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

            await Assert.ThrowsAsync <JobConflictException>(() => _createReindexRequestHandler.Handle(request, CancellationToken.None));
        }
コード例 #8
0
        public static async Task <ResourceElement> CreateReindexJobAsync(
            this IMediator mediator,
            ushort?maximumConcurrency,
            CancellationToken cancellationToken)
        {
            EnsureArg.IsNotNull(mediator, nameof(mediator));

            var request = new CreateReindexRequest(maximumConcurrency);

            CreateReindexResponse response = await mediator.Send(request, cancellationToken);

            return(response.Job.ToParametersResourceElement());
        }
コード例 #9
0
        public async Task GivenOutOfRangeReindexParameter_WhenCreatingAReindexJob_ThenExceptionShouldBeThrown(string jobRecordProperty, int value)
        {
            string errorMessage = "Test error message";

            try
            {
                CreateReindexRequest request;
                switch (jobRecordProperty)
                {
                case JobRecordProperties.MaximumConcurrency:
                    request      = new CreateReindexRequest(new List <string>(), (ushort?)value);
                    errorMessage = string.Format(Fhir.Core.Resources.InvalidReIndexParameterValue, jobRecordProperty, ReindexJobRecord.MinMaximumConcurrency, ReindexJobRecord.MaxMaximumConcurrency);
                    break;

                case JobRecordProperties.MaximumNumberOfResourcesPerQuery:
                    request      = new CreateReindexRequest(new List <string>(), null, (uint?)value);
                    errorMessage = string.Format(Fhir.Core.Resources.InvalidReIndexParameterValue, jobRecordProperty, ReindexJobRecord.MinMaximumNumberOfResourcesPerQuery, ReindexJobRecord.MaxMaximumNumberOfResourcesPerQuery);
                    break;

                case JobRecordProperties.QueryDelayIntervalInMilliseconds:
                    request      = new CreateReindexRequest(new List <string>(), null, null, value);
                    errorMessage = string.Format(Fhir.Core.Resources.InvalidReIndexParameterValue, jobRecordProperty, ReindexJobRecord.MinQueryDelayIntervalInMilliseconds, ReindexJobRecord.MaxQueryDelayIntervalInMilliseconds);
                    break;

                case JobRecordProperties.TargetDataStoreUsagePercentage:
                    request      = new CreateReindexRequest(new List <string>(), null, null, null, (ushort?)value);
                    errorMessage = string.Format(Fhir.Core.Resources.InvalidReIndexParameterValue, jobRecordProperty, ReindexJobRecord.MinTargetDataStoreUsagePercentage, ReindexJobRecord.MaxTargetDataStoreUsagePercentage);
                    break;

                default:
                    request = new CreateReindexRequest(new List <string>()
                    {
                        jobRecordProperty
                    });
                    errorMessage = $"Resource type 'Foo' is not supported. (Parameter 'type')";
                    break;
                }

                CreateReindexResponse response = await _createReindexRequestHandler.Handle(request, CancellationToken.None);
            }
            catch (FhirException fhirExp)
            {
                Assert.NotNull(fhirExp);
                Assert.Equal(errorMessage.ToLower(), fhirExp.Message.ToLower());
            }
            catch (ArgumentException exp)
            {
                Assert.Equal(exp.Message.ToLower(), errorMessage.ToLower());
            }
        }
コード例 #10
0
        public static async Task <ResourceElement> CreateReindexJobAsync(
            this IMediator mediator,
            ushort?maximumConcurrency,
            uint?maxResourcesPerQuery,
            int?queryDelay,
            ushort?targetDataStoreResourcePercentage,
            CancellationToken cancellationToken)
        {
            EnsureArg.IsNotNull(mediator, nameof(mediator));

            var request = new CreateReindexRequest(maximumConcurrency, maxResourcesPerQuery, queryDelay, targetDataStoreResourcePercentage);

            CreateReindexResponse response = await mediator.Send(request, cancellationToken);

            return(response.Job.ToParametersResourceElement());
        }
コード例 #11
0
        private async Task <CreateReindexResponse> SetUpForReindexing()
        {
            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);
            return(response);
        }
コード例 #12
0
        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);
        }
コード例 #13
0
        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;
            }
        }
コード例 #14
0
        private async Task <CreateReindexResponse> SetUpForReindexing(CreateReindexRequest request = null)
        {
            if (request == null)
            {
                request = new CreateReindexRequest(new List <string>());
            }

            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,
                _searchParameterOperations,
                NullLogger <ReindexJobWorker> .Instance);

            await _reindexJobWorker.Handle(new SearchParametersInitializedNotification(), CancellationToken.None);

            return(response);
        }
コード例 #15
0
        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();
            }
        }
コード例 #16
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);
            }
        }
コード例 #17
0
        public async Task GivenNewSearchParamCreatedBeforeResourcesToBeIndexed_WhenReindexJobCompleted_ThenResourcesAreIndexedAndParamIsSearchable()
        {
            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);

            string sampleName1 = randomName + "searchIndicesPatient1";
            string sampleName2 = randomName + "searchIndicesPatient2";

            string sampleId1 = Guid.NewGuid().ToString();
            string sampleId2 = 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))
            };

            MockSearchIndexExtraction(searchValues, searchParam);

            UpsertOutcome sample1 = await CreatePatientResource(sampleName1, sampleId1);

            UpsertOutcome sample2 = await CreatePatientResource(sampleName2, sampleId2);

            // 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(2, searchResults.Results.Count());

            CreateReindexResponse response = await SetUpForReindexing();

            var cancellationTokenSource = new CancellationTokenSource();

            try
            {
                await PerformReindexingOperation(response, OperationStatus.Completed, cancellationTokenSource);

                // Rerun the same search as above
                searchResults = await _searchService.Value.SearchAsync("Patient", queryParams, CancellationToken.None);

                // This time, foo should not be dropped from the query string
                Assert.Single(searchResults.Results);

                // The foo search parameter can be used to filter for the first test patient
                ResourceWrapper patient = searchResults.Results.FirstOrDefault().Resource;
                Assert.Contains(sampleName1, patient.RawResource.Data);

                // Confirm that the reindexing operation did not create a new version of the resource
                Assert.Equal("1", searchResults.Results.FirstOrDefault().Resource.Version);
            }
            finally
            {
                cancellationTokenSource.Cancel();

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

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

                await _fixture.DataStore.HardDeleteAsync(sample2.Wrapper.ToResourceKey(), false, CancellationToken.None);
            }
        }
コード例 #18
0
        public async Task GivenNewSearchParamWithResourceBaseType_WhenReindexJobCompleted_ThenAllResourcesAreIndexedAndParamIsSearchable()
        {
            string patientId     = Guid.NewGuid().ToString();
            string observationId = Guid.NewGuid().ToString();

            UpsertOutcome samplePatient = await CreatePatientResource("samplePatient", patientId);

            UpsertOutcome sampleObservation = await CreateObservationResource(observationId);

            const string    searchParamName = "resourceFoo";
            const string    searchParamCode = "resourceFooCode";
            SearchParameter searchParam     = await CreateSearchParam(searchParamName, SearchParamType.Token, ResourceType.Resource, "Resource.id", searchParamCode);

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

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

            // Set up the values that the search index extraction should return during reindexing
            var searchValues = new List <(string, ISearchValue)> {
                (patientId, new TokenSearchValue(null, patientId, null)), (observationId, new TokenSearchValue(null, observationId, null))
            };

            MockSearchIndexExtraction(searchValues, searchParam);

            CreateReindexResponse response = await SetUpForReindexing();

            var cancellationTokenSource = new CancellationTokenSource();

            try
            {
                await PerformReindexingOperation(response, OperationStatus.Completed, cancellationTokenSource);

                // Rerun the same search as above
                searchResults = await _searchService.Value.SearchAsync("Patient", queryParams, CancellationToken.None);

                Assert.Single(searchResults.Results);

                // Confirm that the search parameter "resourceFoo" isn't marked as unsupported
                Assert.DoesNotContain(searchResults.UnsupportedSearchParameters, t => t.Item1 == searchParamCode);

                // Create the query <fhirserver>/Patient?resourceFooCode=<nonexistent-id>
                queryParams = new List <Tuple <string, string> > {
                    new(searchParamCode, "nonexistent-id")
                };

                // No resources should be returned
                searchResults = await _searchService.Value.SearchAsync("Patient", queryParams, CancellationToken.None);

                Assert.Empty(searchResults.Results);

                // Create the query <fhirserver>/Observation?resourceFooCode=<observationId>
                queryParams = new List <Tuple <string, string> > {
                    new(searchParamCode, observationId)
                };

                // Check that the new search parameter can be used with a different type of resource
                searchResults = await _searchService.Value.SearchAsync("Observation", queryParams, CancellationToken.None);

                Assert.Single(searchResults.Results);

                // Confirm that the search parameter "resourceFoo" isn't marked as unsupported
                Assert.DoesNotContain(searchResults.UnsupportedSearchParameters, t => t.Item1 == searchParamCode);

                // Create the query <fhirserver>/Observation?resourceFooCode=<nonexistent-id>
                queryParams = new List <Tuple <string, string> > {
                    new(searchParamCode, "nonexistent-id")
                };

                // No resources should be returned
                searchResults = await _searchService.Value.SearchAsync("Observation", queryParams, CancellationToken.None);

                Assert.Empty(searchResults.Results);
            }
            finally
            {
                cancellationTokenSource.Cancel();

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

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

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