diff --git a/.github/workflows/change-file-in-pr.yml b/.github/workflows/change-file-in-pr.yml new file mode 100644 index 0000000..25839d6 --- /dev/null +++ b/.github/workflows/change-file-in-pr.yml @@ -0,0 +1,30 @@ +name: Change File Included in PR + +on: + pull_request: + types: [opened, synchronize, reopened, labeled] + +jobs: + check-files-in-directory: + if: ${{ !contains(github.event.pull_request.labels.*.name, 'Release Not Needed') && !contains(github.event.pull_request.labels.*.name, 'Release PR') }} + name: Change File Included in PR + runs-on: ubuntu-latest + + steps: + - name: Checkout PR code + uses: actions/checkout@v3 + + - name: Get List of Changed Files + id: changed-files + uses: tj-actions/changed-files@4edd678ac3f81e2dc578756871e4d00c19191daf #v45 + + - name: Check for Change File(s) in .autover/changes/ + run: | + DIRECTORY=".autover/changes/" + if echo "${{ steps.changed-files.outputs.all_changed_files }}" | grep -q "$DIRECTORY"; then + echo "✅ One or more change files in '$DIRECTORY' are included in this PR." + else + echo "❌ No change files in '$DIRECTORY' are included in this PR." + echo "Refer to the 'Adding a change file to your contribution branch' section of https://github.com/aws/aws-dotnet-extensions-configuration/blob/master/CONTRIBUTING.md" + exit 1 + fi diff --git a/CHANGELOG.md b/CHANGELOG.md index a47b79a..e7c2a84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## Release 2025-02-20 + +### Amazon.Extensions.Configuration.SystemsManager (6.3.0) +* Add opt-in JsonOrStringParameterProcessor processor supporting parameters being either strings or JSON + ## Release 2024-10-17 ### Amazon.Extensions.Configuration.SystemsManager (7.0.0-preview.1) diff --git a/src/Amazon.Extensions.Configuration.SystemsManager/DefaultParameterProcessor.cs b/src/Amazon.Extensions.Configuration.SystemsManager/DefaultParameterProcessor.cs index a5d637b..0072973 100644 --- a/src/Amazon.Extensions.Configuration.SystemsManager/DefaultParameterProcessor.cs +++ b/src/Amazon.Extensions.Configuration.SystemsManager/DefaultParameterProcessor.cs @@ -1,12 +1,12 @@ /* * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * + * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. * A copy of the License is located at - * + * * http://aws.amazon.com/apache2.0 - * + * * or in the "license" file accompanying this file. This file is distributed * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language governing @@ -19,6 +19,7 @@ using Amazon.SimpleSystemsManagement; using Amazon.SimpleSystemsManagement.Model; using Microsoft.Extensions.Configuration; +using static Amazon.Extensions.Configuration.SystemsManager.Utils.ParameterProcessorUtil; namespace Amazon.Extensions.Configuration.SystemsManager { @@ -33,10 +34,11 @@ public class DefaultParameterProcessor : IParameterProcessor public virtual bool IncludeParameter(Parameter parameter, string path) => true; + /// Get the extra prefix if the path is subset of parameter name. public virtual string GetKey(Parameter parameter, string path) { - var name = parameter.Name.StartsWith(path, StringComparison.OrdinalIgnoreCase) - ? parameter.Name.Substring(path.Length) + var name = parameter.Name.StartsWith(path, StringComparison.OrdinalIgnoreCase) + ? parameter.Name.Substring(path.Length) : parameter.Name; #if NETCOREAPP3_1_OR_GREATER return name.TrimStart('/').Replace("/", KeyDelimiter, StringComparison.InvariantCulture); @@ -47,51 +49,25 @@ public virtual string GetKey(Parameter parameter, string path) public virtual string GetValue(Parameter parameter, string path) => parameter.Value; - private IEnumerable> ParseStringList(Parameter parameter, string path) - { - // Items in a StringList must be separated by a comma (,). - // You can't use other punctuation or special characters to escape items in the list. - // If you have a parameter value that requires a comma, then use the String type. - // https://docs.aws.amazon.com/systems-manager/latest/userguide/param-create-cli.html#param-create-cli-stringlist - return parameter.Value.Split(',').Select((value, idx) => - new KeyValuePair($"{GetKey(parameter, path)}:{idx}", value)); - } - public virtual IDictionary ProcessParameters(IEnumerable parameters, string path) { - var result = new List>(); + var result = new Dictionary(StringComparer.OrdinalIgnoreCase); + foreach (var parameter in parameters.Where(parameter => IncludeParameter(parameter, path))) { + var keyPrefix = GetKey(parameter, path); + var value = GetValue(parameter, path); + if (parameter.Type == ParameterType.StringList) { - var parameterList = ParseStringList(parameter, path); - - // Check for duplicate parameter keys. - var stringListKeys = parameterList.Select(p => p.Key); - var duplicateKeys = result.Where(r => stringListKeys.Contains(r.Key, StringComparer.OrdinalIgnoreCase)).Select(r => r.Key); - if (duplicateKeys.Count() > 0) - { - throw new DuplicateParameterException($"Duplicate parameters '{string.Join(";", duplicateKeys)}' found. Parameter keys are case-insensitive."); - } - - result.AddRange(parameterList); + ParseStringListParameter(keyPrefix, value, result); + continue; } - else - { - string parameterKey = GetKey(parameter, path); - // Check for duplicate parameter key. - if (result.Any(r => string.Equals(r.Key, parameterKey, StringComparison.OrdinalIgnoreCase))) - { - throw new DuplicateParameterException($"Duplicate parameter '{parameterKey}' found. Parameter keys are case-insensitive."); - } - - result.Add(new KeyValuePair(parameterKey, GetValue(parameter, path))); - } + ParseStringParameter(keyPrefix, value, result); } - return result.ToDictionary(parameter => parameter.Key, parameter => parameter.Value, - StringComparer.OrdinalIgnoreCase); + return result; } } } \ No newline at end of file diff --git a/src/Amazon.Extensions.Configuration.SystemsManager/JsonOrStringParameterProcessor.cs b/src/Amazon.Extensions.Configuration.SystemsManager/JsonOrStringParameterProcessor.cs new file mode 100644 index 0000000..f77dcb2 --- /dev/null +++ b/src/Amazon.Extensions.Configuration.SystemsManager/JsonOrStringParameterProcessor.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json; +using Amazon.SimpleSystemsManagement; +using Amazon.SimpleSystemsManagement.Model; +using static Amazon.Extensions.Configuration.SystemsManager.Utils.ParameterProcessorUtil; + +namespace Amazon.Extensions.Configuration.SystemsManager +{ + /// + /// + /// A processor that prioritizes JSON parameters but falls back to string parameters, + /// in accordance with Systems Manager's suggested naming conventions + /// + public class JsonOrStringParameterProcessor : DefaultParameterProcessor + { + public override IDictionary ProcessParameters(IEnumerable parameters, string path) + { + var result = new Dictionary(StringComparer.OrdinalIgnoreCase); + + foreach (var parameter in parameters.Where(parameter => IncludeParameter(parameter, path))) + { + var keyPrefix = GetKey(parameter, path); + var value = GetValue(parameter, path); + + if (parameter.Type == ParameterType.StringList) + { + ParseStringListParameter(keyPrefix, value, result); + continue; + } + + try + { + ParseJsonParameter(keyPrefix, value, result); + } + catch (JsonException) + { + ParseStringParameter(keyPrefix, value, result); + } + } + + return result; + } + } +} \ No newline at end of file diff --git a/src/Amazon.Extensions.Configuration.SystemsManager/JsonParameterProcessor.cs b/src/Amazon.Extensions.Configuration.SystemsManager/JsonParameterProcessor.cs index 498053f..a85f2fb 100644 --- a/src/Amazon.Extensions.Configuration.SystemsManager/JsonParameterProcessor.cs +++ b/src/Amazon.Extensions.Configuration.SystemsManager/JsonParameterProcessor.cs @@ -1,12 +1,12 @@ /* * Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * + * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. * A copy of the License is located at - * + * * http://aws.amazon.com/apache2.0 - * + * * or in the "license" file accompanying this file. This file is distributed * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language governing @@ -16,42 +16,31 @@ using System; using System.Collections.Generic; using System.Linq; -using Amazon.Extensions.Configuration.SystemsManager.Internal; using Amazon.SimpleSystemsManagement.Model; -using Microsoft.Extensions.Configuration; +using static Amazon.Extensions.Configuration.SystemsManager.Utils.ParameterProcessorUtil; namespace Amazon.Extensions.Configuration.SystemsManager { /// /// - /// Default parameter processor based on Systems Manager's suggested naming convention + /// A processor specifically designed for handling JSON parameters, + /// following Systems Manager's recommended naming conventions /// public class JsonParameterProcessor : DefaultParameterProcessor { public override IDictionary ProcessParameters(IEnumerable parameters, string path) { - var outputDictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); - foreach (Parameter parameter in parameters.Where(parameter => IncludeParameter(parameter, path))) - { - // Get the extra prefix if the path is subset of paramater name. - string prefix = GetKey(parameter, path); - - var parameterDictionary = JsonConfigurationParser.Parse(parameter.Value); - foreach (var keyValue in parameterDictionary) - { - string key = (!string.IsNullOrEmpty(prefix) ? ConfigurationPath.Combine(prefix, keyValue.Key) : keyValue.Key); + var result = new Dictionary(StringComparer.OrdinalIgnoreCase); - // Check for duplicate parameter key. - if (outputDictionary.ContainsKey(key)) - { - throw new DuplicateParameterException($"Duplicate parameter '{key}' found. Parameter keys are case-insensitive."); - } + foreach (var parameter in parameters.Where(parameter => IncludeParameter(parameter, path))) + { + var keyPrefix = GetKey(parameter, path); + var value = GetValue(parameter, path); - outputDictionary.Add(key, keyValue.Value); - } + ParseJsonParameter(keyPrefix, value, result); } - return outputDictionary; + return result; } } } \ No newline at end of file diff --git a/src/Amazon.Extensions.Configuration.SystemsManager/Utils/ParameterProcessorUtil.cs b/src/Amazon.Extensions.Configuration.SystemsManager/Utils/ParameterProcessorUtil.cs new file mode 100644 index 0000000..7428078 --- /dev/null +++ b/src/Amazon.Extensions.Configuration.SystemsManager/Utils/ParameterProcessorUtil.cs @@ -0,0 +1,79 @@ +using System.Collections.Generic; +using System.Linq; +using Amazon.Extensions.Configuration.SystemsManager.Internal; +using Microsoft.Extensions.Configuration; +using System.Text.Json; + +namespace Amazon.Extensions.Configuration.SystemsManager.Utils +{ + public static class ParameterProcessorUtil + { + /// + /// Parses the SSM parameter as JSON + /// + /// prefix to add in configution key + /// SSM parameter value + /// append the parsed JSON value into + /// SSM parameter key is already present in + /// does not represent a valid single JSON value. + public static void ParseJsonParameter(string keyPrefix, string value, IDictionary result) + { + foreach (var kv in JsonConfigurationParser.Parse(value)) + { + var key = !string.IsNullOrEmpty(keyPrefix) ? ConfigurationPath.Combine(keyPrefix, kv.Key) : kv.Key; + if (result.ContainsKey(key)) + { + throw new DuplicateParameterException($"Duplicate parameter '{key}' found. Parameter keys are case-insensitive."); + } + + result.Add(key, kv.Value); + } + } + + /// + /// Parses the StringList SSM parameter as List of String + ///

+ /// Items in a StringList must be separated by a comma (,). + /// You can't use other punctuation or special characters to escape items in the list. + /// If you have a parameter value that requires a comma, then use the String type. + /// https://docs.aws.amazon.com/systems-manager/latest/userguide/param-create-cli.html#param-create-cli-stringlist + ///
+ /// prefix to add in configution key + /// SSM parameter + /// append the parsed string list value into + /// SSM parameter key is already present in + public static void ParseStringListParameter(string keyPrefix, string value, IDictionary result) + { + var configKeyValuePairs = value + .Split(',') + .Select((eachValue, idx) => new KeyValuePair($"{keyPrefix}{ConfigurationPath.KeyDelimiter}{idx}", eachValue)); + + foreach (var kv in configKeyValuePairs) + { + if (result.ContainsKey(kv.Key)) + { + throw new DuplicateParameterException($"Duplicate parameter '{kv.Key}' found. Parameter keys are case-insensitive."); + } + + result.Add(kv.Key, kv.Value); + } + } + + /// + /// Parses the SSM parameter as String + /// + /// key to be used for configution key + /// SSM parameter + /// append the parsed string value into + /// SSM parameter key is already present in + public static void ParseStringParameter(string key, string value, IDictionary result) + { + if (result.ContainsKey(key)) + { + throw new DuplicateParameterException($"Duplicate parameter '{key}' found. Parameter keys are case-insensitive."); + } + + result.Add(key, value); + } + } +} \ No newline at end of file diff --git a/test/Amazon.Extensions.Configuration.SystemsManager.Tests/DefaultParameterProcessorTests.cs b/test/Amazon.Extensions.Configuration.SystemsManager.Tests/DefaultParameterProcessorTests.cs index ef44742..70f3149 100644 --- a/test/Amazon.Extensions.Configuration.SystemsManager.Tests/DefaultParameterProcessorTests.cs +++ b/test/Amazon.Extensions.Configuration.SystemsManager.Tests/DefaultParameterProcessorTests.cs @@ -1,18 +1,33 @@ using System.Collections.Generic; using Amazon.SimpleSystemsManagement; using Amazon.SimpleSystemsManagement.Model; -using Moq; using Xunit; namespace Amazon.Extensions.Configuration.SystemsManager.Tests { public class DefaultParameterProcessorTests { - private readonly IParameterProcessor _parameterProcessor; + private readonly IParameterProcessor _parameterProcessor = new DefaultParameterProcessor(); - public DefaultParameterProcessorTests() + [Fact] + public void ExtractConfigurationKeyFromParameter() { - _parameterProcessor = new DefaultParameterProcessor(); + var processor = new DefaultParameterProcessor(); + + Assert.Equal("level1:level2", processor.GetKey(new Parameter() { Name = "/level1/level2" }, "")); + Assert.Equal("level1:level2", processor.GetKey(new Parameter() { Name = "/level1/level2" }, "/")); + Assert.Equal("level1:level2", processor.GetKey(new Parameter() { Name = "/level1/level2" }, "/someotherlevel")); + + Assert.Equal("level2:level3", processor.GetKey(new Parameter() { Name = "/level1/level2/level3" }, "/level1")); + Assert.Equal("level2", processor.GetKey(new Parameter() { Name = "/level1/level2" }, "/LEVEL1")); + } + + [Fact] + public void ExtractConfigurationValueFromParameter() + { + var processor = new DefaultParameterProcessor(); + + Assert.Equal("Some value", processor.GetValue(new Parameter() { Value = "Some value" }, null)); } [Fact] @@ -20,10 +35,10 @@ public void ProcessParametersTest() { var parameters = new List { - new Parameter {Name = "/start/path/p1/p2-1", Value = "p1:p2-1"}, - new Parameter {Name = "/start/path/p1/p2-2", Value = "p1:p2-2"}, - new Parameter {Name = "/start/path/p1/p2/p3-1", Value = "p1:p2:p3-1"}, - new Parameter {Name = "/start/path/p1/p2/p3-2", Value = "p1:p2:p3-2"}, + new Parameter { Name = "/start/path/p1/p2-1", Value = "p1:p2-1" }, + new Parameter { Name = "/start/path/p1/p2-2", Value = "p1:p2-2" }, + new Parameter { Name = "/start/path/p1/p2/p3-1", Value = "p1:p2:p3-1" }, + new Parameter { Name = "/start/path/p1/p2/p3-2", Value = "p1:p2:p3-2" }, }; const string path = "/start/path"; @@ -38,9 +53,9 @@ public void ProcessParametersStringListTest() { var parameters = new List { - new Parameter {Name = "/string-list/single", Value = "p1", Type = ParameterType.StringList}, - new Parameter {Name = "/string-list/multiple", Value = "p1,p2,p3", Type = ParameterType.StringList}, - new Parameter {Name = "/string-list/empty", Value = "", Type = ParameterType.StringList}, + new Parameter { Name = "/string-list/single", Value = "p1", Type = ParameterType.StringList }, + new Parameter { Name = "/string-list/multiple", Value = "p1,p2,p3", Type = ParameterType.StringList }, + new Parameter { Name = "/string-list/empty", Value = "", Type = ParameterType.StringList }, }; const string path = "/string-list"; @@ -55,14 +70,14 @@ public void ProcessParametersStringListTest() Assert.Equal("", data["empty:0"]); } - + [Fact] public void ProcessParametersRootTest() { var parameters = new List { - new Parameter {Name = "/p1", Value = "p1"}, - new Parameter {Name = "p2", Value = "p2"}, + new Parameter { Name = "/p1", Value = "p1" }, + new Parameter { Name = "p2", Value = "p2" }, }; const string path = "/"; @@ -77,8 +92,8 @@ public void DuplicateSimpleParametersTest() { var parameters = new List { - new Parameter {Name = "/start/path/p1", Value = "p1:1"}, - new Parameter {Name = "/start/path/P1", Value = "p1:2"} + new Parameter { Name = "/start/path/p1", Value = "p1:1" }, + new Parameter { Name = "/start/path/P1", Value = "p1:2" } }; const string path = "/start/path"; @@ -90,8 +105,8 @@ public void DuplicateStringListParametersTest() { var parameters = new List { - new Parameter {Name = "/string-list/multiple", Value = "p1,p2,p3", Type = ParameterType.StringList}, - new Parameter {Name = "/string-list/MULTIPLE", Value = "p3,p5,p6", Type = ParameterType.StringList} + new Parameter { Name = "/string-list/multiple", Value = "p1,p2,p3", Type = ParameterType.StringList }, + new Parameter { Name = "/string-list/MULTIPLE", Value = "p3,p5,p6", Type = ParameterType.StringList } }; const string path = "/string-list"; diff --git a/test/Amazon.Extensions.Configuration.SystemsManager.Tests/JsonOrStringParameterProcessorTests.cs b/test/Amazon.Extensions.Configuration.SystemsManager.Tests/JsonOrStringParameterProcessorTests.cs new file mode 100644 index 0000000..46e6716 --- /dev/null +++ b/test/Amazon.Extensions.Configuration.SystemsManager.Tests/JsonOrStringParameterProcessorTests.cs @@ -0,0 +1,123 @@ +using System.Collections.Generic; +using Amazon.SimpleSystemsManagement; +using Amazon.SimpleSystemsManagement.Model; +using Xunit; + +namespace Amazon.Extensions.Configuration.SystemsManager.Tests +{ + public class JsonOrStringParameterProcessorTests + { + private readonly IParameterProcessor _parameterProcessor = new JsonOrStringParameterProcessor(); + + [Fact] + public void ParsesJsonParametersSuccessfully() + { + var parameters = new List + { + new Parameter() { Name = "/test/level1/level2", Type = ParameterType.String, Value = "{\"level1Key\":\"level1value\"}" }, + new Parameter() { Name = "/test/level1", Type = ParameterType.String, Value = "{\"level1Key\" : {\"level2key\" : \"level2value\"}}" } + }; + var result = _parameterProcessor.ProcessParameters(parameters, "/test"); + + Assert.Equal(2, result.Count); + Assert.True(result.ContainsKey("level1:level2:level1Key")); + Assert.True(result.ContainsKey("level1:level1Key:level2key")); + Assert.Equal("level1value", result["level1:level2:level1Key"]); + Assert.Equal("level2value", result["level1:level1Key:level2key"]); + } + + [Fact] + public void ProcessParametersParsesJsonParametersWithoutPrefixSuccessfully() + { + var parameters = new List + { + new Parameter() + { + Name = "/test/level1/level2", Type = ParameterType.String, Value = "{\"level1Key\":\"level1value\"}" + }, + new Parameter() + { + Name = "/test/level1", Type = ParameterType.String, + Value = "{\"level1Key\" : {\"level2key\" : \"level2value\"}}" + } + }; + var result = _parameterProcessor.ProcessParameters(parameters, ""); + + Assert.Equal(2, result.Count); + Assert.True(result.ContainsKey("test:level1:level2:level1Key")); + Assert.True(result.ContainsKey("test:level1:level1Key:level2key")); + Assert.Equal("level1value", result["test:level1:level2:level1Key"]); + Assert.Equal("level2value", result["test:level1:level1Key:level2key"]); + } + + + [Fact] + public void ProcessParametersFallBackOnString() + { + var parameters = new List + { + new Parameter() { Name = "/test/stringParam", Type = ParameterType.String, Value = "some string" } + }; + var result = _parameterProcessor.ProcessParameters(parameters, "/test"); + + Assert.Single(result); + Assert.True(result.ContainsKey("stringParam")); + Assert.Equal("some string", result["stringParam"]); + } + + [Fact] + public void ProcessParametersThrowsOnDuplicateParameter() + { + var parameters = new List + { + new Parameter() { Name = "/test/Duplicate", Type = ParameterType.String, Value = "value1" }, + new Parameter() { Name = "/test/duplicate", Type = ParameterType.String, Value = "value2" } + }; + var duplicateParameterException = Assert.Throws(() => _parameterProcessor.ProcessParameters(parameters, "/test")); + Assert.Equal("Duplicate parameter 'duplicate' found. Parameter keys are case-insensitive.", duplicateParameterException.Message); + } + + [Fact] + public void ProcessParametersThrowsOnDuplicateParameterAtMultiLevel() + { + var parameters = new List + { + new Parameter() { Name = "/test/level1", Type = ParameterType.String, Value = "{\"level1Key\":\"level1value\"}" }, + new Parameter() { Name = "/test/level1/level1key", Type = ParameterType.String, Value = "level1valueOverriden" }, + }; + + var duplicateParameterException = Assert.Throws(() => _parameterProcessor.ProcessParameters(parameters, "/test")); + Assert.Equal("Duplicate parameter 'level1:level1key' found. Parameter keys are case-insensitive.", duplicateParameterException.Message); + } + + [Fact] + public void ProcessParametersThrowsOnDuplicateParameterAtMultilevelForJsonArray() + { + var parameters = new List + { + new Parameter() { Name = "/test/level1", Type = ParameterType.String, Value = "{\"level1Key\" : [\"level1value1\", \"level1value2\"] }" }, + new Parameter() { Name = "/test/level1/Level1key", Type = ParameterType.StringList, Value = "level1valueOverriden" }, + }; + + var duplicateParameterException = Assert.Throws(() => _parameterProcessor.ProcessParameters(parameters, "/test")); + Assert.Equal("Duplicate parameter 'level1:Level1key:0' found. Parameter keys are case-insensitive.", duplicateParameterException.Message); + } + + + [Fact] + public void ProcessParametersProcessesStringListParameters() + { + var parameters = new List + { + new Parameter() { Name = "/test/stringList", Type = ParameterType.StringList, Value = "value1,value2" } + }; + var result = _parameterProcessor.ProcessParameters(parameters, "/test"); + + Assert.Equal(2, result.Count); + Assert.True(result.ContainsKey("stringList:0")); + Assert.Equal("value1", result["stringList:0"]); + Assert.True(result.ContainsKey("stringList:1")); + Assert.Equal("value2", result["stringList:1"]); + } + } +} \ No newline at end of file diff --git a/test/Amazon.Extensions.Configuration.SystemsManager.Tests/JsonParameterProcessorTests.cs b/test/Amazon.Extensions.Configuration.SystemsManager.Tests/JsonParameterProcessorTests.cs index a4acec1..ee64555 100644 --- a/test/Amazon.Extensions.Configuration.SystemsManager.Tests/JsonParameterProcessorTests.cs +++ b/test/Amazon.Extensions.Configuration.SystemsManager.Tests/JsonParameterProcessorTests.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Text.Json; using Amazon.SimpleSystemsManagement.Model; using Xunit; @@ -6,12 +7,7 @@ namespace Amazon.Extensions.Configuration.SystemsManager.Tests { public class JsonParameterProcessorTests { - private readonly IParameterProcessor _parameterProcessor; - - public JsonParameterProcessorTests() - { - _parameterProcessor = new JsonParameterProcessor(); - } + private readonly IParameterProcessor _parameterProcessor = new JsonParameterProcessor(); [Fact] public void ProcessParametersTest() @@ -58,5 +54,17 @@ public void DuplicateParametersTest() const string path = "/"; Assert.Throws(() => _parameterProcessor.ProcessParameters(parameters, path)); } + + [Fact] + public void InvalidJsonTest() + { + var parameters = new List + { + new Parameter {Name = "/p1", Value = "String value"}, + }; + + const string path = "/"; + Assert.ThrowsAny(() => _parameterProcessor.ProcessParameters(parameters, path)); + } } } \ No newline at end of file diff --git a/test/Amazon.Extensions.Configuration.SystemsManager.Tests/Utils/ParameterProcessorUtilTests.cs b/test/Amazon.Extensions.Configuration.SystemsManager.Tests/Utils/ParameterProcessorUtilTests.cs new file mode 100644 index 0000000..3b4e5cd --- /dev/null +++ b/test/Amazon.Extensions.Configuration.SystemsManager.Tests/Utils/ParameterProcessorUtilTests.cs @@ -0,0 +1,96 @@ +using System.Collections.Generic; +using System.Text.Json; +using Amazon.Extensions.Configuration.SystemsManager.Utils; +using Xunit; + +namespace Amazon.Extensions.Configuration.SystemsManager.Tests.Utils +{ + public class ParameterProcessorUtilTests + { + [Fact] + public void ParseJsonParameterSuccessfully() + { + var result = new Dictionary(); + var value = "{\"key\": \"value\"}"; + var keyPrefix = "prefix"; + + ParameterProcessorUtil.ParseJsonParameter(keyPrefix, value, result); + + Assert.Single(result); + Assert.Contains("prefix:key", result.Keys); + Assert.Equal("value", result["prefix:key"]); + } + + [Fact] + public void ParseJsonParameterWithDuplicateKeyThrowsException() + { + var result = new Dictionary { { "prefix:key", "value" } }; + var value = "{\"key\": \"newvalue\"}"; + var keyPrefix = "prefix"; + + Assert.Throws(() => ParameterProcessorUtil.ParseJsonParameter(keyPrefix, value, result)); + } + + [Fact] + public void ParseJsonParameterForInvalidJsonThrowsException() + { + var result = new Dictionary(); + var value = "invalid json"; + var keyPrefix = ""; + + Assert.ThrowsAny(() => ParameterProcessorUtil.ParseJsonParameter(keyPrefix, value, result)); + } + + [Fact] + public void ParseStringListParameterSuccessfully() + { + var result = new Dictionary(); + var value = "value1,value2,value3"; + var keyPrefix = "prefix"; + + ParameterProcessorUtil.ParseStringListParameter(keyPrefix, value, result); + + Assert.Equal(3, result.Count); + Assert.Contains("prefix:0", result.Keys); + Assert.Contains("prefix:1", result.Keys); + Assert.Contains("prefix:2", result.Keys); + Assert.Equal("value1", result["prefix:0"]); + Assert.Equal("value2", result["prefix:1"]); + Assert.Equal("value3", result["prefix:2"]); + } + + [Fact] + public void ParseStringListParameterWithDuplicateKeyThrowsException() + { + var result = new Dictionary { { "prefix:0", "value" } }; + var value = "value1,value2,value3"; + var keyPrefix = "prefix"; + + Assert.Throws(() => ParameterProcessorUtil.ParseStringListParameter(keyPrefix, value, result)); + } + + [Fact] + public void ParseStringParameterSuccessfully() + { + var result = new Dictionary(); + var value = "stringValue"; + var key = "myKey"; + + ParameterProcessorUtil.ParseStringParameter(key, value, result); + + Assert.Single(result); + Assert.Contains("myKey", result.Keys); + Assert.Equal("stringValue", result["myKey"]); + } + + [Fact] + public void ParseStringParameterWithDuplicateKeyThrowsException() + { + var result = new Dictionary { { "myKey", "existingValue" } }; + var value = "newValue"; + var key = "myKey"; + + Assert.Throws(() => ParameterProcessorUtil.ParseStringParameter(key, value, result)); + } + } +} \ No newline at end of file