diff --git a/.vscode/launch.json b/.vscode/launch.json index ce279f1..3f0d5fa 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,9 +10,9 @@ "request": "launch", "preLaunchTask": "build", // If you have changed target frameworks, make sure to update the program path. - "program": "${workspaceFolder}/deploy-test/bin/Debug/net8.0/deploy-test.dll", + "program": "${workspaceFolder}/deployment.tests/bin/Debug/net8.0/deployment.tests.dll", "args": [], - "cwd": "${workspaceFolder}/deploy-test", + "cwd": "${workspaceFolder}/deployment.tests", // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console "console": "internalConsole", "stopAtEntry": false diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 05a2991..7bbd3e2 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -7,7 +7,7 @@ "type": "process", "args": [ "build", - "${workspaceFolder}/deploy-test/deploy-test.csproj", + "${workspaceFolder}/deployment.tests/deployment.tests.csproj", "/property:GenerateFullPaths=true", "/consoleloggerparameters:NoSummary;ForceNoAlign" ], @@ -19,7 +19,7 @@ "type": "process", "args": [ "publish", - "${workspaceFolder}/deploy-test/deploy-test.csproj", + "${workspaceFolder}/deployment.tests/deployment.tests.csproj", "/property:GenerateFullPaths=true", "/consoleloggerparameters:NoSummary;ForceNoAlign" ], @@ -33,7 +33,7 @@ "watch", "run", "--project", - "${workspaceFolder}/deploy-test/deploy-test.csproj" + "${workspaceFolder}/deployment.tests/deployment.tests.csproj" ], "problemMatcher": "$msCompile" } diff --git a/Deployment/ConfigurationBootstrapper.cs b/Deployment/ConfigurationBootstrapper.cs deleted file mode 100644 index a7ec107..0000000 --- a/Deployment/ConfigurationBootstrapper.cs +++ /dev/null @@ -1,134 +0,0 @@ -using System; -using System.Dynamic; -using System.Reflection; -using System.Runtime.CompilerServices; -using Newtonsoft.Json; - -[assembly: InternalsVisibleTo("deployment.tests")] -namespace greyn.Deployment -{ - public static class ConfigurationBootstrapper - { - private const string confpath = "appsettings.json"; - - public static T Load() where T : new() - { - if (File.Exists("appsettings.json")) - { - /* "aaaahhh this is the most abstract and reflective thing in the goddamn world aaaahhhhh next you'll make an ECS on a dynamic aaaahhh" - * Ok, yes. I share these fears. but. - * this way we can read a *very* arbitrary configuration file. - * some random external file's configuration values is a good reason to aim for very high flexibility, imo - * if the configuration expects new values we write them in, - * if you left other junk for whatever reason, we don't delete them. - */ - var actualConfig = JsonConvert.DeserializeObject(File.ReadAllText(confpath)) ?? new ExpandoObject(); - var toReturn = new T(); - populateExpando(toReturn, ref actualConfig); - File.WriteAllText(confpath, JsonConvert.SerializeObject(actualConfig, Formatting.Indented)); - - readFromExpando(ref toReturn, actualConfig); - - return toReturn; - } - else - { - var toReturn = new T(); - File.WriteAllText(confpath, JsonConvert.SerializeObject(toReturn)); - return toReturn; - } - } - - //TODO: make private but get tests to cooperate - public static void populateExpando(T config, ref ExpandoObject fromFile) - { - if (config == null) return; - - if (fromFile == null) - { - var expandoPopulated = new ExpandoObject(); - var dictionaryFromExpandoPopulated = (IDictionary)expandoPopulated; - foreach (var property in config.GetType().GetProperties()) - dictionaryFromExpandoPopulated.Add(property.Name, property.GetValue(config)); - expandoPopulated = (ExpandoObject)dictionaryFromExpandoPopulated; - fromFile = expandoPopulated; - return; - } - var dictionaryFromExpandoFromFile = (IDictionary)fromFile; - foreach (var property in config.GetType().GetProperties()) - { - if (dictionaryFromExpandoFromFile.TryGetValue(property.Name, out object? value)) - { - if (value != null) - { - if (property.PropertyType.GetMembers() == null) - { - var childProperty = (ExpandoObject)property.GetValue(fromFile); - populateExpando(property.GetValue(config), ref childProperty); - property.SetValue(fromFile, childProperty); - } - } - } - else - { - fromFile.TryAdd(property.Name, property.GetValue(config)); - } - } - } - public static void readFromExpando(ref T config, ExpandoObject readFromFile) - { - //TODO: read from Expando - } - - // private static T sync(ref T config, ref ExpandoObject readFromFile) - // { - // var fieldsFoundThisLevel = new List(); - - // if(config == null) - // { - // //TODO: it's entirely possible this is null. - // throw new ArgumentNullException(); - // } - // if(readFromFile == null) - // { - // //TODO: it's entirely possible this is null. - // throw new ArgumentNullException(); - // } - // var readUnExpandoed = (IDictionary)readFromFile; - // //if it's present on what was read - // //set it on Config - // //if it's not found on what was read, or type is different - - // foreach (var prop in config.GetType().GetProperties()) - // { - // fieldsFoundThisLevel.Add(prop.Name); - // if(readUnExpandoed.TryGetValue(prop.Name, out object? valueFromFile)) //so a configuration file can *set* a value *to null* - // { - // if(valueFromFile != null) - // { - // var defaultConfigValue = prop.GetValue(config); - // if (defaultConfigValue != null) - // { - // //expandofy, since we objectified it. - // var expandoFromFile = new ExpandoObject(); - // var dictionaryFromExpandoFromFile = (IDictionary)expandoFromFile; - // foreach (var property in valueFromFile.GetType().GetProperties()) - // dictionaryFromExpandoFromFile.Add(property.Name, property.GetValue(valueFromFile)); - // expandoFromFile = (ExpandoObject)dictionaryFromExpandoFromFile; - // //dive in, repeat - // sync(ref defaultConfigValue, ref expandoFromFile); - // //we've now Sync'd expandoFromFile and defaultConfigValue - // prop.SetValue(readFromFile, expandoFromFile); - // prop.SetValue(config, expandoFromFile); - // } - - // } - // } - // else - // { - // readFromFile.TryAdd(prop.Name, prop.GetValue(config)); - // } - // } - // } - } -} \ No newline at end of file diff --git a/Deployment/Configurator.cs b/Deployment/Configurator.cs new file mode 100644 index 0000000..189ccb2 --- /dev/null +++ b/Deployment/Configurator.cs @@ -0,0 +1,71 @@ +using System; +using System.Dynamic; +using System.Reflection; +using System.Runtime.CompilerServices; +using Newtonsoft.Json; + +[assembly: InternalsVisibleTo("deployment.tests")] +namespace greyn.Deployment +{ + public static class Configurator where T : new() + { + private const string confpath = "appsettings.json"; + private static FileSystemWatcher appsettingsWatcher = new FileSystemWatcher("."); + + public static event EventHandler Changed; + public static event System.IO.ErrorEventHandler Error; + + private static T config; + + public static T Load() + { + if (File.Exists(confpath)) + { + /* + * if the configuration expects new values we write them in. + * if you left other junk for whatever reason, get rekt + */ + config = JsonConvert.DeserializeObject(File.ReadAllText(confpath)) ?? new T(); + } + else + { + config = new T(); + } + File.WriteAllText(confpath, JsonConvert.SerializeObject(config, Formatting.Indented)); + + + + + appsettingsWatcher.Filter = confpath; + + appsettingsWatcher.NotifyFilter = NotifyFilters.LastWrite + | NotifyFilters.Security + | NotifyFilters.Size; + + appsettingsWatcher.Changed += internalOnChanged; + appsettingsWatcher.Created += internalOnChanged; + appsettingsWatcher.Deleted += internalOnChanged; + appsettingsWatcher.Renamed += internalOnChanged; + appsettingsWatcher.Error += Error; + + appsettingsWatcher.EnableRaisingEvents = true; + + return config; + } + + internal static void internalOnChanged(object sender, FileSystemEventArgs e) + { + appsettingsWatcher.EnableRaisingEvents = false; + + Load(); + Changed(sender, new ConfigChangedEventArgs(){NewConfig = config}); + } + + //I would like to just pudate the values on our held reference, but we'd have to update each value by reflection. + //2lazy. + public class ConfigChangedEventArgs : EventArgs + { + public T NewConfig; + } + } +} diff --git a/Deployment/Deployment.csproj b/Deployment/Deployment.csproj index 21191a6..19044ac 100644 --- a/Deployment/Deployment.csproj +++ b/Deployment/Deployment.csproj @@ -4,6 +4,8 @@ net8.0 enable enable + true + 0.0.1 @@ -13,5 +15,4 @@ - diff --git a/deployment.tests/ConfigTests.cs b/deployment.tests/ConfigTests.cs index 6231004..d6245cd 100644 --- a/deployment.tests/ConfigTests.cs +++ b/deployment.tests/ConfigTests.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Reflection; using Newtonsoft.Json; using System.Globalization; +using Newtonsoft.Json.Converters; namespace deployment.tests; @@ -33,20 +34,20 @@ public class ConfigTests aValueType: 94.298, aValueTypeButNotAField: 9241, anEnumerableType: - [ - {""test3"": 420.71}, - {""test4"": 420.72} - ] + { + ""test3"": 420.71, + ""test4"": 420.72 + } }, subtyped2: { aValueType: 95.298, aValueTypeButNotAField: 9242, anEnumerableType: - [ - {""test5"": 420.73}, - {""test6"": 420.74} - ] + { + ""test5"": 420.73, + ""test6"": 420.74 + } } }"; private const string EmptyConfiguration = "{}"; @@ -55,422 +56,262 @@ public class ConfigTests aValueTypeButNotAField = ""796.651"", }"; #endregion - - private ExpandoObject parse(string confstr) + + [TearDown] + public void TearDown() { - return JsonConvert.DeserializeObject(confstr) ?? new ExpandoObject(); + if(File.Exists("appsettings.json")) + File.Delete("appsettings.json"); } +/* [Test] - public void parseworks() + public void load_doesnt_explode() { - Assert.IsNotNull(parse(PerfectConfiguration)); - } - - [Test] - public void parseworksasexpected() - { - var expandoed = parse(PerfectConfiguration); - Assert.IsNotNull(expandoed); - var casted = (IDictionary)expandoed; - Assert.IsNotNull(casted); - //Console.WriteLine(JsonConvert.SerializeObject(casted, Formatting.Indented)); - } - - #region jokes - [Test] - public void fuckit_werealreadytestingthetest_letstestthattest() - { - parseworks(); + File.WriteAllText("appsettings.json", PerfectConfiguration); + var conf = greyn.Deployment.Configurator.Load(); Assert.Pass(); } + */ [Test] - public void more_tests_more_good() + public void load_loads() { - fuckit_werealreadytestingthetest_letstestthattest(); - Assert.Pass(); - } - [Test] - public void what_do_you_mean_a_bug_escaped_tests() - { - more_tests_more_good(); - Assert.Pass(); - } - - [Test] - public void vibecheck() - { - Assert.NotZero(new Random().Next(0, 2)); - } - - [Test] - public void populateExpando_doesnt_explode() - { - var toReturn = new AConfigurationType(); - var actualConfig = parse(PerfectConfiguration); - greyn.Deployment.ConfigurationBootstrapper.populateExpando(toReturn, ref actualConfig); - Assert.Pass(); - } - #endregion - - [Test] - public void populateExpando_getsmissing_property() - { - var actualConfig = parse(@"{ - aField: ""I've decided"", - subtyped: - { - aValueType: 94.298, - aValueTypeButNotAField: 9241, - anEnumerableType: - [ - {""test3"": 420.71}, - {""test4"": 420.72} - ] - }, - subtyped2: - { - aValueType: 95.298, - aValueTypeButNotAField: 9242, - anEnumerableType: - [ - {""test5"": 420.73}, - {""test6"": 420.74} - ] - } - }"); - greyn.Deployment.ConfigurationBootstrapper.populateExpando(new AConfigurationType(), ref actualConfig); - var casted = (IDictionary)actualConfig; - Console.WriteLine(casted["aValueTypeButNotAField"]); - Assert.Pass(); - } - - [Test] - public void populateExpando_getsmissing_field() - { - var actualConfig = parse(@"{ - aValueTypeButNotAField: 796.651, - subtyped: - { - aValueType: 94.298, - aValueTypeButNotAField: 9241, - anEnumerableType: - [ - {""test3"": 420.71}, - {""test4"": 420.72} - ] - }, - subtyped2: - { - aValueType: 95.298, - aValueTypeButNotAField: 9242, - anEnumerableType: - [ - {""test5"": 420.73}, - {""test6"": 420.74} - ] - } - }"); - greyn.Deployment.ConfigurationBootstrapper.populateExpando(new AConfigurationType(), ref actualConfig); - var casted = (IDictionary)actualConfig; - Console.WriteLine(casted["aField"]); - Assert.Pass(); - } - [Test] - public void populateExpando_getsmissing_subobject() - { - var actualConfig = parse(@"{ - aValueTypeButNotAField: 796.651, - aField: ""I've decided"", - subtyped2: - { - aValueType: 95.298, - aValueTypeButNotAField: 9242, - anEnumerableType: - [ - {""test5"": 420.73}, - {""test6"": 420.74} - ] - } - }"); - greyn.Deployment.ConfigurationBootstrapper.populateExpando(new AConfigurationType(), ref actualConfig); - var casted = (IDictionary)actualConfig; - Console.WriteLine(casted["subtyped"]); - Assert.Pass(); - } - [Test] - public void populateExpando_getsmissing_subobject_field() - { - var actualConfig = parse(@"{ - aValueTypeButNotAField: 796.651, - aField: ""I've decided"", - subtyped: - { - aValueTypeButNotAField: 9241, - anEnumerableType: - [ - {""test3"": 420.71}, - {""test4"": 420.72} - ] - }, - subtyped2: - { - aValueType: 95.298, - aValueTypeButNotAField: 9242, - anEnumerableType: - [ - {""test5"": 420.73}, - {""test6"": 420.74} - ] - } - }"); - greyn.Deployment.ConfigurationBootstrapper.populateExpando(new AConfigurationType(), ref actualConfig); - var casted = (IDictionary)actualConfig; - var subtypeCasted = (IDictionary)casted["subtyped"]; - Console.WriteLine(subtypeCasted["aValueType"]); - Assert.Pass(); - } - [Test] - public void populateExpando_getsmissing_subobject_property() - { - var actualConfig = parse(@"{ - aValueTypeButNotAField: 796.651, - aField: ""I've decided"", - subtyped: - { - aValueType: 94.298, - anEnumerableType: - [ - {""test3"": 420.71}, - {""test4"": 420.72} - ] - }, - subtyped2: - { - aValueType: 95.298, - aValueTypeButNotAField: 9242, - anEnumerableType: - [ - {""test5"": 420.73}, - {""test6"": 420.74} - ] - } - }"); - greyn.Deployment.ConfigurationBootstrapper.populateExpando(new AConfigurationType(), ref actualConfig); - var casted = (IDictionary)actualConfig; - var subtypeCasted = (IDictionary)casted["subtyped"]; - Console.WriteLine(subtypeCasted["aValueTypeButNotAField"]); - Assert.Pass(); - } - [Test] - public void populateExpando_getsmissing_subobject_enumerable() - { - var actualConfig = parse(@"{ - aValueTypeButNotAField: 796.651, - aField: ""I've decided"", - subtyped: - { - aValueType: 94.298, - aValueTypeButNotAField: 9241, - }, - subtyped2: - { - aValueType: 95.298, - aValueTypeButNotAField: 9242, - anEnumerableType: - [ - {""test5"": 420.73}, - {""test6"": 420.74} - ] - } - }"); - greyn.Deployment.ConfigurationBootstrapper.populateExpando(new AConfigurationType(), ref actualConfig); - var casted = (IDictionary)actualConfig; - var subtypeCasted = (IDictionary)casted["subtyped"]; - Console.WriteLine(subtypeCasted["anEnumerableType"]); - Assert.Pass(); - } - [Test] - public void populateExpando_doesntoverridenullednullable() - { - var actualConfig = parse(@"{ - aValueTypeButNotAField: 796.651, - aField: ""I've decided"", - subtyped: null, - subtyped2: - { - aValueType: 95.298, - aValueTypeButNotAField: 9242, - anEnumerableType: - [ - {""test5"": 420.73}, - {""test6"": 420.74} - ] - } - }"); - greyn.Deployment.ConfigurationBootstrapper.populateExpando(new AConfigurationType(), ref actualConfig); - var casted = (IDictionary)actualConfig; - Assert.IsNull(casted["subtyped"]); - } - [Test] - public void populateExpando_doesntremoveextras() - { - var actualConfig = parse(@"{ - hiImHereToo: ""sup"", - aValueTypeButNotAField: 796.651, - aField: ""I've decided"", - subtyped: - { - aValueType: 94.298, - aValueTypeButNotAField: 9241, - anEnumerableType: - [ - {""test3"": 420.71}, - {""test4"": 420.72} - ] - }, - subtyped2: - { - aValueType: 95.298, - aValueTypeButNotAField: 9242, - anEnumerableType: - [ - {""test5"": 420.73}, - {""test6"": 420.74} - ] - } - }"); - greyn.Deployment.ConfigurationBootstrapper.populateExpando(new AConfigurationType(), ref actualConfig); - var casted = (IDictionary)actualConfig; - Assert.IsNotNull(casted["hiImHereToo"]); - } - [Test] - public void populateExpando_populatesblank() - { - var actualConfig = parse("{}"); - greyn.Deployment.ConfigurationBootstrapper.populateExpando(new AConfigurationType(), ref actualConfig); - var casted = (IDictionary)actualConfig; - var subtypeCasted = (IDictionary)casted["subtyped"]; - Console.WriteLine(subtypeCasted["aValueTypeButNotAField"]); - Assert.Pass(); - } - [Test] - public void readfromExpando_doesnt_explode() - { - var toReturn = new AConfigurationType(); - var actualConfig = parse(PerfectConfiguration); - greyn.Deployment.ConfigurationBootstrapper.readFromExpando(ref toReturn, actualConfig); - Assert.Pass(); - } - [Test] - public void readfromExpando_does() - { - var readConfig = parse(PerfectConfiguration); - var conf = new AConfigurationType(); - greyn.Deployment.ConfigurationBootstrapper.readFromExpando(ref conf, readConfig); - Assert.AreEqual(conf.aValueTypeButNotAField, 796.651); - Assert.AreEqual(conf.aField, "I've decided"); - Assert.AreEqual(conf.subtyped.aValueType, 94.298); - Assert.AreEqual(conf.subtyped.aValueTypeButNotAField, 9241); + File.WriteAllText("appsettings.json", PerfectConfiguration); + var conf = greyn.Deployment.Configurator.Load(); + + Assert.AreEqual(796.651f, conf.aValueTypeButNotAField); + Assert.AreEqual("I've decided", conf.aField); + Assert.AreEqual(94.298, conf.subtyped.aValueType); + Assert.AreEqual(9241, conf.subtyped.aValueTypeButNotAField); Assert.IsNotNull(conf.subtyped.anEnumerableType); - Assert.AreEqual(conf.subtyped.anEnumerableType["test3"], 420.71); - Assert.AreEqual(conf.subtyped.anEnumerableType["test4"], 420.72); + Assert.AreEqual( 420.71, conf.subtyped.anEnumerableType["test3"]); + Assert.AreEqual( 420.72, conf.subtyped.anEnumerableType["test4"]); Assert.IsNotNull(conf.subtyped2); } + /* [Test] - public void readfromExpando_acceptsnull() + public void load_acceptsnullasvalue() { - var readConfig = parse(PerfectConfiguration); - var conf = new AConfigurationType(); - greyn.Deployment.ConfigurationBootstrapper.readFromExpando(ref conf, readConfig); + File.WriteAllText("appsettings.json", @"{ + aValueTypeButNotAField: 796.651, + aField: ""I've decided"", + subtyped: + { + aValueType: 94.298, + aValueTypeButNotAField: 9241, + anEnumerableType: null + }, + subtyped2: + { + aValueType: 95.298, + aValueTypeButNotAField: 9242, + anEnumerableType: + { + ""test5"": 420.73, + ""test6"": 420.74 + } + } + }"); - Assert.AreEqual(conf.aValueTypeButNotAField, 796.651); - Assert.AreEqual(conf.aField, "I've decided"); - Assert.AreEqual(conf.subtyped.aValueType, 94.298); - Assert.AreEqual(conf.subtyped.aValueTypeButNotAField, 9241); + var conf = greyn.Deployment.Configurator.Load(); + System.Threading.Thread.Sleep(1000); + + + Assert.AreEqual(796.651f, conf.aValueTypeButNotAField); + Assert.AreEqual("I've decided", conf.aField); + Assert.AreEqual(94.298, conf.subtyped.aValueType); + Assert.AreEqual(9241, conf.subtyped.aValueTypeButNotAField); Assert.IsNotNull(conf.subtyped); + Assert.IsNull(conf.subtyped.anEnumerableType); + Assert.IsNotNull(conf.subtyped2); - Assert.AreEqual(conf.subtyped2.aValueType, 95.298); - Assert.AreEqual(conf.subtyped2.aValueTypeButNotAField, 9242); + Assert.AreEqual(95.298, conf.subtyped2.aValueType); + Assert.AreEqual(9242, conf.subtyped2.aValueTypeButNotAField); Assert.IsNotNull(conf.subtyped2.anEnumerableType); - Assert.AreEqual(conf.subtyped2.anEnumerableType["test5"], 420.73); - Assert.AreEqual(conf.subtyped2.anEnumerableType["test6"], 420.74); + Assert.AreEqual( 420.73, conf.subtyped2.anEnumerableType["test5"]); + Assert.AreEqual( 420.74, conf.subtyped2.anEnumerableType["test6"]); } [Test] - public void readfromExpando_usesdefaultfornullablemissing() + public void load_acceptsnull_forparenttype() { - var readConfig = parse(@"{ - aValueTypeButNotAField: 796.651, + File.WriteAllText("appsettings.json", @"{ + aValueTypeButNotAField: 796.651, + aField: ""I've decided"", + subtyped: null, + subtyped2: + { + aValueType: 95.298, + aValueTypeButNotAField: 9242, + anEnumerableType: + { + ""test5"": 420.73, + ""test6"": 420.74 + } + } + }"); + var conf = greyn.Deployment.Configurator.Load(); + System.Threading.Thread.Sleep(1000); - subtyped: - { - aValueType: 94.298, - aValueTypeButNotAField: 9241, - anEnumerableType: - [ - {""test3"": 420.71}, - {""test4"": 420.72} - ] - }, - subtyped2: - { - aValueType: 95.298, - aValueTypeButNotAField: 9242, - anEnumerableType: - [ - {""test5"": 420.73}, - {""test6"": 420.74} - ] - } - }"); - var conf = new AConfigurationType(); - greyn.Deployment.ConfigurationBootstrapper.readFromExpando(ref conf, readConfig); - Assert.AreEqual(conf.aValueTypeButNotAField, 796.651); - Assert.AreEqual(conf.aField, "hi there, hello"); - Assert.AreEqual(conf.subtyped.aValueType, 94.298); - Assert.AreEqual(conf.subtyped.aValueTypeButNotAField, 9241); + Assert.AreEqual(796.651f, conf.aValueTypeButNotAField); + Assert.AreEqual("I've decided", conf.aField); + + Assert.IsNull(conf.subtyped); + + Assert.IsNotNull(conf.subtyped2); + Assert.AreEqual(95.298, conf.subtyped2.aValueType); + Assert.AreEqual(9242, conf.subtyped2.aValueTypeButNotAField); + Assert.IsNotNull(conf.subtyped2.anEnumerableType); + Assert.AreEqual( 420.73, conf.subtyped2.anEnumerableType["test5"]); + Assert.AreEqual( 420.74, conf.subtyped2.anEnumerableType["test6"]); + } + [Test] + public void load_usesdefaultfornullablemissing() + { + File.WriteAllText("appsettings.json", @"{ + aValueTypeButNotAField: 796.651, + + subtyped: + { + aValueType: 94.298, + aValueTypeButNotAField: 9241, + anEnumerableType: + { + ""test3"": 420.71, + ""test4"": 420.72 + } + }, + subtyped2: + { + aValueType: 95.298, + aValueTypeButNotAField: 9242, + anEnumerableType: + { + ""test5"": 420.73, + ""test6"": 420.74 + } + } + }"); + var conf = greyn.Deployment.Configurator.Load(); + System.Threading.Thread.Sleep(1000); + + Assert.AreEqual(796.651f, conf.aValueTypeButNotAField); + Assert.AreEqual("hi there, hello", conf.aField); + Assert.AreEqual(94.298, conf.subtyped.aValueType); + Assert.AreEqual(9241, conf.subtyped.aValueTypeButNotAField); Assert.IsNotNull(conf.subtyped.anEnumerableType); - Assert.AreEqual(conf.subtyped.anEnumerableType["test3"], 420.71); - Assert.AreEqual(conf.subtyped.anEnumerableType["test4"], 420.72); + Assert.AreEqual( 420.71, conf.subtyped.anEnumerableType["test3"]); + Assert.AreEqual( 420.72, conf.subtyped.anEnumerableType["test4"]); Assert.IsNotNull(conf.subtyped2); } [Test] - public void readfromExpando_usesdefaultfornonnullablemissing() + public void load_usesdefaultfornonnullablemissing() { - var readConfig = parse(@"{ - - aField: ""I've decided"", - subtyped: - { - aValueType: 94.298, - aValueTypeButNotAField: 9241, - anEnumerableType: - [ - {""test3"": 420.71}, - {""test4"": 420.72} - ] - }, - subtyped2: - { - aValueType: 95.298, - aValueTypeButNotAField: 9242, - anEnumerableType: - [ - {""test5"": 420.73}, - {""test6"": 420.74} - ] - } - }"); - var conf = new AConfigurationType(); - greyn.Deployment.ConfigurationBootstrapper.readFromExpando(ref conf, readConfig); - Assert.AreEqual(conf.aValueTypeButNotAField, 156.697f); - Assert.AreEqual(conf.aField, "I've decided"); - Assert.AreEqual(conf.subtyped.aValueType, 94.298); - Assert.AreEqual(conf.subtyped.aValueTypeButNotAField, 9241); + File.WriteAllText("appsettings.json", @"{ + aField: ""I've decided"", + subtyped: + { + aValueType: 94.298, + aValueTypeButNotAField: 9241, + anEnumerableType: + { + ""test3"": 420.71, + ""test4"": 420.72 + } + }, + subtyped2: + { + aValueType: 95.298, + aValueTypeButNotAField: 9242, + anEnumerableType: + { + ""test5"": 420.73, + ""test6"": 420.74 + } + } + }"); + + var conf = greyn.Deployment.Configurator.Load(); + System.Threading.Thread.Sleep(1000); + + Assert.AreEqual(156.697f, conf.aValueTypeButNotAField); + Assert.AreEqual("I've decided", conf.aField); + Assert.AreEqual(94.298, conf.subtyped.aValueType); + Assert.AreEqual(9241, conf.subtyped.aValueTypeButNotAField); Assert.IsNotNull(conf.subtyped.anEnumerableType); - Assert.AreEqual(conf.subtyped.anEnumerableType["test3"], 420.71); - Assert.AreEqual(conf.subtyped.anEnumerableType["test4"], 420.72); + Assert.AreEqual( 420.71, conf.subtyped.anEnumerableType["test3"]); + Assert.AreEqual( 420.72, conf.subtyped.anEnumerableType["test4"]); Assert.IsNotNull(conf.subtyped2); } +*/ + + [Test] + public void live_reload() + { + File.WriteAllText("appsettings.json", @"{ + aField: ""I've decided"", + subtyped: + { + aValueType: 94.298, + aValueTypeButNotAField: 9241, + anEnumerableType: + { + ""test3"": 420.71, + ""test4"": 420.72 + } + }, + subtyped2: + { + aValueType: 95.298, + aValueTypeButNotAField: 9242, + anEnumerableType: + { + ""test5"": 420.73, + ""test6"": 420.74 + } + } + }"); + + var conf = greyn.Deployment.Configurator.Load(); + System.Threading.Thread.Sleep(1000); + + Assert.AreEqual(94.298, conf.subtyped.aValueType); + + var wait= true; + greyn.Deployment.Configurator.Changed += (sender, e) => { + conf = (e as Configurator.ConfigChangedEventArgs).NewConfig; + wait = false; + }; + +File.WriteAllText("appsettings.json", @"{ + aField: ""I've decided"", + subtyped: + { + aValueType: 94.301, + aValueTypeButNotAField: 9241, + anEnumerableType: + { + ""test3"": 420.71, + ""test4"": 420.72 + } + }, + subtyped2: + { + aValueType: 95.298, + aValueTypeButNotAField: 9242, + anEnumerableType: + { + ""test5"": 420.73, + ""test6"": 420.74 + } + } + }"); + + while(wait) + { + System.Threading.Thread.Sleep(1000); + } + + Assert.AreEqual(94.301, conf.subtyped.aValueType); + } }