예제 #1
0
        public async void GivenAllDifferentStudyInstanceUIDs_WhenStoringWithProvidedStudyInstanceUID_TheServerShouldReturnConflict()
        {
            DicomFile dicomFile1 = Samples.CreateRandomDicomFile();
            DicomFile dicomFile2 = Samples.CreateRandomDicomFile();

            var studyInstanceUID = TestUidGenerator.Generate();

            DicomWebException <DicomDataset> exception = await Assert.ThrowsAsync <DicomWebException <DicomDataset> >(() => _client.StoreAsync(
                                                                                                                          new[] { dicomFile1, dicomFile2 }, studyInstanceUID));

            Assert.Equal(HttpStatusCode.Conflict, exception.StatusCode);
            Assert.NotNull(exception.Value);
            Assert.True(exception.Value.Count() == 1);

            ValidationHelpers.ValidateFailedSopSequence(
                exception.Value,
                ConvertToFailedSopSequenceEntry(dicomFile1.Dataset, MismatchStudyInstanceUidFailureCode),
                ConvertToFailedSopSequenceEntry(dicomFile2.Dataset, MismatchStudyInstanceUidFailureCode));
        }
        public async Task GivenUnsupportedInternalTransferSyntax_WhenRetrieveInstanceWithOriginalTransferSyntax_ThenServerShouldReturnOriginalContent()
        {
            var studyInstanceUid  = TestUidGenerator.Generate();
            var seriesInstanceUid = TestUidGenerator.Generate();
            var sopInstanceUid    = TestUidGenerator.Generate();

            DicomFile dicomFile = Samples.CreateRandomDicomFileWith8BitPixelData(
                studyInstanceUid,
                seriesInstanceUid,
                sopInstanceUid,
                transferSyntax: DicomTransferSyntax.MPEG2.UID.UID,
                encode: false);

            await InternalStoreAsync(new[] { dicomFile });

            using DicomWebResponse <DicomFile> instancesInStudy = await _client.RetrieveInstanceAsync(studyInstanceUid, seriesInstanceUid, sopInstanceUid, dicomTransferSyntax : "*");

            Assert.Equal(dicomFile.ToByteArray(), (await instancesInStudy.GetValueAsync()).ToByteArray());
        }
예제 #3
0
        public async Task GivenRetrieveStudyMetadataRequest_WhenIfNoneMatchMatchesETag_ThenNotModifiedResponseIsReturned()
        {
            string studyInstanceUid = TestUidGenerator.Generate();

            DicomDataset storedInstance = await PostDicomFileAsync(ResourceType.Study, studyInstanceUid, dataSet : GenerateNewDataSet());

            string eTag;

            using (DicomWebAsyncEnumerableResponse <DicomDataset> response = await _client.RetrieveStudyMetadataAsync(studyInstanceUid))
            {
                eTag = GetEtagFromResponse(response);
            }

            using (DicomWebAsyncEnumerableResponse <DicomDataset> response = await _client.RetrieveStudyMetadataAsync(studyInstanceUid, eTag))
            {
                Assert.Equal(HttpStatusCode.NotModified, response.StatusCode);
                ValidateNoContent(response);
            }
        }
예제 #4
0
        public async Task GivenMultipleSeriesInStudy_WhenDeletingSeries_TheServerShouldReturnNoContentAndOnlyTargetSeriesIsDeleted()
        {
            var studyInstanceUid   = TestUidGenerator.Generate();
            var seriesInstanceUid1 = TestUidGenerator.Generate();
            var seriesInstanceUid2 = TestUidGenerator.Generate();
            var sopInstanceUid1    = TestUidGenerator.Generate();
            var sopInstanceUid2    = TestUidGenerator.Generate();

            await CreateFile(studyInstanceUid, seriesInstanceUid1, sopInstanceUid1);
            await CreateFile(studyInstanceUid, seriesInstanceUid2, sopInstanceUid2);

            await _client.DeleteInstanceAsync(studyInstanceUid, seriesInstanceUid1, sopInstanceUid1);

            await VerifySopInstanceRemoval(studyInstanceUid, seriesInstanceUid1, sopInstanceUid1);
            await VerifySeriesRemoval(studyInstanceUid, seriesInstanceUid1);

            await VerifyRemainingSeries(studyInstanceUid, seriesInstanceUid2, 1);
            await VerifyRemainingStudy(studyInstanceUid, 1);
        }
예제 #5
0
        public async Task GivenExistingStudyWithMultipleItemsInEachLevel_WhenDeletingStudy_TheServerShouldReturnNoContentAndAllLevelsShouldBeRemoved()
        {
            var studyInstanceUid   = TestUidGenerator.Generate();
            var seriesInstanceUid1 = TestUidGenerator.Generate();
            var seriesInstanceUid2 = TestUidGenerator.Generate();
            var sopInstanceUid1    = TestUidGenerator.Generate();
            var sopInstanceUid2    = TestUidGenerator.Generate();
            var sopInstanceUid3    = TestUidGenerator.Generate();

            await CreateFile(studyInstanceUid, seriesInstanceUid1, sopInstanceUid1);
            await CreateFile(studyInstanceUid, seriesInstanceUid2, sopInstanceUid2);
            await CreateFile(studyInstanceUid, seriesInstanceUid2, sopInstanceUid3);

            await _client.DeleteStudyAsync(studyInstanceUid);

            await VerifyAllRemoval(studyInstanceUid, seriesInstanceUid1, sopInstanceUid1);
            await VerifyAllRemoval(studyInstanceUid, seriesInstanceUid2, sopInstanceUid2);
            await VerifyAllRemoval(studyInstanceUid, seriesInstanceUid2, sopInstanceUid3);
        }
        public async Task GivenStudyWithMultileInstances_WhenDeleteStudy_ThenAssociatedErrorsShouldBeRemoved()
        {
            string studyUid1    = TestUidGenerator.Generate();
            string seriesUid1   = TestUidGenerator.Generate();
            string instanceUid1 = TestUidGenerator.Generate();
            string seriesUid2   = TestUidGenerator.Generate();
            string instanceUid2 = TestUidGenerator.Generate();
            string studyUid3    = TestUidGenerator.Generate();
            string seriesUid3   = TestUidGenerator.Generate();
            string instanceUid3 = TestUidGenerator.Generate();

            // add instances: instance1 and instance2 are in same study
            long watermark1 = await AddInstanceAsync(studyUid1, seriesUid1, instanceUid1);

            long watermark2 = await AddInstanceAsync(studyUid1, seriesUid2, instanceUid2);

            long watermark3 = await AddInstanceAsync(studyUid3, seriesUid3, instanceUid3);

            // add tag
            DicomTag tag    = DicomTag.DeviceSerialNumber;
            int      tagKey = await AddTagAsync(tag);


            // add errors
            ValidationErrorCode errorCode = ValidationErrorCode.DateIsInvalid;
            await _extendedQueryTagErrorStore.AddExtendedQueryTagErrorAsync(tagKey, errorCode, watermark1);

            await _extendedQueryTagErrorStore.AddExtendedQueryTagErrorAsync(tagKey, errorCode, watermark2);

            await _extendedQueryTagErrorStore.AddExtendedQueryTagErrorAsync(tagKey, errorCode, watermark3);

            // delete instance
            await _indexDataStore.DeleteStudyIndexAsync(DefaultPartition.Key, studyUid1, DateTime.UtcNow);

            // check errors
            var errors = await _extendedQueryTagErrorStore.GetExtendedQueryTagErrorsAsync(tag.GetPath(), int.MaxValue, 0);

            Assert.Single(errors);
            Assert.Equal(studyUid3, errors[0].StudyInstanceUid);
            Assert.Equal(seriesUid3, errors[0].SeriesInstanceUid);
            Assert.Equal(instanceUid3, errors[0].SopInstanceUid);
        }
        public async Task GivenAnIncorrectAcceptHeader_WhenRetrievingResource_NotAcceptableIsReturned(string acceptHeader)
        {
            // Study
            await _client.ValidateResponseStatusCodeAsync(
                string.Format(DicomWebConstants.BasStudyUriFormat, TestUidGenerator.Generate()),
                acceptHeader,
                HttpStatusCode.NotAcceptable);

            // Series
            await _client.ValidateResponseStatusCodeAsync(
                string.Format(DicomWebConstants.BaseSeriesUriFormat, TestUidGenerator.Generate(), TestUidGenerator.Generate()),
                acceptHeader,
                HttpStatusCode.NotAcceptable);

            // Instance
            await _client.ValidateResponseStatusCodeAsync(
                string.Format(DicomWebConstants.BaseInstanceUriFormat, TestUidGenerator.Generate(), TestUidGenerator.Generate(), TestUidGenerator.Generate()),
                acceptHeader,
                HttpStatusCode.NotAcceptable);
        }
        public async Task GivenExtendedQueryTagError_WhenAddExtendedQueryTagError_ThenErrorCountShouldIncrease()
        {
            string studyInstanceUid  = TestUidGenerator.Generate();
            string seriesInstanceUid = TestUidGenerator.Generate();
            string sopInstanceUid    = TestUidGenerator.Generate();

            DicomTag tag       = DicomTag.DeviceSerialNumber;
            long     watermark = await AddInstanceAsync(studyInstanceUid, seriesInstanceUid, sopInstanceUid);

            int tagKey = await AddTagAsync(tag);

            await _extendedQueryTagErrorStore.AddExtendedQueryTagErrorAsync(
                tagKey,
                ValidationErrorCode.UidIsInvalid,
                watermark);

            var tagEntry = await _extendedQueryTagStore.GetExtendedQueryTagAsync(tag.GetPath());

            Assert.Equal(1, tagEntry.ErrorCount);
        }
예제 #9
0
        public async Task GivenRetrieveStudyMetadataRequest_WhenStudyIsUpdatedAndPreviousETagIsUsed_ThenResponseMetadataIsReturnedWithNewETag()
        {
            string studyInstanceUid = TestUidGenerator.Generate();

            DicomDataset firstStoredInstance = await PostDicomFileAsync(ResourceType.Study, studyInstanceUid, dataSet : GenerateNewDataSet());

            string eTag;

            using (DicomWebAsyncEnumerableResponse <DicomDataset> response = await _client.RetrieveStudyMetadataAsync(studyInstanceUid))
            {
                eTag = GetEtagFromResponse(response);
            }

            DicomDataset secondStoredInstance = await PostDicomFileAsync(ResourceType.Study, studyInstanceUid, dataSet : GenerateNewDataSet());

            using (DicomWebAsyncEnumerableResponse <DicomDataset> response = await _client.RetrieveStudyMetadataAsync(studyInstanceUid, eTag))
            {
                await ValidateResponseMetadataDatasetAsync(response, firstStoredInstance, secondStoredInstance);
            }
        }
예제 #10
0
        public async Task GivenFewDeletedInstances_NumMatchRetryCountShouldBeCorrect()
        {
            await _testHelper.ClearDeletedInstanceTable();

            string   studyInstanceUid  = TestUidGenerator.Generate();
            string   seriesInstanceUid = TestUidGenerator.Generate();
            string   sopInstanceUid    = TestUidGenerator.Generate();
            Instance instance1         = await CreateIndexAndVerifyInstance(studyInstanceUid, seriesInstanceUid, sopInstanceUid);

            await _indexDataStore.DeleteInstanceIndexAsync(studyInstanceUid, seriesInstanceUid, sopInstanceUid, Clock.UtcNow);

            string   sopInstanceUid2 = TestUidGenerator.Generate();
            Instance instance2       = await CreateIndexAndVerifyInstance(studyInstanceUid, seriesInstanceUid, sopInstanceUid2);

            await _indexDataStore.DeleteInstanceIndexAsync(studyInstanceUid, seriesInstanceUid, sopInstanceUid2, Clock.UtcNow);

            var numMatchRetryCount = await _indexDataStore.RetrieveNumExhaustedDeletedInstanceAttemptsAsync(0);

            Assert.Equal(2, numMatchRetryCount);
        }
예제 #11
0
        public async Task GivenAnExistingDicomInstance_WhenDeletedByInstanceId_AdditionalInstancesShouldBeMaintained()
        {
            string   studyInstanceUid  = TestUidGenerator.Generate();
            string   seriesInstanceUid = TestUidGenerator.Generate();
            string   sopInstanceUid    = TestUidGenerator.Generate();
            Instance instance          = await CreateIndexAndVerifyInstance(studyInstanceUid, seriesInstanceUid, sopInstanceUid);

            string sopInstanceUid2 = TestUidGenerator.Generate();

            await CreateIndexAndVerifyInstance(studyInstanceUid, seriesInstanceUid, sopInstanceUid2);

            await _indexDataStore.DeleteInstanceIndexAsync(studyInstanceUid, seriesInstanceUid, sopInstanceUid, Clock.UtcNow);

            Assert.Empty(await _testHelper.GetInstancesAsync(studyInstanceUid, seriesInstanceUid, sopInstanceUid));
            Assert.NotEmpty(await _testHelper.GetInstancesAsync(studyInstanceUid, seriesInstanceUid, sopInstanceUid2));
            Assert.NotEmpty(await _testHelper.GetSeriesMetadataAsync(seriesInstanceUid));
            Assert.NotEmpty(await _testHelper.GetStudyMetadataAsync(studyInstanceUid));

            Assert.Collection(await _testHelper.GetDeletedInstanceEntriesAsync(studyInstanceUid, seriesInstanceUid, null), ValidateSingleDeletedInstance(instance));
        }
예제 #12
0
        public async Task WhenRetrievingPartitions_TheServerShouldReturnAllPartitions()
        {
            var newPartition1 = TestUidGenerator.Generate();
            var newPartition2 = TestUidGenerator.Generate();

            DicomFile dicomFile = Samples.CreateRandomDicomFile();

            using DicomWebResponse <DicomDataset> response1 = await _instancesManager.StoreAsync(new[] { dicomFile }, partitionName : newPartition1);

            using DicomWebResponse <DicomDataset> response2 = await _instancesManager.StoreAsync(new[] { dicomFile }, partitionName : newPartition2);

            using DicomWebResponse <IEnumerable <PartitionEntry> > response3 = await _client.GetPartitionsAsync();

            Assert.True(response3.IsSuccessStatusCode);

            IEnumerable <PartitionEntry> values = await response3.GetValueAsync();

            Assert.Contains(values, x => x.PartitionName == newPartition1);
            Assert.Contains(values, x => x.PartitionName == newPartition2);
        }
        public async Task GivenMultipleInstancesWithMixTransferSyntax_WhenRetrieveStudy_ThenServerShouldReturnNotAcceptable()
        {
            var studyInstanceUid = TestUidGenerator.Generate();

            DicomFile dicomFile1 = Samples.CreateRandomDicomFileWith8BitPixelData(
                studyInstanceUid,
                TestUidGenerator.Generate(),
                transferSyntax: DicomTransferSyntax.ExplicitVRLittleEndian.UID.UID);

            DicomFile dicomFile2 = Samples.CreateRandomDicomFileWith8BitPixelData(
                studyInstanceUid,
                TestUidGenerator.Generate(),
                transferSyntax: DicomTransferSyntax.MPEG2.UID.UID,
                encode: false);

            await _instancesManager.StoreAsync(new[] { dicomFile1, dicomFile2 });

            DicomWebException exception = await Assert.ThrowsAsync <DicomWebException>(() => _client.RetrieveStudyAsync(studyInstanceUid, dicomTransferSyntax: DicomTransferSyntax.ExplicitVRLittleEndian.UID.UID));

            Assert.Equal(HttpStatusCode.NotAcceptable, exception.StatusCode);
        }
        public async Task GivenRetrieveSeriesMetadataRequest_WhenInstanceIsDeletedInSeriesAndPreviousETagIsUsed_ThenResponseMetadataIsReturnedWithNewETag()
        {
            string studyInstanceUid    = TestUidGenerator.Generate();
            string seriesInstanceUid   = TestUidGenerator.Generate();
            string firstSopInstanceUid = TestUidGenerator.Generate();

            DicomDataset firstStoredInstance = await PostDicomFileAsync(ResourceType.Instance, studyInstanceUid, seriesInstanceUid, firstSopInstanceUid, dataSet : GenerateNewDataSet());

            DicomDataset secondStoredInstance = await PostDicomFileAsync(ResourceType.Series, studyInstanceUid, seriesInstanceUid, dataSet : GenerateNewDataSet());

            DicomWebResponse <IReadOnlyList <DicomDataset> > response = await _client.RetrieveSeriesMetadataAsync(studyInstanceUid, seriesInstanceUid);

            string eTag = GetEtagFromResponse(response);

            await _client.DeleteInstanceAsync(studyInstanceUid, seriesInstanceUid, firstSopInstanceUid);

            response = await _client.RetrieveSeriesMetadataAsync(studyInstanceUid, seriesInstanceUid, eTag);

            Assert.Single(response.Value);
            ValidateResponseMetadataDataset(secondStoredInstance, response.Value.First());
        }
        public async Task GivenDicomInstanceWithDifferentTypesOfExtendedQueryTags_WhenDeletedBySopInstanceId_ThenTagValuesShouldBeRemoved()
        {
            string studyInstanceUid  = TestUidGenerator.Generate();
            string seriesInstanceUid = TestUidGenerator.Generate();
            string sopInstanceUid    = TestUidGenerator.Generate();
            string sopInstanceUid2   = TestUidGenerator.Generate();

            try
            {
                // Store 5 tags, 1 study level datetime tag, 2 series level string and double tags and 2 instance level long and person name tags.
                IReadOnlyList <QueryTag> tags = await StoreTagsOfSuportedDataTypes();

                // Create 2 instances in same series and same study.
                Instance instance1 = await StoreInstanceWithDifferentTagValues(studyInstanceUid, seriesInstanceUid, sopInstanceUid, 1, tags);

                Instance instance2 = await StoreInstanceWithDifferentTagValues(studyInstanceUid, seriesInstanceUid, sopInstanceUid2, 2, tags);

                var queryTags = tags.ToArray();

                // Delete by instance uid.
                await _indexDataStore.DeleteInstanceIndexAsync(DefaultPartition.Key, studyInstanceUid, seriesInstanceUid, sopInstanceUid, Clock.UtcNow);

                // Study and series level tags should not be deleted.
                Assert.Single(await _extendedQueryTagStoreTestHelper.GetExtendedQueryTagDataAsync(ExtendedQueryTagDataType.DateTimeData, queryTags[0].ExtendedQueryTagStoreEntry.Key, instance1.StudyKey));
                Assert.Single(await _extendedQueryTagStoreTestHelper.GetExtendedQueryTagDataAsync(ExtendedQueryTagDataType.StringData, queryTags[1].ExtendedQueryTagStoreEntry.Key, instance1.StudyKey, instance1.SeriesKey));
                Assert.Single(await _extendedQueryTagStoreTestHelper.GetExtendedQueryTagDataAsync(ExtendedQueryTagDataType.DoubleData, queryTags[2].ExtendedQueryTagStoreEntry.Key, instance1.StudyKey, instance1.SeriesKey));

                // Instance level tags under the deleted instance should be deleted.
                Assert.Empty(await _extendedQueryTagStoreTestHelper.GetExtendedQueryTagDataAsync(ExtendedQueryTagDataType.LongData, queryTags[3].ExtendedQueryTagStoreEntry.Key, instance1.StudyKey, instance1.SeriesKey, instance1.InstanceKey));
                Assert.Empty(await _extendedQueryTagStoreTestHelper.GetExtendedQueryTagDataAsync(ExtendedQueryTagDataType.PersonNameData, queryTags[4].ExtendedQueryTagStoreEntry.Key, instance1.StudyKey, instance1.SeriesKey, instance1.InstanceKey));

                // Instance level tags under the other instance should not be deleted.
                Assert.Single(await _extendedQueryTagStoreTestHelper.GetExtendedQueryTagDataAsync(ExtendedQueryTagDataType.LongData, queryTags[3].ExtendedQueryTagStoreEntry.Key, instance1.StudyKey, instance1.SeriesKey, instance2.InstanceKey));
                Assert.Single(await _extendedQueryTagStoreTestHelper.GetExtendedQueryTagDataAsync(ExtendedQueryTagDataType.PersonNameData, queryTags[4].ExtendedQueryTagStoreEntry.Key, instance1.StudyKey, instance1.SeriesKey, instance2.InstanceKey));
            }
            finally
            {
                await CleanupExtendedQueryTags();
            }
        }
        public async Task GivenAMultipartRequestWithAnInvalidMultipartSection_WhenStoring_TheServerShouldReturnAccepted()
        {
            var multiContent = new MultipartContent("related");

            multiContent.Headers.ContentType.Parameters.Add(new System.Net.Http.Headers.NameValueHeaderValue("type", $"\"{DicomWebConstants.MediaTypeApplicationDicom.MediaType}\""));

            var byteContent = new ByteArrayContent(Array.Empty <byte>());

            byteContent.Headers.ContentType = DicomWebConstants.MediaTypeApplicationDicom;
            multiContent.Add(byteContent);

            string studyInstanceUID = TestUidGenerator.Generate();

            try
            {
                DicomFile validFile = Samples.CreateRandomDicomFile(studyInstanceUID);

                await using (MemoryStream stream = _recyclableMemoryStreamManager.GetStream())
                {
                    await validFile.SaveAsync(stream);

                    var validByteContent = new ByteArrayContent(stream.ToArray());
                    validByteContent.Headers.ContentType = DicomWebConstants.MediaTypeApplicationDicom;
                    multiContent.Add(validByteContent);
                }

                using DicomWebResponse <DicomDataset> response = await _instancesManager.StoreAsync(multiContent, instanceId : DicomInstanceId.FromDicomFile(validFile));

                Assert.Equal(HttpStatusCode.Accepted, response.StatusCode);

                await ValidateReferencedSopSequenceAsync(
                    response,
                    ConvertToReferencedSopSequenceEntry(validFile.Dataset));
            }
            finally
            {
                await _client.DeleteStudyAsync(studyInstanceUID);
            }
        }
예제 #17
0
        public async void GivenAMultipartRequestWithTypeParameterAndFirstSectionWithoutContentType_WhenStoring_TheServerShouldReturnOK()
        {
            var request = new HttpRequestMessage(HttpMethod.Post, "studies");

            request.Headers.Add(HeaderNames.Accept, DicomWebClient.MediaTypeApplicationDicomJson.MediaType);

            var multiContent = new MultipartContent("related");

            multiContent.Headers.ContentType.Parameters.Add(new System.Net.Http.Headers.NameValueHeaderValue("type", $"\"{DicomWebClient.MediaTypeApplicationDicom.MediaType}\""));

            string studyInstanceUID = TestUidGenerator.Generate();

            try
            {
                DicomFile dicomFile = Samples.CreateRandomDicomFile(studyInstanceUID);

                await using (MemoryStream stream = _recyclableMemoryStreamManager.GetStream())
                {
                    await dicomFile.SaveAsync(stream);

                    var byteContent = new ByteArrayContent(stream.ToArray());
                    multiContent.Add(byteContent);
                }

                request.Content = multiContent;

                DicomWebResponse <DicomDataset> response = await _client.PostMultipartContentAsync(multiContent, "studies");

                Assert.Equal(HttpStatusCode.OK, response.StatusCode);

                ValidationHelpers.ValidateReferencedSopSequence(
                    response.Value,
                    ConvertToReferencedSopSequenceEntry(dicomFile.Dataset));
            }
            finally
            {
                await _client.DeleteStudyAsync(studyInstanceUID);
            }
        }
예제 #18
0
        public async Task GivenASetOfDicomInstances_WhenRetrievingChangeFeed_ThenTheExpectedInstanceAreReturned()
        {
            var  studyInstanceUid  = TestUidGenerator.Generate();
            var  seriesInstanceUid = TestUidGenerator.Generate();
            var  sopInstanceUids   = Enumerable.Range(1, 10).Select(x => TestUidGenerator.Generate()).ToArray();
            long initialSequence   = -1;

            for (int i = 0; i < 10; i++)
            {
                await CreateFile(studyInstanceUid, seriesInstanceUid, sopInstanceUids[i]);

                if (initialSequence == -1)
                {
                    var result = await _client.GetChangeFeedLatest();

                    initialSequence = result.Value.Sequence;
                    Assert.Equal(studyInstanceUid, result.Value.StudyInstanceUid);
                    Assert.Equal(seriesInstanceUid, result.Value.SeriesInstanceUid);
                    Assert.Equal(sopInstanceUids[i], result.Value.SopInstanceUid);
                    Assert.Equal(ChangeFeedAction.Create, result.Value.Action);
                    Assert.Equal(ChangeFeedState.Current, result.Value.State);
                }
            }

            var changeFeedResults = await _client.GetChangeFeed();

            Assert.Equal(10, changeFeedResults.Value.Count);

            changeFeedResults = await _client.GetChangeFeed($"?offset={initialSequence - 1}");

            Assert.Equal(10, changeFeedResults.Value.Count);
            for (int i = 0; i < 10; i++)
            {
                Assert.Equal(studyInstanceUid, changeFeedResults.Value[i].StudyInstanceUid);
                Assert.Equal(seriesInstanceUid, changeFeedResults.Value[i].SeriesInstanceUid);
                Assert.Equal(sopInstanceUids[i], changeFeedResults.Value[i].SopInstanceUid);
                Assert.NotNull(changeFeedResults.Value[i].Metadata);
            }
        }
예제 #19
0
        public async void GivenRequestForStudies_WhenRetrievingQueriableExtendedQueryTags_ReturnsStudyTags(QueryResource resourceType)
        {
            var request = new QueryResourceRequest(
                Substitute.For <IEnumerable <KeyValuePair <string, StringValues> > >(),
                resourceType,
                TestUidGenerator.Generate(),
                TestUidGenerator.Generate());

            List <ExtendedQueryTagStoreEntry> storeEntries = new List <ExtendedQueryTagStoreEntry>()
            {
                new ExtendedQueryTagStoreEntry(1, "00741000", "CS", null, QueryTagLevel.Instance, ExtendedQueryTagStatus.Ready),
                new ExtendedQueryTagStoreEntry(2, "0040A121", "DA", null, QueryTagLevel.Series, ExtendedQueryTagStatus.Ready),
                new ExtendedQueryTagStoreEntry(3, "00101005", "PN", null, QueryTagLevel.Study, ExtendedQueryTagStatus.Ready),
            };

            var list = QueryTagService.CoreQueryTags.Concat(storeEntries.Select(item => new QueryTag(item))).ToList();

            _queryStore.QueryAsync(Arg.Any <QueryExpression>(), Arg.Any <CancellationToken>()).ReturnsForAnyArgs(new QueryResult(new List <VersionedInstanceIdentifier>()));
            await _queryService.QueryAsync(request, CancellationToken.None);

            _queryParser.Received().Parse(request, Arg.Do <IReadOnlyCollection <QueryTag> >(x => Assert.Equal(x, list, QueryTagComparer.Default)));
        }
예제 #20
0
        public async Task GivenMultipleDeletedInstances_OldestDeletedIsCorrect()
        {
            await _testHelper.ClearDeletedInstanceTable();

            DateTimeOffset start = Clock.UtcNow;

            string   studyInstanceUid  = TestUidGenerator.Generate();
            string   seriesInstanceUid = TestUidGenerator.Generate();
            string   sopInstanceUid    = TestUidGenerator.Generate();
            Instance instance1         = await CreateIndexAndVerifyInstance(studyInstanceUid, seriesInstanceUid, sopInstanceUid);

            await _indexDataStore.DeleteInstanceIndexAsync(studyInstanceUid, seriesInstanceUid, sopInstanceUid, Clock.UtcNow);

            string   sopInstanceUid2 = TestUidGenerator.Generate();
            Instance instance2       = await CreateIndexAndVerifyInstance(studyInstanceUid, seriesInstanceUid, sopInstanceUid2);

            await Task.Delay(5000);

            await _indexDataStore.DeleteInstanceIndexAsync(studyInstanceUid, seriesInstanceUid, sopInstanceUid2, Clock.UtcNow);

            Assert.InRange(await _indexDataStore.GetOldestDeletedAsync(), start.AddSeconds(-1), start.AddSeconds(1));
        }
        public async Task GivenRetrieveStudyMetadataRequest_WhenIfNoneMatchDoesnotMatchETag_ThenResponseMetadataIsReturnedWithNewETag()
        {
            string studyInstanceUid = TestUidGenerator.Generate();

            DicomDataset firstStoredInstance = await PostDicomFileAsync(ResourceType.Study, studyInstanceUid, dataSet : GenerateNewDataSet());

            DicomDataset secondStoredInstance = await PostDicomFileAsync(ResourceType.Study, studyInstanceUid, dataSet : GenerateNewDataSet());

            DicomWebResponse <IReadOnlyList <DicomDataset> > response = await _client.RetrieveStudyMetadataAsync(studyInstanceUid);

            string eTag        = GetEtagFromResponse(response);
            string ifNoneMatch = null;

            if (!string.IsNullOrEmpty(eTag))
            {
                ifNoneMatch = string.Concat("1", eTag);
            }

            response = await _client.RetrieveStudyMetadataAsync(studyInstanceUid, ifNoneMatch);

            ValidateResponseMetadataDataset(response, firstStoredInstance, secondStoredInstance);
        }
예제 #22
0
        public async Task GivenMultipleDicomInstance_WhenDeletedByStudyInstanceUid_ThenItemsBeRemovedAndAddedToDeletedInstanceTable()
        {
            string   studyInstanceUid  = TestUidGenerator.Generate();
            string   seriesInstanceUid = TestUidGenerator.Generate();
            string   sopInstanceUid    = TestUidGenerator.Generate();
            Instance instance1         = await CreateIndexAndVerifyInstance(studyInstanceUid, seriesInstanceUid, sopInstanceUid);

            string   sopInstanceUid2 = TestUidGenerator.Generate();
            Instance instance2       = await CreateIndexAndVerifyInstance(studyInstanceUid, seriesInstanceUid, sopInstanceUid2);

            await _indexDataStore.DeleteStudyIndexAsync(studyInstanceUid, Clock.UtcNow);

            Assert.Empty(await _testHelper.GetInstancesAsync(studyInstanceUid, seriesInstanceUid, sopInstanceUid));
            Assert.Empty(await _testHelper.GetInstancesAsync(studyInstanceUid, seriesInstanceUid, sopInstanceUid2));
            Assert.Empty(await _testHelper.GetSeriesMetadataAsync(seriesInstanceUid));
            Assert.Empty(await _testHelper.GetStudyMetadataAsync(seriesInstanceUid));

            Assert.Collection(
                await _testHelper.GetDeletedInstanceEntriesAsync(studyInstanceUid, null, null),
                ValidateSingleDeletedInstance(instance1),
                ValidateSingleDeletedInstance(instance2));
        }
예제 #23
0
        public async Task GivenAnInstance_WhenRetrievingChangeFeedWithoutMetadata_ThenMetadataIsNotReturned()
        {
            var studyInstanceUid  = TestUidGenerator.Generate();
            var seriesInstanceUid = TestUidGenerator.Generate();
            var sopInstanceUid    = TestUidGenerator.Generate();

            await CreateFile(studyInstanceUid, seriesInstanceUid, sopInstanceUid);

            var latestResult = await _client.GetChangeFeedLatest("?includemetadata=false");

            long initialSequence = latestResult.Value.Sequence;

            Assert.Equal(studyInstanceUid, latestResult.Value.StudyInstanceUid);
            Assert.Equal(seriesInstanceUid, latestResult.Value.SeriesInstanceUid);
            Assert.Equal(sopInstanceUid, latestResult.Value.SopInstanceUid);
            Assert.Null(latestResult.Value.Metadata);

            var changeFeedResults = await _client.GetChangeFeed($"?offset={initialSequence - 1}&includemetadata=false");

            Assert.Equal(1, changeFeedResults.Value.Count);
            Assert.Null(changeFeedResults.Value[0].Metadata);
            Assert.Equal(ChangeFeedState.Current, changeFeedResults.Value[0].State);
        }
예제 #24
0
        public async Task WhenRetrievingWithPartitionName_TheServerShouldReturnOnlyTheSpecifiedPartition()
        {
            var newPartition1 = "partition1";
            var newPartition2 = "partition2";

            string studyInstanceUID  = TestUidGenerator.Generate();
            string seriesInstanceUID = TestUidGenerator.Generate();
            string sopInstanceUID    = TestUidGenerator.Generate();

            DicomFile dicomFile = Samples.CreateRandomDicomFile(studyInstanceUID, seriesInstanceUID, sopInstanceUID);

            using DicomWebResponse <DicomDataset> response1 = await _instancesManager.StoreAsync(new[] { dicomFile }, partitionName : newPartition1);

            using DicomWebResponse <DicomDataset> response2 = await _instancesManager.StoreAsync(new[] { dicomFile }, partitionName : newPartition2);

            using DicomWebResponse <DicomFile> response3 = await _client.RetrieveInstanceAsync(studyInstanceUID, seriesInstanceUID, sopInstanceUID, partitionName : newPartition1);

            Assert.True(response3.IsSuccessStatusCode);

            using DicomWebResponse <DicomFile> response4 = await _client.RetrieveInstanceAsync(studyInstanceUID, seriesInstanceUID, sopInstanceUID, partitionName : newPartition2);

            Assert.True(response4.IsSuccessStatusCode);
        }
예제 #25
0
        public async Task GivenANonExistingDicomInstance_WhenStatusIsUpdated_ThenDicomInstanceNotFoundExceptionShouldBeThrown()
        {
            string studyInstanceUid  = TestUidGenerator.Generate();
            string seriesInstanceUid = TestUidGenerator.Generate();
            string sopInstanceUid    = TestUidGenerator.Generate();

            DicomDataset dataset = Samples.CreateRandomDicomFile(studyInstanceUid, seriesInstanceUid, sopInstanceUid).Dataset;

            long version = await _indexDataStore.CreateInstanceIndexAsync(dataset);

            VersionedInstanceIdentifier versionedInstanceIdentifier = new VersionedInstanceIdentifier(
                studyInstanceUid,
                seriesInstanceUid,
                sopInstanceUid,
                version);

            await _indexDataStore.DeleteInstanceIndexAsync(versionedInstanceIdentifier);

            await Assert.ThrowsAsync <InstanceNotFoundException>(
                () => _indexDataStore.UpdateInstanceIndexStatusAsync(versionedInstanceIdentifier, IndexStatus.Created));

            Assert.Empty(await _testHelper.GetInstancesAsync(studyInstanceUid, seriesInstanceUid, sopInstanceUid));
        }
예제 #26
0
        public async Task GivenAnInstance_WhenRetrievingChangeFeedWithPartition_ThenPartitionNameIsReturned()
        {
            var    newPartition      = TestUidGenerator.Generate();
            string studyInstanceUID  = TestUidGenerator.Generate();
            string seriesInstanceUID = TestUidGenerator.Generate();
            string sopInstanceUID    = TestUidGenerator.Generate();

            DicomFile dicomFile = Samples.CreateRandomDicomFile(studyInstanceUID, seriesInstanceUID, sopInstanceUID);

            using DicomWebResponse <DicomDataset> response1 = await _instancesManager.StoreAsync(new[] { dicomFile }, partitionName : newPartition);

            Assert.True(response1.IsSuccessStatusCode);

            long initialSequence;

            using (DicomWebResponse <ChangeFeedEntry> response = await _client.GetChangeFeedLatest("?includemetadata=false"))
            {
                ChangeFeedEntry changeFeedEntry = await response.GetValueAsync();

                initialSequence = changeFeedEntry.Sequence;

                Assert.Equal(newPartition, changeFeedEntry.PartitionName);
                Assert.Equal(studyInstanceUID, changeFeedEntry.StudyInstanceUid);
                Assert.Equal(seriesInstanceUID, changeFeedEntry.SeriesInstanceUid);
                Assert.Equal(sopInstanceUID, changeFeedEntry.SopInstanceUid);
            }

            using (DicomWebAsyncEnumerableResponse <ChangeFeedEntry> response = await _client.GetChangeFeed($"?offset={initialSequence - 1}&includemetadata=false"))
            {
                ChangeFeedEntry[] changeFeedResults = await response.ToArrayAsync();

                Assert.Single(changeFeedResults);
                Assert.Null(changeFeedResults[0].Metadata);
                Assert.Equal(newPartition, changeFeedResults[0].PartitionName);
                Assert.Equal(ChangeFeedState.Current, changeFeedResults[0].State);
            }
        }
예제 #27
0
        public async Task GivenAnExistingDicomInstance_WhenStatusIsUpdated_ThenStatusShouldBeUpdated()
        {
            string studyInstanceUid  = TestUidGenerator.Generate();
            string seriesInstanceUid = TestUidGenerator.Generate();
            string sopInstanceUid    = TestUidGenerator.Generate();

            DicomDataset dataset = Samples.CreateRandomDicomFile(studyInstanceUid, seriesInstanceUid, sopInstanceUid).Dataset;

            long version = await _indexDataStore.CreateInstanceIndexAsync(dataset);

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

            Assert.NotNull(instance);

            DateTimeOffset lastStatusUpdatedDate = instance.LastStatusUpdatedDate;

            // Make sure there is delay between.
            await Task.Delay(50);

            await _indexDataStore.UpdateInstanceIndexStatusAsync(
                new VersionedInstanceIdentifier(
                    studyInstanceUid,
                    seriesInstanceUid,
                    sopInstanceUid,
                    version),
                IndexStatus.Created);

            IReadOnlyList <Instance> instances = await _testHelper.GetInstancesAsync(studyInstanceUid, seriesInstanceUid, sopInstanceUid);

            Assert.NotNull(instances);
            Assert.Single(instances);

            Instance updatedInstance = instances[0];

            Assert.Equal((byte)IndexStatus.Created, updatedInstance.Status);
            Assert.True(updatedInstance.LastStatusUpdatedDate > lastStatusUpdatedDate);
        }
        public async Task GivenInstances_WhenDeleteInstance_ThenAssociatedErrorsShouldBeRemoved()
        {
            string studyUid1    = TestUidGenerator.Generate();
            string seriesUid1   = TestUidGenerator.Generate();
            string instanceUid1 = TestUidGenerator.Generate();
            string studyUid2    = TestUidGenerator.Generate();
            string seriesUid2   = TestUidGenerator.Generate();
            string instanceUid2 = TestUidGenerator.Generate();

            // add instances
            long watermark1 = await AddInstanceAsync(studyUid1, seriesUid1, instanceUid1);

            long watermark2 = await AddInstanceAsync(studyUid2, seriesUid2, instanceUid2);

            // add tag
            DicomTag tag1   = DicomTag.DeviceSerialNumber;
            int      tagKey = await AddTagAsync(tag1);


            // add errors
            ValidationErrorCode errorCode = ValidationErrorCode.DateIsInvalid;
            await _extendedQueryTagErrorStore.AddExtendedQueryTagErrorAsync(tagKey, errorCode, watermark1);

            await _extendedQueryTagErrorStore.AddExtendedQueryTagErrorAsync(tagKey, errorCode, watermark2);

            // delete instance
            await _indexDataStore.DeleteInstanceIndexAsync(new InstanceIdentifier(studyUid1, seriesUid1, instanceUid1, DefaultPartition.Key));

            // check errors
            var errors = await _extendedQueryTagErrorStore.GetExtendedQueryTagErrorsAsync(tag1.GetPath(), int.MaxValue, 0);

            Assert.Single(errors);
            Assert.Equal(studyUid2, errors[0].StudyInstanceUid);
            Assert.Equal(seriesUid2, errors[0].SeriesInstanceUid);
            Assert.Equal(instanceUid2, errors[0].SopInstanceUid);
        }
예제 #29
0
        public async Task GivenUnsupportedTransferSyntax_WhenRetrieveFrame_ThenServerShouldReturnNotAcceptable()
        {
            string studyInstanceUid  = TestUidGenerator.Generate();
            string seriesInstanceUid = TestUidGenerator.Generate();
            string sopInstanceUid    = TestUidGenerator.Generate();

            DicomFile dicomFile = Samples.CreateRandomDicomFileWith8BitPixelData(
                studyInstanceUid,
                seriesInstanceUid,
                sopInstanceUid,
                transferSyntax: DicomTransferSyntax.HEVCH265Main10ProfileLevel51.UID.UID,
                encode: false);

            await InternalStoreAsync(new[] { dicomFile });

            DicomWebException exception = await Assert.ThrowsAsync <DicomWebException>(() => _client.RetrieveFramesAsync(
                                                                                           studyInstanceUid,
                                                                                           seriesInstanceUid,
                                                                                           sopInstanceUid,
                                                                                           dicomTransferSyntax: DicomTransferSyntax.JPEG2000Lossless.UID.UID,
                                                                                           frames: new[] { 1 }));

            Assert.Equal(HttpStatusCode.NotAcceptable, exception.StatusCode);
        }
예제 #30
0
        private async Task <List <DicomDataset> > GenerateDicomDatasets(string seriesInstanceUid, int instancesinSeries, bool storeInstanceFile)
        {
            List <DicomDataset> dicomDatasets = new List <DicomDataset>();

            for (int i = 0; i < instancesinSeries; i++)
            {
                var ds = new DicomDataset(DicomTransferSyntax.ExplicitVRLittleEndian)
                {
                    { DicomTag.StudyInstanceUID, _studyInstanceUid },
                    { DicomTag.SeriesInstanceUID, seriesInstanceUid },
                    { DicomTag.SOPInstanceUID, TestUidGenerator.Generate() },
                    { DicomTag.SOPClassUID, TestUidGenerator.Generate() },
                    { DicomTag.PatientID, TestUidGenerator.Generate() },
                    { DicomTag.BitsAllocated, (ushort)8 },
                    { DicomTag.PhotometricInterpretation, PhotometricInterpretation.Monochrome2.Value },
                };

                await StoreDatasetsAndInstances(ds, storeInstanceFile);

                dicomDatasets.Add(ds);
            }

            return(dicomDatasets);
        }