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()); }
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()); }
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)); }
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()); }