diff --git a/Aquality.Selenium.Core/src/Aquality.Selenium.Core/Configurations/LoggerConfiguration.cs b/Aquality.Selenium.Core/src/Aquality.Selenium.Core/Configurations/LoggerConfiguration.cs index 53cc258..e1f3a99 100644 --- a/Aquality.Selenium.Core/src/Aquality.Selenium.Core/Configurations/LoggerConfiguration.cs +++ b/Aquality.Selenium.Core/src/Aquality.Selenium.Core/Configurations/LoggerConfiguration.cs @@ -7,8 +7,7 @@ namespace Aquality.Selenium.Core.Configurations /// public class LoggerConfiguration : ILoggerConfiguration { - private const string defaultLanguage = "en"; - private readonly JsonFile settingsFile; + private const string DefaultLanguage = "en"; /// /// Instantiates class using JSON file with general settings. @@ -16,9 +15,9 @@ public class LoggerConfiguration : ILoggerConfiguration /// JSON settings file. public LoggerConfiguration(JsonFile settingsFile) { - this.settingsFile = settingsFile; + Language = settingsFile.GetValueOrDefault(".logger.language", DefaultLanguage); } - public string Language => settingsFile.GetValueOrDefault(".logger.language", defaultLanguage); + public string Language { get; } } } diff --git a/Aquality.Selenium.Core/src/Aquality.Selenium.Core/Utilities/EnvironmentConfiguration.cs b/Aquality.Selenium.Core/src/Aquality.Selenium.Core/Utilities/EnvironmentConfiguration.cs index 164a382..f862786 100644 --- a/Aquality.Selenium.Core/src/Aquality.Selenium.Core/Utilities/EnvironmentConfiguration.cs +++ b/Aquality.Selenium.Core/src/Aquality.Selenium.Core/Utilities/EnvironmentConfiguration.cs @@ -20,7 +20,9 @@ public static string GetVariable(string key) { Environment.GetEnvironmentVariable(key), Environment.GetEnvironmentVariable(key.ToLower()), - Environment.GetEnvironmentVariable(key.ToUpper()) + Environment.GetEnvironmentVariable(key.ToUpper()), + //necessary for Azure + Environment.GetEnvironmentVariable(key.ToUpper().Replace('.', '_')) }; return variables.FirstOrDefault(variable => variable != null); } diff --git a/Aquality.Selenium.Core/src/Aquality.Selenium.Core/Utilities/JsonFile.cs b/Aquality.Selenium.Core/src/Aquality.Selenium.Core/Utilities/JsonFile.cs index 98cc0cf..b2ed7d8 100644 --- a/Aquality.Selenium.Core/src/Aquality.Selenium.Core/Utilities/JsonFile.cs +++ b/Aquality.Selenium.Core/src/Aquality.Selenium.Core/Utilities/JsonFile.cs @@ -1,12 +1,12 @@ -using Aquality.Selenium.Core.Logging; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using System; +using System; using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Linq; using System.Reflection; +using Aquality.Selenium.Core.Logging; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; namespace Aquality.Selenium.Core.Utilities { @@ -67,23 +67,11 @@ public T GetValue(string jsonPath) var envValue = GetEnvironmentValue(jsonPath); if (envValue != null) { - Logger.Instance.Debug($"***** Using variable passed from environment {jsonPath.Substring(1)}={envValue}"); - try - { - return (T)TypeDescriptor.GetConverter(typeof(T)).ConvertFrom(envValue); - } - catch (ArgumentException ex) - { - var message = $"Value of '{jsonPath}' environment variable has incorrect format: {ex.Message}"; - throw new ArgumentException(message); - } + return ConvertEnvVar(() => (T) TypeDescriptor.GetConverter(typeof(T)).ConvertFrom(envValue), + envValue, jsonPath); } var node = GetJsonNode(jsonPath); - if (node == null) - { - throw new ArgumentException($"There is no value found by path '{jsonPath}' in JSON file '{resourceName}'"); - } return node.ToObject(); } @@ -101,24 +89,35 @@ public IList GetValueList(string jsonPath) var envValue = GetEnvironmentValue(jsonPath); if (envValue != null) { - Logger.Instance.Debug($"***** Using variable passed from environment {jsonPath.Substring(1)}={envValue}"); - try + return ConvertEnvVar(() => { return envValue.Split(',').Select(value => (T)TypeDescriptor.GetConverter(typeof(T)).ConvertFrom(value.Trim())).ToList(); - } - catch (ArgumentException ex) - { - var message = $"Value of '{jsonPath}' environment variable has incorrect format: {ex.Message}"; - throw new ArgumentException(message); - } + }, envValue, jsonPath); } var node = GetJsonNode(jsonPath); - if (node == null) + return node.ToObject>(); + } + + /// + /// Gets dictionary of values from JSON. + /// Note that the value can be overriden via Environment variable with the same name; + /// (e.g. for json path ".timeouts.timeoutImplicit" you can set environment variable ".timeouts.timeoutImplicit") + /// + /// Relative JsonPath to the values. + /// Type of the value. + /// Value from JSON/Environment by JsonPath. + /// Throws when there are no values found by jsonPath in desired JSON file. + public IReadOnlyDictionary GetValueDictionary(string jsonPath) + { + var dict = new Dictionary(); + var node = GetJsonNode(jsonPath);; + foreach (var child in node.Children()) { - throw new ArgumentException($"There are no values found by path '{jsonPath}' in JSON file '{resourceName}'"); + dict.Add(child.Name, GetValue($".{child.Path}")); } - return node.ToObject>(); + + return dict; } /// @@ -128,18 +127,37 @@ public IList GetValueList(string jsonPath) /// True if present and false otherwise. public bool IsValuePresent(string jsonPath) { - return GetEnvironmentValue(jsonPath) != null || GetJsonNode(jsonPath) != null; + return GetEnvironmentValue(jsonPath) != null || JsonObject.SelectToken(jsonPath) != null; } - private string GetEnvironmentValue(string jsonPath) + private static string GetEnvironmentValue(string jsonPath) { - var key = jsonPath.Substring(1); + var key = jsonPath.Replace("['", ".").Replace("']", string.Empty).Substring(1); return EnvironmentConfiguration.GetVariable(key); } private JToken GetJsonNode(string jsonPath) { - return JsonObject.SelectToken(jsonPath); + var node = JsonObject.SelectToken(jsonPath); + if (node == null) + { + throw new ArgumentException($"There are no values found by path '{jsonPath}' in JSON file '{resourceName}'"); + } + return node; + } + + private static T ConvertEnvVar(Func convertMethod, string envValue, string jsonPath) + { + Logger.Instance.Debug($"***** Using variable passed from environment {jsonPath.Substring(1)}={envValue}"); + try + { + return convertMethod(); + } + catch (ArgumentException ex) + { + var message = $"Value of '{jsonPath}' environment variable has incorrect format: {ex.Message}"; + throw new ArgumentException(message); + } } } } diff --git a/Aquality.Selenium.Core/tests/Aquality.Selenium.Core.Tests/Configurations/EnvConfigurationTests.cs b/Aquality.Selenium.Core/tests/Aquality.Selenium.Core.Tests/Configurations/EnvConfigurationTests.cs new file mode 100644 index 0000000..22fae45 --- /dev/null +++ b/Aquality.Selenium.Core/tests/Aquality.Selenium.Core.Tests/Configurations/EnvConfigurationTests.cs @@ -0,0 +1,79 @@ +using Aquality.Selenium.Core.Configurations; +using NUnit.Framework; +using System; +using Microsoft.Extensions.DependencyInjection; + +namespace Aquality.Selenium.Core.Tests.Configurations +{ + [Parallelizable(ParallelScope.None)] + public class EnvConfigurationTests : TestWithoutApplication + { + private const string ProfileVariableName = "profile"; + private const string ProfileName = "custom"; + + [SetUp] + public new void SetUp() + { + Environment.SetEnvironmentVariable(ProfileVariableName, ProfileName); + } + + [TearDown] + public void CleanUp() + { + Environment.SetEnvironmentVariable(ProfileVariableName, null); + } + + [Test] + public void Should_BePossible_ToOverrideTimeouts_WithEnvVariables() + { + const string testValue = "1000"; + var expectedValueSec = TimeSpan.FromSeconds(1000); + var expectedValueMillis = TimeSpan.FromMilliseconds(1000); + const string messageTmp = "{0} timeout should be overridden with env variable"; + Environment.SetEnvironmentVariable("timeouts.timeoutImplicit", testValue); + Environment.SetEnvironmentVariable("timeouts.timeoutCondition", testValue); + Environment.SetEnvironmentVariable("timeouts.timeoutPollingInterval", testValue); + Environment.SetEnvironmentVariable("timeouts.timeoutCommand", testValue); + base.SetUp(); + + var config = ServiceProvider.GetService(); + Assert.Multiple(() => + { + Assert.AreEqual(expectedValueSec, config.Command, string.Format(messageTmp, "Command")); + Assert.AreEqual(expectedValueSec, config.Condition, string.Format(messageTmp, "Condition")); + Assert.AreEqual(expectedValueSec, config.Implicit, string.Format(messageTmp, "Implicit")); + Assert.AreEqual(expectedValueMillis, config.PollingInterval, string.Format(messageTmp, "PollingInterval")); + }); + } + + [Test] + public void Should_BePossible_ToOverrideRetryConfig_WithEnvVariables() + { + const string testValue = "1000"; + var expectedInterval = TimeSpan.FromMilliseconds(1000); + const int expectedNumber = 1000; + const string messageTmp = "Retry value '{0}' should be overridden with env variable"; + Environment.SetEnvironmentVariable("retry.number", testValue); + Environment.SetEnvironmentVariable("retry.pollingInterval", testValue); + base.SetUp(); + + var config = ServiceProvider.GetService(); + Assert.Multiple(() => + { + Assert.AreEqual(expectedInterval, config.PollingInterval, string.Format(messageTmp, "PollingInterval")); + Assert.AreEqual(expectedNumber, config.Number, string.Format(messageTmp, "Number")); + }); + } + + [Test] + public void Should_BePossible_ToOverrideLoggerConfig_WithEnvVariables() + { + const string testValue = "testLang"; + Environment.SetEnvironmentVariable("logger.language", testValue); + base.SetUp(); + + var config = ServiceProvider.GetService(); + Assert.AreEqual(testValue, config.Language, "Logger language value should be overridden with env variable"); + } + } +}