public async Task GivenNullMetadata_WhenRequestIsPrepared_ThenItShouldNotCreateEntryComponent()
        {
            var context = new FhirTransactionContext(ChangeFeedGenerator.Generate());

            await _patientPipeline.PrepareRequestAsync(context, DefaultCancellationToken);

            Assert.Null(context.Request.Patient);
        }
        private async Task ExecuteAndValidateRetryThenThrowTimeOut(Exception ex)
        {
            ChangeFeedEntry changeFeedEntry = ChangeFeedGenerator.Generate();

            _fhirTransactionPipeline.ProcessAsync(changeFeedEntry, DefaultCancellationToken).Throws(ex);

            await Assert.ThrowsAsync <TimeoutRejectedException>(() => _retryableFhirTransactionPipeline.ProcessAsync(changeFeedEntry, DefaultCancellationToken));
        }
        public void GivenNoUpdateToExistingPatient_WhenResponseIsProcessed_ThenItShouldBeNoOp()
        {
            // Simulate there is no update to patient resource (and therefore no response).
            var context = new FhirTransactionContext(ChangeFeedGenerator.Generate());

            context.Response.Patient = null;

            _patientPipeline.ProcessResponse(context);
        }
示例#4
0
        private async Task ExecuteAndValidate(Exception ex, int expectedNumberOfCalls)
        {
            ChangeFeedEntry changeFeedEntry = ChangeFeedGenerator.Generate();

            _fhirTransactionPipeline.ProcessAsync(changeFeedEntry, DefaultCancellationToken).Throws(ex);

            await Assert.ThrowsAsync(ex.GetType(), () => _retryableFhirTransactionPipeline.ProcessAsync(changeFeedEntry, DefaultCancellationToken));

            await _fhirTransactionPipeline.Received(expectedNumberOfCalls).ProcessAsync(changeFeedEntry, DefaultCancellationToken);
        }
示例#5
0
        public async Task GivenAnExistingEndpointWithDifferentAddress_WhenRequestIsPrepared_ThenFhirResourceValidationExceptionShouldBeThrown()
        {
            var context = new FhirTransactionContext(ChangeFeedGenerator.Generate());

            Endpoint endpoint = FhirResourceBuilder.CreateEndpointResource(address: "https://dicom2");

            _fhirService.RetrieveEndpointAsync(Arg.Any <string>(), DefaultCancellationToken).Returns(endpoint);

            await Assert.ThrowsAsync <FhirResourceValidationException>(() => _endpointPipeline.PrepareRequestAsync(context, DefaultCancellationToken));
        }
        private async Task <FhirTransactionRequestEntry> BuildImagingStudyEntryComponent(string studyInstanceUid, string seriesInstanceUid, string sopInstanceUid, string patientResourceId, bool addMetadata = true)
        {
            ChangeFeedEntry changeFeedEntry = ChangeFeedGenerator.Generate(
                action: ChangeFeedAction.Create,
                studyInstanceUid: studyInstanceUid,
                seriesInstanceUid: seriesInstanceUid,
                sopInstanceUid: sopInstanceUid,
                metadata: addMetadata ? FhirTransactionContextBuilder.CreateDicomDataset() : null);

            return(await PrepareRequestAsync(changeFeedEntry, patientResourceId));
        }
示例#7
0
        public async Task GivenNoResourceToProcess_WhenProcessed_ThenTransactionShouldBeExecuted()
        {
            // Setup the pipeline step to simulate no requests.
            IFhirTransactionPipelineStep pipelineStep = Substitute.For <IFhirTransactionPipelineStep>();

            _fhirTransactionPipelineSteps.Add(pipelineStep);

            // Process
            await _fhirTransactionPipeline.ProcessAsync(ChangeFeedGenerator.Generate(), DefaultCancellationToken);

            // There should not be any response.
            pipelineStep.DidNotReceiveWithAnyArgs().ProcessResponse(default);
        public static FhirTransactionContext DefaultFhirTransactionContext(DicomDataset metadata = null)
        {
            var context = new FhirTransactionContext(ChangeFeedGenerator.Generate(metadata: metadata ?? CreateDicomDataset()))
            {
                UtcDateTimeOffset = TimeSpan.Zero,
            };

            context.Request.Patient      = FhirTransactionRequestEntryGenerator.GenerateDefaultCreateRequestEntry <Patient>();
            context.Request.ImagingStudy = FhirTransactionRequestEntryGenerator.GenerateDefaultCreateRequestEntry <ImagingStudy>();
            context.Request.Endpoint     = FhirTransactionRequestEntryGenerator.GenerateDefaultCreateRequestEntry <Endpoint>();

            return(context);
        }
示例#9
0
        public async Task GivenAnExistingEndpointWithMatchingAddress_WhenRequestIsPrepared_ThenCorrectRequestEntryShouldBeCreated()
        {
            var context = new FhirTransactionContext(ChangeFeedGenerator.Generate());

            Endpoint endpoint = FhirResourceBuilder.CreateEndpointResource(address: DefaultDicomWebEndpoint);

            _fhirService.RetrieveEndpointAsync(Arg.Any <string>(), DefaultCancellationToken).Returns(endpoint);

            await _endpointPipeline.PrepareRequestAsync(context, DefaultCancellationToken);

            FhirTransactionRequestEntry actualEndPointEntry = context.Request.Endpoint;

            ValidationUtility.ValidateRequestEntryMinimumRequirementForNoChange(endpoint.ToServerResourceId(), actualEndPointEntry);
        }
        public async Task GivenMultipleChangeFeedEntries_WhenProcessed_ThenEachChangeFeedEntryShouldBeProcessed()
        {
            ChangeFeedEntry[] changeFeeds = new[]
            {
                ChangeFeedGenerator.Generate(1),
                ChangeFeedGenerator.Generate(2),
                ChangeFeedGenerator.Generate(3),
            };

            _changeFeedRetrieveService.RetrieveChangeFeedAsync(0, DefaultCancellationToken).Returns(changeFeeds);

            await ExecuteProcessAsync();

            await _fhirTransactionPipeline.ReceivedWithAnyArgs(3).ProcessAsync(default, default);
        public void GivenARequestToCreateAPatient_WhenResponseIsOK_ThenResourceConflictExceptionShouldBeThrown()
        {
            var response = new Bundle.ResponseComponent();

            response.AddAnnotation(HttpStatusCode.OK);

            var context = new FhirTransactionContext(ChangeFeedGenerator.Generate());

            context.Request.Patient = FhirTransactionRequestEntryGenerator.GenerateDefaultCreateRequestEntry <Patient>();

            context.Response.Patient = new FhirTransactionResponseEntry(response, new Patient());

            Assert.Throws <ResourceConflictException>(() => _patientPipeline.ProcessResponse(context));
        }
        public void GivenARequestToUpdateAPatient_WhenResponseIsOK_ThenItShouldBeNoOp()
        {
            var response = new Bundle.ResponseComponent();

            response.AddAnnotation(HttpStatusCode.OK);

            var context = new FhirTransactionContext(ChangeFeedGenerator.Generate());

            context.Request.Patient = FhirTransactionRequestEntryGenerator.GenerateDefaultUpdateRequestEntry <Patient>(
                new ServerResourceId(ResourceType.Patient, "123"));

            context.Response.Patient = new FhirTransactionResponseEntry(response, new Patient());

            _patientPipeline.ProcessResponse(context);
        }
        public async Task GivenAValidCreateChangeFeed_WhenBuilt_ThenCorrectEntryComponentShouldBeCreated()
        {
            const string studyInstanceUid  = "1";
            const string seriesInstanceUid = "2";
            const string sopInstanceUid    = "3";
            const string patientResourceId = "p1";

            ChangeFeedEntry changeFeedEntry = ChangeFeedGenerator.Generate(
                action: ChangeFeedAction.Create,
                studyInstanceUid: studyInstanceUid,
                seriesInstanceUid: seriesInstanceUid,
                sopInstanceUid: sopInstanceUid);

            FhirTransactionRequestEntry entry = await BuildImagingStudyEntryComponent(studyInstanceUid, seriesInstanceUid, sopInstanceUid, patientResourceId);

            ValidationUtility.ValidateRequestEntryMinimumRequirementForWithChange(FhirTransactionRequestMode.Create, "ImagingStudy", Bundle.HTTPVerb.POST, entry);

            ImagingStudy imagingStudy = Assert.IsType <ImagingStudy>(entry.Resource);

            string jsonString;

            jsonString = JsonSerializer.Serialize(entry);

            Assert.IsType <ClientResourceId>(entry.ResourceId);
            Assert.Equal(ImagingStudy.ImagingStudyStatus.Available, imagingStudy.Status);
            Assert.Null(entry.Request.IfMatch);

            ValidationUtility.ValidateResourceReference("Patient/p1", imagingStudy.Subject);

            Assert.Collection(
                imagingStudy.Identifier,
                identifier => ValidationUtility.ValidateIdentifier("urn:dicom:uid", $"urn:oid:{studyInstanceUid}", identifier),
                identifier => ValidationUtility.ValidateAccessionNumber(null, FhirTransactionContextBuilder.DefaultAccessionNumber, identifier));

            Assert.Collection(
                imagingStudy.Series,
                series =>
            {
                Assert.Equal(seriesInstanceUid, series.Uid);

                Assert.Collection(
                    series.Instance,
                    instance => Assert.Equal(sopInstanceUid, instance.Uid));
            });

            ValidateDicomFilePropertiesAreCorrectlyMapped(imagingStudy, series: imagingStudy.Series.First(), instance: imagingStudy.Series.First().Instance.First());
        }
示例#14
0
        public async Task WhenDoesNotEnforceAllFields_AndPropertyNotRequired_DoesNotThrowError()
        {
            _dicomCastConfig.Features.EnforceValidationOfTagValues = false;

            _propertySynchronizer.When(synchronizer => synchronizer.Synchronize(Arg.Any <DicomDataset>(), Arg.Any <Patient>(), isNewPatient: false)).Do(synchronizer => { throw new InvalidDicomTagValueException("invalid tag", "invalid tag"); });

            IEnumerable <IPatientPropertySynchronizer> patientPropertySynchronizers = new List <IPatientPropertySynchronizer>()
            {
                _propertySynchronizer,
            };

            PatientSynchronizer patientSynchronizer = new PatientSynchronizer(patientPropertySynchronizers, Options.Create(_dicomCastConfig), _exceptionStore);

            FhirTransactionContext context = new FhirTransactionContext(ChangeFeedGenerator.Generate(metadata: DefaultDicomDataset));
            var patient = new Patient();

            await patientSynchronizer.SynchronizeAsync(context, patient, false, DefaultCancellationToken);
        }
        public async Task GivenAChangeFeedEntryForCreate_WhenPreparingTheRequest_ThenCreateHandlerIsCalled()
        {
            const string studyInstanceUid  = "1";
            const string seriesInstanceUid = "2";
            const string sopInstanceUid    = "3";

            ChangeFeedEntry changeFeed = ChangeFeedGenerator.Generate(
                action: ChangeFeedAction.Create,
                studyInstanceUid: studyInstanceUid,
                seriesInstanceUid: seriesInstanceUid,
                sopInstanceUid: sopInstanceUid);

            var fhirTransactionContext = new FhirTransactionContext(changeFeed);

            await _imagingStudyPipeline.PrepareRequestAsync(fhirTransactionContext, DefaultCancellationToken);

            await _imagingStudyUpsertHandler.Received(1).BuildAsync(fhirTransactionContext, DefaultCancellationToken);
        }
示例#16
0
        public async Task WhenPatialValidationDisabled_AndError_ThrowsError()
        {
            _dicomCastConfig.Features.IgnoreSyncOfInvalidTagValue = false;

            _propertySynchronizer.When(synchronizer => synchronizer.Synchronize(Arg.Any <DicomDataset>(), Arg.Any <Patient>(), isNewPatient: false)).Do(synchronizer => { throw new InvalidDicomTagValueException("invalid tag", "invalid tag"); });

            IEnumerable <IPatientPropertySynchronizer> patientPropertySynchronizers = new List <IPatientPropertySynchronizer>()
            {
                _propertySynchronizer,
            };

            PatientSynchronizer patientSynchronizer = new PatientSynchronizer(patientPropertySynchronizers, Options.Create(_dicomCastConfig), _exceptionStore);

            FhirTransactionContext context = new FhirTransactionContext(ChangeFeedGenerator.Generate(metadata: DefaultDicomDataset));
            var patient = new Patient();

            await Assert.ThrowsAsync <InvalidDicomTagValueException>(() => patientSynchronizer.SynchronizeAsync(context, patient, false, DefaultCancellationToken));
        }
        public async Task GivenAChangeFeedEntryForDelete_WhenBuilt_ThenDeleteHandlerIsCalled()
        {
            const string studyInstanceUid  = "1";
            const string seriesInstanceUid = "2";
            const string sopInstanceUid    = "3";
            const string patientResourceId = "p1";

            ChangeFeedEntry changeFeed = ChangeFeedGenerator.Generate(
                action: ChangeFeedAction.Delete,
                studyInstanceUid: studyInstanceUid,
                seriesInstanceUid: seriesInstanceUid,
                sopInstanceUid: sopInstanceUid);

            var fhirTransactionContext = new FhirTransactionContext(changeFeed);

            fhirTransactionContext.Request.Patient = FhirTransactionRequestEntryGenerator.GenerateDefaultNoChangeRequestEntry <Patient>(
                new ServerResourceId(ResourceType.Patient, patientResourceId));

            await _imagingStudyPipeline.PrepareRequestAsync(fhirTransactionContext, DefaultCancellationToken);

            await _imagingStudyDeleteHandler.Received(1).BuildAsync(fhirTransactionContext, DefaultCancellationToken);
        }
示例#18
0
        public async Task GivenEndpointDoesNotAlreadyExist_WhenRequestIsPrepared_ThenCorrentRequestEntryShouldBeCreated()
        {
            var context = new FhirTransactionContext(ChangeFeedGenerator.Generate());

            await _endpointPipeline.PrepareRequestAsync(context, DefaultCancellationToken);

            FhirTransactionRequestEntry actualEndpointEntry = context.Request.Endpoint;

            ValidationUtility.ValidateRequestEntryMinimumRequirementForWithChange(FhirTransactionRequestMode.Create, "Endpoint", Bundle.HTTPVerb.POST, actualEndpointEntry);

            Assert.Equal($"name={EndpointName}&connection-type={EndpointConnectionTypeSystem}|{EndpointConnectionTypeCode}", actualEndpointEntry.Request.IfNoneExist);

            Endpoint endpoint = Assert.IsType <Endpoint>(actualEndpointEntry.Resource);

            Assert.Equal(EndpointName, endpoint.Name);
            Assert.Equal(Endpoint.EndpointStatus.Active, endpoint.Status);
            Assert.NotNull(endpoint.ConnectionType);
            Assert.Equal(EndpointConnectionTypeSystem, endpoint.ConnectionType.System);
            Assert.Equal(EndpointConnectionTypeCode, endpoint.ConnectionType.Code);
            Assert.Equal(_configuration.Endpoint.ToString(), endpoint.Address);
            Assert.Equal(EndpointPayloadTypeText, endpoint.PayloadType.First().Text);
            Assert.Equal(new[] { DicomMimeType }, endpoint.PayloadMimeType);
        }
        private async Task <FhirTransactionRequestEntry> BuildImagingStudyEntryComponent(string studyInstanceUid, string seriesInstanceUid, string sopInstanceUid, string patientResourceId)
        {
            ChangeFeedEntry changeFeedEntry = ChangeFeedGenerator.Generate(action: ChangeFeedAction.Delete, studyInstanceUid: studyInstanceUid, seriesInstanceUid: seriesInstanceUid, sopInstanceUid: sopInstanceUid);

            return(await PrepareRequestAsync(changeFeedEntry, patientResourceId));
        }
示例#20
0
        public async Task WhenThrowAnExceptionInProcess_ThrowTheSameException()
        {
            var pipelineStep = new MockFhirTransactionPipelineStep()
            {
                OnPrepareRequestAsyncCalled = (context, cancellationToken) =>
                {
                    throw new Exception();
                },
            };

            _fhirTransactionPipelineSteps.Add(pipelineStep);

            // Process
            await Assert.ThrowsAsync <Exception>(() => _fhirTransactionPipeline.ProcessAsync(ChangeFeedGenerator.Generate(), DefaultCancellationToken));
        }
        public async Task GivenMissingPatientId_WhenPreparingTheRequest_ThenMissingRequiredDicomTagExceptionShouldBeThrown()
        {
            var context = new FhirTransactionContext(ChangeFeedGenerator.Generate(metadata: new DicomDataset()));

            await Assert.ThrowsAsync <MissingRequiredDicomTagException>(() => _patientPipeline.PrepareRequestAsync(context, DefaultCancellationToken));
        }
示例#22
0
        public async Task GivenAResourceToProcess_WhenProcessed_ThenTransactionShouldBeExecuted(FhirTransactionRequestMode requestMode)
        {
            // Setup the pipeline step to simulate creating/updating patient.
            var patientRequest = new FhirTransactionRequestEntry(
                requestMode,
                new Bundle.RequestComponent(),
                new ClientResourceId(),
                new Patient());

            var pipelineStep = new MockFhirTransactionPipelineStep()
            {
                OnPrepareRequestAsyncCalled = (context, cancellationToken) =>
                {
                    context.Request.Patient = patientRequest;

                    Assert.Equal(DefaultCancellationToken, cancellationToken);
                },
            };

            _fhirTransactionPipelineSteps.Add(pipelineStep);

            // Setup the transaction executor to return response.
            var responseBundle = new Bundle();

            var responseEntry = new Bundle.EntryComponent()
            {
                Response = new Bundle.ResponseComponent(),
                Resource = new Patient(),
            };

            responseBundle.Entry.Add(responseEntry);

            _fhirTransactionExecutor.ExecuteTransactionAsync(
                Arg.Any <Bundle>(),
                DefaultCancellationToken)
            .Returns(call =>
            {
                // Make sure the request bundle is correct.
                Bundle requestBundle = call.ArgAt <Bundle>(0);

                Assert.NotNull(requestBundle);
                Assert.Equal(Bundle.BundleType.Transaction, requestBundle.Type);

                Assert.Collection(
                    requestBundle.Entry,
                    entry =>
                {
                    Assert.Equal(patientRequest.ResourceId.ToString(), entry.FullUrl);
                    Assert.Equal(patientRequest.Request, entry.Request);
                    Assert.Equal(patientRequest.Resource, entry.Resource);
                });

                return(responseBundle);
            });

            // Process
            await _fhirTransactionPipeline.ProcessAsync(ChangeFeedGenerator.Generate(), DefaultCancellationToken);

            // The response should have been processed.
            Assert.NotNull(_capturedFhirTransactionContext);

            FhirTransactionResponseEntry patientResponse = _capturedFhirTransactionContext.Response.Patient;

            Assert.NotNull(patientResponse);
            Assert.Equal(responseEntry.Response, patientResponse.Response);
            Assert.Equal(responseEntry.Resource, patientResponse.Resource);
        }
 private static FhirTransactionContext CreateFhirTransactionContext()
 {
     return(new FhirTransactionContext(ChangeFeedGenerator.Generate(metadata: DefaultDicomDataset)));
 }