public async Task GivenSeriesTag_WhenReindexWithOldInstance_ThenTagValueShouldNotBeUpdated()
        {
            DicomTag tag       = DicomTag.AcquisitionDeviceProcessingCode;
            string   tagValue1 = "test1";
            string   tagValue2 = "test2";

            string studyUid  = TestUidGenerator.Generate();
            string seriesUid = TestUidGenerator.Generate();

            DicomDataset dataset1 = Samples.CreateRandomInstanceDataset(studyUid, seriesUid);

            dataset1.Add(tag, tagValue1);
            DicomDataset dataset2 = Samples.CreateRandomInstanceDataset(studyUid, seriesUid);

            dataset2.Add(tag, tagValue2);
            Instance instance1 = await CreateInstanceIndexAsync(dataset1);

            Instance instance2 = await CreateInstanceIndexAsync(dataset2);

            var tagStoreEntry = await AddExtendedQueryTagAsync(tag.BuildAddExtendedQueryTagEntry(level: QueryTagLevel.Series));

            QueryTag queryTag = new QueryTag(tagStoreEntry);

            await _indexDataStore.ReindexInstanceAsync(dataset2, instance2.Watermark, new[] { queryTag });

            await _indexDataStore.ReindexInstanceAsync(dataset1, instance1.Watermark, new[] { queryTag });

            var row = (await _extendedQueryTagStoreTestHelper.GetExtendedQueryTagDataAsync(ExtendedQueryTagDataType.StringData, tagStoreEntry.Key, instance1.StudyKey, instance1.SeriesKey, null)).First();

            Assert.Equal(tagValue2, row.TagValue);
        }
示例#2
0
        public async Task GivenValidAndInvalidTagValues_WhenValidate_ThenReturnedValidTagsAndStoredFailure()
        {
            DicomTag     tag1     = DicomTag.DeviceSerialNumber;
            DicomTag     tag2     = DicomTag.DeviceID;
            DicomDataset ds       = Samples.CreateRandomInstanceDataset();
            DicomElement element1 = new DicomLongString(tag1, "testvalue1");
            DicomElement element2 = new DicomLongString(tag2, "testvalue2");

            ds.Add(element1);
            ds.Add(element2);
            QueryTag queryTag1 = new QueryTag(new ExtendedQueryTagStoreEntry(1, tag1.GetPath(), tag1.GetDefaultVR().Code, null, QueryTagLevel.Instance, ExtendedQueryTagStatus.Ready, QueryStatus.Enabled, 0));
            QueryTag queryTag2 = new QueryTag(new ExtendedQueryTagStoreEntry(2, tag2.GetPath(), tag2.GetDefaultVR().Code, null, QueryTagLevel.Instance, ExtendedQueryTagStatus.Ready, QueryStatus.Enabled, 0));

            // Throw exception when validate element1
            var ex = ElementValidationExceptionFactory.CreateDateIsInvalidException("testname", "testvalue");

            _minimumValidator.When(x => x.Validate(element1))
            .Throw(ex);

            // only return querytag2
            long watermark      = 1;
            var  validQueryTags = await _datasetValidator.ValidateAsync(ds, watermark, new[] { queryTag1, queryTag2 });

            Assert.Single(validQueryTags);
            Assert.Same(queryTag2, validQueryTags.First());

            // error for querytag1 is logged
            await _tagErrorsService.Received(1)
            .AddExtendedQueryTagErrorAsync(queryTag1.ExtendedQueryTagStoreEntry.Key, ex.ErrorCode, 1, Arg.Any <CancellationToken>());
        }
        private async Task ValidateAddNewExtendedQueryTagIndexData(QueryTagLevel level)
        {
            string       studyInstanceUid  = TestUidGenerator.Generate();
            string       seriesInstanceUid = TestUidGenerator.Generate();
            string       sopInstanceUid    = TestUidGenerator.Generate();
            DicomDataset dataset           = Samples.CreateRandomInstanceDataset(studyInstanceUid, seriesInstanceUid, sopInstanceUid);
            DicomTag     tag   = DicomTag.ConversionType;
            string       value = "SYN";

            dataset.Add(tag, value);

            QueryTag queryTag = await AddExtendedQueryTag(tag.BuildAddExtendedQueryTagEntry(level: level));

            try
            {
                long watermark = await CreateInstanceIndexAsync(dataset, new QueryTag[] { queryTag });

                Instance instance = await _testHelper.GetInstanceAsync(studyInstanceUid, seriesInstanceUid, sopInstanceUid, watermark);

                long?seriesKey   = level != QueryTagLevel.Study ? instance.SeriesKey : null;
                long?instanceKey = level == QueryTagLevel.Instance ? instance.InstanceKey : null;
                var  stringRows  = await _extendedQueryTagStoreTestHelper.GetExtendedQueryTagDataAsync(ExtendedQueryTagDataType.StringData, queryTag.ExtendedQueryTagStoreEntry.Key, instance.StudyKey, seriesKey, instanceKey);

                Assert.Single(stringRows);
                Assert.Equal(stringRows[0].TagValue, value);
                Assert.Equal(stringRows[0].Watermark, watermark);
            }
            finally
            {
                await _extendedQueryTagStore.DeleteExtendedQueryTagAsync(queryTag.ExtendedQueryTagStoreEntry.Path, queryTag.ExtendedQueryTagStoreEntry.VR);
            }
        }
示例#4
0
        public async Task GivenExistingExtendedQueryTagIndexData_WhenDeleteExtendedQueryTag_ThenShouldDeleteIndexData()
        {
            DicomTag tag = DicomTag.DeviceSerialNumber;

            // Prepare index data
            DicomDataset dataset = Samples.CreateRandomInstanceDataset();

            dataset.Add(tag, "123");

            await AddExtendedQueryTagsAsync(new AddExtendedQueryTagEntry[] { tag.BuildAddExtendedQueryTagEntry() });

            ExtendedQueryTagStoreEntry storeEntry = await _extendedQueryTagStore.GetExtendedQueryTagAsync(tag.GetPath());

            QueryTag queryTag  = new QueryTag(storeEntry);
            long     watermark = await _indexDataStore.BeginCreateInstanceIndexAsync(1, dataset, new QueryTag[] { queryTag });

            await _indexDataStore.EndCreateInstanceIndexAsync(1, dataset, watermark, new QueryTag[] { queryTag });

            var extendedQueryTagIndexData = await _extendedQueryTagStoreTestHelper.GetExtendedQueryTagDataForTagKeyAsync(ExtendedQueryTagDataType.StringData, storeEntry.Key);

            Assert.NotEmpty(extendedQueryTagIndexData);

            // Delete tag
            await _extendedQueryTagStore.DeleteExtendedQueryTagAsync(storeEntry.Path, storeEntry.VR);

            await VerifyTagNotExistAsync(storeEntry.Path);

            // Verify index data is removed
            extendedQueryTagIndexData = await _extendedQueryTagStoreTestHelper.GetExtendedQueryTagDataForTagKeyAsync(ExtendedQueryTagDataType.StringData, storeEntry.Key);

            Assert.Empty(extendedQueryTagIndexData);
        }
        internal async Task GivenDicomInstanceWithDifferentTypeOfExtendedQueryTags_WhenStore_ThenTheyShouldBeStoredInProperTable(ExtendedQueryTagDataType dataType, DicomElement element, object expectedValue)
        {
            string       studyInstanceUid  = TestUidGenerator.Generate();
            string       seriesInstanceUid = TestUidGenerator.Generate();
            string       sopInstanceUid    = TestUidGenerator.Generate();
            DicomDataset dataset           = Samples.CreateRandomInstanceDataset(studyInstanceUid, seriesInstanceUid, sopInstanceUid);

            dataset.Add(element);
            QueryTagLevel level = QueryTagLevel.Study;
            var           extendedQueryTagEntry = element.Tag.BuildAddExtendedQueryTagEntry(level: level);

            QueryTag queryTag = await AddExtendedQueryTag(extendedQueryTagEntry);

            try
            {
                long watermark = await CreateInstanceIndexAsync(dataset, new QueryTag[] { queryTag });

                Instance instance = await _testHelper.GetInstanceAsync(studyInstanceUid, seriesInstanceUid, sopInstanceUid, watermark);

                IReadOnlyList <ExtendedQueryTagDataRow> rows = await _extendedQueryTagStoreTestHelper.GetExtendedQueryTagDataAsync(dataType, queryTag.ExtendedQueryTagStoreEntry.Key, instance.StudyKey);

                Assert.Single(rows);
                Assert.Equal(watermark, rows[0].Watermark);
                Assert.Equal(expectedValue, rows[0].TagValue);
            }
            finally
            {
                await _extendedQueryTagStore.DeleteExtendedQueryTagAsync(extendedQueryTagEntry.Path, extendedQueryTagEntry.VR);
            }
        }
        public async Task GivenInstanceNotExist_WhenReindex_ThenShouldThrowException()
        {
            DicomTag tag           = DicomTag.DeviceID;
            var      tagStoreEntry = await AddExtendedQueryTagAsync(tag.BuildAddExtendedQueryTagEntry(level: QueryTagLevel.Instance));

            DicomDataset dataset = Samples.CreateRandomInstanceDataset();
            await Assert.ThrowsAsync <InstanceNotFoundException>(() => _indexDataStore.ReindexInstanceAsync(dataset, 0, new[] { new QueryTag(tagStoreEntry) }));
        }
示例#7
0
        public async Task GivenAValidDicomDatasetWithImplicitVR_WhenValidated_ThenItShouldThrowNotAcceptableException(DicomTransferSyntax transferSyntax)
        {
            var dicomDataset = Samples
                               .CreateRandomInstanceDataset(dicomTransferSyntax: transferSyntax)
                               .NotValidated();

            await Assert.ThrowsAsync <NotAcceptableException>(() => _dicomDatasetValidator.ValidateAsync(dicomDataset, requiredStudyInstanceUid: null));
        }
示例#8
0
        public void GivenDicomDatasetWithImplicitVR_WhenValidating_ThenItShouldThrowNotAcceptableException(DicomTransferSyntax transferSyntax)
        {
            var dicomDataset = Samples
                               .CreateRandomInstanceDataset(dicomTransferSyntax: transferSyntax)
                               .NotValidated();

            Assert.Throws <NotAcceptableException>(() => ImplicitValueRepresentationValidator.Validate(dicomDataset));
        }
示例#9
0
        public void GivenDicomDatasetWithNonImplicitVR_WhenValidating_ThenItShouldSucceed(DicomTransferSyntax transferSyntax)
        {
            var dicomDataset = Samples
                               .CreateRandomInstanceDataset(dicomTransferSyntax: transferSyntax)
                               .NotValidated();

            ImplicitValueRepresentationValidator.Validate(dicomDataset);
        }
        private async Task <long> AddInstanceAsync(string studyId, string seriesId, string sopInstanceId)
        {
            DicomDataset dataset   = Samples.CreateRandomInstanceDataset(studyId, seriesId, sopInstanceId);
            long         watermark = await _indexDataStore.BeginCreateInstanceIndexAsync(1, dataset);

            await _indexDataStore.EndCreateInstanceIndexAsync(1, dataset, watermark);

            return(watermark);
        }
示例#11
0
        public async Task GivenNoExtendedQueryTags_WhenCreateIndex_ThenShouldSucceed()
        {
            var extendedTags = await _extendedQueryTagStore.GetExtendedQueryTagsAsync(int.MaxValue);

            // make sure there is no extended query tags
            Assert.Empty(extendedTags);

            DicomDataset dataset = Samples.CreateRandomInstanceDataset();
            await _indexDataStore.BeginCreateInstanceIndexAsync(DefaultPartition.Key, dataset, QueryTagService.CoreQueryTags);
        }
        public async Task GivenPendingInstance_WhenReindex_ThenShouldThrowException()
        {
            DicomTag tag           = DicomTag.DeviceDescription;
            var      tagStoreEntry = await AddExtendedQueryTagAsync(tag.BuildAddExtendedQueryTagEntry(level: QueryTagLevel.Instance));

            DicomDataset dataset = Samples.CreateRandomInstanceDataset();

            long watermark = await _indexDataStore.BeginCreateInstanceIndexAsync(1, dataset);

            await Assert.ThrowsAsync <PendingInstanceException>(() => _indexDataStore.ReindexInstanceAsync(dataset, watermark, new[] { new QueryTag(tagStoreEntry) }));
        }
        private async Task ValidateUpdateExistingExtendedQueryTagIndexData(QueryTagLevel level)
        {
            if (level == QueryTagLevel.Instance)
            {
                throw new System.ArgumentException("Update value on instance level is not valid case.");
            }

            string       studyInstanceUid  = TestUidGenerator.Generate();
            string       seriesInstanceUid = TestUidGenerator.Generate();
            string       sopInstanceUid    = TestUidGenerator.Generate();
            DicomDataset dataset           = Samples.CreateRandomInstanceDataset(studyInstanceUid, seriesInstanceUid, sopInstanceUid);
            DicomTag     tag   = DicomTag.ConversionType;
            string       value = "SYN";

            dataset.Add(tag, value);

            QueryTag queryTag = await AddExtendedQueryTag(tag.BuildAddExtendedQueryTagEntry(level: level));

            try
            {
                // index extended query tags
                await CreateInstanceIndexAsync(dataset, new QueryTag[] { queryTag });

                // update
                value = "NEWSYN";
                dataset.AddOrUpdate(tag, value);
                sopInstanceUid = TestUidGenerator.Generate();
                dataset.AddOrUpdate(DicomTag.SOPInstanceUID, sopInstanceUid);
                if (level == QueryTagLevel.Study)
                {
                    seriesInstanceUid = TestUidGenerator.Generate();
                    dataset.AddOrUpdate(DicomTag.SeriesInstanceUID, seriesInstanceUid);
                }

                // index new instance
                long watermark = await CreateInstanceIndexAsync(dataset, new QueryTag[] { queryTag });

                Instance instance = await _testHelper.GetInstanceAsync(studyInstanceUid, seriesInstanceUid, sopInstanceUid, watermark);

                long?seriesKey  = level != QueryTagLevel.Study ? instance.SeriesKey : null;
                var  stringRows = await _extendedQueryTagStoreTestHelper.GetExtendedQueryTagDataAsync(ExtendedQueryTagDataType.StringData, queryTag.ExtendedQueryTagStoreEntry.Key, instance.StudyKey, seriesKey);

                Assert.Single(stringRows);
                Assert.Equal(stringRows[0].TagValue, value);
                Assert.Equal(stringRows[0].Watermark, watermark);
            }
            finally
            {
                await _extendedQueryTagStore.DeleteExtendedQueryTagAsync(queryTag.ExtendedQueryTagStoreEntry.Path, queryTag.ExtendedQueryTagStoreEntry.VR);
            }
        }
        private async Task <Instance> StoreInstanceWithDifferentTagValues(string studyInstanceUid, string seriesInstanceUid, string sopInstanceUid, int index, IReadOnlyList <QueryTag> queryTags)
        {
            DicomDataset dataset = Samples.CreateRandomInstanceDataset(studyInstanceUid, seriesInstanceUid, sopInstanceUid);

            dataset.Add(new DicomDate(DicomTag.AcquisitionDate, DateTime.Parse("2020/2/2" + index)));
            dataset.Add(new DicomCodeString(DicomTag.ConversionType, "STRING" + index));
            dataset.Add(new DicomFloatingPointDouble(DicomTag.DopplerCorrectionAngle, 1.0 + index));
            dataset.Add(new DicomSignedLong(DicomTag.ReferencePixelX0, 1 + index));
            dataset.Add(new DicomPersonName(DicomTag.DistributionNameRETIRED, "abc^abc" + index));

            long watermark = await _indexDataStore.CreateInstanceIndexAsync(dataset, queryTags);

            return(await _testHelper.GetInstanceAsync(studyInstanceUid, seriesInstanceUid, sopInstanceUid, watermark));
        }
示例#15
0
        public async Task GivenMaxTagKeyNotMatch_WhenCreateIndex_ThenShouldThrowException()
        {
            AddExtendedQueryTagEntry extendedQueryTagEntry = DicomTag.PatientAge.BuildAddExtendedQueryTagEntry();
            var          tagEntry = (await _extendedQueryTagStore.AddExtendedQueryTagsAsync(new[] { extendedQueryTagEntry }, maxAllowedCount: 128, ready: true))[0];
            DicomDataset dataset  = Samples.CreateRandomInstanceDataset();

            // Add a new tag
            await _extendedQueryTagStore.AddExtendedQueryTagsAsync(new[] { DicomTag.PatientName.BuildAddExtendedQueryTagEntry() }, maxAllowedCount : 128, ready : true);

            var  queryTags = new[] { new QueryTag(tagEntry) };
            long watermark = await _indexDataStore.BeginCreateInstanceIndexAsync(DefaultPartition.Key, dataset, queryTags);

            await Assert.ThrowsAsync <ExtendedQueryTagsOutOfDateException>(
                () => _indexDataStore.EndCreateInstanceIndexAsync(DefaultPartition.Key, dataset, watermark, queryTags));
        }
        public async Task GivenStudyTag_WhenReindexWithNewInstance_ThenTagValueShouldBeUpdated()
        {
            DicomTag tag       = DicomTag.DeviceSerialNumber;
            string   tagValue1 = "test1";
            string   tagValue2 = "test2";
            string   tagValue3 = "test3";

            string studyUid = TestUidGenerator.Generate();

            DicomDataset dataset1 = Samples.CreateRandomInstanceDataset(studyUid);

            dataset1.Add(tag, tagValue1);
            DicomDataset dataset2 = Samples.CreateRandomInstanceDataset(studyUid);

            dataset2.Add(tag, tagValue2);
            DicomDataset dataset3 = Samples.CreateRandomInstanceDataset(studyUid);

            dataset3.Add(tag, tagValue3);

            Instance instance1 = await CreateInstanceIndexAsync(dataset1);

            Instance instance2 = await CreateInstanceIndexAsync(dataset2);

            Instance instance3 = await CreateInstanceIndexAsync(dataset3);

            var tagStoreEntry = await AddExtendedQueryTagAsync(tag.BuildAddExtendedQueryTagEntry(level: QueryTagLevel.Study));

            QueryTag queryTag = new QueryTag(tagStoreEntry);

            // Simulate re-indexing, which may re-index an instance which may re-index
            // the instances for a particular study or series out-of-order
            await _indexDataStore.ReindexInstanceAsync(dataset2, instance2.Watermark, new[] { queryTag });

            ExtendedQueryTagDataRow row = (await _extendedQueryTagStoreTestHelper.GetExtendedQueryTagDataAsync(ExtendedQueryTagDataType.StringData, tagStoreEntry.Key, instance1.StudyKey, null, null)).Single();

            Assert.Equal(tagValue2, row.TagValue); // Added

            await _indexDataStore.ReindexInstanceAsync(dataset3, instance3.Watermark, new[] { queryTag });

            row = (await _extendedQueryTagStoreTestHelper.GetExtendedQueryTagDataAsync(ExtendedQueryTagDataType.StringData, tagStoreEntry.Key, instance1.StudyKey, null, null)).Single();
            Assert.Equal(tagValue3, row.TagValue); // Overwrite

            await _indexDataStore.ReindexInstanceAsync(dataset1, instance1.Watermark, new[] { queryTag });

            row = (await _extendedQueryTagStoreTestHelper.GetExtendedQueryTagDataAsync(ExtendedQueryTagDataType.StringData, tagStoreEntry.Key, instance1.StudyKey, null, null)).Single();
            Assert.Equal(tagValue3, row.TagValue); // Do not overwrite
        }
        public async Task GivenInstanceTag_WhenReindexWithIndexedInstance_ThenTagValueShouldNotBeUpdated()
        {
            DicomTag tag           = DicomTag.DeviceLabel;
            string   tagValue      = "test";
            var      tagStoreEntry = await AddExtendedQueryTagAsync(tag.BuildAddExtendedQueryTagEntry(level: QueryTagLevel.Instance));

            DicomDataset dataset = Samples.CreateRandomInstanceDataset();

            dataset.Add(tag, tagValue);
            var instance = await CreateInstanceIndexAsync(dataset);

            await _indexDataStore.ReindexInstanceAsync(dataset, instance.Watermark, new[] { new QueryTag(tagStoreEntry) });

            var row = (await _extendedQueryTagStoreTestHelper.GetExtendedQueryTagDataAsync(ExtendedQueryTagDataType.StringData, tagStoreEntry.Key, instance.StudyKey, instance.SeriesKey, instance.InstanceKey)).First();

            Assert.Equal(tagValue, row.TagValue);
        }
示例#18
0
        public async Task GivenValidExtendedQueryTags_WhenGoThroughEndToEndScenario_ThenShouldSucceed()
        {
            // Prepare 3 extended query tags.
            // One is private tag on Instance level
            // To add private tag, need to add identification code element at first.
            DicomTag identificationCodeTag = new DicomTag(0x0407, 0x0010);

            DicomElement identificationCodeElement = new DicomLongString(identificationCodeTag, PrivateCreatorName);

            DicomTag privateTag = new DicomTag(0x0407, 0x1001, PrivateCreatorName);
            AddExtendedQueryTagEntry privateQueryTag = new AddExtendedQueryTagEntry {
                Path = privateTag.GetPath(), VR = DicomVRCode.SS, Level = QueryTagLevel.Instance, PrivateCreator = privateTag.PrivateCreator.Creator
            };

            // One is standard tag on Series level
            DicomTag standardTagSeries = DicomTag.ManufacturerModelName;
            AddExtendedQueryTagEntry standardTagSeriesQueryTag = new AddExtendedQueryTagEntry {
                Path = standardTagSeries.GetPath(), VR = standardTagSeries.GetDefaultVR().Code, Level = QueryTagLevel.Series
            };

            // One is standard tag on Study level
            DicomTag standardTagStudy = DicomTag.PatientSex;
            AddExtendedQueryTagEntry standardTagStudyQueryTag = new AddExtendedQueryTagEntry {
                Path = standardTagStudy.GetPath(), VR = standardTagStudy.GetDefaultVR().Code, Level = QueryTagLevel.Study
            };

            AddExtendedQueryTagEntry[] queryTags = new AddExtendedQueryTagEntry[] { privateQueryTag, standardTagSeriesQueryTag, standardTagStudyQueryTag };

            // Create 3 test files on same studyUid.
            string studyUid     = TestUidGenerator.Generate();
            string seriesUid1   = TestUidGenerator.Generate();
            string seriesUid2   = TestUidGenerator.Generate();
            string instanceUid1 = TestUidGenerator.Generate();
            string instanceUid2 = TestUidGenerator.Generate();
            string instanceUid3 = TestUidGenerator.Generate();

            // One is on seriesUid1 and instanceUid1
            DicomDataset dataset1 = Samples.CreateRandomInstanceDataset(studyInstanceUid: studyUid, seriesInstanceUid: seriesUid1, sopInstanceUid: instanceUid1);

            dataset1.Add(identificationCodeElement);
            dataset1.AddOrUpdate(new DicomSignedShort(privateTag, 1));
            dataset1.Add(standardTagSeries, "ManufacturerModelName1");
            dataset1.Add(standardTagStudy, "0");

            // One is on seriesUid1 and instanceUid2
            DicomDataset dataset2 = Samples.CreateRandomInstanceDataset(studyInstanceUid: studyUid, seriesInstanceUid: seriesUid1, sopInstanceUid: instanceUid2);

            dataset2.Add(identificationCodeElement);
            dataset2.AddOrUpdate(new DicomSignedShort(privateTag, 2));
            dataset2.Add(standardTagSeries, "ManufacturerModelName2");
            dataset2.Add(standardTagStudy, "0");

            // One is on seriesUid2 and instanceUid3
            DicomDataset dataset3 = Samples.CreateRandomInstanceDataset(studyInstanceUid: studyUid, seriesInstanceUid: seriesUid2, sopInstanceUid: instanceUid3);

            dataset3.Add(identificationCodeElement);
            dataset3.AddOrUpdate(new DicomSignedShort(privateTag, 3));
            dataset3.Add(standardTagSeries, "ManufacturerModelName3");
            dataset3.Add(standardTagStudy, "1");
            try
            {
                // Add extended query tags

                await _client.AddExtendedQueryTagAsync(queryTags);

                try
                {
                    foreach (var queryTag in queryTags)
                    {
                        GetExtendedQueryTagEntry returnTag = await(await _client.GetExtendedQueryTagAsync(queryTag.Path)).GetValueAsync();
                        CompareExtendedQueryTagEntries(queryTag, returnTag);
                    }

                    // Upload test files
                    IEnumerable <DicomFile> dicomFiles = new DicomDataset[] { dataset1, dataset2, dataset3 }.Select(dataset => new DicomFile(dataset));

                    await _client.StoreAsync(dicomFiles, studyInstanceUid : string.Empty, cancellationToken : default);

                    // Query on instance for private tag
                    DicomWebAsyncEnumerableResponse <DicomDataset> queryInstanceResponse = await _client.QueryAsync(new Uri($"/instances?{privateTag.GetPath()}=3", UriKind.Relative), cancellationToken : default);

                    DicomDataset[] instanceResult = await queryInstanceResponse.ToArrayAsync();

                    Assert.Single(instanceResult);
                    Assert.Equal(instanceUid3, instanceResult[0].GetSingleValue <string>(DicomTag.SOPInstanceUID));

                    // Query on series for standardTagSeries
                    DicomWebAsyncEnumerableResponse <DicomDataset> querySeriesResponse = await _client.QueryAsync(new Uri($"/series?{standardTagSeries.GetPath()}=ManufacturerModelName2", UriKind.Relative), cancellationToken : default);

                    DicomDataset[] seriesResult = await querySeriesResponse.ToArrayAsync();

                    Assert.Single(seriesResult);
                    Assert.Equal(seriesUid1, seriesResult[0].GetSingleValue <string>(DicomTag.SeriesInstanceUID));

                    // Query on study for standardTagStudy
                    DicomWebAsyncEnumerableResponse <DicomDataset> queryStudyResponse = await _client.QueryAsync(new Uri($"/studies?{standardTagStudy.GetPath()}=1", UriKind.Relative), cancellationToken : default);

                    DicomDataset[] studyResult = await queryStudyResponse.ToArrayAsync();

                    Assert.Single(studyResult);
                    Assert.Equal(studyUid, seriesResult[0].GetSingleValue <string>(DicomTag.StudyInstanceUID));
                }
                finally
                {
                    await _client.DeleteStudyAsync(studyUid);
                }
            }
            finally
            {
                // Cleanup extended query tags, also verify GetExtendedQueryTagsAsync.
                var responseQueryTags = await(await _client.GetExtendedQueryTagsAsync()).GetValueAsync();
                foreach (var rTag in responseQueryTags)
                {
                    if (queryTags.Any(tag => tag.Path == rTag.Path))
                    {
                        await _client.DeleteExtendedQueryTagAsync(rTag.Path);
                    }
                }
            }
        }
        public async Task GivenExtendedQueryTagWithErrors_WhenReindexing_ThenShouldSucceedWithErrors()
        {
            // Define tags
            DicomTag tag      = DicomTag.PatientAge;
            string   tagValue = "053Y";

            // Try to delete this extended query tag if it exists.
            await CleanupExtendedQueryTag(tag);

            // Define DICOM files
            DicomDataset instance1 = Samples.CreateRandomInstanceDataset();
            DicomDataset instance2 = Samples.CreateRandomInstanceDataset();
            DicomDataset instance3 = Samples.CreateRandomInstanceDataset();

            // Annotate files
            // (Disable Auto-validate)
            instance1.NotValidated();
            instance2.NotValidated();

            instance1.Add(tag, "foobar");
            instance2.Add(tag, "invalid");
            instance3.Add(tag, tagValue);

            // Upload files (with a few errors)
            await _instanceManager.StoreAsync(new DicomFile(instance1));

            await _instanceManager.StoreAsync(new DicomFile(instance2));

            await _instanceManager.StoreAsync(new DicomFile(instance3));

            // Add extended query tags
            var operationStatus = await _tagManager.AddTagsAsync(
                new AddExtendedQueryTagEntry[]
            {
                new AddExtendedQueryTagEntry {
                    Path = tag.GetPath(), VR = tag.GetDefaultVR().Code, Level = QueryTagLevel.Instance
                },
            });

            Assert.Equal(OperationRuntimeStatus.Completed, operationStatus.Status);

            // Check specific tag
            GetExtendedQueryTagEntry actual = await _tagManager.GetTagAsync(tag.GetPath());

            Assert.Equal(tag.GetPath(), actual.Path);
            Assert.Equal(2, actual.Errors.Count);
            // It should be disabled by default
            Assert.Equal(QueryStatus.Disabled, actual.QueryStatus);

            // Verify Errors
            var errors = await _tagManager.GetTagErrorsAsync(tag.GetPath(), 2, 0);

            Assert.Equal(2, errors.Count);

            Assert.Equal(errors[0].ErrorMessage, (await _tagManager.GetTagErrorsAsync(tag.GetPath(), 1, 0)).Single().ErrorMessage);
            Assert.Equal(errors[1].ErrorMessage, (await _tagManager.GetTagErrorsAsync(tag.GetPath(), 1, 1)).Single().ErrorMessage);

            var exception = await Assert.ThrowsAsync <DicomWebException>(() => _client.QueryInstancesAsync($"{tag.GetPath()}={tagValue}"));

            Assert.Equal(HttpStatusCode.BadRequest, exception.StatusCode);

            // Enable QIDO on Tag
            actual = await _tagManager.UpdateExtendedQueryTagAsync(tag.GetPath(), new UpdateExtendedQueryTagEntry()
            {
                QueryStatus = QueryStatus.Enabled
            });

            Assert.Equal(QueryStatus.Enabled, actual.QueryStatus);

            var response = await _client.QueryInstancesAsync($"{tag.GetPath()}={tagValue}");

            Assert.True(response.ResponseHeaders.Contains(ErroneousDicomAttributesHeader));
            var values = response.ResponseHeaders.GetValues(ErroneousDicomAttributesHeader);

            Assert.Single(values);
            Assert.Equal(tag.GetPath(), values.First());
            Assert.Equal(HttpStatusCode.OK, response.StatusCode);

            // Verify result
            DicomDataset[] instances = await response.ToArrayAsync();

            Assert.Contains(instances, instance => instance.ToInstanceIdentifier().Equals(instance3.ToInstanceIdentifier()));
        }
        public async Task GivenExtendedQueryTag_WhenReindexing_ThenShouldSucceed()
        {
            DicomTag weightTag = DicomTag.PatientWeight;
            DicomTag sizeTag   = DicomTag.PatientSize;

            // Try to delete these extended query tags.
            await CleanupExtendedQueryTag(weightTag);
            await CleanupExtendedQueryTag(sizeTag);

            // Define DICOM files
            DicomDataset instance1 = Samples.CreateRandomInstanceDataset();

            instance1.Add(weightTag, 68.0M);
            instance1.Add(sizeTag, 1.78M);

            DicomDataset instance2 = Samples.CreateRandomInstanceDataset();

            instance2.Add(weightTag, 50.0M);
            instance2.Add(sizeTag, 1.5M);

            // Upload files
            Assert.True((await _instanceManager.StoreAsync(new DicomFile(instance1))).IsSuccessStatusCode);
            Assert.True((await _instanceManager.StoreAsync(new DicomFile(instance2))).IsSuccessStatusCode);

            // Add extended query tag
            OperationStatus operation = await _tagManager.AddTagsAsync(
                new AddExtendedQueryTagEntry[]
            {
                new AddExtendedQueryTagEntry {
                    Path = weightTag.GetPath(), VR = weightTag.GetDefaultVR().Code, Level = QueryTagLevel.Study
                },
                new AddExtendedQueryTagEntry {
                    Path = sizeTag.GetPath(), VR = sizeTag.GetDefaultVR().Code, Level = QueryTagLevel.Study
                },
            });

            Assert.Equal(OperationRuntimeStatus.Completed, operation.Status);

            // Check specific tag
            DicomWebResponse <GetExtendedQueryTagEntry> getResponse;
            GetExtendedQueryTagEntry entry;

            getResponse = await _client.GetExtendedQueryTagAsync(weightTag.GetPath());

            entry = await getResponse.GetValueAsync();

            Assert.Null(entry.Errors);
            Assert.Equal(QueryStatus.Enabled, entry.QueryStatus);

            getResponse = await _client.GetExtendedQueryTagAsync(sizeTag.GetPath());

            entry = await getResponse.GetValueAsync();

            Assert.Null(entry.Errors);
            Assert.Equal(QueryStatus.Enabled, entry.QueryStatus);

            // Query multiple tags
            // Note: We don't necessarily need to check the tags are the above ones, as another test may have added ones beforehand
            var multipleTags = await _tagManager.GetTagsAsync(2, 0);

            Assert.Equal(2, multipleTags.Count);

            Assert.Equal(multipleTags[0].Path, (await _tagManager.GetTagsAsync(1, 0)).Single().Path);
            Assert.Equal(multipleTags[1].Path, (await _tagManager.GetTagsAsync(1, 1)).Single().Path);

            // QIDO
            DicomWebAsyncEnumerableResponse <DicomDataset> queryResponse = await _client.QueryInstancesAsync($"{weightTag.GetPath()}=50.0");

            DicomDataset[] instances = await queryResponse.ToArrayAsync();

            Assert.Contains(instances, instance => instance.ToInstanceIdentifier().Equals(instance2.ToInstanceIdentifier()));
        }