Example #1
0
        public async void GivenAMultipartRequestWithAnInvalidMultipartSection_WhenStoring_TheServerShouldReturnAccepted()
        {
            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}\""));

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

            byteContent.Headers.ContentType = DicomWebClient.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 = DicomWebClient.MediaTypeApplicationDicom;
                    multiContent.Add(validByteContent);
                }

                request.Content = multiContent;

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

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

                ValidationHelpers.ValidateReferencedSopSequence(
                    response.Value,
                    ConvertToReferencedSopSequenceEntry(validFile.Dataset));
            }
            finally
            {
                await _client.DeleteStudyAsync(studyInstanceUID);
            }
        }
        public async Task GivenMultipleErrors_WhenGettingPaginatedResults_ThenProperlyPaginateErrors()
        {
            // Add instances
            DicomTag tag = DicomTag.PatientName;

            long[] watermarks = new long[]
            {
                await AddInstanceAsync(TestUidGenerator.Generate(), TestUidGenerator.Generate(), TestUidGenerator.Generate()),
                await AddInstanceAsync(TestUidGenerator.Generate(), TestUidGenerator.Generate(), TestUidGenerator.Generate()),
                await AddInstanceAsync(TestUidGenerator.Generate(), TestUidGenerator.Generate(), TestUidGenerator.Generate()),
                await AddInstanceAsync(TestUidGenerator.Generate(), TestUidGenerator.Generate(), TestUidGenerator.Generate()),
            };

            int tagKey = await AddTagAsync(tag);

            // Add multiple errors
            await _extendedQueryTagErrorStore.AddExtendedQueryTagErrorAsync(tagKey, ValidationErrorCode.PersonNameExceedMaxGroups, watermarks[0]);

            await _extendedQueryTagErrorStore.AddExtendedQueryTagErrorAsync(tagKey, ValidationErrorCode.ExceedMaxLength, watermarks[1]);

            await _extendedQueryTagErrorStore.AddExtendedQueryTagErrorAsync(tagKey, ValidationErrorCode.InvalidCharacters, watermarks[2]);

            await _extendedQueryTagErrorStore.AddExtendedQueryTagErrorAsync(tagKey, ValidationErrorCode.PersonNameGroupExceedMaxLength, watermarks[3]);

            IReadOnlyList <ExtendedQueryTagError> errors;

            // Page 1
            errors = await _extendedQueryTagErrorStore.GetExtendedQueryTagErrorsAsync(tag.GetPath(), 1, 0);

            Assert.Equal(1, errors.Count);
            Assert.Equal(errors[0].ErrorMessage, ValidationErrorCode.PersonNameExceedMaxGroups.GetMessage());

            // Page 2
            errors = await _extendedQueryTagErrorStore.GetExtendedQueryTagErrorsAsync(tag.GetPath(), 2, 1);

            Assert.Equal(2, errors.Count);
            Assert.Equal(errors[0].ErrorMessage, ValidationErrorCode.ExceedMaxLength.GetMessage());
            Assert.Equal(errors[1].ErrorMessage, ValidationErrorCode.InvalidCharacters.GetMessage());

            // Page 3
            errors = await _extendedQueryTagErrorStore.GetExtendedQueryTagErrorsAsync(tag.GetPath(), 1, 3);

            Assert.Equal(1, errors.Count);
            Assert.Equal(errors[0].ErrorMessage, ValidationErrorCode.PersonNameGroupExceedMaxLength.GetMessage());
        }
Example #3
0
        public async Task GivenStoredDicomFile_WhenRetrievingMetadataForInstance_ThenMetadataIsRetrievedCorrectly()
        {
            string studyInstanceUid  = TestUidGenerator.Generate();
            string seriesInstanceUid = TestUidGenerator.Generate();
            string sopInstanceUid    = TestUidGenerator.Generate();

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

            using DicomWebAsyncEnumerableResponse <DicomDataset> response = await _client.RetrieveInstanceMetadataAsync(studyInstanceUid, seriesInstanceUid, sopInstanceUid);

            Assert.Equal(HttpStatusCode.OK, response.StatusCode);
            Assert.Equal("application/dicom+json", response.ContentHeaders.ContentType.MediaType);

            DicomDataset[] datasets = await response.ToArrayAsync();

            Assert.Single(datasets);
            ValidateResponseMetadataDataset(storedInstance, datasets[0]);
        }
        public async Task GivenUnsupportedInternalTransferSyntax_WhenRetrieveInstance_ThenServerShouldReturnNotAcceptable()
        {
            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 });

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

            Assert.Equal(HttpStatusCode.NotAcceptable, exception.StatusCode);
        }
Example #5
0
        public async Task GivenRetrieveInstanceMetadataRequest_WhenIfNoneMatchIsNotPresent_ThenResponseMetadataIsReturnedWithETag()
        {
            string studyInstanceUid  = TestUidGenerator.Generate();
            string seriesInstanceUid = TestUidGenerator.Generate();
            string sopInstanceUid    = TestUidGenerator.Generate();

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

            using DicomWebAsyncEnumerableResponse <DicomDataset> response = await _client.RetrieveInstanceMetadataAsync(studyInstanceUid, seriesInstanceUid, sopInstanceUid);

            Assert.Equal(HttpStatusCode.OK, response.StatusCode);
            Assert.Equal(KnownContentTypes.ApplicationDicomJson, response.ContentHeaders.ContentType.MediaType);

            DicomDataset[] datasets = await response.ToArrayAsync();

            Assert.Single(datasets);
            ValidateResponseMetadataDataset(storedInstance, datasets[0]);
        }
        public ChangeFeedServiceTests()
        {
            _changeFeedEntries = new List<ChangeFeedEntry>
            {
                new ChangeFeedEntry(1, DateTime.Now, ChangeFeedAction.Create, TestUidGenerator.Generate(), TestUidGenerator.Generate(), TestUidGenerator.Generate(), 1, 1, ChangeFeedState.Current),
                new ChangeFeedEntry(2, DateTime.Now, ChangeFeedAction.Create, TestUidGenerator.Generate(), TestUidGenerator.Generate(), TestUidGenerator.Generate(), 2, 2, ChangeFeedState.Current),
                new ChangeFeedEntry(3, DateTime.Now, ChangeFeedAction.Create, TestUidGenerator.Generate(), TestUidGenerator.Generate(), TestUidGenerator.Generate(), 3, 3, ChangeFeedState.Current),
                new ChangeFeedEntry(4, DateTime.Now, ChangeFeedAction.Create, TestUidGenerator.Generate(), TestUidGenerator.Generate(), TestUidGenerator.Generate(), 4, 4, ChangeFeedState.Current),
                new ChangeFeedEntry(5, DateTime.Now, ChangeFeedAction.Create, TestUidGenerator.Generate(), TestUidGenerator.Generate(), TestUidGenerator.Generate(), 5, 5, ChangeFeedState.Current),
                new ChangeFeedEntry(6, DateTime.Now, ChangeFeedAction.Create, TestUidGenerator.Generate(), TestUidGenerator.Generate(), TestUidGenerator.Generate(), 6, 6, ChangeFeedState.Current),
                new ChangeFeedEntry(7, DateTime.Now, ChangeFeedAction.Create, TestUidGenerator.Generate(), TestUidGenerator.Generate(), TestUidGenerator.Generate(), 7, 7, ChangeFeedState.Current),
                new ChangeFeedEntry(8, DateTime.Now, ChangeFeedAction.Create, TestUidGenerator.Generate(), TestUidGenerator.Generate(), TestUidGenerator.Generate(), 8, 8, ChangeFeedState.Current),
                new ChangeFeedEntry(9, DateTime.Now, ChangeFeedAction.Create, TestUidGenerator.Generate(), TestUidGenerator.Generate(), TestUidGenerator.Generate(), 9, 9, ChangeFeedState.Current),
                new ChangeFeedEntry(10, DateTime.Now, ChangeFeedAction.Create, TestUidGenerator.Generate(), TestUidGenerator.Generate(), TestUidGenerator.Generate(), 10, 10, ChangeFeedState.Current),
            };
            _changeFeedStore = Substitute.For<IChangeFeedStore>();

            _changeFeedStore.GetChangeFeedAsync(offset: default, limit: default, cancellationToken: default)
Example #7
0
        public async Task GivenMultipleFrames_WhenRetrieveFrame_ThenServerShouldReturnExpectedContent()
        {
            var            studyInstanceUid = TestUidGenerator.Generate();
            DicomFile      dicomFile1       = Samples.CreateRandomDicomFileWithPixelData(studyInstanceUid, frames: 3);
            DicomPixelData pixelData        = DicomPixelData.Create(dicomFile1.Dataset);
            var            dicomInstance    = dicomFile1.Dataset.ToInstanceIdentifier();

            await InternalStoreAsync(new[] { dicomFile1 });

            DicomWebResponse <IReadOnlyList <Stream> > frames = await _client.RetrieveFramesAsync(dicomInstance.StudyInstanceUid, dicomInstance.SeriesInstanceUid, dicomInstance.SopInstanceUid, frames : new[] { 1, 2 }, dicomTransferSyntax : "*");

            Assert.NotNull(frames);
            Assert.Equal(HttpStatusCode.OK, frames.StatusCode);
            Assert.Equal(2, frames.Value.Count);
            Assert.Equal(KnownContentTypes.MultipartRelated, frames.Content.Headers.ContentType.MediaType);
            Assert.Equal(pixelData.GetFrame(0).Data, frames.Value[0].ToByteArray());
            Assert.Equal(pixelData.GetFrame(1).Data, frames.Value[1].ToByteArray());
        }
        public async Task GivenMultipleTagsOnSameInstance_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 tags
            DicomTag tag1    = DicomTag.DeviceSerialNumber;
            int      tagKey1 = await AddTagAsync(tag1);

            DicomTag tag2    = DicomTag.DeviceID;
            int      tagKey2 = await AddTagAsync(tag2);

            // add errors
            ValidationErrorCode errorCode = ValidationErrorCode.DateIsInvalid;

            // both tag has error on instance1
            await _extendedQueryTagErrorStore.AddExtendedQueryTagErrorAsync(tagKey1, errorCode, watermark1);

            await _extendedQueryTagErrorStore.AddExtendedQueryTagErrorAsync(tagKey2, errorCode, watermark1);

            // Only tag2 has error on instance2
            await _extendedQueryTagErrorStore.AddExtendedQueryTagErrorAsync(tagKey2, errorCode, watermark2);

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

            // check errors
            Assert.Empty(await _extendedQueryTagErrorStore.GetExtendedQueryTagErrorsAsync(tag1.GetPath(), 1, 0));
            var errors = await _extendedQueryTagErrorStore.GetExtendedQueryTagErrorsAsync(tag2.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);
        }
Example #9
0
        public async Task GivenMultipleSeriesInStudy_WhenDeletingInstance_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);
        }
Example #10
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());
        }
Example #12
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);
            }
        }
Example #13
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);
        }
Example #17
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);
            }
        }
Example #18
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);
        }
Example #19
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));
        }
Example #20
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);
        }
        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 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 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();
            }
        }
Example #24
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);
            }
        }
        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);
        }
Example #26
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)));
        }
Example #27
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));
        }
Example #28
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));
        }
Example #29
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);
        }
Example #30
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));
        }