Skip to content

Commit

Permalink
Personal/rogrdon/create common validation logic (#152)
Browse files Browse the repository at this point in the history
* Initial commit

* Allowing a batch of events to be validated

* Adding documentation

* Changes due to code review

* Changed due to code review

* Ensure multiple deviceEvents get validated

* Updating test
  • Loading branch information
rogordon01 authored Dec 20, 2021
1 parent f660a25 commit 64d7be5
Show file tree
Hide file tree
Showing 21 changed files with 1,186 additions and 11 deletions.
33 changes: 22 additions & 11 deletions Microsoft.Health.Fhir.Ingest.sln
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29009.5
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Health.Fhir.Ingest", "src\lib\Microsoft.Health.Fhir.Ingest\Microsoft.Health.Fhir.Ingest.csproj", "{269436ED-1F69-4A83-A2EB-FBE82233472F}"
ProjectSection(ProjectDependencies) = postProject
{11032625-0B2B-4468-B1F1-431B5682DB7A} = {11032625-0B2B-4468-B1F1-431B5682DB7A}
EndProjectSection
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Health.Fhir.Ingest", "src\lib\Microsoft.Health.Fhir.Ingest\Microsoft.Health.Fhir.Ingest.csproj", "{269436ED-1F69-4A83-A2EB-FBE82233472F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "lib", "lib", "{513D67B4-80E1-476D-955F-E7E7C79D144A}"
EndProject
Expand All @@ -16,14 +13,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{FAF8B402-8
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Health.Fhir.Ingest.Host", "src\func\Microsoft.Health.Fhir.Ingest.Host\Microsoft.Health.Fhir.Ingest.Host.csproj", "{11F6C10F-483A-4DD7-99A3-14FDD5CCA3F1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Health.Fhir.Ingest.UnitTests", "test\Microsoft.Health.Fhir.Ingest.UnitTests\Microsoft.Health.Fhir.Ingest.UnitTests.csproj", "{F6422A39-DC02-436B-AC1F-82CC9CF75E73}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Health.Fhir.Ingest.UnitTests", "test\Microsoft.Health.Fhir.Ingest.UnitTests\Microsoft.Health.Fhir.Ingest.UnitTests.csproj", "{F6422A39-DC02-436B-AC1F-82CC9CF75E73}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Health.Fhir.R4.Ingest", "src\lib\Microsoft.Health.Fhir.R4.Ingest\Microsoft.Health.Fhir.R4.Ingest.csproj", "{98D001A4-3B1B-4E60-9148-71881A0D457D}"
ProjectSection(ProjectDependencies) = postProject
{11032625-0B2B-4468-B1F1-431B5682DB7A} = {11032625-0B2B-4468-B1F1-431B5682DB7A}
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Health.Fhir.R4.Ingest.UnitTests", "test\Microsoft.Health.Fhir.R4.Ingest.UnitTests\Microsoft.Health.Fhir.R4.Ingest.UnitTests.csproj", "{10E71A88-CC24-4DFA-92F3-18E47D42E985}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Health.Fhir.R4.Ingest.UnitTests", "test\Microsoft.Health.Fhir.R4.Ingest.UnitTests\Microsoft.Health.Fhir.R4.Ingest.UnitTests.csproj", "{10E71A88-CC24-4DFA-92F3-18E47D42E985}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "deploy", "deploy", "{AC515DEF-E7DA-4D6C-8EBC-0F17DE83E400}"
EndProject
Expand Down Expand Up @@ -54,13 +51,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Health.Extensions
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Health.Common", "src\lib\Microsoft.Health.Common\Microsoft.Health.Common.csproj", "{B5BDAF20-DA88-47AF-94C2-33789479DF99}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Health.Tests.Common", "test\Microsoft.Health.Tests.Common\Microsoft.Health.Tests.Common.csproj", "{9779F9F5-1F23-48B5-B271-0497D9ECE956}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Health.Tests.Common", "test\Microsoft.Health.Tests.Common\Microsoft.Health.Tests.Common.csproj", "{9779F9F5-1F23-48B5-B271-0497D9ECE956}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Health.Common.UnitTests", "test\Microsoft.Health.Common.UnitTests\Microsoft.Health.Common.UnitTests.csproj", "{F8F17DE0-1A3D-4E08-98C0-7EF9AD1E98B0}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Health.Common.UnitTests", "test\Microsoft.Health.Common.UnitTests\Microsoft.Health.Common.UnitTests.csproj", "{F8F17DE0-1A3D-4E08-98C0-7EF9AD1E98B0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Health.Extensions.Fhir.UnitTests", "test\Microsoft.Health.Extensions.Fhir.UnitTests\Microsoft.Health.Extensions.Fhir.UnitTests.csproj", "{73C97786-1CC7-4CF9-A420-8AB66D0BD731}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Health.Extensions.Fhir.UnitTests", "test\Microsoft.Health.Extensions.Fhir.UnitTests\Microsoft.Health.Extensions.Fhir.UnitTests.csproj", "{73C97786-1CC7-4CF9-A420-8AB66D0BD731}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Health.Extensions.Fhir.R4.UnitTests", "test\Microsoft.Health.Extensions.Fhir.R4.UnitTests\Microsoft.Health.Extensions.Fhir.R4.UnitTests.csproj", "{90402958-43C6-43E8-A22A-1B1469A4FCC5}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Health.Extensions.Fhir.R4.UnitTests", "test\Microsoft.Health.Extensions.Fhir.R4.UnitTests\Microsoft.Health.Extensions.Fhir.R4.UnitTests.csproj", "{90402958-43C6-43E8-A22A-1B1469A4FCC5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Health.Extensions.Host", "src\lib\Microsoft.Health.Extensions.Host\Microsoft.Health.Extensions.Host.csproj", "{9110663E-BFA0-4082-B1BE-F85D91DEFCA2}"
EndProject
Expand All @@ -76,7 +73,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Health.Fhir.Inges
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Health.Fhir.Ingest.Template.UnitTests", "test\Microsoft.Health.Fhir.Ingest.Template.UnitTests\Microsoft.Health.Fhir.Ingest.Template.UnitTests.csproj", "{EE072537-807D-4FE2-BFEB-424B64DCD7F9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Health.Tests.Common.R4", "test\Microsoft.Health.Tests.Common.R4\Microsoft.Health.Tests.Common.R4.csproj", "{0B0F4BCE-E439-47AB-A67A-8B3778407339}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Health.Tests.Common.R4", "test\Microsoft.Health.Tests.Common.R4\Microsoft.Health.Tests.Common.R4.csproj", "{0B0F4BCE-E439-47AB-A67A-8B3778407339}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Health.Events", "src\lib\Microsoft.Health.Events\Microsoft.Health.Events.csproj", "{22275DE3-859D-40F0-9547-7711568164C0}"
EndProject
Expand All @@ -103,6 +100,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Health.Expression
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Health.Expressions.UnitTests", "test\Microsoft.Health.Expressions.UnitTests\Microsoft.Health.Expressions.UnitTests.csproj", "{9BF918FE-E09B-4072-8CC5-2BE479230719}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Health.Fhir.Ingest.Validation", "src\lib\Microsoft.Health.Fhir.Ingest.Validation\Microsoft.Health.Fhir.Ingest.Validation.csproj", "{7F507901-30BD-41CD-99B8-FD8FA103D70A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Health.Fhir.Ingest.Validation.UnitTests", "test\Microsoft.Health.Fhir.Ingest.Validation.UnitTests\Microsoft.Health.Fhir.Ingest.Validation.UnitTests.csproj", "{34B7EABB-DC53-47AC-86E0-35596FF18312}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -201,6 +202,14 @@ Global
{9BF918FE-E09B-4072-8CC5-2BE479230719}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9BF918FE-E09B-4072-8CC5-2BE479230719}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9BF918FE-E09B-4072-8CC5-2BE479230719}.Release|Any CPU.Build.0 = Release|Any CPU
{7F507901-30BD-41CD-99B8-FD8FA103D70A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7F507901-30BD-41CD-99B8-FD8FA103D70A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7F507901-30BD-41CD-99B8-FD8FA103D70A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7F507901-30BD-41CD-99B8-FD8FA103D70A}.Release|Any CPU.Build.0 = Release|Any CPU
{34B7EABB-DC53-47AC-86E0-35596FF18312}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{34B7EABB-DC53-47AC-86E0-35596FF18312}.Debug|Any CPU.Build.0 = Debug|Any CPU
{34B7EABB-DC53-47AC-86E0-35596FF18312}.Release|Any CPU.ActiveCfg = Release|Any CPU
{34B7EABB-DC53-47AC-86E0-35596FF18312}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -235,6 +244,8 @@ Global
{657FB6EC-2F58-43B6-AD14-5EDE9D73C1E5} = {75D08B93-4CE1-4967-B0C3-DAA792F1D19A}
{0BC152B5-DF88-4750-A7CC-1B7429D879F6} = {513D67B4-80E1-476D-955F-E7E7C79D144A}
{9BF918FE-E09B-4072-8CC5-2BE479230719} = {FAF8B402-892E-4EA2-B4CF-69B0C70BA762}
{7F507901-30BD-41CD-99B8-FD8FA103D70A} = {513D67B4-80E1-476D-955F-E7E7C79D144A}
{34B7EABB-DC53-47AC-86E0-35596FF18312} = {FAF8B402-892E-4EA2-B4CF-69B0C70BA762}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A358924D-F948-4AE8-8CD0-A0F56225CE0C}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ public class CollectionContentTemplate : IContentTemplate
{
private readonly IList<IContentTemplate> _templates = new List<IContentTemplate>(10);

public IReadOnlyList<IContentTemplate> Templates => (_templates as List<IContentTemplate>).AsReadOnly();

public CollectionContentTemplate RegisterTemplate(IContentTemplate contentTemplate)
{
EnsureArg.IsNotNull(contentTemplate, nameof(contentTemplate));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

using System;
using System.Collections.Generic;
using System.Linq;
using EnsureThat;

namespace Microsoft.Health.Fhir.Ingest.Template
Expand All @@ -13,6 +14,8 @@ public class FhirLookupTemplate : ILookupTemplate<IFhirTemplate>
{
private readonly IDictionary<string, IFhirTemplate> _templates = new Dictionary<string, IFhirTemplate>(StringComparer.InvariantCultureIgnoreCase);

public IReadOnlyList<IFhirTemplate> Templates => _templates.Values.ToList().AsReadOnly();

public FhirLookupTemplate RegisterTemplate(IFhirTemplate fhirTemplate)
{
EnsureArg.IsNotNull(fhirTemplate, nameof(fhirTemplate));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// -------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// -------------------------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using EnsureThat;
using Microsoft.Health.Fhir.Ingest.Validation.Models;

namespace Microsoft.Health.Fhir.Ingest.Validation.Extensions
{
public static class IResultExtensions
{
public static void CaptureError(this IResult validationResult, string message, ErrorLevel errorLevel)
{
EnsureArg.IsNotNull(validationResult, nameof(validationResult));
EnsureArg.IsNotNullOrWhiteSpace(message, nameof(message));

validationResult.Exceptions.Add(new ValidationError(message, errorLevel));
}

public static void CaptureException(this IResult validationResult, Exception exception)
{
EnsureArg.IsNotNull(validationResult, nameof(validationResult));
EnsureArg.IsNotNull(exception, nameof(exception));

validationResult.Exceptions.Add(new ValidationError(exception.Message));
}

public static void CaptureWarning(this IResult validationResult, string warning)
{
EnsureArg.IsNotNull(validationResult, nameof(validationResult));
EnsureArg.IsNotNullOrWhiteSpace(warning, nameof(warning));

validationResult.Exceptions.Add(new ValidationError(warning, ErrorLevel.WARN));
}

public static IEnumerable<ValidationError> GetErrors(this IResult validationResult, ErrorLevel errorLevel)
{
EnsureArg.IsNotNull(validationResult, nameof(validationResult));
return validationResult.Exceptions.Where(error => errorLevel.Equals(error.Level));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// -------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// -------------------------------------------------------------------------------------------------

using System.Collections.Generic;
using Microsoft.Health.Fhir.Ingest.Validation.Models;
using Newtonsoft.Json.Linq;

namespace Microsoft.Health.Fhir.Ingest.Validation
{
public interface IMappingValidator
{
/// <summary>
/// Performs validation of Device and Fhir Mapping templates. The templates will be first be validated individually and then validated for compatibility
/// with each other. Finally, if a device event is supplied Measurements and Fhir Observations will attempt to be built from it. Any errors/warnings
/// found will be captured in the resulting ValidationResult object.
///
/// At least one of deviceMappingContent or fhirMappingContent must be provided.
/// </summary>
/// <param name="deviceEvent">A sample DeviceEvent. Optional</param>
/// <param name="deviceMappingContent">A device mapping template. Optional</param>
/// <param name="fhirMappingContent">A fhir mapping template. Optional</param>
/// <returns>A ValidationResult object</returns>
ValidationResult PerformValidation(JToken deviceEvent, string deviceMappingContent, string fhirMappingContent);

/// <summary>
/// Performs validation of Device and Fhir Mapping templates. The templates will be first be validated individually and then validated for compatibility
/// with each other. Finally, if device events are supplied Measurements and Fhir Observations will attempt to be built from them. Any errors/warnings
/// found will be captured in the resulting ValidationResult object.
///
/// At least one of deviceMappingContent or fhirMappingContent must be provided.
/// </summary>
/// <param name="deviceEvents">A collection of DeviceEvents. Optional</param>
/// <param name="deviceMappingContent">A device mapping template. Optional</param>
/// <param name="fhirMappingContent">A fhir mapping template. Optional</param>
/// <returns>A ValidationResult object</returns>
ValidationResult PerformValidation(IEnumerable<JToken> deviceEvents, string deviceMappingContent, string fhirMappingContent);
}
}
Loading

0 comments on commit 64d7be5

Please sign in to comment.