public async Task InsufficientStorageSpace()
        {
            var cancellationTokenSource = new CancellationTokenSource();

            cancellationTokenSource.CancelAfter(1000);
            _storageInfoProvider.Setup(p => p.HasSpaceAvailableToRetrieve).Returns(false);
            _storageInfoProvider.Setup(p => p.AvailableFreeSpace).Returns(100);

            var store = new DataRetrievalService(
                _loggerFactory.Object,
                _httpClientFactory.Object,
                _logger.Object,
                _fileSystem,
                _dicomToolkit.Object,
                _serviceScopeFactory.Object,
                _cleanupQueue.Object,
                _storageInfoProvider.Object);

            await store.StartAsync(cancellationTokenSource.Token);

            Thread.Sleep(250);
            await store.StopAsync(cancellationTokenSource.Token);

            _logger.VerifyLogging($"Data Retriever Hosted Service is running.", LogLevel.Information, Times.Once());
            _logger.VerifyLogging($"Data Retriever Hosted Service is stopping.", LogLevel.Information, Times.Once());
            _storageInfoProvider.Verify(p => p.HasSpaceAvailableToRetrieve, Times.AtLeastOnce());
            _storageInfoProvider.Verify(p => p.AvailableFreeSpace, Times.AtLeastOnce());
        }
Beispiel #2
0
        public void CancellationTokenShallCancelTheService()
        {
            var cancellationTokenSource = new CancellationTokenSource();

            cancellationTokenSource.Cancel();

            var store = new DataRetrievalService(
                _dicomWebClient.Object,
                _logger.Object,
                _inferenceRequestStore.Object,
                _fileSystem,
                _dicomToolkit.Object,
                _jobStore.Object);

            store.StartAsync(cancellationTokenSource.Token);
            store.StopAsync(cancellationTokenSource.Token);

            _logger.VerifyLogging($"Data Retriever Hosted Service is running.", LogLevel.Information, Times.Once());
            _logger.VerifyLogging($"Data Retriever Hosted Service is stopping.", LogLevel.Information, Times.Once());
        }
        public async Task ProcessorRequest_ShallRetrieveFhirResources()
        {
            var cancellationTokenSource = new CancellationTokenSource();
            var storagePath             = "/store";

            _fileSystem.Directory.CreateDirectory(storagePath);

            #region Test Data

            var url     = "http://uri.test/";
            var request = new InferenceRequest
            {
                PayloadId     = Guid.NewGuid().ToString(),
                JobId         = Guid.NewGuid().ToString(),
                TransactionId = Guid.NewGuid().ToString(),
            };
            request.InputMetadata = new InferenceRequestMetadata
            {
                Details = new InferenceRequestDetails
                {
                    Type      = InferenceRequestType.FhireResource,
                    Resources = new List <FhirResource>()
                    {
                        new FhirResource
                        {
                            Id   = "1",
                            Type = "Patient"
                        }
                    }
                },
                Inputs = new List <InferenceRequestDetails>()
                {
                    new InferenceRequestDetails
                    {
                        Type      = InferenceRequestType.FhireResource,
                        Resources = new List <FhirResource>()
                        {
                            new FhirResource
                            {
                                Id   = "2",
                                Type = "Observation"
                            }
                        }
                    }
                }
            };
            request.InputResources.Add(
                new RequestInputDataResource
            {
                Interface         = InputInterfaceType.Algorithm,
                ConnectionDetails = new InputConnectionDetails()
            });
            request.InputResources.Add(
                new RequestInputDataResource
            {
                Interface         = InputInterfaceType.Fhir,
                ConnectionDetails = new InputConnectionDetails
                {
                    AuthId   = "token",
                    AuthType = ConnectionAuthType.Bearer,
                    Uri      = url
                }
            });

            Assert.True(request.IsValid(out string _));
            #endregion Test Data

            request.ConfigureTemporaryStorageLocation(storagePath);

            _inferenceRequestStore.SetupSequence(p => p.Take(It.IsAny <CancellationToken>()))
            .Returns(Task.FromResult(request))
            .Returns(() =>
            {
                cancellationTokenSource.Cancel();
                throw new OperationCanceledException("canceled");
            });

            _jobStore.Setup(p => p.Add(It.IsAny <InferenceJob>(), It.IsAny <bool>()));

            _handlerMock = new Mock <HttpMessageHandler>();
            _handlerMock.Protected()
            .Setup <Task <HttpResponseMessage> >(
                "SendAsync",
                ItExpr.IsAny <HttpRequestMessage>(),
                ItExpr.IsAny <CancellationToken>())
            .ReturnsAsync(() => new HttpResponseMessage(System.Net.HttpStatusCode.OK)
            {
                Content = new StringContent("{}")
            });

            _httpClientFactory.Setup(p => p.CreateClient(It.IsAny <string>()))
            .Returns(new HttpClient(_handlerMock.Object));

            _storageInfoProvider.Setup(p => p.HasSpaceAvailableToRetrieve).Returns(true);
            _storageInfoProvider.Setup(p => p.AvailableFreeSpace).Returns(100);

            var store = new DataRetrievalService(
                _loggerFactory.Object,
                _httpClientFactory.Object,
                _logger.Object,
                _fileSystem,
                _dicomToolkit.Object,
                _serviceScopeFactory.Object,
                _cleanupQueue.Object,
                _storageInfoProvider.Object);

            await store.StartAsync(cancellationTokenSource.Token);

            BlockUntilCancelled(cancellationTokenSource.Token);

            _handlerMock.Protected().Verify(
                "SendAsync",
                Times.Once(),
                ItExpr.Is <HttpRequestMessage>(req =>
                                               req.Method == HttpMethod.Get &&
                                               req.RequestUri.PathAndQuery.Contains("Patient/1")),
                ItExpr.IsAny <CancellationToken>());
            _handlerMock.Protected().Verify(
                "SendAsync",
                Times.Once(),
                ItExpr.Is <HttpRequestMessage>(req =>
                                               req.Method == HttpMethod.Get &&
                                               req.RequestUri.PathAndQuery.Contains("Observation/2")),
                ItExpr.IsAny <CancellationToken>());

            _jobStore.Verify(p => p.Add(It.IsAny <InferenceJob>(), false), Times.Once());

            _storageInfoProvider.Verify(p => p.HasSpaceAvailableToRetrieve, Times.AtLeastOnce());
            _storageInfoProvider.Verify(p => p.AvailableFreeSpace, Times.Never());
            _cleanupQueue.Verify(p => p.QueueInstance(It.IsAny <string>()), Times.Exactly(2));
        }
        public async Task ProcessorRequest_ShallQueryByAccessionNumberAndRetrieve()
        {
            var cancellationTokenSource = new CancellationTokenSource();
            var storagePath             = "/store";

            _fileSystem.Directory.CreateDirectory(storagePath);

            #region Test Data

            var url     = "http://uri.test/";
            var request = new InferenceRequest
            {
                PayloadId     = Guid.NewGuid().ToString(),
                JobId         = Guid.NewGuid().ToString(),
                TransactionId = Guid.NewGuid().ToString(),
            };
            request.InputMetadata = new InferenceRequestMetadata
            {
                Details = new InferenceRequestDetails
                {
                    Type            = InferenceRequestType.AccessionNumber,
                    AccessionNumber = new List <string>()
                    {
                        "ABC"
                    }
                }
            };
            request.InputResources.Add(
                new RequestInputDataResource
            {
                Interface         = InputInterfaceType.Algorithm,
                ConnectionDetails = new InputConnectionDetails()
            });
            request.InputResources.Add(
                new RequestInputDataResource
            {
                Interface         = InputInterfaceType.DicomWeb,
                ConnectionDetails = new InputConnectionDetails
                {
                    AuthId   = "token",
                    AuthType = ConnectionAuthType.Basic,
                    Uri      = url
                }
            });

            Assert.True(request.IsValid(out string _));
            #endregion Test Data

            request.ConfigureTemporaryStorageLocation(storagePath);

            _dicomToolkit.Setup(p => p.Save(It.IsAny <DicomFile>(), It.IsAny <string>()));

            _inferenceRequestStore.SetupSequence(p => p.Take(It.IsAny <CancellationToken>()))
            .Returns(Task.FromResult(request))
            .Returns(() =>
            {
                cancellationTokenSource.Cancel();
                throw new OperationCanceledException("canceled");
            });

            _jobStore.Setup(p => p.Add(It.IsAny <InferenceJob>(), It.IsAny <bool>()));

            var studyInstanceUids = new List <string>()
            {
                DicomUIDGenerator.GenerateDerivedFromUUID().UID,
                DicomUIDGenerator.GenerateDerivedFromUUID().UID
            };
            _handlerMock = new Mock <HttpMessageHandler>();
            _handlerMock.Protected()
            .Setup <Task <HttpResponseMessage> >(
                "SendAsync",
                ItExpr.Is <HttpRequestMessage>(p => p.RequestUri.Query.Contains("ABC")),
                ItExpr.IsAny <CancellationToken>())
            .ReturnsAsync(() =>
            {
                return(GenerateQueryResult(DicomTag.AccessionNumber, "ABC", studyInstanceUids));
            });
            _handlerMock.Protected()
            .Setup <Task <HttpResponseMessage> >(
                "SendAsync",
                ItExpr.Is <HttpRequestMessage>(p => !p.RequestUri.Query.Contains("ABC")),
                ItExpr.IsAny <CancellationToken>())
            .ReturnsAsync(() =>
            {
                return(GenerateMultipartResponse());
            });

            _httpClientFactory.Setup(p => p.CreateClient(It.IsAny <string>()))
            .Returns(new HttpClient(_handlerMock.Object));
            _storageInfoProvider.Setup(p => p.HasSpaceAvailableToRetrieve).Returns(true);
            _storageInfoProvider.Setup(p => p.AvailableFreeSpace).Returns(100);

            var store = new DataRetrievalService(
                _loggerFactory.Object,
                _httpClientFactory.Object,
                _logger.Object,
                _fileSystem,
                _dicomToolkit.Object,
                _serviceScopeFactory.Object,
                _cleanupQueue.Object,
                _storageInfoProvider.Object);

            await store.StartAsync(cancellationTokenSource.Token);

            BlockUntilCancelled(cancellationTokenSource.Token);

            _handlerMock.Protected().Verify(
                "SendAsync",
                Times.Once(),
                ItExpr.Is <HttpRequestMessage>(req =>
                                               req.Method == HttpMethod.Get &&
                                               req.RequestUri.Query.Contains("00080050=ABC")),
                ItExpr.IsAny <CancellationToken>());

            foreach (var studyInstanceUid in studyInstanceUids)
            {
                _handlerMock.Protected().Verify(
                    "SendAsync",
                    Times.Once(),
                    ItExpr.Is <HttpRequestMessage>(req =>
                                                   req.Method == HttpMethod.Get &&
                                                   req.RequestUri.ToString().StartsWith($"{url}studies/{studyInstanceUid}")),
                    ItExpr.IsAny <CancellationToken>());
            }
            _jobStore.Verify(p => p.Add(It.IsAny <InferenceJob>(), false), Times.Once());

            _dicomToolkit.Verify(p => p.Save(It.IsAny <DicomFile>(), It.IsAny <string>()), Times.Exactly(studyInstanceUids.Count));
            _storageInfoProvider.Verify(p => p.HasSpaceAvailableToRetrieve, Times.AtLeastOnce());
            _storageInfoProvider.Verify(p => p.AvailableFreeSpace, Times.Never());
            _cleanupQueue.Verify(p => p.QueueInstance(It.IsAny <string>()), Times.Exactly(2));
        }
        public async Task ProcessorRequest_ShallRestorePreviouslyRetrievedFiles()
        {
            var cancellationTokenSource = new CancellationTokenSource();
            var storagePath             = "/store";

            _fileSystem.Directory.CreateDirectory(storagePath);
            _fileSystem.File.Create(_fileSystem.Path.Combine(storagePath, "file1.dcm"));
            _fileSystem.File.Create(_fileSystem.Path.Combine(storagePath, "file2.dcm"));
            _fileSystem.File.Create(_fileSystem.Path.Combine(storagePath, "file3.dcm"));
            _fileSystem.File.Create(_fileSystem.Path.Combine(storagePath, "corrupted.dcm"));
            _fileSystem.File.Create(_fileSystem.Path.Combine(storagePath, "text.txt"));
            var request = new InferenceRequest
            {
                PayloadId     = Guid.NewGuid().ToString(),
                JobId         = Guid.NewGuid().ToString(),
                TransactionId = Guid.NewGuid().ToString(),
                InputMetadata = new InferenceRequestMetadata()
            };

            request.InputMetadata.Details = new InferenceRequestDetails()
            {
                Type      = InferenceRequestType.DicomPatientId,
                PatientId = "123"
            };
            request.InputResources.Add(
                new RequestInputDataResource
            {
                Interface         = InputInterfaceType.Algorithm,
                ConnectionDetails = new InputConnectionDetails()
            });
            request.InputResources.Add(
                new RequestInputDataResource
            {
                Interface         = InputInterfaceType.DicomWeb,
                ConnectionDetails = new InputConnectionDetails()
                {
                    Uri      = "http://valid.uri/api",
                    AuthType = ConnectionAuthType.None
                }
            });
            request.ConfigureTemporaryStorageLocation(storagePath);
            Assert.True(request.IsValid(out string _));

            _dicomToolkit.Setup(p => p.HasValidHeader(It.IsAny <string>()))
            .Returns((string filename) =>
            {
                if (filename.EndsWith("text.txt"))
                {
                    return(false);
                }
                else if (filename.EndsWith("corrupted.dcm"))
                {
                    return(false);
                }
                return(true);
            });

            _dicomToolkit.Setup(p => p.Open(It.IsAny <string>()))
            .Returns(() => InstanceGenerator.GenerateDicomFile());

            _inferenceRequestStore.SetupSequence(p => p.Take(It.IsAny <CancellationToken>()))
            .Returns(Task.FromResult(request))
            .Returns(() =>
            {
                cancellationTokenSource.Cancel();
                throw new OperationCanceledException("canceled");
            });

            _jobStore.Setup(p => p.Add(It.IsAny <InferenceJob>(), It.IsAny <bool>()));

            _handlerMock = new Mock <HttpMessageHandler>();
            _handlerMock
            .Protected()
            .Setup <Task <HttpResponseMessage> >(
                "SendAsync",
                ItExpr.IsAny <HttpRequestMessage>(),
                ItExpr.IsAny <CancellationToken>())
            .ReturnsAsync(() =>
            {
                return(new HttpResponseMessage(System.Net.HttpStatusCode.OK)
                {
                    Content = new StringContent("[]")
                });
            });

            _httpClientFactory.Setup(p => p.CreateClient(It.IsAny <string>()))
            .Returns(new HttpClient(_handlerMock.Object));
            _storageInfoProvider.Setup(p => p.HasSpaceAvailableToRetrieve).Returns(true);
            _storageInfoProvider.Setup(p => p.AvailableFreeSpace).Returns(100);
            _cleanupQueue.Setup(p => p.QueueInstance(It.IsAny <string>()));

            var store = new DataRetrievalService(
                _loggerFactory.Object,
                _httpClientFactory.Object,
                _logger.Object,
                _fileSystem,
                _dicomToolkit.Object,
                _serviceScopeFactory.Object,
                _cleanupQueue.Object,
                _storageInfoProvider.Object);

            await store.StartAsync(cancellationTokenSource.Token);

            BlockUntilCancelled(cancellationTokenSource.Token);

            _logger.VerifyLoggingMessageBeginsWith($"Restored previously retrieved instance", LogLevel.Debug, Times.Exactly(3));
            _logger.VerifyLoggingMessageBeginsWith($"Restored previously retrieved instance", LogLevel.Debug, Times.Exactly(3));
            _logger.VerifyLoggingMessageBeginsWith($"Unable to restore previously retrieved instance from", LogLevel.Warning, Times.Once());
            _jobStore.Verify(p => p.Add(It.IsAny <InferenceJob>(), false), Times.Once());
            _storageInfoProvider.Verify(p => p.HasSpaceAvailableToRetrieve, Times.AtLeastOnce());
            _storageInfoProvider.Verify(p => p.AvailableFreeSpace, Times.Never());
        }
Beispiel #6
0
        public async Task ProcessorRequest_ShallRetrieveViaDicomWebWithDicomUid()
        {
            var cancellationTokenSource = new CancellationTokenSource();
            var storagePath             = "/store";

            _fileSystem.Directory.CreateDirectory(storagePath);

            #region Test Data

            var request = new InferenceRequest
            {
                PayloadId     = Guid.NewGuid().ToString(),
                JobId         = Guid.NewGuid().ToString(),
                TransactionId = Guid.NewGuid().ToString()
            };
            request.InputMetadata = new InferenceRequestMetadata
            {
                Details = new InferenceRequestDetails
                {
                    Type    = InferenceRequestType.DicomUid,
                    Studies = new List <RequestedStudy>
                    {
                        new RequestedStudy
                        {
                            StudyInstanceUid = "1",
                            Series           = new List <RequestedSeries>
                            {
                                new RequestedSeries
                                {
                                    SeriesInstanceUid = "1.1",
                                    Instances         = new List <RequestedInstance>
                                    {
                                        new RequestedInstance
                                        {
                                            SopInstanceUid = new List <string>
                                            {
                                                "1.1.2",
                                                "1.1.3"
                                            }
                                        }
                                    }
                                }
                            }
                        },
                        new RequestedStudy
                        {
                            StudyInstanceUid = "2",
                            Series           = new List <RequestedSeries>
                            {
                                new RequestedSeries
                                {
                                    SeriesInstanceUid = "2.1"
                                }
                            }
                        },
                        new RequestedStudy
                        {
                            StudyInstanceUid = "3"
                        },
                    }
                }
            };
            request.InputResources.Add(
                new RequestInputDataResource
            {
                Interface         = InputInterfaceType.Algorithm,
                ConnectionDetails = new InputConnectionDetails()
            });
            request.InputResources.Add(
                new RequestInputDataResource
            {
                Interface         = InputInterfaceType.DicomWeb,
                ConnectionDetails = new InputConnectionDetails
                {
                    AuthId   = "token",
                    AuthType = ConnectionAuthType.Basic,
                    Uri      = "http://uri.test/"
                }
            });

            #endregion Test Data

            request.ConfigureTemporaryStorageLocation(storagePath);

            _dicomToolkit.Setup(p => p.Save(It.IsAny <DicomFile>(), It.IsAny <string>()));

            _inferenceRequestStore.SetupSequence(p => p.Take(It.IsAny <CancellationToken>()))
            .Returns(Task.FromResult(request))
            .Returns(() =>
            {
                cancellationTokenSource.Cancel();
                throw new OperationCanceledException("canceled");
            });

            _jobStore.Setup(p => p.Add(It.IsAny <Job>(), It.IsAny <string>(), It.IsAny <IList <InstanceStorageInfo> >()));

            _wadoService.Setup(p => p.Retrieve(It.IsAny <string>(), It.IsAny <DicomTransferSyntax[]>()))
            .Returns((string studyInstanceUid, DicomTransferSyntax[] dicomTransferSyntaxes) => GenerateInstance(studyInstanceUid));
            _wadoService.Setup(p => p.Retrieve(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <DicomTransferSyntax[]>()))
            .Returns((string studyInstanceUid, string seriesInstanceUid, DicomTransferSyntax[] dicomTransferSyntaxes) => GenerateInstance(studyInstanceUid, seriesInstanceUid));
            _wadoService.Setup(p => p.Retrieve(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <DicomTransferSyntax[]>()))
            .Returns((string studyInstanceUid, string seriesInstanceUid, string sopInstanceUid, DicomTransferSyntax[] dicomTransferSyntaxes) =>
            {
                return(Task.FromResult(InstanceGenerator.GenerateDicomFile(studyInstanceUid, seriesInstanceUid, sopInstanceUid, _fileSystem)));
            });

            var store = new DataRetrievalService(
                _dicomWebClient.Object,
                _logger.Object,
                _inferenceRequestStore.Object,
                _fileSystem,
                _dicomToolkit.Object,
                _jobStore.Object);

            await store.StartAsync(cancellationTokenSource.Token);

            BlockUntilCancelled(cancellationTokenSource.Token);

            _jobStore.Verify(p => p.Add(It.IsAny <Job>(), It.IsAny <string>(), It.IsAny <IList <InstanceStorageInfo> >()), Times.Once());
            _wadoService.Verify(p => p.Retrieve(It.IsAny <string>(), It.IsAny <DicomTransferSyntax[]>()), Times.Once());
            _wadoService.Verify(p => p.Retrieve(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <DicomTransferSyntax[]>()), Times.Once());
            _wadoService.Verify(p => p.Retrieve(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <DicomTransferSyntax[]>()), Times.Exactly(2));
            _dicomToolkit.Verify(p => p.Save(It.IsAny <DicomFile>(), It.IsAny <string>()), Times.Exactly(4));
        }
Beispiel #7
0
        public async Task ProcessorRequest_ShallRestorePreviouslyRetrievedFiles()
        {
            var cancellationTokenSource = new CancellationTokenSource();
            var storagePath             = "/store";

            _fileSystem.Directory.CreateDirectory(storagePath);
            _fileSystem.File.Create(_fileSystem.Path.Combine(storagePath, "file1.dcm"));
            _fileSystem.File.Create(_fileSystem.Path.Combine(storagePath, "file2.dcm"));
            _fileSystem.File.Create(_fileSystem.Path.Combine(storagePath, "file3.dcm"));
            _fileSystem.File.Create(_fileSystem.Path.Combine(storagePath, "corrupted.dcm"));
            _fileSystem.File.Create(_fileSystem.Path.Combine(storagePath, "text.txt"));
            var request = new InferenceRequest
            {
                PayloadId     = Guid.NewGuid().ToString(),
                JobId         = Guid.NewGuid().ToString(),
                TransactionId = Guid.NewGuid().ToString()
            };

            request.InputResources.Add(
                new RequestInputDataResource
            {
                Interface         = InputInterfaceType.Algorithm,
                ConnectionDetails = new InputConnectionDetails()
            });
            request.ConfigureTemporaryStorageLocation(storagePath);

            _dicomToolkit.Setup(p => p.HasValidHeader(It.IsAny <string>()))
            .Returns((string filename) =>
            {
                if (filename.EndsWith("text.txt"))
                {
                    return(false);
                }
                else if (filename.EndsWith("corrupted.dcm"))
                {
                    return(false);
                }
                return(true);
            });

            _dicomToolkit.Setup(p => p.Open(It.IsAny <string>()))
            .Returns(() => InstanceGenerator.GenerateDicomFile());

            _inferenceRequestStore.SetupSequence(p => p.Take(It.IsAny <CancellationToken>()))
            .Returns(Task.FromResult(request))
            .Returns(() =>
            {
                cancellationTokenSource.Cancel();
                throw new OperationCanceledException("canceled");
            });

            _jobStore.Setup(p => p.Add(It.IsAny <Job>(), It.IsAny <string>(), It.IsAny <IList <InstanceStorageInfo> >()));

            var store = new DataRetrievalService(
                _dicomWebClient.Object,
                _logger.Object,
                _inferenceRequestStore.Object,
                _fileSystem,
                _dicomToolkit.Object,
                _jobStore.Object);

            await store.StartAsync(cancellationTokenSource.Token);

            BlockUntilCancelled(cancellationTokenSource.Token);

            _logger.VerifyLoggingMessageBeginsWith($"Restored previously retrieved instance", LogLevel.Debug, Times.Exactly(3));
            _logger.VerifyLoggingMessageBeginsWith($"Restored previously retrieved instance", LogLevel.Debug, Times.Exactly(3));
            _logger.VerifyLoggingMessageBeginsWith($"Unable to restore previously retrieved instance from", LogLevel.Warning, Times.Once());
            _jobStore.Verify(p => p.Add(It.IsAny <Job>(), It.IsAny <string>(), It.IsAny <IList <InstanceStorageInfo> >()), Times.Once());
        }