Skip to content

Commit

Permalink
Throw proper exception when TypeNameMatch expression is missing (#176)
Browse files Browse the repository at this point in the history
  • Loading branch information
rogordon01 authored Mar 14, 2022
1 parent bc2468a commit 6dc66d7
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
// -------------------------------------------------------------------------------------------------

using EnsureThat;
using Microsoft.Health.Fhir.Ingest.Template;
using Newtonsoft.Json.Linq;

namespace Microsoft.Health.Fhir.Ingest.Template
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace Microsoft.Health.Fhir.Ingest.Template
{
public class IotJsonPathLegacyMeasurementExtractor : LegacyMeasurementExtractor
{
private IotJsonPathContentTemplate _template;
private readonly IotJsonPathContentTemplate _template;

public IotJsonPathLegacyMeasurementExtractor(
IotJsonPathContentTemplate template)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class JsonPathExpressionEvaluatorFactory : IExpressionEvaluatorFactory
{
public IExpressionEvaluator Create(TemplateExpression expression)
{
EnsureArg.IsNotEmptyOrWhiteSpace(expression?.Value, nameof(expression.Value));
EnsureArg.IsNotNullOrWhiteSpace(expression?.Value, nameof(expression.Value));

var expressionLanguage = expression.Language ?? TemplateExpressionLanguage.JsonPath;
if (expressionLanguage != TemplateExpressionLanguage.JsonPath)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public LegacyMeasurementExtractor(
protected override IEnumerable<JToken> MatchTypeTokens(JObject token)
{
EnsureArg.IsNotNull(token, nameof(token));
var evaluator = ExpressionEvaluatorFactory.Create(Template.TypeMatchExpression);
var evaluator = CreateRequiredExpressionEvaluator(Template.TypeMatchExpression, nameof(Template.TypeMatchExpression));

return evaluator.SelectTokens(token);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ protected static bool IsExpressionDefined(params TemplateExpression[] expression
protected virtual IEnumerable<JToken> MatchTypeTokens(JObject token)
{
EnsureArg.IsNotNull(token, nameof(token));
var evaluator = ExpressionEvaluatorFactory.Create(Template.TypeMatchExpression);
var evaluator = CreateRequiredExpressionEvaluator(Template.TypeMatchExpression, nameof(Template.TypeMatchExpression));

foreach (var extractedToken in evaluator.SelectTokens(token))
{
Expand All @@ -134,6 +134,19 @@ protected virtual IEnumerable<JToken> MatchTypeTokens(JObject token)
}
}

protected IExpressionEvaluator CreateRequiredExpressionEvaluator(TemplateExpression expression, string expressionName)
{
EnsureArg.IsNotNullOrWhiteSpace(expressionName, nameof(expressionName));

// If the expression object or its value aren't set, throw a detailed exception
if (string.IsNullOrWhiteSpace(expression?.Value))
{
throw new IncompatibleDataException($"An expression must be set for [{expressionName}]");
}

return ExpressionEvaluatorFactory.Create(Template.TypeMatchExpression);
}

private Measurement CreateMeasurementFromToken(JToken token)
{
// Current assumption is that the expressions should match a single element and will error otherwise.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public TemplateExpressionEvaluatorFactory(JmesPath jmesPath)

public IExpressionEvaluator Create(TemplateExpression expression)
{
EnsureArg.IsNotEmptyOrWhiteSpace(expression?.Value, nameof(expression.Value));
EnsureArg.IsNotNullOrWhiteSpace(expression?.Value, nameof(expression.Value));
EnsureArg.IsNotNull(expression?.Language, nameof(expression.Language));

return expression.Language switch
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

using System.Collections.Generic;
using System.Linq;
using Microsoft.Health.Fhir.Ingest.Template;
using Microsoft.Health.Tests.Common;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
Expand Down Expand Up @@ -36,6 +35,16 @@ public class IotJsonPathContentTemplateTests
},
});

private static readonly IContentTemplate SingleValueMissingTypeNameTemplate = BuildMeasurementExtractor(new IotJsonPathContentTemplate
{
TypeName = "heartrate",
TypeMatchExpression = "$..[?(@Body.heartrate)]",
Values = new List<JsonPathValueExpression>
{
new JsonPathValueExpression { ValueName = "hr", ValueExpression = "$.Body.heartrate", Required = true },
},
});

[Theory]
[FileData(@"TestInput/data_IotHubPayloadExample.json")]
public void GivenTemplateAndSingleValidToken_WhenGetMeasurements_ThenSingleMeasurementReturned_Test(string eventJson)
Expand All @@ -57,6 +66,27 @@ public void GivenTemplateAndSingleValidToken_WhenGetMeasurements_ThenSingleMeasu
});
}

[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData(" ")]
public void GivenTemplateAndMissingTypeNameToken_WhenGetMeasurements_ThenExceptionIsThrown_Test(string typeMatchExpression)
{
var token = JToken.FromObject(new { heartrate = "60", device = "abc" });
var template = BuildMeasurementExtractor(new IotJsonPathContentTemplate
{
TypeName = "heartrate",
TypeMatchExpression = typeMatchExpression,
Values = new List<JsonPathValueExpression>
{
new JsonPathValueExpression { ValueName = "hr", ValueExpression = "$.Body.heartrate", Required = true },
},
});

var ex = Assert.Throws<IncompatibleDataException>(() => template.GetMeasurements(token).ToArray());
Assert.Equal("An expression must be set for [TypeMatchExpression]", ex.Message);
}

[Theory]
[FileData(@"TestInput/data_IotHubPayloadMultiValueExample.json")]
public void GivenTemplateAndSingleMultiValueValidToken_WhenGetMeasurements_ThenSingleMeasurementReturned_Test(string eventJson)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,32 @@ public void GivenPropertyWithSpace_WhenGetMeasurements_ThenSingleMeasurementRetu
Assert.Equal("data", p.Value);
});
});
}
}

[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData(" ")]
public void GivenInvalidTypeMatchExpression_WhenGetMeasurements_ThenExceptionIsThrown_Test(string typeMatchExpression)
{
var time = DateTime.UtcNow;
var token = JToken.FromObject(new JsonWidget { MyProperty = "data", Time = time });

var template = new JsonPathContentTemplate
{
TypeName = "space",
TypeMatchExpression = typeMatchExpression,
DeviceIdExpression = "$.['My Property']",
TimestampExpression = "$.Time",
Values = new List<JsonPathValueExpression>
{
new JsonPathValueExpression { ValueName = "prop", ValueExpression = "$.['My Property']", Required = false },
},
};

var ex = Assert.Throws<IncompatibleDataException>(() => BuildMeasurementExtractor(template).GetMeasurements(token).ToArray());
Assert.Equal("An expression must be set for [TypeMatchExpression]", ex.Message);
}

[Fact]
public void GivenSingleValueCompoundAndTemplateAndPartialToken_WhenGetMeasurements_ThenEmptyIEnumerableReturned_Test()
Expand Down

0 comments on commit 6dc66d7

Please sign in to comment.