From cdc731e3fff4e73e5c807f10567f48623af1b32b Mon Sep 17 00:00:00 2001 From: "FAREAST\\boywu" Date: Mon, 14 Mar 2022 16:12:59 +0800 Subject: [PATCH 1/2] Add check for large for loops --- .../FunctionalTests.cs | 16 +++++----- .../RuleBasedTests.cs | 2 +- ...lth.Fhir.Liquid.Converter.UnitTests.csproj | 2 +- .../Processors/ProcessorTests.cs | 30 +++++++++++++++++++ .../TestTemplates/LargeForLoopTemplate.liquid | 3 ++ .../Processors/BaseProcessor.cs | 3 +- 6 files changed, 45 insertions(+), 11 deletions(-) create mode 100644 src/Microsoft.Health.Fhir.Liquid.Converter.UnitTests/TestTemplates/LargeForLoopTemplate.liquid diff --git a/src/Microsoft.Health.Fhir.Liquid.Converter.FunctionalTests/FunctionalTests.cs b/src/Microsoft.Health.Fhir.Liquid.Converter.FunctionalTests/FunctionalTests.cs index 449c51fa2..7049a3511 100644 --- a/src/Microsoft.Health.Fhir.Liquid.Converter.FunctionalTests/FunctionalTests.cs +++ b/src/Microsoft.Health.Fhir.Liquid.Converter.FunctionalTests/FunctionalTests.cs @@ -78,20 +78,20 @@ public static IEnumerable GetDataForHl7v2() new[] { @"SIU_S26", @"SIU-S26-01.hl7", @"SIU-S26-01-expected.json" }, new[] { @"SIU_S26", @"SIU-S26-02.hl7", @"SIU-S26-02-expected.json" }, - new[] { "ORU_R01", "ORU-R01-01.hl7", @"ORU-R01-01-expected.json"}, + new[] { "ORU_R01", "ORU-R01-01.hl7", @"ORU-R01-01-expected.json" }, new[] { @"ORM_O01", @"ORM-O01-01.hl7", @"ORM-O01-01-expected.json" }, new[] { @"ORM_O01", @"ORM-O01-02.hl7", @"ORM-O01-02-expected.json" }, new[] { @"ORM_O01", @"ORM-O01-03.hl7", @"ORM-O01-03-expected.json" }, - new[] { "MDM_T01", "MDM-T01-01.hl7", @"MDM-T01-01-expected.json"}, - new[] { "MDM_T01", "MDM-T01-02.hl7", @"MDM-T01-02-expected.json"}, - new[] { "MDM_T02", "MDM-T02-01.hl7", @"MDM-T02-01-expected.json"}, - new[] { "MDM_T02", "MDM-T02-02.hl7", @"MDM-T02-02-expected.json"}, - new[] { "MDM_T02", "MDM-T02-03.hl7", @"MDM-T02-03-expected.json"}, + new[] { "MDM_T01", "MDM-T01-01.hl7", @"MDM-T01-01-expected.json" }, + new[] { "MDM_T01", "MDM-T01-02.hl7", @"MDM-T01-02-expected.json" }, + new[] { "MDM_T02", "MDM-T02-01.hl7", @"MDM-T02-01-expected.json" }, + new[] { "MDM_T02", "MDM-T02-02.hl7", @"MDM-T02-02-expected.json" }, + new[] { "MDM_T02", "MDM-T02-03.hl7", @"MDM-T02-03-expected.json" }, - new[] { "OML_O21", "OML-O21-01.hl7", @"OML-O21-01-expected.json"}, - new[] { "OML_O21", "OML-O21-02.hl7", @"OML-O21-02-expected.json"}, + new[] { "OML_O21", "OML-O21-01.hl7", @"OML-O21-01-expected.json" }, + new[] { "OML_O21", "OML-O21-02.hl7", @"OML-O21-02-expected.json" }, new[] { @"ADT_A01", @"ADT01-23.hl7", @"ADT01-23-expected.json" }, new[] { @"ADT_A01", @"ADT01-28.hl7", @"ADT01-28-expected.json" }, diff --git a/src/Microsoft.Health.Fhir.Liquid.Converter.FunctionalTests/RuleBasedTests.cs b/src/Microsoft.Health.Fhir.Liquid.Converter.FunctionalTests/RuleBasedTests.cs index 552c9ce4d..d6fb22708 100644 --- a/src/Microsoft.Health.Fhir.Liquid.Converter.FunctionalTests/RuleBasedTests.cs +++ b/src/Microsoft.Health.Fhir.Liquid.Converter.FunctionalTests/RuleBasedTests.cs @@ -454,7 +454,7 @@ internal static class ResourceFilter "resourceType", "type", "fullUrl", "id", "method", "url", "reference", "system", "code", "display", "gender", "use", "preferred", "status", "mode", "div", "valueString", "valueCode", "text", "endpoint", "value", "category", "type", "criticality", "priority", "severity", "description", - "intent", "docStatus", "contentType", "authorString" + "intent", "docStatus", "contentType", "authorString", }; private static readonly HashSet _explicitValues = new HashSet diff --git a/src/Microsoft.Health.Fhir.Liquid.Converter.UnitTests/Microsoft.Health.Fhir.Liquid.Converter.UnitTests.csproj b/src/Microsoft.Health.Fhir.Liquid.Converter.UnitTests/Microsoft.Health.Fhir.Liquid.Converter.UnitTests.csproj index 31627550d..070470b9b 100644 --- a/src/Microsoft.Health.Fhir.Liquid.Converter.UnitTests/Microsoft.Health.Fhir.Liquid.Converter.UnitTests.csproj +++ b/src/Microsoft.Health.Fhir.Liquid.Converter.UnitTests/Microsoft.Health.Fhir.Liquid.Converter.UnitTests.csproj @@ -30,7 +30,7 @@ - + PreserveNewest diff --git a/src/Microsoft.Health.Fhir.Liquid.Converter.UnitTests/Processors/ProcessorTests.cs b/src/Microsoft.Health.Fhir.Liquid.Converter.UnitTests/Processors/ProcessorTests.cs index 15074933c..364d1c0e7 100644 --- a/src/Microsoft.Health.Fhir.Liquid.Converter.UnitTests/Processors/ProcessorTests.cs +++ b/src/Microsoft.Health.Fhir.Liquid.Converter.UnitTests/Processors/ProcessorTests.cs @@ -79,6 +79,28 @@ public static IEnumerable GetValidInputsWithProcessSettings() }; } + public static IEnumerable GetValidInputsWithLargeForLoop() + { + yield return new object[] + { + new Hl7v2Processor(), + new TemplateProvider(TestConstants.TestTemplateDirectory, DataType.Hl7v2), + _hl7v2TestData, + }; + yield return new object[] + { + new CcdaProcessor(), + new TemplateProvider(TestConstants.TestTemplateDirectory, DataType.Ccda), + _ccdaTestData, + }; + yield return new object[] + { + new JsonProcessor(), + new TemplateProvider(TestConstants.TestTemplateDirectory, DataType.Json), + _jsonTestData, + }; + } + [Theory] [MemberData(nameof(GetValidInputsWithTemplateDirectory))] public void GivenAValidTemplateDirectory_WhenConvert_CorrectResultShouldBeReturned(IFhirConverter processor, ITemplateProvider templateProvider, string data, string rootTemplate) @@ -153,5 +175,13 @@ public void GivenCancellationToken_WhenConvert_CorrectResultsShouldBeReturned(IF cts.Cancel(); Assert.Throws(() => processor.Convert(data, rootTemplate, templateProvider, cts.Token)); } + + [Theory] + [MemberData(nameof(GetValidInputsWithLargeForLoop))] + public void GivenTemplateWithLargeForLoop_WhenConvert_ExceptionShouldBeThrown(IFhirConverter processor, ITemplateProvider templateProvider, string data) + { + var exception = Assert.Throws(() => processor.Convert(data, "LargeForLoopTemplate", templateProvider)); + Assert.Contains("Render Error - Maximum number of iterations 100000 exceeded", exception.Message); + } } } diff --git a/src/Microsoft.Health.Fhir.Liquid.Converter.UnitTests/TestTemplates/LargeForLoopTemplate.liquid b/src/Microsoft.Health.Fhir.Liquid.Converter.UnitTests/TestTemplates/LargeForLoopTemplate.liquid new file mode 100644 index 000000000..1a91c0c5e --- /dev/null +++ b/src/Microsoft.Health.Fhir.Liquid.Converter.UnitTests/TestTemplates/LargeForLoopTemplate.liquid @@ -0,0 +1,3 @@ +{ + "value": [{% for i in (1..10000000) -%}{{ i }},{% endfor -%}] +} \ No newline at end of file diff --git a/src/Microsoft.Health.Fhir.Liquid.Converter/Processors/BaseProcessor.cs b/src/Microsoft.Health.Fhir.Liquid.Converter/Processors/BaseProcessor.cs index 206ae29c7..2162d4101 100644 --- a/src/Microsoft.Health.Fhir.Liquid.Converter/Processors/BaseProcessor.cs +++ b/src/Microsoft.Health.Fhir.Liquid.Converter/Processors/BaseProcessor.cs @@ -18,6 +18,7 @@ namespace Microsoft.Health.Fhir.Liquid.Converter.Processors public abstract class BaseProcessor : IFhirConverter { private readonly ProcessorSettings _settings; + private const int _maxIterations = 100000; protected BaseProcessor(ProcessorSettings processorSettings = null) { @@ -43,7 +44,7 @@ protected virtual Context CreateContext(ITemplateProvider templateProvider, IDic outerScope: new Hash(), registers: Hash.FromDictionary(new Dictionary { { "file_system", templateProvider.GetTemplateFileSystem() } }), errorsOutputMode: ErrorsOutputMode.Rethrow, - maxIterations: 0, + maxIterations: _maxIterations, timeout: timeout, formatProvider: CultureInfo.InvariantCulture); From ff8e3db0c94f825843e777b9313c89863ad7f87b Mon Sep 17 00:00:00 2001 From: "FAREAST\\boywu" Date: Wed, 16 Mar 2022 13:35:05 +0800 Subject: [PATCH 2/2] Add unit test --- .../Processors/ProcessorTests.cs | 8 ++++++++ .../TestTemplates/NestedForLoopTemplate.liquid | 10 ++++++++++ 2 files changed, 18 insertions(+) create mode 100644 src/Microsoft.Health.Fhir.Liquid.Converter.UnitTests/TestTemplates/NestedForLoopTemplate.liquid diff --git a/src/Microsoft.Health.Fhir.Liquid.Converter.UnitTests/Processors/ProcessorTests.cs b/src/Microsoft.Health.Fhir.Liquid.Converter.UnitTests/Processors/ProcessorTests.cs index 364d1c0e7..6bd35988e 100644 --- a/src/Microsoft.Health.Fhir.Liquid.Converter.UnitTests/Processors/ProcessorTests.cs +++ b/src/Microsoft.Health.Fhir.Liquid.Converter.UnitTests/Processors/ProcessorTests.cs @@ -183,5 +183,13 @@ public void GivenTemplateWithLargeForLoop_WhenConvert_ExceptionShouldBeThrown(IF var exception = Assert.Throws(() => processor.Convert(data, "LargeForLoopTemplate", templateProvider)); Assert.Contains("Render Error - Maximum number of iterations 100000 exceeded", exception.Message); } + + [Theory] + [MemberData(nameof(GetValidInputsWithLargeForLoop))] + public void GivenTemplateWithNestedForLoop_WhenConvert_CorrectResultShouldBeReturned(IFhirConverter processor, ITemplateProvider templateProvider, string data) + { + var result = processor.Convert(data, "NestedForLoopTemplate", templateProvider); + Assert.True(result.Length > 0); + } } } diff --git a/src/Microsoft.Health.Fhir.Liquid.Converter.UnitTests/TestTemplates/NestedForLoopTemplate.liquid b/src/Microsoft.Health.Fhir.Liquid.Converter.UnitTests/TestTemplates/NestedForLoopTemplate.liquid new file mode 100644 index 000000000..edc494e19 --- /dev/null +++ b/src/Microsoft.Health.Fhir.Liquid.Converter.UnitTests/TestTemplates/NestedForLoopTemplate.liquid @@ -0,0 +1,10 @@ +{ + "value": + [ + {% for i in (1..1010) -%} + { + "{{ i }}": [{% for j in (1..1010) -%}{{ j }},{% endfor -%}] + }, + {% endfor -%} + ] +} \ No newline at end of file