Skip to content

Commit

Permalink
Support for JSON arrays, bool, long, and other JSON types. (#11)
Browse files Browse the repository at this point in the history
* Added support for int, long, and bool JSON types.

* JSON array support
  • Loading branch information
MrZoidberg authored Jan 24, 2021
1 parent bfebe8d commit 03f4c3f
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ namespace VaultSharp.Extensions.Configuration
{
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
Expand Down Expand Up @@ -122,31 +123,55 @@ private void SetData<TValue>(IEnumerable<KeyValuePair<string, TValue>> data, str
case string sValue:
this.Set(nestedKey, sValue);
break;
case int intValue:
this.Set(nestedKey, intValue.ToString(CultureInfo.InvariantCulture));
break;
case long longValue:
this.Set(nestedKey, longValue.ToString(CultureInfo.InvariantCulture));
break;
case bool boolValue:
this.Set(nestedKey, boolValue.ToString(CultureInfo.InvariantCulture));
break;
case JToken token:
switch (token.Type)
{
case JTokenType.Object:
this.SetData<JToken?>(token.Value<JObject>(), nestedKey);
break;
case JTokenType.String:
this.Set(nestedKey, token.Value<string>());
break;
case JTokenType.None:
case JTokenType.Array:
case JTokenType.Constructor:
var array = (JArray)token;
for (var i = 0; i < array.Count; i++)
{
if (array[i].Type == JTokenType.Array)
{
this.SetData<JToken?>(array[i].Value<JObject>(), $"{nestedKey}:{i}");
}
else if (array[i].Type == JTokenType.Object)
{
this.SetData<JToken?>(array[i].Value<JObject>(), $"{nestedKey}:{i}");
}
else
{
this.Set($"{nestedKey}:{i}", array[i].Value<string>());
}
}

break;

case JTokenType.Property:
case JTokenType.Comment:
case JTokenType.Integer:
case JTokenType.Float:
case JTokenType.Boolean:
case JTokenType.Null:
case JTokenType.Undefined:
case JTokenType.Date:
case JTokenType.Raw:
case JTokenType.Bytes:
case JTokenType.Guid:
case JTokenType.Uri:
case JTokenType.TimeSpan:
case JTokenType.String:
this.Set(nestedKey, token.Value<string>());
break;
}

Expand Down
80 changes: 63 additions & 17 deletions Tests/VaultSharp.Extensions.Configuration.Test/IntegrationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,29 +44,54 @@ private TestcontainersContainer PrepareVaultContainer()
return testcontainersBuilder.Build();
}

private async Task LoadDataAsync(Dictionary<string, KeyValuePair<string,string>> values)
private async Task LoadDataAsync(Dictionary<string, IEnumerable<KeyValuePair<string, object>>> values)
{
var authMethod = new TokenAuthMethodInfo("root");

var vaultClientSettings = new VaultClientSettings("http://localhost:8200", authMethod);
IVaultClient vaultClient = new VaultClient(vaultClientSettings);

foreach (var pair in values)
foreach (var sectionPair in values)
{
var data = new Dictionary<string, object>() { [pair.Value.Key] = pair.Value.Value };
await vaultClient.V1.Secrets.KeyValue.V2.WriteSecretAsync(pair.Key, data).ConfigureAwait(false);
var data = new Dictionary<string, object>();
foreach (var pair in sectionPair.Value)
{
data.Add(pair.Key, pair.Value);
}

await vaultClient.V1.Secrets.KeyValue.V2.WriteSecretAsync(sectionPair.Key, data)
.ConfigureAwait(false);
}
}

[Fact]
public async Task Success_SimpleTest_TokenAuth()
{
// arrange
Dictionary<string, KeyValuePair<string, string>> values =
new Dictionary<string, KeyValuePair<string, string>>
var values =
new Dictionary<string, IEnumerable<KeyValuePair<string, object>>>
{
{ "test", new KeyValuePair<string, string>("option1", "value1") },
{ "test/subsection", new KeyValuePair<string, string>("option2", "value2") },
{
"test", new[]
{
new KeyValuePair<string, object>("option1", "value1"),
new KeyValuePair<string, object>("option3", 5),
new KeyValuePair<string, object>("option4", true),
new KeyValuePair<string, object>("option5", new[] {"v1", "v2", "v3"}),
new KeyValuePair<string, object>("option6",
new[]
{
new TestConfigObject() {OptionA = "a1", OptionB = "b1"},
new TestConfigObject() {OptionA = "a2", OptionB = "b2"},
}),
}
},
{
"test/subsection", new[]
{
new KeyValuePair<string, object>("option2", "value2"),
}
},
};

var container = this.PrepareVaultContainer();
Expand All @@ -86,6 +111,19 @@ public async Task Success_SimpleTest_TokenAuth()

// assert
configurationRoot.GetValue<string>("option1").Should().Be("value1");
configurationRoot.GetValue<int>("option3").Should().Be(5);
configurationRoot.GetValue<bool>("option4").Should().Be(true);
configurationRoot.GetValue<string>("option5:0").Should().Be("v1");
configurationRoot.GetValue<string>("option5:1").Should().Be("v2");
configurationRoot.GetValue<string>("option5:2").Should().Be("v3");
var t1 = new TestConfigObject();
configurationRoot.Bind("option6:0", t1);
t1.OptionA.Should().Be("a1");
t1.OptionB.Should().Be("b1");
var t2 = new TestConfigObject();
configurationRoot.Bind("option6:1", t2);
t2.OptionA.Should().Be("a2");
t2.OptionB.Should().Be("b2");
configurationRoot.GetSection("subsection").GetValue<string>("option2").Should().Be("value2");
}
finally
Expand All @@ -100,11 +138,11 @@ public async Task Success_WatcherTest_TokenAuth()
// arrange
using CancellationTokenSource cts = new CancellationTokenSource();

Dictionary<string, KeyValuePair<string, string>> values =
new Dictionary<string, KeyValuePair<string, string>>
var values =
new Dictionary<string, IEnumerable<KeyValuePair<string, object>>>
{
{ "test", new KeyValuePair<string, string>("option1", "value1") },
{ "test/subsection", new KeyValuePair<string, string>("option2", "value2") },
{"test", new[] {new KeyValuePair<string, object>("option1", "value1"),}},
{"test/subsection", new[] {new KeyValuePair<string, object>("option2", "value2"),}},
};

var container = this.PrepareVaultContainer();
Expand All @@ -117,7 +155,8 @@ public async Task Success_WatcherTest_TokenAuth()
// act
ConfigurationBuilder builder = new ConfigurationBuilder();
builder.AddVaultConfiguration(
() => new VaultOptions("http://localhost:8200", "root", reloadOnChange: true, reloadCheckIntervalSeconds: 10),
() => new VaultOptions("http://localhost:8200", "root", reloadOnChange: true,
reloadCheckIntervalSeconds: 10),
"test",
"secret",
this._logger);
Expand All @@ -132,11 +171,11 @@ public async Task Success_WatcherTest_TokenAuth()
reloadToken.HasChanged.Should().BeFalse();

// load new data and wait for reload
values = new Dictionary<string, KeyValuePair<string, string>>
values = new Dictionary<string, IEnumerable<KeyValuePair<string, object>>>
{
{ "test", new KeyValuePair<string, string>("option1", "value1_new") },
{ "test/subsection", new KeyValuePair<string, string>("option2", "value2_new") },
{ "test/subsection3", new KeyValuePair<string, string>("option3", "value3_new") },
{"test", new[] {new KeyValuePair<string, object>("option1", "value1_new"),}},
{"test/subsection", new[] {new KeyValuePair<string, object>("option2", "value2_new"),}},
{"test/subsection3", new[] {new KeyValuePair<string, object>("option3", "value3_new"),}},
};
await this.LoadDataAsync(values).ConfigureAwait(false);
await Task.Delay(TimeSpan.FromSeconds(15)).ConfigureAwait(true);
Expand All @@ -155,4 +194,11 @@ public async Task Success_WatcherTest_TokenAuth()
}
}
}

public class TestConfigObject
{
public string OptionA { get; set; }

public string OptionB { get; set; }
}
}

0 comments on commit 03f4c3f

Please sign in to comment.