Skip to content

Commit

Permalink
[Dicom-cast] Continue processing of change feed after intransient err…
Browse files Browse the repository at this point in the history
…ors and allow for partial validation of dicom tags (#496)
  • Loading branch information
abdullah248 authored Jan 15, 2021
1 parent 2222487 commit 368a21c
Show file tree
Hide file tree
Showing 53 changed files with 663 additions and 232 deletions.
14 changes: 7 additions & 7 deletions converter/dicom-cast/Microsoft.Health.DicomCast.sln
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Health.DicomCast.
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Health.Dicom.Client", "..\..\src\Microsoft.Health.Dicom.Client\Microsoft.Health.Dicom.Client.csproj", "{3CCE3438-139A-420A-8A60-1144CADA95A1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Health.DicomCast.TableStorage", "Table\Microsoft.Health.DicomCast.TableStorage.csproj", "{A704C557-86FB-46A7-A1C4-10409900DD29}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Health.DicomCast.TableStorage.UnitTests", "src\Microsoft.Health.DicomCast.TableStorage.UnitTests\Microsoft.Health.DicomCast.TableStorage.UnitTests.csproj", "{1444027E-07DA-412E-8E74-F077F5520530}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Health.DicomCast.TableStorage.UnitTests", "src\Microsoft.Health.DicomCast.TableStorage.UnitTests\Microsoft.Health.DicomCast.TableStorage.UnitTests.csproj", "{1444027E-07DA-412E-8E74-F077F5520530}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Health.DicomCast.TableStorage", "src\Microsoft.Health.DicomCast.TableStorage\Microsoft.Health.DicomCast.TableStorage.csproj", "{0DFB24D5-5E2F-435D-A435-F70CD1824F08}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -45,14 +45,14 @@ Global
{3CCE3438-139A-420A-8A60-1144CADA95A1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3CCE3438-139A-420A-8A60-1144CADA95A1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3CCE3438-139A-420A-8A60-1144CADA95A1}.Release|Any CPU.Build.0 = Release|Any CPU
{A704C557-86FB-46A7-A1C4-10409900DD29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A704C557-86FB-46A7-A1C4-10409900DD29}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A704C557-86FB-46A7-A1C4-10409900DD29}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A704C557-86FB-46A7-A1C4-10409900DD29}.Release|Any CPU.Build.0 = Release|Any CPU
{1444027E-07DA-412E-8E74-F077F5520530}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1444027E-07DA-412E-8E74-F077F5520530}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1444027E-07DA-412E-8E74-F077F5520530}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1444027E-07DA-412E-8E74-F077F5520530}.Release|Any CPU.Build.0 = Release|Any CPU
{0DFB24D5-5E2F-435D-A435-F70CD1824F08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0DFB24D5-5E2F-435D-A435-F70CD1824F08}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0DFB24D5-5E2F-435D-A435-F70CD1824F08}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0DFB24D5-5E2F-435D-A435-F70CD1824F08}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -63,8 +63,8 @@ Global
{E60031C2-46AB-40E3-BDD9-A8F28A13CF32} = {E15E21A1-0707-4D98-AEDD-ACC7F59C5681}
{02636774-227C-4D07-A314-0B5015328E39} = {E15E21A1-0707-4D98-AEDD-ACC7F59C5681}
{3CCE3438-139A-420A-8A60-1144CADA95A1} = {E15E21A1-0707-4D98-AEDD-ACC7F59C5681}
{A704C557-86FB-46A7-A1C4-10409900DD29} = {E15E21A1-0707-4D98-AEDD-ACC7F59C5681}
{1444027E-07DA-412E-8E74-F077F5520530} = {E15E21A1-0707-4D98-AEDD-ACC7F59C5681}
{0DFB24D5-5E2F-435D-A435-F70CD1824F08} = {E15E21A1-0707-4D98-AEDD-ACC7F59C5681}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4EF00533-B2AE-4B1B-B4AF-9799AD9F69E2}
Expand Down
64 changes: 0 additions & 64 deletions converter/dicom-cast/Table/Features/Storage/TableStore.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,38 @@

using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Dicom;
using Hl7.Fhir.Model;
using Microsoft.Extensions.Options;
using Microsoft.Health.DicomCast.Core.Configurations;
using Microsoft.Health.DicomCast.Core.Features.ExceptionStorage;
using Microsoft.Health.DicomCast.Core.Features.Worker.FhirTransaction;
using NSubstitute;
using Xunit;
using Task = System.Threading.Tasks.Task;

namespace Microsoft.Health.DicomCast.Core.UnitTests.Features.Worker.FhirTransaction
{
public class ImagingStudyInstancePropertySynchronizerTests
{
private static readonly CancellationToken DefaultCancellationToken = new CancellationTokenSource().Token;
private readonly IImagingStudyInstancePropertySynchronizer _imagingStudyInstancePropertySynchronizer;
private readonly string studyInstanceUid = "111";
private readonly string seriesInstanceUid = "222";
private readonly string sopInstanceUid = "333";
private readonly string sopClassUid = "4444";
private readonly string patientResourceId = "555";
private readonly DicomCastConfiguration _dicomCastConfig = new DicomCastConfiguration();
private readonly IExceptionStore _exceptionStore = Substitute.For<IExceptionStore>();

public ImagingStudyInstancePropertySynchronizerTests()
{
_imagingStudyInstancePropertySynchronizer = new ImagingStudyInstancePropertySynchronizer();
_imagingStudyInstancePropertySynchronizer = new ImagingStudyInstancePropertySynchronizer(Options.Create(_dicomCastConfig), _exceptionStore);
}

[Fact]
public void GivenATransactionContexAndImagingStudy_WhenprocessedForInstance_ThenDicomPropertiesAreCorrectlyMappedtoInstanceWithinImagingStudy()
public async Task GivenATransactionContexAndImagingStudy_WhenprocessedForInstance_ThenDicomPropertiesAreCorrectlyMappedtoInstanceWithinImagingStudyAsync()
{
DicomDataset dataset = FhirTransactionContextBuilder.CreateDicomDataset();

Expand All @@ -37,14 +46,14 @@ public void GivenATransactionContexAndImagingStudy_WhenprocessedForInstance_Then
ImagingStudy.SeriesComponent series = imagingStudy.Series.First();
ImagingStudy.InstanceComponent instance = series.Instance.First();

_imagingStudyInstancePropertySynchronizer.Synchronize(context, instance);
await _imagingStudyInstancePropertySynchronizer.SynchronizeAsync(context, instance, DefaultCancellationToken);

Assert.Equal(sopClassUid, instance.SopClass.Code);
Assert.Equal(1, instance.Number);
}

[Fact]
public void GivenATransactionContextWithUpdatedInstanceNumber_WhenprocessedForInstance_ThenDicomPropertyValuesAreUpdatedCorrectly()
public async Task GivenATransactionContextWithUpdatedInstanceNumber_WhenprocessedForInstance_ThenDicomPropertyValuesAreUpdatedCorrectlyAsync()
{
DicomDataset dataset = FhirTransactionContextBuilder.CreateDicomDataset();

Expand All @@ -54,18 +63,18 @@ public void GivenATransactionContextWithUpdatedInstanceNumber_WhenprocessedForIn
ImagingStudy.SeriesComponent series = imagingStudy.Series.First();
ImagingStudy.InstanceComponent instance = series.Instance.First();

_imagingStudyInstancePropertySynchronizer.Synchronize(context, instance);
await _imagingStudyInstancePropertySynchronizer.SynchronizeAsync(context, instance, DefaultCancellationToken);

Assert.Equal(1, instance.Number);

FhirTransactionContext newContext = FhirTransactionContextBuilder.DefaultFhirTransactionContext(FhirTransactionContextBuilder.CreateDicomDataset(instanceNumber: "2"));

_imagingStudyInstancePropertySynchronizer.Synchronize(newContext, instance);
await _imagingStudyInstancePropertySynchronizer.SynchronizeAsync(newContext, instance, DefaultCancellationToken);
Assert.Equal(2, instance.Number);
}

[Fact]
public void GivenATransactionContextWithNoDicomPropertyValueChange_WhenprocessedForInstancee_ThenDicomPropertyValuesUpdateIsSkipped()
public async Task GivenATransactionContextWithNoDicomPropertyValueChange_WhenprocessedForInstancee_ThenDicomPropertyValuesUpdateIsSkippedAsync()
{
DicomDataset dataset = FhirTransactionContextBuilder.CreateDicomDataset();

Expand All @@ -75,13 +84,13 @@ public void GivenATransactionContextWithNoDicomPropertyValueChange_Whenprocessed
ImagingStudy.SeriesComponent series = imagingStudy.Series.First();
ImagingStudy.InstanceComponent instance = series.Instance.First();

_imagingStudyInstancePropertySynchronizer.Synchronize(context, instance);
await _imagingStudyInstancePropertySynchronizer.SynchronizeAsync(context, instance, DefaultCancellationToken);

Assert.Equal(1, instance.Number);

FhirTransactionContext newContext = FhirTransactionContextBuilder.DefaultFhirTransactionContext(dataset);

_imagingStudyInstancePropertySynchronizer.Synchronize(newContext, instance);
await _imagingStudyInstancePropertySynchronizer.SynchronizeAsync(newContext, instance, DefaultCancellationToken);
Assert.Equal(1, instance.Number);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,26 @@
// -------------------------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using Dicom;
using Hl7.Fhir.Model;
using Microsoft.Health.DicomCast.Core.Features.ExceptionStorage;
using Microsoft.Health.DicomCast.Core.Features.Worker.FhirTransaction;
using NSubstitute;
using Xunit;
using Task = System.Threading.Tasks.Task;

namespace Microsoft.Health.DicomCast.Core.UnitTests.Features.Worker.FhirTransaction
{
public class ImagingStudyPipelineHelperTests
{
private const string DefaultStudyInstanceUid = "111";
private const string DefaultSeriesInstanceUid = "222";
private const string DefaultSopInstanceUid = "333";
private const string DefaultPatientResourceId = "555";

private readonly IExceptionStore _exceptionStore = Substitute.For<IExceptionStore>();

[Fact]
public void GivenAChangeFeedEntryWithInvalidUtcTimeOffset_WhenDateTimeOffsetIsCalculated_ThenInvalidDicomTagValueExceptionIsThrown()
{
Expand Down Expand Up @@ -49,5 +61,41 @@ public void GivenAccessionNumber_WhenGetAccessionNumber_ThenReturnsCorrectIdenti
var result = ImagingStudyPipelineHelper.GetAccessionNumber(accessionNumber);
ValidationUtility.ValidateAccessionNumber(null, accessionNumber, result);
}

[Fact]
public async Task SyncPropertiesAsync_PartialValidationNotEnabled_ThrowsError()
{
ImagingStudy imagingStudy = FhirResourceBuilder.CreateNewImagingStudy(DefaultStudyInstanceUid, new List<string>() { DefaultSeriesInstanceUid }, new List<string>() { DefaultSopInstanceUid }, DefaultPatientResourceId);
FhirTransactionContext context = FhirTransactionContextBuilder.DefaultFhirTransactionContext(FhirTransactionContextBuilder.CreateDicomDataset());

Action<ImagingStudy, FhirTransactionContext> actionSubstitute = Substitute.For<Action<ImagingStudy, FhirTransactionContext>>();
actionSubstitute.When(x => x.Invoke(imagingStudy, context)).Do(x => throw new InvalidDicomTagValueException("invalid tag", "invalid tag"));

await Assert.ThrowsAsync<InvalidDicomTagValueException>(() => ImagingStudyPipelineHelper.SynchronizePropertiesAsync(imagingStudy, context, actionSubstitute, false, false, _exceptionStore));
}

[Fact]
public async Task SyncPropertiesAsync_PartialValidationEnabledAndPropertyRequired_ThrowsError()
{
ImagingStudy imagingStudy = FhirResourceBuilder.CreateNewImagingStudy(DefaultStudyInstanceUid, new List<string>() { DefaultSeriesInstanceUid }, new List<string>() { DefaultSopInstanceUid }, DefaultPatientResourceId);
FhirTransactionContext context = FhirTransactionContextBuilder.DefaultFhirTransactionContext(FhirTransactionContextBuilder.CreateDicomDataset());

Action<ImagingStudy, FhirTransactionContext> actionSubstitute = Substitute.For<Action<ImagingStudy, FhirTransactionContext>>();
actionSubstitute.When(x => x.Invoke(imagingStudy, context)).Do(x => throw new InvalidDicomTagValueException("invalid tag", "invalid tag"));

await Assert.ThrowsAsync<InvalidDicomTagValueException>(() => ImagingStudyPipelineHelper.SynchronizePropertiesAsync(imagingStudy, context, actionSubstitute, true, true, _exceptionStore));
}

[Fact]
public async Task SyncPropertiesAsync_PartialValidationEnabledAndPropertyNotRequired_NoError()
{
ImagingStudy imagingStudy = FhirResourceBuilder.CreateNewImagingStudy(DefaultStudyInstanceUid, new List<string>() { DefaultSeriesInstanceUid }, new List<string>() { DefaultSopInstanceUid }, DefaultPatientResourceId);
FhirTransactionContext context = FhirTransactionContextBuilder.DefaultFhirTransactionContext(FhirTransactionContextBuilder.CreateDicomDataset());

Action<ImagingStudy, FhirTransactionContext> actionSubstitute = Substitute.For<Action<ImagingStudy, FhirTransactionContext>>();
actionSubstitute.When(x => x.Invoke(imagingStudy, context)).Do(x => throw new InvalidDicomTagValueException("invalid tag", "invalid tag"));

await ImagingStudyPipelineHelper.SynchronizePropertiesAsync(imagingStudy, context, actionSubstitute, false, true, _exceptionStore);
}
}
}
Loading

0 comments on commit 368a21c

Please sign in to comment.